diff --git a/docs/html/md__cpp_usage.html b/docs/html/md__cpp_usage.html index 0a7ac1f56..1163e5e15 100644 --- a/docs/html/md__cpp_usage.html +++ b/docs/html/md__cpp_usage.html @@ -65,6 +65,7 @@ $(document).ready(function(){initNavTree('md__cpp_usage.html','');});
CreateString
and CreateVector
serialize these two built-in datatypes, and return offsets into the serialized data indicating where they are stored, such that Monster
below can refer to them.
CreateString
can also take an std::string
, or a const char *
with an explicit length, and is suitable for holding UTF-8 and binary data if needed.
CreateVector
can also take an std::vector
. The offset it returns is typed, i.e. can only be used to set fields of the correct type below. To create a vector of struct objects (which will be stored as contiguous memory in the buffer, use CreateVectorOfStructs
instead.
To create a vector of nested objects (e.g. tables, strings or other vectors) collect their offsets in a temporary array/vector, then call CreateVector
on that (see e.g. the array of strings example in test.cpp
CreateFlatBufferTest
).
Vec3
is the first example of code from our generated header. Structs (unlike tables) translate to simple structs in C++, so we can construct them in a familiar way.
We have now serialized the non-scalar components of of the monster example, so we could create the monster something like this:
diff --git a/docs/html/md__go_usage.html b/docs/html/md__go_usage.html index 3ebc8b6a2..33f729740 100644 --- a/docs/html/md__go_usage.html +++ b/docs/html/md__go_usage.html @@ -94,7 +94,7 @@ $(document).ready(function(){initNavTree('md__go_usage.html','');});The generated method 'StartInventoryVector' is provided as a convenience function which calls 'StartVector' with the correct element size of the vector type which in this case is 'ubyte' or 1 byte per vector element. You pass the number of elements you want to write. You write the elements backwards since the buffer is being constructed back to front. You then pass inv
to the corresponding Add
call when you construct the table containing it afterwards.
The generated method 'StartInventoryVector' is provided as a convenience function which calls 'StartVector' with the correct element size of the vector type which in this case is 'ubyte' or 1 byte per vector element. You pass the number of elements you want to write. You write the elements backwards since the buffer is being constructed back to front. Use the correct Prepend
call for the type, or PrependUOffsetT
for offsets. You then pass inv
to the corresponding Add
call when you construct the table containing it afterwards.
There are Prepend
functions for all the scalar types. You use PrependUOffset
for any previously constructed objects (such as other tables, strings, vectors). For structs, you use the appropriate create
function in-line, as shown above in the Monster
example.
Once you're done constructing a buffer, you call Finish
with the root object offset (mon
in the example above). Your data now resides in Builder.Bytes. Important to note is that the real data starts at the index indicated by Head(), for Offset() bytes (this is because the buffer is constructed backwards). If you wanted to read the buffer right after creating it (using GetRootAsMonster
above), the second argument, instead of 0
would thus also be Head()
.
These are the simplest, and as mentioned, intended for simple data that benefits from being extra efficient and doesn't need versioning / extensibility. They are always stored inline in their parent (a struct, table, or vector) for maximum compactness. Structs define a consistent memory layout where all components are aligned to their size, and structs aligned to their largest scalar member. This is done independent of the alignment rules of the underlying compiler to guarantee a cross platform compatible layout. This layout is then enforced in the generated code.
These start with an soffset_t
to a vtable (signed version of uoffset_t
, since vtables may be stored anywhere), followed by all the fields as aligned scalars (or offsets). Unlike structs, not all fields need to be present. There is no set order and layout.
These start with an soffset_t
to a vtable. This is a signed version of uoffset_t
, since vtables may be stored anywhere relative to the object. This offset is substracted (not added) from the object start to arrive at the vtable start. This offset is followed by all the fields as aligned scalars (or offsets). Unlike structs, not all fields need to be present. There is no set order and layout.
To be able to access fields regardless of these uncertainties, we go through a vtable of offsets. Vtables are shared between any objects that happen to have the same vtable values.
-The elements of a vtable are all of type voffset_t
, which is a uint16_t
. The first element is the number of elements of the vtable, including this one. The second one is the size of the object, in bytes (including the vtable offset). This size is used for streaming, to know how many bytes to read to be able to access all fields of the object. The remaining elements are the N offsets, where N is the amount of fields declared in the schema when the code that constructed this buffer was compiled (thus, the size of the table is N + 2).
The elements of a vtable are all of type voffset_t
, which is a uint16_t
. The first element is the size of the vtable in bytes, including the size element. The second one is the size of the object, in bytes (including the vtable offset). This size could be used for streaming, to know how many bytes to read to be able to access all fields of the object. The remaining elements are the N offsets, where N is the amount of fields declared in the schema when the code that constructed this buffer was compiled (thus, the size of the table is N + 2).
All accessor functions in the generated code for tables contain the offset into this table as a constant. This offset is checked against the first field (the number of elements), to protect against newer code reading older data. If this offset is out of range, or the vtable entry is 0, that means the field is not present in this object, and the default value is return. Otherwise, the entry is used as offset to the field to be read.
Strings are simply a vector of bytes, and are always null-terminated. Vectors are stored as contiguous aligned scalar elements prefixed by a 32bit element count (not including any null termination).
diff --git a/docs/html/md__schemas.html b/docs/html/md__schemas.html index e154a2022..aee2bd096 100644 --- a/docs/html/md__schemas.html +++ b/docs/html/md__schemas.html @@ -145,7 +145,7 @@ root_type Monster;original_order
(on a table): since elements in a table do not need to be stored in any particular order, they are often optimized for space by sorting them to size. This attribute stops that from happening.force_align: size
(on a struct): force the alignment of this struct to be something higher than what it is naturally aligned to. Causes these structs to be aligned to that amount inside a buffer, IF that buffer is allocated with that alignment (which is not necessarily the case for buffers accessed directly inside a FlatBufferBuilder
).bit_flags
(on an enum): the values of this field indicate bits, meaning that any value N specified in the schema will end up representing 1<<N, or if you don't specify values at all, you'll get the sequence 1, 2, 4, 8, ...nested_flatbuffer: table_name
(on a field): this indicates that the field (which must be a vector of ubyte) contains flatbuffer data, for which the root type is given by table_name
. The generated code will then produce a convenient accessor for the nested FlatBuffer.nested_flatbuffer: "table_name"
(on a field): this indicates that the field (which must be a vector of ubyte) contains flatbuffer data, for which the root type is given by table_name
. The generated code will then produce a convenient accessor for the nested FlatBuffer.The same parser that parses the schema declarations above is also able to parse JSON objects that conform to this schema. So, unlike other JSON parsers, this parser is strongly typed, and parses directly into a FlatBuffer (see the compiler documentation on how to do this from the command line, or the C++ documentation on how to do this at runtime).
diff --git a/docs/source/CppUsage.md b/docs/source/CppUsage.md index 62c45d816..91332d282 100755 --- a/docs/source/CppUsage.md +++ b/docs/source/CppUsage.md @@ -42,6 +42,11 @@ correct type below. To create a vector of struct objects (which will be stored as contiguous memory in the buffer, use `CreateVectorOfStructs` instead. +To create a vector of nested objects (e.g. tables, strings or other vectors) +collect their offsets in a temporary array/vector, then call `CreateVector` +on that (see e.g. the array of strings example in `test.cpp` +`CreateFlatBufferTest`). + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp} Vec3 vec(1, 2, 3); ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/docs/source/GoUsage.md b/docs/source/GoUsage.md index 10dbd5ed2..c2a7495c3 100644 --- a/docs/source/GoUsage.md +++ b/docs/source/GoUsage.md @@ -98,7 +98,8 @@ function which calls 'StartVector' with the correct element size of the vector type which in this case is 'ubyte' or 1 byte per vector element. You pass the number of elements you want to write. You write the elements backwards since the buffer -is being constructed back to front. You then pass `inv` to the corresponding +is being constructed back to front. Use the correct `Prepend` call for the type, +or `PrependUOffsetT` for offsets. You then pass `inv` to the corresponding `Add` call when you construct the table containing it afterwards. There are `Prepend` functions for all the scalar types. You use diff --git a/docs/source/Internals.md b/docs/source/Internals.md index bf4b58b49..bf1a980e6 100755 --- a/docs/source/Internals.md +++ b/docs/source/Internals.md @@ -73,8 +73,10 @@ code. ### Tables -These start with an `soffset_t` to a vtable (signed version of -`uoffset_t`, since vtables may be stored anywhere), followed by all the +These start with an `soffset_t` to a vtable. This is a signed version of +`uoffset_t`, since vtables may be stored anywhere relative to the object. +This offset is substracted (not added) from the object start to arrive at +the vtable start. This offset is followed by all the fields as aligned scalars (or offsets). Unlike structs, not all fields need to be present. There is no set order and layout. @@ -83,9 +85,9 @@ through a vtable of offsets. Vtables are shared between any objects that happen to have the same vtable values. The elements of a vtable are all of type `voffset_t`, which is -a `uint16_t`. The first element is the number of elements of the vtable, -including this one. The second one is the size of the object, in bytes -(including the vtable offset). This size is used for streaming, to know +a `uint16_t`. The first element is the size of the vtable in bytes, +including the size element. The second one is the size of the object, in bytes +(including the vtable offset). This size could be used for streaming, to know how many bytes to read to be able to access all fields of the object. The remaining elements are the N offsets, where N is the amount of fields declared in the schema when the code that constructed this buffer was diff --git a/docs/source/Schemas.md b/docs/source/Schemas.md index 9fce33667..1329f9ee2 100755 --- a/docs/source/Schemas.md +++ b/docs/source/Schemas.md @@ -271,7 +271,7 @@ Current understood attributes: meaning that any value N specified in the schema will end up representing 1<