Compare commits

...

212 Commits

Author SHA1 Message Date
Wouter van Oortmerssen
40b03519c1 Updated Xcode project for v7 2015-10-28 12:07:28 -07:00
Wouter van Oortmerssen
d236dea13d Improved C++ asserts for nesting and not finishing buffers.
Change-Id: I82a392bd262b13e978df748bc54b7ac43aec1e15
Tested: on Linux.
2015-10-28 11:57:16 -07:00
Stewart Miles
ed88f7de96 Improved build rule generation for Android flatbuffer headers.
* Added the ability to create a build target for generated headers.
* Made it possible for generated header targets to depend upon each
  other or arbitrary build targets.

Tested:
Verified some pretty complex libraries with numerous flatbuffer schema
dependencies build using this macro on Linux with the NDK.
Bug: 25188384

Change-Id: I846855a50808e58c34cdf7086e93e7ea0df69e0d
2015-10-22 13:16:45 -07:00
Robert
07478a6700 Merge pull request #204 from layzerar/fix_struct_comment
fix comment generation of struct
2015-10-20 13:25:53 -07:00
Wouter van Oortmerssen
48ff729477 Added assert for referring to 0 offsets.
Change-Id: I7c04d934bfacd4aeaa2ba476b934dd3a62d4fc0e
Tested: on Linux.
2015-10-20 09:36:35 -07:00
Wouter van Oortmerssen
7c60937806 Added -M flatc flag to the documentation.
Change-Id: Ie19af91ec5bf0b65297cba58c124bceaa58fd73e
2015-10-19 17:05:42 -07:00
Wouter van Oortmerssen
ace304513f Fixes for JS generator in Xcode 2015-10-19 16:05:39 -07:00
Wouter van Oortmerssen
1917e577a2 Fixes for JS generator in VS 2015-10-19 15:55:28 -07:00
Wouter van Oortmerssen
9c9fce96c7 Vector of structs were not being verified correctly.
Because they are represented as `const T *` in the Vector template,
the sizeof(const T *) was accidentally used instead of sizeof(T).

Change-Id: Ib4dc73e1d21396ba2e30c84e5e229c4147204bb1
Tested: on Linux.
2015-10-19 14:11:13 -07:00
Wouter van Oortmerssen
525130765a Merge pull request #257 from evanw/javascript
Add support for JavaScript code generation with Google Closure Compiler type annotations
2015-10-19 12:49:16 -07:00
Wouter van Oortmerssen
d890ef9e20 Merge pull request #298 from evolutional/master
Ported some of the python fuzz tests to C#
2015-10-19 11:11:05 -07:00
Wouter van Oortmerssen
9f69d79430 Merge pull request #296 from prideout/master
Fix minor typos in the Python documentation.
2015-10-19 10:40:16 -07:00
evolutional
9d66af6efc Ported some of the python fuzz tests to C#
* Refactored the test runner to use attribute based test discovery
* Ported value and vtable/object fuzzing tests from python to C#
2015-10-18 17:08:39 -04:00
Philip Rideout
8f1729f7df Fix minor typos in the Python documentation. 2015-10-17 17:48:06 -07:00
Evan Wallace
4bef5e89c4 Add UTF-8 support to the JavaScript API
This adds an optional argument to generated getters for string fields to
specify the encoding type and overloads the createString() function. It's
now possible to use either JavaScript UTF-16 string objects or C-style
UTF-8 byte arrays (Uint8Array) for string data.
2015-10-14 23:07:40 -07:00
Evan Wallace
79222bf100 Update monster_test_generated.js baseline after rebase 2015-10-14 23:06:58 -07:00
Evan Wallace
c3bfefca57 change DataView to bit twiddling for JavaScript 2015-10-14 21:15:57 -07:00
Evan Wallace
00fd394d23 remove unnecessary return 2015-10-14 21:15:57 -07:00
Evan Wallace
e1e8d53df6 Add low-level fuzzer, fix 64-bit issue it found 2015-10-14 21:15:57 -07:00
Evan Wallace
57a6dd472f Add a test for JavaScript UTF-8 <=> UTF-16 conversion
JavaScript uses UTF-16 but FlatBuffers uses UTF-8. This commit tests the code
that does the conversion between the two encodings. The last entry in the array
is tricky because each code point actually requires two UTF-16 code units,
unlike the other examples. The current JSON output of flatc actually handles
this case incorrectly (it generates invalid JSON with UTF-8 code units). The
generated JavaScript code passes these tests fine, however.
2015-10-14 21:15:57 -07:00
Evan Wallace
224e33ed09 Add support for JavaScript code generation
This adds a JavaScript language target. The generated JavaScript uses Google
Closure Compiler type annotations and can be compiled using the advanced
compilation mode, which performs type checking and optimizations such as
inlining and dead code elimination. The generated JavaScript also exports all
generated symbols for use with Node.js and RequireJS. This export behavior
can be turned off with the --no-js-exports flag for use with Google Closure
Compiler.
2015-10-14 21:15:57 -07:00
Wouter van Oortmerssen
94680f5483 Added support for imports and many other .proto features.
Change-Id: I6600021b7ec8c486794349511232c3e604421c5b
Tested: on Linux.
2015-10-13 14:01:55 -07:00
Robert
b4db88808f Merge pull request #286 from tguo-aa/fix-278
Add self.assertNotNested() in CreateString
2015-10-08 00:23:26 -07:00
tguo-aa
d9db48257b Add self.assertNotNested() in CreateString
And also add a test case.
If you try to nest CreateString you will get a clear exception.
2015-09-29 08:34:10 +08:00
Wouter van Oortmerssen
e1e1bced08 Fixed LoadFile on Windows 2015-09-28 16:24:34 -07:00
Wouter van Oortmerssen
b56add9520 Improved documentation with links to videos, articles and who uses it.
Change-Id: I62de6b7008e397a5043d47f014a7acd83ee64740
2015-09-28 10:49:01 -07:00
Wouter van Oortmerssen
2abe24b9dd Made .proto parsing understand nested declarations.
Bug: 24401812
Change-Id: I196a03b8c5ef0bcd3c26178239c764e40ca1950d
Tested: on Linux.
2015-09-28 09:48:41 -07:00
Wouter van Oortmerssen
a35c32e30f Merge pull request #282 from google/fix-277
Fix 32bit-system integer overflow (test only)
2015-09-25 14:54:50 -07:00
Robert
781c39c708 Fix 32bit-system integer overflow (test only)
For #277
2015-09-25 13:57:17 -07:00
Wouter van Oortmerssen
ff9e539cc5 Merge pull request #280 from alexames/master
Removed call to pop_back on std::string.
2015-09-25 10:38:50 -07:00
Wouter van Oortmerssen
feb4816610 Fixed .proto translation making scalars into required fields.
Change-Id: If414d156b4e9bc7fead5f131823b2c419cdc4e2c
Tested: on Linux.
2015-09-25 09:21:31 -07:00
Alex Ames
703b790939 Removed call to pop_back on std::string.
The pop_back function was added to strings in C++11 and it appears not
all compilers we target support it. The call to pop_back has been
replaced with a call to erase.

Tested on Linux. All unit tests pass.
2015-09-24 14:19:32 -07:00
Wouter van Oortmerssen
811a5c3389 Merge pull request #274 from cogumbreiro/master
Fix an out-of bounds read when the element is bigger than the buffer.
2015-09-23 12:37:45 -07:00
Robert
2736711d67 Merge pull request #275 from brunoqc/patch-1
Remove duplicate Go test
2015-09-21 15:13:24 -07:00
Bruno Bigras
edb3b9c307 Remove duplicate Go test 2015-09-21 17:51:16 -04:00
Tiago Cogumbreiro
477fedccd4 Fix an out-of bounds read when the element is bigger than the buffer.
Ensure the size of the buffer being checked is bigger than the element
of the buffer being checked. The buffer can be triggered when, for
example, the buffer is of length zero and we are checking for:

    Verify<uoffset_t>(buf_)

The condition above should fail.
2015-09-18 20:38:47 -05:00
Björn Reimer
5de28c74f9 serialize boolean in JSON to "true/false" instead of "0/1"
Change-Id: I90cf519c00eaf9ccd9fcab8035a91b9205587c3b
2015-09-16 10:31:38 -07:00
Wouter van Oortmerssen
44261ccdf1 Merge pull request #271 from vijairaj/scoped-enums
Implemented option --scoped-enum for C++ generator
2015-09-16 10:14:49 -07:00
vijairaj
c02b16e195 Implemented option --scoped-enum for C++ generator
This generates C++11 style scoped and strongly typed enums.
Enabling this option also implies --no-prefix.
2015-09-15 16:13:52 +05:30
Wouter van Oortmerssen
169df65df4 Merge pull request #266 from kadirahq/fix-travis-osx
Fix before_install step on .travis.yml file for osx
2015-09-14 17:50:29 -07:00
Wouter van Oortmerssen
af1487bcfb Clarified use of unions in C++.
Change-Id: I9654e0c6a45457c8e150f07dd5f7b39539266f9e
2015-09-14 11:00:12 -07:00
Jason Sanmiya
5db12e9907 Fix Visual Studio 2012 build warning.
Also, remove execute permissions on several source files.

Tested: Builds on Visual Studio 2012, and Linux.

Change-Id: Idaacb2ae8eba98ce2974218c2ab840e97a1d67e9
2015-09-11 14:35:34 -07:00
Wouter van Oortmerssen
dff07b6f31 Merge pull request #269 from teemuandersen/master
Add @SuppressWarnings("all") to generated Java classes
2015-09-11 14:23:53 -07:00
Teemu Andersén
5dd8795a10 Add @SuppressWarnings("unused") to generated Java classes
Usually generators add @SuppressWarnings("all") to generated Java
classes to prevent IDEs from complaining about unused imports, etc.
Solving used imports seems pretty hard with current generator logic so
IMO this is the next best thing.

Yes, it’s appended to import block but that is the block that gives
these warnings in the first place.
2015-09-11 23:33:55 +03:00
Muhammed Thanish
be503cb0f2 Fix OSX related errors on travis
- Install g++ and cmake only on Linux.
 - Use biicode only on Linux machines.
2015-09-11 22:15:27 +05:30
Wouter van Oortmerssen
01e06b69a5 Improved the speed of LoadFile() in debug mode.
Apparently, istreambuf_iterator has a lot of overhead.

Change-Id: I804f4e8f2b380b05e939edefe0e1e88cd10e920c
Tested: on Linux.
2015-09-09 12:56:23 -07:00
Wouter van Oortmerssen
782e05de55 Fixed Android builds on Windows (generated schema rules).
include.mk causes absolute paths to be generated, which doesn't
work on Windows (make doesn't like : in paths).

Change-Id: Ib06c9581620bde1e8452e0dd887d3986d517c4f5
Tested: on Windows, Linux.
2015-08-28 14:42:13 -07:00
Melvi Ts
82a71b18f1 Python: Fix potential code generation issue of documentation comment. 2015-08-28 23:48:28 +08:00
Wouter van Oortmerssen
aeff09d724 Fixed a clang warning about signed shifts.
Change-Id: I7c2bf87972ee0ba6811d6ed42e13300bff90e36f
2015-08-26 16:47:59 -07:00
Björn Reimer
a5c511576f Fix conversion of floats when generating json
Change-Id: I01def42eda9b70308046c048099d85db8f889ede
2015-08-26 14:06:29 -07:00
Maxim Zaks
ac10873e26 fixed code generator for array of bools
Change-Id: I3cdd801b641bf180222203a37634598350d340e3
2015-08-19 14:39:06 -07:00
Robert
9689d38bef Merge pull request #235 from FrankStain/master
2Gb buffer size checks fixed for Python Builder
2015-08-19 23:22:20 +02:00
Wouter van Oortmerssen
d06b2736aa Merge pull request #248 from aeneid/master
Added Java and C# mutators
2015-08-19 11:43:22 -07:00
Maor Itzkovitch
a0f3fb44e7 rebase 2015-08-19 21:32:08 +03:00
Wouter van Oortmerssen
d97f628703 Clarified choice of types in Java/C# codegen.
Change-Id: I1f094f350145d13b12cbe367bae7c623cfbbd8d3
2015-08-19 11:08:53 -07:00
Maor Itzkovitch
fb7f27a7c9 Merge remote-tracking branch 'upstream/master' 2015-08-15 14:48:59 +03:00
Maor Itzkovitch
7bfed4b29a added vector mutators 2015-08-15 14:48:47 +03:00
Wouter van Oortmerssen
a170b69d5d Added authors to support.md
Change-Id: I8f12e60d29a1c587d991bf64011bdf4a4b0d7e5b
2015-08-14 14:07:54 -07:00
Frank Stein
33e4ab65e9 Incorrect buffer size check fixed. 2015-08-14 00:50:39 +03:00
Wouter van Oortmerssen
201699288b Added a platform / language / feature support matrix to docs.
This is just a start, will need to be extended.

Change-Id: I5a9ad671911942dcb83fdd2bae537deed751cbfd
2015-08-12 12:07:43 -07:00
Wouter van Oortmerssen
e9202d85bd Add missing Python files from type cast commit.
Change-Id: I800119d8fe19f4c3e95772aba629ef8b2deb9e4b
2015-08-12 10:17:10 -07:00
Wouter van Oortmerssen
9a1ab5006f Merge pull request #253 from mormegil-cz/issue-252
[Issue 252] Add type cast for default enum values in C#
2015-08-12 09:21:21 -07:00
Mormegil
25c99273d3 [Issue 252] Add type cast for default enum values in C#
When creating a “CreateXxx(...)” method for a “simple table” type,
enum-type fields with a non-zero default must have an explicit
cast for the respective argument default value, because in C#,
there is an implicit cast from int to an enum only for 0.

Also, added an example of such type into the example monster_test
type, so that we test this feature.
2015-08-11 18:07:38 +02:00
Frank Stein
7bcbb19569 MaxBufferSize() changed to MAX_BUFFER_SIZE. Also buffer will never grow more MAX_BUFFER_SIZE. 2015-08-07 21:19:02 +03:00
Maor Itzkovitch
b062af4c8c rebased fork 2015-08-07 18:59:59 +03:00
Maor Itzkovitch
0956719726 added comments 2015-08-07 18:35:28 +03:00
Maor Itzkovitch
766eaad4e7 added a successful test run console print 2015-08-07 18:12:19 +03:00
Maor Itzkovitch
3a74c33ba5 removed console print from code 2015-08-07 10:57:37 +03:00
Maor Itzkovitch
e4c3bf3d2c fixed C# bytebuffer put methods 2015-08-07 10:51:15 +03:00
Maor Itzkovitch
7196c36842 begin to correct C# bytebuffer behavior 2015-08-07 09:05:08 +03:00
Wouter van Oortmerssen
e151160560 Added a link to other FPL libraries to the main page.
Change-Id: I45362806df6d4eff0b0b7521b7caf42c2ec0515c
2015-08-05 17:32:14 -07:00
Jon Simantov
dac63a227e Fix missing break statement in SetAnyValueS case.
Causing SetAnyValueS to treat all scalars as integers.

Change-Id: Ib467b255e7f32a1478180a91e65def31676399eb
2015-08-05 16:06:47 -07:00
Wouter van Oortmerssen
986b52d849 Merge pull request #247 from stewartmiles/master
Clarified the use of the deprecated flatc --gen-includes flag.
2015-08-05 13:58:17 -07:00
Wouter van Oortmerssen
45cc503bbd Changed maximum force_align to match the C++ code generator.
Change-Id: I7df2b0172f5de6f7bdbd8778361794004cd06062
Tested: on Linux.
2015-08-05 13:56:31 -07:00
Stewart Miles
6aeb09b297 Clarified the use of the deprecated flatc --gen-includes flag.
Also, removed the flag from the Android makefile.

Tested:
Verified flatc builds successfully on Linux and regenerated the docs.

Change-Id: I7140daa10b7cb9a29b5ffd63c6b20489e72a5899
2015-08-05 13:26:13 -07:00
Wouter van Oortmerssen
210c0ece54 Fixed VS project file.
Tested: on Windows.
2015-08-03 17:56:09 -07:00
Wouter van Oortmerssen
ad84b5b8fa Fixed AddFlatBuffer using wrong buffer length.
Also made the Xcode project link.

Tested: on OS X.
2015-08-03 17:39:47 -07:00
Wouter van Oortmerssen
7101224d86 Reworked reflection.h to be more general.
e.g. support generic reading/writing from structs/vectors etc.

Change-Id: I2eb6e24db088a72da444d5c8df7e506e53d5bc2d
Tested: on Linux.
Bug: 22660837
2015-08-03 16:42:05 -07:00
Maor Itzkovitch
6be146d67f small refactor to GenSetter method 2015-08-01 19:28:22 +03:00
Maor Itzkovitch
f706a42951 extend java tests 2015-08-01 19:14:12 +03:00
Maor Itzkovitch
e24afd838a extended scalar mutator support 2015-08-01 19:08:22 +03:00
Maor Itzkovitch
81c2b185ef support for scalar mutators 2015-08-01 12:38:47 +03:00
Wouter van Oortmerssen
0e064e415b Fixed small inaccurracies in the schema grammar.
Change-Id: I6e9e66c3d7d67c54617bc892f612b7341bebd7e0
2015-07-31 12:26:23 -07:00
Wouter van Oortmerssen
4998ad7365 Added support for adding new tables/strings to an existing FlatBuffer.
As part of the reflection support.

Change-Id: Ie0a8e233bca7dffa4cff7e564660035d97ff8902
Tested: on Linux.
Bug:22637258
2015-07-31 09:44:25 -07:00
Wouter van Oortmerssen
9a30d3d0df Merge pull request #241 from RevenantX/master
[BREAKING CHANGE] Base type safety in C#. Clear FlatBufferBuilder in C#.
2015-07-29 11:36:03 -07:00
RevenantX
0b761ece4d default in switch. 2015-07-29 00:45:26 +03:00
RevenantX
01249c1d48 remove unused funciton. 2015-07-29 00:40:48 +03:00
RevenantX
588564d74f Base type safety in C#. Clear FlatBufferBuilder in C#. 2015-07-29 00:33:45 +03:00
Wouter van Oortmerssen
6e192fa408 Updated documentation to use new css style.
Change-Id: I05e2f8fd06026645a8e5da1703d757ad9de10b4f
Tested: on Linux.
2015-07-22 13:10:37 -07:00
Wouter van Oortmerssen
12ca3e054e Fixed compile error in older gcc's for trailing comma in enum.
Change-Id: I60f6da32fb2a30557fcf842624f68ca184f65e1f
Tested: on Linux.
2015-07-22 12:35:40 -07:00
Wouter van Oortmerssen
62af533820 Merge pull request #237 from jonsimantov/master
Add optional root table to SetString and ResizeVector, when your Flatbuffer isn't the schema's root type.
2015-07-22 12:03:39 -07:00
Jon Simantov
b56020ad3b Updated pointer syntax to be consistent in SetString, etc. 2015-07-22 11:46:14 -07:00
Jon Simantov
6e160f4c59 Use Object* for optional root_table in SetString/ResizeVector.
Was previously using table name, but no reason not to just let the
calling code worry about getting the object.
2015-07-22 10:56:41 -07:00
Wouter van Oortmerssen
07e77ad0ff Merge pull request #238 from martell/master
Add a libflatbuffers for other projects to use
2015-07-22 10:02:11 -07:00
Wouter van Oortmerssen
b6380aceac Fixed reflection resizing code not checking strings in vectors.
Change-Id: I4081160a8281939ab282d7914ae396276c767882
Tested: on Linux.
2015-07-22 09:57:35 -07:00
Martell Malone
79d3cb6a6c Add a libflatbuffers for other projects to use 2015-07-22 17:53:19 +01:00
Jon Simantov
a4de6de700 Add optional root table name to SetString and ResizeVector.
This allows you to use these functions with a flatbuffer whose root
table type does't correspond with the root table type of the schema.

If you don't specify the table name, it will use the root table from
the schema by default (mimicing the current behavior).
2015-07-22 02:01:56 -07:00
Frank Stein
a1d801c375 2Gb buffer size checks fixed for Python Builder 2015-07-14 00:10:11 +03:00
Wouter van Oortmerssen
f66e93cd8d Merge pull request #233 from aeneid/master
fix for parameter name clash in generated structs
2015-07-13 13:27:54 -07:00
aeneid
59a09cb1d0 comment update 2015-07-13 22:58:54 +03:00
Maor Itzkovitch
c23c620d26 applied struct parameter fix to Go and Python generated classes 2015-07-13 22:53:59 +03:00
Wouter van Oortmerssen
4798456df6 Fixed type specifiers in the grammar document.
Change-Id: Ia6b976f0eb6a99d710bcd09cb56339580ff69f5b
2015-07-13 10:31:10 -07:00
Maor Itzkovitch
147fbb4285 builder.put statements now use correct argument names 2015-07-13 20:00:48 +03:00
aeneid
a9ae9bdcab comment update 2015-07-12 22:12:58 +03:00
aeneid
f7d8102b35 Passed field name as prefix for nested structs
This pull request should fix #232.
Pass field name instead of struct name as nameprefix for nested structures. Continuously concatenate nameprefix arguments to support deeper nested structures.
2015-07-12 22:10:57 +03:00
Wouter van Oortmerssen
d0e9bc6a75 A few schema documentation fixes.
Change-Id: I140e1322fc1bfb3ab8012e00d8f3006ee2e7ce95
2015-07-08 17:49:49 -07:00
Wouter van Oortmerssen
d863df8683 Merge pull request #230 from aeneid/master
included stdio.h in include/flatbuffers/hash.h
2015-07-08 09:01:17 -07:00
aeneid
4834634766 Update flathash.cpp 2015-07-07 08:14:00 +03:00
aeneid
a4c893dbe2 Update hash.h 2015-07-07 08:13:08 +03:00
Wouter van Oortmerssen
8833255ed3 Merge pull request #227 from evanw/master
Round up allocation size to avoid misalignment (issue #226)
2015-07-06 13:32:44 -07:00
aeneid
fb5f9456e9 Merge pull request #1 from aeneid/aeneid-patch-1
added #include <stdio.h>
2015-07-05 20:27:20 +03:00
aeneid
0dacfbbfca added #include <stdio.h> 2015-07-05 19:50:50 +03:00
Evan Wallace
47aab78233 Round up allocation size to avoid misalignment (issue #226)
Before this change, requesting a large initial allocation could cause the
backing store to grow to an unaligned size. Since memory inside vector_downward
is relative to the end of the buffer, this then caused all memory in the buffer
to be misaligned and also misaligns any further loads and stores. Misaligned
loads and stores are undefined behavior and don't work in environments such as
emscripten (a JavaScript to C++ compiler).
2015-07-02 14:05:45 -07:00
Jon Simantov
185b9f9792 Allow customization of flatc cmdline arguments on Android.
On Android builds, set FLATBUFFERS_FLATC_ARGS to change the arguments
passed to the flatc cmdline. Do this in your Android makefile where
you include the flatbuffers include.mk (before or after).

For example FLATBUFFERS_FLATC_ARGS=--gen-mutable

The default value is --gen-includes although since that is deprecated
we could just make the default value blank.

Change-Id: I79fb35f50c3e21bbef18ad40ad3559cb026ffe8e
2015-07-01 11:46:19 -07:00
Wouter van Oortmerssen
21765bea2e Made warning settings in Xcode more aggressive.
Tested: on OS X.
2015-06-29 15:49:13 -07:00
Wouter van Oortmerssen
36c7e9a962 Fixed null root_table access in binary schema generation.
Change-Id: Ia2b7abc10bee52814e815befcad6a89697295d8f
Tested: on Linux.
2015-06-29 15:21:48 -07:00
Wouter van Oortmerssen
cb2b2be54e Reflection: generically copy (parts of) FlatBuffers.
Change-Id: Ief3f1507c003079eac90c2bb6c2abd64a80a0a34
Tested: on Linux.
2015-06-29 15:18:51 -07:00
Robert
1c152cc72a Merge pull request #222 from rw/go-update-panics
Panic when nesting strings. Test panic scenarios.
2015-06-29 18:10:44 -04:00
gwvo
d67661eb39 Merge pull request #224 from rubber-duck/master
Fixed argument value to correct type
2015-06-29 10:44:11 -07:00
gwvo
ea97e1b5e2 Merge pull request #223 from belm0/csharp_docs
Java/C-sharp docs: fix typo, clarify parser availability.
2015-06-29 09:55:38 -07:00
Rafael Munitić
dca3ccf5fd Fixed argument value to correct type 2015-06-26 21:28:39 +02:00
John Belmonte
ef7b3ed8f5 Java/C-sharp docs: fix typo, clarify parser availability. 2015-06-25 14:42:41 -07:00
rw
4d305f5922 Panic when nesting strings. Test panic scenarios.
Also add a new `insideObject` boolean to the Builder to track whether an
object is currently being constructed. This fixes a bug with objects
that have zero fields.
2015-06-24 11:53:44 -04:00
Wouter van Oortmerssen
1e6f8f5b8c Fixed possible crash from reference to non-static variable.
Change-Id: I1842098a7ef461e2e92dd35d79d8ca303e814867
Tested: on Linux.
2015-06-22 10:23:42 -07:00
Wouter van Oortmerssen
c967515da5 Small improvements to the C++ API.
Change-Id: Ib30ffbbd140a8b82fe664129fa4e8c55836267f8
Tested: on Linux.
2015-06-17 17:17:01 -07:00
Wouter van Oortmerssen
576022c64b Changed VS flatc test settings to match Linux. 2015-06-17 10:27:05 -07:00
gwvo
eab9cfbec9 Merge pull request #217 from amoldeshpande/master
option to generate one file for C#
2015-06-17 10:10:50 -07:00
Amol Deshpande
ab4801a82e Merge branch 'master' of https://github.com/amoldeshpande/flatbuffers 2015-06-16 07:23:29 -07:00
Amol Deshpande
8df4b318bc Merge branch 'master' of https://github.com/google/flatbuffers
Conflicts:
	src/flatc.cpp
	src/idl_gen_general.cpp
2015-06-16 07:16:59 -07:00
amoldeshpande
8a98e9ad98 Merge pull request #3 from amoldeshpande/google-master
Merge pull request #2 from amoldeshpande/master
2015-06-15 21:00:40 -07:00
amoldeshpande
eee5628569 Merge pull request #2 from amoldeshpande/master
merge
2015-06-15 20:58:48 -07:00
Amol Deshpande
ad3fd6ecbf merge 2015-06-15 20:26:10 -07:00
Wouter van Oortmerssen
622b8d05cf Fixed warnings on Windows 2015-06-15 17:35:07 -07:00
Wouter van Oortmerssen
5faa0ab1be Removed unused variable.
Tested: on OS X.
2015-06-15 15:57:48 -07:00
Wouter van Oortmerssen
81312c2128 Initial reflection and resizing functionality.
Tested: on Linux.

Change-Id: I8f7bccf9b1ad87fea788f85e23fa69435758feca
2015-06-15 15:53:10 -07:00
Wouter van Oortmerssen
1808337adc Make generating dependent include files for C++ the default.
--gen-includes is now deprecate but still accepted.
--no-includes can be used instead when needed.

Change-Id: I2cd46d193032b9b7c31c76c6f655e9333d3a393a
Tested: on Linux.
2015-06-15 13:09:22 -07:00
Wouter van Oortmerssen
5f091c46ce Allowing _ as first character of identifiers in .fbs/.json.
Change-Id: Ie2cb42632f6a907a38e10b2c9be1536cf330b2fa
Tested: on Linux.
2015-06-15 13:09:22 -07:00
gwvo
a96bfdb369 Merge pull request #219 from jesta88/master
Fix for #218 - Check empty namespace in general generator
2015-06-15 12:04:58 -07:00
Jeremie St-Amand
ad3ebb110b Follow Google code standards 2015-06-14 13:04:04 -04:00
Jeremie St-Amand
929105432c Namespace now optional for general generator
If you have a schema with no namespace, the resulting C#/Java won't have
an erroneous empty namespace keyword.
2015-06-14 12:56:48 -04:00
Amol Deshpande
40fffc8fff fix code formatting and bug with losing enums when using --gen-onefile 2015-06-13 08:55:24 -07:00
Amol Deshpande
2f76141813 option to generate one file for C# 2015-06-06 19:35:12 -07:00
Wouter van Oortmerssen
932b22f043 Added clang & OS X to .travis 2015-05-27 18:32:49 -07:00
Wouter van Oortmerssen
ecf5a6a580 Added --defaults-json to output fields at default value.
Normal behavior is to not output fields that happen to have
the default value, since those will be reproduced anyway
when turned into a FlatBuffer binary. This however can be problematic
when using JSON to interop with other system since they might not
know this default value. This flatc option (and also flag
to GenerateText) will force those fields to be output anyway.

Tested: on Linux.
2015-05-27 16:42:15 -07:00
Wouter van Oortmerssen
788acb08d4 Added GitHub link to start of documentation page. 2015-05-27 15:21:10 -07:00
Wouter van Oortmerssen
ddb1d5ffe4 Added a #define for running tests without file access.
Change-Id: Ib2b7aa8a5641cf73fa0d6f2000db7fdd1aabab66
Tested: on Linux.
2015-05-27 14:00:08 -07:00
Wouter van Oortmerssen
7ba29dbe41 Small readability improvements to recent commits.
Change-Id: I290c33c475f7b019ab0d3c571245d27351d22fa1
Tested: on Linux.
2015-05-20 16:21:22 -07:00
Wouter van Oortmerssen
3b070310f0 Fixed -Wunused-result warning.
Change-Id: Iea5fab66047ac0a5057a743dbb1fdb27c063188c
Tested: on Linux.
2015-05-20 16:21:22 -07:00
Wouter van Oortmerssen
fbe085601b Java: Allow access to the underlying ByteBuffer from a table.
Change-Id: Id268e35de207c25c809a09071b81eea873c9123e
Tested: on Linux.
2015-05-20 16:21:22 -07:00
gwvo
36f9b1ec91 Merge pull request #207 from zachreizner/header
Add include for cstdlib for std::bsearch definition
2015-05-20 15:01:53 -07:00
Zach Reizner
7bcd99451f Add include for cstdlib for std::bsearch definition 2015-05-20 14:54:20 -07:00
Robert
2535a3aa3a Merge pull request #206 from rw/go-faster-string-writing
Go: CreateString now needs zero allocs.
2015-05-20 14:37:53 -07:00
rw
0894c25f2c Improve comment for unicode check. 2015-05-20 14:19:49 -07:00
rw
7810fb9ce4 use escape codes here for non-unicode editors 2015-05-20 13:42:51 -07:00
rw
c127cf78c2 Go: CreateString now needs zero allocs.
Big speed boost for the typical use case of building with strings.
2015-05-20 12:00:44 -07:00
gwvo
6fffa2a14d Merge pull request #198 from zulli73/master
Fixed endianness Vector's begin() and end()
2015-05-20 09:30:10 -07:00
gwvo
2b02d330fd Merge pull request #205 from zachreizner/fb_bsearch
Use std::bsearch in LookupByKey for binary search
2015-05-18 17:36:51 -07:00
Zach Reizner
c8f1682e07 Use std::bsearch in LookupByKey for binary search 2015-05-18 17:29:51 -07:00
gwvo
f64e040896 Merge pull request #201 from rw/python-docs-and-packaging
Update Python docs and package description
2015-05-18 09:33:30 -07:00
rw
339376ba67 Regenerate Doxygen docs to add Python usage page. 2015-05-15 12:23:10 -07:00
rw
7a1b77322b Update Python package description: license, descriptions. 2015-05-15 12:20:20 -07:00
Wouter van Oortmerssen
60b6ca5850 fixed xcode build files 2015-05-13 17:45:20 -07:00
Wouter van Oortmerssen
b8681d8031 fixed the windows build files 2015-05-13 17:26:20 -07:00
Robert
f8139b05cb Merge pull request #112 from rw/python23-read-write-gen-port
Port FlatBuffers to Python.
2015-05-13 11:20:09 -07:00
rw
776c4eb965 use EnsureDirExists from util.h instead of mkdir 2015-05-13 10:54:02 -07:00
rw
2746aabcf1 fix string catenation 2015-05-13 10:50:47 -07:00
Raphael Zulliger
04a06781f5 Fixed endianness Vector's begin() and end() 2015-05-13 16:25:56 +02:00
rw
48dfc69ee6 Port FlatBuffers to Python.
Implement code generation and self-contained runtime library for Python.

The test suite verifies:
  - Correctness of generated Python code by comparing output to that of
    the other language ports.
  - The exact bytes in the Builder buffer during many scenarios.
  - Vtable deduplication correctness.
  - Edge cases for table construction, via a fuzzer derived from the Go
    implementation.
  - All code is simultaneously valid in Python 2.6, 2.7, and 3.4.

The test suite includes benchmarks for:
  - Building 'gold' data.
  - Parsing 'gold' data.
  - Deduplicating vtables.

All tests pass on this author's system for the following Python
implementations:
  - CPython 2.6.7
  - CPython 2.7.8
  - CPython 3.4.2
  - PyPy 2.5.0 (CPython 2.7.8 compatible)
2015-05-12 15:40:29 -07:00
Robert
4d213c2d06 Merge pull request #165 from rw/go-faster
Go speed improvements
2015-05-12 14:53:31 -07:00
gwvo
361bfb6764 Merge pull request #189 from pjulien/188
Issue #188
2015-05-11 14:07:40 -07:00
gwvo
3f96eead4c Merge pull request #192 from Jiboo/fix190
Added a default constructor for Java's FlatBufferBuilder.
2015-05-11 13:59:22 -07:00
Wouter van Oortmerssen
8896587faf Fixed schemas inheriting namespace from included schemas.
Change-Id: Ib561430b235eddf4bfe20f68409e1dfdb359ef2b
Tested: on Linux.
2015-05-11 10:55:22 -07:00
Jean-Baptiste "Jiboo" Lepesme
9fa3e2f387 Added a default costructor for Java's FlatBufferBuilder.
Default's size of 1024b like in cpp. Fixes #190.
2015-05-11 19:17:01 +02:00
rw
e5c21ec666 invoke many fewer growth events 2015-05-09 16:32:26 -07:00
rw
e11da87a24 gofmt 2015-05-09 16:10:03 -07:00
rw
3dd54424c0 remove remaining allocs during build 2015-05-09 16:07:11 -07:00
rw
5d68493df4 update CheckClash for string accesses 2015-05-09 15:37:13 -07:00
pjulien
d322eec3c3 Issue #188
When accessing the array directly of a byte buffer, need to offset
by ``arrayOffset``
2015-05-09 14:08:28 -04:00
Mormegil
221193eaa2 Union accessors in C# should use generic type for the table
When accessing a union field, we should return the same object type
as was given to the method, i.e. the parameter should have a generic
type for any Table-derived type. This way, we do not need to make
superfluous casts (which also reduce type safety) like

var myUnionType = (MyUnionType)buff.GetUnionField(new MyUnionType());

when we can do just
var myUnionType = buff.GetUnionField(new MyUnionType());

Change-Id: Idac1b638e46cc50b1f2dc19f10741481202b1515
2015-05-08 16:21:54 -07:00
pjulien
f7d24f60a2 set version for next dev cycle
Change-Id: I17a7896e257c0ab7e4cd1b22c928d4cee21fbf11
2015-05-08 16:21:54 -07:00
pjulien
e5a1a3129d Initially discussed in #178.
Allows adding an already encoded UTF-8 string directly without
having to convert to a ``String`` first.

Change-Id: I23f9c738eec18fd35f4c14f58dbd0f6cf0970dc7
2015-05-08 16:21:54 -07:00
Wouter van Oortmerssen
39833d7cf0 Added namespaced way to refer to types in schemas.
Also made proper namespacing work for enums.

You can now say namespace.MyTable as the type when declaring
a field that refers to a type in a different namespace.

Previously, it would work just referring to MyTable, however
with the recent commit fixing namespaced types this now
is ambiguous.

Change-Id: Ieaa3f4ac1662b8c4dc1f16e1898ea3cdb02e10fd
Tested: on Linux.
2015-05-08 16:21:53 -07:00
Brett Cooley
ecb27817ca Merge "Initial support for propagating namespaces from schema files to generated code" into ub-games-master 2015-05-08 19:52:54 +00:00
Jason Sanmiya
f59bfdd084 Add missing newline in help text for flatc.
Tested: Help text displays correctly now.
Change-Id: Ibbdc810ae41e24321860879064bdc64f78a67cb9
2015-05-07 10:30:34 -07:00
Mormegil
0ee1b99c5d [BREAKING CHANGE] Field accessors should use property getters in C#
In C#, plain field accessors should not be nonparametric methods
but should be standard property getters.

The accessor methods with parameters were renamed to `GetXxx`
because a method cannot be named identically to a property.

Also, `ByteBuffer.Position`, `FlatBufferBuilder.Offset` and
`FlatBufferBuilder.DataBuffer` are now properties instead
of nonparametric accessor methods, for more idiomatic C# style.

This is a breaking change, all client C# code accessing these
fields needs to be changed (i.e. remove those `()` or add the
`Get` prefix).

Issue: #77
Change-Id: Iaabe9ada076e5ea2c69911cf6170fdda2df3487e
2015-05-06 11:55:07 -07:00
yinlei
a50711ad13 Fix u_int8_t to uint8_t
Change-Id: I475ef9454f51f1b7ec2a7f9086d711359456677a
2015-05-06 11:29:07 -07:00
Brett Cooley
249f71a12b Initial support for propagating namespaces from schema files to generated code
Change-Id: Ifc10c54845ea7553586d1896d509314d68e9ab0f
2015-05-05 17:10:53 -07:00
Wouter van Oortmerssen
1d138fbe07 Merge "Added extra checks for reading binaries in flatc" into ub-games-master 2015-05-04 21:02:00 +00:00
Wouter van Oortmerssen
a0bf238b09 Merge changes I2de7d14d,I56392340 into ub-games-master
* changes:
  Added accessor for file_extension in generated code.
  Added missing --gen-mutable to CMakeLists.txt
2015-05-04 21:00:43 +00:00
Wouter van Oortmerssen
c49c6da803 Added extra checks for reading binaries in flatc
By default, disallow reading binaries that do not correspond to
the schema file_identifier. Override with --raw-binary

Change-Id: I24822c0e4c80dab4e5a238ae2b6e601a09025c27
Tested: on Linux.
2015-05-04 13:38:20 -07:00
Wouter van Oortmerssen
37e6efe1f9 Added accessor for file_extension in generated code.
Change-Id: I2de7d14dbb1f7b8f81022dd2c9da65060ae49300
Tested: on Linux.
2015-05-04 13:38:20 -07:00
Wouter van Oortmerssen
d4d7a84e11 Added missing --gen-mutable to CMakeLists.txt
Change-Id: I56392340de4439d05fa8f06a7336ff72c6f9346d
Tested: on Linux
2015-05-04 13:38:19 -07:00
Jason Sanmiya
fc7e8af55e Merge "Fix bug on flathash compilation option." into ub-games-master 2015-04-29 21:12:07 +00:00
Wouter van Oortmerssen
3ec5dddb00 Mutable FlatBuffers: in-place updates.
This commit contains the first step in providing mutable FlatBuffers,
non-const accessors and mutation functions for existing fields generated
from --gen-mutable.

Change-Id: Iebee3975f05c1001f8e22824725edeaa6d85fbee
Tested: on Linux.
Bug: 15777024
2015-04-29 10:58:45 -07:00
Jason Sanmiya
f47660f510 Fix bug on flathash compilation option.
Change-Id: Ib9d31d08daba7ce54b864417ae93bf479702861b
2015-04-28 15:44:10 -07:00
Mormegil
a8d6962ac2 Tolerate DOS-style EOL in IDL line comments
If an IDL file uses DOS-style EOLs (CR+LF), line comments need to
ignore the second linebreak character, otherwise, as is currently
the case, the parsed documentation comment includes a trailing `\r`
character, which is then output verbatim into the output source
code by flatc.

Change-Id: I39591631995a980622d20a4a32315178b33f18f6
2015-04-15 13:44:54 -07:00
franchuti688
23f75f598e added .travis.yml file (build with original and biicode building);
added bii-travis.sh and readme.md files; added build status section with travis and biicode build
systems

Change-Id: I93acd1ca9497416ade6293d63b5311c4c31b880f
2015-04-15 13:43:25 -07:00
Mormegil
e3b432cba8 Enums use native enums in C#
Enums should not be (badly) emulated with classes in C# but should
use native C# enums instead. Java implementation made an explicit
choice not to use the (more complex) Java enums, but C# enums are
just light-weight syntactic coating over integral types.

Fixes issue #171.

Change-Id: I9f4d6ba5324400a1e52982e49b58603cb7d7cca7
2015-04-13 10:40:30 -07:00
Advay Mengle
557c57eb9d Seal all classes in Java/C#
Makes enums/structs/tables unsubclassable (final or sealed) and
prevents instantiation of enum classes (which are solely static
constants).

Tested (Mac OS 10.10.2):
1. run flattests
2. cd tests && ../flatc -c monster_test.fbs && ../flatc -j
monster_test.fbs && ../flatc -g monster_test.fbs && ../flatc -n
monster_test.fbs  # Note deltas for C# and Java.
3. ./JavaTest.sh

**Breaking api change**

Change-Id: Ie008c941c36d212690da58ddc72c9b228eb7a093
2015-04-10 11:20:19 -07:00
Joël Lamotte
9d368deb05 Fixed: Readme version is not up to date
Change-Id: Ie44419026eca94bce0a2857abef95a82e78cfc3e
2015-04-06 11:44:22 -07:00
Ben Harper
8b99bf614c Add byte slice accessor to Go code
Change-Id: I15cc8924d6607bd93068c762fd67e6088cfd9789
2015-04-06 11:44:22 -07:00
Kyle Jones
c4a3e2f6bd Always add additional space if no more is available
Change-Id: If08b2d839489d40e977de794b13584fa66ff32c1
2015-04-06 11:44:22 -07:00
INADA Naoki
803f9bba27 Fix typo in Benchmarks.md
Change-Id: I1c5fbd019cc233e1d551887ff5fb740420c18c2b
2015-04-06 11:44:21 -07:00
rw
d756efbf76 Reduce allocations when reusing a Builder.
Add the function `Reset` to the Builder, which facilitates reuse of the
underlying byte slice.
2015-04-02 19:33:00 -07:00
rw
ace7fa8094 Reduce allocations when building strings.
Builder has a new CreateByteString function that writes a
null-terimnated byte slice to the buffer. This results in zero
allocations for writing strings.
2015-04-02 18:22:13 -07:00
rw
f02646e357 Remove all string allocations during parsing.
Change the signature for 'string' getters and settings to use byte
slices instead of strings.
2015-04-02 11:56:55 -07:00
rw
0a3a09aaf3 Merge branch 'go-bytevector-getter' of github.com:benharper123/flatbuffers into go-faster 2015-04-02 11:47:17 -07:00
rw
796be3282c Benchmarks for building and parsing 'gold' data.
Identifies alloc-heavy codepaths.
2015-04-02 11:26:00 -07:00
rw
468124fb9b chmod GoTest.sh +x 2015-04-02 11:25:48 -07:00
Advay Mengle
3ad853630c Generate appropriate schema doc comments from .proto files
- Add parse handling of .proto struct and field doc comments (enums and
their values were already handled)
- Add FBS generation handling of doc comments for structs, their
fields, enums, and their values (requires linking idl_gen_general in
the test binary build)
- Tested using test.proto|golden with doc comments added.  Xcode run of
flattest passes.

Change-Id: Idff64dd8064afba227174ab77d2c7be22d006628
2015-04-01 17:17:39 -07:00
Advay Mengle
b8708beeec Generate Java doc comments in JavaDoc style
Tested by regenerating all tests/ generated sources; note that only
Monster.java changes.  Ran flattests as well.

Change-Id: I65b6ea7d208b0ccd6a0b34761162fed6ba391fc5
2015-04-01 17:10:52 -07:00
Ben Harper
8fb6c4f764 Add byte slice accessor to Go code 2015-04-01 16:47:10 +02:00
149 changed files with 13997 additions and 1028 deletions

12
.gitignore vendored
View File

@@ -19,7 +19,9 @@
**/*.dir/**
**/CMakeFiles/**
**/cmake_install.cmake
**/install_manifest.txt
**/CMakeCache.txt
**/CMakeTestfile.cmake
**/Debug/**
**/Release/**
build.xml
@@ -29,20 +31,30 @@ proguard-project.txt
linklint_results
Makefile
flatc
flatc.exe
flathash
flathash.exe
flattests
flattests.exe
flatsamplebinary
flatsamplebinary.exe
flatsampletext
flatsampletext.exe
snapshot.sh
tests/go_gen
tests/monsterdata_java_wire.mon
tests/monsterdata_go_wire.mon
tests/monsterdata_javascript_wire.mon
tests/unicode_test.mon
CMakeLists.txt.user
CMakeScripts/**
CTestTestfile.cmake
FlatBuffers.cbp
build/Xcode/FlatBuffers.xcodeproj/project.xcworkspace/**
build/Xcode/FlatBuffers.xcodeproj/xcuserdata/**
FlatBuffers.xcodeproj/
java/.idea
java/*.iml
java/target
**/*.pyc
.idea

30
.travis.yml Normal file
View File

@@ -0,0 +1,30 @@
language: cpp
os:
- linux
- osx
compiler:
- gcc
#- clang
env:
matrix:
- BUILD_TYPE=Debug BIICODE=false
- BUILD_TYPE=Release BIICODE=false
- BUILD_TYPE=Release BIICODE=true
- BUILD_TYPE=Debug BIICODE=true
global:
- GCC_VERSION="4.9"
before_install:
- if [ "$TRAVIS_OS_NAME" == "linux" ]; then sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test; fi
- if [ "$TRAVIS_OS_NAME" == "linux" ]; then sudo apt-get update -qq; fi
- if [ "$TRAVIS_OS_NAME" == "linux" ]; then sudo apt-get install -qq g++-$GCC_VERSION; fi
- if [ "$TRAVIS_OS_NAME" == "linux" ]; then sudo apt-get install -qq gcc-$GCC_VERSION; fi
- if [ "$TRAVIS_OS_NAME" == "linux" ]; then sudo ln -s -v -f $(which g++-$GCC_VERSION) /usr/bin/g++; fi
- if [ "$TRAVIS_OS_NAME" == "linux" ]; then sudo ln -s -v -f $(which gcc-$GCC_VERSION) /usr/bin/gcc; fi
script:
- if [ "$BIICODE" == "false" ]; then cmake -DCMAKE_BUILD_TYPE=$BUILD_TYPE . && make && make test; fi
- if [ "$BIICODE" == "true" ] && [ "$TRAVIS_OS_NAME" == "linux" ]; then ./biicode/support/bii-travis.sh $BUILD_TYPE; fi

View File

@@ -6,6 +6,7 @@ project(FlatBuffers)
option(FLATBUFFERS_CODE_COVERAGE "Enable the code coverage build option." OFF)
option(FLATBUFFERS_BUILD_TESTS "Enable the build of tests and samples." ON)
option(FLATBUFFERS_INSTALL "Enable the installation of targets." ON)
option(FLATBUFFERS_BUILD_FLATLIB "Enable the build of the flatbuffers library" ON)
option(FLATBUFFERS_BUILD_FLATC "Enable the build of the flatbuffers compiler" ON)
option(FLATBUFFERS_BUILD_FLATHASH "Enable the build of flathash" ON)
@@ -15,16 +16,25 @@ if(NOT FLATBUFFERS_BUILD_FLATC AND FLATBUFFERS_BUILD_TESTS)
set(FLATBUFFERS_BUILD_TESTS OFF)
endif()
set(FlatBuffers_Compiler_SRCS
set(FlatBuffers_Library_SRCS
include/flatbuffers/flatbuffers.h
include/flatbuffers/hash.h
include/flatbuffers/idl.h
include/flatbuffers/util.h
include/flatbuffers/reflection.h
include/flatbuffers/reflection_generated.h
src/idl_parser.cpp
src/idl_gen_text.cpp
src/reflection.cpp
)
set(FlatBuffers_Compiler_SRCS
${FlatBuffers_Library_SRCS}
src/idl_gen_cpp.cpp
src/idl_gen_general.cpp
src/idl_gen_go.cpp
src/idl_gen_text.cpp
src/idl_gen_js.cpp
src/idl_gen_python.cpp
src/idl_gen_fbs.cpp
src/flatc.cpp
)
@@ -35,13 +45,9 @@ set(FlatHash_SRCS
)
set(FlatBuffers_Tests_SRCS
include/flatbuffers/flatbuffers.h
include/flatbuffers/hash.h
include/flatbuffers/idl.h
include/flatbuffers/util.h
src/idl_parser.cpp
src/idl_gen_text.cpp
${FlatBuffers_Library_SRCS}
src/idl_gen_fbs.cpp
src/idl_gen_general.cpp
tests/test.cpp
# file generate by running compiler on tests/monster_test.fbs
${CMAKE_CURRENT_BINARY_DIR}/tests/monster_test_generated.h
@@ -72,9 +78,12 @@ set(FlatBuffers_Sample_Text_SRCS
if(APPLE)
set(CMAKE_CXX_FLAGS
"${CMAKE_CXX_FLAGS} -std=c++11 -stdlib=libc++ -Wall -pedantic -Werror -Wextra")
elseif(CMAKE_COMPILER_IS_GNUCXX OR "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
elseif(CMAKE_COMPILER_IS_GNUCXX)
set(CMAKE_CXX_FLAGS
"${CMAKE_CXX_FLAGS} -std=c++0x -Wall -pedantic -Werror -Wextra")
elseif("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
set(CMAKE_CXX_FLAGS
"${CMAKE_CXX_FLAGS} -std=c++0x -stdlib=libc++ -Wall -pedantic -Werror -Wextra")
endif()
if(FLATBUFFERS_CODE_COVERAGE)
@@ -84,18 +93,21 @@ if(FLATBUFFERS_CODE_COVERAGE)
endif()
if(BIICODE)
# Execute biicode building
include(CMake/biicode.cmake)
include(biicode/cmake/biicode.cmake)
return()
endif(BIICODE)
endif()
include_directories(include)
if(FLATBUFFERS_BUILD_FLATLIB)
add_library(flatbuffers STATIC ${FlatBuffers_Library_SRCS})
endif()
if(FLATBUFFERS_BUILD_FLATC)
add_executable(flatc ${FlatBuffers_Compiler_SRCS})
endif()
if(FLATBUFFERS_BUILD_FLATC)
if(FLATBUFFERS_BUILD_FLATHASH)
add_executable(flathash ${FlatHash_SRCS})
endif()
@@ -104,7 +116,16 @@ function(compile_flatbuffers_schema_to_cpp SRC_FBS)
string(REGEX REPLACE "\\.fbs$" "_generated.h" GEN_HEADER ${SRC_FBS})
add_custom_command(
OUTPUT ${GEN_HEADER}
COMMAND flatc -c -o "${SRC_FBS_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/${SRC_FBS}"
COMMAND flatc -c --no-includes --gen-mutable -o "${SRC_FBS_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/${SRC_FBS}"
DEPENDS flatc)
endfunction()
function(compile_flatbuffers_schema_to_binary SRC_FBS)
get_filename_component(SRC_FBS_DIR ${SRC_FBS} PATH)
string(REGEX REPLACE "\\.fbs$" ".bfbs" GEN_BINARY_SCHEMA ${SRC_FBS})
add_custom_command(
OUTPUT ${GEN_BINARY_SCHEMA}
COMMAND flatc -b --schema -o "${SRC_FBS_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/${SRC_FBS}"
DEPENDS flatc)
endfunction()
@@ -121,6 +142,9 @@ endif()
if(FLATBUFFERS_INSTALL)
install(DIRECTORY include/flatbuffers DESTINATION include)
if(FLATBUFFERS_BUILD_FLATLIB)
install(TARGETS flatbuffers DESTINATION lib)
endif()
if(FLATBUFFERS_BUILD_FLATC)
install(TARGETS flatc DESTINATION bin)
endif()

0
LICENSE.txt Executable file → Normal file
View File

View File

@@ -31,7 +31,9 @@ LOCAL_SRC_FILES := main.cpp \
../../tests/test.cpp \
../../src/idl_parser.cpp \
../../src/idl_gen_text.cpp \
../../src/idl_gen_fbs.cpp
../../src/idl_gen_fbs.cpp \
../../src/idl_gen_general.cpp \
../../src/reflection.cpp
LOCAL_LDLIBS := -llog -landroid
LOCAL_STATIC_LIBRARIES := android_native_app_glue flatbuffers
LOCAL_ARM_MODE := arm

View File

@@ -66,6 +66,8 @@ FLATBUFFERS_FLATC_PATH?=$(FLATBUFFERS_CMAKELISTS_DIR)
FLATBUFFERS_FLATC := $(FLATBUFFERS_FLATC_PATH)/Debug/flatc
endif
FLATBUFFERS_FLATC_ARGS?=
# Search for cmake.
CMAKE_ROOT := $(realpath $(LOCAL_PATH)/../../../../../../prebuilts/cmake)
ifeq (,$(CMAKE))
@@ -84,6 +86,14 @@ ifeq (,$(CMAKE))
CMAKE := cmake
endif
# Windows friendly portable local path.
# GNU-make doesn't like : in paths, must use relative paths on Windows.
ifeq (Windows,$(PROJECT_OS))
PORTABLE_LOCAL_PATH =
else
PORTABLE_LOCAL_PATH = $(LOCAL_PATH)/
endif
# Generate a host build rule for the flatbuffers compiler.
ifeq (Windows,$(PROJECT_OS))
define build_flatc_recipe
@@ -148,13 +158,24 @@ define flatbuffers_header_build_rule
$(eval \
$(call flatbuffers_fbs_to_h,$(2),$(3),$(1)): $(1) $(flatc_target)
$(call host-echo-build-step,generic,Generate) \
$(subst $(LOCAL_PATH)/,,$(call flatbuffers_fbs_to_h,$(2),$(3),$(1)))
$(hide) $$(FLATBUFFERS_FLATC) --gen-includes \
$(foreach include,$(4),-I $(include)) -o $$(dir $$@) -c $$<)
$(subst $(LOCAL_PATH)/,,$(call flatbuffers_fbs_to_h,$(2),$(3),$(1)))
$(hide) $$(FLATBUFFERS_FLATC) $(FLATBUFFERS_FLATC_ARGS) \
$(foreach include,$(4),-I $(include)) -o $$(dir $$@) -c $$<)
endef
# $(flatbuffers_header_build_rules schema_files,schema_dir,output_dir,\
# schema_include_dirs,src_files))
# schema_include_dirs,src_files,[build_target],[dependencies]))
#
# $(1) schema_files: Space separated list of flatbuffer schema files.
# $(2) schema_dir: Directory containing the flatbuffer schemas.
# $(3) output_dir: Where to place the generated files.
# $(4) schema_include_dirs: Directories to include when generating schemas.
# $(5) src_files: Files that should depend upon the headers generated from the
# flatbuffer schemas.
# $(6) build_target: Name of a build target that depends upon all generated
# headers.
# $(7) dependencies: Space seperated list of additional build targets src_files
# should depend upon.
#
# Use this in your own Android.mk file to generate build rules that will
# generate header files for your flatbuffer schemas as well as automatically
@@ -166,11 +187,21 @@ endef
define flatbuffers_header_build_rules
$(foreach schema,$(1),\
$(call flatbuffers_header_build_rule,\
$(schema),$(strip $(2)),$(strip $(3)),$(strip $(4))))\
$(schema),$(strip $(2)),$(strip $(3)),$(strip $(4))))\
$(foreach src,$(strip $(5)),\
$(eval $(LOCAL_PATH)/$$(src): \
$(foreach schema,$(strip $(1)),\
$(call flatbuffers_fbs_to_h,$(strip $(2)),$(strip $(3)),$(schema)))))
$(eval $(PORTABLE_LOCAL_PATH)$$(src): \
$(foreach schema,$(strip $(1)),\
$(call flatbuffers_fbs_to_h,$(strip $(2)),$(strip $(3)),$(schema)))))\
$(if $(6),\
$(foreach schema,$(strip $(1)),\
$(eval $(6): \
$(call flatbuffers_fbs_to_h,$(strip $(2)),$(strip $(3)),$(schema)))),)\
$(if $(7),\
$(foreach src,$(strip $(5)),\
$(eval $(PORTABLE_LOCAL_PATH)$$(src): $(strip $(7)))),)\
$(if $(7),\
$(foreach dependency,$(strip $(7)),\
$(eval $(6): $(dependency))),)
endef
endif # FLATBUFFERS_INCLUDE_MK_

0
android/jni/main.cpp Executable file → Normal file
View File

View File

@@ -1,5 +1,7 @@
# Biicode configuration file
[paths]
# Local directories to look for headers (within block)
include
[mains]
!android/*
[tests]
tests/*

21
biicode/README.md Normal file
View File

@@ -0,0 +1,21 @@
Biicode C/C++ dependency manager
=================================
[![Build Status](https://webapi.biicode.com/v1/badges/fenix/fenix/flatbuffers/master)](https://www.biicode.com/fenix/flatbuffers)
New with biicode? Check the [Getting Started Guide](http://docs.biicode.com/c++/gettingstarted.html).
How to build it?
------------------
Building it is too easy:
$ git clone git@github.com:google/flatbuffers.git
$ cd flatbuffers
$ bii init -L && bii build
$ ./bin/any_executable
Or run its tests:
$ bii test
You can check [the examples/flatbuffers block](https://www.biicode.com/examples/flatbuffers).

View File

@@ -1,6 +1,4 @@
# Initializes block variables
INIT_BIICODE_BLOCK()
set(BII_TESTS_WORKING_DIR ${CMAKE_CURRENT_SOURCE_DIR})
# Copying data files to project/bin folder
if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/samples")
file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/samples/monster.fbs"
@@ -14,9 +12,7 @@ if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/tests")
"${CMAKE_RUNTIME_OUTPUT_DIRECTORY}")
endif()
# Actually create targets: EXEcutables and libraries.
ADD_BIICODE_TARGETS()
string(REPLACE " " ";" REPLACED_FLAGS ${CMAKE_CXX_FLAGS})
target_compile_options(${BII_BLOCK_TARGET} INTERFACE ${REPLACED_FLAGS})
target_include_directories(${BII_BLOCK_TARGET} INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/include)
target_compile_options(${BII_BLOCK_TARGET} INTERFACE ${REPLACED_FLAGS})

16
biicode/support/bii-travis.sh Executable file
View File

@@ -0,0 +1,16 @@
#!/bin/bash
sudo apt-get update -qq
sudo apt-get install libglu1-mesa-dev xorg-dev
wget http://www.biicode.com/downloads/latest/ubuntu64
mv ubuntu64 bii-ubuntu64.deb
(sudo dpkg -i bii-ubuntu64.deb) && sudo apt-get -f install
rm bii-ubuntu64.deb
wget https://s3.amazonaws.com/biibinaries/thirdparty/cmake-3.0.2-Linux-64.tar.gz
tar -xzf cmake-3.0.2-Linux-64.tar.gz
sudo cp -fR cmake-3.0.2-Linux-64/* /usr
rm -rf cmake-3.0.2-Linux-64
rm cmake-3.0.2-Linux-64.tar.gz
cmake --version
bii init -l && bii configure -DCMAKE_BUILD_TYPE=$1 && bii test

View File

@@ -271,6 +271,8 @@
<ClCompile Include="..\..\src\idl_gen_go.cpp">
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Level4</WarningLevel>
</ClCompile>
<ClCompile Include="..\..\src\idl_gen_js.cpp" />
<ClCompile Include="..\..\src\idl_gen_python.cpp" />
<ClCompile Include="..\..\src\idl_parser.cpp" />
<ClCompile Include="..\..\src\idl_gen_cpp.cpp" />
<ClCompile Include="..\..\src\idl_gen_text.cpp" />

View File

@@ -3,7 +3,7 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LocalDebuggerWorkingDirectory>..\..\tests</LocalDebuggerWorkingDirectory>
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
<LocalDebuggerCommandArguments>-j -c -n -g -b -t monster_test.fbs monsterdata_test.golden</LocalDebuggerCommandArguments>
<LocalDebuggerCommandArguments>-j -c -n -g --no-includes --gen-mutable monster_test.fbs</LocalDebuggerCommandArguments>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LocalDebuggerWorkingDirectory>..\..</LocalDebuggerWorkingDirectory>

View File

@@ -265,11 +265,14 @@
<ItemGroup>
<ClInclude Include="..\..\include\flatbuffers\flatbuffers.h" />
<ClInclude Include="..\..\include\flatbuffers\idl.h" />
<ClInclude Include="..\..\include\flatbuffers\reflection.h" />
<ClInclude Include="..\..\include\flatbuffers\util.h" />
<ClInclude Include="..\..\tests\monster_test_generated.h" />
<ClCompile Include="..\..\src\idl_gen_fbs.cpp" />
<ClCompile Include="..\..\src\idl_gen_general.cpp" />
<ClCompile Include="..\..\src\idl_parser.cpp" />
<ClCompile Include="..\..\src\idl_gen_text.cpp" />
<ClCompile Include="..\..\src\reflection.cpp" />
<ClCompile Include="..\..\tests\test.cpp" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />

View File

@@ -8,11 +8,15 @@
/* Begin PBXBuildFile section */
1963D7D2A57344A3B1C1713F /* idl_parser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3709AC883348409592530AE6 /* idl_parser.cpp */; settings = {COMPILER_FLAGS = ""; }; };
5AC48C391ACA9A0A008132C5 /* idl_gen_general.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8CD8717A19CB937D0012A827 /* idl_gen_general.cpp */; };
61823BBC53544106B6DBC38E /* idl_parser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3709AC883348409592530AE6 /* idl_parser.cpp */; settings = {COMPILER_FLAGS = ""; }; };
61FF3C34FBEC4819A1C30F92 /* sample_text.cpp in Sources */ = {isa = PBXBuildFile; fileRef = ECCEBFFA6977404F858F9739 /* sample_text.cpp */; settings = {COMPILER_FLAGS = ""; }; };
8C303C591975D6A700D7C1C5 /* idl_gen_go.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8C303C581975D6A700D7C1C5 /* idl_gen_go.cpp */; };
8C6905F819F835A900CB8866 /* idl_gen_fbs.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8C6905F119F835A900CB8866 /* idl_gen_fbs.cpp */; };
8C6905FD19F835B400CB8866 /* idl_gen_fbs.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8C6905EC19F8357300CB8866 /* idl_gen_fbs.cpp */; };
8C78573E1BD5AE2C00C53C34 /* idl_gen_js.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8C78573D1BD5AE2C00C53C34 /* idl_gen_js.cpp */; };
8C8774631B703D4800E693F5 /* reflection.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8C8774621B703D4800E693F5 /* reflection.cpp */; };
8C8774641B703E1200E693F5 /* idl_gen_fbs.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8C6905EC19F8357300CB8866 /* idl_gen_fbs.cpp */; };
8CA854B31B04244A00040A06 /* idl_gen_python.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8CA854B21B04244A00040A06 /* idl_gen_python.cpp */; };
8CD8717B19CB937D0012A827 /* idl_gen_general.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8CD8717A19CB937D0012A827 /* idl_gen_general.cpp */; };
A9C9A99F719A4ED58DC2D2FC /* idl_parser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3709AC883348409592530AE6 /* idl_parser.cpp */; settings = {COMPILER_FLAGS = ""; }; };
AA9BACF55EB3456BA2F633BB /* flatc.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0DFD29781D8E490284B06504 /* flatc.cpp */; settings = {COMPILER_FLAGS = ""; }; };
@@ -31,22 +35,16 @@
3709AC883348409592530AE6 /* idl_parser.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = idl_parser.cpp; path = src/idl_parser.cpp; sourceTree = SOURCE_ROOT; };
3863042BCEC64791BFB48625 /* flatsamplebinary */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; path = flatsamplebinary; sourceTree = BUILT_PRODUCTS_DIR; };
420E3BC724ED4A008D79297F /* flatsampletext */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; path = flatsampletext; sourceTree = BUILT_PRODUCTS_DIR; };
423CA92401AE442B91546E63 /* CMakeLists.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = CMakeLists.txt; path = /Users/wvo/flatbuffers_snapshot9/CMakeLists.txt; sourceTree = "<absolute>"; };
5EE44BFFAF8E43F485859145 /* sample_binary.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = sample_binary.cpp; path = samples/sample_binary.cpp; sourceTree = SOURCE_ROOT; };
6AD24EEB3D024825A37741FF /* test.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = test.cpp; path = tests/test.cpp; sourceTree = SOURCE_ROOT; };
8C303C581975D6A700D7C1C5 /* idl_gen_go.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = idl_gen_go.cpp; path = src/idl_gen_go.cpp; sourceTree = "<group>"; };
8C6905EC19F8357300CB8866 /* idl_gen_fbs.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = idl_gen_fbs.cpp; path = src/idl_gen_fbs.cpp; sourceTree = "<group>"; };
8C6905EF19F835A900CB8866 /* flatc.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = flatc.cpp; sourceTree = "<group>"; };
8C6905F019F835A900CB8866 /* idl_gen_cpp.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = idl_gen_cpp.cpp; sourceTree = "<group>"; };
8C6905F119F835A900CB8866 /* idl_gen_fbs.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = idl_gen_fbs.cpp; sourceTree = "<group>"; };
8C6905F219F835A900CB8866 /* idl_gen_general.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = idl_gen_general.cpp; sourceTree = "<group>"; };
8C6905F319F835A900CB8866 /* idl_gen_go.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = idl_gen_go.cpp; sourceTree = "<group>"; };
8C6905F419F835A900CB8866 /* idl_gen_text.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = idl_gen_text.cpp; sourceTree = "<group>"; };
8C6905F519F835A900CB8866 /* idl_parser.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = idl_parser.cpp; sourceTree = "<group>"; };
8C78573D1BD5AE2C00C53C34 /* idl_gen_js.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = idl_gen_js.cpp; path = src/idl_gen_js.cpp; sourceTree = "<group>"; };
8C8774621B703D4800E693F5 /* reflection.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = reflection.cpp; path = src/reflection.cpp; sourceTree = "<group>"; };
8CA854B21B04244A00040A06 /* idl_gen_python.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = idl_gen_python.cpp; path = src/idl_gen_python.cpp; sourceTree = "<group>"; };
8CD8717A19CB937D0012A827 /* idl_gen_general.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = idl_gen_general.cpp; path = src/idl_gen_general.cpp; sourceTree = "<group>"; };
A13F25CDAD23435DA293690D /* flattests */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; path = flattests; sourceTree = BUILT_PRODUCTS_DIR; };
AB70F1FBA50E4120BCF37C8D /* monster_test_generated.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = monster_test_generated.h; path = tests/monster_test_generated.h; sourceTree = SOURCE_ROOT; };
AD3682C6E1DD4EABB822C0CC /* monster_generated.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = monster_generated.h; path = samples/monster_generated.h; sourceTree = SOURCE_ROOT; };
C0E7B66C3FF849A0AD9A7168 /* util.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = util.h; path = include/flatbuffers/util.h; sourceTree = SOURCE_ROOT; };
CD90A7F6B2BE4D0384294DD1 /* idl_gen_cpp.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = idl_gen_cpp.cpp; path = src/idl_gen_cpp.cpp; sourceTree = SOURCE_ROOT; };
DD8B353D4756412195777FBA /* flatbuffers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = flatbuffers.h; path = include/flatbuffers/flatbuffers.h; sourceTree = SOURCE_ROOT; };
@@ -55,32 +53,18 @@
/* End PBXFileReference section */
/* Begin PBXGroup section */
194905BCBB5C451DB092EB08 /* Resources */ = {
isa = PBXGroup;
children = (
);
name = Resources;
sourceTree = "<group>";
};
28237E300FE042DEADA302D3 /* Source Files */ = {
isa = PBXGroup;
children = (
8C78573D1BD5AE2C00C53C34 /* idl_gen_js.cpp */,
8CA854B21B04244A00040A06 /* idl_gen_python.cpp */,
8C6905EC19F8357300CB8866 /* idl_gen_fbs.cpp */,
8CD8717A19CB937D0012A827 /* idl_gen_general.cpp */,
8C303C581975D6A700D7C1C5 /* idl_gen_go.cpp */,
0DFD29781D8E490284B06504 /* flatc.cpp */,
CD90A7F6B2BE4D0384294DD1 /* idl_gen_cpp.cpp */,
);
name = "Source Files";
sourceTree = "<group>";
};
355DCA17961E4B2FB2C71403 /* Source Files */ = {
isa = PBXGroup;
children = (
8C6905EE19F835A900CB8866 /* src */,
F6C5D81DBF864365B12E269D /* idl_gen_text.cpp */,
3709AC883348409592530AE6 /* idl_parser.cpp */,
6AD24EEB3D024825A37741FF /* test.cpp */,
CD90A7F6B2BE4D0384294DD1 /* idl_gen_cpp.cpp */,
8C8774621B703D4800E693F5 /* reflection.cpp */,
);
name = "Source Files";
sourceTree = "<group>";
@@ -88,49 +72,17 @@
378446B9D5EF46EF92B35E21 /* flatc */ = {
isa = PBXGroup;
children = (
5FEA84E7D39645988300317C /* Header Files */,
28237E300FE042DEADA302D3 /* Source Files */,
0DFD29781D8E490284B06504 /* flatc.cpp */,
);
name = flatc;
sourceTree = "<group>";
};
40E30B8480BD493EA459E9B4 /* Header Files */ = {
isa = PBXGroup;
children = (
AD3682C6E1DD4EABB822C0CC /* monster_generated.h */,
);
name = "Header Files";
sourceTree = "<group>";
};
4D1151F6FE594E40A1C177FF /* Header Files */ = {
isa = PBXGroup;
children = (
);
name = "Header Files";
sourceTree = "<group>";
};
5235469653ED4BC88A6C504D /* Header Files */ = {
isa = PBXGroup;
children = (
DD8B353D4756412195777FBA /* flatbuffers.h */,
00154BD8654B4B5B9FF45FA6 /* idl.h */,
C0E7B66C3FF849A0AD9A7168 /* util.h */,
AB70F1FBA50E4120BCF37C8D /* monster_test_generated.h */,
);
name = "Header Files";
sourceTree = "<group>";
};
5648A71028E14478841372D3 /* Source Files */ = {
isa = PBXGroup;
children = (
5EE44BFFAF8E43F485859145 /* sample_binary.cpp */,
);
name = "Source Files";
sourceTree = "<group>";
};
5FEA84E7D39645988300317C /* Header Files */ = {
isa = PBXGroup;
children = (
DD8B353D4756412195777FBA /* flatbuffers.h */,
00154BD8654B4B5B9FF45FA6 /* idl.h */,
C0E7B66C3FF849A0AD9A7168 /* util.h */,
);
name = "Header Files";
sourceTree = "<group>";
@@ -138,6 +90,8 @@
866694F9F2F7451382D236B3 /* Sources */ = {
isa = PBXGroup;
children = (
28237E300FE042DEADA302D3 /* Source Files */,
5FEA84E7D39645988300317C /* Header Files */,
378446B9D5EF46EF92B35E21 /* flatc */,
DB9DE41C20F349F694A488F3 /* flatsamplebinary */,
8FA1F43C78914AE5AD04E24E /* flatsampletext */,
@@ -149,31 +103,16 @@
88421F5F87584EE3B67C979A /* flattests */ = {
isa = PBXGroup;
children = (
5235469653ED4BC88A6C504D /* Header Files */,
355DCA17961E4B2FB2C71403 /* Source Files */,
AB70F1FBA50E4120BCF37C8D /* monster_test_generated.h */,
6AD24EEB3D024825A37741FF /* test.cpp */,
);
name = flattests;
sourceTree = "<group>";
};
8C6905EE19F835A900CB8866 /* src */ = {
isa = PBXGroup;
children = (
8C6905EF19F835A900CB8866 /* flatc.cpp */,
8C6905F019F835A900CB8866 /* idl_gen_cpp.cpp */,
8C6905F119F835A900CB8866 /* idl_gen_fbs.cpp */,
8C6905F219F835A900CB8866 /* idl_gen_general.cpp */,
8C6905F319F835A900CB8866 /* idl_gen_go.cpp */,
8C6905F419F835A900CB8866 /* idl_gen_text.cpp */,
8C6905F519F835A900CB8866 /* idl_parser.cpp */,
);
path = src;
sourceTree = "<group>";
};
8F5E926B72104F4194B3BD5A = {
isa = PBXGroup;
children = (
866694F9F2F7451382D236B3 /* Sources */,
194905BCBB5C451DB092EB08 /* Resources */,
99CC11E382B8420AA79A8A14 /* Products */,
);
sourceTree = "<group>";
@@ -181,8 +120,7 @@
8FA1F43C78914AE5AD04E24E /* flatsampletext */ = {
isa = PBXGroup;
children = (
40E30B8480BD493EA459E9B4 /* Header Files */,
A1C826615F904FDE8F0CA154 /* Source Files */,
ECCEBFFA6977404F858F9739 /* sample_text.cpp */,
);
name = flatsampletext;
sourceTree = "<group>";
@@ -198,20 +136,10 @@
name = Products;
sourceTree = "<group>";
};
A1C826615F904FDE8F0CA154 /* Source Files */ = {
isa = PBXGroup;
children = (
ECCEBFFA6977404F858F9739 /* sample_text.cpp */,
);
name = "Source Files";
sourceTree = "<group>";
};
DB9DE41C20F349F694A488F3 /* flatsamplebinary */ = {
isa = PBXGroup;
children = (
4D1151F6FE594E40A1C177FF /* Header Files */,
5648A71028E14478841372D3 /* Source Files */,
423CA92401AE442B91546E63 /* CMakeLists.txt */,
5EE44BFFAF8E43F485859145 /* sample_binary.cpp */,
);
name = flatsamplebinary;
sourceTree = "<group>";
@@ -286,7 +214,7 @@
isa = PBXProject;
attributes = {
BuildIndependentTargetsInParallel = YES;
LastUpgradeCheck = 0510;
LastUpgradeCheck = 0700;
};
buildConfigurationList = 6428BEB363AA4E03A282AA8C /* Build configuration list for PBXProject "FlatBuffers" */;
compatibilityVersion = "Xcode 3.2";
@@ -334,9 +262,11 @@
AA9BACF55EB3456BA2F633BB /* flatc.cpp in Sources */,
BE03D7B0C9584DD58B50ED34 /* idl_gen_cpp.cpp in Sources */,
AD71FEBEE4E846529002C1F0 /* idl_gen_text.cpp in Sources */,
8C8774641B703E1200E693F5 /* idl_gen_fbs.cpp in Sources */,
A9C9A99F719A4ED58DC2D2FC /* idl_parser.cpp in Sources */,
8C6905F819F835A900CB8866 /* idl_gen_fbs.cpp in Sources */,
8CA854B31B04244A00040A06 /* idl_gen_python.cpp in Sources */,
8CD8717B19CB937D0012A827 /* idl_gen_general.cpp in Sources */,
8C78573E1BD5AE2C00C53C34 /* idl_gen_js.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -344,6 +274,8 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
8C8774631B703D4800E693F5 /* reflection.cpp in Sources */,
5AC48C391ACA9A0A008132C5 /* idl_gen_general.cpp in Sources */,
8C6905FD19F835B400CB8866 /* idl_gen_fbs.cpp in Sources */,
E0680D6B5BFD484BA9D88EE8 /* idl_gen_text.cpp in Sources */,
61823BBC53544106B6DBC38E /* idl_parser.cpp in Sources */,
@@ -359,7 +291,7 @@
buildSettings = {
CONFIGURATION_BUILD_DIR = .;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk;
SDKROOT = macosx;
SYMROOT = build;
};
name = RelWithDebInfo;
@@ -367,6 +299,11 @@
04681CC521204B3B87BB1E81 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_WARN_ASSIGN_ENUM = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_IMPLICIT_SIGN_CONVERSION = NO;
CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
COMBINE_HIDPI_IMAGES = YES;
EXECUTABLE_PREFIX = "";
EXECUTABLE_SUFFIX = "";
@@ -375,6 +312,25 @@
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = "'CMAKE_INTDIR=\"$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)\"'";
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES;
GCC_TREAT_INCOMPATIBLE_POINTER_TYPE_WARNINGS_AS_ERRORS = YES;
GCC_TREAT_WARNINGS_AS_ERRORS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES;
GCC_WARN_ABOUT_MISSING_NEWLINE = YES;
GCC_WARN_ABOUT_MISSING_PROTOTYPES = NO;
GCC_WARN_ABOUT_RETURN_TYPE = YES;
GCC_WARN_FOUR_CHARACTER_CONSTANTS = YES;
GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES;
GCC_WARN_PEDANTIC = YES;
GCC_WARN_SHADOW = YES;
GCC_WARN_SIGN_COMPARE = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNKNOWN_PRAGMAS = YES;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_LABEL = YES;
GCC_WARN_UNUSED_PARAMETER = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/include";
INSTALL_PATH = "";
LIBRARY_SEARCH_PATHS = "";
@@ -472,6 +428,11 @@
33335DE09CF844709E9E4AA9 /* RelWithDebInfo */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_WARN_ASSIGN_ENUM = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_IMPLICIT_SIGN_CONVERSION = NO;
CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
COMBINE_HIDPI_IMAGES = YES;
EXECUTABLE_PREFIX = "";
EXECUTABLE_SUFFIX = "";
@@ -480,6 +441,25 @@
GCC_OPTIMIZATION_LEVEL = 2;
GCC_PREPROCESSOR_DEFINITIONS = "'CMAKE_INTDIR=\"$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)\"'";
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES;
GCC_TREAT_INCOMPATIBLE_POINTER_TYPE_WARNINGS_AS_ERRORS = YES;
GCC_TREAT_WARNINGS_AS_ERRORS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES;
GCC_WARN_ABOUT_MISSING_NEWLINE = YES;
GCC_WARN_ABOUT_MISSING_PROTOTYPES = NO;
GCC_WARN_ABOUT_RETURN_TYPE = YES;
GCC_WARN_FOUR_CHARACTER_CONSTANTS = YES;
GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES;
GCC_WARN_PEDANTIC = YES;
GCC_WARN_SHADOW = YES;
GCC_WARN_SIGN_COMPARE = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNKNOWN_PRAGMAS = YES;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_LABEL = YES;
GCC_WARN_UNUSED_PARAMETER = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/include";
INSTALL_PATH = "";
LIBRARY_SEARCH_PATHS = "";
@@ -511,6 +491,11 @@
33B3983234F648E28F058235 /* MinSizeRel */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_WARN_ASSIGN_ENUM = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_IMPLICIT_SIGN_CONVERSION = NO;
CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
COMBINE_HIDPI_IMAGES = YES;
EXECUTABLE_PREFIX = "";
EXECUTABLE_SUFFIX = "";
@@ -519,6 +504,25 @@
GCC_OPTIMIZATION_LEVEL = s;
GCC_PREPROCESSOR_DEFINITIONS = "'CMAKE_INTDIR=\"$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)\"'";
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES;
GCC_TREAT_INCOMPATIBLE_POINTER_TYPE_WARNINGS_AS_ERRORS = YES;
GCC_TREAT_WARNINGS_AS_ERRORS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES;
GCC_WARN_ABOUT_MISSING_NEWLINE = YES;
GCC_WARN_ABOUT_MISSING_PROTOTYPES = NO;
GCC_WARN_ABOUT_RETURN_TYPE = YES;
GCC_WARN_FOUR_CHARACTER_CONSTANTS = YES;
GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES;
GCC_WARN_PEDANTIC = YES;
GCC_WARN_SHADOW = YES;
GCC_WARN_SIGN_COMPARE = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNKNOWN_PRAGMAS = YES;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_LABEL = YES;
GCC_WARN_UNUSED_PARAMETER = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/include";
INSTALL_PATH = "";
LIBRARY_SEARCH_PATHS = "";
@@ -589,6 +593,11 @@
37C0FFB777CF4C19BD7AA662 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_WARN_ASSIGN_ENUM = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_IMPLICIT_SIGN_CONVERSION = NO;
CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
COMBINE_HIDPI_IMAGES = YES;
EXECUTABLE_PREFIX = "";
EXECUTABLE_SUFFIX = "";
@@ -597,6 +606,25 @@
GCC_OPTIMIZATION_LEVEL = 3;
GCC_PREPROCESSOR_DEFINITIONS = "'CMAKE_INTDIR=\"$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)\"'";
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES;
GCC_TREAT_INCOMPATIBLE_POINTER_TYPE_WARNINGS_AS_ERRORS = YES;
GCC_TREAT_WARNINGS_AS_ERRORS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES;
GCC_WARN_ABOUT_MISSING_NEWLINE = YES;
GCC_WARN_ABOUT_MISSING_PROTOTYPES = NO;
GCC_WARN_ABOUT_RETURN_TYPE = YES;
GCC_WARN_FOUR_CHARACTER_CONSTANTS = YES;
GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES;
GCC_WARN_PEDANTIC = YES;
GCC_WARN_SHADOW = YES;
GCC_WARN_SIGN_COMPARE = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNKNOWN_PRAGMAS = YES;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_LABEL = YES;
GCC_WARN_UNUSED_PARAMETER = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/include";
INSTALL_PATH = "";
LIBRARY_SEARCH_PATHS = "";
@@ -779,8 +807,9 @@
isa = XCBuildConfiguration;
buildSettings = {
CONFIGURATION_BUILD_DIR = .;
ENABLE_TESTABILITY = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk;
SDKROOT = macosx;
SYMROOT = build;
};
name = Debug;
@@ -790,7 +819,7 @@
buildSettings = {
CONFIGURATION_BUILD_DIR = .;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk;
SDKROOT = macosx;
SYMROOT = build;
};
name = Release;
@@ -950,7 +979,7 @@
buildSettings = {
CONFIGURATION_BUILD_DIR = .;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk;
SDKROOT = macosx;
SYMROOT = build;
};
name = MinSizeRel;

62
docs/header.html Normal file
View File

@@ -0,0 +1,62 @@
<!-- HTML header for doxygen 1.8.6-->
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=9"/>
<meta name="generator" content="Doxygen $doxygenversion"/>
<!--BEGIN PROJECT_NAME--><title>$projectname: $title</title><!--END PROJECT_NAME-->
<!--BEGIN !PROJECT_NAME--><title>$title</title><!--END !PROJECT_NAME-->
<link href="$relpath^tabs.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="$relpath^jquery.js"></script>
<script type="text/javascript" src="$relpath^dynsections.js"></script>
$treeview
$search
$mathjax
<link href="$relpath^$stylesheet" rel="stylesheet" type="text/css" />
<link href="https://fonts.googleapis.com/css?family=Roboto:300,400,400italic,500,500italic,700,700italic|Roboto+Mono:400,700" rel="stylesheet">
$extrastylesheet
</head>
<body>
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
<!--BEGIN TITLEAREA-->
<div id="titlearea" style="height: 110px;">
<table cellspacing="0" cellpadding="0">
<tbody>
<tr style="height: 56px;">
<!--BEGIN PROJECT_LOGO-->
<td id="projectlogo"><img alt="Logo" src="$relpath^$projectlogo"/></td>
<!--END PROJECT_LOGO-->
<td id="commonprojectlogo">
<img alt="Logo" src="$relpath^fpl_logo_small.png"/>
</td>
<!--BEGIN PROJECT_NAME-->
<td style="padding-left: 0.5em;">
<div id="projectname">$projectname
<!--BEGIN PROJECT_NUMBER-->&#160;<span id="projectnumber">$projectnumber</span><!--END PROJECT_NUMBER-->
</div>
<div style="font-size:12px;">
An open source project by <a href="https://developers.google.com/games/#Tools">FPL</a>.
</div>
<!--BEGIN PROJECT_BRIEF--><div id="projectbrief">$projectbrief</div><!--END PROJECT_BRIEF-->
</td>
<!--END PROJECT_NAME-->
<!--BEGIN !PROJECT_NAME-->
<!--BEGIN PROJECT_BRIEF-->
<td style="padding-left: 0.5em;">
<div id="projectbrief">$projectbrief</div>
</td>
<!--END PROJECT_BRIEF-->
<!--END !PROJECT_NAME-->
<!--BEGIN DISABLE_INDEX-->
<!--BEGIN SEARCHENGINE-->
<td>$searchbox</td>
<!--END SEARCHENGINE-->
<!--END DISABLE_INDEX-->
</tr>
</tbody>
</table>
</div>
<!--END TITLEAREA-->
<!-- end header part -->

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

View File

@@ -1,3 +1,4 @@
<!-- HTML header for doxygen 1.8.6-->
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
@@ -15,17 +16,24 @@
$(document).ready(initResizable);
$(window).load(resizeHeight);
</script>
<link href="doxygen.css" rel="stylesheet" type="text/css" />
<link href="style.css" rel="stylesheet" type="text/css" />
<link href="https://fonts.googleapis.com/css?family=Roboto:300,400,400italic,500,500italic,700,700italic|Roboto+Mono:400,700" rel="stylesheet">
</head>
<body>
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
<div id="titlearea">
<div id="titlearea" style="height: 110px;">
<table cellspacing="0" cellpadding="0">
<tbody>
<tr style="height: 56px;">
<td id="commonprojectlogo">
<img alt="Logo" src="fpl_logo_small.png"/>
</td>
<td style="padding-left: 0.5em;">
<div id="projectname">FlatBuffers
</div>
<div style="font-size:12px;">
An open source project by <a href="https://developers.google.com/games/#Tools">FPL</a>.
</div>
</td>
</tr>
</tbody>
@@ -54,7 +62,7 @@ $(document).ready(function(){initNavTree('index.html','');});
</div><!--header-->
<div class="contents">
<div class="textblock"><p>FlatBuffers is an efficient cross platform serialization library for C++, with support for Java, C# and Go. It was created at Google specifically for game development and other performance-critical applications.</p>
<p>It is available as open source under the Apache license, v2 (see LICENSE.txt).</p>
<p>It is available as Open Source on <a href="http://github.com/google/flatbuffers">GitHub</a> under the Apache license, v2 (see LICENSE.txt).</p>
<h2>Why use FlatBuffers?</h2>
<ul>
<li><b>Access to serialized data without parsing/unpacking</b> - What sets FlatBuffers apart is that it represents hierarchical data in a flat binary buffer in such a way that it can still be accessed directly without parsing/unpacking, while also still supporting data structure evolution (forwards/backwards compatibility).</li>
@@ -72,11 +80,17 @@ $(document).ready(function(){initNavTree('index.html','');});
<h3>But all the cool kids use JSON!</h3>
<p>JSON is very readable (which is why we use it as our optional text format) and very convenient when used together with dynamically typed languages (such as JavaScript). When serializing data from statically typed languages, however, JSON not only has the obvious drawback of runtime inefficiency, but also forces you to write <em>more</em> code to access data (counterintuitively) due to its dynamic-typing serialization system. In this context, it is only a better choice for systems that have very little to no information ahead of time about what data needs to be stored.</p>
<p>Read more about the "why" of FlatBuffers in the <a href="md__white_paper.html">white paper</a>.</p>
<h3>Who uses FlatBuffers?</h3>
<ul>
<li><a href="http://www.cocos2d-x.org/">Cocos2d-x</a>, the #1 open source mobile game engine, uses it to serialize all their <a href="http://www.cocos2d-x.org/reference/native-cpp/V3.5/d7/d2d/namespaceflatbuffers.html">game data</a>.</li>
<li><a href="http://facebook.com/">Facebook</a> uses it for client-server communication in their Android app. They have a nice <a href="https://code.facebook.com/posts/872547912839369/improving-facebook-s-performance-on-android-with-flatbuffers/">article</a> explaining how it speeds up loading their posts.</li>
<li><a href="https://developers.google.com/games/#Tools">Fun Propulsion Labs</a> at Google uses it extensively in all their libraries and games.</li>
</ul>
<h2>Usage in brief</h2>
<p>This section is a quick rundown of how to use this system. Subsequent sections provide a more in-depth usage guide.</p>
<ul>
<li>Write a schema file that allows you to define the data structures you may want to serialize. Fields can have a scalar type (ints/floats of all sizes), or they can be a: string; array of any type; reference to yet another object; or, a set of possible objects (unions). Fields are optional and have defaults, so they don't need to be present for every object instance.</li>
<li>Use <code>flatc</code> (the FlatBuffer compiler) to generate a C++ header (or Java/C#/Go classes) with helper classes to access and construct serialized data. This header (say <code>mydata_generated.h</code>) only depends on <code>flatbuffers.h</code>, which defines the core functionality.</li>
<li>Use <code>flatc</code> (the FlatBuffer compiler) to generate a C++ header (or Java/C#/Go/Python.. classes) with helper classes to access and construct serialized data. This header (say <code>mydata_generated.h</code>) only depends on <code>flatbuffers.h</code>, which defines the core functionality.</li>
<li>Use the <code>FlatBufferBuilder</code> class to construct a flat binary buffer. The generated functions allow you to add objects to this buffer recursively, often as simply as making a single function call.</li>
<li>Store or send your buffer somewhere!</li>
<li>When reading it back, you can obtain the pointer to the root object from the binary buffer, and from there traverse it conveniently in-place with <code>object-&gt;field()</code>.</li>
@@ -89,6 +103,7 @@ $(document).ready(function(){initNavTree('index.html','');});
<li>How to <a href="md__cpp_usage.html">use the generated C++ code</a> in your own programs.</li>
<li>How to <a href="md__java_usage.html">use the generated Java/C# code</a> in your own programs.</li>
<li>How to <a href="md__go_usage.html">use the generated Go code</a> in your own programs.</li>
<li><a href="md__support.html">Support matrix</a> for platforms/languages/features.</li>
<li>Some <a href="md__benchmarks.html">benchmarks</a> showing the advantage of using FlatBuffers.</li>
<li>A <a href="md__white_paper.html">white paper</a> explaining the "why" of FlatBuffers.</li>
<li>A description of the <a href="md__internals.html">internals</a> of FlatBuffers.</li>
@@ -96,10 +111,21 @@ $(document).ready(function(){initNavTree('index.html','');});
</ul>
<h2>Online resources</h2>
<ul>
<li><a href="http://github.com/google/flatbuffers">github repository</a></li>
<li><a href="http://google.github.io/flatbuffers">landing page</a></li>
<li><a href="http://github.com/google/flatbuffers">GitHub repository</a></li>
<li><a href="http://google.github.io/flatbuffers">Landing page</a></li>
<li><a href="http://group.google.com/group/flatbuffers">FlatBuffers Google Group</a></li>
<li><a href="http://github.com/google/flatbuffers/issues">FlatBuffers Issues Tracker</a> </li>
<li><a href="http://github.com/google/flatbuffers/issues">FlatBuffers Issues Tracker</a></li>
<li>Videos:<ul>
<li>Colt's <a href="https://www.youtube.com/watch?v=iQTxMkSJ1dQ">DevByte</a>.</li>
<li>GDC 2015 <a href="https://www.youtube.com/watch?v=olmL1fUnQAQ">Lightning Talk</a>.</li>
<li>FlatBuffers for <a href="https://www.youtube.com/watch?v=-BPVId_lA5w">Go</a>.</li>
<li>Evolution of FlatBuffers <a href="https://www.youtube.com/watch?v=a0QE0xS8rKM">visualization</a>.</li>
</ul>
</li>
<li>Useful documentation created by others:<ul>
<li><a href="http://exiin.com/blog/flatbuffers-for-unity-sample-code/">Using FlatBuffers in Unity</a> </li>
</ul>
</li>
</ul>
</div></div><!-- contents -->
</div><!-- doc-content -->

View File

@@ -1,3 +1,4 @@
<!-- HTML header for doxygen 1.8.6-->
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
@@ -15,17 +16,24 @@
$(document).ready(initResizable);
$(window).load(resizeHeight);
</script>
<link href="doxygen.css" rel="stylesheet" type="text/css" />
<link href="style.css" rel="stylesheet" type="text/css" />
<link href="https://fonts.googleapis.com/css?family=Roboto:300,400,400italic,500,500italic,700,700italic|Roboto+Mono:400,700" rel="stylesheet">
</head>
<body>
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
<div id="titlearea">
<div id="titlearea" style="height: 110px;">
<table cellspacing="0" cellpadding="0">
<tbody>
<tr style="height: 56px;">
<td id="commonprojectlogo">
<img alt="Logo" src="fpl_logo_small.png"/>
</td>
<td style="padding-left: 0.5em;">
<div id="projectname">FlatBuffers
</div>
<div style="font-size:12px;">
An open source project by <a href="https://developers.google.com/games/#Tools">FPL</a>.
</div>
</td>
</tr>
</tbody>
@@ -82,7 +90,7 @@ $(document).ready(function(){initNavTree('md__benchmarks.html','');});
<h3>Some other serialization systems we compared against but did not benchmark (yet), in rough order of applicability:</h3>
<ul>
<li>Cap'n'Proto promises to reduce Protocol Buffers much like FlatBuffers does, though with a more complicated binary encoding and less flexibility (no optional fields to allow deprecating fields or serializing with missing fields for which defaults exist). It currently also isn't fully cross-platform portable (lack of VS support).</li>
<li>msgpack: has very minimal forwards/backwards compatability support when used with the typed C++ interface. Also lacks VS2010 support.</li>
<li>msgpack: has very minimal forwards/backwards compatibility support when used with the typed C++ interface. Also lacks VS2010 support.</li>
<li>Thrift: very similar to Protocol Buffers, but appears to be less efficient, and have more dependencies.</li>
<li>YAML: a superset of JSON and otherwise very similar. Used by e.g. Unity.</li>
<li>C# comes with built-in serialization functionality, as used by Unity also. Being tied to the language, and having no automatic versioning support limits its applicability.</li>

View File

@@ -1,3 +1,4 @@
<!-- HTML header for doxygen 1.8.6-->
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
@@ -15,17 +16,24 @@
$(document).ready(initResizable);
$(window).load(resizeHeight);
</script>
<link href="doxygen.css" rel="stylesheet" type="text/css" />
<link href="style.css" rel="stylesheet" type="text/css" />
<link href="https://fonts.googleapis.com/css?family=Roboto:300,400,400italic,500,500italic,700,700italic|Roboto+Mono:400,700" rel="stylesheet">
</head>
<body>
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
<div id="titlearea">
<div id="titlearea" style="height: 110px;">
<table cellspacing="0" cellpadding="0">
<tbody>
<tr style="height: 56px;">
<td id="commonprojectlogo">
<img alt="Logo" src="fpl_logo_small.png"/>
</td>
<td style="padding-left: 0.5em;">
<div id="projectname">FlatBuffers
</div>
<div style="font-size:12px;">
An open source project by <a href="https://developers.google.com/games/#Tools">FPL</a>.
</div>
</td>
</tr>
</tbody>

View File

@@ -1,3 +1,4 @@
<!-- HTML header for doxygen 1.8.6-->
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
@@ -15,17 +16,24 @@
$(document).ready(initResizable);
$(window).load(resizeHeight);
</script>
<link href="doxygen.css" rel="stylesheet" type="text/css" />
<link href="style.css" rel="stylesheet" type="text/css" />
<link href="https://fonts.googleapis.com/css?family=Roboto:300,400,400italic,500,500italic,700,700italic|Roboto+Mono:400,700" rel="stylesheet">
</head>
<body>
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
<div id="titlearea">
<div id="titlearea" style="height: 110px;">
<table cellspacing="0" cellpadding="0">
<tbody>
<tr style="height: 56px;">
<td id="commonprojectlogo">
<img alt="Logo" src="fpl_logo_small.png"/>
</td>
<td style="padding-left: 0.5em;">
<div id="projectname">FlatBuffers
</div>
<div style="font-size:12px;">
An open source project by <a href="https://developers.google.com/games/#Tools">FPL</a>.
</div>
</td>
</tr>
</tbody>
@@ -67,10 +75,18 @@ $(document).ready(function(){initNavTree('md__compiler.html','');});
<li><code>-t</code> : If data is contained in this file, generate a <code>filename.json</code> representing the data in the flatbuffer.</li>
<li><code>-o PATH</code> : Output all generated files to PATH (either absolute, or relative to the current directory). If omitted, PATH will be the current directory. PATH should end in your systems path separator, e.g. <code>/</code> or <code>\</code>.</li>
<li><code>-I PATH</code> : when encountering <code>include</code> statements, attempt to load the files from this path. Paths will be tried in the order given, and if all fail (or none are specified) it will try to load relative to the path of the schema file being parsed.</li>
<li><code>-M</code> : Print make rules for generated files.</li>
<li><code>--strict-json</code> : Require &amp; generate strict JSON (field names are enclosed in quotes, no trailing commas in tables/vectors). By default, no quotes are required/generated, and trailing commas are allowed.</li>
<li><code>--defaults-json</code> : Output fields whose value is equal to the default value when writing JSON text.</li>
<li><code>--no-prefix</code> : Don't prefix enum values in generated C++ by their enum type.</li>
<li><code>--gen-includes</code> : Generate include statements for included schemas the generated file depends on (C++).</li>
<li><code>--proto</code>: Expect input files to be .proto files (protocol buffers). Output the corresponding .fbs file. Currently supports: <code>package</code>, <code>message</code>, <code>enum</code>. Does not support, but will skip without error: <code>import</code>, <code>option</code>. Does not support, will generate error: <code>service</code>, <code>extend</code>, <code>extensions</code>, <code>oneof</code>, <code>group</code>, custom options, nested declarations. </li>
<li><code>--scoped-enums</code> : Use C++11 style scoped and strongly typed enums in generated C++. This also implies <code>--no-prefix</code>.</li>
<li><code>--gen-includes</code> : (deprecated), this is the default behavior. If the original behavior is required (no include statements) use <code>--no-includes.</code></li>
<li><code>--no-includes</code> : Don't generate include statements for included schemas the generated file depends on (C++).</li>
<li><code>--gen-mutable</code> : Generate additional non-const accessors for mutating FlatBuffers in-place.</li>
<li><code>--gen-onefile</code> : Generate single output file (useful for C#)</li>
<li><code>--raw-binary</code> : Allow binaries without a file_indentifier to be read. This may crash flatc given a mismatched schema.</li>
<li><code>--proto</code>: Expect input files to be .proto files (protocol buffers). Output the corresponding .fbs file. Currently supports: <code>package</code>, <code>message</code>, <code>enum</code>, nested declarations, <code>import</code> (use <code>-I</code> for paths), <code>extend</code>, <code>oneof</code>, <code>group</code>. Does not support, but will skip without error: <code>option</code>, <code>service</code>, <code>extensions</code>, and most everything else.</li>
<li><code>--schema</code>: Serialize schemas instead of JSON (use with -b). This will output a binary version of the specified schema that itself corresponds to the reflection/reflection.fbs schema. Loading this binary file is the basis for reflection functionality. </li>
</ul>
</div></div><!-- contents -->
</div><!-- doc-content -->

View File

@@ -1,3 +1,4 @@
<!-- HTML header for doxygen 1.8.6-->
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
@@ -15,17 +16,24 @@
$(document).ready(initResizable);
$(window).load(resizeHeight);
</script>
<link href="doxygen.css" rel="stylesheet" type="text/css" />
<link href="style.css" rel="stylesheet" type="text/css" />
<link href="https://fonts.googleapis.com/css?family=Roboto:300,400,400italic,500,500italic,700,700italic|Roboto+Mono:400,700" rel="stylesheet">
</head>
<body>
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
<div id="titlearea">
<div id="titlearea" style="height: 110px;">
<table cellspacing="0" cellpadding="0">
<tbody>
<tr style="height: 56px;">
<td id="commonprojectlogo">
<img alt="Logo" src="fpl_logo_small.png"/>
</td>
<td style="padding-left: 0.5em;">
<div id="projectname">FlatBuffers
</div>
<div style="font-size:12px;">
An open source project by <a href="https://developers.google.com/games/#Tools">FPL</a>.
</div>
</td>
</tr>
</tbody>
@@ -71,7 +79,7 @@ $(document).ready(function(){initNavTree('md__cpp_usage.html','');});
<p>We have now serialized the non-scalar components of of the monster example, so we could create the monster something like this:</p>
<div class="fragment"><div class="line"><span class="keyword">auto</span> mloc = CreateMonster(fbb, &amp;vec, 150, 80, name, inventory, Color_Red, 0, Any_NONE);</div>
</div><!-- fragment --><p>Note that we're passing <code>150</code> for the <code>mana</code> field, which happens to be the default value: this means the field will not actually be written to the buffer, since we'll get that value anyway when we query it. This is a nice space savings, since it is very common for fields to be at their default. It means we also don't need to be scared to add fields only used in a minority of cases, since they won't bloat up the buffer sizes if they're not actually used.</p>
<p>We do something similarly for the union field <code>test</code> by specifying a <code>0</code> offset and the <code>NONE</code> enum value (part of every union) to indicate we don't actually want to write this field. You can use <code>0</code> also as a default for other non-scalar types, such as strings, vectors and tables.</p>
<p>We do something similarly for the union field <code>test</code> by specifying a <code>0</code> offset and the <code>NONE</code> enum value (part of every union) to indicate we don't actually want to write this field. You can use <code>0</code> also as a default for other non-scalar types, such as strings, vectors and tables. To pass an actual table, pass a preconstructed table as <code>mytable.Union()</code> that corresponds to union enum you're passing.</p>
<p>Tables (like <code>Monster</code>) give you full flexibility on what fields you write (unlike <code>Vec3</code>, which always has all fields set because it is a <code>struct</code>). If you want even more control over this (i.e. skip fields even when they are not default), instead of the convenient <code>CreateMonster</code> call we can also build the object field-by-field manually:</p>
<div class="fragment"><div class="line">MonsterBuilder mb(fbb);</div>
<div class="line">mb.add_pos(&amp;vec);</div>
@@ -102,7 +110,27 @@ $(document).ready(function(){initNavTree('md__cpp_usage.html','');});
<div class="fragment"><div class="line"><span class="keyword">auto</span> inv = monster-&gt;inventory();</div>
<div class="line">assert(inv);</div>
<div class="line">assert(inv-&gt;Get(9) == 9);</div>
</div><!-- fragment --><h3>Storing maps / dictionaries in a FlatBuffer</h3>
</div><!-- fragment --><h3>Mutating FlatBuffers</h3>
<p>As you saw above, typically once you have created a FlatBuffer, it is read-only from that moment on. There are however cases where you have just received a FlatBuffer, and you'd like to modify something about it before sending it on to another recipient. With the above functionality, you'd have to generate an entirely new FlatBuffer, while tracking what you modify in your own data structures. This is inconvenient.</p>
<p>For this reason FlatBuffers can also be mutated in-place. While this is great for making small fixes to an existing buffer, you generally want to create buffers from scratch whenever possible, since it is much more efficient and the API is much more general purpose.</p>
<p>To get non-const accessors, invoke <code>flatc</code> with <code>--gen-mutable</code>.</p>
<p>Similar to the reading API above, you now can:</p>
<div class="fragment"><div class="line"><span class="keyword">auto</span> monster = GetMutableMonster(buffer_pointer); <span class="comment">// non-const</span></div>
<div class="line">monster-&gt;mutate_hp(10); <span class="comment">// Set table field.</span></div>
<div class="line">monster-&gt;mutable_pos()-&gt;mutate_z(4); <span class="comment">// Set struct field.</span></div>
<div class="line">monster-&gt;mutable_inventory()-&gt;Mutate(0, 1); <span class="comment">// Set vector element.</span></div>
</div><!-- fragment --><p>We use the somewhat verbose term <code>mutate</code> instead of <code>set</code> to indicate that this is a special use case, not to be confused with the default way of constructing FlatBuffer data.</p>
<p>After the above mutations, you can send on the FlatBuffer to a new recipient without any further work!</p>
<p>Note that any <code>mutate_</code> functions on tables return a bool, which is false if the field we're trying to set isn't present in the buffer. Fields are not present if they weren't set, or even if they happen to be equal to the default value. For example, in the creation code above we set the <code>mana</code> field to <code>150</code>, which is the default value, so it was never stored in the buffer. Trying to call mutate_mana() on such data will return false, and the value won't actually be modified!</p>
<p>One way to solve this is to call <code>ForceDefaults()</code> on a <code>FlatBufferBuilder</code> to force all fields you set to actually be written. This of course increases the size of the buffer somewhat, but this may be acceptable for a mutable buffer.</p>
<p>Alternatively, you can use the more powerful reflection functionality:</p>
<h3>Reflection (&amp; Resizing)</h3>
<p>If the above ways of accessing a buffer are still too static for you, 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.</p>
<p>The way this works is very elegant, there is actually a FlatBuffer schema that describes schemas (!) which you can find in <code>reflection/reflection.fbs</code>. The compiler <code>flatc</code> can write out any schemas it has just parsed as a binary FlatBuffer, corresponding to this meta-schema.</p>
<p>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.</p>
<p>For convenient field manipulation, you can include the header <code>flatbuffers/reflection.h</code> which includes both the generated code from the meta schema, as well as a lot of helper functions.</p>
<p>And example of usage for the moment you can find in <code>test.cpp/ReflectionTest()</code>.</p>
<h3>Storing maps / dictionaries in a FlatBuffer</h3>
<p>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 <code>std::map</code> or similar.</p>
<p>To use it:</p><ul>
<li>Designate one of the fields in a table as they "key" field. You do this by setting the <code>key</code> attribute on this field, e.g. <code>name:string (key)</code>. You may only have one key field, and it must be of string or scalar type.</li>

View File

@@ -1,3 +1,4 @@
<!-- HTML header for doxygen 1.8.6-->
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
@@ -15,17 +16,24 @@
$(document).ready(initResizable);
$(window).load(resizeHeight);
</script>
<link href="doxygen.css" rel="stylesheet" type="text/css" />
<link href="style.css" rel="stylesheet" type="text/css" />
<link href="https://fonts.googleapis.com/css?family=Roboto:300,400,400italic,500,500italic,700,700italic|Roboto+Mono:400,700" rel="stylesheet">
</head>
<body>
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
<div id="titlearea">
<div id="titlearea" style="height: 110px;">
<table cellspacing="0" cellpadding="0">
<tbody>
<tr style="height: 56px;">
<td id="commonprojectlogo">
<img alt="Logo" src="fpl_logo_small.png"/>
</td>
<td style="padding-left: 0.5em;">
<div id="projectname">FlatBuffers
</div>
<div style="font-size:12px;">
An open source project by <a href="https://developers.google.com/games/#Tools">FPL</a>.
</div>
</td>
</tr>
</tbody>

View File

@@ -1,10 +1,11 @@
<!-- HTML header for doxygen 1.8.6-->
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=9"/>
<meta name="generator" content="Doxygen 1.8.7"/>
<title>FlatBuffers: Formal Grammar of the schema language</title>
<title>FlatBuffers: Grammar of the schema language</title>
<link href="tabs.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript" src="dynsections.js"></script>
@@ -15,17 +16,24 @@
$(document).ready(initResizable);
$(window).load(resizeHeight);
</script>
<link href="doxygen.css" rel="stylesheet" type="text/css" />
<link href="style.css" rel="stylesheet" type="text/css" />
<link href="https://fonts.googleapis.com/css?family=Roboto:300,400,400italic,500,500italic,700,700italic|Roboto+Mono:400,700" rel="stylesheet">
</head>
<body>
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
<div id="titlearea">
<div id="titlearea" style="height: 110px;">
<table cellspacing="0" cellpadding="0">
<tbody>
<tr style="height: 56px;">
<td id="commonprojectlogo">
<img alt="Logo" src="fpl_logo_small.png"/>
</td>
<td style="padding-left: 0.5em;">
<div id="projectname">FlatBuffers
</div>
<div style="font-size:12px;">
An open source project by <a href="https://developers.google.com/games/#Tools">FPL</a>.
</div>
</td>
</tr>
</tbody>
@@ -50,24 +58,29 @@ $(document).ready(function(){initNavTree('md__grammar.html','');});
<div id="doc-content">
<div class="header">
<div class="headertitle">
<div class="title">Formal Grammar of the schema language </div> </div>
<div class="title">Grammar of the schema language </div> </div>
</div><!--header-->
<div class="contents">
<div class="textblock"><p>schema = include* ( namespace_decl | type_decl | enum_decl | root_decl | attribute_decl | object )*</p>
<div class="textblock"><p>schema = include* ( namespace_decl | type_decl | enum_decl | root_decl | file_extension_decl | file_identifier_decl | attribute_decl | object )*</p>
<p>include = <code>include</code> string_constant <code>;</code></p>
<p>namespace_decl = <code>namespace</code> ident ( <code>.</code> ident )* <code>;</code></p>
<p>attribute_decl = <code>attribute</code> string_constant <code>;</code></p>
<p>type_decl = ( <code>table</code> | <code>struct</code> ) ident metadata <code>{</code> field_decl+ <code>}</code></p>
<p>enum_decl = ( <code>enum</code> | <code>union</code> ) ident [ <code>:</code> type ] metadata <code>{</code> commasep( enumval_decl ) <code>}</code></p>
<p>root_decl = <code>root_type</code> ident <code>;</code></p>
<p>field_decl = type <code>:</code> ident [ <code>=</code> scalar ] metadata <code>;</code></p>
<p>field_decl = ident <code>:</code> type [ <code>=</code> scalar ] metadata <code>;</code></p>
<p>type = <code>bool</code> | <code>byte</code> | <code>ubyte</code> | <code>short</code> | <code>ushort</code> | <code>int</code> | <code>uint</code> | <code>float</code> | <code>long</code> | <code>ulong</code> | <code>double</code> | <code>string</code> | <code>[</code> type <code>]</code> | ident</p>
<p>enumval_decl = ident [ <code>=</code> integer_constant ]</p>
<p>metadata = [ <code>(</code> commasep( ident [ <code>:</code> scalar ] ) <code>)</code> ]</p>
<p>scalar = integer_constant | float_constant | <code>true</code> | <code>false</code></p>
<p>metadata = [ <code>(</code> commasep( ident [ <code>:</code> single_value ] ) <code>)</code> ]</p>
<p>scalar = integer_constant | float_constant</p>
<p>object = { commasep( ident <code>:</code> value ) }</p>
<p>value = scalar | object | string_constant | <code>[</code> commasep( value ) <code>]</code></p>
<p>commasep(x) = [ x ( <code>,</code> x )* ] </p>
<p>single_value = scalar | string_constant</p>
<p>value = single_value | object | <code>[</code> commasep( value ) <code>]</code></p>
<p>commasep(x) = [ x ( <code>,</code> x )* ]</p>
<p>file_extension_decl = <code>file_extension</code> string_constant <code>;</code></p>
<p>file_identifier_decl = <code>file_identifier</code> string_constant <code>;</code></p>
<p>integer_constant = -?[0-9]+ | <code>true</code> | <code>false</code></p>
<p>float_constant = -?[0-9]+.[0-9]+((e|E)(+|-)?[0-9]+)? </p>
</div></div><!-- contents -->
</div><!-- doc-content -->
<!-- Google Analytics -->

View File

@@ -1,3 +1,4 @@
<!-- HTML header for doxygen 1.8.6-->
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
@@ -15,17 +16,24 @@
$(document).ready(initResizable);
$(window).load(resizeHeight);
</script>
<link href="doxygen.css" rel="stylesheet" type="text/css" />
<link href="style.css" rel="stylesheet" type="text/css" />
<link href="https://fonts.googleapis.com/css?family=Roboto:300,400,400italic,500,500italic,700,700italic|Roboto+Mono:400,700" rel="stylesheet">
</head>
<body>
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
<div id="titlearea">
<div id="titlearea" style="height: 110px;">
<table cellspacing="0" cellpadding="0">
<tbody>
<tr style="height: 56px;">
<td id="commonprojectlogo">
<img alt="Logo" src="fpl_logo_small.png"/>
</td>
<td style="padding-left: 0.5em;">
<div id="projectname">FlatBuffers
</div>
<div style="font-size:12px;">
An open source project by <a href="https://developers.google.com/games/#Tools">FPL</a>.
</div>
</td>
</tr>
</tbody>

View File

@@ -1,3 +1,4 @@
<!-- HTML header for doxygen 1.8.6-->
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
@@ -15,17 +16,24 @@
$(document).ready(initResizable);
$(window).load(resizeHeight);
</script>
<link href="doxygen.css" rel="stylesheet" type="text/css" />
<link href="style.css" rel="stylesheet" type="text/css" />
<link href="https://fonts.googleapis.com/css?family=Roboto:300,400,400italic,500,500italic,700,700italic|Roboto+Mono:400,700" rel="stylesheet">
</head>
<body>
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
<div id="titlearea">
<div id="titlearea" style="height: 110px;">
<table cellspacing="0" cellpadding="0">
<tbody>
<tr style="height: 56px;">
<td id="commonprojectlogo">
<img alt="Logo" src="fpl_logo_small.png"/>
</td>
<td style="padding-left: 0.5em;">
<div id="projectname">FlatBuffers
</div>
<div style="font-size:12px;">
An open source project by <a href="https://developers.google.com/games/#Tools">FPL</a>.
</div>
</td>
</tr>
</tbody>
@@ -54,7 +62,7 @@ $(document).ready(function(){initNavTree('md__java_usage.html','');});
</div><!--header-->
<div class="contents">
<div class="textblock"><p>FlatBuffers supports reading and writing binary FlatBuffers in Java and C#. Generate code for Java with the <code>-j</code> option to <code>flatc</code>, or for C# with <code>-n</code> (think .Net).</p>
<p>Note that this document is from the perspective of Java. Code for both languages is generated in the same way, with only very subtle differences, for example any <code>camelCase</code> Java call will be <code>CamelCase</code> in C#.</p>
<p>Note that this document is from the perspective of Java. Code for both languages is generated in the same way, with only minor differences. These differences are <a href="#differences-in-c-sharp">explained in a section below</a>.</p>
<p>See <code>javaTest.java</code> for an example. Essentially, you read a FlatBuffer binary file into a <code>byte[]</code>, which you then turn into a <code>ByteBuffer</code>, which you pass to the <code>getRootAsMyRootType</code> function:</p>
<div class="fragment"><div class="line">ByteBuffer bb = ByteBuffer.wrap(data);</div>
<div class="line">Monster monster = Monster.getRootAsMonster(bb);</div>
@@ -88,7 +96,7 @@ $(document).ready(function(){initNavTree('md__java_usage.html','');});
</div><!-- fragment --><p>For some simpler types, you can use a convenient <code>create</code> function call that allows you to construct tables in one function call. This example definition however contains an inline struct field, so we have to create the table manually. This is to create the buffer without using temporary object allocation.</p>
<p>It's important to understand that fields that are structs are inline (like <code>Vec3</code> above), and MUST thus be created between the start and end calls of a table. Everything else (other tables, strings, vectors) MUST be created before the start of the table they are referenced in.</p>
<p>Structs do have convenient methods that even have arguments for nested structs.</p>
<p>As you can see, references to other objects (e.g. the string above) are simple ints, and thus do not have the type-safety of the Offset type in C++. Extra case must thus be taken that you set the right offset on the right field.</p>
<p>As you can see, references to other objects (e.g. the string above) are simple ints, and thus do not have the type-safety of the Offset type in C++. Extra care must thus be taken that you set the right offset on the right field.</p>
<p>Vectors can be created from the corresponding Java array like so:</p>
<div class="fragment"><div class="line"><span class="keywordtype">int</span> inv = Monster.createInventoryVector(fbb, <span class="keyword">new</span> byte[] { 0, 1, 2, 3, 4 });</div>
</div><!-- fragment --><p>This works for arrays of scalars and (int) offsets to strings/tables, but not structs. If you want to write structs, or what you want to write does not sit in an array, you can also use the start/end pattern:</p>
@@ -100,8 +108,29 @@ $(document).ready(function(){initNavTree('md__java_usage.html','');});
<p>To finish the buffer, call:</p>
<div class="fragment"><div class="line">Monster.finishMonsterBuffer(fbb, mon);</div>
</div><!-- fragment --><p>The buffer is now ready to be transmitted. It is contained in the <code>ByteBuffer</code> which you can obtain from <code>fbb.dataBuffer()</code>. Importantly, the valid data does not start from offset 0 in this buffer, but from <code>fbb.dataBuffer().position()</code> (this is because the data was built backwards in memory). It ends at <code>fbb.capacity()</code>.</p>
<h2>Text Parsing</h2>
<p>There currently is no support for parsing text (Schema's and JSON) directly from Java, though you could use the C++ parser through JNI. Please see the C++ documentation for more on text parsing. </p>
<h2>Differences in C-sharp</h2>
<p>C# code works almost identically to Java, with only a few minor differences. You can see an example of C# code in <code>tests/FlatBuffers.Test/FlatBuffersExampleTests.cs</code>.</p>
<p>First of all, naming follows standard C# style with <code>PascalCasing</code> identifiers, e.g. <code>GetRootAsMyRootType</code>. Also, values (except vectors and unions) are available as properties instead of parameterless accessor methods as in Java. The performance-enhancing methods to which you can pass an already created object are prefixed with <code>Get</code>, e.g.:</p>
<div class="fragment"><div class="line"><span class="comment">// property</span></div>
<div class="line">var pos = monster.Pos;</div>
<div class="line"><span class="comment">// method filling a preconstructed object</span></div>
<div class="line">var preconstructedPos = <span class="keyword">new</span> Vec3();</div>
<div class="line">monster.GetPos(preconstructedPos);</div>
</div><!-- fragment --><h2>Text parsing</h2>
<p>There currently is no support for parsing text (Schema's and JSON) directly from Java or 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.</p>
<h3>Mutating FlatBuffers</h3>
<p>As you saw above, typically once you have created a FlatBuffer, it is read-only from that moment on. There are however cases where you have just received a FlatBuffer, and you'd like to modify something about it before sending it on to another recipient. With the above functionality, you'd have to generate an entirely new FlatBuffer, while tracking what you modify in your own data structures. This is inconvenient.</p>
<p>For this reason FlatBuffers can also be mutated in-place. While this is great for making small fixes to an existing buffer, you generally want to create buffers from scratch whenever possible, since it is much more efficient and the API is much more general purpose.</p>
<p>To get non-const accessors, invoke <code>flatc</code> with <code>--gen-mutable</code>.</p>
<p>You now can:</p>
<div class="fragment"><div class="line">Monster monster = Monster.getRootAsMonster(bb);</div>
<div class="line">monster.mutateHp(10); <span class="comment">// Set table field.</span></div>
<div class="line">monster.pos().mutateZ(4); <span class="comment">// Set struct field.</span></div>
<div class="line">monster.mutateInventory(0, 1); <span class="comment">// Set vector element.</span></div>
</div><!-- fragment --><p>We use the somewhat verbose term <code>mutate</code> instead of <code>set</code> to indicate that this is a special use case, not to be confused with the default way of constructing FlatBuffer data.</p>
<p>After the above mutations, you can send on the FlatBuffer to a new recipient without any further work!</p>
<p>Note that any <code>mutate</code> functions on tables return a boolean, which is false if the field we're trying to set isn't present in the buffer. Fields are not present if they weren't set, or even if they happen to be equal to the default value. For example, in the creation code above we set the <code>mana</code> field to <code>150</code>, which is the default value, so it was never stored in the buffer. Trying to call mutateMana() on such data will return false, and the value won't actually be modified!</p>
<p>One way to solve this is to call <code>forceDefaults()</code> on a <code>FlatBufferBuilder</code> to force all fields you set to actually be written. This of course increases the size of the buffer somewhat, but this may be acceptable for a mutable buffer. </p>
</div></div><!-- contents -->
</div><!-- doc-content -->
<!-- Google Analytics -->

View File

@@ -0,0 +1,120 @@
<!-- HTML header for doxygen 1.8.6-->
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=9"/>
<meta name="generator" content="Doxygen 1.8.7"/>
<title>FlatBuffers: Use in Python</title>
<link href="tabs.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript" src="dynsections.js"></script>
<link href="navtree.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="resize.js"></script>
<script type="text/javascript" src="navtree.js"></script>
<script type="text/javascript">
$(document).ready(initResizable);
$(window).load(resizeHeight);
</script>
<link href="style.css" rel="stylesheet" type="text/css" />
<link href="https://fonts.googleapis.com/css?family=Roboto:300,400,400italic,500,500italic,700,700italic|Roboto+Mono:400,700" rel="stylesheet">
</head>
<body>
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
<div id="titlearea" style="height: 110px;">
<table cellspacing="0" cellpadding="0">
<tbody>
<tr style="height: 56px;">
<td id="commonprojectlogo">
<img alt="Logo" src="fpl_logo_small.png"/>
</td>
<td style="padding-left: 0.5em;">
<div id="projectname">FlatBuffers
</div>
<div style="font-size:12px;">
An open source project by <a href="https://developers.google.com/games/#Tools">FPL</a>.
</div>
</td>
</tr>
</tbody>
</table>
</div>
<!-- end header part -->
<!-- Generated by Doxygen 1.8.7 -->
</div><!-- top -->
<div id="side-nav" class="ui-resizable side-nav-resizable">
<div id="nav-tree">
<div id="nav-tree-contents">
<div id="nav-sync" class="sync"></div>
</div>
</div>
<div id="splitbar" style="-moz-user-select:none;"
class="ui-resizable-handle">
</div>
</div>
<script type="text/javascript">
$(document).ready(function(){initNavTree('md__python_usage.html','');});
</script>
<div id="doc-content">
<div class="header">
<div class="headertitle">
<div class="title">Use in Python </div> </div>
</div><!--header-->
<div class="contents">
<div class="textblock"><p>There's experimental support for reading FlatBuffers in Python. Generate code for Python with the <code>-p</code> option to <code>flatc</code>.</p>
<p>See <code>py_test.py</code> for an example. You import the generated code, read a FlatBuffer binary file into a <code>bytearray</code>, which you pass to the <code>GetRootAsMonster</code> function:</p>
<div class="fragment"><div class="line"><a name="l00001"></a><span class="lineno"> 1</span>&#160;import MyGame.Example <span class="keyword">as</span> example</div>
<div class="line"><a name="l00002"></a><span class="lineno"> 2</span>&#160;<span class="keyword">import</span> flatbuffers</div>
<div class="line"><a name="l00003"></a><span class="lineno"> 3</span>&#160;</div>
<div class="line"><a name="l00004"></a><span class="lineno"> 4</span>&#160;buf = open(<span class="stringliteral">&#39;monster.dat&#39;</span>, <span class="stringliteral">&#39;rb&#39;</span>).read()</div>
<div class="line"><a name="l00005"></a><span class="lineno"> 5</span>&#160;buf = bytearray(buf)</div>
<div class="line"><a name="l00006"></a><span class="lineno"> 6</span>&#160;monster = example.GetRootAsMonster(buf, 0)</div>
</div><!-- fragment --><p>Now you can access values like this:</p>
<div class="fragment"><div class="line"><a name="l00001"></a><span class="lineno"> 1</span>&#160;hp = monster.Hp()</div>
<div class="line"><a name="l00002"></a><span class="lineno"> 2</span>&#160;pos = monster.Pos()</div>
</div><!-- fragment --><p>To access vectors you pass an extra index to the vector field accessor. Then a second method with the same name suffixed by <code>Length</code> let's you know the number of elements you can access:</p>
<div class="fragment"><div class="line"><a name="l00001"></a><span class="lineno"> 1</span>&#160;<span class="keywordflow">for</span> i <span class="keywordflow">in</span> xrange(monster.InventoryLength()):</div>
<div class="line"><a name="l00002"></a><span class="lineno"> 2</span>&#160; monster.Inventory(i) <span class="comment"># do something here</span></div>
</div><!-- fragment --><p>You can also construct these buffers in Python using the functions found in the generated code, and the FlatBufferBuilder class:</p>
<div class="fragment"><div class="line"><a name="l00001"></a><span class="lineno"> 1</span>&#160;builder = flatbuffers.Builder(0)</div>
</div><!-- fragment --><p>Create strings:</p>
<div class="fragment"><div class="line"><a name="l00001"></a><span class="lineno"> 1</span>&#160;s = builder.CreateString(<span class="stringliteral">&quot;MyMonster&quot;</span>)</div>
</div><!-- fragment --><p>Create a table with a struct contained therein:</p>
<div class="fragment"><div class="line"><a name="l00001"></a><span class="lineno"> 1</span>&#160;example.MonsterStart(builder)</div>
<div class="line"><a name="l00002"></a><span class="lineno"> 2</span>&#160;example.MonsterAddPos(builder, example.CreateVec3(builder, 1.0, 2.0, 3.0, 3.0, 4, 5, 6))</div>
<div class="line"><a name="l00003"></a><span class="lineno"> 3</span>&#160;example.MonsterAddHp(builder, 80)</div>
<div class="line"><a name="l00004"></a><span class="lineno"> 4</span>&#160;example.MonsterAddName(builder, str)</div>
<div class="line"><a name="l00005"></a><span class="lineno"> 5</span>&#160;example.MonsterAddInventory(builder, inv)</div>
<div class="line"><a name="l00006"></a><span class="lineno"> 6</span>&#160;example.MonsterAddTest_Type(builder, 1)</div>
<div class="line"><a name="l00007"></a><span class="lineno"> 7</span>&#160;example.MonsterAddTest(builder, mon2)</div>
<div class="line"><a name="l00008"></a><span class="lineno"> 8</span>&#160;example.MonsterAddTest4(builder, test4s)</div>
<div class="line"><a name="l00009"></a><span class="lineno"> 9</span>&#160;mon = example.MonsterEnd(builder)</div>
<div class="line"><a name="l00010"></a><span class="lineno"> 10</span>&#160;</div>
<div class="line"><a name="l00011"></a><span class="lineno"> 11</span>&#160;final_flatbuffer = builder.Output()</div>
</div><!-- fragment --><p>Unlike C++, Python does not support table creation functions like 'createMonster()'. This is to create the buffer without using temporary object allocation (since the <code>Vec3</code> is an inline component of <code>Monster</code>, it has to be created right where it is added, whereas the name and the inventory are not inline, and <b>must</b> be created outside of the table creation sequence). Structs do have convenient methods that allow you to construct them in one call. These also have arguments for nested structs, e.g. if a struct has a field <code>a</code> and a nested struct field <code>b</code> (which has fields <code>c</code> and <code>d</code>), then the arguments will be <code>a</code>, <code>c</code> and <code>d</code>.</p>
<p>Vectors also use this start/end pattern to allow vectors of both scalar types and structs:</p>
<div class="fragment"><div class="line"><a name="l00001"></a><span class="lineno"> 1</span>&#160;example.MonsterStartInventoryVector(builder, 5)</div>
<div class="line"><a name="l00002"></a><span class="lineno"> 2</span>&#160;i = 4</div>
<div class="line"><a name="l00003"></a><span class="lineno"> 3</span>&#160;<span class="keywordflow">while</span> i &gt;= 0:</div>
<div class="line"><a name="l00004"></a><span class="lineno"> 4</span>&#160; builder.PrependByte(byte(i))</div>
<div class="line"><a name="l00005"></a><span class="lineno"> 5</span>&#160; i -= 1</div>
<div class="line"><a name="l00006"></a><span class="lineno"> 6</span>&#160;</div>
<div class="line"><a name="l00007"></a><span class="lineno"> 7</span>&#160;inv = builder.EndVector(5)</div>
</div><!-- fragment --><p>The generated method 'StartInventoryVector' is provided as a convenience function which calls 'StartVector' with the correct element size of the vector type which in this case is 'ubyte' or 1 byte per vector element. You pass the number of elements you want to write. You write the elements backwards since the buffer is being constructed back to front. Use the correct <code>Prepend</code> call for the type, or <code>PrependUOffsetT</code> for offsets. You then pass <code>inv</code> to the corresponding <code>Add</code> call when you construct the table containing it afterwards.</p>
<p>There are <code>Prepend</code> functions for all the scalar types. You use <code>PrependUOffset</code> for any previously constructed objects (such as other tables, strings, vectors). For structs, you use the appropriate <code>create</code> function in-line, as shown above in the <code>Monster</code> example.</p>
<p>Once you're done constructing a buffer, you call <code>Finish</code> with the root object offset (<code>mon</code> in the example above). Your data now resides in Builder.Bytes. Important to note is that the real data starts at the index indicated by Head(), for Offset() bytes (this is because the buffer is constructed backwards). If you wanted to read the buffer right after creating it (using <code>GetRootAsMonster</code> above), the second argument, instead of <code>0</code> would thus also be <code>Head()</code>.</p>
<h2>Text Parsing</h2>
<p>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. </p>
</div></div><!-- contents -->
</div><!-- doc-content -->
<!-- Google Analytics -->
<script>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
ga('create', 'UA-49880327-7', 'auto');
ga('send', 'pageview');
</script>
</body>
</html>

View File

@@ -1,3 +1,4 @@
<!-- HTML header for doxygen 1.8.6-->
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
@@ -15,17 +16,24 @@
$(document).ready(initResizable);
$(window).load(resizeHeight);
</script>
<link href="doxygen.css" rel="stylesheet" type="text/css" />
<link href="style.css" rel="stylesheet" type="text/css" />
<link href="https://fonts.googleapis.com/css?family=Roboto:300,400,400italic,500,500italic,700,700italic|Roboto+Mono:400,700" rel="stylesheet">
</head>
<body>
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
<div id="titlearea">
<div id="titlearea" style="height: 110px;">
<table cellspacing="0" cellpadding="0">
<tbody>
<tr style="height: 56px;">
<td id="commonprojectlogo">
<img alt="Logo" src="fpl_logo_small.png"/>
</td>
<td style="padding-left: 0.5em;">
<div id="projectname">FlatBuffers
</div>
<div style="font-size:12px;">
An open source project by <a href="https://developers.google.com/games/#Tools">FPL</a>.
</div>
</td>
</tr>
</tbody>
@@ -108,7 +116,8 @@ root_type Monster;
</ul>
<p>You can't change types of fields once they're used, with the exception of same-size data where a <code>reinterpret_cast</code> would give you a desirable result, e.g. you could change a <code>uint</code> to an <code>int</code> if no values in current data use the high bit yet.</p>
<h3>(Default) Values</h3>
<p>Values are a sequence of digits, optionally followed by a <code>.</code> and more digits for float constants, and optionally prefixed by a <code>-</code>. Non-scalar defaults are currently not supported (always NULL).</p>
<p>Values are a sequence of digits, optionally followed by a <code>.</code> and more digits for float constants, and optionally prefixed by a <code>-</code>. Floats may end with an <code>e</code> or <code>E</code>, followed by a <code>+</code> or <code>-</code> and more digits (scientific notation).</p>
<p>Only scalar values can have defaults, non-scalar (string/vector/table) fields default to NULL when not present.</p>
<p>You generally do not want to change default values after they're initially defined. Fields that have the default value are not actually stored in the serialized data but are generated in code, so when you change the default, you'd now get a different value than from code generated from an older version of the schema. There are situations however where this may be desirable, especially if you can ensure a simultaneous rebuild of all code.</p>
<h3>Enums</h3>
<p>Define a sequence of named constants, each with a given value, or increasing by one from the previous one. The default first value is <code>0</code>. As you can see in the enum declaration, you specify the underlying integral type of the enum with <code>:</code> (in this case <code>byte</code>), which then determines the type of any fields declared with this enum type.</p>

122
docs/html/md__support.html Normal file
View File

@@ -0,0 +1,122 @@
<!-- HTML header for doxygen 1.8.6-->
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=9"/>
<meta name="generator" content="Doxygen 1.8.7"/>
<title>FlatBuffers: Platform / Language / Feature support</title>
<link href="tabs.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript" src="dynsections.js"></script>
<link href="navtree.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="resize.js"></script>
<script type="text/javascript" src="navtree.js"></script>
<script type="text/javascript">
$(document).ready(initResizable);
$(window).load(resizeHeight);
</script>
<link href="style.css" rel="stylesheet" type="text/css" />
<link href="https://fonts.googleapis.com/css?family=Roboto:300,400,400italic,500,500italic,700,700italic|Roboto+Mono:400,700" rel="stylesheet">
</head>
<body>
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
<div id="titlearea" style="height: 110px;">
<table cellspacing="0" cellpadding="0">
<tbody>
<tr style="height: 56px;">
<td id="commonprojectlogo">
<img alt="Logo" src="fpl_logo_small.png"/>
</td>
<td style="padding-left: 0.5em;">
<div id="projectname">FlatBuffers
</div>
<div style="font-size:12px;">
An open source project by <a href="https://developers.google.com/games/#Tools">FPL</a>.
</div>
</td>
</tr>
</tbody>
</table>
</div>
<!-- end header part -->
<!-- Generated by Doxygen 1.8.7 -->
</div><!-- top -->
<div id="side-nav" class="ui-resizable side-nav-resizable">
<div id="nav-tree">
<div id="nav-tree-contents">
<div id="nav-sync" class="sync"></div>
</div>
</div>
<div id="splitbar" style="-moz-user-select:none;"
class="ui-resizable-handle">
</div>
</div>
<script type="text/javascript">
$(document).ready(function(){initNavTree('md__support.html','');});
</script>
<div id="doc-content">
<div class="header">
<div class="headertitle">
<div class="title">Platform / Language / Feature support </div> </div>
</div><!--header-->
<div class="contents">
<div class="textblock"><p>FlatBuffers is actively being worked on, which means that certain platform / language / feature combinations may not be available yet.</p>
<p>This page tries to track those issues, to make informed decisions easier. In general:</p>
<ul>
<li>Languages: language support beyond the ones created by the original FlatBuffer authors typically depends on community contributions.</li>
<li>Features: C++ was the first language supported, since our original target was high performance game development. It thus has the richest feature set, and is likely most robust. Other languages are catching up however.</li>
<li>Platforms: All language implementations are typically portable to most platforms, unless where noted otherwise.</li>
</ul>
<p>NOTE: this table is a start, it needs to be extended.</p>
<table class="doxtable">
<tr>
<th>Feature </th><th>C++ </th><th>Java </th><th>C# </th><th>Go </th><th>Python </th><th>JS </th></tr>
<tr>
<td>Codegen for all basic features </td><td>Yes </td><td>Yes </td><td>Yes </td><td>Yes </td><td>Yes </td><td>WIP </td></tr>
<tr>
<td>JSON parsing </td><td>Yes </td><td>No </td><td>No </td><td>No </td><td>No </td><td>No </td></tr>
<tr>
<td>Simple mutation </td><td>Yes </td><td>WIP </td><td>WIP </td><td>No </td><td>No </td><td>No </td></tr>
<tr>
<td>Reflection </td><td>Yes </td><td>No </td><td>No </td><td>No </td><td>No </td><td>No </td></tr>
<tr>
<td>Buffer verifier </td><td>Yes </td><td>No </td><td>No </td><td>No </td><td>No </td><td>No </td></tr>
<tr>
<td>Testing: basic </td><td>Yes </td><td>Yes </td><td>Yes </td><td>Yes </td><td>Yes </td><td>WIP </td></tr>
<tr>
<td>Testing: fuzz </td><td>Yes </td><td>No </td><td>No </td><td>Yes </td><td>Yes </td><td>No </td></tr>
<tr>
<td>Performance: </td><td>Superb </td><td>Great </td><td>Great </td><td>Great </td><td>Ok </td><td>? </td></tr>
<tr>
<td>Platform: Windows </td><td>VS2010 </td><td>Yes </td><td>Yes </td><td>? </td><td>? </td><td>? </td></tr>
<tr>
<td>Platform: Linux </td><td>GCC282 </td><td>Yes </td><td>? </td><td>Yes </td><td>Yes </td><td>? </td></tr>
<tr>
<td>Platform: OS X </td><td>Xcode4 </td><td>? </td><td>? </td><td>? </td><td>Yes </td><td>? </td></tr>
<tr>
<td>Platform: Android </td><td>NDK10d </td><td>Yes </td><td>? </td><td>? </td><td>? </td><td>? </td></tr>
<tr>
<td>Platform: iOS </td><td>? </td><td>? </td><td>? </td><td>? </td><td>? </td><td>? </td></tr>
<tr>
<td>Engine: Unity </td><td>? </td><td>? </td><td>Yes </td><td>? </td><td>? </td><td>? </td></tr>
<tr>
<td>Primary authors (github) </td><td>wvo </td><td>wvo </td><td>(ev/js)</td><td>rw </td><td>rw </td><td>(ev) </td></tr>
</table>
<ul>
<li>ev = evolutional</li>
<li>js = jonsimantov </li>
</ul>
</div></div><!-- contents -->
</div><!-- doc-content -->
<!-- Google Analytics -->
<script>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
ga('create', 'UA-49880327-7', 'auto');
ga('send', 'pageview');
</script>
</body>
</html>

View File

@@ -1,3 +1,4 @@
<!-- HTML header for doxygen 1.8.6-->
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
@@ -15,17 +16,24 @@
$(document).ready(initResizable);
$(window).load(resizeHeight);
</script>
<link href="doxygen.css" rel="stylesheet" type="text/css" />
<link href="style.css" rel="stylesheet" type="text/css" />
<link href="https://fonts.googleapis.com/css?family=Roboto:300,400,400italic,500,500italic,700,700italic|Roboto+Mono:400,700" rel="stylesheet">
</head>
<body>
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
<div id="titlearea">
<div id="titlearea" style="height: 110px;">
<table cellspacing="0" cellpadding="0">
<tbody>
<tr style="height: 56px;">
<td id="commonprojectlogo">
<img alt="Logo" src="fpl_logo_small.png"/>
</td>
<td style="padding-left: 0.5em;">
<div id="projectname">FlatBuffers
</div>
<div style="font-size:12px;">
An open source project by <a href="https://developers.google.com/games/#Tools">FPL</a>.
</div>
</td>
</tr>
</tbody>

View File

@@ -7,10 +7,12 @@ var NAVTREE =
[ "Use in C++", "md__cpp_usage.html", null ],
[ "Use in Go", "md__go_usage.html", null ],
[ "Use in Java/C-sharp", "md__java_usage.html", null ],
[ "Use in Python", "md__python_usage.html", null ],
[ "Platform / Language / Feature support", "md__support.html", null ],
[ "Benchmarks", "md__benchmarks.html", null ],
[ "FlatBuffers white paper", "md__white_paper.html", null ],
[ "FlatBuffer Internals", "md__internals.html", null ],
[ "Formal Grammar of the schema language", "md__grammar.html", null ]
[ "Grammar of the schema language", "md__grammar.html", null ]
] ]
];

View File

@@ -1,15 +1,17 @@
var NAVTREEINDEX0 =
{
"index.html":[],
"md__benchmarks.html":[6],
"md__benchmarks.html":[8],
"md__building.html":[0],
"md__compiler.html":[1],
"md__cpp_usage.html":[3],
"md__go_usage.html":[4],
"md__grammar.html":[9],
"md__internals.html":[8],
"md__grammar.html":[11],
"md__internals.html":[10],
"md__java_usage.html":[5],
"md__python_usage.html":[6],
"md__schemas.html":[2],
"md__white_paper.html":[7],
"md__support.html":[7],
"md__white_paper.html":[9],
"pages.html":[]
};

View File

@@ -1,3 +1,4 @@
<!-- HTML header for doxygen 1.8.6-->
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
@@ -15,17 +16,24 @@
$(document).ready(initResizable);
$(window).load(resizeHeight);
</script>
<link href="doxygen.css" rel="stylesheet" type="text/css" />
<link href="style.css" rel="stylesheet" type="text/css" />
<link href="https://fonts.googleapis.com/css?family=Roboto:300,400,400italic,500,500italic,700,700italic|Roboto+Mono:400,700" rel="stylesheet">
</head>
<body>
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
<div id="titlearea">
<div id="titlearea" style="height: 110px;">
<table cellspacing="0" cellpadding="0">
<tbody>
<tr style="height: 56px;">
<td id="commonprojectlogo">
<img alt="Logo" src="fpl_logo_small.png"/>
</td>
<td style="padding-left: 0.5em;">
<div id="projectname">FlatBuffers
</div>
<div style="font-size:12px;">
An open source project by <a href="https://developers.google.com/games/#Tools">FPL</a>.
</div>
</td>
</tr>
</tbody>
@@ -61,10 +69,12 @@ $(document).ready(function(){initNavTree('pages.html','');});
<tr id="row_3_"><td class="entry"><span style="width:16px;display:inline-block;">&#160;</span><a class="el" href="md__cpp_usage.html" target="_self">Use in C++</a></td><td class="desc"></td></tr>
<tr id="row_4_" class="even"><td class="entry"><span style="width:16px;display:inline-block;">&#160;</span><a class="el" href="md__go_usage.html" target="_self">Use in Go</a></td><td class="desc"></td></tr>
<tr id="row_5_"><td class="entry"><span style="width:16px;display:inline-block;">&#160;</span><a class="el" href="md__java_usage.html" target="_self">Use in Java/C-sharp</a></td><td class="desc"></td></tr>
<tr id="row_6_" class="even"><td class="entry"><span style="width:16px;display:inline-block;">&#160;</span><a class="el" href="md__benchmarks.html" target="_self">Benchmarks</a></td><td class="desc"></td></tr>
<tr id="row_7_"><td class="entry"><span style="width:16px;display:inline-block;">&#160;</span><a class="el" href="md__white_paper.html" target="_self">FlatBuffers white paper</a></td><td class="desc"></td></tr>
<tr id="row_8_" class="even"><td class="entry"><span style="width:16px;display:inline-block;">&#160;</span><a class="el" href="md__internals.html" target="_self">FlatBuffer Internals</a></td><td class="desc"></td></tr>
<tr id="row_9_"><td class="entry"><span style="width:16px;display:inline-block;">&#160;</span><a class="el" href="md__grammar.html" target="_self">Formal Grammar of the schema language</a></td><td class="desc"></td></tr>
<tr id="row_6_" class="even"><td class="entry"><span style="width:16px;display:inline-block;">&#160;</span><a class="el" href="md__python_usage.html" target="_self">Use in Python</a></td><td class="desc"></td></tr>
<tr id="row_7_"><td class="entry"><span style="width:16px;display:inline-block;">&#160;</span><a class="el" href="md__support.html" target="_self">Platform / Language / Feature support</a></td><td class="desc"></td></tr>
<tr id="row_8_" class="even"><td class="entry"><span style="width:16px;display:inline-block;">&#160;</span><a class="el" href="md__benchmarks.html" target="_self">Benchmarks</a></td><td class="desc"></td></tr>
<tr id="row_9_"><td class="entry"><span style="width:16px;display:inline-block;">&#160;</span><a class="el" href="md__white_paper.html" target="_self">FlatBuffers white paper</a></td><td class="desc"></td></tr>
<tr id="row_10_" class="even"><td class="entry"><span style="width:16px;display:inline-block;">&#160;</span><a class="el" href="md__internals.html" target="_self">FlatBuffer Internals</a></td><td class="desc"></td></tr>
<tr id="row_11_"><td class="entry"><span style="width:16px;display:inline-block;">&#160;</span><a class="el" href="md__grammar.html" target="_self">Grammar of the schema language</a></td><td class="desc"></td></tr>
</table>
</div><!-- directory -->
</div><!-- contents -->

396
docs/html/style.css Normal file
View File

@@ -0,0 +1,396 @@
body,
#projectname,
table,
div,
p,
dl,
.title,
.tabs,
.tabs2,
.tabs3,
#nav-tree .label {
font-family: roboto, sans-serif;
}
#commonprojectlogo {
padding: 5px 0px 5px 15px;
}
#projectname {
color: #00bcd4;
font-size: 280%;
padding: 15px 0px;
font-weight: 300;
}
#titlearea {
border-bottom: 2px solid #e5e5e5;
}
.title {
color: #212121;
font: 300 34px/40px Roboto,sans-serif;
}
#nav-tree {
background-color: #fff;
}
#navrow1, #navrow2 {
border-bottom: 2px solid #e7e7e7;
}
.tabs, .tabs2, .tabs3 {
font-size: 14px;
}
.tabs,
.tabs2,
.tabs3,
.tablist li,
.tablist li.current a {
background-image: none;
}
.tablist {
list-style: none;
}
.tablist li, .tablist li p {
margin: 0;
}
.tablist li a,
.tablist li.current a {
color: #757575;
text-shadow: none;
}
.tablist li.current a {
background: #00bcd4;
color: #fff;
}
.tablist a {
background-image: none;
border-right: 2px solid #e5e5e5;
font-weight: normal;
}
.tablist a:hover,
.tablist li.current a:hover {
background-image: none;
text-decoration: underline;
text-shadow: none;
}
.tablist a:hover {
color: #00bcd4;
}
.tablist li.current a:hover {
color: #fff;
}
div.header {
background-color: #f7f7f7;
background-image: none;
border-bottom: none;
}
#MSearchBox {
border: 1px solid #ccc;
border-radius: 5px;
display: inline-block;
height: 20px;
right: 10px;
}
#MSearchBox .left,
#MSearchBox .right,
#MSearchField {
background: none;
}
a.SelectItem:hover {
background-color: #00bcd4;
}
#nav-tree {
background-image: none;
}
#nav-tree .selected {
background-image: none;
text-shadow: none;
background-color: #f7f7f7;
}
#nav-tree a {
color: #212121;
}
#nav-tree .selected a {
color: #0288d1;
}
#nav-tree .item:hover {
background-color: #f7f7f7;
}
#nav-tree .item:hover a {
color: #0288d1;
}
#nav-tree .label {
font-size: 13px;
}
#nav-sync {
display: none;
}
.ui-resizable-e {
background: #ebebeb;
border-left: 1px solid #ddd;
border-right: 1px solid #ddd;
}
.contents tr td .image {
margin-top: 24px;
}
.image {
text-align: left;
margin-bottom: 8px;
}
a:link,
a:visited,
.contents a:link,
.contents a:visited,
a.el {
color: #0288d1;
font-weight: normal;
text-decoration: none;
}
div.contents {
margin-right: 12px;
}
.directory tr, .directory tr.even {
background: #7cb342;
border-top: 1px solid #7cb342;
}
.directory td,
.directory td.entry,
.directory td.desc {
background: rgba(255,255,255,.95);
border-left: none;
color: #212121;
padding-top: 10px;
padding-bottom: 10px;
padding-left: 8px;
padding-right: 8px;
}
.directory tr#row_0_ {
border-top-color: #7cb342;
}
.directory tr#row_0_ td {
background: #7cb342;
color: #fff;
font-size: 18px;
}
.memSeparator {
border-bottom: none;
}
.memitem {
background: #7cb342;
}
.memproto, dl.reflist dt {
background: #7cb342;
background-image: none;
border: none;
box-shadow: none;
-webkit-box-shadow: none;
color: #fff;
text-shadow: none;
}
.memproto .memtemplate,
.memproto a.el,
.memproto .paramname {
color: #fff;
}
.memdoc, dl.reflist dd {
border: none;
background-color: rgba(255,255,255,.95);
background-image: none;
box-shadow: none;
-webkit-box-shadow: none;
-webkit-border-bottom-left-radius: 0;
-webkit-border-bottom-right-radius: 0;
}
.memitem, table.doxtable, table.memberdecls {
margin-bottom: 24px;
}
table.doxtable th {
background: #7cb342;
}
table.doxtable tr {
background: #7cb342;
border-top: 1px solid #7cb342;
}
table.doxtable td, table.doxtable th {
border: none;
padding: 10px 8px;
}
table.doxtable td {
background-color: rgba(255,255,255,.95);
}
.memberdecls {
background: #7cb342;
border-top: 1px solid #7cb342;
}
.memberdecls .heading h2 {
border-bottom: none;
color: #fff;
font-size: 110%;
font-weight: bold;
margin: 0 0 0 6px;
}
.memberdecls tr:not(.heading) td {
background-color: rgba(255,255,255,.95);
}
h1, h2, h2.groupheader, h3, h4, h5, h6 {
color: #212121;
}
h1 {
border-bottom: 1px solid #ebebeb;
font: 400 28px/32px Roboto,sans-serif;
letter-spacing: -.01em;
margin: 40px 0 20px;
padding-bottom: 3px;
}
h2, h2.groupheader {
border-bottom: 1px solid #ebebeb;
font: 400 23px/32px Roboto,sans-serif;
letter-spacing: -.01em;
margin: 40px 0 20px;
padding-bottom: 3px;
}
h3 {
font: 500 20px/32px Roboto,sans-serif;
margin: 32px 0 16px;
}
h4 {
font: 500 18px/32px Roboto,sans-serif;
margin: 32px 0 16px;
}
ol,
ul {
margin: 0;
padding-left: 40px;
}
ol {
list-style: decimal outside;
}
ol ol {
list-style-type: lower-alpha;
}
ol ol ol {
list-style-type: lower-roman;
}
ul {
list-style: disc outside;
}
li,
li p {
margin: 8px 0;
padding: 0;
}
div.summary
{
float: none;
font-size: 8pt;
padding-left: 5px;
width: calc(100% - 10px);
text-align: left;
display: block;
}
div.ingroups {
margin-top: 8px;
}
div.fragment {
border: 1px solid #ddd;
color: #455a64;
font: 14px/20px Roboto Mono, monospace;
padding: 8px;
}
div.line {
line-height: 1.5;
font-size: inherit;
}
code, pre {
color: #455a64;
background: #f7f7f7;
font: 400 100%/1 Roboto Mono,monospace;
padding: 1px 4px;
}
span.preprocessor, span.comment {
color: #0b8043;
}
span.keywordtype {
color: #0097a7;
}
.paramname {
color: #ef6c00;
}
.memTemplParams {
color: #ef6c00;
}
span.mlabel {
background: rgba(255,255,255,.25);
border: none;
}
blockquote {
border: 1px solid #ddd;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

BIN
docs/images/ftv2mnode.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

BIN
docs/images/ftv2pnode.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

@@ -39,7 +39,7 @@ meant to be representative of game data, e.g. a scene format.
optional fields to allow deprecating fields or serializing with missing
fields for which defaults exist).
It currently also isn't fully cross-platform portable (lack of VS support).
- msgpack: has very minimal forwards/backwards compatability support when used
- msgpack: has very minimal forwards/backwards compatibility support when used
with the typed C++ interface. Also lacks VS2010 support.
- Thrift: very similar to Protocol Buffers, but appears to be less efficient,
and have more dependencies.

View File

@@ -41,19 +41,44 @@ be generated for each file processed:
fail (or none are specified) it will try to load relative to the path of
the schema file being parsed.
- `-M` : Print make rules for generated files.
- `--strict-json` : Require & generate strict JSON (field names are enclosed
in quotes, no trailing commas in tables/vectors). By default, no quotes are
required/generated, and trailing commas are allowed.
- `--defaults-json` : Output fields whose value is equal to the default value
when writing JSON text.
- `--no-prefix` : Don't prefix enum values in generated C++ by their enum
type.
- `--gen-includes` : Generate include statements for included schemas the
- `--scoped-enums` : Use C++11 style scoped and strongly typed enums in
generated C++. This also implies `--no-prefix`.
- `--gen-includes` : (deprecated), this is the default behavior.
If the original behavior is required (no include
statements) use `--no-includes.`
- `--no-includes` : Don't generate include statements for included schemas the
generated file depends on (C++).
- `--gen-mutable` : Generate additional non-const accessors for mutating
FlatBuffers in-place.
- `--gen-onefile` : Generate single output file (useful for C#)
- `--raw-binary` : Allow binaries without a file_indentifier to be read.
This may crash flatc given a mismatched schema.
- `--proto`: Expect input files to be .proto files (protocol buffers).
Output the corresponding .fbs file.
Currently supports: `package`, `message`, `enum`.
Does not support, but will skip without error: `import`, `option`.
Does not support, will generate error: `service`, `extend`, `extensions`,
`oneof`, `group`, custom options, nested declarations.
Currently supports: `package`, `message`, `enum`, nested declarations,
`import` (use `-I` for paths), `extend`, `oneof`, `group`.
Does not support, but will skip without error: `option`, `service`,
`extensions`, and most everything else.
- `--schema`: Serialize schemas instead of JSON (use with -b). This will
output a binary version of the specified schema that itself corresponds
to the reflection/reflection.fbs schema. Loading this binary file is the
basis for reflection functionality.

View File

@@ -72,7 +72,9 @@ since they won't bloat up the buffer sizes if they're not actually used.
We do something similarly for the union field `test` by specifying a `0` offset
and the `NONE` enum value (part of every union) to indicate we don't actually
want to write this field. You can use `0` also as a default for other
non-scalar types, such as strings, vectors and tables.
non-scalar types, such as strings, vectors and tables. To pass an actual
table, pass a preconstructed table as `mytable.Union()` that corresponds to
union enum you're passing.
Tables (like `Monster`) give you full flexibility on what fields you write
(unlike `Vec3`, which always has all fields set because it is a `struct`).
@@ -163,6 +165,75 @@ Similarly, we can access elements of the inventory array:
assert(inv->Get(9) == 9);
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
### Mutating FlatBuffers
As you saw above, typically once you have created a FlatBuffer, it is
read-only from that moment on. There are however cases where you have just
received a FlatBuffer, and you'd like to modify something about it before
sending it on to another recipient. With the above functionality, you'd have
to generate an entirely new FlatBuffer, while tracking what you modify in your
own data structures. This is inconvenient.
For this reason FlatBuffers can also be mutated in-place. While this is great
for making small fixes to an existing buffer, you generally want to create
buffers from scratch whenever possible, since it is much more efficient and
the API is much more general purpose.
To get non-const accessors, invoke `flatc` with `--gen-mutable`.
Similar to the reading API above, you now can:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
auto monster = GetMutableMonster(buffer_pointer); // non-const
monster->mutate_hp(10); // Set table field.
monster->mutable_pos()->mutate_z(4); // Set struct field.
monster->mutable_inventory()->Mutate(0, 1); // Set vector element.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
We use the somewhat verbose term `mutate` instead of `set` to indicate that
this is a special use case, not to be confused with the default way of
constructing FlatBuffer data.
After the above mutations, you can send on the FlatBuffer to a new recipient
without any further work!
Note that any `mutate_` functions on tables return a bool, which is false
if the field we're trying to set isn't present in the buffer. Fields are not
present if they weren't set, or even if they happen to be equal to the
default value. For example, in the creation code above we set the `mana` field
to `150`, which is the default value, so it was never stored in the buffer.
Trying to call mutate_mana() on such data will return false, and the value won't
actually be modified!
One way to solve this is to call `ForceDefaults()` on a
`FlatBufferBuilder` to force all fields you set to actually be written. This
of course increases the size of the buffer somewhat, but this may be
acceptable for a mutable buffer.
Alternatively, you can use the more powerful reflection functionality:
### Reflection (& Resizing)
If the above ways of accessing a buffer are still too static for you, 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 moment you can find in `test.cpp/ReflectionTest()`.
### Storing maps / dictionaries in a FlatBuffer
FlatBuffers doesn't support maps natively, but there is support to

View File

@@ -4,7 +4,8 @@ FlatBuffers is an efficient cross platform serialization library for C++,
with support for Java, C# and Go. It was created at Google specifically for game
development and other performance-critical applications.
It is available as open source under the Apache license, v2 (see LICENSE.txt).
It is available as Open Source on [GitHub](http://github.com/google/flatbuffers)
under the Apache license, v2 (see LICENSE.txt).
## Why use FlatBuffers?
@@ -75,6 +76,17 @@ little to no information ahead of time about what data needs to be stored.
Read more about the "why" of FlatBuffers in the
[white paper](md__white_paper.html).
### Who uses FlatBuffers?
- [Cocos2d-x](http://www.cocos2d-x.org/), the #1 open source mobile game
engine, uses it to serialize all their
[game data](http://www.cocos2d-x.org/reference/native-cpp/V3.5/d7/d2d/namespaceflatbuffers.html).
- [Facebook](http://facebook.com/) uses it for client-server communication in
their Android app. They have a nice
[article](https://code.facebook.com/posts/872547912839369/improving-facebook-s-performance-on-android-with-flatbuffers/)
explaining how it speeds up loading their posts.
- [Fun Propulsion Labs](https://developers.google.com/games/#Tools)
at Google uses it extensively in all their libraries and games.
## Usage in brief
This section is a quick rundown of how to use this system. Subsequent
@@ -88,8 +100,8 @@ sections provide a more in-depth usage guide.
present for every object instance.
- Use `flatc` (the FlatBuffer compiler) to generate a C++ header (or
Java/C#/Go classes) with helper classes to access and construct serialized
data. This header (say `mydata_generated.h`) only depends on
Java/C#/Go/Python.. classes) with helper classes to access and construct
serialized data. This header (say `mydata_generated.h`) only depends on
`flatbuffers.h`, which defines the core functionality.
- Use the `FlatBufferBuilder` class to construct a flat binary buffer.
@@ -114,6 +126,7 @@ sections provide a more in-depth usage guide.
programs.
- How to [use the generated Go code](md__go_usage.html) in your own
programs.
- [Support matrix](md__support.html) for platforms/languages/features.
- Some [benchmarks](md__benchmarks.html) showing the advantage of using
FlatBuffers.
- A [white paper](md__white_paper.html) explaining the "why" of FlatBuffers.
@@ -122,7 +135,15 @@ sections provide a more in-depth usage guide.
## Online resources
- [github repository](http://github.com/google/flatbuffers)
- [landing page](http://google.github.io/flatbuffers)
- [GitHub repository](http://github.com/google/flatbuffers)
- [Landing page](http://google.github.io/flatbuffers)
- [FlatBuffers Google Group](http://group.google.com/group/flatbuffers)
- [FlatBuffers Issues Tracker](http://github.com/google/flatbuffers/issues)
- Videos:
- Colt's [DevByte](https://www.youtube.com/watch?v=iQTxMkSJ1dQ).
- GDC 2015 [Lightning Talk](https://www.youtube.com/watch?v=olmL1fUnQAQ).
- FlatBuffers for [Go](https://www.youtube.com/watch?v=-BPVId_lA5w).
- Evolution of FlatBuffers
[visualization](https://www.youtube.com/watch?v=a0QE0xS8rKM).
- Useful documentation created by others:
- [Using FlatBuffers in Unity](http://exiin.com/blog/flatbuffers-for-unity-sample-code/)

View File

@@ -1,7 +1,8 @@
# Formal Grammar of the schema language
# Grammar of the schema language
schema = include*
( namespace\_decl | type\_decl | enum\_decl | root\_decl |
file_extension_decl | file_identifier_decl |
attribute\_decl | object )*
include = `include` string\_constant `;`
@@ -17,7 +18,7 @@ enumval\_decl ) `}`
root\_decl = `root_type` ident `;`
field\_decl = type `:` ident [ `=` scalar ] metadata `;`
field\_decl = ident `:` type [ `=` scalar ] metadata `;`
type = `bool` | `byte` | `ubyte` | `short` | `ushort` | `int` | `uint` |
`float` | `long` | `ulong` | `double`
@@ -25,12 +26,22 @@ type = `bool` | `byte` | `ubyte` | `short` | `ushort` | `int` | `uint` |
enumval\_decl = ident [ `=` integer\_constant ]
metadata = [ `(` commasep( ident [ `:` scalar ] ) `)` ]
metadata = [ `(` commasep( ident [ `:` single\_value ] ) `)` ]
scalar = integer\_constant | float\_constant | `true` | `false`
scalar = integer\_constant | float\_constant
object = { commasep( ident `:` value ) }
value = scalar | object | string\_constant | `[` commasep( value ) `]`
single\_value = scalar | string\_constant
value = single\_value | object | `[` commasep( value ) `]`
commasep(x) = [ x ( `,` x )\* ]
file_extension_decl = `file_extension` string\_constant `;`
file_identifier_decl = `file_identifier` string\_constant `;`
integer\_constant = -?[0-9]+ | `true` | `false`
float\_constant = -?[0-9]+.[0-9]+((e|E)(+|-)?[0-9]+)?

View File

@@ -5,8 +5,8 @@ Generate code for Java with the `-j` option to `flatc`, or for C# with `-n`
(think .Net).
Note that this document is from the perspective of Java. Code for both languages
is generated in the same way, with only very subtle differences, for example
any `camelCase` Java call will be `CamelCase` in C#.
is generated in the same way, with only minor differences. These differences
are [explained in a section below](#differences-in-c-sharp).
See `javaTest.java` for an example. Essentially, you read a FlatBuffer binary
file into a `byte[]`, which you then turn into a `ByteBuffer`, which you pass to
@@ -109,7 +109,7 @@ Structs do have convenient methods that even have arguments for nested structs.
As you can see, references to other objects (e.g. the string above) are simple
ints, and thus do not have the type-safety of the Offset type in C++. Extra
case must thus be taken that you set the right offset on the right field.
care must thus be taken that you set the right offset on the right field.
Vectors can be created from the corresponding Java array like so:
@@ -151,8 +151,74 @@ not start from offset 0 in this buffer, but from `fbb.dataBuffer().position()`
It ends at `fbb.capacity()`.
## Text Parsing
## Differences in C-sharp
C# code works almost identically to Java, with only a few minor differences.
You can see an example of C# code in `tests/FlatBuffers.Test/FlatBuffersExampleTests.cs`.
First of all, 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 as in Java. 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);
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
## 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 JNI. Please see the
from Java or 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.
### Mutating FlatBuffers
As you saw above, typically once you have created a FlatBuffer, it is
read-only from that moment on. There are however cases where you have just
received a FlatBuffer, and you'd like to modify something about it before
sending it on to another recipient. With the above functionality, you'd have
to generate an entirely new FlatBuffer, while tracking what you modify in your
own data structures. This is inconvenient.
For this reason FlatBuffers can also be mutated in-place. While this is great
for making small fixes to an existing buffer, you generally want to create
buffers from scratch whenever possible, since it is much more efficient and
the API is much more general purpose.
To get non-const accessors, invoke `flatc` with `--gen-mutable`.
You now can:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.java}
Monster monster = Monster.getRootAsMonster(bb);
monster.mutateHp(10); // Set table field.
monster.pos().mutateZ(4); // Set struct field.
monster.mutateInventory(0, 1); // Set vector element.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
We use the somewhat verbose term `mutate` instead of `set` to indicate that
this is a special use case, not to be confused with the default way of
constructing FlatBuffer data.
After the above mutations, you can send on the FlatBuffer to a new recipient
without any further work!
Note that any `mutate` functions on tables return a boolean, which is false
if the field we're trying to set isn't present in the buffer. Fields are not
present if they weren't set, or even if they happen to be equal to the
default value. For example, in the creation code above we set the `mana` field
to `150`, which is the default value, so it was never stored in the buffer.
Trying to call mutateMana() on such data will return false, and the value won't
actually be modified!
One way to solve this is to call `forceDefaults()` on a
`FlatBufferBuilder` to force all fields you set to actually be written. This
of course increases the size of the buffer somewhat, but this may be
acceptable for a mutable buffer.

115
docs/source/PythonUsage.md Executable file
View File

@@ -0,0 +1,115 @@
# Use in Python
There's experimental support for reading FlatBuffers in Python. Generate
code for Python with the `-p` option to `flatc`.
See `py_test.py` for an example. You import the generated code, 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()
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
To access vectors you pass an extra index to the
vector field accessor. Then a second method with the same name suffixed
by `Length` let's you know the number of elements you can access:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.py}
for i in xrange(monster.InventoryLength()):
monster.Inventory(i) # do something here
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
You can also construct these buffers in Python using the functions found
in the generated code, and the FlatBufferBuilder class:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.py}
builder = flatbuffers.Builder(0)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Create strings:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.py}
s = builder.CreateString("MyMonster")
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Create a table with a struct contained therein:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.py}
example.MonsterStart(builder)
example.MonsterAddPos(builder, example.CreateVec3(builder, 1.0, 2.0, 3.0, 3.0, 4, 5, 6))
example.MonsterAddHp(builder, 80)
example.MonsterAddName(builder, str)
example.MonsterAddInventory(builder, inv)
example.MonsterAddTest_Type(builder, 1)
example.MonsterAddTest(builder, mon2)
example.MonsterAddTest4(builder, test4s)
mon = example.MonsterEnd(builder)
final_flatbuffer = builder.Output()
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Unlike C++, Python does not support table creation functions like 'createMonster()'.
This is to create the buffer without
using temporary object allocation (since the `Vec3` is an inline component of
`Monster`, it has to be created right where it is added, whereas the name and
the inventory are not inline, and **must** be created outside of the table
creation sequence).
Structs do have convenient methods that allow you to construct them in one call.
These also have arguments for nested structs, e.g. if a struct has a field `a`
and a nested struct field `b` (which has fields `c` and `d`), then the arguments
will be `a`, `c` and `d`.
Vectors also use this start/end pattern to allow vectors of both scalar types
and structs:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.py}
example.MonsterStartInventoryVector(builder, 5)
i = 4
while i >= 0:
builder.PrependByte(byte(i))
i -= 1
inv = builder.EndVector(5)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The generated method 'StartInventoryVector' is provided as a convenience
function which calls 'StartVector' with the correct element size of the vector
type which in this case is 'ubyte' or 1 byte per vector element.
You pass the number of elements you want to write.
You write the elements backwards since the buffer
is being constructed back to front. Use the correct `Prepend` call for the type,
or `PrependUOffsetT` for offsets. You then pass `inv` to the corresponding
`Add` call when you construct the table containing it afterwards.
There are `Prepend` functions for all the scalar types. You use
`PrependUOffset` for any previously constructed objects (such as other tables,
strings, vectors). For structs, you use the appropriate `create` function
in-line, as shown above in the `Monster` example.
Once you're done constructing a buffer, you call `Finish` with the root object
offset (`mon` in the example above). Your data now resides in Builder.Bytes.
Important to note is that the real data starts at the index indicated by Head(),
for Offset() bytes (this is because the buffer is constructed backwards).
If you wanted to read the buffer right after creating it (using
`GetRootAsMonster` above), the second argument, instead of `0` would thus
also be `Head()`.
## 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.

View File

@@ -111,8 +111,11 @@ high bit yet.
### (Default) Values
Values are a sequence of digits, optionally followed by a `.` and more digits
for float constants, and optionally prefixed by a `-`. Non-scalar defaults are
currently not supported (always NULL).
for float constants, and optionally prefixed by a `-`. Floats may end with an
`e` or `E`, followed by a `+` or `-` and more digits (scientific notation).
Only scalar values can have defaults, non-scalar (string/vector/table) fields
default to NULL when not present.
You generally do not want to change default values after they're initially
defined. Fields that have the default value are not actually stored in the

39
docs/source/Support.md Executable file
View File

@@ -0,0 +1,39 @@
# Platform / Language / Feature support
FlatBuffers is actively being worked on, which means that certain platform /
language / feature combinations may not be available yet.
This page tries to track those issues, to make informed decisions easier.
In general:
* Languages: language support beyond the ones created by the original
FlatBuffer authors typically depends on community contributions.
* Features: C++ was the first language supported, since our original
target was high performance game development. It thus has the richest
feature set, and is likely most robust. Other languages are catching up
however.
* Platforms: All language implementations are typically portable to most
platforms, unless where noted otherwise.
NOTE: this table is a start, it needs to be extended.
Feature | C++ | Java | C# | Go | Python | JS
------------------------------ | ------ | ------ | ------ | ------ | ------ | ------
Codegen for all basic features | Yes | Yes | Yes | Yes | Yes | WIP
JSON parsing | Yes | No | No | No | No | No
Simple mutation | Yes | WIP | WIP | No | No | No
Reflection | Yes | No | No | No | No | No
Buffer verifier | Yes | No | No | No | No | No
Testing: basic | Yes | Yes | Yes | Yes | Yes | WIP
Testing: fuzz | Yes | No | No | Yes | Yes | No
Performance: | Superb | Great | Great | Great | Ok | ?
Platform: Windows | VS2010 | Yes | Yes | ? | ? | ?
Platform: Linux | GCC282 | Yes | ? | Yes | Yes | ?
Platform: OS X | Xcode4 | ? | ? | ? | Yes | ?
Platform: Android | NDK10d | Yes | ? | ? | ? | ?
Platform: iOS | ? | ? | ? | ? | ? | ?
Engine: Unity | ? | ? | Yes | ? | ? | ?
Primary authors (github) | wvo | wvo | (ev/js)| rw | rw | (ev)
* ev = evolutional
* js = jonsimantov

View File

@@ -750,6 +750,8 @@ INPUT = "FlatBuffers.md" \
"CppUsage.md" \
"GoUsage.md" \
"JavaUsage.md" \
"PythonUsage.md" \
"Support.md" \
"Benchmarks.md" \
"WhitePaper.md" \
"Internals.md" \
@@ -1105,7 +1107,7 @@ HTML_FILE_EXTENSION = .html
# of the possible markers and block names see the documentation.
# This tag requires that the tag GENERATE_HTML is set to YES.
HTML_HEADER =
HTML_HEADER = ../header.html
# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each
# generated HTML page. If the tag is left blank doxygen will generate a standard
@@ -1127,7 +1129,7 @@ HTML_FOOTER = ../footer.html
# obsolete.
# This tag requires that the tag GENERATE_HTML is set to YES.
HTML_STYLESHEET =
HTML_STYLESHEET = style.css
# The HTML_EXTRA_STYLESHEET tag can be used to specify an additional user-
# defined cascading style sheet that is included after the standard style sheets
@@ -1148,7 +1150,7 @@ HTML_EXTRA_STYLESHEET =
# files will be copied as-is; there are no commands or markers available.
# This tag requires that the tag GENERATE_HTML is set to YES.
HTML_EXTRA_FILES =
HTML_EXTRA_FILES = ../images/fpl_logo_small.png ../images/ftv2mnode.png ../images/ftv2pnode.png
# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
# will adjust the colors in the stylesheet and background images according to

396
docs/source/style.css Normal file
View File

@@ -0,0 +1,396 @@
body,
#projectname,
table,
div,
p,
dl,
.title,
.tabs,
.tabs2,
.tabs3,
#nav-tree .label {
font-family: roboto, sans-serif;
}
#commonprojectlogo {
padding: 5px 0px 5px 15px;
}
#projectname {
color: #00bcd4;
font-size: 280%;
padding: 15px 0px;
font-weight: 300;
}
#titlearea {
border-bottom: 2px solid #e5e5e5;
}
.title {
color: #212121;
font: 300 34px/40px Roboto,sans-serif;
}
#nav-tree {
background-color: #fff;
}
#navrow1, #navrow2 {
border-bottom: 2px solid #e7e7e7;
}
.tabs, .tabs2, .tabs3 {
font-size: 14px;
}
.tabs,
.tabs2,
.tabs3,
.tablist li,
.tablist li.current a {
background-image: none;
}
.tablist {
list-style: none;
}
.tablist li, .tablist li p {
margin: 0;
}
.tablist li a,
.tablist li.current a {
color: #757575;
text-shadow: none;
}
.tablist li.current a {
background: #00bcd4;
color: #fff;
}
.tablist a {
background-image: none;
border-right: 2px solid #e5e5e5;
font-weight: normal;
}
.tablist a:hover,
.tablist li.current a:hover {
background-image: none;
text-decoration: underline;
text-shadow: none;
}
.tablist a:hover {
color: #00bcd4;
}
.tablist li.current a:hover {
color: #fff;
}
div.header {
background-color: #f7f7f7;
background-image: none;
border-bottom: none;
}
#MSearchBox {
border: 1px solid #ccc;
border-radius: 5px;
display: inline-block;
height: 20px;
right: 10px;
}
#MSearchBox .left,
#MSearchBox .right,
#MSearchField {
background: none;
}
a.SelectItem:hover {
background-color: #00bcd4;
}
#nav-tree {
background-image: none;
}
#nav-tree .selected {
background-image: none;
text-shadow: none;
background-color: #f7f7f7;
}
#nav-tree a {
color: #212121;
}
#nav-tree .selected a {
color: #0288d1;
}
#nav-tree .item:hover {
background-color: #f7f7f7;
}
#nav-tree .item:hover a {
color: #0288d1;
}
#nav-tree .label {
font-size: 13px;
}
#nav-sync {
display: none;
}
.ui-resizable-e {
background: #ebebeb;
border-left: 1px solid #ddd;
border-right: 1px solid #ddd;
}
.contents tr td .image {
margin-top: 24px;
}
.image {
text-align: left;
margin-bottom: 8px;
}
a:link,
a:visited,
.contents a:link,
.contents a:visited,
a.el {
color: #0288d1;
font-weight: normal;
text-decoration: none;
}
div.contents {
margin-right: 12px;
}
.directory tr, .directory tr.even {
background: #7cb342;
border-top: 1px solid #7cb342;
}
.directory td,
.directory td.entry,
.directory td.desc {
background: rgba(255,255,255,.95);
border-left: none;
color: #212121;
padding-top: 10px;
padding-bottom: 10px;
padding-left: 8px;
padding-right: 8px;
}
.directory tr#row_0_ {
border-top-color: #7cb342;
}
.directory tr#row_0_ td {
background: #7cb342;
color: #fff;
font-size: 18px;
}
.memSeparator {
border-bottom: none;
}
.memitem {
background: #7cb342;
}
.memproto, dl.reflist dt {
background: #7cb342;
background-image: none;
border: none;
box-shadow: none;
-webkit-box-shadow: none;
color: #fff;
text-shadow: none;
}
.memproto .memtemplate,
.memproto a.el,
.memproto .paramname {
color: #fff;
}
.memdoc, dl.reflist dd {
border: none;
background-color: rgba(255,255,255,.95);
background-image: none;
box-shadow: none;
-webkit-box-shadow: none;
-webkit-border-bottom-left-radius: 0;
-webkit-border-bottom-right-radius: 0;
}
.memitem, table.doxtable, table.memberdecls {
margin-bottom: 24px;
}
table.doxtable th {
background: #7cb342;
}
table.doxtable tr {
background: #7cb342;
border-top: 1px solid #7cb342;
}
table.doxtable td, table.doxtable th {
border: none;
padding: 10px 8px;
}
table.doxtable td {
background-color: rgba(255,255,255,.95);
}
.memberdecls {
background: #7cb342;
border-top: 1px solid #7cb342;
}
.memberdecls .heading h2 {
border-bottom: none;
color: #fff;
font-size: 110%;
font-weight: bold;
margin: 0 0 0 6px;
}
.memberdecls tr:not(.heading) td {
background-color: rgba(255,255,255,.95);
}
h1, h2, h2.groupheader, h3, h4, h5, h6 {
color: #212121;
}
h1 {
border-bottom: 1px solid #ebebeb;
font: 400 28px/32px Roboto,sans-serif;
letter-spacing: -.01em;
margin: 40px 0 20px;
padding-bottom: 3px;
}
h2, h2.groupheader {
border-bottom: 1px solid #ebebeb;
font: 400 23px/32px Roboto,sans-serif;
letter-spacing: -.01em;
margin: 40px 0 20px;
padding-bottom: 3px;
}
h3 {
font: 500 20px/32px Roboto,sans-serif;
margin: 32px 0 16px;
}
h4 {
font: 500 18px/32px Roboto,sans-serif;
margin: 32px 0 16px;
}
ol,
ul {
margin: 0;
padding-left: 40px;
}
ol {
list-style: decimal outside;
}
ol ol {
list-style-type: lower-alpha;
}
ol ol ol {
list-style-type: lower-roman;
}
ul {
list-style: disc outside;
}
li,
li p {
margin: 8px 0;
padding: 0;
}
div.summary
{
float: none;
font-size: 8pt;
padding-left: 5px;
width: calc(100% - 10px);
text-align: left;
display: block;
}
div.ingroups {
margin-top: 8px;
}
div.fragment {
border: 1px solid #ddd;
color: #455a64;
font: 14px/20px Roboto Mono, monospace;
padding: 8px;
}
div.line {
line-height: 1.5;
font-size: inherit;
}
code, pre {
color: #455a64;
background: #f7f7f7;
font: 400 100%/1 Roboto Mono,monospace;
padding: 1px 4px;
}
span.preprocessor, span.comment {
color: #0b8043;
}
span.keywordtype {
color: #0097a7;
}
.paramname {
color: #ef6c00;
}
.memTemplParams {
color: #ef6c00;
}
span.mlabel {
background: rgba(255,255,255,.25);
border: none;
}
blockquote {
border: 1px solid #ddd;
}

View File

@@ -8,11 +8,12 @@ package flatbuffers
type Builder struct {
Bytes []byte
minalign int
vtable []UOffsetT
objectEnd UOffsetT
vtables []UOffsetT
head UOffsetT
minalign int
vtable []UOffsetT
objectEnd UOffsetT
insideObject bool
vtables []UOffsetT
head UOffsetT
}
// NewBuilder initializes a Builder of size `initial_size`.
@@ -31,11 +32,40 @@ func NewBuilder(initialSize int) *Builder {
return b
}
// Reset truncates the underlying Builder buffer, facilitating alloc-free
// reuse of a Builder.
func (b *Builder) Reset() {
if b.Bytes != nil {
b.Bytes = b.Bytes[:cap(b.Bytes)]
}
if b.vtables != nil {
b.vtables = b.vtables[:0]
}
if b.vtable != nil {
b.vtable = b.vtable[:0]
}
b.head = UOffsetT(len(b.Bytes))
b.minalign = 1
}
// StartObject initializes bookkeeping for writing a new object.
func (b *Builder) StartObject(numfields int) {
b.notNested()
b.insideObject = true
// use 32-bit offsets so that arithmetic doesn't overflow.
b.vtable = make([]UOffsetT, numfields)
if cap(b.vtable) < numfields || b.vtable == nil {
b.vtable = make([]UOffsetT, numfields)
} else {
b.vtable = b.vtable[:numfields]
for i := 0; i < len(b.vtable); i++ {
b.vtable[i] = 0
}
}
b.objectEnd = b.Offset()
b.minalign = 1
}
@@ -137,16 +167,18 @@ func (b *Builder) WriteVtable() (n UOffsetT) {
SOffsetT(existingVtable)-SOffsetT(objectOffset))
}
b.vtable = nil
b.vtable = b.vtable[:0]
return objectOffset
}
// EndObject writes data necessary to finish object construction.
func (b *Builder) EndObject() UOffsetT {
if b.vtable == nil {
if !b.insideObject {
panic("not in object")
}
return b.WriteVtable()
n := b.WriteVtable()
b.insideObject = false
return n
}
// Doubles the size of the byteslice, and copies the old data towards the
@@ -155,13 +187,20 @@ func (b *Builder) growByteBuffer() {
if (int64(len(b.Bytes)) & int64(0xC0000000)) != 0 {
panic("cannot grow buffer beyond 2 gigabytes")
}
newSize := len(b.Bytes) * 2
if newSize == 0 {
newSize = 1
newLen := len(b.Bytes) * 2
if newLen == 0 {
newLen = 1
}
bytes2 := make([]byte, newSize)
copy(bytes2[newSize-len(b.Bytes):], b.Bytes)
b.Bytes = bytes2
if cap(b.Bytes) >= newLen {
b.Bytes = b.Bytes[:newLen]
} else {
extension := make([]byte, newLen-len(b.Bytes))
b.Bytes = append(b.Bytes, extension...)
}
middle := newLen / 2
copy(b.Bytes[middle:], b.Bytes[:middle])
}
// Head gives the start of useful data in the underlying byte buffer.
@@ -198,7 +237,7 @@ func (b *Builder) Prep(size, additionalBytes int) {
alignSize &= (size - 1)
// Reallocate the buffer if needed:
for int(b.head) < alignSize+size+additionalBytes {
for int(b.head) <= alignSize+size+additionalBytes {
oldBufSize := len(b.Bytes)
b.growByteBuffer()
b.head += UOffsetT(len(b.Bytes) - oldBufSize)
@@ -247,16 +286,32 @@ func (b *Builder) EndVector(vectorNumElems int) UOffsetT {
// CreateString writes a null-terminated string as a vector.
func (b *Builder) CreateString(s string) UOffsetT {
b.notNested()
b.Prep(int(SizeUOffsetT), (len(s)+1)*SizeByte)
b.PlaceByte(0)
x := []byte(s)
l := UOffsetT(len(x))
l := UOffsetT(len(s))
b.head -= l
copy(b.Bytes[b.head:b.head+l], x)
copy(b.Bytes[b.head:b.head+l], s)
return b.EndVector(len(x))
return b.EndVector(len(s))
}
// CreateByteString writes a byte slice as a string (null-terminated).
func (b *Builder) CreateByteString(s []byte) UOffsetT {
b.notNested()
b.Prep(int(SizeUOffsetT), (len(s)+1)*SizeByte)
b.PlaceByte(0)
l := UOffsetT(len(s))
b.head -= l
copy(b.Bytes[b.head:b.head+l], s)
return b.EndVector(len(s))
}
// CreateByteVector writes a ubyte vector
@@ -274,7 +329,7 @@ func (b *Builder) CreateByteVector(v []byte) UOffsetT {
func (b *Builder) notNested() {
// Check that no other objects are being built while making this
// object. If not, panic:
if b.vtable != nil {
if b.insideObject {
panic("non-inline data write inside of object")
}
}

View File

@@ -26,10 +26,15 @@ func (t *Table) Indirect(off UOffsetT) UOffsetT {
// String gets a string from data stored inside the flatbuffer.
func (t *Table) String(off UOffsetT) string {
return string(t.ByteVector(off))
}
// ByteVector gets a byte slice from data stored inside the flatbuffer.
func (t *Table) ByteVector(off UOffsetT) []byte {
off += GetUOffsetT(t.Bytes[off:])
start := off + UOffsetT(SizeUOffsetT)
length := GetUOffsetT(t.Bytes[off:])
return string(t.Bytes[start : start+length])
return t.Bytes[start : start+length]
}
// VectorLen retrieves the length of the vector whose offset is stored at

View File

@@ -21,6 +21,7 @@
#include <cstdint>
#include <cstddef>
#include <cstdlib>
#include <cstring>
#include <string>
#include <type_traits>
@@ -272,6 +273,8 @@ public:
return IndirectHelper<T>::Read(Data(), i);
}
return_type operator[](uoffset_t i) const { return Get(i); }
// If this is a Vector of enums, T will be its storage type, not the enum
// type. This function makes it convenient to retrieve value with enum
// type E.
@@ -286,37 +289,49 @@ public:
iterator begin() { return iterator(Data(), 0); }
const_iterator begin() const { return const_iterator(Data(), 0); }
iterator end() { return iterator(Data(), length_); }
const_iterator end() const { return const_iterator(Data(), length_); }
iterator end() { return iterator(Data(), size()); }
const_iterator end() const { return const_iterator(Data(), size()); }
// Change elements if you have a non-const pointer to this object.
// Scalars only. See reflection.h, and the documentation.
void Mutate(uoffset_t i, T val) {
assert(i < size());
WriteScalar(data() + i, val);
}
// Change an element of a vector of tables (or strings).
// "val" points to the new table/string, as you can obtain from
// e.g. reflection::AddFlatBuffer().
void MutateOffset(uoffset_t i, const uint8_t *val) {
assert(i < size());
assert(sizeof(T) == sizeof(uoffset_t));
WriteScalar(data() + i, val - (Data() + i * sizeof(uoffset_t)));
}
// The raw data in little endian format. Use with care.
const uint8_t *Data() const {
return reinterpret_cast<const uint8_t *>(&length_ + 1);
}
uint8_t *Data() {
return reinterpret_cast<uint8_t *>(&length_ + 1);
}
// Similarly, but typed, much like std::vector::data
const T *data() const { return reinterpret_cast<const T *>(Data()); }
T *data() { return reinterpret_cast<T *>(Data()); }
template<typename K> return_type LookupByKey(K key) const {
auto span = size();
uoffset_t start = 0;
// Perform binary search for key.
while (span) {
// Compare against middle element of current span.
auto middle = span / 2;
auto table = Get(start + middle);
auto comp = table->KeyCompareWithValue(key);
if (comp > 0) {
// Greater than. Adjust span and try again.
span = middle;
} else if (comp < 0) {
// Less than. Adjust span and try again.
middle++;
start += middle;
span -= middle;
} else {
// Found element.
return table;
}
void *search_result = std::bsearch(&key, Data(), size(),
IndirectHelper<T>::element_stride, KeyCompare<K>);
if (!search_result) {
return nullptr; // Key not found.
}
return nullptr; // Key not found.
const uint8_t *data = reinterpret_cast<const uint8_t *>(search_result);
return IndirectHelper<T>::Read(data, 0);
}
protected:
@@ -324,6 +339,35 @@ protected:
// try to construct these manually.
Vector();
uoffset_t length_;
private:
template<typename K> static int KeyCompare(const void *ap, const void *bp) {
const K *key = reinterpret_cast<const K *>(ap);
const uint8_t *data = reinterpret_cast<const uint8_t *>(bp);
auto table = IndirectHelper<T>::Read(data, 0);
// std::bsearch compares with the operands transposed, so we negate the
// result here.
return -table->KeyCompareWithValue(*key);
}
};
// Represent a vector much like the template above, but in this case we
// don't know what the element types are (used with reflection.h).
class VectorOfAny {
public:
uoffset_t size() const { return EndianScalar(length_); }
const uint8_t *Data() const {
return reinterpret_cast<const uint8_t *>(&length_ + 1);
}
uint8_t *Data() {
return reinterpret_cast<uint8_t *>(&length_ + 1);
}
protected:
VectorOfAny();
uoffset_t length_;
};
@@ -335,6 +379,7 @@ template<typename T> static inline size_t VectorLength(const Vector<T> *v) {
struct String : public Vector<char> {
const char *c_str() const { return reinterpret_cast<const char *>(Data()); }
std::string str() const { return c_str(); }
bool operator <(const String &o) const {
return strcmp(c_str(), o.c_str()) < 0;
@@ -399,7 +444,10 @@ class vector_downward {
uint8_t *make_space(size_t len) {
if (len > static_cast<size_t>(cur_ - buf_)) {
auto old_size = size();
auto largest_align = AlignOf<largest_scalar_t>();
reserved_ += std::max(len, growth_policy(reserved_));
// Round up to avoid undefined behavior from unaligned loads and stores.
reserved_ = (reserved_ + (largest_align - 1)) & ~(largest_align - 1);
auto new_buf = allocator_.allocate(reserved_);
auto new_cur = new_buf + reserved_ - old_size;
memcpy(new_cur, cur_, old_size);
@@ -476,7 +524,7 @@ class FlatBufferBuilder FLATBUFFERS_FINAL_CLASS {
explicit FlatBufferBuilder(uoffset_t initial_size = 1024,
const simple_allocator *allocator = nullptr)
: buf_(initial_size, allocator ? *allocator : default_allocator),
minalign_(1), force_defaults_(false) {
nested(false), finished(false), minalign_(1), force_defaults_(false) {
offsetbuf_.reserve(16); // Avoid first few reallocs.
vtables_.reserve(16);
EndianCheck();
@@ -487,6 +535,8 @@ class FlatBufferBuilder FLATBUFFERS_FINAL_CLASS {
void Clear() {
buf_.clear();
offsetbuf_.clear();
nested = false;
finished = false;
vtables_.clear();
minalign_ = 1;
}
@@ -495,11 +545,33 @@ class FlatBufferBuilder FLATBUFFERS_FINAL_CLASS {
uoffset_t GetSize() const { return buf_.size(); }
// Get the serialized buffer (after you call Finish()).
uint8_t *GetBufferPointer() const { return buf_.data(); }
uint8_t *GetBufferPointer() const {
Finished();
return buf_.data();
}
// Get a pointer to an unfinished buffer.
uint8_t *GetCurrentBufferPointer() const { return buf_.data(); }
// Get the released pointer to the serialized buffer.
// Don't attempt to use this FlatBufferBuilder afterwards!
unique_ptr_t ReleaseBufferPointer() { return buf_.release(); }
// The unique_ptr returned has a special allocator that knows how to
// deallocate this pointer (since it points to the middle of an allocation).
// Thus, do not mix this pointer with other unique_ptr's, or call release() /
// reset() on it.
unique_ptr_t ReleaseBufferPointer() {
Finished();
return buf_.release();
}
void Finished() const {
// If you get this assert, you're attempting to get access a buffer
// which hasn't been finished yet. Be sure to call
// FlatBufferBuilder::Finish with your root table.
// If you really need to access an unfinished buffer, call
// GetCurrentBufferPointer instead.
assert(finished);
}
void ForceDefaults(bool fd) { force_defaults_ = fd; }
@@ -573,21 +645,30 @@ class FlatBufferBuilder FLATBUFFERS_FINAL_CLASS {
// This function converts them to be relative to the current location
// in the buffer (when stored here), pointing upwards.
uoffset_t ReferTo(uoffset_t off) {
Align(sizeof(uoffset_t)); // To ensure GetSize() below is correct.
assert(off <= GetSize()); // Must refer to something already in buffer.
// Align to ensure GetSize() below is correct.
Align(sizeof(uoffset_t));
// Offset must refer to something already in buffer.
assert(off && off <= GetSize());
return GetSize() - off + sizeof(uoffset_t);
}
void NotNested() {
// If you hit this, you're trying to construct an object when another
// hasn't finished yet.
assert(!offsetbuf_.size());
// If you hit this, you're trying to construct a Table/Vector/String
// during the construction of its parent table (between the MyTableBuilder
// and table.Finish().
// Move the creation of these sub-objects to above the MyTableBuilder to
// not get this assert.
// Ignoring this assert may appear to work in simple cases, but the reason
// it is here is that storing objects in-line may cause vtable offsets
// to not fit anymore. It also leads to vtable duplication.
assert(!nested);
}
// From generated code (or from the parser), we call StartTable/EndTable
// with a sequence of AddElement calls in between.
uoffset_t StartTable() {
NotNested();
nested = true;
return GetSize();
}
@@ -595,6 +676,8 @@ class FlatBufferBuilder FLATBUFFERS_FINAL_CLASS {
// table, comparing it against existing vtables, and writing the
// resulting vtable offset.
uoffset_t EndTable(uoffset_t start, voffset_t numfields) {
// If you get this assert, a corresponding StartTable wasn't called.
assert(nested);
// Write the vtable offset, which is the start of any Table.
// We fill it's value later.
auto vtableoffsetloc = PushElement<soffset_t>(0);
@@ -641,6 +724,8 @@ class FlatBufferBuilder FLATBUFFERS_FINAL_CLASS {
WriteScalar(buf_.data_at(vtableoffsetloc),
static_cast<soffset_t>(vt_use) -
static_cast<soffset_t>(vtableoffsetloc));
nested = false;
return vtableoffsetloc;
}
@@ -692,11 +777,19 @@ class FlatBufferBuilder FLATBUFFERS_FINAL_CLASS {
return CreateString(str.c_str(), str.length());
}
Offset<String> CreateString(const String *str) {
return CreateString(str->c_str(), str->Length());
}
uoffset_t EndVector(size_t len) {
assert(nested); // Hit if no corresponding StartVector.
nested = false;
return PushElement(static_cast<uoffset_t>(len));
}
void StartVector(size_t len, size_t elemsize) {
NotNested();
nested = true;
PreAlign<uoffset_t>(len * elemsize);
PreAlign(len * elemsize, elemsize); // Just in case elemsize > uoffset_t.
}
@@ -706,7 +799,6 @@ class FlatBufferBuilder FLATBUFFERS_FINAL_CLASS {
}
template<typename T> Offset<Vector<T>> CreateVector(const T *v, size_t len) {
NotNested();
StartVector(len, sizeof(T));
for (auto i = len; i > 0; ) {
PushElement(v[--i]);
@@ -720,7 +812,6 @@ class FlatBufferBuilder FLATBUFFERS_FINAL_CLASS {
template<typename T> Offset<Vector<const T *>> CreateVectorOfStructs(
const T *v, size_t len) {
NotNested();
StartVector(len * sizeof(T) / AlignOf<T>(), AlignOf<T>());
PushBytes(reinterpret_cast<const uint8_t *>(v), sizeof(T) * len);
return Offset<Vector<const T *>>(EndVector(len));
@@ -744,7 +835,7 @@ class FlatBufferBuilder FLATBUFFERS_FINAL_CLASS {
}
template<typename T> Offset<Vector<Offset<T>>> CreateVectorOfSortedTables(
std::vector<T> *v) {
std::vector<Offset<T>> *v) {
return CreateVectorOfSortedTables(v->data(), v->size());
}
@@ -771,6 +862,7 @@ class FlatBufferBuilder FLATBUFFERS_FINAL_CLASS {
// FlatBuffers file header.
template<typename T> void Finish(Offset<T> root,
const char *file_identifier = nullptr) {
NotNested();
// This will cause the whole buffer to be aligned.
PreAlign(sizeof(uoffset_t) + (file_identifier ? kFileIdentifierLength : 0),
minalign_);
@@ -780,6 +872,7 @@ class FlatBufferBuilder FLATBUFFERS_FINAL_CLASS {
kFileIdentifierLength);
}
PushElement(ReferTo(root.o)); // Location of root.
finished = true;
}
private:
@@ -799,6 +892,12 @@ class FlatBufferBuilder FLATBUFFERS_FINAL_CLASS {
// Accumulating offsets of table members while it is being built.
std::vector<FieldLoc> offsetbuf_;
// Ensure objects are not nested.
bool nested;
// Ensure the buffer is finished before it is being accessed.
bool finished;
std::vector<uoffset_t> vtables_; // todo: Could make this into a map?
size_t minalign_;
@@ -806,11 +905,15 @@ class FlatBufferBuilder FLATBUFFERS_FINAL_CLASS {
bool force_defaults_; // Serialize values equal to their defaults anyway.
};
// Helper to get a typed pointer to the root object contained in the buffer.
template<typename T> const T *GetRoot(const void *buf) {
// Helpers to get a typed pointer to the root object contained in the buffer.
template<typename T> T *GetMutableRoot(void *buf) {
EndianCheck();
return reinterpret_cast<const T *>(reinterpret_cast<const uint8_t *>(buf) +
EndianScalar(*reinterpret_cast<const uoffset_t *>(buf)));
return reinterpret_cast<T *>(reinterpret_cast<uint8_t *>(buf) +
EndianScalar(*reinterpret_cast<uoffset_t *>(buf)));
}
template<typename T> const T *GetRoot(const void *buf) {
return GetMutableRoot<T>(const_cast<void *>(buf));
}
// Helper to see if the identifier in a buffer has the expected value.
@@ -838,7 +941,7 @@ class Verifier FLATBUFFERS_FINAL_CLASS {
// Verify any range within the buffer.
bool Verify(const void *elem, size_t elem_len) const {
return Check(elem >= buf_ && elem <= end_ - elem_len);
return Check(elem_len <= (size_t) (end_ - buf_) && elem >= buf_ && elem <= end_ - elem_len);
}
// Verify a range indicated by sizeof(T).
@@ -859,6 +962,11 @@ class Verifier FLATBUFFERS_FINAL_CLASS {
&end);
}
// Verify a pointer (may be NULL) of a vector to struct.
template<typename T> bool Verify(const Vector<const T *> *vec) const {
return Verify(reinterpret_cast<const Vector<T> *>(vec));
}
// Verify a pointer (may be NULL) to string.
bool Verify(const String *str) const {
const uint8_t *end;
@@ -953,6 +1061,9 @@ class Struct FLATBUFFERS_FINAL_CLASS {
return reinterpret_cast<T>(&data_[o]);
}
const uint8_t *GetAddressOf(uoffset_t o) const { return &data_[o]; }
uint8_t *GetAddressOf(uoffset_t o) { return &data_[o]; }
private:
uint8_t data_[1];
};
@@ -978,28 +1089,47 @@ class Table {
return field_offset ? ReadScalar<T>(data_ + field_offset) : defaultval;
}
template<typename P> P GetPointer(voffset_t field) const {
template<typename P> P GetPointer(voffset_t field) {
auto field_offset = GetOptionalFieldOffset(field);
auto p = data_ + field_offset;
return field_offset
? reinterpret_cast<P>(p + ReadScalar<uoffset_t>(p))
: nullptr;
}
template<typename P> P GetPointer(voffset_t field) const {
return const_cast<Table *>(this)->GetPointer<P>(field);
}
template<typename P> P GetStruct(voffset_t field) const {
auto field_offset = GetOptionalFieldOffset(field);
return field_offset ? reinterpret_cast<P>(data_ + field_offset) : nullptr;
auto p = const_cast<uint8_t *>(data_ + field_offset);
return field_offset ? reinterpret_cast<P>(p) : nullptr;
}
template<typename T> void SetField(voffset_t field, T val) {
template<typename T> bool SetField(voffset_t field, T val) {
auto field_offset = GetOptionalFieldOffset(field);
// If this asserts, you're trying to set a field that's not there
// (or should we return a bool instead?).
// check if it exists first using CheckField()
assert(field_offset);
if (!field_offset) return false;
WriteScalar(data_ + field_offset, val);
return true;
}
bool SetPointer(voffset_t field, const uint8_t *val) {
auto field_offset = GetOptionalFieldOffset(field);
if (!field_offset) return false;
WriteScalar(data_ + field_offset, val - (data_ + field_offset));
return true;
}
uint8_t *GetAddressOf(voffset_t field) {
auto field_offset = GetOptionalFieldOffset(field);
return field_offset ? data_ + field_offset : nullptr;
}
const uint8_t *GetAddressOf(voffset_t field) const {
return const_cast<Table *>(this)->GetAddressOf(field);
}
uint8_t *GetVTable() { return data_ - ReadScalar<soffset_t>(data_); }
bool CheckField(voffset_t field) const {
return GetOptionalFieldOffset(field) != 0;
}

View File

@@ -25,6 +25,7 @@
#include "flatbuffers/flatbuffers.h"
#include "flatbuffers/hash.h"
#include "flatbuffers/reflection.h"
// This file defines the data types representing a parsed IDL (Interface
// Definition Language) / schema file.
@@ -35,24 +36,24 @@ namespace flatbuffers {
// Additionally, Parser::ParseType assumes bool..string is a contiguous range
// of type tokens.
#define FLATBUFFERS_GEN_TYPES_SCALAR(TD) \
TD(NONE, "", uint8_t, byte, byte, byte) \
TD(UTYPE, "", uint8_t, byte, byte, byte) /* begin scalar/int */ \
TD(BOOL, "bool", uint8_t, boolean,byte, bool) \
TD(CHAR, "byte", int8_t, byte, int8, sbyte) \
TD(UCHAR, "ubyte", uint8_t, byte, byte, byte) \
TD(SHORT, "short", int16_t, short, int16, short) \
TD(USHORT, "ushort", uint16_t, short, uint16, ushort) \
TD(INT, "int", int32_t, int, int32, int) \
TD(UINT, "uint", uint32_t, int, uint32, uint) \
TD(LONG, "long", int64_t, long, int64, long) \
TD(ULONG, "ulong", uint64_t, long, uint64, ulong) /* end int */ \
TD(FLOAT, "float", float, float, float32, float) /* begin float */ \
TD(DOUBLE, "double", double, double, float64, double) /* end float/scalar */
TD(NONE, "", uint8_t, byte, byte, byte, uint8) \
TD(UTYPE, "", uint8_t, byte, byte, byte, uint8) /* begin scalar/int */ \
TD(BOOL, "bool", uint8_t, boolean,byte, bool, bool) \
TD(CHAR, "byte", int8_t, byte, int8, sbyte, int8) \
TD(UCHAR, "ubyte", uint8_t, byte, byte, byte, uint8) \
TD(SHORT, "short", int16_t, short, int16, short, int16) \
TD(USHORT, "ushort", uint16_t, short, uint16, ushort, uint16) \
TD(INT, "int", int32_t, int, int32, int, int32) \
TD(UINT, "uint", uint32_t, int, uint32, uint, uint32) \
TD(LONG, "long", int64_t, long, int64, long, int64) \
TD(ULONG, "ulong", uint64_t, long, uint64, ulong, uint64) /* end int */ \
TD(FLOAT, "float", float, float, float32, float, float32) /* begin float */ \
TD(DOUBLE, "double", double, double, float64, double, float64) /* end float/scalar */
#define FLATBUFFERS_GEN_TYPES_POINTER(TD) \
TD(STRING, "string", Offset<void>, int, int, int) \
TD(VECTOR, "", Offset<void>, int, int, int) \
TD(STRUCT, "", Offset<void>, int, int, int) \
TD(UNION, "", Offset<void>, int, int, int)
TD(STRING, "string", Offset<void>, int, int, StringOffset, int) \
TD(VECTOR, "", Offset<void>, int, int, VectorOffset, int) \
TD(STRUCT, "", Offset<void>, int, int, int, int) \
TD(UNION, "", Offset<void>, int, int, int, int)
// The fields are:
// - enum
@@ -61,12 +62,13 @@ namespace flatbuffers {
// - Java type.
// - Go type.
// - C# / .Net type.
// - Python type.
// using these macros, we can now write code dealing with types just once, e.g.
/*
switch (type) {
#define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE) \
#define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \
case BASE_TYPE_ ## ENUM: \
// do something specific to CTYPE here
FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
@@ -83,13 +85,13 @@ switch (type) {
__extension__ // Stop GCC complaining about trailing comma with -Wpendantic.
#endif
enum BaseType {
#define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE) \
#define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \
BASE_TYPE_ ## ENUM,
FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
#undef FLATBUFFERS_TD
};
#define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE) \
#define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \
static_assert(sizeof(CTYPE) <= sizeof(largest_scalar_t), \
"define largest_scalar_t as " #CTYPE);
FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
@@ -123,8 +125,15 @@ struct Type {
enum_def(_ed)
{}
bool operator==(const Type &o) {
return base_type == o.base_type && element == o.element &&
struct_def == o.struct_def && enum_def == o.enum_def;
}
Type VectorType() const { return Type(element, struct_def, enum_def); }
Offset<reflection::Type> Serialize(FlatBufferBuilder *builder) const;
BaseType base_type;
BaseType element; // only set if t == BASE_TYPE_VECTOR
StructDef *struct_def; // only set if t or element == BASE_TYPE_STRUCT
@@ -159,6 +168,17 @@ template<typename T> class SymbolTable {
return false;
}
void Move(const std::string &oldname, const std::string &newname) {
auto it = dict.find(oldname);
if (it != dict.end()) {
auto obj = it->second;
dict.erase(it);
dict[newname] = obj;
} else {
assert(false);
}
}
T *Lookup(const std::string &name) const {
auto it = dict.find(name);
return it == dict.end() ? nullptr : it->second;
@@ -174,11 +194,19 @@ template<typename T> class SymbolTable {
// A name space, as set in the schema.
struct Namespace {
std::vector<std::string> components;
// Given a (potentally unqualified) name, return the "fully qualified" name
// which has a full namespaced descriptor.
// With max_components you can request less than the number of components
// the current namespace has.
std::string GetFullyQualifiedName(const std::string &name,
size_t max_components = 1000) const;
};
// Base class for all definition types (fields, structs_, enums_).
struct Definition {
Definition() : generated(false), defined_namespace(nullptr) {}
Definition() : generated(false), defined_namespace(nullptr),
serialized_location(0), index(-1) {}
std::string name;
std::string file;
@@ -186,12 +214,19 @@ struct Definition {
SymbolTable<Value> attributes;
bool generated; // did we already output code for this definition?
Namespace *defined_namespace; // Where it was defined.
// For use with Serialize()
uoffset_t serialized_location;
int index; // Inside the vector it is stored.
};
struct FieldDef : public Definition {
FieldDef() : deprecated(false), required(false), key(false), padding(0),
used(false) {}
Offset<reflection::Field> Serialize(FlatBufferBuilder *builder, uint16_t id)
const;
Value value;
bool deprecated; // Field is allowed to be present in old data, but can't be
// written in new data nor accessed in new code.
@@ -211,12 +246,14 @@ struct StructDef : public Definition {
bytesize(0)
{}
void PadLastField(size_t minalign) {
auto padding = PaddingBytes(bytesize, minalign);
void PadLastField(size_t min_align) {
auto padding = PaddingBytes(bytesize, min_align);
bytesize += padding;
if (fields.vec.size()) fields.vec.back()->padding = padding;
}
Offset<reflection::Object> Serialize(FlatBufferBuilder *builder) const;
SymbolTable<FieldDef> fields;
bool fixed; // If it's struct, not a table.
bool predecl; // If it's used before it was defined.
@@ -242,6 +279,8 @@ struct EnumVal {
EnumVal(const std::string &_name, int64_t _val)
: name(_name), value(_val), struct_def(nullptr) {}
Offset<reflection::EnumVal> Serialize(FlatBufferBuilder *builder) const;
std::string name;
std::vector<std::string> doc_comment;
int64_t value;
@@ -262,6 +301,8 @@ struct EnumDef : public Definition {
return nullptr;
}
Offset<reflection::Enum> Serialize(FlatBufferBuilder *builder) const;
SymbolTable<EnumVal> vals;
bool is_union;
Type underlying_type;
@@ -270,12 +311,13 @@ struct EnumDef : public Definition {
class Parser {
public:
Parser(bool strict_json = false, bool proto_mode = false)
: root_struct_def(nullptr),
: root_struct_def_(nullptr),
source_(nullptr),
cursor_(nullptr),
line_(1),
proto_mode_(proto_mode),
strict_json_(strict_json) {
strict_json_(strict_json),
anonymous_counter(0) {
// Just in case none are declared:
namespaces_.push_back(new Namespace());
known_attributes_.insert("deprecated");
@@ -318,11 +360,18 @@ class Parser {
std::set<std::string> GetIncludedFilesRecursive(
const std::string &file_name) const;
// Fills builder_ with a binary version of the schema parsed.
// See reflection/reflection.fbs
void Serialize();
private:
int64_t ParseHexNum(int nibbles);
void Next();
bool IsNext(int t);
void Expect(int t);
std::string TokenToStringId(int t);
EnumDef *LookupEnum(const std::string &id);
void ParseNamespacing(std::string *id, std::string *last);
void ParseTypeIdent(Type &type);
void ParseType(Type &type);
FieldDef &AddField(StructDef &struct_def,
@@ -339,12 +388,19 @@ class Parser {
void ParseHash(Value &e, FieldDef* field);
void ParseSingleValue(Value &e);
int64_t ParseIntegerFromString(Type &type);
StructDef *LookupCreateStruct(const std::string &name);
void ParseEnum(bool is_union);
StructDef *LookupCreateStruct(const std::string &name,
bool create_if_new = true,
bool definition = false);
EnumDef &ParseEnum(bool is_union);
void ParseNamespace();
StructDef &StartStruct();
StructDef &StartStruct(const std::string &name);
void ParseDecl();
void ParseProtoFields(StructDef *struct_def, bool isextend,
bool inside_oneof);
void ParseProtoOption();
void ParseProtoKey();
void ParseProtoDecl();
void ParseProtoCurliesOrIdent();
Type ParseTypeFromProtoType();
public:
@@ -354,7 +410,7 @@ class Parser {
std::string error_; // User readable error_ if Parse() == false
FlatBufferBuilder builder_; // any data contained in the file
StructDef *root_struct_def;
StructDef *root_struct_def_;
std::string file_identifier_;
std::string file_extension_;
@@ -375,31 +431,47 @@ class Parser {
std::vector<uint8_t> struct_stack_;
std::set<std::string> known_attributes_;
int anonymous_counter;
};
// Utility functions for multiple generators:
extern std::string MakeCamel(const std::string &in, bool first = true);
struct CommentConfig;
extern void GenComment(const std::vector<std::string> &dc,
std::string *code_ptr,
const CommentConfig *config,
const char *prefix = "");
// Container of options that may apply to any of the source/text generators.
struct GeneratorOptions {
bool strict_json;
bool skip_js_exports;
bool output_default_scalars_in_json;
int indent_step;
bool output_enum_identifiers;
bool prefixed_enums;
bool scoped_enums;
bool include_dependence_headers;
bool mutable_buffer;
bool one_file;
// Possible options for the more general generator below.
enum Language { kJava, kCSharp, kGo, kMAX };
Language lang;
GeneratorOptions() : strict_json(false), indent_step(2),
output_enum_identifiers(true), prefixed_enums(true),
include_dependence_headers(false),
GeneratorOptions() : strict_json(false),
skip_js_exports(false),
output_default_scalars_in_json(false),
indent_step(2),
output_enum_identifiers(true), prefixed_enums(true), scoped_enums(false),
include_dependence_headers(true),
mutable_buffer(false),
one_file(false),
lang(GeneratorOptions::kJava) {}
};
@@ -436,6 +508,15 @@ extern bool GenerateCPP(const Parser &parser,
const std::string &file_name,
const GeneratorOptions &opts);
// Generate JavaScript code from the definitions in the Parser object.
// See idl_gen_js.
extern std::string GenerateJS(const Parser &parser,
const GeneratorOptions &opts);
extern bool GenerateJS(const Parser &parser,
const std::string &path,
const std::string &file_name,
const GeneratorOptions &opts);
// Generate Go files from the definitions in the Parser object.
// See idl_gen_go.cpp.
extern bool GenerateGo(const Parser &parser,
@@ -450,6 +531,13 @@ extern bool GenerateJava(const Parser &parser,
const std::string &file_name,
const GeneratorOptions &opts);
// Generate Python files from the definitions in the Parser object.
// See idl_gen_python.cpp.
extern bool GeneratePython(const Parser &parser,
const std::string &path,
const std::string &file_name,
const GeneratorOptions &opts);
// Generate C# files from the definitions in the Parser object.
// See idl_gen_csharp.cpp.
extern bool GenerateCSharp(const Parser &parser,
@@ -474,6 +562,13 @@ extern bool GenerateFBS(const Parser &parser,
const std::string &file_name,
const GeneratorOptions &opts);
// Generate a make rule for the generated JavaScript code.
// See idl_gen_js.cpp.
extern std::string JSMakeRule(const Parser &parser,
const std::string &path,
const std::string &file_name,
const GeneratorOptions &opts);
// Generate a make rule for the generated C++ header.
// See idl_gen_cpp.cpp.
extern std::string CPPMakeRule(const Parser &parser,

View File

@@ -0,0 +1,427 @@
/*
* Copyright 2015 Google Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FLATBUFFERS_REFLECTION_H_
#define FLATBUFFERS_REFLECTION_H_
// This is somewhat of a circular dependency because flatc (and thus this
// file) is needed to generate this header in the first place.
// Should normally not be a problem since it can be generated by the
// previous version of flatc whenever this code needs to change.
// See reflection/generate_code.sh
#include "flatbuffers/reflection_generated.h"
// Helper functionality for reflection.
namespace flatbuffers {
// ------------------------- GETTERS -------------------------
// Size of a basic type, don't use with structs.
inline size_t GetTypeSize(reflection::BaseType base_type) {
// This needs to correspond to the BaseType enum.
static size_t sizes[] = { 0, 1, 1, 1, 1, 2, 2, 4, 4, 8, 8, 4, 8, 4, 4, 4, 4 };
return sizes[base_type];
}
// Same as above, but now correctly returns the size of a struct if
// the field (or vector element) is a struct.
inline size_t GetTypeSizeInline(reflection::BaseType base_type,
int type_index,
const reflection::Schema &schema) {
if (base_type == reflection::Obj &&
schema.objects()->Get(type_index)->is_struct()) {
return schema.objects()->Get(type_index)->bytesize();
} else {
return GetTypeSize(base_type);
}
}
// Get the root, regardless of what type it is.
inline Table *GetAnyRoot(uint8_t *flatbuf) {
return GetMutableRoot<Table>(flatbuf);
}
inline const Table *GetAnyRoot(const uint8_t *flatbuf) {
return GetRoot<Table>(flatbuf);
}
// Get a field, if you know it's an integer, and its exact type.
template<typename T> T GetFieldI(const Table &table,
const reflection::Field &field) {
assert(sizeof(T) == GetTypeSize(field.type()->base_type()));
return table.GetField<T>(field.offset(),
static_cast<T>(field.default_integer()));
}
// Get a field, if you know it's floating point and its exact type.
template<typename T> T GetFieldF(const Table &table,
const reflection::Field &field) {
assert(sizeof(T) == GetTypeSize(field.type()->base_type()));
return table.GetField<T>(field.offset(),
static_cast<T>(field.default_real()));
}
// Get a field, if you know it's a string.
inline const String *GetFieldS(const Table &table,
const reflection::Field &field) {
assert(field.type()->base_type() == reflection::String);
return table.GetPointer<const String *>(field.offset());
}
// Get a field, if you know it's a vector.
template<typename T> Vector<T> *GetFieldV(const Table &table,
const reflection::Field &field) {
assert(field.type()->base_type() == reflection::Vector &&
sizeof(T) == GetTypeSize(field.type()->element()));
return table.GetPointer<Vector<T> *>(field.offset());
}
// Get a field, if you know it's a vector, generically.
// To actually access elements, use the return value together with
// field.type()->element() in any of GetAnyVectorElemI below etc.
inline VectorOfAny *GetFieldAnyV(const Table &table,
const reflection::Field &field) {
return table.GetPointer<VectorOfAny *>(field.offset());
}
// Get a field, if you know it's a table.
inline Table *GetFieldT(const Table &table,
const reflection::Field &field) {
assert(field.type()->base_type() == reflection::Obj ||
field.type()->base_type() == reflection::Union);
return table.GetPointer<Table *>(field.offset());
}
// Raw helper functions used below: get any value in memory as a 64bit int, a
// double or a string.
// All scalars get static_cast to an int64_t, strings use strtoull, every other
// data type returns 0.
int64_t GetAnyValueI(reflection::BaseType type, const uint8_t *data);
// All scalars static cast to double, strings use strtod, every other data
// type is 0.0.
double GetAnyValueF(reflection::BaseType type, const uint8_t *data);
// All scalars converted using stringstream, strings as-is, and all other
// data types provide some level of debug-pretty-printing.
std::string GetAnyValueS(reflection::BaseType type, const uint8_t *data,
const reflection::Schema *schema,
int type_index);
// Get any table field as a 64bit int, regardless of what type it is.
inline int64_t GetAnyFieldI(const Table &table,
const reflection::Field &field) {
auto field_ptr = table.GetAddressOf(field.offset());
return field_ptr ? GetAnyValueI(field.type()->base_type(), field_ptr)
: field.default_integer();
}
// Get any table field as a double, regardless of what type it is.
inline double GetAnyFieldF(const Table &table,
const reflection::Field &field) {
auto field_ptr = table.GetAddressOf(field.offset());
return field_ptr ? GetAnyValueF(field.type()->base_type(), field_ptr)
: field.default_real();
}
// Get any table field as a string, regardless of what type it is.
// You may pass nullptr for the schema if you don't care to have fields that
// are of table type pretty-printed.
inline std::string GetAnyFieldS(const Table &table,
const reflection::Field &field,
const reflection::Schema *schema) {
auto field_ptr = table.GetAddressOf(field.offset());
return field_ptr ? GetAnyValueS(field.type()->base_type(), field_ptr, schema,
field.type()->index())
: "";
}
// Get any struct field as a 64bit int, regardless of what type it is.
inline int64_t GetAnyFieldI(const Struct &st,
const reflection::Field &field) {
return GetAnyValueI(field.type()->base_type(),
st.GetAddressOf(field.offset()));
}
// Get any struct field as a double, regardless of what type it is.
inline double GetAnyFieldF(const Struct &st,
const reflection::Field &field) {
return GetAnyValueF(field.type()->base_type(),
st.GetAddressOf(field.offset()));
}
// Get any struct field as a string, regardless of what type it is.
inline std::string GetAnyFieldS(const Struct &st,
const reflection::Field &field) {
return GetAnyValueS(field.type()->base_type(),
st.GetAddressOf(field.offset()), nullptr, -1);
}
// Get any vector element as a 64bit int, regardless of what type it is.
inline int64_t GetAnyVectorElemI(const VectorOfAny *vec,
reflection::BaseType elem_type, size_t i) {
return GetAnyValueI(elem_type, vec->Data() + GetTypeSize(elem_type) * i);
}
// Get any vector element as a double, regardless of what type it is.
inline double GetAnyVectorElemF(const VectorOfAny *vec,
reflection::BaseType elem_type, size_t i) {
return GetAnyValueF(elem_type, vec->Data() + GetTypeSize(elem_type) * i);
}
// Get any vector element as a string, regardless of what type it is.
inline std::string GetAnyVectorElemS(const VectorOfAny *vec,
reflection::BaseType elem_type, size_t i) {
return GetAnyValueS(elem_type, vec->Data() + GetTypeSize(elem_type) * i,
nullptr, -1);
}
// Get a vector element that's a table/string/vector from a generic vector.
// Pass Table/String/VectorOfAny as template parameter.
// Warning: does no typechecking.
template<typename T> T *GetAnyVectorElemPointer(const VectorOfAny *vec,
size_t i) {
auto elem_ptr = vec->Data() + sizeof(uoffset_t) * i;
return (T *)(elem_ptr + ReadScalar<uoffset_t>(elem_ptr));
}
// Get the inline-address of a vector element. Useful for Structs (pass Struct
// as template arg), or being able to address a range of scalars in-line.
// Get elem_size from GetTypeSizeInline().
// Note: little-endian data on all platforms, use EndianScalar() instead of
// raw pointer access with scalars).
template<typename T> T *GetAnyVectorElemAddressOf(const VectorOfAny *vec,
size_t i,
size_t elem_size) {
// C-cast to allow const conversion.
return (T *)(vec->Data() + elem_size * i);
}
// Similarly, for elements of tables.
template<typename T> T *GetAnyFieldAddressOf(const Table &table,
const reflection::Field &field) {
return (T *)table.GetAddressOf(field.offset());
}
// Similarly, for elements of structs.
template<typename T> T *GetAnyFieldAddressOf(const Struct &st,
const reflection::Field &field) {
return (T *)st.GetAddressOf(field.offset());
}
// ------------------------- SETTERS -------------------------
// Set any scalar field, if you know its exact type.
template<typename T> bool SetField(Table *table, const reflection::Field &field,
T val) {
assert(sizeof(T) == GetTypeSize(field.type()->base_type()));
return table->SetField(field.offset(), val);
}
// Raw helper functions used below: set any value in memory as a 64bit int, a
// double or a string.
// These work for all scalar values, but do nothing for other data types.
// To set a string, see SetString below.
void SetAnyValueI(reflection::BaseType type, uint8_t *data, int64_t val);
void SetAnyValueF(reflection::BaseType type, uint8_t *data, double val);
void SetAnyValueS(reflection::BaseType type, uint8_t *data, const char *val);
// Set any table field as a 64bit int, regardless of type what it is.
inline bool SetAnyFieldI(Table *table, const reflection::Field &field,
int64_t val) {
auto field_ptr = table->GetAddressOf(field.offset());
if (!field_ptr) return false;
SetAnyValueI(field.type()->base_type(), field_ptr, val);
return true;
}
// Set any table field as a double, regardless of what type it is.
inline bool SetAnyFieldF(Table *table, const reflection::Field &field,
double val) {
auto field_ptr = table->GetAddressOf(field.offset());
if (!field_ptr) return false;
SetAnyValueF(field.type()->base_type(), field_ptr, val);
return true;
}
// Set any table field as a string, regardless of what type it is.
inline bool SetAnyFieldS(Table *table, const reflection::Field &field,
const char *val) {
auto field_ptr = table->GetAddressOf(field.offset());
if (!field_ptr) return false;
SetAnyValueS(field.type()->base_type(), field_ptr, val);
return true;
}
// Set any struct field as a 64bit int, regardless of type what it is.
inline void SetAnyFieldI(Struct *st, const reflection::Field &field,
int64_t val) {
SetAnyValueI(field.type()->base_type(), st->GetAddressOf(field.offset()),
val);
}
// Set any struct field as a double, regardless of type what it is.
inline void SetAnyFieldF(Struct *st, const reflection::Field &field,
double val) {
SetAnyValueF(field.type()->base_type(), st->GetAddressOf(field.offset()),
val);
}
// Set any struct field as a string, regardless of type what it is.
inline void SetAnyFieldS(Struct *st, const reflection::Field &field,
const char *val) {
SetAnyValueS(field.type()->base_type(), st->GetAddressOf(field.offset()),
val);
}
// Set any vector element as a 64bit int, regardless of type what it is.
inline void SetAnyVectorElemI(VectorOfAny *vec, reflection::BaseType elem_type,
size_t i, int64_t val) {
SetAnyValueI(elem_type, vec->Data() + GetTypeSize(elem_type) * i, val);
}
// Set any vector element as a double, regardless of type what it is.
inline void SetAnyVectorElemF(VectorOfAny *vec, reflection::BaseType elem_type,
size_t i, double val) {
SetAnyValueF(elem_type, vec->Data() + GetTypeSize(elem_type) * i, val);
}
// Set any vector element as a string, regardless of type what it is.
inline void SetAnyVectorElemS(VectorOfAny *vec, reflection::BaseType elem_type,
size_t i, const char *val) {
SetAnyValueS(elem_type, vec->Data() + GetTypeSize(elem_type) * i, val);
}
// ------------------------- RESIZING SETTERS -------------------------
// "smart" pointer for use with resizing vectors: turns a pointer inside
// a vector into a relative offset, such that it is not affected by resizes.
template<typename T, typename U> class pointer_inside_vector {
public:
pointer_inside_vector(T *ptr, std::vector<U> &vec)
: offset_(reinterpret_cast<uint8_t *>(ptr) -
reinterpret_cast<uint8_t *>(vec.data())),
vec_(vec) {}
T *operator*() const {
return reinterpret_cast<T *>(
reinterpret_cast<uint8_t *>(vec_.data()) + offset_);
}
T *operator->() const {
return operator*();
}
void operator=(const pointer_inside_vector &piv);
private:
size_t offset_;
std::vector<U> &vec_;
};
// Helper to create the above easily without specifying template args.
template<typename T, typename U> pointer_inside_vector<T, U> piv(T *ptr,
std::vector<U> &vec) {
return pointer_inside_vector<T, U>(ptr, vec);
}
// Helper to figure out the actual table type a union refers to.
inline const reflection::Object &GetUnionType(
const reflection::Schema &schema, const reflection::Object &parent,
const reflection::Field &unionfield, const Table &table) {
auto enumdef = schema.enums()->Get(unionfield.type()->index());
// TODO: this is clumsy and slow, but no other way to find it?
auto type_field = parent.fields()->LookupByKey(
(unionfield.name()->str() + "_type").c_str());
assert(type_field);
auto union_type = GetFieldI<uint8_t>(table, *type_field);
auto enumval = enumdef->values()->LookupByKey(union_type);
return *enumval->object();
}
// Changes the contents of a string inside a FlatBuffer. FlatBuffer must
// live inside a std::vector so we can resize the buffer if needed.
// "str" must live inside "flatbuf" and may be invalidated after this call.
// If your FlatBuffer's root table is not the schema's root table, you should
// pass in your root_table type as well.
void SetString(const reflection::Schema &schema, const std::string &val,
const String *str, std::vector<uint8_t> *flatbuf,
const reflection::Object *root_table = nullptr);
// Resizes a flatbuffers::Vector inside a FlatBuffer. FlatBuffer must
// live inside a std::vector so we can resize the buffer if needed.
// "vec" must live inside "flatbuf" and may be invalidated after this call.
// If your FlatBuffer's root table is not the schema's root table, you should
// pass in your root_table type as well.
uint8_t *ResizeAnyVector(const reflection::Schema &schema, uoffset_t newsize,
const VectorOfAny *vec, uoffset_t num_elems,
uoffset_t elem_size, std::vector<uint8_t> *flatbuf,
const reflection::Object *root_table = nullptr);
template <typename T>
void ResizeVector(const reflection::Schema &schema, uoffset_t newsize, T val,
const Vector<T> *vec, std::vector<uint8_t> *flatbuf,
const reflection::Object *root_table = nullptr) {
auto delta_elem = static_cast<int>(newsize) - static_cast<int>(vec->size());
auto newelems = ResizeAnyVector(schema, newsize,
reinterpret_cast<const VectorOfAny *>(vec),
vec->size(),
static_cast<uoffset_t>(sizeof(T)), flatbuf,
root_table);
// Set new elements to "val".
for (int i = 0; i < delta_elem; i++) {
auto loc = newelems + i * sizeof(T);
auto is_scalar = std::is_scalar<T>::value;
if (is_scalar) {
WriteScalar(loc, val);
} else { // struct
*reinterpret_cast<T *>(loc) = val;
}
}
}
// Adds any new data (in the form of a new FlatBuffer) to an existing
// FlatBuffer. This can be used when any of the above methods are not
// sufficient, in particular for adding new tables and new fields.
// This is potentially slightly less efficient than a FlatBuffer constructed
// in one piece, since the new FlatBuffer doesn't share any vtables with the
// existing one.
// The return value can now be set using Vector::MutateOffset or SetFieldT
// below.
const uint8_t *AddFlatBuffer(std::vector<uint8_t> &flatbuf,
const uint8_t *newbuf, size_t newlen);
inline bool SetFieldT(Table *table, const reflection::Field &field,
const uint8_t *val) {
assert(sizeof(uoffset_t) == GetTypeSize(field.type()->base_type()));
return table->SetPointer(field.offset(), val);
}
// ------------------------- COPYING -------------------------
// Generic copying of tables from a FlatBuffer into a FlatBuffer builder.
// Can be used to do any kind of merging/selecting you may want to do out
// of existing buffers. Also useful to reconstruct a whole buffer if the
// above resizing functionality has introduced garbage in a buffer you want
// to remove.
// Note: this does not deal with DAGs correctly. If the table passed forms a
// DAG, the copy will be a tree instead (with duplicates).
Offset<const Table *> CopyTable(FlatBufferBuilder &fbb,
const reflection::Schema &schema,
const reflection::Object &objectdef,
const Table &table);
} // namespace flatbuffers
#endif // FLATBUFFERS_REFLECTION_H_

View File

@@ -0,0 +1,378 @@
// automatically generated by the FlatBuffers compiler, do not modify
#ifndef FLATBUFFERS_GENERATED_REFLECTION_REFLECTION_H_
#define FLATBUFFERS_GENERATED_REFLECTION_REFLECTION_H_
#include "flatbuffers/flatbuffers.h"
namespace reflection {
struct Type;
struct EnumVal;
struct Enum;
struct Field;
struct Object;
struct Schema;
enum BaseType {
None = 0,
UType = 1,
Bool = 2,
Byte = 3,
UByte = 4,
Short = 5,
UShort = 6,
Int = 7,
UInt = 8,
Long = 9,
ULong = 10,
Float = 11,
Double = 12,
String = 13,
Vector = 14,
Obj = 15,
Union = 16
};
inline const char **EnumNamesBaseType() {
static const char *names[] = { "None", "UType", "Bool", "Byte", "UByte", "Short", "UShort", "Int", "UInt", "Long", "ULong", "Float", "Double", "String", "Vector", "Obj", "Union", nullptr };
return names;
}
inline const char *EnumNameBaseType(BaseType e) { return EnumNamesBaseType()[e]; }
struct Type FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
BaseType base_type() const { return static_cast<BaseType>(GetField<int8_t>(4, 0)); }
BaseType element() const { return static_cast<BaseType>(GetField<int8_t>(6, 0)); }
int32_t index() const { return GetField<int32_t>(8, -1); }
bool Verify(flatbuffers::Verifier &verifier) const {
return VerifyTableStart(verifier) &&
VerifyField<int8_t>(verifier, 4 /* base_type */) &&
VerifyField<int8_t>(verifier, 6 /* element */) &&
VerifyField<int32_t>(verifier, 8 /* index */) &&
verifier.EndTable();
}
};
struct TypeBuilder {
flatbuffers::FlatBufferBuilder &fbb_;
flatbuffers::uoffset_t start_;
void add_base_type(BaseType base_type) { fbb_.AddElement<int8_t>(4, static_cast<int8_t>(base_type), 0); }
void add_element(BaseType element) { fbb_.AddElement<int8_t>(6, static_cast<int8_t>(element), 0); }
void add_index(int32_t index) { fbb_.AddElement<int32_t>(8, index, -1); }
TypeBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) { start_ = fbb_.StartTable(); }
TypeBuilder &operator=(const TypeBuilder &);
flatbuffers::Offset<Type> Finish() {
auto o = flatbuffers::Offset<Type>(fbb_.EndTable(start_, 3));
return o;
}
};
inline flatbuffers::Offset<Type> CreateType(flatbuffers::FlatBufferBuilder &_fbb,
BaseType base_type = None,
BaseType element = None,
int32_t index = -1) {
TypeBuilder builder_(_fbb);
builder_.add_index(index);
builder_.add_element(element);
builder_.add_base_type(base_type);
return builder_.Finish();
}
struct EnumVal FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
const flatbuffers::String *name() const { return GetPointer<const flatbuffers::String *>(4); }
int64_t value() const { return GetField<int64_t>(6, 0); }
bool KeyCompareLessThan(const EnumVal *o) const { return value() < o->value(); }
int KeyCompareWithValue(int64_t val) const { return value() < val ? -1 : value() > val; }
const Object *object() const { return GetPointer<const Object *>(8); }
bool Verify(flatbuffers::Verifier &verifier) const {
return VerifyTableStart(verifier) &&
VerifyFieldRequired<flatbuffers::uoffset_t>(verifier, 4 /* name */) &&
verifier.Verify(name()) &&
VerifyField<int64_t>(verifier, 6 /* value */) &&
VerifyField<flatbuffers::uoffset_t>(verifier, 8 /* object */) &&
verifier.VerifyTable(object()) &&
verifier.EndTable();
}
};
struct EnumValBuilder {
flatbuffers::FlatBufferBuilder &fbb_;
flatbuffers::uoffset_t start_;
void add_name(flatbuffers::Offset<flatbuffers::String> name) { fbb_.AddOffset(4, name); }
void add_value(int64_t value) { fbb_.AddElement<int64_t>(6, value, 0); }
void add_object(flatbuffers::Offset<Object> object) { fbb_.AddOffset(8, object); }
EnumValBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) { start_ = fbb_.StartTable(); }
EnumValBuilder &operator=(const EnumValBuilder &);
flatbuffers::Offset<EnumVal> Finish() {
auto o = flatbuffers::Offset<EnumVal>(fbb_.EndTable(start_, 3));
fbb_.Required(o, 4); // name
return o;
}
};
inline flatbuffers::Offset<EnumVal> CreateEnumVal(flatbuffers::FlatBufferBuilder &_fbb,
flatbuffers::Offset<flatbuffers::String> name = 0,
int64_t value = 0,
flatbuffers::Offset<Object> object = 0) {
EnumValBuilder builder_(_fbb);
builder_.add_value(value);
builder_.add_object(object);
builder_.add_name(name);
return builder_.Finish();
}
struct Enum FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
const flatbuffers::String *name() const { return GetPointer<const flatbuffers::String *>(4); }
bool KeyCompareLessThan(const Enum *o) const { return *name() < *o->name(); }
int KeyCompareWithValue(const char *val) const { return strcmp(name()->c_str(), val); }
const flatbuffers::Vector<flatbuffers::Offset<EnumVal>> *values() const { return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<EnumVal>> *>(6); }
uint8_t is_union() const { return GetField<uint8_t>(8, 0); }
const Type *underlying_type() const { return GetPointer<const Type *>(10); }
bool Verify(flatbuffers::Verifier &verifier) const {
return VerifyTableStart(verifier) &&
VerifyFieldRequired<flatbuffers::uoffset_t>(verifier, 4 /* name */) &&
verifier.Verify(name()) &&
VerifyFieldRequired<flatbuffers::uoffset_t>(verifier, 6 /* values */) &&
verifier.Verify(values()) &&
verifier.VerifyVectorOfTables(values()) &&
VerifyField<uint8_t>(verifier, 8 /* is_union */) &&
VerifyFieldRequired<flatbuffers::uoffset_t>(verifier, 10 /* underlying_type */) &&
verifier.VerifyTable(underlying_type()) &&
verifier.EndTable();
}
};
struct EnumBuilder {
flatbuffers::FlatBufferBuilder &fbb_;
flatbuffers::uoffset_t start_;
void add_name(flatbuffers::Offset<flatbuffers::String> name) { fbb_.AddOffset(4, name); }
void add_values(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<EnumVal>>> values) { fbb_.AddOffset(6, values); }
void add_is_union(uint8_t is_union) { fbb_.AddElement<uint8_t>(8, is_union, 0); }
void add_underlying_type(flatbuffers::Offset<Type> underlying_type) { fbb_.AddOffset(10, underlying_type); }
EnumBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) { start_ = fbb_.StartTable(); }
EnumBuilder &operator=(const EnumBuilder &);
flatbuffers::Offset<Enum> Finish() {
auto o = flatbuffers::Offset<Enum>(fbb_.EndTable(start_, 4));
fbb_.Required(o, 4); // name
fbb_.Required(o, 6); // values
fbb_.Required(o, 10); // underlying_type
return o;
}
};
inline flatbuffers::Offset<Enum> CreateEnum(flatbuffers::FlatBufferBuilder &_fbb,
flatbuffers::Offset<flatbuffers::String> name = 0,
flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<EnumVal>>> values = 0,
uint8_t is_union = 0,
flatbuffers::Offset<Type> underlying_type = 0) {
EnumBuilder builder_(_fbb);
builder_.add_underlying_type(underlying_type);
builder_.add_values(values);
builder_.add_name(name);
builder_.add_is_union(is_union);
return builder_.Finish();
}
struct Field FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
const flatbuffers::String *name() const { return GetPointer<const flatbuffers::String *>(4); }
bool KeyCompareLessThan(const Field *o) const { return *name() < *o->name(); }
int KeyCompareWithValue(const char *val) const { return strcmp(name()->c_str(), val); }
const Type *type() const { return GetPointer<const Type *>(6); }
uint16_t id() const { return GetField<uint16_t>(8, 0); }
uint16_t offset() const { return GetField<uint16_t>(10, 0); }
int64_t default_integer() const { return GetField<int64_t>(12, 0); }
double default_real() const { return GetField<double>(14, 0.0); }
uint8_t deprecated() const { return GetField<uint8_t>(16, 0); }
uint8_t required() const { return GetField<uint8_t>(18, 0); }
uint8_t key() const { return GetField<uint8_t>(20, 0); }
bool Verify(flatbuffers::Verifier &verifier) const {
return VerifyTableStart(verifier) &&
VerifyFieldRequired<flatbuffers::uoffset_t>(verifier, 4 /* name */) &&
verifier.Verify(name()) &&
VerifyFieldRequired<flatbuffers::uoffset_t>(verifier, 6 /* type */) &&
verifier.VerifyTable(type()) &&
VerifyField<uint16_t>(verifier, 8 /* id */) &&
VerifyField<uint16_t>(verifier, 10 /* offset */) &&
VerifyField<int64_t>(verifier, 12 /* default_integer */) &&
VerifyField<double>(verifier, 14 /* default_real */) &&
VerifyField<uint8_t>(verifier, 16 /* deprecated */) &&
VerifyField<uint8_t>(verifier, 18 /* required */) &&
VerifyField<uint8_t>(verifier, 20 /* key */) &&
verifier.EndTable();
}
};
struct FieldBuilder {
flatbuffers::FlatBufferBuilder &fbb_;
flatbuffers::uoffset_t start_;
void add_name(flatbuffers::Offset<flatbuffers::String> name) { fbb_.AddOffset(4, name); }
void add_type(flatbuffers::Offset<Type> type) { fbb_.AddOffset(6, type); }
void add_id(uint16_t id) { fbb_.AddElement<uint16_t>(8, id, 0); }
void add_offset(uint16_t offset) { fbb_.AddElement<uint16_t>(10, offset, 0); }
void add_default_integer(int64_t default_integer) { fbb_.AddElement<int64_t>(12, default_integer, 0); }
void add_default_real(double default_real) { fbb_.AddElement<double>(14, default_real, 0.0); }
void add_deprecated(uint8_t deprecated) { fbb_.AddElement<uint8_t>(16, deprecated, 0); }
void add_required(uint8_t required) { fbb_.AddElement<uint8_t>(18, required, 0); }
void add_key(uint8_t key) { fbb_.AddElement<uint8_t>(20, key, 0); }
FieldBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) { start_ = fbb_.StartTable(); }
FieldBuilder &operator=(const FieldBuilder &);
flatbuffers::Offset<Field> Finish() {
auto o = flatbuffers::Offset<Field>(fbb_.EndTable(start_, 9));
fbb_.Required(o, 4); // name
fbb_.Required(o, 6); // type
return o;
}
};
inline flatbuffers::Offset<Field> CreateField(flatbuffers::FlatBufferBuilder &_fbb,
flatbuffers::Offset<flatbuffers::String> name = 0,
flatbuffers::Offset<Type> type = 0,
uint16_t id = 0,
uint16_t offset = 0,
int64_t default_integer = 0,
double default_real = 0.0,
uint8_t deprecated = 0,
uint8_t required = 0,
uint8_t key = 0) {
FieldBuilder builder_(_fbb);
builder_.add_default_real(default_real);
builder_.add_default_integer(default_integer);
builder_.add_type(type);
builder_.add_name(name);
builder_.add_offset(offset);
builder_.add_id(id);
builder_.add_key(key);
builder_.add_required(required);
builder_.add_deprecated(deprecated);
return builder_.Finish();
}
struct Object FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
const flatbuffers::String *name() const { return GetPointer<const flatbuffers::String *>(4); }
bool KeyCompareLessThan(const Object *o) const { return *name() < *o->name(); }
int KeyCompareWithValue(const char *val) const { return strcmp(name()->c_str(), val); }
const flatbuffers::Vector<flatbuffers::Offset<Field>> *fields() const { return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<Field>> *>(6); }
uint8_t is_struct() const { return GetField<uint8_t>(8, 0); }
int32_t minalign() const { return GetField<int32_t>(10, 0); }
int32_t bytesize() const { return GetField<int32_t>(12, 0); }
bool Verify(flatbuffers::Verifier &verifier) const {
return VerifyTableStart(verifier) &&
VerifyFieldRequired<flatbuffers::uoffset_t>(verifier, 4 /* name */) &&
verifier.Verify(name()) &&
VerifyFieldRequired<flatbuffers::uoffset_t>(verifier, 6 /* fields */) &&
verifier.Verify(fields()) &&
verifier.VerifyVectorOfTables(fields()) &&
VerifyField<uint8_t>(verifier, 8 /* is_struct */) &&
VerifyField<int32_t>(verifier, 10 /* minalign */) &&
VerifyField<int32_t>(verifier, 12 /* bytesize */) &&
verifier.EndTable();
}
};
struct ObjectBuilder {
flatbuffers::FlatBufferBuilder &fbb_;
flatbuffers::uoffset_t start_;
void add_name(flatbuffers::Offset<flatbuffers::String> name) { fbb_.AddOffset(4, name); }
void add_fields(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<Field>>> fields) { fbb_.AddOffset(6, fields); }
void add_is_struct(uint8_t is_struct) { fbb_.AddElement<uint8_t>(8, is_struct, 0); }
void add_minalign(int32_t minalign) { fbb_.AddElement<int32_t>(10, minalign, 0); }
void add_bytesize(int32_t bytesize) { fbb_.AddElement<int32_t>(12, bytesize, 0); }
ObjectBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) { start_ = fbb_.StartTable(); }
ObjectBuilder &operator=(const ObjectBuilder &);
flatbuffers::Offset<Object> Finish() {
auto o = flatbuffers::Offset<Object>(fbb_.EndTable(start_, 5));
fbb_.Required(o, 4); // name
fbb_.Required(o, 6); // fields
return o;
}
};
inline flatbuffers::Offset<Object> CreateObject(flatbuffers::FlatBufferBuilder &_fbb,
flatbuffers::Offset<flatbuffers::String> name = 0,
flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<Field>>> fields = 0,
uint8_t is_struct = 0,
int32_t minalign = 0,
int32_t bytesize = 0) {
ObjectBuilder builder_(_fbb);
builder_.add_bytesize(bytesize);
builder_.add_minalign(minalign);
builder_.add_fields(fields);
builder_.add_name(name);
builder_.add_is_struct(is_struct);
return builder_.Finish();
}
struct Schema FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
const flatbuffers::Vector<flatbuffers::Offset<Object>> *objects() const { return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<Object>> *>(4); }
const flatbuffers::Vector<flatbuffers::Offset<Enum>> *enums() const { return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<Enum>> *>(6); }
const flatbuffers::String *file_ident() const { return GetPointer<const flatbuffers::String *>(8); }
const flatbuffers::String *file_ext() const { return GetPointer<const flatbuffers::String *>(10); }
const Object *root_table() const { return GetPointer<const Object *>(12); }
bool Verify(flatbuffers::Verifier &verifier) const {
return VerifyTableStart(verifier) &&
VerifyFieldRequired<flatbuffers::uoffset_t>(verifier, 4 /* objects */) &&
verifier.Verify(objects()) &&
verifier.VerifyVectorOfTables(objects()) &&
VerifyFieldRequired<flatbuffers::uoffset_t>(verifier, 6 /* enums */) &&
verifier.Verify(enums()) &&
verifier.VerifyVectorOfTables(enums()) &&
VerifyField<flatbuffers::uoffset_t>(verifier, 8 /* file_ident */) &&
verifier.Verify(file_ident()) &&
VerifyField<flatbuffers::uoffset_t>(verifier, 10 /* file_ext */) &&
verifier.Verify(file_ext()) &&
VerifyField<flatbuffers::uoffset_t>(verifier, 12 /* root_table */) &&
verifier.VerifyTable(root_table()) &&
verifier.EndTable();
}
};
struct SchemaBuilder {
flatbuffers::FlatBufferBuilder &fbb_;
flatbuffers::uoffset_t start_;
void add_objects(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<Object>>> objects) { fbb_.AddOffset(4, objects); }
void add_enums(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<Enum>>> enums) { fbb_.AddOffset(6, enums); }
void add_file_ident(flatbuffers::Offset<flatbuffers::String> file_ident) { fbb_.AddOffset(8, file_ident); }
void add_file_ext(flatbuffers::Offset<flatbuffers::String> file_ext) { fbb_.AddOffset(10, file_ext); }
void add_root_table(flatbuffers::Offset<Object> root_table) { fbb_.AddOffset(12, root_table); }
SchemaBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) { start_ = fbb_.StartTable(); }
SchemaBuilder &operator=(const SchemaBuilder &);
flatbuffers::Offset<Schema> Finish() {
auto o = flatbuffers::Offset<Schema>(fbb_.EndTable(start_, 5));
fbb_.Required(o, 4); // objects
fbb_.Required(o, 6); // enums
return o;
}
};
inline flatbuffers::Offset<Schema> CreateSchema(flatbuffers::FlatBufferBuilder &_fbb,
flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<Object>>> objects = 0,
flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<Enum>>> enums = 0,
flatbuffers::Offset<flatbuffers::String> file_ident = 0,
flatbuffers::Offset<flatbuffers::String> file_ext = 0,
flatbuffers::Offset<Object> root_table = 0) {
SchemaBuilder builder_(_fbb);
builder_.add_root_table(root_table);
builder_.add_file_ext(file_ext);
builder_.add_file_ident(file_ident);
builder_.add_enums(enums);
builder_.add_objects(objects);
return builder_.Finish();
}
inline const reflection::Schema *GetSchema(const void *buf) { return flatbuffers::GetRoot<reflection::Schema>(buf); }
inline bool VerifySchemaBuffer(flatbuffers::Verifier &verifier) { return verifier.VerifyBuffer<reflection::Schema>(); }
inline const char *SchemaIdentifier() { return "BFBS"; }
inline bool SchemaBufferHasIdentifier(const void *buf) { return flatbuffers::BufferHasIdentifier(buf, SchemaIdentifier()); }
inline const char *SchemaExtension() { return "bfbs"; }
inline void FinishSchemaBuffer(flatbuffers::FlatBufferBuilder &fbb, flatbuffers::Offset<reflection::Schema> root) { fbb.Finish(root, SchemaIdentifier()); }
} // namespace reflection
#endif // FLATBUFFERS_GENERATED_REFLECTION_REFLECTION_H_

View File

@@ -42,10 +42,8 @@ namespace flatbuffers {
// Convert an integer or floating point value to a string.
// In contrast to std::stringstream, "char" values are
// converted to a string of digits.
// converted to a string of digits, and we don't use scientific notation.
template<typename T> std::string NumToString(T t) {
// to_string() prints different numbers of digits for floats depending on
// platform and isn't available on Android, so we use stringstream
std::stringstream ss;
ss << t;
return ss.str();
@@ -58,6 +56,27 @@ template<> inline std::string NumToString<unsigned char>(unsigned char t) {
return NumToString(static_cast<int>(t));
}
// Special versions for floats/doubles.
template<> inline std::string NumToString<double>(double t) {
// to_string() prints different numbers of digits for floats depending on
// platform and isn't available on Android, so we use stringstream
std::stringstream ss;
// Use std::fixed to surpress scientific notation.
ss << std::fixed << t;
auto s = ss.str();
// Sadly, std::fixed turns "1" into "1.00000", so here we undo that.
auto p = s.find_last_not_of('0');
if (p != std::string::npos) {
s.resize(p + 1); // Strip trailing zeroes.
if (s.back() == '.')
s.erase(s.size() - 1, 1); // Strip '.' if a whole number.
}
return s;
}
template<> inline std::string NumToString<float>(float t) {
return NumToString(static_cast<double>(t));
}
// Convert an integer value to a hexadecimal string.
// The returned string length is always xdigits long, prefixed by 0 digits.
// For example, IntToStringHex(0x23, 8) returns the string "00000023".
@@ -71,8 +90,17 @@ inline std::string IntToStringHex(int i, int xdigits) {
return ss.str();
}
// Portable implementation of strtoull().
// Portable implementation of strtoll().
inline int64_t StringToInt(const char *str, int base = 10) {
#ifdef _MSC_VER
return _strtoi64(str, nullptr, base);
#else
return strtoll(str, nullptr, base);
#endif
}
// Portable implementation of strtoull().
inline int64_t StringToUInt(const char *str, int base = 10) {
#ifdef _MSC_VER
return _strtoui64(str, nullptr, base);
#else
@@ -93,8 +121,18 @@ inline bool FileExists(const char *name) {
inline bool LoadFile(const char *name, bool binary, std::string *buf) {
std::ifstream ifs(name, binary ? std::ifstream::binary : std::ifstream::in);
if (!ifs.is_open()) return false;
*buf = std::string(std::istreambuf_iterator<char>(ifs),
std::istreambuf_iterator<char>());
if (binary) {
// The fastest way to read a file into a string.
ifs.seekg(0, std::ios::end);
(*buf).resize(static_cast<size_t>(ifs.tellg()));
ifs.seekg(0, std::ios::beg);
ifs.read(&(*buf)[0], (*buf).size());
} else {
// This is slower, but works correctly on all platforms for text files.
std::ostringstream oss;
oss << ifs.rdbuf();
*buf = oss.str();
}
return !ifs.bad();
}

View File

@@ -52,6 +52,13 @@ public class FlatBufferBuilder {
bb = newByteBuffer(initial_size);
}
/**
* Start with a buffer of 1KiB, then grow as required.
*/
public FlatBufferBuilder() {
this(1024);
}
/**
* Alternative constructor allowing reuse of {@link ByteBuffer}s. The builder
* can still grow the buffer as necessary. User classes should make sure
@@ -262,6 +269,21 @@ public class FlatBufferBuilder {
return endVector();
}
/**
* Encode the string {@code s} in the buffer using UTF-8.
*
* @param s An already encoded UTF-8 string
* @return The offset in the buffer where the encoded string starts
*/
public int createString(ByteBuffer s) {
int length = s.remaining();
addByte((byte)0);
startVector(1, length, 1);
bb.position(space -= length);
bb.put(s);
return endVector();
}
/**
* Should not be creating any other object, string or vector
* while an object is being constructed

View File

@@ -25,6 +25,8 @@ public class Table {
protected int bb_pos;
protected ByteBuffer bb;
public ByteBuffer getByteBuffer() { return bb; }
// Look up a field in the vtable, return an offset into the object, or 0 if the field is not
// present.
protected int __offset(int vtable_offset) {
@@ -45,7 +47,7 @@ public class Table {
protected String __string(int offset) {
offset += bb.getInt(offset);
if (bb.hasArray()) {
return new String(bb.array(), offset + SIZEOF_INT, bb.getInt(offset), FlatBufferBuilder.utf8charset);
return new String(bb.array(), bb.arrayOffset() + offset + SIZEOF_INT, bb.getInt(offset), FlatBufferBuilder.utf8charset);
} else {
// We can't access .array(), since the ByteBuffer is read-only,
// off-heap or a memory map

View File

@@ -5,7 +5,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>com.google.flatbuffers</groupId>
<artifactId>flatbuffers-java</artifactId>
<version>0.0.0-SNAPSHOT</version>
<version>1.2.0-SNAPSHOT</version>
<packaging>jar</packaging>
<name>FlatBuffers Java API</name>
<description>

1072
js/flatbuffers.js Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -17,7 +17,6 @@
//#define UNSAFE_BYTEBUFFER // uncomment this line to use faster ByteBuffer
using System;
using System.Linq;
namespace FlatBuffers
{
@@ -36,13 +35,23 @@ namespace FlatBuffers
public byte[] Data { get { return _buffer; } }
public ByteBuffer(byte[] buffer)
public ByteBuffer(byte[] buffer) : this(buffer, 0) { }
public ByteBuffer(byte[] buffer, int pos)
{
_buffer = buffer;
_pos = 0;
_pos = pos;
}
public int position() { return _pos; }
public int Position {
get { return _pos; }
set { _pos = value; }
}
public void Reset()
{
_pos = 0;
}
// Pre-allocated helper arrays for convertion.
private float[] floathelper = new[] { 0.0f };
@@ -93,7 +102,6 @@ namespace FlatBuffers
_buffer[offset + count - 1 - i] = (byte)(data >> i * 8);
}
}
_pos = offset;
}
protected ulong ReadLittleEndian(int offset, int count)
@@ -130,14 +138,18 @@ namespace FlatBuffers
{
AssertOffsetAndLength(offset, sizeof(sbyte));
_buffer[offset] = (byte)value;
_pos = offset;
}
public void PutByte(int offset, byte value)
{
AssertOffsetAndLength(offset, sizeof(byte));
_buffer[offset] = value;
_pos = offset;
}
// this method exists in order to conform with Java ByteBuffer standards
public void Put(int offset, byte value)
{
PutByte(offset, value);
}
#if UNSAFE_BYTEBUFFER

View File

@@ -1,4 +1,4 @@
/*
/*
* Copyright 2014 Google Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -49,8 +49,19 @@ namespace FlatBuffers
_bb = new ByteBuffer(new byte[initialSize]);
}
public void Clear()
{
_space = _bb.Length;
_bb.Reset();
_minAlign = 1;
_vtable = null;
_objectStart = 0;
_vtables = new int[16];
_numVtables = 0;
_vectorNumElems = 0;
}
public int Offset() { return _bb.Length - _space; }
public int Offset { get { return _bb.Length - _space; } }
public void Pad(int size)
{
@@ -75,8 +86,7 @@ namespace FlatBuffers
Buffer.BlockCopy(oldBuf, 0, newBuf, newBufSize - oldBufSize,
oldBufSize);
_bb = new ByteBuffer(newBuf);
_bb = new ByteBuffer(newBuf, newBufSize);
}
// Prepare to write an element of `size` after `additional_bytes`
@@ -181,10 +191,10 @@ namespace FlatBuffers
public void AddOffset(int off)
{
Prep(sizeof(int), 0); // Ensure alignment is already done.
if (off > Offset())
if (off > Offset)
throw new ArgumentException();
off = Offset() - off + sizeof(int);
off = Offset - off + sizeof(int);
PutInt(off);
}
@@ -196,10 +206,10 @@ namespace FlatBuffers
Prep(alignment, elemSize * count); // Just in case alignment > int.
}
public int EndVector()
public VectorOffset EndVector()
{
PutInt(_vectorNumElems);
return Offset();
return new VectorOffset(Offset);
}
public void Nested(int obj)
@@ -207,7 +217,7 @@ namespace FlatBuffers
// Structs are always stored inline, so need to be created right
// where they are used. You'll get this assert if you created it
// elsewhere.
if (obj != Offset())
if (obj != Offset)
throw new Exception(
"FlatBuffers: struct must be serialized inline.");
}
@@ -225,7 +235,7 @@ namespace FlatBuffers
{
NotNested();
_vtable = new int[numfields];
_objectStart = Offset();
_objectStart = Offset;
}
@@ -233,7 +243,7 @@ namespace FlatBuffers
// buffer.
public void Slot(int voffset)
{
_vtable[voffset] = Offset();
_vtable[voffset] = Offset;
}
// Add a scalar to a table at `o` into its vtable, with value `x` and default `d`
@@ -250,7 +260,7 @@ namespace FlatBuffers
public void AddDouble(int o, double x, double d) { if (x != d) { AddDouble(x); Slot(o); } }
public void AddOffset(int o, int x, int d) { if (x != d) { AddOffset(x); Slot(o); } }
public int CreateString(string s)
public StringOffset CreateString(string s)
{
NotNested();
byte[] utf8 = Encoding.UTF8.GetBytes(s);
@@ -258,7 +268,7 @@ namespace FlatBuffers
StartVector(1, utf8.Length, 1);
Buffer.BlockCopy(utf8, 0, _bb.Data, _space -= utf8.Length,
utf8.Length);
return EndVector();
return new StringOffset(EndVector().Value);
}
// Structs are stored inline, so nothing additional is being added.
@@ -280,7 +290,7 @@ namespace FlatBuffers
"Flatbuffers: calling endObject without a startObject");
AddInt((int)0);
var vtableloc = Offset();
var vtableloc = Offset;
// Write out the current vtable.
for (int i = _vtable.Length - 1; i >= 0 ; i--) {
// Offset relative to the start of the table.
@@ -333,9 +343,9 @@ namespace FlatBuffers
_vtables = newvtables;
};
_vtables[_numVtables++] = Offset();
_vtables[_numVtables++] = Offset;
// Point table to current vtable.
_bb.PutInt(_bb.Length - vtableloc, Offset() - vtableloc);
_bb.PutInt(_bb.Length - vtableloc, Offset - vtableloc);
}
_vtable = null;
@@ -359,16 +369,17 @@ namespace FlatBuffers
{
Prep(_minAlign, sizeof(int));
AddOffset(rootTable);
_bb.Position = _space;
}
public ByteBuffer DataBuffer() { return _bb; }
public ByteBuffer DataBuffer { get { return _bb; } }
// Utility function for copying a byte array that starts at 0.
public byte[] SizedByteArray()
{
var newArray = new byte[_bb.Data.Length - _bb.position()];
Buffer.BlockCopy(_bb.Data, _bb.position(), newArray, 0,
_bb.Data.Length - _bb.position());
var newArray = new byte[_bb.Data.Length - _bb.Position];
Buffer.BlockCopy(_bb.Data, _bb.Position, newArray, 0,
_bb.Data.Length - _bb.Position);
return newArray;
}
@@ -387,7 +398,7 @@ namespace FlatBuffers
{
AddByte((byte)fileIdentifier[i]);
}
AddOffset(rootTable);
Finish(rootTable);
}

View File

@@ -37,6 +37,7 @@
<Compile Include="ByteBuffer.cs" />
<Compile Include="FlatBufferBuilder.cs" />
<Compile Include="FlatBufferConstants.cs" />
<Compile Include="Offset.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Struct.cs" />
<Compile Include="Table.cs" />

48
net/FlatBuffers/Offset.cs Normal file
View File

@@ -0,0 +1,48 @@
/*
* Copyright 2014 Google Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
namespace FlatBuffers
{
/// <summary>
/// Offset class for typesafe assignments.
/// </summary>
public struct Offset<T> where T : class
{
public int Value;
public Offset(int value)
{
Value = value;
}
}
public struct StringOffset
{
public int Value;
public StringOffset(int value)
{
Value = value;
}
}
public struct VectorOffset
{
public int Value;
public VectorOffset(int value)
{
Value = value;
}
}
}

View File

@@ -66,7 +66,7 @@ namespace FlatBuffers
}
// Initialize any Table-derived type to point to the union at the given offset.
protected Table __union(Table t, int offset)
protected TTable __union<TTable>(TTable t, int offset) where TTable : Table
{
offset += bb_pos;
t.bb_pos = offset + bb.GetInt(offset);
@@ -81,7 +81,7 @@ namespace FlatBuffers
for (var i = 0; i < FlatBufferConstants.FileIdentifierLength; i++)
{
if (ident[i] != (char)bb.Get(bb.position() + sizeof(int) + i)) return false;
if (ident[i] != (char)bb.Get(bb.Position + sizeof(int) + i)) return false;
}
return true;

0
python/__init__.py Normal file
View File

View File

@@ -0,0 +1,17 @@
# Copyright 2014 Google Inc. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from .builder import Builder
from .table import Table
from .compat import range_func as compat_range

View File

@@ -0,0 +1,558 @@
# Copyright 2014 Google Inc. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from . import number_types as N
from .number_types import (UOffsetTFlags, SOffsetTFlags, VOffsetTFlags)
from . import encode
from . import packer
from . import compat
from .compat import range_func
from .compat import memoryview_type
class OffsetArithmeticError(RuntimeError):
"""
Error caused by an Offset arithmetic error. Probably caused by bad
writing of fields. This is considered an unreachable situation in
normal circumstances.
"""
pass
class NotInObjectError(RuntimeError):
"""
Error caused by using a Builder to write Object data when not inside
an Object.
"""
pass
class ObjectIsNestedError(RuntimeError):
"""
Error caused by using a Builder to begin an Object when an Object is
already being built.
"""
pass
class StructIsNotInlineError(RuntimeError):
"""
Error caused by using a Builder to write a Struct at a location that
is not the current Offset.
"""
pass
class BuilderSizeError(RuntimeError):
"""
Error caused by causing a Builder to exceed the hardcoded limit of 2
gigabytes.
"""
pass
# VtableMetadataFields is the count of metadata fields in each vtable.
VtableMetadataFields = 2
class Builder(object):
"""
A Builder is used to construct one or more FlatBuffers. Typically, Builder
objects will be used from code generated by the `flatc` compiler.
A Builder constructs byte buffers in a last-first manner for simplicity and
performance during reading.
Internally, a Builder is a state machine for creating FlatBuffer objects.
It holds the following internal state:
Bytes: an array of bytes.
current_vtable: a list of integers.
vtables: a list of vtable entries (i.e. a list of list of integers).
"""
__slots__ = ("Bytes", "current_vtable", "head", "minalign", "objectEnd",
"vtables")
"""
Maximum buffer size constant, in bytes.
Builder will never allow it's buffer grow over this size.
Currently equals 2Gb.
"""
MAX_BUFFER_SIZE = 2**31
def __init__(self, initialSize):
"""
Initializes a Builder of size `initial_size`.
The internal buffer is grown as needed.
"""
if not (0 <= initialSize <= Builder.MAX_BUFFER_SIZE):
msg = "flatbuffers: Cannot create Builder larger than 2 gigabytes."
raise BuilderSizeError(msg)
self.Bytes = bytearray(initialSize)
self.current_vtable = None
self.head = UOffsetTFlags.py_type(initialSize)
self.minalign = 1
self.objectEnd = None
self.vtables = []
def Output(self):
"""
Output returns the portion of the buffer that has been used for
writing data.
"""
return self.Bytes[self.Head():]
def StartObject(self, numfields):
"""StartObject initializes bookkeeping for writing a new object."""
self.assertNotNested()
# use 32-bit offsets so that arithmetic doesn't overflow.
self.current_vtable = [0 for _ in range_func(numfields)]
self.objectEnd = self.Offset()
self.minalign = 1
def WriteVtable(self):
"""
WriteVtable serializes the vtable for the current object, if needed.
Before writing out the vtable, this checks pre-existing vtables for
equality to this one. If an equal vtable is found, point the object to
the existing vtable and return.
Because vtable values are sensitive to alignment of object data, not
all logically-equal vtables will be deduplicated.
A vtable has the following format:
<VOffsetT: size of the vtable in bytes, including this value>
<VOffsetT: size of the object in bytes, including the vtable offset>
<VOffsetT: offset for a field> * N, where N is the number of fields
in the schema for this type. Includes deprecated fields.
Thus, a vtable is made of 2 + N elements, each VOffsetT bytes wide.
An object has the following format:
<SOffsetT: offset to this object's vtable (may be negative)>
<byte: data>+
"""
# Prepend a zero scalar to the object. Later in this function we'll
# write an offset here that points to the object's vtable:
self.PrependSOffsetTRelative(0)
objectOffset = self.Offset()
existingVtable = None
# Search backwards through existing vtables, because similar vtables
# are likely to have been recently appended. See
# BenchmarkVtableDeduplication for a case in which this heuristic
# saves about 30% of the time used in writing objects with duplicate
# tables.
i = len(self.vtables) - 1
while i >= 0:
# Find the other vtable, which is associated with `i`:
vt2Offset = self.vtables[i]
vt2Start = len(self.Bytes) - vt2Offset
vt2Len = encode.Get(packer.voffset, self.Bytes, vt2Start)
metadata = VtableMetadataFields * N.VOffsetTFlags.bytewidth
vt2End = vt2Start + vt2Len
vt2 = self.Bytes[vt2Start+metadata:vt2End]
# Compare the other vtable to the one under consideration.
# If they are equal, store the offset and break:
if vtableEqual(self.current_vtable, objectOffset, vt2):
existingVtable = vt2Offset
break
i -= 1
if existingVtable is None:
# Did not find a vtable, so write this one to the buffer.
# Write out the current vtable in reverse , because
# serialization occurs in last-first order:
i = len(self.current_vtable) - 1
while i >= 0:
off = 0
if self.current_vtable[i] != 0:
# Forward reference to field;
# use 32bit number to ensure no overflow:
off = objectOffset - self.current_vtable[i]
self.PrependVOffsetT(off)
i -= 1
# The two metadata fields are written last.
# First, store the object bytesize:
objectSize = UOffsetTFlags.py_type(objectOffset - self.objectEnd)
self.PrependVOffsetT(VOffsetTFlags.py_type(objectSize))
# Second, store the vtable bytesize:
vBytes = len(self.current_vtable) + VtableMetadataFields
vBytes *= N.VOffsetTFlags.bytewidth
self.PrependVOffsetT(VOffsetTFlags.py_type(vBytes))
# Next, write the offset to the new vtable in the
# already-allocated SOffsetT at the beginning of this object:
objectStart = SOffsetTFlags.py_type(len(self.Bytes) - objectOffset)
encode.Write(packer.soffset, self.Bytes, objectStart,
SOffsetTFlags.py_type(self.Offset() - objectOffset))
# Finally, store this vtable in memory for future
# deduplication:
self.vtables.append(self.Offset())
else:
# Found a duplicate vtable.
objectStart = SOffsetTFlags.py_type(len(self.Bytes) - objectOffset)
self.head = UOffsetTFlags.py_type(objectStart)
# Write the offset to the found vtable in the
# already-allocated SOffsetT at the beginning of this object:
encode.Write(packer.soffset, self.Bytes, self.Head(),
SOffsetTFlags.py_type(existingVtable - objectOffset))
self.current_vtable = None
return objectOffset
def EndObject(self):
"""EndObject writes data necessary to finish object construction."""
if self.current_vtable is None:
msg = ("flatbuffers: Tried to write the end of an Object when "
"the Builder was not currently writing an Object.")
raise NotInObjectError(msg)
return self.WriteVtable()
def growByteBuffer(self):
"""Doubles the size of the byteslice, and copies the old data towards
the end of the new buffer (since we build the buffer backwards)."""
if len(self.Bytes) == Builder.MAX_BUFFER_SIZE:
msg = "flatbuffers: cannot grow buffer beyond 2 gigabytes"
raise BuilderSizeError(msg)
newSize = min(len(self.Bytes) * 2, Builder.MAX_BUFFER_SIZE)
if newSize == 0:
newSize = 1
bytes2 = bytearray(newSize)
bytes2[newSize-len(self.Bytes):] = self.Bytes
self.Bytes = bytes2
def Head(self):
"""
Head gives the start of useful data in the underlying byte buffer.
Note: unlike other functions, this value is interpreted as from the left.
"""
return self.head
def Offset(self):
"""Offset relative to the end of the buffer."""
return UOffsetTFlags.py_type(len(self.Bytes) - self.Head())
def Pad(self, n):
"""Pad places zeros at the current offset."""
for i in range_func(n):
self.Place(0, N.Uint8Flags)
def Prep(self, size, additionalBytes):
"""
Prep prepares to write an element of `size` after `additional_bytes`
have been written, e.g. if you write a string, you need to align
such the int length field is aligned to SizeInt32, and the string
data follows it directly.
If all you need to do is align, `additionalBytes` will be 0.
"""
# Track the biggest thing we've ever aligned to.
if size > self.minalign:
self.minalign = size
# Find the amount of alignment needed such that `size` is properly
# aligned after `additionalBytes`:
alignSize = (~(len(self.Bytes) - self.Head() + additionalBytes)) + 1
alignSize &= (size - 1)
# Reallocate the buffer if needed:
while self.Head() < alignSize+size+additionalBytes:
oldBufSize = len(self.Bytes)
self.growByteBuffer()
updated_head = self.head + len(self.Bytes) - oldBufSize
self.head = UOffsetTFlags.py_type(updated_head)
self.Pad(alignSize)
def PrependSOffsetTRelative(self, off):
"""
PrependSOffsetTRelative prepends an SOffsetT, relative to where it
will be written.
"""
# Ensure alignment is already done:
self.Prep(N.SOffsetTFlags.bytewidth, 0)
if not (off <= self.Offset()):
msg = "flatbuffers: Offset arithmetic error."
raise OffsetArithmeticError(msg)
off2 = self.Offset() - off + N.SOffsetTFlags.bytewidth
self.PlaceSOffsetT(off2)
def PrependUOffsetTRelative(self, off):
"""
PrependUOffsetTRelative prepends an UOffsetT, relative to where it
will be written.
"""
# Ensure alignment is already done:
self.Prep(N.UOffsetTFlags.bytewidth, 0)
if not (off <= self.Offset()):
msg = "flatbuffers: Offset arithmetic error."
raise OffsetArithmeticError(msg)
off2 = self.Offset() - off + N.UOffsetTFlags.bytewidth
self.PlaceUOffsetT(off2)
def StartVector(self, elemSize, numElems, alignment):
"""
StartVector initializes bookkeeping for writing a new vector.
A vector has the following format:
<UOffsetT: number of elements in this vector>
<T: data>+, where T is the type of elements of this vector.
"""
self.assertNotNested()
self.Prep(N.Uint32Flags.bytewidth, elemSize*numElems)
self.Prep(alignment, elemSize*numElems) # In case alignment > int.
return self.Offset()
def EndVector(self, vectorNumElems):
"""EndVector writes data necessary to finish vector construction."""
# we already made space for this, so write without PrependUint32
self.PlaceUOffsetT(vectorNumElems)
return self.Offset()
def CreateString(self, s):
"""CreateString writes a null-terminated byte string as a vector."""
self.assertNotNested()
if isinstance(s, compat.string_types):
x = s.encode()
elif isinstance(s, compat.binary_type):
x = s
else:
raise TypeError("non-string passed to CreateString")
self.Prep(N.UOffsetTFlags.bytewidth, (len(x)+1)*N.Uint8Flags.bytewidth)
self.Place(0, N.Uint8Flags)
l = UOffsetTFlags.py_type(len(s))
self.head = UOffsetTFlags.py_type(self.Head() - l)
self.Bytes[self.Head():self.Head()+l] = x
return self.EndVector(len(x))
def assertNotNested(self):
"""
Check that no other objects are being built while making this
object. If not, raise an exception.
"""
if self.current_vtable is not None:
msg = ("flatbuffers: Tried to write a new Object when the "
"Builder was already writing an Object.")
raise ObjectIsNestedError(msg)
def assertNested(self, obj):
"""
Structs are always stored inline, so need to be created right
where they are used. You'll get this error if you created it
elsewhere.
"""
N.enforce_number(obj, N.UOffsetTFlags)
if obj != self.Offset():
msg = ("flatbuffers: Tried to write a Struct at an Offset that "
"is different from the current Offset of the Builder.")
raise StructIsNotInlineError(msg)
def Slot(self, slotnum):
"""
Slot sets the vtable key `voffset` to the current location in the
buffer.
"""
if self.current_vtable is None:
msg = ("flatbuffers: Tried to write an Object field when "
"the Builder was not currently writing an Object.")
raise NotInObjectError(msg)
self.current_vtable[slotnum] = self.Offset()
def Finish(self, rootTable):
"""Finish finalizes a buffer, pointing to the given `rootTable`."""
N.enforce_number(rootTable, N.UOffsetTFlags)
self.Prep(self.minalign, N.UOffsetTFlags.bytewidth)
self.PrependUOffsetTRelative(rootTable)
return self.Head()
def Prepend(self, flags, off):
self.Prep(flags.bytewidth, 0)
self.Place(off, flags)
def PrependSlot(self, flags, o, x, d):
N.enforce_number(x, flags)
N.enforce_number(d, flags)
if x != d:
self.Prepend(flags, x)
self.Slot(o)
def PrependBoolSlot(self, *args): self.PrependSlot(N.BoolFlags, *args)
def PrependByteSlot(self, *args): self.PrependSlot(N.Uint8Flags, *args)
def PrependUint8Slot(self, *args): self.PrependSlot(N.Uint8Flags, *args)
def PrependUint16Slot(self, *args): self.PrependSlot(N.Uint16Flags, *args)
def PrependUint32Slot(self, *args): self.PrependSlot(N.Uint32Flags, *args)
def PrependUint64Slot(self, *args): self.PrependSlot(N.Uint64Flags, *args)
def PrependInt8Slot(self, *args): self.PrependSlot(N.Int8Flags, *args)
def PrependInt16Slot(self, *args): self.PrependSlot(N.Int16Flags, *args)
def PrependInt32Slot(self, *args): self.PrependSlot(N.Int32Flags, *args)
def PrependInt64Slot(self, *args): self.PrependSlot(N.Int64Flags, *args)
def PrependFloat32Slot(self, *args): self.PrependSlot(N.Float32Flags,
*args)
def PrependFloat64Slot(self, *args): self.PrependSlot(N.Float64Flags,
*args)
def PrependUOffsetTRelativeSlot(self, o, x, d):
"""
PrependUOffsetTRelativeSlot prepends an UOffsetT onto the object at
vtable slot `o`. If value `x` equals default `d`, then the slot will
be set to zero and no other data will be written.
"""
if x != d:
self.PrependUOffsetTRelative(x)
self.Slot(o)
def PrependStructSlot(self, v, x, d):
"""
PrependStructSlot prepends a struct onto the object at vtable slot `o`.
Structs are stored inline, so nothing additional is being added.
In generated code, `d` is always 0.
"""
N.enforce_number(d, N.UOffsetTFlags)
if x != d:
self.assertNested(x)
self.Slot(v)
def PrependBool(self, x): self.Prepend(N.BoolFlags, x)
def PrependByte(self, x): self.Prepend(N.Uint8Flags, x)
def PrependUint8(self, x): self.Prepend(N.Uint8Flags, x)
def PrependUint16(self, x): self.Prepend(N.Uint16Flags, x)
def PrependUint32(self, x): self.Prepend(N.Uint32Flags, x)
def PrependUint64(self, x): self.Prepend(N.Uint64Flags, x)
def PrependInt8(self, x): self.Prepend(N.Int8Flags, x)
def PrependInt16(self, x): self.Prepend(N.Int16Flags, x)
def PrependInt32(self, x): self.Prepend(N.Int32Flags, x)
def PrependInt64(self, x): self.Prepend(N.Int64Flags, x)
def PrependFloat32(self, x): self.Prepend(N.Float32Flags, x)
def PrependFloat64(self, x): self.Prepend(N.Float64Flags, x)
def PrependVOffsetT(self, x): self.Prepend(N.VOffsetTFlags, x)
def Place(self, x, flags):
"""
Place prepends a value specified by `flags` to the Builder,
without checking for available space.
"""
N.enforce_number(x, flags)
self.head = self.head - flags.bytewidth
encode.Write(flags.packer_type, self.Bytes, self.Head(), x)
def PlaceVOffsetT(self, x):
"""
PlaceVOffsetT prepends a VOffsetT to the Builder, without checking for
space.
"""
N.enforce_number(x, N.VOffsetTFlags)
self.head = self.head - N.VOffsetTFlags.bytewidth
encode.Write(packer.voffset, self.Bytes, self.Head(), x)
def PlaceSOffsetT(self, x):
"""
PlaceSOffsetT prepends a SOffsetT to the Builder, without checking for
space.
"""
N.enforce_number(x, N.SOffsetTFlags)
self.head = self.head - N.SOffsetTFlags.bytewidth
encode.Write(packer.soffset, self.Bytes, self.Head(), x)
def PlaceUOffsetT(self, x):
"""
PlaceUOffsetT prepends a UOffsetT to the Builder, without checking for
space.
"""
N.enforce_number(x, N.UOffsetTFlags)
self.head = self.head - N.UOffsetTFlags.bytewidth
encode.Write(packer.uoffset, self.Bytes, self.Head(), x)
def vtableEqual(a, objectStart, b):
"""vtableEqual compares an unwritten vtable to a written vtable."""
N.enforce_number(objectStart, N.UOffsetTFlags)
if len(a) * N.VOffsetTFlags.bytewidth != len(b):
return False
for i, elem in enumerate(a):
x = encode.Get(packer.voffset, b, i * N.VOffsetTFlags.bytewidth)
# Skip vtable entries that indicate a default value.
if x == 0 and elem == 0:
pass
else:
y = objectStart - elem
if x != y:
return False
return True

View File

@@ -0,0 +1,27 @@
""" A tiny version of `six` to help with backwards compability. """
import sys
PY2 = sys.version_info[0] == 2
PY26 = sys.version_info[0:2] == (2, 6)
PY3 = sys.version_info[0] == 3
PY34 = sys.version_info[0:2] >= (3, 4)
if PY3:
string_types = (str,)
binary_type = bytes
range_func = range
memoryview_type = memoryview
struct_bool_decl = "?"
else:
string_types = (basestring,)
binary_type = str
range_func = xrange
if PY26:
memoryview_type = buffer
struct_bool_decl = "<b"
else:
memoryview_type = memoryview
struct_bool_decl = "?"
# NOTE: Future Jython support may require code here (look at `six`).

View File

@@ -0,0 +1,29 @@
# Copyright 2014 Google Inc. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import ctypes
from . import number_types as N
from . import packer
from .compat import memoryview_type
def Get(packer_type, buf, head):
""" Get decodes a value at buf[head:] using `packer_type`. """
return packer_type.unpack_from(memoryview_type(buf), head)[0]
def Write(packer_type, buf, head, n):
""" Write encodes `n` at buf[head:] using `packer_type`. """
packer_type.pack_into(buf, head, n)

View File

@@ -0,0 +1,174 @@
# Copyright 2014 Google Inc. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import ctypes
import collections
import struct
from ctypes import sizeof
from . import packer
# For reference, see:
# https://docs.python.org/2/library/ctypes.html#ctypes-fundamental-data-types-2
# These classes could be collections.namedtuple instances, but those are new
# in 2.6 and we want to work towards 2.5 compatability.
class BoolFlags(object):
bytewidth = 1
min_val = False
max_val = True
py_type = bool
name = "bool"
packer_type = packer.boolean
class Uint8Flags(object):
bytewidth = 1
min_val = 0
max_val = (2**8) - 1
py_type = int
name = "uint8"
packer_type = packer.uint8
class Uint16Flags(object):
bytewidth = 2
min_val = 0
max_val = (2**16) - 1
py_type = int
name = "uint16"
packer_type = packer.uint16
class Uint32Flags(object):
bytewidth = 4
min_val = 0
max_val = (2**32) - 1
py_type = int
name = "uint32"
packer_type = packer.uint32
class Uint64Flags(object):
bytewidth = 8
min_val = 0
max_val = (2**64) - 1
py_type = int
name = "uint64"
packer_type = packer.uint64
class Int8Flags(object):
bytewidth = 1
min_val = -(2**7)
max_val = (2**7) - 1
py_type = int
name = "int8"
packer_type = packer.int8
class Int16Flags(object):
bytewidth = 2
min_val = -(2**15)
max_val = (2**15) - 1
py_type = int
name = "int16"
packer_type = packer.int16
class Int32Flags(object):
bytewidth = 4
min_val = -(2**31)
max_val = (2**31) - 1
py_type = int
name = "int32"
packer_type = packer.int32
class Int64Flags(object):
bytewidth = 8
min_val = -(2**63)
max_val = (2**63) - 1
py_type = int
name = "int64"
packer_type = packer.int64
class Float32Flags(object):
bytewidth = 4
min_val = None
max_val = None
py_type = float
name = "float32"
packer_type = packer.float32
class Float64Flags(object):
bytewidth = 8
min_val = None
max_val = None
py_type = float
name = "float64"
packer_type = packer.float64
class SOffsetTFlags(Int32Flags):
pass
class UOffsetTFlags(Uint32Flags):
pass
class VOffsetTFlags(Uint16Flags):
pass
def valid_number(n, flags):
if flags.min_val is None and flags.max_val is None:
return True
return flags.min_val <= n <= flags.max_val
def enforce_number(n, flags):
if flags.min_val is None and flags.max_val is None:
return
if not flags.min_val <= n <= flags.max_val:
raise TypeError("bad number %s for type %s" % (str(n), flags.name))
def float32_to_uint32(n):
packed = struct.pack("<1f", n)
(converted,) = struct.unpack("<1L", packed)
return converted
def uint32_to_float32(n):
packed = struct.pack("<1L", n)
(unpacked,) = struct.unpack("<1f", packed)
return unpacked
def float64_to_uint64(n):
packed = struct.pack("<1d", n)
(converted,) = struct.unpack("<1Q", packed)
return converted
def uint64_to_float64(n):
packed = struct.pack("<1Q", n)
(unpacked,) = struct.unpack("<1d", packed)
return unpacked

View File

@@ -0,0 +1,28 @@
"""
Provide pre-compiled struct packers for encoding and decoding.
See: https://docs.python.org/2/library/struct.html#format-characters
"""
import struct
from . import compat
boolean = struct.Struct(compat.struct_bool_decl)
uint8 = struct.Struct("<B")
uint16 = struct.Struct("<H")
uint32 = struct.Struct("<I")
uint64 = struct.Struct("<Q")
int8 = struct.Struct("<b")
int16 = struct.Struct("<h")
int32 = struct.Struct("<i")
int64 = struct.Struct("<q")
float32 = struct.Struct("<f")
float64 = struct.Struct("<d")
uoffset = uint32
soffset = int32
voffset = uint16

117
python/flatbuffers/table.py Normal file
View File

@@ -0,0 +1,117 @@
# Copyright 2014 Google Inc. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from . import encode
from . import number_types as N
class Table(object):
"""Table wraps a byte slice and provides read access to its data.
The variable `Pos` indicates the root of the FlatBuffers object therein."""
__slots__ = ("Bytes", "Pos")
def __init__(self, buf, pos):
N.enforce_number(pos, N.UOffsetTFlags)
self.Bytes = buf
self.Pos = pos
def Offset(self, vtableOffset):
"""Offset provides access into the Table's vtable.
Deprecated fields are ignored by checking the vtable's length."""
vtable = self.Pos - self.Get(N.SOffsetTFlags, self.Pos)
vtableEnd = self.Get(N.VOffsetTFlags, vtable)
if vtableOffset < vtableEnd:
return self.Get(N.VOffsetTFlags, vtable + vtableOffset)
return 0
def Indirect(self, off):
"""Indirect retrieves the relative offset stored at `offset`."""
N.enforce_number(off, N.UOffsetTFlags)
return off + encode.Get(N.UOffsetTFlags.packer_type, self.Bytes, off)
def String(self, off):
"""String gets a string from data stored inside the flatbuffer."""
N.enforce_number(off, N.UOffsetTFlags)
off += encode.Get(N.UOffsetTFlags.packer_type, self.Bytes, off)
start = off + N.UOffsetTFlags.bytewidth
length = encode.Get(N.UOffsetTFlags.packer_type, self.Bytes, off)
return bytes(self.Bytes[start:start+length])
def VectorLen(self, off):
"""VectorLen retrieves the length of the vector whose offset is stored
at "off" in this object."""
N.enforce_number(off, N.UOffsetTFlags)
off += self.Pos
off += encode.Get(N.UOffsetTFlags.packer_type, self.Bytes, off)
ret = encode.Get(N.UOffsetTFlags.packer_type, self.Bytes, off)
return ret
def Vector(self, off):
"""Vector retrieves the start of data of the vector whose offset is
stored at "off" in this object."""
N.enforce_number(off, N.UOffsetTFlags)
off += self.Pos
x = off + self.Get(N.UOffsetTFlags, off)
# data starts after metadata containing the vector length
x += N.UOffsetTFlags.bytewidth
return x
def Union(self, t2, off):
"""Union initializes any Table-derived type to point to the union at
the given offset."""
assert type(t2) is Table
N.enforce_number(off, N.UOffsetTFlags)
off += self.Pos
t2.Pos = off + self.Get(N.UOffsetTFlags, off)
t2.Bytes = self.Bytes
def Get(self, flags, off):
"""
Get retrieves a value of the type specified by `flags` at the
given offset.
"""
N.enforce_number(off, N.UOffsetTFlags)
return flags.py_type(encode.Get(flags.packer_type, self.Bytes, off))
def GetSlot(self, slot, d, validator_flags):
N.enforce_number(slot, N.VOffsetTFlags)
if validator_flags is not None:
N.enforce_number(d, validator_flags)
off = self.Offset(slot)
if off == 0:
return d
return self.Get(validator_flags, self.Pos + off)
def GetVOffsetTSlot(self, slot, d):
"""
GetVOffsetTSlot retrieves the VOffsetT that the given vtable location
points to. If the vtable value is zero, the default value `d`
will be returned.
"""
N.enforce_number(slot, N.VOffsetTFlags)
N.enforce_number(d, N.VOffsetTFlags)
off = self.Offset(slot)
if off == 0:
return d
return off

16
python/setup.py Normal file
View File

@@ -0,0 +1,16 @@
from setuptools import setup
setup(
name='flatbuffers',
version='2015.05.14.0',
license='Apache 2.0',
author='FlatBuffers Contributors',
author_email='me@rwinslow.com',
url='https://github.com/google/flatbuffers',
long_description=('Python runtime library for use with the Flatbuffers'
'serialization format.'),
packages=['flatbuffers'],
include_package_data=True,
requires=[],
description='The FlatBuffers serialization format for Python',
)

View File

@@ -1,7 +1,13 @@
FlatBuffers Version 1.0
FlatBuffers Version 1.1.0
# Welcome to FlatBuffers!
## Build Status
- Travis: [![Build Status](https://travis-ci.org/google/flatbuffers.svg?branch=master)](https://travis-ci.org/google/flatbuffers)
----
FlatBuffers is a serialization library for games and other memory constrained
apps. Go to our [landing page][] to browse our documentation.

View File

@@ -0,0 +1 @@
../flatc -c --no-prefix -o ../include/flatbuffers reflection.fbs

81
reflection/reflection.fbs Normal file
View File

@@ -0,0 +1,81 @@
// This schema defines objects that represent a parsed schema, like
// the binary version of a .fbs file.
// This could be used to operate on unknown FlatBuffers at runtime.
// It can even ... represent itself (!)
namespace reflection;
// These must correspond to the enum in idl.h.
enum BaseType : byte {
None,
UType,
Bool,
Byte,
UByte,
Short,
UShort,
Int,
UInt,
Long,
ULong,
Float,
Double,
String,
Vector,
Obj, // Used for tables & structs.
Union
}
table Type {
base_type:BaseType;
element:BaseType = None; // Only if base_type == Vector.
index:int = -1; // If base_type == Object, index into "objects" below.
// If base_type == Union, UnionType, or integral derived
// from an enum, index into "enums" below.
}
table EnumVal {
name:string (required);
value:long (key);
object:Object; // Only if part of a union.
}
table Enum {
name:string (required, key);
values:[EnumVal] (required); // In order of their values.
is_union:bool = false;
underlying_type:Type (required);
}
table Field {
name:string (required, key);
type:Type (required);
id:ushort;
offset:ushort; // Offset into the vtable for tables, or into the struct.
default_integer:long = 0;
default_real:double = 0.0;
deprecated:bool = false;
required:bool = false;
key:bool = false;
}
table Object { // Used for both tables and structs.
name:string (required, key);
fields:[Field] (required); // Sorted.
is_struct:bool = false;
minalign:int;
bytesize:int; // For structs.
}
table Schema {
objects:[Object] (required); // Sorted.
enums:[Enum] (required); // Sorted.
file_ident:string;
file_ext:string;
root_table:Object;
}
root_type Schema;
file_identifier "BFBS";
file_extension "bfbs";

21
samples/monster_generated.h Executable file → Normal file
View File

@@ -23,7 +23,7 @@ inline const char **EnumNamesColor() {
return names;
}
inline const char *EnumNameColor(Color e) { return EnumNamesColor()[e]; }
inline const char *EnumNameColor(Color e) { return EnumNamesColor()[static_cast<int>(e)]; }
enum Any {
Any_NONE = 0,
@@ -35,7 +35,7 @@ inline const char **EnumNamesAny() {
return names;
}
inline const char *EnumNameAny(Any e) { return EnumNamesAny()[e]; }
inline const char *EnumNameAny(Any e) { return EnumNamesAny()[static_cast<int>(e)]; }
inline bool VerifyAny(flatbuffers::Verifier &verifier, const void *union_obj, Any type);
@@ -50,18 +50,27 @@ MANUALLY_ALIGNED_STRUCT(4) Vec3 FLATBUFFERS_FINAL_CLASS {
: x_(flatbuffers::EndianScalar(x)), y_(flatbuffers::EndianScalar(y)), z_(flatbuffers::EndianScalar(z)) { }
float x() const { return flatbuffers::EndianScalar(x_); }
void mutate_x(float x) { flatbuffers::WriteScalar(&x_, x); }
float y() const { return flatbuffers::EndianScalar(y_); }
void mutate_y(float y) { flatbuffers::WriteScalar(&y_, y); }
float z() const { return flatbuffers::EndianScalar(z_); }
void mutate_z(float z) { flatbuffers::WriteScalar(&z_, z); }
};
STRUCT_END(Vec3, 12);
struct Monster FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
const Vec3 *pos() const { return GetStruct<const Vec3 *>(4); }
Vec3 *mutable_pos() { return GetStruct<Vec3 *>(4); }
int16_t mana() const { return GetField<int16_t>(6, 150); }
bool mutate_mana(int16_t mana) { return SetField(6, mana); }
int16_t hp() const { return GetField<int16_t>(8, 100); }
bool mutate_hp(int16_t hp) { return SetField(8, hp); }
const flatbuffers::String *name() const { return GetPointer<const flatbuffers::String *>(10); }
flatbuffers::String *mutable_name() { return GetPointer<flatbuffers::String *>(10); }
const flatbuffers::Vector<uint8_t> *inventory() const { return GetPointer<const flatbuffers::Vector<uint8_t> *>(14); }
flatbuffers::Vector<uint8_t> *mutable_inventory() { return GetPointer<flatbuffers::Vector<uint8_t> *>(14); }
Color color() const { return static_cast<Color>(GetField<int8_t>(16, 2)); }
bool mutate_color(Color color) { return SetField(16, static_cast<int8_t>(color)); }
bool Verify(flatbuffers::Verifier &verifier) const {
return VerifyTableStart(verifier) &&
VerifyField<Vec3>(verifier, 4 /* pos */) &&
@@ -118,11 +127,13 @@ inline bool VerifyAny(flatbuffers::Verifier &verifier, const void *union_obj, An
}
}
inline const Monster *GetMonster(const void *buf) { return flatbuffers::GetRoot<Monster>(buf); }
inline const MyGame::Sample::Monster *GetMonster(const void *buf) { return flatbuffers::GetRoot<MyGame::Sample::Monster>(buf); }
inline bool VerifyMonsterBuffer(flatbuffers::Verifier &verifier) { return verifier.VerifyBuffer<Monster>(); }
inline Monster *GetMutableMonster(void *buf) { return flatbuffers::GetMutableRoot<Monster>(buf); }
inline void FinishMonsterBuffer(flatbuffers::FlatBufferBuilder &fbb, flatbuffers::Offset<Monster> root) { fbb.Finish(root); }
inline bool VerifyMonsterBuffer(flatbuffers::Verifier &verifier) { return verifier.VerifyBuffer<MyGame::Sample::Monster>(); }
inline void FinishMonsterBuffer(flatbuffers::FlatBufferBuilder &fbb, flatbuffers::Offset<MyGame::Sample::Monster> root) { fbb.Finish(root); }
} // namespace Sample
} // namespace MyGame

2
samples/sample_binary.cpp Executable file → Normal file
View File

@@ -49,7 +49,7 @@ int main(int /*argc*/, const char * /*argv*/[]) {
assert(monster->hp() == 80);
assert(monster->mana() == 150); // default
assert(!strcmp(monster->name()->c_str(), "MyMonster"));
assert(monster->name()->str() == "MyMonster");
auto pos = monster->pos();
assert(pos);

0
samples/sample_text.cpp Executable file → Normal file
View File

126
src/flatc.cpp Executable file → Normal file
View File

@@ -18,8 +18,8 @@
#include "flatbuffers/idl.h"
#include "flatbuffers/util.h"
static void Error(const char *err, const char *obj = nullptr,
bool usage = false, bool show_exe_name = true);
static void Error(const std::string &err, bool usage = false,
bool show_exe_name = true);
// This struct allows us to create a table of all possible output generators
// for the various programming languages and formats we support.
@@ -60,20 +60,25 @@ const Generator generators[] = {
flatbuffers::GeneratorOptions::kJava,
"Generate Java classes for tables/structs",
flatbuffers::GeneralMakeRule },
{ flatbuffers::GenerateJS, "-s", "JavaScript",
flatbuffers::GeneratorOptions::kMAX,
"Generate JavaScript code for tables/structs",
flatbuffers::JSMakeRule },
{ flatbuffers::GenerateGeneral, "-n", "C#",
flatbuffers::GeneratorOptions::kCSharp,
"Generate C# classes for tables/structs",
flatbuffers::GeneralMakeRule },
{ flatbuffers::GeneratePython, "-p", "Python",
flatbuffers::GeneratorOptions::kMAX,
"Generate Python files for tables/structs",
flatbuffers::GeneralMakeRule },
};
const char *program_name = NULL;
static void Error(const char *err, const char *obj, bool usage,
bool show_exe_name) {
static void Error(const std::string &err, bool usage, bool show_exe_name) {
if (show_exe_name) printf("%s: ", program_name);
printf("%s", err);
if (obj) printf(": %s", obj);
printf("\n");
printf("%s\n", err.c_str());
if (usage) {
printf("usage: %s [OPTION]... FILE... [-- FILE...]\n", program_name);
for (size_t i = 0; i < sizeof(generators) / sizeof(generators[0]); ++i)
@@ -86,10 +91,22 @@ static void Error(const char *err, const char *obj, bool usage,
" -M Print make rules for generated files.\n"
" --strict-json Strict JSON: field names must be / will be quoted,\n"
" no trailing commas in tables/vectors.\n"
" --defaults-json Output fields whose value is the default when\n"
" writing JSON\n"
" --no-prefix Don\'t prefix enum values with the enum type in C++.\n"
" --gen-includes Generate include statements for included schemas the\n"
" generated file depends on (C++).\n"
" --scoped-enums Use C++11 style scoped and strongly typed enums.\n"
" also implies --no-prefix.\n"
" --gen-includes (deprecated), this is the default behavior.\n"
" If the original behavior is required (no include\n"
" statements) use --no-includes.\n"
" --no-includes Don\'t generate include statements for included\n"
" schemas the generated file depends on (C++).\n"
" --gen-mutable Generate accessors that can mutate buffers in-place.\n"
" --gen-onefile Generate single output file for C#\n"
" --raw-binary Allow binaries without file_indentifier to be read.\n"
" This may crash flatc given a mismatched schema.\n"
" --proto Input is a .proto, translate to .fbs.\n"
" --schema Serialize schemas instead of JSON (use with -b)\n"
"FILEs may depend on declarations in earlier files.\n"
"FILEs after the -- must be binary flatbuffer format files.\n"
"Output files are named using the base file name of the input,\n"
@@ -109,43 +126,62 @@ int main(int argc, const char *argv[]) {
bool any_generator = false;
bool print_make_rules = false;
bool proto_mode = false;
bool raw_binary = false;
bool schema_binary = false;
std::vector<std::string> filenames;
std::vector<const char *> include_directories;
size_t binary_files_from = std::numeric_limits<size_t>::max();
for (int argi = 1; argi < argc; argi++) {
const char *arg = argv[argi];
std::string arg = argv[argi];
if (arg[0] == '-') {
if (filenames.size() && arg[1] != '-')
Error("invalid option location", arg, true);
std::string opt = arg;
if (opt == "-o") {
if (++argi >= argc) Error("missing path following", arg, true);
Error("invalid option location: " + arg, true);
if (arg == "-o") {
if (++argi >= argc) Error("missing path following: " + arg, true);
output_path = flatbuffers::ConCatPathFileName(argv[argi], "");
} else if(opt == "-I") {
if (++argi >= argc) Error("missing path following", arg, true);
} else if(arg == "-I") {
if (++argi >= argc) Error("missing path following" + arg, true);
include_directories.push_back(argv[argi]);
} else if(opt == "--strict-json") {
} else if(arg == "--strict-json") {
opts.strict_json = true;
} else if(opt == "--no-prefix") {
} else if(arg == "--no-js-exports") {
opts.skip_js_exports = true;
} else if(arg == "--defaults-json") {
opts.output_default_scalars_in_json = true;
} else if(arg == "--no-prefix") {
opts.prefixed_enums = false;
} else if(opt == "--gen-includes") {
opts.include_dependence_headers = true;
} else if(opt == "--") { // Separator between text and binary inputs.
} else if(arg == "--scoped-enums") {
opts.prefixed_enums = false;
opts.scoped_enums = true;
} else if(arg == "--gen-mutable") {
opts.mutable_buffer = true;
} else if(arg == "--gen-includes") {
// Deprecated, remove this option some time in the future.
printf("warning: --gen-includes is deprecated (it is now default)\n");
} else if(arg == "--no-includes") {
opts.include_dependence_headers = false;
} else if (arg == "--gen-onefile") {
opts.one_file = true;
} else if (arg == "--raw-binary") {
raw_binary = true;
} else if(arg == "--") { // Separator between text and binary inputs.
binary_files_from = filenames.size();
} else if(opt == "--proto") {
} else if(arg == "--proto") {
proto_mode = true;
any_generator = true;
} else if(opt == "-M") {
} else if(arg == "--schema") {
schema_binary = true;
} else if(arg == "-M") {
print_make_rules = true;
} else {
for (size_t i = 0; i < num_generators; ++i) {
if (opt == generators[i].generator_opt) {
if (arg == generators[i].generator_opt) {
generator_enabled[i] = true;
any_generator = true;
goto found;
}
}
Error("unknown commandline argument", arg, true);
Error("unknown commandline argument" + arg, true);
found:;
}
} else {
@@ -153,10 +189,10 @@ int main(int argc, const char *argv[]) {
}
}
if (!filenames.size()) Error("missing input files", nullptr, true);
if (!filenames.size()) Error("missing input files", false, true);
if (!any_generator)
Error("no options", "specify one of -c -g -j -t -b etc.", true);
Error("no options: specify one of -c -g -j -t -b etc.", true);
// Now process the files:
flatbuffers::Parser parser(opts.strict_json, proto_mode);
@@ -165,7 +201,7 @@ int main(int argc, const char *argv[]) {
++file_it) {
std::string contents;
if (!flatbuffers::LoadFile(file_it->c_str(), true, &contents))
Error("unable to load file", file_it->c_str());
Error("unable to load file" + *file_it);
bool is_binary = static_cast<size_t>(file_it - filenames.begin()) >=
binary_files_from;
@@ -174,13 +210,37 @@ int main(int argc, const char *argv[]) {
parser.builder_.PushBytes(
reinterpret_cast<const uint8_t *>(contents.c_str()),
contents.length());
if (!raw_binary) {
// Generally reading binaries that do not correspond to the schema
// will crash, and sadly there's no way around that when the binary
// does not contain a file identifier.
// We'd expect that typically any binary used as a file would have
// such an identifier, so by default we require them to match.
if (!parser.file_identifier_.length()) {
Error("current schema has no file_identifier: cannot test if \"" +
*file_it +
"\" matches the schema, use --raw-binary to read this file"
" anyway.");
} else if (!flatbuffers::BufferHasIdentifier(contents.c_str(),
parser.file_identifier_.c_str())) {
Error("binary \"" +
*file_it +
"\" does not have expected file_identifier \"" +
parser.file_identifier_ +
"\", use --raw-binary to read this file anyway.");
}
}
} else {
auto local_include_directory = flatbuffers::StripFileName(*file_it);
include_directories.push_back(local_include_directory.c_str());
include_directories.push_back(nullptr);
if (!parser.Parse(contents.c_str(), &include_directories[0],
file_it->c_str()))
Error(parser.error_.c_str(), nullptr, false, false);
Error(parser.error_, false, false);
if (schema_binary) {
parser.Serialize();
parser.file_extension_ = reflection::SchemaExtension();
}
include_directories.pop_back();
include_directories.pop_back();
}
@@ -194,10 +254,10 @@ int main(int argc, const char *argv[]) {
if (!print_make_rules) {
flatbuffers::EnsureDirExists(output_path);
if (!generators[i].generate(parser, output_path, filebase, opts)) {
Error((std::string("Unable to generate ") +
generators[i].lang_name +
" for " +
filebase).c_str());
Error(std::string("Unable to generate ") +
generators[i].lang_name +
" for " +
filebase);
}
} else {
std::string make_rule = generators[i].make_rule(

View File

@@ -18,11 +18,12 @@
#include <sstream>
#include <string>
#include "flatbuffers/hash.h"
#include <stdio.h>
enum OutputFormat {
kDecimal,
kHexadecimal,
kHexadecimal0x,
kHexadecimal0x
};
int main(int argc, char* argv[]) {

View File

@@ -44,12 +44,25 @@ static std::string WrapInNameSpace(const Parser &parser,
return WrapInNameSpace(parser, def.defined_namespace, def.name);
}
// Translates a qualified name in flatbuffer text format to the same name in
// the equivalent C++ namepsace.
static std::string TranslateNameSpace(const std::string &qualified_name) {
std::string cpp_qualified_name = qualified_name;
size_t start_pos = 0;
while((start_pos = cpp_qualified_name.find(".", start_pos)) !=
std::string::npos) {
cpp_qualified_name.replace(start_pos, 1, "::");
}
return cpp_qualified_name;
}
// Return a C++ type from the table in idl.h
static std::string GenTypeBasic(const Parser &parser, const Type &type,
bool real_enum) {
static const char *ctypename[] = {
#define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE) #CTYPE,
#define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \
#CTYPE,
FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
#undef FLATBUFFERS_TD
};
@@ -111,12 +124,28 @@ static std::string GenTypeGet(const Parser &parser, const Type &type,
: beforeptr + GenTypePointer(parser, type) + afterptr;
}
static std::string GenEnumDecl(const EnumDef &enum_def,
const GeneratorOptions &opts) {
return (opts.scoped_enums ? "enum class " : "enum ") + enum_def.name;
}
static std::string GenEnumVal(const EnumDef &enum_def, const EnumVal &enum_val,
const GeneratorOptions &opts) {
return opts.prefixed_enums ? enum_def.name + "_" + enum_val.name
: enum_val.name;
}
static std::string GetEnumVal(const EnumDef &enum_def, const EnumVal &enum_val,
const GeneratorOptions &opts) {
if (opts.scoped_enums) {
return enum_def.name + "::" + enum_val.name;
} else if (opts.prefixed_enums) {
return enum_def.name + "_" + enum_val.name;
} else {
return enum_val.name;
}
}
// Generate an enum declaration and an enum string lookup table.
static void GenEnum(const Parser &parser, EnumDef &enum_def,
std::string *code_ptr, std::string *code_ptr_post,
@@ -124,13 +153,13 @@ static void GenEnum(const Parser &parser, EnumDef &enum_def,
if (enum_def.generated) return;
std::string &code = *code_ptr;
std::string &code_post = *code_ptr_post;
GenComment(enum_def.doc_comment, code_ptr);
code += "enum " + enum_def.name + " {\n";
GenComment(enum_def.doc_comment, code_ptr, nullptr);
code += GenEnumDecl(enum_def, opts) + " {\n";
for (auto it = enum_def.vals.vec.begin();
it != enum_def.vals.vec.end();
++it) {
auto &ev = **it;
GenComment(ev.doc_comment, code_ptr, " ");
GenComment(ev.doc_comment, code_ptr, nullptr, " ");
code += " " + GenEnumVal(enum_def, ev, opts) + " = ";
code += NumToString(ev.value);
code += (it + 1) != enum_def.vals.vec.end() ? ",\n" : "\n";
@@ -158,9 +187,9 @@ static void GenEnum(const Parser &parser, EnumDef &enum_def,
}
code += "nullptr };\n return names;\n}\n\n";
code += "inline const char *EnumName" + enum_def.name;
code += "(" + enum_def.name + " e) { return EnumNames" + enum_def.name + "()[e";
code += "(" + enum_def.name + " e) { return EnumNames" + enum_def.name + "()[static_cast<int>(e)";
if (enum_def.vals.vec.front()->value)
code += " - " + GenEnumVal(enum_def, *enum_def.vals.vec.front(), opts);
code += " - static_cast<int>(" + GetEnumVal(enum_def, *enum_def.vals.vec.front(), opts) +")";
code += "]; }\n\n";
}
@@ -179,7 +208,7 @@ static void GenEnum(const Parser &parser, EnumDef &enum_def,
it != enum_def.vals.vec.end();
++it) {
auto &ev = **it;
code_post += " case " + GenEnumVal(enum_def, ev, opts);
code_post += " case " + GetEnumVal(enum_def, ev, opts);
if (!ev.value) {
code_post += ": return true;\n"; // "NONE" enum value.
} else {
@@ -212,7 +241,7 @@ static void GenTable(const Parser &parser, StructDef &struct_def,
// Generate an accessor struct, with methods of the form:
// type name() const { return GetField<type>(offset, defaultval); }
GenComment(struct_def.doc_comment, code_ptr);
GenComment(struct_def.doc_comment, code_ptr, nullptr);
code += "struct " + struct_def.name;
code += " FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table";
code += " {\n";
@@ -221,29 +250,53 @@ static void GenTable(const Parser &parser, StructDef &struct_def,
++it) {
auto &field = **it;
if (!field.deprecated) { // Deprecated fields won't be accessible.
GenComment(field.doc_comment, code_ptr, " ");
auto is_scalar = IsScalar(field.value.type.base_type);
GenComment(field.doc_comment, code_ptr, nullptr, " ");
code += " " + GenTypeGet(parser, field.value.type, " ", "const ", " *",
true);
code += field.name + "() const { return ";
// Call a different accessor for pointers, that indirects.
std::string call = IsScalar(field.value.type.base_type)
auto accessor = is_scalar
? "GetField<"
: (IsStruct(field.value.type) ? "GetStruct<" : "GetPointer<");
call += GenTypeGet(parser, field.value.type, "", "const ", " *", false);
call += ">(" + NumToString(field.value.offset);
auto offsetstr = NumToString(field.value.offset);
auto call =
accessor +
GenTypeGet(parser, field.value.type, "", "const ", " *", false) +
">(" + offsetstr;
// Default value as second arg for non-pointer types.
if (IsScalar(field.value.type.base_type))
call += ", " + field.value.constant;
call += ")";
code += GenUnderlyingCast(parser, field, true, call);
code += "; }\n";
if (opts.mutable_buffer) {
if (is_scalar) {
code += " bool mutate_" + field.name + "(";
code += GenTypeBasic(parser, field.value.type, true);
code += " " + field.name + ") { return SetField(" + offsetstr + ", ";
code += GenUnderlyingCast(parser, field, false, field.name);
code += "); }\n";
} else {
auto type = GenTypeGet(parser, field.value.type, " ", "", " *", true);
code += " " + type + "mutable_" + field.name + "() { return ";
code += GenUnderlyingCast(parser, field, true,
accessor + type + ">(" + offsetstr + ")");
code += "; }\n";
}
}
auto nested = field.attributes.Lookup("nested_flatbuffer");
if (nested) {
auto nested_root = parser.structs_.Lookup(nested->constant);
std::string qualified_name =
parser.namespaces_.back()->GetFullyQualifiedName(nested->constant);
auto nested_root = parser.structs_.Lookup(qualified_name);
assert(nested_root); // Guaranteed to exist by parser.
code += " const " + nested_root->name + " *" + field.name;
(void)nested_root;
std::string cpp_qualified_name = TranslateNameSpace(qualified_name);
code += " const " + cpp_qualified_name + " *" + field.name;
code += "_nested_root() const { return flatbuffers::GetRoot<";
code += nested_root->name + ">(" + field.name + "()->Data()); }\n";
code += cpp_qualified_name + ">(" + field.name + "()->Data()); }\n";
}
// Generate a comparison function for this field if it is a key.
if (field.key) {
@@ -388,7 +441,7 @@ static void GenTable(const Parser &parser, StructDef &struct_def,
if (ev) {
code += WrapInNameSpace(parser,
field.value.type.enum_def->defined_namespace,
GenEnumVal(*field.value.type.enum_def, *ev,
GetEnumVal(*field.value.type.enum_def, *ev,
opts));
} else {
code += GenUnderlyingCast(parser, field, true, field.value.constant);
@@ -416,7 +469,8 @@ static void GenTable(const Parser &parser, StructDef &struct_def,
code += " return builder_.Finish();\n}\n\n";
}
static void GenPadding(const FieldDef &field, const std::function<void (int bits)> &f) {
static void GenPadding(const FieldDef &field,
const std::function<void (int bits)> &f) {
if (field.padding) {
for (int i = 0; i < 4; i++)
if (static_cast<int>(field.padding) & (1 << i))
@@ -427,7 +481,7 @@ static void GenPadding(const FieldDef &field, const std::function<void (int bits
// Generate an accessor struct with constructor for a flatbuffers struct.
static void GenStruct(const Parser &parser, StructDef &struct_def,
std::string *code_ptr) {
const GeneratorOptions &opts, std::string *code_ptr) {
if (struct_def.generated) return;
std::string &code = *code_ptr;
@@ -436,7 +490,7 @@ static void GenStruct(const Parser &parser, StructDef &struct_def,
// Generates manual padding and alignment.
// Variables are private because they contain little endian data on all
// platforms.
GenComment(struct_def.doc_comment, code_ptr);
GenComment(struct_def.doc_comment, code_ptr, nullptr);
code += "MANUALLY_ALIGNED_STRUCT(" + NumToString(struct_def.minalign) + ") ";
code += struct_def.name + " FLATBUFFERS_FINAL_CLASS {\n private:\n";
int padding_id = 0;
@@ -501,15 +555,31 @@ static void GenStruct(const Parser &parser, StructDef &struct_def,
it != struct_def.fields.vec.end();
++it) {
auto &field = **it;
GenComment(field.doc_comment, code_ptr, " ");
GenComment(field.doc_comment, code_ptr, nullptr, " ");
auto is_scalar = IsScalar(field.value.type.base_type);
code += " " + GenTypeGet(parser, field.value.type, " ", "const ", " &",
true);
code += field.name + "() const { return ";
code += GenUnderlyingCast(parser, field, true,
IsScalar(field.value.type.base_type)
is_scalar
? "flatbuffers::EndianScalar(" + field.name + "_)"
: field.name + "_");
code += "; }\n";
if (opts.mutable_buffer) {
if (is_scalar) {
code += " void mutate_" + field.name + "(";
code += GenTypeBasic(parser, field.value.type, true);
code += " " + field.name + ") { flatbuffers::WriteScalar(&";
code += field.name + "_, ";
code += GenUnderlyingCast(parser, field, false, field.name);
code += "); }\n";
} else {
code += " ";
code += GenTypeGet(parser, field.value.type, "", "", " &", true);
code += "mutable_" + field.name + "() { return " + field.name;
code += "_; }\n";
}
}
}
code += "};\nSTRUCT_END(" + struct_def.name + ", ";
code += NumToString(struct_def.bytesize) + ");\n\n";
@@ -581,7 +651,7 @@ std::string GenerateCPP(const Parser &parser,
std::string decl_code;
for (auto it = parser.structs_.vec.begin();
it != parser.structs_.vec.end(); ++it) {
if ((**it).fixed) GenStruct(parser, **it, &decl_code);
if ((**it).fixed) GenStruct(parser, **it, opts, &decl_code);
}
for (auto it = parser.structs_.vec.begin();
it != parser.structs_.vec.end(); ++it) {
@@ -647,20 +717,30 @@ std::string GenerateCPP(const Parser &parser,
code += enum_code_post;
// Generate convenient global helper functions:
if (parser.root_struct_def) {
auto &name = parser.root_struct_def->name;
if (parser.root_struct_def_) {
auto &name = parser.root_struct_def_->name;
std::string qualified_name =
parser.namespaces_.back()->GetFullyQualifiedName(name);
std::string cpp_qualified_name = TranslateNameSpace(qualified_name);
// The root datatype accessor:
code += "inline const " + name + " *Get";
code += "inline const " + cpp_qualified_name + " *Get";
code += name;
code += "(const void *buf) { return flatbuffers::GetRoot<";
code += name + ">(buf); }\n\n";
code += cpp_qualified_name + ">(buf); }\n\n";
if (opts.mutable_buffer) {
code += "inline " + name + " *GetMutable";
code += name;
code += "(void *buf) { return flatbuffers::GetMutableRoot<";
code += name + ">(buf); }\n\n";
}
// The root verifier:
code += "inline bool Verify";
code += name;
code += "Buffer(flatbuffers::Verifier &verifier) { "
"return verifier.VerifyBuffer<";
code += name + ">(); }\n\n";
code += cpp_qualified_name + ">(); }\n\n";
if (parser.file_identifier_.length()) {
// Return the identifier
@@ -675,10 +755,17 @@ std::string GenerateCPP(const Parser &parser,
code += name + "Identifier()); }\n\n";
}
if (parser.file_extension_.length()) {
// Return the extension
code += "inline const char *" + name;
code += "Extension() { return \"" + parser.file_extension_;
code += "\"; }\n\n";
}
// Finish a buffer with a given root object:
code += "inline void Finish" + name;
code += "Buffer(flatbuffers::FlatBufferBuilder &fbb, flatbuffers::Offset<";
code += name + "> root) { fbb.Finish(root";
code += cpp_qualified_name + "> root) { fbb.Finish(root";
if (parser.file_identifier_.length())
code += ", " + name + "Identifier()";
code += "); }\n\n";

View File

@@ -24,19 +24,49 @@ namespace flatbuffers {
static std::string GenType(const Type &type) {
switch (type.base_type) {
case BASE_TYPE_STRUCT: return type.struct_def->name;
case BASE_TYPE_UNION: return type.enum_def->name;
case BASE_TYPE_VECTOR: return "[" + GenType(type.VectorType()) + "]";
default: return kTypeNames[type.base_type];
case BASE_TYPE_STRUCT:
return type.struct_def->defined_namespace->GetFullyQualifiedName(
type.struct_def->name);
case BASE_TYPE_UNION:
return type.enum_def->defined_namespace->GetFullyQualifiedName(
type.enum_def->name);
case BASE_TYPE_VECTOR:
return "[" + GenType(type.VectorType()) + "]";
default:
return kTypeNames[type.base_type];
}
}
static void GenNameSpace(const Namespace &name_space, std::string *_schema,
const Namespace **last_namespace) {
if (*last_namespace == &name_space) return;
*last_namespace = &name_space;
auto &schema = *_schema;
schema += "namespace ";
for (auto it = name_space.components.begin();
it != name_space.components.end(); ++it) {
if (it != name_space.components.begin()) schema += ".";
schema += *it;
}
schema += ";\n\n";
}
// Generate a flatbuffer schema from the Parser's internal representation.
std::string GenerateFBS(const Parser &parser, const std::string &file_name,
const GeneratorOptions &opts) {
// Proto namespaces may clash with table names, so we have to prefix all:
for (auto it = parser.namespaces_.begin(); it != parser.namespaces_.end();
++it) {
for (auto comp = (*it)->components.begin(); comp != (*it)->components.end();
++comp) {
(*comp) = "_" + (*comp);
}
}
std::string schema;
schema += "// Generated from " + file_name + ".proto\n\n";
if (opts.include_dependence_headers) {
#ifdef FBS_GEN_INCLUDES // TODO: currently all in one file.
int num_includes = 0;
for (auto it = parser.included_files_.begin();
it != parser.included_files_.end(); ++it) {
@@ -48,24 +78,21 @@ std::string GenerateFBS(const Parser &parser, const std::string &file_name,
}
}
if (num_includes) schema += "\n";
#endif
}
schema += "namespace ";
auto name_space = parser.namespaces_.back();
for (auto it = name_space->components.begin();
it != name_space->components.end(); ++it) {
if (it != name_space->components.begin()) schema += ".";
schema += *it;
}
schema += ";\n\n";
// Generate code for all the enum declarations.
const Namespace *last_namespace = nullptr;
for (auto enum_def_it = parser.enums_.vec.begin();
enum_def_it != parser.enums_.vec.end(); ++enum_def_it) {
EnumDef &enum_def = **enum_def_it;
GenNameSpace(*enum_def.defined_namespace, &schema, &last_namespace);
GenComment(enum_def.doc_comment, &schema, nullptr);
schema += "enum " + enum_def.name + " : ";
schema += GenType(enum_def.underlying_type) + " {\n";
for (auto it = enum_def.vals.vec.begin();
it != enum_def.vals.vec.end(); ++it) {
auto &ev = **it;
GenComment(ev.doc_comment, &schema, nullptr, " ");
schema += " " + ev.name + " = " + NumToString(ev.value) + ",\n";
}
schema += "}\n\n";
@@ -74,10 +101,13 @@ std::string GenerateFBS(const Parser &parser, const std::string &file_name,
for (auto it = parser.structs_.vec.begin();
it != parser.structs_.vec.end(); ++it) {
StructDef &struct_def = **it;
GenNameSpace(*struct_def.defined_namespace, &schema, &last_namespace);
GenComment(struct_def.doc_comment, &schema, nullptr);
schema += "table " + struct_def.name + " {\n";
for (auto field_it = struct_def.fields.vec.begin();
field_it != struct_def.fields.vec.end(); ++field_it) {
auto &field = **field_it;
GenComment(field.doc_comment, &schema, nullptr, " ");
schema += " " + field.name + ":" + GenType(field.value.type);
if (field.value.constant != "0") schema += " = " + field.value.constant;
if (field.required) schema += " (required)";

View File

@@ -19,6 +19,7 @@
#include "flatbuffers/flatbuffers.h"
#include "flatbuffers/idl.h"
#include "flatbuffers/util.h"
#include <algorithm>
namespace flatbuffers {
@@ -37,14 +38,34 @@ std::string MakeCamel(const std::string &in, bool first) {
return s;
}
struct CommentConfig {
const char *first_line;
const char *content_line_prefix;
const char *last_line;
};
// Generate a documentation comment, if available.
void GenComment(const std::vector<std::string> &dc, std::string *code_ptr,
const char *prefix) {
const CommentConfig *config, const char *prefix) {
if (dc.begin() == dc.end()) {
// Don't output empty comment blocks with 0 lines of comment content.
return;
}
std::string &code = *code_ptr;
if (config != nullptr && config->first_line != nullptr) {
code += std::string(prefix) + std::string(config->first_line) + "\n";
}
std::string line_prefix = std::string(prefix) +
((config != nullptr && config->content_line_prefix != nullptr) ?
config->content_line_prefix : "///");
for (auto it = dc.begin();
it != dc.end();
++it) {
code += std::string(prefix) + "///" + *it + "\n";
code += line_prefix + *it + "\n";
}
if (config != nullptr && config->last_line != nullptr) {
code += std::string(prefix) + std::string(config->last_line) + "\n";
}
}
@@ -59,12 +80,20 @@ struct LanguageParameters {
const char *bool_type;
const char *open_curly;
const char *const_decl;
const char *unsubclassable_decl;
const char *enum_decl;
const char *enum_separator;
const char *getter_prefix;
const char *getter_suffix;
const char *inheritance_marker;
const char *namespace_ident;
const char *namespace_begin;
const char *namespace_end;
const char *set_bb_byteorder;
const char *get_bb_position;
const char *get_fbb_offset;
const char *includes;
CommentConfig comment_config;
};
LanguageParameters language_parameters[] = {
@@ -76,13 +105,25 @@ LanguageParameters language_parameters[] = {
"boolean ",
" {\n",
" final ",
"final ",
"final class ",
";\n",
"()",
"",
" extends ",
"package ",
";",
"",
"_bb.order(ByteOrder.LITTLE_ENDIAN); ",
"position()",
"offset()",
"import java.nio.*;\nimport java.lang.*;\nimport java.util.*;\n"
"import com.google.flatbuffers.*;\n\n",
"import com.google.flatbuffers.*;\n\n@SuppressWarnings(\"unused\")\n",
{
"/**",
" *",
" */",
},
},
{
GeneratorOptions::kCSharp,
@@ -92,12 +133,24 @@ LanguageParameters language_parameters[] = {
"bool ",
"\n{\n",
" readonly ",
"sealed ",
"enum ",
",\n",
" { get",
"} ",
" : ",
"namespace ",
"\n{",
"\n}\n",
"",
"Position",
"Offset",
"using FlatBuffers;\n\n",
{
nullptr,
"///",
nullptr,
},
},
// TODO: add Go support to the general generator.
// WARNING: this is currently only used for generating make rules for Go.
@@ -109,12 +162,24 @@ LanguageParameters language_parameters[] = {
"bool ",
"\n{\n",
"const ",
" ",
"class ",
";\n",
"()",
"",
"",
"package ",
"",
"",
"",
"position()",
"offset()",
"import (\n\tflatbuffers \"github.com/google/flatbuffers/go\"\n)",
{
nullptr,
"///",
nullptr,
},
}
};
@@ -132,15 +197,29 @@ static std::string FunctionStart(const LanguageParameters &lang, char upper) {
static std::string GenTypeBasic(const LanguageParameters &lang,
const Type &type) {
static const char *gtypename[] = {
#define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE) \
#define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \
#JTYPE, #NTYPE, #GTYPE,
FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
#undef FLATBUFFERS_TD
};
if(lang.language == GeneratorOptions::kCSharp && type.base_type == BASE_TYPE_STRUCT) {
return "Offset<" + type.struct_def->name + ">";
}
return gtypename[type.base_type * GeneratorOptions::kMAX + lang.language];
}
// Generate type to be used in user-facing API
static std::string GenTypeForUser(const LanguageParameters &lang,
const Type &type) {
if (lang.language == GeneratorOptions::kCSharp) {
if (type.enum_def != nullptr &&
type.base_type != BASE_TYPE_UNION) return type.enum_def->name;
}
return GenTypeBasic(lang, type);
}
static std::string GenTypeGet(const LanguageParameters &lang,
const Type &type);
@@ -173,6 +252,8 @@ static Type DestinationType(const LanguageParameters &lang, const Type &type,
bool vectorelem) {
if (lang.language != GeneratorOptions::kJava) return type;
switch (type.base_type) {
// We use int for both uchar/ushort, since that generally means less casting
// than using short for uchar.
case BASE_TYPE_UCHAR: return Type(BASE_TYPE_INT);
case BASE_TYPE_USHORT: return Type(BASE_TYPE_INT);
case BASE_TYPE_UINT: return Type(BASE_TYPE_LONG);
@@ -184,6 +265,49 @@ static Type DestinationType(const LanguageParameters &lang, const Type &type,
}
}
static std::string GenOffsetType(const LanguageParameters &lang, const StructDef &struct_def) {
if(lang.language == GeneratorOptions::kCSharp) {
return "Offset<" + struct_def.name + ">";
} else {
return "int";
}
}
static std::string GenOffsetConstruct(const LanguageParameters &lang,
const StructDef &struct_def,
const std::string &variable_name)
{
if(lang.language == GeneratorOptions::kCSharp) {
return "new Offset<" + struct_def.name + ">(" + variable_name + ")";
}
return variable_name;
}
static std::string GenVectorOffsetType(const LanguageParameters &lang) {
if(lang.language == GeneratorOptions::kCSharp) {
return "VectorOffset";
} else {
return "int";
}
}
// Generate destination type name
static std::string GenTypeNameDest(const LanguageParameters &lang, const Type &type)
{
if (lang.language == GeneratorOptions::kCSharp) {
// C# enums are represented by themselves
if (type.enum_def != nullptr && type.base_type != BASE_TYPE_UNION)
return type.enum_def->name;
// Unions in C# use a generic Table-derived type for better type safety
if (type.base_type == BASE_TYPE_UNION)
return "TTable";
}
// default behavior
return GenTypeGet(lang, DestinationType(lang, type, true));
}
// Mask to turn serialized value into destination type value.
static std::string DestinationMask(const LanguageParameters &lang,
const Type &type, bool vectorelem) {
@@ -200,19 +324,86 @@ static std::string DestinationMask(const LanguageParameters &lang,
}
}
// Cast necessary to correctly read serialized unsigned values.
// Casts necessary to correctly read serialized data
static std::string DestinationCast(const LanguageParameters &lang,
const Type &type) {
if (lang.language == GeneratorOptions::kJava &&
(type.base_type == BASE_TYPE_UINT ||
(type.base_type == BASE_TYPE_VECTOR &&
type.element == BASE_TYPE_UINT))) return "(long)";
switch (lang.language) {
case GeneratorOptions::kJava:
// Cast necessary to correctly read serialized unsigned values.
if (type.base_type == BASE_TYPE_UINT ||
(type.base_type == BASE_TYPE_VECTOR &&
type.element == BASE_TYPE_UINT)) return "(long)";
break;
case GeneratorOptions::kCSharp:
// Cast from raw integral types to enum
if (type.enum_def != nullptr &&
type.base_type != BASE_TYPE_UNION) return "(" + type.enum_def->name + ")";
break;
default:
break;
}
return "";
}
// Read value and possibly process it to get proper value
static std::string DestinationValue(const LanguageParameters &lang,
const std::string &name,
const Type &type) {
std::string type_mask = DestinationMask(lang, type, false);
// is a typecast needed? (for C# enums and unsigned values in Java)
if (type_mask.length() ||
(lang.language == GeneratorOptions::kCSharp &&
type.enum_def != nullptr &&
type.base_type != BASE_TYPE_UNION)) {
return "(" + GenTypeBasic(lang, type) + ")(" + name + type_mask + ")";
} else {
return name;
}
}
// Cast statements for mutator method parameters.
// In Java, parameters representing unsigned numbers need to be cast down to their respective type.
// For example, a long holding an unsigned int value would be cast down to int before being put onto the buffer.
// In C#, one cast directly cast an Enum to its underlying type, which is essential before putting it onto the buffer.
static std::string SourceCast(const LanguageParameters &lang,
const Type &type) {
if (type.base_type == BASE_TYPE_VECTOR) {
return SourceCast(lang, type.VectorType());
} else {
switch (lang.language) {
case GeneratorOptions::kJava:
if (type.base_type == BASE_TYPE_UINT) return "(int)";
else if (type.base_type == BASE_TYPE_USHORT) return "(short)";
else if (type.base_type == BASE_TYPE_UCHAR) return "(byte)";
break;
case GeneratorOptions::kCSharp:
if (type.enum_def != nullptr &&
type.base_type != BASE_TYPE_UNION)
return "(" + GenTypeGet(lang, type) + ")";
break;
default:
break;
}
return "";
}
}
static std::string GenDefaultValue(const LanguageParameters &lang, const Value &value, bool for_buffer) {
if(lang.language == GeneratorOptions::kCSharp && !for_buffer) {
switch(value.type.base_type) {
case BASE_TYPE_STRING:
return "default(StringOffset)";
case BASE_TYPE_STRUCT:
return "default(Offset<" + value.type.struct_def->name + ">)";
case BASE_TYPE_VECTOR:
return "default(VectorOffset)";
default:
break;
}
}
static std::string GenDefaultValue(const Value &value) {
return value.type.base_type == BASE_TYPE_BOOL
? (value.constant == "0" ? "false" : "true")
: value.constant;
@@ -228,49 +419,62 @@ static void GenEnum(const LanguageParameters &lang, EnumDef &enum_def,
// In Java, we use ints rather than the Enum feature, because we want them
// to map directly to how they're used in C/C++ and file formats.
// That, and Java Enums are expensive, and not universally liked.
GenComment(enum_def.doc_comment, code_ptr);
code += "public class " + enum_def.name + lang.open_curly;
GenComment(enum_def.doc_comment, code_ptr, &lang.comment_config);
code += std::string("public ") + lang.enum_decl + enum_def.name;
if (lang.language == GeneratorOptions::kCSharp) {
code += lang.inheritance_marker + GenTypeBasic(lang, enum_def.underlying_type);
}
code += lang.open_curly;
if (lang.language == GeneratorOptions::kJava) {
code += " private " + enum_def.name + "() { }\n";
}
for (auto it = enum_def.vals.vec.begin();
it != enum_def.vals.vec.end();
++it) {
auto &ev = **it;
GenComment(ev.doc_comment, code_ptr, " ");
code += " public static";
code += lang.const_decl;
code += GenTypeBasic(lang, enum_def.underlying_type);
GenComment(ev.doc_comment, code_ptr, &lang.comment_config, " ");
if (lang.language != GeneratorOptions::kCSharp) {
code += " public static";
code += lang.const_decl;
code += GenTypeBasic(lang, enum_def.underlying_type);
}
code += " " + ev.name + " = ";
code += NumToString(ev.value) + ";\n";
code += NumToString(ev.value);
code += lang.enum_separator;
}
// Generate a generate string table for enum values.
// Problem is, if values are very sparse that could generate really big
// tables. Ideally in that case we generate a map lookup instead, but for
// the moment we simply don't output a table at all.
auto range = enum_def.vals.vec.back()->value -
enum_def.vals.vec.front()->value + 1;
// Average distance between values above which we consider a table
// "too sparse". Change at will.
static const int kMaxSparseness = 5;
if (range / static_cast<int64_t>(enum_def.vals.vec.size()) < kMaxSparseness) {
code += "\n private static";
code += lang.const_decl;
code += lang.string_type;
code += "[] names = { ";
auto val = enum_def.vals.vec.front()->value;
for (auto it = enum_def.vals.vec.begin();
it != enum_def.vals.vec.end();
++it) {
while (val++ != (*it)->value) code += "\"\", ";
code += "\"" + (*it)->name + "\", ";
// We do not do that for C# where this functionality is native.
if (lang.language != GeneratorOptions::kCSharp) {
// Problem is, if values are very sparse that could generate really big
// tables. Ideally in that case we generate a map lookup instead, but for
// the moment we simply don't output a table at all.
auto range = enum_def.vals.vec.back()->value -
enum_def.vals.vec.front()->value + 1;
// Average distance between values above which we consider a table
// "too sparse". Change at will.
static const int kMaxSparseness = 5;
if (range / static_cast<int64_t>(enum_def.vals.vec.size()) < kMaxSparseness) {
code += "\n private static";
code += lang.const_decl;
code += lang.string_type;
code += "[] names = { ";
auto val = enum_def.vals.vec.front()->value;
for (auto it = enum_def.vals.vec.begin();
it != enum_def.vals.vec.end();
++it) {
while (val++ != (*it)->value) code += "\"\", ";
code += "\"" + (*it)->name + "\", ";
}
code += "};\n\n";
code += " public static ";
code += lang.string_type;
code += " " + MakeCamel("name", lang.first_camel_upper);
code += "(int e) { return names[e";
if (enum_def.vals.vec.front()->value)
code += " - " + enum_def.vals.vec.front()->name;
code += "]; }\n";
}
code += "};\n\n";
code += " public static ";
code += lang.string_type;
code += " " + MakeCamel("name", lang.first_camel_upper);
code += "(int e) { return names[e";
if (enum_def.vals.vec.front()->value)
code += " - " + enum_def.vals.vec.front()->name;
code += "]; }\n";
}
// Close the class
@@ -297,6 +501,22 @@ static std::string GenGetter(const LanguageParameters &lang,
}
}
// Direct mutation is only allowed for scalar fields.
// Hence a setter method will only be generated for such fields.
static std::string GenSetter(const LanguageParameters &lang,
const Type &type) {
if (IsScalar(type.base_type)) {
std::string setter = "bb." + FunctionStart(lang, 'P') + "ut";
if (GenTypeBasic(lang, type) != "byte" &&
type.base_type != BASE_TYPE_BOOL) {
setter += MakeCamel(GenTypeGet(lang, type));
}
return setter;
} else {
return "";
}
}
// Returns the method name for use with add/put calls.
static std::string GenMethod(const LanguageParameters &lang, const Type &type) {
return IsScalar(type.base_type)
@@ -317,13 +537,13 @@ static void GenStructArgs(const LanguageParameters &lang,
if (IsStruct(field.value.type)) {
// Generate arguments for a struct inside a struct. To ensure names
// don't clash, and to make it obvious these arguments are constructing
// a nested struct, prefix the name with the struct name.
// a nested struct, prefix the name with the field name.
GenStructArgs(lang, *field.value.type.struct_def, code_ptr,
(field.value.type.struct_def->name + "_").c_str());
(nameprefix + (field.name + "_")).c_str());
} else {
code += ", ";
code += GenTypeBasic(lang,
DestinationType(lang, field.value.type, false));
code += GenTypeForUser(lang,
DestinationType(lang, field.value.type, false));
code += " ";
code += nameprefix;
code += MakeCamel(field.name, lang.first_camel_upper);
@@ -350,25 +570,20 @@ static void GenStructBody(const LanguageParameters &lang,
}
if (IsStruct(field.value.type)) {
GenStructBody(lang, *field.value.type.struct_def, code_ptr,
(field.value.type.struct_def->name + "_").c_str());
(nameprefix + (field.name + "_")).c_str());
} else {
code += " builder." + FunctionStart(lang, 'P') + "ut";
code += GenMethod(lang, field.value.type) + "(";
auto argname = nameprefix + MakeCamel(field.name, lang.first_camel_upper);
std::string type_mask = DestinationMask(lang, field.value.type, false);
if (type_mask.length()) {
code += "(" + GenTypeBasic(lang, field.value.type) + ")";
code += "(" + argname + type_mask + ")";
} else {
code += argname;
}
code += DestinationValue(lang, argname, field.value.type);
code += ");\n";
}
}
}
static void GenStruct(const LanguageParameters &lang, const Parser &parser,
StructDef &struct_def, std::string *code_ptr) {
StructDef &struct_def, const GeneratorOptions &opts,
std::string *code_ptr) {
if (struct_def.generated) return;
std::string &code = *code_ptr;
@@ -378,8 +593,9 @@ static void GenStruct(const LanguageParameters &lang, const Parser &parser,
// public type name() {
// int o = __offset(offset); return o != 0 ? bb.getType(o + i) : default;
// }
GenComment(struct_def.doc_comment, code_ptr);
code += "public class " + struct_def.name + lang.inheritance_marker;
GenComment(struct_def.doc_comment, code_ptr, &lang.comment_config);
code += std::string("public ") + lang.unsubclassable_decl;
code += "class " + struct_def.name + lang.inheritance_marker;
code += struct_def.fixed ? "Struct" : "Table";
code += " {\n";
if (!struct_def.fixed) {
@@ -396,8 +612,12 @@ static void GenStruct(const LanguageParameters &lang, const Parser &parser,
code += method_signature + "(ByteBuffer _bb, " + struct_def.name + " obj) { ";
code += lang.set_bb_byteorder;
code += "return (obj.__init(_bb." + FunctionStart(lang, 'G');
code += "etInt(_bb.position()) + _bb.position(), _bb)); }\n";
if (parser.root_struct_def == &struct_def) {
code += "etInt(_bb.";
code += lang.get_bb_position;
code += ") + _bb.";
code += lang.get_bb_position;
code += ", _bb)); }\n";
if (parser.root_struct_def_ == &struct_def) {
if (parser.file_identifier_.length()) {
// Check if a buffer has the identifier.
code += " public static ";
@@ -418,58 +638,88 @@ static void GenStruct(const LanguageParameters &lang, const Parser &parser,
++it) {
auto &field = **it;
if (field.deprecated) continue;
GenComment(field.doc_comment, code_ptr, " ");
GenComment(field.doc_comment, code_ptr, &lang.comment_config, " ");
std::string type_name = GenTypeGet(lang, field.value.type);
std::string type_name_dest =
GenTypeGet(lang, DestinationType(lang, field.value.type, true));
std::string type_name_dest = GenTypeNameDest(lang, field.value.type);
std::string dest_mask = DestinationMask(lang, field.value.type, true);
std::string dest_cast = DestinationCast(lang, field.value.type);
std::string src_cast = SourceCast(lang, field.value.type);
std::string method_start = " public " + type_name_dest + " " +
MakeCamel(field.name, lang.first_camel_upper);
// Most field accessors need to retrieve and test the field offset first,
// this is the prefix code for that:
auto offset_prefix = " { int o = __offset(" +
NumToString(field.value.offset) +
"); return o != 0 ? ";
// Generate the accessors that don't do object reuse.
if (field.value.type.base_type == BASE_TYPE_STRUCT) {
// Calls the accessor that takes an accessor object with a new object.
code += method_start + "() { return ";
code += MakeCamel(field.name, lang.first_camel_upper);
code += "(new ";
code += type_name + "()); }\n";
if (lang.language == GeneratorOptions::kCSharp) {
code += method_start + " { get { return Get";
code += MakeCamel(field.name, lang.first_camel_upper);
code += "(new ";
code += type_name + "()); } }\n";
method_start = " public " + type_name_dest + " Get" + MakeCamel(field.name, lang.first_camel_upper);
}
else {
code += method_start + "() { return ";
code += MakeCamel(field.name, lang.first_camel_upper);
code += "(new ";
code += type_name + "()); }\n";
}
} else if (field.value.type.base_type == BASE_TYPE_VECTOR &&
field.value.type.element == BASE_TYPE_STRUCT) {
// Accessors for vectors of structs also take accessor objects, this
// generates a variant without that argument.
code += method_start + "(int j) { return ";
if (lang.language == GeneratorOptions::kCSharp) {
method_start = " public " + type_name_dest + " Get" + MakeCamel(field.name, lang.first_camel_upper);
code += method_start + "(int j) { return Get";
} else {
code += method_start + "(int j) { return ";
}
code += MakeCamel(field.name, lang.first_camel_upper);
code += "(new ";
code += type_name + "(), j); }\n";
} else if (field.value.type.base_type == BASE_TYPE_VECTOR) {
if (lang.language == GeneratorOptions::kCSharp) {
method_start = " public " + type_name_dest + " Get" + MakeCamel(field.name, lang.first_camel_upper);
}
} else if (field.value.type.base_type == BASE_TYPE_UNION) {
if (lang.language == GeneratorOptions::kCSharp) {
// union types in C# use generic Table-derived type for better type safety
method_start = " public " + type_name_dest + " Get" + MakeCamel(field.name, lang.first_camel_upper) + "<TTable>";
offset_prefix = " where TTable : Table" + offset_prefix;
type_name = type_name_dest;
}
}
std::string getter = dest_cast + GenGetter(lang, field.value.type);
code += method_start + "(";
// Most field accessors need to retrieve and test the field offset first,
// this is the prefix code for that:
auto offset_prefix = ") { int o = __offset(" +
NumToString(field.value.offset) +
"); return o != 0 ? ";
code += method_start;
std::string default_cast = "";
if (lang.language == GeneratorOptions::kCSharp)
default_cast = "(" + type_name_dest + ")";
std::string member_suffix = "";
if (IsScalar(field.value.type.base_type)) {
code += lang.getter_prefix;
member_suffix = lang.getter_suffix;
if (struct_def.fixed) {
code += ") { return " + getter;
code += " { return " + getter;
code += "(bb_pos + " + NumToString(field.value.offset) + ")";
code += dest_mask;
} else {
code += offset_prefix + getter;
code += "(o + bb_pos)" + dest_mask + " : " + default_cast;
code += GenDefaultValue(field.value);
code += GenDefaultValue(lang, field.value, false);
}
} else {
switch (field.value.type.base_type) {
case BASE_TYPE_STRUCT:
code += type_name + " obj";
code += "(" + type_name + " obj";
if (struct_def.fixed) {
code += ") { return obj.__init(bb_pos + ";
code += NumToString(field.value.offset) + ", bb)";
} else {
code += ")";
code += offset_prefix;
code += "obj.__init(";
code += field.value.type.struct_def->fixed
@@ -479,15 +729,18 @@ static void GenStruct(const LanguageParameters &lang, const Parser &parser,
}
break;
case BASE_TYPE_STRING:
code += offset_prefix + getter +"(o + bb_pos) : null";
code += lang.getter_prefix;
member_suffix = lang.getter_suffix;
code += offset_prefix + getter + "(o + bb_pos) : null";
break;
case BASE_TYPE_VECTOR: {
auto vectortype = field.value.type.VectorType();
code += "(";
if (vectortype.base_type == BASE_TYPE_STRUCT) {
code += type_name + " obj, ";
getter = "obj.__init";
}
code += "int j" + offset_prefix + getter +"(";
code += "int j)" + offset_prefix + getter +"(";
auto index = "__vector(o) + j * " +
NumToString(InlineSize(vectortype));
if (vectortype.base_type == BASE_TYPE_STRUCT) {
@@ -499,24 +752,30 @@ static void GenStruct(const LanguageParameters &lang, const Parser &parser,
code += index;
}
code += ")" + dest_mask + " : ";
code += IsScalar(field.value.type.element)
? default_cast + "0"
: "null";
code += field.value.type.element == BASE_TYPE_BOOL ? "false" :
(IsScalar(field.value.type.element) ? default_cast + "0" : "null");
break;
}
case BASE_TYPE_UNION:
code += type_name + " obj" + offset_prefix + getter;
code += "(" + type_name + " obj)" + offset_prefix + getter;
code += "(obj, o) : null";
break;
default:
assert(0);
}
}
code += "; }\n";
code += "; ";
code += member_suffix;
code += "}\n";
if (field.value.type.base_type == BASE_TYPE_VECTOR) {
code += " public int " + MakeCamel(field.name, lang.first_camel_upper);
code += "Length(" + offset_prefix;
code += "__vector_len(o) : 0; }\n";
code += "Length";
code += lang.getter_prefix;
code += offset_prefix;
code += "__vector_len(o) : 0; ";
code += lang.getter_suffix;
code += "}\n";
}
// Generate a ByteBuffer accessor for strings & vectors of scalars.
if (((field.value.type.base_type == BASE_TYPE_VECTOR &&
@@ -531,17 +790,54 @@ static void GenStruct(const LanguageParameters &lang, const Parser &parser,
InlineSize(field.value.type.VectorType()));
code += "); }\n";
}
// generate mutators for scalar fields or vectors of scalars
if (opts.mutable_buffer) {
auto underlying_type = field.value.type.base_type == BASE_TYPE_VECTOR
? field.value.type.VectorType()
: field.value.type;
// boolean parameters have to be explicitly converted to byte representation
auto setter_parameter = underlying_type.base_type == BASE_TYPE_BOOL ? "(byte)(" + field.name + " ? 1 : 0)" : field.name;
auto mutator_prefix = MakeCamel("mutate", lang.first_camel_upper);
//a vector mutator also needs the index of the vector element it should mutate
auto mutator_params = (field.value.type.base_type == BASE_TYPE_VECTOR ? "(int j, " : "(") +
GenTypeNameDest(lang, underlying_type) + " " +
field.name + ") { ";
auto setter_index = field.value.type.base_type == BASE_TYPE_VECTOR
? "__vector(o) + j * " + NumToString(InlineSize(underlying_type))
: (struct_def.fixed ? "bb_pos + " + NumToString(field.value.offset) : "o + bb_pos");
if (IsScalar(field.value.type.base_type) ||
(field.value.type.base_type == BASE_TYPE_VECTOR &&
IsScalar(field.value.type.VectorType().base_type))) {
code += " public ";
code += struct_def.fixed ? "void " : lang.bool_type;
code += mutator_prefix + MakeCamel(field.name, true);
code += mutator_params;
if (struct_def.fixed) {
code += GenSetter(lang, underlying_type) + "(" + setter_index + ", ";
code += src_cast + setter_parameter + "); }\n";
} else {
code += "int o = __offset(" + NumToString(field.value.offset) + ");";
code += " if (o != 0) { " + GenSetter(lang, underlying_type);
code += "(" + setter_index + ", " + src_cast + setter_parameter + "); return true; } else { return false; } }\n";
}
}
}
}
code += "\n";
if (struct_def.fixed) {
// create a struct constructor function
code += " public static int " + FunctionStart(lang, 'C') + "reate";
code += " public static " + GenOffsetType(lang, struct_def) + " ";
code += FunctionStart(lang, 'C') + "reate";
code += struct_def.name + "(FlatBufferBuilder builder";
GenStructArgs(lang, struct_def, code_ptr, "");
code += ") {\n";
GenStructBody(lang, struct_def, code_ptr, "");
code += " return builder.";
code += FunctionStart(lang, 'O') + "ffset();\n }\n";
code += " return ";
code += GenOffsetConstruct(lang, struct_def, "builder." + std::string(lang.get_fbb_offset));
code += ";\n }\n";
} else {
// Generate a method that creates a table in one go. This is only possible
// when the table has no struct fields, since those have to be created
@@ -560,23 +856,31 @@ static void GenStruct(const LanguageParameters &lang, const Parser &parser,
}
if (has_no_struct_fields && num_fields) {
// Generate a table constructor of the form:
// public static void createName(FlatBufferBuilder builder, args...)
code += " public static int " + FunctionStart(lang, 'C') + "reate";
code += struct_def.name;
// public static int createName(FlatBufferBuilder builder, args...)
code += " public static " + GenOffsetType(lang, struct_def) + " ";
code += FunctionStart(lang, 'C') + "reate" + struct_def.name;
code += "(FlatBufferBuilder builder";
for (auto it = struct_def.fields.vec.begin();
it != struct_def.fields.vec.end(); ++it) {
auto &field = **it;
if (field.deprecated) continue;
code += ",\n ";
code += GenTypeBasic(lang,
DestinationType(lang, field.value.type, false));
code += GenTypeForUser(lang,
DestinationType(lang, field.value.type, false));
code += " ";
code += field.name;
// Java doesn't have defaults, which means this method must always
// supply all arguments, and thus won't compile when fields are added.
if (lang.language != GeneratorOptions::kJava) {
code += " = " + GenDefaultValue(field.value);
code += " = ";
// in C#, enum values have their own type, so we need to cast the
// numeric value to the proper type
if (lang.language == GeneratorOptions::kCSharp &&
field.value.type.enum_def != nullptr &&
field.value.type.base_type != BASE_TYPE_UNION) {
code += "(" + field.value.type.enum_def->name + ")";
}
code += GenDefaultValue(lang, field.value, false);
}
}
code += ") {\n builder.";
@@ -618,21 +922,18 @@ static void GenStruct(const LanguageParameters &lang, const Parser &parser,
code += " public static void " + FunctionStart(lang, 'A') + "dd";
code += MakeCamel(field.name);
code += "(FlatBufferBuilder builder, ";
code += GenTypeBasic(lang,
DestinationType(lang, field.value.type, false));
code += GenTypeForUser(lang,
DestinationType(lang, field.value.type, false));
auto argname = MakeCamel(field.name, false);
if (!IsScalar(field.value.type.base_type)) argname += "Offset";
code += " " + argname + ") { builder." + FunctionStart(lang, 'A') + "dd";
code += GenMethod(lang, field.value.type) + "(";
code += NumToString(it - struct_def.fields.vec.begin()) + ", ";
std::string type_mask = DestinationMask(lang, field.value.type, false);
if (type_mask.length()) {
code += "(" + GenTypeBasic(lang, field.value.type) + ")";
code += "(" + argname + type_mask + ")";
} else {
code += argname;
code += DestinationValue(lang, argname, field.value.type);
if(!IsScalar(field.value.type.base_type) && field.value.type.base_type != BASE_TYPE_UNION && lang.language == GeneratorOptions::kCSharp) {
code += ".Value";
}
code += ", " + GenDefaultValue(field.value);
code += ", " + GenDefaultValue(lang, field.value, true);
code += "); }\n";
if (field.value.type.base_type == BASE_TYPE_VECTOR) {
auto vector_type = field.value.type.VectorType();
@@ -640,7 +941,7 @@ static void GenStruct(const LanguageParameters &lang, const Parser &parser,
auto elem_size = InlineSize(vector_type);
if (!IsStruct(vector_type)) {
// Generate a method to create a vector from a Java array.
code += " public static int " + FunctionStart(lang, 'C') + "reate";
code += " public static " + GenVectorOffsetType(lang) + " " + FunctionStart(lang, 'C') + "reate";
code += MakeCamel(field.name);
code += "Vector(FlatBufferBuilder builder, ";
code += GenTypeBasic(lang, vector_type) + "[] data) ";
@@ -652,8 +953,12 @@ static void GenStruct(const LanguageParameters &lang, const Parser &parser,
code += FunctionStart(lang, 'L') + "ength - 1; i >= 0; i--) builder.";
code += FunctionStart(lang, 'A') + "dd";
code += GenMethod(lang, vector_type);
code += "(data[i]); return builder.";
code += FunctionStart(lang, 'E') + "ndVector(); }\n";
code += "(data[i]";
if(lang.language == GeneratorOptions::kCSharp &&
(vector_type.base_type == BASE_TYPE_STRUCT || vector_type.base_type == BASE_TYPE_STRING))
code += ".Value";
code += "); return ";
code += "builder." + FunctionStart(lang, 'E') + "ndVector(); }\n";
}
// Generate a method to start a vector, data to be added manually after.
code += " public static void " + FunctionStart(lang, 'S') + "tart";
@@ -665,7 +970,7 @@ static void GenStruct(const LanguageParameters &lang, const Parser &parser,
code += "); }\n";
}
}
code += " public static int ";
code += " public static " + GenOffsetType(lang, struct_def) + " ";
code += FunctionStart(lang, 'E') + "nd" + struct_def.name;
code += "(FlatBufferBuilder builder) {\n int o = builder.";
code += FunctionStart(lang, 'E') + "ndObject();\n";
@@ -679,12 +984,16 @@ static void GenStruct(const LanguageParameters &lang, const Parser &parser,
code += "); // " + field.name + "\n";
}
}
code += " return o;\n }\n";
if (parser.root_struct_def == &struct_def) {
code += " return " + GenOffsetConstruct(lang, struct_def, "o") + ";\n }\n";
if (parser.root_struct_def_ == &struct_def) {
code += " public static void ";
code += FunctionStart(lang, 'F') + "inish" + struct_def.name;
code += "Buffer(FlatBufferBuilder builder, int offset) { ";
code += "builder." + FunctionStart(lang, 'F') + "inish(offset";
code += "Buffer(FlatBufferBuilder builder, " + GenOffsetType(lang, struct_def) + " offset) {";
code += " builder." + FunctionStart(lang, 'F') + "inish(offset";
if (lang.language == GeneratorOptions::kCSharp) {
code += ".Value";
}
if (parser.file_identifier_.length())
code += ", \"" + parser.file_identifier_ + "\"";
code += "); }\n";
@@ -696,8 +1005,8 @@ static void GenStruct(const LanguageParameters &lang, const Parser &parser,
// Save out the generated code for a single class while adding
// declaration boilerplate.
static bool SaveClass(const LanguageParameters &lang, const Parser &parser,
const Definition &def, const std::string &classcode,
const std::string &path, bool needs_includes) {
const std::string &defname, const std::string &classcode,
const std::string &path, bool needs_includes, bool onefile) {
if (!classcode.length()) return true;
std::string namespace_general;
@@ -708,44 +1017,63 @@ static bool SaveClass(const LanguageParameters &lang, const Parser &parser,
namespace_general += ".";
}
namespace_general += *it;
namespace_dir += *it + kPathSeparator;
if (!onefile) {
namespace_dir += *it + kPathSeparator;
}
}
EnsureDirExists(namespace_dir);
std::string code = "// automatically generated, do not modify\n\n";
code += lang.namespace_ident + namespace_general + lang.namespace_begin;
code += "\n\n";
if (!namespace_general.empty()) {
code += lang.namespace_ident + namespace_general + lang.namespace_begin;
code += "\n\n";
}
if (needs_includes) code += lang.includes;
code += classcode;
code += lang.namespace_end;
auto filename = namespace_dir + def.name + lang.file_extension;
if (!namespace_general.empty()) code += lang.namespace_end;
auto filename = namespace_dir + defname + lang.file_extension;
return SaveFile(filename.c_str(), code, false);
}
bool GenerateGeneral(const Parser &parser,
const std::string &path,
const std::string & /*file_name*/,
const std::string & file_name,
const GeneratorOptions &opts) {
assert(opts.lang <= GeneratorOptions::kMAX);
auto lang = language_parameters[opts.lang];
std::string one_file_code;
for (auto it = parser.enums_.vec.begin();
it != parser.enums_.vec.end(); ++it) {
std::string enumcode;
GenEnum(lang, **it, &enumcode);
if (!SaveClass(lang, parser, **it, enumcode, path, false))
return false;
if (opts.one_file) {
one_file_code += enumcode;
}
else {
if (!SaveClass(lang, parser, (**it).name, enumcode, path, false, false))
return false;
}
}
for (auto it = parser.structs_.vec.begin();
it != parser.structs_.vec.end(); ++it) {
std::string declcode;
GenStruct(lang, parser, **it, &declcode);
if (!SaveClass(lang, parser, **it, declcode, path, true))
return false;
GenStruct(lang, parser, **it, opts, &declcode);
if (opts.one_file) {
one_file_code += declcode;
}
else {
if (!SaveClass(lang, parser, (**it).name, declcode, path, true, false))
return false;
}
}
if (opts.one_file) {
return SaveClass(lang, parser, file_name, one_file_code,path, true, true);
}
return true;
}
@@ -828,7 +1156,7 @@ std::string BinaryMakeRule(const Parser &parser,
std::string make_rule = BinaryFileName(parser, path, filebase) + ": " +
file_name;
auto included_files = parser.GetIncludedFilesRecursive(
parser.root_struct_def->file);
parser.root_struct_def_->file);
for (auto it = included_files.begin();
it != included_files.end(); ++it) {
make_rule += " " + *it;

View File

@@ -144,6 +144,19 @@ static void GetVectorLen(const StructDef &struct_def,
code += "\treturn 0\n}\n\n";
}
// Get a [ubyte] vector as a byte slice.
static void GetUByteSlice(const StructDef &struct_def,
const FieldDef &field,
std::string *code_ptr) {
std::string &code = *code_ptr;
GenReceiver(struct_def, code_ptr);
code += " " + MakeCamel(field.name) + "Bytes(";
code += ") []byte " + OffsetPrefix(field);
code += "\t\treturn rcv._tab.ByteVector(o + rcv._tab.Pos)\n\t}\n";
code += "\treturn nil\n}\n\n";
}
// Get the value of a struct's scalar.
static void GetScalarFieldOfStruct(const StructDef &struct_def,
const FieldDef &field,
@@ -225,7 +238,7 @@ static void GetStringField(const StructDef &struct_def,
code += " " + MakeCamel(field.name);
code += "() " + TypeName(field) + " ";
code += OffsetPrefix(field) + "\t\treturn " + GenGetter(field.value.type);
code += "(o + rcv._tab.Pos)\n\t}\n\treturn \"\"\n";
code += "(o + rcv._tab.Pos)\n\t}\n\treturn nil\n";
code += "}\n\n";
}
@@ -288,7 +301,7 @@ static void GetMemberOfVectorOfNonStruct(const StructDef &struct_def,
code += NumToString(InlineSize(vectortype)) + "))\n";
code += "\t}\n";
if (vectortype.base_type == BASE_TYPE_STRING) {
code += "\treturn \"\"\n";
code += "\treturn nil\n";
} else {
code += "\treturn 0\n";
}
@@ -317,9 +330,9 @@ static void StructBuilderArgs(const StructDef &struct_def,
if (IsStruct(field.value.type)) {
// Generate arguments for a struct inside a struct. To ensure names
// don't clash, and to make it obvious these arguments are constructing
// a nested struct, prefix the name with the struct name.
// a nested struct, prefix the name with the field name.
StructBuilderArgs(*field.value.type.struct_def,
(field.value.type.struct_def->name + "_").c_str(),
(nameprefix + (field.name + "_")).c_str(),
code_ptr);
} else {
std::string &code = *code_ptr;
@@ -352,7 +365,7 @@ static void StructBuilderBody(const StructDef &struct_def,
code += " builder.Pad(" + NumToString(field.padding) + ")\n";
if (IsStruct(field.value.type)) {
StructBuilderBody(*field.value.type.struct_def,
(field.value.type.struct_def->name + "_").c_str(),
(nameprefix + (field.name + "_")).c_str(),
code_ptr);
} else {
code += " builder.Prepend" + GenMethod(field) + "(";
@@ -443,7 +456,7 @@ static void GenReceiver(const StructDef &struct_def, std::string *code_ptr) {
static void GenStructAccessor(const StructDef &struct_def,
const FieldDef &field,
std::string *code_ptr) {
GenComment(field.doc_comment, code_ptr, "");
GenComment(field.doc_comment, code_ptr, nullptr, "");
if (IsScalar(field.value.type.base_type)) {
if (struct_def.fixed) {
GetScalarFieldOfStruct(struct_def, field, code_ptr);
@@ -480,6 +493,9 @@ static void GenStructAccessor(const StructDef &struct_def,
}
if (field.value.type.base_type == BASE_TYPE_VECTOR) {
GetVectorLen(struct_def, field, code_ptr);
if (field.value.type.element == BASE_TYPE_UCHAR) {
GetUByteSlice(struct_def, field, code_ptr);
}
}
}
@@ -510,7 +526,7 @@ static void GenStruct(const StructDef &struct_def,
StructDef *root_struct_def) {
if (struct_def.generated) return;
GenComment(struct_def.doc_comment, code_ptr);
GenComment(struct_def.doc_comment, code_ptr, nullptr);
BeginClass(struct_def, code_ptr);
if (&struct_def == root_struct_def) {
// Generate a special accessor for the table that has been declared as
@@ -542,13 +558,13 @@ static void GenStruct(const StructDef &struct_def,
static void GenEnum(const EnumDef &enum_def, std::string *code_ptr) {
if (enum_def.generated) return;
GenComment(enum_def.doc_comment, code_ptr);
GenComment(enum_def.doc_comment, code_ptr, nullptr);
BeginEnum(code_ptr);
for (auto it = enum_def.vals.vec.begin();
it != enum_def.vals.vec.end();
++it) {
auto &ev = **it;
GenComment(ev.doc_comment, code_ptr, "\t");
GenComment(ev.doc_comment, code_ptr, nullptr, "\t");
EnumMember(enum_def, ev, code_ptr);
}
EndEnum(code_ptr);
@@ -557,7 +573,7 @@ static void GenEnum(const EnumDef &enum_def, std::string *code_ptr) {
// Returns the function name that is able to read a value of the given type.
static std::string GenGetter(const Type &type) {
switch (type.base_type) {
case BASE_TYPE_STRING: return "rcv._tab.String";
case BASE_TYPE_STRING: return "rcv._tab.ByteVector";
case BASE_TYPE_UNION: return "rcv._tab.Union";
case BASE_TYPE_VECTOR: return GenGetter(type.VectorType());
default:
@@ -600,7 +616,8 @@ static bool SaveType(const Parser &parser, const Definition &def,
static std::string GenTypeBasic(const Type &type) {
static const char *ctypename[] = {
#define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE) #GTYPE,
#define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \
#GTYPE,
FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
#undef FLATBUFFERS_TD
};
@@ -610,7 +627,7 @@ static std::string GenTypeBasic(const Type &type) {
static std::string GenTypePointer(const Type &type) {
switch (type.base_type) {
case BASE_TYPE_STRING:
return "string";
return "[]byte";
case BASE_TYPE_VECTOR:
return GenTypeGet(type.VectorType());
case BASE_TYPE_STRUCT:
@@ -660,7 +677,7 @@ bool GenerateGo(const Parser &parser,
for (auto it = parser.structs_.vec.begin();
it != parser.structs_.vec.end(); ++it) {
std::string declcode;
go::GenStruct(**it, &declcode, parser.root_struct_def);
go::GenStruct(**it, &declcode, parser.root_struct_def_);
if (!go::SaveType(parser, **it, declcode, path, true))
return false;
}

727
src/idl_gen_js.cpp Normal file
View File

@@ -0,0 +1,727 @@
/*
* Copyright 2014 Google Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// independent from idl_parser, since this code is not needed for most clients
#include "flatbuffers/flatbuffers.h"
#include "flatbuffers/idl.h"
#include "flatbuffers/util.h"
namespace flatbuffers {
namespace js {
static void GenNamespaces(const Parser &parser, std::string *code_ptr,
std::string *exports_ptr) {
std::set<std::string> namespaces;
for (auto it = parser.namespaces_.begin();
it != parser.namespaces_.end(); ++it) {
std::string namespace_so_far;
// Gather all parent namespaces for this namespace
for (auto component = (*it)->components.begin();
component != (*it)->components.end(); ++component) {
if (!namespace_so_far.empty()) {
namespace_so_far += '.';
}
namespace_so_far += *component;
namespaces.insert(namespace_so_far);
}
}
// Make sure parent namespaces come before child namespaces
std::vector<std::string> sorted_namespaces(
namespaces.begin(), namespaces.end());
std::sort(sorted_namespaces.begin(), sorted_namespaces.end());
// Emit namespaces in a form that Closure Compiler can optimize
std::string &code = *code_ptr;
std::string &exports = *exports_ptr;
for (auto it = sorted_namespaces.begin();
it != sorted_namespaces.end(); it++) {
code += "/**\n * @const\n*/\n";
if (it->find('.') == std::string::npos) {
code += "var ";
exports += "this." + *it + " = " + *it + ";\n";
}
code += *it + " = " + *it + " || {};\n\n";
}
}
// Ensure that a type is prefixed with its namespace whenever it is used
// outside of its namespace.
static std::string WrapInNameSpace(const Namespace *ns,
const std::string &name) {
std::string qualified_name;
for (auto it = ns->components.begin();
it != ns->components.end(); ++it) {
qualified_name += *it + ".";
}
return qualified_name + name;
}
static std::string WrapInNameSpace(const Definition &def) {
return WrapInNameSpace(def.defined_namespace, def.name);
}
// Generate a documentation comment, if available.
static void GenDocComment(const std::vector<std::string> &dc,
std::string *code_ptr,
const std::string &extra_lines,
const char *indent = nullptr) {
if (dc.empty() && extra_lines.empty()) {
// Don't output empty comment blocks with 0 lines of comment content.
return;
}
std::string &code = *code_ptr;
if (indent) code += indent;
code += "/**\n";
for (auto it = dc.begin(); it != dc.end(); ++it) {
if (indent) code += indent;
code += " *" + *it + "\n";
}
if (!extra_lines.empty()) {
if (!dc.empty()) {
if (indent) code += indent;
code += " *\n";
}
if (indent) code += indent;
std::string::size_type start = 0;
for (;;) {
auto end = extra_lines.find('\n', start);
if (end != std::string::npos) {
code += " * " + extra_lines.substr(start, end - start) + "\n";
start = end + 1;
} else {
code += " * " + extra_lines.substr(start) + "\n";
break;
}
}
}
if (indent) code += indent;
code += " */\n";
}
static void GenDocComment(std::string *code_ptr,
const std::string &extra_lines) {
GenDocComment(std::vector<std::string>(), code_ptr, extra_lines);
}
// Generate an enum declaration and an enum string lookup table.
static void GenEnum(EnumDef &enum_def, std::string *code_ptr,
std::string *exports_ptr) {
if (enum_def.generated) return;
std::string &code = *code_ptr;
std::string &exports = *exports_ptr;
GenDocComment(enum_def.doc_comment, code_ptr, "@enum");
if (enum_def.defined_namespace->components.empty()) {
code += "var ";
exports += "this." + enum_def.name + " = " + enum_def.name + ";\n";
}
code += WrapInNameSpace(enum_def) + " = {\n";
for (auto it = enum_def.vals.vec.begin();
it != enum_def.vals.vec.end(); ++it) {
auto &ev = **it;
if (!ev.doc_comment.empty()) {
if (it != enum_def.vals.vec.begin()) {
code += '\n';
}
GenDocComment(ev.doc_comment, code_ptr, "", " ");
}
code += " " + ev.name + ": " + NumToString(ev.value);
code += (it + 1) != enum_def.vals.vec.end() ? ",\n" : "\n";
}
code += "};\n\n";
}
static std::string GenType(const Type &type) {
switch (type.base_type) {
case BASE_TYPE_BOOL:
case BASE_TYPE_CHAR: return "Int8";
case BASE_TYPE_UTYPE:
case BASE_TYPE_UCHAR: return "Uint8";
case BASE_TYPE_SHORT: return "Int16";
case BASE_TYPE_USHORT: return "Uint16";
case BASE_TYPE_INT: return "Int32";
case BASE_TYPE_UINT: return "Uint32";
case BASE_TYPE_LONG: return "Int64";
case BASE_TYPE_ULONG: return "Uint64";
case BASE_TYPE_FLOAT: return "Float32";
case BASE_TYPE_DOUBLE: return "Float64";
case BASE_TYPE_STRING: return "String";
case BASE_TYPE_VECTOR: return GenType(type.VectorType());
case BASE_TYPE_STRUCT: return type.struct_def->name;
default: return "Table";
}
}
static std::string GenGetter(const Type &type, const std::string &arguments) {
switch (type.base_type) {
case BASE_TYPE_STRING: return "this.bb.__string" + arguments;
case BASE_TYPE_STRUCT: return "this.bb.__struct" + arguments;
case BASE_TYPE_UNION: return "this.bb.__union" + arguments;
case BASE_TYPE_VECTOR: return GenGetter(type.VectorType(), arguments);
default: {
auto getter = "this.bb.read" + MakeCamel(GenType(type)) + arguments;
if (type.base_type == BASE_TYPE_BOOL) {
getter = "!!" + getter;
}
if (type.enum_def) {
getter = "/** @type {" + WrapInNameSpace(*type.enum_def) + "} */ (" +
getter + ")";
}
return getter;
}
}
}
static std::string GenDefaultValue(const Value &value) {
if (value.type.enum_def) {
if (auto val = value.type.enum_def->ReverseLookup(
atoi(value.constant.c_str()), false)) {
return WrapInNameSpace(*value.type.enum_def) + "." + val->name;
}
}
switch (value.type.base_type) {
case BASE_TYPE_BOOL:
return value.constant == "0" ? "false" : "true";
case BASE_TYPE_STRING:
return "null";
case BASE_TYPE_LONG:
case BASE_TYPE_ULONG:
if (value.constant != "0") {
int64_t constant = StringToInt(value.constant.c_str());
return "new flatbuffers.Long(" + NumToString((int32_t)constant) +
", " + NumToString((int32_t)(constant >> 32)) + ")";
}
return "flatbuffers.Long.ZERO";
default:
return value.constant;
}
}
static std::string GenTypeName(const Type &type, bool input) {
if (!input) {
if (type.base_type == BASE_TYPE_STRING) {
return "string|Uint8Array";
}
if (type.base_type == BASE_TYPE_STRUCT) {
return WrapInNameSpace(*type.struct_def);
}
}
switch (type.base_type) {
case BASE_TYPE_BOOL: return "boolean";
case BASE_TYPE_LONG:
case BASE_TYPE_ULONG: return "flatbuffers.Long";
default:
if (IsScalar(type.base_type)) {
if (type.enum_def) {
return WrapInNameSpace(*type.enum_def);
}
return "number";
}
return "flatbuffers.Offset";
}
}
// Returns the method name for use with add/put calls.
static std::string GenWriteMethod(const Type &type) {
// Forward to signed versions since unsigned versions don't exist
switch (type.base_type) {
case BASE_TYPE_UTYPE:
case BASE_TYPE_UCHAR: return GenWriteMethod(Type(BASE_TYPE_CHAR));
case BASE_TYPE_USHORT: return GenWriteMethod(Type(BASE_TYPE_SHORT));
case BASE_TYPE_UINT: return GenWriteMethod(Type(BASE_TYPE_INT));
case BASE_TYPE_ULONG: return GenWriteMethod(Type(BASE_TYPE_LONG));
default: break;
}
return IsScalar(type.base_type)
? MakeCamel(GenType(type))
: (IsStruct(type) ? "Struct" : "Offset");
}
template <typename T>
static std::string MaybeAdd(T value) {
return value != 0 ? " + " + NumToString(value) : "";
}
template <typename T>
static std::string MaybeScale(T value) {
return value != 1 ? " * " + NumToString(value) : "";
}
static void GenStructArgs(const StructDef &struct_def,
std::string *annotations,
std::string *arguments,
const std::string &nameprefix) {
for (auto it = struct_def.fields.vec.begin();
it != struct_def.fields.vec.end(); ++it) {
auto &field = **it;
if (IsStruct(field.value.type)) {
// Generate arguments for a struct inside a struct. To ensure names
// don't clash, and to make it obvious these arguments are constructing
// a nested struct, prefix the name with the field name.
GenStructArgs(*field.value.type.struct_def, annotations, arguments,
nameprefix + field.name + "_");
} else {
*annotations += "@param {" + GenTypeName(field.value.type, true);
*annotations += "} " + nameprefix + field.name + "\n";
*arguments += ", " + nameprefix + field.name;
}
}
}
static void GenStructBody(const StructDef &struct_def,
std::string *body,
const std::string &nameprefix) {
*body += " builder.prep(";
*body += NumToString(struct_def.minalign) + ", ";
*body += NumToString(struct_def.bytesize) + ");\n";
for (auto it = struct_def.fields.vec.rbegin();
it != struct_def.fields.vec.rend(); ++it) {
auto &field = **it;
if (field.padding) {
*body += " builder.pad(" + NumToString(field.padding) + ");\n";
}
if (IsStruct(field.value.type)) {
// Generate arguments for a struct inside a struct. To ensure names
// don't clash, and to make it obvious these arguments are constructing
// a nested struct, prefix the name with the field name.
GenStructBody(*field.value.type.struct_def, body,
nameprefix + field.name + "_");
} else {
*body += " builder.write" + GenWriteMethod(field.value.type) + "(";
if (field.value.type.base_type == BASE_TYPE_BOOL) {
*body += "+";
}
*body += nameprefix + field.name + ");\n";
}
}
}
// Generate an accessor struct with constructor for a flatbuffers struct.
static void GenStruct(const Parser &parser, StructDef &struct_def,
std::string *code_ptr, std::string *exports_ptr) {
if (struct_def.generated) return;
std::string &code = *code_ptr;
std::string &exports = *exports_ptr;
// Emit constructor
bool isStatement = struct_def.defined_namespace->components.empty();
std::string object_name = WrapInNameSpace(struct_def);
GenDocComment(struct_def.doc_comment, code_ptr, "@constructor");
if (isStatement) {
exports += "this." + struct_def.name + " = " + struct_def.name + ";\n";
code += "function " + object_name;
} else {
code += object_name + " = function";
}
code += "() {\n";
code += " /**\n";
code += " * @type {flatbuffers.ByteBuffer}\n";
code += " */\n";
code += " this.bb = null;\n";
code += "\n";
code += " /**\n";
code += " * @type {number}\n";
code += " */\n";
code += " this.bb_pos = 0;\n";
code += isStatement ? "}\n\n" : "};\n\n";
// Generate the __init method that sets the field in a pre-existing
// accessor object. This is to allow object reuse.
code += "/**\n";
code += " * @param {number} i\n";
code += " * @param {flatbuffers.ByteBuffer} bb\n";
code += " * @returns {" + object_name + "}\n";
code += " */\n";
code += object_name + ".prototype.__init = function(i, bb) {\n";
code += " this.bb_pos = i;\n";
code += " this.bb = bb;\n";
code += " return this;\n";
code += "};\n\n";
// Generate a special accessor for the table that when used as the root of a
// FlatBuffer
if (!struct_def.fixed) {
GenDocComment(code_ptr,
"@param {flatbuffers.ByteBuffer} bb\n"
"@param {" + object_name + "=} obj\n"
"@returns {" + object_name + "}");
code += object_name + ".getRootAs" + struct_def.name;
code += " = function(bb, obj) {\n";
code += " return (obj || new " + object_name;
code += ").__init(bb.readInt32(bb.position()) + bb.position(), bb);\n";
code += "};\n\n";
// Generate the identifier check method
if (parser.root_struct_def_ == &struct_def &&
!parser.file_identifier_.empty()) {
GenDocComment(code_ptr,
"@param {flatbuffers.ByteBuffer} bb\n"
"@returns {boolean}");
code += object_name + ".bufferHasIdentifier = function(bb) {\n";
code += " return bb.__has_identifier('" + parser.file_identifier_;
code += "');\n};\n\n";
}
}
// Emit field accessors
for (auto it = struct_def.fields.vec.begin();
it != struct_def.fields.vec.end(); ++it) {
auto &field = **it;
if (field.deprecated) continue;
auto offset_prefix = " var offset = this.bb.__offset(this.bb_pos, " +
NumToString(field.value.offset) + ");\n return offset ? ";
// Emit a scalar field
if (IsScalar(field.value.type.base_type) ||
field.value.type.base_type == BASE_TYPE_STRING) {
GenDocComment(field.doc_comment, code_ptr,
std::string(field.value.type.base_type == BASE_TYPE_STRING ?
"@param {flatbuffers.Encoding=} optionalEncoding\n" : "") +
"@returns {" + GenTypeName(field.value.type, false) + "}");
code += object_name + ".prototype." + MakeCamel(field.name, false);
code += " = function(";
if (field.value.type.base_type == BASE_TYPE_STRING) {
code += "optionalEncoding";
}
code += ") {\n";
if (struct_def.fixed) {
code += " return " + GenGetter(field.value.type, "(this.bb_pos" +
MaybeAdd(field.value.offset) + ")") + ";\n";
} else {
std::string index = "this.bb_pos + offset";
if (field.value.type.base_type == BASE_TYPE_STRING) {
index += ", optionalEncoding";
}
code += offset_prefix + GenGetter(field.value.type,
"(" + index + ")") + " : " + GenDefaultValue(field.value);
code += ";\n";
}
}
// Emit an object field
else {
switch (field.value.type.base_type) {
case BASE_TYPE_STRUCT: {
auto type = WrapInNameSpace(*field.value.type.struct_def);
GenDocComment(field.doc_comment, code_ptr,
"@param {" + type + "=} obj\n@returns {" + type + "}");
code += object_name + ".prototype." + MakeCamel(field.name, false);
code += " = function(obj) {\n";
if (struct_def.fixed) {
code += " return (obj || new " + type;
code += ").__init(this.bb_pos";
code += MaybeAdd(field.value.offset) + ", this.bb);\n";
} else {
code += offset_prefix + "(obj || new " + type + ").__init(";
code += field.value.type.struct_def->fixed
? "this.bb_pos + offset"
: "this.bb.__indirect(this.bb_pos + offset)";
code += ", this.bb) : null;\n";
}
break;
}
case BASE_TYPE_VECTOR: {
auto vectortype = field.value.type.VectorType();
auto vectortypename = GenTypeName(vectortype, false);
auto inline_size = InlineSize(vectortype);
auto index = "this.bb.__vector(this.bb_pos + offset) + index" +
MaybeScale(inline_size);
std::string args = "@param {number} index\n";
if (vectortype.base_type == BASE_TYPE_STRUCT) {
args += "@param {" + vectortypename + "=} obj\n";
} else if (vectortype.base_type == BASE_TYPE_STRING) {
args += "@param {flatbuffers.Encoding=} optionalEncoding\n";
}
GenDocComment(field.doc_comment, code_ptr, args +
"@returns {" + vectortypename + "}");
code += object_name + ".prototype." + MakeCamel(field.name, false);
code += " = function(index";
if (vectortype.base_type == BASE_TYPE_STRUCT) {
code += ", obj";
} else if (vectortype.base_type == BASE_TYPE_STRING) {
code += ", optionalEncoding";
}
code += ") {\n";
if (vectortype.base_type == BASE_TYPE_STRUCT) {
code += offset_prefix + "(obj || new " + vectortypename;
code += ").__init(";
code += vectortype.struct_def->fixed
? index
: "this.bb.__indirect(" + index + ")";
code += ", this.bb)";
} else {
if (vectortype.base_type == BASE_TYPE_STRING) {
index += ", optionalEncoding";
}
code += offset_prefix + GenGetter(vectortype, "(" + index + ")");
}
code += " : ";
if (field.value.type.element == BASE_TYPE_BOOL) {
code += "false";
} else if (field.value.type.element == BASE_TYPE_LONG ||
field.value.type.element == BASE_TYPE_ULONG) {
code += "flatbuffers.Long.ZERO";
} else if (IsScalar(field.value.type.element)) {
code += "0";
} else {
code += "null";
}
code += ";\n";
break;
}
case BASE_TYPE_UNION:
GenDocComment(field.doc_comment, code_ptr,
"@param {flatbuffers.Table} obj\n"
"@returns {?flatbuffers.Table}");
code += object_name + ".prototype." + MakeCamel(field.name, false);
code += " = function(obj) {\n";
code += offset_prefix + GenGetter(field.value.type,
"(obj, this.bb_pos + offset)") + " : null;\n";
break;
default:
assert(0);
}
}
code += "};\n\n";
// Emit a length helper
if (field.value.type.base_type == BASE_TYPE_VECTOR) {
GenDocComment(code_ptr, "@returns {number}");
code += object_name + ".prototype." + MakeCamel(field.name, false);
code += "Length = function() {\n" + offset_prefix;
code += "this.bb.__vector_len(this.bb_pos + offset) : 0;\n};\n\n";
}
}
// Emit a factory constructor
if (struct_def.fixed) {
std::string annotations = "@param {flatbuffers.Builder} builder\n";
std::string arguments;
GenStructArgs(struct_def, &annotations, &arguments, "");
GenDocComment(code_ptr, annotations +
"@returns {flatbuffers.Offset}");
code += object_name + ".create" + struct_def.name + " = function(builder";
code += arguments + ") {\n";
GenStructBody(struct_def, &code, "");
code += " return builder.offset();\n};\n\n";
} else {
// Generate a method to start building a new object
GenDocComment(code_ptr,
"@param {flatbuffers.Builder} builder");
code += object_name + ".start" + struct_def.name;
code += " = function(builder) {\n";
code += " builder.startObject(" + NumToString(
struct_def.fields.vec.size()) + ");\n";
code += "};\n\n";
// Generate a set of static methods that allow table construction
for (auto it = struct_def.fields.vec.begin();
it != struct_def.fields.vec.end(); ++it) {
auto &field = **it;
if (field.deprecated) continue;
auto argname = MakeCamel(field.name, false);
if (!IsScalar(field.value.type.base_type)) {
argname += "Offset";
}
// Generate the field insertion method
GenDocComment(code_ptr,
"@param {flatbuffers.Builder} builder\n"
"@param {" + GenTypeName(field.value.type, true) + "} " +
argname);
code += object_name + ".add" + MakeCamel(field.name);
code += " = function(builder, " + argname + ") {\n";
code += " builder.addField" + GenWriteMethod(field.value.type) + "(";
code += NumToString(it - struct_def.fields.vec.begin()) + ", ";
if (field.value.type.base_type == BASE_TYPE_BOOL) {
code += "+";
}
code += argname + ", ";
if (!IsScalar(field.value.type.base_type)) {
code += "0";
} else {
if (field.value.type.base_type == BASE_TYPE_BOOL) {
code += "+";
}
code += GenDefaultValue(field.value);
}
code += ");\n};\n\n";
if (field.value.type.base_type == BASE_TYPE_VECTOR) {
auto vector_type = field.value.type.VectorType();
auto alignment = InlineAlignment(vector_type);
auto elem_size = InlineSize(vector_type);
// Generate a method to create a vector from a JavaScript array
if (!IsStruct(vector_type)) {
GenDocComment(code_ptr,
"@param {flatbuffers.Builder} builder\n"
"@param {Array.<" + GenTypeName(vector_type, true) +
">} data\n"
"@returns {flatbuffers.Offset}");
code += object_name + ".create" + MakeCamel(field.name);
code += "Vector = function(builder, data) {\n";
code += " builder.startVector(" + NumToString(elem_size);
code += ", data.length, " + NumToString(alignment) + ");\n";
code += " for (var i = data.length - 1; i >= 0; i--) {\n";
code += " builder.add" + GenWriteMethod(vector_type) + "(";
if (vector_type.base_type == BASE_TYPE_BOOL) {
code += "+";
}
code += "data[i]);\n";
code += " }\n";
code += " return builder.endVector();\n";
code += "};\n\n";
}
// Generate a method to start a vector, data to be added manually after
GenDocComment(code_ptr,
"@param {flatbuffers.Builder} builder\n"
"@param {number} numElems");
code += object_name + ".start" + MakeCamel(field.name);
code += "Vector = function(builder, numElems) {\n";
code += " builder.startVector(" + NumToString(elem_size);
code += ", numElems, " + NumToString(alignment) + ");\n";
code += "};\n\n";
}
}
// Generate a method to stop building a new object
GenDocComment(code_ptr,
"@param {flatbuffers.Builder} builder\n"
"@returns {flatbuffers.Offset}");
code += object_name + ".end" + struct_def.name;
code += " = function(builder) {\n";
code += " var offset = builder.endObject();\n";
for (auto it = struct_def.fields.vec.begin();
it != struct_def.fields.vec.end(); ++it) {
auto &field = **it;
if (!field.deprecated && field.required) {
code += " builder.requiredField(offset, ";
code += NumToString(field.value.offset);
code += "); // " + field.name + "\n";
}
}
code += " return offset;\n";
code += "};\n\n";
// Generate the method to complete buffer construction
if (parser.root_struct_def_ == &struct_def) {
GenDocComment(code_ptr,
"@param {flatbuffers.Builder} builder\n"
"@param {flatbuffers.Offset} offset");
code += object_name + ".finish" + struct_def.name + "Buffer";
code += " = function(builder, offset) {\n";
code += " builder.finish(offset";
if (!parser.file_identifier_.empty()) {
code += ", '" + parser.file_identifier_ + "'";
}
code += ");\n";
code += "};\n\n";
}
}
}
} // namespace js
// Iterate through all definitions we haven't generate code for (enums, structs,
// and tables) and output them to a single file.
std::string GenerateJS(const Parser &parser,
const GeneratorOptions &opts) {
using namespace js;
// Generate code for all the enum declarations.
std::string enum_code, exports_code;
for (auto it = parser.enums_.vec.begin();
it != parser.enums_.vec.end(); ++it) {
GenEnum(**it, &enum_code, &exports_code);
}
// Generate code for all structs, then all tables.
std::string decl_code;
for (auto it = parser.structs_.vec.begin();
it != parser.structs_.vec.end(); ++it) {
GenStruct(parser, **it, &decl_code, &exports_code);
}
// Only output file-level code if there were any declarations.
if (enum_code.length() || decl_code.length()) {
std::string code;
code = "// automatically generated by the FlatBuffers compiler,"
" do not modify\n\n";
// Generate code for all the namespace declarations.
GenNamespaces(parser, &code, &exports_code);
// Output the main declaration code from above.
code += enum_code;
code += decl_code;
if (!exports_code.empty() && !opts.skip_js_exports) {
code += "// Exports for Node.js and RequireJS\n";
code += exports_code;
}
return code;
}
return std::string();
}
static std::string GeneratedFileName(const std::string &path,
const std::string &file_name) {
return path + file_name + "_generated.js";
}
bool GenerateJS(const Parser &parser,
const std::string &path,
const std::string &file_name,
const GeneratorOptions &opts) {
auto code = GenerateJS(parser, opts);
return !code.length() ||
SaveFile(GeneratedFileName(path, file_name).c_str(), code, false);
}
std::string JSMakeRule(const Parser &parser,
const std::string &path,
const std::string &file_name,
const GeneratorOptions & /*opts*/) {
std::string filebase = flatbuffers::StripPath(
flatbuffers::StripExtension(file_name));
std::string make_rule = GeneratedFileName(path, filebase) + ": ";
auto included_files = parser.GetIncludedFilesRecursive(file_name);
for (auto it = included_files.begin();
it != included_files.end(); ++it) {
make_rule += " " + *it;
}
return make_rule;
}
} // namespace flatbuffers

662
src/idl_gen_python.cpp Normal file
View File

@@ -0,0 +1,662 @@
/*
* Copyright 2014 Google Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// independent from idl_parser, since this code is not needed for most clients
#include <string>
#include "flatbuffers/flatbuffers.h"
#include "flatbuffers/idl.h"
#include "flatbuffers/util.h"
namespace flatbuffers {
namespace python {
static std::string GenGetter(const Type &type);
static std::string GenMethod(const FieldDef &field);
static void GenStructBuilder(const StructDef &struct_def,
std::string *code_ptr);
static void GenReceiver(const StructDef &struct_def, std::string *code_ptr);
static std::string GenTypeBasic(const Type &type);
static std::string GenTypeGet(const Type &type);
static std::string TypeName(const FieldDef &field);
// Hardcode spaces per indentation.
const std::string Indent = " ";
// Most field accessors need to retrieve and test the field offset first,
// this is the prefix code for that.
std::string OffsetPrefix(const FieldDef &field) {
return "\n" + Indent + Indent +
"o = flatbuffers.number_types.UOffsetTFlags.py_type" +
"(self._tab.Offset(" +
NumToString(field.value.offset) +
"))\n" + Indent + Indent + "if o != 0:\n";
}
// Begin by declaring namespace and imports.
static void BeginFile(const std::string name_space_name,
const bool needs_imports,
std::string *code_ptr) {
std::string &code = *code_ptr;
code += "# automatically generated, do not modify\n\n";
code += "# namespace: " + name_space_name + "\n\n";
if (needs_imports) {
code += "import flatbuffers\n\n";
}
}
// Begin a class declaration.
static void BeginClass(const StructDef &struct_def, std::string *code_ptr) {
std::string &code = *code_ptr;
code += "class " + struct_def.name + "(object):\n";
code += Indent + "__slots__ = ['_tab']";
code += "\n\n";
}
// Begin enum code with a class declaration.
static void BeginEnum(const std::string class_name, std::string *code_ptr) {
std::string &code = *code_ptr;
code += "class " + class_name + "(object):\n";
}
// A single enum member.
static void EnumMember(const EnumVal ev, std::string *code_ptr) {
std::string &code = *code_ptr;
code += Indent;
code += ev.name;
code += " = ";
code += NumToString(ev.value) + "\n";
}
// End enum code.
static void EndEnum(std::string *code_ptr) {
std::string &code = *code_ptr;
code += "\n";
}
// Initialize a new struct or table from existing data.
static void NewRootTypeFromBuffer(const StructDef &struct_def,
std::string *code_ptr) {
std::string &code = *code_ptr;
code += Indent + "@classmethod\n";
code += Indent + "def GetRootAs";
code += struct_def.name;
code += "(cls, buf, offset):";
code += "\n";
code += Indent + Indent;
code += "n = flatbuffers.encode.Get";
code += "(flatbuffers.packer.uoffset, buf, offset)\n";
code += Indent + Indent + "x = " + struct_def.name + "()\n";
code += Indent + Indent + "x.Init(buf, n + offset)\n";
code += Indent + Indent + "return x\n";
code += "\n\n";
}
// Initialize an existing object with other data, to avoid an allocation.
static void InitializeExisting(const StructDef &struct_def,
std::string *code_ptr) {
std::string &code = *code_ptr;
GenReceiver(struct_def, code_ptr);
code += "Init(self, buf, pos):\n";
code += Indent + Indent + "self._tab = flatbuffers.table.Table(buf, pos)\n";
code += "\n";
}
// Get the length of a vector.
static void GetVectorLen(const StructDef &struct_def,
const FieldDef &field,
std::string *code_ptr) {
std::string &code = *code_ptr;
GenReceiver(struct_def, code_ptr);
code += MakeCamel(field.name) + "Length(self";
code += "):" + OffsetPrefix(field);
code += Indent + Indent + Indent + "return self._tab.VectorLen(o)\n";
code += Indent + Indent + "return 0\n\n";
}
// Get the value of a struct's scalar.
static void GetScalarFieldOfStruct(const StructDef &struct_def,
const FieldDef &field,
std::string *code_ptr) {
std::string &code = *code_ptr;
std::string getter = GenGetter(field.value.type);
GenReceiver(struct_def, code_ptr);
code += MakeCamel(field.name);
code += "(self): return " + getter;
code += "self._tab.Pos + flatbuffers.number_types.UOffsetTFlags.py_type(";
code += NumToString(field.value.offset) + "))\n";
}
// Get the value of a table's scalar.
static void GetScalarFieldOfTable(const StructDef &struct_def,
const FieldDef &field,
std::string *code_ptr) {
std::string &code = *code_ptr;
std::string getter = GenGetter(field.value.type);
GenReceiver(struct_def, code_ptr);
code += MakeCamel(field.name);
code += "(self):";
code += OffsetPrefix(field);
code += Indent + Indent + Indent + "return " + getter;
code += "o + self._tab.Pos)\n";
code += Indent + Indent + "return " + field.value.constant + "\n\n";
}
// Get a struct by initializing an existing struct.
// Specific to Struct.
static void GetStructFieldOfStruct(const StructDef &struct_def,
const FieldDef &field,
std::string *code_ptr) {
std::string &code = *code_ptr;
GenReceiver(struct_def, code_ptr);
code += MakeCamel(field.name);
code += "(self, obj):\n";
code += Indent + Indent + "obj.Init(self._tab.Bytes, self._tab.Pos + ";
code += NumToString(field.value.offset) + ")";
code += "\n" + Indent + Indent + "return obj\n\n";
}
// Get a struct by initializing an existing struct.
// Specific to Table.
static void GetStructFieldOfTable(const StructDef &struct_def,
const FieldDef &field,
std::string *code_ptr) {
std::string &code = *code_ptr;
GenReceiver(struct_def, code_ptr);
code += MakeCamel(field.name);
code += "(self):";
code += OffsetPrefix(field);
if (field.value.type.struct_def->fixed) {
code += Indent + Indent + Indent + "x = o + self._tab.Pos\n";
} else {
code += Indent + Indent + Indent;
code += "x = self._tab.Indirect(o + self._tab.Pos)\n";
}
code += Indent + Indent + Indent;
code += "from ." + TypeName(field) + " import " + TypeName(field) + "\n";
code += Indent + Indent + Indent + "obj = " + TypeName(field) + "()\n";
code += Indent + Indent + Indent + "obj.Init(self._tab.Bytes, x)\n";
code += Indent + Indent + Indent + "return obj\n";
code += Indent + Indent + "return None\n\n";
}
// Get the value of a string.
static void GetStringField(const StructDef &struct_def,
const FieldDef &field,
std::string *code_ptr) {
std::string &code = *code_ptr;
GenReceiver(struct_def, code_ptr);
code += MakeCamel(field.name);
code += "(self):";
code += OffsetPrefix(field);
code += Indent + Indent + Indent + "return " + GenGetter(field.value.type);
code += "o + self._tab.Pos)\n";
code += Indent + Indent + "return \"\"\n\n";
}
// Get the value of a union from an object.
static void GetUnionField(const StructDef &struct_def,
const FieldDef &field,
std::string *code_ptr) {
std::string &code = *code_ptr;
GenReceiver(struct_def, code_ptr);
code += MakeCamel(field.name) + "(self):";
code += OffsetPrefix(field);
// TODO(rw): this works and is not the good way to it:
bool is_native_table = TypeName(field) == "*flatbuffers.Table";
if (is_native_table) {
code += Indent + Indent + Indent + "from flatbuffers.table import Table\n";
} else {
code += Indent + Indent + Indent;
code += "from ." + TypeName(field) + " import " + TypeName(field) + "\n";
}
code += Indent + Indent + Indent + "obj = Table(bytearray(), 0)\n";
code += Indent + Indent + Indent + GenGetter(field.value.type);
code += "obj, o)\n" + Indent + Indent + Indent + "return obj\n";
code += Indent + Indent + "return None\n\n";
}
// Get the value of a vector's struct member.
static void GetMemberOfVectorOfStruct(const StructDef &struct_def,
const FieldDef &field,
std::string *code_ptr) {
std::string &code = *code_ptr;
auto vectortype = field.value.type.VectorType();
GenReceiver(struct_def, code_ptr);
code += MakeCamel(field.name);
code += "(self, j):" + OffsetPrefix(field);
code += Indent + Indent + Indent + "x = self._tab.Vector(o)\n";
code += Indent + Indent + Indent;
code += "x += flatbuffers.number_types.UOffsetTFlags.py_type(j) * ";
code += NumToString(InlineSize(vectortype)) + "\n";
if (!(vectortype.struct_def->fixed)) {
code += Indent + Indent + Indent + "x = self._tab.Indirect(x)\n";
}
code += Indent + Indent + Indent;
code += "from ." + TypeName(field) + " import " + TypeName(field) + "\n";
code += Indent + Indent + Indent + "obj = " + TypeName(field) + "()\n";
code += Indent + Indent + Indent + "obj.Init(self._tab.Bytes, x)\n";
code += Indent + Indent + Indent + "return obj\n";
code += Indent + Indent + "return None\n\n";
}
// Get the value of a vector's non-struct member. Uses a named return
// argument to conveniently set the zero value for the result.
static void GetMemberOfVectorOfNonStruct(const StructDef &struct_def,
const FieldDef &field,
std::string *code_ptr) {
std::string &code = *code_ptr;
auto vectortype = field.value.type.VectorType();
GenReceiver(struct_def, code_ptr);
code += MakeCamel(field.name);
code += "(self, j):";
code += OffsetPrefix(field);
code += Indent + Indent + Indent + "a = self._tab.Vector(o)\n";
code += Indent + Indent + Indent;
code += "return " + GenGetter(field.value.type);
code += "a + flatbuffers.number_types.UOffsetTFlags.py_type(j * ";
code += NumToString(InlineSize(vectortype)) + "))\n";
if (vectortype.base_type == BASE_TYPE_STRING) {
code += Indent + Indent + "return \"\"\n";
} else {
code += Indent + Indent + "return 0\n";
}
code += "\n";
}
// Begin the creator function signature.
static void BeginBuilderArgs(const StructDef &struct_def,
std::string *code_ptr) {
std::string &code = *code_ptr;
code += "\n";
code += "def Create" + struct_def.name;
code += "(builder";
}
// Recursively generate arguments for a constructor, to deal with nested
// structs.
static void StructBuilderArgs(const StructDef &struct_def,
const char *nameprefix,
std::string *code_ptr) {
for (auto it = struct_def.fields.vec.begin();
it != struct_def.fields.vec.end();
++it) {
auto &field = **it;
if (IsStruct(field.value.type)) {
// Generate arguments for a struct inside a struct. To ensure names
// don't clash, and to make it obvious these arguments are constructing
// a nested struct, prefix the name with the field name.
StructBuilderArgs(*field.value.type.struct_def,
(nameprefix + (field.name + "_")).c_str(),
code_ptr);
} else {
std::string &code = *code_ptr;
code += (std::string)", " + nameprefix;
code += MakeCamel(field.name, false);
}
}
}
// End the creator function signature.
static void EndBuilderArgs(std::string *code_ptr) {
std::string &code = *code_ptr;
code += "):\n";
}
// Recursively generate struct construction statements and instert manual
// padding.
static void StructBuilderBody(const StructDef &struct_def,
const char *nameprefix,
std::string *code_ptr) {
std::string &code = *code_ptr;
code += " builder.Prep(" + NumToString(struct_def.minalign) + ", ";
code += NumToString(struct_def.bytesize) + ")\n";
for (auto it = struct_def.fields.vec.rbegin();
it != struct_def.fields.vec.rend();
++it) {
auto &field = **it;
if (field.padding)
code += " builder.Pad(" + NumToString(field.padding) + ")\n";
if (IsStruct(field.value.type)) {
StructBuilderBody(*field.value.type.struct_def,
(nameprefix + (field.name + "_")).c_str(),
code_ptr);
} else {
code += " builder.Prepend" + GenMethod(field) + "(";
code += nameprefix + MakeCamel(field.name, false) + ")\n";
}
}
}
static void EndBuilderBody(std::string *code_ptr) {
std::string &code = *code_ptr;
code += " return builder.Offset()\n";
}
// Get the value of a table's starting offset.
static void GetStartOfTable(const StructDef &struct_def,
std::string *code_ptr) {
std::string &code = *code_ptr;
code += "def " + struct_def.name + "Start";
code += "(builder): ";
code += "builder.StartObject(";
code += NumToString(struct_def.fields.vec.size());
code += ")\n";
}
// Set the value of a table's field.
static void BuildFieldOfTable(const StructDef &struct_def,
const FieldDef &field,
const size_t offset,
std::string *code_ptr) {
std::string &code = *code_ptr;
code += "def " + struct_def.name + "Add" + MakeCamel(field.name);
code += "(builder, ";
code += MakeCamel(field.name, false);
code += "): ";
code += "builder.Prepend";
code += GenMethod(field) + "Slot(";
code += NumToString(offset) + ", ";
if (!IsScalar(field.value.type.base_type) && (!struct_def.fixed)) {
code += "flatbuffers.number_types.UOffsetTFlags.py_type";
code += "(";
code += MakeCamel(field.name, false) + ")";
} else {
code += MakeCamel(field.name, false);
}
code += ", " + field.value.constant;
code += ")\n";
}
// Set the value of one of the members of a table's vector.
static void BuildVectorOfTable(const StructDef &struct_def,
const FieldDef &field,
std::string *code_ptr) {
std::string &code = *code_ptr;
code += "def " + struct_def.name + "Start";
code += MakeCamel(field.name);
code += "Vector(builder, numElems): return builder.StartVector(";
auto vector_type = field.value.type.VectorType();
auto alignment = InlineAlignment(vector_type);
auto elem_size = InlineSize(vector_type);
code += NumToString(elem_size);
code += ", numElems, " + NumToString(alignment);
code += ")\n";
}
// Get the offset of the end of a table.
static void GetEndOffsetOnTable(const StructDef &struct_def,
std::string *code_ptr) {
std::string &code = *code_ptr;
code += "def " + struct_def.name + "End";
code += "(builder): ";
code += "return builder.EndObject()\n";
}
// Generate the receiver for function signatures.
static void GenReceiver(const StructDef &struct_def, std::string *code_ptr) {
std::string &code = *code_ptr;
code += Indent + "# " + struct_def.name + "\n";
code += Indent + "def ";
}
// Generate a struct field, conditioned on its child type(s).
static void GenStructAccessor(const StructDef &struct_def,
const FieldDef &field,
std::string *code_ptr) {
GenComment(field.doc_comment, code_ptr, nullptr, "# ");
if (IsScalar(field.value.type.base_type)) {
if (struct_def.fixed) {
GetScalarFieldOfStruct(struct_def, field, code_ptr);
} else {
GetScalarFieldOfTable(struct_def, field, code_ptr);
}
} else {
switch (field.value.type.base_type) {
case BASE_TYPE_STRUCT:
if (struct_def.fixed) {
GetStructFieldOfStruct(struct_def, field, code_ptr);
} else {
GetStructFieldOfTable(struct_def, field, code_ptr);
}
break;
case BASE_TYPE_STRING:
GetStringField(struct_def, field, code_ptr);
break;
case BASE_TYPE_VECTOR: {
auto vectortype = field.value.type.VectorType();
if (vectortype.base_type == BASE_TYPE_STRUCT) {
GetMemberOfVectorOfStruct(struct_def, field, code_ptr);
} else {
GetMemberOfVectorOfNonStruct(struct_def, field, code_ptr);
}
break;
}
case BASE_TYPE_UNION:
GetUnionField(struct_def, field, code_ptr);
break;
default:
assert(0);
}
}
if (field.value.type.base_type == BASE_TYPE_VECTOR) {
GetVectorLen(struct_def, field, code_ptr);
}
}
// Generate table constructors, conditioned on its members' types.
static void GenTableBuilders(const StructDef &struct_def,
std::string *code_ptr) {
GetStartOfTable(struct_def, code_ptr);
for (auto it = struct_def.fields.vec.begin();
it != struct_def.fields.vec.end();
++it) {
auto &field = **it;
if (field.deprecated) continue;
auto offset = it - struct_def.fields.vec.begin();
BuildFieldOfTable(struct_def, field, offset, code_ptr);
if (field.value.type.base_type == BASE_TYPE_VECTOR) {
BuildVectorOfTable(struct_def, field, code_ptr);
}
}
GetEndOffsetOnTable(struct_def, code_ptr);
}
// Generate struct or table methods.
static void GenStruct(const StructDef &struct_def,
std::string *code_ptr,
StructDef *root_struct_def) {
if (struct_def.generated) return;
GenComment(struct_def.doc_comment, code_ptr, nullptr, "# ");
BeginClass(struct_def, code_ptr);
if (&struct_def == root_struct_def) {
// Generate a special accessor for the table that has been declared as
// the root type.
NewRootTypeFromBuffer(struct_def, code_ptr);
}
// Generate the Init method that sets the field in a pre-existing
// accessor object. This is to allow object reuse.
InitializeExisting(struct_def, code_ptr);
for (auto it = struct_def.fields.vec.begin();
it != struct_def.fields.vec.end();
++it) {
auto &field = **it;
if (field.deprecated) continue;
GenStructAccessor(struct_def, field, code_ptr);
}
if (struct_def.fixed) {
// create a struct constructor function
GenStructBuilder(struct_def, code_ptr);
} else {
// Create a set of functions that allow table construction.
GenTableBuilders(struct_def, code_ptr);
}
}
// Generate enum declarations.
static void GenEnum(const EnumDef &enum_def, std::string *code_ptr) {
if (enum_def.generated) return;
GenComment(enum_def.doc_comment, code_ptr, nullptr, "# ");
BeginEnum(enum_def.name, code_ptr);
for (auto it = enum_def.vals.vec.begin();
it != enum_def.vals.vec.end();
++it) {
auto &ev = **it;
GenComment(ev.doc_comment, code_ptr, nullptr, "# ");
EnumMember(ev, code_ptr);
}
EndEnum(code_ptr);
}
// Returns the function name that is able to read a value of the given type.
static std::string GenGetter(const Type &type) {
switch (type.base_type) {
case BASE_TYPE_STRING: return "self._tab.String(";
case BASE_TYPE_UNION: return "self._tab.Union(";
case BASE_TYPE_VECTOR: return GenGetter(type.VectorType());
default:
return "self._tab.Get(flatbuffers.number_types." + \
MakeCamel(GenTypeGet(type)) + \
"Flags, ";
}
}
// Returns the method name for use with add/put calls.
static std::string GenMethod(const FieldDef &field) {
return IsScalar(field.value.type.base_type)
? MakeCamel(GenTypeBasic(field.value.type))
: (IsStruct(field.value.type) ? "Struct" : "UOffsetTRelative");
}
// Save out the generated code for a Python Table type.
static bool SaveType(const Parser &parser, const Definition &def,
const std::string &classcode, const std::string &path,
bool needs_imports) {
if (!classcode.length()) return true;
std::string namespace_name;
std::string namespace_dir = path;
auto &namespaces = parser.namespaces_.back()->components;
for (auto it = namespaces.begin(); it != namespaces.end(); ++it) {
if (namespace_name.length()) {
namespace_name += ".";
namespace_dir += kPathSeparator;
}
namespace_name = *it;
namespace_dir += *it;
EnsureDirExists(namespace_dir.c_str());
std::string init_py_filename = namespace_dir + "/__init__.py";
SaveFile(init_py_filename.c_str(), "", false);
}
std::string code = "";
BeginFile(namespace_name, needs_imports, &code);
code += classcode;
std::string filename = namespace_dir + kPathSeparator + def.name + ".py";
return SaveFile(filename.c_str(), code, false);
}
static std::string GenTypeBasic(const Type &type) {
static const char *ctypename[] = {
#define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \
#PTYPE,
FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
#undef FLATBUFFERS_TD
};
return ctypename[type.base_type];
}
static std::string GenTypePointer(const Type &type) {
switch (type.base_type) {
case BASE_TYPE_STRING:
return "string";
case BASE_TYPE_VECTOR:
return GenTypeGet(type.VectorType());
case BASE_TYPE_STRUCT:
return type.struct_def->name;
case BASE_TYPE_UNION:
// fall through
default:
return "*flatbuffers.Table";
}
}
static std::string GenTypeGet(const Type &type) {
return IsScalar(type.base_type)
? GenTypeBasic(type)
: GenTypePointer(type);
}
static std::string TypeName(const FieldDef &field) {
return GenTypeGet(field.value.type);
}
// Create a struct with a builder and the struct's arguments.
static void GenStructBuilder(const StructDef &struct_def,
std::string *code_ptr) {
BeginBuilderArgs(struct_def, code_ptr);
StructBuilderArgs(struct_def, "", code_ptr);
EndBuilderArgs(code_ptr);
StructBuilderBody(struct_def, "", code_ptr);
EndBuilderBody(code_ptr);
}
} // namespace python
bool GeneratePython(const Parser &parser,
const std::string &path,
const std::string & /*file_name*/,
const GeneratorOptions & /*opts*/) {
for (auto it = parser.enums_.vec.begin();
it != parser.enums_.vec.end(); ++it) {
std::string enumcode;
python::GenEnum(**it, &enumcode);
if (!python::SaveType(parser, **it, enumcode, path, false))
return false;
}
for (auto it = parser.structs_.vec.begin();
it != parser.structs_.vec.end(); ++it) {
std::string declcode;
python::GenStruct(**it, &declcode, parser.root_struct_def_);
if (!python::SaveType(parser, **it, declcode, path, true))
return false;
}
return true;
}
} // namespace flatbuffers

View File

@@ -60,7 +60,12 @@ template<typename T> void Print(T val, Type type, int /*indent*/,
return;
}
}
text += NumToString(val);
if (type.base_type == BASE_TYPE_BOOL) {
text += val != 0 ? "true" : "false";
} else {
text += NumToString(val);
}
}
// Print a vector a sequence of JSON values, comma separated, wrapped in "[]".
@@ -80,7 +85,7 @@ template<typename T> void PrintVector(const Vector<T> &v, Type type,
Print(v.GetStructFromOffset(i * type.struct_def->bytesize), type,
indent + Indent(opts), nullptr, opts, _text);
else
Print(v.Get(i), type, indent + Indent(opts), nullptr,
Print(v[i], type, indent + Indent(opts), nullptr,
opts, _text);
}
text += NewLine(opts);
@@ -92,7 +97,7 @@ static void EscapeString(const String &s, std::string *_text) {
std::string &text = *_text;
text += "\"";
for (uoffset_t i = 0; i < s.size(); i++) {
char c = s.Get(i);
char c = s[i];
switch (c) {
case '\n': text += "\\n"; break;
case '\t': text += "\\t"; break;
@@ -159,7 +164,8 @@ template<> void Print<const void *>(const void *val,
type = type.VectorType();
// Call PrintVector above specifically for each element type:
switch (type.base_type) {
#define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE) \
#define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, \
PTYPE) \
case BASE_TYPE_ ## ENUM: \
PrintVector<CTYPE>( \
*reinterpret_cast<const Vector<CTYPE> *>(val), \
@@ -215,8 +221,11 @@ static void GenStruct(const StructDef &struct_def, const Table *table,
it != struct_def.fields.vec.end();
++it) {
FieldDef &fd = **it;
if (struct_def.fixed || table->CheckField(fd.value.offset)) {
// The field is present.
auto is_present = struct_def.fixed || table->CheckField(fd.value.offset);
auto output_anyway = opts.output_default_scalars_in_json &&
IsScalar(fd.value.type.base_type) &&
!fd.deprecated;
if (is_present || output_anyway) {
if (fieldout++) {
text += ",";
}
@@ -224,28 +233,36 @@ static void GenStruct(const StructDef &struct_def, const Table *table,
text.append(indent + Indent(opts), ' ');
OutputIdentifier(fd.name, opts, _text);
text += ": ";
switch (fd.value.type.base_type) {
#define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE) \
case BASE_TYPE_ ## ENUM: \
GenField<CTYPE>(fd, table, struct_def.fixed, \
opts, indent + Indent(opts), _text); \
if (is_present) {
switch (fd.value.type.base_type) {
#define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, \
PTYPE) \
case BASE_TYPE_ ## ENUM: \
GenField<CTYPE>(fd, table, struct_def.fixed, \
opts, indent + Indent(opts), _text); \
break;
FLATBUFFERS_GEN_TYPES_SCALAR(FLATBUFFERS_TD)
#undef FLATBUFFERS_TD
// Generate drop-thru case statements for all pointer types:
#define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, \
PTYPE) \
case BASE_TYPE_ ## ENUM:
FLATBUFFERS_GEN_TYPES_POINTER(FLATBUFFERS_TD)
#undef FLATBUFFERS_TD
GenFieldOffset(fd, table, struct_def.fixed, indent + Indent(opts),
union_sd, opts, _text);
break;
FLATBUFFERS_GEN_TYPES_SCALAR(FLATBUFFERS_TD)
#undef FLATBUFFERS_TD
// Generate drop-thru case statements for all pointer types:
#define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE) \
case BASE_TYPE_ ## ENUM:
FLATBUFFERS_GEN_TYPES_POINTER(FLATBUFFERS_TD)
#undef FLATBUFFERS_TD
GenFieldOffset(fd, table, struct_def.fixed, indent + Indent(opts),
union_sd, opts, _text);
break;
}
if (fd.value.type.base_type == BASE_TYPE_UTYPE) {
auto enum_val = fd.value.type.enum_def->ReverseLookup(
table->GetField<uint8_t>(fd.value.offset, 0));
assert(enum_val);
union_sd = enum_val->struct_def;
}
}
if (fd.value.type.base_type == BASE_TYPE_UTYPE) {
auto enum_val = fd.value.type.enum_def->ReverseLookup(
table->GetField<uint8_t>(fd.value.offset, 0));
assert(enum_val);
union_sd = enum_val->struct_def;
else
{
text += fd.value.constant;
}
}
}
@@ -258,9 +275,9 @@ static void GenStruct(const StructDef &struct_def, const Table *table,
void GenerateText(const Parser &parser, const void *flatbuffer,
const GeneratorOptions &opts, std::string *_text) {
std::string &text = *_text;
assert(parser.root_struct_def); // call SetRootType()
assert(parser.root_struct_def_); // call SetRootType()
text.reserve(1024); // Reduce amount of inevitable reallocs.
GenStruct(*parser.root_struct_def,
GenStruct(*parser.root_struct_def_,
GetRoot<Table>(flatbuffer),
0,
opts,
@@ -277,7 +294,7 @@ bool GenerateTextFile(const Parser &parser,
const std::string &path,
const std::string &file_name,
const GeneratorOptions &opts) {
if (!parser.builder_.GetSize() || !parser.root_struct_def) return true;
if (!parser.builder_.GetSize() || !parser.root_struct_def_) return true;
std::string text;
GenerateText(parser, parser.builder_.GetBufferPointer(), opts,
&text);
@@ -290,12 +307,12 @@ std::string TextMakeRule(const Parser &parser,
const std::string &path,
const std::string &file_name,
const GeneratorOptions & /*opts*/) {
if (!parser.builder_.GetSize() || !parser.root_struct_def) return "";
if (!parser.builder_.GetSize() || !parser.root_struct_def_) return "";
std::string filebase = flatbuffers::StripPath(
flatbuffers::StripExtension(file_name));
std::string make_rule = TextFileName(path, filebase) + ": " + file_name;
auto included_files = parser.GetIncludedFilesRecursive(
parser.root_struct_def->file);
parser.root_struct_def_->file);
for (auto it = included_files.begin();
it != included_files.end(); ++it) {
make_rule += " " + *it;

File diff suppressed because it is too large Load Diff

471
src/reflection.cpp Normal file
View File

@@ -0,0 +1,471 @@
/*
* Copyright 2015 Google Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "flatbuffers/reflection.h"
#include "flatbuffers/util.h"
// Helper functionality for reflection.
namespace flatbuffers {
int64_t GetAnyValueI(reflection::BaseType type, const uint8_t *data) {
# define FLATBUFFERS_GET(T) static_cast<int64_t>(ReadScalar<T>(data))
switch (type) {
case reflection::UType:
case reflection::Bool:
case reflection::UByte: return FLATBUFFERS_GET(uint8_t);
case reflection::Byte: return FLATBUFFERS_GET(int8_t);
case reflection::Short: return FLATBUFFERS_GET(int16_t);
case reflection::UShort: return FLATBUFFERS_GET(uint16_t);
case reflection::Int: return FLATBUFFERS_GET(int32_t);
case reflection::UInt: return FLATBUFFERS_GET(uint32_t);
case reflection::Long: return FLATBUFFERS_GET(int64_t);
case reflection::ULong: return FLATBUFFERS_GET(uint64_t);
case reflection::Float: return FLATBUFFERS_GET(float);
case reflection::Double: return FLATBUFFERS_GET(double);
case reflection::String: {
auto s = reinterpret_cast<const String *>(ReadScalar<uoffset_t>(data) +
data);
return s ? StringToInt(s->c_str()) : 0;
}
default: return 0; // Tables & vectors do not make sense.
}
# undef FLATBUFFERS_GET
}
double GetAnyValueF(reflection::BaseType type, const uint8_t *data) {
switch (type) {
case reflection::Float: return static_cast<double>(ReadScalar<float>(data));
case reflection::Double: return ReadScalar<double>(data);
case reflection::String: {
auto s = reinterpret_cast<const String *>(ReadScalar<uoffset_t>(data) +
data);
return s ? strtod(s->c_str(), nullptr) : 0.0;
}
default: return static_cast<double>(GetAnyValueI(type, data));
}
}
std::string GetAnyValueS(reflection::BaseType type, const uint8_t *data,
const reflection::Schema *schema, int type_index) {
switch (type) {
case reflection::Float:
case reflection::Double: return NumToString(GetAnyValueF(type, data));
case reflection::String: {
auto s = reinterpret_cast<const String *>(ReadScalar<uoffset_t>(data) +
data);
return s ? s->c_str() : "";
}
case reflection::Obj:
if (schema) {
// Convert the table to a string. This is mostly for debugging purposes,
// and does NOT promise to be JSON compliant.
// Also prefixes the type.
auto &objectdef = *schema->objects()->Get(type_index);
auto s = objectdef.name()->str();
if (objectdef.is_struct()) {
s += "(struct)"; // TODO: implement this as well.
} else {
auto table_field = reinterpret_cast<const Table *>(
ReadScalar<uoffset_t>(data) + data);
s += " { ";
auto fielddefs = objectdef.fields();
for (auto it = fielddefs->begin(); it != fielddefs->end(); ++it) {
auto &fielddef = **it;
if (!table_field->CheckField(fielddef.offset())) continue;
auto val = GetAnyFieldS(*table_field, fielddef, schema);
if (fielddef.type()->base_type() == reflection::String)
val = "\"" + val + "\""; // Doesn't deal with escape codes etc.
s += fielddef.name()->str();
s += ": ";
s += val;
s += ", ";
}
s += "}";
}
return s;
} else {
return "(table)";
}
case reflection::Vector:
return "[(elements)]"; // TODO: implement this as well.
case reflection::Union:
return "(union)"; // TODO: implement this as well.
default: return NumToString(GetAnyValueI(type, data));
}
}
void SetAnyValueI(reflection::BaseType type, uint8_t *data, int64_t val) {
# define FLATBUFFERS_SET(T) WriteScalar(data, static_cast<T>(val))
switch (type) {
case reflection::UType:
case reflection::Bool:
case reflection::UByte: FLATBUFFERS_SET(uint8_t ); break;
case reflection::Byte: FLATBUFFERS_SET(int8_t ); break;
case reflection::Short: FLATBUFFERS_SET(int16_t ); break;
case reflection::UShort: FLATBUFFERS_SET(uint16_t); break;
case reflection::Int: FLATBUFFERS_SET(int32_t ); break;
case reflection::UInt: FLATBUFFERS_SET(uint32_t); break;
case reflection::Long: FLATBUFFERS_SET(int64_t ); break;
case reflection::ULong: FLATBUFFERS_SET(uint64_t); break;
case reflection::Float: FLATBUFFERS_SET(float ); break;
case reflection::Double: FLATBUFFERS_SET(double ); break;
// TODO: support strings
default: break;
}
# undef FLATBUFFERS_SET
}
void SetAnyValueF(reflection::BaseType type, uint8_t *data, double val) {
switch (type) {
case reflection::Float: WriteScalar(data, static_cast<float>(val)); break;
case reflection::Double: WriteScalar(data, val); break;
// TODO: support strings.
default: SetAnyValueI(type, data, static_cast<int64_t>(val)); break;
}
}
void SetAnyValueS(reflection::BaseType type, uint8_t *data, const char *val) {
switch (type) {
case reflection::Float:
case reflection::Double:
SetAnyValueF(type, data, strtod(val, nullptr));
break;
// TODO: support strings.
default: SetAnyValueI(type, data, StringToInt(val)); break;
}
}
// Resize a FlatBuffer in-place by iterating through all offsets in the buffer
// and adjusting them by "delta" if they straddle the start offset.
// Once that is done, bytes can now be inserted/deleted safely.
// "delta" may be negative (shrinking).
// Unless "delta" is a multiple of the largest alignment, you'll create a small
// amount of garbage space in the buffer (usually 0..7 bytes).
// If your FlatBuffer's root table is not the schema's root table, you should
// pass in your root_table type as well.
class ResizeContext {
public:
ResizeContext(const reflection::Schema &schema, uoffset_t start, int delta,
std::vector<uint8_t> *flatbuf,
const reflection::Object *root_table = nullptr)
: schema_(schema), startptr_(flatbuf->data() + start),
delta_(delta), buf_(*flatbuf),
dag_check_(flatbuf->size() / sizeof(uoffset_t), false) {
auto mask = static_cast<int>(sizeof(largest_scalar_t) - 1);
delta_ = (delta_ + mask) & ~mask;
if (!delta_) return; // We can't shrink by less than largest_scalar_t.
// Now change all the offsets by delta_.
auto root = GetAnyRoot(buf_.data());
Straddle<uoffset_t, 1>(buf_.data(), root, buf_.data());
ResizeTable(root_table ? *root_table : *schema.root_table(), root);
// We can now add or remove bytes at start.
if (delta_ > 0) buf_.insert(buf_.begin() + start, delta_, 0);
else buf_.erase(buf_.begin() + start, buf_.begin() + start - delta_);
}
// Check if the range between first (lower address) and second straddles
// the insertion point. If it does, change the offset at offsetloc (of
// type T, with direction D).
template<typename T, int D> void Straddle(void *first, void *second,
void *offsetloc) {
if (first <= startptr_ && second >= startptr_) {
WriteScalar<T>(offsetloc, ReadScalar<T>(offsetloc) + delta_ * D);
DagCheck(offsetloc) = true;
}
}
// This returns a boolean that records if the corresponding offset location
// has been modified already. If so, we can't even read the corresponding
// offset, since it is pointing to a location that is illegal until the
// resize actually happens.
// This must be checked for every offset, since we can't know which offsets
// will straddle and which won't.
uint8_t &DagCheck(void *offsetloc) {
auto dag_idx = reinterpret_cast<uoffset_t *>(offsetloc) -
reinterpret_cast<uoffset_t *>(buf_.data());
return dag_check_[dag_idx];
}
void ResizeTable(const reflection::Object &objectdef, Table *table) {
if (DagCheck(table))
return; // Table already visited.
auto vtable = table->GetVTable();
// Check if the vtable offset points beyond the insertion point.
Straddle<soffset_t, -1>(table, vtable, table);
// This direction shouldn't happen because vtables that sit before tables
// are always directly adjacent, but check just in case we ever change the
// way flatbuffers are built.
Straddle<soffset_t, -1>(vtable, table, table);
// Early out: since all fields inside the table must point forwards in
// memory, if the insertion point is before the table we can stop here.
auto tableloc = reinterpret_cast<uint8_t *>(table);
if (startptr_ <= tableloc) return;
// Check each field.
auto fielddefs = objectdef.fields();
for (auto it = fielddefs->begin(); it != fielddefs->end(); ++it) {
auto &fielddef = **it;
auto base_type = fielddef.type()->base_type();
// Ignore scalars.
if (base_type <= reflection::Double) continue;
// Ignore fields that are not stored.
auto offset = table->GetOptionalFieldOffset(fielddef.offset());
if (!offset) continue;
// Ignore structs.
auto subobjectdef = base_type == reflection::Obj ?
schema_.objects()->Get(fielddef.type()->index()) : nullptr;
if (subobjectdef && subobjectdef->is_struct()) continue;
// Get this fields' offset, and read it if safe.
auto offsetloc = tableloc + offset;
if (DagCheck(offsetloc))
continue; // This offset already visited.
auto ref = offsetloc + ReadScalar<uoffset_t>(offsetloc);
Straddle<uoffset_t, 1>(offsetloc, ref, offsetloc);
// Recurse.
switch (base_type) {
case reflection::Obj: {
ResizeTable(*subobjectdef, reinterpret_cast<Table *>(ref));
break;
}
case reflection::Vector: {
auto elem_type = fielddef.type()->element();
if (elem_type != reflection::Obj && elem_type != reflection::String)
break;
auto vec = reinterpret_cast<Vector<uoffset_t> *>(ref);
auto elemobjectdef = elem_type == reflection::Obj
? schema_.objects()->Get(fielddef.type()->index())
: nullptr;
if (elemobjectdef && elemobjectdef->is_struct()) break;
for (uoffset_t i = 0; i < vec->size(); i++) {
auto loc = vec->Data() + i * sizeof(uoffset_t);
if (DagCheck(loc))
continue; // This offset already visited.
auto dest = loc + vec->Get(i);
Straddle<uoffset_t, 1>(loc, dest ,loc);
if (elemobjectdef)
ResizeTable(*elemobjectdef, reinterpret_cast<Table *>(dest));
}
break;
}
case reflection::Union: {
ResizeTable(GetUnionType(schema_, objectdef, fielddef, *table),
reinterpret_cast<Table *>(ref));
break;
}
case reflection::String:
break;
default:
assert(false);
}
}
}
void operator=(const ResizeContext &rc);
private:
const reflection::Schema &schema_;
uint8_t *startptr_;
int delta_;
std::vector<uint8_t> &buf_;
std::vector<uint8_t> dag_check_;
};
void SetString(const reflection::Schema &schema, const std::string &val,
const String *str, std::vector<uint8_t> *flatbuf,
const reflection::Object *root_table) {
auto delta = static_cast<int>(val.size()) - static_cast<int>(str->Length());
auto start = static_cast<uoffset_t>(reinterpret_cast<const uint8_t *>(str) -
flatbuf->data() +
sizeof(uoffset_t));
if (delta) {
// Clear the old string, since we don't want parts of it remaining.
memset(flatbuf->data() + start, 0, str->Length());
// Different size, we must expand (or contract).
ResizeContext(schema, start, delta, flatbuf, root_table);
}
// Copy new data. Safe because we created the right amount of space.
memcpy(flatbuf->data() + start, val.c_str(), val.size() + 1);
}
uint8_t *ResizeAnyVector(const reflection::Schema &schema, uoffset_t newsize,
const VectorOfAny *vec, uoffset_t num_elems,
uoffset_t elem_size, std::vector<uint8_t> *flatbuf,
const reflection::Object *root_table) {
auto delta_elem = static_cast<int>(newsize) - static_cast<int>(num_elems);
auto delta_bytes = delta_elem * static_cast<int>(elem_size);
auto vec_start = reinterpret_cast<const uint8_t *>(vec) - flatbuf->data();
auto start = static_cast<uoffset_t>(vec_start + sizeof(uoffset_t) +
elem_size * num_elems);
if (delta_bytes) {
if (delta_elem < 0) {
// Clear elements we're throwing away, since some might remain in the
// buffer.
auto size_clear = -delta_elem * elem_size;
memset(flatbuf->data() + start - size_clear, 0, size_clear);
}
ResizeContext(schema, start, delta_bytes, flatbuf, root_table);
WriteScalar(flatbuf->data() + vec_start, newsize); // Length field.
// Set new elements to 0.. this can be overwritten by the caller.
if (delta_elem > 0) {
memset(flatbuf->data() + start, 0, delta_elem * elem_size);
}
}
return flatbuf->data() + start;
}
const uint8_t *AddFlatBuffer(std::vector<uint8_t> &flatbuf,
const uint8_t *newbuf, size_t newlen) {
// Align to sizeof(uoffset_t) past sizeof(largest_scalar_t) since we're
// going to chop off the root offset.
while ((flatbuf.size() & (sizeof(uoffset_t) - 1)) ||
!(flatbuf.size() & (sizeof(largest_scalar_t) - 1))) {
flatbuf.push_back(0);
}
auto insertion_point = static_cast<uoffset_t>(flatbuf.size());
// Insert the entire FlatBuffer minus the root pointer.
flatbuf.insert(flatbuf.end(), newbuf + sizeof(uoffset_t), newbuf + newlen);
auto root_offset = ReadScalar<uoffset_t>(newbuf) - sizeof(uoffset_t);
return flatbuf.data() + insertion_point + root_offset;
}
void CopyInline(FlatBufferBuilder &fbb, const reflection::Field &fielddef,
const Table &table, size_t align, size_t size) {
fbb.Align(align);
fbb.PushBytes(table.GetStruct<const uint8_t *>(fielddef.offset()), size);
fbb.TrackField(fielddef.offset(), fbb.GetSize());
}
Offset<const Table *> CopyTable(FlatBufferBuilder &fbb,
const reflection::Schema &schema,
const reflection::Object &objectdef,
const Table &table) {
// Before we can construct the table, we have to first generate any
// subobjects, and collect their offsets.
std::vector<uoffset_t> offsets;
auto fielddefs = objectdef.fields();
for (auto it = fielddefs->begin(); it != fielddefs->end(); ++it) {
auto &fielddef = **it;
// Skip if field is not present in the source.
if (!table.CheckField(fielddef.offset())) continue;
uoffset_t offset = 0;
switch (fielddef.type()->base_type()) {
case reflection::String: {
offset = fbb.CreateString(GetFieldS(table, fielddef)).o;
break;
}
case reflection::Obj: {
auto &subobjectdef = *schema.objects()->Get(fielddef.type()->index());
if (!subobjectdef.is_struct()) {
offset = CopyTable(fbb, schema, subobjectdef,
*GetFieldT(table, fielddef)).o;
}
break;
}
case reflection::Union: {
auto &subobjectdef = GetUnionType(schema, objectdef, fielddef, table);
offset = CopyTable(fbb, schema, subobjectdef,
*GetFieldT(table, fielddef)).o;
break;
}
case reflection::Vector: {
auto vec = table.GetPointer<const Vector<Offset<Table>> *>(
fielddef.offset());
auto element_base_type = fielddef.type()->element();
auto elemobjectdef = element_base_type == reflection::Obj
? schema.objects()->Get(fielddef.type()->index())
: nullptr;
switch (element_base_type) {
case reflection::String: {
std::vector<Offset<const String *>> elements(vec->size());
auto vec_s = reinterpret_cast<const Vector<Offset<String>> *>(vec);
for (uoffset_t i = 0; i < vec_s->size(); i++) {
elements[i] = fbb.CreateString(vec_s->Get(i)).o;
}
offset = fbb.CreateVector(elements).o;
break;
}
case reflection::Obj: {
if (!elemobjectdef->is_struct()) {
std::vector<Offset<const Table *>> elements(vec->size());
for (uoffset_t i = 0; i < vec->size(); i++) {
elements[i] =
CopyTable(fbb, schema, *elemobjectdef, *vec->Get(i));
}
offset = fbb.CreateVector(elements).o;
break;
}
// FALL-THRU:
}
default: { // Scalars and structs.
auto element_size = GetTypeSize(element_base_type);
if (elemobjectdef && elemobjectdef->is_struct())
element_size = elemobjectdef->bytesize();
fbb.StartVector(element_size, vec->size());
fbb.PushBytes(vec->Data(), element_size * vec->size());
offset = fbb.EndVector(vec->size());
break;
}
}
break;
}
default: // Scalars.
break;
}
if (offset) {
offsets.push_back(offset);
}
}
// Now we can build the actual table from either offsets or scalar data.
auto start = objectdef.is_struct()
? fbb.StartStruct(objectdef.minalign())
: fbb.StartTable();
size_t offset_idx = 0;
for (auto it = fielddefs->begin(); it != fielddefs->end(); ++it) {
auto &fielddef = **it;
if (!table.CheckField(fielddef.offset())) continue;
auto base_type = fielddef.type()->base_type();
switch (base_type) {
case reflection::Obj: {
auto &subobjectdef = *schema.objects()->Get(fielddef.type()->index());
if (subobjectdef.is_struct()) {
CopyInline(fbb, fielddef, table, subobjectdef.minalign(),
subobjectdef.bytesize());
break;
}
// else: FALL-THRU:
}
case reflection::Union:
case reflection::String:
case reflection::Vector:
fbb.AddOffset(fielddef.offset(), Offset<void>(offsets[offset_idx++]));
break;
default: { // Scalars.
auto size = GetTypeSize(base_type);
CopyInline(fbb, fielddef, table, size, size);
break;
}
}
}
assert(offset_idx == offsets.size());
if (objectdef.is_struct()) {
fbb.ClearOffsets();
return fbb.EndStruct();
} else {
return fbb.EndTable(start, static_cast<voffset_t>(fielddefs->size()));
}
}
} // namespace flatbuffers

View File

@@ -39,6 +39,25 @@ namespace FlatBuffers.Test
}
}
public class AssertArrayFailedException : Exception
{
private readonly int _index;
private readonly object _expected;
private readonly object _actual;
public AssertArrayFailedException(int index, object expected, object actual)
{
_index = index;
_expected = expected;
_actual = actual;
}
public override string Message
{
get { return string.Format("Expected {0} at index {1} but saw {2}", _expected, _index, _actual); }
}
}
public class AssertUnexpectedThrowException : Exception
{
private readonly object _expected;
@@ -64,6 +83,22 @@ namespace FlatBuffers.Test
}
}
public static void ArrayEqual<T>(T[] expected, T[] actual)
{
if (expected.Length != actual.Length)
{
throw new AssertFailedException(expected, actual);
}
for(var i = 0; i < expected.Length; ++i)
{
if (!expected[i].Equals(actual[i]))
{
throw new AssertArrayFailedException(i, expected, actual);
}
}
}
public static void IsTrue(bool value)
{
if (!value)

View File

@@ -18,9 +18,11 @@ using System;
namespace FlatBuffers.Test
{
[FlatBuffersTestClass]
public class ByteBufferTests
{
[FlatBuffersTestMethod]
public void ByteBuffer_Length_MatchesBufferLength()
{
var buffer = new byte[1000];
@@ -28,6 +30,7 @@ namespace FlatBuffers.Test
Assert.AreEqual(buffer.Length, uut.Length);
}
[FlatBuffersTestMethod]
public void ByteBuffer_PutBytePopulatesBufferAtZeroOffset()
{
var buffer = new byte[1];
@@ -37,6 +40,7 @@ namespace FlatBuffers.Test
Assert.AreEqual((byte)99, buffer[0]);
}
[FlatBuffersTestMethod]
public void ByteBuffer_PutByteCannotPutAtOffsetPastLength()
{
var buffer = new byte[1];
@@ -44,6 +48,7 @@ namespace FlatBuffers.Test
Assert.Throws<ArgumentOutOfRangeException>(() => uut.PutByte(1, 99));
}
[FlatBuffersTestMethod]
public void ByteBuffer_PutShortPopulatesBufferCorrectly()
{
var buffer = new byte[2];
@@ -55,6 +60,7 @@ namespace FlatBuffers.Test
Assert.AreEqual((byte)0, buffer[1]);
}
[FlatBuffersTestMethod]
public void ByteBuffer_PutShortCannotPutAtOffsetPastLength()
{
var buffer = new byte[2];
@@ -62,6 +68,7 @@ namespace FlatBuffers.Test
Assert.Throws<ArgumentOutOfRangeException>(() => uut.PutShort(2, 99));
}
[FlatBuffersTestMethod]
public void ByteBuffer_PutShortChecksLength()
{
var buffer = new byte[1];
@@ -69,6 +76,7 @@ namespace FlatBuffers.Test
Assert.Throws<ArgumentOutOfRangeException>(() => uut.PutShort(0, 99));
}
[FlatBuffersTestMethod]
public void ByteBuffer_PutShortChecksLengthAndOffset()
{
var buffer = new byte[2];
@@ -76,6 +84,7 @@ namespace FlatBuffers.Test
Assert.Throws<ArgumentOutOfRangeException>(() => uut.PutShort(1, 99));
}
[FlatBuffersTestMethod]
public void ByteBuffer_PutIntPopulatesBufferCorrectly()
{
var buffer = new byte[4];
@@ -89,6 +98,7 @@ namespace FlatBuffers.Test
Assert.AreEqual(0x0A, buffer[3]);
}
[FlatBuffersTestMethod]
public void ByteBuffer_PutIntCannotPutAtOffsetPastLength()
{
var buffer = new byte[4];
@@ -96,6 +106,7 @@ namespace FlatBuffers.Test
Assert.Throws<ArgumentOutOfRangeException>(() => uut.PutInt(2, 0x0A0B0C0D));
}
[FlatBuffersTestMethod]
public void ByteBuffer_PutIntChecksLength()
{
var buffer = new byte[1];
@@ -103,6 +114,7 @@ namespace FlatBuffers.Test
Assert.Throws<ArgumentOutOfRangeException>(() => uut.PutInt(0, 0x0A0B0C0D));
}
[FlatBuffersTestMethod]
public void ByteBuffer_PutIntChecksLengthAndOffset()
{
var buffer = new byte[4];
@@ -110,6 +122,7 @@ namespace FlatBuffers.Test
Assert.Throws<ArgumentOutOfRangeException>(() => uut.PutInt(2, 0x0A0B0C0D));
}
[FlatBuffersTestMethod]
public void ByteBuffer_PutLongPopulatesBufferCorrectly()
{
var buffer = new byte[8];
@@ -127,6 +140,7 @@ namespace FlatBuffers.Test
Assert.AreEqual(0x01, buffer[7]);
}
[FlatBuffersTestMethod]
public void ByteBuffer_PutLongCannotPutAtOffsetPastLength()
{
var buffer = new byte[8];
@@ -134,6 +148,7 @@ namespace FlatBuffers.Test
Assert.Throws<ArgumentOutOfRangeException>(() => uut.PutLong(2, 0x010203040A0B0C0D));
}
[FlatBuffersTestMethod]
public void ByteBuffer_PutLongChecksLength()
{
var buffer = new byte[1];
@@ -141,6 +156,7 @@ namespace FlatBuffers.Test
Assert.Throws<ArgumentOutOfRangeException>(() => uut.PutLong(0, 0x010203040A0B0C0D));
}
[FlatBuffersTestMethod]
public void ByteBuffer_PutLongChecksLengthAndOffset()
{
var buffer = new byte[8];
@@ -148,6 +164,7 @@ namespace FlatBuffers.Test
Assert.Throws<ArgumentOutOfRangeException>(() => uut.PutLong(2, 0x010203040A0B0C0D));
}
[FlatBuffersTestMethod]
public void ByteBuffer_GetByteReturnsCorrectData()
{
var buffer = new byte[1];
@@ -156,6 +173,7 @@ namespace FlatBuffers.Test
Assert.AreEqual((byte)99, uut.Get(0));
}
[FlatBuffersTestMethod]
public void ByteBuffer_GetByteChecksOffset()
{
var buffer = new byte[1];
@@ -163,6 +181,7 @@ namespace FlatBuffers.Test
Assert.Throws<ArgumentOutOfRangeException>(()=>uut.Get(1));
}
[FlatBuffersTestMethod]
public void ByteBuffer_GetShortReturnsCorrectData()
{
var buffer = new byte[2];
@@ -172,6 +191,7 @@ namespace FlatBuffers.Test
Assert.AreEqual(1, uut.GetShort(0));
}
[FlatBuffersTestMethod]
public void ByteBuffer_GetShortChecksOffset()
{
var buffer = new byte[2];
@@ -179,6 +199,7 @@ namespace FlatBuffers.Test
Assert.Throws<ArgumentOutOfRangeException>(() => uut.GetShort(2));
}
[FlatBuffersTestMethod]
public void ByteBuffer_GetShortChecksLength()
{
var buffer = new byte[2];
@@ -186,6 +207,7 @@ namespace FlatBuffers.Test
Assert.Throws<ArgumentOutOfRangeException>(() => uut.GetShort(1));
}
[FlatBuffersTestMethod]
public void ByteBuffer_GetIntReturnsCorrectData()
{
var buffer = new byte[4];
@@ -197,6 +219,7 @@ namespace FlatBuffers.Test
Assert.AreEqual(0x0A0B0C0D, uut.GetInt(0));
}
[FlatBuffersTestMethod]
public void ByteBuffer_GetIntChecksOffset()
{
var buffer = new byte[4];
@@ -204,6 +227,7 @@ namespace FlatBuffers.Test
Assert.Throws<ArgumentOutOfRangeException>(() => uut.GetInt(4));
}
[FlatBuffersTestMethod]
public void ByteBuffer_GetIntChecksLength()
{
var buffer = new byte[2];
@@ -211,6 +235,7 @@ namespace FlatBuffers.Test
Assert.Throws<ArgumentOutOfRangeException>(() => uut.GetInt(0));
}
[FlatBuffersTestMethod]
public void ByteBuffer_GetLongReturnsCorrectData()
{
var buffer = new byte[8];
@@ -226,6 +251,7 @@ namespace FlatBuffers.Test
Assert.AreEqual(0x010203040A0B0C0D, uut.GetLong(0));
}
[FlatBuffersTestMethod]
public void ByteBuffer_GetLongChecksOffset()
{
var buffer = new byte[8];
@@ -233,39 +259,44 @@ namespace FlatBuffers.Test
Assert.Throws<ArgumentOutOfRangeException>(() => uut.GetLong(8));
}
[FlatBuffersTestMethod]
public void ByteBuffer_GetLongChecksLength()
{
var buffer = new byte[7];
var uut = new ByteBuffer(buffer);
Assert.Throws<ArgumentOutOfRangeException>(() => uut.GetLong(0));
}
[FlatBuffersTestMethod]
public void ByteBuffer_ReverseBytesUshort()
{
ushort original = (ushort)0x1234U;
ushort reverse = ByteBuffer.ReverseBytes(original);
const ushort original = (ushort)0x1234U;
var reverse = ByteBuffer.ReverseBytes(original);
Assert.AreEqual(0x3412U, reverse);
ushort rereverse = ByteBuffer.ReverseBytes(reverse);
var rereverse = ByteBuffer.ReverseBytes(reverse);
Assert.AreEqual(original, rereverse);
}
[FlatBuffersTestMethod]
public void ByteBuffer_ReverseBytesUint()
{
uint original = 0x12345678;
uint reverse = ByteBuffer.ReverseBytes(original);
const uint original = 0x12345678;
var reverse = ByteBuffer.ReverseBytes(original);
Assert.AreEqual(0x78563412U, reverse);
uint rereverse = ByteBuffer.ReverseBytes(reverse);
var rereverse = ByteBuffer.ReverseBytes(reverse);
Assert.AreEqual(original, rereverse);
}
[FlatBuffersTestMethod]
public void ByteBuffer_ReverseBytesUlong()
{
ulong original = 0x1234567890ABCDEFUL;
ulong reverse = ByteBuffer.ReverseBytes(original);
const ulong original = 0x1234567890ABCDEFUL;
var reverse = ByteBuffer.ReverseBytes(original);
Assert.AreEqual(0xEFCDAB9078563412UL, reverse);
ulong rereverse = ByteBuffer.ReverseBytes(reverse);
var rereverse = ByteBuffer.ReverseBytes(reverse);
Assert.AreEqual(original, rereverse);
}
}

View File

@@ -41,6 +41,9 @@
<Compile Include="..\..\net\FlatBuffers\ByteBuffer.cs">
<Link>FlatBuffers\ByteBuffer.cs</Link>
</Compile>
<Compile Include="..\..\net\FlatBuffers\Offset.cs">
<Link>FlatBuffers\Offset.cs</Link>
</Compile>
<Compile Include="..\..\net\FlatBuffers\FlatBufferBuilder.cs">
<Link>FlatBuffers\FlatBufferBuilder.cs</Link>
</Compile>
@@ -68,14 +71,23 @@
<Compile Include="..\MyGame\Example\Test.cs">
<Link>MyGame\Example\Test.cs</Link>
</Compile>
<Compile Include="..\MyGame\Example\TestSimpleTableWithEnum.cs">
<Link>MyGame\Example\TestSimpleTableWithEnum.cs</Link>
</Compile>
<Compile Include="..\MyGame\Example\Vec3.cs">
<Link>MyGame\Example\Vec3.cs</Link>
</Compile>
<Compile Include="Assert.cs" />
<Compile Include="ByteBufferTests.cs" />
<Compile Include="FlatBuffersFuzzTests.cs" />
<Compile Include="FlatBuffersTestClassAttribute.cs" />
<Compile Include="FlatBuffersTestMethodAttribute.cs" />
<Compile Include="FuzzTestData.cs" />
<Compile Include="Lcg.cs" />
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="FlatBuffersExampleTests.cs" />
<Compile Include="TestTable.cs" />
</ItemGroup>
<ItemGroup>
<Content Include="..\monsterdata_test.mon">

View File

@@ -19,6 +19,7 @@ using MyGame.Example;
namespace FlatBuffers.Test
{
[FlatBuffersTestClass]
public class FlatBuffersExampleTests
{
public void RunTests()
@@ -28,6 +29,7 @@ namespace FlatBuffers.Test
TestEnums();
}
[FlatBuffersTestMethod]
public void CanCreateNewFlatBufferFromScratch()
{
// Second, let's create a FlatBuffer from scratch in C#, and test it also.
@@ -61,84 +63,130 @@ namespace FlatBuffers.Test
var test4 = fbb.EndVector();
Monster.StartTestarrayofstringVector(fbb, 2);
fbb.AddOffset(test2);
fbb.AddOffset(test1);
fbb.AddOffset(test2.Value);
fbb.AddOffset(test1.Value);
var testArrayOfString = fbb.EndVector();
Monster.StartMonster(fbb);
Monster.AddPos(fbb, Vec3.CreateVec3(fbb, 1.0f, 2.0f, 3.0f, 3.0,
Color.Green, (short)5, (sbyte)6));
Monster.AddHp(fbb, (short)80);
Monster.AddName(fbb, str);
Monster.AddInventory(fbb, inv);
Monster.AddTestType(fbb, (byte)1);
Monster.AddTest(fbb, mon2);
Monster.AddTestType(fbb, Any.Monster);
Monster.AddTest(fbb, mon2.Value);
Monster.AddTest4(fbb, test4);
Monster.AddTestarrayofstring(fbb, testArrayOfString);
Monster.AddTestbool(fbb, false);
var mon = Monster.EndMonster(fbb);
fbb.Finish(mon);
Monster.FinishMonsterBuffer(fbb, mon);
// Dump to output directory so we can inspect later, if needed
using (var ms = new MemoryStream(fbb.DataBuffer().Data, fbb.DataBuffer().position(), fbb.Offset()))
using (var ms = new MemoryStream(fbb.DataBuffer.Data, fbb.DataBuffer.Position, fbb.Offset))
{
var data = ms.ToArray();
File.WriteAllBytes(@"Resources/monsterdata_cstest.mon",data);
}
// Now assert the buffer
TestBuffer(fbb.DataBuffer());
TestBuffer(fbb.DataBuffer);
//Attempt to mutate Monster fields and check whether the buffer has been mutated properly
// revert to original values after testing
Monster monster = Monster.GetRootAsMonster(fbb.DataBuffer);
// mana is optional and does not exist in the buffer so the mutation should fail
// the mana field should retain its default value
Assert.AreEqual(monster.MutateMana((short)10), false);
Assert.AreEqual(monster.Mana, (short)150);
// testType is an existing field and mutating it should succeed
Assert.AreEqual(monster.TestType, Any.Monster);
Assert.AreEqual(monster.MutateTestType(Any.NONE), true);
Assert.AreEqual(monster.TestType, Any.NONE);
Assert.AreEqual(monster.MutateTestType(Any.Monster), true);
Assert.AreEqual(monster.TestType, Any.Monster);
//mutate the inventory vector
Assert.AreEqual(monster.MutateInventory(0, 1), true);
Assert.AreEqual(monster.MutateInventory(1, 2), true);
Assert.AreEqual(monster.MutateInventory(2, 3), true);
Assert.AreEqual(monster.MutateInventory(3, 4), true);
Assert.AreEqual(monster.MutateInventory(4, 5), true);
for (int i = 0; i < monster.InventoryLength; i++)
{
Assert.AreEqual(monster.GetInventory(i), i + 1);
}
//reverse mutation
Assert.AreEqual(monster.MutateInventory(0, 0), true);
Assert.AreEqual(monster.MutateInventory(1, 1), true);
Assert.AreEqual(monster.MutateInventory(2, 2), true);
Assert.AreEqual(monster.MutateInventory(3, 3), true);
Assert.AreEqual(monster.MutateInventory(4, 4), true);
// get a struct field and edit one of its fields
Vec3 pos = monster.Pos;
Assert.AreEqual(pos.X, 1.0f);
pos.MutateX(55.0f);
Assert.AreEqual(pos.X, 55.0f);
pos.MutateX(1.0f);
Assert.AreEqual(pos.X, 1.0f);
TestBuffer(fbb.DataBuffer);
}
private void TestBuffer(ByteBuffer bb)
{
var monster = Monster.GetRootAsMonster(bb);
Assert.AreEqual(80, monster.Hp());
Assert.AreEqual(150, monster.Mana());
Assert.AreEqual("MyMonster", monster.Name());
Assert.AreEqual(80, monster.Hp);
Assert.AreEqual(150, monster.Mana);
Assert.AreEqual("MyMonster", monster.Name);
var pos = monster.Pos();
Assert.AreEqual(1.0f, pos.X());
Assert.AreEqual(2.0f, pos.Y());
Assert.AreEqual(3.0f, pos.Z());
var pos = monster.Pos;
Assert.AreEqual(1.0f, pos.X);
Assert.AreEqual(2.0f, pos.Y);
Assert.AreEqual(3.0f, pos.Z);
Assert.AreEqual(3.0f, pos.Test1());
Assert.AreEqual(Color.Green, pos.Test2());
var t = pos.Test3();
Assert.AreEqual((short)5, t.A());
Assert.AreEqual((sbyte)6, t.B());
Assert.AreEqual(3.0f, pos.Test1);
Assert.AreEqual(Color.Green, pos.Test2);
var t = pos.Test3;
Assert.AreEqual((short)5, t.A);
Assert.AreEqual((sbyte)6, t.B);
Assert.AreEqual((byte)Any.Monster, monster.TestType());
Assert.AreEqual(Any.Monster, monster.TestType);
var monster2 = new Monster();
Assert.IsTrue(monster.Test(monster2) != null);
Assert.AreEqual("Fred", monster2.Name());
Assert.IsTrue(monster.GetTest(monster2) != null);
Assert.AreEqual("Fred", monster2.Name);
Assert.AreEqual(5, monster.InventoryLength());
Assert.AreEqual(5, monster.InventoryLength);
var invsum = 0;
for (var i = 0; i < monster.InventoryLength(); i++)
for (var i = 0; i < monster.InventoryLength; i++)
{
invsum += monster.Inventory(i);
invsum += monster.GetInventory(i);
}
Assert.AreEqual(10, invsum);
var test0 = monster.Test4(0);
var test1 = monster.Test4(1);
Assert.AreEqual(2, monster.Test4Length());
var test0 = monster.GetTest4(0);
var test1 = monster.GetTest4(1);
Assert.AreEqual(2, monster.Test4Length);
Assert.AreEqual(100, test0.A() + test0.B() + test1.A() + test1.B());
Assert.AreEqual(100, test0.A + test0.B + test1.A + test1.B);
Assert.AreEqual(2, monster.TestarrayofstringLength());
Assert.AreEqual("test1", monster.Testarrayofstring(0));
Assert.AreEqual("test2", monster.Testarrayofstring(1));
Assert.AreEqual(2, monster.TestarrayofstringLength);
Assert.AreEqual("test1", monster.GetTestarrayofstring(0));
Assert.AreEqual("test2", monster.GetTestarrayofstring(1));
Assert.AreEqual(false, monster.Testbool());
Assert.AreEqual(false, monster.Testbool);
}
[FlatBuffersTestMethod]
public void CanReadCppGeneratedWireFile()
{
var data = File.ReadAllBytes(@"Resources/monsterdata_test.mon");
@@ -146,12 +194,13 @@ namespace FlatBuffers.Test
TestBuffer(bb);
}
[FlatBuffersTestMethod]
public void TestEnums()
{
Assert.AreEqual(Color.Name(Color.Red), "Red");
Assert.AreEqual(Color.Name(Color.Blue), "Blue");
Assert.AreEqual(Any.Name(Any.NONE), "NONE");
Assert.AreEqual(Any.Name(Any.Monster), "Monster");
Assert.AreEqual("Red", Color.Red.ToString());
Assert.AreEqual("Blue", Color.Blue.ToString());
Assert.AreEqual("NONE", Any.NONE.ToString());
Assert.AreEqual("Monster", Any.Monster.ToString());
}
}
}

View File

@@ -0,0 +1,742 @@
/*
* Copyright 2015 Google Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
namespace FlatBuffers.Test
{
[FlatBuffersTestClass]
public class FlatBuffersFuzzTests
{
private readonly Lcg _lcg = new Lcg();
[FlatBuffersTestMethod]
public void TestObjects()
{
CheckObjects(11, 100);
}
[FlatBuffersTestMethod]
public void TestNumbers()
{
var builder = new FlatBufferBuilder(1);
Assert.ArrayEqual(new byte[] { 0 }, builder.DataBuffer.Data);
builder.AddBool(true);
Assert.ArrayEqual(new byte[] { 1 }, builder.DataBuffer.Data);
builder.AddSbyte(-127);
Assert.ArrayEqual(new byte[] { 129, 1 }, builder.DataBuffer.Data);
builder.AddByte(255);
Assert.ArrayEqual(new byte[] { 0, 255, 129, 1 }, builder.DataBuffer.Data); // First pad
builder.AddShort(-32222);
Assert.ArrayEqual(new byte[] { 0, 0, 0x22, 0x82, 0, 255, 129, 1 }, builder.DataBuffer.Data); // Second pad
builder.AddUshort(0xFEEE);
Assert.ArrayEqual(new byte[] { 0xEE, 0xFE, 0x22, 0x82, 0, 255, 129, 1 }, builder.DataBuffer.Data); // no pad
builder.AddInt(-53687092);
Assert.ArrayEqual(new byte[] { 0, 0, 0, 0, 204, 204, 204, 252, 0xEE, 0xFE, 0x22, 0x82, 0, 255, 129, 1 }, builder.DataBuffer.Data); // third pad
builder.AddUint(0x98765432);
Assert.ArrayEqual(new byte[] { 0x32, 0x54, 0x76, 0x98, 204, 204, 204, 252, 0xEE, 0xFE, 0x22, 0x82, 0, 255, 129, 1 }, builder.DataBuffer.Data); // no pad
}
[FlatBuffersTestMethod]
public void TestNumbers64()
{
var builder = new FlatBufferBuilder(1);
builder.AddUlong(0x1122334455667788);
Assert.ArrayEqual(new byte[] { 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11 }, builder.DataBuffer.Data);
builder = new FlatBufferBuilder(1);
builder.AddLong(0x1122334455667788);
Assert.ArrayEqual(new byte[] { 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11 }, builder.DataBuffer.Data);
}
[FlatBuffersTestMethod]
public void TestVector_1xUInt8()
{
var builder = new FlatBufferBuilder(1);
builder.StartVector(sizeof(byte), 1, 1);
Assert.ArrayEqual(new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 }, builder.DataBuffer.Data);
builder.AddByte(1);
Assert.ArrayEqual(new byte[] { 0, 0, 0, 0, 1, 0, 0, 0 }, builder.DataBuffer.Data);
builder.EndVector();
Assert.ArrayEqual(new byte[] { 1, 0, 0, 0, 1, 0, 0, 0 }, builder.DataBuffer.Data);
}
[FlatBuffersTestMethod]
public void TestVector_2xUint8()
{
var builder = new FlatBufferBuilder(1);
builder.StartVector(sizeof(byte), 2, 1);
Assert.ArrayEqual(new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 }, builder.DataBuffer.Data);
builder.AddByte(1);
Assert.ArrayEqual(new byte[] { 0, 0, 0, 0, 0, 1, 0, 0 }, builder.DataBuffer.Data);
builder.AddByte(2);
Assert.ArrayEqual(new byte[] { 0, 0, 0, 0, 2, 1, 0, 0 }, builder.DataBuffer.Data);
builder.EndVector();
Assert.ArrayEqual(new byte[] { 2, 0, 0, 0, 2, 1, 0, 0 }, builder.DataBuffer.Data);
}
[FlatBuffersTestMethod]
public void TestVector_1xUInt16()
{
var builder = new FlatBufferBuilder(1);
builder.StartVector(sizeof(ushort), 1, 1);
Assert.ArrayEqual(new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 }, builder.DataBuffer.Data);
builder.AddUshort(1);
Assert.ArrayEqual(new byte[] { 0, 0, 0, 0, 1, 0, 0, 0 }, builder.DataBuffer.Data);
builder.EndVector();
Assert.ArrayEqual(new byte[] { 1, 0, 0, 0, 1, 0, 0, 0 }, builder.DataBuffer.Data);
}
[FlatBuffersTestMethod]
public void TestVector_2xUInt16()
{
var builder = new FlatBufferBuilder(1);
builder.StartVector(sizeof(ushort), 2, 1);
Assert.ArrayEqual(new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 }, builder.DataBuffer.Data);
builder.AddUshort(0xABCD);
Assert.ArrayEqual(new byte[] { 0, 0, 0, 0, 0, 0, 0xCD, 0xAB }, builder.DataBuffer.Data);
builder.AddUshort(0xDCBA);
Assert.ArrayEqual(new byte[] { 0, 0, 0, 0, 0xBA, 0xDC, 0xCD, 0xAB }, builder.DataBuffer.Data);
builder.EndVector();
Assert.ArrayEqual(new byte[] { 2, 0, 0, 0, 0xBA, 0xDC, 0xCD, 0xAB }, builder.DataBuffer.Data);
}
[FlatBuffersTestMethod]
public void TestCreateAsciiString()
{
var builder = new FlatBufferBuilder(1);
builder.CreateString("foo");
Assert.ArrayEqual(new byte[] { 3, 0, 0, 0, (byte)'f', (byte)'o', (byte)'o', 0 }, builder.DataBuffer.Data);
builder.CreateString("moop");
Assert.ArrayEqual(new byte[]
{
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0, // Padding to 32 bytes
4, 0, 0, 0,
(byte)'m', (byte)'o', (byte)'o', (byte)'p',
0, 0, 0, 0, // zero terminator with 3 byte pad
3, 0, 0, 0,
(byte)'f', (byte)'o', (byte)'o', 0
}, builder.DataBuffer.Data);
}
[FlatBuffersTestMethod]
public void TestCreateArbitarytring()
{
var builder = new FlatBufferBuilder(1);
builder.CreateString("\x01\x02\x03");
Assert.ArrayEqual(new byte[]
{
3, 0, 0, 0,
0x01, 0x02, 0x03, 0
}, builder.DataBuffer.Data); // No padding
builder.CreateString("\x04\x05\x06\x07");
Assert.ArrayEqual(new byte[]
{
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0, // Padding to 32 bytes
4, 0, 0, 0,
0x04, 0x05, 0x06, 0x07,
0, 0, 0, 0, // zero terminator with 3 byte pad
3, 0, 0, 0,
0x01, 0x02, 0x03, 0
}, builder.DataBuffer.Data); // No padding
}
[FlatBuffersTestMethod]
public void TestEmptyVTable()
{
var builder = new FlatBufferBuilder(1);
builder.StartObject(0);
Assert.ArrayEqual(new byte[] { 0 }, builder.DataBuffer.Data);
builder.EndObject();
Assert.ArrayEqual(new byte[]
{
4, 0, 4, 0,
4, 0, 0, 0
},
builder.DataBuffer.Data);
}
[FlatBuffersTestMethod]
public void TestVTableWithOneBool()
{
var builder = new FlatBufferBuilder(1);
builder.StartObject(1);
Assert.ArrayEqual(new byte[] { 0 }, builder.DataBuffer.Data);
builder.AddBool(0, true, false);
builder.EndObject();
Assert.ArrayEqual(new byte[]
{
0, 0, // padding to 16 bytes
6, 0, // vtable bytes
8, 0, // object length inc vtable offset
7, 0, // start of bool value
6, 0, 0, 0, // int32 offset for start of vtable
0, 0, 0, // padding
1, // value 0
},
builder.DataBuffer.Data);
}
[FlatBuffersTestMethod]
public void TestVTableWithOneBool_DefaultValue()
{
var builder = new FlatBufferBuilder(1);
builder.StartObject(1);
Assert.ArrayEqual(new byte[] { 0 }, builder.DataBuffer.Data);
builder.AddBool(0, false, false);
builder.EndObject();
Assert.ArrayEqual(new byte[]
{
0, 0, 0, 0, 0, 0, // padding to 16 bytes
6, 0, // vtable bytes
4, 0, // end of object from here
0, 0, // entry 0 is empty (default value)
6, 0, 0, 0, // int32 offset for start of vtable
},
builder.DataBuffer.Data);
}
[FlatBuffersTestMethod]
public void TestVTableWithOneInt16()
{
var builder = new FlatBufferBuilder(1);
builder.StartObject(1);
Assert.ArrayEqual(new byte[] { 0 }, builder.DataBuffer.Data);
builder.AddShort(0, 0x789A, 0);
builder.EndObject();
Assert.ArrayEqual(new byte[]
{
0, 0, // padding to 16 bytes
6, 0, // vtable bytes
8, 0, // object length inc vtable offset
6, 0, // start of int16 value
6, 0, 0, 0, // int32 offset for start of vtable
0, 0, // padding
0x9A, 0x78, //value 0
},
builder.DataBuffer.Data);
}
[FlatBuffersTestMethod]
public void TestVTableWithTwoInt16()
{
var builder = new FlatBufferBuilder(1);
builder.StartObject(2);
Assert.ArrayEqual(new byte[] { 0 }, builder.DataBuffer.Data);
builder.AddShort(0, 0x3456, 0);
builder.AddShort(1, 0x789A, 0);
builder.EndObject();
Assert.ArrayEqual(new byte[]
{
8, 0, // vtable bytes
8, 0, // object length inc vtable offset
6, 0, // start of int16 value 0
4, 0, // start of int16 value 1
8, 0, 0, 0, // int32 offset for start of vtable
0x9A, 0x78, // value 1
0x56, 0x34, // value 0
},
builder.DataBuffer.Data);
}
[FlatBuffersTestMethod]
public void TestVTableWithInt16AndBool()
{
var builder = new FlatBufferBuilder(1);
builder.StartObject(2);
Assert.ArrayEqual(new byte[] { 0 }, builder.DataBuffer.Data);
builder.AddShort(0, 0x3456, 0);
builder.AddBool(1, true, false);
builder.EndObject();
Assert.ArrayEqual(new byte[]
{
8, 0, // vtable bytes
8, 0, // object length inc vtable offset
6, 0, // start of int16 value 0
5, 0, // start of bool value 1
8, 0, 0, 0, // int32 offset for start of vtable
0, 1, // padding + value 1
0x56, 0x34, // value 0
},
builder.DataBuffer.Data);
}
[FlatBuffersTestMethod]
public void TestVTableWithEmptyVector()
{
var builder = new FlatBufferBuilder(1);
builder.StartVector(sizeof(byte), 0, 1);
var vecEnd = builder.EndVector();
builder.StartObject(1);
builder.AddOffset(0, vecEnd.Value, 0);
builder.EndObject();
Assert.ArrayEqual(new byte[]
{
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, // Padding to 32 bytes
6, 0, // vtable bytes
8, 0, // object length inc vtable offset
4, 0, // start of vector offset value 0
6, 0, 0, 0, // int32 offset for start of vtable
4, 0, 0, 0,
0, 0, 0, 0,
},
builder.DataBuffer.Data);
}
[FlatBuffersTestMethod]
public void TestVTableWithEmptyVectorAndScalars()
{
var builder = new FlatBufferBuilder(1);
builder.StartVector(sizeof(byte), 0, 1);
var vecEnd = builder.EndVector();
builder.StartObject(2);
builder.AddShort(0, 55, 0);
builder.AddOffset(1, vecEnd.Value, 0);
builder.EndObject();
Assert.ArrayEqual(new byte[]
{
0, 0, 0, 0,
0, 0, 0, 0, // Padding to 32 bytes
8, 0, // vtable bytes
12, 0, // object length inc vtable offset
10, 0, // offset to int16 value 0
4, 0, // start of vector offset value 1
8, 0, 0, 0, // int32 offset for start of vtable
8, 0, 0, 0, // value 1
0, 0, 55, 0, // value 0
0, 0, 0, 0, // length of vector (not in sctruc)
},
builder.DataBuffer.Data);
}
[FlatBuffersTestMethod]
public void TestVTableWith_1xInt16_and_Vector_or_2xInt16()
{
var builder = new FlatBufferBuilder(1);
builder.StartVector(sizeof(short), 2, 1);
builder.AddShort(0x1234);
builder.AddShort(0x5678);
var vecEnd = builder.EndVector();
builder.StartObject(2);
builder.AddOffset(1, vecEnd.Value, 0);
builder.AddShort(0, 55, 0);
builder.EndObject();
Assert.ArrayEqual(new byte[]
{
0, 0, 0, 0, // Padding to 32 bytes
8, 0, // vtable bytes
12, 0, // object length
6, 0, // start of value 0 from end of vtable
8, 0, // start of value 1 from end of buffer
8, 0, 0, 0, // int32 offset for start of vtable
0, 0, 55, 0, // padding + value 0
4, 0, 0, 0, // position of vector from here
2, 0, 0, 0, // length of vector
0x78, 0x56, // vector value 0
0x34, 0x12, // vector value 1
},
builder.DataBuffer.Data);
}
[FlatBuffersTestMethod]
public void TestVTableWithAStruct_of_int8_int16_int32()
{
var builder = new FlatBufferBuilder(1);
builder.StartObject(1);
builder.Prep(4+4+4, 0);
builder.AddSbyte(55);
builder.Pad(3);
builder.AddShort(0x1234);
builder.Pad(2);
builder.AddInt(0x12345678);
var structStart = builder.Offset;
builder.AddStruct(0, structStart, 0);
builder.EndObject();
Assert.ArrayEqual(new byte[]
{
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, // Padding to 32 bytes
6, 0, // vtable bytes
16, 0, // object length
4, 0, // start of struct from here
6, 0, 0, 0, // int32 offset for start of vtable
0x78, 0x56, 0x34, 0x12, // struct value 2
0x00, 0x00, 0x34, 0x12, // struct value 1
0x00, 0x00, 0x00, 55, // struct value 0
},
builder.DataBuffer.Data);
}
[FlatBuffersTestMethod]
public void TestVTableWithAVectorOf_2xStructOf_2xInt8()
{
var builder = new FlatBufferBuilder(1);
builder.StartVector(sizeof(byte)*2, 2, 1);
builder.AddByte(33);
builder.AddByte(44);
builder.AddByte(55);
builder.AddByte(66);
var vecEnd = builder.EndVector();
builder.StartObject(1);
builder.AddOffset(0, vecEnd.Value, 0);
builder.EndObject();
Assert.ArrayEqual(new byte[]
{
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, // Padding to 32 bytes
6, 0, // vtable bytes
8, 0, // object length
4, 0, // offset of vector offset
6, 0, 0, 0, // int32 offset for start of vtable
4, 0, 0, 0, // Vector start offset
2, 0, 0, 0, // Vector len
66, // vector 1, 1
55, // vector 1, 0
44, // vector 0, 1
33, // vector 0, 0
},
builder.DataBuffer.Data);
}
[FlatBuffersTestMethod]
public void TestVTableWithSomeElements()
{
var builder = new FlatBufferBuilder(1);
builder.StartObject(2);
builder.AddByte(0, 33, 0);
builder.AddShort(1, 66, 0);
var off = builder.EndObject();
builder.Finish(off);
Assert.ArrayEqual(new byte[]
{
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0, //Padding to 32 bytes
12, 0, 0, 0, // root of table, pointing to vtable offset
8, 0, // vtable bytes
8, 0, // object length
7, 0, // start of value 0
4, 0, // start of value 1
8, 0, 0, 0, // int32 offset for start of vtable
66, 0, // value 1
0, 33, // value 0
},
builder.DataBuffer.Data);
}
[FlatBuffersTestMethod]
public void TestTwoFinishTable()
{
var builder = new FlatBufferBuilder(1);
builder.StartObject(2);
builder.AddByte(0, 33, 0);
builder.AddByte(1, 44, 0);
var off0 = builder.EndObject();
builder.Finish(off0);
builder.StartObject(3);
builder.AddByte(0, 55, 0);
builder.AddByte(1, 66, 0);
builder.AddByte(2, 77, 0);
var off1 = builder.EndObject();
builder.Finish(off1);
Assert.ArrayEqual(new byte[]
{
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0, // padding to 64 bytes
16, 0, 0, 0, // root of table, pointing to vtable offset (obj1)
0, 0, // padding
10, 0, // vtable bytes
8, 0, // object length
7, 0, // start of value 0
6, 0, // start of value 1
5, 0, // start of value 2
10, 0, 0, 0, // int32 offset for start of vtable
0, // pad
77, // values 2, 1, 0
66,
55,
12, 0, 0, 0, // root of table, pointing to vtable offset (obj0)
8, 0, // vtable bytes
8, 0, // object length
7, 0, // start of value 0
6, 0, // start of value 1
8, 0, 0, 0, // int32 offset for start of vtable
0, 0, // pad
44, // value 1, 0
33,
},
builder.DataBuffer.Data);
}
[FlatBuffersTestMethod]
public void TestBunchOfBools()
{
var builder = new FlatBufferBuilder(1);
builder.StartObject(8);
for (var i = 0; i < 8; i++)
{
builder.AddBool(i, true, false);
}
var off = builder.EndObject();
builder.Finish(off);
Assert.ArrayEqual(new byte[]
{
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0, // padding to 64 bytes
24, 0, 0, 0, // root of table, pointing to vtable offset (obj0)
20, 0, // vtable bytes
12, 0, // object length
11, 0, // start of value 0
10, 0, // start of value 1
9, 0, // start of value 2
8, 0, // start of value 3
7, 0, // start of value 4
6, 0, // start of value 5
5, 0, // start of value 6
4, 0, // start of value 7
20, 0, 0, 0, // int32 offset for start of vtable
1, 1, 1, 1, // values
1, 1, 1, 1,
},
builder.DataBuffer.Data);
}
[FlatBuffersTestMethod]
public void TestWithFloat()
{
var builder = new FlatBufferBuilder(1);
builder.StartObject(1);
builder.AddFloat(0, 1, 0);
builder.EndObject();
Assert.ArrayEqual(new byte[]
{
0, 0,
6, 0, // vtable bytes
8, 0, // object length
4, 0, // start of value 0
6, 0, 0, 0, // int32 offset for start of vtable
0, 0, 128, 63, // value
},
builder.DataBuffer.Data);
}
private void CheckObjects(int fieldCount, int objectCount)
{
_lcg.Reset();
const int testValuesMax = 11;
var builder = new FlatBufferBuilder(1);
var objects = new int[objectCount];
for (var i = 0; i < objectCount; ++i)
{
builder.StartObject(fieldCount);
for (var j = 0; j < fieldCount; ++j)
{
var fieldType = _lcg.Next()%testValuesMax;
switch (fieldType)
{
case 0:
{
builder.AddBool(j, FuzzTestData.BoolValue, false);
break;
}
case 1:
{
builder.AddSbyte(j, FuzzTestData.Int8Value, 0);
break;
}
case 2:
{
builder.AddByte(j, FuzzTestData.UInt8Value, 0);
break;
}
case 3:
{
builder.AddShort(j, FuzzTestData.Int16Value, 0);
break;
}
case 4:
{
builder.AddUshort(j, FuzzTestData.UInt16Value, 0);
break;
}
case 5:
{
builder.AddInt(j, FuzzTestData.Int32Value, 0);
break;
}
case 6:
{
builder.AddUint(j, FuzzTestData.UInt32Value, 0);
break;
}
case 7:
{
builder.AddLong(j, FuzzTestData.Int64Value, 0);
break;
}
case 8:
{
builder.AddUlong(j, FuzzTestData.UInt64Value, 0);
break;
}
case 9:
{
builder.AddFloat(j, FuzzTestData.Float32Value, 0);
break;
}
case 10:
{
builder.AddDouble(j, FuzzTestData.Float64Value, 0);
break;
}
default:
throw new Exception("Unreachable");
}
}
var offset = builder.EndObject();
// Store the object offset
objects[i] = offset;
}
_lcg.Reset();
// Test all objects are readable and return expected values...
for (var i = 0; i < objectCount; ++i)
{
var table = new TestTable(builder.DataBuffer, builder.DataBuffer.Length - objects[i]);
for (var j = 0; j < fieldCount; ++j)
{
var fieldType = _lcg.Next() % testValuesMax;
var fc = 2 + j; // 2 == VtableMetadataFields
var f = fc * 2;
switch (fieldType)
{
case 0:
{
Assert.AreEqual(FuzzTestData.BoolValue, table.GetSlot(f, false));
break;
}
case 1:
{
Assert.AreEqual(FuzzTestData.Int8Value, table.GetSlot(f, (sbyte)0));
break;
}
case 2:
{
Assert.AreEqual(FuzzTestData.UInt8Value, table.GetSlot(f, (byte)0));
break;
}
case 3:
{
Assert.AreEqual(FuzzTestData.Int16Value, table.GetSlot(f, (short)0));
break;
}
case 4:
{
Assert.AreEqual(FuzzTestData.UInt16Value, table.GetSlot(f, (ushort)0));
break;
}
case 5:
{
Assert.AreEqual(FuzzTestData.Int32Value, table.GetSlot(f, (int)0));
break;
}
case 6:
{
Assert.AreEqual(FuzzTestData.UInt32Value, table.GetSlot(f, (uint)0));
break;
}
case 7:
{
Assert.AreEqual(FuzzTestData.Int64Value, table.GetSlot(f, (long)0));
break;
}
case 8:
{
Assert.AreEqual(FuzzTestData.UInt64Value, table.GetSlot(f, (ulong)0));
break;
}
case 9:
{
Assert.AreEqual(FuzzTestData.Float32Value, table.GetSlot(f, (float)0));
break;
}
case 10:
{
Assert.AreEqual(FuzzTestData.Float64Value, table.GetSlot(f, (double)0));
break;
}
default:
throw new Exception("Unreachable");
}
}
}
}
}
}

View File

@@ -0,0 +1,12 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace FlatBuffers.Test
{
[AttributeUsage(AttributeTargets.Class)]
public class FlatBuffersTestClassAttribute : Attribute
{
}
}

View File

@@ -0,0 +1,9 @@
using System;
namespace FlatBuffers.Test
{
[AttributeUsage(AttributeTargets.Method)]
public class FlatBuffersTestMethodAttribute : Attribute
{
}
}

View File

@@ -0,0 +1,22 @@
using System;
namespace FlatBuffers.Test
{
internal static class FuzzTestData
{
private static readonly byte[] _overflowInt32 = new byte[] {0x83, 0x33, 0x33, 0x33};
private static readonly byte[] _overflowInt64 = new byte[] { 0x84, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44 };
public static readonly bool BoolValue = true;
public static readonly sbyte Int8Value = -127; // 0x81
public static readonly byte UInt8Value = 255; // 0xFF
public static readonly short Int16Value = -32222; // 0x8222;
public static readonly ushort UInt16Value = 65262; // 0xFEEE
public static readonly int Int32Value = BitConverter.ToInt32(_overflowInt32, 0);
public static readonly uint UInt32Value = 0xFDDDDDDD;
public static readonly long Int64Value = BitConverter.ToInt64(_overflowInt64, 0);
public static readonly ulong UInt64Value = 0xFCCCCCCCCCCCCCCC;
public static readonly float Float32Value = 3.14159f;
public static readonly double Float64Value = 3.14159265359;
}
}

View File

@@ -0,0 +1,26 @@
namespace FlatBuffers.Test
{
/// <summary>
/// Lcg Pseudo RNG
/// </summary>
internal sealed class Lcg
{
private const uint InitialValue = 10000;
private uint _state;
public Lcg()
{
_state = InitialValue;
}
public uint Next()
{
return (_state = 69069 * _state + 362437);
}
public void Reset()
{
_state = InitialValue;
}
}
}

View File

@@ -15,6 +15,7 @@
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
@@ -24,38 +25,43 @@ namespace FlatBuffers.Test
{
public static int Main(string[] args)
{
var tests = new FlatBuffersExampleTests();
try
var testResults = new List<bool>();
var testClasses = Assembly.GetExecutingAssembly().GetExportedTypes()
.Where(t => t.IsClass && t.GetCustomAttributes(typeof (FlatBuffersTestClassAttribute), false).Length > 0);
foreach (var testClass in testClasses)
{
tests.RunTests();
var methods = testClass.GetMethods(BindingFlags.Public |
BindingFlags.Instance)
.Where(m => m.GetCustomAttributes(typeof(FlatBuffersTestMethodAttribute), false).Length > 0);
var inst = Activator.CreateInstance(testClass);
foreach (var method in methods)
{
try
{
method.Invoke(inst, new object[] { });
testResults.Add(true);
}
catch (Exception ex)
{
Console.WriteLine("{0}: FAILED when invoking {1} with error {2}",
testClass.Name ,method.Name, ex.GetBaseException());
testResults.Add(false);
}
}
}
catch (Exception ex)
var failedCount = testResults.Count(i => i == false);
Console.WriteLine("{0} tests run, {1} failed", testResults.Count, failedCount);
if (failedCount > 0)
{
Console.WriteLine("FlatBuffersExampleTests FAILED - {0}", ex.GetBaseException());
return -1;
}
// Run ByteBuffers Tests
var testClass = new ByteBufferTests();
var methods = testClass.GetType().GetMethods(BindingFlags.Public |
BindingFlags.Instance)
.Where(m => m.Name.StartsWith("ByteBuffer_"));
foreach (var method in methods)
{
try
{
method.Invoke(testClass, new object[] { });
}
catch (Exception ex)
{
Console.WriteLine("ByteBufferTests FAILED when invoking {0} with error {1}",
method.Name, ex.GetBaseException());
return -1;
}
}
return 0;
}
}

Some files were not shown because too many files have changed in this diff Show More