diff --git a/docs/source/CUsage.md b/docs/source/CUsage.md new file mode 100644 index 0000000000000000000000000000000000000000..9aafa6f775efb2a29229be04f44405d269149217 --- /dev/null +++ b/docs/source/CUsage.md @@ -0,0 +1,224 @@ +Use in C {#flatbuffers_guide_use_c} +========== + +The C language binding exists in a separate project named [FlatCC](https://github.com/dvidelabs/flatcc). + +The `flatcc` C schema compiler can generate code offline as well as +online via a C library. It can also generate buffer verifiers and fast +JSON parsers, printers. + +Great care has been taken to ensure compatibily with the main `flatc` +project. + +## General Documention + +- [Tutorial](@ref flatbuffers_guide_tutorial) - select C as language + when scrolling down +- [FlatCC Guide](https://github.com/dvidelabs/flatcc#flatcc-flatbuffers-in-c-for-c) +- [The C Builder Interface](https://github.com/dvidelabs/flatcc/blob/master/doc/builder.md#the-builder-interface) +- [The Monster Sample in C](https://github.com/dvidelabs/flatcc/blob/master/samples/monster/monster.c) +- [GitHub](https://github.com/dvidelabs/flatcc) + + +## Supported Platforms + +- Ubuntu (clang / gcc, ninja / gnu make) +- OS-X (clang / gcc, ninja / gnu make) +- Windows MSVC 2010, 2013, 2015 + +CI builds recent versions of gcc, clang and MSVC on OS-X, Ubuntu, and +Windows, and occasionally older compiler versions. See main project [Status](https://github.com/dvidelabs/flatcc#status). + +Other platforms may well work, including Centos, but are not tested +regularly. + +The monster sample project was specifically written for C99 in order to +follow the C++ version and for that reason it will not work with MSVC +2010. + +## 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 + +The C-API does support reading binary schema (.bfbs) +files via code generated from the `reflection.fbs` schema, and an +[example usage](https://github.com/dvidelabs/flatcc/tree/master/samples/reflection) +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). + + +## Mutations and Reflection + +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). + +The generated reader interface supports sorting vectors in-place after +casting them to a mutating type because it is not practical to do so +while building a buffer. This is covered in the builder documentation. +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 +these. + +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 +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 +the best approach. If the namespace is absent, or 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_add_type(B, ns(Equipment_Weapon)); + ns(Monster_equipped_add_member(B, axe)); +~~~ +</div> + +## Why not integrate with the `flatc` tool? + +[It was considered how the C code generator could be integrated into the +`flatc` tool](https://github.com/dvidelabs/flatcc/issues/1), but it +would either require that the standalone C implementation of the schema +compiler was dropped, or it would lead to excessive code duplication, or +a complicated intermediate representation would have to be invented. +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 +FlatBuffers C runtime library needs to be made available regardless. + + diff --git a/docs/source/FlatBuffers.md b/docs/source/FlatBuffers.md index bbb0dce589368f8c56daa3d3995a17bcdb63073a..46d4c12014e628f4416a0f50330382318dfc873b 100644 --- a/docs/source/FlatBuffers.md +++ b/docs/source/FlatBuffers.md @@ -4,9 +4,9 @@ FlatBuffers {#flatbuffers_index} # Overview {#flatbuffers_overview} [FlatBuffers](@ref flatbuffers_overview) is an efficient cross platform -serialization library for C++, C#, Go, Java, JavaScript, PHP, and Python -(C and Ruby in progress). It was originally created at Google for game -development and other performance-critical applications. +serialization library for C++, C#, C, Go, Java, JavaScript, PHP, and Python. +It was originally created at Google for game development and other +performance-critical applications. It is available as Open Source on [GitHub](http://github.com/google/flatbuffers) under the Apache license, v2 (see LICENSE.txt). @@ -131,6 +131,8 @@ sections provide a more in-depth usage guide. in your own programs. - How to [use the generated Go code](@ref flatbuffers_guide_use_go) in your own programs. +- How to [use FlatBuffers in C with `flatcc`](@ref flatbuffers_guide_use_c) in your + own programs. - [Support matrix](@ref flatbuffers_support) for platforms/languages/features. - Some [benchmarks](@ref flatbuffers_benchmarks) showing the advantage of using FlatBuffers. diff --git a/docs/source/Support.md b/docs/source/Support.md index ba8c76579f9f9e1faa2898d5239ee386a2bb391f..7bc33481de551350a8f3a62fa4a2582fc7b0e399 100755 --- a/docs/source/Support.md +++ b/docs/source/Support.md @@ -18,23 +18,23 @@ In general: NOTE: this table is a start, it needs to be extended. -Feature | C++ | Java | C# | Go | Python | JS | C | PHP | Ruby ------------------------------- | ------ | ------ | ------ | ------ | ------ | --------- | ---- | --- | ---- -Codegen for all basic features | Yes | Yes | Yes | Yes | Yes | Yes | WiP | WiP | WiP -JSON parsing | Yes | No | No | No | No | No | No | No | No -Simple mutation | Yes | WIP | WIP | No | No | No | No | No | No -Reflection | Yes | No | No | No | No | No | No | No | No -Buffer verifier | Yes | No | No | No | No | No | No | No | No -Testing: basic | Yes | Yes | Yes | Yes | Yes | Yes | ? | ? | ? -Testing: fuzz | Yes | No | No | Yes | Yes | No | ? | ? | ? -Performance: | Superb | Great | Great | Great | Ok | ? |Superb| ? | ? -Platform: Windows | VS2010 | Yes | Yes | ? | ? | ? | ? | ? | ? -Platform: Linux | GCC282 | Yes | ? | Yes | Yes | ? | ? | ? | ? -Platform: OS X | Xcode4 | ? | ? | ? | Yes | ? | ? | ? | ? -Platform: Android | NDK10d | Yes | ? | ? | ? | ? | ? | ? | ? -Platform: iOS | ? | ? | ? | ? | ? | ? | ? | ? | ? -Engine: Unity | ? | ? | Yes | ? | ? | ? | ? | ? | ? -Primary authors (github) | gwvo | gwvo | ev*/js*| rw | rw | evanw/ev* | mik* | ch* | rw +Feature | C++ | Java | C# | Go | Python | JS | C | PHP | Ruby +------------------------------ | ------ | ------ | ------ | ------ | ------ | --------- | ------ | --- | ---- +Codegen for all basic features | Yes | Yes | Yes | Yes | Yes | Yes | Yes | WiP | WiP +JSON parsing | Yes | No | No | No | No | No | Yes | No | No +Simple mutation | Yes | WIP | WIP | No | No | No | No | No | No +Reflection | Yes | No | No | No | No | No | Basic | No | No +Buffer verifier | Yes | No | No | No | No | No | Yes | No | No +Testing: basic | Yes | Yes | Yes | Yes | Yes | Yes | Yes | ? | ? +Testing: fuzz | Yes | No | No | Yes | Yes | No | No | ? | ? +Performance: | Superb | Great | Great | Great | Ok | ? | Superb | ? | ? +Platform: Windows | VS2010 | Yes | Yes | ? | ? | ? | VS2010 | ? | ? +Platform: Linux | GCC282 | Yes | ? | Yes | Yes | ? | Yes | ? | ? +Platform: OS X | Xcode4 | ? | ? | ? | Yes | ? | Yes | ? | ? +Platform: Android | NDK10d | Yes | ? | ? | ? | ? | ? | ? | ? +Platform: iOS | ? | ? | ? | ? | ? | ? | ? | ? | ? +Engine: Unity | ? | ? | Yes | ? | ? | ? | ? | ? | ? +Primary authors (github) | gwvo | gwvo | ev*/js*| rw | rw | evanw/ev* | mik* | ch* | rw * ev = evolutional * js = jonsimantov diff --git a/docs/source/Tutorial.md b/docs/source/Tutorial.md index de1e9fd95ea3189501c4465392a8e98e5e35fe9c..1e48796d9a89fc958d5c00b5b653b1f4f4190f1f 100644 --- a/docs/source/Tutorial.md +++ b/docs/source/Tutorial.md @@ -19,7 +19,6 @@ character, the hero of the story, needs to slay some `orc`s. We will walk through each step necessary to create this monster type using FlatBuffers. Please select your desired language for our quest: - \htmlonly <form> <input type="radio" name="language" value="cpp" checked="checked">C++</input> @@ -29,6 +28,7 @@ Please select your desired language for our quest: <input type="radio" name="language" value="python">Python</input> <input type="radio" name="language" value="javascript">JavaScript</input> <input type="radio" name="language" value="php">PHP</input> + <input type="radio" name="language" value="c">C</input> </form> \endhtmlonly @@ -98,6 +98,10 @@ Samples demonstating the concepts in this example are located in the source code package, under the `samples` directory. You can browse the samples on GitHub [here](https://github.com/google/flatbuffers/tree/master/samples). +<div class="language-c"> +*Note: The above does not apply to C, instead [look here](https://github.com/dvidelabs/flatcc/tree/master/samples).* +</div> + For your chosen language, please cross-reference with: <div class="language-cpp"> @@ -121,6 +125,9 @@ For your chosen language, please cross-reference with: <div class="language-php"> [SampleBinary.php](https://github.com/google/flatbuffers/blob/master/samples/SampleBinary.php) </div> +<div class="language-c"> +[monster.c](https://github.com/dvidelabs/flatcc/blob/master/samples/monster/monster.c) +</div> ## Writing the Monsters' FlatBuffer Schema @@ -225,6 +232,15 @@ FlatBuffer compiler. Once `flatc` is built successfully, compile the schema for your language: +<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.* +<br> +See [flatcc build instructions](https://github.com/dvidelabs/flatcc#building). +<br> +Please be aware of the difference between `flatc` and `flatcc` tools. +<br> +</div> + <div class="language-cpp"> ~~~{.sh} cd flatbuffers/sample @@ -267,8 +283,17 @@ Once `flatc` is built successfully, compile the schema for your language: ./../flatc --php samples/monster.fbs ~~~ </div> +<div class="language-c"> +~~~{.sh} + cd flatcc + mkdir -p build/tmp/samples/monster + bin/flatcc -a -o build/tmp/samples/monster samples/monster/monster.fbs + # or just + flatcc/samples/monster/build.sh +~~~ +</div> -For a more complete guide to using the `flatc` compiler, pleaes read the +For a more complete guide to using the `flatc` compiler, please read the [Using the schema compiler](@ref flatbuffers_guide_using_schema_compiler) section of the Programmer's Guide. @@ -359,6 +384,18 @@ The first step is to import/include the library, generated files, etc. } ~~~ </div> +<div class="language-c"> +~~~{.c} + #include "monster_builder.h" // Generated by `flatcc`. + + // Convenient namespace macro to manage long namespace prefix. + #undef ns + #define ns(x) FLATBUFFERS_WRAP_NAMESPACE(MyGame_Sample, x) // Specified in the schema. + + // A helper to simplify creating vectors from C-arrays. + #define c_vec_len(V) (sizeof(V)/sizeof((V)[0])) +~~~ +</div> Now we are ready to start building some buffers. In order to start, we need to create an instance of the `FlatBufferBuilder`, which will contain the buffer @@ -413,6 +450,14 @@ as it grows: $builder = new Google\FlatBuffers\FlatbufferBuilder(0); ~~~ </div> +<div class="language-c"> +~~~{.c} + flatcc_builder_t builder, *B; + B = &builder; + // Initialize the builder object. + flatcc_builder_init(B); +~~~ +</div> After creating the `builder`, we can start serializing our data. Before we make our `orc` Monster, lets create some `Weapon`s: a `Sword` and an `Axe`. @@ -525,6 +570,18 @@ our `orc` Monster, lets create some `Weapon`s: a `Sword` and an `Axe`. $weapons = \MyGame\Sample\Monster::CreateWeaponsVector($builder, $weaps); ~~~ </div> +<div class="language-c"> +~~~{.c} + ns(Weapon_ref_t) weapon_one_name = flatbuffers_string_create_str(B, "Sword"); + uint16_t weapon_one_damage = 3; + + ns(Weapon_ref_t) weapon_two_name = flatbuffers_string_create_str(B, "Axe"); + 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) axe = ns(Weapon_create(B, weapon_two_name, weapon_two_damage)); +~~~ +</div> Now let's create our monster, the `orc`. For this `orc`, lets make him `red` with rage, positioned at `(1.0, 2.0, 3.0)`, and give him @@ -627,6 +684,20 @@ traversal. This is generally easy to do on any tree structures. $inv = \MyGame\Sample\Monster::CreateInventoryVector($builder, $treasure); ~~~ </div> +<div class="language-c"> +~~~{.c} + // Serialize a name for our monster, called "Orc". + // The _str suffix indicates the source is an ascii-z string. + flatbuffers_string_ref_t name = flatbuffers_string_create_str(B, "Orc"); + + // Create a `vector` representing the inventory of the Orc. Each number + // 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}; + flatbuffers_uint8_vec_ref_t inventory; + // `c_vec_len` is the convenience macro we defined earlier. + inventory = flatbuffers_uint8_vec_create(B, treasure, c_vec_len(treasure)); +~~~ +</div> We serialized two built-in data types (`string` and `vector`) and captured their return values. These values are offsets into the serialized data, @@ -709,8 +780,18 @@ offsets. $weapons = \MyGame\Sample\Monster::CreateWeaponsVector($builder, $weaps); ~~~ </div> +<div class="language-c"> +~~~{.c} + // We use the internal builder stack to implement a dynamic vector. + ns(Weapon_vec_start(B)); + ns(Weapon_vec_push(B, sword)); + ns(Weapon_vec_push(B, axe)); + ns(Weapon_vec_ref_t) weapons = ns(Weapon_vec_end(B)); +~~~ +</div> -To create a `struct`, use the `Vec3` class/struct that was generated by `flatc`: +To create a `struct`, use the `Vec3` class/struct that was generated by +the schema compiler: <div class="language-cpp"> ~~~{.cpp} @@ -754,6 +835,12 @@ To create a `struct`, use the `Vec3` class/struct that was generated by `flatc`: $pos = \MyGame\Sample\Vec3::CreateVec3($builder, 1.0, 2.0, 3.0); ~~~ </div> +<div class="language-c"> +~~~{.c} + // Create a `Vec3`, representing the Orc's position in 3-D space. + ns(Vec3_t) pos = { 1.0f, 2.0f, 3.0f }; +~~~ +</div> We have now serialized the non-scalar components of the orc, so we can serialize the monster itself: @@ -862,16 +949,29 @@ can serialize the monster itself: $orc = \MyGame\Sample\Monster::EndMonster($builder); ~~~ </div> +<div class="language-c"> +~~~{.c} + // Set his hit points to 300 and his mana to 150. + uint16_t hp = 300; + uint16_t mana = 150; -<div class="language-cpp"> -<br> -*Note: Since we passing `150` as the `mana` field, which happens to be the + // Define an equipment union. `create` calls in C has a single + // argument for unions where C++ has both a type and a data argument. + 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), + weapons, equipped)); +~~~ +</div> + +*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> + +<div class="language-cpp"> +<br> 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()`. The following snippet is functionally equivalent to the above code, but provides @@ -892,6 +992,31 @@ a bit more flexibility. auto orc = monster_builder.Finish(); ~~~ </div> +<div class="language-c"> +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()`. +The following snippet is functionally equivalent to the above code, but provides +a bit more flexibility. +<br> +~~~{.c} + // It is important to pair `start_as_root` with `end_as_root`. + ns(Monster_start_as_root(B)); + ns(Monster_pos_create(B, 1.0f, 2.0f, 3.0f)); + // or alternatively + //ns(Monster_pos_add(&pos); + + ns(Monster_hp_add(B, hp)); + // Notice that `Monser_name_add` adds a string reference unlike the + // add_str and add_strn variants. + ns(Monster_name_add(B, name)); + ns(Monster_inventory_add(B, inventory)); + ns(Monster_color_add(B, ns(Color_Red))); + ns(Monster_weapons_add(B, weapons)); + ns(Monster_equipped_add(B, equipped)); + // Complete the monster object and make it the buffer root object. + ns(Monster_end_as_root(B)); +~~~ +</div> Before finishing the serialization, let's take a quick look at FlatBuffer `union Equipped`. There are two parts to each FlatBuffer `union`. The first, is @@ -947,11 +1072,18 @@ Here is a repetition these lines, to help highlight them more clearly: \MyGame\Sample\Monster::AddEquipped($builder, $axe); // Union data ~~~ </div> +<div class="language-c"> +~~~{.c} + // Add union type and data simultanously. + ns(Monster_equipped_Weapon_add(B, axe)); +~~~ +</div> 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 appropriate `finish` method. + <div class="language-cpp"> ~~~{.cpp} // Call `Finish()` to instruct the builder that this monster is complete. @@ -999,6 +1131,11 @@ appropriate `finish` method. // $builder, $orc);`. ~~~ </div> +<div class="language-c"> +~~~{.c} + // Because we used `Monster_create_as_root`, we do not need a `finish` call in C`. +~~~ +</div> The buffer is now ready to be stored somewhere, sent over the network, be compressed, or whatever you'd like to do with it. You can access the buffer @@ -1048,6 +1185,29 @@ like so: $buf = $builder->dataBuffer(); // Of type `Google\FlatBuffers\ByteBuffer` ~~~ </div> +<div class="language-c"> +~~~{.c} + uint8_t *buf; + size_t size; + + // Allocate and extract a readable buffer from internal builder heap. + // The returned buffer must be deallocated using `free`. + // NOTE: Finalizing the buffer does NOT change the builder, it + // just creates a snapshot of the builder content. + buf = flatcc_builder_finalize_buffer(B, &size); + // use buf + free(buf); + + // Optionally reset builder to reuse builder without deallocating + // internal stack and heap. + flatcc_builder_reset(B); + // build next buffer. + // ... + + // Cleanup. + flatcc_builder_clear(B); +~~~ +</div> #### Reading Orc FlatBuffers @@ -1055,7 +1215,7 @@ Now that we have successfully created an `Orc` FlatBuffer, the monster data can be saved, sent over a network, etc. Let's now adventure into the inverse, and deserialize a FlatBuffer. -This seciton requires the same import/include, namespace, etc. requirements as +This section requires the same import/include, namespace, etc. requirements as before: <div class="language-cpp"> @@ -1134,6 +1294,15 @@ before: } ~~~ </div> +<div class="language-c"> +~~~{.c} + // Only needed if we don't have `#include "monster_builder.h"`. + #include "monster_reader.h" + + #undef ns + #define ns(x) FLATBUFFERS_WRAP_NAMESPACE(MyGame_Sample, x) // Specified in the schema. +~~~ +</div> Then, assuming you have a variable containing to the bytes of data from disk, network, etc., you can create a monster from this data: @@ -1224,8 +1393,18 @@ network, etc., you can create a monster from this data: $monster = \MyGame\Sample\Monster::GetRootAsMonster($buf); ~~~ </div> +<div class="language-c"> +~~~{.c} + // Note that we use the `table_t` suffix when reading a table object + // as opposed to the `ref_t` suffix used during the construction of + // the buffer. + ns(Monster_table_t) monster = ns(Monster_as_root(buffer)); -If you look in the generated files from `flatc`, you will see it generated + // Note: root object pointers are NOT the same as the `buffer` pointer. +~~~ +</div> + +If you look in the generated files from the schema compiler, you will see it generated accessors for all non-`deprecated` fields. For example: <div class="language-cpp"> @@ -1279,10 +1458,17 @@ accessors for all non-`deprecated` fields. For example: $name = monster->getName(); ~~~ </div> +<div class="language-c"> +~~~{.c} + uint16_t hp = ns(Monster_hp(monster)); + uint16_t mana = ns(Monster_mana(monster)); + flatbuffers_string_t name = ns(Monster_name(monster)); +~~~ +</div> These should hold `300`, `150`, and `"Orc"` respectively. -*Note: We never stored a value in `mp`, 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`: @@ -1348,10 +1534,18 @@ To access sub-objects, in the case of our `pos`, which is a `Vec3`: $z = $pos->getZ(); ~~~ </div> +<div class="language-c"> +~~~{.c} + ns(Vec3_struct_t) pos = ns(Monster_pos(monster)); + float x = ns(Vec3_x(pos)); + float y = ns(Vec3_y(pos)); + float z = ns(Vec3_z(pos)); +~~~ +</div> `x`, `y`, and `z` will contain `1.0`, `2.0`, and `3.0`, respectively. -*Note: Had we not set `pos` during serialization, it would be `NULL`-value.* +*Note: Had we not set `pos` during serialization, it would be a `NULL`-value.* Similarly, we can access elements of the inventory `vector` by indexing it. You can also iterate over the length of the array/vector representing the @@ -1400,6 +1594,14 @@ FlatBuffers `vector`. $third_item = $monster->getInventory(2); ~~~ </div> +<div class="language-c"> +~~~{.c} + // If `inv` hasn't been set, it will be null. It is valid get + // the length of null which will be 0, useful for iteration. + flatbuffers_uint8_vec_t inv = ns(Monster_inventory(monster)); + size_t inv_len = flatbuffers_uint8_vec_len(inv); +~~~ +</div> For `vector`s of `table`s, you can access the elements like any other vector, except your need to handle the result as a FlatBuffer `table`: @@ -1458,6 +1660,15 @@ except your need to handle the result as a FlatBuffer `table`: $second_weapon_damage = $monster->getWeapons(1)->getDamage(); ~~~ </div> +<div class="language-c"> +~~~{.c} + ns(Weapon_vec_t) weapons = ns(Monster_weapons(monster)); + size_t weapons_len = ns(Weapon_vec_len(weapons)); + // We can use `const char *` instead of `flatbuffers_string_t`. + 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)))); +~~~ +</div> Last, we can access our `Equipped` FlatBuffer `union`. Just like when we created the `union`, we need to get both parts of the `union`: the type and the data. @@ -1560,6 +1771,18 @@ We can access the type to dynamically cast the data as needed (since the } ~~~ </div> +<div class="language-c"> +~~~{.c} + // Access union type field. + if (ns(Monster_equipped_type(monster)) == ns(Equipment_Weapon)) { + // Cast to appropriate type: + // C allows for silent void pointer assignment, so we need no explicit cast. + ns(Weapon_table_t) weapon = ns(Monster_equipped(monster)); + const char *weapon_name = ns(Weapon_name(weapon)); // "Axe" + uint16_t weapon_damage = ns(Weapon_damage(weapon)); // 5 + } +~~~ +</div> ## Mutating FlatBuffers @@ -1624,6 +1847,12 @@ mutators like so: <API for mutating FlatBuffers is not yet supported in PHP.> ~~~ </div> +<div class="language-c"> +~~~{.c} + <API for in-place mutating FlatBuffers will not be supported in C + (except in-place vector sorting is possible).> +~~~ +</div> 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 @@ -1687,6 +1916,14 @@ FlatBuffer binary representation of the contents from our `.json` file. [Use in C++](@ref flatbuffers_guide_use_cpp) section of the Programmer's Guide for more information.* </div> +<div class="language-c"> +*Note: If you're working in C, the `flatcc --json` (not `flatc`) +compiler will generate schema specific high performance json parsers and +printers that you can compile and use at runtime. The `flatc` compiler (not +`flatcc`) on the other hand, is still useful for general offline json to +flatbuffer conversion from a given schema. There are no current plans +for `flatcc` to support this.* +</div> ## Advanced Features for Each Language @@ -1716,5 +1953,8 @@ For your chosen language, see: <div class="language-php"> [Use in PHP](@ref flatbuffers_guide_use_php) </div> +<div class="language-c"> +[Use in C](@ref flatbuffers_guide_use_c) +</div> <br> diff --git a/docs/source/doxyfile b/docs/source/doxyfile index ba6fbcbd6310b9ac0217093ab81e54a405d1d693..bef63f582770ddc49d98b6c9de189394685d203e 100755 --- a/docs/source/doxyfile +++ b/docs/source/doxyfile @@ -750,6 +750,7 @@ INPUT = "FlatBuffers.md" \ "Compiler.md" \ "Schemas.md" \ "CppUsage.md" \ + "CUsage.md" \ "GoUsage.md" \ "JavaCsharpUsage.md" \ "JavaScriptUsage.md" \ diff --git a/docs/source/doxygen_layout.xml b/docs/source/doxygen_layout.xml index 1437016ea87d4d2518f72a0db8f44540dc286115..b5d8644c1666bc3bc4d25b4b9cdb63d4e6df1513 100644 --- a/docs/source/doxygen_layout.xml +++ b/docs/source/doxygen_layout.xml @@ -25,6 +25,8 @@ title="Writing a schema"/> <tab type="user" url="@ref flatbuffers_guide_use_cpp" title="Use in C++"/> + <tab type="user" url="@ref flatbuffers_guide_use_c" + title="Use in C"/> <tab type="user" url="@ref flatbuffers_guide_use_go" title="Use in Go"/> <tab type="user" url="@ref flatbuffers_guide_use_java_c-sharp" diff --git a/readme.md b/readme.md index 95460486380e3420b89a80ce8ef64b7a0c45bd2c..15dd41b111dd9ff78cddac4b5f4a37e9f08ab3fc 100755 --- a/readme.md +++ b/readme.md @@ -15,6 +15,7 @@ unpacking/parsing it first, while still having great forwards/backwards compatib ## Supported programming languages * C++ * C# +* C * Go * Java * JavaScript