Move some C specifics out of tutorial and clarify platform support

parent 9b8c91c9
...@@ -19,31 +19,193 @@ project. ...@@ -19,31 +19,193 @@ project.
- The C Builder Interface (advanced) <https://github.com/dvidelabs/flatcc/blob/master/doc/builder.md> - The C Builder Interface (advanced) <https://github.com/dvidelabs/flatcc/blob/master/doc/builder.md>
## Supported Platforms
Ubuntu and OS-X are regularly tested during releases. Centos 7.1
has also been tested. Cross compilation to little-endian ARM has been
reported to work with warnings.
Windows has not been tested. The `include/flatcc/portable` library is
intended to abstract platform differences, including Windows. User
feedback and patches are welcome.
Big endian platforms have not been tested and may contain bugs, but care
has been taken to provide support for it.
## Modular Object Creation
In the tutorial we used the call `Monster_create_as_root` to create the
root buffer object since this is easier in simple use cases. Sometimes
we need more modularity so we can reuse a function to create nested
tables and root tables the same way. For this we need the
`flatcc_builder_buffer_create_call`. It is best to keep `flatcc_builder`
calls isolated at the top driver level, so we get:
<div class="language-c">
~~~{.c}
ns(Monster_ref_t) create_orc(flatcc_builder_t *B)
{
// ... same as in the tutorial.
return s(Monster_create(B, ...));
}
void create_monster_buffer()
{
uint8_t *buf;
size_t size;
flatcc_builder_t builder, *B;
// Initialize the builder object.
B = &builder;
flatcc_builder_init(B);
// Only use `buffer_create` without `create/start/end_as_root`.
flatcc_builder_buffer_create(create_orc(B));
// Allocate and copy buffer to user memory.
buf = flatcc_builder_finalize_buffer(B, &size);
// ... write the buffer to disk or network, or something.
free(buf);
flatcc_builder_clear(B);
}
~~~
</div>
The same principle applies with `start/end` vs `start/end_as_root` in
the top-down approach.
## Top Down Example
The tutorial uses a bottom up approach. In C it is also possible to use
a top-down approach by starting and ending objects nested within each
other. In the tutorial there is no deep nesting, so the difference is
limited, but it shows the idea:
<div class="language-c">
<br>
~~~{.c}
uint8_t treasure[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
size_t treasure_count = c_vec_len(treasure);
ns(Weapon_ref_t) axe;
// NOTE: if we use end_as_root, we MUST also start as root.
ns(Monster_start_as_root(B));
ns(Monster_pos_create(B, 1.0f, 2.0f, 3.0f));
ns(Monster_hp_add(B, 300));
ns(Monster_mana_add(B, 150));
// We use create_str instead of add because we have no existing string reference.
ns(Monster_name_create_str(B, "Orc"));
// Again we use create because we no existing vector object, only a C-array.
ns(Monster_inventory_create(B, treasure, treasure_count));
ns(Monster_color_add(B, ns(Color_Red)));
if (1) {
ns(Monster_weapons_start(B));
ns(Monster_weapons_push_create(B, flatbuffers_string_create_str(B, "Sword"), 3));
// We reuse the axe object later. Note that we dereference a pointer
// because push always returns a short-term pointer to the stored element.
// We could also have created the axe object first and simply pushed it.
axe = *ns(Monster_weapons_push_create(B, flatbuffers_string_create_str(B, "Axe"), 5));
ns(Monster_weapons_end(B));
} else {
// We can have more control with the table elements added to a vector:
//
ns(Monster_weapons_start(B));
ns(Monster_weapons_push_start(B));
ns(Weapon_name_create_str(B, "Sword"));
ns(Weapon_damage_add(B, 3));
ns(Monster_weapons_push_end(B));
ns(Monster_weapons_push_start(B));
ns(Monster_weapons_push_start(B));
ns(Weapon_name_create_str(B, "Axe"));
ns(Weapon_damage_add(B, 5));
axe = *ns(Monster_weapons_push_end(B));
ns(Monster_weapons_end(B));
}
// Unions can get their type by using a type-specific add/create/start method.
ns(Monster_equipped_Weapon_add(B, axe));
ns(Monster_end_as_root(B));
~~~
</div>
## Basic Reflection ## Basic Reflection
The C-API does support reading binary schema (.bfbs) The C-API does support reading binary schema (.bfbs)
files via code generated from the `reflection.fbs` schema, and an files via code generated from the `reflection.fbs` schema, and an
[example usage](https://github.com/dvidelabs/flatcc/tree/master/samples/reflection) [example usage](https://github.com/dvidelabs/flatcc/tree/master/samples/reflection)
shows how to use this. The schema files are pre-generated shows how to use this. The reflection schema files are pre-generated
in the [runtime distribution](https://github.com/dvidelabs/flatcc/tree/master/include/flatcc/reflection). in the [runtime distribution](https://github.com/dvidelabs/flatcc/tree/master/include/flatcc/reflection).
## Mutating Reflection ## Mutations and Reflection
The C-API does not support mutating reflection like C++ does. The C-API does not support mutating reflection like C++ does, nor does
the reader interface support mutating scalars (and it is generally
unsafe to do so even after verification).
Although the following isn't reflection, it is possible to create new The generated reader interface supports sorting vectors in-place after
buffers using complex objects from existing buffers as source. This can casting them to a mutating type because it is not practical to do so
be very efficient due to direct copy semantics without endian conversion or while building a buffer. This is covered in the builder documentation.
temporary stack allocation. The reflection example makes use of this feature to look up objects by
name.
It is possible to build new buffers using complex objects from existing
buffers as source. This can be very efficient due to direct copy
semantics without endian conversion or temporary stack allocation.
Scalars, structs and strings can be used as source, as well vectors of Scalars, structs and strings can be used as source, as well vectors of
these. these.
It is currently not possible to use an existing table or vector of table It is currently not possible to use an existing table or vector of table
as source, but it would be possible to add support for this at some as source, but it would be possible to add support for this at some
point. Vectors of strings point.
## Namespaces
The `FLATBUFFERS_WRAP_NAMESPACE` approach used in the tutorial is convenient
when each function has a very long namespace prefix. But it isn't always
we the best approach. If the namespace is absent, or very simple and
informative, we might as well use the prefix directly. The
[reflection example](https://github.com/dvidelabs/flatcc/blob/master/samples/reflection/bfbs2json.c)
mentioned above uses this approach.
## Checking for Present Members
Not all languages support testing if a field is present, but in C we can
elaborate the reader section of the tutorial with tests for this. Recall
that `mana` was set to the default value `150` and therefore shouldn't
be present.
<div class="language-c">
~~~{.c}
int hp_present = ns(Monster_hp_is_present(monster)); // 1
int mana_present = ns(Monster_mana_is_present(monster)); // 0
~~~
</div>
## Alternative ways to add a Union
In the tutorial we used a single call to add a union. Here we show
different ways to accomplish the same thing. The last form is rarely
used, but is the low-level way to do it. It can be used to group small
values together in the table by adding type and data at different
points in time.
<div class="language-c">
~~~{.c}
ns(Equipment_union_ref_t) equipped = ns(Equipment_as_Weapon(axe));
ns(Monster_equipped_add(B, equipped));
// or alternatively
ns(Monster_equipped_Weapon_add(B, axe);
// or alternatively
ns(Monster_equipped_type_add(B, ns(Equipment_Weapon));
ns(Monster_equipped_add_member(B, axe));
~~~
</div>
## Why not integrate with the `flatc` tool? ## Why not integrate with the `flatc` tool?
...@@ -55,3 +217,5 @@ a complicated intermediate representation would have to be invented. ...@@ -55,3 +217,5 @@ a complicated intermediate representation would have to be invented.
Neither of these alternatives are very attractive, and it isn't a big Neither of these alternatives are very attractive, and it isn't a big
deal to use the `flatcc` tool instead of `flatc` given that the deal to use the `flatcc` tool instead of `flatc` given that the
FlatBuffers C runtime library needs to be made available regardless. FlatBuffers C runtime library needs to be made available regardless.
...@@ -131,7 +131,7 @@ sections provide a more in-depth usage guide. ...@@ -131,7 +131,7 @@ sections provide a more in-depth usage guide.
in your own programs. in your own programs.
- How to [use the generated Go code](@ref flatbuffers_guide_use_go) in your - How to [use the generated Go code](@ref flatbuffers_guide_use_go) in your
own programs. own programs.
- How to [use the generated C code](@ref flatbuffers_guide_use_c) in your - How to [use FlatBuffers in C with `flatcc`](@ref flatbuffers_guide_use_c) in your
own programs. own programs.
- [Support matrix](@ref flatbuffers_support) for platforms/languages/features. - [Support matrix](@ref flatbuffers_support) for platforms/languages/features.
- Some [benchmarks](@ref flatbuffers_benchmarks) showing the advantage of - Some [benchmarks](@ref flatbuffers_benchmarks) showing the advantage of
......
...@@ -28,7 +28,7 @@ Buffer verifier | Yes | No | No | No | No | No ...@@ -28,7 +28,7 @@ Buffer verifier | Yes | No | No | No | No | No
Testing: basic | Yes | Yes | Yes | Yes | Yes | Yes | Yes | ? | ? Testing: basic | Yes | Yes | Yes | Yes | Yes | Yes | Yes | ? | ?
Testing: fuzz | Yes | No | No | Yes | Yes | No | No | ? | ? Testing: fuzz | Yes | No | No | Yes | Yes | No | No | ? | ?
Performance: | Superb | Great | Great | Great | Ok | ? |Superb| ? | ? Performance: | Superb | Great | Great | Great | Ok | ? |Superb| ? | ?
Platform: Windows | VS2010 | Yes | Yes | ? | ? | ? | No | ? | ? Platform: Windows | VS2010 | Yes | Yes | ? | ? | ? | ? | ? | ?
Platform: Linux | GCC282 | Yes | ? | Yes | Yes | ? | Yes | ? | ? Platform: Linux | GCC282 | Yes | ? | Yes | Yes | ? | Yes | ? | ?
Platform: OS X | Xcode4 | ? | ? | ? | Yes | ? | Yes | ? | ? Platform: OS X | Xcode4 | ? | ? | ? | Yes | ? | Yes | ? | ?
Platform: Android | NDK10d | Yes | ? | ? | ? | ? | ? | ? | ? Platform: Android | NDK10d | Yes | ? | ? | ? | ? | ? | ? | ?
......
...@@ -234,7 +234,6 @@ FlatBuffer compiler. ...@@ -234,7 +234,6 @@ FlatBuffer compiler.
Once `flatc` is built successfully, compile the schema for your language: Once `flatc` is built successfully, compile the schema for your language:
<div class="language-c"> <div class="language-c">
*Note: If you're working in C, you need to use the separate project [FlatCC](https://github.com/dvidelabs/flatcc) which contains a schema compiler and runtime library in C for C.* *Note: If you're working in C, you need to use the separate project [FlatCC](https://github.com/dvidelabs/flatcc) which contains a schema compiler and runtime library in C for C.*
<br> <br>
See [flatcc build instructions](https://github.com/dvidelabs/flatcc#building). See [flatcc build instructions](https://github.com/dvidelabs/flatcc#building).
...@@ -391,14 +390,11 @@ The first step is to import/include the library, generated files, etc. ...@@ -391,14 +390,11 @@ The first step is to import/include the library, generated files, etc.
#include "monster_builder.h" // Generated by `flatcc`. #include "monster_builder.h" // Generated by `flatcc`.
// Convenient namespace macro to manage long namespace prefix. // Convenient namespace macro to manage long namespace prefix.
#undef ns
#define ns(x) FLATBUFFERS_WRAP_NAMESPACE(MyGame_Sample, x) // Specified in the schema. #define ns(x) FLATBUFFERS_WRAP_NAMESPACE(MyGame_Sample, x) // Specified in the schema.
// Convenient common namespace macro.
#define nsc(x) FLATBUFFERS_WRAP_NAMESPACE(flatbuffers, x)
// A helper to simplify creating vectors from C-arrays. // A helper to simplify creating vectors from C-arrays.
#define c_vec_len(V) (sizeof(V)/sizeof((V)[0])) #define c_vec_len(V) (sizeof(V)/sizeof((V)[0]))
// The ns macro makes it possible to write `ns(Monster_create(...))`
// instead of `MyGame_Sample_Monster_create(...)`.
~~~ ~~~
</div> </div>
...@@ -577,10 +573,10 @@ our `orc` Monster, lets create some `Weapon`s: a `Sword` and an `Axe`. ...@@ -577,10 +573,10 @@ our `orc` Monster, lets create some `Weapon`s: a `Sword` and an `Axe`.
</div> </div>
<div class="language-c"> <div class="language-c">
~~~{.c} ~~~{.c}
ns(Weapon_ref_t) weapon_one_name = nsc(string_create_str(B, "Sword")); ns(Weapon_ref_t) weapon_one_name = flatbuffers_string_create_str(B, "Sword");
uint16_t weapon_one_damage = 3; uint16_t weapon_one_damage = 3;
ns(Weapon_ref_t) weapon_two_name = nsc(string_create_str(B, "Axe")); ns(Weapon_ref_t) weapon_two_name = flatbuffers_string_create_str(B, "Axe");
uint16_t weapon_two_damage = 5; uint16_t weapon_two_damage = 5;
ns(Weapon_ref_t) sword = ns(Weapon_create(B, weapon_one_name, weapon_one_damage)); ns(Weapon_ref_t) sword = ns(Weapon_create(B, weapon_one_name, weapon_one_damage));
...@@ -693,14 +689,14 @@ traversal. This is generally easy to do on any tree structures. ...@@ -693,14 +689,14 @@ traversal. This is generally easy to do on any tree structures.
~~~{.c} ~~~{.c}
// Serialize a name for our monster, called "Orc". // Serialize a name for our monster, called "Orc".
// The _str suffix indicates the source is an ascii-z string. // The _str suffix indicates the source is an ascii-z string.
nsc(string_ref_t) name = nsc(string_create_str(B, "Orc")); flatbuffers_string_ref_t name = flatbuffers_string_create_str(B, "Orc");
// Create a `vector` representing the inventory of the Orc. Each number // Create a `vector` representing the inventory of the Orc. Each number
// could correspond to an item that can be claimed after he is slain. // could correspond to an item that can be claimed after he is slain.
uint8_t treasure[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; uint8_t treasure[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
nsc(uint8_vec_ref_t) inventory; flatbuffers_uint8_vec_ref_t inventory;
// `c_vec_len` is the convenience macro we defined earlier. // `c_vec_len` is the convenience macro we defined earlier.
inventory = nsc(uint8_vec_create(B, treasure, c_vec_len(treasure))); inventory = flatbuffers_uint8_vec_create(B, treasure, c_vec_len(treasure));
~~~ ~~~
</div> </div>
...@@ -718,13 +714,6 @@ and `Axe`). These are both FlatBuffer `table`s, whose offsets we now store in ...@@ -718,13 +714,6 @@ and `Axe`). These are both FlatBuffer `table`s, whose offsets we now store in
memory. Therefore we can create a FlatBuffer `vector` to contain these memory. Therefore we can create a FlatBuffer `vector` to contain these
offsets. offsets.
<div class="language-c">
*Note: If you're using C, there is also an often shorter top-down
approach that avoids storing temporary references because the runtime
has an internal stack. The top-down version is shown at the end of build
section.*
</div>
<div class="language-cpp"> <div class="language-cpp">
~~~{.cpp} ~~~{.cpp}
// Place the weapons into a `std::vector`, then convert that into a FlatBuffer `vector`. // Place the weapons into a `std::vector`, then convert that into a FlatBuffer `vector`.
...@@ -794,10 +783,7 @@ section.* ...@@ -794,10 +783,7 @@ section.*
</div> </div>
<div class="language-c"> <div class="language-c">
~~~{.c} ~~~{.c}
// Here we use a top-down approach locally to build a Weapons vector // We use the internal builder stack to implement a dynamic vector.
// in-place instead of creating a temporary external vector to use
// as argument like we did with the `inventory` earlier on, but the
// overall approach is still bottom-up.
ns(Weapon_vec_start(B)); ns(Weapon_vec_start(B));
ns(Weapon_vec_push(B, sword)); ns(Weapon_vec_push(B, sword));
ns(Weapon_vec_push(B, axe)); ns(Weapon_vec_push(B, axe));
...@@ -970,31 +956,23 @@ can serialize the monster itself: ...@@ -970,31 +956,23 @@ can serialize the monster itself:
uint16_t hp = 300; uint16_t hp = 300;
uint16_t mana = 150; uint16_t mana = 150;
// Create the equipment union. In the C++ language API this is given // Define an equipment union. `create` calls in C has a single
// as two arguments to the create call, or as two separate add // argument for unions where C++ has both a type and a data argument.
// operations for the type and the table reference. In C we create
// a single union value that carries both the type and reference.
ns(Equipment_union_ref_t) equipped = ns(Equipment_as_Weapon(axe)); ns(Equipment_union_ref_t) equipped = ns(Equipment_as_Weapon(axe));
ns(Monster_create_as_root(B, &pos, mana, hp, name, inventory, ns(Color_Red), ns(Monster_create_as_root(B, &pos, mana, hp, name, inventory, ns(Color_Red),
weapons, equipped)); weapons, equipped));
~~~ ~~~
</div> </div>
<div class="language-c">
*Note: in C we use `create_as_root` instead of the also valid `create` call
because it simplfies constructing the root object.*
</div>
<div class="language-cpp">
<br>
*Note: Since we are passing `150` as the `mana` field, which happens to be the *Note: Since we are passing `150` as the `mana` field, which happens to be the
default value, the field will not actually be written to the buffer, since the default value, the field will not actually be written to the buffer, since the
default value will be returned on query anyway. This is a nice space savings, default value will be returned on query anyway. This is a nice space savings,
especially if default values are common in your data. It also means that you do especially if default values are common in your data. It also means that you do
not need to be worried of adding a lot of fields that are only used in a small not need to be worried of adding a lot of fields that are only used in a small
number of instances, as it will not bloat the buffer if unused.* number of instances, as it will not bloat the buffer if unused.*
<br><br>
<div class="language-cpp">
<br>
If you do not wish to set every field in a `table`, it may be more convenient to If you do not wish to set every field in a `table`, it may be more convenient to
manually set each field of your monster, instead of calling `CreateMonster()`. manually set each field of your monster, instead of calling `CreateMonster()`.
The following snippet is functionally equivalent to the above code, but provides The following snippet is functionally equivalent to the above code, but provides
...@@ -1016,14 +994,6 @@ a bit more flexibility. ...@@ -1016,14 +994,6 @@ a bit more flexibility.
~~~ ~~~
</div> </div>
<div class="language-c"> <div class="language-c">
<br>
*Note: Since we are passing `150` as the `mana` field, which happens to be the
default value, the field will not actually be written to the buffer, since the
default value will be returned on query anyway. This is a nice space savings,
especially if default values are common in your data. It also means that you do
not need to be worried of adding a lot of fields that are only used in a small
number of instances, as it will not bloat the buffer if unused.*
<br><br>
If you do not wish to set every field in a `table`, it may be more convenient to If you do not wish to set every field in a `table`, it may be more convenient to
manually set each field of your monster, instead of calling `create_monster_as_root()`. manually set each field of your monster, instead of calling `create_monster_as_root()`.
The following snippet is functionally equivalent to the above code, but provides The following snippet is functionally equivalent to the above code, but provides
...@@ -1058,11 +1028,6 @@ Second, is the `union`'s data. ...@@ -1058,11 +1028,6 @@ Second, is the `union`'s data.
In our example, the last two things we added to our `Monster` were the In our example, the last two things we added to our `Monster` were the
`Equipped Type` and the `Equipped` union itself. `Equipped Type` and the `Equipped` union itself.
<div class="language-c">
*Note: In C, several different helpers make these two fields appear as
one field, but they can be added separately.*
</div>
Here is a repetition these lines, to help highlight them more clearly: Here is a repetition these lines, to help highlight them more clearly:
<div class="language-cpp"> <div class="language-cpp">
...@@ -1110,62 +1075,8 @@ Here is a repetition these lines, to help highlight them more clearly: ...@@ -1110,62 +1075,8 @@ Here is a repetition these lines, to help highlight them more clearly:
</div> </div>
<div class="language-c"> <div class="language-c">
~~~{.c} ~~~{.c}
ns(Equipment_union_ref_t) equipped = ns(Equipment_as_Weapon(axe)); // Add union type and data simultanously.
ns(Monster_equipped_add(B, equipped)); ns(Monster_equipped_Weapon_add(B, axe));
// or alternatively
ns(Monster_equipped_Weapon_add(B, axe);
// or alternatively
ns(Monster_equipped_type_add(B, ns(Equipment_Weapon));
ns(Monster_equipped_add_member(B, axe));
~~~
</div>
<div class="language-c">
Here is an alternative top-down approach unique to the C builder
library.
<br>
~~~{.c}
uint8_t treasure[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
size_t treasure_count = c_vec_len(treasure);
ns(Weapon_ref_t) axe;
// NOTE: if we use end_as_root, we MUST also start as root.
ns(Monster_start_as_root(B));
ns(Monster_pos_create(B, 1.0f, 2.0f, 3.0f));
ns(Monster_hp_add(B, 300));
ns(Monster_mana_add(B, 150));
// We use create_str instead of add because we have no existing string reference.
ns(Monster_name_create_str(B, "Orc"));
// Again we use create because we no existing vector object, only a C-array.
ns(Monster_inventory_create(B, treasure, treasure_count));
ns(Monster_color_add(B, ns(Color_Red)));
if (1) {
ns(Monster_weapons_start(B));
ns(Monster_weapons_push_create(B, nsc(string_create_str(B, "Sword")), 3));
// We reuse the axe object later. Note that we dereference a pointer
// because push always returns a short-term pointer to the stored element.
// We could also have created the axe object first and simply pushed it.
axe = *ns(Monster_weapons_push_create(B, nsc(string_create_str(B, "Axe")), 5));
ns(Monster_weapons_end(B));
} else {
// We can have more control with the table elements added to a vector:
//
ns(Monster_weapons_start(B));
ns(Monster_weapons_push_start(B));
ns(Weapon_name_create_str(B, "Sword"));
ns(Weapon_damage_add(B, 3));
ns(Monster_weapons_push_end(B));
ns(Monster_weapons_push_start(B));
ns(Monster_weapons_push_start(B));
ns(Weapon_name_create_str(B, "Axe"));
ns(Weapon_damage_add(B, 5));
axe = *ns(Monster_weapons_push_end(B));
ns(Monster_weapons_end(B));
}
// Unions can get their type by using a type-specific add/create/start method.
ns(Monster_equipped_Weapon_add(B, axe));
ns(Monster_end_as_root(B));
~~~ ~~~
</div> </div>
...@@ -1173,12 +1084,6 @@ After you have created your buffer, you will have the offset to the root of the ...@@ -1173,12 +1084,6 @@ After you have created your buffer, you will have the offset to the root of the
data in the `orc` variable, so you can finish the buffer by calling the data in the `orc` variable, so you can finish the buffer by calling the
appropriate `finish` method. appropriate `finish` method.
<div class="language-c">
*Note: C does not have a `finish` call, and it is not needed when we use
`create_as_root` or `start/end_as_root`. For the sake of modularity, it
is sometimes useful to create an object without knowing if it will be a
root. We show this below, but do NOT mix it with the `_as_root` calls.*
</div>
<div class="language-cpp"> <div class="language-cpp">
~~~{.cpp} ~~~{.cpp}
...@@ -1229,10 +1134,7 @@ root. We show this below, but do NOT mix it with the `_as_root` calls.* ...@@ -1229,10 +1134,7 @@ root. We show this below, but do NOT mix it with the `_as_root` calls.*
</div> </div>
<div class="language-c"> <div class="language-c">
~~~{.c} ~~~{.c}
// Alternative approach separating object creation from being root object. // Because we used `Monster_create_as_root`, we do not need a `finish` call in C`.
ns(Monster_ref_t) orc = ns(Monster_create(B, ...));
// `flatcc_` calls should be isolated to top-level driver logic.
flatcc_builder_buffer_create(orc);
~~~ ~~~
</div> </div>
...@@ -1317,12 +1219,6 @@ deserialize a FlatBuffer. ...@@ -1317,12 +1219,6 @@ deserialize a FlatBuffer.
This section requires the same import/include, namespace, etc. requirements as This section requires the same import/include, namespace, etc. requirements as
before: before:
<div class="language-c">
*Note: In C there is a separate include file for the reader which is automatically
included by the generated builder header. A standalone reader only depends on header
files while the builder must link with a small runtime library.*
</div>
<div class="language-cpp"> <div class="language-cpp">
~~~{.cpp} ~~~{.cpp}
#include "monster_generate.h" // This was generated by `flatc`. #include "monster_generate.h" // This was generated by `flatc`.
...@@ -1401,10 +1297,11 @@ files while the builder must link with a small runtime library.* ...@@ -1401,10 +1297,11 @@ files while the builder must link with a small runtime library.*
</div> </div>
<div class="language-c"> <div class="language-c">
~~~{.c} ~~~{.c}
// Only needed if we don't have `#include "monster_builder.h"`.
#include "monster_reader.h" #include "monster_reader.h"
#undef ns
#define ns(x) FLATBUFFERS_WRAP_NAMESPACE(MyGame_Sample, x) // Specified in the schema. #define ns(x) FLATBUFFERS_WRAP_NAMESPACE(MyGame_Sample, x) // Specified in the schema.
#define nsc(x) FLATBUFFERS_WRAP_NAMESPACE(flatbuffers, x)
~~~ ~~~
</div> </div>
...@@ -1565,29 +1462,14 @@ accessors for all non-`deprecated` fields. For example: ...@@ -1565,29 +1462,14 @@ accessors for all non-`deprecated` fields. For example:
<div class="language-c"> <div class="language-c">
~~~{.c} ~~~{.c}
uint16_t hp = ns(Monster_hp(monster)); uint16_t hp = ns(Monster_hp(monster));
// Since 150 is the default, we are reading a value that wasn't stored.
uint16_t mana = ns(Monster_mana(monster)); uint16_t mana = ns(Monster_mana(monster));
// This is just a const char *, but it also supports a fast length operation. flatbuffers_string_t name = ns(Monster_name(monster));
nsc(string_t) name = ns(Monster_name(monster));
size_t name_len = nsc(string_len(name));
~~~ ~~~
</div> </div>
<div class="language-c">
*Note: In C we can check if a field is present. For example `mana`
should not be present because it was set with a default value or not at
all, but `hp` should be present.*
~~~{.c}
int hp_present = ns(Monster_hp_is_present(monster)); // 1
int mana_present = ns(Monster_mana_is_present(monster)); // 0
~~~
</div>
These should hold `300`, `150`, and `"Orc"` respectively. These should hold `300`, `150`, and `"Orc"` respectively.
*Note: We never stored a value in `mana`, so we got the default value of `150`.* *Note: The default value `150` wasn't stored in `mana`, but we are still able to retrieve it.*
To access sub-objects, in the case of our `pos`, which is a `Vec3`: To access sub-objects, in the case of our `pos`, which is a `Vec3`:
...@@ -1659,13 +1541,6 @@ To access sub-objects, in the case of our `pos`, which is a `Vec3`: ...@@ -1659,13 +1541,6 @@ To access sub-objects, in the case of our `pos`, which is a `Vec3`:
float x = ns(Vec3_x(pos)); float x = ns(Vec3_x(pos));
float y = ns(Vec3_y(pos)); float y = ns(Vec3_y(pos));
float z = ns(Vec3_z(pos)); float z = ns(Vec3_z(pos));
// or alternatively
ns(Vec3_t) pos_vec;
// `pe` indicates endian conversion from protocol to native.
ns(Vec3_copy_from_pe(&pos_vec, pos));
x = pos_vec.x;
// ...
~~~ ~~~
</div> </div>
...@@ -1722,15 +1597,10 @@ FlatBuffers `vector`. ...@@ -1722,15 +1597,10 @@ FlatBuffers `vector`.
</div> </div>
<div class="language-c"> <div class="language-c">
~~~{.c} ~~~{.c}
// This is a const uint8_t *, but it shouldn't be accessed directly // If `inv` hasn't been set, it will be null. It is valid get
// to ensure proper endian conversion. Incidentally the uint8 (ubyte) // the length of null which will be 0, useful for iteration.
// is not sensitive to endianness, so we *could* have accessed it directly. flatbuffers_uint8_vec_t inv = ns(Monster_inventory(monster));
// The compiler likely optimizes this so that it doesn't matter. size_t inv_len = flatbuffers_uint8_vec_len(inv);
nsc(uint8_vec_t) inv = ns(Monster_inventory(monster));
size_t inv_len = nsc(uint8_vec_len(inv));
// If `inv` was not set, it will be null, but the length is still
// valid to read and will then be zero.
~~~ ~~~
</div> </div>
...@@ -1795,7 +1665,7 @@ except your need to handle the result as a FlatBuffer `table`: ...@@ -1795,7 +1665,7 @@ except your need to handle the result as a FlatBuffer `table`:
~~~{.c} ~~~{.c}
ns(Weapon_vec_t) weapons = ns(Monster_weapons(monster)); ns(Weapon_vec_t) weapons = ns(Monster_weapons(monster));
size_t weapons_len = ns(Weapon_vec_len(weapons)); size_t weapons_len = ns(Weapon_vec_len(weapons));
// We don't have to use `nsc(string_t)` as type if we don't need fast length access. // We can use `const char *` instead of `flatbuffers_string_t`.
const char *second_weapon_name = ns(Weapon_name(ns(Weapon_vec_at(weapons, 1)))); const char *second_weapon_name = ns(Weapon_name(ns(Weapon_vec_at(weapons, 1))));
uint16_t second_weapon_damage = ns(Weapon_damage(ns(Weapon_vec_at(weapons, 1)))); uint16_t second_weapon_damage = ns(Weapon_damage(ns(Weapon_vec_at(weapons, 1))));
~~~ ~~~
...@@ -1917,11 +1787,6 @@ We can access the type to dynamically cast the data as needed (since the ...@@ -1917,11 +1787,6 @@ We can access the type to dynamically cast the data as needed (since the
## Mutating FlatBuffers ## Mutating FlatBuffers
<div class="language-c">
*Note: This section does not fully apply to C which has no generated mutation
interface (except for sorting vectors in-place which is an advanced topic).*
</div>
As you saw above, typically once you have created a FlatBuffer, it is read-only 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 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 FlatBuffer, and you'd like to modify something about it before sending it on to
...@@ -1984,8 +1849,9 @@ mutators like so: ...@@ -1984,8 +1849,9 @@ mutators like so:
~~~ ~~~
</div> </div>
<div class="language-c"> <div class="language-c">
~~~{.php} ~~~{.c}
<API for in-place mutating FlatBuffers will not be supported in C.> <API for in-place mutating FlatBuffers will not be supported in C
(except in-place vector sorting is possible).>
~~~ ~~~
</div> </div>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment