mirror of
https://github.com/google/flatbuffers.git
synced 2026-06-04 04:33:23 +00:00
Mutable FlatBuffers: in-place updates.
This commit contains the first step in providing mutable FlatBuffers, non-const accessors and mutation functions for existing fields generated from --gen-mutable. Change-Id: Iebee3975f05c1001f8e22824725edeaa6d85fbee Tested: on Linux. Bug: 15777024
This commit is contained in:
@@ -51,6 +51,9 @@ be generated for each file processed:
|
||||
- `--gen-includes` : Generate include statements for included schemas the
|
||||
generated file depends on (C++).
|
||||
|
||||
- `--gen-mutable` : Generate additional non-const accessors for mutating
|
||||
FlatBuffers in-place.
|
||||
|
||||
- `--proto`: Expect input files to be .proto files (protocol buffers).
|
||||
Output the corresponding .fbs file.
|
||||
Currently supports: `package`, `message`, `enum`.
|
||||
|
||||
@@ -163,6 +163,55 @@ Similarly, we can access elements of the inventory array:
|
||||
assert(inv->Get(9) == 9);
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
### 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`.
|
||||
|
||||
Similar to the reading API above, you now can:
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
|
||||
auto monster = GetMutableMonster(buffer_pointer); // non-const
|
||||
monster->mutate_hp(10); // Set table field.
|
||||
monster->mutable_pos()->mutate_z(4); // Set struct field.
|
||||
monster->mutable_inventory()->Mutate(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 bool, 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 mutate_mana() on such data will return false, and the value won't
|
||||
actually be modified!
|
||||
|
||||
There's two ways around this. First, you can 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.
|
||||
|
||||
Alternatively, you can use mutation functions that are able to insert fields
|
||||
and change the size of things. These functions are expensive however, since
|
||||
they need to resize the buffer and create new data.
|
||||
|
||||
### Storing maps / dictionaries in a FlatBuffer
|
||||
|
||||
FlatBuffers doesn't support maps natively, but there is support to
|
||||
|
||||
Reference in New Issue
Block a user