Compare commits

..

145 Commits

Author SHA1 Message Date
Wouter van Oortmerssen
c0698cc33f Bumped version to 1.10.1 for all languages.
Change-Id: I9a6256d90ea800834a887afdcf888df412018933
2018-10-03 12:48:47 -07:00
Wouter van Oortmerssen
ea8a4296e7 Updated TestAll.sh with Rust.
Change-Id: I751f3bbd85eb1b521e1533c68f95442af0d18b8a
2018-10-03 12:27:27 -07:00
Jason Neufeld
f85af46262 Adds __reset method to Struct and Table (#4966)
This allow recycling/pooling instances without leaking ByteBuffers, by
providing a mechanism to reset instance to newly constructed state.
2018-10-03 12:09:30 -07:00
Vladimir Glavnyy
7a43775661 Assert tests on the first failure. (#4952)
* Assert tests on the first failure. Disable pop-up message box on assertion.

* Fix format and code style

* Move MSVC dependent code to ifdef
2018-10-03 12:04:14 -07:00
kostya-sh
062dcf7007 Use standard header for generated Go files (#4961)
As recommended by https://golang.org/pkg/cmd/go/internal/generate/:

  To convey to humans and machine tools that code is generated,
  generated source should have a line early in the file that
  matches the following regular expression (in Go syntax):

        ^// Code generated .* DO NOT EDIT\.$
2018-10-03 11:19:40 -07:00
Taj Morton
ebb410062b Allow tables that are entirely composed of native inlines to be copied. (#4958) 2018-10-01 16:27:54 -07:00
Sumant Tambe
4b864fd172 Turn on gRPC tests in travis build (#4955)
Download and build with a known grpc version
2018-10-01 15:59:04 -07:00
Vladimir Glavnyy
7e711f80d7 Parser error message reports both the line number and the cursor position. (#4954) 2018-10-01 14:57:36 -07:00
Matt Mastracci
bf871ffd7f Remove lifetime specifier on table getter methods (#4949)
With the old-style code, the test fails with a borrow-checker error:

```
  #[inline]
  pub fn name(&'a self) -> &'a str {
    self._tab.get::<flatbuffers::ForwardsUOffset<&str>>(Monster::VT_NAME, None).unwrap()
  }
```

```
error[E0597]: `e` does not live long enough
   --> tests/integration_test.rs:273:57
    |
273 |         let enemy_of_my_enemy = monster.enemy().map(|e| e.name());
    |                                                         ^      - `e` dropped here while still borrowed
    |                                                         |
    |                                                         borrowed value does not live long enough
274 |         assert_eq!(enemy_of_my_enemy, Some("Fred"));
275 |     }
    |     - borrowed value needs to live until here
```
2018-09-28 20:11:05 -07:00
kzvi
a89be8739c loosen lifetimes in type signature of Table::get (#4925) 2018-09-27 20:56:49 -07:00
Shivendra Agarwal
0bffce5aef Add more apis to query vector types from a reference (#4823)
* Add more apis to query vector types from a reference

https://github.com/google/flatbuffers/issues/4818

* changing order of apis

* another reordering

* removed vector element type api as not needed as for now
2018-09-27 12:34:27 -07:00
Vladimir Glavnyy
d48f08acfe Add missed defined(clang) and fix the wrong placement of #pragma push/pop for MSVC compiler (#4946) 2018-09-27 12:31:43 -07:00
kzvi
43132560f9 don't return Option from required table field accessors (#4926) 2018-09-26 21:11:25 -07:00
jean-airoldie
c56fff88a2 rust: Fixed MakeCamelCase (#4932) (#4936)
* Fixed MakeCamelCase behavior when supplied Upper_Camel_Case,
snake_case and UPPERCASE strings.
* Modified the rust integration test to reflect changes.
2018-09-26 13:35:02 -07:00
Sumant Tambe
49fed8c4f6 Add FlatBufferBuilder move semantics tests to the main test suite (#4902)
* Add FlatBufferBuilder move semantics tests to main

Do not eagerly delete/reset allocators in release and release_raw functions
Update android, vs2010 build files
New tests for various types of FlatBufferBuilders and move semantics

* Improve test failure output with function names
2018-09-24 12:03:31 -07:00
Michael Edwards
b1a925dfc2 ToStringVisitor settings to allow pretty formatted JSON (#4933) 2018-09-24 09:29:49 -07:00
Thomas
33791dc7b0 Add compare operator to code generated for c++ (#4940)
* Add operator== for c++ genated code

New "--gen-compare" option for flatc to generate compare operators. The operators are defined based on object based api types.

Inspired by issue #263.

* Improve compare operator for c++.
Thanks for the code review.

- Improve robustness against future schema extensions
- Code style
- Fix --rust generation in generate_code.sh
2018-09-21 16:53:59 -07:00
Wouter van Oortmerssen
873a60b0d8 Updated readme.md
Change-Id: I9b0664a3bde44a4ee44ef0fd117d0e4bedc132d9
2018-09-21 10:42:00 -07:00
Wouter van Oortmerssen
4b10656f9b Changed JS/TS codegen to use stable non-compiler dependent hash.
Different implementations of std::hash kept littering commits with
namespace changes.

Change-Id: Ic2d4fdcd76f8fef9802bc1572eb74ae7427085e3
2018-09-21 09:42:43 -07:00
Wouter van Oortmerssen
e317b148dc Added missing Dart codegen files.
Change-Id: Ic97f5b50fa191f967672c404f737d302462fc6ac
2018-09-21 09:42:43 -07:00
Christopher Cifra
ed03faaf07 [C#] Fix compile issue when compiling with older versions of C# (#4938)
* C# support for directly reading and writting to memory other than byte[].  For example, ByteBuffer can be initialized with a custom allocator which uses shared memory / memory mapped files.

Public access to the backing buffer uses Span<T> instead of ArraySegment<T>.

Writing to the buffer now supports Span<T> in addition to T[].

To maintain backwards compatibility ENABLE_SPAN_T must be defined.

* Remove usage of expression bodied method so that ByteBuffer can be compiled with older version of C#.
2018-09-20 15:07:03 -07:00
Robert
02a7807dd8 Add Rust to Appveyor config. (#4928) 2018-09-12 11:44:51 -07:00
Enrico Olivelli
615885e889 Add ByteBufferFactory#releaseByteBuffer (#4914)
This adds the ability to dispose unused buffers or to return them to an object pool
2018-09-06 11:08:08 -07:00
Robert
528ccdd458 rust: more builder lifetimes predicates (#4923) 2018-09-05 18:15:30 -07:00
Robert
c23ba6756f rust: more builder lifetimes logic (#4917) 2018-09-04 21:53:39 -07:00
Onur Karaman
10e1d1a69e fix rust flatbuffers create_vector docs (#4913)
Manual vector creation begins with start_vector, not create_vector.
2018-09-04 14:30:31 -07:00
Robert
660c491265 rust generator: fix builder lifetime switch (#4912) 2018-09-04 14:29:27 -07:00
Robert
c504a45404 rust generator: fix enum member comments (#4911) 2018-09-04 13:52:31 -07:00
Robert
919c929d30 readme.md: add Rust as a supported language 2018-09-03 23:38:41 -07:00
Robert
ba4a02b46a Update Cargo.toml for Crates.io package 2018-09-03 19:42:25 -07:00
Robert
be3d0b9c64 delete and ignore Cargo.lock files (#4906) 2018-09-03 19:33:38 -07:00
Chris Holcombe
872fad049e Fix extern crate in root namespace (#4905)
Imports the Rust FlatBuffers runtime crate even when not using a namespace in a schema.
2018-09-03 19:09:38 -07:00
Robert
9e648c392b Rust: Add basic crate-level documentation 2018-09-03 18:01:31 -07:00
Robert
d4f65bb8a3 Update Rust runtime crate version for publishing 2018-09-03 17:13:10 -07:00
Robert
3c54fd964b Port FlatBuffers to Rust (#4898)
This is a port of FlatBuffers to Rust. It provides code generation and a
runtime library derived from the C++ implementation. It utilizes the
Rust type system to provide safe and fast traversal of FlatBuffers data.

There are 188 tests, including many fuzz tests of roundtrips for various
serialization scenarios. Initial benchmarks indicate that the canonical
example payload can be written in ~700ns, and traversed in ~100ns.

Rustaceans may be interested in the Follow, Push, and SafeSliceAccess
traits. These traits lift traversals, reads, writes, and slice accesses
into the type system, providing abstraction with no runtime penalty.
2018-09-02 18:26:55 -07:00
Sumant Tambe
e7578548a5 Add move semantics to MessageBuilder, FlatBufferBuilder, SliceAllocator, and vector_downward (#4893)
Unit tests
Update flatbuffers + gRPC build instructions
Update CMakeLists.txt with cmake variables for grpc and protobuf install paths
Update tests for travis build
2018-08-30 16:43:22 -07:00
Gabriel Nützi
99acd0bcd7 DetachedBuffer cannot be rewrapped (#4885)
* Simple ReleaseRaw implemented

* [doc]

* clear_buffer and clear_allocator introduced

* auto

* typos

* rename because of -Werror=shadow
2018-08-24 10:57:57 -07:00
Christopher Cifra
d0321df8cf C# support for directly reading and writting to memory other than byte[]. For example, ByteBuffer can be initialized with a custom allocator which uses shared memory / memory mapped files. (#4886)
Public access to the backing buffer uses Span<T> instead of ArraySegment<T>.

Writing to the buffer now supports Span<T> in addition to T[].

To maintain backwards compatibility ENABLE_SPAN_T must be defined.
2018-08-23 10:05:31 -07:00
Derek Bailey
e1f48ad35a Updated preprocessor check for template aliases. (#4888) 2018-08-23 09:48:03 -07:00
Derek Bailey
d8f49e18d7 Mono Fix for Unsafe Mode (#4887)
* Added preprocessor define for C++ if Template Aliases are supported by the compiler

* Revert "Revert "Performance Increase of Vector of Structures using .NET BlockCopy (#4830)""

This reverts commit 1f5eae5d6a.

* Put<T> method was inside #if UNSAFE_BYTEBUFFER which caused compilation failure when building in unsafe mode

* Revert "Added preprocessor define for C++ if Template Aliases are supported by the compiler"

This reverts commit a75af73521.
2018-08-20 16:31:44 -07:00
Wouter van Oortmerssen
1f5eae5d6a Revert "Performance Increase of Vector of Structures using .NET BlockCopy (#4830)"
This reverts commit 7b50004ec9.

Change-Id: I09d6869c16aa3c7fadc537fc9c76eaa3cf7ee7ea
2018-08-20 12:08:21 -07:00
Wouter van Oortmerssen
ea9d60bbdf Added missing dart/ts test changes.
Change-Id: I836091193485b890710f1df779d4d770f729a27a
2018-08-20 12:05:37 -07:00
Andy Martin
c2c3a84aaf Add C#/Java generator behaviour for 'private' attribute (#4882)
* Added 'private' attribute, supported when generating C# and Java

* Added use of 'private' attribute in monster_test
2018-08-16 15:25:33 -07:00
Uilian Ries
1f03becd24 Conan build packages on CI (#4590) (#4594)
* Build Conan package on Travis CI (#4590)

- Added multi package support on Linux, running on Travis CI
- Only upload when branch is a tag and named "vX.Y.Z"
- Replace Conan injection by Conan wrapper
- Removed os_build os_arch -- Conan 1.0.1 hotfix

Signed-off-by: Uilian Ries <uilianries@gmail.com>

* Build Conan package on OSX (#4590)

- Added jobs to build Flatbuffers on OSX running on Travis

Signed-off-by: Uilian Ries <uilianries@gmail.com>

* Build Conan package on Windows (#4590)

- Added support necessary to build Flatbuffers on Windows (conan)
- Added Appveyor jobs to build Conan package
- Only build Conan package when release (tag)

Signed-off-by: Uilian Ries <uilianries@gmail.com>

* Reduce Conan CI support to simple scripts (#4590)

- Removed msvc 10 x86_64 workaround
- Updated conan remote address
- Added Bincrafters' package tools

Signed-off-by: Uilian Ries <uilianries@gmail.com>

* Add fPIC option on Conan recipe (#4590)

- Add fPIC as optional. It works on Linux and OSX
- Update recipe metadata: author, homepage, license
- Checking for flatc and flathash on Conan package

Signed-off-by: Uilian Ries <uilianries@gmail.com>

* Build Conan package on CI (#4590)

- Add rule to run conan job only for tags
- Run Conan on Linux, OSX and Windows
- Update package tool to new interface

Signed-off-by: Uilian Ries <uilianries@gmail.com>

* Update Conan username (#4590)

- Use google as default username

Signed-off-by: Uilian Ries <uilianries@gmail.com>

* Update OSX version on CI (#4590)

- Use latest OSX 9.3 version to build Conan package

Signed-off-by: Uilian Ries <uilianries@gmail.com>
2018-08-16 12:17:52 -07:00
kulswanand
c721009491 Proposing use of C++ header files and functions (#4869)
* Proposing use of C++ header files and functions 

Proposing use of C++ header files and functions instead of C header file and functions. 
Here are few examples for comparison : 

C                            C++
<cstdio>                <iostream> & <fstream>
printf()                     cout 
fopen()                    ifstream
etc ...

Please let me know if there are any comments.

* Updated diff based on review comments
2018-08-13 16:36:11 -07:00
iceboy
55289c55bf Use string_view if _HAS_CXX17 is true (#4876)
Current version of VC2017 is not setting __cplusplus to correct value, instead they use _MSC_VER, _MSVC_LANG and _HAS_CXX17 macros.
2018-08-13 16:19:51 -07:00
Wouter van Oortmerssen
ed2415eb72 Fixed use of uoffset_t in verifier could cause wrap around.
The verifier must be resilient against any corrupt data, so
now using size_t thru-out to ensure any 64-bit offsets can
be represented.

Also added verification of alignment.

Change-Id: I87a22aa6b045c2d83b69b47a47153f2e15ad7e06
Tested: on Linux, also with libfuzzer.
2018-08-13 14:52:50 -07:00
Matias Cudich
aaa89429d3 Update JavaScript IDL generator to remove invalid Closure JSDoc comments (#4873)
* Update JavaScript IDL generator to remove invalid Closure JSDoc comments

* Revert erroneous changes

* A few more tweaks

* Updated generated code
2018-08-10 15:27:51 -07:00
iceboy
12e5cf0b29 Remove FLATBUFFERS_COPTS from bazel BUILD (#4872)
fixes #4868
2018-08-10 13:43:48 -07:00
cubeleo
75601b81cc Correctly generate identifier for enums. (#4871)
This should allow the EnumName* function to work with enums generated
using the --scoped-enum flag.
2018-08-10 13:41:32 -07:00
Andrew Selle
e203882d54 Clarify flatbuffer reflection struct sizes to be less error-prone. (#4870) 2018-08-10 10:55:54 -07:00
iceboy
b9f1103b8a Add licenses to BUILD (#4867)
This allows to build flatbuffers from third_party directory.
2018-08-10 08:21:17 -07:00
Dan Field
fd40cc61a4 Ensure strings are null terminated when written from Dart (#4862)
* Update for Dart 2.x constants

* Fix strings, update test, add CHANGELOG for Dart
2018-08-09 09:50:54 -07:00
Wouter van Oortmerssen
38a6623f34 Temporarily disabled Android CI until fix.
Change-Id: I0c6758db7b4007e84b7ab8daaecd233711df8cab
2018-08-06 16:52:09 -07:00
Vladimir Glavnyy
27e4f43b77 Attach header directory information to the "flatbuffers" library target (#4849)
* Attach header directory information to the "flatbuffers" library target, if the CMake version supports it.

* Cleanup and documentation update
2018-08-06 14:59:29 -07:00
Kamil Rojewski
42515cfd33 Publishing flatc with conan (#4852)
* Eclipse ignore

* TypeScript support

* Prefixing enums

* Test results

* Merged JS and TS generators

* Fixed AppVeyor build problems

* Fixed more AppVeyor build problems

* Fixed more AppVeyor build problems

* Changed TS flag to options struct

* Storing options by value

* Removed unneeded const

* Re-export support for unions

* Uint support

* Casting bools to numbers for mutation

* TS shell tests

* Reverted generates js test file to original version

* Backing up js tests and properly generating test data

* Not importing flatbuffers for TS test generation

* Not overwriting generated js for tests

* AppVeyor test fixes

* Generating the most strict TS code possible

* Not returning null when creating vectors

* Not returning null from struct contructors

* Vector of unions for ts/js

* Sanity check for languages

* Indentation fix + output test files

* Vectors of unions for php

* Fixes to union vector handling + tests

* Fix for strictPropertyInitialization

* Fix for new aligned operator new for gcc >= 7.1

* Not generating imports/ns prefixes with --gen-all

* TypeScript docs

* Missing imports of enums

* Missing TS links

* Enabled vector of unions for java, since it seems to work

* Added jitpack config

* Added obj to vector of unions getter

* Removed unneeded accessor

* Bumped jdk version in pom.xml

* Vector of unions support for c#

* Missing TypeScript doc processing

* Option to NOT force libc++ when building with clang

* Publishing flatc with conan
2018-08-06 12:45:35 -07:00
Charlie Harrison
5d3648b88a Remove using namespace std; (#4851) 2018-08-06 12:08:49 -07:00
Wouter van Oortmerssen
fc3ce7d1ab Fixed VS2010 compile error.
Change-Id: Ibd970d30b51f77a2ac9c125e400c9f1b19a81cbc
2018-08-06 12:06:59 -07:00
aardappel
4898809eca FlatBuffers implementation for the Lobster programming language
Language, see: http://strlen.com/lobster/ and https://github.com/aardappel/lobster
2018-07-29 13:23:00 -07:00
shassani
ca5aaf62d3 Adds multi-line to FLatBufferToString (#4847)
Adding multi-line option to FlatBufferToString method in minireflect to allow more readable output for larger flatbuffers.
2018-07-27 12:45:12 -07:00
Wouter van Oortmerssen
c80f8d18c1 Fixed FlatBufferBuilder::Required not checking vtable size.
As reported in: https://github.com/google/flatbuffers/issues/4846
Tested: on Linux.

Change-Id: Id5e82dc5a46a681119cfe5a15415d522aac0e1f2
2018-07-27 12:41:50 -07:00
cubeleo
0d1559bdd4 For sparse enums, use a switch statement to generate EnumNameXXX(). (#4845) 2018-07-27 08:32:19 -07:00
Robert
8b39a0ee53 Merge pull request #4843 from rw/2018-07--explicit-enumish-types
go: give enums their own scalar types
2018-07-26 16:57:01 -07:00
rw
f675f6433c go: give enums their own scalar types 2018-07-26 16:46:35 -07:00
Paul Reimer
118093b613 Update FLATBUFFERS_HAS_STRING_VIEW __cplusplus checks to the versions provided by the standard feature test macros. (#4841) 2018-07-26 15:40:41 -07:00
Robert
1bb2a3bd08 Merge pull request #4820 from nairb774/master
[Go] encode.go performance changes
2018-07-26 15:35:45 -07:00
Dan Field
2361dfb66a Update for Dart 2.x constants (#4842) 2018-07-26 14:21:23 -07:00
Derek Bailey
7b50004ec9 Performance Increase of Vector of Structures using .NET BlockCopy (#4830)
* Added Get<vector_name>Array() method for accessing vectors of structures in C# using Buffer.Blockcopy().

* Added Get<vector_name>Array() method for accessing vectors of structures in C# using Buffer.Blockcopy().

Added Create<Name>VectorBlock() method to add a typed array using Buffer.BlockCopy() to speed up creation of vector of arrays

New Lua files for namespace test

* fixed c++ style issue
2018-07-26 13:44:40 -07:00
Wouter van Oortmerssen
6e185d06a7 Fixed minalign in Lua being reset on StartObject
Change-Id: I9cd62b38c8dc526f069726a88baef63e4b0dae57
2018-07-23 16:36:21 -07:00
Robert
c949229395 go: do not clobber minalign when we create objects (#4834) 2018-07-23 16:34:08 -07:00
Robert
e1d5fda5d4 python: do not clobber minalign when we create objects (#4833) 2018-07-23 16:29:45 -07:00
Evan Moran
a2603ec27e Add missing public header minireflect.h to bazel build (#4832) 2018-07-23 16:28:49 -07:00
Evan Moran
5f1b1ad42c Fixing bazel build's missing lua file (#4831) 2018-07-23 16:28:09 -07:00
shassani
4235a25640 Adds ForceStringAlignment to flatbuffers. (#4828)
ForceStringAlignment is useful for memory aligning string fields in flatbuffers.
2018-07-19 16:00:31 -07:00
Shivendra Agarwal
88cd182349 Restricting (typed=false, fixed=true) combination in flexbuffer CreateVector (#4825)
https://github.com/google/flatbuffers/issues/4815
2018-07-19 14:59:06 -07:00
Shivendra Agarwal
7c824ef690 Fixing an assert in flexbuffers CreateVector (#4824)
An assert was blocking the creation of typedvectors. It was wrongly checking for limited types even though vector was not of fixedTyped.
2018-07-19 14:55:06 -07:00
Kamil Rojewski
6bfa107f4e Option to NOT force libc++ when building with clang (#4826)
* Eclipse ignore

* TypeScript support

* Prefixing enums

* Test results

* Merged JS and TS generators

* Fixed AppVeyor build problems

* Fixed more AppVeyor build problems

* Fixed more AppVeyor build problems

* Changed TS flag to options struct

* Storing options by value

* Removed unneeded const

* Re-export support for unions

* Uint support

* Casting bools to numbers for mutation

* TS shell tests

* Reverted generates js test file to original version

* Backing up js tests and properly generating test data

* Not importing flatbuffers for TS test generation

* Not overwriting generated js for tests

* AppVeyor test fixes

* Generating the most strict TS code possible

* Not returning null when creating vectors

* Not returning null from struct contructors

* Vector of unions for ts/js

* Sanity check for languages

* Indentation fix + output test files

* Vectors of unions for php

* Fixes to union vector handling + tests

* Fix for strictPropertyInitialization

* Fix for new aligned operator new for gcc >= 7.1

* Not generating imports/ns prefixes with --gen-all

* TypeScript docs

* Missing imports of enums

* Missing TS links

* Enabled vector of unions for java, since it seems to work

* Added jitpack config

* Added obj to vector of unions getter

* Removed unneeded accessor

* Bumped jdk version in pom.xml

* Vector of unions support for c#

* Missing TypeScript doc processing

* Option to NOT force libc++ when building with clang
2018-07-19 09:40:28 -07:00
Wouter van Oortmerssen
0cd8daf14e Missing Lua generated files
Change-Id: Id668ade474805dd9c7e108a478db3551d6a62b48
2018-07-16 16:44:49 -07:00
Wouter van Oortmerssen
79f2adc50a Renamed Verifier methods
The name Verify was getting too overloaded, and confused
the VS compiler

Change-Id: I26423a4d513e4def2f4e41d7f278bb683fc12518
2018-07-16 16:42:10 -07:00
Wouter van Oortmerssen
dcfe38c58f Dart generated code changes
Change-Id: I1110974a375acb9668552294632658d9d1779772
2018-07-16 16:42:10 -07:00
shassani
51d9641de6 flatbuffer force-empty option (#4822) 2018-07-16 16:05:06 -07:00
Wouter van Oortmerssen
af6c0e6839 Updated fuzzer scripts
Point to new Chromium location
Also enable UBSan

Change-Id: I4ba182e3c6a967ad89090b776d05762fa9ae6e40
2018-07-16 15:51:28 -07:00
Wouter van Oortmerssen
7c3cb5caa1 Fixed assert in ParseSingleValue (found by fuzzer)
Change-Id: I84674eaab75b2b455e918b04e3027920430678ac
2018-07-16 15:51:28 -07:00
Wouter van Oortmerssen
8f1bebba05 C++ verifier now primarily uses offsets instead of pointers.
Fix for: https://bugs.chromium.org/p/chromium/issues/detail?id=834710

Before, the verifier would create pointers to objects, and then
verify they are inside the buffer. But since even constructing pointers
that are outside a valid allocation is Undefinied Behavior in C++, this
can trigger UBSAN (with -fsanitize=pointer-overflow).

Now instead the bounds checking is first performed using offsets
before pointers are even created.

Change-Id: If4d376e90df9847e543247e70a062671914dae1b
Tested: on Linux.
2018-07-16 15:51:28 -07:00
xgdgsc
cda1525f84 📝 release mode in building doc (#4819) 2018-07-16 12:56:14 -07:00
Damien Pontifex
72b05bc865 Convert net/FlatBuffers project to be compatible with netstandard (#4811) 2018-07-16 09:13:36 -07:00
Brian Atkinson
b3e4d9169b [Go] Force a single, early bounds check on read and write paths.
As an example, GetInt64 used to perform 8 bounds checks, one for each
slice access. By performing a bound check on the highest index, the
number of checks is reduced to one through bounds-check-elimination.
2018-07-15 16:49:21 -07:00
Brian Atkinson
e2eb6af3e3 [Go] Unroll WriteUint64 and WriteInt64.
This enables both WriteUint64 and WriteInt64 to both be inlined as
well as implemented with a single assembly instruction. The current Go
compiler refuses to inline functions with for loops. The compiler is
also not smart enough to produce a single assembly instruction for the
for-loop.
2018-07-15 16:47:17 -07:00
Wouter van Oortmerssen
b188fde27e Fixed Uint() method actually storing a signed int.
Also fixed two constructors missing explicit.

Change-Id: I147b2d2517bb660d92d4b0167992c115ed65dca7
2018-07-06 12:30:43 -07:00
Derek Bailey
ba5eb3b5cf Lua (5.3) Language addition (#4804)
* starting Lua port of python implmention. Syncing commit

* Bulk of Lua module port from Python done. Not tested, only static analysis. Need to work on binary strings. Started work on flatc lua code generation

* Fixed all the basic errors to produced a binary output from the builder, don't know if it is generated correctly, but it contains data, so that must be good

* fixed binary set command that was extending the array improperly

* continued improvement

* Moved lua submodules down a directory so their names don't clash with potential other modules. Added compat module to provide Lua versioning logic

* Successful sample port from Python

* working on testing Lua code with formal tests

* continued to work on tests and fixes to code to make tests pass

* Added reading buffer test

* Changed binaryarray implmentation to use a temporary table for storing data, and then serialize it to a string when requested. This double the rate of building flatbuffers compared to the string approach.

* Didn't need encode module as it just added another layer of indirection that isn't need

* profiled reading buffers, optimizations to increase read performance of monster data to ~7 monster / millisecond

* Writing profiler improvments. Get about
~2 monsters/millisecond building rate

* removed Numpy generation from Lua (came from the Python port)

* math.pow is deprecated in Lua 5.3, so changed to ^ notation. Also added .bat script for starting Lua tests

* adding results of generate_code.bat

* simple edits for code review in PR.

* There was a buffer overflow in inserting the keywords into the unorder set for both the Lua and Python code gens. Changed insertion to use iterators.

* fixed spacing issue

* basic documenation/tutorial updates. Updated sample_binary.lua to reflect the tutorial better

* removed windows-specific build step in Lua tests
2018-07-05 15:55:57 -07:00
Vladimir Glavnyy
8ea293b988 Issue #4799 fixed. Generator for KeyCompareWithValue is extracted. (#4802)
* Issue #4799 fixed. Generator for KeyCompareWithValue is extracted.

* format fix
2018-07-05 09:23:40 -07:00
Woody Guo
f19803d364 Dart: Add missing imports (#4803) 2018-07-03 08:44:27 -07:00
shassani
b2d69aacf4 Helper function to get empty string on nullptr (#4800)
Adds helper function to get empty string when String is nullptr.

This is to get over the fact that flat buffer builders will record null when data
is not present.
2018-07-02 09:34:18 -07:00
Woody Guo
3331805a1c Dart: Fix default values (#4795) 2018-06-28 10:12:18 -07:00
Kapil Sharma
ea06768ad1 Go GRPC generator Updates - Fixes #4787 (#4797)
* Fix for #4787

- Updated the grpc generator for go to use full namespace for service
rpc method names

* Formatting Fix

- Set to Google Style Formatting
2018-06-27 09:57:40 -07:00
Paul Reimer
741c63052d Add --force-defaults option to flatc [C++, parser] (#4729)
* Add --force-defaults option to flatc

To emit default values for fields which are not present or which are set
to the default value.

* flatc option --force-defaults should have a default value (false) and take action on the builder_ within the Parser constructor

* Add help text from flatc --force-defaults to Compiler.md doc

* Clarified docs for flatc --force-defaults, and imply that this behaviour is not normally needed.

* Updated docs and flatc help text for --force-defaults option
2018-06-27 09:12:52 -07:00
Wouter van Oortmerssen
e9912e9298 Added setup.cfg to default to python 2/3 wheels for pypi.
Change-Id: I64cf42aca79c32d21cd15c1415125ba97665d134
2018-06-25 15:08:06 -07:00
Polynomdivision
7dbc8f564a docs: fix flatc instructions (#4794) 2018-06-25 14:55:18 -07:00
Wouter van Oortmerssen
a2fe49b498 Fixed documentation comments at the start of a file.
Change-Id: Ic24018a6cd604c71b4d8d3cd35dc7a583fb18394
2018-06-25 14:02:12 -07:00
Wouter van Oortmerssen
7dd5cfb510 Fixed empty structs generating bad constructor.
This was fixed previously here:
5fd0fefab6
but somehow got undone in intermediate refactors.

Change-Id: I86e45a3f96f67a2b3d84d44081403baef6798921
2018-06-25 12:28:01 -07:00
Shivendra Agarwal
00b741e5fb Comment update for ForceDefaults. (#4788)
Current comment is a bit ambiguous. Default values can be read either if field is not written (like in table), or if they are written explicitly by client but not serialized due to optimization. Impression from current comment is that all the default values which are coming during read are from binaries when we turn-on Force-Defaults. However, that will be a wrong interpretation.

Force_Defaults = true ensures to turn OFF later optimization. In case a field is not written, during read we will get default values but they will still not be serialized.
2018-06-21 08:50:36 -07:00
Shivendra Agarwal
bb321fbe19 CreateUnitializedVectorOfStructs and tests (#4781)
* CreateUnitializedVectorOfStructs and tests

* Incorporating review comments

* snake_case variable names
2018-06-18 10:12:26 -07:00
Wouter van Oortmerssen
7330436713 Protected parser against infinite recursion.
Will error-out after e.g. 64 levels of nested JSON tables.

Change-Id: I3ab66cdd509378bfab87b85f85c07ab42aded788
Tested: on Linux.
2018-06-14 16:17:19 -07:00
Wouter van Oortmerssen
f9c64891dd Fixed ASan array out of bounds.
Change-Id: I53366bd14548aa41c3d25bcd187d7436d47e8665
Tested: on Linux.
2018-06-14 15:13:01 -07:00
zejal
b752e4a9bb Fix misaligned nested buffers (#4785) 2018-06-14 09:21:42 -07:00
Kamil Rojewski
3e3c770c4e Fixed TypeScript links in docs (#4783)
* Eclipse ignore

* TypeScript support

* Prefixing enums

* Test results

* Merged JS and TS generators

* Fixed AppVeyor build problems

* Fixed more AppVeyor build problems

* Fixed more AppVeyor build problems

* Changed TS flag to options struct

* Storing options by value

* Removed unneeded const

* Re-export support for unions

* Uint support

* Casting bools to numbers for mutation

* TS shell tests

* Reverted generates js test file to original version

* Backing up js tests and properly generating test data

* Not importing flatbuffers for TS test generation

* Not overwriting generated js for tests

* AppVeyor test fixes

* Generating the most strict TS code possible

* Not returning null when creating vectors

* Not returning null from struct contructors

* Vector of unions for ts/js

* Sanity check for languages

* Indentation fix + output test files

* Vectors of unions for php

* Fixes to union vector handling + tests

* Fix for strictPropertyInitialization

* Fix for new aligned operator new for gcc >= 7.1

* Not generating imports/ns prefixes with --gen-all

* TypeScript docs

* Missing imports of enums

* Missing TS links

* Enabled vector of unions for java, since it seems to work

* Added jitpack config

* Added obj to vector of unions getter

* Removed unneeded accessor

* Bumped jdk version in pom.xml

* Vector of unions support for c#

* Missing TypeScript doc processing
2018-06-12 11:37:10 -07:00
Woody Guo
5a3f18d17d Dart: Generate the enum from 0 if value is null and fix inconsistent naming when generating object builder (#4782)
* Dart: Generate the enum from 0 if value is null

* Dart: Fix inconsistent naming when generating object builder
2018-06-12 11:35:40 -07:00
Wouter van Oortmerssen
10bdcefa4a Re-enable clang / os x in .travis
Change-Id: I45f6326f1b7da2d83eeee72fe44fd9626a288b5b
2018-06-08 11:20:57 -07:00
Wouter van Oortmerssen
9bab626cbf Removed biicode from repo.
Change-Id: I8b517fb8eaf02772052d95ca55bdaa0efbffa65a
2018-06-08 11:03:34 -07:00
Wouter van Oortmerssen
effb608027 Added missing Dart generated files.
Change-Id: I27986e8aaf2f672145af9beae6ab659b272c9721
2018-06-08 10:59:46 -07:00
Michael Seifert
a96f2bd6ca Python: Escape enum member names if they correspond to a Python keyword (#4772)
* Python: Generated enum member names are now escaped if they correspond to a Python keyword.

* Keyword list in Python generator is now a const char* instead of an std::string array.

* Moved static functions and keyword list of Python generator into the PythonGenerator class.

* Python generator escapes keyword identifiers in all definitions.
2018-06-08 10:55:19 -07:00
Tin Tvrtković
ab3b721a54 Python: fix default bool value. (#4773)
* Python: fix default bool value.

* Small style tweak.
2018-06-07 12:02:35 -07:00
Wouter van Oortmerssen
4cfe36ae8e Enforcing CreateUninitializedVector is only used with scalars.
This function cannot work with any offset types (since offsets
must always point forward) so this avoid possible mistakes.

Change-Id: I1b3dfbefc8d40da630345b9b04f9aff4a990e8e5
2018-06-07 08:49:38 -07:00
Vladimir Glavnyy
c7a797b966 Makes VectorIterator compatible with STL iterators. (#4768) 2018-06-04 12:02:08 -07:00
Vladimir Glavnyy
ecc07e7793 Fix a small problem with add_subdirectory(${FLATBUFFERS_DIR}) from top level project. (#4764) 2018-06-01 08:22:17 -07:00
Christian Helmich
43944a0ab1 renamed flexbuffers::Type enum values TYPE_ -> FBT_ (#4761)
reason: TYPE_BOOL is a macro defined in some iOS build configurations.
2018-05-31 11:06:44 -07:00
Wouter van Oortmerssen
27ce09860a Fixed typo in Java/C# tutorial.
Change-Id: I956b27f37b11988e67d0403a596c0569eacbfc2a
2018-05-31 09:53:47 -07:00
Wouter van Oortmerssen
3a2f6d5300 Fixed ASAN false positive.
Change-Id: I79d9b2cddc61df5919bc4a93627fba2aa69e5d49
Tested: on Linux.
2018-05-31 09:49:05 -07:00
Steve Barman
06d3229dc3 adds https to landing page link so it resolves (#4757) 2018-05-31 09:37:51 -07:00
Gautham B A
348fcb5b88 Fix typo in tutorial for Go (#4756)
Fixed a typo in serialising the inventory for Orc.
2018-05-31 09:17:34 -07:00
Nathan Mitchell
b4ca4d3cde Javascript: Add suppport for ES6 style exports (#4754)
* Add suppport for ES6 style exports

Adds support for ECMAScript 6 module exports during Javascript
generation. This is useful as many development projects are
switching to this new standard and away from custom module
solutions. By integrating support into flatbuffers, users
do not need to perform additional post-processing of generated
files in order to use flatbuffers output directly in their
codebases.

Reference to ECMAScript 6 modules:
https://www.ecma-international.org/ecma-262/6.0/#sec-exports

Changes:
* Added `--es6-js-export` option to cli parser tool
* Added conditional code to generate a ES6 style export
  line, replacing the normal NodeJS/RequireJS line.

* Fixed missing export statements

Added exports for definition and struct names that were not inside namespaces

* Updated Compiler.md with new generator option

Added entry to Compiler.md in docs for the `--es6-js-export` flag, including a brief description of the effects and usefulness.
2018-05-31 08:29:58 -07:00
Wouter van Oortmerssen
0848f58cdd Changed how the default allocator is handled.
This is to not need static variables, which could trip up users
with destruction order problems.

This potentially makes these operations slightly slower, but I
think they're infrequent enough that this should not be noticable.

Also there is one breaking API change, for a method that is not
used by any code in FlatBuffers and is assumed to affect very
few if any users. A namechange and comment ensures that those
affected, if any, will not run into trouble silently.

Change-Id: I16c1352d1dfc9092c816ddb7e353ed7f5f417444
Tested: on Linux.
2018-05-18 14:48:59 -07:00
Vitaly Bondar
8e42f44807 Fix of namespace problem described in #4747 (#4752) 2018-05-18 12:21:08 -07:00
Dan Field
88912640d0 Add [Dart] support (#4676)
* Add [Dart] support

* fix enum vectors

* Allow for opt out of string interning

* fix comment style, make interning opt in

* remove Offset<T>, prefer int

* avoid creating unnecessary vtable objects

* start work on tests - do not generate builder if struct has 0 fields - add int64

* support reading structs properly

* correctly handle reading vectors of structs, dartfmt

* support structs, fix unnecessary prepares

* fix bool customizations

* undo unintentional removal of file

* docs updates, complete tutorial, bug fix for codegen

* more documentation

* Update docs, add to doxygen file

* update package structure, add samples script/code

* rearrange sample

* Tests

* Add readme for pub

* cleanup package for pub

* update docs for renamed file

* remove custom matcher, use `closeTo` instead

* remove unintentional file

* remove unintended file checkin

* use auto, move method, cleanup

* refactor to ObjectBuilders, add Builders

* Update tests, examples

* Add files missing from previous commit

* documentation and example updates

* Update LICENSE, make dartanalyzer happy, fix minor bugs, get rid of duplicate files, publish script

* fix sample for slightly different schema

* Update pubspec.yaml
2018-05-18 11:06:15 -07:00
joligarson
c43a0beff0 Fix undertermined execution behavior (#4751)
Fix for the issue #4744: Ambiguous side-effect execution on vector_downward::make_space() method.
C++ does not impose evaluation order on the two expressions on the right side of the assignment, so compiler can freely decide. As ensure_space() method can change the value of "cur_" variable, the result of the subtraction may be different depending on the evaluation order, which is ambiguous in C++.
In order to make this code deterministic and correct, cur_ must be evaluated after ensure_space() is called.
2018-05-18 09:15:20 -07:00
Tin Tvrtković
a9640bd9e1 [BREAKING CHANGE] Python: handle bool table fields properly. (#4736)
* Python: handle bool table fields properly.

* Small refactor.

* Use snake_case instead of camelCase. Use auto.
2018-05-14 13:30:10 -07:00
Kamil Rojewski
f11ffedb2b Vector of unions support for java and c# (#4735)
* Eclipse ignore

* TypeScript support

* Prefixing enums

* Test results

* Merged JS and TS generators

* Fixed AppVeyor build problems

* Fixed more AppVeyor build problems

* Fixed more AppVeyor build problems

* Changed TS flag to options struct

* Storing options by value

* Removed unneeded const

* Re-export support for unions

* Uint support

* Casting bools to numbers for mutation

* TS shell tests

* Reverted generates js test file to original version

* Backing up js tests and properly generating test data

* Not importing flatbuffers for TS test generation

* Not overwriting generated js for tests

* AppVeyor test fixes

* Generating the most strict TS code possible

* Not returning null when creating vectors

* Not returning null from struct contructors

* Vector of unions for ts/js

* Sanity check for languages

* Indentation fix + output test files

* Vectors of unions for php

* Fixes to union vector handling + tests

* Fix for strictPropertyInitialization

* Fix for new aligned operator new for gcc >= 7.1

* Not generating imports/ns prefixes with --gen-all

* TypeScript docs

* Missing imports of enums

* Missing TS links

* Enabled vector of unions for java, since it seems to work

* Added jitpack config

* Added obj to vector of unions getter

* Removed unneeded accessor

* Bumped jdk version in pom.xml

* Vector of unions support for c#
2018-05-14 11:12:24 -07:00
Keef Aragon
5d42c8352e Set Working Directory for flatc commands (#4737) 2018-05-14 09:20:49 -07:00
Paul Reimer
7c1203d44c Add define/ifdef blocks, alternate sprintf implementation via FLATBUFFERS_PREFER_PRINTF [C++] (#4700)
* Add define/ifdef blocks for FLATBUFFERS_PREFER_PRINTF to avoid using std::*streams for idl_parser

* Use string::size() as limit in snprintf

* Refactored FLATBUFFERS_PREFER_PRINTF guarded feature into NumToStringImplWrapper around sprintf

* Remove '.0' where not needed from IntToDigitCount

* Remove leading dot from name in GetFullyQualifiedName when FLATBUFFERS_PREFER_PRINTF is enabled

* Return string directly from conversion functions where possible when FLATBUFFERS_PREFER_PRINTF is enabled

* Use string instead of stringstream for GetFullyQualifiedName

* Revert removing leading dot from GetFullyQualifiedName, it does need to be there for parity with the stringstream implementation

* Dot is single char in Namespace::GetFullyQualifiedName

* Remove trailing (duplicate) null-byte from NumToStringImplWrapper when using FLATBUFFERS_PREFER_PRINTF.

* Update preprocessor indenting (and use clang-format off/on) for FLATBUFFERS_PREFER_PRINTF

* Reduce whitespace, unneeded braces in FLATBUFFERS_PREFER_PRINTF string width functions

* Remove unneeded use of iostream from idl_parser.cpp, std::string is used instead

* Tell snprintf to use the trailing null byte expected at the end of std::string buffer
2018-05-10 13:31:02 -07:00
Paul Reimer
a0a33d94a7 Add string view [C++] (#4730)
* Add view() method on flatbuffers::String, to return a string_view type
if support for std::string_view (or alternately
std::experimental::string_view) is found

* Move detection/definition of FLATBUFFERS_STRING_VIEW to base.h, use the
macro (if it is defined) as the argument type for an overload of CreateString

* Rename String::view() to String::string_view() and use the existing c_str() method for the data pointer

* Add and explain minimum C++ standard version checks for FLATBUFFERS_STRING_VIEW implementations

* Updated preprocessor indenting for FLATBUFFERS_STRING_VIEW

* Convert FLATBUFFERS_STRING_VIEW macro to typedef in flatbuffers:: namespace, and boolean feature toggle macro FLATBUFFERS_HAS_STRING_VIEW

* Prepend flatbuffers:: namespace to disambiguate flatbuffers::string_view typedef from String::string_view()

* clang-format as-she-is-spoke for FLATBUFFERS_HAS_STRING_VIEW
2018-05-10 13:30:35 -07:00
Tin Tvrtković
b10123ff63 Python: return None for missing strings. (#4733)
[BREAKING CHANGE] Python: return None for missing strings.
2018-05-10 10:34:20 -07:00
Mike Mansell
3a2c535592 Remove @Nullable (Java) for required fields (fixes #4724) (#4726)
@Nullable is only a compiler informational attribute.
Removing for required fields improves compiler warnings
but doesn't impact any running code.
2018-05-10 09:27:23 -07:00
Paul Reimer
6621424308 Add --root-type option to flatc [C++, parser, JSON] (#4728)
* Add --root-type option to flatc

To select or override a root_type

* Add help text from flatc --root-type to Compiler.md doc
2018-05-07 16:07:52 -07:00
Wouter van Oortmerssen
d215852f52 Several pom.xml files did not have their version bumped to 1.9.0
Change-Id: I7c9bb5406ae8df951afe12a008f0d071e0195bfa
2018-05-07 08:46:34 -07:00
Vladimir Glavnyy
12c4c2238c Output JSON strings as natural UTF-8 text without escapes (#4710)
* Added support for the non-escaped print of utf-8 string.

* EscapeString: the first invalid symbol resets print_natural_utf8 flag to false.

* Move the test to ParseAndGenerateTextTest. Fixes.

* Removed dependence between `natural_utf8` and `allow_non_utf8` flags.
2018-05-03 12:10:45 -07:00
iceboy
85faa46fb3 Fix union escaping order. (#4722)
* Fix union escaping order.

Fixes #4712

* style
2018-05-03 11:59:30 -07:00
iceboy
cc354ea368 Delete ByteBuffer.exe (#4721) 2018-05-03 11:58:29 -07:00
husobee
bed19a5340 Addition of Go FinishWithFileIdentifier (#4720)
* Addition of Go FinishWithFileIdentifier, allows for Go flatbuffer data to contain a file identifier

* adding panic as per review if fileIdentifier does not match length, letting prep pad the file identifier

* updated error message to not use fmt.Sprintf

* using minalign for alignment for file identifier
2018-04-30 14:37:24 -07:00
Tobias Oberstein
9bb88a026a Include services in reflection data (fixes #4639) (#4713)
* include service in reflection data (fixes #4639)

* changes from review

* regenerated test data
2018-04-27 13:31:18 -07:00
Mark Henderson
34cb163e38 Adding JS function to get the File Identifier (#4715)
* Adding JS  function to get the File Identifier

* Update flatbuffers.js
2018-04-23 12:54:20 -07:00
Vladimir Glavnyy
a66f9e769b The asserts replaced by FLATBUFFERS_ASSERT. (#4701)
* The asserts replaced by FLATBUFFERS_ASSERT. Several asserts have converted to static_asserts.

* Regenerate header monster generate_code.sh
2018-04-16 08:57:59 -07:00
Sergey Avseyev
86153fd740 Remove unnecessary const qualifier (#4698)
In file included from include/flatbuffers/flexbuffers.h:24,
                 from src/idl_gen_text.cpp:20:
include/flatbuffers/util.h: In function 'int flatbuffers::FromUTF8(const char**)':
include/flatbuffers/util.h:324:45: error: type qualifiers ignored on cast result type [-Werror=ignored-qualifiers]
   if ((static_cast<const unsigned char>(**in) << len) & 0x80) return -1;  // Bit after leading 1's must be 0.
                                             ^
cc1plus: all warnings being treated as errors
make[2]: *** [CMakeFiles/flatbuffers_shared.dir/build.make:92: CMakeFiles/flatbuffers_shared.dir/src/idl_gen_text.cpp.o] Error 1
2018-04-06 11:33:07 -07:00
Vladimir Glavnyy
7eb4c6098e An user-defined attribute name validation (#4689)
* User-declared attribute should be either identifier or string with the identifier.

* Attribute can be identifier or string in metadata.
2018-04-06 09:07:59 -07:00
Paul Reimer
af3c598189 Rename MANUALLY_ALIGNED_STRUCT to add FLATBUFFERS_ prefix in generated code within tests/. Via running cd tests && sh generate_code.sh (#4696) 2018-04-05 16:36:42 -07:00
Paul Reimer
eac0bc6490 Add FLATBUFFERS_ prefix to defines [C++] (#4695)
* Rename STRUCT_END to add FLATBUFFERS_ prefix, now FLATBUFFERS_STRUCT_END. Via running `ag -l STRUCT_END | xargs rpl STRUCT_END FLATBUFFERS_STRUCT_END`

* Rename MANUALLY_ALIGNED_STRUCT to add FLATBUFFERS_ prefix, now FLATBUFFERS_MANUALLY_ALIGNED_STRUCT. Via running `ag -l MANUALLY_ALIGNED_STRUCT | xargs rpl MANUALLY_ALIGNED_STRUCT FLATBUFFERS_MANUALLY_ALIGNED_STRUCT && cd tests && sh generate_code.sh`

* Rename DEFINE_BITMASK_OPERATORS to add FLATBUFFERS_ prefix, now FLATBUFFERS_DEFINE_BITMASK_OPERATORS. Via running `ag -l DEFINE_BITMASK_OPERATORS | xargs rpl DEFINE_BITMASK_OPERATORS FLATBUFFERS_DEFINE_BITMASK_OPERATORS`
2018-04-05 16:00:54 -07:00
242 changed files with 29439 additions and 2764 deletions

16
.gitignore vendored
View File

@@ -12,8 +12,11 @@
*.vcxproj.user
*.sln
*.suo
*.opendb
*.keystore
**/.vs/**
**/bin/**
!tests/rust_usage_test/bin/**
**/gen/**
**/libs/**
**/obj/**
@@ -25,6 +28,8 @@
**/CMakeTestfile.cmake
**/Debug/**
**/Release/**
**/RelWithDebInfo/**
**/x64/ #build artifacts from VS
build.xml
local.properties
project.properties
@@ -45,11 +50,14 @@ grpctest
grpctest.exe
snapshot.sh
tags
tests/dart_gen
tests/go_gen
tests/monsterdata_java_wire.mon
tests/monsterdata_java_wire_sp.mon
tests/monsterdata_go_wire.mon
tests/monsterdata_javascript_wire.mon
tests/monsterdata_lobster_wire.mon
tests/monsterdata_rust_wire.mon
tests/unicode_test.mon
tests/ts/
tests/php/
@@ -93,3 +101,11 @@ js/flatbuffers.mjs
.ninja_log
build.ninja
rules.ninja
.vscode
dart/.pub/
dart/.packages
dart/pubspec.lock
dart/.dart_tool/
dart/build/
dart/doc/api/
Cargo.lock

View File

@@ -2,6 +2,29 @@ env:
global:
# Set at the root level as this is ignored when set under matrix.env.
- GCC_VERSION="4.9"
conan-linux: &conan-linux
os: linux
sudo: required
language: python
python: "3.6"
services:
- docker
install:
- ./conan/travis/install.sh
script:
- ./conan/travis/build.sh
if: tag IS present
conan-osx: &conan-osx
os: osx
language: generic
install:
- ./conan/travis/install.sh
script:
- ./conan/travis/build.sh
if: tag IS present
matrix:
include:
#- language: python
@@ -31,19 +54,14 @@ matrix:
- language: cpp
os:
- linux
- osx
compiler:
- gcc
#- clang
env:
matrix:
- BUILD_TYPE=Debug BIICODE=false
- BUILD_TYPE=Release BIICODE=false CONAN=true
# biicode .deb files no longer available.
# - BUILD_TYPE=Release BIICODE=true
# - BUILD_TYPE=Debug BIICODE=true
- BUILD_TYPE=Debug
- BUILD_TYPE=Release CONAN=true
before_install:
- if [ "$TRAVIS_OS_NAME" == "linux" ]; then sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test; fi
@@ -54,30 +72,75 @@ matrix:
- 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
- if [ "$CONAN" == "true" ] && [ "$TRAVIS_OS_NAME" == "linux" ]; then sudo pip install conan && conan create . flatbuffers/testing -s build_type=$BUILD_TYPE; fi
- bash grpc/build_grpc.sh
- cmake -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DFLATBUFFERS_BUILD_GRPCTEST=ON -DGRPC_INSTALL_PATH=$TRAVIS_BUILD_DIR/google/grpc/install -DPROTOBUF_DOWNLOAD_PATH=$TRAVIS_BUILD_DIR/google/grpc/third_party/protobuf . && make
- LD_LIBRARY_PATH=$TRAVIS_BUILD_DIR/google/grpc/install/lib make test ARGS=-V
- if [ "$CONAN" == "true" ] && [ "$TRAVIS_OS_NAME" == "linux" ]; then sudo pip install conan && conan create . google/testing -s build_type=$BUILD_TYPE -tf conan/test_package; fi
- language: android
sudo: true
android:
components:
- tools
- platform-tools
- build-tools-25.0.2
- android-25
- extra-android-m2repository
compiler:
- gcc
before_install:
- git clone https://github.com/urho3d/android-ndk.git $HOME/android-ndk-root
- export ANDROID_NDK_HOME=$HOME/android-ndk-root
# Setup environment for Linux build which is required to build the sample.
- 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
- language: cpp
os: osx
osx_image: xcode9.3
env:
matrix:
- BUILD_TYPE=Debug
- BUILD_TYPE=Release
script:
- failed=0; for build_gradle in $(git ls-files | grep build.gradle); do ( cd "$(dirname "${build_gradle}")" && ./gradlew build ) || failed=1; done; exit $((failed))
- bash grpc/build_grpc.sh
- cmake -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DFLATBUFFERS_BUILD_GRPCTEST=ON -DGRPC_INSTALL_PATH=$TRAVIS_BUILD_DIR/google/grpc/install -DPROTOBUF_DOWNLOAD_PATH=$TRAVIS_BUILD_DIR/google/grpc/third_party/protobuf . && make
- ./flattests
- DYLD_LIBRARY_PATH=$TRAVIS_BUILD_DIR/google/grpc/install/lib ./grpctest
- <<: *conan-linux
env: CONAN_GCC_VERSIONS=4.9 CONAN_DOCKER_IMAGE=lasote/conangcc49
- <<: *conan-linux
env: CONAN_GCC_VERSIONS=5 CONAN_DOCKER_IMAGE=lasote/conangcc5
- <<: *conan-linux
env: CONAN_GCC_VERSIONS=6 CONAN_DOCKER_IMAGE=lasote/conangcc6
- <<: *conan-linux
env: CONAN_GCC_VERSIONS=7 CONAN_DOCKER_IMAGE=lasote/conangcc7
- <<: *conan-linux
env: CONAN_GCC_VERSIONS=8 CONAN_DOCKER_IMAGE=lasote/conangcc8
- <<: *conan-linux
env: CONAN_CLANG_VERSIONS=3.9 CONAN_DOCKER_IMAGE=lasote/conanclang39
- <<: *conan-linux
env: CONAN_CLANG_VERSIONS=4.0 CONAN_DOCKER_IMAGE=lasote/conanclang40
- <<: *conan-linux
env: CONAN_CLANG_VERSIONS=5.0 CONAN_DOCKER_IMAGE=lasote/conanclang50
- <<: *conan-linux
env: CONAN_CLANG_VERSIONS=6.0 CONAN_DOCKER_IMAGE=lasote/conanclang60
- <<: *conan-osx
osx_image: xcode7.3
env: CONAN_APPLE_CLANG_VERSIONS=7.3
- <<: *conan-osx
osx_image: xcode8.3
env: CONAN_APPLE_CLANG_VERSIONS=8.1
- <<: *conan-osx
osx_image: xcode9
env: CONAN_APPLE_CLANG_VERSIONS=9.0
- <<: *conan-osx
osx_image: xcode9.3
env: CONAN_APPLE_CLANG_VERSIONS=9.1
#- language: android
# sudo: true
# android:
# components:
# - tools
# - platform-tools
# - build-tools-25.0.2
# - android-25
# - extra-android-m2repository
# compiler:
# - gcc
# before_install:
# - git clone https://github.com/urho3d/android-ndk.git $HOME/android-ndk-root
# - export ANDROID_NDK_HOME=$HOME/android-ndk-root
# # Setup environment for Linux build which is required to build the sample.
# - 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:
# - failed=0; for build_gradle in $(git ls-files | grep build.gradle); do ( cd "$(dirname "${build_gradle}")" && ./gradlew build ) || failed=1; done; exit $((failed))

21
BUILD
View File

@@ -1,3 +1,5 @@
licenses(["notice"])
package(
default_visibility = ["//visibility:public"],
features = [
@@ -10,11 +12,6 @@ exports_files([
"LICENSE",
])
FLATBUFFERS_COPTS = [
"-Wno-implicit-fallthrough",
"-linclude",
]
# Public flatc library to compile flatbuffer files at runtime.
cc_library(
name = "flatbuffers",
@@ -28,7 +25,6 @@ cc_library(
"src/util.cpp",
],
hdrs = [":public_headers"],
copts = FLATBUFFERS_COPTS,
includes = ["include/"],
linkstatic = 1,
)
@@ -43,6 +39,7 @@ filegroup(
"include/flatbuffers/flexbuffers.h",
"include/flatbuffers/hash.h",
"include/flatbuffers/idl.h",
"include/flatbuffers/minireflect.h",
"include/flatbuffers/reflection.h",
"include/flatbuffers/reflection_generated.h",
"include/flatbuffers/stl_emulation.h",
@@ -65,7 +62,6 @@ cc_library(
"include/flatbuffers/flatc.h",
":public_headers",
],
copts = FLATBUFFERS_COPTS,
includes = [
"grpc/",
"include/",
@@ -86,16 +82,19 @@ cc_binary(
"grpc/src/compiler/schema_interface.h",
"src/flatc_main.cpp",
"src/idl_gen_cpp.cpp",
"src/idl_gen_dart.cpp",
"src/idl_gen_general.cpp",
"src/idl_gen_go.cpp",
"src/idl_gen_grpc.cpp",
"src/idl_gen_js.cpp",
"src/idl_gen_json_schema.cpp",
"src/idl_gen_lua.cpp",
"src/idl_gen_lobster.cpp",
"src/idl_gen_php.cpp",
"src/idl_gen_python.cpp",
"src/idl_gen_rust.cpp",
"src/idl_gen_text.cpp",
],
copts = FLATBUFFERS_COPTS,
includes = [
"grpc/",
"include/",
@@ -123,10 +122,14 @@ cc_test(
"tests/namespace_test/namespace_test1_generated.h",
"tests/namespace_test/namespace_test2_generated.h",
"tests/test.cpp",
"tests/test_builder.h",
"tests/test_assert.h",
"tests/test_builder.cpp",
"tests/test_assert.cpp",
"tests/union_vector/union_vector_generated.h",
":public_headers",
],
copts = FLATBUFFERS_COPTS + [
copts = [
"-DFLATBUFFERS_TRACK_VERIFIER_BUFFER_SIZE",
],
data = [

View File

@@ -71,6 +71,8 @@ function(build_flatbuffers flatbuffers_schemas
)
endif()
set(working_dir "${CMAKE_CURRENT_SOURCE_DIR}")
set(schema_glob "*.fbs")
# Generate the include files parameters.
set(include_params "")
@@ -97,7 +99,8 @@ function(build_flatbuffers flatbuffers_schemas
-o ${generated_includes_dir}
${include_params}
-c ${schema}
DEPENDS ${FLATC_TARGET} ${schema} ${additional_dependencies})
DEPENDS ${FLATC_TARGET} ${schema} ${additional_dependencies}
WORKING_DIRECTORY "${working_dir}")
list(APPEND all_generated_files ${generated_include})
endif()
@@ -109,7 +112,8 @@ function(build_flatbuffers flatbuffers_schemas
-o ${binary_schemas_dir}
${include_params}
${schema}
DEPENDS ${FLATC_TARGET} ${schema} ${additional_dependencies})
DEPENDS ${FLATC_TARGET} ${schema} ${additional_dependencies}
WORKING_DIRECTORY "${working_dir}")
list(APPEND all_generated_files ${binary_schema})
endif()

View File

@@ -1,7 +1,7 @@
find_program(GIT git)
execute_process(
COMMAND ${GIT} describe
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
OUTPUT_VARIABLE GIT_DESCRIBE_DIRTY
OUTPUT_STRIP_TRAILING_WHITESPACE
)

View File

@@ -15,6 +15,7 @@ option(FLATBUFFERS_BUILD_GRPCTEST "Enable the build of grpctest" OFF)
option(FLATBUFFERS_BUILD_SHAREDLIB
"Enable the build of the flatbuffers shared library"
OFF)
option(FLATBUFFERS_LIBCXX_WITH_CLANG "Force libc++ when using Clang" ON)
if(NOT FLATBUFFERS_BUILD_FLATC AND FLATBUFFERS_BUILD_TESTS)
message(WARNING
@@ -45,11 +46,15 @@ set(FlatBuffers_Library_SRCS
set(FlatBuffers_Compiler_SRCS
${FlatBuffers_Library_SRCS}
src/idl_gen_cpp.cpp
src/idl_gen_dart.cpp
src/idl_gen_general.cpp
src/idl_gen_go.cpp
src/idl_gen_js.cpp
src/idl_gen_php.cpp
src/idl_gen_python.cpp
src/idl_gen_lobster.cpp
src/idl_gen_lua.cpp
src/idl_gen_rust.cpp
src/idl_gen_fbs.cpp
src/idl_gen_grpc.cpp
src/idl_gen_json_schema.cpp
@@ -73,6 +78,10 @@ set(FlatBuffers_Tests_SRCS
${FlatBuffers_Library_SRCS}
src/idl_gen_fbs.cpp
tests/test.cpp
tests/test_assert.h
tests/test_assert.cpp
tests/test_builder.h
tests/test_builder.cpp
# file generate by running compiler on tests/monster_test.fbs
${CMAKE_CURRENT_BINARY_DIR}/tests/monster_test_generated.h
)
@@ -95,8 +104,13 @@ set(FlatBuffers_GRPCTest_SRCS
include/flatbuffers/flatbuffers.h
include/flatbuffers/grpc.h
tests/monster_test.grpc.fb.h
tests/test_assert.h
tests/test_builder.h
tests/monster_test.grpc.fb.cc
tests/test_assert.cpp
tests/test_builder.cpp
grpc/tests/grpctest.cpp
grpc/tests/message_builder_test.cpp
# file generated by running compiler on samples/monster.fbs
${CMAKE_CURRENT_BINARY_DIR}/samples/monster_generated.h
)
@@ -137,14 +151,16 @@ elseif(CMAKE_COMPILER_IS_GNUCXX)
elseif(${CMAKE_CXX_COMPILER_ID} MATCHES "Clang")
set(CMAKE_CXX_FLAGS
"${CMAKE_CXX_FLAGS} -std=c++0x -Wall -pedantic -Werror -Wextra -Wno-unused-parameter")
if(NOT "${CMAKE_SYSTEM_NAME}" MATCHES "Linux")
set(CMAKE_CXX_FLAGS
"${CMAKE_CXX_FLAGS} -stdlib=libc++")
endif()
if(NOT ("${CMAKE_SYSTEM_NAME}" MATCHES "FreeBSD" OR
"${CMAKE_SYSTEM_NAME}" MATCHES "Linux"))
set(CMAKE_EXE_LINKER_FLAGS
"${CMAKE_EXE_LINKER_FLAGS} -lc++abi")
if(FLATBUFFERS_LIBCXX_WITH_CLANG)
if(NOT "${CMAKE_SYSTEM_NAME}" MATCHES "Linux")
set(CMAKE_CXX_FLAGS
"${CMAKE_CXX_FLAGS} -stdlib=libc++")
endif()
if(NOT ("${CMAKE_SYSTEM_NAME}" MATCHES "FreeBSD" OR
"${CMAKE_SYSTEM_NAME}" MATCHES "Linux"))
set(CMAKE_EXE_LINKER_FLAGS
"${CMAKE_EXE_LINKER_FLAGS} -lc++abi")
endif()
endif()
# Certain platforms such as ARM do not use signed chars by default
@@ -174,7 +190,10 @@ include_directories(include)
include_directories(grpc)
if(FLATBUFFERS_BUILD_FLATLIB)
add_library(flatbuffers STATIC ${FlatBuffers_Library_SRCS})
add_library(flatbuffers STATIC ${FlatBuffers_Library_SRCS})
# CMake > 2.8.11: Attach header directory for when build via add_subdirectory().
target_include_directories(flatbuffers INTERFACE
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>)
endif()
if(FLATBUFFERS_BUILD_FLATC)
@@ -200,7 +219,7 @@ if(FLATBUFFERS_BUILD_SHAREDLIB)
# - minor updated when there are additions in API/ABI
# - major (ABI number) updated when there are changes in ABI (or removals)
set(FlatBuffers_Library_SONAME_MAJOR "1")
set(FlatBuffers_Library_SONAME_FULL "${FlatBuffers_Library_SONAME_MAJOR}.9.0")
set(FlatBuffers_Library_SONAME_FULL "${FlatBuffers_Library_SONAME_MAJOR}.10.0")
set_target_properties(flatbuffers_shared PROPERTIES OUTPUT_NAME flatbuffers
SOVERSION "${FlatBuffers_Library_SONAME_MAJOR}"
VERSION "${FlatBuffers_Library_SONAME_FULL}")
@@ -212,7 +231,7 @@ function(compile_flatbuffers_schema_to_cpp SRC_FBS)
add_custom_command(
OUTPUT ${GEN_HEADER}
COMMAND "${FLATBUFFERS_FLATC_EXECUTABLE}" -c --no-includes --gen-mutable
--gen-object-api -o "${SRC_FBS_DIR}"
--gen-object-api --gen-compare -o "${SRC_FBS_DIR}"
--cpp-ptr-type flatbuffers::unique_ptr # Used to test with C++98 STLs
--reflect-names
-I "${CMAKE_CURRENT_SOURCE_DIR}/tests/include_test"
@@ -248,6 +267,15 @@ if(FLATBUFFERS_BUILD_GRPCTEST)
if(CMAKE_COMPILER_IS_GNUCXX)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-unused-parameter -Wno-shadow")
endif()
if(NOT GRPC_INSTALL_PATH)
message(SEND_ERROR "GRPC_INSTALL_PATH variable is not defined. See grpc/README.md")
endif()
if(NOT PROTOBUF_DOWNLOAD_PATH)
message(SEND_ERROR "PROTOBUF_DOWNLOAD_PATH variable is not defined. See grpc/README.md")
endif()
INCLUDE_DIRECTORIES(${GRPC_INSTALL_PATH}/include)
INCLUDE_DIRECTORIES(${PROTOBUF_DOWNLOAD_PATH}/src)
LINK_DIRECTORIES(${GRPC_INSTALL_PATH}/lib)
add_executable(grpctest ${FlatBuffers_GRPCTest_SRCS})
target_link_libraries(grpctest grpc++_unsecure grpc_unsecure gpr pthread dl)
endif()
@@ -337,6 +365,9 @@ if(FLATBUFFERS_BUILD_TESTS)
file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/tests" DESTINATION
"${CMAKE_CURRENT_BINARY_DIR}")
add_test(NAME flattests COMMAND flattests)
if(FLATBUFFERS_BUILD_GRPCTEST)
add_test(NAME grpctest COMMAND grpctest)
endif()
endif()
include(CMake/BuildFlatBuffers.cmake)

View File

@@ -47,6 +47,10 @@ include $(CLEAR_VARS)
LOCAL_MODULE := FlatBufferTest
LOCAL_SRC_FILES := android/jni/main.cpp \
tests/test.cpp \
tests/test_assert.h \
tests/test_builder.h \
tests/test_assert.cpp \
tests/test_builder.cpp \
src/idl_gen_fbs.cpp \
src/idl_gen_general.cpp
LOCAL_LDLIBS := -llog -landroid -latomic

View File

@@ -13,6 +13,7 @@ environment:
matrix:
- CMAKE_VS_VERSION: "10 2010"
- CMAKE_VS_VERSION: "12 2013"
- CMAKE_VS_VERSION: "14 2015"
platform:
@@ -32,8 +33,17 @@ build:
project: ALL_BUILD.vcxproj
verbosity: minimal
after_build:
- python conan/appveyor/install.py
- python conan/appveyor/build.py
install:
- set PATH=%CONDA_INSTALL_LOCN%;%CONDA_INSTALL_LOCN%\scripts;%PATH%;
- curl -sSf -o rustup-init.exe https://win.rustup.rs/
- rustup-init.exe -y
- set PATH=%PATH%;C:\Users\appveyor\.cargo\bin
- rustc -V
- cargo -V
test_script:
- "cd tests"
@@ -47,6 +57,8 @@ test_script:
- rem "---------------- Java -----------------"
- "java -version"
- "JavaTest.bat"
- rem "---------------- Rust ----------------"
- "RustTest.bat"
- rem "---------------- JS -----------------"
- "node --version"
- "..\\%CONFIGURATION%\\flatc -b -I include_test monster_test.fbs unicode_test.json"

View File

@@ -1,7 +0,0 @@
# Biicode configuration file
[paths]
include
[mains]
!android/*
[tests]
tests/*

View File

@@ -1,21 +0,0 @@
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,18 +0,0 @@
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"
"${CMAKE_CURRENT_SOURCE_DIR}/samples/monsterdata.json"
DESTINATION
"${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/samples")
endif()
if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/tests")
file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/tests"
DESTINATION
"${CMAKE_RUNTIME_OUTPUT_DIRECTORY}")
endif()
ADD_BIICODE_TARGETS()
string(REPLACE " " ";" REPLACED_FLAGS ${CMAKE_CXX_FLAGS})
target_compile_options(${BII_BLOCK_TARGET} INTERFACE ${REPLACED_FLAGS})

View File

@@ -1,30 +0,0 @@
#!/bin/bash
#
# Copyright 2016 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.
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

12
conan/CMakeLists.txt Normal file
View File

@@ -0,0 +1,12 @@
cmake_minimum_required(VERSION 2.8)
message(STATUS "Conan FlatBuffers Wrapper")
include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake)
conan_basic_setup()
if (WIN32 AND MSVC AND FLATBUFFERS_BUILD_SHAREDLIB)
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
endif(WIN32 AND MSVC AND FLATBUFFERS_BUILD_SHAREDLIB)
include(${CMAKE_SOURCE_DIR}/CMakeListsOriginal.txt)

8
conan/appveyor/build.py Normal file
View File

@@ -0,0 +1,8 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import os
if os.getenv("APPVEYOR_REPO_TAG") != "true":
print("Skip build step. It's not TAG")
else:
os.system("python conan/build.py")

View File

@@ -0,0 +1,8 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import os
if os.getenv("APPVEYOR_REPO_TAG") != "true":
print("Skip step. It's not TAG")
else:
os.system("pip install conan conan-package-tools")

32
conan/build.py Normal file
View File

@@ -0,0 +1,32 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from cpt.packager import ConanMultiPackager
import os
def set_appveyor_environment():
if os.getenv("APPVEYOR") is not None:
compiler_version = os.getenv("CMAKE_VS_VERSION").split(" ")[0].replace('"', '')
os.environ["CONAN_VISUAL_VERSIONS"] = compiler_version
os.environ["CONAN_STABLE_BRANCH_PATTERN"] = "master"
ci_platform = os.getenv("Platform").replace('"', '')
ci_platform = "x86" if ci_platform == "x86" else "x86_64"
os.environ["CONAN_ARCHS"] = ci_platform
os.environ["CONAN_BUILD_TYPES"] = os.getenv("Configuration").replace('"', '')
if __name__ == "__main__":
login_username = os.getenv("CONAN_LOGIN_USERNAME", "aardappel")
username = os.getenv("CONAN_USERNAME", "google")
upload = os.getenv("CONAN_UPLOAD", "https://api.bintray.com/conan/aardappel/flatbuffers")
stable_branch_pattern = os.getenv("CONAN_STABLE_BRANCH_PATTERN", r"v\d+\.\d+\.\d+.*")
test_folder = os.getenv("CPT_TEST_FOLDER", os.path.join("conan", "test_package"))
upload_only_when_stable = os.getenv("CONAN_UPLOAD_ONLY_WHEN_STABLE", True)
set_appveyor_environment()
builder = ConanMultiPackager(username=username,
login_username=login_username,
upload=upload,
stable_branch_pattern=stable_branch_pattern,
upload_only_when_stable=upload_only_when_stable,
test_folder=test_folder)
builder.add_common_builds(pure_c=False)
builder.run()

View File

@@ -0,0 +1,9 @@
project(test_package CXX)
cmake_minimum_required(VERSION 2.8.11)
include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake)
conan_basic_setup()
add_executable(${PROJECT_NAME} test_package.cpp)
target_link_libraries(${PROJECT_NAME} ${CONAN_LIBS})
set_property(TARGET ${PROJECT_NAME} PROPERTY CXX_STANDARD 11)

View File

@@ -0,0 +1,21 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from conans import ConanFile, CMake
import os
class TestPackageConan(ConanFile):
settings = "os", "compiler", "build_type", "arch"
generators = "cmake"
def build(self):
cmake = CMake(self)
cmake.configure()
cmake.build()
def test(self):
bin_path = os.path.join("bin", "test_package")
self.run(bin_path, run_environment=True)
self.run("flatc --version", run_environment=True)
self.run("flathash fnv1_16 conan", run_environment=True)

View File

@@ -0,0 +1,35 @@
/*
* Copyright 2018 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 <cstdlib>
#include <iostream>
#include "flatbuffers/util.h"
// Test to validate Conan package generated
int main(int /*argc*/, const char * /*argv*/ []) {
const std::string filename("conanbuildinfo.cmake");
if (flatbuffers::FileExists(filename.c_str())) {
std::cout << "File " << filename << " exists.\n";
} else {
std::cout << "File " << filename << " does not exist.\n";
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}

14
conan/travis/build.sh Executable file
View File

@@ -0,0 +1,14 @@
#!/bin/bash
set -e
set -x
if [[ "$(uname -s)" == 'Darwin' ]]; then
if which pyenv > /dev/null; then
eval "$(pyenv init -)"
fi
pyenv activate conan
fi
conan user
python conan/build.py

22
conan/travis/install.sh Executable file
View File

@@ -0,0 +1,22 @@
#!/bin/bash
set -e
set -x
if [[ "$(uname -s)" == 'Darwin' ]]; then
brew update || brew update
brew outdated pyenv || brew upgrade pyenv
brew install pyenv-virtualenv
brew install cmake || true
if which pyenv > /dev/null; then
eval "$(pyenv init -)"
fi
pyenv install 2.7.10
pyenv virtualenv 2.7.10 conan
pyenv rehash
pyenv activate conan
fi
pip install -U conan_package_tools conan

View File

@@ -4,50 +4,71 @@
"""Conan recipe package for Google FlatBuffers
"""
import os
import shutil
from conans import ConanFile, CMake, tools
class FlatbuffersConan(ConanFile):
name = "flatbuffers"
version = "1.9.0"
license = "https://github.com/google/flatbuffers/blob/master/LICENSE.txt"
version = "1.10.0"
license = "Apache-2.0"
url = "https://github.com/google/flatbuffers"
homepage = "http://google.github.io/flatbuffers/"
author = "Wouter van Oortmerssen"
description = "Memory Efficient Serialization Library"
settings = "os", "compiler", "build_type", "arch", "os_build", "arch_build"
options = {"shared": [True, False]}
default_options = "shared=False"
settings = "os", "compiler", "build_type", "arch"
options = {"shared": [True, False], "fPIC": [True, False]}
default_options = "shared=False", "fPIC=True"
generators = "cmake"
exports = "LICENSE.txt"
exports_sources = ["CMake/*", "include/*", "src/*", "grpc/*", "CMakeLists.txt"]
exports_sources = ["CMake/*", "include/*", "src/*", "grpc/*", "CMakeLists.txt", "conan/CMakeLists.txt"]
def _inject_magic_lines(self):
"""Inject Conan setup in cmake file to solve exteral dependencies.
def source(self):
"""Wrap the original CMake file to call conan_basic_setup
"""
conan_magic_lines = '''project(FlatBuffers)
include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake)
conan_basic_setup()
'''
tools.replace_in_file("CMakeLists.txt", "project(FlatBuffers)", conan_magic_lines)
shutil.move("CMakeLists.txt", "CMakeListsOriginal.txt")
shutil.move(os.path.join("conan", "CMakeLists.txt"), "CMakeLists.txt")
def config_options(self):
"""Remove fPIC option on Windows platform
"""
if self.settings.os == "Windows":
self.options.remove("fPIC")
def configure_cmake(self):
"""Create CMake instance and execute configure step
"""
cmake = CMake(self)
cmake.definitions["FLATBUFFERS_BUILD_TESTS"] = False
cmake.definitions["FLATBUFFERS_BUILD_SHAREDLIB"] = self.options.shared
cmake.definitions["FLATBUFFERS_BUILD_FLATLIB"] = not self.options.shared
cmake.configure()
return cmake
def build(self):
"""Configure, build and install FlatBuffers using CMake.
"""
self._inject_magic_lines()
cmake = CMake(self)
cmake.definitions["FLATBUFFERS_BUILD_TESTS"] = False
cmake.definitions["FLATBUFFERS_BUILD_SHAREDLIB"] = self.options.shared
cmake.configure()
cmake = self.configure_cmake()
cmake.build()
cmake.install()
def package(self):
"""Copy Flatbuffers' artifacts to package folder
"""
cmake = self.configure_cmake()
cmake.install()
self.copy(pattern="LICENSE.txt", dst="licenses")
self.copy(pattern="flathash*", dst="bin", src="bin")
self.copy(pattern="flatc*", dst="bin", src="bin")
if self.settings.os == "Windows" and self.options.shared:
if self.settings.compiler == "Visual Studio":
shutil.move(os.path.join(self.package_folder, "lib", "%s.dll" % self.name),
os.path.join(self.package_folder, "bin", "%s.dll" % self.name))
elif self.settings.compiler == "gcc":
shutil.move(os.path.join(self.package_folder, "lib", "lib%s.dll" % self.name),
os.path.join(self.package_folder, "bin", "lib%s.dll" % self.name))
def package_info(self):
"""Collect built libraries names and solve flatc path.
"""
self.cpp_info.libs = tools.collect_libs(self)
self.env_info.PATH.append(os.path.join(self.package_folder, "bin"))
self.user_info.flatc = os.path.join(self.package_folder, "bin", "flatc")

14
dart/CHANGELOG.md Normal file
View File

@@ -0,0 +1,14 @@
# CHANGELOG
## 1.9.2
- Ensure `_writeString` adds enough padding to null terminate strings.
## 1.9.1
- Changed constant identifiers to be compatible with Dart 2.x
- No longer supports Dart 1.x
## 1.9.0
- Initial release, supports Dart 1.x and many dev versions of Dart 2.x

233
dart/LICENSE Normal file
View File

@@ -0,0 +1,233 @@
The code in lib/flat_buffers.dart is based on code that was releases under the
following license:
Copyright 2012, the Dart project authors. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials provided
with the distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
To the extent permissible, the changes to that code and the other assets in
this package are licensed under the Apache2 license:
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright 2014 Google Inc.
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.

13
dart/README.md Normal file
View File

@@ -0,0 +1,13 @@
# FlatBuffers for Dart
This package is used to read and write FlatBuffer files in Dart.
Most consumers will want to use the [`flatc`](https://github.com/google/flatbuffers)
compiler to generate Dart code from a FlatBuffers IDL schema. For example, the
`monster_my_game.sample_generated.dart` was generated with `flatc` from
`monster.fbs` in the example folder. The generated classes can be used to read
or write binary files that are interoperable with other languages and platforms
supported by FlatBuffers, as illustrated in the `example.dart` in the
examples folder.
Additional documentation and examples are available [at the FlatBuffers site](https://google.github.io/flatbuffers/index.html)

155
dart/example/example.dart Normal file
View File

@@ -0,0 +1,155 @@
/*
* Copyright 2018 Dan Field. 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 'package:flat_buffers/flat_buffers.dart' as fb;
import './monster_my_game.sample_generated.dart' as myGame;
// Example how to use FlatBuffers to create and read binary buffers.
void main() {
builderTest();
objectBuilderTest();
}
void builderTest() {
final builder = new fb.Builder(initialSize: 1024);
final int weaponOneName = builder.writeString("Sword");
final int weaponOneDamage = 3;
final int weaponTwoName = builder.writeString("Axe");
final int weaponTwoDamage = 5;
final swordBuilder = new myGame.WeaponBuilder(builder)
..begin()
..addNameOffset(weaponOneName)
..addDamage(weaponOneDamage);
final int sword = swordBuilder.finish();
final axeBuilder = new myGame.WeaponBuilder(builder)
..begin()
..addNameOffset(weaponTwoName)
..addDamage(weaponTwoDamage);
final int axe = axeBuilder.finish();
// Serialize a name for our monster, called "Orc".
final int name = builder.writeString('Orc');
// Create a list representing the inventory of the Orc. Each number
// could correspond to an item that can be claimed after he is slain.
final List<int> treasure = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
final inventory = builder.writeListUint8(treasure);
final weapons = builder.writeList([sword, axe]);
// Struct builders are very easy to reuse.
final vec3Builder = new myGame.Vec3Builder(builder);
vec3Builder.finish(4.0, 5.0, 6.0);
vec3Builder.finish(1.0, 2.0, 3.0);
// Set his hit points to 300 and his mana to 150.
final int hp = 300;
final int mana = 150;
final monster = new myGame.MonsterBuilder(builder)
..begin()
..addNameOffset(name)
..addInventoryOffset(inventory)
..addWeaponsOffset(weapons)
..addEquippedType(myGame.EquipmentTypeId.Weapon)
..addEquippedOffset(axe)
..addHp(hp)
..addMana(mana)
..addPos(vec3Builder.finish(1.0, 2.0, 3.0))
..addColor(myGame.Color.Red);
final int monsteroff = monster.finish();
final buffer = builder.finish(monsteroff);
if (verify(buffer)) {
print(
"The FlatBuffer was successfully created with a builder and verified!");
}
}
void objectBuilderTest() {
// Create the builder here so we can use it for both weapons and equipped
// the actual data will only be written to the buffer once.
var axe = new myGame.WeaponObjectBuilder(name: 'Axe', damage: 5);
var monsterBuilder = new myGame.MonsterObjectBuilder(
pos: new myGame.Vec3ObjectBuilder(x: 1.0, y: 2.0, z: 3.0),
mana: 150,
hp: 300,
name: 'Orc',
inventory: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
color: myGame.Color.Red,
weapons: [new myGame.WeaponObjectBuilder(name: 'Sword', damage: 3), axe],
equippedType: myGame.EquipmentTypeId.Weapon,
equipped: axe,
);
var buffer = monsterBuilder.toBytes();
// We now have a FlatBuffer we can store on disk or send over a network.
// ** file/network code goes here :) **
// Instead, we're going to access it right away (as if we just received it).
if (verify(buffer)) {
print(
"The FlatBuffer was successfully created with an object builder and verified!");
}
}
bool verify(List<int> buffer) {
// Get access to the root:
var monster = new myGame.Monster(buffer);
// Get and test some scalar types from the FlatBuffer.
assert(monster.hp == 80);
assert(monster.mana == 150); // default
assert(monster.name == "MyMonster");
// Get and test a field of the FlatBuffer's `struct`.
var pos = monster.pos;
assert(pos != null);
assert(pos.z == 3.0);
// Get a test an element from the `inventory` FlatBuffer's `vector`.
var inv = monster.inventory;
assert(inv != null);
assert(inv.length == 10);
assert(inv[9] == 9);
// Get and test the `weapons` FlatBuffers's `vector`.
var expected_weapon_names = ["Sword", "Axe"];
var expected_weapon_damages = [3, 5];
var weps = monster.weapons;
for (int i = 0; i < weps.length; i++) {
assert(weps[i].name == expected_weapon_names[i]);
assert(weps[i].damage == expected_weapon_damages[i]);
}
// Get and test the `Equipment` union (`equipped` field).
assert(monster.equippedType.value == myGame.EquipmentTypeId.Weapon.value);
assert(monster.equippedType == myGame.EquipmentTypeId.Weapon);
assert(monster.equipped is myGame.Weapon);
var equipped = monster.equipped as myGame.Weapon;
assert(equipped.name == "Axe");
assert(equipped.damage == 5);
print(monster);
return true;
}

View File

@@ -0,0 +1,440 @@
// automatically generated by the FlatBuffers compiler, do not modify
// ignore_for_file: unused_import, non_constant_identifier_names
library my_game.sample;
import 'dart:typed_data' show Uint8List;
import 'package:flat_buffers/flat_buffers.dart' as fb;
class Color {
final int value;
const Color._(this.value);
factory Color.fromValue(int value) {
if (value == null) return null;
if (!values.containsKey(value)) {
throw new StateError('Invalid value $value for bit flag enum Color');
}
return values[value];
}
static const int minValue = 0;
static const int maxValue = 2;
static bool containsValue(int value) => values.containsKey(value);
static const Color Red = const Color._(0);
static const Color Green = const Color._(1);
static const Color Blue = const Color._(2);
static get values => {0: Red,1: Green,2: Blue,};
static const fb.Reader<Color> reader = const _ColorReader();
@override
String toString() {
return 'Color{value: $value}';
}
}
class _ColorReader extends fb.Reader<Color> {
const _ColorReader();
@override
int get size => 1;
@override
Color read(fb.BufferContext bc, int offset) =>
new Color.fromValue(const fb.Int8Reader().read(bc, offset));
}
class EquipmentTypeId {
final int value;
const EquipmentTypeId._(this.value);
factory EquipmentTypeId.fromValue(int value) {
if (value == null) return null;
if (!values.containsKey(value)) {
throw new StateError('Invalid value $value for bit flag enum EquipmentTypeId');
}
return values[value];
}
static const int minValue = 0;
static const int maxValue = 1;
static bool containsValue(int value) => values.containsKey(value);
static const EquipmentTypeId NONE = const EquipmentTypeId._(0);
static const EquipmentTypeId Weapon = const EquipmentTypeId._(1);
static get values => {0: NONE,1: Weapon,};
static const fb.Reader<EquipmentTypeId> reader = const _EquipmentTypeIdReader();
@override
String toString() {
return 'EquipmentTypeId{value: $value}';
}
}
class _EquipmentTypeIdReader extends fb.Reader<EquipmentTypeId> {
const _EquipmentTypeIdReader();
@override
int get size => 1;
@override
EquipmentTypeId read(fb.BufferContext bc, int offset) =>
new EquipmentTypeId.fromValue(const fb.Uint8Reader().read(bc, offset));
}
class Vec3 {
Vec3._(this._bc, this._bcOffset);
static const fb.Reader<Vec3> reader = const _Vec3Reader();
final fb.BufferContext _bc;
final int _bcOffset;
double get x => const fb.Float32Reader().read(_bc, _bcOffset + 0);
double get y => const fb.Float32Reader().read(_bc, _bcOffset + 4);
double get z => const fb.Float32Reader().read(_bc, _bcOffset + 8);
@override
String toString() {
return 'Vec3{x: $x, y: $y, z: $z}';
}
}
class _Vec3Reader extends fb.StructReader<Vec3> {
const _Vec3Reader();
@override
int get size => 12;
@override
Vec3 createObject(fb.BufferContext bc, int offset) =>
new Vec3._(bc, offset);
}
class Vec3Builder {
Vec3Builder(this.fbBuilder) {
assert(fbBuilder != null);
}
final fb.Builder fbBuilder;
int finish(double x, double y, double z) {
fbBuilder.putFloat32(z);
fbBuilder.putFloat32(y);
fbBuilder.putFloat32(x);
return fbBuilder.offset;
}
}
class Vec3ObjectBuilder extends fb.ObjectBuilder {
final double _x;
final double _y;
final double _z;
Vec3ObjectBuilder({
double x,
double y,
double z,
})
: _x = x,
_y = y,
_z = z;
/// Finish building, and store into the [fbBuilder].
@override
int finish(
fb.Builder fbBuilder) {
assert(fbBuilder != null);
fbBuilder.putFloat32(_z);
fbBuilder.putFloat32(_y);
fbBuilder.putFloat32(_x);
return fbBuilder.offset;
}
/// Convenience method to serialize to byte list.
@override
Uint8List toBytes([String fileIdentifier]) {
fb.Builder fbBuilder = new fb.Builder();
int offset = finish(fbBuilder);
return fbBuilder.finish(offset, fileIdentifier);
}
}
class Monster {
Monster._(this._bc, this._bcOffset);
factory Monster(List<int> bytes) {
fb.BufferContext rootRef = new fb.BufferContext.fromBytes(bytes);
return reader.read(rootRef, 0);
}
static const fb.Reader<Monster> reader = const _MonsterReader();
final fb.BufferContext _bc;
final int _bcOffset;
Vec3 get pos => Vec3.reader.vTableGet(_bc, _bcOffset, 4, null);
int get mana => const fb.Int16Reader().vTableGet(_bc, _bcOffset, 6, 150);
int get hp => const fb.Int16Reader().vTableGet(_bc, _bcOffset, 8, 100);
String get name => const fb.StringReader().vTableGet(_bc, _bcOffset, 10, null);
List<int> get inventory => const fb.ListReader<int>(const fb.Uint8Reader()).vTableGet(_bc, _bcOffset, 14, null);
Color get color => new Color.fromValue(const fb.Int8Reader().vTableGet(_bc, _bcOffset, 16, 2));
List<Weapon> get weapons => const fb.ListReader<Weapon>(Weapon.reader).vTableGet(_bc, _bcOffset, 18, null);
EquipmentTypeId get equippedType => new EquipmentTypeId.fromValue(const fb.Uint8Reader().vTableGet(_bc, _bcOffset, 20, null));
dynamic get equipped {
switch (equippedType?.value) {
case 1: return Weapon.reader.vTableGet(_bc, _bcOffset, 22, null);
default: return null;
}
}
List<Vec3> get path => const fb.ListReader<Vec3>(Vec3.reader).vTableGet(_bc, _bcOffset, 24, null);
@override
String toString() {
return 'Monster{pos: $pos, mana: $mana, hp: $hp, name: $name, inventory: $inventory, color: $color, weapons: $weapons, equippedType: $equippedType, equipped: $equipped, path: $path}';
}
}
class _MonsterReader extends fb.TableReader<Monster> {
const _MonsterReader();
@override
Monster createObject(fb.BufferContext bc, int offset) =>
new Monster._(bc, offset);
}
class MonsterBuilder {
MonsterBuilder(this.fbBuilder) {
assert(fbBuilder != null);
}
final fb.Builder fbBuilder;
void begin() {
fbBuilder.startTable();
}
int addPos(int offset) {
fbBuilder.addStruct(0, offset);
return fbBuilder.offset;
}
int addMana(int mana) {
fbBuilder.addInt16(1, mana);
return fbBuilder.offset;
}
int addHp(int hp) {
fbBuilder.addInt16(2, hp);
return fbBuilder.offset;
}
int addNameOffset(int offset) {
fbBuilder.addOffset(3, offset);
return fbBuilder.offset;
}
int addInventoryOffset(int offset) {
fbBuilder.addOffset(5, offset);
return fbBuilder.offset;
}
int addColor(Color color) {
fbBuilder.addInt8(6, color?.value);
return fbBuilder.offset;
}
int addWeaponsOffset(int offset) {
fbBuilder.addOffset(7, offset);
return fbBuilder.offset;
}
int addEquippedType(EquipmentTypeId equippedType) {
fbBuilder.addUint8(8, equippedType?.value);
return fbBuilder.offset;
}
int addEquippedOffset(int offset) {
fbBuilder.addOffset(9, offset);
return fbBuilder.offset;
}
int addPathOffset(int offset) {
fbBuilder.addOffset(10, offset);
return fbBuilder.offset;
}
int finish() {
return fbBuilder.endTable();
}
}
class MonsterObjectBuilder extends fb.ObjectBuilder {
final Vec3ObjectBuilder _pos;
final int _mana;
final int _hp;
final String _name;
final List<int> _inventory;
final Color _color;
final List<WeaponObjectBuilder> _weapons;
final EquipmentTypeId _equippedType;
final dynamic _equipped;
final List<Vec3ObjectBuilder> _path;
MonsterObjectBuilder({
Vec3ObjectBuilder pos,
int mana,
int hp,
String name,
List<int> inventory,
Color color,
List<WeaponObjectBuilder> weapons,
EquipmentTypeId equippedType,
dynamic equipped,
List<Vec3ObjectBuilder> path,
})
: _pos = pos,
_mana = mana,
_hp = hp,
_name = name,
_inventory = inventory,
_color = color,
_weapons = weapons,
_equippedType = equippedType,
_equipped = equipped,
_path = path;
/// Finish building, and store into the [fbBuilder].
@override
int finish(
fb.Builder fbBuilder) {
assert(fbBuilder != null);
final int nameOffset = fbBuilder.writeString(_name);
final int inventoryOffset = _inventory?.isNotEmpty == true
? fbBuilder.writeListUint8(_inventory)
: null;
final int weaponsOffset = _weapons?.isNotEmpty == true
? fbBuilder.writeList(_weapons.map((b) => b.getOrCreateOffset(fbBuilder)).toList())
: null;
final int equippedOffset = _equipped?.getOrCreateOffset(fbBuilder);
final int pathOffset = _path?.isNotEmpty == true
? fbBuilder.writeListOfStructs(_path)
: null;
fbBuilder.startTable();
if (_pos != null) {
fbBuilder.addStruct(0, _pos.finish(fbBuilder));
}
fbBuilder.addInt16(1, _mana);
fbBuilder.addInt16(2, _hp);
if (nameOffset != null) {
fbBuilder.addOffset(3, nameOffset);
}
if (inventoryOffset != null) {
fbBuilder.addOffset(5, inventoryOffset);
}
fbBuilder.addInt8(6, _color?.value);
if (weaponsOffset != null) {
fbBuilder.addOffset(7, weaponsOffset);
}
fbBuilder.addUint8(8, _equippedType?.value);
if (equippedOffset != null) {
fbBuilder.addOffset(9, equippedOffset);
}
if (pathOffset != null) {
fbBuilder.addOffset(10, pathOffset);
}
return fbBuilder.endTable();
}
/// Convenience method to serialize to byte list.
@override
Uint8List toBytes([String fileIdentifier]) {
fb.Builder fbBuilder = new fb.Builder();
int offset = finish(fbBuilder);
return fbBuilder.finish(offset, fileIdentifier);
}
}
class Weapon {
Weapon._(this._bc, this._bcOffset);
factory Weapon(List<int> bytes) {
fb.BufferContext rootRef = new fb.BufferContext.fromBytes(bytes);
return reader.read(rootRef, 0);
}
static const fb.Reader<Weapon> reader = const _WeaponReader();
final fb.BufferContext _bc;
final int _bcOffset;
String get name => const fb.StringReader().vTableGet(_bc, _bcOffset, 4, null);
int get damage => const fb.Int16Reader().vTableGet(_bc, _bcOffset, 6, null);
@override
String toString() {
return 'Weapon{name: $name, damage: $damage}';
}
}
class _WeaponReader extends fb.TableReader<Weapon> {
const _WeaponReader();
@override
Weapon createObject(fb.BufferContext bc, int offset) =>
new Weapon._(bc, offset);
}
class WeaponBuilder {
WeaponBuilder(this.fbBuilder) {
assert(fbBuilder != null);
}
final fb.Builder fbBuilder;
void begin() {
fbBuilder.startTable();
}
int addNameOffset(int offset) {
fbBuilder.addOffset(0, offset);
return fbBuilder.offset;
}
int addDamage(int damage) {
fbBuilder.addInt16(1, damage);
return fbBuilder.offset;
}
int finish() {
return fbBuilder.endTable();
}
}
class WeaponObjectBuilder extends fb.ObjectBuilder {
final String _name;
final int _damage;
WeaponObjectBuilder({
String name,
int damage,
})
: _name = name,
_damage = damage;
/// Finish building, and store into the [fbBuilder].
@override
int finish(
fb.Builder fbBuilder) {
assert(fbBuilder != null);
final int nameOffset = fbBuilder.writeString(_name);
fbBuilder.startTable();
if (nameOffset != null) {
fbBuilder.addOffset(0, nameOffset);
}
fbBuilder.addInt16(1, _damage);
return fbBuilder.endTable();
}
/// Convenience method to serialize to byte list.
@override
Uint8List toBytes([String fileIdentifier]) {
fb.Builder fbBuilder = new fb.Builder();
int offset = finish(fbBuilder);
return fbBuilder.finish(offset, fileIdentifier);
}
}

1241
dart/lib/flat_buffers.dart Normal file

File diff suppressed because it is too large Load Diff

28
dart/publish.sh Executable file
View File

@@ -0,0 +1,28 @@
#!/bin/sh
#
# Copyright 2018 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.
#
# Note to pub consumers: this file is used to assist with publishing the
# pub package from the flatbuffers repository and is not meant for general use.
# As pub does not currently provide a way to exclude files, it is included here.
command -v pub >/dev/null 2>&1 || { echo >&2 "Require `pub` but it's not installed. Aborting."; exit 1; }
cp ../samples/monster.fbs example/
cp ../tests/monster_test.fbs test/
pub publish
rm example/monster.fbs
rm test/monster_test.fbs

20
dart/pubspec.yaml Normal file
View File

@@ -0,0 +1,20 @@
name: flat_buffers
version: 1.10.0
description: >
FlatBuffers reading and writing library for Dart. Use the flatc compiler to
generate Dart classes for a FlatBuffers schema, and this library to assist with
reading and writing the binary format.
Based on original work by Konstantin Scheglov and Paul Berry of the Dart SDK team.
authors:
- Dan Field <dfield@gmail.com>
- Konstantin Scheglov
- Paul Berry
homepage: https://github.com/google/flatbuffers
documentation: https://google.github.io/flatbuffers/index.html
dev_dependencies:
test: ^1.3.0
test_reflective_loader: ^0.1.4
path: ^1.5.1
environment:
sdk: '>=2.0.0-dev.28.0 <3.0.0'

View File

@@ -0,0 +1,573 @@
// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import 'dart:typed_data';
import 'dart:io' as io;
import 'package:path/path.dart' as path;
import 'package:flat_buffers/flat_buffers.dart';
import 'package:test/test.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
import './monster_test_my_game.example_generated.dart' as example;
main() {
defineReflectiveSuite(() {
defineReflectiveTests(BuilderTest);
defineReflectiveTests(CheckOtherLangaugesData);
});
}
int indexToField(int index) {
return (1 + 1 + index) * 2;
}
@reflectiveTest
class CheckOtherLangaugesData {
test_cppData() async {
List<int> data = await new io.File(path.join(
path.dirname(io.Platform.script.path),
'monsterdata_test.mon',
))
.readAsBytes();
example.Monster mon = new example.Monster(data);
expect(mon.hp, 80);
expect(mon.mana, 150);
expect(mon.name, 'MyMonster');
expect(mon.pos.x, 1.0);
expect(mon.pos.y, 2.0);
expect(mon.pos.z, 3.0);
expect(mon.pos.test1, 3.0);
expect(mon.pos.test2.value, 2.0);
expect(mon.pos.test3.a, 5);
expect(mon.pos.test3.b, 6);
expect(mon.testType.value, example.AnyTypeId.Monster.value);
expect(mon.test is example.Monster, true);
final monster2 = mon.test as example.Monster;
expect(monster2.name, "Fred");
expect(mon.inventory.length, 5);
expect(mon.inventory.reduce((cur, next) => cur + next), 10);
expect(mon.test4.length, 2);
expect(
mon.test4[0].a + mon.test4[0].b + mon.test4[1].a + mon.test4[1].b, 100);
expect(mon.testarrayofstring.length, 2);
expect(mon.testarrayofstring[0], "test1");
expect(mon.testarrayofstring[1], "test2");
// this will fail if accessing any field fails.
expect(mon.toString(),
'Monster{pos: Vec3{x: 1.0, y: 2.0, z: 3.0, test1: 3.0, test2: Color{value: 2}, test3: Test{a: 5, b: 6}}, mana: 150, hp: 80, name: MyMonster, inventory: [0, 1, 2, 3, 4], color: Color{value: 8}, testType: AnyTypeId{value: 1}, test: Monster{pos: null, mana: 150, hp: 100, name: Fred, inventory: null, color: Color{value: 8}, testType: AnyTypeId{value: 0}, test: null, test4: null, testarrayofstring: null, testarrayoftables: null, enemy: null, testnestedflatbuffer: null, testempty: null, testbool: false, testhashs32Fnv1: 0, testhashu32Fnv1: 0, testhashs64Fnv1: 0, testhashu64Fnv1: 0, testhashs32Fnv1a: 0, testhashu32Fnv1a: 0, testhashs64Fnv1a: 0, testhashu64Fnv1a: 0, testarrayofbools: null, testf: 3.14159, testf2: 3.0, testf3: 0.0, testarrayofstring2: null, testarrayofsortedstruct: null, flex: null, test5: null, vectorOfLongs: null, vectorOfDoubles: null, parentNamespaceTest: null, vectorOfReferrables: null, singleWeakReference: 0, vectorOfWeakReferences: null, vectorOfStrongReferrables: null, coOwningReference: 0, vectorOfCoOwningReferences: null, nonOwningReference: 0, vectorOfNonOwningReferences: null}, test4: [Test{a: 10, b: 20}, Test{a: 30, b: 40}], testarrayofstring: [test1, test2], testarrayoftables: null, enemy: Monster{pos: null, mana: 150, hp: 100, name: Fred, inventory: null, color: Color{value: 8}, testType: AnyTypeId{value: 0}, test: null, test4: null, testarrayofstring: null, testarrayoftables: null, enemy: null, testnestedflatbuffer: null, testempty: null, testbool: false, testhashs32Fnv1: 0, testhashu32Fnv1: 0, testhashs64Fnv1: 0, testhashu64Fnv1: 0, testhashs32Fnv1a: 0, testhashu32Fnv1a: 0, testhashs64Fnv1a: 0, testhashu64Fnv1a: 0, testarrayofbools: null, testf: 3.14159, testf2: 3.0, testf3: 0.0, testarrayofstring2: null, testarrayofsortedstruct: null, flex: null, test5: null, vectorOfLongs: null, vectorOfDoubles: null, parentNamespaceTest: null, vectorOfReferrables: null, singleWeakReference: 0, vectorOfWeakReferences: null, vectorOfStrongReferrables: null, coOwningReference: 0, vectorOfCoOwningReferences: null, nonOwningReference: 0, vectorOfNonOwningReferences: null}, testnestedflatbuffer: null, testempty: null, testbool: false, testhashs32Fnv1: -579221183, testhashu32Fnv1: 3715746113, testhashs64Fnv1: 7930699090847568257, testhashu64Fnv1: 7930699090847568257, testhashs32Fnv1a: -1904106383, testhashu32Fnv1a: 2390860913, testhashs64Fnv1a: 4898026182817603057, testhashu64Fnv1a: 4898026182817603057, testarrayofbools: [true, false, true], testf: 3.14159, testf2: 3.0, testf3: 0.0, testarrayofstring2: null, testarrayofsortedstruct: null, flex: null, test5: [Test{a: 10, b: 20}, Test{a: 30, b: 40}], vectorOfLongs: [1, 100, 10000, 1000000, 100000000], vectorOfDoubles: [-1.7976931348623157e+308, 0.0, 1.7976931348623157e+308], parentNamespaceTest: null, vectorOfReferrables: null, singleWeakReference: 0, vectorOfWeakReferences: null, vectorOfStrongReferrables: null, coOwningReference: 0, vectorOfCoOwningReferences: null, nonOwningReference: 0, vectorOfNonOwningReferences: null}');
}
}
@reflectiveTest
class BuilderTest {
void test_monsterBuilder() {
final fbBuilder = new Builder();
final str = fbBuilder.writeString('MyMonster');
fbBuilder.writeString('test1');
fbBuilder.writeString('test2');
final testArrayOfString = fbBuilder.endStructVector(2);
final fred = fbBuilder.writeString('Fred');
final List<int> treasure = [0, 1, 2, 3, 4];
final inventory = fbBuilder.writeListUint8(treasure);
final monBuilder = new example.MonsterBuilder(fbBuilder)
..begin()
..addNameOffset(fred);
final mon2 = monBuilder.finish();
final testBuilder = new example.TestBuilder(fbBuilder);
testBuilder.finish(10, 20);
testBuilder.finish(30, 40);
final test4 = fbBuilder.endStructVector(2);
monBuilder
..begin()
..addPos(
new example.Vec3Builder(fbBuilder).finish(
1.0,
2.0,
3.0,
3.0,
example.Color.Green,
() => testBuilder.finish(5, 6),
),
)
..addHp(80)
..addNameOffset(str)
..addInventoryOffset(inventory)
..addTestType(example.AnyTypeId.Monster)
..addTestOffset(mon2)
..addTest4Offset(test4)
..addTestarrayofstringOffset(testArrayOfString);
final mon = monBuilder.finish();
fbBuilder.finish(mon);
}
void test_error_addInt32_withoutStartTable() {
Builder builder = new Builder();
expect(() {
builder.addInt32(0, 0);
}, throwsStateError);
}
void test_error_addOffset_withoutStartTable() {
Builder builder = new Builder();
expect(() {
builder.addOffset(0, 0);
}, throwsStateError);
}
void test_error_endTable_withoutStartTable() {
Builder builder = new Builder();
expect(() {
builder.endTable();
}, throwsStateError);
}
void test_error_startTable_duringTable() {
Builder builder = new Builder();
builder.startTable();
expect(() {
builder.startTable();
}, throwsStateError);
}
void test_error_writeString_duringTable() {
Builder builder = new Builder();
builder.startTable();
expect(() {
builder.writeString('12345');
}, throwsStateError);
}
void test_file_identifier() {
Uint8List byteList;
{
Builder builder = new Builder(initialSize: 0);
builder.startTable();
int offset = builder.endTable();
byteList = builder.finish(offset, 'Az~ÿ');
}
// Convert byteList to a ByteData so that we can read data from it.
ByteData byteData = byteList.buffer.asByteData(byteList.offsetInBytes);
// First 4 bytes are an offset to the table data.
int tableDataLoc = byteData.getUint32(0, Endian.little);
// Next 4 bytes are the file identifier.
expect(byteData.getUint8(4), 65); // 'a'
expect(byteData.getUint8(5), 122); // 'z'
expect(byteData.getUint8(6), 126); // '~'
expect(byteData.getUint8(7), 255); // 'ÿ'
// First 4 bytes of the table data are a backwards offset to the vtable.
int vTableLoc = tableDataLoc -
byteData.getInt32(tableDataLoc, Endian.little);
// First 2 bytes of the vtable are the size of the vtable in bytes, which
// should be 4.
expect(byteData.getUint16(vTableLoc, Endian.little), 4);
// Next 2 bytes are the size of the object in bytes (including the vtable
// pointer), which should be 4.
expect(byteData.getUint16(vTableLoc + 2, Endian.little), 4);
}
void test_low() {
Builder builder = new Builder(initialSize: 0);
expect((builder..putUint8(1)).lowFinish(), [1]);
expect((builder..putUint32(2)).lowFinish(), [2, 0, 0, 0, 0, 0, 0, 1]);
expect((builder..putUint8(3)).lowFinish(),
[0, 0, 0, 3, 2, 0, 0, 0, 0, 0, 0, 1]);
expect((builder..putUint8(4)).lowFinish(),
[0, 0, 4, 3, 2, 0, 0, 0, 0, 0, 0, 1]);
expect((builder..putUint8(5)).lowFinish(),
[0, 5, 4, 3, 2, 0, 0, 0, 0, 0, 0, 1]);
expect((builder..putUint32(6)).lowFinish(),
[6, 0, 0, 0, 0, 5, 4, 3, 2, 0, 0, 0, 0, 0, 0, 1]);
}
void test_table_default() {
List<int> byteList;
{
Builder builder = new Builder(initialSize: 0);
builder.startTable();
builder.addInt32(0, 10, 10);
builder.addInt32(1, 20, 10);
int offset = builder.endTable();
byteList = builder.finish(offset);
}
// read and verify
BufferContext buffer = new BufferContext.fromBytes(byteList);
int objectOffset = buffer.derefObject(0);
// was not written, so uses the new default value
expect(
const Int32Reader()
.vTableGet(buffer, objectOffset, indexToField(0), 15),
15);
// has the written value
expect(
const Int32Reader()
.vTableGet(buffer, objectOffset, indexToField(1), 15),
20);
}
void test_table_format() {
Uint8List byteList;
{
Builder builder = new Builder(initialSize: 0);
builder.startTable();
builder.addInt32(0, 10);
builder.addInt32(1, 20);
builder.addInt32(2, 30);
byteList = builder.finish(builder.endTable());
}
// Convert byteList to a ByteData so that we can read data from it.
ByteData byteData = byteList.buffer.asByteData(byteList.offsetInBytes);
// First 4 bytes are an offset to the table data.
int tableDataLoc = byteData.getUint32(0, Endian.little);
// First 4 bytes of the table data are a backwards offset to the vtable.
int vTableLoc = tableDataLoc -
byteData.getInt32(tableDataLoc, Endian.little);
// First 2 bytes of the vtable are the size of the vtable in bytes, which
// should be 10.
expect(byteData.getUint16(vTableLoc, Endian.little), 10);
// Next 2 bytes are the size of the object in bytes (including the vtable
// pointer), which should be 16.
expect(byteData.getUint16(vTableLoc + 2, Endian.little), 16);
// Remaining 6 bytes are the offsets within the object where the ints are
// located.
for (int i = 0; i < 3; i++) {
int offset =
byteData.getUint16(vTableLoc + 4 + 2 * i, Endian.little);
expect(byteData.getInt32(tableDataLoc + offset, Endian.little),
10 + 10 * i);
}
}
void test_table_string() {
String latinString = 'test';
String unicodeString = 'Проба пера';
List<int> byteList;
{
Builder builder = new Builder(initialSize: 0);
int latinStringOffset = builder.writeString(latinString);
int unicodeStringOffset = builder.writeString(unicodeString);
builder.startTable();
builder.addOffset(0, latinStringOffset);
builder.addOffset(1, unicodeStringOffset);
int offset = builder.endTable();
byteList = builder.finish(offset);
}
// read and verify
BufferContext buf = new BufferContext.fromBytes(byteList);
int objectOffset = buf.derefObject(0);
expect(const StringReader().vTableGet(buf, objectOffset, indexToField(0)),
latinString);
expect(const StringReader().vTableGet(buf, objectOffset, indexToField(1)),
unicodeString);
}
void test_table_types() {
List<int> byteList;
{
Builder builder = new Builder(initialSize: 0);
int stringOffset = builder.writeString('12345');
builder.startTable();
builder.addBool(0, true);
builder.addInt8(1, 10);
builder.addInt32(2, 20);
builder.addOffset(3, stringOffset);
builder.addInt32(4, 40);
builder.addUint32(5, 0x9ABCDEF0);
builder.addUint8(6, 0x9A);
int offset = builder.endTable();
byteList = builder.finish(offset);
}
// read and verify
BufferContext buf = new BufferContext.fromBytes(byteList);
int objectOffset = buf.derefObject(0);
expect(
const BoolReader().vTableGet(buf, objectOffset, indexToField(0)), true);
expect(
const Int8Reader().vTableGet(buf, objectOffset, indexToField(1)), 10);
expect(
const Int32Reader().vTableGet(buf, objectOffset, indexToField(2)), 20);
expect(const StringReader().vTableGet(buf, objectOffset, indexToField(3)),
'12345');
expect(
const Int32Reader().vTableGet(buf, objectOffset, indexToField(4)), 40);
expect(const Uint32Reader().vTableGet(buf, objectOffset, indexToField(5)),
0x9ABCDEF0);
expect(const Uint8Reader().vTableGet(buf, objectOffset, indexToField(6)),
0x9A);
}
void test_writeList_of_Uint32() {
List<int> values = <int>[10, 100, 12345, 0x9abcdef0];
// write
List<int> byteList;
{
Builder builder = new Builder(initialSize: 0);
int offset = builder.writeListUint32(values);
byteList = builder.finish(offset);
}
// read and verify
BufferContext buf = new BufferContext.fromBytes(byteList);
List<int> items = const Uint32ListReader().read(buf, 0);
expect(items, hasLength(4));
expect(items, orderedEquals(values));
}
void test_writeList_ofBool() {
void verifyListBooleans(int len, List<int> trueBits) {
// write
List<int> byteList;
{
Builder builder = new Builder(initialSize: 0);
List<bool> values = new List<bool>.filled(len, false);
for (int bit in trueBits) {
values[bit] = true;
}
int offset = builder.writeListBool(values);
byteList = builder.finish(offset);
}
// read and verify
BufferContext buf = new BufferContext.fromBytes(byteList);
List<bool> items = const BoolListReader().read(buf, 0);
expect(items, hasLength(len));
for (int i = 0; i < items.length; i++) {
expect(items[i], trueBits.contains(i), reason: 'bit $i of $len');
}
}
verifyListBooleans(0, <int>[]);
verifyListBooleans(1, <int>[]);
verifyListBooleans(1, <int>[0]);
verifyListBooleans(31, <int>[0, 1]);
verifyListBooleans(31, <int>[1, 2, 24, 25, 30]);
verifyListBooleans(31, <int>[0, 30]);
verifyListBooleans(32, <int>[1, 2, 24, 25, 31]);
verifyListBooleans(33, <int>[1, 2, 24, 25, 32]);
verifyListBooleans(33, <int>[1, 2, 24, 25, 31, 32]);
verifyListBooleans(63, <int>[]);
verifyListBooleans(63, <int>[0, 1, 2, 61, 62]);
verifyListBooleans(63, new List<int>.generate(63, (i) => i));
verifyListBooleans(64, <int>[]);
verifyListBooleans(64, <int>[0, 1, 2, 61, 62, 63]);
verifyListBooleans(64, <int>[1, 2, 62]);
verifyListBooleans(64, <int>[0, 1, 2, 63]);
verifyListBooleans(64, new List<int>.generate(64, (i) => i));
verifyListBooleans(100, <int>[0, 3, 30, 60, 90, 99]);
}
void test_writeList_ofInt32() {
List<int> byteList;
{
Builder builder = new Builder(initialSize: 0);
int offset = builder.writeListInt32(<int>[1, 2, 3, 4, 5]);
byteList = builder.finish(offset);
}
// read and verify
BufferContext buf = new BufferContext.fromBytes(byteList);
List<int> items = const ListReader<int>(const Int32Reader()).read(buf, 0);
expect(items, hasLength(5));
expect(items, orderedEquals(<int>[1, 2, 3, 4, 5]));
}
void test_writeList_ofFloat64() {
List<double> values = <double>[-1.234567, 3.4E+9, -5.6E-13, 7.8, 12.13];
// write
List<int> byteList;
{
Builder builder = new Builder(initialSize: 0);
int offset = builder.writeListFloat64(values);
byteList = builder.finish(offset);
}
// read and verify
BufferContext buf = new BufferContext.fromBytes(byteList);
List<double> items = const Float64ListReader().read(buf, 0);
expect(items, hasLength(values.length));
for (int i = 0; i < values.length; i++) {
expect(values[i], closeTo(items[i], .001));
}
}
void test_writeList_ofFloat32() {
List<double> values = [1.0, 2.23, -3.213, 7.8, 12.13];
// write
List<int> byteList;
{
Builder builder = new Builder(initialSize: 0);
int offset = builder.writeListFloat32(values);
byteList = builder.finish(offset);
}
// read and verify
BufferContext buf = new BufferContext.fromBytes(byteList);
List<double> items = const Float32ListReader().read(buf, 0);
expect(items, hasLength(5));
for (int i = 0; i < values.length; i++) {
expect(values[i], closeTo(items[i], .001));
}
}
void test_writeList_ofObjects() {
List<int> byteList;
{
Builder builder = new Builder(initialSize: 0);
// write the object #1
int object1;
{
builder.startTable();
builder.addInt32(0, 10);
builder.addInt32(1, 20);
object1 = builder.endTable();
}
// write the object #1
int object2;
{
builder.startTable();
builder.addInt32(0, 100);
builder.addInt32(1, 200);
object2 = builder.endTable();
}
// write the list
int offset = builder.writeList([object1, object2]);
byteList = builder.finish(offset);
}
// read and verify
BufferContext buf = new BufferContext.fromBytes(byteList);
List<TestPointImpl> items =
const ListReader<TestPointImpl>(const TestPointReader()).read(buf, 0);
expect(items, hasLength(2));
expect(items[0].x, 10);
expect(items[0].y, 20);
expect(items[1].x, 100);
expect(items[1].y, 200);
}
void test_writeList_ofStrings_asRoot() {
List<int> byteList;
{
Builder builder = new Builder(initialSize: 0);
int str1 = builder.writeString('12345');
int str2 = builder.writeString('ABC');
int offset = builder.writeList([str1, str2]);
byteList = builder.finish(offset);
}
// read and verify
BufferContext buf = new BufferContext.fromBytes(byteList);
List<String> items =
const ListReader<String>(const StringReader()).read(buf, 0);
expect(items, hasLength(2));
expect(items, contains('12345'));
expect(items, contains('ABC'));
}
void test_writeList_ofStrings_inObject() {
List<int> byteList;
{
Builder builder = new Builder(initialSize: 0);
int listOffset = builder.writeList(
[builder.writeString('12345'), builder.writeString('ABC')]);
builder.startTable();
builder.addOffset(0, listOffset);
int offset = builder.endTable();
byteList = builder.finish(offset);
}
// read and verify
BufferContext buf = new BufferContext.fromBytes(byteList);
StringListWrapperImpl reader = new StringListWrapperReader().read(buf, 0);
List<String> items = reader.items;
expect(items, hasLength(2));
expect(items, contains('12345'));
expect(items, contains('ABC'));
}
void test_writeList_ofUint32() {
List<int> byteList;
{
Builder builder = new Builder(initialSize: 0);
int offset = builder.writeListUint32(<int>[1, 2, 0x9ABCDEF0]);
byteList = builder.finish(offset);
}
// read and verify
BufferContext buf = new BufferContext.fromBytes(byteList);
List<int> items = const Uint32ListReader().read(buf, 0);
expect(items, hasLength(3));
expect(items, orderedEquals(<int>[1, 2, 0x9ABCDEF0]));
}
void test_writeList_ofUint16() {
List<int> byteList;
{
Builder builder = new Builder(initialSize: 0);
int offset = builder.writeListUint16(<int>[1, 2, 60000]);
byteList = builder.finish(offset);
}
// read and verify
BufferContext buf = new BufferContext.fromBytes(byteList);
List<int> items = const Uint16ListReader().read(buf, 0);
expect(items, hasLength(3));
expect(items, orderedEquals(<int>[1, 2, 60000]));
}
void test_writeList_ofUint8() {
List<int> byteList;
{
Builder builder = new Builder(initialSize: 0);
int offset = builder.writeListUint8(<int>[1, 2, 3, 4, 0x9A]);
byteList = builder.finish(offset);
}
// read and verify
BufferContext buf = new BufferContext.fromBytes(byteList);
List<int> items = const Uint8ListReader().read(buf, 0);
expect(items, hasLength(5));
expect(items, orderedEquals(<int>[1, 2, 3, 4, 0x9A]));
}
}
class StringListWrapperImpl {
final BufferContext bp;
final int offset;
StringListWrapperImpl(this.bp, this.offset);
List<String> get items => const ListReader<String>(const StringReader())
.vTableGet(bp, offset, indexToField(0));
}
class StringListWrapperReader extends TableReader<StringListWrapperImpl> {
const StringListWrapperReader();
@override
StringListWrapperImpl createObject(BufferContext object, int offset) {
return new StringListWrapperImpl(object, offset);
}
}
class TestPointImpl {
final BufferContext bp;
final int offset;
TestPointImpl(this.bp, this.offset);
int get x => const Int32Reader().vTableGet(bp, offset, indexToField(0), 0);
int get y => const Int32Reader().vTableGet(bp, offset, indexToField(1), 0);
}
class TestPointReader extends TableReader<TestPointImpl> {
const TestPointReader();
@override
TestPointImpl createObject(BufferContext object, int offset) {
return new TestPointImpl(object, offset);
}
}

View File

@@ -0,0 +1,62 @@
// automatically generated by the FlatBuffers compiler, do not modify
// ignore_for_file: unused_import, unused_field, unused_local_variable
library my_game.example2;
import 'dart:typed_data' show Uint8List;
import 'package:flat_buffers/flat_buffers.dart' as fb;
import 'include_test1_my_game.example2_generated.dart';
import 'include_test2_my_game.example2_generated.dart';
import './monster_test_my_game.example_generated.dart' as my_game_example;
import './monster_test_my_game_generated.dart' as my_game;
class Monster {
Monster._(this._bc, this._bcOffset);
factory Monster(List<int> bytes) {
fb.BufferContext rootRef = new fb.BufferContext.fromBytes(bytes);
return reader.read(rootRef, 0);
}
static const fb.Reader<Monster> reader = const _MonsterReader();
final fb.BufferContext _bc;
final int _bcOffset;
@override
String toString() {
return 'Monster{}';
}
}
class _MonsterReader extends fb.TableReader<Monster> {
const _MonsterReader();
@override
Monster createObject(fb.BufferContext bc, int offset) =>
new Monster._(bc, offset);
}
class MonsterObjectBuilder extends fb.ObjectBuilder {
MonsterObjectBuilder();
/// Finish building, and store into the [fbBuilder].
@override
int finish(
fb.Builder fbBuilder) {
assert(fbBuilder != null);
fbBuilder.startTable();
return fbBuilder.endTable();
}
/// Convenience method to serialize to byte list.
@override
Uint8List toBytes([String fileIdentifier]) {
fb.Builder fbBuilder = new fb.Builder();
int offset = finish(fbBuilder);
return fbBuilder.finish(offset, fileIdentifier);
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,62 @@
// automatically generated by the FlatBuffers compiler, do not modify
// ignore_for_file: unused_import, unused_field, unused_local_variable
library my_game;
import 'dart:typed_data' show Uint8List;
import 'package:flat_buffers/flat_buffers.dart' as fb;
import 'include_test1_my_game_generated.dart';
import 'include_test2_my_game_generated.dart';
import './monster_test_my_game.example_generated.dart' as my_game_example;
import './monster_test_my_game.example2_generated.dart' as my_game_example2;
class InParentNamespace {
InParentNamespace._(this._bc, this._bcOffset);
factory InParentNamespace(List<int> bytes) {
fb.BufferContext rootRef = new fb.BufferContext.fromBytes(bytes);
return reader.read(rootRef, 0);
}
static const fb.Reader<InParentNamespace> reader = const _InParentNamespaceReader();
final fb.BufferContext _bc;
final int _bcOffset;
@override
String toString() {
return 'InParentNamespace{}';
}
}
class _InParentNamespaceReader extends fb.TableReader<InParentNamespace> {
const _InParentNamespaceReader();
@override
InParentNamespace createObject(fb.BufferContext bc, int offset) =>
new InParentNamespace._(bc, offset);
}
class InParentNamespaceObjectBuilder extends fb.ObjectBuilder {
InParentNamespaceObjectBuilder();
/// Finish building, and store into the [fbBuilder].
@override
int finish(
fb.Builder fbBuilder) {
assert(fbBuilder != null);
fbBuilder.startTable();
return fbBuilder.endTable();
}
/// Convenience method to serialize to byte list.
@override
Uint8List toBytes([String fileIdentifier]) {
fb.Builder fbBuilder = new fb.Builder();
int offset = finish(fbBuilder);
return fbBuilder.finish(offset, fileIdentifier);
}
}

View File

@@ -8,9 +8,9 @@ you to build project/make files for any platform. For details on `cmake`, see
<https://www.cmake.org>. In brief, depending on your platform, use one of
e.g.:
cmake -G "Unix Makefiles"
cmake -G "Visual Studio 10"
cmake -G "Xcode"
cmake -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Release
cmake -G "Visual Studio 10" -DCMAKE_BUILD_TYPE=Release
cmake -G "Xcode" -DCMAKE_BUILD_TYPE=Release
Then, build as normal for your platform. This should result in a `flatc`
executable, essential for the next steps.
@@ -41,7 +41,7 @@ running the `android_sample.sh` script. Optionally, you may go to the
`flatbuffers/samples/android` folder and build the sample with the
`build_apk.sh` script or `ndk_build` / `adb` etc.
## Using FlatBuffers in your own projects.
## Using FlatBuffers in your own projects
For C++, there is usually no runtime to compile, as the code consists of a
single header, `include/flatbuffers/flatbuffers.h`. You should add the
@@ -55,6 +55,31 @@ To see how to include FlatBuffers in any of our supported languages, please
view the [Tutorial](@ref flatbuffers_guide_tutorial) and select your appropriate
language using the radio buttons.
### Using in CMake-based projects
If you want to use FlatBuffers in a project which already uses CMake, then a more
robust and flexible approach is to build FlatBuffers as part of that project directly.
This is done by making the FlatBuffers source code available to the main build
and adding it using CMake's `add_subdirectory()` command. This has the
significant advantage that the same compiler and linker settings are used
between FlatBuffers and the rest of your project, so issues associated with using
incompatible libraries (eg debug/release), etc. are avoided. This is
particularly useful on Windows.
Suppose you put FlatBuffers source code in directory `${FLATBUFFERS_SRC_DIR}`.
To build it as part of your project, add following code to your `CMakeLists.txt` file:
```cmake
# Add FlatBuffers directly to our build. This defines the `flatbuffers` target.
add_subdirectory(${FLATBUFFERS_SRC_DIR}
${CMAKE_CURRENT_BINARY_DIR}/flatbuffers-build
EXCLUDE_FROM_ALL)
# Now simply link against flatbuffers as needed to your already declared target.
# The flatbuffers target carry header search path automatically if CMake > 2.8.11.
target_link_libraries(own_project_target PRIVATE flatbuffers)
```
When build your project the `flatbuffers` library will be compiled and linked
to a target as part of your project.
#### For Google Play apps
For applications on Google Play that integrate this library, usage is tracked.

View File

@@ -31,10 +31,20 @@ For any schema input files, one or more generators can be specified:
- `--js`, `-s`: Generate JavaScript code.
- `--ts`: Generate TypeScript code.
- `--php`: Generate PHP code.
- `--grpc`: Generate RPC stub code for GRPC.
- `--dart`: Generate Dart code.
- `--lua`: Generate Lua code.
- `--lobster`: Generate Lobster code.
- `--rust`, `-r` : Generate Rust code.
For any data input files:
- `--binary`, `-b` : If data is contained in this file, generate a
@@ -86,6 +96,8 @@ Additional options:
at the cost of efficiency (object allocation). Recommended only to be used
if other options are insufficient.
- `--gen-compare` : Generate operator== for object-based API types.
- `--gen-onefile` : Generate single output file (useful for C#)
- `--gen-all`: Generate not just code for the current schema files, but
@@ -99,6 +111,10 @@ Additional options:
instead of Node.js style exporting. Needed for compatibility with the
Google closure compiler (useful for JS).
- `--es6-js-export` : Generates ECMAScript v6 style export definitions
instead of Node.js style exporting. Useful when integrating flatbuffers
with modern Javascript projects.
- `--raw-binary` : Allow binaries without a file_indentifier to be read.
This may crash flatc given a mismatched schema.
@@ -128,5 +144,12 @@ Additional options:
- `--reflect-types` : Add minimal type reflection to code generation.
- `--reflect-names` : Add minimal type/name reflection.
- `--root-type T` : Select or override the default root_type.
- `--force-defaults` : Emit default values in binary output from JSON.
- `--force-empty` : When serializing from object API representation, force
strings and vectors to empty rather than null.
NOTE: short-form options for generators are deprecated, use the long form
whenever possible.

View File

@@ -59,15 +59,18 @@ a `char *` array, which you pass to `GetMonster()`.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
#include "flatbuffers/flatbuffers.h"
#include "monster_test_generate.h"
#include <cstdio> // For printing and file access.
#include <iostream> // C++ header file for printing
#include <fstream> // C++ header file for file access
FILE* file = fopen("monsterdata_test.mon", "rb");
fseek(file, 0L, SEEK_END);
int length = ftell(file);
fseek(file, 0L, SEEK_SET);
std::ifstream infile;
infile.open("monsterdata_test.mon", std::ios::binary | std::ios::in);
infile.seekg(0,std::ios::end);
int length = infile.tellg();
infile.seekg(0,std::ios::beg);
char *data = new char[length];
fread(data, sizeof(char), length, file);
fclose(file);
infile.read(data, length);
infile.close();
auto monster = GetMonster(data);
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -78,9 +81,9 @@ If you look in your generated header, you'll see it has
convenient accessors for all fields, e.g. `hp()`, `mana()`, etc:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
printf("%d\n", monster->hp()); // `80`
printf("%d\n", monster->mana()); // default value of `150`
printf("%s\n", monster->name()->c_str()); // "MyMonster"
std::cout << "hp : " << monster->hp() << std::endl; // `80`
std::cout << "mana : " << monster->mana() << std::endl; // default value of `150`
std::cout << "name : " << monster->name()->c_str() << std::endl; // "MyMonster"
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*Note: That we never stored a `mana` value, so it will return the default.*

108
docs/source/DartUsage.md Normal file
View File

@@ -0,0 +1,108 @@
Use in Dart {#flatbuffers_guide_use_dart}
===========
## Before you get started
Before diving into the FlatBuffers usage in Dart, it should be noted that
the [Tutorial](@ref flatbuffers_guide_tutorial) page has a complete guide
to general FlatBuffers usage in all of the supported languages (including Dart).
This page is designed to cover the nuances of FlatBuffers usage, specific to
Dart.
You should also have read the [Building](@ref flatbuffers_guide_building)
documentation to build `flatc` and should be familiar with
[Using the schema compiler](@ref flatbuffers_guide_using_schema_compiler) and
[Writing a schema](@ref flatbuffers_guide_writing_schema).
## FlatBuffers Dart library code location
The code for the FlatBuffers Go library can be found at
`flatbuffers/dart`. You can browse the library code on the [FlatBuffers
GitHub page](https://github.com/google/flatbuffers/tree/master/dart).
## Testing the FlatBuffers Dart library
The code to test the Dart library can be found at `flatbuffers/tests`.
The test code itself is located in [dart_test.dart](https://github.com/google/
flatbuffers/blob/master/tests/dart_test.dart).
To run the tests, use the [DartTest.sh](https://github.com/google/flatbuffers/
blob/master/tests/DartTest.sh) shell script.
*Note: The shell script requires the [Dart SDK](https://www.dartlang.org/tools/sdk)
to be installed.*
## Using the FlatBuffers Dart library
*Note: See [Tutorial](@ref flatbuffers_guide_tutorial) for a more in-depth
example of how to use FlatBuffers in Dart.*
FlatBuffers supports reading and writing binary FlatBuffers in Dart.
To use FlatBuffers in your own code, first generate Dart classes from your
schema with the `--dart` option to `flatc`. Then you can include both FlatBuffers
and the generated code to read or write a FlatBuffer.
For example, here is how you would read a FlatBuffer binary file in Dart: First,
include the library and generated code. Then read a FlatBuffer binary file into
a `List<int>`, which you pass to the factory constructor for `Monster`:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.dart}
import 'dart:io' as io;
import 'package:flat_buffers/flat_buffers.dart' as fb;
import './monster_my_game.sample_generated.dart' as myGame;
List<int> data = await new io.File('monster.dat').readAsBytes();
var monster = new myGame.Monster(data);
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Now you can access values like this:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.dart}
var hp = monster.hp;
var pos = monster.pos;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
## Differences from the Dart SDK Front End flat_buffers
The work in this repository is signfiicantly based on the implementation used
internally by the Dart SDK in the front end/analyzer package. Several
significant changes have been made.
1. Support for packed boolean lists has been removed. This is not standard
in other implementations and is not compatible with them. Do note that,
like in the JavaScript implementation, __null values in boolean lists
will be treated as false__. It is also still entirely possible to pack data
in a single scalar field, but that would have to be done on the application
side.
2. The SDK implementation supports enums with regular Dart enums, which
works if enums are always indexed at 1; however, FlatBuffers does not
require that. This implementation uses specialized enum-like classes to
ensure proper mapping from FlatBuffers to Dart and other platforms.
3. The SDK implementation does not appear to support FlatBuffer structs or
vectors of structs - it treated everything as a built-in scalar or a table.
This implementation treats structs in a way that is compatible with other
non-Dart implementations, and properly handles vectors of structs. Many of
the methods prefixed with 'low' have been prepurposed to support this.
4. The SDK implementation treats int64 and uint64 as float64s. This
implementation does not. This may cause problems with JavaScript
compatibility - however, it should be possible to use the JavaScript
implementation, or to do a customized implementation that treats all 64 bit
numbers as floats. Supporting the Dart VM and Flutter was a more important
goal of this implementation. Support for 16 bit integers was also added.
5. The code generation in this offers an "ObjectBuilder", which generates code
very similar to the SDK classes that consume FlatBuffers, as well as Builder
classes, which produces code which more closely resembles the builders in
other languages. The ObjectBuilder classes are easier to use, at the cost of
additional references allocated.
## Text Parsing
There currently is no support for parsing text (Schema's and JSON) directly
from Dart, though you could use the C++ parser through Dart Native Extensions.
Please see the C++ documentation for more on text parsing (note that this is
not currently an option in Flutter - follow [this issue](https://github.com/flutter/flutter/issues/7053)
for the latest).
<br>

View File

@@ -4,7 +4,7 @@ FlatBuffers {#flatbuffers_index}
# Overview {#flatbuffers_overview}
[FlatBuffers](@ref flatbuffers_overview) is an efficient cross platform
serialization library for C++, C#, C, Go, Java, JavaScript, TypeScript, PHP, and Python.
serialization library for C++, C#, C, Go, Java, JavaScript, Lobster, Lua, TypeScript, PHP, Python, and Rust.
It was originally created at Google for game development and other
performance-critical applications.
@@ -134,12 +134,18 @@ sections provide a more in-depth usage guide.
in your own programs.
- How to [use the generated Go code](@ref flatbuffers_guide_use_go) in your
own programs.
- How to [use the generated Lua code](@ref flatbuffers_guide_use_lua) in your
own programs.
- How to [use the generated JavaScript code](@ref flatbuffers_guide_use_javascript) in your
own programs.
- How to [use the generated TypeScript code](@ref flatbuffers_guide_use_typescript) in your
own programs.
- How to [use FlatBuffers in C with `flatcc`](@ref flatbuffers_guide_use_c) in your
own programs.
- How to [use the generated Lobster code](@ref flatbuffers_guide_use_lobster) in your
own programs.
- How to [use the generated Rust code](@ref flatbuffers_guide_use_rust) in your
own programs.
- [Support matrix](@ref flatbuffers_support) for platforms/languages/features.
- Some [benchmarks](@ref flatbuffers_benchmarks) showing the advantage of
using FlatBuffers.

View File

@@ -10,7 +10,7 @@ include = `include` string\_constant `;`
namespace\_decl = `namespace` ident ( `.` ident )* `;`
attribute\_decl = `attribute` string\_constant `;`
attribute\_decl = `attribute` ident | `"`ident`"` `;`
type\_decl = ( `table` | `struct` ) ident metadata `{` field\_decl+ `}`

View File

@@ -169,7 +169,7 @@ Unions share a lot with enums.
Predeclare all data types since circular references between types are allowed
(circular references between object are not, though).
MANUALLY_ALIGNED_STRUCT(4) Vec3 {
FLATBUFFERS_MANUALLY_ALIGNED_STRUCT(4) Vec3 {
private:
float x_;
float y_;
@@ -183,7 +183,7 @@ Predeclare all data types since circular references between types are allowed
float y() const { return flatbuffers::EndianScalar(y_); }
float z() const { return flatbuffers::EndianScalar(z_); }
};
STRUCT_END(Vec3, 12);
FLATBUFFERS_STRUCT_END(Vec3, 12);
These ugly macros do a couple of things: they turn off any padding the compiler
might normally do, since we add padding manually (though none in this example),

View File

@@ -0,0 +1,85 @@
Use in Lobster {#flatbuffers_guide_use_lobster}
==============
## Before you get started
Before diving into the FlatBuffers usage in Lobster, it should be noted that the
[Tutorial](@ref flatbuffers_guide_tutorial) page has a complete guide to general
FlatBuffers usage in all of the supported languages (including Lobster). This
page is designed to cover the nuances of FlatBuffers usage, specific to
Lobster.
You should also have read the [Building](@ref flatbuffers_guide_building)
documentation to build `flatc` and should be familiar with
[Using the schema compiler](@ref flatbuffers_guide_using_schema_compiler) and
[Writing a schema](@ref flatbuffers_guide_writing_schema).
## FlatBuffers Lobster library code location
The code for the FlatBuffers Lobster library can be found at
`flatbuffers/lobster`. You can browse the library code on the
[FlatBuffers GitHub page](https://github.com/google/flatbuffers/tree/master/
lobster).
## Testing the FlatBuffers Lobster library
The code to test the Lobster library can be found at `flatbuffers/tests`.
The test code itself is located in [lobstertest.lobster](https://github.com/google/
flatbuffers/blob/master/tests/lobstertest.lobster).
To run the tests, run `lobster lobstertest.lobster`. To obtain Lobster itself,
go to the [Lobster homepage](http://strlen.com/lobster) or
[github](https://github.com/aardappel/lobster) to learn how to build it for your
platform.
## Using the FlatBuffers Lobster library
*Note: See [Tutorial](@ref flatbuffers_guide_tutorial) for a more in-depth
example of how to use FlatBuffers in Lobster.*
There is support for both reading and writing FlatBuffers in Lobster.
To use FlatBuffers in your own code, first generate Lobster classes from your
schema with the `--lobster` option to `flatc`. Then you can include both
FlatBuffers and the generated code to read or write a FlatBuffer.
For example, here is how you would read a FlatBuffer binary file in Lobster:
First, import the library and the generated code. Then read a FlatBuffer binary
file into a string, which you pass to the `GetRootAsMonster` function:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.lobster}
include "monster_generated.lobster"
let fb = read_file("monsterdata_test.mon")
assert fb
let monster = MyGame_Example_GetRootAsMonster(fb)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Now you can access values like this:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.lobster}
let hp = monster.hp
let pos = monster.pos
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
As you can see, even though `hp` and `pos` are functions that access FlatBuffer
data in-place in the string buffer, they appear as field accesses.
## Speed
Using FlatBuffers in Lobster should be relatively fast, as the implementation
makes use of native support for writing binary values, and access of vtables.
Both generated code and the runtime library are therefore small and fast.
Actual speed will depend on wether you use Lobster as bytecode VM or compiled to
C++.
## Text Parsing
Lobster has full support for parsing JSON into FlatBuffers, or generating
JSON from FlatBuffers. See `samples/sample_test.lobster` for an example.
This uses the C++ parser and generator underneath, so should be both fast and
conformant.
<br>

81
docs/source/LuaUsage.md Normal file
View File

@@ -0,0 +1,81 @@
Use in Lua {#flatbuffers_guide_use_lua}
=============
## Before you get started
Before diving into the FlatBuffers usage in Lua, it should be noted that the
[Tutorial](@ref flatbuffers_guide_tutorial) page has a complete guide to general
FlatBuffers usage in all of the supported languages (including Lua). This
page is designed to cover the nuances of FlatBuffers usage, specific to
Lua.
You should also have read the [Building](@ref flatbuffers_guide_building)
documentation to build `flatc` and should be familiar with
[Using the schema compiler](@ref flatbuffers_guide_using_schema_compiler) and
[Writing a schema](@ref flatbuffers_guide_writing_schema).
## FlatBuffers Lua library code location
The code for the FlatBuffers Lua library can be found at
`flatbuffers/lua`. You can browse the library code on the
[FlatBuffers GitHub page](https://github.com/google/flatbuffers/tree/master/lua).
## Testing the FlatBuffers Lua library
The code to test the Lua library can be found at `flatbuffers/tests`.
The test code itself is located in [luatest.lua](https://github.com/google/
flatbuffers/blob/master/tests/luatest.lua).
To run the tests, use the [LuaTest.sh](https://github.com/google/flatbuffers/
blob/master/tests/LuaTest.sh) shell script.
*Note: This script requires [Lua 5.3](https://www.lua.org/) to be
installed.*
## Using the FlatBuffers Lua library
*Note: See [Tutorial](@ref flatbuffers_guide_tutorial) for a more in-depth
example of how to use FlatBuffers in Lua.*
There is support for both reading and writing FlatBuffers in Lua.
To use FlatBuffers in your own code, first generate Lua classes from your
schema with the `--lua` option to `flatc`. Then you can include both
FlatBuffers and the generated code to read or write a FlatBuffer.
For example, here is how you would read a FlatBuffer binary file in Lua:
First, require the module and the generated code. Then read a FlatBuffer binary
file into a `string`, which you pass to the `GetRootAsMonster` function:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.lua}
-- require the library
local flatbuffers = require("flatbuffers")
-- require the generated code
local monster = require("MyGame.Sample.Monster")
-- read the flatbuffer from a file into a string
local f = io.open('monster.dat', 'rb')
local buf = f:read('*a')
f:close()
-- parse the flatbuffer to get an instance to the root monster
local monster1 = monster.GetRootAsMonster(buf, 0)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Now you can access values like this:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.lua}
-- use the : notation to access member data
local hp = monster1:Hp()
local pos = monster1:Pos()
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
## Text Parsing
There currently is no support for parsing text (Schema's and JSON) directly
from Lua, though you could use the C++ parser through SWIG or ctypes. Please
see the C++ documentation for more on text parsing.
<br>

166
docs/source/RustUsage.md Normal file
View File

@@ -0,0 +1,166 @@
Use in Rust {#flatbuffers_guide_use_rust}
==========
## Before you get started
Before diving into the FlatBuffers usage in Rust, it should be noted that
the [Tutorial](@ref flatbuffers_guide_tutorial) page has a complete guide
to general FlatBuffers usage in all of the supported languages (including Rust).
This page is designed to cover the nuances of FlatBuffers usage, specific to
Rust.
#### Prerequisites
This page assumes you have written a FlatBuffers schema and compiled it
with the Schema Compiler. If you have not, please see
[Using the schema compiler](@ref flatbuffers_guide_using_schema_compiler)
and [Writing a schema](@ref flatbuffers_guide_writing_schema).
Assuming you wrote a schema, say `mygame.fbs` (though the extension doesn't
matter), you've generated a Rust file called `mygame_generated.rs` using the
compiler (e.g. `flatc --rust mygame.fbs`), you can now start using this in
your program by including the file. As noted, this header relies on the crate
`flatbuffers`, which should be in your include `Cargo.toml`.
## FlatBuffers Rust library code location
The code for the FlatBuffers Rust library can be found at
`flatbuffers/rust`. You can browse the library code on the
[FlatBuffers GitHub page](https://github.com/google/flatbuffers/tree/master/rust).
## Testing the FlatBuffers Rust library
The code to test the Rust library can be found at `flatbuffers/tests/rust_usage_test`.
The test code itself is located in
[integration_test.rs](https://github.com/google/flatbuffers/blob/master/tests/rust_usage_test/tests/integration_test.rs)
This test file requires `flatc` to be present. To review how to build the project,
please read the [Building](@ref flatbuffers_guide_building) documenation.
To run the tests, execute `RustTest.sh` from the `flatbuffers/tests` directory.
For example, on [Linux](https://en.wikipedia.org/wiki/Linux), you would simply
run: `cd tests && ./RustTest.sh`.
*Note: The shell script requires [Rust](https://www.rust-lang.org) to
be installed.*
## Using the FlatBuffers Rust library
*Note: See [Tutorial](@ref flatbuffers_guide_tutorial) for a more in-depth
example of how to use FlatBuffers in Rust.*
FlatBuffers supports both reading and writing FlatBuffers in Rust.
To use FlatBuffers in your code, first generate the Rust modules from your
schema with the `--rust` option to `flatc`. Then you can import both FlatBuffers
and the generated code to read or write FlatBuffers.
For example, here is how you would read a FlatBuffer binary file in Rust:
First, include the library and generated code. Then read the file into
a `u8` vector, which you pass, as a byte slice, to `get_root_as_monster()`.
This full example program is available in the Rust test suite:
[monster_example.rs](https://github.com/google/flatbuffers/blob/master/tests/rust_usage_test/bin/monster_example.rs)
It can be run by `cd`ing to the `rust_usage_test` directory and executing: `cargo run monster_example`.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.rs}
extern crate flatbuffers;
#[path = "../../monster_test_generated.rs"]
mod monster_test_generated;
pub use monster_test_generated::my_game;
use std::io::Read;
fn main() {
let mut f = std::fs::File::open("../monsterdata_test.mon").unwrap();
let mut buf = Vec::new();
f.read_to_end(&mut buf).expect("file reading failed");
let monster = my_game::example::get_root_as_monster(&buf[..]);
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
`monster` is of type `Monster`, and points to somewhere *inside* your
buffer (root object pointers are not the same as `buffer_pointer` !).
If you look in your generated header, you'll see it has
convenient accessors for all fields, e.g. `hp()`, `mana()`, etc:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.rs}
println!("{}", monster.hp()); // `80`
println!("{}", monster.mana()); // default value of `150`
println!("{:?}", monster.name()); // Some("MyMonster")
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*Note: That we never stored a `mana` value, so it will return the default.*
## Direct memory access
As you can see from the above examples, all elements in a buffer are
accessed through generated accessors. This is because everything is
stored in little endian format on all platforms (the accessor
performs a swap operation on big endian machines), and also because
the layout of things is generally not known to the user.
For structs, layout is deterministic and guaranteed to be the same
across platforms (scalars are aligned to their
own size, and structs themselves to their largest member), and you
are allowed to access this memory directly by using `safe_slice` and
on the reference to a struct, or even an array of structs.
To compute offsets to sub-elements of a struct, make sure they
are structs themselves, as then you can use the pointers to
figure out the offset without having to hardcode it. This is
handy for use of arrays of structs with calls like `glVertexAttribPointer`
in OpenGL or similar APIs.
It is important to note is that structs are still little endian on all
machines, so only use tricks like this if you can guarantee you're not
shipping on a big endian machine (using an `#[cfg(target_endian = "little")]`
attribute would be wise).
The special function `safe_slice` is implemented on Vector objects that are
represented in memory the same way as they are represented on the wire. This
function is always available on vectors of struct, bool, u8, and i8. It is
conditionally-compiled on little-endian systems for all the remaining scalar
types.
The FlatBufferBuilder function `create_vector_direct` is implemented for all
types that are endian-safe to write with a `memcpy`. It is the write-equivalent
of `safe_slice`.
## Access of untrusted buffers
The generated accessor functions access fields over offsets, which is
very quick. These offsets are used to index into Rust slices, so they are
bounds-checked by the Rust runtime. However, our Rust implementation may
change: we may convert access functions to use direct pointer dereferencing, to
improve lookup speed. As a result, users should not rely on the aforementioned
bounds-checking behavior.
When you're processing large amounts of data from a source you know (e.g.
your own generated data on disk), this is acceptable, but when reading
data from the network that can potentially have been modified by an
attacker, this is undesirable.
The C++ port provides a buffer verifier. At this time, Rust does not. Rust may
provide a verifier in a future version. In the meantime, Rust users can access
the buffer verifier generated by the C++ port through a foreign function
interface (FFI).
## Threading
Reading a FlatBuffer does not touch any memory outside the original buffer,
and is entirely read-only (all immutable), so is safe to access from multiple
threads even without synchronisation primitives.
Creating a FlatBuffer is not thread safe. All state related to building
a FlatBuffer is contained in a FlatBufferBuilder instance, and no memory
outside of it is touched. To make this thread safe, either do not
share instances of FlatBufferBuilder between threads (recommended), or
manually wrap it in synchronisation primitives. There's no automatic way to
accomplish this, by design, as we feel multithreaded construction
of a single buffer will be rare, and synchronisation overhead would be costly.
<br>

View File

@@ -18,24 +18,25 @@ In general:
NOTE: this table is a start, it needs to be extended.
Feature | C++ | Java | C# | Go | Python | JS | TS | C | PHP | Ruby
------------------------------ | ------ | ------ | ------ | ------ | ------ | --------- | --------- | ------ | --- | ----
Codegen for all basic features | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | WiP | WiP
JSON parsing | Yes | No | No | No | No | No | No | Yes | No | No
Simple mutation | Yes | Yes | Yes | Yes | No | No | No | No | No | No
Reflection | Yes | No | No | No | No | No | No | Basic | No | No
Buffer verifier | Yes | No | No | No | No | No | No | Yes | No | No
Testing: basic | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | ? | ?
Testing: fuzz | Yes | No | No | Yes | Yes | No | No | No | ? | ?
Performance: | Superb | Great | Great | Great | Ok | ? | ? | Superb | ? | ?
Platform: Windows | VS2010 | Yes | Yes | ? | ? | ? | Yes | VS2010 | ? | ?
Platform: Linux | GCC282 | Yes | ? | Yes | Yes | ? | Yes | Yes | ? | ?
Platform: OS X | Xcode4 | ? | ? | ? | Yes | ? | Yes | Yes | ? | ?
Platform: Android | NDK10d | Yes | ? | ? | ? | ? | ? | ? | ? | ?
Platform: iOS | ? | ? | ? | ? | ? | ? | ? | ? | ? | ?
Engine: Unity | ? | ? | Yes | ? | ? | ? | ? | ? | ? | ?
Primary authors (github) | gwvo | gwvo | ev*/js*| rw | rw | evanw/ev* | kr | mik* | ch* | rw
Feature | C++ | Java | C# | Go | Python | JS | TS | C | PHP | Dart | Lobster | Rust
------------------------------ | ------ | ------ | ------ | ------ | ------ | --------- | --------- | ------ | --- | ------- | ------- | ----
Codegen for all basic features | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | WiP | Yes | Yes | Yes
JSON parsing | Yes | No | No | No | No | No | No | Yes | No | No | Yes | No
Simple mutation | Yes | Yes | Yes | Yes | No | No | No | No | No | No | No | No
Reflection | Yes | No | No | No | No | No | No | Basic | No | No | No | No
Buffer verifier | Yes | No | No | No | No | No | No | Yes | No | No | No | No
Testing: basic | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | ? | Yes | Yes | Yes
Testing: fuzz | Yes | No | No | Yes | Yes | No | No | No | ? | No | No | Yes
Performance: | Superb | Great | Great | Great | Ok | ? | ? | Superb | ? | ? | Great | Superb
Platform: Windows | VS2010 | Yes | Yes | ? | ? | ? | Yes | VS2010 | ? | Yes | Yes | Yes
Platform: Linux | GCC282 | Yes | ? | Yes | Yes | ? | Yes | Yes | ? | Yes | Yes | Yes
Platform: OS X | Xcode4 | ? | ? | ? | Yes | ? | Yes | Yes | ? | Yes | Yes | Yes
Platform: Android | NDK10d | Yes | ? | ? | ? | ? | ? | ? | ? | Flutter | Yes | ?
Platform: iOS | ? | ? | ? | ? | ? | ? | ? | ? | ? | Flutter | Yes | ?
Engine: Unity | ? | ? | Yes | ? | ? | ? | ? | ? | ? | ? | No | ?
Primary authors (github) | aard* | aard* | ev*/js*| rw | rw | evanw/ev* | kr* | mik* | ch* | dnfield | aard* | rw
* aard = aardappel (previously: gwvo)
* ev = evolutional
* js = jonsimantov
* mik = mikkelfj

File diff suppressed because it is too large Load Diff

View File

@@ -751,11 +751,16 @@ INPUT = "FlatBuffers.md" \
"Schemas.md" \
"CppUsage.md" \
"CUsage.md" \
"DartUsage.md" \
"GoUsage.md" \
"JavaCsharpUsage.md" \
"JavaScriptUsage.md" \
"TypeScriptUsage.md" \
"PHPUsage.md" \
"PythonUsage.md" \
"LuaUsage.md" \
"LobsterUsage.md" \
"RustUsage.md" \
"Support.md" \
"Benchmarks.md" \
"WhitePaper.md" \
@@ -774,6 +779,7 @@ INPUT = "FlatBuffers.md" \
"../../net/FlatBuffers/FlatBufferBuilder.cs" \
"../../include/flatbuffers/flatbuffers.h" \
"../../go/builder.go"
"../../rust/flatbuffers/src/builder.rs"
# This tag can be used to specify the character encoding of the source files
# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses

View File

@@ -39,6 +39,12 @@
title="Use in PHP"/>
<tab type="user" url="@ref flatbuffers_guide_use_python"
title="Use in Python"/>
<tab type="user" url="@ref flatbuffers_guide_use_dart"
title="Use in Dart"/>
<tab type="user" url="@ref flatbuffers_guide_use_lua"
title="Use in Lua"/>
<tab type="user" url="@ref flatbuffers_guide_use_lobster"
title="Use in Lobster"/>
<tab type="user" url="@ref flexbuffers"
title="Schema-less version"/>
<tab type="usergroup" url="" title="gRPC">

View File

@@ -19,6 +19,8 @@ type Builder struct {
finished bool
}
const fileIdentifierLength = 4
// NewBuilder initializes a Builder of size `initial_size`.
// The internal buffer is grown as needed.
func NewBuilder(initialSize int) *Builder {
@@ -80,7 +82,6 @@ func (b *Builder) StartObject(numfields int) {
}
b.objectEnd = b.Offset()
b.minalign = 1
}
// WriteVtable serializes the vtable for the current object, if applicable.
@@ -111,9 +112,10 @@ func (b *Builder) WriteVtable() (n UOffsetT) {
existingVtable := UOffsetT(0)
// Trim vtable of trailing zeroes.
i := len(b.vtable) - 1;
for ; i >= 0 && b.vtable[i] == 0; i-- {}
b.vtable = b.vtable[:i + 1];
i := len(b.vtable) - 1
for ; i >= 0 && b.vtable[i] == 0; i-- {
}
b.vtable = b.vtable[:i+1]
// Search backwards through existing vtables, because similar vtables
// are likely to have been recently appended. See
@@ -540,6 +542,23 @@ func (b *Builder) Slot(slotnum int) {
b.vtable[slotnum] = UOffsetT(b.Offset())
}
// FinishWithFileIdentifier finalizes a buffer, pointing to the given `rootTable`.
// as well as applys a file identifier
func (b *Builder) FinishWithFileIdentifier(rootTable UOffsetT, fid []byte) {
if fid == nil || len(fid) != fileIdentifierLength {
panic("incorrect file identifier length")
}
// In order to add a file identifier to the flatbuffer message, we need
// to prepare an alignment and file identifier length
b.Prep(b.minalign, SizeInt32+fileIdentifierLength)
for i := fileIdentifierLength - 1; i >= 0; i-- {
// place the file identifier
b.PlaceByte(fid[i])
}
// finish
b.Finish(rootTable)
}
// Finish finalizes a buffer, pointing to the given `rootTable`.
func (b *Builder) Finish(rootTable UOffsetT) {
b.assertNotNested()

View File

@@ -36,6 +36,7 @@ func GetUint8(buf []byte) (n uint8) {
// GetUint16 decodes a little-endian uint16 from a byte slice.
func GetUint16(buf []byte) (n uint16) {
_ = buf[1] // Force one bounds check. See: golang.org/issue/14808
n |= uint16(buf[0])
n |= uint16(buf[1]) << 8
return
@@ -43,6 +44,7 @@ func GetUint16(buf []byte) (n uint16) {
// GetUint32 decodes a little-endian uint32 from a byte slice.
func GetUint32(buf []byte) (n uint32) {
_ = buf[3] // Force one bounds check. See: golang.org/issue/14808
n |= uint32(buf[0])
n |= uint32(buf[1]) << 8
n |= uint32(buf[2]) << 16
@@ -52,6 +54,7 @@ func GetUint32(buf []byte) (n uint32) {
// GetUint64 decodes a little-endian uint64 from a byte slice.
func GetUint64(buf []byte) (n uint64) {
_ = buf[7] // Force one bounds check. See: golang.org/issue/14808
n |= uint64(buf[0])
n |= uint64(buf[1]) << 8
n |= uint64(buf[2]) << 16
@@ -71,6 +74,7 @@ func GetInt8(buf []byte) (n int8) {
// GetInt16 decodes a little-endian int16 from a byte slice.
func GetInt16(buf []byte) (n int16) {
_ = buf[1] // Force one bounds check. See: golang.org/issue/14808
n |= int16(buf[0])
n |= int16(buf[1]) << 8
return
@@ -78,6 +82,7 @@ func GetInt16(buf []byte) (n int16) {
// GetInt32 decodes a little-endian int32 from a byte slice.
func GetInt32(buf []byte) (n int32) {
_ = buf[3] // Force one bounds check. See: golang.org/issue/14808
n |= int32(buf[0])
n |= int32(buf[1]) << 8
n |= int32(buf[2]) << 16
@@ -87,6 +92,7 @@ func GetInt32(buf []byte) (n int32) {
// GetInt64 decodes a little-endian int64 from a byte slice.
func GetInt64(buf []byte) (n int64) {
_ = buf[7] // Force one bounds check. See: golang.org/issue/14808
n |= int64(buf[0])
n |= int64(buf[1]) << 8
n |= int64(buf[2]) << 16
@@ -145,12 +151,14 @@ func WriteUint8(buf []byte, n uint8) {
// WriteUint16 encodes a little-endian uint16 into a byte slice.
func WriteUint16(buf []byte, n uint16) {
_ = buf[1] // Force one bounds check. See: golang.org/issue/14808
buf[0] = byte(n)
buf[1] = byte(n >> 8)
}
// WriteUint32 encodes a little-endian uint32 into a byte slice.
func WriteUint32(buf []byte, n uint32) {
_ = buf[3] // Force one bounds check. See: golang.org/issue/14808
buf[0] = byte(n)
buf[1] = byte(n >> 8)
buf[2] = byte(n >> 16)
@@ -159,9 +167,15 @@ func WriteUint32(buf []byte, n uint32) {
// WriteUint64 encodes a little-endian uint64 into a byte slice.
func WriteUint64(buf []byte, n uint64) {
for i := uint(0); i < uint(SizeUint64); i++ {
buf[i] = byte(n >> (i * 8))
}
_ = buf[7] // Force one bounds check. See: golang.org/issue/14808
buf[0] = byte(n)
buf[1] = byte(n >> 8)
buf[2] = byte(n >> 16)
buf[3] = byte(n >> 24)
buf[4] = byte(n >> 32)
buf[5] = byte(n >> 40)
buf[6] = byte(n >> 48)
buf[7] = byte(n >> 56)
}
// WriteInt8 encodes a little-endian int8 into a byte slice.
@@ -171,12 +185,14 @@ func WriteInt8(buf []byte, n int8) {
// WriteInt16 encodes a little-endian int16 into a byte slice.
func WriteInt16(buf []byte, n int16) {
_ = buf[1] // Force one bounds check. See: golang.org/issue/14808
buf[0] = byte(n)
buf[1] = byte(n >> 8)
}
// WriteInt32 encodes a little-endian int32 into a byte slice.
func WriteInt32(buf []byte, n int32) {
_ = buf[3] // Force one bounds check. See: golang.org/issue/14808
buf[0] = byte(n)
buf[1] = byte(n >> 8)
buf[2] = byte(n >> 16)
@@ -185,9 +201,15 @@ func WriteInt32(buf []byte, n int32) {
// WriteInt64 encodes a little-endian int64 into a byte slice.
func WriteInt64(buf []byte, n int64) {
for i := uint(0); i < uint(SizeInt64); i++ {
buf[i] = byte(n >> (i * 8))
}
_ = buf[7] // Force one bounds check. See: golang.org/issue/14808
buf[0] = byte(n)
buf[1] = byte(n >> 8)
buf[2] = byte(n >> 16)
buf[3] = byte(n >> 24)
buf[4] = byte(n >> 32)
buf[5] = byte(n >> 40)
buf[6] = byte(n >> 48)
buf[7] = byte(n >> 56)
}
// WriteFloat32 encodes a little-endian float32 into a byte slice.

View File

@@ -9,3 +9,23 @@ from GRPC, and work with both the Protobuf and FlatBuffers code generator.
the GRPC libraries for this to compile. This test will build using the
`FLATBUFFERS_BUILD_GRPCTEST` option to the main FlatBuffers CMake project.
## Building Flatbuffers with gRPC
### Linux
1. Download, build and install gRPC. See [instructions](https://github.com/grpc/grpc/tree/master/src/cpp).
* Lets say your gRPC clone is at `/your/path/to/grpc_repo`.
* Install gRPC in a custom directory by running `make install prefix=/your/path/to/grpc_repo/install`.
2. `export GRPC_INSTALL_PATH=/your/path/to/grpc_repo/install`
3. `export PROTOBUF_DOWNLOAD_PATH=/your/path/to/grpc_repo/third_party/protobuf`
4. `mkdir build ; cd build`
5. `cmake -DFLATBUFFERS_BUILD_GRPCTEST=ON -DGRPC_INSTALL_PATH=${GRPC_INSTALL_PATH} -DPROTOBUF_DOWNLOAD_PATH=${PROTOBUF_DOWNLOAD_PATH} ..`
6. `make`
## Running FlatBuffer gRPC tests
### Linux
1. `ln -s ${GRPC_INSTALL_PATH}/lib/libgrpc++_unsecure.so.6 ${GRPC_INSTALL_PATH}/lib/libgrpc++_unsecure.so.1`
2. `export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:${GRPC_INSTALL_PATH}/lib`
3. `make test ARGS=-V`

21
grpc/build_grpc.sh Executable file
View File

@@ -0,0 +1,21 @@
#!/bin/bash
grpc_1_15_1_githash=1a60e6971f428323245a930031ad267bb3142ba4
function build_grpc () {
git clone https://github.com/grpc/grpc.git google/grpc
cd google/grpc
git checkout ${grpc_1_15_1_githash}
git submodule update --init
make
make install prefix=`pwd`/install
if [ ! -f ${GRPC_INSTALL_PATH}/lib/libgrpc++_unsecure.so.1 ]; then
ln -s ${GRPC_INSTALL_PATH}/lib/libgrpc++_unsecure.so.6 ${GRPC_INSTALL_PATH}/lib/libgrpc++_unsecure.so.1
fi
cd ../..
}
GRPC_INSTALL_PATH=`pwd`/google/grpc/install
PROTOBUF_DOWNLOAD_PATH=`pwd`/google/grpc/third_party/protobuf
build_grpc

View File

@@ -6,7 +6,7 @@
<parent>
<groupId>com.google.flatbuffers</groupId>
<artifactId>flatbuffers-parent</artifactId>
<version>1.8.0</version>
<version>1.10.0</version>
</parent>
<artifactId>flatbuffers-java-grpc</artifactId>
<name>${project.artifactId}</name>
@@ -24,7 +24,7 @@
</developer>
</developers>
<properties>
<gRPC.version>1.8.0</gRPC.version>
<gRPC.version>1.9.0</gRPC.version>
</properties>
<dependencies>
<dependency>

View File

@@ -4,7 +4,7 @@
<groupId>com.google.flatbuffers</groupId>
<artifactId>flatbuffers-parent</artifactId>
<packaging>pom</packaging>
<version>1.8.0</version>
<version>1.10.0</version>
<name>flatbuffers-parent</name>
<description>parent pom for flatbuffers java artifacts</description>
<properties>
@@ -201,7 +201,7 @@
</build>
<modules>
<!-- consider the benefits of publishing all maven artifacts in this project
<!-- consider the benefits of publishing all maven artifacts in this project
<module>flatbuffers-compiler</module>
<module>flatbuffers-java</module>

View File

@@ -110,7 +110,7 @@ void GenerateServerMethod(const grpc_generator::Method *method, grpc_generator::
vars["Method"] = exportName(method->name());
vars["Request"] = method->get_input_type_name();
vars["Response"] = (vars["CustomMethodIO"] == "") ? method->get_output_type_name() : vars["CustomMethodIO"];
vars["FullMethodName"] = "/" + vars["Package"] + "." + vars["Service"] + "/" + vars["Method"];
vars["FullMethodName"] = "/" + vars["ServicePrefix"] + "." + vars["Service"] + "/" + vars["Method"];
vars["Handler"] = "_" + vars["Service"] + "_" + vars["Method"] + "_Handler";
if (method->NoStreaming()) {
printer->Print(vars, "func $Handler$(srv interface{}, ctx $context$.Context,\n\tdec func(interface{}) error, interceptor $grpc$.UnaryServerInterceptor) (interface{}, error) {\n");
@@ -223,7 +223,7 @@ void GenerateClientMethod(const grpc_generator::Method *method, grpc_generator::
vars["Method"] = exportName(method->name());
vars["Request"] = (vars["CustomMethodIO"] == "") ? method->get_input_type_name() : vars["CustomMethodIO"];
vars["Response"] = method->get_output_type_name();
vars["FullMethodName"] = "/" + vars["Package"] + "." + vars["Service"] + "/" + vars["Method"];
vars["FullMethodName"] = "/" + vars["ServicePrefix"] + "." + vars["Service"] + "/" + vars["Method"];
if (method->NoStreaming()) {
printer->Print(vars, "out := new($Response$)\n");
printer->Print(vars, "err := $grpc$.Invoke(ctx, \"$FullMethodName$\", in, out, c.cc, opts...)\n");
@@ -374,7 +374,7 @@ void GenerateService(const grpc_generator::Service *service, grpc_generator::Pri
//Service Descriptor
printer->Print(vars, "var $ServiceDesc$ = $grpc$.ServiceDesc{\n");
printer->Indent();
printer->Print(vars, "ServiceName: \"$Package$.$Service$\",\n");
printer->Print(vars, "ServiceName: \"$ServicePrefix$.$Service$\",\n");
printer->Print(vars, "HandlerType: (*$Service$Server)(nil),\n");
printer->Print(vars, "Methods: []$grpc$.MethodDesc{\n");
printer->Indent();
@@ -433,6 +433,7 @@ grpc::string GenerateServiceSource(grpc_generator::File *file,
auto printer = p.get();
std::map<grpc::string, grpc::string> vars;
vars["Package"] = parameters->package_name;
vars["ServicePrefix"] = parameters->service_prefix;
vars["grpc"] = "grpc";
vars["context"] = "context";
GenerateImports(file, printer, vars);

View File

@@ -49,6 +49,9 @@ struct Parameters {
//Package name for the service
grpc::string package_name;
//Prefix for RPC Calls
grpc::string service_prefix;
};
// Return the source of the generated service file.

View File

@@ -65,8 +65,6 @@ class LogHelper {
// Abort the program after logging the mesage.
#define GRPC_CODEGEN_FAIL GRPC_CODEGEN_CHECK(false)
using namespace std;
namespace grpc_java_generator {
struct Parameters {
// //Defines the custom parameter types for methods

View File

@@ -20,8 +20,10 @@
#include "monster_test.grpc.fb.h"
#include "monster_test_generated.h"
#include "test_assert.h"
using namespace MyGame::Example;
void message_builder_tests();
// The callback implementation of our server, that derives from the generated
// code. It implements all rpcs specified in the FlatBuffers schema.
@@ -92,7 +94,7 @@ void RunServer() {
server_instance->Wait();
}
int main(int /*argc*/, const char * /*argv*/ []) {
int grpc_server_test() {
// Launch server.
std::thread server_thread(RunServer);
@@ -163,3 +165,17 @@ int main(int /*argc*/, const char * /*argv*/ []) {
return 0;
}
int main(int /*argc*/, const char * /*argv*/ []) {
message_builder_tests();
grpc_server_test();
if (!testing_fails) {
TEST_OUTPUT_LINE("ALL TESTS PASSED");
return 0;
} else {
TEST_OUTPUT_LINE("%d FAILED TESTS", testing_fails);
return 1;
}
}

View File

@@ -0,0 +1,188 @@
#include "flatbuffers/grpc.h"
#include "monster_test_generated.h"
#include "test_assert.h"
#include "test_builder.h"
bool verify(flatbuffers::grpc::Message<Monster> &msg, const std::string &expected_name, Color color) {
const Monster *monster = msg.GetRoot();
return (monster->name()->str() == expected_name) && (monster->color() == color);
}
bool release_n_verify(flatbuffers::grpc::MessageBuilder &mbb, const std::string &expected_name, Color color) {
flatbuffers::grpc::Message<Monster> msg = mbb.ReleaseMessage<Monster>();
const Monster *monster = msg.GetRoot();
return (monster->name()->str() == expected_name) && (monster->color() == color);
}
template <>
struct BuilderReuseTests<flatbuffers::grpc::MessageBuilder> {
static void builder_reusable_after_release_message_test(TestSelector selector) {
if (!selector.count(REUSABLE_AFTER_RELEASE_MESSAGE)) {
return;
}
flatbuffers::grpc::MessageBuilder b1;
std::vector<flatbuffers::grpc::Message<Monster>> buffers;
for (int i = 0; i < 5; ++i) {
auto root_offset1 = populate1(b1);
b1.Finish(root_offset1);
buffers.push_back(b1.ReleaseMessage<Monster>());
TEST_ASSERT_FUNC(verify(buffers[i], m1_name, m1_color));
}
}
static void builder_reusable_after_release_test(TestSelector selector) {
if (!selector.count(REUSABLE_AFTER_RELEASE)) {
return;
}
// FIXME: Populate-Release loop fails assert(GRPC_SLICE_IS_EMPTY(slice_)).
flatbuffers::grpc::MessageBuilder b1;
std::vector<flatbuffers::DetachedBuffer> buffers;
for (int i = 0; i < 5; ++i) {
auto root_offset1 = populate1(b1);
b1.Finish(root_offset1);
buffers.push_back(b1.Release());
TEST_ASSERT_FUNC(verify(buffers[i], m1_name, m1_color));
}
}
static void builder_reusable_after_releaseraw_test(TestSelector selector) {
if (!selector.count(REUSABLE_AFTER_RELEASE_RAW)) {
return;
}
flatbuffers::grpc::MessageBuilder b1;
for (int i = 0; i < 5; ++i) {
auto root_offset1 = populate1(b1);
b1.Finish(root_offset1);
size_t size, offset;
grpc_slice slice;
const uint8_t *buf = b1.ReleaseRaw(size, offset, slice);
TEST_ASSERT_FUNC(verify(buf, offset, m1_name, m1_color));
grpc_slice_unref(slice);
}
}
static void builder_reusable_after_release_and_move_assign_test(TestSelector selector) {
if (!selector.count(REUSABLE_AFTER_RELEASE_AND_MOVE_ASSIGN)) {
return;
}
// FIXME: Release-move_assign loop fails assert(p == GRPC_SLICE_START_PTR(slice_)).
flatbuffers::grpc::MessageBuilder b1;
std::vector<flatbuffers::DetachedBuffer> buffers;
for (int i = 0; i < 1; ++i) {
auto root_offset1 = populate1(b1);
b1.Finish(root_offset1);
buffers.push_back(b1.Release());
TEST_ASSERT_FUNC(verify(buffers[i], m1_name, m1_color));
// bring b1 back to life.
flatbuffers::grpc::MessageBuilder b2;
b1 = std::move(b2);
TEST_EQ_FUNC(b1.GetSize(), 0);
TEST_EQ_FUNC(b2.GetSize(), 0);
}
}
static void builder_reusable_after_release_message_and_move_assign_test(TestSelector selector) {
if (!selector.count(REUSABLE_AFTER_RELEASE_MESSAGE_AND_MOVE_ASSIGN)) {
return;
}
flatbuffers::grpc::MessageBuilder b1;
std::vector<flatbuffers::grpc::Message<Monster>> buffers;
for (int i = 0; i < 5; ++i) {
auto root_offset1 = populate1(b1);
b1.Finish(root_offset1);
buffers.push_back(b1.ReleaseMessage<Monster>());
TEST_ASSERT_FUNC(verify(buffers[i], m1_name, m1_color));
// bring b1 back to life.
flatbuffers::grpc::MessageBuilder b2;
b1 = std::move(b2);
TEST_EQ_FUNC(b1.GetSize(), 0);
TEST_EQ_FUNC(b2.GetSize(), 0);
}
}
static void builder_reusable_after_releaseraw_and_move_assign_test(TestSelector selector) {
if (!selector.count(REUSABLE_AFTER_RELEASE_RAW_AND_MOVE_ASSIGN)) {
return;
}
flatbuffers::grpc::MessageBuilder b1;
for (int i = 0; i < 5; ++i) {
auto root_offset1 = populate1(b1);
b1.Finish(root_offset1);
size_t size, offset;
grpc_slice slice = grpc_empty_slice();
const uint8_t *buf = b1.ReleaseRaw(size, offset, slice);
TEST_ASSERT_FUNC(verify(buf, offset, m1_name, m1_color));
grpc_slice_unref(slice);
flatbuffers::grpc::MessageBuilder b2;
b1 = std::move(b2);
TEST_EQ_FUNC(b1.GetSize(), 0);
TEST_EQ_FUNC(b2.GetSize(), 0);
}
}
static void run_tests(TestSelector selector) {
builder_reusable_after_release_test(selector);
builder_reusable_after_release_message_test(selector);
builder_reusable_after_releaseraw_test(selector);
builder_reusable_after_release_and_move_assign_test(selector);
builder_reusable_after_releaseraw_and_move_assign_test(selector);
builder_reusable_after_release_message_and_move_assign_test(selector);
}
};
void slice_allocator_tests() {
// move-construct no-delete test
{
size_t size = 2048;
flatbuffers::grpc::SliceAllocator sa1;
uint8_t *buf = sa1.allocate(size);
TEST_ASSERT_FUNC(buf != 0);
buf[0] = 100;
buf[size-1] = 200;
flatbuffers::grpc::SliceAllocator sa2(std::move(sa1));
// buf should be deleted after move-construct
TEST_EQ_FUNC(buf[0], 100);
TEST_EQ_FUNC(buf[size-1], 200);
// buf is freed here
}
// move-assign test
{
flatbuffers::grpc::SliceAllocator sa1, sa2;
uint8_t *buf = sa1.allocate(2048);
sa1 = std::move(sa2);
// sa1 deletes previously allocated memory in move-assign.
// So buf is no longer usable here.
TEST_ASSERT_FUNC(buf != 0);
}
}
void message_builder_tests() {
slice_allocator_tests();
BuilderTests<flatbuffers::grpc::MessageBuilder>::all_tests();
BuilderReuseTestSelector tests[6] = {
// REUSABLE_AFTER_RELEASE, // Assertion failed: (GRPC_SLICE_IS_EMPTY(slice_))
// REUSABLE_AFTER_RELEASE_AND_MOVE_ASSIGN, // Assertion failed: (p == GRPC_SLICE_START_PTR(slice_)
REUSABLE_AFTER_RELEASE_RAW,
REUSABLE_AFTER_RELEASE_MESSAGE,
REUSABLE_AFTER_RELEASE_MESSAGE_AND_MOVE_ASSIGN,
REUSABLE_AFTER_RELEASE_RAW_AND_MOVE_ASSIGN
};
BuilderReuseTests<flatbuffers::grpc::MessageBuilder>::run_tests(TestSelector(tests, tests+6));
}

View File

@@ -4,13 +4,13 @@
<parent>
<groupId>com.google.flatbuffers</groupId>
<artifactId>flatbuffers-parent</artifactId>
<version>1.8.0</version>
<version>1.10.0</version>
</parent>
<artifactId>grpc-test</artifactId>
<description>Example/Test project demonstrating usage of flatbuffers with GRPC-Java instead of protobufs
</description>
<properties>
<gRPC.version>1.8.0</gRPC.version>
<gRPC.version>1.9.0</gRPC.version>
</properties>
<dependencies>
<dependency>

View File

@@ -9,6 +9,10 @@
#include <assert.h>
#if !defined(FLATBUFFERS_ASSERT)
#define FLATBUFFERS_ASSERT assert
#endif
#ifndef ARDUINO
#include <cstdint>
#endif
@@ -47,6 +51,12 @@
#include "flatbuffers/stl_emulation.h"
// Note the __clang__ check is needed, because clang presents itself
// as an older GNUC compiler (4.2).
// Clang 3.3 and later implement all of the ISO C++ 2011 standard.
// Clang 3.4 and later implement all of the ISO C++ 2014 standard.
// http://clang.llvm.org/cxx_status.html
/// @cond FLATBUFFERS_INTERNAL
#if __cplusplus <= 199711L && \
(!defined(_MSC_VER) || _MSC_VER < 1600) && \
@@ -100,13 +110,14 @@
#endif // !defined(FLATBUFFERS_LITTLEENDIAN)
#define FLATBUFFERS_VERSION_MAJOR 1
#define FLATBUFFERS_VERSION_MINOR 9
#define FLATBUFFERS_VERSION_MINOR 10
#define FLATBUFFERS_VERSION_REVISION 0
#define FLATBUFFERS_STRING_EXPAND(X) #X
#define FLATBUFFERS_STRING(X) FLATBUFFERS_STRING_EXPAND(X)
#if (!defined(_MSC_VER) || _MSC_VER > 1600) && \
(!defined(__GNUC__) || (__GNUC__ * 100 + __GNUC_MINOR__ >= 407))
(!defined(__GNUC__) || (__GNUC__ * 100 + __GNUC_MINOR__ >= 407)) || \
defined(__clang__)
#define FLATBUFFERS_FINAL_CLASS final
#define FLATBUFFERS_OVERRIDE override
#else
@@ -115,7 +126,8 @@
#endif
#if (!defined(_MSC_VER) || _MSC_VER >= 1900) && \
(!defined(__GNUC__) || (__GNUC__ * 100 + __GNUC_MINOR__ >= 406))
(!defined(__GNUC__) || (__GNUC__ * 100 + __GNUC_MINOR__ >= 406)) || \
(defined(__cpp_constexpr) && __cpp_constexpr >= 200704)
#define FLATBUFFERS_CONSTEXPR constexpr
#else
#define FLATBUFFERS_CONSTEXPR
@@ -128,8 +140,9 @@
#define FLATBUFFERS_CONSTEXPR_CPP14
#endif
#if defined(__GXX_EXPERIMENTAL_CXX0X__) && __GNUC__ * 10 + __GNUC_MINOR__ >= 46 || \
defined(_MSC_FULL_VER) && _MSC_FULL_VER >= 190023026
#if (defined(__GXX_EXPERIMENTAL_CXX0X__) && (__GNUC__ * 100 + __GNUC_MINOR__ >= 406)) || \
(defined(_MSC_FULL_VER) && (_MSC_FULL_VER >= 190023026)) || \
defined(__clang__)
#define FLATBUFFERS_NOEXCEPT noexcept
#else
#define FLATBUFFERS_NOEXCEPT
@@ -138,16 +151,34 @@
// NOTE: the FLATBUFFERS_DELETE_FUNC macro may change the access mode to
// private, so be sure to put it at the end or reset access mode explicitly.
#if (!defined(_MSC_VER) || _MSC_FULL_VER >= 180020827) && \
(!defined(__GNUC__) || (__GNUC__ * 100 + __GNUC_MINOR__ >= 404))
(!defined(__GNUC__) || (__GNUC__ * 100 + __GNUC_MINOR__ >= 404)) || \
defined(__clang__)
#define FLATBUFFERS_DELETE_FUNC(func) func = delete;
#else
#define FLATBUFFERS_DELETE_FUNC(func) private: func;
#endif
#if defined(_MSC_VER)
#pragma warning(push)
#pragma warning(disable: 4127) // C4127: conditional expression is constant
#endif
#ifndef FLATBUFFERS_HAS_STRING_VIEW
// Only provide flatbuffers::string_view if __has_include can be used
// to detect a header that provides an implementation
#if defined(__has_include)
// Check for std::string_view (in c++17)
#if __has_include(<string_view>) && (__cplusplus >= 201606 || _HAS_CXX17)
#include <string_view>
namespace flatbuffers {
typedef std::string_view string_view;
}
#define FLATBUFFERS_HAS_STRING_VIEW 1
// Check for std::experimental::string_view (in c++14, compiler-dependent)
#elif __has_include(<experimental/string_view>) && (__cplusplus >= 201411)
#include <experimental/string_view>
namespace flatbuffers {
typedef std::experimental::string_view string_view;
}
#define FLATBUFFERS_HAS_STRING_VIEW 1
#endif
#endif // __has_include
#endif // !FLATBUFFERS_HAS_STRING_VIEW
/// @endcond
@@ -175,6 +206,11 @@ typedef uintmax_t largest_scalar_t;
// We support aligning the contents of buffers up to this size.
#define FLATBUFFERS_MAX_ALIGNMENT 16
#if defined(_MSC_VER)
#pragma warning(push)
#pragma warning(disable: 4127) // C4127: conditional expression is constant
#endif
template<typename T> T EndianSwap(T t) {
#if defined(_MSC_VER)
#define FLATBUFFERS_BYTESWAP16 _byteswap_ushort
@@ -209,10 +245,14 @@ template<typename T> T EndianSwap(T t) {
u.i = FLATBUFFERS_BYTESWAP64(u.i);
return u.t;
} else {
assert(0);
FLATBUFFERS_ASSERT(0);
}
}
#if defined(_MSC_VER)
#pragma warning(pop)
#endif
template<typename T> T EndianScalar(T t) {
#if FLATBUFFERS_LITTLEENDIAN

View File

@@ -33,7 +33,8 @@ template<typename T> struct Offset {
inline void EndianCheck() {
int endiantest = 1;
// If this fails, see FLATBUFFERS_LITTLEENDIAN above.
assert(*reinterpret_cast<char *>(&endiantest) == FLATBUFFERS_LITTLEENDIAN);
FLATBUFFERS_ASSERT(*reinterpret_cast<char *>(&endiantest) ==
FLATBUFFERS_LITTLEENDIAN);
(void)endiantest;
}
@@ -90,7 +91,7 @@ template<typename T> struct IndirectHelper<const T *> {
template<typename T, typename IT> struct VectorIterator {
typedef std::random_access_iterator_tag iterator_category;
typedef IT value_type;
typedef uoffset_t difference_type;
typedef ptrdiff_t difference_type;
typedef IT *pointer;
typedef IT &reference;
@@ -120,7 +121,7 @@ template<typename T, typename IT> struct VectorIterator {
return data_ != other.data_;
}
ptrdiff_t operator-(const VectorIterator &other) const {
difference_type operator-(const VectorIterator &other) const {
return (data_ - other.data_) / IndirectHelper<T>::element_stride;
}
@@ -194,7 +195,7 @@ template<typename T> class Vector {
typedef typename IndirectHelper<T>::mutable_return_type mutable_return_type;
return_type Get(uoffset_t i) const {
assert(i < size());
FLATBUFFERS_ASSERT(i < size());
return IndirectHelper<T>::Read(Data(), i);
}
@@ -232,7 +233,7 @@ template<typename T> class Vector {
// 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, const T &val) {
assert(i < size());
FLATBUFFERS_ASSERT(i < size());
WriteScalar(data() + i, val);
}
@@ -240,15 +241,15 @@ template<typename T> class Vector {
// "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));
FLATBUFFERS_ASSERT(i < size());
static_assert(sizeof(T) == sizeof(uoffset_t), "Unrelated types");
WriteScalar(data() + i,
static_cast<uoffset_t>(val - (Data() + i * sizeof(uoffset_t))));
}
// Get a mutable pointer to tables/strings inside this vector.
mutable_return_type GetMutableObject(uoffset_t i) const {
assert(i < size());
FLATBUFFERS_ASSERT(i < size());
return const_cast<mutable_return_type>(IndirectHelper<T>::Read(Data(), i));
}
@@ -334,7 +335,7 @@ const Vector<Offset<T>> *VectorCast(const Vector<Offset<U>> *ptr) {
#endif
// Convenient helper function to get the length of any vector, regardless
// of wether it is null or not (the field is not set).
// of whether it is null or not (the field is not set).
template<typename T> static inline size_t VectorLength(const Vector<T> *v) {
return v ? v->Length() : 0;
}
@@ -343,11 +344,31 @@ struct String : public Vector<char> {
const char *c_str() const { return reinterpret_cast<const char *>(Data()); }
std::string str() const { return std::string(c_str(), Length()); }
// clang-format off
#ifdef FLATBUFFERS_HAS_STRING_VIEW
flatbuffers::string_view string_view() const {
return flatbuffers::string_view(c_str(), Length());
}
#endif // FLATBUFFERS_HAS_STRING_VIEW
// clang-format on
bool operator<(const String &o) const {
return strcmp(c_str(), o.c_str()) < 0;
}
};
// Convenience function to get std::string from a String returning an empty
// string on null pointer.
static inline std::string GetString(const String * str) {
return str ? str->str() : "";
}
// Convenience function to get char* from a String returning an empty string on
// null pointer.
static inline const char * GetCstring(const String * str) {
return str ? str->c_str() : "";
}
// Allocator interface. This is flatbuffers-specific and meant only for
// `vector_downward` usage.
class Allocator {
@@ -368,7 +389,7 @@ class Allocator {
virtual uint8_t *reallocate_downward(uint8_t *old_p, size_t old_size,
size_t new_size, size_t in_use_back,
size_t in_use_front) {
assert(new_size > old_size); // vector_downward only grows
FLATBUFFERS_ASSERT(new_size > old_size); // vector_downward only grows
uint8_t *new_p = allocate(new_size);
memcpy_downward(old_p, old_size, new_p, new_size, in_use_back,
in_use_front);
@@ -393,20 +414,39 @@ class Allocator {
// DefaultAllocator uses new/delete to allocate memory regions
class DefaultAllocator : public Allocator {
public:
virtual uint8_t *allocate(size_t size) FLATBUFFERS_OVERRIDE {
uint8_t *allocate(size_t size) FLATBUFFERS_OVERRIDE {
return new uint8_t[size];
}
virtual void deallocate(uint8_t *p, size_t) FLATBUFFERS_OVERRIDE {
void deallocate(uint8_t *p, size_t) FLATBUFFERS_OVERRIDE {
delete[] p;
}
static DefaultAllocator &instance() {
static DefaultAllocator inst;
return inst;
}
};
// These functions allow for a null allocator to mean use the default allocator,
// as used by DetachedBuffer and vector_downward below.
// This is to avoid having a statically or dynamically allocated default
// allocator, or having to move it between the classes that may own it.
inline uint8_t *Allocate(Allocator *allocator, size_t size) {
return allocator ? allocator->allocate(size)
: DefaultAllocator().allocate(size);
}
inline void Deallocate(Allocator *allocator, uint8_t *p, size_t size) {
if (allocator) allocator->deallocate(p, size);
else DefaultAllocator().deallocate(p, size);
}
inline uint8_t *ReallocateDownward(Allocator *allocator, uint8_t *old_p,
size_t old_size, size_t new_size,
size_t in_use_back, size_t in_use_front) {
return allocator
? allocator->reallocate_downward(old_p, old_size, new_size,
in_use_back, in_use_front)
: DefaultAllocator().reallocate_downward(old_p, old_size, new_size,
in_use_back, in_use_front);
}
// DetachedBuffer is a finished flatbuffer memory region, detached from its
// builder. The original memory region and allocator are also stored so that
// the DetachedBuffer can manage the memory lifetime.
@@ -427,9 +467,7 @@ class DetachedBuffer {
buf_(buf),
reserved_(reserved),
cur_(cur),
size_(sz) {
assert(allocator_);
}
size_(sz) {}
DetachedBuffer(DetachedBuffer &&other)
: allocator_(other.allocator_),
@@ -498,12 +536,8 @@ class DetachedBuffer {
size_t size_;
inline void destroy() {
if (buf_) {
assert(allocator_);
allocator_->deallocate(buf_, reserved_);
}
if (buf_) Deallocate(allocator_, buf_, reserved_);
if (own_allocator_ && allocator_) { delete allocator_; }
reset();
}
@@ -529,31 +563,48 @@ class vector_downward {
Allocator *allocator,
bool own_allocator,
size_t buffer_minalign)
: allocator_(allocator ? allocator : &DefaultAllocator::instance()),
: allocator_(allocator),
own_allocator_(own_allocator),
initial_size_(initial_size),
buffer_minalign_(buffer_minalign),
reserved_(0),
buf_(nullptr),
cur_(nullptr),
scratch_(nullptr) {
assert(allocator_);
scratch_(nullptr) {}
vector_downward(vector_downward &&other)
: allocator_(other.allocator_),
own_allocator_(other.own_allocator_),
initial_size_(other.initial_size_),
buffer_minalign_(other.buffer_minalign_),
reserved_(other.reserved_),
buf_(other.buf_),
cur_(other.cur_),
scratch_(other.scratch_) {
// No change in other.allocator_
// No change in other.initial_size_
// No change in other.buffer_minalign_
other.own_allocator_ = false;
other.reserved_ = 0;
other.buf_ = nullptr;
other.cur_ = nullptr;
other.scratch_ = nullptr;
}
vector_downward &operator=(vector_downward &&other) {
// Move construct a temporary and swap idiom
vector_downward temp(std::move(other));
swap(temp);
return *this;
}
~vector_downward() {
if (buf_) {
assert(allocator_);
allocator_->deallocate(buf_, reserved_);
}
if (own_allocator_ && allocator_) { delete allocator_; }
clear_buffer();
clear_allocator();
}
void reset() {
if (buf_) {
assert(allocator_);
allocator_->deallocate(buf_, reserved_);
buf_ = nullptr;
}
clear_buffer();
clear();
}
@@ -571,32 +622,61 @@ class vector_downward {
scratch_ = buf_;
}
// Relinquish the pointer to the caller.
DetachedBuffer release() {
DetachedBuffer fb(allocator_, own_allocator_, buf_, reserved_, cur_,
size());
void clear_allocator() {
if (own_allocator_ && allocator_) { delete allocator_; }
allocator_ = nullptr;
own_allocator_ = false;
}
void clear_buffer() {
if (buf_) Deallocate(allocator_, buf_, reserved_);
buf_ = nullptr;
}
// Relinquish the pointer to the caller.
uint8_t *release_raw(size_t &allocated_bytes, size_t &offset) {
auto *buf = buf_;
allocated_bytes = reserved_;
offset = static_cast<size_t>(cur_ - buf_);
// release_raw only relinquishes the buffer ownership.
// Does not deallocate or reset the allocator. Destructor will do that.
buf_ = nullptr;
clear();
return buf;
}
// Relinquish the pointer to the caller.
DetachedBuffer release() {
// allocator ownership (if any) is transferred to DetachedBuffer.
DetachedBuffer fb(allocator_, own_allocator_, buf_, reserved_, cur_,
size());
if (own_allocator_) {
allocator_ = nullptr;
own_allocator_ = false;
}
buf_ = nullptr;
clear();
return fb;
}
size_t ensure_space(size_t len) {
assert(cur_ >= scratch_ && scratch_ >= buf_);
FLATBUFFERS_ASSERT(cur_ >= scratch_ && scratch_ >= buf_);
if (len > static_cast<size_t>(cur_ - scratch_)) { reallocate(len); }
// Beyond this, signed offsets may not have enough range:
// (FlatBuffers > 2GB not supported).
assert(size() < FLATBUFFERS_MAX_BUFFER_SIZE);
FLATBUFFERS_ASSERT(size() < FLATBUFFERS_MAX_BUFFER_SIZE);
return len;
}
inline uint8_t *make_space(size_t len) {
cur_ -= ensure_space(len);
size_t space = ensure_space(len);
cur_ -= space;
return cur_;
}
Allocator &get_allocator() { return *allocator_; }
// Returns nullptr if using the DefaultAllocator.
Allocator *get_custom_allocator() { return allocator_; }
uoffset_t size() const {
return static_cast<uoffset_t>(reserved_ - (cur_ - buf_));
@@ -609,17 +689,17 @@ class vector_downward {
size_t capacity() const { return reserved_; }
uint8_t *data() const {
assert(cur_);
FLATBUFFERS_ASSERT(cur_);
return cur_;
}
uint8_t *scratch_data() const {
assert(buf_);
FLATBUFFERS_ASSERT(buf_);
return buf_;
}
uint8_t *scratch_end() const {
assert(scratch_);
FLATBUFFERS_ASSERT(scratch_);
return scratch_;
}
@@ -656,6 +736,24 @@ class vector_downward {
void pop(size_t bytes_to_remove) { cur_ += bytes_to_remove; }
void scratch_pop(size_t bytes_to_remove) { scratch_ -= bytes_to_remove; }
void swap(vector_downward &other) {
using std::swap;
swap(allocator_, other.allocator_);
swap(own_allocator_, other.own_allocator_);
swap(initial_size_, other.initial_size_);
swap(buffer_minalign_, other.buffer_minalign_);
swap(reserved_, other.reserved_);
swap(buf_, other.buf_);
swap(cur_, other.cur_);
swap(scratch_, other.scratch_);
}
void swap_allocator(vector_downward &other) {
using std::swap;
swap(allocator_, other.allocator_);
swap(own_allocator_, other.own_allocator_);
}
private:
// You shouldn't really be copying instances of this class.
FLATBUFFERS_DELETE_FUNC(vector_downward(const vector_downward &))
@@ -671,7 +769,6 @@ class vector_downward {
uint8_t *scratch_; // Points to the end of the scratchpad in use.
void reallocate(size_t len) {
assert(allocator_);
auto old_reserved = reserved_;
auto old_size = size();
auto old_scratch_size = scratch_size();
@@ -679,10 +776,10 @@ class vector_downward {
old_reserved ? old_reserved / 2 : initial_size_);
reserved_ = (reserved_ + buffer_minalign_ - 1) & ~(buffer_minalign_ - 1);
if (buf_) {
buf_ = allocator_->reallocate_downward(buf_, old_reserved, reserved_,
old_size, old_scratch_size);
buf_ = ReallocateDownward(allocator_, buf_, old_reserved, reserved_,
old_size, old_scratch_size);
} else {
buf_ = allocator_->allocate(reserved_);
buf_ = Allocate(allocator_, reserved_);
}
cur_ = buf_ + reserved_ - old_size;
scratch_ = buf_ + old_scratch_size;
@@ -720,8 +817,8 @@ class FlatBufferBuilder {
/// @brief Default constructor for FlatBufferBuilder.
/// @param[in] initial_size The initial size of the buffer, in bytes. Defaults
/// to `1024`.
/// @param[in] allocator An `Allocator` to use. Defaults to a new instance of
/// a `DefaultAllocator`.
/// @param[in] allocator An `Allocator` to use. If null will use
/// `DefaultAllocator`.
/// @param[in] own_allocator Whether the builder/vector should own the
/// allocator. Defaults to / `false`.
/// @param[in] buffer_minalign Force the buffer to be aligned to the given
@@ -745,6 +842,44 @@ class FlatBufferBuilder {
EndianCheck();
}
/// @brief Move constructor for FlatBufferBuilder.
FlatBufferBuilder(FlatBufferBuilder &&other)
: buf_(1024, nullptr, false, AlignOf<largest_scalar_t>()),
num_field_loc(0),
max_voffset_(0),
nested(false),
finished(false),
minalign_(1),
force_defaults_(false),
dedup_vtables_(true),
string_pool(nullptr) {
EndianCheck();
// Default construct and swap idiom.
// Lack of delegating constructors in vs2010 makes it more verbose than needed.
Swap(other);
}
/// @brief Move assignment operator for FlatBufferBuilder.
FlatBufferBuilder &operator=(FlatBufferBuilder &&other) {
// Move construct a temporary and swap idiom
FlatBufferBuilder temp(std::move(other));
Swap(temp);
return *this;
}
void Swap(FlatBufferBuilder &other) {
using std::swap;
buf_.swap(other.buf_);
swap(num_field_loc, other.num_field_loc);
swap(max_voffset_, other.max_voffset_);
swap(nested, other.nested);
swap(finished, other.finished);
swap(minalign_, other.minalign_);
swap(force_defaults_, other.force_defaults_);
swap(dedup_vtables_, other.dedup_vtables_);
swap(string_pool, other.string_pool);
}
~FlatBufferBuilder() {
if (string_pool) delete string_pool;
}
@@ -798,6 +933,19 @@ class FlatBufferBuilder {
return buf_.release();
}
/// @brief Get the released pointer to the serialized buffer.
/// @param The size of the memory block containing
/// the serialized `FlatBuffer`.
/// @param The offset from the released pointer where the finished
/// `FlatBuffer` starts.
/// @return A raw pointer to the start of the memory block containing
/// the serialized `FlatBuffer`.
/// @remark If the allocator is owned, it gets deleted during this call.
uint8_t *ReleaseRaw(size_t &size, size_t &offset) {
Finished();
return buf_.release_raw(size, offset);
}
/// @brief get the minimum alignment this buffer needs to be accessed
/// properly. This is only known once all elements have been written (after
/// you call Finish()). You can use this information if you need to embed
@@ -815,13 +963,14 @@ class FlatBufferBuilder {
// FlatBufferBuilder::Finish with your root table.
// If you really need to access an unfinished buffer, call
// GetCurrentBufferPointer instead.
assert(finished);
FLATBUFFERS_ASSERT(finished);
}
/// @endcond
/// @brief In order to save space, fields that are set to their default value
/// don't get serialized into the buffer.
/// @param[in] bool fd When set to `true`, always serializes default values.
/// @param[in] bool fd When set to `true`, always serializes default values that are set.
/// Optional fields which are not set explicitly, will still not be serialized.
void ForceDefaults(bool fd) { force_defaults_ = fd; }
/// @brief By default vtables are deduped in order to save space.
@@ -908,7 +1057,7 @@ class FlatBufferBuilder {
// Align to ensure GetSize() below is correct.
Align(sizeof(uoffset_t));
// Offset must refer to something already in buffer.
assert(off && off <= GetSize());
FLATBUFFERS_ASSERT(off && off <= GetSize());
return GetSize() - off + static_cast<uoffset_t>(sizeof(uoffset_t));
}
@@ -921,9 +1070,9 @@ class FlatBufferBuilder {
// 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);
FLATBUFFERS_ASSERT(!nested);
// If you hit this, fields were added outside the scope of a table.
assert(!num_field_loc);
FLATBUFFERS_ASSERT(!num_field_loc);
}
// From generated code (or from the parser), we call StartTable/EndTable
@@ -939,7 +1088,7 @@ class FlatBufferBuilder {
// resulting vtable offset.
uoffset_t EndTable(uoffset_t start) {
// If you get this assert, a corresponding StartTable wasn't called.
assert(nested);
FLATBUFFERS_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);
@@ -953,7 +1102,8 @@ class FlatBufferBuilder {
FieldIndexToOffset(0));
buf_.fill_big(max_voffset_);
auto table_object_size = vtableoffsetloc - start;
assert(table_object_size < 0x10000); // Vtable use 16bit offsets.
// Vtable use 16bit offsets.
FLATBUFFERS_ASSERT(table_object_size < 0x10000);
WriteScalar<voffset_t>(buf_.data() + sizeof(voffset_t),
static_cast<voffset_t>(table_object_size));
WriteScalar<voffset_t>(buf_.data(), max_voffset_);
@@ -963,7 +1113,8 @@ class FlatBufferBuilder {
auto field_location = reinterpret_cast<FieldLoc *>(it);
auto pos = static_cast<voffset_t>(vtableoffsetloc - field_location->off);
// If this asserts, it means you've set a field twice.
assert(!ReadScalar<voffset_t>(buf_.data() + field_location->id));
FLATBUFFERS_ASSERT(
!ReadScalar<voffset_t>(buf_.data() + field_location->id));
WriteScalar<voffset_t>(buf_.data() + field_location->id, pos);
}
ClearOffsets();
@@ -1006,14 +1157,7 @@ class FlatBufferBuilder {
// This checks a required field has been set in a given table that has
// just been constructed.
template<typename T> void Required(Offset<T> table, voffset_t field) {
auto table_ptr = buf_.data_at(table.o);
auto vtable_ptr = table_ptr - ReadScalar<soffset_t>(table_ptr);
bool ok = ReadScalar<voffset_t>(vtable_ptr + field) != 0;
// If this fails, the caller will show what field needs to be set.
assert(ok);
(void)ok;
}
template<typename T> void Required(Offset<T> table, voffset_t field);
uoffset_t StartStruct(size_t alignment) {
Align(alignment);
@@ -1074,6 +1218,17 @@ class FlatBufferBuilder {
return CreateString(str.c_str(), str.length());
}
// clang-format off
#ifdef FLATBUFFERS_HAS_STRING_VIEW
/// @brief Store a string in the buffer, which can contain any binary data.
/// @param[in] str A const string_view to copy in to the buffer.
/// @return Returns the offset in the buffer where the string starts.
Offset<String> CreateString(flatbuffers::string_view str) {
return CreateString(str.data(), str.size());
}
#endif // FLATBUFFERS_HAS_STRING_VIEW
// clang-format on
/// @brief Store a string in the buffer, which can contain any binary data.
/// @param[in] str A const pointer to a `String` struct to add to the buffer.
/// @return Returns the offset in the buffer where the string starts
@@ -1143,7 +1298,7 @@ class FlatBufferBuilder {
/// @cond FLATBUFFERS_INTERNAL
uoffset_t EndVector(size_t len) {
assert(nested); // Hit if no corresponding StartVector.
FLATBUFFERS_ASSERT(nested); // Hit if no corresponding StartVector.
nested = false;
return PushElement(static_cast<uoffset_t>(len));
}
@@ -1164,6 +1319,11 @@ class FlatBufferBuilder {
PreAlign(len * elemsize, alignment);
}
// Similar to ForceVectorAlignment but for String fields.
void ForceStringAlignment(size_t len, size_t alignment) {
PreAlign((len + 1) * sizeof(char), alignment);
}
/// @endcond
/// @brief Serialize an array into a FlatBuffer `vector`.
@@ -1510,6 +1670,13 @@ class FlatBufferBuilder {
/// in the buffer.
template<typename T>
Offset<Vector<T>> CreateUninitializedVector(size_t len, T **buf) {
AssertScalarT<T>();
return CreateUninitializedVector(len, sizeof(T),
reinterpret_cast<uint8_t **>(buf));
}
template<typename T>
Offset<Vector<const T*>> CreateUninitializedVectorOfStructs(size_t len, T **buf) {
return CreateUninitializedVector(len, sizeof(T),
reinterpret_cast<uint8_t **>(buf));
}
@@ -1559,7 +1726,7 @@ class FlatBufferBuilder {
(file_identifier ? kFileIdentifierLength : 0),
minalign_);
if (file_identifier) {
assert(strlen(file_identifier) == kFileIdentifierLength);
FLATBUFFERS_ASSERT(strlen(file_identifier) == kFileIdentifierLength);
PushBytes(reinterpret_cast<const uint8_t *>(file_identifier),
kFileIdentifierLength);
}
@@ -1681,49 +1848,63 @@ class Verifier FLATBUFFERS_FINAL_CLASS {
Verifier(const uint8_t *buf, size_t buf_len, uoffset_t _max_depth = 64,
uoffset_t _max_tables = 1000000)
: buf_(buf),
end_(buf + buf_len),
size_(buf_len),
depth_(0),
max_depth_(_max_depth),
num_tables_(0),
max_tables_(_max_tables)
// clang-format off
#ifdef FLATBUFFERS_TRACK_VERIFIER_BUFFER_SIZE
, upper_bound_(buf)
, upper_bound_(0)
#endif
// clang-format on
{
assert(size_ < FLATBUFFERS_MAX_BUFFER_SIZE);
}
// Central location where any verification failures register.
bool Check(bool ok) const {
// clang-format off
#ifdef FLATBUFFERS_DEBUG_VERIFICATION_FAILURE
assert(ok);
FLATBUFFERS_ASSERT(ok);
#endif
#ifdef FLATBUFFERS_TRACK_VERIFIER_BUFFER_SIZE
if (!ok)
upper_bound_ = buf_;
upper_bound_ = 0;
#endif
// clang-format on
return ok;
}
// Verify any range within the buffer.
bool Verify(const void *elem, size_t elem_len) const {
bool Verify(size_t elem, size_t elem_len) const {
// clang-format off
#ifdef FLATBUFFERS_TRACK_VERIFIER_BUFFER_SIZE
auto upper_bound = reinterpret_cast<const uint8_t *>(elem) + elem_len;
auto upper_bound = elem + elem_len;
if (upper_bound_ < upper_bound)
upper_bound_ = upper_bound;
#endif
// clang-format on
return Check(elem_len <= (size_t)(end_ - buf_) && elem >= buf_ &&
elem <= end_ - elem_len);
return Check(elem_len < size_ && elem <= size_ - elem_len);
}
template<typename T> bool VerifyAlignment(size_t elem) const {
return (elem & (sizeof(T) - 1)) == 0;
}
// Verify a range indicated by sizeof(T).
template<typename T> bool Verify(const void *elem) const {
return Verify(elem, sizeof(T));
template<typename T> bool Verify(size_t elem) const {
return VerifyAlignment<T>(elem) && Verify(elem, sizeof(T));
}
// Verify relative to a known-good base pointer.
bool Verify(const uint8_t *base, voffset_t elem_off, size_t elem_len) const {
return Verify(static_cast<size_t>(base - buf_) + elem_off, elem_len);
}
template<typename T> bool Verify(const uint8_t *base, voffset_t elem_off)
const {
return Verify(static_cast<size_t>(base - buf_) + elem_off, sizeof(T));
}
// Verify a pointer (may be NULL) of a table type.
@@ -1732,31 +1913,32 @@ class Verifier FLATBUFFERS_FINAL_CLASS {
}
// Verify a pointer (may be NULL) of any vector type.
template<typename T> bool Verify(const Vector<T> *vec) const {
const uint8_t *end;
return !vec || VerifyVector(reinterpret_cast<const uint8_t *>(vec),
sizeof(T), &end);
template<typename T> bool VerifyVector(const Vector<T> *vec) const {
return !vec || VerifyVectorOrString(reinterpret_cast<const uint8_t *>(vec),
sizeof(T));
}
// 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));
template<typename T> bool VerifyVector(const Vector<const T *> *vec) const {
return VerifyVector(reinterpret_cast<const Vector<T> *>(vec));
}
// Verify a pointer (may be NULL) to string.
bool Verify(const String *str) const {
const uint8_t *end;
bool VerifyString(const String *str) const {
size_t end;
return !str ||
(VerifyVector(reinterpret_cast<const uint8_t *>(str), 1, &end) &&
(VerifyVectorOrString(reinterpret_cast<const uint8_t *>(str),
1, &end) &&
Verify(end, 1) && // Must have terminator
Check(*end == '\0')); // Terminating byte must be 0.
Check(buf_[end] == '\0')); // Terminating byte must be 0.
}
// Common code between vectors and strings.
bool VerifyVector(const uint8_t *vec, size_t elem_size,
const uint8_t **end) const {
bool VerifyVectorOrString(const uint8_t *vec, size_t elem_size,
size_t *end = nullptr) const {
auto veco = static_cast<size_t>(vec - buf_);
// Check we can read the size field.
if (!Verify<uoffset_t>(vec)) return false;
if (!Verify<uoffset_t>(veco)) return false;
// Check the whole array. If this is a string, the byte past the array
// must be 0.
auto size = ReadScalar<uoffset_t>(vec);
@@ -1764,15 +1946,15 @@ class Verifier FLATBUFFERS_FINAL_CLASS {
if (!Check(size < max_elems))
return false; // Protect against byte_size overflowing.
auto byte_size = sizeof(size) + elem_size * size;
*end = vec + byte_size;
return Verify(vec, byte_size);
if (end) *end = veco + byte_size;
return Verify(veco, byte_size);
}
// Special case for string contents, after the above has been called.
bool VerifyVectorOfStrings(const Vector<Offset<String>> *vec) const {
if (vec) {
for (uoffset_t i = 0; i < vec->size(); i++) {
if (!Verify(vec->Get(i))) return false;
if (!VerifyString(vec->Get(i))) return false;
}
}
return true;
@@ -1788,43 +1970,68 @@ class Verifier FLATBUFFERS_FINAL_CLASS {
return true;
}
bool VerifyTableStart(const uint8_t *table) {
// Check the vtable offset.
auto tableo = static_cast<size_t>(table - buf_);
if (!Verify<soffset_t>(tableo)) return false;
// This offset may be signed, but doing the substraction unsigned always
// gives the result we want.
auto vtableo = tableo - static_cast<size_t>(ReadScalar<soffset_t>(table));
// Check the vtable size field, then check vtable fits in its entirety.
return VerifyComplexity() && Verify<voffset_t>(vtableo) &&
VerifyAlignment<voffset_t>(ReadScalar<voffset_t>(buf_ + vtableo)) &&
Verify(vtableo, ReadScalar<voffset_t>(buf_ + vtableo));
}
template<typename T>
bool VerifyBufferFromStart(const char *identifier, const uint8_t *start) {
bool VerifyBufferFromStart(const char *identifier, size_t start) {
if (identifier &&
(size_t(end_ - start) < 2 * sizeof(flatbuffers::uoffset_t) ||
!BufferHasIdentifier(start, identifier))) {
(size_ < 2 * sizeof(flatbuffers::uoffset_t) ||
!BufferHasIdentifier(buf_ + start, identifier))) {
return false;
}
// Call T::Verify, which must be in the generated code for this type.
auto o = VerifyOffset(start);
return o && reinterpret_cast<const T *>(start + o)->Verify(*this)
#ifdef FLATBUFFERS_TRACK_VERIFIER_BUFFER_SIZE
return o && reinterpret_cast<const T *>(buf_ + start + o)->Verify(*this)
// clang-format off
#ifdef FLATBUFFERS_TRACK_VERIFIER_BUFFER_SIZE
&& GetComputedSize()
#endif
#endif
;
// clang-format on
}
// Verify this whole buffer, starting with root type T.
template<typename T> bool VerifyBuffer() { return VerifyBuffer<T>(nullptr); }
template<typename T> bool VerifyBuffer(const char *identifier) {
return VerifyBufferFromStart<T>(identifier, buf_);
return VerifyBufferFromStart<T>(identifier, 0);
}
template<typename T> bool VerifySizePrefixedBuffer(const char *identifier) {
return Verify<uoffset_t>(buf_) &&
ReadScalar<uoffset_t>(buf_) == end_ - buf_ - sizeof(uoffset_t) &&
VerifyBufferFromStart<T>(identifier, buf_ + sizeof(uoffset_t));
return Verify<uoffset_t>(0U) &&
ReadScalar<uoffset_t>(buf_) == size_ - sizeof(uoffset_t) &&
VerifyBufferFromStart<T>(identifier, sizeof(uoffset_t));
}
uoffset_t VerifyOffset(const uint8_t *start) const {
if (!Verify<uoffset_t>(start)) return false;
auto o = ReadScalar<uoffset_t>(start);
uoffset_t VerifyOffset(size_t start) const {
if (!Verify<uoffset_t>(start)) return 0;
auto o = ReadScalar<uoffset_t>(buf_ + start);
// May not point to itself.
Check(o != 0);
// Can't wrap around / buffers are max 2GB.
if (!Check(static_cast<soffset_t>(o) >= 0)) return 0;
// Must be inside the buffer to create a pointer from it (pointer outside
// buffer is UB).
if (!Verify(start + o, 1)) return 0;
return o;
}
uoffset_t VerifyOffset(const uint8_t *base, voffset_t start) const {
return VerifyOffset(static_cast<size_t>(base - buf_) + start);
}
// Called at the start of a table to increase counters measuring data
// structure depth and amount, and possibly bails out with false if
// limits set by the constructor have been hit. Needs to be balanced
@@ -1845,24 +2052,24 @@ class Verifier FLATBUFFERS_FINAL_CLASS {
#ifdef FLATBUFFERS_TRACK_VERIFIER_BUFFER_SIZE
// Returns the message size in bytes
size_t GetComputedSize() const {
uintptr_t size = upper_bound_ - buf_;
uintptr_t size = upper_bound_;
// Align the size to uoffset_t
size = (size - 1 + sizeof(uoffset_t)) & ~(sizeof(uoffset_t) - 1);
return (buf_ + size > end_) ? 0 : size;
return (size > size_) ? 0 : size;
}
#endif
// clang-format on
private:
const uint8_t *buf_;
const uint8_t *end_;
size_t size_;
uoffset_t depth_;
uoffset_t max_depth_;
uoffset_t num_tables_;
uoffset_t max_tables_;
// clang-format off
#ifdef FLATBUFFERS_TRACK_VERIFIER_BUFFER_SIZE
mutable const uint8_t *upper_bound_;
mutable size_t upper_bound_;
#endif
// clang-format on
};
@@ -1984,13 +2191,7 @@ class Table {
// Verify the vtable of this table.
// Call this once per table, followed by VerifyField once per field.
bool VerifyTableStart(Verifier &verifier) const {
// Check the vtable offset.
if (!verifier.Verify<soffset_t>(data_)) return false;
auto vtable = GetVTable();
// Check the vtable size field, then check vtable fits in its entirety.
return verifier.VerifyComplexity() && verifier.Verify<voffset_t>(vtable) &&
(ReadScalar<voffset_t>(vtable) & (sizeof(voffset_t) - 1)) == 0 &&
verifier.Verify(vtable, ReadScalar<voffset_t>(vtable));
return verifier.VerifyTableStart(data_);
}
// Verify a particular field.
@@ -2000,7 +2201,7 @@ class Table {
// VerifyTable().
auto field_offset = GetOptionalFieldOffset(field);
// Check the actual field.
return !field_offset || verifier.Verify<T>(data_ + field_offset);
return !field_offset || verifier.Verify<T>(data_, field_offset);
}
// VerifyField for required fields.
@@ -2008,19 +2209,19 @@ class Table {
bool VerifyFieldRequired(const Verifier &verifier, voffset_t field) const {
auto field_offset = GetOptionalFieldOffset(field);
return verifier.Check(field_offset != 0) &&
verifier.Verify<T>(data_ + field_offset);
verifier.Verify<T>(data_, field_offset);
}
// Versions for offsets.
bool VerifyOffset(const Verifier &verifier, voffset_t field) const {
auto field_offset = GetOptionalFieldOffset(field);
return !field_offset || verifier.VerifyOffset(data_ + field_offset);
return !field_offset || verifier.VerifyOffset(data_, field_offset);
}
bool VerifyOffsetRequired(const Verifier &verifier, voffset_t field) const {
auto field_offset = GetOptionalFieldOffset(field);
return verifier.Check(field_offset != 0) &&
verifier.VerifyOffset(data_ + field_offset);
verifier.VerifyOffset(data_, field_offset);
}
private:
@@ -2032,6 +2233,15 @@ class Table {
uint8_t data_[1];
};
template<typename T> void FlatBufferBuilder::Required(Offset<T> table,
voffset_t field) {
auto table_ptr = reinterpret_cast<const Table *>(buf_.data_at(table.o));
bool ok = table_ptr->GetOptionalFieldOffset(field) != 0;
// If this fails, the caller will show what field needs to be set.
FLATBUFFERS_ASSERT(ok);
(void)ok;
}
/// @brief This can compute the start of a FlatBuffer from a root pointer, i.e.
/// it is the opposite transformation of GetRoot().
/// This may be useful if you want to pass on a root and have the recipient
@@ -2066,7 +2276,7 @@ inline const uint8_t *GetBufferStartFromRootPointer(const void *root) {
// or the buffer is corrupt.
// Assert, because calling this function with bad data may cause reads
// outside of buffer boundaries.
assert(false);
FLATBUFFERS_ASSERT(false);
return nullptr;
}
@@ -2131,17 +2341,17 @@ inline int LookupEnum(const char **names, const char *name) {
// clang-format off
#if defined(_MSC_VER)
#define MANUALLY_ALIGNED_STRUCT(alignment) \
#define FLATBUFFERS_MANUALLY_ALIGNED_STRUCT(alignment) \
__pragma(pack(1)); \
struct __declspec(align(alignment))
#define STRUCT_END(name, size) \
#define FLATBUFFERS_STRUCT_END(name, size) \
__pragma(pack()); \
static_assert(sizeof(name) == size, "compiler breaks packing rules")
#elif defined(__GNUC__) || defined(__clang__)
#define MANUALLY_ALIGNED_STRUCT(alignment) \
#define FLATBUFFERS_MANUALLY_ALIGNED_STRUCT(alignment) \
_Pragma("pack(1)") \
struct __attribute__((aligned(alignment)))
#define STRUCT_END(name, size) \
#define FLATBUFFERS_STRUCT_END(name, size) \
_Pragma("pack()") \
static_assert(sizeof(name) == size, "compiler breaks packing rules")
#else
@@ -2211,9 +2421,9 @@ typedef const TypeTable *(*TypeFunction)();
struct TypeTable {
SequenceType st;
size_t num_elems; // of each of the arrays below.
const TypeCode *type_codes;
const TypeFunction *type_refs;
size_t num_elems; // of type_codes, values, names (but not type_refs).
const TypeCode *type_codes; // num_elems count
const TypeFunction *type_refs; // less than num_elems entries (see TypeCode).
const int32_t *values; // Only set for non-consecutive enum/union or structs.
const char * const *names; // Only set if compiled with --reflect-names.
};
@@ -2240,7 +2450,7 @@ volatile __attribute__((weak)) const char *flatbuffer_version_string =
#endif // !defined(_WIN32) && !defined(__CYGWIN__)
#define DEFINE_BITMASK_OPERATORS(E, T)\
#define FLATBUFFERS_DEFINE_BITMASK_OPERATORS(E, T)\
inline E operator | (E lhs, E rhs){\
return E(T(lhs) | T(rhs));\
}\
@@ -2272,9 +2482,6 @@ volatile __attribute__((weak)) const char *flatbuffer_version_string =
/// @endcond
} // namespace flatbuffers
#if defined(_MSC_VER)
#pragma warning(pop)
#endif
// clang-format on
#endif // FLATBUFFERS_H_

View File

@@ -49,75 +49,75 @@ enum BitWidth {
// These are used as the upper 6 bits of a type field to indicate the actual
// type.
enum Type {
TYPE_NULL = 0,
TYPE_INT = 1,
TYPE_UINT = 2,
TYPE_FLOAT = 3,
FBT_NULL = 0,
FBT_INT = 1,
FBT_UINT = 2,
FBT_FLOAT = 3,
// Types above stored inline, types below store an offset.
TYPE_KEY = 4,
TYPE_STRING = 5,
TYPE_INDIRECT_INT = 6,
TYPE_INDIRECT_UINT = 7,
TYPE_INDIRECT_FLOAT = 8,
TYPE_MAP = 9,
TYPE_VECTOR = 10, // Untyped.
TYPE_VECTOR_INT = 11, // Typed any size (stores no type table).
TYPE_VECTOR_UINT = 12,
TYPE_VECTOR_FLOAT = 13,
TYPE_VECTOR_KEY = 14,
TYPE_VECTOR_STRING = 15,
TYPE_VECTOR_INT2 = 16, // Typed tuple (no type table, no size field).
TYPE_VECTOR_UINT2 = 17,
TYPE_VECTOR_FLOAT2 = 18,
TYPE_VECTOR_INT3 = 19, // Typed triple (no type table, no size field).
TYPE_VECTOR_UINT3 = 20,
TYPE_VECTOR_FLOAT3 = 21,
TYPE_VECTOR_INT4 = 22, // Typed quad (no type table, no size field).
TYPE_VECTOR_UINT4 = 23,
TYPE_VECTOR_FLOAT4 = 24,
TYPE_BLOB = 25,
TYPE_BOOL = 26,
TYPE_VECTOR_BOOL =
FBT_KEY = 4,
FBT_STRING = 5,
FBT_INDIRECT_INT = 6,
FBT_INDIRECT_UINT = 7,
FBT_INDIRECT_FLOAT = 8,
FBT_MAP = 9,
FBT_VECTOR = 10, // Untyped.
FBT_VECTOR_INT = 11, // Typed any size (stores no type table).
FBT_VECTOR_UINT = 12,
FBT_VECTOR_FLOAT = 13,
FBT_VECTOR_KEY = 14,
FBT_VECTOR_STRING = 15,
FBT_VECTOR_INT2 = 16, // Typed tuple (no type table, no size field).
FBT_VECTOR_UINT2 = 17,
FBT_VECTOR_FLOAT2 = 18,
FBT_VECTOR_INT3 = 19, // Typed triple (no type table, no size field).
FBT_VECTOR_UINT3 = 20,
FBT_VECTOR_FLOAT3 = 21,
FBT_VECTOR_INT4 = 22, // Typed quad (no type table, no size field).
FBT_VECTOR_UINT4 = 23,
FBT_VECTOR_FLOAT4 = 24,
FBT_BLOB = 25,
FBT_BOOL = 26,
FBT_VECTOR_BOOL =
36, // To Allow the same type of conversion of type to vector type
};
inline bool IsInline(Type t) { return t <= TYPE_FLOAT || t == TYPE_BOOL; }
inline bool IsInline(Type t) { return t <= FBT_FLOAT || t == FBT_BOOL; }
inline bool IsTypedVectorElementType(Type t) {
return (t >= TYPE_INT && t <= TYPE_STRING) || t == TYPE_BOOL;
return (t >= FBT_INT && t <= FBT_STRING) || t == FBT_BOOL;
}
inline bool IsTypedVector(Type t) {
return (t >= TYPE_VECTOR_INT && t <= TYPE_VECTOR_STRING) ||
t == TYPE_VECTOR_BOOL;
return (t >= FBT_VECTOR_INT && t <= FBT_VECTOR_STRING) ||
t == FBT_VECTOR_BOOL;
}
inline bool IsFixedTypedVector(Type t) {
return t >= TYPE_VECTOR_INT2 && t <= TYPE_VECTOR_FLOAT4;
return t >= FBT_VECTOR_INT2 && t <= FBT_VECTOR_FLOAT4;
}
inline Type ToTypedVector(Type t, size_t fixed_len = 0) {
assert(IsTypedVectorElementType(t));
FLATBUFFERS_ASSERT(IsTypedVectorElementType(t));
switch (fixed_len) {
case 0: return static_cast<Type>(t - TYPE_INT + TYPE_VECTOR_INT);
case 2: return static_cast<Type>(t - TYPE_INT + TYPE_VECTOR_INT2);
case 3: return static_cast<Type>(t - TYPE_INT + TYPE_VECTOR_INT3);
case 4: return static_cast<Type>(t - TYPE_INT + TYPE_VECTOR_INT4);
default: assert(0); return TYPE_NULL;
case 0: return static_cast<Type>(t - FBT_INT + FBT_VECTOR_INT);
case 2: return static_cast<Type>(t - FBT_INT + FBT_VECTOR_INT2);
case 3: return static_cast<Type>(t - FBT_INT + FBT_VECTOR_INT3);
case 4: return static_cast<Type>(t - FBT_INT + FBT_VECTOR_INT4);
default: FLATBUFFERS_ASSERT(0); return FBT_NULL;
}
}
inline Type ToTypedVectorElementType(Type t) {
assert(IsTypedVector(t));
return static_cast<Type>(t - TYPE_VECTOR_INT + TYPE_INT);
FLATBUFFERS_ASSERT(IsTypedVector(t));
return static_cast<Type>(t - FBT_VECTOR_INT + FBT_INT);
}
inline Type ToFixedTypedVectorElementType(Type t, uint8_t *len) {
assert(IsFixedTypedVector(t));
auto fixed_type = t - TYPE_VECTOR_INT2;
FLATBUFFERS_ASSERT(IsFixedTypedVector(t));
auto fixed_type = t - FBT_VECTOR_INT2;
*len = static_cast<uint8_t>(fixed_type / 3 +
2); // 3 types each, starting from length 2.
return static_cast<Type>(fixed_type % 3 + TYPE_INT);
return static_cast<Type>(fixed_type % 3 + FBT_INT);
}
// TODO: implement proper support for 8/16bit floats, or decide not to
@@ -271,7 +271,7 @@ class TypedVector : public Sized {
static TypedVector EmptyTypedVector() {
static const uint8_t empty_typed_vector[] = { 0 /*len*/ };
return TypedVector(empty_typed_vector + 1, 1, TYPE_INT);
return TypedVector(empty_typed_vector + 1, 1, FBT_INT);
}
bool IsTheEmptyVector() const {
return data_ == TypedVector::EmptyTypedVector().data_;
@@ -295,7 +295,7 @@ class FixedTypedVector : public Object {
static FixedTypedVector EmptyFixedTypedVector() {
static const uint8_t fixed_empty_vector[] = { 0 /* unused */ };
return FixedTypedVector(fixed_empty_vector, 1, TYPE_INT, 0);
return FixedTypedVector(fixed_empty_vector, 1, FBT_INT, 0);
}
bool IsTheEmptyFixedTypedVector() const {
return data_ == FixedTypedVector::EmptyFixedTypedVector().data_;
@@ -324,7 +324,7 @@ class Map : public Vector {
return TypedVector(Indirect(keys_offset, byte_width_),
static_cast<uint8_t>(
ReadUInt64(keys_offset + byte_width_, byte_width_)),
TYPE_KEY);
FBT_KEY);
}
static Map EmptyMap() {
@@ -354,25 +354,28 @@ class Reference {
Type GetType() const { return type_; }
bool IsNull() const { return type_ == TYPE_NULL; }
bool IsBool() const { return type_ == TYPE_BOOL; }
bool IsInt() const { return type_ == TYPE_INT || type_ == TYPE_INDIRECT_INT; }
bool IsNull() const { return type_ == FBT_NULL; }
bool IsBool() const { return type_ == FBT_BOOL; }
bool IsInt() const { return type_ == FBT_INT || type_ == FBT_INDIRECT_INT; }
bool IsUInt() const {
return type_ == TYPE_UINT || type_ == TYPE_INDIRECT_UINT;
return type_ == FBT_UINT || type_ == FBT_INDIRECT_UINT;
}
bool IsIntOrUint() const { return IsInt() || IsUInt(); }
bool IsFloat() const {
return type_ == TYPE_FLOAT || type_ == TYPE_INDIRECT_FLOAT;
return type_ == FBT_FLOAT || type_ == FBT_INDIRECT_FLOAT;
}
bool IsNumeric() const { return IsIntOrUint() || IsFloat(); }
bool IsString() const { return type_ == TYPE_STRING; }
bool IsKey() const { return type_ == TYPE_KEY; }
bool IsVector() const { return type_ == TYPE_VECTOR || type_ == TYPE_MAP; }
bool IsMap() const { return type_ == TYPE_MAP; }
bool IsBlob() const { return type_ == TYPE_BLOB; }
bool IsString() const { return type_ == FBT_STRING; }
bool IsKey() const { return type_ == FBT_KEY; }
bool IsVector() const { return type_ == FBT_VECTOR || type_ == FBT_MAP; }
bool IsTypedVector() const { return flexbuffers::IsTypedVector(type_); }
bool IsFixedTypedVector() const { return flexbuffers::IsFixedTypedVector(type_); }
bool IsAnyVector() const { return (IsTypedVector() || IsFixedTypedVector() || IsVector());}
bool IsMap() const { return type_ == FBT_MAP; }
bool IsBlob() const { return type_ == FBT_BLOB; }
bool AsBool() const {
return (type_ == TYPE_BOOL ? ReadUInt64(data_, parent_width_)
return (type_ == FBT_BOOL ? ReadUInt64(data_, parent_width_)
: AsUInt64()) != 0;
}
@@ -380,22 +383,22 @@ class Reference {
// Truncates floats, strings are attempted to be parsed for a number,
// vectors/maps return their size. Returns 0 if all else fails.
int64_t AsInt64() const {
if (type_ == TYPE_INT) {
if (type_ == FBT_INT) {
// A fast path for the common case.
return ReadInt64(data_, parent_width_);
} else
switch (type_) {
case TYPE_INDIRECT_INT: return ReadInt64(Indirect(), byte_width_);
case TYPE_UINT: return ReadUInt64(data_, parent_width_);
case TYPE_INDIRECT_UINT: return ReadUInt64(Indirect(), byte_width_);
case TYPE_FLOAT:
case FBT_INDIRECT_INT: return ReadInt64(Indirect(), byte_width_);
case FBT_UINT: return ReadUInt64(data_, parent_width_);
case FBT_INDIRECT_UINT: return ReadUInt64(Indirect(), byte_width_);
case FBT_FLOAT:
return static_cast<int64_t>(ReadDouble(data_, parent_width_));
case TYPE_INDIRECT_FLOAT:
case FBT_INDIRECT_FLOAT:
return static_cast<int64_t>(ReadDouble(Indirect(), byte_width_));
case TYPE_NULL: return 0;
case TYPE_STRING: return flatbuffers::StringToInt(AsString().c_str());
case TYPE_VECTOR: return static_cast<int64_t>(AsVector().size());
case TYPE_BOOL: return ReadInt64(data_, parent_width_);
case FBT_NULL: return 0;
case FBT_STRING: return flatbuffers::StringToInt(AsString().c_str());
case FBT_VECTOR: return static_cast<int64_t>(AsVector().size());
case FBT_BOOL: return ReadInt64(data_, parent_width_);
default:
// Convert other things to int.
return 0;
@@ -409,22 +412,22 @@ class Reference {
int8_t AsInt8() const { return static_cast<int8_t>(AsInt64()); }
uint64_t AsUInt64() const {
if (type_ == TYPE_UINT) {
if (type_ == FBT_UINT) {
// A fast path for the common case.
return ReadUInt64(data_, parent_width_);
} else
switch (type_) {
case TYPE_INDIRECT_UINT: return ReadUInt64(Indirect(), byte_width_);
case TYPE_INT: return ReadInt64(data_, parent_width_);
case TYPE_INDIRECT_INT: return ReadInt64(Indirect(), byte_width_);
case TYPE_FLOAT:
case FBT_INDIRECT_UINT: return ReadUInt64(Indirect(), byte_width_);
case FBT_INT: return ReadInt64(data_, parent_width_);
case FBT_INDIRECT_INT: return ReadInt64(Indirect(), byte_width_);
case FBT_FLOAT:
return static_cast<uint64_t>(ReadDouble(data_, parent_width_));
case TYPE_INDIRECT_FLOAT:
case FBT_INDIRECT_FLOAT:
return static_cast<uint64_t>(ReadDouble(Indirect(), byte_width_));
case TYPE_NULL: return 0;
case TYPE_STRING: return flatbuffers::StringToUInt(AsString().c_str());
case TYPE_VECTOR: return static_cast<uint64_t>(AsVector().size());
case TYPE_BOOL: return ReadUInt64(data_, parent_width_);
case FBT_NULL: return 0;
case FBT_STRING: return flatbuffers::StringToUInt(AsString().c_str());
case FBT_VECTOR: return static_cast<uint64_t>(AsVector().size());
case FBT_BOOL: return ReadUInt64(data_, parent_width_);
default:
// Convert other things to uint.
return 0;
@@ -436,24 +439,24 @@ class Reference {
uint8_t AsUInt8() const { return static_cast<uint8_t>(AsUInt64()); }
double AsDouble() const {
if (type_ == TYPE_FLOAT) {
if (type_ == FBT_FLOAT) {
// A fast path for the common case.
return ReadDouble(data_, parent_width_);
} else
switch (type_) {
case TYPE_INDIRECT_FLOAT: return ReadDouble(Indirect(), byte_width_);
case TYPE_INT:
case FBT_INDIRECT_FLOAT: return ReadDouble(Indirect(), byte_width_);
case FBT_INT:
return static_cast<double>(ReadInt64(data_, parent_width_));
case TYPE_UINT:
case FBT_UINT:
return static_cast<double>(ReadUInt64(data_, parent_width_));
case TYPE_INDIRECT_INT:
case FBT_INDIRECT_INT:
return static_cast<double>(ReadInt64(Indirect(), byte_width_));
case TYPE_INDIRECT_UINT:
case FBT_INDIRECT_UINT:
return static_cast<double>(ReadUInt64(Indirect(), byte_width_));
case TYPE_NULL: return 0.0;
case TYPE_STRING: return strtod(AsString().c_str(), nullptr);
case TYPE_VECTOR: return static_cast<double>(AsVector().size());
case TYPE_BOOL:
case FBT_NULL: return 0.0;
case FBT_STRING: return strtod(AsString().c_str(), nullptr);
case FBT_VECTOR: return static_cast<double>(AsVector().size());
case FBT_BOOL:
return static_cast<double>(ReadUInt64(data_, parent_width_));
default:
// Convert strings and other things to float.
@@ -464,7 +467,7 @@ class Reference {
float AsFloat() const { return static_cast<float>(AsDouble()); }
const char *AsKey() const {
if (type_ == TYPE_KEY) {
if (type_ == FBT_KEY) {
return reinterpret_cast<const char *>(Indirect());
} else {
return "";
@@ -473,7 +476,7 @@ class Reference {
// This function returns the empty string if you try to read a not-string.
String AsString() const {
if (type_ == TYPE_STRING) {
if (type_ == FBT_STRING) {
return String(Indirect(), byte_width_);
} else {
return String::EmptyString();
@@ -492,17 +495,17 @@ class Reference {
// they always do). keys_quoted determines if keys are quoted, at any level.
// TODO(wvo): add further options to have indentation/newlines.
void ToString(bool strings_quoted, bool keys_quoted, std::string &s) const {
if (type_ == TYPE_STRING) {
if (type_ == FBT_STRING) {
String str(Indirect(), byte_width_);
if (strings_quoted) {
flatbuffers::EscapeString(str.c_str(), str.length(), &s, true);
flatbuffers::EscapeString(str.c_str(), str.length(), &s, true, false);
} else {
s.append(str.c_str(), str.length());
}
} else if (IsKey()) {
auto str = AsKey();
if (keys_quoted) {
flatbuffers::EscapeString(str, strlen(str), &s, true);
flatbuffers::EscapeString(str, strlen(str), &s, true, false);
} else {
s += str;
}
@@ -544,7 +547,7 @@ class Reference {
// This function returns the empty blob if you try to read a not-blob.
// Strings can be viewed as blobs too.
Blob AsBlob() const {
if (type_ == TYPE_BLOB || type_ == TYPE_STRING) {
if (type_ == FBT_BLOB || type_ == FBT_STRING) {
return Blob(Indirect(), byte_width_);
} else {
return Blob::EmptyBlob();
@@ -554,7 +557,7 @@ class Reference {
// This function returns the empty vector if you try to read a not-vector.
// Maps can be viewed as vectors too.
Vector AsVector() const {
if (type_ == TYPE_VECTOR || type_ == TYPE_MAP) {
if (type_ == FBT_VECTOR || type_ == FBT_MAP) {
return Vector(Indirect(), byte_width_);
} else {
return Vector::EmptyVector();
@@ -562,7 +565,7 @@ class Reference {
}
TypedVector AsTypedVector() const {
if (IsTypedVector(type_)) {
if (IsTypedVector()) {
return TypedVector(Indirect(), byte_width_,
ToTypedVectorElementType(type_));
} else {
@@ -571,7 +574,7 @@ class Reference {
}
FixedTypedVector AsFixedTypedVector() const {
if (IsFixedTypedVector(type_)) {
if (IsFixedTypedVector()) {
uint8_t len = 0;
auto vtype = ToFixedTypedVectorElementType(type_, &len);
return FixedTypedVector(Indirect(), byte_width_, vtype, len);
@@ -581,7 +584,7 @@ class Reference {
}
Map AsMap() const {
if (type_ == TYPE_MAP) {
if (type_ == FBT_MAP) {
return Map(Indirect(), byte_width_);
} else {
return Map::EmptyMap();
@@ -597,14 +600,14 @@ class Reference {
// To avoid this, you can construct the values you intend to mutate using
// Builder::ForceMinimumBitWidth.
bool MutateInt(int64_t i) {
if (type_ == TYPE_INT) {
if (type_ == FBT_INT) {
return Mutate(data_, i, parent_width_, WidthI(i));
} else if (type_ == TYPE_INDIRECT_INT) {
} else if (type_ == FBT_INDIRECT_INT) {
return Mutate(Indirect(), i, byte_width_, WidthI(i));
} else if (type_ == TYPE_UINT) {
} else if (type_ == FBT_UINT) {
auto u = static_cast<uint64_t>(i);
return Mutate(data_, u, parent_width_, WidthU(u));
} else if (type_ == TYPE_INDIRECT_UINT) {
} else if (type_ == FBT_INDIRECT_UINT) {
auto u = static_cast<uint64_t>(i);
return Mutate(Indirect(), u, byte_width_, WidthU(u));
} else {
@@ -613,18 +616,18 @@ class Reference {
}
bool MutateBool(bool b) {
return type_ == TYPE_BOOL && Mutate(data_, b, parent_width_, BIT_WIDTH_8);
return type_ == FBT_BOOL && Mutate(data_, b, parent_width_, BIT_WIDTH_8);
}
bool MutateUInt(uint64_t u) {
if (type_ == TYPE_UINT) {
if (type_ == FBT_UINT) {
return Mutate(data_, u, parent_width_, WidthU(u));
} else if (type_ == TYPE_INDIRECT_UINT) {
} else if (type_ == FBT_INDIRECT_UINT) {
return Mutate(Indirect(), u, byte_width_, WidthU(u));
} else if (type_ == TYPE_INT) {
} else if (type_ == FBT_INT) {
auto i = static_cast<int64_t>(u);
return Mutate(data_, i, parent_width_, WidthI(i));
} else if (type_ == TYPE_INDIRECT_INT) {
} else if (type_ == FBT_INDIRECT_INT) {
auto i = static_cast<int64_t>(u);
return Mutate(Indirect(), i, byte_width_, WidthI(i));
} else {
@@ -633,9 +636,9 @@ class Reference {
}
bool MutateFloat(float f) {
if (type_ == TYPE_FLOAT) {
if (type_ == FBT_FLOAT) {
return MutateF(data_, f, parent_width_, BIT_WIDTH_32);
} else if (type_ == TYPE_INDIRECT_FLOAT) {
} else if (type_ == FBT_INDIRECT_FLOAT) {
return MutateF(Indirect(), f, byte_width_, BIT_WIDTH_32);
} else {
return false;
@@ -643,9 +646,9 @@ class Reference {
}
bool MutateFloat(double d) {
if (type_ == TYPE_FLOAT) {
if (type_ == FBT_FLOAT) {
return MutateF(data_, d, parent_width_, WidthF(d));
} else if (type_ == TYPE_INDIRECT_FLOAT) {
} else if (type_ == FBT_INDIRECT_FLOAT) {
return MutateF(Indirect(), d, byte_width_, WidthF(d));
} else {
return false;
@@ -690,7 +693,7 @@ class Reference {
return Mutate(dest, static_cast<double>(t), byte_width, value_width);
if (byte_width == sizeof(float))
return Mutate(dest, static_cast<float>(t), byte_width, value_width);
assert(false);
FLATBUFFERS_ASSERT(false);
return false;
}
@@ -735,7 +738,7 @@ inline uint8_t PackedType(BitWidth bit_width, Type type) {
return static_cast<uint8_t>(bit_width | (type << 2));
}
inline uint8_t NullPackedType() { return PackedType(BIT_WIDTH_8, TYPE_NULL); }
inline uint8_t NullPackedType() { return PackedType(BIT_WIDTH_8, FBT_NULL); }
// Vector accessors.
// Note: if you try to access outside of bounds, you get a Null value back
@@ -870,16 +873,16 @@ class Builder FLATBUFFERS_FINAL_CLASS {
Null();
}
void Int(int64_t i) { stack_.push_back(Value(i, TYPE_INT, WidthI(i))); }
void Int(int64_t i) { stack_.push_back(Value(i, FBT_INT, WidthI(i))); }
void Int(const char *key, int64_t i) {
Key(key);
Int(i);
}
void UInt(uint64_t u) { stack_.push_back(Value(u, TYPE_UINT, WidthU(u))); }
void UInt(uint64_t u) { stack_.push_back(Value(u, FBT_UINT, WidthU(u))); }
void UInt(const char *key, uint64_t u) {
Key(key);
Int(u);
UInt(u);
}
void Float(float f) { stack_.push_back(Value(f)); }
@@ -900,14 +903,14 @@ class Builder FLATBUFFERS_FINAL_CLASS {
Bool(b);
}
void IndirectInt(int64_t i) { PushIndirect(i, TYPE_INDIRECT_INT, WidthI(i)); }
void IndirectInt(int64_t i) { PushIndirect(i, FBT_INDIRECT_INT, WidthI(i)); }
void IndirectInt(const char *key, int64_t i) {
Key(key);
IndirectInt(i);
}
void IndirectUInt(uint64_t u) {
PushIndirect(u, TYPE_INDIRECT_UINT, WidthU(u));
PushIndirect(u, FBT_INDIRECT_UINT, WidthU(u));
}
void IndirectUInt(const char *key, uint64_t u) {
Key(key);
@@ -915,7 +918,7 @@ class Builder FLATBUFFERS_FINAL_CLASS {
}
void IndirectFloat(float f) {
PushIndirect(f, TYPE_INDIRECT_FLOAT, BIT_WIDTH_32);
PushIndirect(f, FBT_INDIRECT_FLOAT, BIT_WIDTH_32);
}
void IndirectFloat(const char *key, float f) {
Key(key);
@@ -923,7 +926,7 @@ class Builder FLATBUFFERS_FINAL_CLASS {
}
void IndirectDouble(double f) {
PushIndirect(f, TYPE_INDIRECT_FLOAT, WidthF(f));
PushIndirect(f, FBT_INDIRECT_FLOAT, WidthF(f));
}
void IndirectDouble(const char *key, double d) {
Key(key);
@@ -944,7 +947,7 @@ class Builder FLATBUFFERS_FINAL_CLASS {
key_pool.insert(sloc);
}
}
stack_.push_back(Value(static_cast<uint64_t>(sloc), TYPE_KEY, BIT_WIDTH_8));
stack_.push_back(Value(static_cast<uint64_t>(sloc), FBT_KEY, BIT_WIDTH_8));
return sloc;
}
@@ -953,7 +956,7 @@ class Builder FLATBUFFERS_FINAL_CLASS {
size_t String(const char *str, size_t len) {
auto reset_to = buf_.size();
auto sloc = CreateBlob(str, len, 1, TYPE_STRING);
auto sloc = CreateBlob(str, len, 1, FBT_STRING);
if (flags_ & BUILDER_FLAG_SHARE_STRINGS) {
StringOffset so(sloc, len);
auto it = string_pool.find(so);
@@ -991,10 +994,10 @@ class Builder FLATBUFFERS_FINAL_CLASS {
}
size_t Blob(const void *data, size_t len) {
return CreateBlob(data, len, 0, TYPE_BLOB);
return CreateBlob(data, len, 0, FBT_BLOB);
}
size_t Blob(const std::vector<uint8_t> &v) {
return CreateBlob(flatbuffers::vector_data(v), v.size(), 0, TYPE_BLOB);
return CreateBlob(flatbuffers::vector_data(v), v.size(), 0, FBT_BLOB);
}
// TODO(wvo): support all the FlexBuffer types (like flexbuffers::String),
@@ -1026,11 +1029,11 @@ class Builder FLATBUFFERS_FINAL_CLASS {
// We should have interleaved keys and values on the stack.
// Make sure it is an even number:
auto len = stack_.size() - start;
assert(!(len & 1));
FLATBUFFERS_ASSERT(!(len & 1));
len /= 2;
// Make sure keys are all strings:
for (auto key = start; key < stack_.size(); key += 2) {
assert(stack_[key].type_ == TYPE_KEY);
FLATBUFFERS_ASSERT(stack_[key].type_ == FBT_KEY);
}
// Now sort values, so later we can do a binary seach lookup.
// We want to sort 2 array elements at a time.
@@ -1061,7 +1064,7 @@ class Builder FLATBUFFERS_FINAL_CLASS {
// TODO: Have to check for pointer equality, as some sort
// implementation apparently call this function with the same
// element?? Why?
assert(comp || &a == &b);
FLATBUFFERS_ASSERT(comp || &a == &b);
return comp < 0;
});
// First create a vector out of all keys.
@@ -1141,9 +1144,9 @@ class Builder FLATBUFFERS_FINAL_CLASS {
template<typename T> size_t FixedTypedVector(const T *elems, size_t len) {
// We only support a few fixed vector lengths. Anything bigger use a
// regular typed vector.
assert(len >= 2 && len <= 4);
FLATBUFFERS_ASSERT(len >= 2 && len <= 4);
// And only scalar values.
assert(flatbuffers::is_scalar<T>::value);
static_assert(flatbuffers::is_scalar<T>::value, "Unrelated types");
return ScalarVector(elems, len, true);
}
@@ -1222,7 +1225,7 @@ class Builder FLATBUFFERS_FINAL_CLASS {
// in a parent. You need to have exactly one root to finish a buffer.
// Check your Start/End calls are matched, and all objects are inside
// some other object.
assert(stack_.size() == 1);
FLATBUFFERS_ASSERT(stack_.size() == 1);
// Write root value.
auto byte_width = Align(stack_[0].ElemWidth(buf_.size(), 0));
@@ -1240,7 +1243,7 @@ class Builder FLATBUFFERS_FINAL_CLASS {
// If you get this assert, you're attempting to get access a buffer
// which hasn't been finished yet. Be sure to call
// Builder::Finish with your root object.
assert(finished_);
FLATBUFFERS_ASSERT(finished_);
}
// Align to prepare for writing a scalar with a certain size.
@@ -1257,7 +1260,7 @@ class Builder FLATBUFFERS_FINAL_CLASS {
}
template<typename T> void Write(T val, size_t byte_width) {
assert(sizeof(T) >= byte_width);
FLATBUFFERS_ASSERT(sizeof(T) >= byte_width);
val = flatbuffers::EndianScalar(val);
WriteBytes(&val, byte_width);
}
@@ -1268,13 +1271,13 @@ class Builder FLATBUFFERS_FINAL_CLASS {
case 4: Write(static_cast<float>(f), byte_width); break;
// case 2: Write(static_cast<half>(f), byte_width); break;
// case 1: Write(static_cast<quarter>(f), byte_width); break;
default: assert(0);
default: FLATBUFFERS_ASSERT(0);
}
}
void WriteOffset(uint64_t o, uint8_t byte_width) {
auto reloff = buf_.size() - o;
assert(byte_width == 8 || reloff < 1ULL << (byte_width * 8));
FLATBUFFERS_ASSERT(byte_width == 8 || reloff < 1ULL << (byte_width * 8));
Write(reloff, byte_width);
}
@@ -1291,18 +1294,18 @@ class Builder FLATBUFFERS_FINAL_CLASS {
case 2: return BIT_WIDTH_16;
case 4: return BIT_WIDTH_32;
case 8: return BIT_WIDTH_64;
default: assert(false); return BIT_WIDTH_64;
default: FLATBUFFERS_ASSERT(false); return BIT_WIDTH_64;
}
}
template<typename T> static Type GetScalarType() {
assert(flatbuffers::is_scalar<T>::value);
static_assert(flatbuffers::is_scalar<T>::value, "Unrelated types");
return flatbuffers::is_floating_point<T>::value
? TYPE_FLOAT
? FBT_FLOAT
: flatbuffers::is_same<T, bool>::value
? TYPE_BOOL
: (flatbuffers::is_unsigned<T>::value ? TYPE_UINT
: TYPE_INT);
? FBT_BOOL
: (flatbuffers::is_unsigned<T>::value ? FBT_UINT
: FBT_INT);
}
struct Value {
@@ -1317,11 +1320,11 @@ class Builder FLATBUFFERS_FINAL_CLASS {
// For scalars: of itself, for vector: of its elements, for string: length.
BitWidth min_bit_width_;
Value() : i_(0), type_(TYPE_NULL), min_bit_width_(BIT_WIDTH_8) {}
Value() : i_(0), type_(FBT_NULL), min_bit_width_(BIT_WIDTH_8) {}
Value(bool b)
: u_(static_cast<uint64_t>(b)),
type_(TYPE_BOOL),
type_(FBT_BOOL),
min_bit_width_(BIT_WIDTH_8) {}
Value(int64_t i, Type t, BitWidth bw)
@@ -1329,8 +1332,8 @@ class Builder FLATBUFFERS_FINAL_CLASS {
Value(uint64_t u, Type t, BitWidth bw)
: u_(u), type_(t), min_bit_width_(bw) {}
Value(float f) : f_(f), type_(TYPE_FLOAT), min_bit_width_(BIT_WIDTH_32) {}
Value(double f) : f_(f), type_(TYPE_FLOAT), min_bit_width_(WidthF(f)) {}
Value(float f) : f_(f), type_(FBT_FLOAT), min_bit_width_(BIT_WIDTH_32) {}
Value(double f) : f_(f), type_(FBT_FLOAT), min_bit_width_(WidthF(f)) {}
uint8_t StoredPackedType(BitWidth parent_bit_width_ = BIT_WIDTH_8) const {
return PackedType(StoredWidth(parent_bit_width_), type_);
@@ -1360,7 +1363,7 @@ class Builder FLATBUFFERS_FINAL_CLASS {
byte_width)
return bit_width;
}
assert(false); // Must match one of the sizes above.
FLATBUFFERS_ASSERT(false); // Must match one of the sizes above.
return BIT_WIDTH_64;
}
}
@@ -1376,11 +1379,11 @@ class Builder FLATBUFFERS_FINAL_CLASS {
void WriteAny(const Value &val, uint8_t byte_width) {
switch (val.type_) {
case TYPE_NULL:
case TYPE_INT: Write(val.i_, byte_width); break;
case TYPE_BOOL:
case TYPE_UINT: Write(val.u_, byte_width); break;
case TYPE_FLOAT: WriteDouble(val.f_, byte_width); break;
case FBT_NULL:
case FBT_INT: Write(val.i_, byte_width); break;
case FBT_BOOL:
case FBT_UINT: Write(val.u_, byte_width); break;
case FBT_FLOAT: WriteDouble(val.f_, byte_width); break;
default: WriteOffset(val.u_, byte_width); break;
}
}
@@ -1405,7 +1408,7 @@ class Builder FLATBUFFERS_FINAL_CLASS {
// byte vector > 255 elements). For such types, write a "blob" instead.
// TODO: instead of asserting, could write vector with larger elements
// instead, though that would be wasteful.
assert(WidthU(len) <= bit_width);
FLATBUFFERS_ASSERT(WidthU(len) <= bit_width);
if (!fixed) Write<uint64_t>(len, byte_width);
auto vloc = buf_.size();
for (size_t i = 0; i < len; i++) Write(elems[i], byte_width);
@@ -1417,6 +1420,7 @@ class Builder FLATBUFFERS_FINAL_CLASS {
Value CreateVector(size_t start, size_t vec_len, size_t step, bool typed,
bool fixed, const Value *keys = nullptr) {
FLATBUFFERS_ASSERT(!fixed || typed); // typed=false, fixed=true combination is not supported.
// Figure out smallest bit width we can store this vector with.
auto bit_width = (std::max)(force_min_bit_width_, WidthU(vec_len));
auto prefix_elems = 1;
@@ -1426,7 +1430,7 @@ class Builder FLATBUFFERS_FINAL_CLASS {
bit_width = (std::max)(bit_width, keys->ElemWidth(buf_.size(), 0));
prefix_elems += 2;
}
Type vector_type = TYPE_KEY;
Type vector_type = FBT_KEY;
// Check bit widths and types for all elements.
for (size_t i = start; i < stack_.size(); i += step) {
auto elem_width = stack_[i].ElemWidth(buf_.size(), i + prefix_elems);
@@ -1437,13 +1441,13 @@ class Builder FLATBUFFERS_FINAL_CLASS {
} else {
// If you get this assert, you are writing a typed vector with
// elements that are not all the same type.
assert(vector_type == stack_[i].type_);
FLATBUFFERS_ASSERT(vector_type == stack_[i].type_);
}
}
}
// If you get this assert, your fixed types are not one of:
// Int / UInt / Float / Key.
assert(IsTypedVectorElementType(vector_type));
FLATBUFFERS_ASSERT(!fixed || IsTypedVectorElementType(vector_type));
auto byte_width = Align(bit_width);
// Write vector. First the keys width/offset if available, and size.
if (keys) {
@@ -1463,9 +1467,9 @@ class Builder FLATBUFFERS_FINAL_CLASS {
}
}
return Value(static_cast<uint64_t>(vloc),
keys ? TYPE_MAP
keys ? FBT_MAP
: (typed ? ToTypedVector(vector_type, fixed ? vec_len : 0)
: TYPE_VECTOR),
: FBT_VECTOR),
bit_width);
}
@@ -1483,7 +1487,7 @@ class Builder FLATBUFFERS_FINAL_CLASS {
BitWidth force_min_bit_width_;
struct KeyOffsetCompare {
KeyOffsetCompare(const std::vector<uint8_t> &buf) : buf_(&buf) {}
explicit KeyOffsetCompare(const std::vector<uint8_t> &buf) : buf_(&buf) {}
bool operator()(size_t a, size_t b) const {
auto stra =
reinterpret_cast<const char *>(flatbuffers::vector_data(*buf_) + a);
@@ -1496,7 +1500,7 @@ class Builder FLATBUFFERS_FINAL_CLASS {
typedef std::pair<size_t, size_t> StringOffset;
struct StringOffsetCompare {
StringOffsetCompare(const std::vector<uint8_t> &buf) : buf_(&buf) {}
explicit StringOffsetCompare(const std::vector<uint8_t> &buf) : buf_(&buf) {}
bool operator()(const StringOffset &a, const StringOffset &b) const {
auto stra = reinterpret_cast<const char *>(
flatbuffers::vector_data(*buf_) + a.first);

View File

@@ -88,17 +88,35 @@ class SliceAllocator : public Allocator {
SliceAllocator(const SliceAllocator &other) = delete;
SliceAllocator &operator=(const SliceAllocator &other) = delete;
SliceAllocator(SliceAllocator &&other)
: slice_(grpc_empty_slice()) {
// default-construct and swap idiom
swap(other);
}
SliceAllocator &operator=(SliceAllocator &&other) {
// move-construct and swap idiom
SliceAllocator temp(std::move(other));
swap(temp);
return *this;
}
void swap(SliceAllocator &other) {
using std::swap;
swap(slice_, other.slice_);
}
virtual ~SliceAllocator() { grpc_slice_unref(slice_); }
virtual uint8_t *allocate(size_t size) override {
assert(GRPC_SLICE_IS_EMPTY(slice_));
FLATBUFFERS_ASSERT(GRPC_SLICE_IS_EMPTY(slice_));
slice_ = grpc_slice_malloc(size);
return GRPC_SLICE_START_PTR(slice_);
}
virtual void deallocate(uint8_t *p, size_t size) override {
assert(p == GRPC_SLICE_START_PTR(slice_));
assert(size == GRPC_SLICE_LENGTH(slice_));
FLATBUFFERS_ASSERT(p == GRPC_SLICE_START_PTR(slice_));
FLATBUFFERS_ASSERT(size == GRPC_SLICE_LENGTH(slice_));
grpc_slice_unref(slice_);
slice_ = grpc_empty_slice();
}
@@ -106,9 +124,9 @@ class SliceAllocator : public Allocator {
virtual uint8_t *reallocate_downward(uint8_t *old_p, size_t old_size,
size_t new_size, size_t in_use_back,
size_t in_use_front) override {
assert(old_p == GRPC_SLICE_START_PTR(slice_));
assert(old_size == GRPC_SLICE_LENGTH(slice_));
assert(new_size > old_size);
FLATBUFFERS_ASSERT(old_p == GRPC_SLICE_START_PTR(slice_));
FLATBUFFERS_ASSERT(old_size == GRPC_SLICE_LENGTH(slice_));
FLATBUFFERS_ASSERT(new_size > old_size);
grpc_slice old_slice = slice_;
grpc_slice new_slice = grpc_slice_malloc(new_size);
uint8_t *new_p = GRPC_SLICE_START_PTR(new_slice);
@@ -121,8 +139,8 @@ class SliceAllocator : public Allocator {
private:
grpc_slice &get_slice(uint8_t *p, size_t size) {
assert(p == GRPC_SLICE_START_PTR(slice_));
assert(size == GRPC_SLICE_LENGTH(slice_));
FLATBUFFERS_ASSERT(p == GRPC_SLICE_START_PTR(slice_));
FLATBUFFERS_ASSERT(size == GRPC_SLICE_LENGTH(slice_));
return slice_;
}
@@ -151,6 +169,39 @@ class MessageBuilder : private detail::SliceAllocatorMember,
MessageBuilder(const MessageBuilder &other) = delete;
MessageBuilder &operator=(const MessageBuilder &other) = delete;
MessageBuilder(MessageBuilder &&other)
: FlatBufferBuilder(1024, &slice_allocator_, false) {
// Default construct and swap idiom.
Swap(other);
}
MessageBuilder &operator=(MessageBuilder &&other) {
// Move construct a temporary and swap
MessageBuilder temp(std::move(other));
Swap(temp);
return *this;
}
void Swap(MessageBuilder &other) {
slice_allocator_.swap(other.slice_allocator_);
FlatBufferBuilder::Swap(other);
// After swapping the FlatBufferBuilder, we swap back the allocator, which restores
// the original allocator back in place. This is necessary because MessageBuilder's
// allocator is its own member (SliceAllocatorMember). The allocator passed to
// FlatBufferBuilder::vector_downward must point to this member.
buf_.swap_allocator(other.buf_);
}
// Releases the ownership of the buffer pointer.
// Returns the size, offset, and the original grpc_slice that
// allocated the buffer. Also see grpc_slice_unref().
uint8_t *ReleaseRaw(size_t &size, size_t &offset, grpc_slice &slice) {
uint8_t *buf = FlatBufferBuilder::ReleaseRaw(size, offset);
slice = slice_allocator_.slice_;
slice_allocator_.slice_ = grpc_empty_slice();
return buf;
}
~MessageBuilder() {}
// GetMessage extracts the subslice of the buffer corresponding to the
@@ -162,10 +213,10 @@ class MessageBuilder : private detail::SliceAllocatorMember,
auto msg_data = buf_.data(); // pointer to msg
auto msg_size = buf_.size(); // size of msg
// Do some sanity checks on data/size
assert(msg_data);
assert(msg_size);
assert(msg_data >= buf_data);
assert(msg_data + msg_size <= buf_data + buf_size);
FLATBUFFERS_ASSERT(msg_data);
FLATBUFFERS_ASSERT(msg_size);
FLATBUFFERS_ASSERT(msg_data >= buf_data);
FLATBUFFERS_ASSERT(msg_data + msg_size <= buf_data + buf_size);
// Calculate offsets from the buffer start
auto begin = msg_data - buf_data;
auto end = begin + msg_size;

View File

@@ -41,24 +41,24 @@ namespace flatbuffers {
// of type tokens.
// clang-format off
#define FLATBUFFERS_GEN_TYPES_SCALAR(TD) \
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 */
TD(NONE, "", uint8_t, byte, byte, byte, uint8, u8) \
TD(UTYPE, "", uint8_t, byte, byte, byte, uint8, u8) /* begin scalar/int */ \
TD(BOOL, "bool", uint8_t, boolean,byte, bool, bool, bool) \
TD(CHAR, "byte", int8_t, byte, int8, sbyte, int8, i8) \
TD(UCHAR, "ubyte", uint8_t, byte, byte, byte, uint8, u8) \
TD(SHORT, "short", int16_t, short, int16, short, int16, i16) \
TD(USHORT, "ushort", uint16_t, short, uint16, ushort, uint16, u16) \
TD(INT, "int", int32_t, int, int32, int, int32, i32) \
TD(UINT, "uint", uint32_t, int, uint32, uint, uint32, u32) \
TD(LONG, "long", int64_t, long, int64, long, int64, i64) \
TD(ULONG, "ulong", uint64_t, long, uint64, ulong, uint64, u64) /* end int */ \
TD(FLOAT, "float", float, float, float32, float, float32, f32) /* begin float */ \
TD(DOUBLE, "double", double, double, float64, double, float64, f64) /* end float/scalar */
#define FLATBUFFERS_GEN_TYPES_POINTER(TD) \
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)
TD(STRING, "string", Offset<void>, int, int, StringOffset, int, unused) \
TD(VECTOR, "", Offset<void>, int, int, VectorOffset, int, unused) \
TD(STRUCT, "", Offset<void>, int, int, int, int, unused) \
TD(UNION, "", Offset<void>, int, int, int, int, unused)
// The fields are:
// - enum
@@ -68,12 +68,14 @@ namespace flatbuffers {
// - Go type.
// - C# / .Net type.
// - Python type.
// - Rust 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, PTYPE) \
#define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, \
RTYPE) \
case BASE_TYPE_ ## ENUM: \
// do something specific to CTYPE here
FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
@@ -90,13 +92,15 @@ switch (type) {
__extension__ // Stop GCC complaining about trailing comma with -Wpendantic.
#endif
enum BaseType {
#define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \
#define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, \
RTYPE) \
BASE_TYPE_ ## ENUM,
FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
#undef FLATBUFFERS_TD
};
#define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \
#define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, \
RTYPE) \
static_assert(sizeof(CTYPE) <= sizeof(largest_scalar_t), \
"define largest_scalar_t as " #CTYPE);
FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
@@ -111,6 +115,8 @@ inline bool IsFloat (BaseType t) { return t == BASE_TYPE_FLOAT ||
inline bool IsLong (BaseType t) { return t == BASE_TYPE_LONG ||
t == BASE_TYPE_ULONG; }
inline bool IsBool (BaseType t) { return t == BASE_TYPE_BOOL; }
inline bool IsOneByte(BaseType t) { return t >= BASE_TYPE_UTYPE &&
t <= BASE_TYPE_UCHAR; }
// clang-format on
extern const char *const kTypeNames[];
@@ -181,7 +187,7 @@ template<typename T> class SymbolTable {
dict.erase(it);
dict[newname] = obj;
} else {
assert(false);
FLATBUFFERS_ASSERT(false);
}
}
@@ -306,7 +312,7 @@ inline size_t InlineAlignment(const Type &type) {
struct EnumVal {
EnumVal(const std::string &_name, int64_t _val) : name(_name), value(_val) {}
Offset<reflection::EnumVal> Serialize(FlatBufferBuilder *builder) const;
Offset<reflection::EnumVal> Serialize(FlatBufferBuilder *builder, const Parser &parser) const;
std::string name;
std::vector<std::string> doc_comment;
@@ -326,8 +332,7 @@ struct EnumDef : public Definition {
return nullptr;
}
Offset<reflection::Enum> Serialize(FlatBufferBuilder *builder,
const Parser &parser) const;
Offset<reflection::Enum> Serialize(FlatBufferBuilder *builder, const Parser &parser) const;
SymbolTable<EnumVal> vals;
bool is_union;
@@ -342,14 +347,15 @@ inline bool EqualByName(const Type &a, const Type &b) {
(a.enum_def == b.enum_def || a.enum_def->name == b.enum_def->name);
}
struct RPCCall {
std::string name;
SymbolTable<Value> attributes;
struct RPCCall : public Definition {
Offset<reflection::RPCCall> Serialize(FlatBufferBuilder *builder, const Parser &parser) const;
StructDef *request, *response;
std::vector<std::string> rpc_comment;
};
struct ServiceDef : public Definition {
Offset<reflection::Service> Serialize(FlatBufferBuilder *builder, const Parser &parser) const;
SymbolTable<RPCCall> calls;
};
@@ -358,6 +364,7 @@ struct IDLOptions {
bool strict_json;
bool skip_js_exports;
bool use_goog_js_export_format;
bool use_ES6_js_export_format;
bool output_default_scalars_in_json;
int indent_step;
bool output_enum_identifiers;
@@ -372,6 +379,7 @@ struct IDLOptions {
bool skip_unexpected_fields_in_json;
bool generate_name_strings;
bool generate_object_based_api;
bool gen_compare;
std::string cpp_object_api_pointer_type;
std::string cpp_object_api_string_type;
bool gen_nullable;
@@ -379,15 +387,19 @@ struct IDLOptions {
std::string object_suffix;
bool union_value_namespacing;
bool allow_non_utf8;
bool natural_utf8;
std::string include_prefix;
bool keep_include_path;
bool binary_schema_comments;
bool binary_schema_builtins;
bool skip_flatbuffers_import;
std::string go_import;
std::string go_namespace;
bool reexport_ts_modules;
bool protobuf_ascii_alike;
bool size_prefixed;
std::string root_type;
bool force_defaults;
// Possible options for the more general generator below.
enum Language {
@@ -402,6 +414,10 @@ struct IDLOptions {
kBinary = 1 << 8,
kTs = 1 << 9,
kJsonSchema = 1 << 10,
kDart = 1 << 11,
kLua = 1 << 12,
kLobster = 1 << 13,
kRust = 1 << 14,
kMAX
};
@@ -415,10 +431,15 @@ struct IDLOptions {
// for code generation.
unsigned long lang_to_generate;
// If set (default behavior), empty string and vector fields will be set to
// nullptr to make the flatbuffer more compact.
bool set_empty_to_null;
IDLOptions()
: strict_json(false),
skip_js_exports(false),
use_goog_js_export_format(false),
use_ES6_js_export_format(false),
output_default_scalars_in_json(false),
indent_step(2),
output_enum_identifiers(true),
@@ -433,28 +454,51 @@ struct IDLOptions {
skip_unexpected_fields_in_json(false),
generate_name_strings(false),
generate_object_based_api(false),
gen_compare(false),
cpp_object_api_pointer_type("std::unique_ptr"),
gen_nullable(false),
object_suffix("T"),
union_value_namespacing(true),
allow_non_utf8(false),
natural_utf8(false),
keep_include_path(false),
binary_schema_comments(false),
binary_schema_builtins(false),
skip_flatbuffers_import(false),
reexport_ts_modules(true),
protobuf_ascii_alike(false),
size_prefixed(false),
force_defaults(false),
lang(IDLOptions::kJava),
mini_reflect(IDLOptions::kNone),
lang_to_generate(0) {}
lang_to_generate(0),
set_empty_to_null(true) {}
};
// This encapsulates where the parser is in the current source file.
struct ParserState {
ParserState() : cursor_(nullptr), line_(1), token_(-1) {}
ParserState()
: cursor_(nullptr), line_start_(nullptr), line_(0), token_(-1) {}
protected:
void ResetState(const char *source) {
cursor_ = source;
line_ = 0;
MarkNewLine();
}
void MarkNewLine() {
line_start_ = cursor_;
line_ += 1;
}
int64_t CursorPosition() const {
FLATBUFFERS_ASSERT(cursor_ && line_start_ && cursor_ >= line_start_);
return static_cast<int64_t>(cursor_ - line_start_);
}
const char *cursor_;
const char *line_start_;
int line_; // the current line being parsed
int token_;
@@ -485,7 +529,7 @@ class CheckedError {
*this = other; // Use assignment operator.
}
~CheckedError() { assert(has_been_checked_); }
~CheckedError() { FLATBUFFERS_ASSERT(has_been_checked_); }
bool Check() {
has_been_checked_ = true;
@@ -517,7 +561,11 @@ class Parser : public ParserState {
opts(options),
uses_flexbuffers_(false),
source_(nullptr),
anonymous_counter(0) {
anonymous_counter(0),
recurse_protection_counter(0) {
if (opts.force_defaults) {
builder_.ForceDefaults(true);
}
// Start out with the empty namespace being current.
empty_namespace_ = new Namespace();
namespaces_.push_back(empty_namespace_);
@@ -543,6 +591,7 @@ class Parser : public ParserState {
known_attributes_["native_type"] = true;
known_attributes_["native_default"] = true;
known_attributes_["flexbuffer"] = true;
known_attributes_["private"] = true;
}
~Parser() {
@@ -696,6 +745,15 @@ class Parser : public ParserState {
bool SupportsVectorOfUnions() const;
Namespace *UniqueNamespace(Namespace *ns);
enum { kMaxParsingDepth = 64 };
FLATBUFFERS_CHECKED_ERROR RecurseError();
template<typename F> CheckedError Recurse(F f) {
if (++recurse_protection_counter >= kMaxParsingDepth) return RecurseError();
auto ce = f();
recurse_protection_counter--;
return ce;
}
public:
SymbolTable<Type> types_;
SymbolTable<StructDef> structs_;
@@ -728,6 +786,7 @@ class Parser : public ParserState {
std::vector<std::pair<Value, FieldDef *>> field_stack_;
int anonymous_counter;
int recurse_protection_counter;
};
// Utility functions for multiple generators:
@@ -762,6 +821,10 @@ extern bool GenerateCPP(const Parser &parser,
const std::string &path,
const std::string &file_name);
extern bool GenerateDart(const Parser &parser,
const std::string &path,
const std::string &file_name);
// Generate JavaScript or TypeScript code from the definitions in the Parser object.
// See idl_gen_js.
extern bool GenerateJS(const Parser &parser,
@@ -786,6 +849,24 @@ extern bool GeneratePython(const Parser &parser,
const std::string &path,
const std::string &file_name);
// Generate Lobster files from the definitions in the Parser object.
// See idl_gen_lobster.cpp.
extern bool GenerateLobster(const Parser &parser,
const std::string &path,
const std::string &file_name);
// Generate Lua files from the definitions in the Parser object.
// See idl_gen_lua.cpp.
extern bool GenerateLua(const Parser &parser,
const std::string &path,
const std::string &file_name);
// Generate Rust files from the definitions in the Parser object.
// See idl_gen_rust.cpp.
extern bool GenerateRust(const Parser &parser,
const std::string &path,
const std::string &file_name);
// Generate Json schema file
// See idl_gen_json_schema.cpp.
extern bool GenerateJsonSchema(const Parser &parser,
@@ -818,6 +899,18 @@ extern std::string CPPMakeRule(const Parser &parser,
const std::string &path,
const std::string &file_name);
// Generate a make rule for the generated Dart code
// see idl_gen_dart.cpp
extern std::string DartMakeRule(const Parser &parser,
const std::string &path,
const std::string &file_name);
// Generate a make rule for the generated Rust code.
// See idl_gen_rust.cpp.
extern std::string RustMakeRule(const Parser &parser,
const std::string &path,
const std::string &file_name);
// Generate a make rule for the generated Java/C#/... files.
// See idl_gen_general.cpp.
extern std::string GeneralMakeRule(const Parser &parser,

View File

@@ -89,9 +89,9 @@ inline size_t InlineSize(ElementaryType type, const TypeTable *type_table) {
case ST_TABLE:
case ST_UNION: return 4;
case ST_STRUCT: return type_table->values[type_table->num_elems];
default: assert(false); return 1;
default: FLATBUFFERS_ASSERT(false); return 1;
}
default: assert(false); return 1;
default: FLATBUFFERS_ASSERT(false); return 1;
}
}
@@ -190,7 +190,7 @@ inline void IterateValue(ElementaryType type, const uint8_t *val,
case ST_STRUCT: IterateObject(val, type_table, visitor); break;
case ST_UNION: {
val += ReadScalar<uoffset_t>(val);
assert(prev_val);
FLATBUFFERS_ASSERT(prev_val);
auto union_type = *prev_val; // Always a uint8_t.
if (vector_index >= 0) {
auto type_vec = reinterpret_cast<const Vector<uint8_t> *>(prev_val);
@@ -217,7 +217,7 @@ inline void IterateValue(ElementaryType type, const uint8_t *val,
}
break;
}
case ST_ENUM: assert(false); break;
case ST_ENUM: FLATBUFFERS_ASSERT(false); break;
}
break;
}
@@ -283,23 +283,54 @@ inline void IterateFlatBuffer(const uint8_t *buffer,
struct ToStringVisitor : public IterationVisitor {
std::string s;
void StartSequence() { s += "{ "; }
void EndSequence() { s += " }"; }
std::string d;
bool q;
std::string in;
size_t indent_level;
ToStringVisitor(std::string delimiter, bool quotes, std::string indent)
: d(delimiter), q(quotes), in(indent), indent_level(0) {}
ToStringVisitor(std::string delimiter)
: d(delimiter), q(false), in(""), indent_level(0) {}
void append_indent() {
for (size_t i = 0; i < indent_level; i++) { s += in; }
}
void StartSequence() {
s += "{";
s += d;
indent_level++;
}
void EndSequence() {
s += d;
indent_level--;
append_indent();
s += "}";
}
void Field(size_t /*field_idx*/, size_t set_idx, ElementaryType /*type*/,
bool /*is_vector*/, const TypeTable * /*type_table*/,
const char *name, const uint8_t *val) {
if (!val) return;
if (set_idx) s += ", ";
if (set_idx) {
s += ",";
s += d;
}
append_indent();
if (name) {
if (q) s += "\"";
s += name;
if (q) s += "\"";
s += ": ";
}
}
template<typename T> void Named(T x, const char *name) {
if (name)
if (name) {
if (q) s += "\"";
s += name;
else
if (q) s += "\"";
} else {
s += NumToString(x);
}
}
void UType(uint8_t x, const char *name) { Named(x, name); }
void Bool(bool x) { s += x ? "true" : "false"; }
@@ -314,20 +345,35 @@ struct ToStringVisitor : public IterationVisitor {
void Float(float x) { s += NumToString(x); }
void Double(double x) { s += NumToString(x); }
void String(const struct String *str) {
EscapeString(str->c_str(), str->size(), &s, true);
EscapeString(str->c_str(), str->size(), &s, true, false);
}
void Unknown(const uint8_t *) { s += "(?)"; }
void StartVector() { s += "[ "; }
void EndVector() { s += " ]"; }
void StartVector() {
s += "[";
s += d;
indent_level++;
append_indent();
}
void EndVector() {
s += d;
indent_level--;
append_indent();
s += "]";
}
void Element(size_t i, ElementaryType /*type*/,
const TypeTable * /*type_table*/, const uint8_t * /*val*/) {
if (i) s += ", ";
if (i) {
s += ",";
s += d;
append_indent();
}
}
};
inline std::string FlatBufferToString(const uint8_t *buffer,
const TypeTable *type_table) {
ToStringVisitor tostring_visitor;
const TypeTable *type_table,
bool multi_line = false) {
ToStringVisitor tostring_visitor(multi_line ? "\n" : " ");
IterateFlatBuffer(buffer, type_table, &tostring_visitor);
return tostring_visitor.s;
}

View File

@@ -72,20 +72,20 @@ inline const Table *GetAnyRoot(const uint8_t *flatbuf) {
// Get a field's default, if you know it's an integer, and its exact type.
template<typename T> T GetFieldDefaultI(const reflection::Field &field) {
assert(sizeof(T) == GetTypeSize(field.type()->base_type()));
FLATBUFFERS_ASSERT(sizeof(T) == GetTypeSize(field.type()->base_type()));
return static_cast<T>(field.default_integer());
}
// Get a field's default, if you know it's floating point and its exact type.
template<typename T> T GetFieldDefaultF(const reflection::Field &field) {
assert(sizeof(T) == GetTypeSize(field.type()->base_type()));
FLATBUFFERS_ASSERT(sizeof(T) == GetTypeSize(field.type()->base_type()));
return static_cast<T>(field.default_real());
}
// 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()));
FLATBUFFERS_ASSERT(sizeof(T) == GetTypeSize(field.type()->base_type()));
return table.GetField<T>(field.offset(),
static_cast<T>(field.default_integer()));
}
@@ -93,7 +93,7 @@ T GetFieldI(const Table &table, const reflection::Field &field) {
// 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()));
FLATBUFFERS_ASSERT(sizeof(T) == GetTypeSize(field.type()->base_type()));
return table.GetField<T>(field.offset(),
static_cast<T>(field.default_real()));
}
@@ -101,15 +101,15 @@ T GetFieldF(const Table &table, const reflection::Field &field) {
// 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);
FLATBUFFERS_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()));
FLATBUFFERS_ASSERT(field.type()->base_type() == reflection::Vector &&
sizeof(T) == GetTypeSize(field.type()->element()));
return table.GetPointer<Vector<T> *>(field.offset());
}
@@ -123,8 +123,8 @@ inline VectorOfAny *GetFieldAnyV(const Table &table,
// 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);
FLATBUFFERS_ASSERT(field.type()->base_type() == reflection::Obj ||
field.type()->base_type() == reflection::Union);
return table.GetPointer<Table *>(field.offset());
}
@@ -133,14 +133,14 @@ inline const Struct *GetFieldStruct(const Table &table,
const reflection::Field &field) {
// TODO: This does NOT check if the field is a table or struct, but we'd need
// access to the schema to check the is_struct flag.
assert(field.type()->base_type() == reflection::Obj);
FLATBUFFERS_ASSERT(field.type()->base_type() == reflection::Obj);
return table.GetStruct<const Struct *>(field.offset());
}
// Get a structure's field, if you know it's a struct.
inline const Struct *GetFieldStruct(const Struct &structure,
const reflection::Field &field) {
assert(field.type()->base_type() == reflection::Obj);
FLATBUFFERS_ASSERT(field.type()->base_type() == reflection::Obj);
return structure.GetStruct<const Struct *>(field.offset());
}
@@ -262,12 +262,12 @@ template<typename T>
bool SetField(Table *table, const reflection::Field &field, T val) {
reflection::BaseType type = field.type()->base_type();
if (!IsScalar(type)) { return false; }
assert(sizeof(T) == GetTypeSize(type));
FLATBUFFERS_ASSERT(sizeof(T) == GetTypeSize(type));
T def;
if (IsInteger(type)) {
def = GetFieldDefaultI<T>(field);
} else {
assert(IsFloat(type));
FLATBUFFERS_ASSERT(IsFloat(type));
def = GetFieldDefaultF<T>(field);
}
return table->SetField(field.offset(), val, def);
@@ -386,7 +386,7 @@ inline const reflection::Object &GetUnionType(
// TODO: this is clumsy and slow, but no other way to find it?
auto type_field = parent.fields()->LookupByKey(
(unionfield.name()->str() + UnionTypeFieldSuffix()).c_str());
assert(type_field);
FLATBUFFERS_ASSERT(type_field);
auto union_type = GetFieldI<uint8_t>(table, *type_field);
auto enumval = enumdef->values()->LookupByKey(union_type);
return *enumval->object();
@@ -444,7 +444,8 @@ const uint8_t *AddFlatBuffer(std::vector<uint8_t> &flatbuf,
inline bool SetFieldT(Table *table, const reflection::Field &field,
const uint8_t *val) {
assert(sizeof(uoffset_t) == GetTypeSize(field.type()->base_type()));
FLATBUFFERS_ASSERT(sizeof(uoffset_t) ==
GetTypeSize(field.type()->base_type()));
return table->SetPointer(field.offset(), val);
}

View File

@@ -20,6 +20,10 @@ struct Field;
struct Object;
struct RPCCall;
struct Service;
struct Schema;
enum BaseType {
@@ -174,9 +178,9 @@ struct KeyValue FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
bool Verify(flatbuffers::Verifier &verifier) const {
return VerifyTableStart(verifier) &&
VerifyOffsetRequired(verifier, VT_KEY) &&
verifier.Verify(key()) &&
verifier.VerifyString(key()) &&
VerifyOffset(verifier, VT_VALUE) &&
verifier.Verify(value()) &&
verifier.VerifyString(value()) &&
verifier.EndTable();
}
};
@@ -228,7 +232,8 @@ struct EnumVal FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
VT_NAME = 4,
VT_VALUE = 6,
VT_OBJECT = 8,
VT_UNION_TYPE = 10
VT_UNION_TYPE = 10,
VT_DOCUMENTATION = 12
};
const flatbuffers::String *name() const {
return GetPointer<const flatbuffers::String *>(VT_NAME);
@@ -240,14 +245,7 @@ struct EnumVal FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
return value() < o->value();
}
int KeyCompareWithValue(int64_t val) const {
const auto key = value();
if (key < val) {
return -1;
} else if (key > val) {
return 1;
} else {
return 0;
}
return static_cast<int>(value() > val) - static_cast<int>(value() < val);
}
const Object *object() const {
return GetPointer<const Object *>(VT_OBJECT);
@@ -255,15 +253,21 @@ struct EnumVal FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
const Type *union_type() const {
return GetPointer<const Type *>(VT_UNION_TYPE);
}
const flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>> *documentation() const {
return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>> *>(VT_DOCUMENTATION);
}
bool Verify(flatbuffers::Verifier &verifier) const {
return VerifyTableStart(verifier) &&
VerifyOffsetRequired(verifier, VT_NAME) &&
verifier.Verify(name()) &&
verifier.VerifyString(name()) &&
VerifyField<int64_t>(verifier, VT_VALUE) &&
VerifyOffset(verifier, VT_OBJECT) &&
verifier.VerifyTable(object()) &&
VerifyOffset(verifier, VT_UNION_TYPE) &&
verifier.VerifyTable(union_type()) &&
VerifyOffset(verifier, VT_DOCUMENTATION) &&
verifier.VerifyVector(documentation()) &&
verifier.VerifyVectorOfStrings(documentation()) &&
verifier.EndTable();
}
};
@@ -283,6 +287,9 @@ struct EnumValBuilder {
void add_union_type(flatbuffers::Offset<Type> union_type) {
fbb_.AddOffset(EnumVal::VT_UNION_TYPE, union_type);
}
void add_documentation(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>>> documentation) {
fbb_.AddOffset(EnumVal::VT_DOCUMENTATION, documentation);
}
explicit EnumValBuilder(flatbuffers::FlatBufferBuilder &_fbb)
: fbb_(_fbb) {
start_ = fbb_.StartTable();
@@ -301,9 +308,11 @@ inline flatbuffers::Offset<EnumVal> CreateEnumVal(
flatbuffers::Offset<flatbuffers::String> name = 0,
int64_t value = 0,
flatbuffers::Offset<Object> object = 0,
flatbuffers::Offset<Type> union_type = 0) {
flatbuffers::Offset<Type> union_type = 0,
flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>>> documentation = 0) {
EnumValBuilder builder_(_fbb);
builder_.add_value(value);
builder_.add_documentation(documentation);
builder_.add_union_type(union_type);
builder_.add_object(object);
builder_.add_name(name);
@@ -315,13 +324,15 @@ inline flatbuffers::Offset<EnumVal> CreateEnumValDirect(
const char *name = nullptr,
int64_t value = 0,
flatbuffers::Offset<Object> object = 0,
flatbuffers::Offset<Type> union_type = 0) {
flatbuffers::Offset<Type> union_type = 0,
const std::vector<flatbuffers::Offset<flatbuffers::String>> *documentation = nullptr) {
return reflection::CreateEnumVal(
_fbb,
name ? _fbb.CreateString(name) : 0,
value,
object,
union_type);
union_type,
documentation ? _fbb.CreateVector<flatbuffers::Offset<flatbuffers::String>>(*documentation) : 0);
}
struct Enum FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
@@ -360,18 +371,18 @@ struct Enum FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
bool Verify(flatbuffers::Verifier &verifier) const {
return VerifyTableStart(verifier) &&
VerifyOffsetRequired(verifier, VT_NAME) &&
verifier.Verify(name()) &&
verifier.VerifyString(name()) &&
VerifyOffsetRequired(verifier, VT_VALUES) &&
verifier.Verify(values()) &&
verifier.VerifyVector(values()) &&
verifier.VerifyVectorOfTables(values()) &&
VerifyField<uint8_t>(verifier, VT_IS_UNION) &&
VerifyOffsetRequired(verifier, VT_UNDERLYING_TYPE) &&
verifier.VerifyTable(underlying_type()) &&
VerifyOffset(verifier, VT_ATTRIBUTES) &&
verifier.Verify(attributes()) &&
verifier.VerifyVector(attributes()) &&
verifier.VerifyVectorOfTables(attributes()) &&
VerifyOffset(verifier, VT_DOCUMENTATION) &&
verifier.Verify(documentation()) &&
verifier.VerifyVector(documentation()) &&
verifier.VerifyVectorOfStrings(documentation()) &&
verifier.EndTable();
}
@@ -505,7 +516,7 @@ struct Field FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
bool Verify(flatbuffers::Verifier &verifier) const {
return VerifyTableStart(verifier) &&
VerifyOffsetRequired(verifier, VT_NAME) &&
verifier.Verify(name()) &&
verifier.VerifyString(name()) &&
VerifyOffsetRequired(verifier, VT_TYPE) &&
verifier.VerifyTable(type()) &&
VerifyField<uint16_t>(verifier, VT_ID) &&
@@ -516,10 +527,10 @@ struct Field FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
VerifyField<uint8_t>(verifier, VT_REQUIRED) &&
VerifyField<uint8_t>(verifier, VT_KEY) &&
VerifyOffset(verifier, VT_ATTRIBUTES) &&
verifier.Verify(attributes()) &&
verifier.VerifyVector(attributes()) &&
verifier.VerifyVectorOfTables(attributes()) &&
VerifyOffset(verifier, VT_DOCUMENTATION) &&
verifier.Verify(documentation()) &&
verifier.VerifyVector(documentation()) &&
verifier.VerifyVectorOfStrings(documentation()) &&
verifier.EndTable();
}
@@ -671,18 +682,18 @@ struct Object FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
bool Verify(flatbuffers::Verifier &verifier) const {
return VerifyTableStart(verifier) &&
VerifyOffsetRequired(verifier, VT_NAME) &&
verifier.Verify(name()) &&
verifier.VerifyString(name()) &&
VerifyOffsetRequired(verifier, VT_FIELDS) &&
verifier.Verify(fields()) &&
verifier.VerifyVector(fields()) &&
verifier.VerifyVectorOfTables(fields()) &&
VerifyField<uint8_t>(verifier, VT_IS_STRUCT) &&
VerifyField<int32_t>(verifier, VT_MINALIGN) &&
VerifyField<int32_t>(verifier, VT_BYTESIZE) &&
VerifyOffset(verifier, VT_ATTRIBUTES) &&
verifier.Verify(attributes()) &&
verifier.VerifyVector(attributes()) &&
verifier.VerifyVectorOfTables(attributes()) &&
VerifyOffset(verifier, VT_DOCUMENTATION) &&
verifier.Verify(documentation()) &&
verifier.VerifyVector(documentation()) &&
verifier.VerifyVectorOfStrings(documentation()) &&
verifier.EndTable();
}
@@ -766,13 +777,224 @@ inline flatbuffers::Offset<Object> CreateObjectDirect(
documentation ? _fbb.CreateVector<flatbuffers::Offset<flatbuffers::String>>(*documentation) : 0);
}
struct RPCCall FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
enum {
VT_NAME = 4,
VT_REQUEST = 6,
VT_RESPONSE = 8,
VT_ATTRIBUTES = 10,
VT_DOCUMENTATION = 12
};
const flatbuffers::String *name() const {
return GetPointer<const flatbuffers::String *>(VT_NAME);
}
bool KeyCompareLessThan(const RPCCall *o) const {
return *name() < *o->name();
}
int KeyCompareWithValue(const char *val) const {
return strcmp(name()->c_str(), val);
}
const Object *request() const {
return GetPointer<const Object *>(VT_REQUEST);
}
const Object *response() const {
return GetPointer<const Object *>(VT_RESPONSE);
}
const flatbuffers::Vector<flatbuffers::Offset<KeyValue>> *attributes() const {
return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<KeyValue>> *>(VT_ATTRIBUTES);
}
const flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>> *documentation() const {
return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>> *>(VT_DOCUMENTATION);
}
bool Verify(flatbuffers::Verifier &verifier) const {
return VerifyTableStart(verifier) &&
VerifyOffsetRequired(verifier, VT_NAME) &&
verifier.VerifyString(name()) &&
VerifyOffsetRequired(verifier, VT_REQUEST) &&
verifier.VerifyTable(request()) &&
VerifyOffsetRequired(verifier, VT_RESPONSE) &&
verifier.VerifyTable(response()) &&
VerifyOffset(verifier, VT_ATTRIBUTES) &&
verifier.VerifyVector(attributes()) &&
verifier.VerifyVectorOfTables(attributes()) &&
VerifyOffset(verifier, VT_DOCUMENTATION) &&
verifier.VerifyVector(documentation()) &&
verifier.VerifyVectorOfStrings(documentation()) &&
verifier.EndTable();
}
};
struct RPCCallBuilder {
flatbuffers::FlatBufferBuilder &fbb_;
flatbuffers::uoffset_t start_;
void add_name(flatbuffers::Offset<flatbuffers::String> name) {
fbb_.AddOffset(RPCCall::VT_NAME, name);
}
void add_request(flatbuffers::Offset<Object> request) {
fbb_.AddOffset(RPCCall::VT_REQUEST, request);
}
void add_response(flatbuffers::Offset<Object> response) {
fbb_.AddOffset(RPCCall::VT_RESPONSE, response);
}
void add_attributes(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<KeyValue>>> attributes) {
fbb_.AddOffset(RPCCall::VT_ATTRIBUTES, attributes);
}
void add_documentation(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>>> documentation) {
fbb_.AddOffset(RPCCall::VT_DOCUMENTATION, documentation);
}
explicit RPCCallBuilder(flatbuffers::FlatBufferBuilder &_fbb)
: fbb_(_fbb) {
start_ = fbb_.StartTable();
}
RPCCallBuilder &operator=(const RPCCallBuilder &);
flatbuffers::Offset<RPCCall> Finish() {
const auto end = fbb_.EndTable(start_);
auto o = flatbuffers::Offset<RPCCall>(end);
fbb_.Required(o, RPCCall::VT_NAME);
fbb_.Required(o, RPCCall::VT_REQUEST);
fbb_.Required(o, RPCCall::VT_RESPONSE);
return o;
}
};
inline flatbuffers::Offset<RPCCall> CreateRPCCall(
flatbuffers::FlatBufferBuilder &_fbb,
flatbuffers::Offset<flatbuffers::String> name = 0,
flatbuffers::Offset<Object> request = 0,
flatbuffers::Offset<Object> response = 0,
flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<KeyValue>>> attributes = 0,
flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>>> documentation = 0) {
RPCCallBuilder builder_(_fbb);
builder_.add_documentation(documentation);
builder_.add_attributes(attributes);
builder_.add_response(response);
builder_.add_request(request);
builder_.add_name(name);
return builder_.Finish();
}
inline flatbuffers::Offset<RPCCall> CreateRPCCallDirect(
flatbuffers::FlatBufferBuilder &_fbb,
const char *name = nullptr,
flatbuffers::Offset<Object> request = 0,
flatbuffers::Offset<Object> response = 0,
const std::vector<flatbuffers::Offset<KeyValue>> *attributes = nullptr,
const std::vector<flatbuffers::Offset<flatbuffers::String>> *documentation = nullptr) {
return reflection::CreateRPCCall(
_fbb,
name ? _fbb.CreateString(name) : 0,
request,
response,
attributes ? _fbb.CreateVector<flatbuffers::Offset<KeyValue>>(*attributes) : 0,
documentation ? _fbb.CreateVector<flatbuffers::Offset<flatbuffers::String>>(*documentation) : 0);
}
struct Service FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
enum {
VT_NAME = 4,
VT_CALLS = 6,
VT_ATTRIBUTES = 8,
VT_DOCUMENTATION = 10
};
const flatbuffers::String *name() const {
return GetPointer<const flatbuffers::String *>(VT_NAME);
}
bool KeyCompareLessThan(const Service *o) const {
return *name() < *o->name();
}
int KeyCompareWithValue(const char *val) const {
return strcmp(name()->c_str(), val);
}
const flatbuffers::Vector<flatbuffers::Offset<RPCCall>> *calls() const {
return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<RPCCall>> *>(VT_CALLS);
}
const flatbuffers::Vector<flatbuffers::Offset<KeyValue>> *attributes() const {
return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<KeyValue>> *>(VT_ATTRIBUTES);
}
const flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>> *documentation() const {
return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>> *>(VT_DOCUMENTATION);
}
bool Verify(flatbuffers::Verifier &verifier) const {
return VerifyTableStart(verifier) &&
VerifyOffsetRequired(verifier, VT_NAME) &&
verifier.VerifyString(name()) &&
VerifyOffset(verifier, VT_CALLS) &&
verifier.VerifyVector(calls()) &&
verifier.VerifyVectorOfTables(calls()) &&
VerifyOffset(verifier, VT_ATTRIBUTES) &&
verifier.VerifyVector(attributes()) &&
verifier.VerifyVectorOfTables(attributes()) &&
VerifyOffset(verifier, VT_DOCUMENTATION) &&
verifier.VerifyVector(documentation()) &&
verifier.VerifyVectorOfStrings(documentation()) &&
verifier.EndTable();
}
};
struct ServiceBuilder {
flatbuffers::FlatBufferBuilder &fbb_;
flatbuffers::uoffset_t start_;
void add_name(flatbuffers::Offset<flatbuffers::String> name) {
fbb_.AddOffset(Service::VT_NAME, name);
}
void add_calls(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<RPCCall>>> calls) {
fbb_.AddOffset(Service::VT_CALLS, calls);
}
void add_attributes(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<KeyValue>>> attributes) {
fbb_.AddOffset(Service::VT_ATTRIBUTES, attributes);
}
void add_documentation(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>>> documentation) {
fbb_.AddOffset(Service::VT_DOCUMENTATION, documentation);
}
explicit ServiceBuilder(flatbuffers::FlatBufferBuilder &_fbb)
: fbb_(_fbb) {
start_ = fbb_.StartTable();
}
ServiceBuilder &operator=(const ServiceBuilder &);
flatbuffers::Offset<Service> Finish() {
const auto end = fbb_.EndTable(start_);
auto o = flatbuffers::Offset<Service>(end);
fbb_.Required(o, Service::VT_NAME);
return o;
}
};
inline flatbuffers::Offset<Service> CreateService(
flatbuffers::FlatBufferBuilder &_fbb,
flatbuffers::Offset<flatbuffers::String> name = 0,
flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<RPCCall>>> calls = 0,
flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<KeyValue>>> attributes = 0,
flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>>> documentation = 0) {
ServiceBuilder builder_(_fbb);
builder_.add_documentation(documentation);
builder_.add_attributes(attributes);
builder_.add_calls(calls);
builder_.add_name(name);
return builder_.Finish();
}
inline flatbuffers::Offset<Service> CreateServiceDirect(
flatbuffers::FlatBufferBuilder &_fbb,
const char *name = nullptr,
const std::vector<flatbuffers::Offset<RPCCall>> *calls = nullptr,
const std::vector<flatbuffers::Offset<KeyValue>> *attributes = nullptr,
const std::vector<flatbuffers::Offset<flatbuffers::String>> *documentation = nullptr) {
return reflection::CreateService(
_fbb,
name ? _fbb.CreateString(name) : 0,
calls ? _fbb.CreateVector<flatbuffers::Offset<RPCCall>>(*calls) : 0,
attributes ? _fbb.CreateVector<flatbuffers::Offset<KeyValue>>(*attributes) : 0,
documentation ? _fbb.CreateVector<flatbuffers::Offset<flatbuffers::String>>(*documentation) : 0);
}
struct Schema FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
enum {
VT_OBJECTS = 4,
VT_ENUMS = 6,
VT_FILE_IDENT = 8,
VT_FILE_EXT = 10,
VT_ROOT_TABLE = 12
VT_ROOT_TABLE = 12,
VT_SERVICES = 14
};
const flatbuffers::Vector<flatbuffers::Offset<Object>> *objects() const {
return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<Object>> *>(VT_OBJECTS);
@@ -789,20 +1011,26 @@ struct Schema FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
const Object *root_table() const {
return GetPointer<const Object *>(VT_ROOT_TABLE);
}
const flatbuffers::Vector<flatbuffers::Offset<Service>> *services() const {
return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<Service>> *>(VT_SERVICES);
}
bool Verify(flatbuffers::Verifier &verifier) const {
return VerifyTableStart(verifier) &&
VerifyOffsetRequired(verifier, VT_OBJECTS) &&
verifier.Verify(objects()) &&
verifier.VerifyVector(objects()) &&
verifier.VerifyVectorOfTables(objects()) &&
VerifyOffsetRequired(verifier, VT_ENUMS) &&
verifier.Verify(enums()) &&
verifier.VerifyVector(enums()) &&
verifier.VerifyVectorOfTables(enums()) &&
VerifyOffset(verifier, VT_FILE_IDENT) &&
verifier.Verify(file_ident()) &&
verifier.VerifyString(file_ident()) &&
VerifyOffset(verifier, VT_FILE_EXT) &&
verifier.Verify(file_ext()) &&
verifier.VerifyString(file_ext()) &&
VerifyOffset(verifier, VT_ROOT_TABLE) &&
verifier.VerifyTable(root_table()) &&
VerifyOffset(verifier, VT_SERVICES) &&
verifier.VerifyVector(services()) &&
verifier.VerifyVectorOfTables(services()) &&
verifier.EndTable();
}
};
@@ -825,6 +1053,9 @@ struct SchemaBuilder {
void add_root_table(flatbuffers::Offset<Object> root_table) {
fbb_.AddOffset(Schema::VT_ROOT_TABLE, root_table);
}
void add_services(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<Service>>> services) {
fbb_.AddOffset(Schema::VT_SERVICES, services);
}
explicit SchemaBuilder(flatbuffers::FlatBufferBuilder &_fbb)
: fbb_(_fbb) {
start_ = fbb_.StartTable();
@@ -845,8 +1076,10 @@ inline flatbuffers::Offset<Schema> CreateSchema(
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) {
flatbuffers::Offset<Object> root_table = 0,
flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<Service>>> services = 0) {
SchemaBuilder builder_(_fbb);
builder_.add_services(services);
builder_.add_root_table(root_table);
builder_.add_file_ext(file_ext);
builder_.add_file_ident(file_ident);
@@ -861,14 +1094,16 @@ inline flatbuffers::Offset<Schema> CreateSchemaDirect(
const std::vector<flatbuffers::Offset<Enum>> *enums = nullptr,
const char *file_ident = nullptr,
const char *file_ext = nullptr,
flatbuffers::Offset<Object> root_table = 0) {
flatbuffers::Offset<Object> root_table = 0,
const std::vector<flatbuffers::Offset<Service>> *services = nullptr) {
return reflection::CreateSchema(
_fbb,
objects ? _fbb.CreateVector<flatbuffers::Offset<Object>>(*objects) : 0,
enums ? _fbb.CreateVector<flatbuffers::Offset<Enum>>(*enums) : 0,
file_ident ? _fbb.CreateString(file_ident) : 0,
file_ext ? _fbb.CreateString(file_ext) : 0,
root_table);
root_table,
services ? _fbb.CreateVector<flatbuffers::Offset<Service>>(*services) : 0);
}
inline const reflection::Schema *GetSchema(const void *buf) {

View File

@@ -33,6 +33,16 @@
#include <cctype>
#endif // defined(FLATBUFFERS_CPP98_STL)
// Check if we can use template aliases
// Not possible if Microsoft Compiler before 2012
// Possible is the language feature __cpp_alias_templates is defined well
// Or possible if the C++ std is C+11 or newer
#if !(defined(_MSC_VER) && _MSC_VER <= 1700 /* MSVC2012 */) \
&& ((defined(__cpp_alias_templates) && __cpp_alias_templates >= 200704) \
|| (defined(__cplusplus) && __cplusplus >= 201103L))
#define FLATBUFFERS_TEMPLATES_ALIASES
#endif
// This header provides backwards compatibility for C++98 STLs like stlport.
namespace flatbuffers {
@@ -69,13 +79,13 @@ inline void vector_emplace_back(std::vector<T> *vector, V &&data) {
}
#ifndef FLATBUFFERS_CPP98_STL
#if !(defined(_MSC_VER) && _MSC_VER <= 1700 /* MSVC2012 */)
#if defined(FLATBUFFERS_TEMPLATES_ALIASES)
template <typename T>
using numeric_limits = std::numeric_limits<T>;
#else
template <typename T> class numeric_limits :
public std::numeric_limits<T> {};
#endif // !(defined(_MSC_VER) && _MSC_VER <= 1700 /* MSVC2012 */)
#endif // defined(FLATBUFFERS_TEMPLATES_ALIASES)
#else
template <typename T> class numeric_limits :
public std::numeric_limits<T> {};
@@ -98,7 +108,7 @@ inline void vector_emplace_back(std::vector<T> *vector, V &&data) {
};
#endif // FLATBUFFERS_CPP98_STL
#if !(defined(_MSC_VER) && _MSC_VER <= 1700 /* MSVC2012 */)
#if defined(FLATBUFFERS_TEMPLATES_ALIASES)
#ifndef FLATBUFFERS_CPP98_STL
template <typename T> using is_scalar = std::is_scalar<T>;
template <typename T, typename U> using is_same = std::is_same<T,U>;
@@ -119,10 +129,10 @@ inline void vector_emplace_back(std::vector<T> *vector, V &&data) {
template <typename T> struct is_floating_point :
public std::is_floating_point<T> {};
template <typename T> struct is_unsigned : public std::is_unsigned<T> {};
#endif // !(defined(_MSC_VER) && _MSC_VER <= 1700 /* MSVC2012 */)
#endif // defined(FLATBUFFERS_TEMPLATES_ALIASES)
#ifndef FLATBUFFERS_CPP98_STL
#if !(defined(_MSC_VER) && _MSC_VER <= 1700 /* MSVC2012 */)
#if defined(FLATBUFFERS_TEMPLATES_ALIASES)
template <class T> using unique_ptr = std::unique_ptr<T>;
#else
// MSVC 2010 doesn't support C++11 aliases.
@@ -148,7 +158,7 @@ inline void vector_emplace_back(std::vector<T> *vector, V &&data) {
return std::unique_ptr<T>::operator=(p);
}
};
#endif // !(defined(_MSC_VER) && _MSC_VER <= 1700 /* MSVC2012 */)
#endif // defined(FLATBUFFERS_TEMPLATES_ALIASES)
#else
// Very limited implementation of unique_ptr.
// This is provided simply to allow the C++ code generated from the default

View File

@@ -22,7 +22,12 @@
#include <stdlib.h>
#include <fstream>
#include <iomanip>
#include <sstream>
#ifndef FLATBUFFERS_PREFER_PRINTF
# include <sstream>
#else // FLATBUFFERS_PREFER_PRINTF
# include <float.h>
# include <stdio.h>
#endif // FLATBUFFERS_PREFER_PRINTF
#include <string>
#ifdef _WIN32
# ifndef WIN32_LEAN_AND_MEAN
@@ -45,13 +50,53 @@
namespace flatbuffers {
#ifdef FLATBUFFERS_PREFER_PRINTF
template<typename T> size_t IntToDigitCount(T t) {
size_t digit_count = 0;
// Count the sign for negative numbers
if (t < 0) digit_count++;
// Count a single 0 left of the dot for fractional numbers
if (-1 < t && t < 1) digit_count++;
// Count digits until fractional part
T eps = std::numeric_limits<float>::epsilon();
while (t <= (-1 + eps) || (1 - eps) <= t) {
t /= 10;
digit_count++;
}
return digit_count;
}
template<typename T> size_t NumToStringWidth(T t, int precision = 0) {
size_t string_width = IntToDigitCount(t);
// Count the dot for floating point numbers
if (precision) string_width += (precision + 1);
return string_width;
}
template<typename T> std::string NumToStringImplWrapper(T t, const char* fmt,
int precision = 0) {
size_t string_width = NumToStringWidth(t, precision);
std::string s(string_width, 0x00);
// Allow snprintf to use std::string trailing null to detect buffer overflow
snprintf(const_cast<char*>(s.data()), (s.size()+1), fmt, precision, t);
return s;
}
#endif // FLATBUFFERS_PREFER_PRINTF
// Convert an integer or floating point value to a string.
// In contrast to std::stringstream, "char" values are
// converted to a string of digits, and we don't use scientific notation.
template<typename T> std::string NumToString(T t) {
std::stringstream ss;
ss << t;
return ss.str();
// clang-format off
#ifndef FLATBUFFERS_PREFER_PRINTF
std::stringstream ss;
ss << t;
return ss.str();
#else // FLATBUFFERS_PREFER_PRINTF
auto v = static_cast<long long>(t);
return NumToStringImplWrapper(v, "%.*lld");
#endif // FLATBUFFERS_PREFER_PRINTF
// clang-format on
}
// Avoid char types used as character data.
template<> inline std::string NumToString<signed char>(signed char t) {
@@ -77,15 +122,22 @@ inline std::string NumToString<unsigned long long>(unsigned long long t) {
// Special versions for floats/doubles.
template<typename T> std::string FloatToString(T t, int precision) {
// 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;
// Default precision is 6, we want that to be higher for doubles.
ss << std::setprecision(precision);
ss << t;
auto s = ss.str();
// clang-format off
#ifndef FLATBUFFERS_PREFER_PRINTF
// 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 suppress scientific notation.
ss << std::fixed;
// Default precision is 6, we want that to be higher for doubles.
ss << std::setprecision(precision);
ss << t;
auto s = ss.str();
#else // FLATBUFFERS_PREFER_PRINTF
auto v = static_cast<double>(t);
auto s = NumToStringImplWrapper(v, "%0.*f", precision);
#endif // FLATBUFFERS_PREFER_PRINTF
// clang-format on
// 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) {
@@ -106,10 +158,16 @@ template<> inline std::string NumToString<float>(float t) {
// The returned string length is always xdigits long, prefixed by 0 digits.
// For example, IntToStringHex(0x23, 8) returns the string "00000023".
inline std::string IntToStringHex(int i, int xdigits) {
std::stringstream ss;
ss << std::setw(xdigits) << std::setfill('0') << std::hex << std::uppercase
<< i;
return ss.str();
// clang-format off
#ifndef FLATBUFFERS_PREFER_PRINTF
std::stringstream ss;
ss << std::setw(xdigits) << std::setfill('0') << std::hex << std::uppercase
<< i;
return ss.str();
#else // FLATBUFFERS_PREFER_PRINTF
return NumToStringImplWrapper(i, "%.*X", xdigits);
#endif // FLATBUFFERS_PREFER_PRINTF
// clang-format on
}
// Portable implementation of strtoll().
@@ -284,7 +342,7 @@ inline std::string AbsolutePath(const std::string &filepath) {
// Convert a unicode code point into a UTF-8 representation by appending it
// to a string. Returns the number of bytes generated.
inline int ToUTF8(uint32_t ucc, std::string *out) {
assert(!(ucc & 0x80000000)); // Top bit can't be set.
FLATBUFFERS_ASSERT(!(ucc & 0x80000000)); // Top bit can't be set.
// 6 possible encodings: http://en.wikipedia.org/wiki/UTF-8
for (int i = 0; i < 6; i++) {
// Max bits this encoding can represent.
@@ -302,7 +360,7 @@ inline int ToUTF8(uint32_t ucc, std::string *out) {
return i + 1; // Return the number of bytes added.
}
}
assert(0); // Impossible to arrive here.
FLATBUFFERS_ASSERT(0); // Impossible to arrive here.
return -1;
}
@@ -321,7 +379,7 @@ inline int FromUTF8(const char **in) {
break;
}
}
if ((static_cast<const unsigned char>(**in) << len) & 0x80) return -1; // Bit after leading 1's must be 0.
if ((static_cast<unsigned char>(**in) << len) & 0x80) return -1; // Bit after leading 1's must be 0.
if (!len) return *(*in)++;
// UTF-8 encoded values with a length are between 2 and 4 bytes.
if (len < 2 || len > 4) { return -1; }
@@ -353,6 +411,7 @@ inline int FromUTF8(const char **in) {
return ucc;
}
#ifndef FLATBUFFERS_PREFER_PRINTF
// Wraps a string to a maximum length, inserting new lines where necessary. Any
// existing whitespace will be collapsed down to a single space. A prefix or
// suffix can be provided, which will be inserted before or after a wrapped
@@ -379,9 +438,10 @@ inline std::string WordWrap(const std::string in, size_t max_length,
return wrapped;
}
#endif // !FLATBUFFERS_PREFER_PRINTF
inline bool EscapeString(const char *s, size_t length, std::string *_text,
bool allow_non_utf8) {
bool allow_non_utf8, bool natural_utf8) {
std::string &text = *_text;
text += "\"";
for (uoffset_t i = 0; i < length; i++) {
@@ -421,7 +481,10 @@ inline bool EscapeString(const char *s, size_t length, std::string *_text,
return false;
}
} else {
if (ucc <= 0xFFFF) {
if (natural_utf8) {
// utf8 points to past all utf-8 bytes parsed
text.append(s + i, static_cast<size_t>(utf8 - s - i));
} else if (ucc <= 0xFFFF) {
// Parses as Unicode within JSON's \uXXXX range, so use that.
text += "\\u";
text += IntToStringHex(ucc, 4);

View File

@@ -152,6 +152,18 @@ public class FlatBufferBuilder {
* @return Returns the new `ByteBuffer` that was allocated.
*/
ByteBuffer newByteBuffer(int capacity);
/**
* Release a ByteBuffer. Current {@link FlatBufferBuilder}
* released any reference to it, so it is safe to dispose the buffer
* or return it to a pool.
* It is not guaranteed that the buffer has been created
* with {@link #newByteBuffer(int) }.
*
* @param bb the buffer to release
*/
default void releaseByteBuffer(ByteBuffer bb) {
}
}
/**
@@ -241,7 +253,11 @@ public class FlatBufferBuilder {
// Reallocate the buffer if needed.
while (space < align_size + size + additional_bytes) {
int old_buf_size = bb.capacity();
bb = growByteBuffer(bb, bb_factory);
ByteBuffer old = bb;
bb = growByteBuffer(old, bb_factory);
if (old != bb) {
bb_factory.releaseByteBuffer(old);
}
space += bb.capacity() - old_buf_size;
}
pad(align_size);

View File

@@ -28,6 +28,20 @@ public class Struct {
protected int bb_pos;
/** The underlying ByteBuffer to hold the data of the Struct. */
protected ByteBuffer bb;
/**
* Resets internal state with a null {@code ByteBuffer} and a zero position.
*
* This method exists primarily to allow recycling Struct instances without risking memory leaks
* due to {@code ByteBuffer} references. The instance will be unusable until it is assigned
* again to a {@code ByteBuffer}.
*
* @param struct the instance to reset to initial state
*/
public void __reset() {
bb = null;
bb_pos = 0;
}
}
/// @endcond

View File

@@ -292,6 +292,18 @@ public class Table {
}
return len_1 - len_2;
}
/**
* Resets the internal state with a null {@code ByteBuffer} and a zero position.
*
* This method exists primarily to allow recycling Table instances without risking memory leaks
* due to {@code ByteBuffer} references. The instance will be unusable until it is assigned
* again to a {@code ByteBuffer}.
*/
public void __reset() {
bb = null;
bb_pos = 0;
}
}
/// @endcond

View File

@@ -1040,6 +1040,26 @@ flatbuffers.ByteBuffer.prototype.writeFloat64 = function(offset, value) {
this.writeInt32(offset + 4, flatbuffers.int32[flatbuffers.isLittleEndian ? 1 : 0]);
};
/**
* Return the file identifier. Behavior is undefined for FlatBuffers whose
* schema does not include a file_identifier (likely points at padding or the
* start of a the root vtable).
* @returns {string}
*/
flatbuffers.ByteBuffer.prototype.getBufferIdentifier = function() {
if (this.bytes_.length < this.position_ + flatbuffers.SIZEOF_INT +
flatbuffers.FILE_IDENTIFIER_LENGTH) {
throw new Error(
'FlatBuffers: ByteBuffer is too short to contain an identifier.');
}
var result = "";
for (var i = 0; i < flatbuffers.FILE_IDENTIFIER_LENGTH; i++) {
result += String.fromCharCode(
this.readInt8(this.position_ + flatbuffers.SIZEOF_INT + i));
}
return result;
};
/**
* Look up a field in the vtable, return an offset into the object, or 0 if the
* field is not present.

278
lobster/flatbuffers.lobster Normal file
View File

@@ -0,0 +1,278 @@
// Copyright 2018 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 "std.lobster"
namespace flatbuffers
struct handle:
buf_:string
pos_:int
enum + sz_8 = 1,
sz_16 = 2,
sz_32 = 4,
sz_64 = 8,
sz_voffset = 2,
sz_uoffset = 4,
sz_soffset = 4,
sz_metadata_fields = 2
struct builder:
buf:string = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
current_vtable:[int] = []
head:int = 0
minalign:int = 1
object_end:int = 0
vtables:[int] = []
nested:int = false
finished:int = false
// Optionally call this right after creating the builder for a larger initial buffer.
def Initial(initial_size:int):
buf = "\x00".repeat_string(initial_size)
def Start():
// Get the start of useful data in the underlying byte buffer.
return buf.length - head
def Offset():
// Offset relative to the end of the buffer.
return head
// Returns a copy of the part of the buffer containing only the finished FlatBuffer
def SizedCopy():
assert finished
return buf.substring(Start(), -1)
def StartNesting():
assert not nested
nested = true
def EndNesting():
assert nested
nested = false
def StartObject(numfields):
StartNesting()
current_vtable = map(numfields): 0
object_end = head
minalign = 1
def EndObject():
EndNesting()
// Prepend a zero scalar to the object. Later in this function we'll
// write an offset here that points to the object's vtable:
PrependInt32(0)
object_offset := head
// Write out new vtable speculatively.
vtable_size := (current_vtable.length + sz_metadata_fields) * sz_voffset
while current_vtable.length:
o := current_vtable.pop()
PrependVOffsetT(if o: object_offset - o else: 0)
// The two metadata fields are written last.
// First, store the object bytesize:
PrependVOffsetT(object_offset - object_end)
// Second, store the vtable bytesize:
PrependVOffsetT(vtable_size)
// 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.
existing_vtable := do():
reverse(vtables) vt2_offset:
// Find the other vtable:
vt2_start := buf.length - vt2_offset
vt2_len := buf.read_int16_le(vt2_start)
// Compare the other vtable to the one under consideration.
// If they are equal, return the offset:
if vtable_size == vt2_len and
not compare_substring(buf, Start(), buf, vt2_start, vtable_size):
return vt2_offset from do
0
if existing_vtable:
// Found a duplicate vtable, remove the one we wrote.
head = object_offset
// Write the offset to the found vtable in the
// already-allocated offset at the beginning of this object:
buf.write_int32_le(Start(), existing_vtable - object_offset)
else:
// Did not find a vtable, so keep the one we wrote.
// Next, write the offset to the new vtable in the
// already-allocated offset at the beginning of this object:
buf.write_int32_le(buf.length - object_offset, head - object_offset)
// Finally, store this vtable in memory for future
// deduplication:
vtables.push(head)
return object_offset
def Pad(n):
for(n): buf, head = buf.write_int8_le_back(head, 0)
def Prep(size, additional_bytes):
// Track the biggest thing we've ever aligned to.
if size > minalign:
minalign = size
// Find the amount of alignment needed such that `size` is properly
// aligned after `additionalBytes`:
align_size := ((~(head + additional_bytes)) + 1) & (size - 1)
Pad(align_size)
def PrependUOffsetTRelative(off):
// Prepends an unsigned offset into vector data, relative to where it will be written.
Prep(sz_uoffset, 0)
assert off <= head
PlaceUOffsetT(head - off + sz_uoffset)
def StartVector(elem_size, num_elems, alignment):
// Initializes bookkeeping for writing a new vector.
StartNesting()
Prep(sz_32, elem_size * num_elems)
Prep(alignment, elem_size * num_elems) // In case alignment > int.
return head
def EndVector(vector_num_elems):
EndNesting()
// we already made space for this, so write without PrependUint32
PlaceUOffsetT(vector_num_elems)
return head
def CreateString(s:string):
// writes a null-terminated byte string.
StartNesting()
Prep(sz_32, s.length + 1)
buf, head = buf.write_substring_back(head, s, true)
return EndVector(s.length)
def CreateByteVector(s:string):
// writes a non-null-terminated byte string.
StartNesting()
Prep(sz_32, s.length)
buf, head = buf.write_substring_back(head, s, false)
return EndVector(s.length)
def Slot(slotnum):
assert nested
while current_vtable.length <= slotnum: current_vtable.push(0)
current_vtable[slotnum] = head
def __Finish(root_table:int, size_prefix:int):
// Finish finalizes a buffer, pointing to the given root_table
assert not finished
assert not nested
prep_size := sz_32
if size_prefix:
prep_size += sz_32
Prep(minalign, prep_size)
PrependUOffsetTRelative(root_table)
if size_prefix:
PrependInt32(head)
finished = true
return Start()
def Finish(root_table:int):
return __Finish(root_table, false)
def FinishSizePrefixed(root_table:int):
return __Finish(root_table, true)
def PrependBool(x):
buf, head = buf.write_int8_le_back(head, x)
def PrependByte(x):
buf, head = buf.write_int8_le_back(head, x)
def PrependUint8(x):
buf, head = buf.write_int8_le_back(head, x)
def PrependUint16(x):
Prep(sz_16, 0)
buf, head = buf.write_int16_le_back(head, x)
def PrependUint32(x):
Prep(sz_32, 0)
buf, head = buf.write_int32_le_back(head, x)
def PrependUint64(x):
Prep(sz_64, 0)
buf, head = buf.write_int64_le_back(head, x)
def PrependInt8(x):
buf, head = buf.write_int8_le_back(head, x)
def PrependInt16(x):
Prep(sz_16, 0)
buf, head = buf.write_int16_le_back(head, x)
def PrependInt32(x):
Prep(sz_32, 0)
buf, head = buf.write_int32_le_back(head, x)
def PrependInt64(x):
Prep(sz_64, 0)
buf, head = buf.write_int64_le_back(head, x)
def PrependFloat32(x):
Prep(sz_32, 0)
buf, head = buf.write_float32_le_back(head, x)
def PrependFloat64(x):
Prep(sz_64, 0)
buf, head = buf.write_float64_le_back(head, x)
def PrependVOffsetT(x):
Prep(sz_voffset, 0)
buf, head = buf.write_int16_le_back(head, x)
def PlaceVOffsetT(x):
buf, head = buf.write_int16_le_back(head, x)
def PlaceSOffsetT(x):
buf, head = buf.write_int32_le_back(head, x)
def PlaceUOffsetT(x):
buf, head = buf.write_int32_le_back(head, x)
def PrependSlot(o:int, x, d, f):
if x != d:
f(x)
Slot(o)
def PrependBoolSlot(o, x, d): PrependSlot(o, x, d): PrependBool(_)
def PrependByteSlot(o, x, d): PrependSlot(o, x, d): PrependByte(_)
def PrependUint8Slot(o, x, d): PrependSlot(o, x, d): PrependUint8(_)
def PrependUint16Slot(o, x, d): PrependSlot(o, x, d): PrependUint16(_)
def PrependUint32Slot(o, x, d): PrependSlot(o, x, d): PrependUint32(_)
def PrependUint64Slot(o, x, d): PrependSlot(o, x, d): PrependUint64(_)
def PrependInt8Slot(o, x, d): PrependSlot(o, x, d): PrependInt8(_)
def PrependInt16Slot(o, x, d): PrependSlot(o, x, d): PrependInt16(_)
def PrependInt32Slot(o, x, d): PrependSlot(o, x, d): PrependInt32(_)
def PrependInt64Slot(o, x, d): PrependSlot(o, x, d): PrependInt64(_)
def PrependFloat32Slot(o, x, d): PrependSlot(o, x, d): PrependFloat32(_)
def PrependFloat64Slot(o, x, d): PrependSlot(o, x, d): PrependFloat64(_)
def PrependUOffsetTRelativeSlot(o, x, d):
if x != d:
PrependUOffsetTRelative(x)
Slot(o)
def PrependStructSlot(v, x, d):
if x != d:
// 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.
assert x == head
Slot(v)

8
lua/flatbuffers.lua Normal file
View File

@@ -0,0 +1,8 @@
local m = {}
m.Builder = require("flatbuffers.builder").New
m.N = require("flatbuffers.numTypes")
m.view = require("flatbuffers.view")
m.binaryArray = require("flatbuffers.binaryarray")
return m

View File

@@ -0,0 +1,123 @@
local m = {} -- the module table
local mt = {} -- the module metatable
-- given a binary array, set a metamethod to return its length
-- (e.g., #binaryArray, calls this)
function mt:__len()
return self.size
end
-- Create a new binary array of an initial size
function m.New(sizeOrString)
-- the array storage itself
local o = {}
if type(sizeOrString) == "string" then
o.str = sizeOrString
o.size = #sizeOrString
elseif type(sizeOrString) == "number" then
o.data = {}
o.size = sizeOrString
else
error("Expect a integer size value or string to construct a binary array")
end
-- set the inheritance
setmetatable(o, {__index = mt, __len = mt.__len})
return o
end
-- Get a slice of the binary array from start to end position
function mt:Slice(startPos, endPos)
startPos = startPos or 0
endPos = endPos or self.size
local d = self.data
if d then
-- if the self.data is defined, we are building the buffer
-- in a Lua table
-- new table to store the slice components
local b = {}
-- starting with the startPos, put all
-- values into the new table to be concat later
-- updated the startPos based on the size of the
-- value
while startPos < endPos do
local v = d[startPos] or '/0'
table.insert(b, v)
startPos = startPos + #v
end
-- combine the table of strings into one string
-- this is faster than doing a bunch of concats by themselves
return table.concat(b)
else
-- n.b start/endPos are 0-based incoming, so need to convert
-- correctly. in python a slice includes start -> end - 1
return self.str:sub(startPos+1, endPos)
end
end
-- Grow the binary array to a new size, placing the exisiting data
-- at then end of the new array
function mt:Grow(newsize)
-- the new table to store the data
local newT = {}
-- the offset to be applied to existing entries
local offset = newsize - self.size
-- loop over all the current entries and
-- add them to the new table at the correct
-- offset location
local d = self.data
for i,data in pairs(d) do
newT[i + offset] = data
end
-- update this storage with the new table and size
self.data = newT
self.size = newsize
end
-- memorization for padding strings
local pads = {}
-- pad the binary with n \0 bytes at the starting position
function mt:Pad(n, startPos)
-- use memorization to avoid creating a bunch of strings
-- all the time
local s = pads[n]
if not s then
s = string.rep('\0', n)
pads[n] = s
end
-- store the padding string at the start position in the
-- Lua table
self.data[startPos] = s
end
-- Sets the binary array value at the specified position
function mt:Set(value, position)
self.data[position] = value
end
-- locals for slightly faster access
local sunpack = string.unpack
local spack = string.pack
-- Pack the data into a binary representation
function m.Pack(fmt, ...)
return spack(fmt, ...)
end
-- Unpack the data from a binary representation in
-- a Lua value
function m.Unpack(fmt, s, pos)
return sunpack(fmt, s.str, pos + 1)
end
-- Return the binary array module
return m

367
lua/flatbuffers/builder.lua Normal file
View File

@@ -0,0 +1,367 @@
local N = require("flatbuffers.numTypes")
local ba = require("flatbuffers.binaryarray")
local compat = require("flatbuffers.compat")
local m = {}
local mt = {}
-- get locals for faster access
local VOffsetT = N.VOffsetT
local UOffsetT = N.UOffsetT
local SOffsetT = N.SOffsetT
local Bool = N.Bool
local Uint8 = N.Uint8
local Uint16 = N.Uint16
local Uint32 = N.Uint32
local Uint64 = N.Uint64
local Int8 = N.Int8
local Int16 = N.Int16
local Int32 = N.Int32
local Int64 = N.Int64
local Float32 = N.Float32
local Float64 = N.Float64
local MAX_BUFFER_SIZE = 0x80000000 -- 2 GB
local VtableMetadataFields = 2
local getAlignSize = compat.GetAlignSize
local function vtableEqual(a, objectStart, b)
UOffsetT:EnforceNumber(objectStart)
if (#a * VOffsetT.bytewidth) ~= #b then
return false
end
for i, elem in ipairs(a) do
local x = VOffsetT:Unpack(b, i * VOffsetT.bytewidth)
if x ~= 0 or elem ~= 0 then
local y = objectStart - elem
if x ~= y then
return false
end
end
end
return true
end
function m.New(initialSize)
assert(0 <= initialSize and initialSize < MAX_BUFFER_SIZE)
local o =
{
finished = false,
bytes = ba.New(initialSize),
nested = false,
head = initialSize,
minalign = 1,
vtables = {}
}
setmetatable(o, {__index = mt})
return o
end
function mt:Output(full)
assert(self.finished, "Builder Not Finished")
if full then
return self.bytes:Slice()
else
return self.bytes:Slice(self.head)
end
end
function mt:StartObject(numFields)
assert(not self.nested)
local vtable = {}
for _=1,numFields do
table.insert(vtable, 0)
end
self.currentVTable = vtable
self.objectEnd = self:Offset()
self.nested = true
end
function mt:WriteVtable()
self:PrependSOffsetTRelative(0)
local objectOffset = self:Offset()
local exisitingVTable
local i = #self.vtables
while i >= 1 do
if self.vtables[i] == 0 then
table.remove(self.vtables,i)
end
i = i - 1
end
while i >= 1 do
local vt2Offset = self.vtables[i]
local vt2Start = #self.bytes - vt2Offset
local vt2len = VOffsetT:Unpack(self.bytes, vt2Start)
local metadata = VtableMetadataFields * VOffsetT.bytewidth
local vt2End = vt2Start + vt2Len
local vt2 = self.bytes:Slice(vt2Start+metadata,vt2End)
if vtableEqual(self.currentVTable, objectOffset, vt2) then
exisitingVTable = vt2Offset
break
end
i = i - 1
end
if not exisitingVTable then
i = #self.currentVTable
while i >= 1 do
local off = 0
local a = self.currentVTable[i]
if a and a ~= 0 then
off = objectOffset - a
end
self:PrependVOffsetT(off)
i = i - 1
end
local objectSize = objectOffset - self.objectEnd
self:PrependVOffsetT(objectSize)
local vBytes = #self.currentVTable + VtableMetadataFields
vBytes = vBytes * VOffsetT.bytewidth
self:PrependVOffsetT(vBytes)
local objectStart = #self.bytes - objectOffset
self.bytes:Set(SOffsetT:Pack(self:Offset() - objectOffset),objectStart)
table.insert(self.vtables, self:Offset())
else
local objectStart = #self.bytes - objectOffset
self.head = objectStart
self.bytes:Set(SOffsetT:Pack(exisitingVTable - objectOffset),self.head)
end
self.currentVTable = nil
return objectOffset
end
function mt:EndObject()
assert(self.nested)
self.nested = false
return self:WriteVtable()
end
local function growByteBuffer(self, desiredSize)
local s = #self.bytes
assert(s < MAX_BUFFER_SIZE, "Flat Buffers cannot grow buffer beyond 2 gigabytes")
local newsize = s
repeat
newsize = math.min(newsize * 2, MAX_BUFFER_SIZE)
if newsize == 0 then newsize = 1 end
until newsize > desiredSize
self.bytes:Grow(newsize)
end
function mt:Head()
return self.head
end
function mt:Offset()
return #self.bytes - self.head
end
function mt:Pad(n)
if n > 0 then
-- pads are 8-bit, so skip the bytewidth lookup
local h = self.head - n -- UInt8
self.head = h
self.bytes:Pad(n, h)
end
end
function mt:Prep(size, additionalBytes)
if size > self.minalign then
self.minalign = size
end
local h = self.head
local k = #self.bytes - h + additionalBytes
local alignsize = ((~k) + 1) & (size - 1) -- getAlignSize(k, size)
local desiredSize = alignsize + size + additionalBytes
while self.head < desiredSize do
local oldBufSize = #self.bytes
growByteBuffer(self, desiredSize)
local updatedHead = self.head + #self.bytes - oldBufSize
self.head = updatedHead
end
self:Pad(alignsize)
end
function mt:PrependSOffsetTRelative(off)
self:Prep(SOffsetT.bytewidth, 0)
assert(off <= self:Offset(), "Offset arithmetic error")
local off2 = self:Offset() - off + SOffsetT.bytewidth
self:Place(off2, SOffsetT)
end
function mt:PrependUOffsetTRelative(off)
self:Prep(UOffsetT.bytewidth, 0)
local soffset = self:Offset()
if off <= soffset then
local off2 = soffset - off + UOffsetT.bytewidth
self:Place(off2, UOffsetT)
else
error("Offset arithmetic error")
end
end
function mt:StartVector(elemSize, numElements, alignment)
assert(not self.nested)
self.nested = true
self:Prep(Uint32.bytewidth, elemSize * numElements)
self:Prep(alignment, elemSize * numElements)
return self:Offset()
end
function mt:EndVector(vectorNumElements)
assert(self.nested)
self.nested = false
self:Place(vectorNumElements, UOffsetT)
return self:Offset()
end
function mt:CreateString(s)
assert(not self.nested)
self.nested = true
assert(type(s) == "string")
self:Prep(UOffsetT.bytewidth, (#s + 1)*Uint8.bytewidth)
self:Place(0, Uint8)
local l = #s
self.head = self.head - l
self.bytes:Set(s, self.head, self.head + l)
return self:EndVector(#s)
end
function mt:CreateByteVector(x)
assert(not self.nested)
self.nested = true
self:Prep(UOffsetT.bytewidth, #x*Uint8.bytewidth)
local l = #x
self.head = self.head - l
self.bytes:Set(x, self.head, self.head + l)
return self:EndVector(#x)
end
function mt:Slot(slotnum)
assert(self.nested)
-- n.b. slot number is 0-based
self.currentVTable[slotnum + 1] = self:Offset()
end
local function finish(self, rootTable, sizePrefix)
UOffsetT:EnforceNumber(rootTable)
local prepSize = UOffsetT.bytewidth
if sizePrefix then
prepSize = prepSize + Int32.bytewidth
end
self:Prep(self.minalign, prepSize)
self:PrependUOffsetTRelative(rootTable)
if sizePrefix then
local size = #self.bytes - self.head
Int32:EnforceNumber(size)
self:PrependInt32(size)
end
self.finished = true
return self.head
end
function mt:Finish(rootTable)
return finish(self, rootTable, false)
end
function mt:FinishSizePrefixed(rootTable)
return finish(self, rootTable, true)
end
function mt:Prepend(flags, off)
self:Prep(flags.bytewidth, 0)
self:Place(off, flags)
end
function mt:PrependSlot(flags, o, x, d)
flags:EnforceNumber(x)
flags:EnforceNumber(d)
if x ~= d then
self:Prepend(flags, x)
self:Slot(o)
end
end
function mt:PrependBoolSlot(...) self:PrependSlot(Bool, ...) end
function mt:PrependByteSlot(...) self:PrependSlot(Uint8, ...) end
function mt:PrependUint8Slot(...) self:PrependSlot(Uint8, ...) end
function mt:PrependUint16Slot(...) self:PrependSlot(Uint16, ...) end
function mt:PrependUint32Slot(...) self:PrependSlot(Uint32, ...) end
function mt:PrependUint64Slot(...) self:PrependSlot(Uint64, ...) end
function mt:PrependInt8Slot(...) self:PrependSlot(Int8, ...) end
function mt:PrependInt16Slot(...) self:PrependSlot(Int16, ...) end
function mt:PrependInt32Slot(...) self:PrependSlot(Int32, ...) end
function mt:PrependInt64Slot(...) self:PrependSlot(Int64, ...) end
function mt:PrependFloat32Slot(...) self:PrependSlot(Float32, ...) end
function mt:PrependFloat64Slot(...) self:PrependSlot(Float64, ...) end
function mt:PrependUOffsetTRelativeSlot(o,x,d)
if x~=d then
self:PrependUOffsetTRelative(x)
self:Slot(o)
end
end
function mt:PrependStructSlot(v,x,d)
UOffsetT:EnforceNumber(d)
if x~=d then
UOffsetT:EnforceNumber(x)
assert(x == self:Offset(), "Tried to write a Struct at an Offset that is different from the current Offset of the Builder.")
self:Slot(v)
end
end
function mt:PrependBool(x) self:Prepend(Bool, x) end
function mt:PrependByte(x) self:Prepend(Uint8, x) end
function mt:PrependUint8(x) self:Prepend(Uint8, x) end
function mt:PrependUint16(x) self:Prepend(Uint16, x) end
function mt:PrependUint32(x) self:Prepend(Uint32, x) end
function mt:PrependUint64(x) self:Prepend(Uint64, x) end
function mt:PrependInt8(x) self:Prepend(Int8, x) end
function mt:PrependInt16(x) self:Prepend(Int16, x) end
function mt:PrependInt32(x) self:Prepend(Int32, x) end
function mt:PrependInt64(x) self:Prepend(Int64, x) end
function mt:PrependFloat32(x) self:Prepend(Float32, x) end
function mt:PrependFloat64(x) self:Prepend(Float64, x) end
function mt:PrependVOffsetT(x) self:Prepend(VOffsetT, x) end
function mt:Place(x, flags)
local d = flags:EnforceNumberAndPack(x)
local h = self.head - flags.bytewidth
self.head = h
self.bytes:Set(d, h)
end
return m

View File

@@ -0,0 +1,17 @@
local m = {}
local getAlignSize
if _VERSION == "Lua 5.3" then
getAlignSize = function(k, size)
return ((~k) + 1) & (size - 1)
end
else
getAlignSize = function(self, size, additionalBytes)
local alignsize = bit32.bnot(#self.bytes-self:Head() + additionalBytes) + 1
return bit32.band(alignsize,(size - 1))
end
end
m.GetAlignSize = getAlignSize
return m

View File

@@ -0,0 +1,198 @@
local m = {}
local ba = require("flatbuffers.binaryarray")
local bpack = ba.Pack
local bunpack = ba.Unpack
local type_mt = {}
function type_mt:Pack(value)
return bpack(self.packFmt, value)
end
function type_mt:Unpack(buf, pos)
return bunpack(self.packFmt, buf, pos)
end
function type_mt:ValidNumber(n)
if not self.min_value and not self.max_value then return true end
return self.min_value <= n and n <= self.max_value
end
function type_mt:EnforceNumber(n)
-- duplicate code since the overhead of function calls
-- for such a popular method is time consuming
if not self.min_value and not self.max_value then
return
end
if self.min_value <= n and n <= self.max_value then
return
end
error("Number is not in the valid range")
end
function type_mt:EnforceNumberAndPack(n)
return bpack(self.packFmt, n)
end
function type_mt:ConvertType(n, otherType)
assert(self.bytewidth == otherType.bytewidth, "Cannot convert between types of different widths")
if self == otherType then
return n
end
return otherType:Unpack(self:Pack(n))
end
local bool_mt =
{
bytewidth = 1,
min_value = false,
max_value = true,
lua_type = type(true),
name = "bool",
packFmt = "<b"
}
local uint8_mt =
{
bytewidth = 1,
min_value = 0,
max_value = 2^8-1,
lua_type = type(1),
name = "uint8",
packFmt = "<I1"
}
local uint16_mt =
{
bytewidth = 2,
min_value = 0,
max_value = 2^16-1,
lua_type = type(1),
name = "uint16",
packFmt = "<I2"
}
local uint32_mt =
{
bytewidth = 4,
min_value = 0,
max_value = 2^32-1,
lua_type = type(1),
name = "uint32",
packFmt = "<I4"
}
local uint64_mt =
{
bytewidth = 8,
min_value = 0,
max_value = 2^64-1,
lua_type = type(1),
name = "uint64",
packFmt = "<I8"
}
local int8_mt =
{
bytewidth = 1,
min_value = -2^7,
max_value = 2^7-1,
lua_type = type(1),
name = "int8",
packFmt = "<i1"
}
local int16_mt =
{
bytewidth = 2,
min_value = -2^15,
max_value = 2^15-1,
lua_type = type(1),
name = "int16",
packFmt = "<i2"
}
local int32_mt =
{
bytewidth = 4,
min_value = -2^15,
max_value = 2^15-1,
lua_type = type(1),
name = "int32",
packFmt = "<i4"
}
local int64_mt =
{
bytewidth = 8,
min_value = -2^63,
max_value = 2^63-1,
lua_type = type(1),
name = "int64",
packFmt = "<i8"
}
local float32_mt =
{
bytewidth = 4,
min_value = nil,
max_value = nil,
lua_type = type(1.0),
name = "float32",
packFmt = "<f"
}
local float64_mt =
{
bytewidth = 8,
min_value = nil,
max_value = nil,
lua_type = type(1.0),
name = "float64",
packFmt = "<d"
}
-- register the base class
setmetatable(bool_mt, {__index = type_mt})
setmetatable(uint8_mt, {__index = type_mt})
setmetatable(uint16_mt, {__index = type_mt})
setmetatable(uint32_mt, {__index = type_mt})
setmetatable(uint64_mt, {__index = type_mt})
setmetatable(int8_mt, {__index = type_mt})
setmetatable(int16_mt, {__index = type_mt})
setmetatable(int32_mt, {__index = type_mt})
setmetatable(int64_mt, {__index = type_mt})
setmetatable(float32_mt, {__index = type_mt})
setmetatable(float64_mt, {__index = type_mt})
m.Bool = bool_mt
m.Uint8 = uint8_mt
m.Uint16 = uint16_mt
m.Uint32 = uint32_mt
m.Uint64 = uint64_mt
m.Int8 = int8_mt
m.Int16 = int16_mt
m.Int32 = int32_mt
m.Int64 = int64_mt
m.Float32 = float32_mt
m.Float64 = float64_mt
m.UOffsetT = uint32_mt
m.VOffsetT = uint16_mt
m.SOffsetT = int32_mt
function GenerateTypes(listOfTypes)
for _,t in pairs(listOfTypes) do
t.Pack = function(self, value) return bpack(self.packFmt, value) end
t.Unpack = function(self, buf, pos) return bunpack(self.packFmt, buf, pos) end
end
end
GenerateTypes(m)
return m

97
lua/flatbuffers/view.lua Normal file
View File

@@ -0,0 +1,97 @@
local m = {}
local mt = {}
local mt_name = "flatbuffers.view.mt"
local N = require("flatbuffers.numTypes")
local binaryarray = require("flatbuffers.binaryarray")
function m.New(buf, pos)
N.UOffsetT:EnforceNumber(pos)
-- need to convert from a string buffer into
-- a binary array
local o = {
bytes = type(buf) == "string" and binaryarray.New(buf) or buf,
pos = pos
}
setmetatable(o, {__index = mt, __metatable = mt_name})
return o
end
function mt:Offset(vtableOffset)
local vtable = self.pos - self:Get(N.SOffsetT, self.pos)
local vtableEnd = self:Get(N.VOffsetT, vtable)
if vtableOffset < vtableEnd then
return self:Get(N.VOffsetT, vtable + vtableOffset)
end
return 0
end
function mt:Indirect(off)
N.UOffsetT:EnforceNumber(off)
return off + N.UOffsetT:Unpack(self.bytes, off)
end
function mt:String(off)
N.UOffsetT:EnforceNumber(off)
off = off + N.UOffsetT:Unpack(self.bytes, off)
local start = off + N.UOffsetT.bytewidth
local length = N.UOffsetT:Unpack(self.bytes, off)
return self.bytes:Slice(start, start+length)
end
function mt:VectorLen(off)
N.UOffsetT:EnforceNumber(off)
off = off + self.pos
off = off + N.UOffsetT:Unpack(self.bytes, off)
return N.UOffsetT:Unpack(self.bytes, off)
end
function mt:Vector(off)
N.UOffsetT:EnforceNumber(off)
off = off + self.pos
local x = off + self:Get(N.UOffsetT, off)
x = x + N.UOffsetT.bytewidth
return x
end
function mt:Union(t2, off)
assert(getmetatable(t2) == mt_name)
N.UOffsetT:EnforceNumber(off)
off = off + self.pos
t2.pos = off + self:Get(N.UOffsetT, off)
t2.bytes = self.bytes
end
function mt:Get(flags, off)
N.UOffsetT:EnforceNumber(off)
return flags:Unpack(self.bytes, off)
end
function mt:GetSlot(slot, d, validatorFlags)
N.VOffsetT:EnforceNumber(slot)
if validatorFlags then
validatorFlags:EnforceNumber(d)
end
local off = self:Offset(slot)
if off == 0 then
return d
end
return self:Get(validatorFlags, self.pos + off)
end
function mt:GetVOffsetTSlot(slot, d)
N.VOffsetT:EnforceNumber(slot)
N.VOffsetT:EnforceNumber(d)
local off = self:Offset(slot)
if off == 0 then
return d
end
return off
end
return m

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
// There are 2 #defines that have an impact on performance of this ByteBuffer implementation
// There are 3 #defines that have an impact on performance / features of this ByteBuffer implementation
//
// UNSAFE_BYTEBUFFER
// This will use unsafe code to manipulate the underlying byte array. This
@@ -24,26 +24,149 @@
// This will disable the bounds check asserts to the byte array. This can
// yield a small performance gain in normal code..
//
// ENABLE_SPAN_T
// This will enable reading and writing blocks of memory with a Span<T> instead if just
// T[]. You can also enable writing directly to shared memory or other types of memory
// by providing a custom implementation of ByteBufferAllocator.
// ENABLE_SPAN_T also requires UNSAFE_BYTEBUFFER to be defined
//
// Using UNSAFE_BYTEBUFFER and BYTEBUFFER_NO_BOUNDS_CHECK together can yield a
// performance gain of ~15% for some operations, however doing so is potentially
// dangerous. Do so at your own risk!
//
using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Text;
#if ENABLE_SPAN_T && !UNSAFE_BYTEBUFFER
#error ENABLE_SPAN_T requires UNSAFE_BYTEBUFFER to also be defined
#endif
namespace FlatBuffers
{
public abstract class ByteBufferAllocator : IDisposable
{
#if UNSAFE_BYTEBUFFER
public unsafe byte* Buffer
{
get;
protected set;
}
#else
public byte[] Buffer
{
get;
protected set;
}
#endif
public int Length
{
get;
protected set;
}
public abstract void Dispose();
public abstract void GrowFront(int newSize);
#if !ENABLE_SPAN_T
public abstract byte[] ByteArray { get; }
#endif
}
public class ByteArrayAllocator : ByteBufferAllocator
{
private byte[] _buffer;
public ByteArrayAllocator(byte[] buffer)
{
_buffer = buffer;
InitPointer();
}
public override void GrowFront(int newSize)
{
if ((Length & 0xC0000000) != 0)
throw new Exception(
"ByteBuffer: cannot grow buffer beyond 2 gigabytes.");
if (newSize < Length)
throw new Exception("ByteBuffer: cannot truncate buffer.");
byte[] newBuffer = new byte[newSize];
System.Buffer.BlockCopy(_buffer, 0, newBuffer, newSize - Length, Length);
_buffer = newBuffer;
InitPointer();
}
public override void Dispose()
{
GC.SuppressFinalize(this);
#if UNSAFE_BYTEBUFFER
if (_handle.IsAllocated)
{
_handle.Free();
}
#endif
}
#if !ENABLE_SPAN_T
public override byte[] ByteArray
{
get { return _buffer; }
}
#endif
#if UNSAFE_BYTEBUFFER
private GCHandle _handle;
~ByteArrayAllocator()
{
if (_handle.IsAllocated)
{
_handle.Free();
}
}
#endif
private void InitPointer()
{
Length = _buffer.Length;
#if UNSAFE_BYTEBUFFER
if (_handle.IsAllocated)
{
_handle.Free();
}
_handle = GCHandle.Alloc(_buffer, GCHandleType.Pinned);
unsafe
{
Buffer = (byte*)_handle.AddrOfPinnedObject().ToPointer();
}
#else
Buffer = _buffer;
#endif
}
}
/// <summary>
/// Class to mimic Java's ByteBuffer which is used heavily in Flatbuffers.
/// </summary>
public class ByteBuffer
public class ByteBuffer : IDisposable
{
protected byte[] _buffer;
private ByteBufferAllocator _buffer;
private int _pos; // Must track start of the buffer.
public int Length { get { return _buffer.Length; } }
public ByteBuffer(ByteBufferAllocator allocator, int position)
{
_buffer = allocator;
_pos = position;
}
public ByteBuffer(int size) : this(new byte[size]) { }
@@ -51,15 +174,25 @@ namespace FlatBuffers
public ByteBuffer(byte[] buffer, int pos)
{
_buffer = buffer;
_buffer = new ByteArrayAllocator(buffer);
_pos = pos;
}
public void Dispose()
{
if (_buffer != null)
{
_buffer.Dispose();
}
}
public int Position {
get { return _pos; }
set { _pos = value; }
}
public int Length { get { return _buffer.Length; } }
public void Reset()
{
_pos = 0;
@@ -76,45 +209,126 @@ namespace FlatBuffers
// the end of the new buffer.
public void GrowFront(int newSize)
{
if ((Length & 0xC0000000) != 0)
throw new Exception(
"ByteBuffer: cannot grow buffer beyond 2 gigabytes.");
if (newSize < Length)
throw new Exception("ByteBuffer: cannot truncate buffer.");
byte[] newBuffer = new byte[newSize];
Buffer.BlockCopy(_buffer, 0, newBuffer, newSize - Length,
Length);
_buffer = newBuffer;
_buffer.GrowFront(newSize);
}
public byte[] ToArray(int pos, int len)
{
byte[] arr = new byte[len];
Buffer.BlockCopy(_buffer, pos, arr, 0, len);
return ToArray<byte>(pos, len);
}
/// <summary>
/// A lookup of type sizes. Used instead of Marshal.SizeOf() which has additional
/// overhead, but also is compatible with generic functions for simplified code.
/// </summary>
private static Dictionary<Type, int> genericSizes = new Dictionary<Type, int>()
{
{ typeof(bool), sizeof(bool) },
{ typeof(float), sizeof(float) },
{ typeof(double), sizeof(double) },
{ typeof(sbyte), sizeof(sbyte) },
{ typeof(byte), sizeof(byte) },
{ typeof(short), sizeof(short) },
{ typeof(ushort), sizeof(ushort) },
{ typeof(int), sizeof(int) },
{ typeof(uint), sizeof(uint) },
{ typeof(ulong), sizeof(ulong) },
{ typeof(long), sizeof(long) },
};
/// <summary>
/// Get the wire-size (in bytes) of a type supported by flatbuffers.
/// </summary>
/// <param name="t">The type to get the wire size of</param>
/// <returns></returns>
public static int SizeOf<T>()
{
return genericSizes[typeof(T)];
}
/// <summary>
/// Checks if the Type provided is supported as scalar value
/// </summary>
/// <typeparam name="T">The Type to check</typeparam>
/// <returns>True if the type is a scalar type that is supported, falsed otherwise</returns>
public static bool IsSupportedType<T>()
{
return genericSizes.ContainsKey(typeof(T));
}
/// <summary>
/// Get the wire-size (in bytes) of an typed array
/// </summary>
/// <typeparam name="T">The type of the array</typeparam>
/// <param name="x">The array to get the size of</param>
/// <returns>The number of bytes the array takes on wire</returns>
public static int ArraySize<T>(T[] x)
{
return SizeOf<T>() * x.Length;
}
#if ENABLE_SPAN_T
public static int ArraySize<T>(Span<T> x)
{
return SizeOf<T>() * x.Length;
}
#endif
// Get a portion of the buffer casted into an array of type T, given
// the buffer position and length.
#if ENABLE_SPAN_T
public T[] ToArray<T>(int pos, int len)
where T: struct
{
unsafe
{
AssertOffsetAndLength(pos, len);
T[] arr = new T[len];
var typed = MemoryMarshal.Cast<byte, T>(new Span<byte>(_buffer.Buffer + pos, _buffer.Length));
typed.Slice(0, arr.Length).CopyTo(arr);
return arr;
}
}
#else
public T[] ToArray<T>(int pos, int len)
where T : struct
{
AssertOffsetAndLength(pos, len);
T[] arr = new T[len];
Buffer.BlockCopy(_buffer.ByteArray, pos, arr, 0, ArraySize(arr));
return arr;
}
#endif
public byte[] ToSizedArray()
{
return ToArray(Position, Length - Position);
return ToArray<byte>(Position, Length - Position);
}
public byte[] ToFullArray()
{
return ToArray(0, Length);
return ToArray<byte>(0, Length);
}
#if ENABLE_SPAN_T
public unsafe Span<byte> ToSpan(int pos, int len)
{
return new Span<byte>(_buffer.Buffer, _buffer.Length).Slice(pos, len);
}
#else
public ArraySegment<byte> ToArraySegment(int pos, int len)
{
return new ArraySegment<byte>(_buffer, pos, len);
return new ArraySegment<byte>(_buffer.ByteArray, pos, len);
}
#endif
#if !ENABLE_SPAN_T
public MemoryStream ToMemoryStream(int pos, int len)
{
return new MemoryStream(_buffer, pos, len);
return new MemoryStream(_buffer.ByteArray, pos, len);
}
#endif
#if !UNSAFE_BYTEBUFFER
// Pre-allocated helper arrays for convertion.
@@ -157,14 +371,14 @@ namespace FlatBuffers
{
for (int i = 0; i < count; i++)
{
_buffer[offset + i] = (byte)(data >> i * 8);
_buffer.Buffer[offset + i] = (byte)(data >> i * 8);
}
}
else
{
for (int i = 0; i < count; i++)
{
_buffer[offset + count - 1 - i] = (byte)(data >> i * 8);
_buffer.Buffer[offset + count - 1 - i] = (byte)(data >> i * 8);
}
}
}
@@ -177,14 +391,14 @@ namespace FlatBuffers
{
for (int i = 0; i < count; i++)
{
r |= (ulong)_buffer[offset + i] << i * 8;
r |= (ulong)_buffer.Buffer[offset + i] << i * 8;
}
}
else
{
for (int i = 0; i < count; i++)
{
r |= (ulong)_buffer[offset + count - 1 - i] << i * 8;
r |= (ulong)_buffer.Buffer[offset + count - 1 - i] << i * 8;
}
}
return r;
@@ -193,30 +407,32 @@ namespace FlatBuffers
private void AssertOffsetAndLength(int offset, int length)
{
#if !BYTEBUFFER_NO_BOUNDS_CHECK
#if !BYTEBUFFER_NO_BOUNDS_CHECK
if (offset < 0 ||
offset > _buffer.Length - length)
throw new ArgumentOutOfRangeException();
#endif
#endif
}
public void PutSbyte(int offset, sbyte value)
#if UNSAFE_BYTEBUFFER
public unsafe void PutSbyte(int offset, sbyte value)
{
AssertOffsetAndLength(offset, sizeof(sbyte));
_buffer[offset] = (byte)value;
_buffer.Buffer[offset] = (byte)value;
}
public void PutByte(int offset, byte value)
public unsafe void PutByte(int offset, byte value)
{
AssertOffsetAndLength(offset, sizeof(byte));
_buffer[offset] = value;
_buffer.Buffer[offset] = value;
}
public void PutByte(int offset, byte value, int count)
public unsafe void PutByte(int offset, byte value, int count)
{
AssertOffsetAndLength(offset, sizeof(byte) * count);
for (var i = 0; i < count; ++i)
_buffer[offset + i] = value;
_buffer.Buffer[offset + i] = value;
}
// this method exists in order to conform with Java ByteBuffer standards
@@ -224,13 +440,50 @@ namespace FlatBuffers
{
PutByte(offset, value);
}
#else
public void PutSbyte(int offset, sbyte value)
{
AssertOffsetAndLength(offset, sizeof(sbyte));
_buffer.Buffer[offset] = (byte)value;
}
public void PutByte(int offset, byte value)
{
AssertOffsetAndLength(offset, sizeof(byte));
_buffer.Buffer[offset] = value;
}
public void PutByte(int offset, byte value, int count)
{
AssertOffsetAndLength(offset, sizeof(byte) * count);
for (var i = 0; i < count; ++i)
_buffer.Buffer[offset + i] = value;
}
// this method exists in order to conform with Java ByteBuffer standards
public void Put(int offset, byte value)
{
PutByte(offset, value);
}
#endif
#if ENABLE_SPAN_T
public unsafe void PutStringUTF8(int offset, string value)
{
AssertOffsetAndLength(offset, value.Length);
fixed (char* s = value)
{
Encoding.UTF8.GetBytes(s, value.Length, _buffer.Buffer + offset, Length - offset);
}
}
#else
public void PutStringUTF8(int offset, string value)
{
AssertOffsetAndLength(offset, value.Length);
Encoding.UTF8.GetBytes(value, 0, value.Length,
_buffer, offset);
_buffer.ByteArray, offset);
}
#endif
#if UNSAFE_BYTEBUFFER
// Unsafe but more efficient versions of Put*.
@@ -242,12 +495,10 @@ namespace FlatBuffers
public unsafe void PutUshort(int offset, ushort value)
{
AssertOffsetAndLength(offset, sizeof(ushort));
fixed (byte* ptr = _buffer)
{
*(ushort*)(ptr + offset) = BitConverter.IsLittleEndian
? value
: ReverseBytes(value);
}
byte* ptr = _buffer.Buffer;
*(ushort*)(ptr + offset) = BitConverter.IsLittleEndian
? value
: ReverseBytes(value);
}
public void PutInt(int offset, int value)
@@ -258,12 +509,10 @@ namespace FlatBuffers
public unsafe void PutUint(int offset, uint value)
{
AssertOffsetAndLength(offset, sizeof(uint));
fixed (byte* ptr = _buffer)
{
*(uint*)(ptr + offset) = BitConverter.IsLittleEndian
? value
: ReverseBytes(value);
}
byte* ptr = _buffer.Buffer;
*(uint*)(ptr + offset) = BitConverter.IsLittleEndian
? value
: ReverseBytes(value);
}
public unsafe void PutLong(int offset, long value)
@@ -274,44 +523,38 @@ namespace FlatBuffers
public unsafe void PutUlong(int offset, ulong value)
{
AssertOffsetAndLength(offset, sizeof(ulong));
fixed (byte* ptr = _buffer)
{
*(ulong*)(ptr + offset) = BitConverter.IsLittleEndian
? value
: ReverseBytes(value);
}
byte* ptr = _buffer.Buffer;
*(ulong*)(ptr + offset) = BitConverter.IsLittleEndian
? value
: ReverseBytes(value);
}
public unsafe void PutFloat(int offset, float value)
{
AssertOffsetAndLength(offset, sizeof(float));
fixed (byte* ptr = _buffer)
byte* ptr = _buffer.Buffer;
if (BitConverter.IsLittleEndian)
{
if (BitConverter.IsLittleEndian)
{
*(float*)(ptr + offset) = value;
}
else
{
*(uint*)(ptr + offset) = ReverseBytes(*(uint*)(&value));
}
*(float*)(ptr + offset) = value;
}
else
{
*(uint*)(ptr + offset) = ReverseBytes(*(uint*)(&value));
}
}
public unsafe void PutDouble(int offset, double value)
{
AssertOffsetAndLength(offset, sizeof(double));
fixed (byte* ptr = _buffer)
byte* ptr = _buffer.Buffer;
if (BitConverter.IsLittleEndian)
{
if (BitConverter.IsLittleEndian)
{
*(double*)(ptr + offset) = value;
*(double*)(ptr + offset) = value;
}
else
{
*(ulong*)(ptr + offset) = ReverseBytes(*(ulong*)(ptr + offset));
}
}
else
{
*(ulong*)(ptr + offset) = ReverseBytes(*(ulong*)(ptr + offset));
}
}
#else // !UNSAFE_BYTEBUFFER
@@ -370,22 +613,43 @@ namespace FlatBuffers
#endif // UNSAFE_BYTEBUFFER
#if UNSAFE_BYTEBUFFER
public unsafe sbyte GetSbyte(int index)
{
AssertOffsetAndLength(index, sizeof(sbyte));
return (sbyte)_buffer.Buffer[index];
}
public unsafe byte Get(int index)
{
AssertOffsetAndLength(index, sizeof(byte));
return _buffer.Buffer[index];
}
#else
public sbyte GetSbyte(int index)
{
AssertOffsetAndLength(index, sizeof(sbyte));
return (sbyte)_buffer[index];
return (sbyte)_buffer.Buffer[index];
}
public byte Get(int index)
{
AssertOffsetAndLength(index, sizeof(byte));
return _buffer[index];
return _buffer.Buffer[index];
}
#endif
#if ENABLE_SPAN_T
public unsafe string GetStringUTF8(int startPos, int len)
{
return Encoding.UTF8.GetString(_buffer.Buffer + startPos, len);
}
#else
public string GetStringUTF8(int startPos, int len)
{
return Encoding.UTF8.GetString(_buffer, startPos, len);
return Encoding.UTF8.GetString(_buffer.ByteArray, startPos, len);
}
#endif
#if UNSAFE_BYTEBUFFER
// Unsafe but more efficient versions of Get*.
@@ -397,7 +661,7 @@ namespace FlatBuffers
public unsafe ushort GetUshort(int offset)
{
AssertOffsetAndLength(offset, sizeof(ushort));
fixed (byte* ptr = _buffer)
byte* ptr = _buffer.Buffer;
{
return BitConverter.IsLittleEndian
? *(ushort*)(ptr + offset)
@@ -413,7 +677,7 @@ namespace FlatBuffers
public unsafe uint GetUint(int offset)
{
AssertOffsetAndLength(offset, sizeof(uint));
fixed (byte* ptr = _buffer)
byte* ptr = _buffer.Buffer;
{
return BitConverter.IsLittleEndian
? *(uint*)(ptr + offset)
@@ -429,7 +693,7 @@ namespace FlatBuffers
public unsafe ulong GetUlong(int offset)
{
AssertOffsetAndLength(offset, sizeof(ulong));
fixed (byte* ptr = _buffer)
byte* ptr = _buffer.Buffer;
{
return BitConverter.IsLittleEndian
? *(ulong*)(ptr + offset)
@@ -440,7 +704,7 @@ namespace FlatBuffers
public unsafe float GetFloat(int offset)
{
AssertOffsetAndLength(offset, sizeof(float));
fixed (byte* ptr = _buffer)
byte* ptr = _buffer.Buffer;
{
if (BitConverter.IsLittleEndian)
{
@@ -457,7 +721,7 @@ namespace FlatBuffers
public unsafe double GetDouble(int offset)
{
AssertOffsetAndLength(offset, sizeof(double));
fixed (byte* ptr = _buffer)
byte* ptr = _buffer.Buffer;
{
if (BitConverter.IsLittleEndian)
{
@@ -519,5 +783,98 @@ namespace FlatBuffers
return doublehelper[0];
}
#endif // UNSAFE_BYTEBUFFER
/// <summary>
/// Copies an array of type T into this buffer, ending at the given
/// offset into this buffer. The starting offset is calculated based on the length
/// of the array and is the value returned.
/// </summary>
/// <typeparam name="T">The type of the input data (must be a struct)</typeparam>
/// <param name="offset">The offset into this buffer where the copy will end</param>
/// <param name="x">The array to copy data from</param>
/// <returns>The 'start' location of this buffer now, after the copy completed</returns>
public int Put<T>(int offset, T[] x)
where T : struct
{
if (x == null)
{
throw new ArgumentNullException("Cannot put a null array");
}
if (x.Length == 0)
{
throw new ArgumentException("Cannot put an empty array");
}
if (!IsSupportedType<T>())
{
throw new ArgumentException("Cannot put an array of type "
+ typeof(T) + " into this buffer");
}
if (BitConverter.IsLittleEndian)
{
int numBytes = ByteBuffer.ArraySize(x);
offset -= numBytes;
AssertOffsetAndLength(offset, numBytes);
// if we are LE, just do a block copy
#if ENABLE_SPAN_T
unsafe
{
MemoryMarshal.Cast<T, byte>(x).CopyTo(new Span<byte>(_buffer.Buffer, _buffer.Length).Slice(offset, numBytes));
}
#else
Buffer.BlockCopy(x, 0, _buffer.ByteArray, offset, numBytes);
#endif
}
else
{
throw new NotImplementedException("Big Endian Support not implemented yet " +
"for putting typed arrays");
// if we are BE, we have to swap each element by itself
//for(int i = x.Length - 1; i >= 0; i--)
//{
// todo: low priority, but need to genericize the Put<T>() functions
//}
}
return offset;
}
#if ENABLE_SPAN_T
public unsafe int Put<T>(int offset, Span<T> x)
where T : struct
{
if (x.Length == 0)
{
throw new ArgumentException("Cannot put an empty array");
}
if (!IsSupportedType<T>())
{
throw new ArgumentException("Cannot put an array of type "
+ typeof(T) + " into this buffer");
}
if (BitConverter.IsLittleEndian)
{
int numBytes = ByteBuffer.ArraySize(x);
offset -= numBytes;
AssertOffsetAndLength(offset, numBytes);
// if we are LE, just do a block copy
MemoryMarshal.Cast<T, byte>(x).CopyTo(new Span<byte>(_buffer.Buffer, _buffer.Length).Slice(offset, numBytes));
}
else
{
throw new NotImplementedException("Big Endian Support not implemented yet " +
"for putting typed arrays");
// if we are BE, we have to swap each element by itself
//for(int i = x.Length - 1; i >= 0; i--)
//{
// todo: low priority, but need to genericize the Put<T>() functions
//}
}
return offset;
}
#endif
}
}

Binary file not shown.

View File

@@ -62,6 +62,17 @@ namespace FlatBuffers
_bb = new ByteBuffer(initialSize);
}
/// <summary>
/// Create a FlatBufferBuilder backed by the pased in ByteBuffer
/// </summary>
/// <param name="buffer">The ByteBuffer to write to</param>
public FlatBufferBuilder(ByteBuffer buffer)
{
_bb = buffer;
_space = buffer.Length;
buffer.Reset();
}
/// <summary>
/// Reset the FlatBufferBuilder by purging all data that it holds.
/// </summary>
@@ -179,6 +190,32 @@ namespace FlatBuffers
_bb.PutFloat(_space -= sizeof(float), x);
}
/// <summary>
/// Puts an array of type T into this builder at the
/// current offset
/// </summary>
/// <typeparam name="T">The type of the input data </typeparam>
/// <param name="x">The array to copy data from</param>
public void Put<T>(T[] x)
where T : struct
{
_space = _bb.Put(_space, x);
}
#if ENABLE_SPAN_T
/// <summary>
/// Puts a span of type T into this builder at the
/// current offset
/// </summary>
/// <typeparam name="T">The type of the input data </typeparam>
/// <param name="x">The span to copy data from</param>
public void Put<T>(Span<T> x)
where T : struct
{
_space = _bb.Put(_space, x);
}
#endif
public void PutDouble(double x)
{
_bb.PutDouble(_space -= sizeof(double), x);
@@ -245,6 +282,59 @@ namespace FlatBuffers
/// <param name="x">The `float` to add to the buffer.</param>
public void AddFloat(float x) { Prep(sizeof(float), 0); PutFloat(x); }
/// <summary>
/// Add an array of type T to the buffer (aligns the data and grows if necessary).
/// </summary>
/// <typeparam name="T">The type of the input data</typeparam>
/// <param name="x">The array to copy data from</param>
public void Add<T>(T[] x)
where T : struct
{
if (x == null)
{
throw new ArgumentNullException("Cannot add a null array");
}
if( x.Length == 0)
{
// don't do anything if the array is empty
return;
}
if(!ByteBuffer.IsSupportedType<T>())
{
throw new ArgumentException("Cannot add this Type array to the builder");
}
int size = ByteBuffer.SizeOf<T>();
// Need to prep on size (for data alignment) and then we pass the
// rest of the length (minus 1) as additional bytes
Prep(size, size * (x.Length - 1));
Put(x);
}
#if ENABLE_SPAN_T
/// <summary>
/// Add a span of type T to the buffer (aligns the data and grows if necessary).
/// </summary>
/// <typeparam name="T">The type of the input data</typeparam>
/// <param name="x">The span to copy data from</param>
public void Add<T>(Span<T> x)
where T : struct
{
if (!ByteBuffer.IsSupportedType<T>())
{
throw new ArgumentException("Cannot add this Type array to the builder");
}
int size = ByteBuffer.SizeOf<T>();
// Need to prep on size (for data alignment) and then we pass the
// rest of the length (minus 1) as additional bytes
Prep(size, size * (x.Length - 1));
Put(x);
}
#endif
/// <summary>
/// Add a `double` to the buffer (aligns the data and grows if necessary).
/// </summary>
@@ -468,6 +558,27 @@ namespace FlatBuffers
return new StringOffset(EndVector().Value);
}
#if ENABLE_SPAN_T
/// <summary>
/// Creates a string in the buffer from a Span containing
/// a UTF8 string.
/// </summary>
/// <param name="chars">the UTF8 string to add to the buffer</param>
/// <returns>
/// The offset in the buffer where the encoded string starts.
/// </returns>
public StringOffset CreateUTF8String(Span<byte> chars)
{
NotNested();
AddByte(0);
var utf8StringLen = chars.Length;
StartVector(1, utf8StringLen, 1);
_space = _bb.Put(_space, chars);
return new StringOffset(EndVector().Value);
}
#endif
/// @cond FLATBUFFERS_INTERNAL
// Structs are stored inline, so nothing additional is being added.
// `d` is always 0.
@@ -525,7 +636,7 @@ namespace FlatBuffers
break;
}
endLoop: { }
endLoop: { }
}
if (existingVtable != 0) {

View File

@@ -1,54 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{28C00774-1E73-4A75-AD8F-844CD21A064D}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<TargetFrameworks>netstandard1.1;netstandard1.4;netstandard2.0</TargetFrameworks>
<RootNamespace>FlatBuffers</RootNamespace>
<AssemblyName>FlatBuffers</AssemblyName>
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<AssemblyVersion>1.0.0.0</AssemblyVersion>
<Copyright>Copyright (c) 2015 Google Inc</Copyright>
<RepositoryUrl>https://github.com/google/flatbuffers</RepositoryUrl>
<PackageLicenseUrl>https://github.com/google/flatbuffers/blob/master/LICENSE.txt</PackageLicenseUrl>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
<PackageReference Include="System.Memory" Version="4.5.1" />
</ItemGroup>
<ItemGroup>
<Compile Include="ByteBuffer.cs" />
<Compile Include="FlatBufferBuilder.cs" />
<Compile Include="FlatBufferConstants.cs" />
<Compile Include="IFlatbufferObject.cs" />
<Compile Include="Offset.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Struct.cs" />
<Compile Include="Table.cs" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

View File

@@ -1,52 +0,0 @@
/*
* 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.
*/
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("FlatBuffers")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("FlatBuffers")]
[assembly: AssemblyCopyright("Copyright (c) 2015 Google Inc")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("91c32e64-ef20-47df-9c9f-cec9207bc6df")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

View File

@@ -78,6 +78,23 @@ namespace FlatBuffers
return offset + bb.GetInt(offset) + sizeof(int); // data starts after the length
}
#if ENABLE_SPAN_T
// Get the data of a vector whoses offset is stored at "offset" in this object as an
// Spant&lt;byte&gt;. If the vector is not present in the ByteBuffer,
// then an empty span will be returned.
public Span<byte> __vector_as_span(int offset)
{
var o = this.__offset(offset);
if (0 == o)
{
return new Span<byte>();
}
var pos = this.__vector(o);
var len = this.__vector_len(o);
return bb.ToSpan(pos, len);
}
#else
// Get the data of a vector whoses offset is stored at "offset" in this object as an
// ArraySegment&lt;byte&gt;. If the vector is not present in the ByteBuffer,
// then a null value will be returned.
@@ -93,6 +110,30 @@ namespace FlatBuffers
var len = this.__vector_len(o);
return bb.ToArraySegment(pos, len);
}
#endif
// Get the data of a vector whoses offset is stored at "offset" in this object as an
// T[]. If the vector is not present in the ByteBuffer, then a null value will be
// returned.
public T[] __vector_as_array<T>(int offset)
where T : struct
{
if(!BitConverter.IsLittleEndian)
{
throw new NotSupportedException("Getting typed arrays on a Big Endian " +
"system is not support");
}
var o = this.__offset(offset);
if (0 == o)
{
return null;
}
var pos = this.__vector(o);
var len = this.__vector_len(o);
return bb.ToArray<T>(pos, len);
}
// Initialize any Table-derived type to point to the union at the given offset.
public T __union<T>(int offset) where T : struct, IFlatbufferObject

View File

@@ -1,6 +1,6 @@
{
"name": "flatbuffers",
"version": "1.9.0",
"version": "1.10.0",
"description": "Memory Efficient Serialization Library",
"files": ["js/flatbuffers.js", "js/flatbuffers.mjs"],
"main": "js/flatbuffers",

View File

@@ -5,7 +5,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>com.google.flatbuffers</groupId>
<artifactId>flatbuffers-java</artifactId>
<version>1.9.0</version>
<version>1.10.0</version>
<packaging>bundle</packaging>
<name>FlatBuffers Java API</name>
<description>
@@ -47,8 +47,8 @@
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.6</source>
<target>1.6</target>
<source>1.8</source>
<target>1.8</target>
</configuration>
<version>3.2</version>
</plugin>

View File

@@ -160,7 +160,6 @@ class Builder(object):
# 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
self.nested = True
def WriteVtable(self):

2
python/setup.cfg Normal file
View File

@@ -0,0 +1,2 @@
[bdist_wheel]
universal=1

View File

@@ -4,29 +4,34 @@
[![Join the chat at https://gitter.im/google/flatbuffers](https://badges.gitter.im/google/flatbuffers.svg)](https://gitter.im/google/flatbuffers?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
[![Build Status](https://travis-ci.org/google/flatbuffers.svg?branch=master)](https://travis-ci.org/google/flatbuffers) [![Build status](https://ci.appveyor.com/api/projects/status/yg5idd2fnusv1n10?svg=true)](https://ci.appveyor.com/project/gwvo/flatbuffers)
**FlatBuffers** is an efficient cross platform serialization library for games and
other memory constrained apps. It allows you to directly access serialized data without
unpacking/parsing it first, while still having great forwards/backwards compatibility.
**FlatBuffers** is a cross platform serialization library architected for
maximum memory efficiency. It allows you to directly access serialized data without parsing/unpacking it first, while still having great forwards/backwards compatibility.
**Go to our [landing page][] to browse our documentation.**
## Supported operating systems
* Android
* Windows
* MacOS X
* Linux
* Android
* And any others with a recent C++ compiler.
## Supported programming languages
* C++
* C#
* C
* Dart
* Go
* Java
* JavaScript
* Lobster
* Lua
* PHP
* Python
* Rust
* TypeScript
*and many more in progress...*
*and more in progress...*
## Contribution
* [FlatBuffers Google Group][] to discuss FlatBuffers with other developers and users.
@@ -35,16 +40,6 @@ unpacking/parsing it first, while still having great forwards/backwards compatib
*To contribute to this project,* see [CONTRIBUTING][].
## Integration
For applications on Google Play that integrate this tool, usage is tracked.
This tracking is done automatically using the embedded version string
(**`flatbuffer_version_string`**), and helps us continue to optimize it. Aside from
consuming a few extra bytes in your application binary, it shouldn't affect
your application at all. We use this information to let us know if FlatBuffers
is useful and if we should continue to invest in it. Since this is open
source, you are free to remove the version string but we would appreciate if
you would leave it in.
## Licensing
*Flatbuffers* is licensed under the Apache License, Version 2.0. See [LICENSE][] for the full license text.
@@ -55,5 +50,5 @@ you would leave it in.
[FlatBuffers Google Group]: https://groups.google.com/forum/#!forum/flatbuffers
[FlatBuffers Issues Tracker]: http://github.com/google/flatbuffers/issues
[stackoverflow.com]: http://stackoverflow.com/search?q=flatbuffers
[landing page]: http://google.github.io/flatbuffers
[landing page]: https://google.github.io/flatbuffers
[LICENSE]: https://github.com/google/flatbuffers/blob/master/LICENSE.txt

0
reflection/generate_code.sh Normal file → Executable file
View File

View File

@@ -44,6 +44,7 @@ table EnumVal {
value:long (key);
object:Object; // Will be deprecated in favor of union_type in the future.
union_type:Type;
documentation:[string];
}
table Enum {
@@ -79,12 +80,28 @@ table Object { // Used for both tables and structs.
documentation:[string];
}
table RPCCall {
name:string (required, key);
request:Object (required); // must be a table (not a struct)
response:Object (required); // must be a table (not a struct)
attributes:[KeyValue];
documentation:[string];
}
table Service {
name:string (required, key);
calls:[RPCCall];
attributes:[KeyValue];
documentation:[string];
}
table Schema {
objects:[Object] (required); // Sorted.
enums:[Enum] (required); // Sorted.
objects:[Object] (required); // Sorted.
enums:[Enum] (required); // Sorted.
file_ident:string;
file_ext:string;
root_table:Object;
services:[Service]; // Sorted.
}
root_type Schema;

View File

@@ -0,0 +1,13 @@
[package]
name = "flatbuffers"
version = "0.5.0"
authors = ["Robert Winslow <hello@rwinslow.com>", "FlatBuffers Maintainers"]
license = "Apache-2.0"
description = "Official FlatBuffers Rust runtime library."
homepage = "https://google.github.io/flatbuffers/"
repository = "https://github.com/google/flatbuffers"
keywords = ["flatbuffers", "serialization", "zero-copy"]
categories = ["encoding", "data-structures", "memory-management"]
[dependencies]
smallvec = "0.6"

View File

@@ -0,0 +1,636 @@
/*
* Copyright 2018 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.
*/
extern crate smallvec;
use std::cmp::max;
use std::marker::PhantomData;
use std::ptr::write_bytes;
use std::slice::from_raw_parts;
use endian_scalar::{read_scalar, emplace_scalar};
use primitives::*;
use push::{Push, PushAlignment};
use table::Table;
use vtable::{VTable, field_index_to_field_offset};
use vtable_writer::VTableWriter;
use vector::{SafeSliceAccess, Vector};
#[derive(Clone, Copy, Debug)]
struct FieldLoc {
off: UOffsetT,
id: VOffsetT,
}
/// FlatBufferBuilder builds a FlatBuffer through manipulating its internal
/// state. It has an owned `Vec<u8>` that grows as needed (up to the hardcoded
/// limit of 2GiB, which is set by the FlatBuffers format).
pub struct FlatBufferBuilder<'fbb> {
owned_buf: Vec<u8>,
head: usize,
field_locs: Vec<FieldLoc>,
written_vtable_revpos: Vec<UOffsetT>,
nested: bool,
finished: bool,
min_align: usize,
_phantom: PhantomData<&'fbb ()>,
}
impl<'fbb> FlatBufferBuilder<'fbb> {
/// Create a FlatBufferBuilder that is ready for writing.
pub fn new() -> Self {
Self::new_with_capacity(0)
}
/// Create a FlatBufferBuilder that is ready for writing, with a
/// ready-to-use capacity of the provided size.
///
/// The maximum valid value is `FLATBUFFERS_MAX_BUFFER_SIZE`.
pub fn new_with_capacity(size: usize) -> Self {
// we need to check the size here because we create the backing buffer
// directly, bypassing the typical way of using grow_owned_buf:
assert!(size <= FLATBUFFERS_MAX_BUFFER_SIZE,
"cannot initialize buffer bigger than 2 gigabytes");
FlatBufferBuilder {
owned_buf: vec![0u8; size],
head: size,
field_locs: Vec::new(),
written_vtable_revpos: Vec::new(),
nested: false,
finished: false,
min_align: 0,
_phantom: PhantomData,
}
}
/// Reset the FlatBufferBuilder internal state. Use this method after a
/// call to a `finish` function in order to re-use a FlatBufferBuilder.
///
/// This function is the only way to reset the `finished` state and start
/// again.
///
/// If you are using a FlatBufferBuilder repeatedly, make sure to use this
/// function, because it re-uses the FlatBufferBuilder's existing
/// heap-allocated `Vec<u8>` internal buffer. This offers significant speed
/// improvements as compared to creating a new FlatBufferBuilder for every
/// new object.
pub fn reset(&mut self) {
// memset only the part of the buffer that could be dirty:
{
let to_clear = self.owned_buf.len() - self.head;
let ptr = (&mut self.owned_buf[self.head..]).as_mut_ptr();
unsafe { write_bytes(ptr, 0, to_clear); }
}
self.head = self.owned_buf.len();
self.written_vtable_revpos.clear();
self.nested = false;
self.finished = false;
self.min_align = 0;
}
/// Destroy the FlatBufferBuilder, returning its internal byte vector
/// and the index into it that represents the start of valid data.
pub fn collapse(self) -> (Vec<u8>, usize) {
(self.owned_buf, self.head)
}
/// Push a Push'able value onto the front of the in-progress data.
///
/// This function uses traits to provide a unified API for writing
/// scalars, tables, vectors, and WIPOffsets.
#[inline]
pub fn push<P: Push>(&mut self, x: P) -> WIPOffset<P::Output> {
let sz = P::size();
self.align(sz, P::alignment());
self.make_space(sz);
{
let (dst, rest) = (&mut self.owned_buf[self.head..]).split_at_mut(sz);
x.push(dst, rest);
}
WIPOffset::new(self.used_space() as UOffsetT)
}
/// Push a Push'able value onto the front of the in-progress data, and
/// store a reference to it in the in-progress vtable. If the value matches
/// the default, then this is a no-op.
#[inline]
pub fn push_slot<X: Push + PartialEq>(&mut self, slotoff: VOffsetT, x: X, default: X) {
self.assert_nested("push_slot");
if x == default {
return;
}
self.push_slot_always(slotoff, x);
}
/// Push a Push'able value onto the front of the in-progress data, and
/// store a reference to it in the in-progress vtable.
#[inline]
pub fn push_slot_always<X: Push>(&mut self, slotoff: VOffsetT, x: X) {
self.assert_nested("push_slot_always");
let off = self.push(x);
self.track_field(slotoff, off.value());
}
/// Retrieve the number of vtables that have been serialized into the
/// FlatBuffer. This is primarily used to check vtable deduplication.
#[inline]
pub fn num_written_vtables(&self) -> usize {
self.written_vtable_revpos.len()
}
/// Start a Table write.
///
/// Asserts that the builder is not in a nested state.
///
/// Users probably want to use `push_slot` to add values after calling this.
#[inline]
pub fn start_table(&mut self) -> WIPOffset<TableUnfinishedWIPOffset> {
self.assert_not_nested("start_table can not be called when a table or vector is under construction");
self.nested = true;
WIPOffset::new(self.used_space() as UOffsetT)
}
/// End a Table write.
///
/// Asserts that the builder is in a nested state.
#[inline]
pub fn end_table(&mut self, off: WIPOffset<TableUnfinishedWIPOffset>) -> WIPOffset<TableFinishedWIPOffset> {
self.assert_nested("end_table");
let o = self.write_vtable(off);
self.nested = false;
self.field_locs.clear();
WIPOffset::new(o.value())
}
/// Start a Vector write.
///
/// Asserts that the builder is not in a nested state.
///
/// Most users will prefer to call `create_vector`.
/// Speed optimizing users who choose to create vectors manually using this
/// function will want to use `push` to add values.
#[inline]
pub fn start_vector<T: Push>(&mut self, num_items: usize) {
self.assert_not_nested("start_vector can not be called when a table or vector is under construction");
self.nested = true;
self.align(num_items * T::size(), T::alignment().max_of(SIZE_UOFFSET));
}
/// End a Vector write.
///
/// Note that the `num_elems` parameter is the number of written items, not
/// the byte count.
///
/// Asserts that the builder is in a nested state.
#[inline]
pub fn end_vector<T: Push>(&mut self, num_elems: usize) -> WIPOffset<Vector<'fbb, T>> {
self.assert_nested("end_vector");
self.nested = false;
let o = self.push::<UOffsetT>(num_elems as UOffsetT);
WIPOffset::new(o.value())
}
/// Create a utf8 string.
///
/// The wire format represents this as a zero-terminated byte vector.
#[inline]
pub fn create_string<'a: 'b, 'b>(&'a mut self, s: &'b str) -> WIPOffset<&'fbb str> {
self.assert_not_nested("create_string can not be called when a table or vector is under construction");
WIPOffset::new(self.create_byte_string(s.as_bytes()).value())
}
/// Create a zero-terminated byte vector.
#[inline]
pub fn create_byte_string(&mut self, data: &[u8]) -> WIPOffset<&'fbb [u8]> {
self.assert_not_nested("create_byte_string can not be called when a table or vector is under construction");
self.align(data.len() + 1, PushAlignment::new(SIZE_UOFFSET));
self.push(0u8);
self.push_bytes_unprefixed(data);
self.push(data.len() as UOffsetT);
WIPOffset::new(self.used_space() as UOffsetT)
}
/// Create a vector by memcpy'ing. This is much faster than calling
/// `create_vector`, but the underlying type must be represented as
/// little-endian on the host machine. This property is encoded in the
/// type system through the SafeSliceAccess trait. The following types are
/// always safe, on any platform: bool, u8, i8, and any
/// FlatBuffers-generated struct.
#[inline]
pub fn create_vector_direct<'a: 'b, 'b, T: SafeSliceAccess + Push + Sized + 'b>(&'a mut self, items: &'b [T]) -> WIPOffset<Vector<'fbb, T>> {
self.assert_not_nested("create_vector_direct can not be called when a table or vector is under construction");
let elem_size = T::size();
self.align(items.len() * elem_size, T::alignment().max_of(SIZE_UOFFSET));
let bytes = {
let ptr = items.as_ptr() as *const T as *const u8;
unsafe { from_raw_parts(ptr, items.len() * elem_size) }
};
self.push_bytes_unprefixed(bytes);
self.push(items.len() as UOffsetT);
WIPOffset::new(self.used_space() as UOffsetT)
}
/// Create a vector of strings.
///
/// Speed-sensitive users may wish to reduce memory usage by creating the
/// vector manually: use `start_vector`, `push`, and `end_vector`.
#[inline]
pub fn create_vector_of_strings<'a, 'b>(&'a mut self, xs: &'b [&'b str]) -> WIPOffset<Vector<'fbb, ForwardsUOffset<&'fbb str>>> {
self.assert_not_nested("create_vector_of_strings can not be called when a table or vector is under construction");
// internally, smallvec can be a stack-allocated or heap-allocated vector.
// we expect it to usually be stack-allocated.
let mut offsets: smallvec::SmallVec<[WIPOffset<&str>; 0]> = smallvec::SmallVec::with_capacity(xs.len());
unsafe { offsets.set_len(xs.len()); }
for (i, &s) in xs.iter().enumerate().rev() {
let o = self.create_string(s);
offsets[i] = o;
}
self.create_vector(&offsets[..])
}
/// Create a vector of Push-able objects.
///
/// Speed-sensitive users may wish to reduce memory usage by creating the
/// vector manually: use `start_vector`, `push`, and `end_vector`.
#[inline]
pub fn create_vector<'a: 'b, 'b, T: Push + Copy + 'b>(&'a mut self, items: &'b [T]) -> WIPOffset<Vector<'fbb, T::Output>> {
let elem_size = T::size();
self.align(items.len() * elem_size, T::alignment().max_of(SIZE_UOFFSET));
for i in (0..items.len()).rev() {
self.push(items[i]);
}
WIPOffset::new(self.push::<UOffsetT>(items.len() as UOffsetT).value())
}
/// Get the byte slice for the data that has been written, regardless of
/// whether it has been finished.
#[inline]
pub fn unfinished_data(&self) -> &[u8] {
&self.owned_buf[self.head..]
}
/// Get the byte slice for the data that has been written after a call to
/// one of the `finish` functions.
#[inline]
pub fn finished_data(&self) -> &[u8] {
self.assert_finished("finished_bytes cannot be called when the buffer is not yet finished");
&self.owned_buf[self.head..]
}
/// Assert that a field is present in the just-finished Table.
///
/// This is somewhat low-level and is mostly used by the generated code.
#[inline]
pub fn required(&self,
tab_revloc: WIPOffset<TableFinishedWIPOffset>,
slot_byte_loc: VOffsetT,
assert_msg_name: &'static str) {
let idx = self.used_space() - tab_revloc.value() as usize;
let tab = Table::new(&self.owned_buf[self.head..], idx);
let o = tab.vtable().get(slot_byte_loc) as usize;
assert!(o != 0, "missing required field {}", assert_msg_name);
}
/// Finalize the FlatBuffer by: aligning it, pushing an optional file
/// identifier on to it, pushing a size prefix on to it, and marking the
/// internal state of the FlatBufferBuilder as `finished`. Afterwards,
/// users can call `finished_data` to get the resulting data.
#[inline]
pub fn finish_size_prefixed<T>(&mut self, root: WIPOffset<T>, file_identifier: Option<&str>) {
self.finish_with_opts(root, file_identifier, true);
}
/// Finalize the FlatBuffer by: aligning it, pushing an optional file
/// identifier on to it, and marking the internal state of the
/// FlatBufferBuilder as `finished`. Afterwards, users can call
/// `finished_data` to get the resulting data.
#[inline]
pub fn finish<T>(&mut self, root: WIPOffset<T>, file_identifier: Option<&str>) {
self.finish_with_opts(root, file_identifier, false);
}
/// Finalize the FlatBuffer by: aligning it and marking the internal state
/// of the FlatBufferBuilder as `finished`. Afterwards, users can call
/// `finished_data` to get the resulting data.
#[inline]
pub fn finish_minimal<T>(&mut self, root: WIPOffset<T>) {
self.finish_with_opts(root, None, false);
}
#[inline]
fn used_space(&self) -> usize {
self.owned_buf.len() - self.head as usize
}
#[inline]
fn track_field(&mut self, slot_off: VOffsetT, off: UOffsetT) {
let fl = FieldLoc {
id: slot_off,
off: off,
};
self.field_locs.push(fl);
}
/// Write the VTable, if it is new.
fn write_vtable(&mut self, table_tail_revloc: WIPOffset<TableUnfinishedWIPOffset>) -> WIPOffset<VTableWIPOffset> {
self.assert_nested("write_vtable");
// Write the vtable offset, which is the start of any Table.
// We fill its value later.
let object_revloc_to_vtable: WIPOffset<VTableWIPOffset> =
WIPOffset::new(self.push::<UOffsetT>(0xF0F0F0F0 as UOffsetT).value());
// Layout of the data this function will create when a new vtable is
// needed.
// --------------------------------------------------------------------
// vtable starts here
// | x, x -- vtable len (bytes) [u16]
// | x, x -- object inline len (bytes) [u16]
// | x, x -- zero, or num bytes from start of object to field #0 [u16]
// | ...
// | x, x -- zero, or num bytes from start of object to field #n-1 [u16]
// vtable ends here
// table starts here
// | x, x, x, x -- offset (negative direction) to the vtable [i32]
// | aka "vtableoffset"
// | -- table inline data begins here, we don't touch it --
// table ends here -- aka "table_start"
// --------------------------------------------------------------------
//
// Layout of the data this function will create when we re-use an
// existing vtable.
//
// We always serialize this particular vtable, then compare it to the
// other vtables we know about to see if there is a duplicate. If there
// is, then we erase the serialized vtable we just made.
// We serialize it first so that we are able to do byte-by-byte
// comparisons with already-serialized vtables. This 1) saves
// bookkeeping space (we only keep revlocs to existing vtables), 2)
// allows us to convert to little-endian once, then do
// fast memcmp comparisons, and 3) by ensuring we are comparing real
// serialized vtables, we can be more assured that we are doing the
// comparisons correctly.
//
// --------------------------------------------------------------------
// table starts here
// | x, x, x, x -- offset (negative direction) to an existing vtable [i32]
// | aka "vtableoffset"
// | -- table inline data begins here, we don't touch it --
// table starts here: aka "table_start"
// --------------------------------------------------------------------
// fill the WIP vtable with zeros:
let vtable_byte_len = get_vtable_byte_len(&self.field_locs);
self.make_space(vtable_byte_len);
// compute the length of the table (not vtable!) in bytes:
let table_object_size = object_revloc_to_vtable.value() - table_tail_revloc.value();
debug_assert!(table_object_size < 0x10000); // vTable use 16bit offsets.
// Write the VTable (we may delete it afterwards, if it is a duplicate):
let vt_start_pos = self.head;
let vt_end_pos = self.head + vtable_byte_len;
{
// write the vtable header:
let vtfw = &mut VTableWriter::init(&mut self.owned_buf[vt_start_pos..vt_end_pos]);
vtfw.write_vtable_byte_length(vtable_byte_len as VOffsetT);
vtfw.write_object_inline_size(table_object_size as VOffsetT);
// serialize every FieldLoc to the vtable:
for &fl in self.field_locs.iter() {
let pos: VOffsetT = (object_revloc_to_vtable.value() - fl.off) as VOffsetT;
debug_assert_eq!(vtfw.get_field_offset(fl.id),
0,
"tried to write a vtable field multiple times");
vtfw.write_field_offset(fl.id, pos);
}
}
let dup_vt_use = {
let this_vt = VTable::init(&self.owned_buf[..], self.head);
self.find_duplicate_stored_vtable_revloc(this_vt)
};
let vt_use = match dup_vt_use {
Some(n) => {
VTableWriter::init(&mut self.owned_buf[vt_start_pos..vt_end_pos]).clear();
self.head += vtable_byte_len;
n
}
None => {
let new_vt_use = self.used_space() as UOffsetT;
self.written_vtable_revpos.push(new_vt_use);
new_vt_use
}
};
{
let n = self.head + self.used_space() - object_revloc_to_vtable.value() as usize;
let saw = read_scalar::<UOffsetT>(&self.owned_buf[n..n + SIZE_SOFFSET]);
debug_assert_eq!(saw, 0xF0F0F0F0);
emplace_scalar::<SOffsetT>(&mut self.owned_buf[n..n + SIZE_SOFFSET],
vt_use as SOffsetT - object_revloc_to_vtable.value() as SOffsetT);
}
self.field_locs.clear();
object_revloc_to_vtable
}
#[inline]
fn find_duplicate_stored_vtable_revloc(&self, needle: VTable) -> Option<UOffsetT> {
for &revloc in self.written_vtable_revpos.iter().rev() {
let o = VTable::init(&self.owned_buf[..], self.head + self.used_space() - revloc as usize);
if needle == o {
return Some(revloc);
}
}
None
}
// Only call this when you know it is safe to double the size of the buffer.
#[inline]
fn grow_owned_buf(&mut self) {
let old_len = self.owned_buf.len();
let new_len = max(1, old_len * 2);
let starting_active_size = self.used_space();
let diff = new_len - old_len;
self.owned_buf.resize(new_len, 0);
self.head += diff;
let ending_active_size = self.used_space();
debug_assert_eq!(starting_active_size, ending_active_size);
if new_len == 1 {
return;
}
// calculate the midpoint, and safely copy the old end data to the new
// end position:
let middle = new_len / 2;
{
let (left, right) = &mut self.owned_buf[..].split_at_mut(middle);
right.copy_from_slice(left);
}
// finally, zero out the old end data.
{
let ptr = (&mut self.owned_buf[..middle]).as_mut_ptr();
unsafe { write_bytes(ptr, 0, middle); }
}
}
// with or without a size prefix changes how we load the data, so finish*
// functions are split along those lines.
fn finish_with_opts<T>(&mut self,
root: WIPOffset<T>,
file_identifier: Option<&str>,
size_prefixed: bool) {
self.assert_not_finished("buffer cannot be finished when it is already finished");
self.assert_not_nested("buffer cannot be finished when a table or vector is under construction");
self.written_vtable_revpos.clear();
let to_align = {
// for the root offset:
let a = SIZE_UOFFSET;
// for the size prefix:
let b = if size_prefixed { SIZE_UOFFSET } else { 0 };
// for the file identifier (a string that is not zero-terminated):
let c = if file_identifier.is_some() {
FILE_IDENTIFIER_LENGTH
} else {
0
};
a + b + c
};
{
let ma = PushAlignment::new(self.min_align);
self.align(to_align, ma);
}
if let Some(ident) = file_identifier {
debug_assert_eq!(ident.len(), FILE_IDENTIFIER_LENGTH);
self.push_bytes_unprefixed(ident.as_bytes());
}
self.push(root);
if size_prefixed {
let sz = self.used_space() as UOffsetT;
self.push::<UOffsetT>(sz);
}
self.finished = true;
}
#[inline]
fn align(&mut self, len: usize, alignment: PushAlignment) {
self.track_min_align(alignment.value());
let s = self.used_space() as usize;
self.make_space(padding_bytes(s + len, alignment.value()));
}
#[inline]
fn track_min_align(&mut self, alignment: usize) {
self.min_align = max(self.min_align, alignment);
}
#[inline]
fn push_bytes_unprefixed(&mut self, x: &[u8]) -> UOffsetT {
let n = self.make_space(x.len());
&mut self.owned_buf[n..n + x.len()].copy_from_slice(x);
n as UOffsetT
}
#[inline]
fn make_space(&mut self, want: usize) -> usize {
self.ensure_capacity(want);
self.head -= want;
self.head
}
#[inline]
fn ensure_capacity(&mut self, want: usize) -> usize {
if self.unused_ready_space() >= want {
return want;
}
assert!(want <= FLATBUFFERS_MAX_BUFFER_SIZE,
"cannot grow buffer beyond 2 gigabytes");
while self.unused_ready_space() < want {
self.grow_owned_buf();
}
want
}
#[inline]
fn unused_ready_space(&self) -> usize {
self.head
}
#[inline]
fn assert_nested(&self, fn_name: &'static str) {
// we don't assert that self.field_locs.len() >0 because the vtable
// could be empty (e.g. for empty tables, or for all-default values).
debug_assert!(self.nested, format!("incorrect FlatBufferBuilder usage: {} must be called while in a nested state", fn_name));
}
#[inline]
fn assert_not_nested(&self, msg: &'static str) {
debug_assert!(!self.nested, msg);
}
#[inline]
fn assert_finished(&self, msg: &'static str) {
debug_assert!(self.finished, msg);
}
#[inline]
fn assert_not_finished(&self, msg: &'static str) {
debug_assert!(!self.finished, msg);
}
}
/// Compute the length of the vtable needed to represent the provided FieldLocs.
/// If there are no FieldLocs, then provide the minimum number of bytes
/// required: enough to write the VTable header.
#[inline]
fn get_vtable_byte_len(field_locs: &[FieldLoc]) -> usize {
let max_voffset = field_locs.iter().map(|fl| fl.id).max();
match max_voffset {
None => { field_index_to_field_offset(0) as usize }
Some(mv) => { mv as usize + SIZE_VOFFSET }
}
}
#[inline]
fn padding_bytes(buf_size: usize, scalar_size: usize) -> usize {
// ((!buf_size) + 1) & (scalar_size - 1)
(!buf_size).wrapping_add(1) & (scalar_size.wrapping_sub(1))
}

View File

@@ -0,0 +1,180 @@
/*
* Copyright 2018 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.
*/
use std::mem::size_of;
/// Trait for values that must be stored in little-endian byte order, but
/// might be represented in memory as big-endian. Every type that implements
/// EndianScalar is a valid FlatBuffers scalar value.
///
/// The Rust stdlib does not provide a trait to represent scalars, so this trait
/// serves that purpose, too.
///
/// Note that we do not use the num-traits crate for this, because it provides
/// "too much". For example, num-traits provides i128 support, but that is an
/// invalid FlatBuffers type.
pub trait EndianScalar: Sized + PartialEq + Copy + Clone {
fn to_little_endian(self) -> Self;
fn from_little_endian(self) -> Self;
}
/// Macro for implementing a no-op endian conversion. This is used for types
/// that are one byte wide.
macro_rules! impl_endian_scalar_noop {
($ty:ident) => (
impl EndianScalar for $ty {
#[inline]
fn to_little_endian(self) -> Self {
self
}
#[inline]
fn from_little_endian(self) -> Self {
self
}
}
)
}
/// Macro for implementing an endian conversion using the stdlib `to_le` and
/// `from_le` functions. This is used for integer types. It is not used for
/// floats, because the `to_le` and `from_le` are not implemented for them in
/// the stdlib.
macro_rules! impl_endian_scalar_stdlib_le_conversion {
($ty:ident) => (
impl EndianScalar for $ty {
#[inline]
fn to_little_endian(self) -> Self {
Self::to_le(self)
}
#[inline]
fn from_little_endian(self) -> Self {
Self::from_le(self)
}
}
)
}
impl_endian_scalar_noop!(bool);
impl_endian_scalar_noop!(u8);
impl_endian_scalar_noop!(i8);
impl_endian_scalar_stdlib_le_conversion!(u16);
impl_endian_scalar_stdlib_le_conversion!(u32);
impl_endian_scalar_stdlib_le_conversion!(u64);
impl_endian_scalar_stdlib_le_conversion!(i16);
impl_endian_scalar_stdlib_le_conversion!(i32);
impl_endian_scalar_stdlib_le_conversion!(i64);
impl EndianScalar for f32 {
/// Convert f32 from host endian-ness to little-endian.
#[inline]
fn to_little_endian(self) -> Self {
#[cfg(target_endian = "little")]
{
self
}
#[cfg(not(target_endian = "little"))]
{
byte_swap_f32(&self)
}
}
/// Convert f32 from little-endian to host endian-ness.
#[inline]
fn from_little_endian(self) -> Self {
#[cfg(target_endian = "little")]
{
self
}
#[cfg(not(target_endian = "little"))]
{
byte_swap_f32(&self)
}
}
}
impl EndianScalar for f64 {
/// Convert f64 from host endian-ness to little-endian.
#[inline]
fn to_little_endian(self) -> Self {
#[cfg(target_endian = "little")]
{
self
}
#[cfg(not(target_endian = "little"))]
{
byte_swap_f64(&self)
}
}
/// Convert f64 from little-endian to host endian-ness.
#[inline]
fn from_little_endian(self) -> Self {
#[cfg(target_endian = "little")]
{
self
}
#[cfg(not(target_endian = "little"))]
{
byte_swap_f64(&self)
}
}
}
/// Swaps the bytes of an f32.
#[allow(dead_code)]
#[inline]
pub fn byte_swap_f32(x: f32) -> f32 {
f32::from_bits(x.to_bits().swap_bytes())
}
/// Swaps the bytes of an f64.
#[allow(dead_code)]
#[inline]
pub fn byte_swap_f64(x: f64) -> f64 {
f64::from_bits(x.to_bits().swap_bytes())
}
/// Place an EndianScalar into the provided mutable byte slice. Performs
/// endian conversion, if necessary.
#[inline]
pub fn emplace_scalar<T: EndianScalar>(s: &mut [u8], x: T) {
let sz = size_of::<T>();
let mut_ptr = (&mut s[..sz]).as_mut_ptr() as *mut T;
let val = x.to_little_endian();
unsafe {
*mut_ptr = val;
}
}
/// Read an EndianScalar from the provided byte slice at the specified location.
/// Performs endian conversion, if necessary.
#[inline]
pub fn read_scalar_at<T: EndianScalar>(s: &[u8], loc: usize) -> T {
let buf = &s[loc..loc + size_of::<T>()];
read_scalar(buf)
}
/// Read an EndianScalar from the provided byte slice. Performs endian
/// conversion, if necessary.
#[inline]
pub fn read_scalar<T: EndianScalar>(s: &[u8]) -> T {
let sz = size_of::<T>();
let p = (&s[..sz]).as_ptr() as *const T;
let x = unsafe { *p };
x.from_little_endian()
}

View File

@@ -0,0 +1,62 @@
/*
* Copyright 2018 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.
*/
use std::marker::PhantomData;
/// Follow is a trait that allows us to access FlatBuffers in a declarative,
/// type safe, and fast way. They compile down to almost no code (after
/// optimizations). Conceptually, Follow lifts the offset-based access
/// patterns of FlatBuffers data into the type system. This trait is used
/// pervasively at read time, to access tables, vtables, vectors, strings, and
/// all other data. At this time, Follow is not utilized much on the write
/// path.
///
/// Writing a new Follow implementation primarily involves deciding whether
/// you want to return data (of the type Self::Inner) or do you want to
/// continue traversing the FlatBuffer.
pub trait Follow<'a> {
type Inner;
fn follow(buf: &'a [u8], loc: usize) -> Self::Inner;
}
/// Execute a follow as a top-level function.
#[allow(dead_code)]
#[inline]
pub fn lifted_follow<'a, T: Follow<'a>>(buf: &'a [u8], loc: usize) -> T::Inner {
T::follow(buf, loc)
}
/// FollowStart wraps a Follow impl in a struct type. This can make certain
/// programming patterns more ergonomic.
#[derive(Debug)]
pub struct FollowStart<T>(PhantomData<T>);
impl<'a, T: Follow<'a> + 'a> FollowStart<T> {
#[inline]
pub fn new() -> Self {
Self { 0: PhantomData }
}
#[inline]
pub fn self_follow(&'a self, buf: &'a [u8], loc: usize) -> T::Inner {
T::follow(buf, loc)
}
}
impl<'a, T: Follow<'a>> Follow<'a> for FollowStart<T> {
type Inner = T::Inner;
#[inline]
fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
T::follow(buf, loc)
}
}

View File

@@ -0,0 +1,52 @@
/*
* Copyright 2018 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.
*/
//! # FlatBuffers
//!
//! A library for memory-efficient serialization of data.
//!
//! This crate provides runtime support for the FlatBuffers format in the Rust programming language.
//! To use this crate, first generate code with the `flatc` compiler, as described here: https://google.github.io/flatbuffers/
//! Then, include that code into your project.
//! Finally, add this crate to your `Cargo.toml`.
//!
//! At this time, Rust support is experimental, and APIs may change between minor versions.
//!
//! At this time, to generate Rust code, you will need the latest `master` version of `flatc`, available from here: https://github.com/google/flatbuffers
//! (On OSX, you can install FlatBuffers from `HEAD` with the Homebrew package manager.)
mod builder;
mod endian_scalar;
mod follow;
mod primitives;
mod push;
mod table;
mod vector;
mod vtable;
mod vtable_writer;
pub use builder::FlatBufferBuilder;
pub use endian_scalar::{EndianScalar, emplace_scalar, read_scalar, read_scalar_at, byte_swap_f32, byte_swap_f64};
pub use follow::{Follow, FollowStart};
pub use primitives::*;
pub use push::Push;
pub use table::{Table, buffer_has_identifier, get_root, get_size_prefixed_root};
pub use vector::{SafeSliceAccess, Vector, follow_cast_ref};
pub use vtable::field_index_to_field_offset;
// TODO(rw): Unify `create_vector` and `create_vector_direct` by using
// `Into<Vector<...>>`.
// TODO(rw): Split fill ops in builder into fill_small, fill_big like in C++.

View File

@@ -0,0 +1,298 @@
/*
* Copyright 2018 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.
*/
use std::marker::PhantomData;
use std::mem::size_of;
use std::ops::Deref;
use endian_scalar::{emplace_scalar, read_scalar, read_scalar_at};
use follow::Follow;
use push::Push;
pub const FLATBUFFERS_MAX_BUFFER_SIZE: usize = (1u64 << 31) as usize;
pub const FILE_IDENTIFIER_LENGTH: usize = 4;
pub const VTABLE_METADATA_FIELDS: usize = 2;
pub const SIZE_U8: usize = size_of::<u8>();
pub const SIZE_I8: usize = size_of::<i8>();
pub const SIZE_U16: usize = size_of::<u16>();
pub const SIZE_I16: usize = size_of::<i16>();
pub const SIZE_U32: usize = size_of::<u32>();
pub const SIZE_I32: usize = size_of::<i32>();
pub const SIZE_U64: usize = size_of::<u64>();
pub const SIZE_I64: usize = size_of::<i64>();
pub const SIZE_F32: usize = size_of::<f32>();
pub const SIZE_F64: usize = size_of::<f64>();
pub const SIZE_SOFFSET: usize = SIZE_I32;
pub const SIZE_UOFFSET: usize = SIZE_U32;
pub const SIZE_VOFFSET: usize = SIZE_I16;
pub const SIZE_SIZEPREFIX: usize = SIZE_UOFFSET;
/// SOffsetT is an i32 that is used by tables to reference their vtables.
pub type SOffsetT = i32;
/// UOffsetT is a u32 that is used by pervasively to represent both pointers
/// and lengths of vectors.
pub type UOffsetT = u32;
/// VOffsetT is a i32 that is used by vtables to store field data.
pub type VOffsetT = i16;
/// TableFinishedWIPOffset marks a WIPOffset as being for a finished table.
pub struct TableFinishedWIPOffset {}
/// TableUnfinishedWIPOffset marks a WIPOffset as being for an unfinished table.
pub struct TableUnfinishedWIPOffset {}
/// UnionWIPOffset marks a WIPOffset as being for a union value.
pub struct UnionWIPOffset {}
/// VTableWIPOffset marks a WIPOffset as being for a vtable.
pub struct VTableWIPOffset {}
/// WIPOffset contains an UOffsetT with a special meaning: it is the location of
/// data relative to the *end* of an in-progress FlatBuffer. The
/// FlatBufferBuilder uses this to track the location of objects in an absolute
/// way. The impl of Push converts a WIPOffset into a ForwardsUOffset.
#[derive(Debug)]
pub struct WIPOffset<T>(UOffsetT, PhantomData<T>);
// TODO(rw): why do we need to reimplement (with a default impl) Copy to
// avoid ownership errors?
impl<T> Copy for WIPOffset<T> {}
impl<T> Clone for WIPOffset<T> {
#[inline]
fn clone(&self) -> WIPOffset<T> {
WIPOffset::new(self.0.clone())
}
}
impl<T> PartialEq for WIPOffset<T> {
fn eq(&self, o: &WIPOffset<T>) -> bool {
self.value() == o.value()
}
}
impl<T> Deref for WIPOffset<T> {
type Target = UOffsetT;
#[inline]
fn deref(&self) -> &UOffsetT {
&self.0
}
}
impl<'a, T: 'a> WIPOffset<T> {
/// Create a new WIPOffset.
#[inline]
pub fn new(o: UOffsetT) -> WIPOffset<T> {
WIPOffset {
0: o,
1: PhantomData,
}
}
/// Return a wrapped value that brings its meaning as a union WIPOffset
/// into the type system.
#[inline(always)]
pub fn as_union_value(&self) -> WIPOffset<UnionWIPOffset> {
WIPOffset::new(self.0)
}
/// Get the underlying value.
#[inline(always)]
pub fn value(&self) -> UOffsetT {
self.0
}
}
impl<T> Push for WIPOffset<T> {
type Output = ForwardsUOffset<T>;
#[inline(always)]
fn push(&self, dst: &mut [u8], rest: &[u8]) {
let n = (SIZE_UOFFSET + rest.len() - self.value() as usize) as UOffsetT;
emplace_scalar::<UOffsetT>(dst, n);
}
}
impl<T> Push for ForwardsUOffset<T> {
type Output = Self;
#[inline(always)]
fn push(&self, dst: &mut [u8], rest: &[u8]) {
self.value().push(dst, rest);
}
}
/// ForwardsUOffset is used by Follow to traverse a FlatBuffer: the pointer
/// is incremented by the value contained in this type.
#[derive(Debug)]
pub struct ForwardsUOffset<T>(UOffsetT, PhantomData<T>);
impl<T> ForwardsUOffset<T> {
#[inline(always)]
pub fn value(&self) -> UOffsetT {
self.0
}
}
impl<'a, T: Follow<'a>> Follow<'a> for ForwardsUOffset<T> {
type Inner = T::Inner;
#[inline(always)]
fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
let slice = &buf[loc..loc + SIZE_UOFFSET];
let off = read_scalar::<u32>(slice) as usize;
T::follow(buf, loc + off)
}
}
/// ForwardsVOffset is used by Follow to traverse a FlatBuffer: the pointer
/// is incremented by the value contained in this type.
#[derive(Debug)]
pub struct ForwardsVOffset<T>(VOffsetT, PhantomData<T>);
impl<T> ForwardsVOffset<T> {
#[inline(always)]
pub fn value(&self) -> VOffsetT {
self.0
}
}
impl<'a, T: Follow<'a>> Follow<'a> for ForwardsVOffset<T> {
type Inner = T::Inner;
#[inline(always)]
fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
let slice = &buf[loc..loc + SIZE_VOFFSET];
let off = read_scalar::<VOffsetT>(slice) as usize;
T::follow(buf, loc + off)
}
}
impl<T> Push for ForwardsVOffset<T> {
type Output = Self;
#[inline]
fn push(&self, dst: &mut [u8], rest: &[u8]) {
self.value().push(dst, rest);
}
}
/// ForwardsSOffset is used by Follow to traverse a FlatBuffer: the pointer
/// is incremented by the *negative* of the value contained in this type.
#[derive(Debug)]
pub struct BackwardsSOffset<T>(SOffsetT, PhantomData<T>);
impl<T> BackwardsSOffset<T> {
#[inline(always)]
pub fn value(&self) -> SOffsetT {
self.0
}
}
impl<'a, T: Follow<'a>> Follow<'a> for BackwardsSOffset<T> {
type Inner = T::Inner;
#[inline(always)]
fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
let slice = &buf[loc..loc + SIZE_SOFFSET];
let off = read_scalar::<SOffsetT>(slice);
T::follow(buf, (loc as SOffsetT - off) as usize)
}
}
impl<T> Push for BackwardsSOffset<T> {
type Output = Self;
#[inline]
fn push(&self, dst: &mut [u8], rest: &[u8]) {
self.value().push(dst, rest);
}
}
/// SkipSizePrefix is used by Follow to traverse a FlatBuffer: the pointer is
/// incremented by a fixed constant in order to skip over the size prefix value.
pub struct SkipSizePrefix<T>(PhantomData<T>);
impl<'a, T: Follow<'a> + 'a> Follow<'a> for SkipSizePrefix<T> {
type Inner = T::Inner;
#[inline(always)]
fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
T::follow(buf, loc + SIZE_SIZEPREFIX)
}
}
/// SkipRootOffset is used by Follow to traverse a FlatBuffer: the pointer is
/// incremented by a fixed constant in order to skip over the root offset value.
pub struct SkipRootOffset<T>(PhantomData<T>);
impl<'a, T: Follow<'a> + 'a> Follow<'a> for SkipRootOffset<T> {
type Inner = T::Inner;
#[inline(always)]
fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
T::follow(buf, loc + SIZE_UOFFSET)
}
}
/// FileIdentifier is used by Follow to traverse a FlatBuffer: the pointer is
/// dereferenced into a byte slice, whose bytes are the file identifer value.
pub struct FileIdentifier;
impl<'a> Follow<'a> for FileIdentifier {
type Inner = &'a [u8];
#[inline(always)]
fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
&buf[loc..loc + FILE_IDENTIFIER_LENGTH]
}
}
/// SkipFileIdentifier is used by Follow to traverse a FlatBuffer: the pointer
/// is incremented by a fixed constant in order to skip over the file
/// identifier value.
pub struct SkipFileIdentifier<T>(PhantomData<T>);
impl<'a, T: Follow<'a> + 'a> Follow<'a> for SkipFileIdentifier<T> {
type Inner = T::Inner;
#[inline(always)]
fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
T::follow(buf, loc + FILE_IDENTIFIER_LENGTH)
}
}
/// Follow trait impls for primitive types.
///
/// Ideally, these would be implemented as a single impl using trait bounds on
/// EndianScalar, but implementing Follow that way causes a conflict with
/// other impls.
macro_rules! impl_follow_for_endian_scalar {
($ty:ident) => (
impl<'a> Follow<'a> for $ty {
type Inner = $ty;
#[inline(always)]
fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
read_scalar_at::<$ty>(buf, loc)
}
}
)
}
impl_follow_for_endian_scalar!(bool);
impl_follow_for_endian_scalar!(u8);
impl_follow_for_endian_scalar!(u16);
impl_follow_for_endian_scalar!(u32);
impl_follow_for_endian_scalar!(u64);
impl_follow_for_endian_scalar!(i8);
impl_follow_for_endian_scalar!(i16);
impl_follow_for_endian_scalar!(i32);
impl_follow_for_endian_scalar!(i64);
impl_follow_for_endian_scalar!(f32);
impl_follow_for_endian_scalar!(f64);

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