From ce4d3316d36cf8bc95b90bb6ecf0724b98dcdf6b Mon Sep 17 00:00:00 2001 From: Will Gardner Date: Mon, 29 Feb 2016 17:28:40 +0000 Subject: [PATCH 1/8] Allow builds on platforms with unsigned chars by default Certain architectures, such as ARM, use unsigned chars by default so require the `-fsigned-char` for certain value comparisons to make sense and in order to compile. --- CMakeLists.txt | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index d2edf829b..944a73e9c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -86,6 +86,12 @@ elseif(CMAKE_COMPILER_IS_GNUCXX) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wunused-result -Werror=unused-result") endif() + + # Certain platforms such as ARM do not use signed chars by default + # which causes issues with certain bounds checks. + set(CMAKE_CXX_FLAGS + "${CMAKE_CXX_FLAGS} -fsigned-char") + elseif("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x -stdlib=libc++ -Wall -pedantic -Werror -Wextra") @@ -93,6 +99,12 @@ elseif("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -lc++abi") endif() + + # Certain platforms such as ARM do not use signed chars by default + # which causes issues with certain bounds checks. + set(CMAKE_CXX_FLAGS + "${CMAKE_CXX_FLAGS} -fsigned-char") + endif() if(FLATBUFFERS_CODE_COVERAGE) From 47d4b46950d92cf5056094f8f25a0a26d0ba3865 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mikkel=20Fahn=C3=B8e=20J=C3=B8rgensen?= Date: Sat, 26 Mar 2016 00:28:31 +0100 Subject: [PATCH 2/8] Documentation for C bindings --- docs/source/CUsage.md | 54 +++++ docs/source/FlatBuffers.md | 6 +- docs/source/Support.md | 18 +- docs/source/Tutorial.md | 393 ++++++++++++++++++++++++++++++++- docs/source/doxyfile | 1 + docs/source/doxygen_layout.xml | 2 + 6 files changed, 454 insertions(+), 20 deletions(-) create mode 100644 docs/source/CUsage.md diff --git a/docs/source/CUsage.md b/docs/source/CUsage.md new file mode 100644 index 000000000..0c87ce955 --- /dev/null +++ b/docs/source/CUsage.md @@ -0,0 +1,54 @@ +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 effort has been made to ensure compatibily with the main `flatc` +project. + + +## General Documention + +- [Tutorial](@ref flatbuffers_guide_tutorial) - select C as language + when scrolling down +- General Use in C (the README) +- The C Builder Interface, advanced + + +## 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 schema files are pre-generated +in the [runtime distribution](https://github.com/dvidelabs/flatcc/tree/master/include/flatcc/reflection). Extended reflection + + +## Mutating Reflection + +The C-API does not support mutating reflection like C++ does. + +Although the following isn't reflection, it is possible to create 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. + +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. + + +## 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 bbb0dce58..445121cb3 100644 --- a/docs/source/FlatBuffers.md +++ b/docs/source/FlatBuffers.md @@ -4,8 +4,8 @@ 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 +serialization library for C++, C#, C, Go, Java, JavaScript, PHP, and Python +(Ruby and Swift in progress). 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) @@ -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 the generated C code](@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 ba8c76579..270f88bb9 100755 --- a/docs/source/Support.md +++ b/docs/source/Support.md @@ -20,17 +20,17 @@ 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 +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 | 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 | ? | ? | ? +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 | ? | ? | ? | ? | ? | ? -Platform: Linux | GCC282 | Yes | ? | Yes | Yes | ? | ? | ? | ? -Platform: OS X | Xcode4 | ? | ? | ? | Yes | ? | ? | ? | ? +Platform: Windows | VS2010 | Yes | Yes | ? | ? | ? | No | ? | ? +Platform: Linux | GCC282 | Yes | ? | Yes | Yes | ? | Yes | ? | ? +Platform: OS X | Xcode4 | ? | ? | ? | Yes | ? | Yes | ? | ? Platform: Android | NDK10d | Yes | ? | ? | ? | ? | ? | ? | ? Platform: iOS | ? | ? | ? | ? | ? | ? | ? | ? | ? Engine: Unity | ? | ? | Yes | ? | ? | ? | ? | ? | ? diff --git a/docs/source/Tutorial.md b/docs/source/Tutorial.md index de1e9fd95..dfcc3ad7c 100644 --- a/docs/source/Tutorial.md +++ b/docs/source/Tutorial.md @@ -23,12 +23,13 @@ Please select your desired language for our quest: \htmlonly
C++ - Java C# + C Go - Python + Java JavaScript PHP + Python
\endhtmlonly @@ -98,6 +99,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). +
+*Note: The above does not apply to C, instead [look here](https://github.com/dvidelabs/flatcc/tree/master/samples).* +
+ For your chosen language, please cross-reference with:
@@ -121,6 +126,9 @@ For your chosen language, please cross-reference with:
[SampleBinary.php](https://github.com/google/flatbuffers/blob/master/samples/SampleBinary.php)
+
+[monster.c](https://github.com/dvidelabs/flatcc/blob/master/samples/monster/monster.c) +
## Writing the Monsters' FlatBuffer Schema @@ -225,6 +233,16 @@ FlatBuffer compiler. Once `flatc` is built successfully, compile the schema for your language: +
+ +*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.* +
+See [flatcc build instructions](https://github.com/dvidelabs/flatcc#building). +
+Please be aware of the difference between `flatc` and `flatcc` tools. +
+
+
~~~{.sh} cd flatbuffers/sample @@ -267,8 +285,17 @@ Once `flatc` is built successfully, compile the schema for your language: ./../flatc --php samples/monster.fbs ~~~
+
+~~~{.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 +~~~ +
-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 +386,21 @@ The first step is to import/include the library, generated files, etc. } ~~~
+
+~~~{.c} + #include "monster_builder.h" // Generated by `flatcc`. + + // Convenient namespace macro to manage long namespace prefix. + #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. + #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(...)`. +~~~ +
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 +455,14 @@ as it grows: $builder = new Google\FlatBuffers\FlatbufferBuilder(0); ~~~ +
+~~~{.c} + flatcc_builder_t builder, *B; + B = &builder; + // Initialize the builder object. + flatcc_builder_init(B); +~~~ +
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 +575,18 @@ our `orc` Monster, lets create some `Weapon`s: a `Sword` and an `Axe`. $weapons = \MyGame\Sample\Monster::CreateWeaponsVector($builder, $weaps); ~~~ +
+~~~{.c} + ns(Weapon_ref_t) weapon_one_name = nsc(string_create_str(B, "Sword")); + uint16_t weapon_one_damage = 3; + + ns(Weapon_ref_t) weapon_two_name = nsc(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)); +~~~ +
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 +689,20 @@ traversal. This is generally easy to do on any tree structures. $inv = \MyGame\Sample\Monster::CreateInventoryVector($builder, $treasure); ~~~ +
+~~~{.c} + // Serialize a name for our monster, called "Orc". + // The _str suffix indicates the source is an ascii-z string. + nsc(string_ref_t) name = nsc(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}; + nsc(uint8_vec_ref_t) inventory; + // `c_vec_len` is the convenience macro we defined earlier. + inventory = nsc(uint8_vec_create(B, treasure, c_vec_len(treasure))); +~~~ +
We serialized two built-in data types (`string` and `vector`) and captured their return values. These values are offsets into the serialized data, @@ -642,6 +718,13 @@ 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 offsets. +
+*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.* +
+
~~~{.cpp} // Place the weapons into a `std::vector`, then convert that into a FlatBuffer `vector`. @@ -709,8 +792,21 @@ offsets. $weapons = \MyGame\Sample\Monster::CreateWeaponsVector($builder, $weaps); ~~~
+
+~~~{.c} + // Here we use a top-down approach locally to build a Weapons 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_push(B, sword)); + ns(Weapon_vec_push(B, axe)); + ns(Weapon_vec_ref_t) weapons = ns(Weapon_vec_end(B)); +~~~ +
-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:
~~~{.cpp} @@ -754,6 +850,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); ~~~
+
+~~~{.c} + // Create a `Vec3`, representing the Orc's position in 3-D space. + ns(Vec3_t) pos = { 1.0f, 2.0f, 3.0f }; +~~~ +
We have now serialized the non-scalar components of the orc, so we can serialize the monster itself: @@ -862,10 +964,31 @@ can serialize the monster itself: $orc = \MyGame\Sample\Monster::EndMonster($builder); ~~~ +
+~~~{.c} + // Set his hit points to 300 and his mana to 150. + uint16_t hp = 300; + uint16_t mana = 150; + + // Create the equipment union. In the C++ language API this is given + // as two arguments to the create call, or as two separate add + // 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(Monster_create_as_root(B, &pos, mana, hp, name, inventory, ns(Color_Red), + weapons, equipped)); +~~~ +
+ +
+*Note: in C we use `create_as_root` instead of the also valid `create` call +because it simplfies constructing the root object.* +

-*Note: Since we 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 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 @@ -892,6 +1015,39 @@ a bit more flexibility. auto orc = monster_builder.Finish(); ~~~
+
+
+*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.* +

+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. +
+~~~{.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)); +~~~ +
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 @@ -902,6 +1058,11 @@ Second, is the `union`'s data. In our example, the last two things we added to our `Monster` were the `Equipped Type` and the `Equipped` union itself. +
+*Note: In C, several different helpers make these two fields appear as +one field, but they can be added separately.* +
+ Here is a repetition these lines, to help highlight them more clearly:
@@ -947,11 +1108,78 @@ Here is a repetition these lines, to help highlight them more clearly: \MyGame\Sample\Monster::AddEquipped($builder, $axe); // Union data ~~~
+
+~~~{.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)); +~~~ +
+ +
+Here is an alternative top-down approach unique to the C builder +library. +
+~~~{.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)); +~~~ +
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. +
+*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.* +
+
~~~{.cpp} // Call `Finish()` to instruct the builder that this monster is complete. @@ -999,6 +1227,14 @@ appropriate `finish` method. // $builder, $orc);`. ~~~
+
+~~~{.c} + // Alternative approach separating object creation from being root object. + ns(Monster_ref_t) orc = ns(Monster_create(B, ...)); + // `flatcc_` calls should be isolated to top-level driver logic. + flatcc_builder_buffer_create(orc); +~~~ +
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 +1284,29 @@ like so: $buf = $builder->dataBuffer(); // Of type `Google\FlatBuffers\ByteBuffer` ~~~ +
+~~~{.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(&builder, &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); +~~~ +
#### Reading Orc FlatBuffers @@ -1055,9 +1314,15 @@ 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: +
+*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.* +
+
~~~{.cpp} #include "monster_generate.h" // This was generated by `flatc`. @@ -1134,6 +1399,14 @@ before: } ~~~
+
+~~~{.c} + #include "monster_reader.h" + + #define ns(x) FLATBUFFERS_WRAP_NAMESPACE(MyGame_Sample, x) // Specified in the schema. + #define nsc(x) FLATBUFFERS_WRAP_NAMESPACE(flatbuffers, x) +~~~ +
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 +1497,18 @@ network, etc., you can create a monster from this data: $monster = \MyGame\Sample\Monster::GetRootAsMonster($buf); ~~~ +
+~~~{.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. +~~~ +
+ +If you look in the generated files from the schema compiler, you will see it generated accessors for all non-`deprecated` fields. For example:
@@ -1279,10 +1562,32 @@ accessors for all non-`deprecated` fields. For example: $name = monster->getName(); ~~~
+
+~~~{.c} + 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)); + // This is just a const char *, but it also supports a fast length operation. + nsc(string_t) name = ns(Monster_name(monster)); + size_t name_len = nsc(string_len(name)); +~~~ +
+ +
+*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 +~~~ +
+ 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: We never stored a value in `mana`, so we got the default value of `150`.* To access sub-objects, in the case of our `pos`, which is a `Vec3`: @@ -1348,10 +1653,25 @@ To access sub-objects, in the case of our `pos`, which is a `Vec3`: $z = $pos->getZ(); ~~~ +
+~~~{.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)); + + // 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; + // ... +~~~ +
`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 +1720,19 @@ FlatBuffers `vector`. $third_item = $monster->getInventory(2); ~~~ +
+~~~{.c} + // This is a const uint8_t *, but it shouldn't be accessed directly + // to ensure proper endian conversion. Incidentally the uint8 (ubyte) + // is not sensitive to endianness, so we *could* have accessed it directly. + // The compiler likely optimizes this so that it doesn't matter. + 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. +~~~ +
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 +1791,15 @@ except your need to handle the result as a FlatBuffer `table`: $second_weapon_damage = $monster->getWeapons(1)->getDamage(); ~~~ +
+~~~{.c} + ns(Weapon_vec_t) weapons = ns(Monster_weapons(monster)); + 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. + 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)))); +~~~ +
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,9 +1902,26 @@ We can access the type to dynamically cast the data as needed (since the } ~~~ +
+~~~{.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 + } +~~~ +
## Mutating FlatBuffers +
+*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).* +
+ 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 @@ -1624,6 +1983,11 @@ mutators like so: ~~~ +
+~~~{.php} + +~~~ +
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 +2051,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.* +
+*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.* +
## Advanced Features for Each Language @@ -1716,5 +2088,8 @@ For your chosen language, see:
[Use in PHP](@ref flatbuffers_guide_use_php)
+
+[Use in C](@ref flatbuffers_guide_use_c) +

diff --git a/docs/source/doxyfile b/docs/source/doxyfile index ba6fbcbd6..bef63f582 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 1437016ea..b5d8644c1 100644 --- a/docs/source/doxygen_layout.xml +++ b/docs/source/doxygen_layout.xml @@ -25,6 +25,8 @@ title="Writing a schema"/> + Date: Sat, 26 Mar 2016 09:22:56 +0100 Subject: [PATCH 3/8] Add C support in README, minor updates in other C doc --- docs/source/CUsage.md | 11 +++++++---- docs/source/Tutorial.md | 2 +- readme.md | 1 + 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/docs/source/CUsage.md b/docs/source/CUsage.md index 0c87ce955..9397e04dd 100644 --- a/docs/source/CUsage.md +++ b/docs/source/CUsage.md @@ -15,8 +15,8 @@ project. - [Tutorial](@ref flatbuffers_guide_tutorial) - select C as language when scrolling down -- General Use in C (the README) -- The C Builder Interface, advanced +- General Use in C (README) +- The C Builder Interface (advanced) ## Basic Reflection @@ -25,7 +25,7 @@ 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 schema files are pre-generated -in the [runtime distribution](https://github.com/dvidelabs/flatcc/tree/master/include/flatcc/reflection). Extended reflection +in the [runtime distribution](https://github.com/dvidelabs/flatcc/tree/master/include/flatcc/reflection). ## Mutating Reflection @@ -37,9 +37,12 @@ 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. +point. Vectors of strings ## Why not integrate with the `flatc` tool? diff --git a/docs/source/Tutorial.md b/docs/source/Tutorial.md index dfcc3ad7c..4547a2198 100644 --- a/docs/source/Tutorial.md +++ b/docs/source/Tutorial.md @@ -1293,7 +1293,7 @@ like so: // 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(&builder, &size); + buf = flatcc_builder_finalize_buffer(B, &size); // use buf free(buf); diff --git a/readme.md b/readme.md index 954604863..15dd41b11 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 From 7d9779fc677372bb5af7b3f10f387116109e67ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mikkel=20Fahn=C3=B8e=20J=C3=B8rgensen?= Date: Mon, 28 Mar 2016 22:52:10 +0200 Subject: [PATCH 4/8] Move some C specifics out of tutorial and clarify platform support --- docs/source/CUsage.md | 180 +++++++++++++++++++++++++++++++++-- docs/source/FlatBuffers.md | 2 +- docs/source/Support.md | 2 +- docs/source/Tutorial.md | 190 ++++++------------------------------- 4 files changed, 202 insertions(+), 172 deletions(-) diff --git a/docs/source/CUsage.md b/docs/source/CUsage.md index 9397e04dd..434038731 100644 --- a/docs/source/CUsage.md +++ b/docs/source/CUsage.md @@ -19,32 +19,194 @@ project. - The C Builder Interface (advanced) +## 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: + +
+~~~{.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); + } +~~~ +
+ +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: + +
+
+~~~{.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)); +~~~ +
+ + ## 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 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). -## 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 -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. +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. 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. + +
+~~~{.c} + int hp_present = ns(Monster_hp_is_present(monster)); // 1 + int mana_present = ns(Monster_mana_is_present(monster)); // 0 +~~~ +
+ +## 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. + +
+~~~{.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)); +~~~ +
+ ## Why not integrate with the `flatc` tool? [It was considered how the C code generator could be integrated into the @@ -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 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 445121cb3..7da09903b 100644 --- a/docs/source/FlatBuffers.md +++ b/docs/source/FlatBuffers.md @@ -131,7 +131,7 @@ 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 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. - [Support matrix](@ref flatbuffers_support) for platforms/languages/features. - Some [benchmarks](@ref flatbuffers_benchmarks) showing the advantage of diff --git a/docs/source/Support.md b/docs/source/Support.md index 270f88bb9..23bf41aa8 100755 --- a/docs/source/Support.md +++ b/docs/source/Support.md @@ -28,7 +28,7 @@ Buffer verifier | Yes | No | No | No | 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 | ? | ? | ? | No | ? | ? +Platform: Windows | VS2010 | Yes | Yes | ? | ? | ? | ? | ? | ? Platform: Linux | GCC282 | Yes | ? | Yes | Yes | ? | Yes | ? | ? Platform: OS X | Xcode4 | ? | ? | ? | Yes | ? | Yes | ? | ? Platform: Android | NDK10d | Yes | ? | ? | ? | ? | ? | ? | ? diff --git a/docs/source/Tutorial.md b/docs/source/Tutorial.md index 4547a2198..fdf7aca90 100644 --- a/docs/source/Tutorial.md +++ b/docs/source/Tutorial.md @@ -234,7 +234,6 @@ FlatBuffer compiler. Once `flatc` is built successfully, compile the schema for your language:
- *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.*
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. #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. - // Convenient common namespace macro. - #define nsc(x) FLATBUFFERS_WRAP_NAMESPACE(flatbuffers, x) + // A helper to simplify creating vectors from C-arrays. #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(...)`. ~~~
@@ -577,10 +573,10 @@ our `orc` Monster, lets create some `Weapon`s: a `Sword` and an `Axe`.
~~~{.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; - 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; 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. ~~~{.c} // Serialize a name for our monster, called "Orc". // 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 // 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}; - nsc(uint8_vec_ref_t) inventory; + flatbuffers_uint8_vec_ref_t inventory; // `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)); ~~~
@@ -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 offsets. -
-*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.* -
-
~~~{.cpp} // Place the weapons into a `std::vector`, then convert that into a FlatBuffer `vector`. @@ -794,10 +783,7 @@ section.*
~~~{.c} - // Here we use a top-down approach locally to build a Weapons 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. + // 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)); @@ -970,31 +956,23 @@ can serialize the monster itself: uint16_t hp = 300; uint16_t mana = 150; - // Create the equipment union. In the C++ language API this is given - // as two arguments to the create call, or as two separate add - // operations for the type and the table reference. In C we create - // a single union value that carries both the type and reference. + // 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)); ~~~
-
-*Note: in C we use `create_as_root` instead of the also valid `create` call -because it simplfies constructing the root object.* -
- -
-
*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.* -

+ +
+
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 @@ -1016,14 +994,6 @@ a bit more flexibility. ~~~
-
-*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.* -

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 @@ -1058,11 +1028,6 @@ Second, is the `union`'s data. In our example, the last two things we added to our `Monster` were the `Equipped Type` and the `Equipped` union itself. -
-*Note: In C, several different helpers make these two fields appear as -one field, but they can be added separately.* -
- 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:
~~~{.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)); -~~~ -
- -
-Here is an alternative top-down approach unique to the C builder -library. -
-~~~{.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)); + // Add union type and data simultanously. + ns(Monster_equipped_Weapon_add(B, axe)); ~~~
@@ -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 appropriate `finish` method. -
-*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.* -
~~~{.cpp} @@ -1229,10 +1134,7 @@ root. We show this below, but do NOT mix it with the `_as_root` calls.*
~~~{.c} - // Alternative approach separating object creation from being root object. - ns(Monster_ref_t) orc = ns(Monster_create(B, ...)); - // `flatcc_` calls should be isolated to top-level driver logic. - flatcc_builder_buffer_create(orc); + // Because we used `Monster_create_as_root`, we do not need a `finish` call in C`. ~~~
@@ -1317,12 +1219,6 @@ deserialize a FlatBuffer. This section requires the same import/include, namespace, etc. requirements as before: -
-*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.* -
-
~~~{.cpp} #include "monster_generate.h" // This was generated by `flatc`. @@ -1401,10 +1297,11 @@ files while the builder must link with a small runtime library.*
~~~{.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. - #define nsc(x) FLATBUFFERS_WRAP_NAMESPACE(flatbuffers, x) ~~~
@@ -1565,29 +1462,14 @@ accessors for all non-`deprecated` fields. For example:
~~~{.c} 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)); - // This is just a const char *, but it also supports a fast length operation. - nsc(string_t) name = ns(Monster_name(monster)); - size_t name_len = nsc(string_len(name)); + flatbuffers_string_t name = ns(Monster_name(monster)); ~~~
-
-*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 -~~~ -
- - 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`: @@ -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 y = ns(Vec3_y(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; - // ... ~~~
@@ -1722,15 +1597,10 @@ FlatBuffers `vector`.
~~~{.c} - // This is a const uint8_t *, but it shouldn't be accessed directly - // to ensure proper endian conversion. Incidentally the uint8 (ubyte) - // is not sensitive to endianness, so we *could* have accessed it directly. - // The compiler likely optimizes this so that it doesn't matter. - 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. + // 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); ~~~
@@ -1795,7 +1665,7 @@ except your need to handle the result as a FlatBuffer `table`: ~~~{.c} ns(Weapon_vec_t) weapons = ns(Monster_weapons(monster)); 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)))); 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 ## Mutating FlatBuffers -
-*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).* -
- 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 @@ -1984,8 +1849,9 @@ mutators like so: ~~~
-~~~{.php} - +~~~{.c} + ~~~
From 5b38134431cb770e2a3d7f7f5ef185b9de0e9b29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mikkel=20Fahn=C3=B8e=20J=C3=B8rgensen?= Date: Sun, 3 Apr 2016 21:37:57 +0200 Subject: [PATCH 5/8] Document FlatCC support for Windows --- docs/source/CUsage.md | 21 ++++++++++++--------- docs/source/Support.md | 2 +- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/docs/source/CUsage.md b/docs/source/CUsage.md index 434038731..1f48050e7 100644 --- a/docs/source/CUsage.md +++ b/docs/source/CUsage.md @@ -7,7 +7,7 @@ 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 effort has been made to ensure compatibily with the main `flatc` +Great care has been taken to ensure compatibily with the main `flatc` project. @@ -21,13 +21,16 @@ project. ## 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. +Not all platforms are tested regularly but the following platforms have +all successfully built and passed all tests: -Windows has not been tested. The `include/flatcc/portable` library is -intended to abstract platform differences, including Windows. User -feedback and patches are welcome. +- 64-bit Ubuntu 14.04, gcc, CMake with Ninja Build or GNU Make +- 64-bit OS-X 10.11, Apple Clang, CMake with Ninja Build or GNU Make +- 64-bit Centos 7.1, CMake with GNU Make +- 32-bit Windows 10, CMake with MSVC 14 2015 + +ARM cross compilation from Linux has been reported to work to some +extend. Big endian platforms have not been tested and may contain bugs, but care has been taken to provide support for it. @@ -167,7 +170,7 @@ point. 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 +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. @@ -202,7 +205,7 @@ points in time. // or alternatively ns(Monster_equipped_Weapon_add(B, axe); // or alternatively - ns(Monster_equipped_type_add(B, ns(Equipment_Weapon)); + ns(Monster_equipped_add_type(B, ns(Equipment_Weapon)); ns(Monster_equipped_add_member(B, axe)); ~~~ diff --git a/docs/source/Support.md b/docs/source/Support.md index 23bf41aa8..7b01d1582 100755 --- a/docs/source/Support.md +++ b/docs/source/Support.md @@ -28,7 +28,7 @@ Buffer verifier | Yes | No | No | No | 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 | ? | ? | ? | ? | ? | ? +Platform: Windows | VS2010 | Yes | Yes | ? | ? | ? | Yes | ? | ? Platform: Linux | GCC282 | Yes | ? | Yes | Yes | ? | Yes | ? | ? Platform: OS X | Xcode4 | ? | ? | ? | Yes | ? | Yes | ? | ? Platform: Android | NDK10d | Yes | ? | ? | ? | ? | ? | ? | ? From 1db9783bfc2f08fd86d710eb4b936829af842442 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mikkel=20Fahn=C3=B8e=20J=C3=B8rgensen?= Date: Mon, 4 Apr 2016 16:33:20 +0200 Subject: [PATCH 6/8] Remove details on FlatCC builds that would easily become outdated --- docs/source/CUsage.md | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/docs/source/CUsage.md b/docs/source/CUsage.md index 1f48050e7..6f293a81b 100644 --- a/docs/source/CUsage.md +++ b/docs/source/CUsage.md @@ -18,23 +18,14 @@ project. - General Use in C (README) - The C Builder Interface (advanced) - ## Supported Platforms -Not all platforms are tested regularly but the following platforms have -all successfully built and passed all tests: - -- 64-bit Ubuntu 14.04, gcc, CMake with Ninja Build or GNU Make -- 64-bit OS-X 10.11, Apple Clang, CMake with Ninja Build or GNU Make -- 64-bit Centos 7.1, CMake with GNU Make -- 32-bit Windows 10, CMake with MSVC 14 2015 - -ARM cross compilation from Linux has been reported to work to some -extend. - -Big endian platforms have not been tested and may contain bugs, but care -has been taken to provide support for it. +- Ubuntu +- OS-X +- Windows +Centos has been tested at some point and ARM cross compilation has been reported to +work to some extend, but these are not regularly tested. ## Modular Object Creation From 7d396bc2e75c25062e9084efb7f740e28fa86eb9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mikkel=20Fahn=C3=B8e=20J=C3=B8rgensen?= Date: Thu, 7 Apr 2016 18:52:00 +0200 Subject: [PATCH 7/8] Update C documentation with supported MSVC versions, and other minor updates. --- docs/source/CUsage.md | 25 +++++++++++++++++-------- docs/source/FlatBuffers.md | 6 +++--- docs/source/Support.md | 34 +++++++++++++++++----------------- docs/source/Tutorial.md | 9 ++++----- 4 files changed, 41 insertions(+), 33 deletions(-) diff --git a/docs/source/CUsage.md b/docs/source/CUsage.md index 6f293a81b..9aafa6f77 100644 --- a/docs/source/CUsage.md +++ b/docs/source/CUsage.md @@ -10,22 +10,31 @@ 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 -- General Use in C (README) -- The C Builder Interface (advanced) +- [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 -- OS-X -- Windows +- Ubuntu (clang / gcc, ninja / gnu make) +- OS-X (clang / gcc, ninja / gnu make) +- Windows MSVC 2010, 2013, 2015 -Centos has been tested at some point and ARM cross compilation has been reported to -work to some extend, but these are not regularly tested. +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 diff --git a/docs/source/FlatBuffers.md b/docs/source/FlatBuffers.md index 7da09903b..46d4c1201 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#, C, Go, Java, JavaScript, PHP, and Python -(Ruby and Swift 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). diff --git a/docs/source/Support.md b/docs/source/Support.md index 7b01d1582..7bc33481d 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 | 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 | ? | ? | ? | Yes | ? | ? -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 +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 fdf7aca90..1e48796d9 100644 --- a/docs/source/Tutorial.md +++ b/docs/source/Tutorial.md @@ -19,17 +19,16 @@ 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
C++ - C# - C - Go Java + C# + Go + Python JavaScript PHP - Python + C
\endhtmlonly From c837d29eabd8b844a10e20f102f3de4d5a05ad60 Mon Sep 17 00:00:00 2001 From: Wojciech Jaszczak Date: Fri, 8 Apr 2016 19:56:02 +0200 Subject: [PATCH 8/8] Remove unnecessary condition in AssertOffsetAndLength. Condition is already checked and covered in the following condition, the second one was excess. Signed-off-by: Wojciech Jaszczak --- net/FlatBuffers/ByteBuffer.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/net/FlatBuffers/ByteBuffer.cs b/net/FlatBuffers/ByteBuffer.cs index 37779b593..7ca491dc5 100755 --- a/net/FlatBuffers/ByteBuffer.cs +++ b/net/FlatBuffers/ByteBuffer.cs @@ -129,8 +129,7 @@ namespace FlatBuffers private void AssertOffsetAndLength(int offset, int length) { if (offset < 0 || - offset >= _buffer.Length || - offset + length > _buffer.Length) + offset > _buffer.Length - length) throw new ArgumentOutOfRangeException(); }