Commit 9f2b05df authored by Wouter van Oortmerssen's avatar Wouter van Oortmerssen

Merge branch 'master' of https://github.com/google/flatbuffers

parents 83dc5ed4 3ea54466
...@@ -95,6 +95,12 @@ elseif(CMAKE_COMPILER_IS_GNUCXX) ...@@ -95,6 +95,12 @@ elseif(CMAKE_COMPILER_IS_GNUCXX)
set(CMAKE_CXX_FLAGS set(CMAKE_CXX_FLAGS
"${CMAKE_CXX_FLAGS} -Wunused-result -Werror=unused-result") "${CMAKE_CXX_FLAGS} -Wunused-result -Werror=unused-result")
endif() 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") elseif("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
set(CMAKE_CXX_FLAGS set(CMAKE_CXX_FLAGS
"${CMAKE_CXX_FLAGS} -std=c++0x -stdlib=libc++ -Wall -pedantic -Werror -Wextra") "${CMAKE_CXX_FLAGS} -std=c++0x -stdlib=libc++ -Wall -pedantic -Werror -Wextra")
...@@ -102,6 +108,12 @@ elseif("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") ...@@ -102,6 +108,12 @@ elseif("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
set(CMAKE_EXE_LINKER_FLAGS set(CMAKE_EXE_LINKER_FLAGS
"${CMAKE_EXE_LINKER_FLAGS} -lc++abi") "${CMAKE_EXE_LINKER_FLAGS} -lc++abi")
endif() 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() endif()
if(FLATBUFFERS_CODE_COVERAGE) if(FLATBUFFERS_CODE_COVERAGE)
......
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.
...@@ -4,9 +4,9 @@ FlatBuffers {#flatbuffers_index} ...@@ -4,9 +4,9 @@ FlatBuffers {#flatbuffers_index}
# Overview {#flatbuffers_overview} # Overview {#flatbuffers_overview}
[FlatBuffers](@ref flatbuffers_overview) is an efficient cross platform [FlatBuffers](@ref flatbuffers_overview) is an efficient cross platform
serialization library for C++, C#, Go, Java, JavaScript, PHP, and Python serialization library for C++, C#, C, Go, Java, JavaScript, PHP, and Python.
(C and Ruby in progress). It was originally created at Google for game It was originally created at Google for game development and other
development and other performance-critical applications. performance-critical applications.
It is available as Open Source on [GitHub](http://github.com/google/flatbuffers) It is available as Open Source on [GitHub](http://github.com/google/flatbuffers)
under the Apache license, v2 (see LICENSE.txt). under the Apache license, v2 (see LICENSE.txt).
...@@ -131,6 +131,8 @@ sections provide a more in-depth usage guide. ...@@ -131,6 +131,8 @@ sections provide a more in-depth usage guide.
in your own programs. in your own programs.
- How to [use the generated Go code](@ref flatbuffers_guide_use_go) in your - How to [use the generated Go code](@ref flatbuffers_guide_use_go) in your
own programs. own programs.
- How to [use FlatBuffers in C with `flatcc`](@ref flatbuffers_guide_use_c) in your
own programs.
- [Support matrix](@ref flatbuffers_support) for platforms/languages/features. - [Support matrix](@ref flatbuffers_support) for platforms/languages/features.
- Some [benchmarks](@ref flatbuffers_benchmarks) showing the advantage of - Some [benchmarks](@ref flatbuffers_benchmarks) showing the advantage of
using FlatBuffers. using FlatBuffers.
......
...@@ -18,23 +18,23 @@ In general: ...@@ -18,23 +18,23 @@ In general:
NOTE: this table is a start, it needs to be extended. NOTE: this table is a start, it needs to be extended.
Feature | C++ | Java | C# | Go | Python | JS | C | PHP | Ruby Feature | C++ | Java | C# | Go | Python | JS | C | PHP | Ruby
------------------------------ | ------ | ------ | ------ | ------ | ------ | --------- | ---- | --- | ---- ------------------------------ | ------ | ------ | ------ | ------ | ------ | --------- | ------ | --- | ----
Codegen for all basic features | Yes | Yes | Yes | Yes | Yes | Yes | WiP | WiP | WiP Codegen for all basic features | Yes | Yes | Yes | Yes | Yes | Yes | Yes | WiP | WiP
JSON parsing | Yes | No | No | No | No | No | No | No | No JSON parsing | Yes | No | No | No | No | No | Yes | No | No
Simple mutation | Yes | WIP | WIP | 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 Reflection | Yes | No | No | No | No | No | Basic | No | No
Buffer verifier | Yes | No | No | No | No | No | No | No | No Buffer verifier | Yes | No | No | No | No | No | Yes | No | No
Testing: basic | Yes | Yes | Yes | Yes | Yes | Yes | ? | ? | ? Testing: basic | Yes | Yes | Yes | Yes | Yes | Yes | Yes | ? | ?
Testing: fuzz | Yes | No | No | Yes | Yes | No | ? | ? | ? Testing: fuzz | Yes | No | No | Yes | Yes | No | No | ? | ?
Performance: | Superb | Great | Great | Great | Ok | ? |Superb| ? | ? Performance: | Superb | Great | Great | Great | Ok | ? | Superb | ? | ?
Platform: Windows | VS2010 | Yes | Yes | ? | ? | ? | ? | ? | ? Platform: Windows | VS2010 | Yes | Yes | ? | ? | ? | VS2010 | ? | ?
Platform: Linux | GCC282 | Yes | ? | Yes | Yes | ? | ? | ? | ? Platform: Linux | GCC282 | Yes | ? | Yes | Yes | ? | Yes | ? | ?
Platform: OS X | Xcode4 | ? | ? | ? | Yes | ? | ? | ? | ? Platform: OS X | Xcode4 | ? | ? | ? | Yes | ? | Yes | ? | ?
Platform: Android | NDK10d | Yes | ? | ? | ? | ? | ? | ? | ? Platform: Android | NDK10d | Yes | ? | ? | ? | ? | ? | ? | ?
Platform: iOS | ? | ? | ? | ? | ? | ? | ? | ? | ? Platform: iOS | ? | ? | ? | ? | ? | ? | ? | ? | ?
Engine: Unity | ? | ? | Yes | ? | ? | ? | ? | ? | ? Engine: Unity | ? | ? | Yes | ? | ? | ? | ? | ? | ?
Primary authors (github) | gwvo | gwvo | ev*/js*| rw | rw | evanw/ev* | mik* | ch* | rw Primary authors (github) | gwvo | gwvo | ev*/js*| rw | rw | evanw/ev* | mik* | ch* | rw
* ev = evolutional * ev = evolutional
* js = jonsimantov * js = jonsimantov
......
...@@ -19,7 +19,6 @@ character, the hero of the story, needs to slay some `orc`s. We will walk ...@@ -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. through each step necessary to create this monster type using FlatBuffers.
Please select your desired language for our quest: Please select your desired language for our quest:
\htmlonly \htmlonly
<form> <form>
<input type="radio" name="language" value="cpp" checked="checked">C++</input> <input type="radio" name="language" value="cpp" checked="checked">C++</input>
...@@ -29,6 +28,7 @@ Please select your desired language for our quest: ...@@ -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="python">Python</input>
<input type="radio" name="language" value="javascript">JavaScript</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="php">PHP</input>
<input type="radio" name="language" value="c">C</input>
</form> </form>
\endhtmlonly \endhtmlonly
...@@ -98,6 +98,10 @@ Samples demonstating the concepts in this example are located in the source code ...@@ -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 package, under the `samples` directory. You can browse the samples on GitHub
[here](https://github.com/google/flatbuffers/tree/master/samples). [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: For your chosen language, please cross-reference with:
<div class="language-cpp"> <div class="language-cpp">
...@@ -121,6 +125,9 @@ For your chosen language, please cross-reference with: ...@@ -121,6 +125,9 @@ For your chosen language, please cross-reference with:
<div class="language-php"> <div class="language-php">
[SampleBinary.php](https://github.com/google/flatbuffers/blob/master/samples/SampleBinary.php) [SampleBinary.php](https://github.com/google/flatbuffers/blob/master/samples/SampleBinary.php)
</div> </div>
<div class="language-c">
[monster.c](https://github.com/dvidelabs/flatcc/blob/master/samples/monster/monster.c)
</div>
## Writing the Monsters' FlatBuffer Schema ## Writing the Monsters' FlatBuffer Schema
...@@ -225,6 +232,15 @@ FlatBuffer compiler. ...@@ -225,6 +232,15 @@ FlatBuffer compiler.
Once `flatc` is built successfully, compile the schema for your language: Once `flatc` is built successfully, compile the schema for your language:
<div class="language-c">
*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"> <div class="language-cpp">
~~~{.sh} ~~~{.sh}
cd flatbuffers/sample cd flatbuffers/sample
...@@ -267,8 +283,17 @@ Once `flatc` is built successfully, compile the schema for your language: ...@@ -267,8 +283,17 @@ Once `flatc` is built successfully, compile the schema for your language:
./../flatc --php samples/monster.fbs ./../flatc --php samples/monster.fbs
~~~ ~~~
</div> </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) [Using the schema compiler](@ref flatbuffers_guide_using_schema_compiler)
section of the Programmer's Guide. section of the Programmer's Guide.
...@@ -359,6 +384,18 @@ The first step is to import/include the library, generated files, etc. ...@@ -359,6 +384,18 @@ The first step is to import/include the library, generated files, etc.
} }
~~~ ~~~
</div> </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 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 to create an instance of the `FlatBufferBuilder`, which will contain the buffer
...@@ -413,6 +450,14 @@ as it grows: ...@@ -413,6 +450,14 @@ as it grows:
$builder = new Google\FlatBuffers\FlatbufferBuilder(0); $builder = new Google\FlatBuffers\FlatbufferBuilder(0);
~~~ ~~~
</div> </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 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`. 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`. ...@@ -525,6 +570,18 @@ our `orc` Monster, lets create some `Weapon`s: a `Sword` and an `Axe`.
$weapons = \MyGame\Sample\Monster::CreateWeaponsVector($builder, $weaps); $weapons = \MyGame\Sample\Monster::CreateWeaponsVector($builder, $weaps);
~~~ ~~~
</div> </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 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 `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. ...@@ -627,6 +684,20 @@ traversal. This is generally easy to do on any tree structures.
$inv = \MyGame\Sample\Monster::CreateInventoryVector($builder, $treasure); $inv = \MyGame\Sample\Monster::CreateInventoryVector($builder, $treasure);
~~~ ~~~
</div> </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 We serialized two built-in data types (`string` and `vector`) and captured
their return values. These values are offsets into the serialized data, their return values. These values are offsets into the serialized data,
...@@ -709,8 +780,18 @@ offsets. ...@@ -709,8 +780,18 @@ offsets.
$weapons = \MyGame\Sample\Monster::CreateWeaponsVector($builder, $weaps); $weapons = \MyGame\Sample\Monster::CreateWeaponsVector($builder, $weaps);
~~~ ~~~
</div> </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"> <div class="language-cpp">
~~~{.cpp} ~~~{.cpp}
...@@ -754,6 +835,12 @@ To create a `struct`, use the `Vec3` class/struct that was generated by `flatc`: ...@@ -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); $pos = \MyGame\Sample\Vec3::CreateVec3($builder, 1.0, 2.0, 3.0);
~~~ ~~~
</div> </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 We have now serialized the non-scalar components of the orc, so we
can serialize the monster itself: can serialize the monster itself:
...@@ -862,16 +949,29 @@ can serialize the monster itself: ...@@ -862,16 +949,29 @@ can serialize the monster itself:
$orc = \MyGame\Sample\Monster::EndMonster($builder); $orc = \MyGame\Sample\Monster::EndMonster($builder);
~~~ ~~~
</div> </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"> // Define an equipment union. `create` calls in C has a single
<br> // argument for unions where C++ has both a type and a data argument.
*Note: Since we passing `150` as the `mana` field, which happens to be the 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, the field will not actually be written to the buffer, since the
default value will be returned on query anyway. This is a nice space savings, default value will be returned on query anyway. This is a nice space savings,
especially if default values are common in your data. It also means that you do especially if default values are common in your data. It also means that you do
not need to be worried of adding a lot of fields that are only used in a small not need to be worried of adding a lot of fields that are only used in a small
number of instances, as it will not bloat the buffer if unused.* number of instances, as it will not bloat the buffer if unused.*
<br><br>
<div class="language-cpp">
<br>
If you do not wish to set every field in a `table`, it may be more convenient to If you do not wish to set every field in a `table`, it may be more convenient to
manually set each field of your monster, instead of calling `CreateMonster()`. manually set each field of your monster, instead of calling `CreateMonster()`.
The following snippet is functionally equivalent to the above code, but provides The following snippet is functionally equivalent to the above code, but provides
...@@ -892,6 +992,31 @@ a bit more flexibility. ...@@ -892,6 +992,31 @@ a bit more flexibility.
auto orc = monster_builder.Finish(); auto orc = monster_builder.Finish();
~~~ ~~~
</div> </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 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 `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: ...@@ -947,11 +1072,18 @@ Here is a repetition these lines, to help highlight them more clearly:
\MyGame\Sample\Monster::AddEquipped($builder, $axe); // Union data \MyGame\Sample\Monster::AddEquipped($builder, $axe); // Union data
~~~ ~~~
</div> </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 After you have created your buffer, you will have the offset to the root of the
data in the `orc` variable, so you can finish the buffer by calling the data in the `orc` variable, so you can finish the buffer by calling the
appropriate `finish` method. appropriate `finish` method.
<div class="language-cpp"> <div class="language-cpp">
~~~{.cpp} ~~~{.cpp}
// Call `Finish()` to instruct the builder that this monster is complete. // Call `Finish()` to instruct the builder that this monster is complete.
...@@ -999,6 +1131,11 @@ appropriate `finish` method. ...@@ -999,6 +1131,11 @@ appropriate `finish` method.
// $builder, $orc);`. // $builder, $orc);`.
~~~ ~~~
</div> </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 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 compressed, or whatever you'd like to do with it. You can access the buffer
...@@ -1048,6 +1185,29 @@ like so: ...@@ -1048,6 +1185,29 @@ like so:
$buf = $builder->dataBuffer(); // Of type `Google\FlatBuffers\ByteBuffer` $buf = $builder->dataBuffer(); // Of type `Google\FlatBuffers\ByteBuffer`
~~~ ~~~
</div> </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 #### Reading Orc FlatBuffers
...@@ -1055,7 +1215,7 @@ Now that we have successfully created an `Orc` FlatBuffer, the monster data can ...@@ -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 be saved, sent over a network, etc. Let's now adventure into the inverse, and
deserialize a FlatBuffer. 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: before:
<div class="language-cpp"> <div class="language-cpp">
...@@ -1134,6 +1294,15 @@ before: ...@@ -1134,6 +1294,15 @@ before:
} }
~~~ ~~~
</div> </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, Then, assuming you have a variable containing to the bytes of data from disk,
network, etc., you can create a monster from this data: network, etc., you can create a monster from this data:
...@@ -1224,8 +1393,18 @@ 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); $monster = \MyGame\Sample\Monster::GetRootAsMonster($buf);
~~~ ~~~
</div> </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: accessors for all non-`deprecated` fields. For example:
<div class="language-cpp"> <div class="language-cpp">
...@@ -1279,10 +1458,17 @@ accessors for all non-`deprecated` fields. For example: ...@@ -1279,10 +1458,17 @@ accessors for all non-`deprecated` fields. For example:
$name = monster->getName(); $name = monster->getName();
~~~ ~~~
</div> </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. 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`: 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`: ...@@ -1348,10 +1534,18 @@ To access sub-objects, in the case of our `pos`, which is a `Vec3`:
$z = $pos->getZ(); $z = $pos->getZ();
~~~ ~~~
</div> </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. `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 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 can also iterate over the length of the array/vector representing the
...@@ -1400,6 +1594,14 @@ FlatBuffers `vector`. ...@@ -1400,6 +1594,14 @@ FlatBuffers `vector`.
$third_item = $monster->getInventory(2); $third_item = $monster->getInventory(2);
~~~ ~~~
</div> </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, 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`: 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`: ...@@ -1458,6 +1660,15 @@ except your need to handle the result as a FlatBuffer `table`:
$second_weapon_damage = $monster->getWeapons(1)->getDamage(); $second_weapon_damage = $monster->getWeapons(1)->getDamage();
~~~ ~~~
</div> </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 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. 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 ...@@ -1560,6 +1771,18 @@ We can access the type to dynamically cast the data as needed (since the
} }
~~~ ~~~
</div> </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 ## Mutating FlatBuffers
...@@ -1624,6 +1847,12 @@ mutators like so: ...@@ -1624,6 +1847,12 @@ mutators like so:
<API for mutating FlatBuffers is not yet supported in PHP.> <API for mutating FlatBuffers is not yet supported in PHP.>
~~~ ~~~
</div> </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 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 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. ...@@ -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 [Use in C++](@ref flatbuffers_guide_use_cpp) section of the Programmer's
Guide for more information.* Guide for more information.*
</div> </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 ## Advanced Features for Each Language
...@@ -1716,5 +1953,8 @@ For your chosen language, see: ...@@ -1716,5 +1953,8 @@ For your chosen language, see:
<div class="language-php"> <div class="language-php">
[Use in PHP](@ref flatbuffers_guide_use_php) [Use in PHP](@ref flatbuffers_guide_use_php)
</div> </div>
<div class="language-c">
[Use in C](@ref flatbuffers_guide_use_c)
</div>
<br> <br>
...@@ -750,6 +750,7 @@ INPUT = "FlatBuffers.md" \ ...@@ -750,6 +750,7 @@ INPUT = "FlatBuffers.md" \
"Compiler.md" \ "Compiler.md" \
"Schemas.md" \ "Schemas.md" \
"CppUsage.md" \ "CppUsage.md" \
"CUsage.md" \
"GoUsage.md" \ "GoUsage.md" \
"JavaCsharpUsage.md" \ "JavaCsharpUsage.md" \
"JavaScriptUsage.md" \ "JavaScriptUsage.md" \
......
...@@ -25,6 +25,8 @@ ...@@ -25,6 +25,8 @@
title="Writing a schema"/> title="Writing a schema"/>
<tab type="user" url="@ref flatbuffers_guide_use_cpp" <tab type="user" url="@ref flatbuffers_guide_use_cpp"
title="Use in C++"/> 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" <tab type="user" url="@ref flatbuffers_guide_use_go"
title="Use in Go"/> title="Use in Go"/>
<tab type="user" url="@ref flatbuffers_guide_use_java_c-sharp" <tab type="user" url="@ref flatbuffers_guide_use_java_c-sharp"
......
...@@ -129,8 +129,7 @@ namespace FlatBuffers ...@@ -129,8 +129,7 @@ namespace FlatBuffers
private void AssertOffsetAndLength(int offset, int length) private void AssertOffsetAndLength(int offset, int length)
{ {
if (offset < 0 || if (offset < 0 ||
offset >= _buffer.Length || offset > _buffer.Length - length)
offset + length > _buffer.Length)
throw new ArgumentOutOfRangeException(); throw new ArgumentOutOfRangeException();
} }
......
...@@ -15,6 +15,7 @@ unpacking/parsing it first, while still having great forwards/backwards compatib ...@@ -15,6 +15,7 @@ unpacking/parsing it first, while still having great forwards/backwards compatib
## Supported programming languages ## Supported programming languages
* C++ * C++
* C# * C#
* C
* Go * Go
* Java * Java
* JavaScript * JavaScript
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment