From af1487bcfb1c223d6eb58bb6c1426e00197d55ed Mon Sep 17 00:00:00 2001 From: Wouter van Oortmerssen Date: Mon, 14 Sep 2015 11:00:12 -0700 Subject: [PATCH] Clarified use of unions in C++. Change-Id: I9654e0c6a45457c8e150f07dd5f7b39539266f9e --- docs/html/md__cpp_usage.html | 2 +- docs/html/md__java_usage.html | 15 ++++++++++++++- docs/source/CppUsage.md | 4 +++- 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/docs/html/md__cpp_usage.html b/docs/html/md__cpp_usage.html index 91bf63649..e22feedfc 100644 --- a/docs/html/md__cpp_usage.html +++ b/docs/html/md__cpp_usage.html @@ -79,7 +79,7 @@ $(document).ready(function(){initNavTree('md__cpp_usage.html','');});

We have now serialized the non-scalar components of of the monster example, so we could create the monster something like this:

auto mloc = CreateMonster(fbb, &vec, 150, 80, name, inventory, Color_Red, 0, Any_NONE);

Note that we're passing 150 for the mana field, which happens to be the default value: this means the field will not actually be written to the buffer, since we'll get that value anyway when we query it. This is a nice space savings, since it is very common for fields to be at their default. It means we also don't need to be scared to add fields only used in a minority of cases, since they won't bloat up the buffer sizes if they're not actually used.

-

We do something similarly for the union field test by specifying a 0 offset and the NONE enum value (part of every union) to indicate we don't actually want to write this field. You can use 0 also as a default for other non-scalar types, such as strings, vectors and tables.

+

We do something similarly for the union field test by specifying a 0 offset and the NONE enum value (part of every union) to indicate we don't actually want to write this field. You can use 0 also as a default for other non-scalar types, such as strings, vectors and tables. To pass an actual table, pass a preconstructed table as mytable.Union() that corresponds to union enum you're passing.

Tables (like Monster) give you full flexibility on what fields you write (unlike Vec3, which always has all fields set because it is a struct). If you want even more control over this (i.e. skip fields even when they are not default), instead of the convenient CreateMonster call we can also build the object field-by-field manually:

MonsterBuilder mb(fbb);
mb.add_pos(&vec);
diff --git a/docs/html/md__java_usage.html b/docs/html/md__java_usage.html index a7ed783ca..96904fc25 100644 --- a/docs/html/md__java_usage.html +++ b/docs/html/md__java_usage.html @@ -117,7 +117,20 @@ $(document).ready(function(){initNavTree('md__java_usage.html','');});
var preconstructedPos = new Vec3();
monster.GetPos(preconstructedPos);

Text parsing

-

There currently is no support for parsing text (Schema's and JSON) directly from Java or C#, though you could use the C++ parser through native call interfaces available to each language. Please see the C++ documentation for more on text parsing.

+

There currently is no support for parsing text (Schema's and JSON) directly from Java or C#, though you could use the C++ parser through native call interfaces available to each language. Please see the C++ documentation for more on text parsing.

+

Mutating FlatBuffers

+

As you saw above, typically once you have created a FlatBuffer, it is read-only from that moment on. There are however cases where you have just received a FlatBuffer, and you'd like to modify something about it before sending it on to another recipient. With the above functionality, you'd have to generate an entirely new FlatBuffer, while tracking what you modify in your own data structures. This is inconvenient.

+

For this reason FlatBuffers can also be mutated in-place. While this is great for making small fixes to an existing buffer, you generally want to create buffers from scratch whenever possible, since it is much more efficient and the API is much more general purpose.

+

To get non-const accessors, invoke flatc with --gen-mutable.

+

You now can:

+
Monster monster = Monster.getRootAsMonster(bb);
+
monster.mutateHp(10); // Set table field.
+
monster.pos().mutateZ(4); // Set struct field.
+
monster.mutateInventory(0, 1); // Set vector element.
+

We use the somewhat verbose term mutate instead of set to indicate that this is a special use case, not to be confused with the default way of constructing FlatBuffer data.

+

After the above mutations, you can send on the FlatBuffer to a new recipient without any further work!

+

Note that any mutate functions on tables return a boolean, which is false if the field we're trying to set isn't present in the buffer. Fields are not present if they weren't set, or even if they happen to be equal to the default value. For example, in the creation code above we set the mana field to 150, which is the default value, so it was never stored in the buffer. Trying to call mutateMana() on such data will return false, and the value won't actually be modified!

+

One way to solve this is to call forceDefaults() on a FlatBufferBuilder to force all fields you set to actually be written. This of course increases the size of the buffer somewhat, but this may be acceptable for a mutable buffer.

diff --git a/docs/source/CppUsage.md b/docs/source/CppUsage.md index 0786dcbf3..31619e9d4 100755 --- a/docs/source/CppUsage.md +++ b/docs/source/CppUsage.md @@ -72,7 +72,9 @@ since they won't bloat up the buffer sizes if they're not actually used. We do something similarly for the union field `test` by specifying a `0` offset and the `NONE` enum value (part of every union) to indicate we don't actually want to write this field. You can use `0` also as a default for other -non-scalar types, such as strings, vectors and tables. +non-scalar types, such as strings, vectors and tables. To pass an actual +table, pass a preconstructed table as `mytable.Union()` that corresponds to +union enum you're passing. Tables (like `Monster`) give you full flexibility on what fields you write (unlike `Vec3`, which always has all fields set because it is a `struct`).