mirror of
https://github.com/google/flatbuffers.git
synced 2026-06-10 07:06:26 +00:00
Quick copy of all pages
This commit is contained in:
224
docs/source/languages/c.md
Normal file
224
docs/source/languages/c.md
Normal file
@@ -0,0 +1,224 @@
|
||||
Use in C {#flatbuffers_guide_use_c}
|
||||
==========
|
||||
|
||||
The C language binding exists in a separate project named [FlatCC](https://github.com/dvidelabs/flatcc).
|
||||
|
||||
The `flatcc` C schema compiler can generate code offline as well as
|
||||
online via a C library. It can also generate buffer verifiers and fast
|
||||
JSON parsers, printers.
|
||||
|
||||
Great care has been taken to ensure compatibility 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.
|
||||
|
||||
|
||||
265
docs/source/languages/c_sharp.md
Normal file
265
docs/source/languages/c_sharp.md
Normal file
@@ -0,0 +1,265 @@
|
||||
Use in C\# {#flatbuffers_guide_use_c-sharp}
|
||||
==============
|
||||
|
||||
## Before you get started
|
||||
|
||||
Before diving into the FlatBuffers usage in C#, it should be noted that
|
||||
the [Tutorial](@ref flatbuffers_guide_tutorial) page has a complete guide to
|
||||
general FlatBuffers usage in all of the supported languages (including C#).
|
||||
This page is designed to cover the nuances of FlatBuffers usage,
|
||||
specific to C#.
|
||||
|
||||
You should also have read the [Building](@ref flatbuffers_guide_building)
|
||||
documentation to build `flatc` and should be familiar with
|
||||
[Using the schema compiler](@ref flatbuffers_guide_using_schema_compiler) and
|
||||
[Writing a schema](@ref flatbuffers_guide_writing_schema).
|
||||
|
||||
## FlatBuffers C# code location
|
||||
|
||||
The code for the FlatBuffers C# library can be found at
|
||||
`flatbuffers/net/FlatBuffers`. You can browse the library on the
|
||||
[FlatBuffers GitHub page](https://github.com/google/flatbuffers/tree/master/net/
|
||||
FlatBuffers).
|
||||
|
||||
## Building the FlatBuffers C# library
|
||||
|
||||
The `FlatBuffers.csproj` project contains multitargeting for .NET Standard 2.1,
|
||||
.NET 6 and .NET 8.
|
||||
|
||||
You can build for a specific framework target when using the cross-platform
|
||||
[.NET Core SDK](https://dotnet.microsoft.com/download) by adding the `-f`
|
||||
command line option:
|
||||
|
||||
~~~{.sh}
|
||||
dotnet build -f netstandard2.1 "FlatBuffers.csproj"
|
||||
~~~
|
||||
|
||||
The `FlatBuffers.csproj` project also provides support for defining various
|
||||
conditional compilation symbols (see "Conditional compilation symbols" section
|
||||
below) using the `-p` command line option:
|
||||
|
||||
~~~{.sh}
|
||||
dotnet build -f netstandard2.1 -p:ENABLE_SPAN_T=true -p:UNSAFE_BYTEBUFFER=true "FlatBuffers.csproj"
|
||||
~~~
|
||||
|
||||
## Testing the FlatBuffers C# library
|
||||
|
||||
The code to test the libraries can be found at `flatbuffers/tests`.
|
||||
|
||||
The test code for C# is located in the [FlatBuffers.Test](https://github.com/
|
||||
google/flatbuffers/tree/master/tests/FlatBuffers.Test) subfolder. To run the
|
||||
tests, open `FlatBuffers.Test.csproj` in [Visual Studio](
|
||||
https://www.visualstudio.com), and compile/run the project.
|
||||
|
||||
Optionally, you can run this using [Mono](http://www.mono-project.com/) instead.
|
||||
Once you have installed Mono, you can run the tests from the command line
|
||||
by running the following commands from inside the `FlatBuffers.Test` folder:
|
||||
|
||||
~~~{.sh}
|
||||
mcs *.cs ../MyGame/Example/*.cs ../../net/FlatBuffers/*.cs
|
||||
mono Assert.exe
|
||||
~~~
|
||||
|
||||
## Using the FlatBuffers C# library
|
||||
|
||||
*Note: See [Tutorial](@ref flatbuffers_guide_tutorial) for a more in-depth
|
||||
example of how to use FlatBuffers in C#.*
|
||||
|
||||
FlatBuffers supports reading and writing binary FlatBuffers in C#.
|
||||
|
||||
To use FlatBuffers in your own code, first generate C# classes from your
|
||||
schema with the `--csharp` option to `flatc`.
|
||||
Then you can include both FlatBuffers and the generated code to read
|
||||
or write a FlatBuffer.
|
||||
|
||||
For example, here is how you would read a FlatBuffer binary file in C#:
|
||||
First, import the library and generated code. Then, you read a FlatBuffer binary
|
||||
file into a `byte[]`. You then turn the `byte[]` into a `ByteBuffer`, which you
|
||||
pass to the `GetRootAsMyRootType` function:
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cs}
|
||||
using MyGame.Example;
|
||||
using Google.FlatBuffers;
|
||||
|
||||
// This snippet ignores exceptions for brevity.
|
||||
byte[] data = File.ReadAllBytes("monsterdata_test.mon");
|
||||
|
||||
ByteBuffer bb = new ByteBuffer(data);
|
||||
Monster monster = Monster.GetRootAsMonster(bb);
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Now you can access the data from the `Monster monster`:
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cs}
|
||||
short hp = monster.Hp;
|
||||
Vec3 pos = monster.Pos;
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
C# code naming follows standard C# style with PascalCasing identifiers,
|
||||
e.g. `GetRootAsMyRootType`. Also, values (except vectors and unions) are
|
||||
available as properties instead of parameterless accessor methods.
|
||||
The performance-enhancing methods to which you can pass an already created
|
||||
object are prefixed with `Get`, e.g.:
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cs}
|
||||
// property
|
||||
var pos = monster.Pos;
|
||||
|
||||
// method filling a preconstructed object
|
||||
var preconstructedPos = new Vec3();
|
||||
monster.GetPos(preconstructedPos);
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
## Storing dictionaries in a FlatBuffer
|
||||
|
||||
FlatBuffers doesn't support dictionaries natively, but there is support to
|
||||
emulate their behavior with vectors and binary search, which means you
|
||||
can have fast lookups directly from a FlatBuffer without having to unpack
|
||||
your data into a `Dictionary` or similar.
|
||||
|
||||
To use it:
|
||||
- Designate one of the fields in a table as the "key" field. You do this
|
||||
by setting the `key` attribute on this field, e.g.
|
||||
`name:string (key)`.
|
||||
You may only have one key field, and it must be of string or scalar type.
|
||||
- Write out tables of this type as usual, collect their offsets in an
|
||||
array.
|
||||
- Instead of calling standard generated method,
|
||||
e.g.: `Monster.createTestarrayoftablesVector`,
|
||||
call `CreateSortedVectorOfMonster` in C#
|
||||
which will first sort all offsets such that the tables they refer to
|
||||
are sorted by the key field, then serialize it.
|
||||
- Now when you're accessing the FlatBuffer, you can use
|
||||
the `ByKey` accessor to access elements of the vector, e.g.:
|
||||
`monster.TestarrayoftablesByKey("Frodo")` in C#,
|
||||
which returns an object of the corresponding table type,
|
||||
or `null` if not found.
|
||||
`ByKey` performs a binary search, so should have a similar
|
||||
speed to `Dictionary`, though may be faster because of better caching.
|
||||
`ByKey` only works if the vector has been sorted, it will
|
||||
likely not find elements if it hasn't been sorted.
|
||||
|
||||
## Buffer verification
|
||||
|
||||
As mentioned in [C++ Usage](@ref flatbuffers_guide_use_cpp) buffer
|
||||
accessor functions do not verify buffer offsets at run-time.
|
||||
If it is necessary, you can optionally use a buffer verifier before you
|
||||
access the data. This verifier will check all offsets, all sizes of
|
||||
fields, and null termination of strings to ensure that when a buffer
|
||||
is accessed, all reads will end up inside the buffer.
|
||||
|
||||
Each root type will have a verification function generated for it,
|
||||
e.g. `Monster.VerifyMonster`. This can be called as shown:
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cs}
|
||||
var ok = Monster.VerifyMonster(buf);
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
if `ok` is true, the buffer is safe to read.
|
||||
|
||||
For a more detailed control of verification `MonsterVerify.Verify`
|
||||
for `Monster` type can be used:
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cs}
|
||||
# Sequence of calls
|
||||
FlatBuffers.Verifier verifier = new FlatBuffers.Verifier(buf);
|
||||
var ok = verifier.VerifyBuffer("MONS", false, MonsterVerify.Verify);
|
||||
|
||||
# Or single line call
|
||||
var ok = new FlatBuffers.Verifier(bb).setStringCheck(true).\
|
||||
VerifyBuffer("MONS", false, MonsterVerify.Verify);
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
if `ok` is true, the buffer is safe to read.
|
||||
|
||||
A second parameter of `verifyBuffer` specifies whether buffer content is
|
||||
size prefixed or not. In the example above, the buffer is assumed to not include
|
||||
size prefix (`false`).
|
||||
|
||||
Verifier supports options that can be set using appropriate fluent methods:
|
||||
* SetMaxDepth - limit the nesting depth. Default: 1000000
|
||||
* SetMaxTables - total amount of tables the verifier may encounter. Default: 64
|
||||
* SetAlignmentCheck - check content alignment. Default: True
|
||||
* SetStringCheck - check if strings contain termination '0' character. Default: true
|
||||
|
||||
|
||||
## Text parsing
|
||||
|
||||
There currently is no support for parsing text (Schema's and JSON) directly
|
||||
from C#, though you could use the C++ parser through native call
|
||||
interfaces available to each language. Please see the
|
||||
C++ documentation for more on text parsing.
|
||||
|
||||
## Object based API
|
||||
|
||||
FlatBuffers is all about memory efficiency, which is why its base API is written
|
||||
around using as little as possible of it. This does make the API clumsier
|
||||
(requiring pre-order construction of all data, and making mutation harder).
|
||||
|
||||
For times when efficiency is less important a more convenient object based API
|
||||
can be used (through `--gen-object-api`) that is able to unpack & pack a
|
||||
FlatBuffer into objects and standard `System.Collections.Generic` containers,
|
||||
allowing for convenient construction, access and mutation.
|
||||
|
||||
To use:
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cs}
|
||||
// Deserialize from buffer into object.
|
||||
MonsterT monsterobj = GetMonster(flatbuffer).UnPack();
|
||||
|
||||
// Update object directly like a C# class instance.
|
||||
Console.WriteLine(monsterobj.Name);
|
||||
monsterobj.Name = "Bob"; // Change the name.
|
||||
|
||||
// Serialize into new flatbuffer.
|
||||
FlatBufferBuilder fbb = new FlatBufferBuilder(1);
|
||||
fbb.Finish(Monster.Pack(fbb, monsterobj).Value);
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
### Json Serialization
|
||||
|
||||
An additional feature of the object API is the ability to allow you to
|
||||
serialize & deserialize a JSON text.
|
||||
To use Json Serialization, add `--cs-gen-json-serializer` option to `flatc` and
|
||||
add `Newtonsoft.Json` nuget package to csproj. This requires explicitly setting
|
||||
the `--gen-object-api` option as well.
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cs}
|
||||
// Deserialize MonsterT from json
|
||||
string jsonText = File.ReadAllText(@"Resources/monsterdata_test.json");
|
||||
MonsterT mon = MonsterT.DeserializeFromJson(jsonText);
|
||||
|
||||
// Serialize MonsterT to json
|
||||
string jsonText2 = mon.SerializeToJson();
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
* Limitation
|
||||
* `hash` attribute currently not supported.
|
||||
* NuGet package Dependency
|
||||
* [Newtonsoft.Json](https://github.com/JamesNK/Newtonsoft.Json)
|
||||
|
||||
## Conditional compilation symbols
|
||||
|
||||
There are three conditional compilation symbols that have an impact on
|
||||
performance/features of the C# `ByteBuffer` implementation.
|
||||
|
||||
* `UNSAFE_BYTEBUFFER`
|
||||
|
||||
This will use unsafe code to manipulate the underlying byte array. This can
|
||||
yield a reasonable performance increase.
|
||||
|
||||
* `BYTEBUFFER_NO_BOUNDS_CHECK`
|
||||
|
||||
This will disable the bounds check asserts to the byte array. This can yield a
|
||||
small performance gain in normal code.
|
||||
|
||||
* `ENABLE_SPAN_T`
|
||||
|
||||
This will enable reading and writing blocks of memory with a `Span<T>` instead
|
||||
of just `T[]`. You can also enable writing directly to shared memory or other
|
||||
types of memory by providing a custom implementation of `ByteBufferAllocator`.
|
||||
`ENABLE_SPAN_T` also requires `UNSAFE_BYTEBUFFER` to be defined, or .NET
|
||||
Standard 2.1.
|
||||
|
||||
Using `UNSAFE_BYTEBUFFER` and `BYTEBUFFER_NO_BOUNDS_CHECK` together can yield a
|
||||
performance gain of ~15% for some operations, however doing so is potentially
|
||||
dangerous. Do so at your own risk!
|
||||
|
||||
<br>
|
||||
672
docs/source/languages/cpp.md
Normal file
672
docs/source/languages/cpp.md
Normal file
@@ -0,0 +1,672 @@
|
||||
# Language Guide: C++
|
||||
|
||||
## Before you get started
|
||||
|
||||
Before diving into the FlatBuffers usage in C++, it should be noted that
|
||||
the [Tutorial](@ref flatbuffers_guide_tutorial) page has a complete guide
|
||||
to general FlatBuffers usage in all of the supported languages (including C++).
|
||||
This page is designed to cover the nuances of FlatBuffers usage, specific to
|
||||
C++.
|
||||
|
||||
#### Prerequisites
|
||||
|
||||
This page assumes you have written a FlatBuffers schema and compiled it
|
||||
with the Schema Compiler. If you have not, please see
|
||||
[Using the schema compiler](@ref flatbuffers_guide_using_schema_compiler)
|
||||
and [Writing a schema](@ref flatbuffers_guide_writing_schema).
|
||||
|
||||
Assuming you wrote a schema, say `mygame.fbs` (though the extension doesn't
|
||||
matter), you've generated a C++ header called `mygame_generated.h` using the
|
||||
compiler (e.g. `flatc -c mygame.fbs`), you can now start using this in
|
||||
your program by including the header. As noted, this header relies on
|
||||
`flatbuffers/flatbuffers.h`, which should be in your include path.
|
||||
|
||||
## FlatBuffers C++ library code location
|
||||
|
||||
The code for the FlatBuffers C++ library can be found at
|
||||
`flatbuffers/include/flatbuffers`. You can browse the library code on the
|
||||
[FlatBuffers GitHub page](https://github.com/google/flatbuffers/tree/master/include/flatbuffers).
|
||||
|
||||
## Testing the FlatBuffers C++ library
|
||||
|
||||
The code to test the C++ library can be found at `flatbuffers/tests`.
|
||||
The test code itself is located in
|
||||
[test.cpp](https://github.com/google/flatbuffers/blob/master/tests/test.cpp).
|
||||
|
||||
This test file is built alongside `flatc`. To review how to build the project,
|
||||
please read the [Building](@ref flatbuffers_guide_building) documentation.
|
||||
|
||||
To run the tests, execute `flattests` from the root `flatbuffers/` directory.
|
||||
For example, on [Linux](https://en.wikipedia.org/wiki/Linux), you would simply
|
||||
run: `./flattests`.
|
||||
|
||||
## Using the FlatBuffers C++ library
|
||||
|
||||
*Note: See [Tutorial](@ref flatbuffers_guide_tutorial) for a more in-depth
|
||||
example of how to use FlatBuffers in C++.*
|
||||
|
||||
FlatBuffers supports both reading and writing FlatBuffers in C++.
|
||||
|
||||
To use FlatBuffers in your code, first generate the C++ classes from your
|
||||
schema with the `--cpp` option to `flatc`. Then you can include both FlatBuffers
|
||||
and the generated code to read or write FlatBuffers.
|
||||
|
||||
For example, here is how you would read a FlatBuffer binary file in C++:
|
||||
First, include the library and generated code. Then read the file into
|
||||
a `char *` array, which you pass to `GetMonster()`.
|
||||
|
||||
```cpp
|
||||
#include "flatbuffers/flatbuffers.h"
|
||||
#include "monster_test_generate.h"
|
||||
#include <iostream> // C++ header file for printing
|
||||
#include <fstream> // C++ header file for file access
|
||||
|
||||
|
||||
std::ifstream infile;
|
||||
infile.open("monsterdata_test.mon", std::ios::binary | std::ios::in);
|
||||
infile.seekg(0,std::ios::end);
|
||||
int length = infile.tellg();
|
||||
infile.seekg(0,std::ios::beg);
|
||||
char *data = new char[length];
|
||||
infile.read(data, length);
|
||||
infile.close();
|
||||
|
||||
auto monster = GetMonster(data);
|
||||
```
|
||||
|
||||
`monster` is of type `Monster *`, and points to somewhere *inside* your
|
||||
buffer (root object pointers are not the same as `buffer_pointer` \!).
|
||||
If you look in your generated header, you'll see it has
|
||||
convenient accessors for all fields, e.g. `hp()`, `mana()`, etc:
|
||||
|
||||
```cpp
|
||||
std::cout << "hp : " << monster->hp() << std::endl; // '80'
|
||||
std::cout << "mana : " << monster->mana() << std::endl; // default value of '150'
|
||||
std::cout << "name : " << monster->name()->c_str() << std::endl; // "MyMonster"
|
||||
```
|
||||
|
||||
*Note: That we never stored a `mana` value, so it will return the default.*
|
||||
|
||||
The following attributes are supported:
|
||||
|
||||
- `shared` (on a field): For string fields, this enables the usage of string
|
||||
pooling (i.e. `CreateSharedString`) as default serialization behavior.
|
||||
|
||||
Specifically, `CreateXxxDirect` functions and `Pack` functions for object
|
||||
based API (see below) will use `CreateSharedString` to create strings.
|
||||
|
||||
## Object based API
|
||||
|
||||
FlatBuffers is all about memory efficiency, which is why its base API is written
|
||||
around using as little as possible of it. This does make the API clumsier
|
||||
(requiring pre-order construction of all data, and making mutation harder).
|
||||
|
||||
For times when efficiency is less important a more convenient object based API
|
||||
can be used (through `--gen-object-api`) that is able to unpack & pack a
|
||||
FlatBuffer into objects and standard STL containers, allowing for convenient
|
||||
construction, access and mutation.
|
||||
|
||||
To use:
|
||||
|
||||
```cpp
|
||||
// Autogenerated class from table Monster.
|
||||
MonsterT monsterobj;
|
||||
|
||||
// Deserialize from buffer into object.
|
||||
GetMonster(flatbuffer)->UnPackTo(&monsterobj);
|
||||
|
||||
// Update object directly like a C++ class instance.
|
||||
cout << monsterobj.name; // This is now a std::string!
|
||||
monsterobj.name = "Bob"; // Change the name.
|
||||
|
||||
// Serialize into new flatbuffer.
|
||||
FlatBufferBuilder fbb;
|
||||
fbb.Finish(Monster::Pack(fbb, &monsterobj));
|
||||
```
|
||||
|
||||
The following attributes are specific to the object-based API code generation:
|
||||
|
||||
- `native_inline` (on a field): Because FlatBuffer tables and structs are
|
||||
optionally present in a given buffer, they are best represented as pointers
|
||||
(specifically std::unique_ptrs) in the native class since they can be null.
|
||||
This attribute changes the member declaration to use the type directly
|
||||
rather than wrapped in a unique_ptr.
|
||||
|
||||
- `native_default("value")` (on a field): For members that are declared
|
||||
"native_inline", the value specified with this attribute will be included
|
||||
verbatim in the class constructor initializer list for this member.
|
||||
|
||||
- `native_custom_alloc("custom_allocator")` (on a table or struct): When using the
|
||||
object-based API all generated NativeTables that are allocated when unpacking
|
||||
your flatbuffer will use "custom allocator". The allocator is also used by
|
||||
any std::vector that appears in a table defined with `native_custom_alloc`.
|
||||
This can be used to provide allocation from a pool for example, for faster
|
||||
unpacking when using the object-based API.
|
||||
|
||||
Minimal Example:
|
||||
|
||||
schema:
|
||||
|
||||
```cpp
|
||||
table mytable(native_custom_alloc:"custom_allocator") {
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
with `custom_allocator` defined before `flatbuffers.h` is included, as:
|
||||
|
||||
```cpp
|
||||
template <typename T> struct custom_allocator : public std::allocator<T> {
|
||||
|
||||
typedef T *pointer;
|
||||
|
||||
template <class U>
|
||||
struct rebind {
|
||||
typedef custom_allocator<U> other;
|
||||
};
|
||||
|
||||
pointer allocate(const std::size_t n) {
|
||||
return std::allocator<T>::allocate(n);
|
||||
}
|
||||
|
||||
void deallocate(T* ptr, std::size_t n) {
|
||||
return std::allocator<T>::deallocate(ptr,n);
|
||||
}
|
||||
|
||||
custom_allocator() throw() {}
|
||||
|
||||
template <class U>
|
||||
custom_allocator(const custom_allocator<U>&) throw() {}
|
||||
};
|
||||
```
|
||||
|
||||
- `native_type("type")` (on a struct): In some cases, a more optimal C++ data
|
||||
type exists for a given struct. For example, the following schema:
|
||||
|
||||
```cpp
|
||||
struct Vec2 {
|
||||
x: float;
|
||||
y: float;
|
||||
}
|
||||
```
|
||||
|
||||
generates the following Object-Based API class:
|
||||
|
||||
```cpp
|
||||
struct Vec2T : flatbuffers::NativeTable {
|
||||
float x;
|
||||
float y;
|
||||
};
|
||||
```
|
||||
|
||||
However, it can be useful to instead use a user-defined C++ type since it
|
||||
can provide more functionality, eg.
|
||||
|
||||
```cpp
|
||||
struct vector2 {
|
||||
float x = 0, y = 0;
|
||||
vector2 operator+(vector2 rhs) const { ... }
|
||||
vector2 operator-(vector2 rhs) const { ... }
|
||||
float length() const { ... }
|
||||
// etc.
|
||||
};
|
||||
```
|
||||
|
||||
The `native_type` attribute will replace the usage of the generated class
|
||||
with the given type. So, continuing with the example, the generated
|
||||
code would use `vector2` in place of `Vec2T` for all generated code of
|
||||
the Object-Based API.
|
||||
|
||||
However, because the `native_type` is unknown to flatbuffers, the user must
|
||||
provide the following functions to aide in the serialization process:
|
||||
|
||||
```cpp
|
||||
namespace flatbuffers {
|
||||
Vec2 Pack(const vector2& obj);
|
||||
vector2 UnPack(const Vec2& obj);
|
||||
}
|
||||
```
|
||||
|
||||
- `native_type_pack_name("name")` (on a struct when `native_type` is
|
||||
specified, too): when you want to use the same `native_type` multiple times
|
||||
(e. g. with different precision) you must make the names of the Pack/UnPack
|
||||
functions unique, otherwise you will run into compile errors. This attribute
|
||||
appends a name to the expected Pack/UnPack functions. So when you
|
||||
specify `native_type_pack_name("Vec2")` in the above example you now need to
|
||||
implement these serialization functions instead:
|
||||
|
||||
```cpp
|
||||
namespace flatbuffers {
|
||||
Vec2 PackVec2(const vector2& obj);
|
||||
vector2 UnPackVec2(const Vec2& obj);
|
||||
}
|
||||
```
|
||||
|
||||
Finally, the following top-level attributes:
|
||||
|
||||
- `native_include("path")` (at file level): Because the `native_type` attribute
|
||||
can be used to introduce types that are unknown to flatbuffers, it may be
|
||||
necessary to include "external" header files in the generated code. This
|
||||
attribute can be used to directly add an #include directive to the top of
|
||||
the generated code that includes the specified path directly.
|
||||
|
||||
- `force_align`: this attribute may not be respected in the object API,
|
||||
depending on the aligned of the allocator used with `new`.
|
||||
|
||||
## External references
|
||||
|
||||
An additional feature of the object API is the ability to allow you to load
|
||||
multiple independent FlatBuffers, and have them refer to eachothers objects
|
||||
using hashes which are then represented as typed pointers in the object API.
|
||||
|
||||
To make this work have a field in the objects you want to referred to which is
|
||||
using the string hashing feature (see `hash` attribute in the
|
||||
[schema](@ref flatbuffers_guide_writing_schema) documentation). Then you have
|
||||
a similar hash in the field referring to it, along with a `cpp_type`
|
||||
attribute specifying the C++ type this will refer to (this can be any C++
|
||||
type, and will get a `*` added).
|
||||
|
||||
Then, in JSON or however you create these buffers, make sure they use the
|
||||
same string (or hash).
|
||||
|
||||
When you call `UnPack` (or `Create`), you'll need a function that maps from
|
||||
hash to the object (see `resolver_function_t` for details).
|
||||
|
||||
## Using different pointer types
|
||||
|
||||
By default the object tree is built out of `std::unique_ptr`, but you can
|
||||
influence this either globally (using the `--cpp-ptr-type` argument to
|
||||
`flatc`) or per field (using the `cpp_ptr_type` attribute) to by any smart
|
||||
pointer type (`my_ptr<T>`), or by specifying `naked` as the type to get `T *`
|
||||
pointers. Unlike the smart pointers, naked pointers do not manage memory for
|
||||
you, so you'll have to manage their lifecycles manually. To reference the
|
||||
pointer type specified by the `--cpp-ptr-type` argument to `flatc` from a
|
||||
flatbuffer field set the `cpp_ptr_type` attribute to `default_ptr_type`.
|
||||
|
||||
## Using different string type
|
||||
|
||||
By default the object tree is built out of `std::string`, but you can
|
||||
influence this either globally (using the `--cpp-str-type` argument to
|
||||
`flatc`) or per field using the `cpp_str_type` attribute.
|
||||
|
||||
The type must support `T::c_str()`, `T::length()` and `T::empty()` as member functions.
|
||||
|
||||
Further, the type must be constructible from std::string, as by default a
|
||||
std::string instance is constructed and then used to initialize the custom
|
||||
string type. This behavior impedes efficient and zero-copy construction of
|
||||
custom string types; the `--cpp-str-flex-ctor` argument to `flatc` or the
|
||||
per field attribute `cpp_str_flex_ctor` can be used to change this behavior,
|
||||
so that the custom string type is constructed by passing the pointer and
|
||||
length of the FlatBuffers String. The custom string class will require a
|
||||
constructor in the following format: `custom_str_class(const char *, size_t)`.
|
||||
Please note that the character array is not guaranteed to be NULL terminated,
|
||||
you should always use the provided size to determine end of string.
|
||||
|
||||
## Reflection (& Resizing)
|
||||
|
||||
There is experimental support for reflection in FlatBuffers, allowing you to
|
||||
read and write data even if you don't know the exact format of a buffer, and
|
||||
even allows you to change sizes of strings and vectors in-place.
|
||||
|
||||
The way this works is very elegant; there is actually a FlatBuffer schema that
|
||||
describes schemas (\!) which you can find in `reflection/reflection.fbs`.
|
||||
The compiler, `flatc`, can write out any schemas it has just parsed as a binary
|
||||
FlatBuffer, corresponding to this meta-schema.
|
||||
|
||||
Loading in one of these binary schemas at runtime allows you traverse any
|
||||
FlatBuffer data that corresponds to it without knowing the exact format. You
|
||||
can query what fields are present, and then read/write them after.
|
||||
|
||||
For convenient field manipulation, you can include the header
|
||||
`flatbuffers/reflection.h` which includes both the generated code from the meta
|
||||
schema, as well as a lot of helper functions.
|
||||
|
||||
And example of usage, for the time being, can be found in
|
||||
`test.cpp/ReflectionTest()`.
|
||||
|
||||
## Mini Reflection
|
||||
|
||||
A more limited form of reflection is available for direct inclusion in
|
||||
generated code, which doesn't do any (binary) schema access at all. It was designed
|
||||
to keep the overhead of reflection as low as possible (on the order of 2-6
|
||||
bytes per field added to your executable), but doesn't contain all the
|
||||
information the (binary) schema contains.
|
||||
|
||||
You add this information to your generated code by specifying `--reflect-types`
|
||||
(or instead `--reflect-names` if you also want field / enum names).
|
||||
|
||||
You can now use this information, for example to print a FlatBuffer to text:
|
||||
|
||||
auto s = flatbuffers::FlatBufferToString(flatbuf, MonsterTypeTable());
|
||||
|
||||
`MonsterTypeTable()` is declared in the generated code for each type. The
|
||||
string produced is very similar to the JSON produced by the `Parser` based
|
||||
text generator.
|
||||
|
||||
You'll need `flatbuffers/minireflect.h` for this functionality. In there is also
|
||||
a convenient visitor/iterator so you can write your own output / functionality
|
||||
based on the mini reflection tables without having to know the FlatBuffers or
|
||||
reflection encoding.
|
||||
|
||||
## Storing maps / dictionaries in a FlatBuffer
|
||||
|
||||
FlatBuffers doesn't support maps natively, but there is support to
|
||||
emulate their behavior with vectors and binary search, which means you
|
||||
can have fast lookups directly from a FlatBuffer without having to unpack
|
||||
your data into a `std::map` or similar.
|
||||
|
||||
To use it:
|
||||
- Designate one of the fields in a table as they "key" field. You do this
|
||||
by setting the `key` attribute on this field, e.g.
|
||||
`name:string (key)`.
|
||||
You may only have one key field, and it must be of string or scalar type.
|
||||
- Write out tables of this type as usual, collect their offsets in an
|
||||
array or vector.
|
||||
- Instead of `CreateVector`, call `CreateVectorOfSortedTables`,
|
||||
which will first sort all offsets such that the tables they refer to
|
||||
are sorted by the key field, then serialize it.
|
||||
- Now when you're accessing the FlatBuffer, you can use `Vector::LookupByKey`
|
||||
instead of just `Vector::Get` to access elements of the vector, e.g.:
|
||||
`myvector->LookupByKey("Fred")`, which returns a pointer to the
|
||||
corresponding table type, or `nullptr` if not found.
|
||||
`LookupByKey` performs a binary search, so should have a similar speed to
|
||||
`std::map`, though may be faster because of better caching. `LookupByKey`
|
||||
only works if the vector has been sorted, it will likely not find elements
|
||||
if it hasn't been sorted.
|
||||
|
||||
## Direct memory access
|
||||
|
||||
As you can see from the above examples, all elements in a buffer are
|
||||
accessed through generated accessors. This is because everything is
|
||||
stored in little endian format on all platforms (the accessor
|
||||
performs a swap operation on big endian machines), and also because
|
||||
the layout of things is generally not known to the user.
|
||||
|
||||
For structs, layout is deterministic and guaranteed to be the same
|
||||
across platforms (scalars are aligned to their
|
||||
own size, and structs themselves to their largest member), and you
|
||||
are allowed to access this memory directly by using `sizeof()` and
|
||||
`memcpy` on the pointer to a struct, or even an array of structs.
|
||||
|
||||
To compute offsets to sub-elements of a struct, make sure they
|
||||
are a structs themselves, as then you can use the pointers to
|
||||
figure out the offset without having to hardcode it. This is
|
||||
handy for use of arrays of structs with calls like `glVertexAttribPointer`
|
||||
in OpenGL or similar APIs.
|
||||
|
||||
It is important to note is that structs are still little endian on all
|
||||
machines, so only use tricks like this if you can guarantee you're not
|
||||
shipping on a big endian machine (an `assert(FLATBUFFERS_LITTLEENDIAN)`
|
||||
would be wise).
|
||||
|
||||
## Access of untrusted buffers
|
||||
|
||||
The generated accessor functions access fields over offsets, which is
|
||||
very quick. These offsets are not verified at run-time, so a malformed
|
||||
buffer could cause a program to crash by accessing random memory.
|
||||
|
||||
When you're processing large amounts of data from a source you know (e.g.
|
||||
your own generated data on disk), this is acceptable, but when reading
|
||||
data from the network that can potentially have been modified by an
|
||||
attacker, this is undesirable.
|
||||
|
||||
For this reason, you can optionally use a buffer verifier before you
|
||||
access the data. This verifier will check all offsets, all sizes of
|
||||
fields, and null termination of strings to ensure that when a buffer
|
||||
is accessed, all reads will end up inside the buffer.
|
||||
|
||||
Each root type will have a verification function generated for it,
|
||||
e.g. for `Monster`, you can call:
|
||||
|
||||
```cpp
|
||||
bool ok = VerifyMonsterBuffer(Verifier(buf, len));
|
||||
```
|
||||
|
||||
if `ok` is true, the buffer is safe to read.
|
||||
|
||||
Besides untrusted data, this function may be useful to call in debug
|
||||
mode, as extra insurance against data being corrupted somewhere along
|
||||
the way.
|
||||
|
||||
While verifying a buffer isn't "free", it is typically faster than
|
||||
a full traversal (since any scalar data is not actually touched),
|
||||
and since it may cause the buffer to be brought into cache before
|
||||
reading, the actual overhead may be even lower than expected.
|
||||
|
||||
In specialized cases where a denial of service attack is possible,
|
||||
the verifier has two additional constructor arguments that allow
|
||||
you to limit the nesting depth and total amount of tables the
|
||||
verifier may encounter before declaring the buffer malformed. The default is
|
||||
`Verifier(buf, len, 64 /* max depth */, 1000000, /* max tables */)` which
|
||||
should be sufficient for most uses.
|
||||
|
||||
## Text & schema parsing
|
||||
|
||||
Using binary buffers with the generated header provides a super low
|
||||
overhead use of FlatBuffer data. There are, however, times when you want
|
||||
to use text formats, for example because it interacts better with source
|
||||
control, or you want to give your users easy access to data.
|
||||
|
||||
Another reason might be that you already have a lot of data in JSON
|
||||
format, or a tool that generates JSON, and if you can write a schema for
|
||||
it, this will provide you an easy way to use that data directly.
|
||||
|
||||
(see the schema documentation for some specifics on the JSON format
|
||||
accepted).
|
||||
|
||||
Schema evolution compatibility for the JSON format follows the same rules as the binary format (JSON formatted data will be forwards/backwards compatible with schemas that evolve in a compatible way).
|
||||
|
||||
There are two ways to use text formats:
|
||||
|
||||
#### Using the compiler as a conversion tool
|
||||
|
||||
This is the preferred path, as it doesn't require you to add any new
|
||||
code to your program, and is maximally efficient since you can ship with
|
||||
binary data. The disadvantage is that it is an extra step for your
|
||||
users/developers to perform, though you might be able to automate it.
|
||||
|
||||
flatc -b myschema.fbs mydata.json
|
||||
|
||||
This will generate the binary file `mydata_wire.bin` which can be loaded
|
||||
as before.
|
||||
|
||||
#### Making your program capable of loading text directly
|
||||
|
||||
This gives you maximum flexibility. You could even opt to support both,
|
||||
i.e. check for both files, and regenerate the binary from text when
|
||||
required, otherwise just load the binary.
|
||||
|
||||
This option is currently only available for C++, or Java through JNI.
|
||||
|
||||
As mentioned in the section "Building" above, this technique requires
|
||||
you to link a few more files into your program, and you'll want to include
|
||||
`flatbuffers/idl.h`.
|
||||
|
||||
Load text (either a schema or json) into an in-memory buffer (there is a
|
||||
convenient `LoadFile()` utility function in `flatbuffers/util.h` if you
|
||||
wish). Construct a parser:
|
||||
|
||||
```cpp
|
||||
flatbuffers::Parser parser;
|
||||
```
|
||||
|
||||
Now you can parse any number of text files in sequence:
|
||||
|
||||
```cpp
|
||||
parser.Parse(text_file.c_str());
|
||||
```
|
||||
|
||||
This works similarly to how the command-line compiler works: a sequence
|
||||
of files parsed by the same `Parser` object allow later files to
|
||||
reference definitions in earlier files. Typically this means you first
|
||||
load a schema file (which populates `Parser` with definitions), followed
|
||||
by one or more JSON files.
|
||||
|
||||
As optional argument to `Parse`, you may specify a null-terminated list of
|
||||
include paths. If not specified, any include statements try to resolve from
|
||||
the current directory.
|
||||
|
||||
If there were any parsing errors, `Parse` will return `false`, and
|
||||
`Parser::error_` contains a human readable error string with a line number
|
||||
etc, which you should present to the creator of that file.
|
||||
|
||||
After each JSON file, the `Parser::fbb` member variable is the
|
||||
`FlatBufferBuilder` that contains the binary buffer version of that
|
||||
file, that you can access as described above.
|
||||
|
||||
`samples/sample_text.cpp` is a code sample showing the above operations.
|
||||
|
||||
## Threading
|
||||
|
||||
Reading a FlatBuffer does not touch any memory outside the original buffer,
|
||||
and is entirely read-only (all const), so is safe to access from multiple
|
||||
threads even without synchronisation primitives.
|
||||
|
||||
Creating a FlatBuffer is not thread safe. All state related to building
|
||||
a FlatBuffer is contained in a FlatBufferBuilder instance, and no memory
|
||||
outside of it is touched. To make this thread safe, either do not
|
||||
share instances of FlatBufferBuilder between threads (recommended), or
|
||||
manually wrap it in synchronisation primitives. There's no automatic way to
|
||||
accomplish this, by design, as we feel multithreaded construction
|
||||
of a single buffer will be rare, and synchronisation overhead would be costly.
|
||||
|
||||
## Advanced union features
|
||||
|
||||
The C++ implementation currently supports vectors of unions (i.e. you can
|
||||
declare a field as `[T]` where `T` is a union type instead of a table type). It
|
||||
also supports structs and strings in unions, besides tables.
|
||||
|
||||
For an example of these features, see `tests/union_vector`, and
|
||||
`UnionVectorTest` in `test.cpp`.
|
||||
|
||||
Since these features haven't been ported to other languages yet, if you
|
||||
choose to use them, you won't be able to use these buffers in other languages
|
||||
(`flatc` will refuse to compile a schema that uses these features).
|
||||
|
||||
These features reduce the amount of "table wrapping" that was previously
|
||||
needed to use unions.
|
||||
|
||||
To use scalars, simply wrap them in a struct.
|
||||
|
||||
## Depth limit of nested objects and stack-overflow control
|
||||
The parser of Flatbuffers schema or json-files is kind of recursive parser.
|
||||
To avoid stack-overflow problem the parser has a built-in limiter of
|
||||
recursion depth. Number of nested declarations in a schema or number of
|
||||
nested json-objects is limited. By default, this depth limit set to `64`.
|
||||
It is possible to override this limit with `FLATBUFFERS_MAX_PARSING_DEPTH`
|
||||
definition. This definition can be helpful for testing purposes or embedded
|
||||
applications. For details see [build](@ref flatbuffers_guide_building) of
|
||||
CMake-based projects.
|
||||
|
||||
## Dependence from C-locale {#flatbuffers_locale_cpp}
|
||||
The Flatbuffers [grammar](@ref flatbuffers grammar) uses ASCII
|
||||
character set for identifiers, alphanumeric literals, reserved words.
|
||||
|
||||
Internal implementation of the Flatbuffers depends from functions which
|
||||
depend from C-locale: `strtod()` or `strtof()`, for example.
|
||||
The library expects the dot `.` symbol as the separator of an integer
|
||||
part from the fractional part of a float number.
|
||||
Another separator symbols (`,` for example) will break the compatibility
|
||||
and may lead to an error while parsing a Flatbuffers schema or a json file.
|
||||
|
||||
The Standard C locale is a global resource, there is only one locale for
|
||||
the entire application. Some modern compilers and platforms have
|
||||
locale-independent or locale-narrow functions `strtof_l`, `strtod_l`,
|
||||
`strtoll_l`, `strtoull_l` to resolve this dependency.
|
||||
These functions use specified locale rather than the global or per-thread
|
||||
locale instead. They are part of POSIX-2008 but not part of the C/C++
|
||||
standard library, therefore, may be missing on some platforms.
|
||||
The Flatbuffers library try to detect these functions at configuration and
|
||||
compile time:
|
||||
- CMake `"CMakeLists.txt"`:
|
||||
- Check existence of `strtol_l` and `strtod_l` in the `<stdlib.h>`.
|
||||
- Compile-time `"/include/base.h"`:
|
||||
- `_MSC_VER >= 1900`: MSVC2012 or higher if build with MSVC.
|
||||
- `_XOPEN_SOURCE>=700`: POSIX-2008 if build with GCC/Clang.
|
||||
|
||||
After detection, the definition `FLATBUFFERS_LOCALE_INDEPENDENT` will be
|
||||
set to `0` or `1`.
|
||||
To override or stop this detection use CMake `-DFLATBUFFERS_LOCALE_INDEPENDENT={0|1}`
|
||||
or predefine `FLATBUFFERS_LOCALE_INDEPENDENT` symbol.
|
||||
|
||||
To test the compatibility of the Flatbuffers library with
|
||||
a specific locale use the environment variable `FLATBUFFERS_TEST_LOCALE`:
|
||||
```sh
|
||||
>FLATBUFFERS_TEST_LOCALE="" ./flattests
|
||||
>FLATBUFFERS_TEST_LOCALE="ru_RU.CP1251" ./flattests
|
||||
```
|
||||
|
||||
## Support of floating-point numbers
|
||||
The Flatbuffers library assumes that a C++ compiler and a CPU are
|
||||
compatible with the `IEEE-754` floating-point standard.
|
||||
The schema and json parser may fail if `fast-math` or `/fp:fast` mode is active.
|
||||
|
||||
### Support of hexadecimal and special floating-point numbers
|
||||
According to the [grammar](@ref flatbuffers_grammar) `fbs` and `json` files
|
||||
may use hexadecimal and special (`NaN`, `Inf`) floating-point literals.
|
||||
The Flatbuffers uses `strtof` and `strtod` functions to parse floating-point
|
||||
literals. The Flatbuffers library has a code to detect a compiler compatibility
|
||||
with the literals. If necessary conditions are met the preprocessor constant
|
||||
`FLATBUFFERS_HAS_NEW_STRTOD` will be set to `1`.
|
||||
The support of floating-point literals will be limited at compile time
|
||||
if `FLATBUFFERS_HAS_NEW_STRTOD` constant is less than `1`.
|
||||
In this case, schemas with hexadecimal or special literals cannot be used.
|
||||
|
||||
### Comparison of floating-point NaN values
|
||||
The floating-point `NaN` (`not a number`) is special value which
|
||||
representing an undefined or unrepresentable value.
|
||||
`NaN` may be explicitly assigned to variables, typically as a representation
|
||||
for missing values or may be a result of a mathematical operation.
|
||||
The `IEEE-754` defines two kind of `NaNs`:
|
||||
- Quiet NaNs, or `qNaNs`.
|
||||
- Signaling NaNs, or `sNaNs`.
|
||||
|
||||
According to the `IEEE-754`, a comparison with `NaN` always returns
|
||||
an unordered result even when compared with itself. As a result, a whole
|
||||
Flatbuffers object will be not equal to itself if has one or more `NaN`.
|
||||
Flatbuffers scalar fields that have the default value are not actually stored
|
||||
in the serialized data but are generated in code (see [Writing a schema](@ref flatbuffers_guide_writing_schema)).
|
||||
Scalar fields with `NaN` defaults break this behavior.
|
||||
If a schema has a lot of `NaN` defaults the Flatbuffers can override
|
||||
the unordered comparison by the ordered: `(NaN==NaN)->true`.
|
||||
This ordered comparison is enabled when compiling a program with the symbol
|
||||
`FLATBUFFERS_NAN_DEFAULTS` defined.
|
||||
Additional computations added by `FLATBUFFERS_NAN_DEFAULTS` are very cheap
|
||||
if GCC or Clang used. These compilers have a compile-time implementation
|
||||
of `isnan` checking which MSVC does not.
|
||||
|
||||
## gRPC
|
||||
|
||||
### Before you get started
|
||||
|
||||
Before diving into the FlatBuffers gRPC usage in C++, you should already be
|
||||
familiar with the following:
|
||||
|
||||
- FlatBuffers as a serialization format
|
||||
- [gRPC](http://www.grpc.io/docs/) usage
|
||||
|
||||
### Using the FlatBuffers gRPC C++ library
|
||||
|
||||
NOTE: The examples below are also in the `grpc/samples/greeter` directory.
|
||||
|
||||
We will illustrate usage with the following schema:
|
||||
|
||||
``` title="grpc/samples/greeter/greeter.fbs"
|
||||
--8<-- "https://raw.githubusercontent.com/google/flatbuffers/refs/heads/master/grpc/samples/greeter/greeter.fbs"
|
||||
```
|
||||
|
||||
When we run `flatc`, we pass in the `--grpc` option and generage an additional
|
||||
`greeter.grpc.fb.h` and `greeter.grpc.fb.cc`.
|
||||
|
||||
Example server code looks like this:
|
||||
|
||||
``` title="grpc/samples/greeter/server.cpp"
|
||||
--8<-- "https://raw.githubusercontent.com/google/flatbuffers/refs/heads/master/grpc/samples/greeter/server.cpp"
|
||||
```
|
||||
|
||||
Example client code looks like this:
|
||||
|
||||
``` title="grpc/samples/greeter/client.cpp"
|
||||
--8<-- "https://raw.githubusercontent.com/google/flatbuffers/refs/heads/master/grpc/samples/greeter/client.cpp"
|
||||
```
|
||||
|
||||
131
docs/source/languages/dart.md
Normal file
131
docs/source/languages/dart.md
Normal file
@@ -0,0 +1,131 @@
|
||||
Use in Dart {#flatbuffers_guide_use_dart}
|
||||
===========
|
||||
|
||||
## Before you get started
|
||||
|
||||
Before diving into the FlatBuffers usage in Dart, it should be noted that
|
||||
the [Tutorial](@ref flatbuffers_guide_tutorial) page has a complete guide
|
||||
to general FlatBuffers usage in all of the supported languages (including Dart).
|
||||
This page is designed to cover the nuances of FlatBuffers usage, specific to
|
||||
Dart.
|
||||
|
||||
You should also have read the [Building](@ref flatbuffers_guide_building)
|
||||
documentation to build `flatc` and should be familiar with
|
||||
[Using the schema compiler](@ref flatbuffers_guide_using_schema_compiler) and
|
||||
[Writing a schema](@ref flatbuffers_guide_writing_schema).
|
||||
|
||||
## FlatBuffers Dart library code location
|
||||
|
||||
The code for the FlatBuffers Dart library can be found at
|
||||
`flatbuffers/dart`. You can browse the library code on the [FlatBuffers
|
||||
GitHub page](https://github.com/google/flatbuffers/tree/master/dart).
|
||||
|
||||
## Testing the FlatBuffers Dart library
|
||||
|
||||
The code to test the Dart library can be found at `flatbuffers/tests`.
|
||||
The test code itself is located in [dart_test.dart](https://github.com/google/
|
||||
flatbuffers/blob/master/tests/dart_test.dart).
|
||||
|
||||
To run the tests, use the [DartTest.sh](https://github.com/google/flatbuffers/
|
||||
blob/master/tests/DartTest.sh) shell script.
|
||||
|
||||
*Note: The shell script requires the [Dart SDK](https://www.dartlang.org/tools/sdk)
|
||||
to be installed.*
|
||||
|
||||
## Using the FlatBuffers Dart library
|
||||
|
||||
*Note: See [Tutorial](@ref flatbuffers_guide_tutorial) for a more in-depth
|
||||
example of how to use FlatBuffers in Dart.*
|
||||
|
||||
FlatBuffers supports reading and writing binary FlatBuffers in Dart.
|
||||
|
||||
To use FlatBuffers in your own code, first generate Dart classes from your
|
||||
schema with the `--dart` option to `flatc`. Then you can include both FlatBuffers
|
||||
and the generated code to read or write a FlatBuffer.
|
||||
|
||||
For example, here is how you would read a FlatBuffer binary file in Dart: First,
|
||||
include the library and generated code. Then read a FlatBuffer binary file into
|
||||
a `List<int>`, which you pass to the factory constructor for `Monster`:
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.dart}
|
||||
import 'dart:io' as io;
|
||||
|
||||
import 'package:flat_buffers/flat_buffers.dart' as fb;
|
||||
import './monster_my_game.sample_generated.dart' as myGame;
|
||||
|
||||
List<int> data = await new io.File('monster.dat').readAsBytes();
|
||||
var monster = new myGame.Monster(data);
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Now you can access values like this:
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.dart}
|
||||
var hp = monster.hp;
|
||||
var pos = monster.pos;
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
## Differences from the Dart SDK Front End flat_buffers
|
||||
|
||||
The work in this repository is signfiicantly based on the implementation used
|
||||
internally by the Dart SDK in the front end/analyzer package. Several
|
||||
significant changes have been made.
|
||||
|
||||
1. Support for packed boolean lists has been removed. This is not standard
|
||||
in other implementations and is not compatible with them. Do note that,
|
||||
like in the JavaScript implementation, __null values in boolean lists
|
||||
will be treated as false__. It is also still entirely possible to pack data
|
||||
in a single scalar field, but that would have to be done on the application
|
||||
side.
|
||||
2. The SDK implementation supports enums with regular Dart enums, which
|
||||
works if enums are always indexed at 1; however, FlatBuffers does not
|
||||
require that. This implementation uses specialized enum-like classes to
|
||||
ensure proper mapping from FlatBuffers to Dart and other platforms.
|
||||
3. The SDK implementation does not appear to support FlatBuffer structs or
|
||||
vectors of structs - it treated everything as a built-in scalar or a table.
|
||||
This implementation treats structs in a way that is compatible with other
|
||||
non-Dart implementations, and properly handles vectors of structs. Many of
|
||||
the methods prefixed with 'low' have been prepurposed to support this.
|
||||
4. The SDK implementation treats int64 and uint64 as float64s. This
|
||||
implementation does not. This may cause problems with JavaScript
|
||||
compatibility - however, it should be possible to use the JavaScript
|
||||
implementation, or to do a customized implementation that treats all 64 bit
|
||||
numbers as floats. Supporting the Dart VM and Flutter was a more important
|
||||
goal of this implementation. Support for 16 bit integers was also added.
|
||||
5. The code generation in this offers an "ObjectBuilder", which generates code
|
||||
very similar to the SDK classes that consume FlatBuffers, as well as Builder
|
||||
classes, which produces code which more closely resembles the builders in
|
||||
other languages. The ObjectBuilder classes are easier to use, at the cost of
|
||||
additional references allocated.
|
||||
|
||||
## Text Parsing
|
||||
|
||||
There currently is no support for parsing text (Schema's and JSON) directly
|
||||
from Dart, though you could use the C++ parser through Dart Native Extensions.
|
||||
Please see the C++ documentation for more on text parsing (note that this is
|
||||
not currently an option in Flutter - follow [this issue](https://github.com/flutter/flutter/issues/7053)
|
||||
for the latest).
|
||||
|
||||
## Object based API
|
||||
|
||||
FlatBuffers is all about memory efficiency, which is why its base API is written
|
||||
around using as little as possible of it. This does make the API clumsier
|
||||
(requiring pre-order construction of all data, and making mutation harder).
|
||||
|
||||
For times when efficiency is less important a more convenient object based API
|
||||
can be used (through `--gen-object-api`) that is able to unpack & pack a FlatBuffer
|
||||
into objects and lists, allowing for convenient construction, access and mutation.
|
||||
|
||||
To use:
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.dart}
|
||||
// Deserialize from buffer into object.
|
||||
MonsterT monster = Monster(flatbuffer).unpack();
|
||||
|
||||
// Update object directly like a Dart class instance.
|
||||
print(monster.Name);
|
||||
monster.Name = "Bob"; // Change the name.
|
||||
|
||||
// Serialize into new flatbuffer.
|
||||
final fbb = Builder();
|
||||
fbb.Finish(monster.pack(fbb));
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
99
docs/source/languages/go.md
Normal file
99
docs/source/languages/go.md
Normal file
@@ -0,0 +1,99 @@
|
||||
Use in Go {#flatbuffers_guide_use_go}
|
||||
=========
|
||||
|
||||
## Before you get started
|
||||
|
||||
Before diving into the FlatBuffers usage in Go, it should be noted that
|
||||
the [Tutorial](@ref flatbuffers_guide_tutorial) page has a complete guide
|
||||
to general FlatBuffers usage in all of the supported languages (including Go).
|
||||
This page is designed to cover the nuances of FlatBuffers usage, specific to
|
||||
Go.
|
||||
|
||||
You should also have read the [Building](@ref flatbuffers_guide_building)
|
||||
documentation to build `flatc` and should be familiar with
|
||||
[Using the schema compiler](@ref flatbuffers_guide_using_schema_compiler) and
|
||||
[Writing a schema](@ref flatbuffers_guide_writing_schema).
|
||||
|
||||
## FlatBuffers Go library code location
|
||||
|
||||
The code for the FlatBuffers Go library can be found at
|
||||
`flatbuffers/go`. You can browse the library code on the [FlatBuffers
|
||||
GitHub page](https://github.com/google/flatbuffers/tree/master/go).
|
||||
|
||||
## Testing the FlatBuffers Go library
|
||||
|
||||
The code to test the Go library can be found at `flatbuffers/tests`.
|
||||
The test code itself is located in [go_test.go](https://github.com/google/
|
||||
flatbuffers/blob/master/tests/go_test.go).
|
||||
|
||||
To run the tests, use the [GoTest.sh](https://github.com/google/flatbuffers/
|
||||
blob/master/tests/GoTest.sh) shell script.
|
||||
|
||||
*Note: The shell script requires [Go](https://golang.org/doc/install) to
|
||||
be installed.*
|
||||
|
||||
## Using the FlatBuffers Go library
|
||||
|
||||
*Note: See [Tutorial](@ref flatbuffers_guide_tutorial) for a more in-depth
|
||||
example of how to use FlatBuffers in Go.*
|
||||
|
||||
FlatBuffers supports reading and writing binary FlatBuffers in Go.
|
||||
|
||||
To use FlatBuffers in your own code, first generate Go classes from your
|
||||
schema with the `--go` option to `flatc`. Then you can include both FlatBuffers
|
||||
and the generated code to read or write a FlatBuffer.
|
||||
|
||||
For example, here is how you would read a FlatBuffer binary file in Go: First,
|
||||
include the library and generated code. Then read a FlatBuffer binary file into
|
||||
a `[]byte`, which you pass to the `GetRootAsMonster` function:
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.go}
|
||||
import (
|
||||
example "MyGame/Example"
|
||||
flatbuffers "github.com/google/flatbuffers/go"
|
||||
|
||||
"os"
|
||||
)
|
||||
|
||||
buf, err := os.ReadFile("monster.dat")
|
||||
// handle err
|
||||
monster := example.GetRootAsMonster(buf, 0)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Now you can access values like this:
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.go}
|
||||
hp := monster.Hp()
|
||||
pos := monster.Pos(nil)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
||||
In some cases it's necessary to modify values in an existing FlatBuffer in place (without creating a copy). For this reason, scalar fields of a Flatbuffer table or struct can be mutated.
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.go}
|
||||
monster := example.GetRootAsMonster(buf, 0)
|
||||
|
||||
// Set table field.
|
||||
if ok := monster.MutateHp(10); !ok {
|
||||
panic("failed to mutate Hp")
|
||||
}
|
||||
|
||||
// Set struct field.
|
||||
monster.Pos().MutateZ(4)
|
||||
|
||||
// This mutation will fail because the mana field is not available in
|
||||
// the buffer. It should be set when creating the buffer.
|
||||
if ok := monster.MutateMana(20); !ok {
|
||||
panic("failed to mutate Hp")
|
||||
}
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The term `mutate` is used instead of `set` to indicate that this is a special use case. All mutate functions return a boolean value which is false if the field we're trying to mutate is not available in the buffer.
|
||||
|
||||
## Text Parsing
|
||||
|
||||
There currently is no support for parsing text (Schema's and JSON) directly
|
||||
from Go, though you could use the C++ parser through cgo. Please see the
|
||||
C++ documentation for more on text parsing.
|
||||
|
||||
<br>
|
||||
114
docs/source/languages/java.md
Normal file
114
docs/source/languages/java.md
Normal file
@@ -0,0 +1,114 @@
|
||||
Use in Java {#flatbuffers_guide_use_java}
|
||||
==============
|
||||
|
||||
## Before you get started
|
||||
|
||||
Before diving into the FlatBuffers usage in Java, it should be noted that
|
||||
the [Tutorial](@ref flatbuffers_guide_tutorial) page has a complete guide to
|
||||
general FlatBuffers usage in all of the supported languages (including Java).
|
||||
This page is designed to cover the nuances of FlatBuffers usage,
|
||||
specific to Java.
|
||||
|
||||
You should also have read the [Building](@ref flatbuffers_guide_building)
|
||||
documentation to build `flatc` and should be familiar with
|
||||
[Using the schema compiler](@ref flatbuffers_guide_using_schema_compiler) and
|
||||
[Writing a schema](@ref flatbuffers_guide_writing_schema).
|
||||
|
||||
## FlatBuffers Java code location
|
||||
|
||||
The code for the FlatBuffers Java library can be found at
|
||||
`flatbuffers/java/com/google/flatbuffers`. You can browse the library on the
|
||||
[FlatBuffers GitHub page](https://github.com/google/flatbuffers/tree/master/
|
||||
java/com/google/flatbuffers).
|
||||
|
||||
## Testing the FlatBuffers Java libraries
|
||||
|
||||
The code to test the libraries can be found at `flatbuffers/tests`.
|
||||
|
||||
The test code for Java is located in [JavaTest.java](https://github.com/google
|
||||
/flatbuffers/blob/master/tests/JavaTest.java).
|
||||
|
||||
To run the tests, use either [JavaTest.sh](https://github.com/google/
|
||||
flatbuffers/blob/master/tests/JavaTest.sh) or [JavaTest.bat](https://github.com/
|
||||
google/flatbuffers/blob/master/tests/JavaTest.bat), depending on your operating
|
||||
system.
|
||||
|
||||
*Note: These scripts require that [Java](https://www.oracle.com/java/index.html)
|
||||
is installed.*
|
||||
|
||||
## Using the FlatBuffers Java library
|
||||
|
||||
*Note: See [Tutorial](@ref flatbuffers_guide_tutorial) for a more in-depth
|
||||
example of how to use FlatBuffers in Java.*
|
||||
|
||||
FlatBuffers supports reading and writing binary FlatBuffers in Java.
|
||||
|
||||
To use FlatBuffers in your own code, first generate Java classes from your
|
||||
schema with the `--java` option to `flatc`.
|
||||
Then you can include both FlatBuffers and the generated code to read
|
||||
or write a FlatBuffer.
|
||||
|
||||
For example, here is how you would read a FlatBuffer binary file in Java:
|
||||
First, import the library and generated code. Then, you read a FlatBuffer binary
|
||||
file into a `byte[]`. You then turn the `byte[]` into a `ByteBuffer`, which you
|
||||
pass to the `getRootAsMyRootType` function:
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.java}
|
||||
import MyGame.Example.*;
|
||||
import com.google.flatbuffers.FlatBufferBuilder;
|
||||
|
||||
// This snippet ignores exceptions for brevity.
|
||||
File file = new File("monsterdata_test.mon");
|
||||
RandomAccessFile f = new RandomAccessFile(file, "r");
|
||||
byte[] data = new byte[(int)f.length()];
|
||||
f.readFully(data);
|
||||
f.close();
|
||||
|
||||
ByteBuffer bb = ByteBuffer.wrap(data);
|
||||
Monster monster = Monster.getRootAsMonster(bb);
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Now you can access the data from the `Monster monster`:
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.java}
|
||||
short hp = monster.hp();
|
||||
Vec3 pos = monster.pos();
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
## Storing dictionaries in a FlatBuffer
|
||||
|
||||
FlatBuffers doesn't support dictionaries natively, but there is support to
|
||||
emulate their behavior with vectors and binary search, which means you
|
||||
can have fast lookups directly from a FlatBuffer without having to unpack
|
||||
your data into a `Dictionary` or similar.
|
||||
|
||||
To use it:
|
||||
- Designate one of the fields in a table as the "key" field. You do this
|
||||
by setting the `key` attribute on this field, e.g.
|
||||
`name:string (key)`.
|
||||
You may only have one key field, and it must be of string or scalar type.
|
||||
- Write out tables of this type as usual, collect their offsets in an
|
||||
array.
|
||||
- Instead of calling standard generated method,
|
||||
e.g.: `Monster.createTestarrayoftablesVector`,
|
||||
call `createSortedVectorOfTables` (from the `FlatBufferBuilder` object).
|
||||
which will first sort all offsets such that the tables they refer to
|
||||
are sorted by the key field, then serialize it.
|
||||
- Now when you're accessing the FlatBuffer, you can use
|
||||
the `ByKey` accessor to access elements of the vector, e.g.:
|
||||
`monster.testarrayoftablesByKey("Frodo")`.
|
||||
which returns an object of the corresponding table type,
|
||||
or `null` if not found.
|
||||
`ByKey` performs a binary search, so should have a similar
|
||||
speed to `Dictionary`, though may be faster because of better caching.
|
||||
`ByKey` only works if the vector has been sorted, it will
|
||||
likely not find elements if it hasn't been sorted.
|
||||
|
||||
## Text parsing
|
||||
|
||||
There currently is no support for parsing text (Schema's and JSON) directly
|
||||
from Java, though you could use the C++ parser through native call
|
||||
interfaces available to each language. Please see the
|
||||
C++ documentation for more on text parsing.
|
||||
|
||||
<br>
|
||||
93
docs/source/languages/javascript.md
Normal file
93
docs/source/languages/javascript.md
Normal file
@@ -0,0 +1,93 @@
|
||||
Use in JavaScript {#flatbuffers_guide_use_javascript}
|
||||
=================
|
||||
|
||||
## Before you get started
|
||||
|
||||
Before diving into the FlatBuffers usage in JavaScript, it should be noted that
|
||||
the [Tutorial](@ref flatbuffers_guide_tutorial) page has a complete guide to
|
||||
general FlatBuffers usage in all of the supported languages
|
||||
(including JavaScript). This page is specifically designed to cover the nuances
|
||||
of FlatBuffers usage in JavaScript.
|
||||
|
||||
You should also have read the [Building](@ref flatbuffers_guide_building)
|
||||
documentation to build `flatc` and should be familiar with
|
||||
[Using the schema compiler](@ref flatbuffers_guide_using_schema_compiler) and
|
||||
[Writing a schema](@ref flatbuffers_guide_writing_schema).
|
||||
|
||||
## FlatBuffers JavaScript library code location
|
||||
|
||||
The generated code for the FlatBuffers JavaScript library can be found at
|
||||
https://www.npmjs.com/package/flatbuffers. To use it from sources:
|
||||
|
||||
1. Run `npm run compile` from the main folder to generate JS files from TS.
|
||||
1. In your project, install it as a normal dependency, using the flatbuffers
|
||||
folder as the source.
|
||||
|
||||
## Using the FlatBuffers JavaScript library
|
||||
|
||||
*Note: See [Tutorial](@ref flatbuffers_guide_tutorial) for a more in-depth
|
||||
example of how to use FlatBuffers.*
|
||||
|
||||
Due to the complexity related with large amounts of JS flavors and module types,
|
||||
native JS support has been replaced in 2.0 by transpilation from TypeScript.
|
||||
|
||||
Please look at [TypeScript usage](@ref flatbuffers_guide_use_typescript) and
|
||||
transpile your sources to desired JS flavor. The minimal steps to get up and
|
||||
running with JS are:
|
||||
|
||||
1. Generate TS files from `*.fbs` by using the `--ts` option.
|
||||
1. Transpile resulting TS files to desired JS flavor using `tsc` (see
|
||||
https://www.typescriptlang.org/download for installation instructions).
|
||||
|
||||
~~~{.js}
|
||||
// Note: These require functions are an example - use your desired module flavor.
|
||||
var fs = require('fs');
|
||||
|
||||
var flatbuffers = require('../flatbuffers').flatbuffers;
|
||||
var MyGame = require('./monster_generated').MyGame;
|
||||
|
||||
var data = new Uint8Array(fs.readFileSync('monster.dat'));
|
||||
var buf = new flatbuffers.ByteBuffer(data);
|
||||
|
||||
var monster = MyGame.Example.Monster.getRootAsMonster(buf);
|
||||
|
||||
//--------------------------------------------------------------------------//
|
||||
|
||||
// Note: This code is an example of browser-based HTML/JavaScript. See above
|
||||
// for the code using JavaScript module loaders (e.g. Node.js).
|
||||
<script src="../js/flatbuffers.js"></script>
|
||||
<script src="monster_generated.js"></script>
|
||||
<script>
|
||||
function readFile() {
|
||||
var reader = new FileReader(); // This example uses the HTML5 FileReader.
|
||||
var file = document.getElementById(
|
||||
'file_input').files[0]; // "monster.dat" from the HTML <input> field.
|
||||
|
||||
reader.onload = function() { // Executes after the file is read.
|
||||
var data = new Uint8Array(reader.result);
|
||||
|
||||
var buf = new flatbuffers.ByteBuffer(data);
|
||||
|
||||
var monster = MyGame.Example.Monster.getRootAsMonster(buf);
|
||||
}
|
||||
|
||||
reader.readAsArrayBuffer(file);
|
||||
}
|
||||
</script>
|
||||
|
||||
// Open the HTML file in a browser and select "monster.dat" from with the
|
||||
// <input> field.
|
||||
<input type="file" id="file_input" onchange="readFile();">
|
||||
~~~
|
||||
|
||||
Now you can access values like this:
|
||||
|
||||
~~~{.js}
|
||||
var hp = monster.hp();
|
||||
var pos = monster.pos();
|
||||
~~~
|
||||
|
||||
## Text parsing FlatBuffers in JavaScript
|
||||
|
||||
There currently is no support for parsing text (Schema's and JSON) directly
|
||||
from JavaScript.
|
||||
85
docs/source/languages/lobster.md
Normal file
85
docs/source/languages/lobster.md
Normal file
@@ -0,0 +1,85 @@
|
||||
Use in Lobster {#flatbuffers_guide_use_lobster}
|
||||
==============
|
||||
|
||||
## Before you get started
|
||||
|
||||
Before diving into the FlatBuffers usage in Lobster, it should be noted that the
|
||||
[Tutorial](@ref flatbuffers_guide_tutorial) page has a complete guide to general
|
||||
FlatBuffers usage in all of the supported languages (including Lobster). This
|
||||
page is designed to cover the nuances of FlatBuffers usage, specific to
|
||||
Lobster.
|
||||
|
||||
You should also have read the [Building](@ref flatbuffers_guide_building)
|
||||
documentation to build `flatc` and should be familiar with
|
||||
[Using the schema compiler](@ref flatbuffers_guide_using_schema_compiler) and
|
||||
[Writing a schema](@ref flatbuffers_guide_writing_schema).
|
||||
|
||||
## FlatBuffers Lobster library code location
|
||||
|
||||
The code for the FlatBuffers Lobster library can be found at
|
||||
`flatbuffers/lobster`. You can browse the library code on the
|
||||
[FlatBuffers GitHub page](https://github.com/google/flatbuffers/tree/master/
|
||||
lobster).
|
||||
|
||||
## Testing the FlatBuffers Lobster library
|
||||
|
||||
The code to test the Lobster library can be found at `flatbuffers/tests`.
|
||||
The test code itself is located in [lobstertest.lobster](https://github.com/google/
|
||||
flatbuffers/blob/master/tests/lobstertest.lobster).
|
||||
|
||||
To run the tests, run `lobster lobstertest.lobster`. To obtain Lobster itself,
|
||||
go to the [Lobster homepage](http://strlen.com/lobster) or
|
||||
[github](https://github.com/aardappel/lobster) to learn how to build it for your
|
||||
platform.
|
||||
|
||||
## Using the FlatBuffers Lobster library
|
||||
|
||||
*Note: See [Tutorial](@ref flatbuffers_guide_tutorial) for a more in-depth
|
||||
example of how to use FlatBuffers in Lobster.*
|
||||
|
||||
There is support for both reading and writing FlatBuffers in Lobster.
|
||||
|
||||
To use FlatBuffers in your own code, first generate Lobster classes from your
|
||||
schema with the `--lobster` option to `flatc`. Then you can include both
|
||||
FlatBuffers and the generated code to read or write a FlatBuffer.
|
||||
|
||||
For example, here is how you would read a FlatBuffer binary file in Lobster:
|
||||
First, import the library and the generated code. Then read a FlatBuffer binary
|
||||
file into a string, which you pass to the `GetRootAsMonster` function:
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.lobster}
|
||||
include "monster_generated.lobster"
|
||||
|
||||
let fb = read_file("monsterdata_test.mon")
|
||||
assert fb
|
||||
let monster = MyGame_Example_GetRootAsMonster(fb)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Now you can access values like this:
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.lobster}
|
||||
let hp = monster.hp
|
||||
let pos = monster.pos
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
As you can see, even though `hp` and `pos` are functions that access FlatBuffer
|
||||
data in-place in the string buffer, they appear as field accesses.
|
||||
|
||||
## Speed
|
||||
|
||||
Using FlatBuffers in Lobster should be relatively fast, as the implementation
|
||||
makes use of native support for writing binary values, and access of vtables.
|
||||
Both generated code and the runtime library are therefore small and fast.
|
||||
|
||||
Actual speed will depend on whether you use Lobster as bytecode VM or compiled to
|
||||
C++.
|
||||
|
||||
## Text Parsing
|
||||
|
||||
Lobster has full support for parsing JSON into FlatBuffers, or generating
|
||||
JSON from FlatBuffers. See `samples/sample_test.lobster` for an example.
|
||||
|
||||
This uses the C++ parser and generator underneath, so should be both fast and
|
||||
conformant.
|
||||
|
||||
<br>
|
||||
81
docs/source/languages/lua.md
Normal file
81
docs/source/languages/lua.md
Normal file
@@ -0,0 +1,81 @@
|
||||
Use in Lua {#flatbuffers_guide_use_lua}
|
||||
=============
|
||||
|
||||
## Before you get started
|
||||
|
||||
Before diving into the FlatBuffers usage in Lua, it should be noted that the
|
||||
[Tutorial](@ref flatbuffers_guide_tutorial) page has a complete guide to general
|
||||
FlatBuffers usage in all of the supported languages (including Lua). This
|
||||
page is designed to cover the nuances of FlatBuffers usage, specific to
|
||||
Lua.
|
||||
|
||||
You should also have read the [Building](@ref flatbuffers_guide_building)
|
||||
documentation to build `flatc` and should be familiar with
|
||||
[Using the schema compiler](@ref flatbuffers_guide_using_schema_compiler) and
|
||||
[Writing a schema](@ref flatbuffers_guide_writing_schema).
|
||||
|
||||
## FlatBuffers Lua library code location
|
||||
|
||||
The code for the FlatBuffers Lua library can be found at
|
||||
`flatbuffers/lua`. You can browse the library code on the
|
||||
[FlatBuffers GitHub page](https://github.com/google/flatbuffers/tree/master/lua).
|
||||
|
||||
## Testing the FlatBuffers Lua library
|
||||
|
||||
The code to test the Lua library can be found at `flatbuffers/tests`.
|
||||
The test code itself is located in [luatest.lua](https://github.com/google/
|
||||
flatbuffers/blob/master/tests/luatest.lua).
|
||||
|
||||
To run the tests, use the [LuaTest.sh](https://github.com/google/flatbuffers/
|
||||
blob/master/tests/LuaTest.sh) shell script.
|
||||
|
||||
*Note: This script requires [Lua 5.3](https://www.lua.org/) and
|
||||
[LuaJIT](http://luajit.org/) to be installed.*
|
||||
|
||||
## Using the FlatBuffers Lua library
|
||||
|
||||
*Note: See [Tutorial](@ref flatbuffers_guide_tutorial) for a more in-depth
|
||||
example of how to use FlatBuffers in Lua.*
|
||||
|
||||
There is support for both reading and writing FlatBuffers in Lua.
|
||||
|
||||
To use FlatBuffers in your own code, first generate Lua classes from your
|
||||
schema with the `--lua` option to `flatc`. Then you can include both
|
||||
FlatBuffers and the generated code to read or write a FlatBuffer.
|
||||
|
||||
For example, here is how you would read a FlatBuffer binary file in Lua:
|
||||
First, require the module and the generated code. Then read a FlatBuffer binary
|
||||
file into a `string`, which you pass to the `GetRootAsMonster` function:
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.lua}
|
||||
-- require the library
|
||||
local flatbuffers = require("flatbuffers")
|
||||
|
||||
-- require the generated code
|
||||
local monster = require("MyGame.Sample.Monster")
|
||||
|
||||
-- read the flatbuffer from a file into a string
|
||||
local f = io.open('monster.dat', 'rb')
|
||||
local buf = f:read('*a')
|
||||
f:close()
|
||||
|
||||
-- parse the flatbuffer to get an instance to the root monster
|
||||
local monster1 = monster.GetRootAsMonster(buf, 0)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Now you can access values like this:
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.lua}
|
||||
-- use the : notation to access member data
|
||||
local hp = monster1:Hp()
|
||||
local pos = monster1:Pos()
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
||||
## Text Parsing
|
||||
|
||||
There currently is no support for parsing text (Schema's and JSON) directly
|
||||
from Lua, though you could use the C++ parser through SWIG or ctypes. Please
|
||||
see the C++ documentation for more on text parsing.
|
||||
|
||||
<br>
|
||||
89
docs/source/languages/php.md
Normal file
89
docs/source/languages/php.md
Normal file
@@ -0,0 +1,89 @@
|
||||
Use in PHP {#flatbuffers_guide_use_php}
|
||||
==========
|
||||
|
||||
## Before you get started
|
||||
|
||||
Before diving into the FlatBuffers usage in PHP, it should be noted that
|
||||
the [Tutorial](@ref flatbuffers_guide_tutorial) page has a complete guide to
|
||||
general FlatBuffers usage in all of the supported languages
|
||||
(including PHP). This page is specifically designed to cover the nuances of
|
||||
FlatBuffers usage in PHP.
|
||||
|
||||
You should also have read the [Building](@ref flatbuffers_guide_building)
|
||||
documentation to build `flatc` and should be familiar with
|
||||
[Using the schema compiler](@ref flatbuffers_guide_using_schema_compiler) and
|
||||
[Writing a schema](@ref flatbuffers_guide_writing_schema).
|
||||
|
||||
## FlatBuffers PHP library code location
|
||||
|
||||
The code for FlatBuffers PHP library can be found at `flatbuffers/php`. You
|
||||
can browse the library code on the [FlatBuffers
|
||||
GitHub page](https://github.com/google/flatbuffers/tree/master/php).
|
||||
|
||||
## Testing the FlatBuffers JavaScript library
|
||||
|
||||
The code to test the PHP library can be found at `flatbuffers/tests`.
|
||||
The test code itself is located in [phpTest.php](https://github.com/google/
|
||||
flatbuffers/blob/master/tests/phpTest.php).
|
||||
|
||||
You can run the test with `php phpTest.php` from the command line.
|
||||
|
||||
*Note: The PHP test file requires
|
||||
[PHP](http://php.net/manual/en/install.php) to be installed.*
|
||||
|
||||
## Using theFlatBuffers PHP library
|
||||
|
||||
*Note: See [Tutorial](@ref flatbuffers_guide_tutorial) for a more in-depth
|
||||
example of how to use FlatBuffers in PHP.*
|
||||
|
||||
FlatBuffers supports both reading and writing FlatBuffers in PHP.
|
||||
|
||||
To use FlatBuffers in your own code, first generate PHP classes from your schema
|
||||
with the `--php` option to `flatc`. Then you can include both FlatBuffers and
|
||||
the generated code to read or write a FlatBuffer.
|
||||
|
||||
For example, here is how you would read a FlatBuffer binary file in PHP:
|
||||
First, include the library and generated code (using the PSR `autoload`
|
||||
function). Then you can read a FlatBuffer binary file, which you
|
||||
pass the contents of to the `GetRootAsMonster` function:
|
||||
|
||||
~~~{.php}
|
||||
// It is recommended that your use PSR autoload when using FlatBuffers in PHP.
|
||||
// Here is an example:
|
||||
function __autoload($class_name) {
|
||||
// The last segment of the class name matches the file name.
|
||||
$class = substr($class_name, strrpos($class_name, "\\") + 1);
|
||||
$root_dir = join(DIRECTORY_SEPARATOR, array(dirname(dirname(__FILE__)))); // `flatbuffers` root.
|
||||
|
||||
// Contains the `*.php` files for the FlatBuffers library and the `flatc` generated files.
|
||||
$paths = array(join(DIRECTORY_SEPARATOR, array($root_dir, "php")),
|
||||
join(DIRECTORY_SEPARATOR, array($root_dir, "tests", "MyGame", "Example")));
|
||||
foreach ($paths as $path) {
|
||||
$file = join(DIRECTORY_SEPARATOR, array($path, $class . ".php"));
|
||||
if (file_exists($file)) {
|
||||
require($file);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Read the contents of the FlatBuffer binary file.
|
||||
$filename = "monster.dat";
|
||||
$handle = fopen($filename, "rb");
|
||||
$contents = $fread($handle, filesize($filename));
|
||||
fclose($handle);
|
||||
|
||||
// Pass the contents to `GetRootAsMonster`.
|
||||
$monster = \MyGame\Example\Monster::GetRootAsMonster($contents);
|
||||
~~~
|
||||
|
||||
Now you can access values like this:
|
||||
|
||||
~~~{.php}
|
||||
$hp = $monster->GetHp();
|
||||
$pos = $monster->GetPos();
|
||||
~~~
|
||||
|
||||
## Text Parsing
|
||||
|
||||
There currently is no support for parsing text (Schema's and JSON) directly
|
||||
from PHP.
|
||||
100
docs/source/languages/python.md
Normal file
100
docs/source/languages/python.md
Normal file
@@ -0,0 +1,100 @@
|
||||
Use in Python {#flatbuffers_guide_use_python}
|
||||
=============
|
||||
|
||||
## Before you get started
|
||||
|
||||
Before diving into the FlatBuffers usage in Python, it should be noted that the
|
||||
[Tutorial](@ref flatbuffers_guide_tutorial) page has a complete guide to general
|
||||
FlatBuffers usage in all of the supported languages (including Python). This
|
||||
page is designed to cover the nuances of FlatBuffers usage, specific to
|
||||
Python.
|
||||
|
||||
You should also have read the [Building](@ref flatbuffers_guide_building)
|
||||
documentation to build `flatc` and should be familiar with
|
||||
[Using the schema compiler](@ref flatbuffers_guide_using_schema_compiler) and
|
||||
[Writing a schema](@ref flatbuffers_guide_writing_schema).
|
||||
|
||||
## FlatBuffers Python library code location
|
||||
|
||||
The code for the FlatBuffers Python library can be found at
|
||||
`flatbuffers/python/flatbuffers`. You can browse the library code on the
|
||||
[FlatBuffers GitHub page](https://github.com/google/flatbuffers/tree/master/
|
||||
python).
|
||||
|
||||
## Testing the FlatBuffers Python library
|
||||
|
||||
The code to test the Python library can be found at `flatbuffers/tests`.
|
||||
The test code itself is located in [py_test.py](https://github.com/google/
|
||||
flatbuffers/blob/master/tests/py_test.py).
|
||||
|
||||
To run the tests, use the [PythonTest.sh](https://github.com/google/flatbuffers/
|
||||
blob/master/tests/PythonTest.sh) shell script.
|
||||
|
||||
*Note: This script requires [python](https://www.python.org/) to be
|
||||
installed.*
|
||||
|
||||
## Using the FlatBuffers Python library
|
||||
|
||||
*Note: See [Tutorial](@ref flatbuffers_guide_tutorial) for a more in-depth
|
||||
example of how to use FlatBuffers in Python.*
|
||||
|
||||
There is support for both reading and writing FlatBuffers in Python.
|
||||
|
||||
To use FlatBuffers in your own code, first generate Python classes from your
|
||||
schema with the `--python` option to `flatc`. Then you can include both
|
||||
FlatBuffers and the generated code to read or write a FlatBuffer.
|
||||
|
||||
For example, here is how you would read a FlatBuffer binary file in Python:
|
||||
First, import the library and the generated code. Then read a FlatBuffer binary
|
||||
file into a `bytearray`, which you pass to the `GetRootAsMonster` function:
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.py}
|
||||
import MyGame.Example as example
|
||||
import flatbuffers
|
||||
|
||||
buf = open('monster.dat', 'rb').read()
|
||||
buf = bytearray(buf)
|
||||
monster = example.GetRootAsMonster(buf, 0)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Now you can access values like this:
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.py}
|
||||
hp = monster.Hp()
|
||||
pos = monster.Pos()
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
## Support for Numpy arrays
|
||||
|
||||
The Flatbuffers python library also has support for accessing scalar
|
||||
vectors as numpy arrays. This can be orders of magnitude faster than
|
||||
iterating over the vector one element at a time, and is particularly
|
||||
useful when unpacking large nested flatbuffers. The generated code for
|
||||
a scalar vector will have a method `<vector name>AsNumpy()`. In the
|
||||
case of the Monster example, you could access the inventory vector
|
||||
like this:
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.py}
|
||||
inventory = monster.InventoryAsNumpy()
|
||||
# inventory is a numpy array of type np.dtype('uint8')
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
instead of
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.py}
|
||||
inventory = []
|
||||
for i in range(monster.InventoryLength()):
|
||||
inventory.append(int(monster.Inventory(i)))
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Numpy is not a requirement. If numpy is not installed on your system,
|
||||
then attempting to access one of the `*asNumpy()` methods will result
|
||||
in a `NumpyRequiredForThisFeature` exception.
|
||||
|
||||
## Text Parsing
|
||||
|
||||
There currently is no support for parsing text (Schema's and JSON) directly
|
||||
from Python, though you could use the C++ parser through SWIG or ctypes. Please
|
||||
see the C++ documentation for more on text parsing.
|
||||
|
||||
<br>
|
||||
186
docs/source/languages/rust.md
Normal file
186
docs/source/languages/rust.md
Normal file
@@ -0,0 +1,186 @@
|
||||
Use in Rust {#flatbuffers_guide_use_rust}
|
||||
==========
|
||||
|
||||
## Before you get started
|
||||
|
||||
Before diving into the FlatBuffers usage in Rust, it should be noted that
|
||||
the [Tutorial](@ref flatbuffers_guide_tutorial) page has a complete guide
|
||||
to general FlatBuffers usage in all of the supported languages (including Rust).
|
||||
This page is designed to cover the nuances of FlatBuffers usage, specific to
|
||||
Rust.
|
||||
|
||||
#### Prerequisites
|
||||
|
||||
This page assumes you have written a FlatBuffers schema and compiled it
|
||||
with the Schema Compiler. If you have not, please see
|
||||
[Using the schema compiler](@ref flatbuffers_guide_using_schema_compiler)
|
||||
and [Writing a schema](@ref flatbuffers_guide_writing_schema).
|
||||
|
||||
Assuming you wrote a schema, say `mygame.fbs` (though the extension doesn't
|
||||
matter), you've generated a Rust file called `mygame_generated.rs` using the
|
||||
compiler (e.g. `flatc --rust mygame.fbs` or via helpers listed in "Useful
|
||||
tools created by others" section bellow), you can now start using this in
|
||||
your program by including the file. As noted, this header relies on the crate
|
||||
`flatbuffers`, which should be in your include `Cargo.toml`.
|
||||
|
||||
## FlatBuffers Rust library code location
|
||||
|
||||
The code for the FlatBuffers Rust library can be found at
|
||||
`flatbuffers/rust`. You can browse the library code on the
|
||||
[FlatBuffers GitHub page](https://github.com/google/flatbuffers/tree/master/rust).
|
||||
|
||||
## Testing the FlatBuffers Rust library
|
||||
|
||||
The code to test the Rust library can be found at `flatbuffers/tests/rust_usage_test`.
|
||||
The test code itself is located in
|
||||
[integration_test.rs](https://github.com/google/flatbuffers/blob/master/tests/rust_usage_test/tests/integration_test.rs)
|
||||
|
||||
This test file requires `flatc` to be present. To review how to build the project,
|
||||
please read the [Building](@ref flatbuffers_guide_building) documentation.
|
||||
|
||||
To run the tests, execute `RustTest.sh` from the `flatbuffers/tests` directory.
|
||||
For example, on [Linux](https://en.wikipedia.org/wiki/Linux), you would simply
|
||||
run: `cd tests && ./RustTest.sh`.
|
||||
|
||||
*Note: The shell script requires [Rust](https://www.rust-lang.org) to
|
||||
be installed.*
|
||||
|
||||
## Using the FlatBuffers Rust library
|
||||
|
||||
*Note: See [Tutorial](@ref flatbuffers_guide_tutorial) for a more in-depth
|
||||
example of how to use FlatBuffers in Rust.*
|
||||
|
||||
FlatBuffers supports both reading and writing FlatBuffers in Rust.
|
||||
|
||||
To use FlatBuffers in your code, first generate the Rust modules from your
|
||||
schema with the `--rust` option to `flatc`. Then you can import both FlatBuffers
|
||||
and the generated code to read or write FlatBuffers.
|
||||
|
||||
For example, here is how you would read a FlatBuffer binary file in Rust:
|
||||
First, include the library and generated code. Then read the file into
|
||||
a `u8` vector, which you pass, as a byte slice, to `root_as_monster()`.
|
||||
|
||||
This full example program is available in the Rust test suite:
|
||||
[monster_example.rs](https://github.com/google/flatbuffers/blob/master/tests/rust_usage_test/bin/monster_example.rs)
|
||||
|
||||
It can be run by `cd`ing to the `rust_usage_test` directory and executing: `cargo run monster_example`.
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.rs}
|
||||
extern crate flatbuffers;
|
||||
|
||||
#[allow(dead_code, unused_imports)]
|
||||
#[path = "../../monster_test_generated.rs"]
|
||||
mod monster_test_generated;
|
||||
pub use monster_test_generated::my_game;
|
||||
|
||||
use std::io::Read;
|
||||
|
||||
fn main() {
|
||||
let mut f = std::fs::File::open("../monsterdata_test.mon").unwrap();
|
||||
let mut buf = Vec::new();
|
||||
f.read_to_end(&mut buf).expect("file reading failed");
|
||||
|
||||
let monster = my_game::example::root_as_monster(&buf[..]);
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
`monster` is of type `Monster`, and points to somewhere *inside* your
|
||||
buffer (root object pointers are not the same as `buffer_pointer` !).
|
||||
If you look in your generated header, you'll see it has
|
||||
convenient accessors for all fields, e.g. `hp()`, `mana()`, etc:
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.rs}
|
||||
println!("{}", monster.hp()); // `80`
|
||||
println!("{}", monster.mana()); // default value of `150`
|
||||
println!("{:?}", monster.name()); // Some("MyMonster")
|
||||
}
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
*Note: That we never stored a `mana` value, so it will return the default.*
|
||||
|
||||
## Direct memory access
|
||||
|
||||
As you can see from the above examples, all elements in a buffer are
|
||||
accessed through generated accessors. This is because everything is
|
||||
stored in little endian format on all platforms (the accessor
|
||||
performs a swap operation on big endian machines), and also because
|
||||
the layout of things is generally not known to the user.
|
||||
|
||||
For structs, layout is deterministic and guaranteed to be the same
|
||||
across platforms (scalars are aligned to their
|
||||
own size, and structs themselves to their largest member), and you
|
||||
are allowed to access this memory directly by using `safe_slice`
|
||||
on the reference to a struct, or even an array of structs.
|
||||
|
||||
To compute offsets to sub-elements of a struct, make sure they
|
||||
are structs themselves, as then you can use the pointers to
|
||||
figure out the offset without having to hardcode it. This is
|
||||
handy for use of arrays of structs with calls like `glVertexAttribPointer`
|
||||
in OpenGL or similar APIs.
|
||||
|
||||
It is important to note is that structs are still little endian on all
|
||||
machines, so the functions to enable tricks like this are only exposed on little
|
||||
endian machines. If you also ship on big endian machines, using an
|
||||
`#[cfg(target_endian = "little")]` attribute would be wise or your code will not
|
||||
compile.
|
||||
|
||||
The special function `safe_slice` is implemented on Vector objects that are
|
||||
represented in memory the same way as they are represented on the wire. This
|
||||
function is always available on vectors of struct, bool, u8, and i8. It is
|
||||
conditionally-compiled on little-endian systems for all the remaining scalar
|
||||
types.
|
||||
|
||||
The FlatBufferBuilder function `create_vector_direct` is implemented for all
|
||||
types that are endian-safe to write with a `memcpy`. It is the write-equivalent
|
||||
of `safe_slice`.
|
||||
|
||||
## Access of untrusted buffers
|
||||
|
||||
The safe Rust functions to interpret a slice as a table (`root`,
|
||||
`size_prefixed_root`, `root_with_opts`, and `size_prefixed_root_with_opts`)
|
||||
verify the data first. This has some performance cost, but is intended to be
|
||||
safe for use on flatbuffers from untrusted sources. There are corresponding
|
||||
`unsafe` versions with names ending in `_unchecked` which skip this
|
||||
verification, and may access arbitrary memory.
|
||||
|
||||
The generated accessor functions access fields over offsets, which is
|
||||
very quick. The current implementation uses these to access memory without any
|
||||
further bounds checking. All of the safe Rust APIs ensure the verifier is run
|
||||
over these flatbuffers before accessing them.
|
||||
|
||||
When you're processing large amounts of data from a source you know (e.g.
|
||||
your own generated data on disk), the `_unchecked` versions are acceptable, but
|
||||
when reading data from the network that can potentially have been modified by an
|
||||
attacker, it is desirable to use the safe versions which use the verifier.
|
||||
|
||||
## Threading
|
||||
|
||||
Reading a FlatBuffer does not touch any memory outside the original buffer,
|
||||
and is entirely read-only (all immutable), so is safe to access from multiple
|
||||
threads even without synchronisation primitives.
|
||||
|
||||
Creating a FlatBuffer is not thread safe. All state related to building
|
||||
a FlatBuffer is contained in a FlatBufferBuilder instance, and no memory
|
||||
outside of it is touched. To make this thread safe, either do not
|
||||
share instances of FlatBufferBuilder between threads (recommended), or
|
||||
manually wrap it in synchronisation primitives. There's no automatic way to
|
||||
accomplish this, by design, as we feel multithreaded construction
|
||||
of a single buffer will be rare, and synchronisation overhead would be costly.
|
||||
|
||||
Unlike most other languages, in Rust these properties are exposed to and
|
||||
enforced by the type system. `flatbuffers::Table` and the generated table types
|
||||
are `Send + Sync`, indicating they may be freely shared across threads and data
|
||||
may be accessed from any thread which receives a const (aka shared) reference.
|
||||
There are no functions which require a mutable (aka exclusive) reference, which
|
||||
means all the available functions may be called like this.
|
||||
`flatbuffers::FlatBufferBuilder` is also `Send + Sync`, but all of the mutating
|
||||
functions require a mutable (aka exclusive) reference which can only be created
|
||||
when no other references to the `FlatBufferBuilder` exist, and may not be copied
|
||||
within the same thread, let alone to a second thread.
|
||||
|
||||
## Useful tools created by others
|
||||
|
||||
* [flatc-rust](https://github.com/frol/flatc-rust) - FlatBuffers compiler
|
||||
(flatc) as API for transparent `.fbs` to `.rs` code-generation via Cargo
|
||||
build scripts integration.
|
||||
|
||||
<br>
|
||||
97
docs/source/languages/swift.md
Normal file
97
docs/source/languages/swift.md
Normal file
@@ -0,0 +1,97 @@
|
||||
Use in Swift {#flatbuffers_guide_use_swift}
|
||||
=========
|
||||
|
||||
## Before you get started
|
||||
|
||||
Before diving into the FlatBuffers usage in Swift, it should be noted that
|
||||
the [Tutorial](@ref flatbuffers_guide_tutorial) page has a complete guide
|
||||
to general FlatBuffers usage in all of the supported languages (including Swift).
|
||||
This page is designed to cover the nuances of FlatBuffers usage, specific to
|
||||
Swift.
|
||||
|
||||
You should also have read the [Building](@ref flatbuffers_guide_building)
|
||||
documentation to build `flatc` and should be familiar with
|
||||
[Using the schema compiler](@ref flatbuffers_guide_using_schema_compiler) and
|
||||
[Writing a schema](@ref flatbuffers_guide_writing_schema).
|
||||
|
||||
## FlatBuffers Swift library code location
|
||||
|
||||
The code for the FlatBuffers Swift library can be found at
|
||||
`flatbuffers/swift`. You can browse the library code on the [FlatBuffers
|
||||
GitHub page](https://github.com/google/flatbuffers/tree/master/swift).
|
||||
|
||||
## Testing the FlatBuffers Swift library
|
||||
|
||||
The code to test the Swift library can be found at `flatbuffers/tests/swift/tests`.
|
||||
The test code itself is located in [flatbuffers/tests/swift/tests](https://github.com/google/flatbuffers/blob/master/tests/swift/tests).
|
||||
|
||||
To run the tests, use the [SwiftTest.sh](https://github.com/google/flatbuffers/blob/master/tests/swift/tests/SwiftTest.sh) shell script.
|
||||
|
||||
*Note: The shell script requires [Swift](https://swift.org) to
|
||||
be installed.*
|
||||
|
||||
## Using the FlatBuffers Swift library
|
||||
|
||||
*Note: See [Tutorial](@ref flatbuffers_guide_tutorial) for a more in-depth
|
||||
example of how to use FlatBuffers in Swift.*
|
||||
|
||||
FlatBuffers supports reading and writing binary FlatBuffers in Swift.
|
||||
|
||||
To use FlatBuffers in your own code, first generate Swift structs from your
|
||||
schema with the `--swift` option to `flatc`. Then include FlatBuffers using `SPM` in
|
||||
by adding the path to `FlatBuffers/swift` into it. The generated code should also be
|
||||
added to xcode or the path of the package you will be using. Note: sometimes xcode cant
|
||||
and wont see the generated files, so it's better that you copy them to xcode.
|
||||
|
||||
For example, here is how you would read a FlatBuffer binary file in Swift: First,
|
||||
include the library and copy thegenerated code. Then read a FlatBuffer binary file or
|
||||
a data object from the server, which you can pass into the `GetRootAsMonster` function.
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.swift}
|
||||
import FlatBuffers
|
||||
|
||||
typealias Monster1 = MyGame.Sample.Monster
|
||||
typealias Vec3 = MyGame.Sample.Vec3
|
||||
|
||||
let path = FileManager.default.currentDirectoryPath
|
||||
let url = URL(fileURLWithPath: path, isDirectory: true).appendingPathComponent("monsterdata_test").appendingPathExtension("mon")
|
||||
guard let data = try? Data(contentsOf: url) else { return }
|
||||
|
||||
let monster = Monster.getRootAsMonster(bb: ByteBuffer(data: data))
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Now you can access values like this:
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.swift}
|
||||
let hp = monster.hp
|
||||
let pos = monster.pos // uses native swift structs
|
||||
let pos = monster.mutablePos // uses flatbuffers structs
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
||||
In some cases it's necessary to modify values in an existing FlatBuffer in place (without creating a copy). For this reason, scalar fields of a Flatbuffer table or struct can be mutated.
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.swift}
|
||||
var byteBuffer = ByteBuffer(bytes: data)
|
||||
// Get an accessor to the root object inside the buffer.
|
||||
let monster: Monster = try! getCheckedRoot(byteBuffer: &byteBuffer)
|
||||
// let monster: Monster = getRoot(byteBuffer: &byteBuffer)
|
||||
|
||||
if !monster.mutate(hp: 10) {
|
||||
fatalError("couldn't mutate")
|
||||
}
|
||||
// mutate a struct field using flatbuffers struct
|
||||
// DONT use monster.pos to mutate since swift copy on write
|
||||
// will not mutate the value in the buffer
|
||||
let vec = monster.mutablePos.mutate(z: 4)
|
||||
|
||||
// This mutation will fail because the mana field is not available in
|
||||
// the buffer. It should be set when creating the buffer.
|
||||
if !monster.mutate(mana: 20) {
|
||||
fatalError("couldn't mutate")
|
||||
}
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The term `mutate` is used instead of `set` to indicate that this is a special use case. All mutate functions return a boolean value which is false if the field we're trying to mutate is not available in the buffer.
|
||||
|
||||
<br>
|
||||
96
docs/source/languages/typescript.md
Normal file
96
docs/source/languages/typescript.md
Normal file
@@ -0,0 +1,96 @@
|
||||
Use in TypeScript {#flatbuffers_guide_use_typescript}
|
||||
=================
|
||||
|
||||
## Before you get started
|
||||
|
||||
Before diving into the FlatBuffers usage in TypeScript, it should be noted that
|
||||
the [Tutorial](@ref flatbuffers_guide_tutorial) page has a complete guide to
|
||||
general FlatBuffers usage in all of the supported languages
|
||||
(including TypeScript). This page is specifically designed to cover the nuances
|
||||
of FlatBuffers usage in TypeScript.
|
||||
|
||||
You should also have read the [Building](@ref flatbuffers_guide_building)
|
||||
documentation to build `flatc` and should be familiar with
|
||||
[Using the schema compiler](@ref flatbuffers_guide_using_schema_compiler) and
|
||||
[Writing a schema](@ref flatbuffers_guide_writing_schema).
|
||||
|
||||
## FlatBuffers TypeScript library code location
|
||||
|
||||
The code for the FlatBuffers TypeScript library can be found at
|
||||
https://www.npmjs.com/package/flatbuffers.
|
||||
|
||||
## Testing the FlatBuffers TypeScript library
|
||||
|
||||
To run the tests, use the [TypeScriptTest.py](https://github.com/google/
|
||||
flatbuffers/blob/master/tests/TypeScriptTest.py) Python3 script.
|
||||
|
||||
*Note: The TypeScript test file requires [Node.js](https://nodejs.org/en/).*
|
||||
|
||||
## Using the FlatBuffers TypeScript library
|
||||
|
||||
*Note: See [Tutorial](@ref flatbuffers_guide_tutorial) for a more in-depth
|
||||
example of how to use FlatBuffers in TypeScript.*
|
||||
|
||||
FlatBuffers supports both reading and writing FlatBuffers in TypeScript.
|
||||
|
||||
To use FlatBuffers in your own code, first generate TypeScript classes from your
|
||||
schema with the `--ts` option to `flatc`. Then you can include both FlatBuffers
|
||||
and the generated code to read or write a FlatBuffer.
|
||||
|
||||
For example, here is how you would read a FlatBuffer binary file in TypeScript:
|
||||
First, include the library and generated code. Then read the file into an
|
||||
`Uint8Array`. Make a `flatbuffers.ByteBuffer` out of the `Uint8Array`, and pass
|
||||
the ByteBuffer to the `getRootAsMonster` function.
|
||||
|
||||
~~~{.ts}
|
||||
import * as flatbuffers from 'flatbuffers';
|
||||
|
||||
import { MyGame } from './monster_generated';
|
||||
|
||||
let data = new Uint8Array(fs.readFileSync('monster.dat'));
|
||||
let buf = new flatbuffers.ByteBuffer(data);
|
||||
|
||||
let monster = MyGame.Example.Monster.getRootAsMonster(buf);
|
||||
~~~
|
||||
|
||||
Now you can access values like this:
|
||||
|
||||
~~~{.ts}
|
||||
let hp = monster.hp();
|
||||
let pos = monster.pos();
|
||||
~~~
|
||||
|
||||
## Object based API
|
||||
|
||||
FlatBuffers is all about memory efficiency, which is why its base API is written
|
||||
around using as little as possible of it. This does make the API clumsier
|
||||
(requiring pre-order construction of all data, and making mutation harder).
|
||||
|
||||
For times when efficiency is less important a more convenient object based API
|
||||
can be used (through `--gen-object-api`) that is able to unpack & pack a
|
||||
FlatBuffer into objects and standard TS types.
|
||||
|
||||
To use:
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.ts}
|
||||
// Autogenerated class from table Monster.
|
||||
let monsterobj = new MonsterT();
|
||||
|
||||
// Deserialize from buffer into object.
|
||||
Monster.getRootAsMonster(flatbuffer).unpackTo(monsterobj);
|
||||
// or
|
||||
let monsterobj = Monster.getRootAsMonster(flatbuffer).unpack();
|
||||
|
||||
// Update object directly like a regular TS class instance.
|
||||
console.log(monsterobj.name);
|
||||
monsterobj.name = "Bob";
|
||||
|
||||
// Serialize into new flatbuffer.
|
||||
let fbb = new flatbuffers.Builder(1);
|
||||
Monster.finishMonsterBuffer(fbb, monsterobj.pack(fbb));
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
## Text parsing FlatBuffers in TypeScript
|
||||
|
||||
There currently is no support for parsing text (Schema's and JSON) directly
|
||||
from TypeScript.
|
||||
Reference in New Issue
Block a user