Compare commits

..

109 Commits

Author SHA1 Message Date
Wouter van Oortmerssen
6f94fb51b1 Updated version numbers to 1.7.0
Change-Id: If2802ca48b61cfa7e5ec131e2a268400523217e2
2017-06-16 16:15:02 -07:00
Christopher Berner
57f3752d5e Optimize CreateVector for types > 1 byte on little endian (#4355)
This gives a 10x speed up in my test, when creating a Vector of floats
2017-06-16 15:29:47 -07:00
Wouter van Oortmerssen
f52f848b95 Added move assignment operator to DetachedBuffer.
Change-Id: I4610946ac27d9d0d73c2fc2e4834bd2cfed88cdc
Tested: on Linux.
2017-06-16 15:22:40 -07:00
Wouter van Oortmerssen
3c3742a54a Adding a method to get the file identifier from a flatbuffer.
Change-Id: Ie28fd1f0b463aac23647d38921600f15c8b7c10a
2017-06-16 12:30:36 -07:00
Wouter van Oortmerssen
f325cce6fd Initial support for parsing (and generating) Protobuf ASCII.
Change-Id: I955b4b3eed27f26773d7dc0acceff13c88d1333d
Tested: on Linux.
2017-06-16 11:57:58 -07:00
Wouter van Oortmerssen
88a85ffbbd Added convenient schema registry.
Change-Id: I9d71375059369fbc538d0d051d8d2885e467bf29
Tested: on Mac OS X.
2017-06-16 11:10:07 -07:00
Wouter van Oortmerssen
35cbd23f63 Fixed missing lambda return type.
Change-Id: I48d41a240c8bf362b1f931f20a3ed9ae64f2d295
2017-06-16 09:54:25 -07:00
Stephen Lane-Walsh
210a1ab969 Fixed build error in Visual Studio 2017 (#4353)
flatbuffers.h(591): error C2220: warning treated as error - no 'object' file generated
flatbuffers.h(591): warning C4267: 'return': conversion from 'size_t' to 'flatbuffers::uoffset_t', possible loss of data
2017-06-16 09:53:53 -07:00
Lawrence Chan
90c8ded449 gRPC: fix memory leak (#4351)
SerializationTraits<T>::Deserialize _transfers_ ownership of the buffer,
so we must destroy it.

This commit also includes some misc fixes:
- Use grpc::Status::OK rather than default ctor for clarity.
- Check for a null buffer passed into Deserialize, and handle it the
  same way as the protobuf deserializer.
2017-06-13 08:50:27 -07:00
Wouter van Oortmerssen
8f864aad7b Added (nested) FlexBuffer JSON parsing and output.
FlexBuffer parser is just 40 lines of code (on top of existing parser!).

Change-Id: Idebebadafb661ca5333f5621139031f6df3c3e1a
Tested: on Linux.
2017-06-12 16:40:47 -07:00
Wouter van Oortmerssen
dddd0865cb Added nested FlexBuffer parsing
Change-Id: I918b66eb5646d035e3aae675f745802eb54b03ea
2017-06-12 14:34:45 -07:00
Christopher Berner
0a81eb6463 Fix memory leak in Message move operator (#4344) 2017-06-12 11:23:55 -07:00
Guillaume Giraud
b1740688bf [cpp] Json parsing: adding support for parsing nested lists and top level lists (#4338)
* Extended json parsing capability: add support for parsing nested lists and top level lists

* Stylistic conformance with surrounding code + generalized comments

* More code tidy-up for stylistic conformance with surrounding code

* Blank lines

* Reverted changes related to top-level list parsing

* Styling: newline before else

* Taking out ProcessTableFields which is no longer needed as the top level list change was reverted.
2017-06-07 16:58:19 -07:00
Stephan T. Lavavej
86b505e412 [C++] Remove std::iterator usage (#4340) (#4341)
* [C++] Remove std::iterator usage (#4340)

Inheriting from std::iterator has never been required, and it's
deprecated in C++17. It can be replaced by directly providing typedefs.

Include <iterator> for std::random_access_iterator_tag.

Note that structs default to public access control.

* [C++] Change whitespace style in typedefs.
2017-06-07 16:26:06 -07:00
Lawrence Chan
da67c0a71f [C++] Improve flatbuffers + gRPC integration (#4310)
* Rework flatbuffers + gRPC integration

- Introduce `flatbuffers::grpc::Message<T>`, a `grpc_slice`-backed
message buffer that handles refcounting and allows flatbuffers to
transfer ownership to gRPC efficiently. This replaces
`flatbuffers::BufferRef<T>`, which required a copy call and was also
unsafe w.r.t. buffer lifetime.
- Introduce `flatbuffers::grpc::MessageBuilder`, a gRPC-specific builder
that forces a `grpc_slice`-backed allocator and also adds some helpful
`Message<T>`-related methods.
- Update serializers accordingly (now zero-copy between flatbuffers and
gRPC).

* gRPC: verify messages by default, but allow user to override

* gRPC: fix some formatting issues

* Disable verification by default, but add helper method

* Make FlatBufferBuilder fields protected + remove vec accessor

* Use bool add_ref parameter to toggle refcount incr

* Remove unnecessary inline specifiers

* Fix formatting

* Use auto

* Remove empty lines

* Use grpc_slice helper macros

* Simplify reset code

* Disable Message copy ctor and assignment by default

* Remove unused member

* Enable gRPC verification by default

* Use auto

* Bake in message verification (remove template specialization)

* Add RoundUp func

* Consolidate gRPC message copy flag

* Make vector_downward allocations fully lazy

* Test message verification failure code/message

* Add grpctest verification test comments

* Simplify reallocate implementation

* Make initial_size a size_t

* Use ternary op for growth_policy

* Use truthiness rather than dont explicit nullptr check

* Indent preprocessor directives

* Remove grpc message copy/assignment

* Fix a few bugs

* Add gRPC example

* Add basic gRPC docs

* Use doxygen EXAMPLE_PATH + @include

* Reference example fbs in grpc docs

* Move gRPC examples into grpc/samples

* Fix pointer/reference formatting

* Use std::function rather than templated callback func

* Create fresh message builder for each request

* Use Clear() in Reset() impl

* Use FLATBUFFERS_CONSTEXPR
2017-06-07 13:56:49 -07:00
rufeooo
dadd1a926e Generate a C++ function for EnumValues{{ENUM_NAME}} (#4337)
* enables "for each" logic on enumeration types
2017-06-07 13:49:56 -07:00
vabr-g
01c50d57a6 [C++] Remove std::move around a raw pointer in flatbuffers.h (#4339)
* Remove std::move around a raw pointer

Calling std::move on a raw pointer has no advantage to just copying its value. Moreover, it is confusing, because it indicates that the argument is movable in some non-trivial way (e.g., is it actually meant to be a smart pointer?). More context in https://crbug.com/729393.

* Remove the move constructor altogether
2017-06-05 10:33:04 -07:00
Wouter van Oortmerssen
e9f1f4d9b7 Disallowing field name same as table name.
Change-Id: I4b5d822cc4eda975949d1b7cf33674c5bbf9d4b1
Tested: on Linux.
2017-06-02 15:55:02 -07:00
Wouter van Oortmerssen
dd05f3249a Added test for nested FlatBuffers functionality.
Also fixed that the parsing test wasn't calling the buffer
testing function.

Change-Id: I5baae071bf0832c7797b4ef1d19d9b015e3ff5bc
Tested: on Linux.
2017-06-02 12:36:18 -07:00
AntonYudintsev
43611fcc0b refactor flatbuffers.h and util.h so FlexBuffers do not depend on flatbuffers.h (#4331)
FlexBuffers are actually completely unrelated to FlatBuffers and can be used separately.
However, since they utilize several utility functions from flatbuffer.h, they require this header file, which creates unreasonable dependency.
By moving those utility functions to separate base header, both libraries can use same code but still be independent
2017-06-02 10:26:11 -07:00
Pavel Kalinnikov
642254bee6 Track included files in PATH-agnostic way. (#4329)
* Track included files in PATH-agnostic way.

Use full paths as keys in the map of included files. Store logical
include path as a value, in order to put it to the generated file.

* Fix tests by accepting null |include_filename|.

* Fix self-includes code generators.
2017-06-02 08:50:18 -07:00
Wouter van Oortmerssen
22743ca45a Fixed --keep-prefix functionality.
Changing to keep include prefixes had two side effects: the main
file being parsed wasn't filtered out anymore, and include directory
paths would be added to the path in the include statement.

Also moved the include_test*.fbs files to sub directories so we
can actually test the handling of -I etc.

tested: on Linux.

Change-Id: Ibae095cea7ab0cccbac15cfb5171719f6b5cad8c
2017-05-24 16:26:57 -07:00
Lawrence Chan
fb87c0d3c6 [C++] Improve Allocator handling (#4312)
* Improve Allocator handling

- Templatize Allocator on vector_downward, and make it own the allocator
instance so it can manage lifetimes.
- Templatize + rename FlatBufferBuilderT accordingly, and add a typedef
to FlatBufferBuilder so old code continues to work.
- Fix some issues with the release deleter
- More details in github issue #4311

* Fix constexpr for older MSVC

* Reimplement allocator improvements via inheritance

Instead of templates, use an abstract base class and some unique_ptrs to
implement the new and improved allocator.

* Fix misplaced newline

* Add missing override keyword

* Add macro for func delete to support older compilers

* Explicitly move BufferDeleter (maybe fixes VS 10?)

* Revert previous attempt at VS10 fix

* Try yet another workaround for MS 10

* Use FLATBUFFERS_NOEXCEPT macro

* Add FLATBUFFERS_OVERRIDE macro

* Fix some issues with MSVC 16 hack

* Remove dep on unique_ptr

* Update DEPRECATED macro with a message

* Sigh, no delegating ctors before c++11

* Fix simple_allocator stub

* Relax FlatBufferBuilder ctor

* Add vector_downward reset + assert in clear

* Rename DetachedBuffer to FlatBuffer + remove unnecessary deprecations

* Add flatbuffers::FlatBufferBuilder::Release()

* Address remaining allocator-improvements comments
2017-05-24 13:55:15 -07:00
Wouter van Oortmerssen
398ae0cb6b Some code in the samples and docs still used old C# API.
Change-Id: I7914c88ad7b31baa7586771423069dc2b90d534f
Tested: on Linux.
2017-05-22 15:14:46 -07:00
Wouter van Oortmerssen
aaf5598a03 Standardized internal path handling on Posix separators.
There were several possible bugs involving paths not being
recognized as being the same on Windows. Rather than trying
to ensure all code deals with / and \ correctly, paths now
get transformed to / on input, fixing all current and
future such bugs.

Tested: on OS X.
2017-05-18 17:22:47 -07:00
Kamil Rojewski
3d2cf554d7 Fix for invalid null returns (#4318)
* 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
2017-05-18 10:30:30 -07:00
sfariv
55dec4d2f8 added check for presence of required fields. (flatc) c++ (#4316)
* added check for presence of required fields.

* updates to resolve Travis CI build error.

* fixes for resolving appveyor build errors.

* fixes for resolving appveyor build errors.

* fixes for resolving appveyor build errors.

* updates per aardappel's comments.

* updated a variable's name.

* updates per aardappel's comments.
2017-05-18 09:32:04 -07:00
schoetbi
0f5f7faa9f C#: Added <autogenerated> in cs generator file header comment (#4291)
* Added <autogenerated> in cs generator file header comment
#4287

* CS: Added xml-correct file header comment including "<auto-generated>...</auto-generated>"
code_generators.cpp: FlatBuffersGeneratedWarning() function replaced by compile time constant "GeneratedWarning"
 also removed extra newlines at end of GeneratedWarning to be able to generate a xml well formed file comment for cs files
#4291

* code_generators: Changed static string GeneratedWarning back to function FlatBuffersGeneratedWarning()
#4291

* Added modified Unit-Test files
#4291

* idl_gen_general: Add autogenerated only in C# code
#4291
2017-05-16 14:28:34 -07:00
Wouter van Oortmerssen
90daabd5b1 Made root test path configurable.
Change-Id: I9629a7648f0c3346c4724ca8938fed47d7828018
Tested: on Linux.
2017-05-15 16:57:39 -07:00
Wouter van Oortmerssen
262e1d7bf9 Updated tutorial with a vector of structs example.
Since it wasn't documented and very different from a vector of
tables, this has caused a lot of confusion in the past.

Change-Id: Iab47c61b55c19abe5c4f25c86d71335a6b6321ca
2017-05-15 13:41:27 -07:00
Wouter van Oortmerssen
c559eb451e Made codegen always output a file, even on an empty schema.
Previously, we had a check to simply skip such files, but this
tends to make build systems unhappy.

This only affects C++ and JS, since other language output per-class
files.

Change-Id: I54224642725bbafb9f6e1654ed3693e62ca9f7d7
Tested: on Linux.
2017-05-12 16:08:58 -07:00
Lawrence Chan
6a7ec85e83 [C++] Fix code gen indentation when empty Print (#4313)
* Fix C++ code gen indentation when empty Print

* Also commit modified tests/monster_test.bfbs
2017-05-12 14:36:35 -07:00
akamat-ibm
81ecc98e02 Adding support for s390x (#4297)
* changes to support s390x

* added flag for s390x

* Adding support for Linux s390x
2017-05-12 10:12:19 -07:00
Per Grön
9aeeddf5ac C++/Go: Update gRPC related code to work with gRPC 1.3+ (#4305)
* Don't fail the build on unused parameters

gRPC headers have unused parameters so this breaks the test build.

* Pull in updated compiler files from gRPC

There have been some API breaks in gRPC lately. This commit
pulls in the most recent version of the files in this repo
that are just copied from gRPC.

* Modify the gRPC files so that they can work with Flatbuffers

The files taken from gRPC do not work out-of-the-box with Flatbuffers.
This commit modifies them so that they work. Hopefully this commit
will be able to serve as a guide or maybe even be cherry-picked on
top of new versions of those files as newer versions from gRPC are
pulled in.

* Adjust the rest of Flatbuffers to work with the new gRPC

* Change idl_gen_grpc.cpp to work with the new API
* Add missing #include in flatbuffers/grpc.h
* Run tests/generate_code.sh and check in the results
* Don't link with grpc++_unsecure and (secure) grpc. That's just weird

* Revert unrelated JS/TS test changes

* Simplify compiler/config.h

There is no need to import this file from gRPC. In fact, it probably
makes sense to not do so, since it seems to be intended to have
project specific configuration in it.

* Don't emit C++ types in the Go gRPC code generator

* Don't emit C++ #includes in generated gRPC code

Before this PR, there was a Go-specific additional_includes method
in schema_interface.h, which is shared with the gRPC repo. The
additional parameter to FlatBufFile in idl_gen_grpc.cpp makes that
unnecessary, which means we need less Flatbuffer-specific changes
in gRPC.
2017-05-12 09:48:17 -07:00
Wouter van Oortmerssen
c7bfe06c54 Reverting part of PR #4286
This is because it trips up the Closure compiler with errors like:

ERROR - assignment to property bb of SomeTable
found : undefined
required: (flatbuffers.ByteBuffer|null)
this.bb = undefined;
^^^^^^^^^^^^^^^^^^^

Change-Id: Iaf032b5249ec655e151331e81532e549c12bcd78
2017-05-10 18:04:53 -07:00
Wouter van Oortmerssen
349a391208 Removed unnecessary check for Offset in AssertScalarT()
This will avoid it accidentally accepting structs of size 4.

Change-Id: I251285ae1e4bffb859367dcf89562741a3980bba
Tested: on Linux.
2017-05-10 18:00:27 -07:00
Wouter van Oortmerssen
9d01bfaea3 Added error message for union values out of range.
Change-Id: I481afcde6a554d1cad519ff95acac7f38a7f4ee5
Tested: on Linux.
2017-05-10 17:21:47 -07:00
Travis Wellman
cfbab31fb1 cleaning up JavaTest.sh - quote paths, and less error-prone deletion (#4301) 2017-05-10 16:45:08 -07:00
Wouter van Oortmerssen
cb2481efdc Ensured flatc.exe is statically linked on Windows 2017-05-10 16:20:53 -07:00
Wouter van Oortmerssen
d7ac3788e8 Clarified the semantics of the Offset type.
Change-Id: Iccc36d24321ac4d556692ac715c0cc69a2c9e09e
Tested: on Linux.
2017-05-10 14:55:11 -07:00
Wouter van Oortmerssen
a0a313b101 Added missing js/ts generated code.
Change-Id: I146e9e1b8f997c11d1675dbef1b958ddbd181092
2017-05-10 13:25:51 -07:00
Wouter van Oortmerssen
93c0960c3a Added --keep-prefix to not strip schema include path in C++ includes.
Change-Id: I3c6356fc6664072796f273096df64829108b4a34
Tested: on Linux.
2017-05-10 13:21:20 -07:00
Wouter van Oortmerssen
04d734d6d2 Added more test scripts: Mono on Linux, and one for all.
Change-Id: Ia107557225db27b396f0d666c5c5b1b324ea22fa
Tested: on Linux.
2017-05-10 12:55:27 -07:00
Wouter van Oortmerssen
8468ea1ab4 Fixed LookupByKey for Java & C#
Change-Id: I05c02223675dee241d1ae8cb466e5186444058c8
Tested: on Linux.
2017-05-10 12:55:27 -07:00
水樹素子
0920d663d5 [C++] Add grpc/streaming test and fix Deserialize (#4296)
* [C++] Add delete msg->buf

* [C++] Add grpc streaming test

* Use free instead of delete

* Refactoring grpctest
2017-05-08 13:49:34 -07:00
Heiko Becker
bbb72f0b73 Tweak fallthrough comments to get recognized by gcc7 (#4298)
GCC gained a new warning, -Wimplicit-fallthrough, which warns about
implicitly falling through a case statement. The regular expressions
used at the default level (-Wimplicit-fallthrough=3) don't match with
a colon at the end. The comment also needs to be followed (after
optional whitespace and other comments) by a 'case' or 'default'
keyword, i.e. it will not be recognized with a '}' between the comment
and the keyword.
2017-05-08 13:35:55 -07:00
moti
8f8a27d6e5 [C++] Add grpc_slice_unref(slice) (#4294) 2017-05-04 15:44:31 -07:00
Kamil Rojewski
86777bd66b Generating the most strict TS code possible (#4286)
* 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
2017-05-01 16:05:53 -07:00
Wouter van Oortmerssen
8b92122f33 Made the verifier catch zero-offsets.
Zero offsets are non-sensical in FlatBuffers (since offsets are
relative to themselves) but were allowed by the verifier. This could
cause buffers made up of all zeroes to be interpreted as correct
buffers with an empty root object.

Generally, not allowing such offsets will make the verifier more
likely to catch problems earlier.

Change-Id: I54010bea29721b326ff8e5348fcd9fe78e5e7506
Tested: on Linux.
2017-04-26 14:26:18 -07:00
Wouter van Oortmerssen
e93a5652d0 Fixes for VS 2015 build.
Change-Id: I23280e611163a89b8eba7b9b0016c297fea2396e
2017-04-24 10:48:35 -07:00
Wouter van Oortmerssen
0c80b3a7cc Added VS 2015 test to AppVeyor CI.
Change-Id: I354c13fbe6f159058fbeff47100ef357e99c6cd5
2017-04-24 10:06:55 -07:00
Wouter van Oortmerssen
f52ddfbd68 Fix Android STLPort build.
Change-Id: Iceca7b8b455c8463d9b82b928332a875dee3d19e
2017-04-21 10:50:03 -07:00
Kamil Rojewski
808b44f87a TS tests fixes (#4265)
* 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
2017-04-21 09:29:42 -07:00
Wouter van Oortmerssen
340d1a3447 Fix FlexBuffers writing incomplete length for 64-bit vectors. 2017-04-19 17:51:52 -07:00
Carlos Sanchez
ba20d9bff3 Added a clear function for purging all data that is holded by the FlatBuffer. (#4259) 2017-04-19 17:06:33 -07:00
Dmitry Ermolov
370693a200 Specify `std' namespace for remove function (#4268) 2017-04-19 16:55:41 -07:00
Christian Helmich
33932ceea4 Fixed CreateVectorOfStructs for native_type (2nd try) (#4276)
* Added support for serializing native_type with CreateVectorOfNativeStructs

* Added support for serializing native_type with CreateVectorOfSortedNativeStructs

* Added C++ code generation for vectors of native_types
2017-04-19 10:14:31 -07:00
Per Eckerdal
fb03f78fb4 Fix minor const correctness issue (#4271) 2017-04-19 08:56:55 -07:00
Wouter van Oortmerssen
523f3833eb VS fix for ambiguous union assignment operator.
Change-Id: I1c37db1ced462fd558d3e893a501341f3eca6379
2017-04-17 18:00:41 -07:00
Wouter van Oortmerssen
46497e4f9a Fixed hashed values in JSON for signed ints.
Change-Id: Iae389c6dc9776058b39f4017d30efbf9580aced1
Tested: on Linux.
2017-04-17 17:40:02 -07:00
Wouter van Oortmerssen
b627b7c6c6 Undo PR: make flatbuffers.js into a UMD module (#4228)
This PR did not work in all JS environments and caused
downstream breakage.

Change-Id: Ib565129e26622d02bad2d45816bd05f6b961b994
2017-04-17 17:31:03 -07:00
Wouter van Oortmerssen
e093f72d00 Improved union copy constructor.
It now at least works in simple cases.

Change-Id: I3af0738e676e62166b69accaa6bd19f531fbe5ee
Tested: on Linux.
2017-04-17 17:27:20 -07:00
Wouter van Oortmerssen
728bb64fed Fixed clang needing union copy constructor.
Move constructors are present, which it should use instead.

This is a temp fix to make it compile, but eventually we should
generate a proper copy constructor just in-case people want to
copy objects with unions.

Tested on: Linux, OS X.

Change-Id: Idf85419995c96f5959061882157541573e306083
2017-04-17 14:01:43 -07:00
Jason Stubbs
a07f0d428d [C++] fix bounds checking on integer parsing (#4250)
* fix bounds checking on integer parsing

the previous code was allowing 255 for int8_t, similar for int16_t
and int32_t, and even negative values for unsignd types.

this patch fixes bounds checking for 8-bit, 16-bit and 32-bit types.
testing for both acceptable values and unacceptable values at the
boundaries are also improved.

bounds checking on 64-bit types isn't addressed by this patch.

* fix 'unary minus operator applied to unsigned type, result still unsigned'

* fix & placement
2017-04-17 11:19:43 -07:00
Wouter van Oortmerssen
b90d4e049d VS warning fixes.
Change-Id: I19662241d56560c064cff73dbebfb2a81d226934
2017-04-12 17:56:19 -07:00
Wouter van Oortmerssen
b0752e179b Added support for structs and strings in unions.
(C++ only for now).
Also fixed vector of union support in the object API.

Bug: 36902939
Change-Id: I935f4cc2c303a4728e26c7916a8ec0adcd6f84cb
Tested: on Linux.
2017-04-12 17:47:47 -07:00
schoetbi
1fc12e0e5b C++ fixed compile error C2678 with msvc when using std::find_if on vectors (#4262)
In Debug mode it is checked that iterator begin is less than end
therefore the operator< in class VectorIterator is needed
2017-04-12 16:37:22 -07:00
chronoxor
e6fa7b1133 Fix Visual Studio 2017 new warning (C4244: 'argument': conversion fro… (#4261)
* Fix Visual Studio 2017 new warning (C4244: 'argument': conversion from 'int' to 'const char', possible loss of data)

* Fix Visual Studio 2017 pedantic warnings

* Fix Visual Studio 2017 pedantic warnings
2017-04-12 13:13:10 -07:00
Kamil Rojewski
28e7dbd3d3 TypeScript support (#4232)
* 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
2017-04-10 10:01:13 -07:00
Iain van der Bloat
adc50051e0 make flatbuffers.js into a UMD module (#4228) 2017-04-07 17:14:01 -07:00
moti
2aec880347 [C++]Use noexcept in union type move ctor/Add move assingment (#4249)
* Use noexcept in union type move ctor/Add move assingment

* Add NOEXCEPT macro to deal with _MS_VER/Remove delegating ctor in union type class

* Add FLATBUFFERS_NOEXCEPT to generated union class
2017-03-29 18:00:20 -07:00
Wouter van Oortmerssen
238a8ebb15 Suppress warning in Flatbuffer VS2010 builds.
Change-Id: I4f66a96ba581704c1a384cc700b8fb731d3eeed4
2017-03-29 12:01:11 -07:00
Wouter van Oortmerssen
86992476da Update StackOverflow links to have relevant queries.
Change-Id: I59159fb7205e4802f041b749d502a8f305d4176c
2017-03-29 11:58:42 -07:00
Wouter van Oortmerssen
751aeabc80 Updated .gitignore for C#
Change-Id: I6c253b0ded187a4945f5e862aae721cf4fda6398
2017-03-29 11:55:20 -07:00
Wouter van Oortmerssen
b4bb1b103f Fix flatc code gen.
Mutable functions should return a non-const reference to the member variable.

Change-Id: I833077d2c9a38a5d71868e43aca6b250d79b6625
2017-03-29 11:51:20 -07:00
Wouter van Oortmerssen
cffd187fc7 Added missing generated code for C#
Change-Id: I1affced255eb96977119d8480793b5bba42f065f
2017-03-29 11:51:02 -07:00
Spencer Bench
ccfa317486 C#: Fixed possible conflicts between usings and user-supplied namespace (#4247)
* C#: Fixed possible conflicts between usings and user-supplied namespace

C#: Added the global qualifier to using directives to prevent possible conflicts with the user-supplied namespace. Also prevents unintentional type hiding. Resolves issue #4242.

* Updated C# generated code files
2017-03-29 11:09:25 -07:00
tianyapiaozi
a5cc2092a6 Support binary search for struct in cpp (#4245)
* Support binary search for struct in cpp

CreateVectorOfSortedStruct is provided for convenience.

* fix continuous-integration error

* add generated files

* compile Ability.cs in csharp test

* compile Ability.cs in csharp

* modify according to code review
2017-03-29 09:51:12 -07:00
Wouter van Oortmerssen
89041a1686 Add a VectorCast function that safely casts from
Vector<Offset<T>> to Vector<Offset<U>> if U is a base
class of T.

This is useful for when you want to generically
iterate over a vector of objects that derive from
flatbuffers::Table.

Change-Id: I59161e3b9f40501f72e02b46509be9dc8ab86c6b
2017-03-27 17:50:30 -07:00
Wouter van Oortmerssen
7a36419f24 Fixing closure compile compatibility when --gen-mutable is used.
Change-Id: I8bf575ba6dc795d2d2eec02fa8977dcc2594eaa6
2017-03-27 17:50:30 -07:00
Jesper Stemann Andersen
281284fa5d Fixed building and warnings on Arduino (16 bit platform). (#4197)
Building on Arduino fixed by conditional includes of cstdint and utility. In the Standard C++ for Arduino (port of uClibc++):
* cstdint is not present.
* utility is named utility.h.

Replaced size_t with uoffset_t for Verifier::max_tables_, max_depth_, depth_, and num_tables_ to ensure 32-bit values are used (and not 16-bit) - gave rise to a warning.
2017-03-27 09:38:04 -07:00
Lawrence Chan
1a27c7017a C++: Add default value handling to mutation/SetField code (#4230)
* Add default value handling to mutation/SetField code

* Shorten reflection SetField impl

* Modify impl to work with C++03

* Add more mutation tests

* Fail SetField if non-scalar

* Add IsScalar/IsInteger/IsFloat for reflection::BaseType

* Use new IsScalar/IsInteger/IsFloat in reflection SetField

* Assume scalar is either int or float
2017-03-20 17:36:27 -07:00
Flier Lu
b8f5f84437 add command line argument for go namespace (#4222) 2017-03-20 16:08:35 -07:00
Alexander Gallego
f2071e4f80 Add arbitrary string type to the native object API (#4218)
* Custom strings are very common for optimizations around small objects
  or growth style optimizations, i.e.: grow at 1.57 times vs doubling vs..

  A second common strategy is to cooperate w/ the memory allocator
  see FBString[1] and seastar[2] string for examples.

[1] fbstring: https://github.com/facebook/folly/blob/master/folly/docs/FBString.md
[2] sstring: https://github.com/scylladb/seastar/blob/master/core/sstring.hh
2017-03-20 16:02:04 -07:00
Jun Hyeon, Nam
9c25ecdcd1 C++: add String::str() function (#4234)
for convenience
2017-03-18 10:09:56 -07:00
Jun Hyeon, Nam
1beed12e59 fixed duplicate symbol error in flexbuffers.h (#4233)
1. modified the function that omitted inline.
2. changed the static global functions to inline functions.
2017-03-18 10:08:39 -07:00
Flier Lu
4cd71d67f1 GO: add _ postfix to identiy conflict golang keyword (#4221)
* add _ postfix to identiy conflict golang keyword

* make VS2010 happy
2017-03-15 18:34:53 -07:00
Aaron Hudon
d9bc5ec047 fixed flag for javascript (#4223)
--javascript flag does not work in the 1.6 flatc.exe, changed to --js
2017-03-15 15:16:43 -07:00
Koichi Shiraishi
c04c143cf0 tests: update monster_test.bfbs binary file with generate_code.sh (#4220)
Signed-off-by: Koichi Shiraishi <zchee.io@gmail.com>
2017-03-15 14:53:37 -07:00
Koichi Shiraishi
c6aae45364 sample: update auto-generated monster_generated.h (#4219)
Signed-off-by: Koichi Shiraishi <zchee.io@gmail.com>
2017-03-15 14:52:47 -07:00
Alexander Theißen
7f2a1c90d5 Prevent flatbuffers::Vector and flatbuffers::VectorOfAny to be copied (#4217) 2017-03-13 08:53:30 -07:00
chronoxor
f5387387de Pedantic Visual Studio build (/W4 /WX) (#4214)
* Pedantic Visual Studio build (/W4 /WX)

* Pedantic Visual Studio build (/W4 /WX)

* Pedantic Visual Studio build (/W4 /WX)

* Remove /wd4512 from CMakeLists.txt

* Suppress Visual Studio 4512 warning ('class' : assignment operator could not be generated)
2017-03-10 10:27:30 -08:00
Louis-Paul CORDIER
e7e4dc755d NoError was returning on DoParse method when file was empty (#4208)
* NoError was returning on DoParse method when file was empty.

* change NoError message in DoParse.
2017-03-10 08:50:44 -08:00
chronoxor
b8224809ad VS2015 warning "conditional expression is constant" (#4210)
* VS2015 warning "conditional expression is constant"

* VS2015 warning "conditional expression is constant"
2017-03-08 13:34:38 -08:00
Dale Lukas Peterson
bb22fb5756 Fix broken symlink to CONTRIBUTING.md (#4212) 2017-03-08 13:16:11 -08:00
Christian Helmich
ff274771ba fixed path being ignored in GenerateCppGRPC (#4207) 2017-03-08 09:08:40 -08:00
Hadriel Kaplan
15bf626191 Add a backwards-compatible version of VerifyBuffer() (#4201) 2017-03-08 08:25:37 -08:00
Zarian Waheed
ac106e835c Fixing broken link and added missing <map> header include. (#4199) 2017-03-03 09:47:52 -08:00
xiaohaoliang
640b525e83 optimization of FlatBufferBuilder::CreateVector() (#4198)
optimization of FlatBufferBuilder::CreateVector()
1. optimization of FlatBufferBuilder::CreateVector() for "1 == sizeof(T)" ( such as [byte], [ubyte]).
2. For my project, it was about 10x improvement on flatbuffers serialization.
3. why not "string": "string, which may only hold UTF-8 or 7-bit ASCII. For other text encodings or general binary data use vectors ([byte] or [ubyte]) instead."
2017-03-03 09:40:43 -08:00
Raman
0b379211dc Fixed problem with uint keys (#4172)
* Fixed problem with uint keys

* removed excess check

* Resolved problem with big uint, ubyte keys in Java
2017-02-28 14:16:50 -08:00
Louis-Paul CORDIER
bb223da258 C++ generator: Pre-allocating std::vector in UnPack methods. (#4187) 2017-02-25 22:10:17 -08:00
Andrei Lebedev
17c5f89d4f Fixed move constructor in generated union class (#4192)
* Fixed move constructor in generated union class

* Removed delegating constructor
2017-02-25 22:06:48 -08:00
Andrei Lebedev
695d26183a Remove libc++ and c++abi requirement on Linux with clang (#4189) 2017-02-25 21:47:57 -08:00
Kameiha
f5120a2aaf more safer (#4186)
push_small(T little_endian_t) => push_small(const T& little_endian_t)
2017-02-25 21:24:43 -08:00
Franken
037314a059 [C++] Additional accessors for fields of union types. (#4184)
* Additional accessors for fields of union types.

* Reveal the hidden parameter.

* External explicit specializations for templated accessors.

* Changes according to code style. Generated code included as well.
2017-02-25 21:23:32 -08:00
litianzhao
ebcfbbadf0 fix #4180: Long.prototype.toFloat64() overflow (#4182) 2017-02-20 11:20:56 -08:00
Wouter van Oortmerssen
6561c7a31f Temporarily disabled VS2010 warning 4512.
Change-Id: Ib75b4cc651ac8f67cd262c8293fca1ac590f6b71
2017-02-15 17:46:00 -08:00
Wouter van Oortmerssen
a6d98fb067 Fixed VS x64 warnings in flexbuffers.h 2017-02-15 17:41:00 -08:00
Wouter van Oortmerssen
3a2d3a232f Removed spurious "aa" from flatc usage message.
Change-Id: Ia1812d594882ce6c51002d07827ccec267d138bb
2017-02-15 14:59:25 -08:00
114 changed files with 8227 additions and 1693 deletions

6
.gitignore vendored
View File

@@ -48,6 +48,7 @@ tests/monsterdata_java_wire.mon
tests/monsterdata_go_wire.mon tests/monsterdata_go_wire.mon
tests/monsterdata_javascript_wire.mon tests/monsterdata_javascript_wire.mon
tests/unicode_test.mon tests/unicode_test.mon
tests/ts/
CMakeLists.txt.user CMakeLists.txt.user
CMakeScripts/** CMakeScripts/**
CTestTestfile.cmake CTestTestfile.cmake
@@ -66,3 +67,8 @@ build/VS2010/FlatBuffers.opensdf
build/VS2010/ipch/**/*.ipch build/VS2010/ipch/**/*.ipch
*.so *.so
Testing/Temporary Testing/Temporary
.cproject
.settings/
.project
net/**/obj
node_modules/

View File

@@ -24,6 +24,7 @@ endif()
set(FlatBuffers_Library_SRCS set(FlatBuffers_Library_SRCS
include/flatbuffers/code_generators.h include/flatbuffers/code_generators.h
include/flatbuffers/base.h
include/flatbuffers/flatbuffers.h include/flatbuffers/flatbuffers.h
include/flatbuffers/hash.h include/flatbuffers/hash.h
include/flatbuffers/idl.h include/flatbuffers/idl.h
@@ -31,6 +32,7 @@ set(FlatBuffers_Library_SRCS
include/flatbuffers/reflection.h include/flatbuffers/reflection.h
include/flatbuffers/reflection_generated.h include/flatbuffers/reflection_generated.h
include/flatbuffers/flexbuffers.h include/flatbuffers/flexbuffers.h
include/flatbuffers/registry.h
src/code_generators.cpp src/code_generators.cpp
src/idl_parser.cpp src/idl_parser.cpp
src/idl_gen_text.cpp src/idl_gen_text.cpp
@@ -102,7 +104,7 @@ if(EXISTS "${CMAKE_TOOLCHAIN_FILE}")
# is being configured externally # is being configured externally
elseif(APPLE) elseif(APPLE)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -stdlib=libc++") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -stdlib=libc++")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -pedantic -Werror -Wextra") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -pedantic -Werror -Wextra -Wno-unused-parameter")
elseif(CMAKE_COMPILER_IS_GNUCXX) elseif(CMAKE_COMPILER_IS_GNUCXX)
if(CYGWIN) if(CYGWIN)
set(CMAKE_CXX_FLAGS set(CMAKE_CXX_FLAGS
@@ -126,9 +128,14 @@ elseif(CMAKE_COMPILER_IS_GNUCXX)
elseif(${CMAKE_CXX_COMPILER_ID} MATCHES "Clang") elseif(${CMAKE_CXX_COMPILER_ID} MATCHES "Clang")
set(CMAKE_CXX_FLAGS set(CMAKE_CXX_FLAGS
"${CMAKE_CXX_FLAGS} -std=c++0x -stdlib=libc++ -Wall -pedantic -Werror \ "${CMAKE_CXX_FLAGS} -std=c++0x -Wall -pedantic -Werror \
-Wextra") -Wextra -Wno-unused-parameter")
if(NOT "${CMAKE_SYSTEM_NAME}" MATCHES "FreeBSD") 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 set(CMAKE_EXE_LINKER_FLAGS
"${CMAKE_EXE_LINKER_FLAGS} -lc++abi") "${CMAKE_EXE_LINKER_FLAGS} -lc++abi")
endif() endif()
@@ -138,6 +145,11 @@ elseif(${CMAKE_CXX_COMPILER_ID} MATCHES "Clang")
set(CMAKE_CXX_FLAGS set(CMAKE_CXX_FLAGS
"${CMAKE_CXX_FLAGS} -fsigned-char") "${CMAKE_CXX_FLAGS} -fsigned-char")
elseif(MSVC)
# Visual Studio pedantic build settings
# warning C4512: assignment operator could not be generated
# warning C4316: object allocated on the heap may not be aligned
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4 /WX /wd4512 /wd4316")
endif() endif()
if(FLATBUFFERS_CODE_COVERAGE) if(FLATBUFFERS_CODE_COVERAGE)
@@ -163,6 +175,10 @@ if(FLATBUFFERS_BUILD_FLATC)
if(NOT FLATBUFFERS_FLATC_EXECUTABLE) if(NOT FLATBUFFERS_FLATC_EXECUTABLE)
set(FLATBUFFERS_FLATC_EXECUTABLE $<TARGET_FILE:flatc>) set(FLATBUFFERS_FLATC_EXECUTABLE $<TARGET_FILE:flatc>)
endif() endif()
if(MSVC)
# Make flatc.exe not depend on runtime dlls for easy distribution.
target_compile_options(flatc PUBLIC $<$<CONFIG:Release>:/MT>)
endif()
endif() endif()
if(FLATBUFFERS_BUILD_FLATHASH) if(FLATBUFFERS_BUILD_FLATHASH)
@@ -181,6 +197,7 @@ function(compile_flatbuffers_schema_to_cpp SRC_FBS)
OUTPUT ${GEN_HEADER} OUTPUT ${GEN_HEADER}
COMMAND "${FLATBUFFERS_FLATC_EXECUTABLE}" -c --no-includes --gen-mutable COMMAND "${FLATBUFFERS_FLATC_EXECUTABLE}" -c --no-includes --gen-mutable
--gen-object-api -o "${SRC_FBS_DIR}" --gen-object-api -o "${SRC_FBS_DIR}"
-I "${CMAKE_CURRENT_SOURCE_DIR}/tests/include_test"
"${CMAKE_CURRENT_SOURCE_DIR}/${SRC_FBS}" "${CMAKE_CURRENT_SOURCE_DIR}/${SRC_FBS}"
DEPENDS flatc) DEPENDS flatc)
endfunction() endfunction()
@@ -211,10 +228,10 @@ endif()
if(FLATBUFFERS_BUILD_GRPCTEST) if(FLATBUFFERS_BUILD_GRPCTEST)
if(CMAKE_COMPILER_IS_GNUCXX) if(CMAKE_COMPILER_IS_GNUCXX)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-unused-parameter") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-unused-parameter -Wno-shadow")
endif() endif()
add_executable(grpctest ${FlatBuffers_GRPCTest_SRCS}) add_executable(grpctest ${FlatBuffers_GRPCTest_SRCS})
target_link_libraries(grpctest grpc++_unsecure grpc pthread dl) target_link_libraries(grpctest grpc++_unsecure pthread dl)
endif() endif()
if(FLATBUFFERS_INSTALL) if(FLATBUFFERS_INSTALL)

View File

@@ -4,6 +4,11 @@ branches:
os: Visual Studio 2015 os: Visual Studio 2015
environment:
matrix:
- CMAKE_VS_VERSION: "10 2010"
- CMAKE_VS_VERSION: "14 2015"
platform: platform:
- x86 - x86
- x64 - x64
@@ -13,7 +18,7 @@ configuration:
- Release - Release
before_build: before_build:
- cmake -G"Visual Studio 10 2010" - cmake -G"Visual Studio %CMAKE_VS_VERSION%"
# This cuts down on a lot of noise generated by xamarin warnings. # This cuts down on a lot of noise generated by xamarin warnings.
- del "C:\Program Files (x86)\MSBuild\14.0\Microsoft.Common.targets\ImportAfter\Xamarin.Common.targets" - del "C:\Program Files (x86)\MSBuild\14.0\Microsoft.Common.targets\ImportAfter\Xamarin.Common.targets"
@@ -30,8 +35,8 @@ test_script:
- "JavaTest.bat" - "JavaTest.bat"
- rem "---------------- JS -----------------" - rem "---------------- JS -----------------"
- "node --version" - "node --version"
- "..\\%CONFIGURATION%\\flatc -b monster_test.fbs unicode_test.json" - "..\\%CONFIGURATION%\\flatc -b -I include_test monster_test.fbs unicode_test.json"
- "node JavaScriptTest" - "node JavaScriptTest ./monster_test_generated"
- rem "---------------- C# -----------------" - rem "---------------- C# -----------------"
# Have to compile this here rather than in "build" above because AppVeyor only # Have to compile this here rather than in "build" above because AppVeyor only
# supports building one project?? # supports building one project??

View File

@@ -1 +1 @@
../../CONTRIBUTING ../../CONTRIBUTING.md

View File

@@ -29,7 +29,7 @@ For any schema input files, one or more generators can be specified:
- `--python`, `-p`: Generate Python code. - `--python`, `-p`: Generate Python code.
- `--javascript`, `-s`: Generate JavaScript code. - `--js`, `-s`: Generate JavaScript code.
- `--php`: Generate PHP code. - `--php`: Generate PHP code.
@@ -123,5 +123,7 @@ Additional options:
- `--include-prefix PATH` : Prefix this path to any generated include - `--include-prefix PATH` : Prefix this path to any generated include
statements. statements.
- `--keep-prefix` : Keep original prefix of schema include statement.
NOTE: short-form options for generators are deprecated, use the long form NOTE: short-form options for generators are deprecated, use the long form
whenever possible. whenever possible.

View File

@@ -200,6 +200,15 @@ pointer type (`my_ptr<T>`), or by specifying `naked` as the type to get `T *`
pointers. Unlike the smart pointers, naked pointers do not manage memory for pointers. Unlike the smart pointers, naked pointers do not manage memory for
you, so you'll have to manage their lifecycles manually. you, so you'll have to manage their lifecycles manually.
# Using different string type.
By default the object tree is built out of `std::string`, but you can
influence this either globally (using the `--cpp-str-type` argument to
`flatc`) or per field using the `cpp_str_type` attribute.
The type must support T::c_str() and T::length() as member functions.
## Reflection (& Resizing) ## Reflection (& Resizing)
There is experimental support for reflection in FlatBuffers, allowing you to There is experimental support for reflection in FlatBuffers, allowing you to
@@ -402,4 +411,22 @@ manually wrap it in synchronisation primites. There's no automatic way to
accomplish this, by design, as we feel multithreaded construction accomplish this, by design, as we feel multithreaded construction
of a single buffer will be rare, and synchronisation overhead would be costly. of a single buffer will be rare, and synchronisation overhead would be costly.
## Advanced union features
The C++ implementation currently supports vectors of unions (i.e. you can
declare a field as `[T]` where `T` is a union type instead of a table type). It
also supports structs and strings in unions, besides tables.
For an example of these features, see `tests/union_vector`, and
`UnionVectorTest` in `test.cpp`.
Since these features haven't been ported to other languages yet, if you
choose to use them, you won't be able to use these buffers in other languages
(`flatc` will refuse to compile a schema that uses these features).
These features reduce the amount of "table wrapping" that was previously
needed to use unions.
To use scalars, simply wrap them in a struct.
<br> <br>

View File

@@ -125,7 +125,17 @@ map["unknown"].IsNull(); // true
# Binary encoding # Binary encoding
A description of how FlexBuffers are encoded is in the A description of how FlexBuffers are encoded is in the
[internals](@ref flatbuffers_internals) document. [internals](Internals.md#flexbuffers) document.
# Nesting inside a FlatBuffer
You can mark a field as containing a FlexBuffer, e.g.
a:[ubyte] (flexbuffer);
A special accessor will be generated that allows you to access the root value
directly, e.g. `a_flexbuffer_root().AsInt64()`.
# Efficiency tips # Efficiency tips

View File

@@ -147,19 +147,20 @@ To use it:
array. array.
- Instead of calling standard generated method, - Instead of calling standard generated method,
e.g.: `Monster.createTestarrayoftablesVector`, e.g.: `Monster.createTestarrayoftablesVector`,
call `CreateMySortedVectorOfTables` in C# or call `CreateSortedVectorOfMonster` in C# or
`createSortedVectorOfTables` (from the `FlatBufferBuilder` object) in Java, `createSortedVectorOfTables` (from the `FlatBufferBuilder` object) in Java,
which will first sort all offsets such that the tables they refer to which will first sort all offsets such that the tables they refer to
are sorted by the key field, then serialize it. are sorted by the key field, then serialize it.
- Now when you're accessing the FlatBuffer, you can use `LookupByKey` - Now when you're accessing the FlatBuffer, you can use
to access elements of the vector, e.g.: the `ByKey` accessor to access elements of the vector, e.g.:
`Monster.lookupByKey(tablesVectorOffset, "Frodo", dataBuffer)`, `monster.testarrayoftablesByKey("Frodo")` in Java or
`monster.TestarrayoftablesByKey("Frodo")` in C#,
which returns an object of the corresponding table type, which returns an object of the corresponding table type,
or `null` if not found. or `null` if not found.
`LookupByKey` performs a binary search, so should have a similar speed to `ByKey` performs a binary search, so should have a similar
`Dictionary`, though may be faster because of better caching. `LookupByKey` speed to `Dictionary`, though may be faster because of better caching.
only works if the vector has been sorted, it will likely not find elements `ByKey` only works if the vector has been sorted, it will
if it hasn't been sorted. likely not find elements if it hasn't been sorted.
## Text parsing ## Text parsing

View File

@@ -302,6 +302,9 @@ Current understood attributes:
(which must be a vector of ubyte) contains flatbuffer data, for which the (which must be a vector of ubyte) contains flatbuffer data, for which the
root type is given by `table_name`. The generated code will then produce root type is given by `table_name`. The generated code will then produce
a convenient accessor for the nested FlatBuffer. a convenient accessor for the nested FlatBuffer.
- `flexbuffer` (on a field): this indicates that the field
(which must be a vector of ubyte) contains flexbuffer data. The generated
code will then produce a convenient accessor for the FlexBuffer root.
- `key` (on a field): this field is meant to be used as a key when sorting - `key` (on a field): this field is meant to be used as a key when sorting
a vector of the type of table it sits in. Can be used for in-place a vector of the type of table it sits in. Can be used for in-place
binary search. binary search.

View File

@@ -160,6 +160,7 @@ the `schema` that defines the template for our monsters:
color:Color = Blue; // Enum. color:Color = Blue; // Enum.
weapons:[Weapon]; // Vector of tables. weapons:[Weapon]; // Vector of tables.
equipped:Equipment; // Union. equipped:Equipment; // Union.
path:[Vec3]; // Vector of structs.
} }
table Weapon { table Weapon {
@@ -799,6 +800,70 @@ elements by calling a lambda. For the common case of `std::vector<std::string>`
there's also `CreateVectorOfStrings`. there's also `CreateVectorOfStrings`.
</div> </div>
Note that vectors of structs are serialized differently from tables, since
structs are stored in-line in the vector. For example, to create a vector
for the `path` field above:
<div class="language-cpp">
~~~{.cpp}
Vec3 points[] = { Vec3(1.0f, 2.0f, 3.0f), Vec3(4.0f, 5.0f, 6.0f) };
auto path = fbb.CreateVectorOfStructs(points, 2);
~~~
</div>
<div class="language-java">
~~~{.java}
Monster.startPathVector(fbb, 2);
Vec3.createVec3(builder, 1.0f, 2.0f, 3.0f);
Vec3.createVec3(builder, 4.0f, 5.0f, 6.0f);
int path = fbb.endVector();
~~~
</div>
<div class="language-csharp">
~~~{.cs}
Monster.StartPathVector(fbb, 2);
Vec3.CreateVec3(builder, 1.0f, 2.0f, 3.0f);
Vec3.CreateVec3(builder, 4.0f, 5.0f, 6.0f);
var path = fbb.EndVector();
~~~
</div>
<div class="language-go">
~~~{.go}
sample.MonsterStartPathVector(builder, 2)
sample.CreateVec3(builder, 1.0, 2.0, 3.0)
sample.CreateVec3(builder, 4.0, 5.0, 6.0)
path := builder.EndVector(2)
~~~
</div>
<div class="language-python">
~~~{.py}
MyGame.Example.Monster.MonsterStartPathVector(builder, 2)
MyGame.Sample.Vec3.CreateVec3(builder, 1.0, 2.0, 3.0)
MyGame.Sample.Vec3.CreateVec3(builder, 4.0, 5.0, 6.0)
path = builder.EndVector(2)
~~~
</div>
<div class="language-javascript">
~~~{.js}
MyGame.Example.Monster.startPathVector(builder, 2);
MyGame.Sample.Vec3.createVec3(builder, 1.0, 2.0, 3.0);
MyGame.Sample.Vec3.createVec3(builder, 4.0, 5.0, 6.0);
var path = builder.endVector();
~~~
</div>
<div class="language-php">
~~~{.php}
\MyGame\Example\Monster::StartPathVector($builder, 2);
\MyGame\Sample\Vec3::CreateVec3($builder, 1.0, 2.0, 3.0);
\MyGame\Sample\Vec3::CreateVec3($builder, 1.0, 2.0, 3.0);
$path = $builder->endVector();
~~~
</div>
<div class="language-c">
~~~{.c}
// TBD
~~~
</div>
We have now serialized the non-scalar components of the orc, so we We have now serialized the non-scalar components of the orc, so we
can serialize the monster itself: can serialize the monster itself:
@@ -812,7 +877,7 @@ can serialize the monster itself:
// to set all fields. // to set all fields.
auto orc = CreateMonster(builder, Vec3(1.0f, 2.0f, 3.0f), mana, hp, name, auto orc = CreateMonster(builder, Vec3(1.0f, 2.0f, 3.0f), mana, hp, name,
inventory, Color_Red, weapons, Equipment_Weapon, inventory, Color_Red, weapons, Equipment_Weapon,
axe.Union()); axe.Union(), path);
~~~ ~~~
</div> </div>
<div class="language-java"> <div class="language-java">
@@ -827,6 +892,7 @@ can serialize the monster itself:
Monster.addWeapons(builder, weapons); Monster.addWeapons(builder, weapons);
Monster.addEquippedType(builder, Equipment.Weapon); Monster.addEquippedType(builder, Equipment.Weapon);
Monster.addEquipped(builder, axe); Monster.addEquipped(builder, axe);
Monster.addPath(builder, path);
int orc = Monster.endMonster(builder); int orc = Monster.endMonster(builder);
~~~ ~~~
</div> </div>
@@ -842,6 +908,7 @@ can serialize the monster itself:
Monster.AddWeapons(builder, weapons); Monster.AddWeapons(builder, weapons);
Monster.AddEquippedType(builder, Equipment.Weapon); Monster.AddEquippedType(builder, Equipment.Weapon);
Monster.AddEquipped(builder, axe.Value); // Axe Monster.AddEquipped(builder, axe.Value); // Axe
Monster.AddPath(builder, path);
var orc = Monster.EndMonster(builder); var orc = Monster.EndMonster(builder);
~~~ ~~~
</div> </div>
@@ -857,6 +924,7 @@ can serialize the monster itself:
sample.MonsterAddWeapons(builder, weapons) sample.MonsterAddWeapons(builder, weapons)
sample.MonsterAddEquippedType(builder, sample.EquipmentWeapon) sample.MonsterAddEquippedType(builder, sample.EquipmentWeapon)
sample.MonsterAddEquipped(builder, axe) sample.MonsterAddEquipped(builder, axe)
sample.MonsterAddPath(builder, path)
orc := sample.MonsterEnd(builder) orc := sample.MonsterEnd(builder)
~~~ ~~~
</div> </div>
@@ -875,6 +943,7 @@ can serialize the monster itself:
MyGame.Sample.Monster.MonsterAddEquippedType( MyGame.Sample.Monster.MonsterAddEquippedType(
builder, MyGame.Sample.Equipment.Equipment().Weapon) builder, MyGame.Sample.Equipment.Equipment().Weapon)
MyGame.Sample.Monster.MonsterAddEquipped(builder, axe) MyGame.Sample.Monster.MonsterAddEquipped(builder, axe)
MyGame.Sample.Monster.MonsterAddPath(builder, path)
orc = MyGame.Sample.Monster.MonsterEnd(builder) orc = MyGame.Sample.Monster.MonsterEnd(builder)
~~~ ~~~
</div> </div>
@@ -891,6 +960,7 @@ can serialize the monster itself:
MyGame.Sample.Monster.addWeapons(builder, weapons); MyGame.Sample.Monster.addWeapons(builder, weapons);
MyGame.Sample.Monster.addEquippedType(builder, MyGame.Sample.Equipment.Weapon); MyGame.Sample.Monster.addEquippedType(builder, MyGame.Sample.Equipment.Weapon);
MyGame.Sample.Monster.addEquipped(builder, axe); MyGame.Sample.Monster.addEquipped(builder, axe);
MyGame.Sample.Monster.addPath(builder, path);
var orc = MyGame.Sample.Monster.endMonster(builder); var orc = MyGame.Sample.Monster.endMonster(builder);
~~~ ~~~
</div> </div>
@@ -907,6 +977,7 @@ can serialize the monster itself:
\MyGame\Sample\Monster::AddWeapons($builder, $weapons); \MyGame\Sample\Monster::AddWeapons($builder, $weapons);
\MyGame\Sample\Monster::AddEquippedType($builder, \MyGame\Sample\Equipment::Weapon); \MyGame\Sample\Monster::AddEquippedType($builder, \MyGame\Sample\Equipment::Weapon);
\MyGame\Sample\Monster::AddEquipped($builder, $axe); \MyGame\Sample\Monster::AddEquipped($builder, $axe);
\MyGame\Sample\Monster::AddPath($builder, $path);
$orc = \MyGame\Sample\Monster::EndMonster($builder); $orc = \MyGame\Sample\Monster::EndMonster($builder);
~~~ ~~~
</div> </div>
@@ -921,7 +992,7 @@ can serialize the monster itself:
ns(Equipment_union_ref_t) equipped = ns(Equipment_as_Weapon(axe)); ns(Equipment_union_ref_t) equipped = ns(Equipment_as_Weapon(axe));
ns(Vec3_t) pos = { 1.0f, 2.0f, 3.0f }; ns(Vec3_t) pos = { 1.0f, 2.0f, 3.0f };
ns(Monster_create_as_root(B, &pos, mana, hp, name, inventory, ns(Color_Red), ns(Monster_create_as_root(B, &pos, mana, hp, name, inventory, ns(Color_Red),
weapons, equipped)); weapons, equipped, path));
~~~ ~~~
</div> </div>
@@ -929,10 +1000,10 @@ Note how we create `Vec3` struct in-line in the table. Unlike tables, structs
are simple combinations of scalars that are always stored inline, just like are simple combinations of scalars that are always stored inline, just like
scalars themselves. scalars themselves.
**Important**: you should not nest tables or any other objects, which is why **Important**: Unlike structs, you should not nest tables or other objects,
we created all the strings/vectors/tables that this monster refers to before which is why we created all the strings/vectors/tables that this monster refers
`start`. If you try to create any of them between `start` and `end`, you to before `start`. If you try to create any of them between `start` and `end`,
will get an assert/exception/panic depending on your language. you will get an assert/exception/panic depending on your language.
*Note: Since we are passing `150` as the `mana` field, which happens to be the *Note: Since we are passing `150` as the `mana` field, which happens to be the
default value, the field will not actually be written to the buffer, since the default value, the field will not actually be written to the buffer, since the
@@ -1470,10 +1541,10 @@ To access sub-objects, in the case of our `pos`, which is a `Vec3`:
</div> </div>
<div class="language-csharp"> <div class="language-csharp">
~~~{.cs} ~~~{.cs}
var pos = monster.Pos var pos = monster.Pos.Value;
var x = pos.X var x = pos.X;
var y = pos.Y var y = pos.Y;
var z = pos.Z var z = pos.Z;
~~~ ~~~
</div> </div>
<div class="language-go"> <div class="language-go">
@@ -1547,7 +1618,7 @@ FlatBuffers `vector`.
<div class="language-csharp"> <div class="language-csharp">
~~~{.cs} ~~~{.cs}
int invLength = monster.InventoryLength; int invLength = monster.InventoryLength;
var thirdItem = monster.GetInventory(2); var thirdItem = monster.Inventory(2);
~~~ ~~~
</div> </div>
<div class="language-go"> <div class="language-go">
@@ -1604,8 +1675,8 @@ except your need to handle the result as a FlatBuffer `table`:
<div class="language-csharp"> <div class="language-csharp">
~~~{.cs} ~~~{.cs}
int weaponsLength = monster.WeaponsLength; int weaponsLength = monster.WeaponsLength;
var secondWeaponName = monster.GetWeapons(1).Name; var secondWeaponName = monster.Weapons(1).Name;
var secondWeaponDamage = monster.GetWeapons(1).Damage; var secondWeaponDamage = monster.Weapons(1).Damage;
~~~ ~~~
</div> </div>
<div class="language-go"> <div class="language-go">
@@ -1687,8 +1758,7 @@ We can access the type to dynamically cast the data as needed (since the
var unionType = monster.EquippedType; var unionType = monster.EquippedType;
if (unionType == Equipment.Weapon) { if (unionType == Equipment.Weapon) {
var weapon = (Weapon)monster.GetEquipped(new Weapon()); // Requires explicit cast var weapon = monster.Equipped<Weapon>().Value;
// to `Weapon`.
var weaponName = weapon.Name; // "Axe" var weaponName = weapon.Name; // "Axe"
var weaponDamage = weapon.Damage; // 5 var weaponDamage = weapon.Damage; // 5

View File

@@ -765,6 +765,7 @@ INPUT = "FlatBuffers.md" \
"../../CONTRIBUTING.md" \ "../../CONTRIBUTING.md" \
"Tutorial.md" \ "Tutorial.md" \
"GoApi.md" \ "GoApi.md" \
"gRPC/CppUsage.md" \
"groups" \ "groups" \
"../../java/com/google/flatbuffers" \ "../../java/com/google/flatbuffers" \
"../../python/flatbuffers/builder.py" \ "../../python/flatbuffers/builder.py" \
@@ -883,21 +884,21 @@ EXCLUDE_SYMBOLS =
# that contain example code fragments that are included (see the \include # that contain example code fragments that are included (see the \include
# command). # command).
EXAMPLE_PATH = "GoApi_generated.txt" EXAMPLE_PATH = "GoApi_generated.txt" "../../grpc/samples"
# If the value of the EXAMPLE_PATH tag contains directories, you can use the # If the value of the EXAMPLE_PATH tag contains directories, you can use the
# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and # EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and
# *.h) to filter out the source-files in the directories. If left blank all # *.h) to filter out the source-files in the directories. If left blank all
# files are included. # files are included.
EXAMPLE_PATTERNS = * EXAMPLE_PATTERNS = *.cpp *.h *.txt *.fbs
# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be # If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
# searched for input files to be used with the \include or \dontinclude commands # searched for input files to be used with the \include or \dontinclude commands
# irrespective of the value of the RECURSIVE tag. # irrespective of the value of the RECURSIVE tag.
# The default value is: NO. # The default value is: NO.
EXAMPLE_RECURSIVE = NO EXAMPLE_RECURSIVE = YES
# The IMAGE_PATH tag can be used to specify one or more files or directories # The IMAGE_PATH tag can be used to specify one or more files or directories
# that contain images that are to be included in the documentation (see the # that contain images that are to be included in the documentation (see the

View File

@@ -39,6 +39,10 @@
title="Use in Python"/> title="Use in Python"/>
<tab type="user" url="@ref flexbuffers" <tab type="user" url="@ref flexbuffers"
title="Schema-less version"/> title="Schema-less version"/>
<tab type="usergroup" url="" title="gRPC">
<tab type="user" url="@ref flatbuffers_grpc_guide_use_cpp"
title="Use in C++"/>
</tab>
</tab> </tab>
<tab type="user" url="@ref flatbuffers_support" <tab type="user" url="@ref flatbuffers_support"
title="Platform / Language / Feature support"/> title="Platform / Language / Feature support"/>

View File

@@ -0,0 +1,29 @@
Use in C++ {#flatbuffers_grpc_guide_use_cpp}
==========
## Before you get started
Before diving into the FlatBuffers gRPC usage in C++, you should already be
familiar with the following:
- FlatBuffers as a serialization format
- [gRPC](http://www.grpc.io/docs/) usage
## Using the FlatBuffers gRPC C++ library
NOTE: The examples below are also in the `grpc/samples/greeter` directory.
We will illustrate usage with the following schema:
@include grpc/samples/greeter/greeter.fbs
When we run `flatc`, we pass in the `--grpc` option and generage an additional
`greeter.grpc.fb.h` and `greeter.grpc.fb.cc`.
Example server code looks like this:
@include grpc/samples/greeter/server.cpp
Example client code looks like this:
@include grpc/samples/greeter/client.cpp

View File

@@ -0,0 +1,14 @@
CXXFLAGS ?= -I../../../include
LDFLAGS ?=
.PHONY: all
all: server client
greeter_generated.h: greeter.fbs
flatc --grpc --cpp $<
server: server.cpp greeter.grpc.fb.cc greeter_generated.h greeter.grpc.fb.h
g++ -std=c++11 -O2 $(CXXFLAGS) $(LDFLAGS) -lgpr -lgrpc -lgrpc++ server.cpp greeter.grpc.fb.cc -o $@
client: client.cpp greeter.grpc.fb.cc greeter_generated.h greeter.grpc.fb.h
g++ -std=c++11 -O2 $(CXXFLAGS) $(LDFLAGS) -lgpr -lgrpc -lgrpc++ client.cpp greeter.grpc.fb.cc -o $@

View File

@@ -0,0 +1,85 @@
#include "greeter.grpc.fb.h"
#include "greeter_generated.h"
#include <grpc++/grpc++.h>
#include <iostream>
#include <memory>
#include <string>
class GreeterClient {
public:
GreeterClient(std::shared_ptr<grpc::Channel> channel)
: stub_(Greeter::NewStub(channel)) {}
std::string SayHello(const std::string &name) {
flatbuffers::grpc::MessageBuilder mb;
auto name_offset = mb.CreateString(name);
auto request_offset = CreateHelloRequest(mb, name_offset);
mb.Finish(request_offset);
auto request_msg = mb.ReleaseMessage<HelloRequest>();
flatbuffers::grpc::Message<HelloReply> response_msg;
grpc::ClientContext context;
auto status = stub_->SayHello(&context, request_msg, &response_msg);
if (status.ok()) {
const HelloReply *response = response_msg.GetRoot();
return response->message()->str();
} else {
std::cerr << status.error_code() << ": " << status.error_message()
<< std::endl;
return "RPC failed";
}
}
void SayManyHellos(const std::string &name, int num_greetings,
std::function<void(const std::string &)> callback) {
flatbuffers::grpc::MessageBuilder mb;
auto name_offset = mb.CreateString(name);
auto request_offset =
CreateManyHellosRequest(mb, name_offset, num_greetings);
mb.Finish(request_offset);
auto request_msg = mb.ReleaseMessage<ManyHellosRequest>();
flatbuffers::grpc::Message<HelloReply> response_msg;
grpc::ClientContext context;
auto stream = stub_->SayManyHellos(&context, request_msg);
while (stream->Read(&response_msg)) {
const HelloReply *response = response_msg.GetRoot();
callback(response->message()->str());
}
auto status = stream->Finish();
if (!status.ok()) {
std::cerr << status.error_code() << ": " << status.error_message()
<< std::endl;
callback("RPC failed");
}
}
private:
std::unique_ptr<Greeter::Stub> stub_;
};
int main(int argc, char **argv) {
std::string server_address("localhost:50051");
auto channel =
grpc::CreateChannel(server_address, grpc::InsecureChannelCredentials());
GreeterClient greeter(channel);
std::string name("world");
std::string message = greeter.SayHello(name);
std::cerr << "Greeter received: " << message << std::endl;
int num_greetings = 10;
greeter.SayManyHellos(name, num_greetings, [](const std::string &message) {
std::cerr << "Greeter received: " << message << std::endl;
});
return 0;
}

View File

@@ -0,0 +1,17 @@
table HelloReply {
message:string;
}
table HelloRequest {
name:string;
}
table ManyHellosRequest {
name:string;
num_greetings:int;
}
rpc_service Greeter {
SayHello(HelloRequest):HelloReply;
SayManyHellos(ManyHellosRequest):HelloReply (streaming: "server");
}

View File

@@ -0,0 +1,80 @@
#include "greeter.grpc.fb.h"
#include "greeter_generated.h"
#include <grpc++/grpc++.h>
#include <iostream>
#include <memory>
#include <string>
class GreeterServiceImpl final : public Greeter::Service {
virtual grpc::Status SayHello(
grpc::ServerContext *context,
const flatbuffers::grpc::Message<HelloRequest> *request_msg,
flatbuffers::grpc::Message<HelloReply> *response_msg) override {
// flatbuffers::grpc::MessageBuilder mb_;
// We call GetRoot to "parse" the message. Verification is already
// performed by default. See the notes below for more details.
const HelloRequest *request = request_msg->GetRoot();
// Fields are retrieved as usual with FlatBuffers
const std::string &name = request->name()->str();
// `flatbuffers::grpc::MessageBuilder` is a `FlatBufferBuilder` with a
// special allocator for efficient gRPC buffer transfer, but otherwise
// usage is the same as usual.
auto msg_offset = mb_.CreateString("Hello, " + name);
auto hello_offset = CreateHelloReply(mb_, msg_offset);
mb_.Finish(hello_offset);
// The `ReleaseMessage<T>()` function detaches the message from the
// builder, so we can transfer the resopnse to gRPC while simultaneously
// detaching that memory buffer from the builer.
*response_msg = mb_.ReleaseMessage<HelloReply>();
assert(response_msg->Verify());
// Return an OK status.
return grpc::Status::OK;
}
virtual grpc::Status SayManyHellos(
grpc::ServerContext *context,
const flatbuffers::grpc::Message<ManyHellosRequest> *request_msg,
grpc::ServerWriter<flatbuffers::grpc::Message<HelloReply>> *writer)
override {
// The streaming usage below is simply a combination of standard gRPC
// streaming with the FlatBuffers usage shown above.
const ManyHellosRequest *request = request_msg->GetRoot();
const std::string &name = request->name()->str();
int num_greetings = request->num_greetings();
for (int i = 0; i < num_greetings; i++) {
auto msg_offset = mb_.CreateString("Many hellos, " + name);
auto hello_offset = CreateHelloReply(mb_, msg_offset);
mb_.Finish(hello_offset);
writer->Write(mb_.ReleaseMessage<HelloReply>());
}
return grpc::Status::OK;
}
flatbuffers::grpc::MessageBuilder mb_;
};
void RunServer() {
std::string server_address("0.0.0.0:50051");
GreeterServiceImpl service;
grpc::ServerBuilder builder;
builder.AddListeningPort(server_address, grpc::InsecureServerCredentials());
builder.RegisterService(&service);
std::unique_ptr<grpc::Server> server(builder.BuildAndStart());
std::cerr << "Server listening on " << server_address << std::endl;
server->Wait();
}
int main(int argc, const char *argv[]) {
RunServer();
return 0;
}

View File

@@ -0,0 +1,40 @@
/*
*
* Copyright 2015, Google Inc.
* 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.
*
*/
#ifndef SRC_COMPILER_CONFIG_H
#define SRC_COMPILER_CONFIG_H
// This file is here only because schema_interface.h, which is copied from gRPC,
// includes it. There is nothing for Flatbuffers to configure.
#endif // SRC_COMPILER_CONFIG_H

File diff suppressed because it is too large Load Diff

View File

@@ -41,8 +41,20 @@
#include <memory> #include <memory>
#include <vector> #include <vector>
#include "src/compiler/config.h"
#include "src/compiler/schema_interface.h" #include "src/compiler/schema_interface.h"
#ifndef GRPC_CUSTOM_STRING
#include <string>
#define GRPC_CUSTOM_STRING std::string
#endif
namespace grpc {
typedef GRPC_CUSTOM_STRING string;
} // namespace grpc
namespace grpc_cpp_generator { namespace grpc_cpp_generator {
// Contains all the parameters that are parsed from the command line. // Contains all the parameters that are parsed from the command line.
@@ -53,31 +65,73 @@ struct Parameters {
bool use_system_headers; bool use_system_headers;
// Prefix to any grpc include // Prefix to any grpc include
grpc::string grpc_search_path; grpc::string grpc_search_path;
// Generate GMOCK code to facilitate unit testing.
bool generate_mock_code;
}; };
// Return the prologue of the generated header file. // Return the prologue of the generated header file.
grpc::string GetHeaderPrologue(grpc_generator::File *file, const Parameters &params); grpc::string GetHeaderPrologue(grpc_generator::File *file,
const Parameters &params);
// Return the includes needed for generated header file. // Return the includes needed for generated header file.
grpc::string GetHeaderIncludes(grpc_generator::File *file, const Parameters &params); grpc::string GetHeaderIncludes(grpc_generator::File *file,
const Parameters &params);
// Return the includes needed for generated source file. // Return the includes needed for generated source file.
grpc::string GetSourceIncludes(grpc_generator::File *file, const Parameters &params); grpc::string GetSourceIncludes(grpc_generator::File *file,
const Parameters &params);
// Return the epilogue of the generated header file. // Return the epilogue of the generated header file.
grpc::string GetHeaderEpilogue(grpc_generator::File *file, const Parameters &params); grpc::string GetHeaderEpilogue(grpc_generator::File *file,
const Parameters &params);
// Return the prologue of the generated source file. // Return the prologue of the generated source file.
grpc::string GetSourcePrologue(grpc_generator::File *file, const Parameters &params); grpc::string GetSourcePrologue(grpc_generator::File *file,
const Parameters &params);
// Return the services for generated header file. // Return the services for generated header file.
grpc::string GetHeaderServices(grpc_generator::File *file, const Parameters &params); grpc::string GetHeaderServices(grpc_generator::File *file,
const Parameters &params);
// Return the services for generated source file. // Return the services for generated source file.
grpc::string GetSourceServices(grpc_generator::File *file, const Parameters &params); grpc::string GetSourceServices(grpc_generator::File *file,
const Parameters &params);
// Return the epilogue of the generated source file. // Return the epilogue of the generated source file.
grpc::string GetSourceEpilogue(grpc_generator::File *file, const Parameters &params); grpc::string GetSourceEpilogue(grpc_generator::File *file,
const Parameters &params);
// Return the prologue of the generated mock file.
grpc::string GetMockPrologue(grpc_generator::File *file,
const Parameters &params);
// Return the includes needed for generated mock file.
grpc::string GetMockIncludes(grpc_generator::File *file,
const Parameters &params);
// Return the services for generated mock file.
grpc::string GetMockServices(grpc_generator::File *file,
const Parameters &params);
// Return the epilogue of generated mock file.
grpc::string GetMockEpilogue(grpc_generator::File *file,
const Parameters &params);
// Return the prologue of the generated mock file.
grpc::string GetMockPrologue(grpc_generator::File *file,
const Parameters &params);
// Return the includes needed for generated mock file.
grpc::string GetMockIncludes(grpc_generator::File *file,
const Parameters &params);
// Return the services for generated mock file.
grpc::string GetMockServices(grpc_generator::File *file,
const Parameters &params);
// Return the epilogue of generated mock file.
grpc::string GetMockEpilogue(grpc_generator::File *file,
const Parameters &params);
} // namespace grpc_cpp_generator } // namespace grpc_cpp_generator

View File

@@ -44,6 +44,14 @@ grpc::string as_string(T x) {
return out.str(); return out.str();
} }
inline bool ClientOnlyStreaming(const grpc_generator::Method *method) {
return method->ClientStreaming() && !method->ServerStreaming();
}
inline bool ServerOnlyStreaming(const grpc_generator::Method *method) {
return !method->ClientStreaming() && method->ServerStreaming();
}
namespace grpc_go_generator { namespace grpc_go_generator {
// Returns string with first letter to lowerCase // Returns string with first letter to lowerCase
@@ -70,8 +78,8 @@ void GenerateImports(grpc_generator::File *file, grpc_generator::Printer *printe
printer->Print("//If you make any local changes, they will be lost\n"); printer->Print("//If you make any local changes, they will be lost\n");
printer->Print(vars, "//source: $filename$\n\n"); printer->Print(vars, "//source: $filename$\n\n");
printer->Print(vars, "package $Package$\n\n"); printer->Print(vars, "package $Package$\n\n");
if (file->additional_imports() != "") { if (file->additional_headers() != "") {
printer->Print(file->additional_imports().c_str()); printer->Print(file->additional_headers().c_str());
printer->Print("\n\n"); printer->Print("\n\n");
} }
printer->Print("import (\n"); printer->Print("import (\n");
@@ -86,11 +94,11 @@ void GenerateImports(grpc_generator::File *file, grpc_generator::Printer *printe
void GenerateServerMethodSignature(const grpc_generator::Method *method, grpc_generator::Printer *printer, void GenerateServerMethodSignature(const grpc_generator::Method *method, grpc_generator::Printer *printer,
std::map<grpc::string, grpc::string> vars) { std::map<grpc::string, grpc::string> vars) {
vars["Method"] = exportName(method->name()); vars["Method"] = exportName(method->name());
vars["Request"] = method->input_name(); vars["Request"] = method->get_input_type_name();
vars["Response"] = (vars["CustomMethodIO"] == "") ? method->output_name() : vars["CustomMethodIO"]; vars["Response"] = (vars["CustomMethodIO"] == "") ? method->get_output_type_name() : vars["CustomMethodIO"];
if (method->NoStreaming()) { if (method->NoStreaming()) {
printer->Print(vars, "$Method$($context$.Context, *$Request$) (*$Response$, error)"); printer->Print(vars, "$Method$($context$.Context, *$Request$) (*$Response$, error)");
} else if (method->ServerOnlyStreaming()) { } else if (ServerOnlyStreaming(method)) {
printer->Print(vars, "$Method$(*$Request$, $Service$_$Method$Server) error"); printer->Print(vars, "$Method$(*$Request$, $Service$_$Method$Server) error");
} else { } else {
printer->Print(vars, "$Method$($Service$_$Method$Server) error"); printer->Print(vars, "$Method$($Service$_$Method$Server) error");
@@ -100,8 +108,8 @@ void GenerateServerMethodSignature(const grpc_generator::Method *method, grpc_ge
void GenerateServerMethod(const grpc_generator::Method *method, grpc_generator::Printer *printer, void GenerateServerMethod(const grpc_generator::Method *method, grpc_generator::Printer *printer,
std::map<grpc::string, grpc::string> vars) { std::map<grpc::string, grpc::string> vars) {
vars["Method"] = exportName(method->name()); vars["Method"] = exportName(method->name());
vars["Request"] = method->input_name(); vars["Request"] = method->get_input_type_name();
vars["Response"] = (vars["CustomMethodIO"] == "") ? method->output_name() : vars["CustomMethodIO"]; vars["Response"] = (vars["CustomMethodIO"] == "") ? method->get_output_type_name() : vars["CustomMethodIO"];
vars["FullMethodName"] = "/" + vars["Package"] + "." + vars["Service"] + "/" + vars["Method"]; vars["FullMethodName"] = "/" + vars["Package"] + "." + vars["Service"] + "/" + vars["Method"];
vars["Handler"] = "_" + vars["Service"] + "_" + vars["Method"] + "_Handler"; vars["Handler"] = "_" + vars["Service"] + "_" + vars["Method"] + "_Handler";
if (method->NoStreaming()) { if (method->NoStreaming()) {
@@ -129,7 +137,7 @@ void GenerateServerMethod(const grpc_generator::Method *method, grpc_generator::
vars["StreamType"] = vars["ServiceUnexported"] + vars["Method"] + "Server"; vars["StreamType"] = vars["ServiceUnexported"] + vars["Method"] + "Server";
printer->Print(vars, "func $Handler$(srv interface{}, stream $grpc$.ServerStream) error {\n"); printer->Print(vars, "func $Handler$(srv interface{}, stream $grpc$.ServerStream) error {\n");
printer->Indent(); printer->Indent();
if (method->ServerOnlyStreaming()) { if (ServerOnlyStreaming(method)) {
printer->Print(vars, "m := new($Request$)\n"); printer->Print(vars, "m := new($Request$)\n");
printer->Print(vars, "if err := stream.RecvMsg(m); err != nil { return err }\n"); printer->Print(vars, "if err := stream.RecvMsg(m); err != nil { return err }\n");
printer->Print(vars, "return srv.($Service$Server).$Method$(m, &$StreamType${stream})\n"); printer->Print(vars, "return srv.($Service$Server).$Method$(m, &$StreamType${stream})\n");
@@ -139,9 +147,9 @@ void GenerateServerMethod(const grpc_generator::Method *method, grpc_generator::
printer->Outdent(); printer->Outdent();
printer->Print("}\n\n"); printer->Print("}\n\n");
bool genSend = method->BidiStreaming() || method->ServerOnlyStreaming(); bool genSend = method->BidiStreaming() || ServerOnlyStreaming(method);
bool genRecv = method->BidiStreaming() || method->ClientOnlyStreaming(); bool genRecv = method->BidiStreaming() || ClientOnlyStreaming(method);
bool genSendAndClose = method->ClientOnlyStreaming(); bool genSendAndClose = ClientOnlyStreaming(method);
printer->Print(vars, "type $Service$_$Method$Server interface { \n"); printer->Print(vars, "type $Service$_$Method$Server interface { \n");
printer->Indent(); printer->Indent();
@@ -194,12 +202,12 @@ void GenerateServerMethod(const grpc_generator::Method *method, grpc_generator::
void GenerateClientMethodSignature(const grpc_generator::Method *method, grpc_generator::Printer *printer, void GenerateClientMethodSignature(const grpc_generator::Method *method, grpc_generator::Printer *printer,
std::map<grpc::string, grpc::string> vars) { std::map<grpc::string, grpc::string> vars) {
vars["Method"] = exportName(method->name()); vars["Method"] = exportName(method->name());
vars["Request"] = ", in *" + ((vars["CustomMethodIO"] == "") ? method->input_name() : vars["CustomMethodIO"]); vars["Request"] = ", in *" + ((vars["CustomMethodIO"] == "") ? method->get_input_type_name() : vars["CustomMethodIO"]);
if (method->ClientOnlyStreaming() || method->BidiStreaming()) { if (ClientOnlyStreaming(method) || method->BidiStreaming()) {
vars["Request"] = ""; vars["Request"] = "";
} }
vars["Response"] = "* " + method->output_name(); vars["Response"] = "* " + method->get_output_type_name();
if (method->ClientOnlyStreaming() || method->BidiStreaming() || method->ServerOnlyStreaming()) { if (ClientOnlyStreaming(method) || method->BidiStreaming() || ServerOnlyStreaming(method)) {
vars["Response"] = vars["Service"] + "_" + vars["Method"] + "Client" ; vars["Response"] = vars["Service"] + "_" + vars["Method"] + "Client" ;
} }
printer->Print(vars, "$Method$(ctx $context$.Context$Request$, \n\topts... $grpc$.CallOption) ($Response$, error)"); printer->Print(vars, "$Method$(ctx $context$.Context$Request$, \n\topts... $grpc$.CallOption) ($Response$, error)");
@@ -213,8 +221,8 @@ void GenerateClientMethod(const grpc_generator::Method *method, grpc_generator::
printer->Print(" {\n"); printer->Print(" {\n");
printer->Indent(); printer->Indent();
vars["Method"] = exportName(method->name()); vars["Method"] = exportName(method->name());
vars["Request"] = (vars["CustomMethodIO"] == "") ? method->input_name() : vars["CustomMethodIO"]; vars["Request"] = (vars["CustomMethodIO"] == "") ? method->get_input_type_name() : vars["CustomMethodIO"];
vars["Response"] = method->output_name(); vars["Response"] = method->get_output_type_name();
vars["FullMethodName"] = "/" + vars["Package"] + "." + vars["Service"] + "/" + vars["Method"]; vars["FullMethodName"] = "/" + vars["Package"] + "." + vars["Service"] + "/" + vars["Method"];
if (method->NoStreaming()) { if (method->NoStreaming()) {
printer->Print(vars, "out := new($Response$)\n"); printer->Print(vars, "out := new($Response$)\n");
@@ -230,7 +238,7 @@ void GenerateClientMethod(const grpc_generator::Method *method, grpc_generator::
printer->Print("if err != nil { return nil, err }\n"); printer->Print("if err != nil { return nil, err }\n");
printer->Print(vars, "x := &$StreamType${stream}\n"); printer->Print(vars, "x := &$StreamType${stream}\n");
if (method->ServerOnlyStreaming()) { if (ServerOnlyStreaming(method)) {
printer->Print("if err := x.ClientStream.SendMsg(in); err != nil { return nil, err }\n"); printer->Print("if err := x.ClientStream.SendMsg(in); err != nil { return nil, err }\n");
printer->Print("if err := x.ClientStream.CloseSend(); err != nil { return nil, err }\n"); printer->Print("if err := x.ClientStream.CloseSend(); err != nil { return nil, err }\n");
} }
@@ -238,9 +246,9 @@ void GenerateClientMethod(const grpc_generator::Method *method, grpc_generator::
printer->Outdent(); printer->Outdent();
printer->Print("}\n\n"); printer->Print("}\n\n");
bool genSend = method->BidiStreaming() || method->ClientOnlyStreaming(); bool genSend = method->BidiStreaming() || ClientOnlyStreaming(method);
bool genRecv = method->BidiStreaming() || method->ServerOnlyStreaming(); bool genRecv = method->BidiStreaming() || ServerOnlyStreaming(method);
bool genCloseAndRecv = method->ClientOnlyStreaming(); bool genCloseAndRecv = ClientOnlyStreaming(method);
//Stream interface //Stream interface
printer->Print(vars, "type $Service$_$Method$Client interface {\n"); printer->Print(vars, "type $Service$_$Method$Client interface {\n");
@@ -396,9 +404,9 @@ void GenerateService(const grpc_generator::Service *service, grpc_generator::Pri
printer->Indent(); printer->Indent();
printer->Print(vars, "StreamName: \"$Method$\",\n"); printer->Print(vars, "StreamName: \"$Method$\",\n");
printer->Print(vars, "Handler: $Handler$, \n"); printer->Print(vars, "Handler: $Handler$, \n");
if (method->ClientOnlyStreaming()) { if (ClientOnlyStreaming(method.get())) {
printer->Print("ClientStreams: true,\n"); printer->Print("ClientStreams: true,\n");
} else if (method->ServerOnlyStreaming()) { } else if (ServerOnlyStreaming(method.get())) {
printer->Print("ServerStreams: true,\n"); printer->Print("ServerStreams: true,\n");
} else { } else {
printer->Print("ServerStreams: true,\n"); printer->Print("ServerStreams: true,\n");

View File

@@ -43,12 +43,12 @@
namespace grpc_go_generator { namespace grpc_go_generator {
struct Parameters { struct Parameters {
//Defines the custom parameter types for methods //Defines the custom parameter types for methods
//eg: flatbuffers uses flatbuffers.Builder as input for the client and output for the server //eg: flatbuffers uses flatbuffers.Builder as input for the client and output for the server
grpc::string custom_method_io_type; grpc::string custom_method_io_type;
//Package name for the service //Package name for the service
grpc::string package_name; grpc::string package_name;
}; };
// Return the source of the generated service file. // Return the source of the generated service file.

View File

@@ -34,79 +34,93 @@
#ifndef GRPC_INTERNAL_COMPILER_SCHEMA_INTERFACE_H #ifndef GRPC_INTERNAL_COMPILER_SCHEMA_INTERFACE_H
#define GRPC_INTERNAL_COMPILER_SCHEMA_INTERFACE_H #define GRPC_INTERNAL_COMPILER_SCHEMA_INTERFACE_H
#include <map> #include "src/compiler/config.h"
#include <memory> #include <memory>
#include <vector> #include <vector>
#ifndef GRPC_CUSTOM_STRING #ifndef GRPC_CUSTOM_STRING
#include <string> #include <string>
#define GRPC_CUSTOM_STRING std::string #define GRPC_CUSTOM_STRING std::string
#endif #endif
namespace grpc { namespace grpc {
typedef GRPC_CUSTOM_STRING string; typedef GRPC_CUSTOM_STRING string;
} // namespace grpc } // namespace grpc
namespace grpc_generator { namespace grpc_generator {
// An abstract interface representing a method. // A common interface for objects having comments in the source.
struct Method { // Return formatted comments to be inserted in generated code.
virtual ~Method() {} struct CommentHolder {
virtual ~CommentHolder() {}
virtual grpc::string GetLeadingComments(const grpc::string prefix) const = 0;
virtual grpc::string GetTrailingComments(const grpc::string prefix) const = 0;
virtual std::vector<grpc::string> GetAllComments() const = 0;
};
virtual grpc::string name() const = 0; // An abstract interface representing a method.
struct Method : public CommentHolder {
virtual ~Method() {}
virtual grpc::string input_type_name() const = 0; virtual grpc::string name() const = 0;
virtual grpc::string output_type_name() const = 0;
virtual grpc::string input_name() const = 0;
virtual grpc::string output_name() const = 0;
virtual bool NoStreaming() const = 0; virtual grpc::string input_type_name() const = 0;
virtual bool ClientOnlyStreaming() const = 0; virtual grpc::string output_type_name() const = 0;
virtual bool ServerOnlyStreaming() const = 0;
virtual bool BidiStreaming() const = 0;
};
// An abstract interface representing a service. virtual bool get_module_and_message_path_input(
struct Service { grpc::string *str, grpc::string generator_file_name,
virtual ~Service() {} bool generate_in_pb2_grpc, grpc::string import_prefix) const = 0;
virtual bool get_module_and_message_path_output(
grpc::string *str, grpc::string generator_file_name,
bool generate_in_pb2_grpc, grpc::string import_prefix) const = 0;
virtual grpc::string name() const = 0; virtual grpc::string get_input_type_name() const = 0;
virtual grpc::string get_output_type_name() const = 0;
virtual bool NoStreaming() const = 0;
virtual bool ClientStreaming() const = 0;
virtual bool ServerStreaming() const = 0;
virtual bool BidiStreaming() const = 0;
};
virtual int method_count() const = 0; // An abstract interface representing a service.
virtual std::unique_ptr<const Method> method(int i) const = 0; struct Service : public CommentHolder {
}; virtual ~Service() {}
struct Printer { virtual grpc::string name() const = 0;
virtual ~Printer() {}
virtual void Print(const std::map<grpc::string, grpc::string> &vars, virtual int method_count() const = 0;
const char *template_string) = 0; virtual std::unique_ptr<const Method> method(int i) const = 0;
virtual void Print(const char *string) = 0; };
virtual void Indent() = 0;
virtual void Outdent() = 0;
};
// An interface that allows the source generated to be output using various struct Printer {
// libraries/idls/serializers. virtual ~Printer() {}
struct File {
virtual ~File() {}
virtual grpc::string filename() const = 0; virtual void Print(const std::map<grpc::string, grpc::string> &vars,
virtual grpc::string filename_without_ext() const = 0; const char *template_string) = 0;
virtual grpc::string message_header_ext() const = 0; virtual void Print(const char *string) = 0;
virtual grpc::string service_header_ext() const = 0; virtual void Indent() = 0;
virtual grpc::string package() const = 0; virtual void Outdent() = 0;
virtual std::vector<grpc::string> package_parts() const = 0; };
virtual grpc::string additional_headers() const = 0;
virtual grpc::string additional_imports() const = 0;
virtual int service_count() const = 0; // An interface that allows the source generated to be output using various
virtual std::unique_ptr<const Service> service(int i) const = 0; // libraries/idls/serializers.
struct File : public CommentHolder {
virtual ~File() {}
virtual std::unique_ptr<Printer> CreatePrinter(grpc::string *str) const = 0; virtual grpc::string filename() const = 0;
}; virtual grpc::string filename_without_ext() const = 0;
} // namespace grpc_generator virtual grpc::string package() const = 0;
virtual std::vector<grpc::string> package_parts() const = 0;
virtual grpc::string additional_headers() const = 0;
virtual int service_count() const = 0;
virtual std::unique_ptr<const Service> service(int i) const = 0;
virtual std::unique_ptr<Printer> CreatePrinter(grpc::string *str) const = 0;
};
} // namespace grpc_generator
#endif // GRPC_INTERNAL_COMPILER_SCHEMA_INTERFACE_H #endif // GRPC_INTERNAL_COMPILER_SCHEMA_INTERFACE_H

View File

@@ -27,31 +27,41 @@ using namespace MyGame::Example;
// code. It implements all rpcs specified in the FlatBuffers schema. // code. It implements all rpcs specified in the FlatBuffers schema.
class ServiceImpl final : public MyGame::Example::MonsterStorage::Service { class ServiceImpl final : public MyGame::Example::MonsterStorage::Service {
virtual ::grpc::Status Store(::grpc::ServerContext* context, virtual ::grpc::Status Store(::grpc::ServerContext* context,
const flatbuffers::BufferRef<Monster> *request, const flatbuffers::grpc::Message<Monster> *request,
flatbuffers::BufferRef<Stat> *response) flatbuffers::grpc::Message<Stat> *response)
override { override {
// Create a response from the incoming request name. // Create a response from the incoming request name.
fbb_.Clear(); fbb_.Clear();
auto stat_offset = CreateStat(fbb_, fbb_.CreateString("Hello, " + auto stat_offset = CreateStat(fbb_, fbb_.CreateString("Hello, " +
request->GetRoot()->name()->str())); request->GetRoot()->name()->str()));
fbb_.Finish(stat_offset); fbb_.Finish(stat_offset);
// Since we keep reusing the same FlatBufferBuilder, the memory it owns // Transfer ownership of the message to gRPC
// remains valid until the next call (this BufferRef doesn't own the *response = fbb_.ReleaseMessage<Stat>();
// memory it points to).
*response = flatbuffers::BufferRef<Stat>(fbb_.GetBufferPointer(),
fbb_.GetSize());
return grpc::Status::OK; return grpc::Status::OK;
} }
virtual ::grpc::Status Retrieve(::grpc::ServerContext *context, virtual ::grpc::Status Retrieve(::grpc::ServerContext *context,
const flatbuffers::BufferRef<Stat> *request, const flatbuffers::grpc::Message<Stat> *request,
::grpc::ServerWriter< flatbuffers::BufferRef<Monster>>* writer) ::grpc::ServerWriter< flatbuffers::grpc::Message<Monster>>* writer)
override { override {
assert(false); // We're not actually using this RPC.
return grpc::Status::CANCELLED; for (int i=0; i<10; i++) {
fbb_.Clear();
// Create 10 monsters for resposne.
auto monster_offset =
CreateMonster(fbb_, 0, 0, 0, fbb_.CreateString(
request->GetRoot()->id()->str() + " No." + std::to_string(i)));
fbb_.Finish(monster_offset);
flatbuffers::grpc::Message<Monster> monster = fbb_.ReleaseMessage<Monster>();
// Send monster to client using streaming.
writer->Write(monster);
}
return grpc::Status::OK;
} }
private: private:
flatbuffers::FlatBufferBuilder fbb_; flatbuffers::grpc::MessageBuilder fbb_;
}; };
// Track the server instance, so we can terminate it later. // Track the server instance, so we can terminate it later.
@@ -93,25 +103,55 @@ int main(int /*argc*/, const char * /*argv*/[]) {
grpc::InsecureChannelCredentials()); grpc::InsecureChannelCredentials());
auto stub = MyGame::Example::MonsterStorage::NewStub(channel); auto stub = MyGame::Example::MonsterStorage::NewStub(channel);
grpc::ClientContext context;
// Build a request with the name set. flatbuffers::grpc::MessageBuilder fbb;
flatbuffers::FlatBufferBuilder fbb; {
auto monster_offset = CreateMonster(fbb, 0, 0, 0, fbb.CreateString("Fred")); grpc::ClientContext context;
fbb.Finish(monster_offset); // Build a request with the name set.
auto request = flatbuffers::BufferRef<Monster>(fbb.GetBufferPointer(), auto monster_offset = CreateMonster(fbb, 0, 0, 0, fbb.CreateString("Fred"));
fbb.GetSize()); fbb.Finish(monster_offset);
flatbuffers::BufferRef<Stat> response; auto request = fbb.ReleaseMessage<Monster>();
flatbuffers::grpc::Message<Stat> response;
// The actual RPC. // The actual RPC.
auto status = stub->Store(&context, request, &response); auto status = stub->Store(&context, request, &response);
if (status.ok()) { if (status.ok()) {
auto resp = response.GetRoot()->id(); auto resp = response.GetRoot()->id();
std::cout << "RPC response: " << resp->str() << std::endl; std::cout << "RPC response: " << resp->str() << std::endl;
} else { } else {
std::cout << "RPC failed" << std::endl; std::cout << "RPC failed" << std::endl;
}
} }
{
grpc::ClientContext context;
fbb.Clear();
auto stat_offset = CreateStat(fbb, fbb.CreateString("Fred"));
fbb.Finish(stat_offset);
auto request = fbb.ReleaseMessage<Stat>();
flatbuffers::grpc::Message<Monster> response;
auto stream = stub->Retrieve(&context, request);
while (stream->Read(&response)) {
auto resp = response.GetRoot()->name();
std::cout << "RPC Streaming response: " << resp->str() << std::endl;
}
}
#if !FLATBUFFERS_GRPC_DISABLE_AUTO_VERIFICATION
{
// Test that an invalid request errors out correctly
grpc::ClientContext context;
flatbuffers::grpc::Message<Monster> request; // simulate invalid message
flatbuffers::grpc::Message<Stat> response;
auto status = stub->Store(&context, request, &response);
// The rpc status should be INTERNAL to indicate a verification error. This
// matches the protobuf gRPC status code for an unparseable message.
assert(!status.ok());
assert(status.error_code() == ::grpc::StatusCode::INTERNAL);
assert(strcmp(status.error_message().c_str(), "Message verification failed") == 0);
}
#endif
server_instance->Shutdown(); server_instance->Shutdown();
@@ -121,4 +161,3 @@ int main(int /*argc*/, const char * /*argv*/[]) {
return 0; return 0;
} }

177
include/flatbuffers/base.h Normal file
View File

@@ -0,0 +1,177 @@
#ifndef FLATBUFFERS_BASE_H_
#define FLATBUFFERS_BASE_H_
#include <assert.h>
#ifndef ARDUINO
#include <cstdint>
#endif
#include <cstddef>
#include <cstdlib>
#include <cstring>
#include <string>
#ifndef ARDUINO
#include <utility>
#else
#include <utility.h>
#endif
#include <type_traits>
#include <vector>
#include <set>
#include <algorithm>
#include <iterator>
#include <memory>
#ifdef _STLPORT_VERSION
#define FLATBUFFERS_CPP98_STL
#endif
#ifndef FLATBUFFERS_CPP98_STL
#include <functional>
#endif
/// @cond FLATBUFFERS_INTERNAL
#if __cplusplus <= 199711L && \
(!defined(_MSC_VER) || _MSC_VER < 1600) && \
(!defined(__GNUC__) || \
(__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__ < 40400))
#error A C++11 compatible compiler with support for the auto typing is \
required for FlatBuffers.
#error __cplusplus _MSC_VER __GNUC__ __GNUC_MINOR__ __GNUC_PATCHLEVEL__
#endif
#if !defined(__clang__) && \
defined(__GNUC__) && \
(__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__ < 40600)
// Backwards compatability for g++ 4.4, and 4.5 which don't have the nullptr
// and constexpr keywords. Note the __clang__ check is needed, because clang
// presents itself as an older GNUC compiler.
#ifndef nullptr_t
const class nullptr_t {
public:
template<class T> inline operator T*() const { return 0; }
private:
void operator&() const;
} nullptr = {};
#endif
#ifndef constexpr
#define constexpr const
#endif
#endif
// The wire format uses a little endian encoding (since that's efficient for
// the common platforms).
#if defined(__s390x__)
#define FLATBUFFERS_LITTLEENDIAN 0
#endif // __s390x__
#if !defined(FLATBUFFERS_LITTLEENDIAN)
#if defined(__GNUC__) || defined(__clang__)
#ifdef __BIG_ENDIAN__
#define FLATBUFFERS_LITTLEENDIAN 0
#else
#define FLATBUFFERS_LITTLEENDIAN 1
#endif // __BIG_ENDIAN__
#elif defined(_MSC_VER)
#if defined(_M_PPC)
#define FLATBUFFERS_LITTLEENDIAN 0
#else
#define FLATBUFFERS_LITTLEENDIAN 1
#endif
#else
#error Unable to determine endianness, define FLATBUFFERS_LITTLEENDIAN.
#endif
#endif // !defined(FLATBUFFERS_LITTLEENDIAN)
#define FLATBUFFERS_VERSION_MAJOR 1
#define FLATBUFFERS_VERSION_MINOR 7
#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))
#define FLATBUFFERS_FINAL_CLASS final
#define FLATBUFFERS_OVERRIDE override
#else
#define FLATBUFFERS_FINAL_CLASS
#define FLATBUFFERS_OVERRIDE
#endif
#if (!defined(_MSC_VER) || _MSC_VER >= 1900) && \
(!defined(__GNUC__) || (__GNUC__ * 100 + __GNUC_MINOR__ >= 406))
#define FLATBUFFERS_CONSTEXPR constexpr
#else
#define FLATBUFFERS_CONSTEXPR
#endif
#if defined(__GXX_EXPERIMENTAL_CXX0X__) && __GNUC__ * 10 + __GNUC_MINOR__ >= 46 || \
defined(_MSC_FULL_VER) && _MSC_FULL_VER >= 190023026
#define FLATBUFFERS_NOEXCEPT noexcept
#else
#define FLATBUFFERS_NOEXCEPT
#endif
// 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))
#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
/// @endcond
/// @file
namespace flatbuffers {
/// @cond FLATBUFFERS_INTERNAL
// Our default offset / size type, 32bit on purpose on 64bit systems.
// Also, using a consistent offset type maintains compatibility of serialized
// offset values between 32bit and 64bit systems.
typedef uint32_t uoffset_t;
// Signed offsets for references that can go in both directions.
typedef int32_t soffset_t;
// Offset/index used in v-tables, can be changed to uint8_t in
// format forks to save a bit of space if desired.
typedef uint16_t voffset_t;
typedef uintmax_t largest_scalar_t;
// In 32bits, this evaluates to 2GB - 1
#define FLATBUFFERS_MAX_BUFFER_SIZE ((1ULL << (sizeof(soffset_t) * 8 - 1)) - 1)
// We support aligning the contents of buffers up to this size.
#define FLATBUFFERS_MAX_ALIGNMENT 16
template<typename T> T EndianScalar(T t) {
#if FLATBUFFERS_LITTLEENDIAN
return t;
#else
return EndianSwap(t);
#endif
}
template<typename T> T ReadScalar(const void *p) {
return EndianScalar(*reinterpret_cast<const T *>(p));
}
template<typename T> void WriteScalar(void *p, T t) {
*reinterpret_cast<T *>(p) = EndianScalar(t);
}
// Computes how many bytes you'd have to pad to be able to write an
// "scalar_size" scalar if the buffer had grown to "buf_size" (downwards in
// memory).
inline size_t PaddingBytes(size_t buf_size, size_t scalar_size) {
return ((~buf_size) + 1) & (scalar_size - 1);
}
}
#endif // FLATBUFFERS_BASE_H_

View File

@@ -95,8 +95,6 @@ class BaseGenerator {
static const char *FlatBuffersGeneratedWarning(); static const char *FlatBuffersGeneratedWarning();
bool IsEverythingGenerated() const;
static std::string FullNamespace(const char *separator, const Namespace &ns); static std::string FullNamespace(const char *separator, const Namespace &ns);
static std::string LastNamespacePart(const Namespace &ns); static std::string LastNamespacePart(const Namespace &ns);
@@ -114,6 +112,8 @@ class BaseGenerator {
std::string WrapInNameSpace(const Definition &def) const; std::string WrapInNameSpace(const Definition &def) const;
std::string GetNameSpace(const Definition &def) const;
const Parser &parser_; const Parser &parser_;
const std::string &path_; const std::string &path_;
const std::string &file_name_; const std::string &file_name_;

View File

@@ -17,134 +17,17 @@
#ifndef FLATBUFFERS_H_ #ifndef FLATBUFFERS_H_
#define FLATBUFFERS_H_ #define FLATBUFFERS_H_
#include <assert.h> #include "flatbuffers/base.h"
#include <cstdint>
#include <cstddef>
#include <cstdlib>
#include <cstring>
#include <string>
#include <utility>
#include <type_traits>
#include <vector>
#include <set>
#include <algorithm>
#include <memory>
#ifdef _STLPORT_VERSION
#define FLATBUFFERS_CPP98_STL
#endif
#ifndef FLATBUFFERS_CPP98_STL
#include <functional>
#endif
/// @cond FLATBUFFERS_INTERNAL
#if __cplusplus <= 199711L && \
(!defined(_MSC_VER) || _MSC_VER < 1600) && \
(!defined(__GNUC__) || \
(__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__ < 40400))
#error A C++11 compatible compiler with support for the auto typing is \
required for FlatBuffers.
#error __cplusplus _MSC_VER __GNUC__ __GNUC_MINOR__ __GNUC_PATCHLEVEL__
#endif
#if !defined(__clang__) && \
defined(__GNUC__) && \
(__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__ < 40600)
// Backwards compatability for g++ 4.4, and 4.5 which don't have the nullptr
// and constexpr keywords. Note the __clang__ check is needed, because clang
// presents itself as an older GNUC compiler.
#ifndef nullptr_t
const class nullptr_t {
public:
template<class T> inline operator T*() const { return 0; }
private:
void operator&() const;
} nullptr = {};
#endif
#ifndef constexpr
#define constexpr const
#endif
#endif
// The wire format uses a little endian encoding (since that's efficient for
// the common platforms).
#if !defined(FLATBUFFERS_LITTLEENDIAN)
#if defined(__GNUC__) || defined(__clang__)
#ifdef __BIG_ENDIAN__
#define FLATBUFFERS_LITTLEENDIAN 0
#else
#define FLATBUFFERS_LITTLEENDIAN 1
#endif // __BIG_ENDIAN__
#elif defined(_MSC_VER)
#if defined(_M_PPC)
#define FLATBUFFERS_LITTLEENDIAN 0
#else
#define FLATBUFFERS_LITTLEENDIAN 1
#endif
#else
#error Unable to determine endianness, define FLATBUFFERS_LITTLEENDIAN.
#endif
#endif // !defined(FLATBUFFERS_LITTLEENDIAN)
#define FLATBUFFERS_VERSION_MAJOR 1
#define FLATBUFFERS_VERSION_MINOR 6
#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))
#define FLATBUFFERS_FINAL_CLASS final
#else
#define FLATBUFFERS_FINAL_CLASS
#endif
#if (!defined(_MSC_VER) || _MSC_VER >= 1900) && \
(!defined(__GNUC__) || (__GNUC__ * 100 + __GNUC_MINOR__ >= 406))
#define FLATBUFFERS_CONSTEXPR constexpr
#else
#define FLATBUFFERS_CONSTEXPR
#endif
/// @endcond
/// @file
namespace flatbuffers { namespace flatbuffers {
/// @cond FLATBUFFERS_INTERNAL
// Our default offset / size type, 32bit on purpose on 64bit systems.
// Also, using a consistent offset type maintains compatibility of serialized
// offset values between 32bit and 64bit systems.
typedef uint32_t uoffset_t;
// Signed offsets for references that can go in both directions.
typedef int32_t soffset_t;
// Offset/index used in v-tables, can be changed to uint8_t in
// format forks to save a bit of space if desired.
typedef uint16_t voffset_t;
typedef uintmax_t largest_scalar_t;
// In 32bits, this evaluates to 2GB - 1
#define FLATBUFFERS_MAX_BUFFER_SIZE ((1ULL << (sizeof(soffset_t) * 8 - 1)) - 1)
// We support aligning the contents of buffers up to this size.
#define FLATBUFFERS_MAX_ALIGNMENT 16
#ifndef FLATBUFFERS_CPP98_STL
// Pointer to relinquished memory.
typedef std::unique_ptr<uint8_t, std::function<void(uint8_t * /* unused */)>>
unique_ptr_t;
#endif
// Wrapper for uoffset_t to allow safe template specialization. // Wrapper for uoffset_t to allow safe template specialization.
// Value is allowed to be 0 to indicate a null object (see e.g. AddOffset).
template<typename T> struct Offset { template<typename T> struct Offset {
uoffset_t o; uoffset_t o;
Offset() : o(0) {} Offset() : o(0) {}
Offset(uoffset_t _o) : o(_o) {} Offset(uoffset_t _o) : o(_o) {}
Offset<void> Union() const { return Offset<void>(o); } Offset<void> Union() const { return Offset<void>(o); }
bool IsNull() const { return !o; }
}; };
inline void EndianCheck() { inline void EndianCheck() {
@@ -186,23 +69,7 @@ template<typename T> T EndianSwap(T t) {
} }
} }
template<typename T> T EndianScalar(T t) { template<typename T> FLATBUFFERS_CONSTEXPR size_t AlignOf() {
#if FLATBUFFERS_LITTLEENDIAN
return t;
#else
return EndianSwap(t);
#endif
}
template<typename T> T ReadScalar(const void *p) {
return EndianScalar(*reinterpret_cast<const T *>(p));
}
template<typename T> void WriteScalar(void *p, T t) {
*reinterpret_cast<T *>(p) = EndianScalar(t);
}
template<typename T> size_t AlignOf() {
#ifdef _MSC_VER #ifdef _MSC_VER
return __alignof(T); return __alignof(T);
#else #else
@@ -251,18 +118,16 @@ template<typename T> struct IndirectHelper<const T *> {
// An STL compatible iterator implementation for Vector below, effectively // An STL compatible iterator implementation for Vector below, effectively
// calling Get() for every element. // calling Get() for every element.
template<typename T, typename IT> template<typename T, typename IT>
struct VectorIterator struct VectorIterator {
: public std::iterator<std::random_access_iterator_tag, IT, uoffset_t> { typedef std::random_access_iterator_tag iterator_category;
typedef IT value_type;
typedef uoffset_t difference_type;
typedef IT *pointer;
typedef IT &reference;
typedef std::iterator<std::random_access_iterator_tag, IT, uoffset_t> super_type;
public:
VectorIterator(const uint8_t *data, uoffset_t i) : VectorIterator(const uint8_t *data, uoffset_t i) :
data_(data + IndirectHelper<T>::element_stride * i) {} data_(data + IndirectHelper<T>::element_stride * i) {}
VectorIterator(const VectorIterator &other) : data_(other.data_) {} VectorIterator(const VectorIterator &other) : data_(other.data_) {}
#ifndef FLATBUFFERS_CPP98_STL
VectorIterator(VectorIterator &&other) : data_(std::move(other.data_)) {}
#endif
VectorIterator &operator=(const VectorIterator &other) { VectorIterator &operator=(const VectorIterator &other) {
data_ = other.data_; data_ = other.data_;
@@ -278,6 +143,10 @@ public:
return data_ == other.data_; return data_ == other.data_;
} }
bool operator<(const VectorIterator &other) const {
return data_ < other.data_;
}
bool operator!=(const VectorIterator &other) const { bool operator!=(const VectorIterator &other) const {
return data_ != other.data_; return data_ != other.data_;
} }
@@ -286,11 +155,11 @@ public:
return (data_ - other.data_) / IndirectHelper<T>::element_stride; return (data_ - other.data_) / IndirectHelper<T>::element_stride;
} }
typename super_type::value_type operator *() const { IT operator *() const {
return IndirectHelper<T>::Read(data_, 0); return IndirectHelper<T>::Read(data_, 0);
} }
typename super_type::value_type operator->() const { IT operator->() const {
return IndirectHelper<T>::Read(data_, 0); return IndirectHelper<T>::Read(data_, 0);
} }
@@ -305,7 +174,7 @@ public:
return temp; return temp;
} }
VectorIterator operator+(const uoffset_t &offset) { VectorIterator operator+(const uoffset_t &offset) const {
return VectorIterator(data_ + offset * IndirectHelper<T>::element_stride, 0); return VectorIterator(data_ + offset * IndirectHelper<T>::element_stride, 0);
} }
@@ -338,6 +207,8 @@ private:
const uint8_t *data_; const uint8_t *data_;
}; };
struct String;
// This is used as a helper type for accessing vectors. // This is used as a helper type for accessing vectors.
// Vector::data() assumes the vector elements start after the length field. // Vector::data() assumes the vector elements start after the length field.
template<typename T> class Vector { template<typename T> class Vector {
@@ -369,6 +240,18 @@ public:
return static_cast<E>(Get(i)); return static_cast<E>(Get(i));
} }
// If this a vector of unions, this does the cast for you. There's no check
// to make sure this is the right type!
template<typename U> const U *GetAs(uoffset_t i) const {
return reinterpret_cast<const U *>(Get(i));
}
// If this a vector of unions, this does the cast for you. There's no check
// to make sure this is actually a string!
const String *GetAsString(uoffset_t i) const {
return reinterpret_cast<const String *>(Get(i));
}
const void *GetStructFromOffset(size_t o) const { const void *GetStructFromOffset(size_t o) const {
return reinterpret_cast<const void *>(Data() + o); return reinterpret_cast<const void *>(Data() + o);
} }
@@ -436,6 +319,10 @@ protected:
uoffset_t length_; uoffset_t length_;
private: private:
// This class is a pointer. Copying will therefore create an invalid object.
// Private and unimplemented copy constructor.
Vector(const Vector&);
template<typename K> static int KeyCompare(const void *ap, const void *bp) { template<typename K> static int KeyCompare(const void *ap, const void *bp) {
const K *key = reinterpret_cast<const K *>(ap); const K *key = reinterpret_cast<const K *>(ap);
const uint8_t *data = reinterpret_cast<const uint8_t *>(bp); const uint8_t *data = reinterpret_cast<const uint8_t *>(bp);
@@ -463,8 +350,25 @@ protected:
VectorOfAny(); VectorOfAny();
uoffset_t length_; uoffset_t length_;
private:
VectorOfAny(const VectorOfAny&);
}; };
#ifndef FLATBUFFERS_CPP98_STL
template<typename T, typename U>
Vector<Offset<T>> *VectorCast(Vector<Offset<U>> *ptr) {
static_assert(std::is_base_of<T, U>::value, "Unrelated types");
return reinterpret_cast<Vector<Offset<T>> *>(ptr);
}
template<typename T, typename U>
const Vector<Offset<T>> *VectorCast(const Vector<Offset<U>> *ptr) {
static_assert(std::is_base_of<T, U>::value, "Unrelated types");
return reinterpret_cast<const Vector<Offset<T>> *>(ptr);
}
#endif
// Convenient helper function to get the length of any vector, regardless // Convenient helper function to get the length of any vector, regardless
// of wether it is null or not (the field is not set). // of wether it is null or not (the field is not set).
template<typename T> static inline size_t VectorLength(const Vector<T> *v) { template<typename T> static inline size_t VectorLength(const Vector<T> *v) {
@@ -480,13 +384,137 @@ struct String : public Vector<char> {
} }
}; };
// Simple indirection for buffer allocation, to allow this to be overridden // Allocator interface. This is flatbuffers-specific and meant only for
// with custom allocation (see the FlatBufferBuilder constructor). // `vector_downward` usage.
class simple_allocator { class Allocator {
public: public:
virtual ~simple_allocator() {} virtual ~Allocator() {}
virtual uint8_t *allocate(size_t size) const { return new uint8_t[size]; }
virtual void deallocate(uint8_t *p) const { delete[] p; } // Allocate `size` bytes of memory.
virtual uint8_t *allocate(size_t size) = 0;
// Deallocate `size` bytes of memory at `p` allocated by this allocator.
virtual void deallocate(uint8_t *p, size_t size) = 0;
// Reallocate `new_size` bytes of memory, replacing the old region of size
// `old_size` at `p`. In contrast to a normal realloc, this grows downwards,
// and is intended specifcally for `vector_downward` use.
virtual uint8_t *reallocate_downward(uint8_t *old_p, size_t old_size,
size_t new_size) {
assert(new_size > old_size); // vector_downward only grows
uint8_t *new_p = allocate(new_size);
memcpy(new_p + (new_size - old_size), old_p, old_size);
deallocate(old_p, old_size);
return new_p;
}
};
// DefaultAllocator uses new/delete to allocate memory regions
class DefaultAllocator : public Allocator {
public:
virtual uint8_t *allocate(size_t size) FLATBUFFERS_OVERRIDE {
return new uint8_t[size];
}
virtual void deallocate(uint8_t *p, size_t) FLATBUFFERS_OVERRIDE {
delete[] p;
}
static DefaultAllocator &instance() {
static DefaultAllocator inst;
return inst;
}
};
// 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.
class DetachedBuffer {
public:
DetachedBuffer() : allocator_(nullptr), own_allocator_(false), buf_(nullptr),
reserved_(0), cur_(nullptr), size_(0) {}
DetachedBuffer(Allocator *allocator, bool own_allocator, uint8_t *buf,
size_t reserved, uint8_t *cur, size_t sz)
: allocator_(allocator), own_allocator_(own_allocator), buf_(buf),
reserved_(reserved), cur_(cur), size_(sz) {
assert(allocator_);
}
DetachedBuffer(DetachedBuffer &&other)
: allocator_(other.allocator_), own_allocator_(other.own_allocator_),
buf_(other.buf_), reserved_(other.reserved_), cur_(other.cur_),
size_(other.size_) {
other.allocator_ = nullptr;
other.own_allocator_ = false;
other.buf_ = nullptr;
other.reserved_ = 0;
other.cur_ = nullptr;
other.size_ = 0;
}
DetachedBuffer &operator=(DetachedBuffer &&other) {
std::swap(allocator_, other.allocator_);
std::swap(own_allocator_, other.own_allocator_);
std::swap(buf_, other.buf_);
std::swap(reserved_, other.reserved_);
std::swap(cur_, other.cur_);
std::swap(size_, other.size_);
return *this;
}
~DetachedBuffer() {
if (buf_) {
assert(allocator_);
allocator_->deallocate(buf_, reserved_);
}
if (own_allocator_ && allocator_) {
delete allocator_;
}
}
const uint8_t *data() const {
return cur_;
}
uint8_t *data() {
return cur_;
}
size_t size() const {
return size_;
}
#if 0 // disabled for now due to the ordering of classes in this header
template <class T>
bool Verify() const {
Verifier verifier(data(), size());
return verifier.Verify<T>(nullptr);
}
template <class T>
const T* GetRoot() const {
return flatbuffers::GetRoot<T>(data());
}
template <class T>
T* GetRoot() {
return flatbuffers::GetRoot<T>(data());
}
#endif
// These may change access mode, leave these at end of public section
FLATBUFFERS_DELETE_FUNC(DetachedBuffer(const DetachedBuffer &other))
FLATBUFFERS_DELETE_FUNC(
DetachedBuffer &operator=(const DetachedBuffer &other))
protected:
Allocator *allocator_;
bool own_allocator_;
uint8_t *buf_;
size_t reserved_;
uint8_t *cur_;
size_t size_;
}; };
// This is a minimal replication of std::vector<uint8_t> functionality, // This is a minimal replication of std::vector<uint8_t> functionality,
@@ -494,49 +522,64 @@ class simple_allocator {
// in the lowest address in the vector. // in the lowest address in the vector.
class vector_downward { class vector_downward {
public: public:
explicit vector_downward(size_t initial_size, explicit vector_downward(size_t initial_size = 1024,
const simple_allocator &allocator) Allocator *allocator = nullptr,
: reserved_((initial_size + sizeof(largest_scalar_t) - 1) & bool own_allocator = false)
~(sizeof(largest_scalar_t) - 1)), : allocator_(allocator ? allocator : &DefaultAllocator::instance()),
buf_(allocator.allocate(reserved_)), own_allocator_(own_allocator), initial_size_(initial_size), reserved_(0),
cur_(buf_ + reserved_), buf_(nullptr), cur_(nullptr) {
allocator_(allocator) {} assert(allocator_);
}
~vector_downward() { ~vector_downward() {
if (buf_) if (buf_) {
allocator_.deallocate(buf_); assert(allocator_);
allocator_->deallocate(buf_, reserved_);
}
if (own_allocator_ && allocator_) {
delete allocator_;
}
}
void reset() {
if (buf_) {
assert(allocator_);
allocator_->deallocate(buf_, reserved_);
}
reserved_ = 0;
buf_ = nullptr;
cur_ = nullptr;
} }
void clear() { void clear() {
if (buf_ == nullptr) if (buf_) {
buf_ = allocator_.allocate(reserved_); cur_ = buf_ + reserved_;
} else {
cur_ = buf_ + reserved_; reserved_ = 0;
buf_ = nullptr;
cur_ = nullptr;
}
} }
#ifndef FLATBUFFERS_CPP98_STL
// Relinquish the pointer to the caller. // Relinquish the pointer to the caller.
unique_ptr_t release() { DetachedBuffer release() {
// Actually deallocate from the start of the allocated memory. DetachedBuffer fb(allocator_, own_allocator_, buf_, reserved_, cur_,
std::function<void(uint8_t *)> deleter( size());
std::bind(&simple_allocator::deallocate, allocator_, buf_)); allocator_ = nullptr;
own_allocator_ = false;
// Point to the desired offset. reserved_ = 0;
unique_ptr_t retval(data(), deleter);
// Don't deallocate when this instance is destroyed.
buf_ = nullptr; buf_ = nullptr;
cur_ = nullptr; cur_ = nullptr;
return fb;
return retval;
} }
#endif
size_t growth_policy(size_t bytes) { size_t growth_policy(size_t bytes) {
return (bytes / 2) & ~(sizeof(largest_scalar_t) - 1); return (bytes == 0) ? initial_size_
: ((bytes / 2) & ~(AlignOf<largest_scalar_t>() - 1));
} }
uint8_t *make_space(size_t len) { uint8_t *make_space(size_t len) {
assert(cur_ >= buf_);
if (len > static_cast<size_t>(cur_ - buf_)) { if (len > static_cast<size_t>(cur_ - buf_)) {
reallocate(len); reallocate(len);
} }
@@ -547,13 +590,23 @@ class vector_downward {
return cur_; return cur_;
} }
Allocator &get_allocator() { return *allocator_; }
uoffset_t size() const { uoffset_t size() const {
assert(cur_ != nullptr && buf_ != nullptr);
return static_cast<uoffset_t>(reserved_ - (cur_ - buf_)); return static_cast<uoffset_t>(reserved_ - (cur_ - buf_));
} }
size_t capacity() const {
return reserved_;
}
uint8_t *buf() const {
assert(buf_);
return buf_;
}
uint8_t *data() const { uint8_t *data() const {
assert(cur_ != nullptr); assert(cur_);
return cur_; return cur_;
} }
@@ -565,7 +618,7 @@ class vector_downward {
} }
// Specialized version of push() that avoids memcpy call for small data. // Specialized version of push() that avoids memcpy call for small data.
template<typename T> void push_small(T little_endian_t) { template<typename T> void push_small(const T& little_endian_t) {
auto dest = make_space(sizeof(T)); auto dest = make_space(sizeof(T));
*reinterpret_cast<T *>(dest) = little_endian_t; *reinterpret_cast<T *>(dest) = little_endian_t;
} }
@@ -587,26 +640,29 @@ class vector_downward {
private: private:
// You shouldn't really be copying instances of this class. // You shouldn't really be copying instances of this class.
vector_downward(const vector_downward &); FLATBUFFERS_DELETE_FUNC(vector_downward(const vector_downward &))
vector_downward &operator=(const vector_downward &); FLATBUFFERS_DELETE_FUNC(vector_downward &operator=(const vector_downward &))
Allocator *allocator_;
bool own_allocator_;
size_t initial_size_;
size_t reserved_; size_t reserved_;
uint8_t *buf_; uint8_t *buf_;
uint8_t *cur_; // Points at location between empty (below) and used (above). uint8_t *cur_; // Points at location between empty (below) and used (above).
const simple_allocator &allocator_;
void reallocate(size_t len) { void reallocate(size_t len) {
assert(allocator_);
auto old_reserved = reserved_;
auto old_size = size(); auto old_size = size();
auto largest_align = AlignOf<largest_scalar_t>(); reserved_ += (std::max)(len, growth_policy(old_reserved));
reserved_ += (std::max)(len, growth_policy(reserved_)); FLATBUFFERS_CONSTEXPR size_t alignment = AlignOf<largest_scalar_t>();
// Round up to avoid undefined behavior from unaligned loads and stores. reserved_ = (reserved_ + alignment - 1) & ~(alignment - 1);
reserved_ = (reserved_ + (largest_align - 1)) & ~(largest_align - 1); if (buf_) {
auto new_buf = allocator_.allocate(reserved_); buf_ = allocator_->reallocate_downward(buf_, old_reserved, reserved_);
auto new_cur = new_buf + reserved_ - old_size; } else {
memcpy(new_cur, cur_, old_size); buf_ = allocator_->allocate(reserved_);
cur_ = new_cur; }
allocator_.deallocate(buf_); cur_ = buf_ + reserved_ - old_size;
buf_ = new_buf;
} }
}; };
@@ -617,13 +673,6 @@ inline voffset_t FieldIndexToOffset(voffset_t field_id) {
return static_cast<voffset_t>((field_id + fixed_fields) * sizeof(voffset_t)); return static_cast<voffset_t>((field_id + fixed_fields) * sizeof(voffset_t));
} }
// Computes how many bytes you'd have to pad to be able to write an
// "scalar_size" scalar if the buffer had grown to "buf_size" (downwards in
// memory).
inline size_t PaddingBytes(size_t buf_size, size_t scalar_size) {
return ((~buf_size) + 1) & (scalar_size - 1);
}
template <typename T> const T* data(const std::vector<T> &v) { template <typename T> const T* data(const std::vector<T> &v) {
return v.empty() ? nullptr : &v.front(); return v.empty() ? nullptr : &v.front();
} }
@@ -643,22 +692,21 @@ template <typename T> T* data(std::vector<T> &v) {
/// `CreateVector` functions. Do this is depth-first order to build up a tree to /// `CreateVector` functions. Do this is depth-first order to build up a tree to
/// the root. `Finish()` wraps up the buffer ready for transport. /// the root. `Finish()` wraps up the buffer ready for transport.
class FlatBufferBuilder class FlatBufferBuilder
/// @cond FLATBUFFERS_INTERNAL
FLATBUFFERS_FINAL_CLASS
/// @endcond
{ {
public: public:
/// @brief Default constructor for FlatBufferBuilder. /// @brief Default constructor for FlatBufferBuilder.
/// @param[in] initial_size The initial size of the buffer, in bytes. Defaults /// @param[in] initial_size The initial size of the buffer, in bytes. Defaults
/// to`1024`. /// to `1024`.
/// @param[in] allocator A pointer to the `simple_allocator` that should be /// @param[in] allocator An `Allocator` to use. Defaults to a new instance of
/// used. Defaults to `nullptr`, which means the `default_allocator` will be /// a `DefaultAllocator`.
/// be used. /// @param[in] own_allocator Whether the builder/vector should own the
explicit FlatBufferBuilder(uoffset_t initial_size = 1024, /// allocator. Defaults to / `false`.
const simple_allocator *allocator = nullptr) explicit FlatBufferBuilder(size_t initial_size = 1024,
: buf_(initial_size, allocator ? *allocator : default_allocator), Allocator *allocator = nullptr,
nested(false), finished(false), minalign_(1), force_defaults_(false), bool own_allocator = false)
dedup_vtables_(true), string_pool(nullptr) { : buf_(initial_size, allocator, own_allocator), nested(false),
finished(false), minalign_(1), force_defaults_(false),
dedup_vtables_(true), string_pool(nullptr) {
offsetbuf_.reserve(16); // Avoid first few reallocs. offsetbuf_.reserve(16); // Avoid first few reallocs.
vtables_.reserve(16); vtables_.reserve(16);
EndianCheck(); EndianCheck();
@@ -668,6 +716,11 @@ FLATBUFFERS_FINAL_CLASS
if (string_pool) delete string_pool; if (string_pool) delete string_pool;
} }
void Reset() {
Clear(); // clear builder state
buf_.reset(); // deallocate buffer
}
/// @brief Reset all the state in this FlatBufferBuilder so it can be reused /// @brief Reset all the state in this FlatBufferBuilder so it can be reused
/// to construct another buffer. /// to construct another buffer.
void Clear() { void Clear() {
@@ -696,18 +749,22 @@ FLATBUFFERS_FINAL_CLASS
/// @return Returns a `uint8_t` pointer to the unfinished buffer. /// @return Returns a `uint8_t` pointer to the unfinished buffer.
uint8_t *GetCurrentBufferPointer() const { return buf_.data(); } uint8_t *GetCurrentBufferPointer() const { return buf_.data(); }
#ifndef FLATBUFFERS_CPP98_STL
/// @brief Get the released pointer to the serialized buffer. /// @brief Get the released pointer to the serialized buffer.
/// @warning Do NOT attempt to use this FlatBufferBuilder afterwards! /// @warning Do NOT attempt to use this FlatBufferBuilder afterwards!
/// @return The `unique_ptr` returned has a special allocator that knows how /// @return A `FlatBuffer` that owns the buffer and its allocator and
/// to deallocate this pointer (since it points to the middle of an /// behaves similar to a `unique_ptr` with a deleter.
/// allocation). Thus, do not mix this pointer with other `unique_ptr`'s, or /// Deprecated: use Release() instead
/// call `release()`/`reset()` on it. DetachedBuffer ReleaseBufferPointer() {
unique_ptr_t ReleaseBufferPointer() { Finished();
return buf_.release();
}
/// @brief Get the released DetachedBuffer.
/// @return A `DetachedBuffer` that owns the buffer and its allocator.
DetachedBuffer Release() {
Finished(); Finished();
return buf_.release(); return buf_.release();
} }
#endif
/// @brief get the minimum alignment this buffer needs to be accessed /// @brief get the minimum alignment this buffer needs to be accessed
/// properly. This is only known once all elements have been written (after /// properly. This is only known once all elements have been written (after
@@ -761,10 +818,7 @@ FLATBUFFERS_FINAL_CLASS
template<typename T> void AssertScalarT() { template<typename T> void AssertScalarT() {
#ifndef FLATBUFFERS_CPP98_STL #ifndef FLATBUFFERS_CPP98_STL
// The code assumes power of 2 sizes and endian-swap-ability. // The code assumes power of 2 sizes and endian-swap-ability.
static_assert(std::is_scalar<T>::value static_assert(std::is_scalar<T>::value, "T must be a scalar type");
// The Offset<T> type is essentially a scalar but fails is_scalar.
|| sizeof(T) == sizeof(Offset<void>),
"T must be a scalar type");
#endif #endif
} }
@@ -798,7 +852,7 @@ FLATBUFFERS_FINAL_CLASS
} }
template<typename T> void AddOffset(voffset_t field, Offset<T> off) { template<typename T> void AddOffset(voffset_t field, Offset<T> off) {
if (!off.o) return; // An offset of 0 means NULL, don't store. if (off.IsNull()) return; // Don't store.
AddElement(field, ReferTo(off.o), static_cast<uoffset_t>(0)); AddElement(field, ReferTo(off.o), static_cast<uoffset_t>(0));
} }
@@ -968,6 +1022,15 @@ FLATBUFFERS_FINAL_CLASS
return str ? CreateString(str->c_str(), str->Length()) : 0; return str ? CreateString(str->c_str(), str->Length()) : 0;
} }
/// @brief Store a string in the buffer, which can contain any binary data.
/// @param[in] str A const reference to a std::string like type with support
/// of T::c_str() and T::length() to store in the buffer.
/// @return Returns the offset in the buffer where the string starts.
template<typename T>
Offset<String> CreateString(const T &str) {
return CreateString(str.c_str(), str.length());
}
/// @brief Store a string in the buffer, which can contain any binary data. /// @brief Store a string in the buffer, which can contain any binary data.
/// If a string with this exact contents has already been serialized before, /// If a string with this exact contents has already been serialized before,
/// instead simply returns the offset of the existing string. /// instead simply returns the offset of the existing string.
@@ -1057,10 +1120,26 @@ FLATBUFFERS_FINAL_CLASS
/// where the vector is stored. /// where the vector is stored.
template<typename T> Offset<Vector<T>> CreateVector(const T *v, size_t len) { template<typename T> Offset<Vector<T>> CreateVector(const T *v, size_t len) {
StartVector(len, sizeof(T)); StartVector(len, sizeof(T));
#if FLATBUFFERS_LITTLEENDIAN
PushBytes(reinterpret_cast<const uint8_t *>(v), len * sizeof(T));
#else
if (sizeof(T) == 1) {
PushBytes(reinterpret_cast<const uint8_t *>(v), len);
} else {
for (auto i = len; i > 0; ) {
PushElement(v[--i]);
}
}
#endif
return Offset<Vector<T>>(EndVector(len));
}
template<typename T> Offset<Vector<Offset<T>>> CreateVector(const Offset<T> *v, size_t len) {
StartVector(len, sizeof(Offset<T>));
for (auto i = len; i > 0; ) { for (auto i = len; i > 0; ) {
PushElement(v[--i]); PushElement(v[--i]);
} }
return Offset<Vector<T>>(EndVector(len)); return Offset<Vector<Offset<T>>>(EndVector(len));
} }
/// @brief Serialize a `std::vector` into a FlatBuffer `vector`. /// @brief Serialize a `std::vector` into a FlatBuffer `vector`.
@@ -1127,6 +1206,24 @@ FLATBUFFERS_FINAL_CLASS
return Offset<Vector<const T *>>(EndVector(len)); return Offset<Vector<const T *>>(EndVector(len));
} }
/// @brief Serialize an array of native structs into a FlatBuffer `vector`.
/// @tparam T The data type of the struct array elements.
/// @tparam S The data type of the native struct array elements.
/// @param[in] v A pointer to the array of type `S` to serialize into the
/// buffer as a `vector`.
/// @param[in] len The number of elements to serialize.
/// @return Returns a typed `Offset` into the serialized data indicating
/// where the vector is stored.
template<typename T, typename S> Offset<Vector<const T *>> CreateVectorOfNativeStructs(
const S *v, size_t len) {
extern T Pack(const S&);
typedef T (*Pack_t)(const S&);
std::vector<T> vv(len);
std::transform(v, v+len, vv.begin(), *(Pack_t)&Pack);
return CreateVectorOfStructs<T>(vv.data(), vv.size());
}
#ifndef FLATBUFFERS_CPP98_STL #ifndef FLATBUFFERS_CPP98_STL
/// @brief Serialize an array of structs into a FlatBuffer `vector`. /// @brief Serialize an array of structs into a FlatBuffer `vector`.
/// @tparam T The data type of the struct array elements. /// @tparam T The data type of the struct array elements.
@@ -1159,6 +1256,88 @@ FLATBUFFERS_FINAL_CLASS
return CreateVectorOfStructs(data(v), v.size()); return CreateVectorOfStructs(data(v), v.size());
} }
/// @brief Serialize a `std::vector` of native structs into a FlatBuffer `vector`.
/// @tparam T The data type of the `std::vector` struct elements.
/// @tparam S The data type of the `std::vector` native struct elements.
/// @param[in]] v A const reference to the `std::vector` of structs to
/// serialize into the buffer as a `vector`.
/// @return Returns a typed `Offset` into the serialized data indicating
/// where the vector is stored.
template<typename T, typename S> Offset<Vector<const T *>> CreateVectorOfNativeStructs(
const std::vector<S> &v) {
return CreateVectorOfNativeStructs<T, S>(data(v), v.size());
}
/// @cond FLATBUFFERS_INTERNAL
template<typename T>
struct StructKeyComparator {
bool operator()(const T &a, const T &b) const {
return a.KeyCompareLessThan(&b);
}
private:
StructKeyComparator& operator= (const StructKeyComparator&);
};
/// @endcond
/// @brief Serialize a `std::vector` of structs into a FlatBuffer `vector`
/// in sorted order.
/// @tparam T The data type of the `std::vector` struct elements.
/// @param[in]] v A const reference to the `std::vector` of structs to
/// serialize into the buffer as a `vector`.
/// @return Returns a typed `Offset` into the serialized data indicating
/// where the vector is stored.
template<typename T> Offset<Vector<const T *>> CreateVectorOfSortedStructs(
std::vector<T> *v) {
return CreateVectorOfSortedStructs(data(*v), v->size());
}
/// @brief Serialize a `std::vector` of native structs into a FlatBuffer `vector`
/// in sorted order.
/// @tparam T The data type of the `std::vector` struct elements.
/// @tparam S The data type of the `std::vector` native struct elements.
/// @param[in]] v A const reference to the `std::vector` of structs to
/// serialize into the buffer as a `vector`.
/// @return Returns a typed `Offset` into the serialized data indicating
/// where the vector is stored.
template<typename T, typename S> Offset<Vector<const T *>> CreateVectorOfSortedNativeStructs(
std::vector<S> *v) {
return CreateVectorOfSortedNativeStructs<T, S>(data(*v), v->size());
}
/// @brief Serialize an array of structs into a FlatBuffer `vector` in sorted
/// order.
/// @tparam T The data type of the struct array elements.
/// @param[in] v A pointer to the array of type `T` to serialize into the
/// buffer as a `vector`.
/// @param[in] len The number of elements to serialize.
/// @return Returns a typed `Offset` into the serialized data indicating
/// where the vector is stored.
template<typename T> Offset<Vector<const T *>> CreateVectorOfSortedStructs(
T *v, size_t len) {
std::sort(v, v + len, StructKeyComparator<T>());
return CreateVectorOfStructs(v, len);
}
/// @brief Serialize an array of native structs into a FlatBuffer `vector` in sorted
/// order.
/// @tparam T The data type of the struct array elements.
/// @tparam S The data type of the native struct array elements.
/// @param[in] v A pointer to the array of type `S` to serialize into the
/// buffer as a `vector`.
/// @param[in] len The number of elements to serialize.
/// @return Returns a typed `Offset` into the serialized data indicating
/// where the vector is stored.
template<typename T, typename S> Offset<Vector<const T *>> CreateVectorOfSortedNativeStructs(
S *v, size_t len) {
extern T Pack(const S&);
typedef T (*Pack_t)(const S&);
std::vector<T> vv(len);
std::transform(v, v+len, vv.begin(), *(Pack_t)&Pack);
return CreateVectorOfSortedStructs<T>(vv, len);
}
/// @cond FLATBUFFERS_INTERNAL /// @cond FLATBUFFERS_INTERNAL
template<typename T> template<typename T>
struct TableKeyComparator { struct TableKeyComparator {
@@ -1233,6 +1412,13 @@ FLATBUFFERS_FINAL_CLASS
reinterpret_cast<uint8_t **>(buf)); reinterpret_cast<uint8_t **>(buf));
} }
/// @brief Write a struct by itself, typically to be part of a union.
template<typename T> Offset<const T *> CreateStruct(const T &structobj) {
Align(AlignOf<T>());
buf_.push_small(structobj);
return Offset<const T *>(GetSize());
}
/// @brief The length of a FlatBuffer file header. /// @brief The length of a FlatBuffer file header.
static const size_t kFileIdentifierLength = 4; static const size_t kFileIdentifierLength = 4;
@@ -1257,7 +1443,7 @@ FLATBUFFERS_FINAL_CLASS
Finish(root.o, file_identifier, true); Finish(root.o, file_identifier, true);
} }
private: protected:
// You shouldn't really be copying instances of this class. // You shouldn't really be copying instances of this class.
FlatBufferBuilder(const FlatBufferBuilder &); FlatBufferBuilder(const FlatBufferBuilder &);
FlatBufferBuilder &operator=(const FlatBufferBuilder &); FlatBufferBuilder &operator=(const FlatBufferBuilder &);
@@ -1286,8 +1472,6 @@ FLATBUFFERS_FINAL_CLASS
voffset_t id; voffset_t id;
}; };
simple_allocator default_allocator;
vector_downward buf_; vector_downward buf_;
// Accumulating offsets of table members while it is being built. // Accumulating offsets of table members while it is being built.
@@ -1354,17 +1538,29 @@ template<typename T> const T *GetTemporaryPointer(FlatBufferBuilder &fbb,
return GetMutableTemporaryPointer<T>(fbb, offset); return GetMutableTemporaryPointer<T>(fbb, offset);
} }
/// @brief Get a pointer to the the file_identifier section of the buffer.
/// @return Returns a const char pointer to the start of the file_identifier
/// characters in the buffer. The returned char * has length
/// 'flatbuffers::FlatBufferBuilder::kFileIdentifierLength'.
/// This function is UNDEFINED for FlatBuffers whose schema does not include
/// a file_identifier (likely points at padding or the start of a the root
/// vtable).
inline const char *GetBufferIdentifier(const void *buf) {
return reinterpret_cast<const char *>(buf) + sizeof(uoffset_t);
}
// Helper to see if the identifier in a buffer has the expected value. // Helper to see if the identifier in a buffer has the expected value.
inline bool BufferHasIdentifier(const void *buf, const char *identifier) { inline bool BufferHasIdentifier(const void *buf, const char *identifier) {
return strncmp(reinterpret_cast<const char *>(buf) + sizeof(uoffset_t), return strncmp(GetBufferIdentifier(buf),
identifier, FlatBufferBuilder::kFileIdentifierLength) == 0; identifier, FlatBufferBuilder::kFileIdentifierLength) == 0;
} }
// Helper class to verify the integrity of a FlatBuffer // Helper class to verify the integrity of a FlatBuffer
class Verifier FLATBUFFERS_FINAL_CLASS { class Verifier FLATBUFFERS_FINAL_CLASS {
public: public:
Verifier(const uint8_t *buf, size_t buf_len, size_t _max_depth = 64, Verifier(const uint8_t *buf, size_t buf_len, uoffset_t _max_depth = 64,
size_t _max_tables = 1000000) uoffset_t _max_tables = 1000000)
: buf_(buf), end_(buf + buf_len), depth_(0), max_depth_(_max_depth), : buf_(buf), end_(buf + buf_len), depth_(0), max_depth_(_max_depth),
num_tables_(0), max_tables_(_max_tables) num_tables_(0), max_tables_(_max_tables)
#ifdef FLATBUFFERS_TRACK_VERIFIER_BUFFER_SIZE #ifdef FLATBUFFERS_TRACK_VERIFIER_BUFFER_SIZE
@@ -1473,8 +1669,9 @@ class Verifier FLATBUFFERS_FINAL_CLASS {
} }
// Call T::Verify, which must be in the generated code for this type. // Call T::Verify, which must be in the generated code for this type.
return Verify<uoffset_t>(start) && auto o = VerifyOffset(start);
reinterpret_cast<const T *>(start + ReadScalar<uoffset_t>(start))-> return o &&
reinterpret_cast<const T *>(start + o)->
Verify(*this) Verify(*this)
#ifdef FLATBUFFERS_TRACK_VERIFIER_BUFFER_SIZE #ifdef FLATBUFFERS_TRACK_VERIFIER_BUFFER_SIZE
&& GetComputedSize() && GetComputedSize()
@@ -1483,6 +1680,10 @@ class Verifier FLATBUFFERS_FINAL_CLASS {
} }
// Verify this whole buffer, starting with root type T. // 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) { template<typename T> bool VerifyBuffer(const char *identifier) {
return VerifyBufferFromStart<T>(identifier, buf_); return VerifyBufferFromStart<T>(identifier, buf_);
} }
@@ -1493,6 +1694,13 @@ class Verifier FLATBUFFERS_FINAL_CLASS {
VerifyBufferFromStart<T>(identifier, buf_ + sizeof(uoffset_t)); VerifyBufferFromStart<T>(identifier, buf_ + sizeof(uoffset_t));
} }
uoffset_t VerifyOffset(const uint8_t *start) const {
if (!Verify<uoffset_t>(start)) return false;
auto o = ReadScalar<uoffset_t>(start);
Check(o != 0);
return o;
}
// Called at the start of a table to increase counters measuring data // Called at the start of a table to increase counters measuring data
// structure depth and amount, and possibly bails out with false if // structure depth and amount, and possibly bails out with false if
// limits set by the constructor have been hit. Needs to be balanced // limits set by the constructor have been hit. Needs to be balanced
@@ -1522,10 +1730,10 @@ class Verifier FLATBUFFERS_FINAL_CLASS {
private: private:
const uint8_t *buf_; const uint8_t *buf_;
const uint8_t *end_; const uint8_t *end_;
size_t depth_; uoffset_t depth_;
size_t max_depth_; uoffset_t max_depth_;
size_t num_tables_; uoffset_t num_tables_;
size_t max_tables_; uoffset_t max_tables_;
#ifdef FLATBUFFERS_TRACK_VERIFIER_BUFFER_SIZE #ifdef FLATBUFFERS_TRACK_VERIFIER_BUFFER_SIZE
mutable const uint8_t *upper_bound_; mutable const uint8_t *upper_bound_;
#endif #endif
@@ -1617,9 +1825,9 @@ class Table {
return field_offset ? reinterpret_cast<P>(p) : nullptr; return field_offset ? reinterpret_cast<P>(p) : nullptr;
} }
template<typename T> bool SetField(voffset_t field, T val) { template<typename T> bool SetField(voffset_t field, T val, T def) {
auto field_offset = GetOptionalFieldOffset(field); auto field_offset = GetOptionalFieldOffset(field);
if (!field_offset) return false; if (!field_offset) return val == def;
WriteScalar(data_ + field_offset, val); WriteScalar(data_ + field_offset, val);
return true; return true;
} }
@@ -1669,12 +1877,24 @@ class Table {
// VerifyField for required fields. // VerifyField for required fields.
template<typename T> bool VerifyFieldRequired(const Verifier &verifier, template<typename T> bool VerifyFieldRequired(const Verifier &verifier,
voffset_t field) const { voffset_t field) const {
auto field_offset = GetOptionalFieldOffset(field); auto field_offset = GetOptionalFieldOffset(field);
return verifier.Check(field_offset != 0) && 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);
}
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);
}
private: private:
// private constructor & copy constructor: you obtain instances of this // private constructor & copy constructor: you obtain instances of this
// class by pointing to existing data only // class by pointing to existing data only
@@ -1849,4 +2069,8 @@ volatile __attribute__((weak)) const char *flatbuffer_version_string =
/// @endcond /// @endcond
} // namespace flatbuffers } // namespace flatbuffers
#if defined(_MSC_VER)
#pragma warning(pop)
#endif
#endif // FLATBUFFERS_H_ #endif // FLATBUFFERS_H_

View File

@@ -42,6 +42,7 @@ class FlatCompiler {
const char *generator_opt_short; const char *generator_opt_short;
const char *generator_opt_long; const char *generator_opt_long;
const char *lang_name; const char *lang_name;
bool schema_only;
GenerateFn generateGRPC; GenerateFn generateGRPC;
flatbuffers::IDLOptions::Language lang; flatbuffers::IDLOptions::Language lang;
const char *generator_help; const char *generator_help;

View File

@@ -17,14 +17,19 @@
#ifndef FLATBUFFERS_FLEXBUFFERS_H_ #ifndef FLATBUFFERS_FLEXBUFFERS_H_
#define FLATBUFFERS_FLEXBUFFERS_H_ #define FLATBUFFERS_FLEXBUFFERS_H_
#include <map>
// We use the basic binary writing functions from the regular FlatBuffers. // We use the basic binary writing functions from the regular FlatBuffers.
#include "flatbuffers/flatbuffers.h"
#include "flatbuffers/util.h" #include "flatbuffers/util.h"
#ifdef _MSC_VER #ifdef _MSC_VER
#include <intrin.h> #include <intrin.h>
#endif #endif
#if defined(_MSC_VER)
#pragma warning(push)
#pragma warning(disable: 4127) // C4127: conditional expression is constant
#endif
namespace flexbuffers { namespace flexbuffers {
class Reference; class Reference;
@@ -85,7 +90,7 @@ inline bool IsFixedTypedVector(Type t) {
return t >= TYPE_VECTOR_INT2 && t <= TYPE_VECTOR_FLOAT4; return t >= TYPE_VECTOR_INT2 && t <= TYPE_VECTOR_FLOAT4;
} }
inline Type ToTypedVector(Type t, int fixed_len = 0) { inline Type ToTypedVector(Type t, size_t fixed_len = 0) {
assert(IsTypedVectorElementType(t)); assert(IsTypedVectorElementType(t));
switch (fixed_len) { switch (fixed_len) {
case 0: return static_cast<Type>(t - TYPE_INT + TYPE_VECTOR_INT); case 0: return static_cast<Type>(t - TYPE_INT + TYPE_VECTOR_INT);
@@ -104,7 +109,7 @@ inline Type ToTypedVectorElementType(Type t) {
inline Type ToFixedTypedVectorElementType(Type t, uint8_t *len) { inline Type ToFixedTypedVectorElementType(Type t, uint8_t *len) {
assert(IsFixedTypedVector(t)); assert(IsFixedTypedVector(t));
auto fixed_type = t - TYPE_VECTOR_INT2; auto fixed_type = t - TYPE_VECTOR_INT2;
*len = fixed_type / 3 + 2; // 3 types each, starting from length 2. *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 + TYPE_INT);
} }
@@ -155,7 +160,7 @@ inline double ReadDouble(const uint8_t *data, uint8_t byte_width) {
byte_width); byte_width);
} }
const uint8_t *Indirect(const uint8_t *offset, uint8_t byte_width) { inline const uint8_t *Indirect(const uint8_t *offset, uint8_t byte_width) {
return offset - ReadUInt64(offset, byte_width); return offset - ReadUInt64(offset, byte_width);
} }
@@ -163,7 +168,7 @@ template<typename T> const uint8_t *Indirect(const uint8_t *offset) {
return offset - flatbuffers::ReadScalar<T>(offset); return offset - flatbuffers::ReadScalar<T>(offset);
} }
static BitWidth WidthU(uint64_t u) { inline BitWidth WidthU(uint64_t u) {
#define FLATBUFFERS_GET_FIELD_BIT_WIDTH(value, width) { \ #define FLATBUFFERS_GET_FIELD_BIT_WIDTH(value, width) { \
if (!((u) & ~((1ULL << (width)) - 1ULL))) return BIT_WIDTH_##width; \ if (!((u) & ~((1ULL << (width)) - 1ULL))) return BIT_WIDTH_##width; \
} }
@@ -174,12 +179,12 @@ static BitWidth WidthU(uint64_t u) {
return BIT_WIDTH_64; return BIT_WIDTH_64;
} }
static BitWidth WidthI(int64_t i) { inline BitWidth WidthI(int64_t i) {
auto u = static_cast<uint64_t>(i) << 1; auto u = static_cast<uint64_t>(i) << 1;
return WidthU(i >= 0 ? u : ~u); return WidthU(i >= 0 ? u : ~u);
} }
static BitWidth WidthF(double f) { inline BitWidth WidthF(double f) {
return static_cast<double>(static_cast<float>(f)) == f ? BIT_WIDTH_32 return static_cast<double>(static_cast<float>(f)) == f ? BIT_WIDTH_32
: BIT_WIDTH_64; : BIT_WIDTH_64;
} }
@@ -212,6 +217,7 @@ class String : public Sized {
size_t length() const { return size(); } size_t length() const { return size(); }
const char *c_str() const { return reinterpret_cast<const char *>(data_); } const char *c_str() const { return reinterpret_cast<const char *>(data_); }
std::string str() const { return std::string(c_str(), length()); }
static String EmptyString() { static String EmptyString() {
static const uint8_t empty_string[] = { 0/*len*/, 0/*terminator*/ }; static const uint8_t empty_string[] = { 0/*len*/, 0/*terminator*/ };
@@ -451,25 +457,61 @@ class Reference {
} }
// Unlike AsString(), this will convert any type to a std::string. // Unlike AsString(), this will convert any type to a std::string.
std::string ToString() const { std::string ToString() {
std::string s;
ToString(false, false, s);
return s;
}
// Convert any type to a JSON-like string. strings_quoted determines if
// string values at the top level receive "" quotes (inside other values
// 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_ == TYPE_STRING) {
return String(Indirect(), byte_width_).c_str(); String str(Indirect(), byte_width_);
if (strings_quoted) {
flatbuffers::EscapeString(str.c_str(), str.length(), &s, true);
} else {
s.append(str.c_str(), str.length());
}
} else if (IsKey()) { } else if (IsKey()) {
return AsKey(); auto str = AsKey();
if (keys_quoted) {
flatbuffers::EscapeString(str, strlen(str), &s, true);
} else {
s += str;
}
} else if (IsInt()) { } else if (IsInt()) {
return flatbuffers::NumToString(AsInt64()); s += flatbuffers::NumToString(AsInt64());
} else if (IsUInt()) { } else if (IsUInt()) {
return flatbuffers::NumToString(AsUInt64()); s += flatbuffers::NumToString(AsUInt64());
} else if (IsFloat()) { } else if (IsFloat()) {
return flatbuffers::NumToString(AsDouble()); s += flatbuffers::NumToString(AsDouble());
} else if (IsNull()) { } else if (IsNull()) {
return "null"; s += "null";
} else if (IsMap()) { } else if (IsMap()) {
return "{..}"; // TODO: show elements. s += "{ ";
auto m = AsMap();
auto keys = m.Keys();
auto vals = m.Values();
for (size_t i = 0; i < keys.size(); i++) {
keys[i].ToString(true, keys_quoted, s);
s += ": ";
vals[i].ToString(true, keys_quoted, s);
if (i < keys.size() - 1) s += ", ";
}
s += " }";
} else if (IsVector()) { } else if (IsVector()) {
return "[..]"; // TODO: show elements. s += "[ ";
auto v = AsVector();
for (size_t i = 0; i < v.size(); i++) {
v[i].ToString(true, keys_quoted, s);
if (i < v.size() - 1) s += ", ";
}
s += " ]";
} else { } else {
return "(?)"; s += "(?)";
} }
} }
@@ -601,7 +643,7 @@ class Reference {
template<typename T> bool Mutate(const uint8_t *dest, T t, size_t byte_width, template<typename T> bool Mutate(const uint8_t *dest, T t, size_t byte_width,
BitWidth value_width) { BitWidth value_width) {
auto fits = (1U << value_width) <= byte_width; auto fits = static_cast<size_t>(static_cast<size_t>(1U) << value_width) <= byte_width;
if (fits) { if (fits) {
t = flatbuffers::EndianScalar(t); t = flatbuffers::EndianScalar(t);
memcpy(const_cast<uint8_t *>(dest), &t, byte_width); memcpy(const_cast<uint8_t *>(dest), &t, byte_width);
@@ -740,6 +782,17 @@ class Builder FLATBUFFERS_FINAL_CLASS {
return buf_; return buf_;
} }
// Reset all state so we can re-use the buffer.
void Clear() {
buf_.clear();
stack_.clear();
finished_ = false;
// flags_ remains as-is;
force_min_bit_width_ = BIT_WIDTH_8;
key_pool.clear();
string_pool.clear();
}
// All value constructing functions below have two versions: one that // All value constructing functions below have two versions: one that
// takes a key (for placement inside a map) and one that doesn't (for inside // takes a key (for placement inside a map) and one that doesn't (for inside
// vectors and elsewhere). // vectors and elsewhere).
@@ -1072,7 +1125,7 @@ class Builder FLATBUFFERS_FINAL_CLASS {
auto byte_width = 1U << alignment; auto byte_width = 1U << alignment;
buf_.insert(buf_.end(), flatbuffers::PaddingBytes(buf_.size(), byte_width), buf_.insert(buf_.end(), flatbuffers::PaddingBytes(buf_.size(), byte_width),
0); 0);
return byte_width; return static_cast<uint8_t>(byte_width);
} }
void WriteBytes(const void *val, size_t size) { void WriteBytes(const void *val, size_t size) {
@@ -1081,8 +1134,8 @@ class Builder FLATBUFFERS_FINAL_CLASS {
reinterpret_cast<const uint8_t *>(val) + size); reinterpret_cast<const uint8_t *>(val) + size);
} }
// For values T >= byte_width template<typename T> void Write(T val, size_t byte_width) {
template<typename T> void Write(T val, uint8_t byte_width) { assert(sizeof(T) >= byte_width);
val = flatbuffers::EndianScalar(val); val = flatbuffers::EndianScalar(val);
WriteBytes(&val, byte_width); WriteBytes(&val, byte_width);
} }
@@ -1176,7 +1229,8 @@ class Builder FLATBUFFERS_FINAL_CLASS {
auto offset = offset_loc - u_; auto offset = offset_loc - u_;
// Does it fit? // Does it fit?
auto bit_width = WidthU(offset); auto bit_width = WidthU(offset);
if (1U << bit_width == byte_width) return bit_width; if (static_cast<size_t>(static_cast<size_t>(1U) << bit_width) == byte_width)
return bit_width;
} }
assert(false); // Must match one of the sizes above. assert(false); // Must match one of the sizes above.
return BIT_WIDTH_64; return BIT_WIDTH_64;
@@ -1231,7 +1285,7 @@ class Builder FLATBUFFERS_FINAL_CLASS {
// TODO: instead of asserting, could write vector with larger elements // TODO: instead of asserting, could write vector with larger elements
// instead, though that would be wasteful. // instead, though that would be wasteful.
assert(WidthU(len) <= bit_width); assert(WidthU(len) <= bit_width);
if (!fixed) Write(len, byte_width); if (!fixed) Write<uint64_t>(len, byte_width);
auto vloc = buf_.size(); auto vloc = buf_.size();
for (size_t i = 0; i < len; i++) Write(elems[i], byte_width); for (size_t i = 0; i < len; i++) Write(elems[i], byte_width);
stack_.push_back(Value(static_cast<uint64_t>(vloc), stack_.push_back(Value(static_cast<uint64_t>(vloc),
@@ -1273,9 +1327,9 @@ class Builder FLATBUFFERS_FINAL_CLASS {
// Write vector. First the keys width/offset if available, and size. // Write vector. First the keys width/offset if available, and size.
if (keys) { if (keys) {
WriteOffset(keys->u_, byte_width); WriteOffset(keys->u_, byte_width);
Write(1U << keys->min_bit_width_, byte_width); Write<uint64_t>(1ULL << keys->min_bit_width_, byte_width);
} }
if (!fixed) Write(vec_len, byte_width); if (!fixed) Write<uint64_t>(vec_len, byte_width);
// Then the actual data. // Then the actual data.
auto vloc = buf_.size(); auto vloc = buf_.size();
for (size_t i = start; i < stack_.size(); i += step) { for (size_t i = start; i < stack_.size(); i += step) {
@@ -1338,4 +1392,8 @@ class Builder FLATBUFFERS_FINAL_CLASS {
} // namespace flexbuffers } // namespace flexbuffers
#if defined(_MSC_VER)
#pragma warning(pop)
#endif
#endif // FLATBUFFERS_FLEXBUFFERS_H_ #endif // FLATBUFFERS_FLEXBUFFERS_H_

View File

@@ -19,49 +19,234 @@
// Helper functionality to glue FlatBuffers and GRPC. // Helper functionality to glue FlatBuffers and GRPC.
#include "flatbuffers/flatbuffers.h"
#include "grpc++/support/byte_buffer.h" #include "grpc++/support/byte_buffer.h"
#include "grpc/byte_buffer_reader.h" #include "grpc/byte_buffer_reader.h"
namespace flatbuffers {
namespace grpc {
// Message is a typed wrapper around a buffer that manages the underlying
// `grpc_slice` and also provides flatbuffers-specific helpers such as `Verify`
// and `GetRoot`. Since it is backed by a `grpc_slice`, the underlying buffer
// is refcounted and ownership is be managed automatically.
template <class T>
class Message {
public:
Message() : slice_(grpc_empty_slice()) {}
Message(grpc_slice slice, bool add_ref)
: slice_(add_ref ? grpc_slice_ref(slice) : slice) {}
Message &operator=(const Message &other) = delete;
Message(Message &&other) : slice_(other.slice_) {
other.slice_ = grpc_empty_slice();
}
Message(const Message &other) = delete;
Message &operator=(Message &&other) {
grpc_slice_unref(slice_);
slice_ = other.slice_;
other.slice_ = grpc_empty_slice();
return *this;
}
~Message() { grpc_slice_unref(slice_); }
const uint8_t *mutable_data() const { return GRPC_SLICE_START_PTR(slice_); }
const uint8_t *data() const { return GRPC_SLICE_START_PTR(slice_); }
size_t size() const { return GRPC_SLICE_LENGTH(slice_); }
bool Verify() const {
Verifier verifier(data(), size());
return verifier.VerifyBuffer<T>(nullptr);
}
T *GetMutableRoot() { return flatbuffers::GetMutableRoot<T>(mutable_data()); }
const T *GetRoot() const { return flatbuffers::GetRoot<T>(data()); }
// This is only intended for serializer use, or if you know what you're doing
const grpc_slice &BorrowSlice() const { return slice_; }
private:
grpc_slice slice_;
};
class MessageBuilder;
// SliceAllocator is a gRPC-specific allocator that uses the `grpc_slice`
// refcounted slices to manage memory ownership. This makes it easy and
// efficient to transfer buffers to gRPC.
class SliceAllocator : public Allocator {
public:
SliceAllocator() : slice_(grpc_empty_slice()) {}
SliceAllocator(const SliceAllocator &other) = delete;
SliceAllocator &operator=(const SliceAllocator &other) = delete;
virtual ~SliceAllocator() { grpc_slice_unref(slice_); }
virtual uint8_t *allocate(size_t size) override {
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_));
grpc_slice_unref(slice_);
slice_ = grpc_empty_slice();
}
virtual uint8_t *reallocate_downward(uint8_t *old_p, size_t old_size,
size_t new_size) override {
assert(old_p == GRPC_SLICE_START_PTR(slice_));
assert(old_size == GRPC_SLICE_LENGTH(slice_));
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);
memcpy(new_p + (new_size - old_size), old_p, old_size);
slice_ = new_slice;
grpc_slice_unref(old_slice);
return new_p;
}
private:
grpc_slice &get_slice(uint8_t *p, size_t size) {
assert(p == GRPC_SLICE_START_PTR(slice_));
assert(size == GRPC_SLICE_LENGTH(slice_));
return slice_;
}
grpc_slice slice_;
friend class MessageBuilder;
};
// SliceAllocatorMember is a hack to ensure that the MessageBuilder's
// slice_allocator_ member is constructed before the FlatBufferBuilder, since
// the allocator is used in the FlatBufferBuilder ctor.
namespace detail {
struct SliceAllocatorMember {
SliceAllocator slice_allocator_;
};
}
// MessageBuilder is a gRPC-specific FlatBufferBuilder that uses SliceAllocator
// to allocate gRPC buffers.
class MessageBuilder : private detail::SliceAllocatorMember,
public FlatBufferBuilder {
public:
explicit MessageBuilder(uoffset_t initial_size = 1024)
: FlatBufferBuilder(initial_size, &slice_allocator_, false) {}
MessageBuilder(const MessageBuilder &other) = delete;
MessageBuilder &operator=(const MessageBuilder &other) = delete;
~MessageBuilder() {}
// GetMessage extracts the subslice of the buffer corresponding to the
// flatbuffers-encoded region and wraps it in a `Message<T>` to handle buffer
// ownership.
template <class T>
Message<T> GetMessage() {
auto buf_data = buf_.buf(); // pointer to memory
auto buf_size = buf_.capacity(); // size of memory
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);
// Calculate offsets from the buffer start
auto begin = msg_data - buf_data;
auto end = begin + msg_size;
// Get the slice we are working with (no refcount change)
grpc_slice slice = slice_allocator_.get_slice(buf_data, buf_size);
// Extract a subslice of the existing slice (increment refcount)
grpc_slice subslice = grpc_slice_sub(slice, begin, end);
// Wrap the subslice in a `Message<T>`, but don't increment refcount
Message<T> msg(subslice, false);
return msg;
}
template <class T>
Message<T> ReleaseMessage() {
Message<T> msg = GetMessage<T>();
Reset();
return msg;
}
private:
// SliceAllocator slice_allocator_; // part of SliceAllocatorMember
};
} // namespace grpc
} // namespace flatbuffers
namespace grpc { namespace grpc {
template <class T> template <class T>
class SerializationTraits<T, typename std::enable_if<std::is_base_of< class SerializationTraits<flatbuffers::grpc::Message<T>> {
flatbuffers::BufferRefBase, T>::value>::type> {
public: public:
// The type we're passing here is a BufferRef, which is already serialized static grpc::Status Serialize(const flatbuffers::grpc::Message<T> &msg,
// FlatBuffer data, which then gets passed to GRPC. grpc_byte_buffer **buffer, bool *own_buffer) {
static grpc::Status Serialize(const T& msg, // We are passed in a `Message<T>`, which is a wrapper around a
grpc_byte_buffer **buffer, // `grpc_slice`. We extract it here using `BorrowSlice()`. The const cast
bool *own_buffer) { // is necesary because the `grpc_raw_byte_buffer_create` func expects
// TODO(wvo): make this work without copying. // non-const slices in order to increment their refcounts.
auto slice = gpr_slice_from_copied_buffer( grpc_slice *slice = const_cast<grpc_slice *>(&msg.BorrowSlice());
reinterpret_cast<const char *>(msg.buf), msg.len); // Now use `grpc_raw_byte_buffer_create` to package the single slice into a
*buffer = grpc_raw_byte_buffer_create(&slice, 1); // `grpc_byte_buffer`, incrementing the refcount in the process.
*buffer = grpc_raw_byte_buffer_create(slice, 1);
*own_buffer = true; *own_buffer = true;
return grpc::Status(); return grpc::Status::OK;
} }
// There is no de-serialization step in FlatBuffers, so we just receive // Deserialize by pulling the
// the data from GRPC. static grpc::Status Deserialize(grpc_byte_buffer *buffer,
static grpc::Status Deserialize(grpc_byte_buffer *buffer, T *msg) { flatbuffers::grpc::Message<T> *msg) {
// TODO(wvo): make this more efficient / zero copy when possible. if (!buffer) {
auto len = grpc_byte_buffer_length(buffer); return ::grpc::Status(::grpc::StatusCode::INTERNAL, "No payload");
msg->buf = reinterpret_cast<uint8_t *>(malloc(len)); }
msg->len = static_cast<flatbuffers::uoffset_t>(len); // Check if this is a single uncompressed slice.
msg->must_free = true; if ((buffer->type == GRPC_BB_RAW) &&
uint8_t *current = msg->buf; (buffer->data.raw.compression == GRPC_COMPRESS_NONE) &&
grpc_byte_buffer_reader reader; (buffer->data.raw.slice_buffer.count == 1)) {
grpc_byte_buffer_reader_init(&reader, buffer); // If it is, then we can reference the `grpc_slice` directly.
gpr_slice slice; grpc_slice slice = buffer->data.raw.slice_buffer.slices[0];
while (grpc_byte_buffer_reader_next(&reader, &slice)) { // We wrap a `Message<T>` around the slice, incrementing the refcount.
memcpy(current, GPR_SLICE_START_PTR(slice), GPR_SLICE_LENGTH(slice)); *msg = flatbuffers::grpc::Message<T>(slice, true);
current += GPR_SLICE_LENGTH(slice); } else {
gpr_slice_unref(slice); // Otherwise, we need to use `grpc_byte_buffer_reader_readall` to read
// `buffer` into a single contiguous `grpc_slice`. The gRPC reader gives
// us back a new slice with the refcount already incremented.
grpc_byte_buffer_reader reader;
grpc_byte_buffer_reader_init(&reader, buffer);
grpc_slice slice = grpc_byte_buffer_reader_readall(&reader);
grpc_byte_buffer_reader_destroy(&reader);
// We wrap a `Message<T>` around the slice, but dont increment refcount
*msg = flatbuffers::grpc::Message<T>(slice, false);
} }
GPR_ASSERT(current == msg->buf + msg->len);
grpc_byte_buffer_reader_destroy(&reader);
grpc_byte_buffer_destroy(buffer); grpc_byte_buffer_destroy(buffer);
return grpc::Status(); #if FLATBUFFERS_GRPC_DISABLE_AUTO_VERIFICATION
return ::grpc::Status::OK;
#else
if (msg->Verify()) {
return ::grpc::Status::OK;
} else {
return ::grpc::Status(::grpc::StatusCode::INTERNAL,
"Message verification failed");
}
#endif
} }
}; };

View File

@@ -25,6 +25,7 @@
#include "flatbuffers/flatbuffers.h" #include "flatbuffers/flatbuffers.h"
#include "flatbuffers/hash.h" #include "flatbuffers/hash.h"
#include "flatbuffers/reflection.h" #include "flatbuffers/reflection.h"
#include "flatbuffers/flexbuffers.h"
// This file defines the data types representing a parsed IDL (Interface // This file defines the data types representing a parsed IDL (Interface
// Definition Language) / schema file. // Definition Language) / schema file.
@@ -226,18 +227,20 @@ struct Definition {
}; };
struct FieldDef : public Definition { struct FieldDef : public Definition {
FieldDef() : deprecated(false), required(false), key(false), padding(0) {} FieldDef() : deprecated(false), required(false), key(false),
flexbuffer(false), padding(0) {}
Offset<reflection::Field> Serialize(FlatBufferBuilder *builder, uint16_t id, Offset<reflection::Field> Serialize(FlatBufferBuilder *builder, uint16_t id,
const Parser &parser) const; const Parser &parser) const;
Value value; Value value;
bool deprecated; // Field is allowed to be present in old data, but can't be bool deprecated; // Field is allowed to be present in old data, but can't be.
// written in new data nor accessed in new code. // written in new data nor accessed in new code.
bool required; // Field must always be present. bool required; // Field must always be present.
bool key; // Field functions as a key for creating sorted vectors. bool key; // Field functions as a key for creating sorted vectors.
bool native_inline; // Field will be defined inline (instead of as a pointer) bool native_inline; // Field will be defined inline (instead of as a pointer)
// for native tables if field is a struct. // for native tables if field is a struct.
bool flexbuffer; // This field contains FlexBuffer data.
size_t padding; // Bytes to always pad after this field. size_t padding; // Bytes to always pad after this field.
}; };
@@ -283,18 +286,18 @@ inline size_t InlineAlignment(const Type &type) {
struct EnumVal { struct EnumVal {
EnumVal(const std::string &_name, int64_t _val) EnumVal(const std::string &_name, int64_t _val)
: name(_name), value(_val), struct_def(nullptr) {} : name(_name), value(_val) {}
Offset<reflection::EnumVal> Serialize(FlatBufferBuilder *builder) const; Offset<reflection::EnumVal> Serialize(FlatBufferBuilder *builder) const;
std::string name; std::string name;
std::vector<std::string> doc_comment; std::vector<std::string> doc_comment;
int64_t value; int64_t value;
StructDef *struct_def; // only set if this is a union Type union_type;
}; };
struct EnumDef : public Definition { struct EnumDef : public Definition {
EnumDef() : is_union(false) {} EnumDef() : is_union(false), uses_type_aliases(false) {}
EnumVal *ReverseLookup(int enum_idx, bool skip_union_default = true) { EnumVal *ReverseLookup(int enum_idx, bool skip_union_default = true) {
for (auto it = vals.vec.begin() + static_cast<int>(is_union && for (auto it = vals.vec.begin() + static_cast<int>(is_union &&
@@ -312,6 +315,7 @@ struct EnumDef : public Definition {
SymbolTable<EnumVal> vals; SymbolTable<EnumVal> vals;
bool is_union; bool is_union;
bool uses_type_aliases;
Type underlying_type; Type underlying_type;
}; };
@@ -353,10 +357,16 @@ struct IDLOptions {
bool escape_proto_identifiers; bool escape_proto_identifiers;
bool generate_object_based_api; bool generate_object_based_api;
std::string cpp_object_api_pointer_type; std::string cpp_object_api_pointer_type;
std::string cpp_object_api_string_type;
bool union_value_namespacing; bool union_value_namespacing;
bool allow_non_utf8; bool allow_non_utf8;
std::string include_prefix; std::string include_prefix;
bool keep_include_path;
bool binary_schema_comments; bool binary_schema_comments;
bool skip_flatbuffers_import;
std::string go_namespace;
bool reexport_ts_modules;
bool protobuf_ascii_alike;
// Possible options for the more general generator below. // Possible options for the more general generator below.
enum Language { enum Language {
@@ -369,6 +379,7 @@ struct IDLOptions {
kPhp = 1 << 6, kPhp = 1 << 6,
kJson = 1 << 7, kJson = 1 << 7,
kBinary = 1 << 8, kBinary = 1 << 8,
kTs = 1 << 9,
kMAX kMAX
}; };
@@ -397,7 +408,11 @@ struct IDLOptions {
cpp_object_api_pointer_type("std::unique_ptr"), cpp_object_api_pointer_type("std::unique_ptr"),
union_value_namespacing(true), union_value_namespacing(true),
allow_non_utf8(false), allow_non_utf8(false),
keep_include_path(false),
binary_schema_comments(false), binary_schema_comments(false),
skip_flatbuffers_import(false),
reexport_ts_modules(true),
protobuf_ascii_alike(false),
lang(IDLOptions::kJava), lang(IDLOptions::kJava),
lang_to_generate(0) {} lang_to_generate(0) {}
}; };
@@ -461,6 +476,7 @@ class Parser : public ParserState {
explicit Parser(const IDLOptions &options = IDLOptions()) explicit Parser(const IDLOptions &options = IDLOptions())
: root_struct_def_(nullptr), : root_struct_def_(nullptr),
opts(options), opts(options),
uses_flexbuffers_(false),
source_(nullptr), source_(nullptr),
anonymous_counter(0) { anonymous_counter(0) {
// Just in case none are declared: // Just in case none are declared:
@@ -479,9 +495,11 @@ class Parser : public ParserState {
known_attributes_["idempotent"] = true; known_attributes_["idempotent"] = true;
known_attributes_["cpp_type"] = true; known_attributes_["cpp_type"] = true;
known_attributes_["cpp_ptr_type"] = true; known_attributes_["cpp_ptr_type"] = true;
known_attributes_["cpp_str_type"] = true;
known_attributes_["native_inline"] = true; known_attributes_["native_inline"] = true;
known_attributes_["native_type"] = true; known_attributes_["native_type"] = true;
known_attributes_["native_default"] = true; known_attributes_["native_default"] = true;
known_attributes_["flexbuffer"] = true;
} }
~Parser() { ~Parser() {
@@ -499,6 +517,8 @@ class Parser : public ParserState {
// directory. // directory.
// If the source was loaded from a file and isn't an include file, // If the source was loaded from a file and isn't an include file,
// supply its name in source_filename. // supply its name in source_filename.
// All paths specified in this call must be in posix format, if you accept
// paths from user input, please call PosixPath on them first.
bool Parse(const char *_source, const char **include_paths = nullptr, bool Parse(const char *_source, const char **include_paths = nullptr,
const char *source_filename = nullptr); const char *source_filename = nullptr);
@@ -521,7 +541,12 @@ class Parser : public ParserState {
// of the schema provided. Returns non-empty error on any problems. // of the schema provided. Returns non-empty error on any problems.
std::string ConformTo(const Parser &base); std::string ConformTo(const Parser &base);
FLATBUFFERS_CHECKED_ERROR CheckBitsFit(int64_t val, size_t bits); // Similar to Parse(), but now only accepts JSON to be parsed into a
// FlexBuffer.
bool ParseFlexBuffer(const char *source, const char *source_filename,
flexbuffers::Builder *builder);
FLATBUFFERS_CHECKED_ERROR CheckInRange(int64_t val, int64_t min, int64_t max);
private: private:
FLATBUFFERS_CHECKED_ERROR Error(const std::string &msg); FLATBUFFERS_CHECKED_ERROR Error(const std::string &msg);
@@ -540,18 +565,26 @@ private:
const std::string &name, const Type &type, const std::string &name, const Type &type,
FieldDef **dest); FieldDef **dest);
FLATBUFFERS_CHECKED_ERROR ParseField(StructDef &struct_def); FLATBUFFERS_CHECKED_ERROR ParseField(StructDef &struct_def);
FLATBUFFERS_CHECKED_ERROR ParseString(Value &val);
FLATBUFFERS_CHECKED_ERROR ParseComma();
FLATBUFFERS_CHECKED_ERROR ParseAnyValue(Value &val, FieldDef *field, FLATBUFFERS_CHECKED_ERROR ParseAnyValue(Value &val, FieldDef *field,
size_t parent_fieldn, size_t parent_fieldn,
const StructDef *parent_struct_def); const StructDef *parent_struct_def);
FLATBUFFERS_CHECKED_ERROR ParseTableDelimiters(size_t &fieldn,
const StructDef *struct_def,
const std::function<CheckedError(const std::string &name)> &body);
FLATBUFFERS_CHECKED_ERROR ParseTable(const StructDef &struct_def, FLATBUFFERS_CHECKED_ERROR ParseTable(const StructDef &struct_def,
std::string *value, uoffset_t *ovalue); std::string *value, uoffset_t *ovalue);
void SerializeStruct(const StructDef &struct_def, const Value &val); void SerializeStruct(const StructDef &struct_def, const Value &val);
void AddVector(bool sortbysize, int count); void AddVector(bool sortbysize, int count);
FLATBUFFERS_CHECKED_ERROR ParseVectorDelimiters(size_t &count,
const std::function<CheckedError()> &body);
FLATBUFFERS_CHECKED_ERROR ParseVector(const Type &type, uoffset_t *ovalue); FLATBUFFERS_CHECKED_ERROR ParseVector(const Type &type, uoffset_t *ovalue);
FLATBUFFERS_CHECKED_ERROR ParseMetaData(SymbolTable<Value> *attributes); FLATBUFFERS_CHECKED_ERROR ParseMetaData(SymbolTable<Value> *attributes);
FLATBUFFERS_CHECKED_ERROR TryTypedValue(int dtoken, bool check, Value &e, FLATBUFFERS_CHECKED_ERROR TryTypedValue(int dtoken, bool check, Value &e,
BaseType req, bool *destmatch); BaseType req, bool *destmatch);
FLATBUFFERS_CHECKED_ERROR ParseHash(Value &e, FieldDef* field); FLATBUFFERS_CHECKED_ERROR ParseHash(Value &e, FieldDef* field);
FLATBUFFERS_CHECKED_ERROR TokenError();
FLATBUFFERS_CHECKED_ERROR ParseSingleValue(Value &e); FLATBUFFERS_CHECKED_ERROR ParseSingleValue(Value &e);
FLATBUFFERS_CHECKED_ERROR ParseEnumFromString(Type &type, int64_t *result); FLATBUFFERS_CHECKED_ERROR ParseEnumFromString(Type &type, int64_t *result);
StructDef *LookupCreateStruct(const std::string &name, StructDef *LookupCreateStruct(const std::string &name,
@@ -571,12 +604,13 @@ private:
FLATBUFFERS_CHECKED_ERROR ParseProtoCurliesOrIdent(); FLATBUFFERS_CHECKED_ERROR ParseProtoCurliesOrIdent();
FLATBUFFERS_CHECKED_ERROR ParseTypeFromProtoType(Type *type); FLATBUFFERS_CHECKED_ERROR ParseTypeFromProtoType(Type *type);
FLATBUFFERS_CHECKED_ERROR SkipAnyJsonValue(); FLATBUFFERS_CHECKED_ERROR SkipAnyJsonValue();
FLATBUFFERS_CHECKED_ERROR SkipJsonObject(); FLATBUFFERS_CHECKED_ERROR ParseFlexBufferValue(flexbuffers::Builder *builder);
FLATBUFFERS_CHECKED_ERROR SkipJsonArray(); FLATBUFFERS_CHECKED_ERROR StartParseFile(const char *source,
FLATBUFFERS_CHECKED_ERROR SkipJsonString(); const char *source_filename);
FLATBUFFERS_CHECKED_ERROR DoParse(const char *_source, FLATBUFFERS_CHECKED_ERROR DoParse(const char *_source,
const char **include_paths, const char **include_paths,
const char *source_filename); const char *source_filename,
const char *include_filename);
FLATBUFFERS_CHECKED_ERROR CheckClash(std::vector<FieldDef*> &fields, FLATBUFFERS_CHECKED_ERROR CheckClash(std::vector<FieldDef*> &fields,
StructDef *struct_def, StructDef *struct_def,
const char *suffix, const char *suffix,
@@ -595,13 +629,14 @@ private:
std::string file_identifier_; std::string file_identifier_;
std::string file_extension_; std::string file_extension_;
std::map<std::string, bool> included_files_; std::map<std::string, std::string> included_files_;
std::map<std::string, std::set<std::string>> files_included_per_file_; std::map<std::string, std::set<std::string>> files_included_per_file_;
std::vector<std::string> native_included_files_; std::vector<std::string> native_included_files_;
std::map<std::string, bool> known_attributes_; std::map<std::string, bool> known_attributes_;
IDLOptions opts; IDLOptions opts;
bool uses_flexbuffers_;
private: private:
const char *source_; const char *source_;
@@ -647,7 +682,7 @@ extern bool GenerateCPP(const Parser &parser,
const std::string &path, const std::string &path,
const std::string &file_name); const std::string &file_name);
// Generate JavaScript code from the definitions in the Parser object. // Generate JavaScript or TypeScript code from the definitions in the Parser object.
// See idl_gen_js. // See idl_gen_js.
extern std::string GenerateJS(const Parser &parser); extern std::string GenerateJS(const Parser &parser);
extern bool GenerateJS(const Parser &parser, extern bool GenerateJS(const Parser &parser,
@@ -698,7 +733,7 @@ extern bool GenerateFBS(const Parser &parser,
const std::string &path, const std::string &path,
const std::string &file_name); const std::string &file_name);
// Generate a make rule for the generated JavaScript code. // Generate a make rule for the generated JavaScript or TypeScript code.
// See idl_gen_js.cpp. // See idl_gen_js.cpp.
extern std::string JSMakeRule(const Parser &parser, extern std::string JSMakeRule(const Parser &parser,
const std::string &path, const std::string &path,
@@ -743,4 +778,3 @@ bool GenerateGoGRPC(const Parser &parser,
} // namespace flatbuffers } // namespace flatbuffers
#endif // FLATBUFFERS_IDL_H_ #endif // FLATBUFFERS_IDL_H_

View File

@@ -30,6 +30,15 @@ namespace flatbuffers {
// ------------------------- GETTERS ------------------------- // ------------------------- GETTERS -------------------------
inline bool IsScalar (reflection::BaseType t) { return t >= reflection::UType &&
t <= reflection::Double; }
inline bool IsInteger(reflection::BaseType t) { return t >= reflection::UType &&
t <= reflection::ULong; }
inline bool IsFloat (reflection::BaseType t) { return t == reflection::Float ||
t == reflection::Double; }
inline bool IsLong (reflection::BaseType t) { return t == reflection::Long ||
t == reflection::ULong; }
// Size of a basic type, don't use with structs. // Size of a basic type, don't use with structs.
inline size_t GetTypeSize(reflection::BaseType base_type) { inline size_t GetTypeSize(reflection::BaseType base_type) {
// This needs to correspond to the BaseType enum. // This needs to correspond to the BaseType enum.
@@ -58,6 +67,18 @@ inline const Table *GetAnyRoot(const uint8_t *flatbuf) {
return GetRoot<Table>(flatbuf); return GetRoot<Table>(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()));
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()));
return static_cast<T>(field.default_real());
}
// Get a field, if you know it's an integer, and its exact type. // Get a field, if you know it's an integer, and its exact type.
template<typename T> T GetFieldI(const Table &table, template<typename T> T GetFieldI(const Table &table,
const reflection::Field &field) { const reflection::Field &field) {
@@ -242,8 +263,19 @@ template<typename T> T *GetAnyFieldAddressOf(const Struct &st,
// Set any scalar field, if you know its exact type. // Set any scalar field, if you know its exact type.
template<typename T> bool SetField(Table *table, const reflection::Field &field, template<typename T> bool SetField(Table *table, const reflection::Field &field,
T val) { T val) {
assert(sizeof(T) == GetTypeSize(field.type()->base_type())); reflection::BaseType type = field.type()->base_type();
return table->SetField(field.offset(), val); if (!IsScalar(type)) {
return false;
}
assert(sizeof(T) == GetTypeSize(type));
T def;
if (IsInteger(type)) {
def = GetFieldDefaultI<T>(field);
} else {
assert(IsFloat(type));
def = GetFieldDefaultF<T>(field);
}
return table->SetField(field.offset(), val, def);
} }
// Raw helper functions used below: set any value in memory as a 64bit int, a // Raw helper functions used below: set any value in memory as a 64bit int, a
@@ -258,7 +290,7 @@ void SetAnyValueS(reflection::BaseType type, uint8_t *data, const char *val);
inline bool SetAnyFieldI(Table *table, const reflection::Field &field, inline bool SetAnyFieldI(Table *table, const reflection::Field &field,
int64_t val) { int64_t val) {
auto field_ptr = table->GetAddressOf(field.offset()); auto field_ptr = table->GetAddressOf(field.offset());
if (!field_ptr) return false; if (!field_ptr) return val == GetFieldDefaultI<int64_t>(field);
SetAnyValueI(field.type()->base_type(), field_ptr, val); SetAnyValueI(field.type()->base_type(), field_ptr, val);
return true; return true;
} }
@@ -267,7 +299,7 @@ inline bool SetAnyFieldI(Table *table, const reflection::Field &field,
inline bool SetAnyFieldF(Table *table, const reflection::Field &field, inline bool SetAnyFieldF(Table *table, const reflection::Field &field,
double val) { double val) {
auto field_ptr = table->GetAddressOf(field.offset()); auto field_ptr = table->GetAddressOf(field.offset());
if (!field_ptr) return false; if (!field_ptr) return val == GetFieldDefaultF<double>(field);
SetAnyValueF(field.type()->base_type(), field_ptr, val); SetAnyValueF(field.type()->base_type(), field_ptr, val);
return true; return true;
} }

View File

@@ -150,9 +150,9 @@ struct KeyValue FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
} }
bool Verify(flatbuffers::Verifier &verifier) const { bool Verify(flatbuffers::Verifier &verifier) const {
return VerifyTableStart(verifier) && return VerifyTableStart(verifier) &&
VerifyFieldRequired<flatbuffers::uoffset_t>(verifier, VT_KEY) && VerifyOffsetRequired(verifier, VT_KEY) &&
verifier.Verify(key()) && verifier.Verify(key()) &&
VerifyField<flatbuffers::uoffset_t>(verifier, VT_VALUE) && VerifyOffset(verifier, VT_VALUE) &&
verifier.Verify(value()) && verifier.Verify(value()) &&
verifier.EndTable(); verifier.EndTable();
} }
@@ -204,7 +204,8 @@ struct EnumVal FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
enum { enum {
VT_NAME = 4, VT_NAME = 4,
VT_VALUE = 6, VT_VALUE = 6,
VT_OBJECT = 8 VT_OBJECT = 8,
VT_UNION_TYPE = 10
}; };
const flatbuffers::String *name() const { const flatbuffers::String *name() const {
return GetPointer<const flatbuffers::String *>(VT_NAME); return GetPointer<const flatbuffers::String *>(VT_NAME);
@@ -228,13 +229,18 @@ struct EnumVal FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
const Object *object() const { const Object *object() const {
return GetPointer<const Object *>(VT_OBJECT); return GetPointer<const Object *>(VT_OBJECT);
} }
const Type *union_type() const {
return GetPointer<const Type *>(VT_UNION_TYPE);
}
bool Verify(flatbuffers::Verifier &verifier) const { bool Verify(flatbuffers::Verifier &verifier) const {
return VerifyTableStart(verifier) && return VerifyTableStart(verifier) &&
VerifyFieldRequired<flatbuffers::uoffset_t>(verifier, VT_NAME) && VerifyOffsetRequired(verifier, VT_NAME) &&
verifier.Verify(name()) && verifier.Verify(name()) &&
VerifyField<int64_t>(verifier, VT_VALUE) && VerifyField<int64_t>(verifier, VT_VALUE) &&
VerifyField<flatbuffers::uoffset_t>(verifier, VT_OBJECT) && VerifyOffset(verifier, VT_OBJECT) &&
verifier.VerifyTable(object()) && verifier.VerifyTable(object()) &&
VerifyOffset(verifier, VT_UNION_TYPE) &&
verifier.VerifyTable(union_type()) &&
verifier.EndTable(); verifier.EndTable();
} }
}; };
@@ -251,13 +257,16 @@ struct EnumValBuilder {
void add_object(flatbuffers::Offset<Object> object) { void add_object(flatbuffers::Offset<Object> object) {
fbb_.AddOffset(EnumVal::VT_OBJECT, object); fbb_.AddOffset(EnumVal::VT_OBJECT, object);
} }
void add_union_type(flatbuffers::Offset<Type> union_type) {
fbb_.AddOffset(EnumVal::VT_UNION_TYPE, union_type);
}
EnumValBuilder(flatbuffers::FlatBufferBuilder &_fbb) EnumValBuilder(flatbuffers::FlatBufferBuilder &_fbb)
: fbb_(_fbb) { : fbb_(_fbb) {
start_ = fbb_.StartTable(); start_ = fbb_.StartTable();
} }
EnumValBuilder &operator=(const EnumValBuilder &); EnumValBuilder &operator=(const EnumValBuilder &);
flatbuffers::Offset<EnumVal> Finish() { flatbuffers::Offset<EnumVal> Finish() {
const auto end = fbb_.EndTable(start_, 3); const auto end = fbb_.EndTable(start_, 4);
auto o = flatbuffers::Offset<EnumVal>(end); auto o = flatbuffers::Offset<EnumVal>(end);
fbb_.Required(o, EnumVal::VT_NAME); fbb_.Required(o, EnumVal::VT_NAME);
return o; return o;
@@ -268,9 +277,11 @@ inline flatbuffers::Offset<EnumVal> CreateEnumVal(
flatbuffers::FlatBufferBuilder &_fbb, flatbuffers::FlatBufferBuilder &_fbb,
flatbuffers::Offset<flatbuffers::String> name = 0, flatbuffers::Offset<flatbuffers::String> name = 0,
int64_t value = 0, int64_t value = 0,
flatbuffers::Offset<Object> object = 0) { flatbuffers::Offset<Object> object = 0,
flatbuffers::Offset<Type> union_type = 0) {
EnumValBuilder builder_(_fbb); EnumValBuilder builder_(_fbb);
builder_.add_value(value); builder_.add_value(value);
builder_.add_union_type(union_type);
builder_.add_object(object); builder_.add_object(object);
builder_.add_name(name); builder_.add_name(name);
return builder_.Finish(); return builder_.Finish();
@@ -280,12 +291,14 @@ inline flatbuffers::Offset<EnumVal> CreateEnumValDirect(
flatbuffers::FlatBufferBuilder &_fbb, flatbuffers::FlatBufferBuilder &_fbb,
const char *name = nullptr, const char *name = nullptr,
int64_t value = 0, int64_t value = 0,
flatbuffers::Offset<Object> object = 0) { flatbuffers::Offset<Object> object = 0,
flatbuffers::Offset<Type> union_type = 0) {
return reflection::CreateEnumVal( return reflection::CreateEnumVal(
_fbb, _fbb,
name ? _fbb.CreateString(name) : 0, name ? _fbb.CreateString(name) : 0,
value, value,
object); object,
union_type);
} }
struct Enum FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { struct Enum FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
@@ -323,18 +336,18 @@ struct Enum FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
} }
bool Verify(flatbuffers::Verifier &verifier) const { bool Verify(flatbuffers::Verifier &verifier) const {
return VerifyTableStart(verifier) && return VerifyTableStart(verifier) &&
VerifyFieldRequired<flatbuffers::uoffset_t>(verifier, VT_NAME) && VerifyOffsetRequired(verifier, VT_NAME) &&
verifier.Verify(name()) && verifier.Verify(name()) &&
VerifyFieldRequired<flatbuffers::uoffset_t>(verifier, VT_VALUES) && VerifyOffsetRequired(verifier, VT_VALUES) &&
verifier.Verify(values()) && verifier.Verify(values()) &&
verifier.VerifyVectorOfTables(values()) && verifier.VerifyVectorOfTables(values()) &&
VerifyField<uint8_t>(verifier, VT_IS_UNION) && VerifyField<uint8_t>(verifier, VT_IS_UNION) &&
VerifyFieldRequired<flatbuffers::uoffset_t>(verifier, VT_UNDERLYING_TYPE) && VerifyOffsetRequired(verifier, VT_UNDERLYING_TYPE) &&
verifier.VerifyTable(underlying_type()) && verifier.VerifyTable(underlying_type()) &&
VerifyField<flatbuffers::uoffset_t>(verifier, VT_ATTRIBUTES) && VerifyOffset(verifier, VT_ATTRIBUTES) &&
verifier.Verify(attributes()) && verifier.Verify(attributes()) &&
verifier.VerifyVectorOfTables(attributes()) && verifier.VerifyVectorOfTables(attributes()) &&
VerifyField<flatbuffers::uoffset_t>(verifier, VT_DOCUMENTATION) && VerifyOffset(verifier, VT_DOCUMENTATION) &&
verifier.Verify(documentation()) && verifier.Verify(documentation()) &&
verifier.VerifyVectorOfStrings(documentation()) && verifier.VerifyVectorOfStrings(documentation()) &&
verifier.EndTable(); verifier.EndTable();
@@ -468,9 +481,9 @@ struct Field FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
} }
bool Verify(flatbuffers::Verifier &verifier) const { bool Verify(flatbuffers::Verifier &verifier) const {
return VerifyTableStart(verifier) && return VerifyTableStart(verifier) &&
VerifyFieldRequired<flatbuffers::uoffset_t>(verifier, VT_NAME) && VerifyOffsetRequired(verifier, VT_NAME) &&
verifier.Verify(name()) && verifier.Verify(name()) &&
VerifyFieldRequired<flatbuffers::uoffset_t>(verifier, VT_TYPE) && VerifyOffsetRequired(verifier, VT_TYPE) &&
verifier.VerifyTable(type()) && verifier.VerifyTable(type()) &&
VerifyField<uint16_t>(verifier, VT_ID) && VerifyField<uint16_t>(verifier, VT_ID) &&
VerifyField<uint16_t>(verifier, VT_OFFSET) && VerifyField<uint16_t>(verifier, VT_OFFSET) &&
@@ -479,10 +492,10 @@ struct Field FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
VerifyField<uint8_t>(verifier, VT_DEPRECATED) && VerifyField<uint8_t>(verifier, VT_DEPRECATED) &&
VerifyField<uint8_t>(verifier, VT_REQUIRED) && VerifyField<uint8_t>(verifier, VT_REQUIRED) &&
VerifyField<uint8_t>(verifier, VT_KEY) && VerifyField<uint8_t>(verifier, VT_KEY) &&
VerifyField<flatbuffers::uoffset_t>(verifier, VT_ATTRIBUTES) && VerifyOffset(verifier, VT_ATTRIBUTES) &&
verifier.Verify(attributes()) && verifier.Verify(attributes()) &&
verifier.VerifyVectorOfTables(attributes()) && verifier.VerifyVectorOfTables(attributes()) &&
VerifyField<flatbuffers::uoffset_t>(verifier, VT_DOCUMENTATION) && VerifyOffset(verifier, VT_DOCUMENTATION) &&
verifier.Verify(documentation()) && verifier.Verify(documentation()) &&
verifier.VerifyVectorOfStrings(documentation()) && verifier.VerifyVectorOfStrings(documentation()) &&
verifier.EndTable(); verifier.EndTable();
@@ -634,18 +647,18 @@ struct Object FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
} }
bool Verify(flatbuffers::Verifier &verifier) const { bool Verify(flatbuffers::Verifier &verifier) const {
return VerifyTableStart(verifier) && return VerifyTableStart(verifier) &&
VerifyFieldRequired<flatbuffers::uoffset_t>(verifier, VT_NAME) && VerifyOffsetRequired(verifier, VT_NAME) &&
verifier.Verify(name()) && verifier.Verify(name()) &&
VerifyFieldRequired<flatbuffers::uoffset_t>(verifier, VT_FIELDS) && VerifyOffsetRequired(verifier, VT_FIELDS) &&
verifier.Verify(fields()) && verifier.Verify(fields()) &&
verifier.VerifyVectorOfTables(fields()) && verifier.VerifyVectorOfTables(fields()) &&
VerifyField<uint8_t>(verifier, VT_IS_STRUCT) && VerifyField<uint8_t>(verifier, VT_IS_STRUCT) &&
VerifyField<int32_t>(verifier, VT_MINALIGN) && VerifyField<int32_t>(verifier, VT_MINALIGN) &&
VerifyField<int32_t>(verifier, VT_BYTESIZE) && VerifyField<int32_t>(verifier, VT_BYTESIZE) &&
VerifyField<flatbuffers::uoffset_t>(verifier, VT_ATTRIBUTES) && VerifyOffset(verifier, VT_ATTRIBUTES) &&
verifier.Verify(attributes()) && verifier.Verify(attributes()) &&
verifier.VerifyVectorOfTables(attributes()) && verifier.VerifyVectorOfTables(attributes()) &&
VerifyField<flatbuffers::uoffset_t>(verifier, VT_DOCUMENTATION) && VerifyOffset(verifier, VT_DOCUMENTATION) &&
verifier.Verify(documentation()) && verifier.Verify(documentation()) &&
verifier.VerifyVectorOfStrings(documentation()) && verifier.VerifyVectorOfStrings(documentation()) &&
verifier.EndTable(); verifier.EndTable();
@@ -755,17 +768,17 @@ struct Schema FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
} }
bool Verify(flatbuffers::Verifier &verifier) const { bool Verify(flatbuffers::Verifier &verifier) const {
return VerifyTableStart(verifier) && return VerifyTableStart(verifier) &&
VerifyFieldRequired<flatbuffers::uoffset_t>(verifier, VT_OBJECTS) && VerifyOffsetRequired(verifier, VT_OBJECTS) &&
verifier.Verify(objects()) && verifier.Verify(objects()) &&
verifier.VerifyVectorOfTables(objects()) && verifier.VerifyVectorOfTables(objects()) &&
VerifyFieldRequired<flatbuffers::uoffset_t>(verifier, VT_ENUMS) && VerifyOffsetRequired(verifier, VT_ENUMS) &&
verifier.Verify(enums()) && verifier.Verify(enums()) &&
verifier.VerifyVectorOfTables(enums()) && verifier.VerifyVectorOfTables(enums()) &&
VerifyField<flatbuffers::uoffset_t>(verifier, VT_FILE_IDENT) && VerifyOffset(verifier, VT_FILE_IDENT) &&
verifier.Verify(file_ident()) && verifier.Verify(file_ident()) &&
VerifyField<flatbuffers::uoffset_t>(verifier, VT_FILE_EXT) && VerifyOffset(verifier, VT_FILE_EXT) &&
verifier.Verify(file_ext()) && verifier.Verify(file_ext()) &&
VerifyField<flatbuffers::uoffset_t>(verifier, VT_ROOT_TABLE) && VerifyOffset(verifier, VT_ROOT_TABLE) &&
verifier.VerifyTable(root_table()) && verifier.VerifyTable(root_table()) &&
verifier.EndTable(); verifier.EndTable();
} }

View File

@@ -0,0 +1,131 @@
/*
* Copyright 2017 Google Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FLATBUFFERS_REGISTRY_H_
#define FLATBUFFERS_REGISTRY_H_
#include "flatbuffers/idl.h"
namespace flatbuffers {
// Convenience class to easily parse or generate text for arbitrary FlatBuffers.
// Simply pre-populate it with all schema filenames that may be in use, and
// This class will look them up using the file_identifier declared in the
// schema.
class Registry {
public:
// Call this for all schemas that may be in use. The identifier has
// a function in the generated code, e.g. MonsterIdentifier().
void Register(const char *file_identifier, const char *schema_path) {
Schema schema;
schema.path_ = schema_path;
schemas_[file_identifier] = schema;
}
// Generate text from an arbitrary FlatBuffer by looking up its
// file_identifier in the registry.
bool FlatBufferToText(const uint8_t *flatbuf, size_t len,
std::string *dest) {
// Get the identifier out of the buffer.
// If the buffer is truncated, exit.
if (len < sizeof(uoffset_t) +
FlatBufferBuilder::kFileIdentifierLength) {
lasterror_ = "buffer truncated";
return false;
}
std::string ident(reinterpret_cast<const char *>(flatbuf) +
sizeof(uoffset_t),
FlatBufferBuilder::kFileIdentifierLength);
// Load and parse the schema.
Parser parser;
if (!LoadSchema(ident, &parser)) return false;
// Now we're ready to generate text.
if (!GenerateText(parser, flatbuf, dest)) {
lasterror_ = "unable to generate text for FlatBuffer binary";
return false;
}
return true;
}
// Converts a binary buffer to text using one of the schemas in the registry,
// use the file_identifier to indicate which.
// If DetachedBuffer::data() is null then parsing failed.
DetachedBuffer TextToFlatBuffer(const char *text,
const char *file_identifier) {
// Load and parse the schema.
Parser parser;
if (!LoadSchema(file_identifier, &parser)) return DetachedBuffer();
// Parse the text.
if (!parser.Parse(text)) {
lasterror_ = parser.error_;
return DetachedBuffer();
}
// We have a valid FlatBuffer. Detach it from the builder and return.
return parser.builder_.ReleaseBufferPointer();
}
// Modify any parsing / output options used by the other functions.
void SetOptions(const IDLOptions &opts) { opts_ = opts; }
// If schemas used contain include statements, call this function for every
// directory the parser should search them for.
void AddIncludeDirectory(const char *path) {
include_paths_.push_back(path);
}
// Returns a human readable error if any of the above functions fail.
const std::string &GetLastError() { return lasterror_; }
private:
bool LoadSchema(const std::string &ident, Parser *parser) {
// Find the schema, if not, exit.
auto it = schemas_.find(ident);
if (it == schemas_.end()) {
// Don't attach the identifier, since it may not be human readable.
lasterror_ = "identifier for this buffer not in the registry";
return false;
}
auto &schema = it->second;
// Load the schema from disk. If not, exit.
std::string schematext;
if (!LoadFile(schema.path_.c_str(), false, &schematext)) {
lasterror_ = "could not load schema: " + schema.path_;
return false;
}
// Parse schema.
parser->opts = opts_;
if (!parser->Parse(schematext.c_str(), include_paths_.data(),
schema.path_.c_str())) {
lasterror_ = parser->error_;
return false;
}
return true;
}
struct Schema {
std::string path_;
// TODO(wvo) optionally cache schema file or parsed schema here.
};
std::string lasterror_;
IDLOptions opts_;
std::vector<const char *> include_paths_;
std::map<std::string, Schema> schemas_;
};
} // namespace flatbuffers
#endif // FLATBUFFERS_REGISTRY_H_

View File

@@ -40,7 +40,8 @@
#include <sys/types.h> #include <sys/types.h>
#include <sys/stat.h> #include <sys/stat.h>
#include "flatbuffers/flatbuffers.h" #include "flatbuffers/base.h"
namespace flatbuffers { namespace flatbuffers {
@@ -71,9 +72,8 @@ template<> inline std::string NumToString<double>(double t) {
// Sadly, std::fixed turns "1" into "1.00000", so here we undo that. // Sadly, std::fixed turns "1" into "1.00000", so here we undo that.
auto p = s.find_last_not_of('0'); auto p = s.find_last_not_of('0');
if (p != std::string::npos) { if (p != std::string::npos) {
s.resize(p + 1); // Strip trailing zeroes. // Strip trailing zeroes. If it is a whole number, keep one zero.
if (s[s.size() - 1] == '.') s.resize(p + (s[p] == '.' ? 2 : 1));
s.erase(s.size() - 1, 1); // Strip '.' if a whole number.
} }
return s; return s;
} }
@@ -157,16 +157,20 @@ inline bool SaveFile(const char *name, const std::string &buf, bool binary) {
return SaveFile(name, buf.c_str(), buf.size(), binary); return SaveFile(name, buf.c_str(), buf.size(), binary);
} }
// Functionality for minimalistic portable path handling: // Functionality for minimalistic portable path handling.
static const char kPosixPathSeparator = '/'; // The functions below behave correctly regardless of whether posix ('/') or
#ifdef _WIN32 // Windows ('/' or '\\') separators are used.
static const char kPathSeparator = '\\';
// Any new separators inserted are always posix.
// We internally store paths in posix format ('/'). Paths supplied
// by the user should go through PosixPath to ensure correct behavior
// on Windows when paths are string-compared.
static const char kPathSeparator = '/';
static const char kPathSeparatorWindows = '\\';
static const char *PathSeparatorSet = "\\/"; // Intentionally no ':' static const char *PathSeparatorSet = "\\/"; // Intentionally no ':'
#else
static const char kPathSeparator = kPosixPathSeparator;
static const char *PathSeparatorSet = "/";
#endif // _WIN32
// Returns the path with the extension, if any, removed. // Returns the path with the extension, if any, removed.
inline std::string StripExtension(const std::string &filepath) { inline std::string StripExtension(const std::string &filepath) {
@@ -197,13 +201,24 @@ inline std::string StripFileName(const std::string &filepath) {
inline std::string ConCatPathFileName(const std::string &path, inline std::string ConCatPathFileName(const std::string &path,
const std::string &filename) { const std::string &filename) {
std::string filepath = path; std::string filepath = path;
if (path.length() && path[path.size() - 1] != kPathSeparator && if (filepath.length()) {
path[path.size() - 1] != kPosixPathSeparator) if (filepath.back() == kPathSeparatorWindows) {
filepath += kPathSeparator; filepath.back() = kPathSeparator;
} else if (filepath.back() != kPathSeparator) {
filepath += kPathSeparator;
}
}
filepath += filename; filepath += filename;
return filepath; return filepath;
} }
// Replaces any '\\' separators with '/'
inline std::string PosixPath(const char *path) {
std::string p = path;
std::replace(p.begin(), p.end(), '\\', '/');
return p;
}
// This function ensure a directory exists, by recursively // This function ensure a directory exists, by recursively
// creating dirs for any parts of the path that don't exist yet. // creating dirs for any parts of the path that don't exist yet.
inline void EnsureDirExists(const std::string &filepath) { inline void EnsureDirExists(const std::string &filepath) {
@@ -345,6 +360,72 @@ inline std::string WordWrap(const std::string in, size_t max_length,
return wrapped; return wrapped;
} }
inline bool EscapeString(const char *s, size_t length, std::string *_text,
bool allow_non_utf8) {
std::string &text = *_text;
text += "\"";
for (uoffset_t i = 0; i < length; i++) {
char c = s[i];
switch (c) {
case '\n': text += "\\n"; break;
case '\t': text += "\\t"; break;
case '\r': text += "\\r"; break;
case '\b': text += "\\b"; break;
case '\f': text += "\\f"; break;
case '\"': text += "\\\""; break;
case '\\': text += "\\\\"; break;
default:
if (c >= ' ' && c <= '~') {
text += c;
} else {
// Not printable ASCII data. Let's see if it's valid UTF-8 first:
const char *utf8 = s + i;
int ucc = FromUTF8(&utf8);
if (ucc < 0) {
if (allow_non_utf8) {
text += "\\x";
text += IntToStringHex(static_cast<uint8_t>(c), 2);
} else {
// There are two cases here:
//
// 1) We reached here by parsing an IDL file. In that case,
// we previously checked for non-UTF-8, so we shouldn't reach
// here.
//
// 2) We reached here by someone calling GenerateText()
// on a previously-serialized flatbuffer. The data might have
// non-UTF-8 Strings, or might be corrupt.
//
// In both cases, we have to give up and inform the caller
// they have no JSON.
return false;
}
} else {
if (ucc <= 0xFFFF) {
// Parses as Unicode within JSON's \uXXXX range, so use that.
text += "\\u";
text += IntToStringHex(ucc, 4);
} else if (ucc <= 0x10FFFF) {
// Encode Unicode SMP values to a surrogate pair using two \u escapes.
uint32_t base = ucc - 0x10000;
auto high_surrogate = (base >> 10) + 0xD800;
auto low_surrogate = (base & 0x03FF) + 0xDC00;
text += "\\u";
text += IntToStringHex(high_surrogate, 4);
text += "\\u";
text += IntToStringHex(low_surrogate, 4);
}
// Skip past characters recognized.
i = static_cast<uoffset_t>(utf8 - s - 1);
}
}
break;
}
}
text += "\"";
return true;
}
} // namespace flatbuffers } // namespace flatbuffers
#endif // FLATBUFFERS_UTIL_H_ #endif // FLATBUFFERS_UTIL_H_

View File

@@ -106,6 +106,22 @@ public class FlatBufferBuilder {
return this; return this;
} }
/**
* Reset the FlatBufferBuilder by purging all data that it holds.
*/
public void clear(){
space = bb.capacity();
bb.clear();
minalign = 1;
while(vtable_in_use > 0) vtable[--vtable_in_use] = 0;
vtable_in_use = 0;
nested = false;
finished = false;
object_start = 0;
num_vtables = 0;
vector_num_elems = 0;
}
/// @cond FLATBUFFERS_INTERNAL /// @cond FLATBUFFERS_INTERNAL
/** /**
* Create a `ByteBuffer` with a given capacity. * Create a `ByteBuffer` with a given capacity.

View File

@@ -115,7 +115,7 @@ flatbuffers.Long.create = function(low, high) {
* @returns {number} * @returns {number}
*/ */
flatbuffers.Long.prototype.toFloat64 = function() { flatbuffers.Long.prototype.toFloat64 = function() {
return this.low + this.high * 0x100000000; return (this.low >>> 0) + this.high * 0x100000000;
}; };
/** /**
@@ -944,9 +944,17 @@ flatbuffers.ByteBuffer.prototype.readFloat64 = function(offset) {
/** /**
* @param {number} offset * @param {number} offset
* @param {number} value * @param {number|boolean} value
*/ */
flatbuffers.ByteBuffer.prototype.writeInt8 = function(offset, value) { flatbuffers.ByteBuffer.prototype.writeInt8 = function(offset, value) {
this.bytes_[offset] = /** @type {number} */(value);
};
/**
* @param {number} offset
* @param {number} value
*/
flatbuffers.ByteBuffer.prototype.writeUint8 = function(offset, value) {
this.bytes_[offset] = value; this.bytes_[offset] = value;
}; };
@@ -959,6 +967,15 @@ flatbuffers.ByteBuffer.prototype.writeInt16 = function(offset, value) {
this.bytes_[offset + 1] = value >> 8; this.bytes_[offset + 1] = value >> 8;
}; };
/**
* @param {number} offset
* @param {number} value
*/
flatbuffers.ByteBuffer.prototype.writeUint16 = function(offset, value) {
this.bytes_[offset] = value;
this.bytes_[offset + 1] = value >> 8;
};
/** /**
* @param {number} offset * @param {number} offset
* @param {number} value * @param {number} value
@@ -970,6 +987,17 @@ flatbuffers.ByteBuffer.prototype.writeInt32 = function(offset, value) {
this.bytes_[offset + 3] = value >> 24; this.bytes_[offset + 3] = value >> 24;
}; };
/**
* @param {number} offset
* @param {number} value
*/
flatbuffers.ByteBuffer.prototype.writeUint32 = function(offset, value) {
this.bytes_[offset] = value;
this.bytes_[offset + 1] = value >> 8;
this.bytes_[offset + 2] = value >> 16;
this.bytes_[offset + 3] = value >> 24;
};
/** /**
* @param {number} offset * @param {number} offset
* @param {flatbuffers.Long} value * @param {flatbuffers.Long} value
@@ -979,6 +1007,15 @@ flatbuffers.ByteBuffer.prototype.writeInt64 = function(offset, value) {
this.writeInt32(offset + 4, value.high); this.writeInt32(offset + 4, value.high);
}; };
/**
* @param {number} offset
* @param {flatbuffers.Long} value
*/
flatbuffers.ByteBuffer.prototype.writeUint64 = function(offset, value) {
this.writeUint32(offset, value.low);
this.writeUint32(offset + 4, value.high);
};
/** /**
* @param {number} offset * @param {number} offset
* @param {number} value * @param {number} value

View File

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

View File

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

View File

@@ -54,6 +54,6 @@ you would leave it in.
[`flatbuffers` tag]: https://stackoverflow.com/questions/tagged/flatbuffers [`flatbuffers` tag]: https://stackoverflow.com/questions/tagged/flatbuffers
[FlatBuffers Google Group]: https://groups.google.com/forum/#!forum/flatbuffers [FlatBuffers Google Group]: https://groups.google.com/forum/#!forum/flatbuffers
[FlatBuffers Issues Tracker]: http://github.com/google/flatbuffers/issues [FlatBuffers Issues Tracker]: http://github.com/google/flatbuffers/issues
[stackoverflow.com]: http://www.stackoverflow.com [stackoverflow.com]: http://stackoverflow.com/search?q=flatbuffers
[landing page]: http://google.github.io/flatbuffers [landing page]: http://google.github.io/flatbuffers
[LICENSE]: https://github.com/google/flatbuffers/blob/master/LICENSE.txt [LICENSE]: https://github.com/google/flatbuffers/blob/master/LICENSE.txt

View File

@@ -42,7 +42,8 @@ table KeyValue {
table EnumVal { table EnumVal {
name:string (required); name:string (required);
value:long (key); value:long (key);
object:Object; // Only if part of a union. object:Object; // Will be deprecated in favor of union_type in the future.
union_type:Type;
} }
table Enum { table Enum {

View File

@@ -81,22 +81,19 @@ class SampleBinary
Assert(monster.Color == Color.Red, "monster.Color", Convert.ToString(monster.Color), Assert(monster.Color == Color.Red, "monster.Color", Convert.ToString(monster.Color),
Convert.ToString(Color.Red)); Convert.ToString(Color.Red));
// C# also allows you to use performance-enhanced methods to fill an object that has already var vec = monster.Pos.Value;
// been created. These functions are prefixed with "Get". For example: `monster.GetPos()`. Assert(vec.X == 1.0f, "vec.X",
var myAlreadyCreatedVector = new Vec3(); Convert.ToString(vec.X), Convert.ToString(1.0f));
monster.GetPos(myAlreadyCreatedVector); // Instead of `var myNewVec3 = monster.Pos`. Assert(vec.Y == 2.0f, "vec.Y",
Assert(myAlreadyCreatedVector.X == 1.0f, "myAlreadyCreatedVector.X", Convert.ToString(vec.Y), Convert.ToString(2.0f));
Convert.ToString(myAlreadyCreatedVector.X), Convert.ToString(1.0f)); Assert(vec.Z == 3.0f, "vec.Z",
Assert(myAlreadyCreatedVector.Y == 2.0f, "myAlreadyCreatedVector.Y", Convert.ToString(vec.Z), Convert.ToString(3.0f));
Convert.ToString(myAlreadyCreatedVector.Y), Convert.ToString(2.0f));
Assert(myAlreadyCreatedVector.Z == 3.0f, "myAlreadyCreatedVector.Z",
Convert.ToString(myAlreadyCreatedVector.Z), Convert.ToString(3.0f));
// Get and test the `Inventory` FlatBuffer `vector`. // Get and test the `Inventory` FlatBuffer `vector`.
for (int i = 0; i < monster.InventoryLength; i++) for (int i = 0; i < monster.InventoryLength; i++)
{ {
Assert(monster.GetInventory(i) == i, "monster.GetInventory", Assert(monster.Inventory(i) == i, "monster.Inventory",
Convert.ToString(monster.GetInventory(i)), Convert.ToString(i)); Convert.ToString(monster.Inventory(i)), Convert.ToString(i));
} }
// Get and test the `Weapons` FlatBuffer `vector` of `table`s. // Get and test the `Weapons` FlatBuffer `vector` of `table`s.
@@ -104,17 +101,17 @@ class SampleBinary
var expectedWeaponDamages = new short[] {3, 5}; var expectedWeaponDamages = new short[] {3, 5};
for (int i = 0; i < monster.WeaponsLength; i++) for (int i = 0; i < monster.WeaponsLength; i++)
{ {
Assert(monster.GetWeapons(i).Name.Equals(expectedWeaponNames[i], StringComparison.Ordinal), Assert(monster.Weapons(i).Value.Name.Equals(expectedWeaponNames[i], StringComparison.Ordinal),
"monster.GetWeapons", monster.GetWeapons(i).Name, expectedWeaponNames[i]); "monster.Weapons", monster.Weapons(i).Value.Name, expectedWeaponNames[i]);
Assert(monster.GetWeapons(i).Damage == expectedWeaponDamages[i], "monster.GetWeapons", Assert(monster.Weapons(i).Value.Damage == expectedWeaponDamages[i], "monster.GetWeapons",
Convert.ToString(monster.GetWeapons(i).Damage), Convert.ToString(monster.Weapons(i).Value.Damage),
Convert.ToString(expectedWeaponDamages[i])); Convert.ToString(expectedWeaponDamages[i]));
} }
// Get and test the `Equipped` FlatBuffer `union`. // Get and test the `Equipped` FlatBuffer `union`.
Assert(monster.EquippedType == Equipment.Weapon, "monster.EquippedType", Assert(monster.EquippedType == Equipment.Weapon, "monster.EquippedType",
Convert.ToString(monster.EquippedType), Convert.ToString(Equipment.Weapon)); Convert.ToString(monster.EquippedType), Convert.ToString(Equipment.Weapon));
var equipped = (Weapon)monster.GetEquipped(new Weapon()); var equipped = monster.Equipped<Weapon>().Value;
Assert(equipped.Name.Equals("Axe", StringComparison.Ordinal), "equipped.Name", equipped.Name, Assert(equipped.Name.Equals("Axe", StringComparison.Ordinal), "equipped.Name", equipped.Name,
"Axe"); "Axe");
Assert(equipped.Damage == 5, "equipped.Damage", Convert.ToString(equipped.Damage), Assert(equipped.Damage == 5, "equipped.Damage", Convert.ToString(equipped.Damage),

View File

@@ -25,6 +25,15 @@ enum Color {
Color_MAX = Color_Blue Color_MAX = Color_Blue
}; };
inline Color (&EnumValuesColor())[3] {
static Color values[] = {
Color_Red,
Color_Green,
Color_Blue
};
return values;
}
inline const char **EnumNamesColor() { inline const char **EnumNamesColor() {
static const char *names[] = { static const char *names[] = {
"Red", "Red",
@@ -47,6 +56,14 @@ enum Equipment {
Equipment_MAX = Equipment_Weapon Equipment_MAX = Equipment_Weapon
}; };
inline Equipment (&EnumValuesEquipment())[2] {
static Equipment values[] = {
Equipment_NONE,
Equipment_Weapon
};
return values;
}
inline const char **EnumNamesEquipment() { inline const char **EnumNamesEquipment() {
static const char *names[] = { static const char *names[] = {
"NONE", "NONE",
@@ -71,32 +88,36 @@ template<> struct EquipmentTraits<Weapon> {
struct EquipmentUnion { struct EquipmentUnion {
Equipment type; Equipment type;
flatbuffers::NativeTable *table; void *value;
EquipmentUnion() : type(Equipment_NONE), table(nullptr) {} EquipmentUnion() : type(Equipment_NONE), value(nullptr) {}
EquipmentUnion(EquipmentUnion&& u): EquipmentUnion(EquipmentUnion&& u) FLATBUFFERS_NOEXCEPT :
type(std::move(u.type)), table(std::move(u.table)) {} type(Equipment_NONE), value(nullptr)
EquipmentUnion(const EquipmentUnion &); { std::swap(type, u.type); std::swap(value, u.value); }
EquipmentUnion &operator=(const EquipmentUnion &); EquipmentUnion(const EquipmentUnion &) FLATBUFFERS_NOEXCEPT;
EquipmentUnion &operator=(const EquipmentUnion &u) FLATBUFFERS_NOEXCEPT
{ EquipmentUnion t(u); std::swap(type, t.type); std::swap(value, t.value); return *this; }
EquipmentUnion &operator=(EquipmentUnion &&u) FLATBUFFERS_NOEXCEPT
{ std::swap(type, u.type); std::swap(value, u.value); return *this; }
~EquipmentUnion() { Reset(); } ~EquipmentUnion() { Reset(); }
void Reset(); void Reset();
template <typename T> template <typename T>
void Set(T&& value) { void Set(T&& val) {
Reset(); Reset();
type = EquipmentTraits<typename T::TableType>::enum_value; type = EquipmentTraits<typename T::TableType>::enum_value;
if (type != Equipment_NONE) { if (type != Equipment_NONE) {
table = new T(std::forward<T>(value)); value = new T(std::forward<T>(val));
} }
} }
static flatbuffers::NativeTable *UnPack(const void *obj, Equipment type, const flatbuffers::resolver_function_t *resolver); static void *UnPack(const void *obj, Equipment type, const flatbuffers::resolver_function_t *resolver);
flatbuffers::Offset<void> Pack(flatbuffers::FlatBufferBuilder &_fbb, const flatbuffers::rehasher_function_t *_rehasher = nullptr) const; flatbuffers::Offset<void> Pack(flatbuffers::FlatBufferBuilder &_fbb, const flatbuffers::rehasher_function_t *_rehasher = nullptr) const;
WeaponT *AsWeapon() { WeaponT *AsWeapon() {
return type == Equipment_Weapon ? return type == Equipment_Weapon ?
reinterpret_cast<WeaponT *>(table) : nullptr; reinterpret_cast<WeaponT *>(value) : nullptr;
} }
}; };
@@ -182,13 +203,13 @@ struct Monster FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
return GetField<int16_t>(VT_MANA, 150); return GetField<int16_t>(VT_MANA, 150);
} }
bool mutate_mana(int16_t _mana) { bool mutate_mana(int16_t _mana) {
return SetField(VT_MANA, _mana); return SetField<int16_t>(VT_MANA, _mana, 150);
} }
int16_t hp() const { int16_t hp() const {
return GetField<int16_t>(VT_HP, 100); return GetField<int16_t>(VT_HP, 100);
} }
bool mutate_hp(int16_t _hp) { bool mutate_hp(int16_t _hp) {
return SetField(VT_HP, _hp); return SetField<int16_t>(VT_HP, _hp, 100);
} }
const flatbuffers::String *name() const { const flatbuffers::String *name() const {
return GetPointer<const flatbuffers::String *>(VT_NAME); return GetPointer<const flatbuffers::String *>(VT_NAME);
@@ -206,7 +227,7 @@ struct Monster FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
return static_cast<Color>(GetField<int8_t>(VT_COLOR, 2)); return static_cast<Color>(GetField<int8_t>(VT_COLOR, 2));
} }
bool mutate_color(Color _color) { bool mutate_color(Color _color) {
return SetField(VT_COLOR, static_cast<int8_t>(_color)); return SetField<int8_t>(VT_COLOR, static_cast<int8_t>(_color), 2);
} }
const flatbuffers::Vector<flatbuffers::Offset<Weapon>> *weapons() const { const flatbuffers::Vector<flatbuffers::Offset<Weapon>> *weapons() const {
return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<Weapon>> *>(VT_WEAPONS); return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<Weapon>> *>(VT_WEAPONS);
@@ -218,11 +239,15 @@ struct Monster FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
return static_cast<Equipment>(GetField<uint8_t>(VT_EQUIPPED_TYPE, 0)); return static_cast<Equipment>(GetField<uint8_t>(VT_EQUIPPED_TYPE, 0));
} }
bool mutate_equipped_type(Equipment _equipped_type) { bool mutate_equipped_type(Equipment _equipped_type) {
return SetField(VT_EQUIPPED_TYPE, static_cast<uint8_t>(_equipped_type)); return SetField<uint8_t>(VT_EQUIPPED_TYPE, static_cast<uint8_t>(_equipped_type), 0);
} }
const void *equipped() const { const void *equipped() const {
return GetPointer<const void *>(VT_EQUIPPED); return GetPointer<const void *>(VT_EQUIPPED);
} }
template<typename T> const T *equipped_as() const;
const Weapon *equipped_as_Weapon() const {
return equipped_type() == Equipment_Weapon ? static_cast<const Weapon *>(equipped()) : nullptr;
}
void *mutable_equipped() { void *mutable_equipped() {
return GetPointer<void *>(VT_EQUIPPED); return GetPointer<void *>(VT_EQUIPPED);
} }
@@ -231,16 +256,16 @@ struct Monster FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
VerifyField<Vec3>(verifier, VT_POS) && VerifyField<Vec3>(verifier, VT_POS) &&
VerifyField<int16_t>(verifier, VT_MANA) && VerifyField<int16_t>(verifier, VT_MANA) &&
VerifyField<int16_t>(verifier, VT_HP) && VerifyField<int16_t>(verifier, VT_HP) &&
VerifyField<flatbuffers::uoffset_t>(verifier, VT_NAME) && VerifyOffset(verifier, VT_NAME) &&
verifier.Verify(name()) && verifier.Verify(name()) &&
VerifyField<flatbuffers::uoffset_t>(verifier, VT_INVENTORY) && VerifyOffset(verifier, VT_INVENTORY) &&
verifier.Verify(inventory()) && verifier.Verify(inventory()) &&
VerifyField<int8_t>(verifier, VT_COLOR) && VerifyField<int8_t>(verifier, VT_COLOR) &&
VerifyField<flatbuffers::uoffset_t>(verifier, VT_WEAPONS) && VerifyOffset(verifier, VT_WEAPONS) &&
verifier.Verify(weapons()) && verifier.Verify(weapons()) &&
verifier.VerifyVectorOfTables(weapons()) && verifier.VerifyVectorOfTables(weapons()) &&
VerifyField<uint8_t>(verifier, VT_EQUIPPED_TYPE) && VerifyField<uint8_t>(verifier, VT_EQUIPPED_TYPE) &&
VerifyField<flatbuffers::uoffset_t>(verifier, VT_EQUIPPED) && VerifyOffset(verifier, VT_EQUIPPED) &&
VerifyEquipment(verifier, equipped(), equipped_type()) && VerifyEquipment(verifier, equipped(), equipped_type()) &&
verifier.EndTable(); verifier.EndTable();
} }
@@ -249,6 +274,10 @@ struct Monster FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
static flatbuffers::Offset<Monster> Pack(flatbuffers::FlatBufferBuilder &_fbb, const MonsterT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); static flatbuffers::Offset<Monster> Pack(flatbuffers::FlatBufferBuilder &_fbb, const MonsterT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr);
}; };
template<> inline const Weapon *Monster::equipped_as<Weapon>() const {
return equipped_as_Weapon();
}
struct MonsterBuilder { struct MonsterBuilder {
flatbuffers::FlatBufferBuilder &fbb_; flatbuffers::FlatBufferBuilder &fbb_;
flatbuffers::uoffset_t start_; flatbuffers::uoffset_t start_;
@@ -366,11 +395,11 @@ struct Weapon FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
return GetField<int16_t>(VT_DAMAGE, 0); return GetField<int16_t>(VT_DAMAGE, 0);
} }
bool mutate_damage(int16_t _damage) { bool mutate_damage(int16_t _damage) {
return SetField(VT_DAMAGE, _damage); return SetField<int16_t>(VT_DAMAGE, _damage, 0);
} }
bool Verify(flatbuffers::Verifier &verifier) const { bool Verify(flatbuffers::Verifier &verifier) const {
return VerifyTableStart(verifier) && return VerifyTableStart(verifier) &&
VerifyField<flatbuffers::uoffset_t>(verifier, VT_NAME) && VerifyOffset(verifier, VT_NAME) &&
verifier.Verify(name()) && verifier.Verify(name()) &&
VerifyField<int16_t>(verifier, VT_DAMAGE) && VerifyField<int16_t>(verifier, VT_DAMAGE) &&
verifier.EndTable(); verifier.EndTable();
@@ -436,11 +465,11 @@ inline void Monster::UnPackTo(MonsterT *_o, const flatbuffers::resolver_function
{ auto _e = mana(); _o->mana = _e; }; { auto _e = mana(); _o->mana = _e; };
{ auto _e = hp(); _o->hp = _e; }; { auto _e = hp(); _o->hp = _e; };
{ auto _e = name(); if (_e) _o->name = _e->str(); }; { auto _e = name(); if (_e) _o->name = _e->str(); };
{ auto _e = inventory(); if (_e) for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->inventory.push_back(_e->Get(_i)); } }; { auto _e = inventory(); if (_e) { _o->inventory.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->inventory[_i] = _e->Get(_i); } } };
{ auto _e = color(); _o->color = _e; }; { auto _e = color(); _o->color = _e; };
{ auto _e = weapons(); if (_e) for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->weapons.push_back(std::unique_ptr<WeaponT>(_e->Get(_i)->UnPack(_resolver))); } }; { auto _e = weapons(); if (_e) { _o->weapons.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->weapons[_i] = std::unique_ptr<WeaponT>(_e->Get(_i)->UnPack(_resolver)); } } };
{ auto _e = equipped_type(); _o->equipped.type = _e; }; { auto _e = equipped_type(); _o->equipped.type = _e; };
{ auto _e = equipped(); if (_e) _o->equipped.table = EquipmentUnion::UnPack(_e, equipped_type(),_resolver); }; { auto _e = equipped(); if (_e) _o->equipped.value = EquipmentUnion::UnPack(_e, equipped_type(), _resolver); };
} }
inline flatbuffers::Offset<Monster> Monster::Pack(flatbuffers::FlatBufferBuilder &_fbb, const MonsterT* _o, const flatbuffers::rehasher_function_t *_rehasher) { inline flatbuffers::Offset<Monster> Monster::Pack(flatbuffers::FlatBufferBuilder &_fbb, const MonsterT* _o, const flatbuffers::rehasher_function_t *_rehasher) {
@@ -524,7 +553,7 @@ inline bool VerifyEquipmentVector(flatbuffers::Verifier &verifier, const flatbuf
return true; return true;
} }
inline flatbuffers::NativeTable *EquipmentUnion::UnPack(const void *obj, Equipment type, const flatbuffers::resolver_function_t *resolver) { inline void *EquipmentUnion::UnPack(const void *obj, Equipment type, const flatbuffers::resolver_function_t *resolver) {
switch (type) { switch (type) {
case Equipment_Weapon: { case Equipment_Weapon: {
auto ptr = reinterpret_cast<const Weapon *>(obj); auto ptr = reinterpret_cast<const Weapon *>(obj);
@@ -537,23 +566,34 @@ inline flatbuffers::NativeTable *EquipmentUnion::UnPack(const void *obj, Equipme
inline flatbuffers::Offset<void> EquipmentUnion::Pack(flatbuffers::FlatBufferBuilder &_fbb, const flatbuffers::rehasher_function_t *_rehasher) const { inline flatbuffers::Offset<void> EquipmentUnion::Pack(flatbuffers::FlatBufferBuilder &_fbb, const flatbuffers::rehasher_function_t *_rehasher) const {
switch (type) { switch (type) {
case Equipment_Weapon: { case Equipment_Weapon: {
auto ptr = reinterpret_cast<const WeaponT *>(table); auto ptr = reinterpret_cast<const WeaponT *>(value);
return CreateWeapon(_fbb, ptr, _rehasher).Union(); return CreateWeapon(_fbb, ptr, _rehasher).Union();
} }
default: return 0; default: return 0;
} }
} }
inline EquipmentUnion::EquipmentUnion(const EquipmentUnion &u) FLATBUFFERS_NOEXCEPT : type(u.type), value(nullptr) {
switch (type) {
case Equipment_Weapon: {
value = new WeaponT(*reinterpret_cast<WeaponT *>(u.value));
break;
}
default:
break;
}
}
inline void EquipmentUnion::Reset() { inline void EquipmentUnion::Reset() {
switch (type) { switch (type) {
case Equipment_Weapon: { case Equipment_Weapon: {
auto ptr = reinterpret_cast<WeaponT *>(table); auto ptr = reinterpret_cast<WeaponT *>(value);
delete ptr; delete ptr;
break; break;
} }
default: break; default: break;
} }
table = nullptr; value = nullptr;
type = Equipment_NONE; type = Equipment_NONE;
} }

View File

@@ -18,6 +18,11 @@
#include <assert.h> #include <assert.h>
#include "flatbuffers/util.h" #include "flatbuffers/util.h"
#if defined(_MSC_VER)
#pragma warning(push)
#pragma warning(disable: 4127) // C4127: conditional expression is constant
#endif
namespace flatbuffers { namespace flatbuffers {
void CodeWriter::operator+=(std::string text) { void CodeWriter::operator+=(std::string text) {
@@ -63,7 +68,7 @@ void CodeWriter::operator+=(std::string text) {
const char *BaseGenerator::FlatBuffersGeneratedWarning() { const char *BaseGenerator::FlatBuffersGeneratedWarning() {
return "automatically generated by the FlatBuffers compiler," return "automatically generated by the FlatBuffers compiler,"
" do not modify\n\n"; " do not modify";
} }
std::string BaseGenerator::NamespaceDir(const Parser &parser, std::string BaseGenerator::NamespaceDir(const Parser &parser,
@@ -84,18 +89,6 @@ std::string BaseGenerator::NamespaceDir(const Namespace &ns) const {
return BaseGenerator::NamespaceDir(parser_, path_, ns); return BaseGenerator::NamespaceDir(parser_, path_, ns);
} }
bool BaseGenerator::IsEverythingGenerated() const {
for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
++it) {
if (!(*it)->generated) return false;
}
for (auto it = parser_.structs_.vec.begin();
it != parser_.structs_.vec.end(); ++it) {
if (!(*it)->generated) return false;
}
return true;
}
std::string BaseGenerator::FullNamespace(const char *separator, std::string BaseGenerator::FullNamespace(const char *separator,
const Namespace &ns) { const Namespace &ns) {
std::string namespace_name; std::string namespace_name;
@@ -130,6 +123,20 @@ std::string BaseGenerator::WrapInNameSpace(const Definition &def) const {
return WrapInNameSpace(def.defined_namespace, def.name); return WrapInNameSpace(def.defined_namespace, def.name);
} }
std::string BaseGenerator::GetNameSpace(const Definition &def) const {
const Namespace *ns = def.defined_namespace;
if (CurrentNameSpace() == ns) return "";
std::string qualified_name = qualifying_start_;
for (auto it = ns->components.begin(); it != ns->components.end(); ++it) {
qualified_name += *it;
if (std::next(it) != ns->components.end()) {
qualified_name += qualifying_separator_;
}
}
return qualified_name;
}
// Generate a documentation comment, if available. // Generate a documentation comment, if available.
void GenComment(const std::vector<std::string> &dc, std::string *code_ptr, void GenComment(const std::vector<std::string> &dc, std::string *code_ptr,
const CommentConfig *config, const char *prefix) { const CommentConfig *config, const char *prefix) {
@@ -156,3 +163,8 @@ void GenComment(const std::vector<std::string> &dc, std::string *code_ptr,
} }
} // namespace flatbuffers } // namespace flatbuffers
#if defined(_MSC_VER)
#pragma warning(pop)
#endif

View File

@@ -16,7 +16,9 @@
#include "flatbuffers/flatc.h" #include "flatbuffers/flatc.h"
#define FLATC_VERSION "1.6.0 (" __DATE__ ")" #include <list>
#define FLATC_VERSION "1.7.0 (" __DATE__ ")"
namespace flatbuffers { namespace flatbuffers {
@@ -46,7 +48,7 @@ void FlatCompiler::Error(const std::string &err, bool usage,
std::string FlatCompiler::GetUsageString(const char* program_name) const { std::string FlatCompiler::GetUsageString(const char* program_name) const {
std::stringstream ss; std::stringstream ss;
ss << "Usageaa: " << program_name << " [OPTION]... FILE... [-- FILE...]\n"; ss << "Usage: " << program_name << " [OPTION]... FILE... [-- FILE...]\n";
for (size_t i = 0; i < params_.num_generators; ++i) { for (size_t i = 0; i < params_.num_generators; ++i) {
const Generator& g = params_.generators[i]; const Generator& g = params_.generators[i];
@@ -86,8 +88,11 @@ std::string FlatCompiler::GetUsageString(const char* program_name) const {
" --escape-proto-ids Disable appending '_' in namespaces names.\n" " --escape-proto-ids Disable appending '_' in namespaces names.\n"
" --gen-object-api Generate an additional object-based API.\n" " --gen-object-api Generate an additional object-based API.\n"
" --cpp-ptr-type T Set object API pointer type (default std::unique_ptr)\n" " --cpp-ptr-type T Set object API pointer type (default std::unique_ptr)\n"
" --cpp-str-type T Set object API string type (default std::string)\n"
" T::c_str() and T::length() must be supported\n"
" --no-js-exports Removes Node.js style export lines in JS.\n" " --no-js-exports Removes Node.js style export lines in JS.\n"
" --goog-js-export Uses goog.exports* for closure compiler exporting in JS.\n" " --goog-js-export Uses goog.exports* for closure compiler exporting in JS.\n"
" --go-namespace Generate the overrided namespace in Golang.\n"
" --raw-binary Allow binaries without file_indentifier to be read.\n" " --raw-binary Allow binaries without file_indentifier to be read.\n"
" This may crash flatc given a mismatched schema.\n" " This may crash flatc given a mismatched schema.\n"
" --proto Input is a .proto, translate to .fbs.\n" " --proto Input is a .proto, translate to .fbs.\n"
@@ -100,6 +105,9 @@ std::string FlatCompiler::GetUsageString(const char* program_name) const {
" PATH \n" " PATH \n"
" --include-prefix Prefix this path to any generated include statements.\n" " --include-prefix Prefix this path to any generated include statements.\n"
" PATH\n" " PATH\n"
" --keep-prefix Keep original prefix of schema include statement.\n"
" --no-fb-import Don't include flatbuffers import statement for TypeScript.\n"
" --no-ts-reexport Don't re-export imported dependencies for TypeScript.\n"
"FILEs may be schemas, or JSON files (conforming to preceding schema)\n" "FILEs may be schemas, or JSON files (conforming to preceding schema)\n"
"FILEs after the -- must be binary flatbuffer format files.\n" "FILEs after the -- must be binary flatbuffer format files.\n"
"Output files are named using the base file name of the input,\n" "Output files are named using the base file name of the input,\n"
@@ -122,6 +130,7 @@ int FlatCompiler::Compile(int argc, const char** argv) {
bool schema_binary = false; bool schema_binary = false;
bool grpc_enabled = false; bool grpc_enabled = false;
std::vector<std::string> filenames; std::vector<std::string> filenames;
std::list<std::string> include_directories_storage;
std::vector<const char *> include_directories; std::vector<const char *> include_directories;
std::vector<const char *> conform_include_directories; std::vector<const char *> conform_include_directories;
std::vector<bool> generator_enabled(params_.num_generators, false); std::vector<bool> generator_enabled(params_.num_generators, false);
@@ -135,21 +144,29 @@ int FlatCompiler::Compile(int argc, const char** argv) {
Error("invalid option location: " + arg, true); Error("invalid option location: " + arg, true);
if (arg == "-o") { if (arg == "-o") {
if (++argi >= argc) Error("missing path following: " + arg, true); if (++argi >= argc) Error("missing path following: " + arg, true);
output_path = flatbuffers::ConCatPathFileName(argv[argi], ""); output_path = flatbuffers::ConCatPathFileName(
flatbuffers::PosixPath(argv[argi]), "");
} else if(arg == "-I") { } else if(arg == "-I") {
if (++argi >= argc) Error("missing path following" + arg, true); if (++argi >= argc) Error("missing path following" + arg, true);
include_directories.push_back(argv[argi]); include_directories_storage.push_back(
flatbuffers::PosixPath(argv[argi]));
include_directories.push_back(
include_directories_storage.back().c_str());
} else if(arg == "--conform") { } else if(arg == "--conform") {
if (++argi >= argc) Error("missing path following" + arg, true); if (++argi >= argc) Error("missing path following" + arg, true);
conform_to_schema = argv[argi]; conform_to_schema = flatbuffers::PosixPath(argv[argi]);
} else if (arg == "--conform-includes") { } else if (arg == "--conform-includes") {
if (++argi >= argc) Error("missing path following" + arg, true); if (++argi >= argc) Error("missing path following" + arg, true);
conform_include_directories.push_back(argv[argi]); include_directories_storage.push_back(
flatbuffers::PosixPath(argv[argi]));
conform_include_directories.push_back(
include_directories_storage.back().c_str());
} else if (arg == "--include-prefix") { } else if (arg == "--include-prefix") {
if (++argi >= argc) Error("missing path following" + arg, true); if (++argi >= argc) Error("missing path following" + arg, true);
opts.include_prefix = argv[argi]; opts.include_prefix = flatbuffers::ConCatPathFileName(
if (opts.include_prefix.back() != '/' && flatbuffers::PosixPath(argv[argi]), "");
opts.include_prefix.back() != '\\') opts.include_prefix += "/"; } else if(arg == "--keep-prefix") {
opts.keep_include_path = true;
} else if(arg == "--strict-json") { } else if(arg == "--strict-json") {
opts.strict_json = true; opts.strict_json = true;
} else if(arg == "--allow-non-utf8") { } else if(arg == "--allow-non-utf8") {
@@ -158,6 +175,9 @@ int FlatCompiler::Compile(int argc, const char** argv) {
opts.skip_js_exports = true; opts.skip_js_exports = true;
} else if(arg == "--goog-js-export") { } else if(arg == "--goog-js-export") {
opts.use_goog_js_export_format = true; opts.use_goog_js_export_format = true;
} else if(arg == "--go-namespace") {
if (++argi >= argc) Error("missing golang namespace" + arg, true);
opts.go_namespace = argv[argi];
} else if(arg == "--defaults-json") { } else if(arg == "--defaults-json") {
opts.output_default_scalars_in_json = true; opts.output_default_scalars_in_json = true;
} else if (arg == "--unknown-json") { } else if (arg == "--unknown-json") {
@@ -178,6 +198,9 @@ int FlatCompiler::Compile(int argc, const char** argv) {
} else if (arg == "--cpp-ptr-type") { } else if (arg == "--cpp-ptr-type") {
if (++argi >= argc) Error("missing type following" + arg, true); if (++argi >= argc) Error("missing type following" + arg, true);
opts.cpp_object_api_pointer_type = argv[argi]; opts.cpp_object_api_pointer_type = argv[argi];
} else if (arg == "--cpp-str-type") {
if (++argi >= argc) Error("missing type following" + arg, true);
opts.cpp_object_api_string_type = argv[argi];
} else if(arg == "--gen-all") { } else if(arg == "--gen-all") {
opts.generate_all = true; opts.generate_all = true;
opts.include_dependence_headers = false; opts.include_dependence_headers = false;
@@ -207,6 +230,10 @@ int FlatCompiler::Compile(int argc, const char** argv) {
grpc_enabled = true; grpc_enabled = true;
} else if(arg == "--bfbs-comments") { } else if(arg == "--bfbs-comments") {
opts.binary_schema_comments = true; opts.binary_schema_comments = true;
} else if(arg == "--no-fb-import") {
opts.skip_flatbuffers_import = true;
} else if(arg == "--no-ts-reexport") {
opts.reexport_ts_modules = false;
} else { } else {
for (size_t i = 0; i < params_.num_generators; ++i) { for (size_t i = 0; i < params_.num_generators; ++i) {
if (arg == params_.generators[i].generator_opt_long || if (arg == params_.generators[i].generator_opt_long ||
@@ -222,7 +249,7 @@ int FlatCompiler::Compile(int argc, const char** argv) {
found:; found:;
} }
} else { } else {
filenames.push_back(argv[argi]); filenames.push_back(flatbuffers::PosixPath(argv[argi]));
} }
} }
@@ -249,101 +276,103 @@ int FlatCompiler::Compile(int argc, const char** argv) {
for (auto file_it = filenames.begin(); for (auto file_it = filenames.begin();
file_it != filenames.end(); file_it != filenames.end();
++file_it) { ++file_it) {
std::string contents; auto &filename = *file_it;
if (!flatbuffers::LoadFile(file_it->c_str(), true, &contents)) std::string contents;
Error("unable to load file: " + *file_it); if (!flatbuffers::LoadFile(filename.c_str(), true, &contents))
Error("unable to load file: " + filename);
bool is_binary = static_cast<size_t>(file_it - filenames.begin()) >= bool is_binary = static_cast<size_t>(file_it - filenames.begin()) >=
binary_files_from; binary_files_from;
if (is_binary) { auto is_schema = flatbuffers::GetExtension(filename) == "fbs";
parser->builder_.Clear(); if (is_binary) {
parser->builder_.PushFlatBuffer( parser->builder_.Clear();
reinterpret_cast<const uint8_t *>(contents.c_str()), parser->builder_.PushFlatBuffer(
contents.length()); reinterpret_cast<const uint8_t *>(contents.c_str()),
if (!raw_binary) { contents.length());
// Generally reading binaries that do not correspond to the schema if (!raw_binary) {
// will crash, and sadly there's no way around that when the binary // Generally reading binaries that do not correspond to the schema
// does not contain a file identifier. // will crash, and sadly there's no way around that when the binary
// We'd expect that typically any binary used as a file would have // does not contain a file identifier.
// such an identifier, so by default we require them to match. // We'd expect that typically any binary used as a file would have
if (!parser->file_identifier_.length()) { // such an identifier, so by default we require them to match.
Error("current schema has no file_identifier: cannot test if \"" + if (!parser->file_identifier_.length()) {
*file_it + Error("current schema has no file_identifier: cannot test if \"" +
"\" matches the schema, use --raw-binary to read this file" filename +
" anyway."); "\" matches the schema, use --raw-binary to read this file"
} else if (!flatbuffers::BufferHasIdentifier(contents.c_str(), " anyway.");
parser->file_identifier_.c_str())) { } else if (!flatbuffers::BufferHasIdentifier(contents.c_str(),
Error("binary \"" + parser->file_identifier_.c_str())) {
*file_it + Error("binary \"" +
"\" does not have expected file_identifier \"" + filename +
parser->file_identifier_ + "\" does not have expected file_identifier \"" +
"\", use --raw-binary to read this file anyway."); parser->file_identifier_ +
} "\", use --raw-binary to read this file anyway.");
}
} else {
// Check if file contains 0 bytes.
if (contents.length() != strlen(contents.c_str())) {
Error("input file appears to be binary: " + *file_it, true);
}
auto is_schema = flatbuffers::GetExtension(*file_it) == "fbs";
if (is_schema) {
// If we're processing multiple schemas, make sure to start each
// one from scratch. If it depends on previous schemas it must do
// so explicitly using an include.
parser.reset(new flatbuffers::Parser(opts));
}
ParseFile(*parser.get(), *file_it, contents, include_directories);
if (is_schema && !conform_to_schema.empty()) {
auto err = parser->ConformTo(conform_parser);
if (!err.empty()) Error("schemas don\'t conform: " + err);
}
if (schema_binary) {
parser->Serialize();
parser->file_extension_ = reflection::SchemaExtension();
} }
} }
} else {
// Check if file contains 0 bytes.
if (contents.length() != strlen(contents.c_str())) {
Error("input file appears to be binary: " + filename, true);
}
if (is_schema) {
// If we're processing multiple schemas, make sure to start each
// one from scratch. If it depends on previous schemas it must do
// so explicitly using an include.
parser.reset(new flatbuffers::Parser(opts));
}
ParseFile(*parser.get(), filename, contents, include_directories);
if (is_schema && !conform_to_schema.empty()) {
auto err = parser->ConformTo(conform_parser);
if (!err.empty()) Error("schemas don\'t conform: " + err);
}
if (schema_binary) {
parser->Serialize();
parser->file_extension_ = reflection::SchemaExtension();
}
}
std::string filebase = flatbuffers::StripPath( std::string filebase = flatbuffers::StripPath(
flatbuffers::StripExtension(*file_it)); flatbuffers::StripExtension(filename));
for (size_t i = 0; i < params_.num_generators; ++i) { for (size_t i = 0; i < params_.num_generators; ++i) {
parser->opts.lang = params_.generators[i].lang; parser->opts.lang = params_.generators[i].lang;
if (generator_enabled[i]) { if (generator_enabled[i]) {
if (!print_make_rules) { if (!print_make_rules) {
flatbuffers::EnsureDirExists(output_path); flatbuffers::EnsureDirExists(output_path);
if (!params_.generators[i].generate(*parser.get(), output_path, filebase)) { if ((!params_.generators[i].schema_only || is_schema) &&
Error(std::string("Unable to generate ") + !params_.generators[i].generate(*parser.get(), output_path, filebase)) {
params_.generators[i].lang_name + Error(std::string("Unable to generate ") +
" for " + params_.generators[i].lang_name +
filebase); " for " +
filebase);
}
} else {
std::string make_rule = params_.generators[i].make_rule(
*parser.get(), output_path, filename);
if (!make_rule.empty())
printf("%s\n", flatbuffers::WordWrap(
make_rule, 80, " ", " \\").c_str());
}
if (grpc_enabled) {
if (params_.generators[i].generateGRPC != nullptr) {
if (!params_.generators[i].generateGRPC(*parser.get(), output_path,
filebase)) {
Error(std::string("Unable to generate GRPC interface for") +
params_.generators[i].lang_name);
} }
} else { } else {
std::string make_rule = params_.generators[i].make_rule( Warn(std::string("GRPC interface generator not implemented for ")
*parser.get(), output_path, *file_it); + params_.generators[i].lang_name);
if (!make_rule.empty())
printf("%s\n", flatbuffers::WordWrap(
make_rule, 80, " ", " \\").c_str());
}
if (grpc_enabled) {
if (params_.generators[i].generateGRPC != nullptr) {
if (!params_.generators[i].generateGRPC(*parser.get(), output_path,
filebase)) {
Error(std::string("Unable to generate GRPC interface for") +
params_.generators[i].lang_name);
}
} else {
Warn(std::string("GRPC interface generator not implemented for ")
+ params_.generators[i].lang_name);
}
} }
} }
} }
}
if (opts.proto_mode) GenerateFBS(*parser.get(), output_path, filebase); if (opts.proto_mode) GenerateFBS(*parser.get(), output_path, filebase);
// We do not want to generate code for the definitions in this file // We do not want to generate code for the definitions in this file
// in any files coming up next. // in any files coming up next.
parser->MarkGenerated(); parser->MarkGenerated();
} }
return 0; return 0;
} }

View File

@@ -46,47 +46,52 @@ int main(int argc, const char *argv[]) {
g_program_name = argv[0]; g_program_name = argv[0];
const flatbuffers::FlatCompiler::Generator generators[] = { const flatbuffers::FlatCompiler::Generator generators[] = {
{ flatbuffers::GenerateBinary, "-b", "--binary", "binary", { flatbuffers::GenerateBinary, "-b", "--binary", "binary", false,
nullptr, nullptr,
flatbuffers::IDLOptions::kBinary, flatbuffers::IDLOptions::kBinary,
"Generate wire format binaries for any data definitions", "Generate wire format binaries for any data definitions",
flatbuffers::BinaryMakeRule }, flatbuffers::BinaryMakeRule },
{ flatbuffers::GenerateTextFile, "-t", "--json", "text", { flatbuffers::GenerateTextFile, "-t", "--json", "text", false,
nullptr, nullptr,
flatbuffers::IDLOptions::kJson, flatbuffers::IDLOptions::kJson,
"Generate text output for any data definitions", "Generate text output for any data definitions",
flatbuffers::TextMakeRule }, flatbuffers::TextMakeRule },
{ flatbuffers::GenerateCPP, "-c", "--cpp", "C++", { flatbuffers::GenerateCPP, "-c", "--cpp", "C++", true,
flatbuffers::GenerateCppGRPC, flatbuffers::GenerateCppGRPC,
flatbuffers::IDLOptions::kCpp, flatbuffers::IDLOptions::kCpp,
"Generate C++ headers for tables/structs", "Generate C++ headers for tables/structs",
flatbuffers::CPPMakeRule }, flatbuffers::CPPMakeRule },
{ flatbuffers::GenerateGo, "-g", "--go", "Go", { flatbuffers::GenerateGo, "-g", "--go", "Go", true,
flatbuffers::GenerateGoGRPC, flatbuffers::GenerateGoGRPC,
flatbuffers::IDLOptions::kGo, flatbuffers::IDLOptions::kGo,
"Generate Go files for tables/structs", "Generate Go files for tables/structs",
flatbuffers::GeneralMakeRule }, flatbuffers::GeneralMakeRule },
{ flatbuffers::GenerateGeneral, "-j", "--java", "Java", { flatbuffers::GenerateGeneral, "-j", "--java", "Java", true,
nullptr, nullptr,
flatbuffers::IDLOptions::kJava, flatbuffers::IDLOptions::kJava,
"Generate Java classes for tables/structs", "Generate Java classes for tables/structs",
flatbuffers::GeneralMakeRule }, flatbuffers::GeneralMakeRule },
{ flatbuffers::GenerateJS, "-s", "--js", "JavaScript", { flatbuffers::GenerateJS, "-s", "--js", "JavaScript", true,
nullptr, nullptr,
flatbuffers::IDLOptions::kJs, flatbuffers::IDLOptions::kJs,
"Generate JavaScript code for tables/structs", "Generate JavaScript code for tables/structs",
flatbuffers::JSMakeRule }, flatbuffers::JSMakeRule },
{ flatbuffers::GenerateGeneral, "-n", "--csharp", "C#", { flatbuffers::GenerateJS, "-T", "--ts", "TypeScript", true,
nullptr,
flatbuffers::IDLOptions::kTs,
"Generate TypeScript code for tables/structs",
flatbuffers::JSMakeRule },
{ flatbuffers::GenerateGeneral, "-n", "--csharp", "C#", true,
nullptr, nullptr,
flatbuffers::IDLOptions::kCSharp, flatbuffers::IDLOptions::kCSharp,
"Generate C# classes for tables/structs", "Generate C# classes for tables/structs",
flatbuffers::GeneralMakeRule }, flatbuffers::GeneralMakeRule },
{ flatbuffers::GeneratePython, "-p", "--python", "Python", { flatbuffers::GeneratePython, "-p", "--python", "Python", true,
nullptr, nullptr,
flatbuffers::IDLOptions::kPython, flatbuffers::IDLOptions::kPython,
"Generate Python files for tables/structs", "Generate Python files for tables/structs",
flatbuffers::GeneralMakeRule }, flatbuffers::GeneralMakeRule },
{ flatbuffers::GeneratePhp, nullptr, "--php", "PHP", { flatbuffers::GeneratePhp, nullptr, "--php", "PHP", true,
nullptr, nullptr,
flatbuffers::IDLOptions::kPhp, flatbuffers::IDLOptions::kPhp,
"Generate PHP files for tables/structs", "Generate PHP files for tables/structs",

View File

@@ -23,6 +23,11 @@
namespace flatbuffers { namespace flatbuffers {
// Pedantic warning free version of toupper().
inline char ToUpper(char c) {
return static_cast<char>(::toupper(c));
}
static std::string GeneratedFileName(const std::string &path, static std::string GeneratedFileName(const std::string &path,
const std::string &file_name) { const std::string &file_name) {
return path + file_name + "_generated.h"; return path + file_name + "_generated.h";
@@ -54,7 +59,7 @@ class CppGenerator : public BaseGenerator {
guard += *it + "_"; guard += *it + "_";
} }
guard += "H_"; guard += "H_";
std::transform(guard.begin(), guard.end(), guard.begin(), ::toupper); std::transform(guard.begin(), guard.end(), guard.begin(), ToUpper);
return guard; return guard;
} }
@@ -67,13 +72,15 @@ class CppGenerator : public BaseGenerator {
} }
for (auto it = parser_.included_files_.begin(); for (auto it = parser_.included_files_.begin();
it != parser_.included_files_.end(); ++it) { it != parser_.included_files_.end(); ++it) {
const auto basename = if (it->second.empty())
flatbuffers::StripPath(flatbuffers::StripExtension(it->first)); continue;
if (basename != file_name_) { auto noext = flatbuffers::StripExtension(it->second);
code_ += "#include \"" + parser_.opts.include_prefix + basename + auto basename = flatbuffers::StripPath(noext);
"_generated.h\"";
num_includes++; code_ += "#include \"" + parser_.opts.include_prefix +
} (parser_.opts.keep_include_path ? noext : basename) +
"_generated.h\"";
num_includes++;
} }
if (num_includes) code_ += ""; if (num_includes) code_ += "";
} }
@@ -81,10 +88,8 @@ class CppGenerator : public BaseGenerator {
// Iterate through all definitions we haven't generate code for (enums, // Iterate through all definitions we haven't generate code for (enums,
// structs, and tables) and output them to a single file. // structs, and tables) and output them to a single file.
bool generate() { bool generate() {
if (IsEverythingGenerated()) return true;
code_.Clear(); code_.Clear();
code_ += "// " + std::string(FlatBuffersGeneratedWarning()); code_ += "// " + std::string(FlatBuffersGeneratedWarning()) + "\n\n";
const auto include_guard = GenIncludeGuard(); const auto include_guard = GenIncludeGuard();
code_ += "#ifndef " + include_guard; code_ += "#ifndef " + include_guard;
@@ -92,6 +97,9 @@ class CppGenerator : public BaseGenerator {
code_ += ""; code_ += "";
code_ += "#include \"flatbuffers/flatbuffers.h\""; code_ += "#include \"flatbuffers/flatbuffers.h\"";
if (parser_.uses_flexbuffers_) {
code_ += "#include \"flatbuffers/flexbuffers.h\"";
}
code_ += ""; code_ += "";
if (parser_.opts.include_dependence_headers) { if (parser_.opts.include_dependence_headers) {
@@ -109,7 +117,7 @@ class CppGenerator : public BaseGenerator {
SetNameSpace(struct_def.defined_namespace); SetNameSpace(struct_def.defined_namespace);
code_ += "struct " + struct_def.name + ";"; code_ += "struct " + struct_def.name + ";";
if (parser_.opts.generate_object_based_api && !struct_def.fixed) { if (parser_.opts.generate_object_based_api && !struct_def.fixed) {
code_ += "struct " + NativeName(struct_def.name) + ";"; code_ += "struct " + NativeName(struct_def.name, &struct_def) + ";";
} }
code_ += ""; code_ += "";
} }
@@ -239,7 +247,7 @@ class CppGenerator : public BaseGenerator {
if (parser_.opts.generate_object_based_api) { if (parser_.opts.generate_object_based_api) {
// A convenient root unpack function. // A convenient root unpack function.
auto native_name = auto native_name =
NativeName(WrapInNameSpace(struct_def)); NativeName(WrapInNameSpace(struct_def), &struct_def);
code_.SetValue("UNPACK_RETURN", code_.SetValue("UNPACK_RETURN",
GenTypeNativePtr(native_name, nullptr, false)); GenTypeNativePtr(native_name, nullptr, false));
code_.SetValue("UNPACK_TYPE", code_.SetValue("UNPACK_TYPE",
@@ -255,8 +263,7 @@ class CppGenerator : public BaseGenerator {
} }
} }
assert(cur_name_space_); if (cur_name_space_) SetNameSpace(nullptr);
SetNameSpace(nullptr);
// Close the include guard. // Close the include guard.
code_ += "#endif // " + include_guard; code_ += "#endif // " + include_guard;
@@ -355,13 +362,24 @@ class CppGenerator : public BaseGenerator {
} }
// TODO(wvo): make this configurable. // TODO(wvo): make this configurable.
static std::string NativeName(const std::string &name) { return name + "T"; } static std::string NativeName(const std::string &name, const StructDef *sd) {
return sd && !sd->fixed ? name + "T" : name;
}
const std::string &PtrType(const FieldDef *field) { const std::string &PtrType(const FieldDef *field) {
auto attr = field ? field->attributes.Lookup("cpp_ptr_type") : nullptr; auto attr = field ? field->attributes.Lookup("cpp_ptr_type") : nullptr;
return attr ? attr->constant : parser_.opts.cpp_object_api_pointer_type; return attr ? attr->constant : parser_.opts.cpp_object_api_pointer_type;
} }
const std::string NativeString(const FieldDef *field) {
auto attr = field ? field->attributes.Lookup("cpp_str_type") : nullptr;
auto &ret = attr ? attr->constant : parser_.opts.cpp_object_api_string_type;
if (ret.empty()) {
return "std::string";
}
return ret;
}
std::string GenTypeNativePtr(const std::string &type, const FieldDef *field, std::string GenTypeNativePtr(const std::string &type, const FieldDef *field,
bool is_constructor) { bool is_constructor) {
auto &ptr_type = PtrType(field); auto &ptr_type = PtrType(field);
@@ -383,7 +401,7 @@ class CppGenerator : public BaseGenerator {
const FieldDef &field) { const FieldDef &field) {
switch (type.base_type) { switch (type.base_type) {
case BASE_TYPE_STRING: { case BASE_TYPE_STRING: {
return "std::string"; return NativeString(&field);
} }
case BASE_TYPE_VECTOR: { case BASE_TYPE_VECTOR: {
const auto type_name = GenTypeNative(type.VectorType(), true, field); const auto type_name = GenTypeNative(type.VectorType(), true, field);
@@ -402,7 +420,8 @@ class CppGenerator : public BaseGenerator {
return GenTypeNativePtr(type_name, &field, false); return GenTypeNativePtr(type_name, &field, false);
} }
} else { } else {
return GenTypeNativePtr(NativeName(type_name), &field, false); return GenTypeNativePtr(NativeName(type_name, type.struct_def),
&field, false);
} }
} }
case BASE_TYPE_UNION: { case BASE_TYPE_UNION: {
@@ -449,6 +468,27 @@ class CppGenerator : public BaseGenerator {
} }
} }
std::string StripUnionType(const std::string &name) {
return name.substr(0, name.size() - strlen(UnionTypeFieldSuffix()));
}
std::string GetUnionElement(const EnumVal &ev, bool wrap, bool actual_type,
bool native_type = false) {
if (ev.union_type.base_type == BASE_TYPE_STRUCT) {
auto name = actual_type ? ev.union_type.struct_def->name : ev.name;
return wrap
? WrapInNameSpace(ev.union_type.struct_def->defined_namespace, name)
: name;
} else if (ev.union_type.base_type == BASE_TYPE_STRING) {
return actual_type
? (native_type ? "std::string" : "flatbuffers::String")
: ev.name;
} else {
assert(false);
return ev.name;
}
}
static std::string UnionVerifySignature(const EnumDef &enum_def) { static std::string UnionVerifySignature(const EnumDef &enum_def) {
return "bool Verify" + enum_def.name + return "bool Verify" + enum_def.name +
"(flatbuffers::Verifier &verifier, const void *obj, " + "(flatbuffers::Verifier &verifier, const void *obj, " +
@@ -465,7 +505,7 @@ class CppGenerator : public BaseGenerator {
static std::string UnionUnPackSignature(const EnumDef &enum_def, static std::string UnionUnPackSignature(const EnumDef &enum_def,
bool inclass) { bool inclass) {
return (inclass ? "static " : "") + return (inclass ? "static " : "") +
std::string("flatbuffers::NativeTable *") + std::string("void *") +
(inclass ? "" : enum_def.name + "Union::") + (inclass ? "" : enum_def.name + "Union::") +
"UnPack(const void *obj, " + enum_def.name + "UnPack(const void *obj, " + enum_def.name +
" type, const flatbuffers::resolver_function_t *resolver)"; " type, const flatbuffers::resolver_function_t *resolver)";
@@ -484,7 +524,7 @@ class CppGenerator : public BaseGenerator {
return "flatbuffers::Offset<" + struct_def.name + "> Create" + return "flatbuffers::Offset<" + struct_def.name + "> Create" +
struct_def.name + struct_def.name +
"(flatbuffers::FlatBufferBuilder &_fbb, const " + "(flatbuffers::FlatBufferBuilder &_fbb, const " +
NativeName(struct_def.name) + NativeName(struct_def.name, &struct_def) +
" *_o, const flatbuffers::rehasher_function_t *_rehasher" + " *_o, const flatbuffers::rehasher_function_t *_rehasher" +
(predecl ? " = nullptr" : "") + ")"; (predecl ? " = nullptr" : "") + ")";
} }
@@ -495,14 +535,14 @@ class CppGenerator : public BaseGenerator {
"flatbuffers::Offset<" + struct_def.name + "> " + "flatbuffers::Offset<" + struct_def.name + "> " +
(inclass ? "" : struct_def.name + "::") + (inclass ? "" : struct_def.name + "::") +
"Pack(flatbuffers::FlatBufferBuilder &_fbb, " + "Pack(flatbuffers::FlatBufferBuilder &_fbb, " +
"const " + NativeName(struct_def.name) + "* _o, " + "const " + NativeName(struct_def.name, &struct_def) + "* _o, " +
"const flatbuffers::rehasher_function_t *_rehasher" + "const flatbuffers::rehasher_function_t *_rehasher" +
(inclass ? " = nullptr" : "") + ")"; (inclass ? " = nullptr" : "") + ")";
} }
static std::string TableUnPackSignature(const StructDef &struct_def, static std::string TableUnPackSignature(const StructDef &struct_def,
bool inclass) { bool inclass) {
return NativeName(struct_def.name) + " *" + return NativeName(struct_def.name, &struct_def) + " *" +
(inclass ? "" : struct_def.name + "::") + (inclass ? "" : struct_def.name + "::") +
"UnPack(const flatbuffers::resolver_function_t *_resolver" + "UnPack(const flatbuffers::resolver_function_t *_resolver" +
(inclass ? " = nullptr" : "") + ") const"; (inclass ? " = nullptr" : "") + ") const";
@@ -511,12 +551,14 @@ class CppGenerator : public BaseGenerator {
static std::string TableUnPackToSignature(const StructDef &struct_def, static std::string TableUnPackToSignature(const StructDef &struct_def,
bool inclass) { bool inclass) {
return "void " + (inclass ? "" : struct_def.name + "::") + return "void " + (inclass ? "" : struct_def.name + "::") +
"UnPackTo(" + NativeName(struct_def.name) + " *" + "_o, " + "UnPackTo(" + NativeName(struct_def.name, &struct_def) + " *" +
"const flatbuffers::resolver_function_t *_resolver" + "_o, const flatbuffers::resolver_function_t *_resolver" +
(inclass ? " = nullptr" : "") + ") const"; (inclass ? " = nullptr" : "") + ") const";
} }
// Generate an enum declaration and an enum string lookup table. // Generate an enum declaration,
// an enum string lookup table,
// and an enum array of values
void GenEnum(const EnumDef &enum_def) { void GenEnum(const EnumDef &enum_def) {
code_.SetValue("ENUM_NAME", enum_def.name); code_.SetValue("ENUM_NAME", enum_def.name);
code_.SetValue("BASE_TYPE", GenTypeBasic(enum_def.underlying_type, false)); code_.SetValue("BASE_TYPE", GenTypeBasic(enum_def.underlying_type, false));
@@ -575,6 +617,22 @@ class CppGenerator : public BaseGenerator {
} }
code_ += ""; code_ += "";
// Generate an array of all enumeration values
auto num_fields = NumToString(enum_def.vals.vec.size());
code_ += "inline {{ENUM_NAME}} (&EnumValues{{ENUM_NAME}}())[" + num_fields + "] {";
code_ += " static {{ENUM_NAME}} values[] = {";
for (auto it = enum_def.vals.vec.begin(); it != enum_def.vals.vec.end();
++it) {
const auto &ev = **it;
auto value = GetEnumValUse(enum_def, ev);
auto suffix = *it != enum_def.vals.vec.back() ? "," : "";
code_ += " " + value + suffix;
}
code_ += " };";
code_ += " return values;";
code_ += "}";
code_ += "";
// Generate a generate string table for enum values. // Generate a generate string table for enum values.
// Problem is, if values are very sparse that could generate really big // Problem is, if values are very sparse that could generate really big
// tables. Ideally in that case we generate a map lookup instead, but for // tables. Ideally in that case we generate a map lookup instead, but for
@@ -620,7 +678,7 @@ class CppGenerator : public BaseGenerator {
} }
// Generate type traits for unions to map from a type to union enum value. // Generate type traits for unions to map from a type to union enum value.
if (enum_def.is_union) { if (enum_def.is_union && !enum_def.uses_type_aliases) {
for (auto it = enum_def.vals.vec.begin(); it != enum_def.vals.vec.end(); for (auto it = enum_def.vals.vec.begin(); it != enum_def.vals.vec.end();
++it) { ++it) {
const auto &ev = **it; const auto &ev = **it;
@@ -629,7 +687,7 @@ class CppGenerator : public BaseGenerator {
code_ += "template<typename T> struct {{ENUM_NAME}}Traits {"; code_ += "template<typename T> struct {{ENUM_NAME}}Traits {";
} }
else { else {
auto name = WrapInNameSpace(*ev.struct_def); auto name = GetUnionElement(ev, true, true);
code_ += "template<> struct {{ENUM_NAME}}Traits<" + name + "> {"; code_ += "template<> struct {{ENUM_NAME}}Traits<" + name + "> {";
} }
@@ -648,26 +706,32 @@ class CppGenerator : public BaseGenerator {
code_ += "struct {{NAME}}Union {"; code_ += "struct {{NAME}}Union {";
code_ += " {{NAME}} type;"; code_ += " {{NAME}} type;";
code_ += " flatbuffers::NativeTable *table;"; code_ += " void *value;";
code_ += ""; code_ += "";
code_ += " {{NAME}}Union() : type({{NONE}}), table(nullptr) {}"; code_ += " {{NAME}}Union() : type({{NONE}}), value(nullptr) {}";
code_ += " {{NAME}}Union({{NAME}}Union&& u):"; code_ += " {{NAME}}Union({{NAME}}Union&& u) FLATBUFFERS_NOEXCEPT :";
code_ += " type(std::move(u.type)), table(std::move(u.table)) {}"; code_ += " type({{NONE}}), value(nullptr)";
code_ += " {{NAME}}Union(const {{NAME}}Union &);"; code_ += " { std::swap(type, u.type); std::swap(value, u.value); }";
code_ += " {{NAME}}Union &operator=(const {{NAME}}Union &);"; code_ += " {{NAME}}Union(const {{NAME}}Union &) FLATBUFFERS_NOEXCEPT;";
code_ += " {{NAME}}Union &operator=(const {{NAME}}Union &u) FLATBUFFERS_NOEXCEPT";
code_ += " { {{NAME}}Union t(u); std::swap(type, t.type); std::swap(value, t.value); return *this; }";
code_ += " {{NAME}}Union &operator=({{NAME}}Union &&u) FLATBUFFERS_NOEXCEPT";
code_ += " { std::swap(type, u.type); std::swap(value, u.value); return *this; }";
code_ += " ~{{NAME}}Union() { Reset(); }"; code_ += " ~{{NAME}}Union() { Reset(); }";
code_ += ""; code_ += "";
code_ += " void Reset();"; code_ += " void Reset();";
code_ += ""; code_ += "";
code_ += " template <typename T>"; if (!enum_def.uses_type_aliases) {
code_ += " void Set(T&& value) {"; code_ += " template <typename T>";
code_ += " Reset();"; code_ += " void Set(T&& val) {";
code_ += " type = {{NAME}}Traits<typename T::TableType>::enum_value;"; code_ += " Reset();";
code_ += " if (type != {{NONE}}) {"; code_ += " type = {{NAME}}Traits<typename T::TableType>::enum_value;";
code_ += " table = new T(std::forward<T>(value));"; code_ += " if (type != {{NONE}}) {";
code_ += " }"; code_ += " value = new T(std::forward<T>(val));";
code_ += " }"; code_ += " }";
code_ += ""; code_ += " }";
code_ += "";
}
code_ += " " + UnionUnPackSignature(enum_def, true) + ";"; code_ += " " + UnionUnPackSignature(enum_def, true) + ";";
code_ += " " + UnionPackSignature(enum_def, true) + ";"; code_ += " " + UnionPackSignature(enum_def, true) + ";";
code_ += ""; code_ += "";
@@ -679,14 +743,16 @@ class CppGenerator : public BaseGenerator {
continue; continue;
} }
const auto native_type = NativeName(WrapInNameSpace(*ev.struct_def)); const auto native_type =
NativeName(GetUnionElement(ev, true, true, true),
ev.union_type.struct_def);
code_.SetValue("NATIVE_TYPE", native_type); code_.SetValue("NATIVE_TYPE", native_type);
code_.SetValue("NATIVE_NAME", ev.name); code_.SetValue("NATIVE_NAME", ev.name);
code_.SetValue("NATIVE_ID", GetEnumValUse(enum_def, ev)); code_.SetValue("NATIVE_ID", GetEnumValUse(enum_def, ev));
code_ += " {{NATIVE_TYPE}} *As{{NATIVE_NAME}}() {"; code_ += " {{NATIVE_TYPE}} *As{{NATIVE_NAME}}() {";
code_ += " return type == {{NATIVE_ID}} ?"; code_ += " return type == {{NATIVE_ID}} ?";
code_ += " reinterpret_cast<{{NATIVE_TYPE}} *>(table) : nullptr;"; code_ += " reinterpret_cast<{{NATIVE_TYPE}} *>(value) : nullptr;";
code_ += " }"; code_ += " }";
} }
code_ += "};"; code_ += "};";
@@ -716,10 +782,23 @@ class CppGenerator : public BaseGenerator {
code_.SetValue("LABEL", GetEnumValUse(enum_def, ev)); code_.SetValue("LABEL", GetEnumValUse(enum_def, ev));
if (ev.value) { if (ev.value) {
code_.SetValue("TYPE", WrapInNameSpace(*ev.struct_def)); code_.SetValue("TYPE", GetUnionElement(ev, true, true));
code_ += " case {{LABEL}}: {"; code_ += " case {{LABEL}}: {";
code_ += " auto ptr = reinterpret_cast<const {{TYPE}} *>(obj);"; auto getptr =
code_ += " return verifier.VerifyTable(ptr);"; " auto ptr = reinterpret_cast<const {{TYPE}} *>(obj);";
if (ev.union_type.base_type == BASE_TYPE_STRUCT) {
if (ev.union_type.struct_def->fixed) {
code_ += " return true;";
} else {
code_ += getptr;
code_ += " return verifier.VerifyTable(ptr);";
}
} else if (ev.union_type.base_type == BASE_TYPE_STRING) {
code_ += getptr;
code_ += " return verifier.Verify(ptr);";
} else {
assert(false);
}
code_ += " }"; code_ += " }";
} else { } else {
code_ += " case {{LABEL}}: {"; code_ += " case {{LABEL}}: {";
@@ -756,10 +835,21 @@ class CppGenerator : public BaseGenerator {
} }
code_.SetValue("LABEL", GetEnumValUse(enum_def, ev)); code_.SetValue("LABEL", GetEnumValUse(enum_def, ev));
code_.SetValue("TYPE", WrapInNameSpace(*ev.struct_def)); code_.SetValue("TYPE", GetUnionElement(ev, true, true));
code_ += " case {{LABEL}}: {"; code_ += " case {{LABEL}}: {";
code_ += " auto ptr = reinterpret_cast<const {{TYPE}} *>(obj);"; code_ += " auto ptr = reinterpret_cast<const {{TYPE}} *>(obj);";
code_ += " return ptr->UnPack(resolver);"; if (ev.union_type.base_type == BASE_TYPE_STRUCT) {
if (ev.union_type.struct_def->fixed) {
code_ += " return new " +
WrapInNameSpace(*ev.union_type.struct_def) + "(*ptr);";
} else {
code_ += " return ptr->UnPack(resolver);";
}
} else if (ev.union_type.base_type == BASE_TYPE_STRING) {
code_ += " return new std::string(ptr->c_str(), ptr->size());";
} else {
assert(false);
}
code_ += " }"; code_ += " }";
} }
code_ += " default: return nullptr;"; code_ += " default: return nullptr;";
@@ -777,11 +867,23 @@ class CppGenerator : public BaseGenerator {
} }
code_.SetValue("LABEL", GetEnumValUse(enum_def, ev)); code_.SetValue("LABEL", GetEnumValUse(enum_def, ev));
code_.SetValue("TYPE", NativeName(WrapInNameSpace(*ev.struct_def))); code_.SetValue("TYPE", NativeName(GetUnionElement(ev, true, true, true),
code_.SetValue("NAME", ev.struct_def->name); ev.union_type.struct_def));
code_.SetValue("NAME", GetUnionElement(ev, false, true));
code_ += " case {{LABEL}}: {"; code_ += " case {{LABEL}}: {";
code_ += " auto ptr = reinterpret_cast<const {{TYPE}} *>(table);"; code_ += " auto ptr = reinterpret_cast<const {{TYPE}} *>(value);";
code_ += " return Create{{NAME}}(_fbb, ptr, _rehasher).Union();"; if (ev.union_type.base_type == BASE_TYPE_STRUCT) {
if (ev.union_type.struct_def->fixed) {
code_ += " return _fbb.CreateStruct(*ptr).Union();";
} else {
code_ +=
" return Create{{NAME}}(_fbb, ptr, _rehasher).Union();";
}
} else if (ev.union_type.base_type == BASE_TYPE_STRING) {
code_ += " return _fbb.CreateString(*ptr).Union();";
} else {
assert(false);
}
code_ += " }"; code_ += " }";
} }
code_ += " default: return 0;"; code_ += " default: return 0;";
@@ -789,6 +891,49 @@ class CppGenerator : public BaseGenerator {
code_ += "}"; code_ += "}";
code_ += ""; code_ += "";
// Union copy constructor
code_ += "inline {{ENUM_NAME}}Union::{{ENUM_NAME}}Union(const "
"{{ENUM_NAME}}Union &u) FLATBUFFERS_NOEXCEPT : type(u.type), "
"value(nullptr) {";
code_ += " switch (type) {";
for (auto it = enum_def.vals.vec.begin(); it != enum_def.vals.vec.end();
++it) {
const auto &ev = **it;
if (!ev.value) {
continue;
}
code_.SetValue("LABEL", GetEnumValUse(enum_def, ev));
code_.SetValue("TYPE", NativeName(GetUnionElement(ev, true, true, true),
ev.union_type.struct_def));
code_ += " case {{LABEL}}: {";
bool copyable = true;
if (ev.union_type.base_type == BASE_TYPE_STRUCT) {
// Don't generate code to copy if table is not copyable.
// TODO(wvo): make tables copyable instead.
for (auto fit = ev.union_type.struct_def->fields.vec.begin();
fit != ev.union_type.struct_def->fields.vec.end(); ++fit) {
const auto &field = **fit;
if (!field.deprecated && field.value.type.struct_def) {
copyable = false;
break;
}
}
}
if (copyable) {
code_ += " value = new {{TYPE}}(*reinterpret_cast<{{TYPE}} *>"
"(u.value));";
} else {
code_ += " assert(false); // {{TYPE}} not copyable.";
}
code_ += " break;";
code_ += " }";
}
code_ += " default:";
code_ += " break;";
code_ += " }";
code_ += "}";
code_ += "";
// Union Reset() function. // Union Reset() function.
code_.SetValue("NONE", code_.SetValue("NONE",
GetEnumValUse(enum_def, *enum_def.vals.Lookup("NONE"))); GetEnumValUse(enum_def, *enum_def.vals.Lookup("NONE")));
@@ -801,19 +946,18 @@ class CppGenerator : public BaseGenerator {
if (!ev.value) { if (!ev.value) {
continue; continue;
} }
code_.SetValue("LABEL", GetEnumValUse(enum_def, ev)); code_.SetValue("LABEL", GetEnumValUse(enum_def, ev));
code_.SetValue("TYPE", NativeName(WrapInNameSpace(*ev.struct_def))); code_.SetValue("TYPE", NativeName(GetUnionElement(ev, true, true, true),
ev.union_type.struct_def));
code_ += " case {{LABEL}}: {"; code_ += " case {{LABEL}}: {";
code_ += " auto ptr = reinterpret_cast<{{TYPE}} *>(table);"; code_ += " auto ptr = reinterpret_cast<{{TYPE}} *>(value);";
code_ += " delete ptr;"; code_ += " delete ptr;";
code_ += " break;"; code_ += " break;";
code_ += " }"; code_ += " }";
} }
code_ += " default: break;"; code_ += " default: break;";
code_ += " }"; code_ += " }";
code_ += " table = nullptr;"; code_ += " value = nullptr;";
code_ += " type = {{NONE}};"; code_ += " type = {{NONE}};";
code_ += "}"; code_ += "}";
code_ += ""; code_ += "";
@@ -840,7 +984,7 @@ class CppGenerator : public BaseGenerator {
std::string GenFieldOffsetName(const FieldDef &field) { std::string GenFieldOffsetName(const FieldDef &field) {
std::string uname = field.name; std::string uname = field.name;
std::transform(uname.begin(), uname.end(), uname.begin(), ::toupper); std::transform(uname.begin(), uname.end(), uname.begin(), ToUpper);
return "VT_" + uname; return "VT_" + uname;
} }
@@ -902,7 +1046,9 @@ class CppGenerator : public BaseGenerator {
// Generate a member, including a default value for scalars and raw pointers. // Generate a member, including a default value for scalars and raw pointers.
void GenMember(const FieldDef &field) { void GenMember(const FieldDef &field) {
if (!field.deprecated && // Deprecated fields won't be accessible. if (!field.deprecated && // Deprecated fields won't be accessible.
field.value.type.base_type != BASE_TYPE_UTYPE) { field.value.type.base_type != BASE_TYPE_UTYPE &&
(field.value.type.base_type != BASE_TYPE_VECTOR ||
field.value.type.element != BASE_TYPE_UTYPE)) {
auto type = GenTypeNative(field.value.type, false, field); auto type = GenTypeNative(field.value.type, false, field);
auto cpp_type = field.attributes.Lookup("cpp_type"); auto cpp_type = field.attributes.Lookup("cpp_type");
auto full_type = (cpp_type ? cpp_type->constant + " *" : type + " "); auto full_type = (cpp_type ? cpp_type->constant + " *" : type + " ");
@@ -952,7 +1098,7 @@ class CppGenerator : public BaseGenerator {
initializer_list = "\n : " + initializer_list; initializer_list = "\n : " + initializer_list;
} }
code_.SetValue("NATIVE_NAME", NativeName(struct_def.name)); code_.SetValue("NATIVE_NAME", NativeName(struct_def.name, &struct_def));
code_.SetValue("INIT_LIST", initializer_list); code_.SetValue("INIT_LIST", initializer_list);
code_ += " {{NATIVE_NAME}}(){{INIT_LIST}} {"; code_ += " {{NATIVE_NAME}}(){{INIT_LIST}} {";
@@ -960,7 +1106,7 @@ class CppGenerator : public BaseGenerator {
} }
void GenNativeTable(const StructDef &struct_def) { void GenNativeTable(const StructDef &struct_def) {
const auto native_name = NativeName(struct_def.name); const auto native_name = NativeName(struct_def.name, &struct_def);
code_.SetValue("STRUCT_NAME", struct_def.name); code_.SetValue("STRUCT_NAME", struct_def.name);
code_.SetValue("NATIVE_NAME", native_name); code_.SetValue("NATIVE_NAME", native_name);
@@ -984,7 +1130,12 @@ class CppGenerator : public BaseGenerator {
code_.SetValue("REQUIRED", field.required ? "Required" : ""); code_.SetValue("REQUIRED", field.required ? "Required" : "");
code_.SetValue("SIZE", GenTypeSize(field.value.type)); code_.SetValue("SIZE", GenTypeSize(field.value.type));
code_.SetValue("OFFSET", GenFieldOffsetName(field)); code_.SetValue("OFFSET", GenFieldOffsetName(field));
code_ += "{{PRE}}VerifyField{{REQUIRED}}<{{SIZE}}>(verifier, {{OFFSET}})\\"; if (IsScalar(field.value.type.base_type) || IsStruct(field.value.type)) {
code_ +=
"{{PRE}}VerifyField{{REQUIRED}}<{{SIZE}}>(verifier, {{OFFSET}})\\";
} else {
code_ += "{{PRE}}VerifyOffset{{REQUIRED}}(verifier, {{OFFSET}})\\";
}
switch (field.value.type.base_type) { switch (field.value.type.base_type) {
case BASE_TYPE_UNION: { case BASE_TYPE_UNION: {
@@ -1118,16 +1269,50 @@ class CppGenerator : public BaseGenerator {
code_ += " return {{FIELD_VALUE}};"; code_ += " return {{FIELD_VALUE}};";
code_ += " }"; code_ += " }";
if (field.value.type.base_type == BASE_TYPE_UNION) {
auto u = field.value.type.enum_def;
code_ += " template<typename T> "
"const T *{{FIELD_NAME}}_as() const;";
for (auto u_it = u->vals.vec.begin();
u_it != u->vals.vec.end(); ++u_it) {
auto &ev = **u_it;
if (ev.union_type.base_type == BASE_TYPE_NONE) {
continue;
}
auto full_struct_name = GetUnionElement(ev, true, true);
// @TODO: Mby make this decisions more universal? How?
code_.SetValue("U_GET_TYPE", field.name + UnionTypeFieldSuffix());
code_.SetValue("U_ELEMENT_TYPE", WrapInNameSpace(
u->defined_namespace, GetEnumValUse(*u, ev)));
code_.SetValue("U_FIELD_TYPE", "const " + full_struct_name + " *");
code_.SetValue("U_FIELD_NAME",
field.name + "_as_" + ev.name);
// `const Type *union_name_asType() const` accessor.
code_ += " {{U_FIELD_TYPE}}{{U_FIELD_NAME}}() const {";
code_ += " return {{U_GET_TYPE}}() == {{U_ELEMENT_TYPE}} ? "
"static_cast<{{U_FIELD_TYPE}}>({{FIELD_NAME}}()) "
": nullptr;";
code_ += " }";
}
}
if (parser_.opts.mutable_buffer) { if (parser_.opts.mutable_buffer) {
if (is_scalar) { if (is_scalar) {
const auto type = GenTypeWire(field.value.type, "", false);
code_.SetValue("SET_FN", "SetField<" + type + ">");
code_.SetValue("OFFSET_NAME", offset_str); code_.SetValue("OFFSET_NAME", offset_str);
code_.SetValue("FIELD_TYPE", GenTypeBasic(field.value.type, true)); code_.SetValue("FIELD_TYPE", GenTypeBasic(field.value.type, true));
code_.SetValue("FIELD_VALUE", code_.SetValue("FIELD_VALUE",
GenUnderlyingCast(field, false, "_" + field.name)); GenUnderlyingCast(field, false, "_" + field.name));
code_.SetValue("DEFAULT_VALUE", GenDefaultConstant(field));
code_ += " bool mutate_{{FIELD_NAME}}({{FIELD_TYPE}} " code_ += " bool mutate_{{FIELD_NAME}}({{FIELD_TYPE}} "
"_{{FIELD_NAME}}) {"; "_{{FIELD_NAME}}) {";
code_ += " return SetField({{OFFSET_NAME}}, {{FIELD_VALUE}});"; code_ += " return {{SET_FN}}({{OFFSET_NAME}}, {{FIELD_VALUE}}, {{DEFAULT_VALUE}});";
code_ += " }"; code_ += " }";
} else { } else {
auto type = GenTypeGet(field.value.type, " ", "", " *", true); auto type = GenTypeGet(field.value.type, " ", "", " *", true);
@@ -1153,11 +1338,19 @@ class CppGenerator : public BaseGenerator {
code_.SetValue("CPP_NAME", TranslateNameSpace(qualified_name)); code_.SetValue("CPP_NAME", TranslateNameSpace(qualified_name));
code_ += " const {{CPP_NAME}} *{{FIELD_NAME}}_nested_root() const {"; code_ += " const {{CPP_NAME}} *{{FIELD_NAME}}_nested_root() const {";
code_ += " const uint8_t* data = {{FIELD_NAME}}()->Data();"; code_ += " auto data = {{FIELD_NAME}}()->Data();";
code_ += " return flatbuffers::GetRoot<{{CPP_NAME}}>(data);"; code_ += " return flatbuffers::GetRoot<{{CPP_NAME}}>(data);";
code_ += " }"; code_ += " }";
} }
if (field.flexbuffer) {
code_ += " flexbuffers::Reference {{FIELD_NAME}}_flexbuffer_root()"
" const {";
code_ += " auto v = {{FIELD_NAME}}();";
code_ += " return flexbuffers::GetRoot(v->Data(), v->size());";
code_ += " }";
}
// Generate a comparison function for this field if it is a key. // Generate a comparison function for this field if it is a key.
if (field.key) { if (field.key) {
const bool is_string = (field.value.type.base_type == BASE_TYPE_STRING); const bool is_string = (field.value.type.base_type == BASE_TYPE_STRING);
@@ -1222,6 +1415,46 @@ class CppGenerator : public BaseGenerator {
code_ += "};"; // End of table. code_ += "};"; // End of table.
code_ += ""; code_ += "";
// Explicit specializations for union accessors
for (auto it = struct_def.fields.vec.begin();
it != struct_def.fields.vec.end(); ++it) {
const auto &field = **it;
if (field.deprecated ||
field.value.type.base_type != BASE_TYPE_UNION) {
continue;
}
auto u = field.value.type.enum_def;
if (u->uses_type_aliases) continue;
code_.SetValue("FIELD_NAME", field.name);
for (auto u_it = u->vals.vec.begin();
u_it != u->vals.vec.end(); ++u_it) {
auto &ev = **u_it;
if (ev.union_type.base_type == BASE_TYPE_NONE) {
continue;
}
auto full_struct_name = GetUnionElement(ev, true, true);
code_.SetValue("U_ELEMENT_TYPE", WrapInNameSpace(
u->defined_namespace, GetEnumValUse(*u, ev)));
code_.SetValue("U_FIELD_TYPE", "const " + full_struct_name + " *");
code_.SetValue("U_ELEMENT_NAME", full_struct_name);
code_.SetValue("U_FIELD_NAME",
field.name + "_as_" + ev.name);
// `template<> const T *union_name_as<T>() const` accessor.
code_ += "template<> "
"inline {{U_FIELD_TYPE}}{{STRUCT_NAME}}::{{FIELD_NAME}}_as"
"<{{U_ELEMENT_NAME}}>() const {";
code_ += " return {{U_FIELD_NAME}}();";
code_ += "}";
code_ += "";
}
}
GenBuilders(struct_def); GenBuilders(struct_def);
if (parser_.opts.generate_object_based_api) { if (parser_.opts.generate_object_based_api) {
@@ -1390,6 +1623,14 @@ class CppGenerator : public BaseGenerator {
} }
} }
std::string GenUnionUnpackVal(const FieldDef &afield,
const char *vec_elem_access,
const char *vec_type_access) {
return afield.value.type.enum_def->name + "Union::UnPack(" + "_e" +
vec_elem_access + ", " + afield.name + UnionTypeFieldSuffix() +
"()" + vec_type_access + ", _resolver)";
}
std::string GenUnpackVal(const Type &type, const std::string &val, std::string GenUnpackVal(const Type &type, const std::string &val,
bool invector, const FieldDef &afield) { bool invector, const FieldDef &afield) {
switch (type.base_type) { switch (type.base_type) {
@@ -1409,10 +1650,18 @@ class CppGenerator : public BaseGenerator {
return ptype + "(new " + name + "(*" + val + "))"; return ptype + "(new " + name + "(*" + val + "))";
} }
} else { } else {
const auto ptype = GenTypeNativePtr(NativeName(name), &afield, true); const auto ptype = GenTypeNativePtr(NativeName(name, type.struct_def),
&afield, true);
return ptype + "(" + val + "->UnPack(_resolver))"; return ptype + "(" + val + "->UnPack(_resolver))";
} }
} }
case BASE_TYPE_UNION: {
return GenUnionUnpackVal(afield,
invector ? "->Get(_i)" : "",
invector ? ("->GetEnum<" +
type.enum_def->name +
">(_i)").c_str() : "");
}
default: { default: {
return val; return val;
break; break;
@@ -1438,12 +1687,22 @@ class CppGenerator : public BaseGenerator {
// for (uoffset_t i = 0; i < _e->size(); ++i) { // for (uoffset_t i = 0; i < _e->size(); ++i) {
// _o->field.push_back(_e->Get(_i)); // _o->field.push_back(_e->Get(_i));
// } // }
auto name = field.name;
if (field.value.type.element == BASE_TYPE_UTYPE) {
name = StripUnionType(field.name);
}
auto access = field.value.type.element == BASE_TYPE_UTYPE
? ".type"
: (field.value.type.element == BASE_TYPE_UNION
? ".value"
: "");
code += "{ _o->" + name + ".resize(_e->size()); ";
code += "for (flatbuffers::uoffset_t _i = 0;"; code += "for (flatbuffers::uoffset_t _i = 0;";
code += " _i < _e->size(); _i++) { "; code += " _i < _e->size(); _i++) { ";
code += "_o->" + field.name + ".push_back("; code += "_o->" + name + "[_i]" + access + " = ";
code += GenUnpackVal(field.value.type.VectorType(), code += GenUnpackVal(field.value.type.VectorType(),
indexing, true, field); indexing, true, field);
code += "); }"; code += "; } }";
break; break;
} }
case BASE_TYPE_UTYPE: { case BASE_TYPE_UTYPE: {
@@ -1454,12 +1713,11 @@ class CppGenerator : public BaseGenerator {
break; break;
} }
case BASE_TYPE_UNION: { case BASE_TYPE_UNION: {
// Generate code that sets the union table, of the form: // Generate code that sets the union value, of the form:
// _o->field.table = Union::Unpack(_e, field_type(), resolver); // _o->field.value = Union::Unpack(_e, field_type(), resolver);
code += "_o->" + field.name + ".table = "; code += "_o->" + field.name + ".value = ";
code += field.value.type.enum_def->name + "Union::UnPack("; code += GenUnionUnpackVal(field, "", "");
code += "_e, " + field.name + UnionTypeFieldSuffix() + "(),"; code += ";";
code += "_resolver);";
break; break;
} }
default: { default: {
@@ -1491,8 +1749,7 @@ class CppGenerator : public BaseGenerator {
std::string GenCreateParam(const FieldDef &field) { std::string GenCreateParam(const FieldDef &field) {
std::string value = "_o->"; std::string value = "_o->";
if (field.value.type.base_type == BASE_TYPE_UTYPE) { if (field.value.type.base_type == BASE_TYPE_UTYPE) {
value += field.name.substr(0, field.name.size() - value += StripUnionType(field.name);
strlen(UnionTypeFieldSuffix()));
value += ".type"; value += ".type";
} else { } else {
value += field.name; value += field.name;
@@ -1534,7 +1791,15 @@ class CppGenerator : public BaseGenerator {
} }
case BASE_TYPE_STRUCT: { case BASE_TYPE_STRUCT: {
if (IsStruct(vector_type)) { if (IsStruct(vector_type)) {
code += "_fbb.CreateVectorOfStructs(" + value + ")"; auto native_type =
field.value.type.struct_def->attributes.Lookup("native_type");
if (native_type) {
code += "_fbb.CreateVectorOfNativeStructs<";
code += WrapInNameSpace(*vector_type.struct_def) + ">";
} else {
code += "_fbb.CreateVectorOfStructs";
}
code += "(" + value + ")";
} else { } else {
code += "_fbb.CreateVector<flatbuffers::Offset<"; code += "_fbb.CreateVector<flatbuffers::Offset<";
code += WrapInNameSpace(*vector_type.struct_def) + ">>"; code += WrapInNameSpace(*vector_type.struct_def) + ">>";
@@ -1549,6 +1814,19 @@ class CppGenerator : public BaseGenerator {
code += "_fbb.CreateVector(" + value + ")"; code += "_fbb.CreateVector(" + value + ")";
break; break;
} }
case BASE_TYPE_UNION: {
code += "_fbb.CreateVector<flatbuffers::Offset<void>>(" + value +
".size(), [&](size_t i) { return " + value +
"[i].Pack(_fbb, _rehasher); })";
break;
}
case BASE_TYPE_UTYPE: {
value = StripUnionType(value);
code += "_fbb.CreateVector<uint8_t>(" + value +
".size(), [&](size_t i) { return static_cast<uint8_t>(" + value +
"[i].type); })";
break;
}
default: { default: {
if (field.value.type.enum_def) { if (field.value.type.enum_def) {
// For enumerations, we need to get access to the array data for // For enumerations, we need to get access to the array data for
@@ -1607,7 +1885,7 @@ class CppGenerator : public BaseGenerator {
// Generate code for tables that needs to come after the regular definition. // Generate code for tables that needs to come after the regular definition.
void GenTablePost(const StructDef &struct_def) { void GenTablePost(const StructDef &struct_def) {
code_.SetValue("STRUCT_NAME", struct_def.name); code_.SetValue("STRUCT_NAME", struct_def.name);
code_.SetValue("NATIVE_NAME", NativeName(struct_def.name)); code_.SetValue("NATIVE_NAME", NativeName(struct_def.name, &struct_def));
if (parser_.opts.generate_object_based_api) { if (parser_.opts.generate_object_based_api) {
// Generate the X::UnPack() method. // Generate the X::UnPack() method.
@@ -1844,6 +2122,8 @@ class CppGenerator : public BaseGenerator {
code_ += " }"; code_ += " }";
if (parser_.opts.mutable_buffer) { if (parser_.opts.mutable_buffer) {
auto mut_field_type = GenTypeGet(field.value.type, " ", "", " &", true);
code_.SetValue("FIELD_TYPE", mut_field_type);
if (is_scalar) { if (is_scalar) {
code_.SetValue("ARG", GenTypeBasic(field.value.type, true)); code_.SetValue("ARG", GenTypeBasic(field.value.type, true));
code_.SetValue("FIELD_VALUE", code_.SetValue("FIELD_VALUE",
@@ -1859,6 +2139,24 @@ class CppGenerator : public BaseGenerator {
code_ += " }"; code_ += " }";
} }
} }
// Generate a comparison function for this field if it is a key.
if (field.key) {
code_ += " bool KeyCompareLessThan(const {{STRUCT_NAME}} *o) const {";
code_ += " return {{FIELD_NAME}}() < o->{{FIELD_NAME}}();";
code_ += " }";
auto type = GenTypeBasic(field.value.type, false);
if (parser_.opts.scoped_enums && field.value.type.enum_def &&
IsScalar(field.value.type.base_type)) {
type = GenTypeGet(field.value.type, " ", "const ", " *", true);
}
code_.SetValue("KEY_TYPE", type);
code_ += " int KeyCompareWithValue({{KEY_TYPE}} val) const {";
code_ += " const auto key = {{FIELD_NAME}}();";
code_ += " return static_cast<int>(key > val) - static_cast<int>(key < val);";
code_ += " }";
}
} }
code_ += "};"; code_ += "};";

View File

@@ -72,12 +72,12 @@ std::string GenerateFBS(const Parser &parser, const std::string &file_name) {
int num_includes = 0; int num_includes = 0;
for (auto it = parser.included_files_.begin(); for (auto it = parser.included_files_.begin();
it != parser.included_files_.end(); ++it) { it != parser.included_files_.end(); ++it) {
if (it->second.empty())
continue;
auto basename = flatbuffers::StripPath( auto basename = flatbuffers::StripPath(
flatbuffers::StripExtension(it->first)); flatbuffers::StripExtension(it->second));
if (basename != file_name) { schema += "include \"" + basename + ".fbs\";\n";
schema += "include \"" + basename + ".fbs\";\n"; num_includes++;
num_includes++;
}
} }
if (num_includes) schema += "\n"; if (num_includes) schema += "\n";
#endif #endif

View File

@@ -20,7 +20,6 @@
#include "flatbuffers/idl.h" #include "flatbuffers/idl.h"
#include "flatbuffers/util.h" #include "flatbuffers/util.h"
#include "flatbuffers/code_generators.h" #include "flatbuffers/code_generators.h"
#include <algorithm>
namespace flatbuffers { namespace flatbuffers {
@@ -128,7 +127,7 @@ const LanguageParameters& GetLangParams(IDLOptions::Language lang) {
"__p.", "__p.",
"Table.", "Table.",
"?", "?",
"using System;\nusing FlatBuffers;\n\n", "using global::System;\nusing global::FlatBuffers;\n\n",
{ {
nullptr, nullptr,
"///", "///",
@@ -204,7 +203,14 @@ class GeneralGenerator : public BaseGenerator {
if (!classcode.length()) return true; if (!classcode.length()) return true;
std::string code; std::string code;
code = code + "// " + FlatBuffersGeneratedWarning(); if (lang_.language == IDLOptions::kCSharp) {
code = "// <auto-generated>\n"
"// " + std::string(FlatBuffersGeneratedWarning()) + "\n"
"// </auto-generated>\n\n";
} else {
code = "// " + std::string(FlatBuffersGeneratedWarning()) + "\n\n";
}
std::string namespace_name = FullNamespace(".", ns); std::string namespace_name = FullNamespace(".", ns);
if (!namespace_name.empty()) { if (!namespace_name.empty()) {
code += lang_.namespace_ident + namespace_name + lang_.namespace_begin; code += lang_.namespace_ident + namespace_name + lang_.namespace_begin;
@@ -301,7 +307,7 @@ Type DestinationType(const Type &type, bool vectorelem) {
case BASE_TYPE_VECTOR: case BASE_TYPE_VECTOR:
if (vectorelem) if (vectorelem)
return DestinationType(type.VectorType(), vectorelem); return DestinationType(type.VectorType(), vectorelem);
// else fall thru: // else fall thru
default: return type; default: return type;
} }
} }
@@ -348,7 +354,7 @@ std::string DestinationMask(const Type &type, bool vectorelem) {
case BASE_TYPE_VECTOR: case BASE_TYPE_VECTOR:
if (vectorelem) if (vectorelem)
return DestinationMask(type.VectorType(), vectorelem); return DestinationMask(type.VectorType(), vectorelem);
// else fall thru: // else fall thru
default: return ""; default: return "";
} }
} }
@@ -587,6 +593,22 @@ std::string GenGetter(const Type &type) {
} }
} }
// Returns the function name that is able to read a value of the given type.
std::string GenGetterForLookupByKey(flatbuffers::FieldDef *key_field,
const std::string &data_buffer,
const char *num = nullptr) {
auto type = key_field->value.type;
auto dest_mask = DestinationMask(type, true);
auto dest_cast = DestinationCast(type);
auto getter = data_buffer + "." + FunctionStart('G') + "et";
if (GenTypeBasic(type, false) != "byte") {
getter += MakeCamel(GenTypeBasic(type, false));
}
getter = dest_cast + getter + "(" + GenOffsetGetter(key_field, num) + ")"
+ dest_mask;
return getter;
}
// Direct mutation is only allowed for scalar fields. // Direct mutation is only allowed for scalar fields.
// Hence a setter method will only be generated for such fields. // Hence a setter method will only be generated for such fields.
std::string GenSetter(const Type &type) { std::string GenSetter(const Type &type) {
@@ -699,12 +721,11 @@ std::string GenLookupKeyGetter(flatbuffers::FieldDef *key_field) {
key_getter += GenOffsetGetter(key_field); key_getter += GenOffsetGetter(key_field);
key_getter += ", byteKey, bb);\n"; key_getter += ", byteKey, bb);\n";
} else { } else {
auto get_val = GenGetter(key_field->value.type) + auto get_val = GenGetterForLookupByKey(key_field, "bb");
"(" + GenOffsetGetter(key_field) + ")";
if (lang_.language == IDLOptions::kCSharp) { if (lang_.language == IDLOptions::kCSharp) {
key_getter += "int comp = " + get_val + ".CompareTo(key);\n"; key_getter += "int comp = " + get_val + ".CompareTo(key);\n";
} else { } else {
key_getter += GenTypeGet(key_field->value.type) + " val = "; key_getter += GenTypeNameDest(key_field->value.type) + " val = ";
key_getter += get_val + ";\n"; key_getter += get_val + ";\n";
key_getter += " int comp = val > key ? 1 : val < key ? -1 : 0;\n"; key_getter += " int comp = val > key ? 1 : val < key ? -1 : 0;\n";
} }
@@ -728,20 +749,17 @@ std::string GenKeyGetter(flatbuffers::FieldDef *key_field) {
key_getter += ";"; key_getter += ";";
} }
else { else {
auto field_getter = data_buffer + GenGetter(key_field->value.type).substr(2) + auto field_getter = GenGetterForLookupByKey(key_field, data_buffer, "o1");
"(" + GenOffsetGetter(key_field, "o1") + ")";
if (lang_.language == IDLOptions::kCSharp) { if (lang_.language == IDLOptions::kCSharp) {
key_getter += field_getter; key_getter += field_getter;
field_getter = data_buffer + GenGetter(key_field->value.type).substr(2) + field_getter = GenGetterForLookupByKey(key_field, data_buffer, "o2");
"(" + GenOffsetGetter(key_field, "o2") + ")";
key_getter += ".CompareTo(" + field_getter + ")"; key_getter += ".CompareTo(" + field_getter + ")";
} }
else { else {
key_getter += "\n " + GenTypeGet(key_field->value.type) + " val_1 = "; key_getter += "\n " + GenTypeNameDest(key_field->value.type) + " val_1 = ";
key_getter += field_getter + ";\n " + GenTypeGet(key_field->value.type); key_getter += field_getter + ";\n " + GenTypeNameDest(key_field->value.type);
key_getter += " val_2 = "; key_getter += " val_2 = ";
field_getter = data_buffer + GenGetter(key_field->value.type).substr(2) + field_getter = GenGetterForLookupByKey(key_field, data_buffer, "o2");
"(" + GenOffsetGetter(key_field, "o2") + ")";
key_getter += field_getter + ";\n"; key_getter += field_getter + ";\n";
key_getter += " return val_1 > val_2 ? 1 : val_1 < val_2 ? -1 : 0;\n "; key_getter += " return val_1 > val_2 ? 1 : val_1 < val_2 ? -1 : 0;\n ";
} }
@@ -993,6 +1011,26 @@ void GenStruct(StructDef &struct_def, std::string *code_ptr) {
code += lang_.accessor_prefix + "__vector_len(o) : 0; "; code += lang_.accessor_prefix + "__vector_len(o) : 0; ";
code += lang_.getter_suffix; code += lang_.getter_suffix;
code += "}\n"; code += "}\n";
// See if we should generate a by-key accessor.
if (field.value.type.element == BASE_TYPE_STRUCT &&
!field.value.type.struct_def->fixed) {
auto &sd = *field.value.type.struct_def;
auto &fields = sd.fields.vec;
for (auto kit = fields.begin(); kit != fields.end(); ++kit) {
auto &key_field = **kit;
if (key_field.key) {
code += " public " + sd.name + lang_.optional_suffix + " ";
code += MakeCamel(field.name, lang_.first_camel_upper) + "ByKey(";
code += GenTypeNameDest(key_field.value.type) + " key)";
code += offset_prefix;
code += sd.name + ".__lookup_by_key(";
code += lang_.accessor_prefix + "__vector(o), key, ";
code += lang_.accessor_prefix + "bb) : null; ";
code += "}\n";
break;
}
}
}
} }
// Generate a ByteBuffer accessor for strings & vectors of scalars. // Generate a ByteBuffer accessor for strings & vectors of scalars.
if ((field.value.type.base_type == BASE_TYPE_VECTOR && if ((field.value.type.base_type == BASE_TYPE_VECTOR &&
@@ -1279,7 +1317,9 @@ void GenStruct(StructDef &struct_def, std::string *code_ptr) {
code += "); }\n"; code += "); }\n";
} }
} }
if (struct_def.has_key) { // Only generate key compare function for table,
// because `key_field` is not set for struct
if (struct_def.has_key && !struct_def.fixed) {
if (lang_.language == IDLOptions::kJava) { if (lang_.language == IDLOptions::kJava) {
code += "\n @Override\n protected int keysCompare("; code += "\n @Override\n protected int keysCompare(";
code += "Integer o1, Integer o2, ByteBuffer _bb) {"; code += "Integer o1, Integer o2, ByteBuffer _bb) {";
@@ -1288,7 +1328,8 @@ void GenStruct(StructDef &struct_def, std::string *code_ptr) {
} }
else { else {
code += "\n public static VectorOffset "; code += "\n public static VectorOffset ";
code += "CreateMySortedVectorOfTables(FlatBufferBuilder builder, "; code += "CreateSortedVectorOf" + struct_def.name;
code += "(FlatBufferBuilder builder, ";
code += "Offset<" + struct_def.name + ">"; code += "Offset<" + struct_def.name + ">";
code += "[] offsets) {\n"; code += "[] offsets) {\n";
code += " Array.Sort(offsets, (Offset<" + struct_def.name + code += " Array.Sort(offsets, (Offset<" + struct_def.name +
@@ -1298,8 +1339,8 @@ void GenStruct(StructDef &struct_def, std::string *code_ptr) {
} }
code += "\n public static " + struct_def.name + lang_.optional_suffix; code += "\n public static " + struct_def.name + lang_.optional_suffix;
code += " " + FunctionStart('L') + "ookupByKey(" + GenVectorOffsetType(); code += " __lookup_by_key(int vectorLocation, ";
code += " vectorOffset, " + GenTypeGet(key_field->value.type); code += GenTypeNameDest(key_field->value.type);
code += " key, ByteBuffer bb) {\n"; code += " key, ByteBuffer bb) {\n";
if (key_field->value.type.base_type == BASE_TYPE_STRING) { if (key_field->value.type.base_type == BASE_TYPE_STRING) {
code += " byte[] byteKey = "; code += " byte[] byteKey = ";
@@ -1308,13 +1349,9 @@ void GenStruct(StructDef &struct_def, std::string *code_ptr) {
else else
code += "System.Text.Encoding.UTF8.GetBytes(key);\n"; code += "System.Text.Encoding.UTF8.GetBytes(key);\n";
} }
code += " int vectorLocation = " + GenByteBufferLength("bb"); code += " int span = ";
code += " - vectorOffset"; code += "bb." + FunctionStart('G') + "etInt(vectorLocation - 4);\n";
if (lang_.language == IDLOptions::kCSharp) code += ".Value";
code += ";\n int span = ";
code += "bb." + FunctionStart('G') + "etInt(vectorLocation);\n";
code += " int start = 0;\n"; code += " int start = 0;\n";
code += " vectorLocation += 4;\n";
code += " while (span != 0) {\n"; code += " while (span != 0) {\n";
code += " int middle = span / 2;\n"; code += " int middle = span / 2;\n";
code += GenLookupKeyGetter(key_field); code += GenLookupKeyGetter(key_field);

View File

@@ -17,6 +17,7 @@
// independent from idl_parser, since this code is not needed for most clients // independent from idl_parser, since this code is not needed for most clients
#include <string> #include <string>
#include <sstream>
#include "flatbuffers/flatbuffers.h" #include "flatbuffers/flatbuffers.h"
#include "flatbuffers/idl.h" #include "flatbuffers/idl.h"
@@ -35,6 +36,13 @@
namespace flatbuffers { namespace flatbuffers {
namespace go { namespace go {
// see https://golang.org/ref/spec#Keywords
static const char *g_golang_keywords[] = {
"break", "default", "func", "interface", "select", "case", "defer", "go",
"map", "struct", "chan", "else", "goto", "package", "switch", "const",
"fallthrough", "if", "range", "type", "continue", "for", "import", "return", "var",
};
static std::string GenGetter(const Type &type); static std::string GenGetter(const Type &type);
static std::string GenMethod(const FieldDef &field); static std::string GenMethod(const FieldDef &field);
static void GenStructBuilder(const StructDef &struct_def, static void GenStructBuilder(const StructDef &struct_def,
@@ -43,6 +51,15 @@ static void GenReceiver(const StructDef &struct_def, std::string *code_ptr);
static std::string GenTypeBasic(const Type &type); static std::string GenTypeBasic(const Type &type);
static std::string GenTypeGet(const Type &type); static std::string GenTypeGet(const Type &type);
static std::string TypeName(const FieldDef &field); static std::string TypeName(const FieldDef &field);
static std::string GoIdentity(const std::string& name) {
for (size_t i=0; i<sizeof(g_golang_keywords)/sizeof(g_golang_keywords[0]); i++) {
if (name == g_golang_keywords[i]) {
return MakeCamel(name + "_", false);
}
}
return MakeCamel(name, false);
}
// Most field accessors need to retrieve and test the field offset first, // Most field accessors need to retrieve and test the field offset first,
@@ -368,7 +385,7 @@ static void StructBuilderArgs(const StructDef &struct_def,
} else { } else {
std::string &code = *code_ptr; std::string &code = *code_ptr;
code += (std::string)", " + nameprefix; code += (std::string)", " + nameprefix;
code += MakeCamel(field.name, false); code += GoIdentity(field.name);
code += " " + GenTypeBasic(field.value.type); code += " " + GenTypeBasic(field.value.type);
} }
} }
@@ -400,7 +417,7 @@ static void StructBuilderBody(const StructDef &struct_def,
code_ptr); code_ptr);
} else { } else {
code += "\tbuilder.Prepend" + GenMethod(field) + "("; code += "\tbuilder.Prepend" + GenMethod(field) + "(";
code += nameprefix + MakeCamel(field.name, false) + ")\n"; code += nameprefix + GoIdentity(field.name) + ")\n";
} }
} }
} }
@@ -430,7 +447,7 @@ static void BuildFieldOfTable(const StructDef &struct_def,
std::string &code = *code_ptr; std::string &code = *code_ptr;
code += "func " + struct_def.name + "Add" + MakeCamel(field.name); code += "func " + struct_def.name + "Add" + MakeCamel(field.name);
code += "(builder *flatbuffers.Builder, "; code += "(builder *flatbuffers.Builder, ";
code += MakeCamel(field.name, false) + " "; code += GoIdentity(field.name) + " ";
if (!IsScalar(field.value.type.base_type) && (!struct_def.fixed)) { if (!IsScalar(field.value.type.base_type) && (!struct_def.fixed)) {
code += "flatbuffers.UOffsetT"; code += "flatbuffers.UOffsetT";
} else { } else {
@@ -443,9 +460,9 @@ static void BuildFieldOfTable(const StructDef &struct_def,
if (!IsScalar(field.value.type.base_type) && (!struct_def.fixed)) { if (!IsScalar(field.value.type.base_type) && (!struct_def.fixed)) {
code += "flatbuffers.UOffsetT"; code += "flatbuffers.UOffsetT";
code += "("; code += "(";
code += MakeCamel(field.name, false) + ")"; code += GoIdentity(field.name) + ")";
} else { } else {
code += MakeCamel(field.name, false); code += GoIdentity(field.name);
} }
code += ", " + field.value.constant; code += ", " + field.value.constant;
code += ")\n}\n"; code += ")\n}\n";
@@ -724,9 +741,15 @@ static void GenStructBuilder(const StructDef &struct_def,
class GoGenerator : public BaseGenerator { class GoGenerator : public BaseGenerator {
public: public:
GoGenerator(const Parser &parser, const std::string &path, GoGenerator(const Parser &parser, const std::string &path,
const std::string &file_name) const std::string &file_name, const std::string &go_namespace)
: BaseGenerator(parser, path, file_name, "" /* not used*/, : BaseGenerator(parser, path, file_name, "" /* not used*/, "" /* not used */) {
"" /* not used */){}; std::istringstream iss(go_namespace);
std::string component;
while (std::getline(iss, component, '.')) {
go_namespace_.components.push_back(component);
}
}
bool generate() { bool generate() {
for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end(); for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
++it) { ++it) {
@@ -750,7 +773,7 @@ class GoGenerator : public BaseGenerator {
void BeginFile(const std::string name_space_name, const bool needs_imports, void BeginFile(const std::string name_space_name, const bool needs_imports,
std::string *code_ptr) { std::string *code_ptr) {
std::string &code = *code_ptr; std::string &code = *code_ptr;
code = code + "// " + FlatBuffersGeneratedWarning(); code = code + "// " + FlatBuffersGeneratedWarning() + "\n\n";
code += "package " + name_space_name + "\n\n"; code += "package " + name_space_name + "\n\n";
if (needs_imports) { if (needs_imports) {
code += "import (\n"; code += "import (\n";
@@ -764,19 +787,22 @@ class GoGenerator : public BaseGenerator {
bool needs_imports) { bool needs_imports) {
if (!classcode.length()) return true; if (!classcode.length()) return true;
Namespace& ns = go_namespace_.components.empty() ? *def.defined_namespace : go_namespace_;
std::string code = ""; std::string code = "";
BeginFile(LastNamespacePart(*def.defined_namespace), needs_imports, &code); BeginFile(LastNamespacePart(ns), needs_imports, &code);
code += classcode; code += classcode;
std::string filename = std::string filename =
NamespaceDir(*def.defined_namespace) + def.name + ".go"; NamespaceDir(ns) + def.name + ".go";
return SaveFile(filename.c_str(), code, false); return SaveFile(filename.c_str(), code, false);
} }
Namespace go_namespace_;
}; };
} // namespace go } // namespace go
bool GenerateGo(const Parser &parser, const std::string &path, bool GenerateGo(const Parser &parser, const std::string &path,
const std::string &file_name) { const std::string &file_name) {
go::GoGenerator generator(parser, path, file_name); go::GoGenerator generator(parser, path, file_name, parser.opts.go_namespace);
return generator.generate(); return generator.generate();
} }

View File

@@ -24,6 +24,11 @@
#include "src/compiler/cpp_generator.h" #include "src/compiler/cpp_generator.h"
#include "src/compiler/go_generator.h" #include "src/compiler/go_generator.h"
#if defined(_MSC_VER)
#pragma warning(push)
#pragma warning(disable: 4512) // C4512: 'class' : assignment operator could not be generated
#endif
namespace flatbuffers { namespace flatbuffers {
class FlatBufMethod : public grpc_generator::Method { class FlatBufMethod : public grpc_generator::Method {
@@ -41,30 +46,52 @@ class FlatBufMethod : public grpc_generator::Method {
} }
} }
grpc::string GetLeadingComments(const grpc::string) const {
return "";
}
grpc::string GetTrailingComments(const grpc::string) const {
return "";
}
std::vector<grpc::string> GetAllComments() const {
return std::vector<grpc::string>();
}
std::string name() const { return method_->name; } std::string name() const { return method_->name; }
std::string GRPCType(const StructDef &sd) const { std::string GRPCType(const StructDef &sd) const {
return "flatbuffers::BufferRef<" + sd.name + ">"; return "flatbuffers::grpc::Message<" + sd.name + ">";
}
std::string get_input_type_name() const {
return (*method_->request).name;
}
std::string get_output_type_name() const {
return (*method_->response).name;
}
bool get_module_and_message_path_input(
grpc::string * /*str*/, grpc::string /*generator_file_name*/,
bool /*generate_in_pb2_grpc*/, grpc::string /*import_prefix*/) const {
return true;
}
bool get_module_and_message_path_output(
grpc::string * /*str*/, grpc::string /*generator_file_name*/,
bool /*generate_in_pb2_grpc*/, grpc::string /*import_prefix*/) const {
return true;
} }
std::string input_type_name() const { std::string input_type_name() const {
return GRPCType(*method_->request); return GRPCType(*method_->request);
} }
std::string output_type_name() const { std::string output_type_name() const {
return GRPCType(*method_->response); return GRPCType(*method_->response);
} }
std::string input_name() const {
return (*method_->request).name;
}
std::string output_name() const {
return (*method_->response).name;
}
bool NoStreaming() const { return streaming_ == kNone; } bool NoStreaming() const { return streaming_ == kNone; }
bool ClientOnlyStreaming() const { return streaming_ == kClient; } bool ClientStreaming() const { return streaming_ == kClient; }
bool ServerOnlyStreaming() const { return streaming_ == kServer; } bool ServerStreaming() const { return streaming_ == kServer; }
bool BidiStreaming() const { return streaming_ == kBiDi; } bool BidiStreaming() const { return streaming_ == kBiDi; }
private: private:
@@ -76,6 +103,16 @@ class FlatBufService : public grpc_generator::Service {
public: public:
FlatBufService(const ServiceDef *service) : service_(service) {} FlatBufService(const ServiceDef *service) : service_(service) {}
grpc::string GetLeadingComments(const grpc::string) const {
return "";
}
grpc::string GetTrailingComments(const grpc::string) const {
return "";
}
std::vector<grpc::string> GetAllComments() const {
return std::vector<grpc::string>();
}
std::string name() const { return service_->name; } std::string name() const { return service_->name; }
int method_count() const { int method_count() const {
@@ -117,6 +154,9 @@ class FlatBufPrinter : public grpc_generator::Printer {
} }
void Print(const char *s) { void Print(const char *s) {
if (s == nullptr || std::strlen(s) == 0) {
return;
}
// Add this string, but for each part separated by \n, add indentation. // Add this string, but for each part separated by \n, add indentation.
for (;;) { for (;;) {
// Current indentation. // Current indentation.
@@ -145,10 +185,26 @@ class FlatBufPrinter : public grpc_generator::Printer {
class FlatBufFile : public grpc_generator::File { class FlatBufFile : public grpc_generator::File {
public: public:
FlatBufFile(const Parser &parser, const std::string &file_name) enum Language {
: parser_(parser), file_name_(file_name) {} kLanguageGo,
kLanguageCpp
};
FlatBufFile(
const Parser &parser, const std::string &file_name, Language language)
: parser_(parser), file_name_(file_name), language_(language) {}
FlatBufFile &operator=(const FlatBufFile &); FlatBufFile &operator=(const FlatBufFile &);
grpc::string GetLeadingComments(const grpc::string) const {
return "";
}
grpc::string GetTrailingComments(const grpc::string) const {
return "";
}
std::vector<grpc::string> GetAllComments() const {
return std::vector<grpc::string>();
}
std::string filename() const { return file_name_; } std::string filename() const { return file_name_; }
std::string filename_without_ext() const { std::string filename_without_ext() const {
return StripExtension(file_name_); return StripExtension(file_name_);
@@ -166,11 +222,15 @@ class FlatBufFile : public grpc_generator::File {
} }
std::string additional_headers() const { std::string additional_headers() const {
return "#include \"flatbuffers/grpc.h\"\n"; switch (language_) {
} case kLanguageCpp: {
return "#include \"flatbuffers/grpc.h\"\n";
std::string additional_imports() const { }
return "import \"github.com/google/flatbuffers/go\""; case kLanguageGo: {
return "import \"github.com/google/flatbuffers/go\"";
}
}
return "";
} }
int service_count() const { int service_count() const {
@@ -190,6 +250,7 @@ class FlatBufFile : public grpc_generator::File {
private: private:
const Parser &parser_; const Parser &parser_;
const std::string &file_name_; const std::string &file_name_;
const Language language_;
}; };
class GoGRPCGenerator : public flatbuffers::BaseGenerator { class GoGRPCGenerator : public flatbuffers::BaseGenerator {
@@ -200,7 +261,7 @@ class GoGRPCGenerator : public flatbuffers::BaseGenerator {
parser_(parser), path_(path), file_name_(file_name) {} parser_(parser), path_(path), file_name_(file_name) {}
bool generate() { bool generate() {
FlatBufFile file(parser_, file_name_); FlatBufFile file(parser_, file_name_, FlatBufFile::kLanguageGo);
grpc_go_generator::Parameters p; grpc_go_generator::Parameters p;
p.custom_method_io_type = "flatbuffers.Builder"; p.custom_method_io_type = "flatbuffers.Builder";
for (int i = 0; i < file.service_count(); i++) { for (int i = 0; i < file.service_count(); i++) {
@@ -233,7 +294,7 @@ bool GenerateGoGRPC(const Parser &parser,
} }
bool GenerateCppGRPC(const Parser &parser, bool GenerateCppGRPC(const Parser &parser,
const std::string &/*path*/, const std::string &path,
const std::string &file_name) { const std::string &file_name) {
int nservices = 0; int nservices = 0;
@@ -247,7 +308,7 @@ bool GenerateCppGRPC(const Parser &parser,
// TODO(wvo): make the other parameters in this struct configurable. // TODO(wvo): make the other parameters in this struct configurable.
generator_parameters.use_system_headers = true; generator_parameters.use_system_headers = true;
FlatBufFile fbfile(parser, file_name); FlatBufFile fbfile(parser, file_name, FlatBufFile::kLanguageCpp);
std::string header_code = std::string header_code =
grpc_cpp_generator::GetHeaderPrologue(&fbfile, generator_parameters) + grpc_cpp_generator::GetHeaderPrologue(&fbfile, generator_parameters) +
@@ -261,11 +322,15 @@ bool GenerateCppGRPC(const Parser &parser,
grpc_cpp_generator::GetSourceServices(&fbfile, generator_parameters) + grpc_cpp_generator::GetSourceServices(&fbfile, generator_parameters) +
grpc_cpp_generator::GetSourceEpilogue(&fbfile, generator_parameters); grpc_cpp_generator::GetSourceEpilogue(&fbfile, generator_parameters);
return flatbuffers::SaveFile((file_name + ".grpc.fb.h").c_str(), return flatbuffers::SaveFile((path + file_name + ".grpc.fb.h").c_str(),
header_code, false) && header_code, false) &&
flatbuffers::SaveFile((file_name + ".grpc.fb.cc").c_str(), flatbuffers::SaveFile((path + file_name + ".grpc.fb.cc").c_str(),
source_code, false); source_code, false);
} }
} // namespace flatbuffers } // namespace flatbuffers
#if defined(_MSC_VER)
#pragma warning(pop)
#endif

View File

@@ -15,6 +15,9 @@
*/ */
// independent from idl_parser, since this code is not needed for most clients // independent from idl_parser, since this code is not needed for most clients
#include <unordered_set>
#include <unordered_map>
#include <cassert>
#include "flatbuffers/flatbuffers.h" #include "flatbuffers/flatbuffers.h"
#include "flatbuffers/idl.h" #include "flatbuffers/idl.h"
@@ -23,9 +26,43 @@
namespace flatbuffers { namespace flatbuffers {
const std::string kGeneratedFileNamePostfix = "_generated";
struct JsLanguageParameters {
IDLOptions::Language language;
std::string file_extension;
};
struct ReexportDescription {
std::string symbol;
std::string source_namespace;
std::string target_namespace;
};
const JsLanguageParameters& GetJsLangParams(IDLOptions::Language lang) {
static JsLanguageParameters js_language_parameters[] = {
{
IDLOptions::kJs,
".js",
},
{
IDLOptions::kTs,
".ts",
},
};
if (lang == IDLOptions::kJs) {
return js_language_parameters[0];
} else {
assert(lang == IDLOptions::kTs);
return js_language_parameters[1];
}
}
static std::string GeneratedFileName(const std::string &path, static std::string GeneratedFileName(const std::string &path,
const std::string &file_name) { const std::string &file_name,
return path + file_name + "_generated.js"; const JsLanguageParameters &lang) {
return path + file_name + kGeneratedFileNamePostfix + lang.file_extension;
} }
namespace js { namespace js {
@@ -33,56 +70,127 @@ namespace js {
// and tables) and output them to a single file. // and tables) and output them to a single file.
class JsGenerator : public BaseGenerator { class JsGenerator : public BaseGenerator {
public: public:
typedef std::unordered_set<std::string> imported_fileset;
typedef std::unordered_multimap<std::string, ReexportDescription>
reexport_map;
JsGenerator(const Parser &parser, const std::string &path, JsGenerator(const Parser &parser, const std::string &path,
const std::string &file_name) const std::string &file_name)
: BaseGenerator(parser, path, file_name, "", "."){}; : BaseGenerator(parser, path, file_name, "", "."),
lang_(GetJsLangParams(parser_.opts.lang))
{
};
// Iterate through all definitions we haven't generate code for (enums, // Iterate through all definitions we haven't generate code for (enums,
// structs, and tables) and output them to a single file. // structs, and tables) and output them to a single file.
bool generate() { bool generate() {
if (IsEverythingGenerated()) return true; imported_fileset imported_files;
reexport_map reexports;
std::string enum_code, struct_code, exports_code, code; std::string enum_code, struct_code, import_code, exports_code, code;
generateEnums(&enum_code, &exports_code); generateEnums(&enum_code, &exports_code, reexports);
generateStructs(&struct_code, &exports_code); generateStructs(&struct_code, &exports_code, imported_files);
generateImportDependencies(&import_code, imported_files);
generateReexports(&import_code, reexports, imported_files);
code = code + "// " + FlatBuffersGeneratedWarning(); code = code + "// " + FlatBuffersGeneratedWarning() + "\n\n";
// Generate code for all the namespace declarations. // Generate code for all the namespace declarations.
GenNamespaces(&code, &exports_code); GenNamespaces(&code, &exports_code);
// Output the main declaration code from above. // Output the main declaration code from above.
code += import_code;
code += enum_code; code += enum_code;
code += struct_code; code += struct_code;
if (!exports_code.empty() && !parser_.opts.skip_js_exports) { if (lang_.language == IDLOptions::kJs && !exports_code.empty() &&
!parser_.opts.skip_js_exports) {
code += "// Exports for Node.js and RequireJS\n"; code += "// Exports for Node.js and RequireJS\n";
code += exports_code; code += exports_code;
} }
return SaveFile(GeneratedFileName(path_, file_name_).c_str(), code, false); return SaveFile(GeneratedFileName(path_, file_name_, lang_).c_str(), code,
false);
} }
private: private:
JsLanguageParameters lang_;
// Generate code for imports
void generateImportDependencies(std::string *code_ptr,
const imported_fileset &imported_files) {
std::string &code = *code_ptr;
for (auto it = imported_files.begin(); it != imported_files.end(); ++it) {
const auto &file = *it;
const auto basename =
flatbuffers::StripPath(flatbuffers::StripExtension(file));
if (basename != file_name_) {
const auto file_name = basename + kGeneratedFileNamePostfix;
code += GenPrefixedImport(file, file_name);
}
}
}
// Generate reexports, which might not have been explicitly imported using the
// "export import" trick
void generateReexports(std::string *code_ptr,
const reexport_map &reexports,
imported_fileset imported_files) {
if (!parser_.opts.reexport_ts_modules ||
lang_.language != IDLOptions::kTs) {
return;
}
std::string &code = *code_ptr;
for (auto it = reexports.begin(); it != reexports.end(); ++it) {
const auto &file = *it;
const auto basename =
flatbuffers::StripPath(flatbuffers::StripExtension(file.first));
if (basename != file_name_) {
const auto file_name = basename + kGeneratedFileNamePostfix;
if (imported_files.find(file.first) == imported_files.end()) {
code += GenPrefixedImport(file.first, file_name);
imported_files.emplace(file.first);
}
code += "export namespace " + file.second.target_namespace + " { \n";
code += "export import " + file.second.symbol + " = ";
code += GenFileNamespacePrefix(file.first) + "." +
file.second.source_namespace + "." + file.second.symbol +
"; }\n";
}
}
}
// Generate code for all enums. // Generate code for all enums.
void generateEnums(std::string *enum_code_ptr, void generateEnums(std::string *enum_code_ptr,
std::string *exports_code_ptr) { std::string *exports_code_ptr,
reexport_map &reexports) {
for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end(); for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
++it) { ++it) {
auto &enum_def = **it; auto &enum_def = **it;
GenEnum(enum_def, enum_code_ptr, exports_code_ptr); GenEnum(enum_def, enum_code_ptr, exports_code_ptr, reexports);
} }
} }
// Generate code for all structs. // Generate code for all structs.
void generateStructs(std::string *decl_code_ptr, void generateStructs(std::string *decl_code_ptr,
std::string *exports_code_ptr) { std::string *exports_code_ptr,
imported_fileset &imported_files) {
for (auto it = parser_.structs_.vec.begin(); for (auto it = parser_.structs_.vec.begin();
it != parser_.structs_.vec.end(); ++it) { it != parser_.structs_.vec.end(); ++it) {
auto &struct_def = **it; auto &struct_def = **it;
GenStruct(parser_, struct_def, decl_code_ptr, exports_code_ptr); GenStruct(parser_, struct_def, decl_code_ptr, exports_code_ptr,
imported_files);
} }
} }
void GenNamespaces(std::string *code_ptr, std::string *exports_ptr) { void GenNamespaces(std::string *code_ptr, std::string *exports_ptr) {
if (lang_.language == IDLOptions::kTs &&
parser_.opts.skip_flatbuffers_import) {
return;
}
std::set<std::string> namespaces; std::set<std::string> namespaces;
for (auto it = parser_.namespaces_.begin(); for (auto it = parser_.namespaces_.begin();
@@ -110,16 +218,23 @@ class JsGenerator : public BaseGenerator {
std::string &exports = *exports_ptr; std::string &exports = *exports_ptr;
for (auto it = sorted_namespaces.begin(); for (auto it = sorted_namespaces.begin();
it != sorted_namespaces.end(); it++) { it != sorted_namespaces.end(); it++) {
code += "/**\n * @const\n * @namespace\n */\n"; if (lang_.language == IDLOptions::kTs) {
if (it->find('.') == std::string::npos) { if (it->find('.') == std::string::npos) {
code += "var "; code += "import { flatbuffers } from \"./flatbuffers\"\n";
if(parser_.opts.use_goog_js_export_format) { break;
exports += "goog.exportSymbol('" + *it + "', " + *it + ");\n";
} else {
exports += "this." + *it + " = " + *it + ";\n";
} }
} else {
code += "/**\n * @const\n * @namespace\n */\n";
if (it->find('.') == std::string::npos) {
code += "var ";
if(parser_.opts.use_goog_js_export_format) {
exports += "goog.exportSymbol('" + *it + "', " + *it + ");\n";
} else {
exports += "this." + *it + " = " + *it + ";\n";
}
}
code += *it + " = " + *it + " || {};\n\n";
} }
code += *it + " = " + *it + " || {};\n\n";
} }
} }
@@ -169,21 +284,26 @@ static void GenDocComment(std::string *code_ptr,
// Generate an enum declaration and an enum string lookup table. // Generate an enum declaration and an enum string lookup table.
void GenEnum(EnumDef &enum_def, std::string *code_ptr, void GenEnum(EnumDef &enum_def, std::string *code_ptr,
std::string *exports_ptr) { std::string *exports_ptr, reexport_map &reexports) {
if (enum_def.generated) return; if (enum_def.generated) return;
std::string &code = *code_ptr; std::string &code = *code_ptr;
std::string &exports = *exports_ptr; std::string &exports = *exports_ptr;
GenDocComment(enum_def.doc_comment, code_ptr, "@enum"); GenDocComment(enum_def.doc_comment, code_ptr, "@enum");
if (enum_def.defined_namespace->components.empty()) { if (lang_.language == IDLOptions::kTs) {
code += "var "; code += "export namespace " + GetNameSpace(enum_def) + "{\n" +
if(parser_.opts.use_goog_js_export_format) { "export enum " + enum_def.name + "{\n";
exports += "goog.exportSymbol('" + enum_def.name + "', " + enum_def.name + } else {
");\n"; if (enum_def.defined_namespace->components.empty()) {
} else { code += "var ";
exports += "this." + enum_def.name + " = " + enum_def.name + ";\n"; if(parser_.opts.use_goog_js_export_format) {
exports += "goog.exportSymbol('" + enum_def.name + "', " +
enum_def.name + ");\n";
} else {
exports += "this." + enum_def.name + " = " + enum_def.name + ";\n";
}
} }
code += WrapInNameSpace(enum_def) + " = {\n";
} }
code += WrapInNameSpace(enum_def) + " = {\n";
for (auto it = enum_def.vals.vec.begin(); for (auto it = enum_def.vals.vec.begin();
it != enum_def.vals.vec.end(); ++it) { it != enum_def.vals.vec.end(); ++it) {
auto &ev = **it; auto &ev = **it;
@@ -193,10 +313,27 @@ void GenEnum(EnumDef &enum_def, std::string *code_ptr,
} }
GenDocComment(ev.doc_comment, code_ptr, "", " "); GenDocComment(ev.doc_comment, code_ptr, "", " ");
} }
code += " " + ev.name + ": " + NumToString(ev.value); code += " " + ev.name;
code += lang_.language == IDLOptions::kTs ? "= " : ": ";
code += NumToString(ev.value);
code += (it + 1) != enum_def.vals.vec.end() ? ",\n" : "\n"; code += (it + 1) != enum_def.vals.vec.end() ? ",\n" : "\n";
if (ev.union_type.struct_def) {
ReexportDescription desc = {
ev.name,
GetNameSpace(*ev.union_type.struct_def),
GetNameSpace(enum_def)
};
reexports.insert(std::make_pair(ev.union_type.struct_def->file,
std::move(desc)));
}
}
if (lang_.language == IDLOptions::kTs) {
code += "}};\n\n";
} else {
code += "};\n\n";
} }
code += "};\n\n";
} }
static std::string GenType(const Type &type) { static std::string GenType(const Type &type) {
@@ -244,7 +381,12 @@ std::string GenDefaultValue(const Value &value, const std::string &context) {
if (value.type.enum_def) { if (value.type.enum_def) {
if (auto val = value.type.enum_def->ReverseLookup( if (auto val = value.type.enum_def->ReverseLookup(
atoi(value.constant.c_str()), false)) { atoi(value.constant.c_str()), false)) {
return WrapInNameSpace(*value.type.enum_def) + "." + val->name; if (lang_.language == IDLOptions::kTs) {
return GenPrefixedTypeName(WrapInNameSpace(*value.type.enum_def),
value.type.enum_def->file) + "." + val->name;
} else {
return WrapInNameSpace(*value.type.enum_def) + "." + val->name;
}
} else { } else {
return "/** @type {" + WrapInNameSpace(*value.type.enum_def) + "} */ (" return "/** @type {" + WrapInNameSpace(*value.type.enum_def) + "} */ ("
+ value.constant + ")"; + value.constant + ")";
@@ -270,13 +412,16 @@ std::string GenDefaultValue(const Value &value, const std::string &context) {
} }
} }
std::string GenTypeName(const Type &type, bool input) { std::string GenTypeName(const Type &type, bool input, bool allowNull = false) {
if (!input) { if (!input) {
if (type.base_type == BASE_TYPE_STRING) { if (type.base_type == BASE_TYPE_STRING || type.base_type == BASE_TYPE_STRUCT) {
return "string|Uint8Array"; std::string name;
} if (type.base_type == BASE_TYPE_STRING) {
if (type.base_type == BASE_TYPE_STRUCT) { name = "string|Uint8Array";
return WrapInNameSpace(*type.struct_def); } else {
name = WrapInNameSpace(*type.struct_def);
}
return (allowNull) ? (name + "|null") : (name);
} }
} }
@@ -322,6 +467,28 @@ static std::string MaybeScale(T value) {
return value != 1 ? " * " + NumToString(value) : ""; return value != 1 ? " * " + NumToString(value) : "";
} }
static std::string GenFileNamespacePrefix(const std::string &file) {
return "NS" + std::to_string(
static_cast<unsigned long long>(std::hash<std::string>()(file)));
}
static std::string GenPrefixedImport(const std::string &full_file_name,
const std::string &base_file_name) {
return "import * as "+ GenFileNamespacePrefix(full_file_name) +
" from \"./" + base_file_name + "\";\n";
}
// Adds a source-dependent prefix, for of import * statements.
std::string GenPrefixedTypeName(const std::string &typeName,
const std::string &file) {
const auto basename =
flatbuffers::StripPath(flatbuffers::StripExtension(file));
if (basename == file_name_) {
return typeName;
}
return GenFileNamespacePrefix(file) + "." + typeName;
}
void GenStructArgs(const StructDef &struct_def, void GenStructArgs(const StructDef &struct_def,
std::string *annotations, std::string *annotations,
std::string *arguments, std::string *arguments,
@@ -338,7 +505,13 @@ void GenStructArgs(const StructDef &struct_def,
} else { } else {
*annotations += "@param {" + GenTypeName(field.value.type, true); *annotations += "@param {" + GenTypeName(field.value.type, true);
*annotations += "} " + nameprefix + field.name + "\n"; *annotations += "} " + nameprefix + field.name + "\n";
*arguments += ", " + nameprefix + field.name;
if (lang_.language == IDLOptions::kTs) {
*arguments += ", " + nameprefix + field.name + ": " +
GenTypeName(field.value.type, true);
} else {
*arguments += ", " + nameprefix + field.name;
}
} }
} }
} }
@@ -373,37 +546,59 @@ static void GenStructBody(const StructDef &struct_def,
} }
// Generate an accessor struct with constructor for a flatbuffers struct. // Generate an accessor struct with constructor for a flatbuffers struct.
void GenStruct(const Parser &parser, StructDef &struct_def, std::string *code_ptr, std::string *exports_ptr) { void GenStruct(const Parser &parser, StructDef &struct_def,
std::string *code_ptr, std::string *exports_ptr,
imported_fileset &imported_files) {
if (struct_def.generated) return; if (struct_def.generated) return;
std::string &code = *code_ptr; std::string &code = *code_ptr;
std::string &exports = *exports_ptr; std::string &exports = *exports_ptr;
std::string object_name;
// Emit constructor // Emit constructor
bool isStatement = struct_def.defined_namespace->components.empty(); if (lang_.language == IDLOptions::kTs) {
std::string object_name = WrapInNameSpace(struct_def); object_name = struct_def.name;
GenDocComment(struct_def.doc_comment, code_ptr, "@constructor"); std::string object_namespace = GetNameSpace(struct_def);
if (isStatement) { GenDocComment(struct_def.doc_comment, code_ptr, "@constructor");
if(parser_.opts.use_goog_js_export_format) { code += "export namespace " + object_namespace + "{\n";
exports += "goog.exportSymbol('" + struct_def.name + "', " + code += "export class " + struct_def.name;
struct_def.name + ");\n"; code += " {\n";
} else { code += " /**\n";
exports += "this." + struct_def.name + " = " + struct_def.name + ";\n"; code += " * @type {flatbuffers.ByteBuffer}\n";
} code += " */\n";
code += "function " + object_name; code += " bb: flatbuffers.ByteBuffer;\n";
code += "\n";
code += " /**\n";
code += " * @type {number}\n";
code += " */\n";
code += " bb_pos:number = 0;\n";
} else { } else {
code += object_name + " = function"; bool isStatement = struct_def.defined_namespace->components.empty();
object_name = WrapInNameSpace(struct_def);
GenDocComment(struct_def.doc_comment, code_ptr, "@constructor");
if (isStatement) {
if(parser_.opts.use_goog_js_export_format) {
exports += "goog.exportSymbol('" + struct_def.name + "', " +
struct_def.name + ");\n";
} else {
exports += "this." + struct_def.name + " = " + struct_def.name + ";\n";
}
code += "function " + object_name;
} else {
code += object_name + " = function";
}
code += "() {\n";
code += " /**\n";
code += " * @type {flatbuffers.ByteBuffer}\n";
code += " */\n";
code += " this.bb = null;\n";
code += "\n";
code += " /**\n";
code += " * @type {number}\n";
code += " */\n";
code += " this.bb_pos = 0;\n";
code += isStatement ? "}\n\n" : "};\n\n";
} }
code += "() {\n";
code += " /**\n";
code += " * @type {flatbuffers.ByteBuffer}\n";
code += " */\n";
code += " this.bb = null;\n";
code += "\n";
code += " /**\n";
code += " * @type {number}\n";
code += " */\n";
code += " this.bb_pos = 0;\n";
code += isStatement ? "}\n\n" : "};\n\n";
// Generate the __init method that sets the field in a pre-existing // Generate the __init method that sets the field in a pre-existing
// accessor object. This is to allow object reuse. // accessor object. This is to allow object reuse.
@@ -412,7 +607,14 @@ void GenStruct(const Parser &parser, StructDef &struct_def, std::string *code_pt
code += " * @param {flatbuffers.ByteBuffer} bb\n"; code += " * @param {flatbuffers.ByteBuffer} bb\n";
code += " * @returns {" + object_name + "}\n"; code += " * @returns {" + object_name + "}\n";
code += " */\n"; code += " */\n";
code += object_name + ".prototype.__init = function(i, bb) {\n";
if (lang_.language == IDLOptions::kTs) {
code += "__init(i:number, bb:flatbuffers.ByteBuffer):" + object_name +
" {\n";
} else {
code += object_name + ".prototype.__init = function(i, bb) {\n";
}
code += " this.bb_pos = i;\n"; code += " this.bb_pos = i;\n";
code += " this.bb = bb;\n"; code += " this.bb = bb;\n";
code += " return this;\n"; code += " return this;\n";
@@ -425,8 +627,14 @@ void GenStruct(const Parser &parser, StructDef &struct_def, std::string *code_pt
"@param {flatbuffers.ByteBuffer} bb\n" "@param {flatbuffers.ByteBuffer} bb\n"
"@param {" + object_name + "=} obj\n" "@param {" + object_name + "=} obj\n"
"@returns {" + object_name + "}"); "@returns {" + object_name + "}");
code += object_name + ".getRootAs" + struct_def.name; if (lang_.language == IDLOptions::kTs) {
code += " = function(bb, obj) {\n"; code += "static getRootAs" + struct_def.name;
code += "(bb:flatbuffers.ByteBuffer, obj?:" + object_name + "):" +
object_name + " {\n";
} else {
code += object_name + ".getRootAs" + struct_def.name;
code += " = function(bb, obj) {\n";
}
code += " return (obj || new " + object_name; code += " return (obj || new " + object_name;
code += ").__init(bb.readInt32(bb.position()) + bb.position(), bb);\n"; code += ").__init(bb.readInt32(bb.position()) + bb.position(), bb);\n";
code += "};\n\n"; code += "};\n\n";
@@ -437,7 +645,13 @@ void GenStruct(const Parser &parser, StructDef &struct_def, std::string *code_pt
GenDocComment(code_ptr, GenDocComment(code_ptr,
"@param {flatbuffers.ByteBuffer} bb\n" "@param {flatbuffers.ByteBuffer} bb\n"
"@returns {boolean}"); "@returns {boolean}");
code += object_name + ".bufferHasIdentifier = function(bb) {\n"; if (lang_.language == IDLOptions::kTs) {
code +=
"static bufferHasIdentifier(bb:flatbuffers.ByteBuffer):boolean {\n";
} else {
code += object_name + ".bufferHasIdentifier = function(bb) {\n";
}
code += " return bb.__has_identifier('" + parser_.file_identifier_; code += " return bb.__has_identifier('" + parser_.file_identifier_;
code += "');\n};\n\n"; code += "');\n};\n\n";
} }
@@ -457,13 +671,33 @@ void GenStruct(const Parser &parser, StructDef &struct_def, std::string *code_pt
GenDocComment(field.doc_comment, code_ptr, GenDocComment(field.doc_comment, code_ptr,
std::string(field.value.type.base_type == BASE_TYPE_STRING ? std::string(field.value.type.base_type == BASE_TYPE_STRING ?
"@param {flatbuffers.Encoding=} optionalEncoding\n" : "") + "@param {flatbuffers.Encoding=} optionalEncoding\n" : "") +
"@returns {" + GenTypeName(field.value.type, false) + "}"); "@returns {" + GenTypeName(field.value.type, false, true) + "}");
code += object_name + ".prototype." + MakeCamel(field.name, false); if (lang_.language == IDLOptions::kTs) {
code += " = function("; std::string prefix = MakeCamel(field.name, false) + "(";
if (field.value.type.base_type == BASE_TYPE_STRING) { if (field.value.type.base_type == BASE_TYPE_STRING) {
code += "optionalEncoding"; code += prefix + "):string|null\n";
code += prefix + "optionalEncoding:flatbuffers.Encoding"+"):" +
GenTypeName(field.value.type, false, true)+"\n";
code += prefix + "optionalEncoding?:any";
} else {
code += prefix;
}
if (field.value.type.enum_def) {
code += "):" +
GenPrefixedTypeName(GenTypeName(field.value.type, false, true),
field.value.type.enum_def->file) + " {\n";
} else {
code += "):" + GenTypeName(field.value.type, false, true) + " {\n";
}
} else {
code += object_name + ".prototype." + MakeCamel(field.name, false);
code += " = function(";
if (field.value.type.base_type == BASE_TYPE_STRING) {
code += "optionalEncoding";
}
code += ") {\n";
} }
code += ") {\n";
if (struct_def.fixed) { if (struct_def.fixed) {
code += " return " + GenGetter(field.value.type, "(this.bb_pos" + code += " return " + GenGetter(field.value.type, "(this.bb_pos" +
MaybeAdd(field.value.offset) + ")") + ";\n"; MaybeAdd(field.value.offset) + ")") + ";\n";
@@ -484,9 +718,16 @@ void GenStruct(const Parser &parser, StructDef &struct_def, std::string *code_pt
case BASE_TYPE_STRUCT: { case BASE_TYPE_STRUCT: {
auto type = WrapInNameSpace(*field.value.type.struct_def); auto type = WrapInNameSpace(*field.value.type.struct_def);
GenDocComment(field.doc_comment, code_ptr, GenDocComment(field.doc_comment, code_ptr,
"@param {" + type + "=} obj\n@returns {" + type + "}"); "@param {" + type + "=} obj\n@returns {" + type + "|null}");
code += object_name + ".prototype." + MakeCamel(field.name, false); if (lang_.language == IDLOptions::kTs) {
code += " = function(obj) {\n"; type = GenPrefixedTypeName(type, field.value.type.struct_def->file);
code += MakeCamel(field.name, false);
code += "(obj?:" + type + "):" + type + "|null {\n";
} else {
code += object_name + ".prototype." + MakeCamel(field.name, false);
code += " = function(obj) {\n";
}
if (struct_def.fixed) { if (struct_def.fixed) {
code += " return (obj || new " + type; code += " return (obj || new " + type;
code += ").__init(this.bb_pos"; code += ").__init(this.bb_pos";
@@ -498,6 +739,11 @@ void GenStruct(const Parser &parser, StructDef &struct_def, std::string *code_pt
: "this.bb.__indirect(this.bb_pos + offset)"; : "this.bb.__indirect(this.bb_pos + offset)";
code += ", this.bb) : null;\n"; code += ", this.bb) : null;\n";
} }
if (lang_.language == IDLOptions::kTs) {
imported_files.insert(field.value.type.struct_def->file);
}
break; break;
} }
@@ -515,14 +761,34 @@ void GenStruct(const Parser &parser, StructDef &struct_def, std::string *code_pt
} }
GenDocComment(field.doc_comment, code_ptr, args + GenDocComment(field.doc_comment, code_ptr, args +
"@returns {" + vectortypename + "}"); "@returns {" + vectortypename + "}");
code += object_name + ".prototype." + MakeCamel(field.name, false); if (lang_.language == IDLOptions::kTs) {
code += " = function(index"; std::string prefix = MakeCamel(field.name, false);
if (vectortype.base_type == BASE_TYPE_STRUCT) { prefix += "(index: number";
code += ", obj"; if (vectortype.base_type == BASE_TYPE_STRUCT) {
} else if (vectortype.base_type == BASE_TYPE_STRING) { vectortypename = GenPrefixedTypeName(vectortypename,
code += ", optionalEncoding"; vectortype.struct_def->file);
code += prefix + ", obj?:" + vectortypename;
imported_files.insert(vectortype.struct_def->file);
} else if (vectortype.base_type == BASE_TYPE_STRING) {
code += prefix + "):string\n";
code += prefix + ",optionalEncoding:flatbuffers.Encoding" + "):" +
vectortypename + "\n";
code += prefix + ",optionalEncoding?:any";
} else {
code += prefix;
}
code += "):" + vectortypename + "|null {\n";
} else {
code += object_name + ".prototype." + MakeCamel(field.name, false);
code += " = function(index";
if (vectortype.base_type == BASE_TYPE_STRUCT) {
code += ", obj";
} else if (vectortype.base_type == BASE_TYPE_STRING) {
code += ", optionalEncoding";
}
code += ") {\n";
} }
code += ") {\n";
if (vectortype.base_type == BASE_TYPE_STRUCT) { if (vectortype.base_type == BASE_TYPE_STRUCT) {
code += offset_prefix + "(obj || new " + vectortypename; code += offset_prefix + "(obj || new " + vectortypename;
code += ").__init("; code += ").__init(";
@@ -561,8 +827,14 @@ void GenStruct(const Parser &parser, StructDef &struct_def, std::string *code_pt
GenDocComment(field.doc_comment, code_ptr, GenDocComment(field.doc_comment, code_ptr,
"@param {flatbuffers.Table} obj\n" "@param {flatbuffers.Table} obj\n"
"@returns {?flatbuffers.Table}"); "@returns {?flatbuffers.Table}");
code += object_name + ".prototype." + MakeCamel(field.name, false); if (lang_.language == IDLOptions::kTs) {
code += " = function(obj) {\n"; code += MakeCamel(field.name, false);
code += "<T extends flatbuffers.Table>(obj:T):T|null {\n";
} else {
code += object_name + ".prototype." + MakeCamel(field.name, false);
code += " = function(obj) {\n";
}
code += offset_prefix + GenGetter(field.value.type, code += offset_prefix + GenGetter(field.value.type,
"(obj, this.bb_pos + offset)") + " : null;\n"; "(obj, this.bb_pos + offset)") + " : null;\n";
break; break;
@@ -581,16 +853,41 @@ void GenStruct(const Parser &parser, StructDef &struct_def, std::string *code_pt
// Adds the mutable scalar value to the output // Adds the mutable scalar value to the output
if (IsScalar(field.value.type.base_type) && parser.opts.mutable_buffer) { if (IsScalar(field.value.type.base_type) && parser.opts.mutable_buffer) {
std::string annotations = "@param {" + GenTypeName(field.value.type, true) + "} value\n"; std::string annotations =
"@param {" + GenTypeName(field.value.type, true) + "} value\n";
GenDocComment(code_ptr, annotations + GenDocComment(code_ptr, annotations +
"@returns {boolean}"); "@returns {boolean}");
code += object_name + ".prototype.mutate_" + field.name + " = function(value) {\n"; if (lang_.language == IDLOptions::kTs) {
code += " var offset = this.bb.__offset(this.bb_pos, " + NumToString(field.value.offset) + ");\n\n"; std::string type;
if (field.value.type.enum_def) {
type = GenPrefixedTypeName(GenTypeName(field.value.type, true),
field.value.type.enum_def->file);
} else {
type = GenTypeName(field.value.type, true);
}
code += "mutate_" + field.name + "(value:" + type + "):boolean {\n";
} else {
code += object_name + ".prototype.mutate_" + field.name +
" = function(value) {\n";
}
code += " var offset = this.bb.__offset(this.bb_pos, " +
NumToString(field.value.offset) + ");\n\n";
code += " if (offset === 0) {\n"; code += " if (offset === 0) {\n";
code += " return false;\n"; code += " return false;\n";
code += " }\n\n"; code += " }\n\n";
code += " this.bb.write" + MakeCamel(GenType(field.value.type)) + "(this.bb_pos + offset, value);\n";
// special case for bools, which are treated as uint8
code += " this.bb.write" + MakeCamel(GenType(field.value.type)) +
"(this.bb_pos + offset, ";
if (field.value.type.base_type == BASE_TYPE_BOOL &&
lang_.language == IDLOptions::kTs) {
code += "+";
}
code += "value);\n";
code += " return true;\n"; code += " return true;\n";
code += "};\n\n"; code += "};\n\n";
@@ -605,8 +902,14 @@ void GenStruct(const Parser &parser, StructDef &struct_def, std::string *code_pt
if (field.value.type.base_type == BASE_TYPE_VECTOR) { if (field.value.type.base_type == BASE_TYPE_VECTOR) {
// Emit a length helper // Emit a length helper
GenDocComment(code_ptr, "@returns {number}"); GenDocComment(code_ptr, "@returns {number}");
code += object_name + ".prototype." + MakeCamel(field.name, false); if (lang_.language == IDLOptions::kTs) {
code += "Length = function() {\n" + offset_prefix; code += MakeCamel(field.name, false);
code += "Length():number {\n" + offset_prefix;
} else {
code += object_name + ".prototype." + MakeCamel(field.name, false);
code += "Length = function() {\n" + offset_prefix;
}
code += "this.bb.__vector_len(this.bb_pos + offset) : 0;\n};\n\n"; code += "this.bb.__vector_len(this.bb_pos + offset) : 0;\n};\n\n";
if(parser_.opts.use_goog_js_export_format) { if(parser_.opts.use_goog_js_export_format) {
@@ -619,8 +922,16 @@ void GenStruct(const Parser &parser, StructDef &struct_def, std::string *code_pt
auto vectorType = field.value.type.VectorType(); auto vectorType = field.value.type.VectorType();
if (IsScalar(vectorType.base_type) && !IsLong(vectorType.base_type)) { if (IsScalar(vectorType.base_type) && !IsLong(vectorType.base_type)) {
GenDocComment(code_ptr, "@returns {" + GenType(vectorType) + "Array}"); GenDocComment(code_ptr, "@returns {" + GenType(vectorType) + "Array}");
code += object_name + ".prototype." + MakeCamel(field.name, false);
code += "Array = function() {\n" + offset_prefix; if (lang_.language == IDLOptions::kTs) {
code += MakeCamel(field.name, false);
code += "Array():" + GenType(vectorType) + "Array|null {\n" +
offset_prefix;
} else {
code += object_name + ".prototype." + MakeCamel(field.name, false);
code += "Array = function() {\n" + offset_prefix;
}
code += "new " + GenType(vectorType) + "Array(this.bb.bytes().buffer, " code += "new " + GenType(vectorType) + "Array(this.bb.bytes().buffer, "
"this.bb.bytes().byteOffset + this.bb.__vector(this.bb_pos + offset), " "this.bb.bytes().byteOffset + this.bb.__vector(this.bb_pos + offset), "
"this.bb.__vector_len(this.bb_pos + offset)) : null;\n};\n\n"; "this.bb.__vector_len(this.bb_pos + offset)) : null;\n};\n\n";
@@ -641,16 +952,30 @@ void GenStruct(const Parser &parser, StructDef &struct_def, std::string *code_pt
GenStructArgs(struct_def, &annotations, &arguments, ""); GenStructArgs(struct_def, &annotations, &arguments, "");
GenDocComment(code_ptr, annotations + GenDocComment(code_ptr, annotations +
"@returns {flatbuffers.Offset}"); "@returns {flatbuffers.Offset}");
code += object_name + ".create" + struct_def.name + " = function(builder";
code += arguments + ") {\n"; if (lang_.language == IDLOptions::kTs) {
code += "static create" + struct_def.name + "(builder:flatbuffers.Builder";
code += arguments + "):flatbuffers.Offset {\n";
} else {
code += object_name + ".create" + struct_def.name + " = function(builder";
code += arguments + ") {\n";
}
GenStructBody(struct_def, &code, ""); GenStructBody(struct_def, &code, "");
code += " return builder.offset();\n};\n\n"; code += " return builder.offset();\n};\n\n";
} else { } else {
// Generate a method to start building a new object // Generate a method to start building a new object
GenDocComment(code_ptr, GenDocComment(code_ptr,
"@param {flatbuffers.Builder} builder"); "@param {flatbuffers.Builder} builder");
code += object_name + ".start" + struct_def.name;
code += " = function(builder) {\n"; if (lang_.language == IDLOptions::kTs) {
code += "static start" + struct_def.name;
code += "(builder:flatbuffers.Builder) {\n";
} else {
code += object_name + ".start" + struct_def.name;
code += " = function(builder) {\n";
}
code += " builder.startObject(" + NumToString( code += " builder.startObject(" + NumToString(
struct_def.fields.vec.size()) + ");\n"; struct_def.fields.vec.size()) + ");\n";
code += "};\n\n"; code += "};\n\n";
@@ -670,8 +995,24 @@ void GenStruct(const Parser &parser, StructDef &struct_def, std::string *code_pt
"@param {flatbuffers.Builder} builder\n" "@param {flatbuffers.Builder} builder\n"
"@param {" + GenTypeName(field.value.type, true) + "} " + "@param {" + GenTypeName(field.value.type, true) + "} " +
argname); argname);
code += object_name + ".add" + MakeCamel(field.name);
code += " = function(builder, " + argname + ") {\n"; if (lang_.language == IDLOptions::kTs) {
std::string argType;
if (field.value.type.enum_def) {
argType = GenPrefixedTypeName(GenTypeName(field.value.type, true),
field.value.type.enum_def->file);
} else {
argType = GenTypeName(field.value.type, true);
}
code += "static add" + MakeCamel(field.name);
code += "(builder:flatbuffers.Builder, " + argname + ":" + argType +
") {\n";
} else {
code += object_name + ".add" + MakeCamel(field.name);
code += " = function(builder, " + argname + ") {\n";
}
code += " builder.addField" + GenWriteMethod(field.value.type) + "("; code += " builder.addField" + GenWriteMethod(field.value.type) + "(";
code += NumToString(it - struct_def.fields.vec.begin()) + ", "; code += NumToString(it - struct_def.fields.vec.begin()) + ", ";
if (field.value.type.base_type == BASE_TYPE_BOOL) { if (field.value.type.base_type == BASE_TYPE_BOOL) {
@@ -700,8 +1041,20 @@ void GenStruct(const Parser &parser, StructDef &struct_def, std::string *code_pt
"@param {Array.<" + GenTypeName(vector_type, true) + "@param {Array.<" + GenTypeName(vector_type, true) +
">} data\n" ">} data\n"
"@returns {flatbuffers.Offset}"); "@returns {flatbuffers.Offset}");
code += object_name + ".create" + MakeCamel(field.name);
code += "Vector = function(builder, data) {\n"; if (lang_.language == IDLOptions::kTs) {
code += "static create" + MakeCamel(field.name);
std::string type = GenTypeName(vector_type, true) + "[]";
if (type == "number[]") {
type += " | Uint8Array";
}
code += "Vector(builder:flatbuffers.Builder, data:" + type +
"):flatbuffers.Offset {\n";
} else {
code += object_name + ".create" + MakeCamel(field.name);
code += "Vector = function(builder, data) {\n";
}
code += " builder.startVector(" + NumToString(elem_size); code += " builder.startVector(" + NumToString(elem_size);
code += ", data.length, " + NumToString(alignment) + ");\n"; code += ", data.length, " + NumToString(alignment) + ");\n";
code += " for (var i = data.length - 1; i >= 0; i--) {\n"; code += " for (var i = data.length - 1; i >= 0; i--) {\n";
@@ -719,8 +1072,15 @@ void GenStruct(const Parser &parser, StructDef &struct_def, std::string *code_pt
GenDocComment(code_ptr, GenDocComment(code_ptr,
"@param {flatbuffers.Builder} builder\n" "@param {flatbuffers.Builder} builder\n"
"@param {number} numElems"); "@param {number} numElems");
code += object_name + ".start" + MakeCamel(field.name);
code += "Vector = function(builder, numElems) {\n"; if (lang_.language == IDLOptions::kTs) {
code += "static start" + MakeCamel(field.name);
code += "Vector(builder:flatbuffers.Builder, numElems:number) {\n";
} else {
code += object_name + ".start" + MakeCamel(field.name);
code += "Vector = function(builder, numElems) {\n";
}
code += " builder.startVector(" + NumToString(elem_size); code += " builder.startVector(" + NumToString(elem_size);
code += ", numElems, " + NumToString(alignment) + ");\n"; code += ", numElems, " + NumToString(alignment) + ");\n";
code += "};\n\n"; code += "};\n\n";
@@ -731,8 +1091,15 @@ void GenStruct(const Parser &parser, StructDef &struct_def, std::string *code_pt
GenDocComment(code_ptr, GenDocComment(code_ptr,
"@param {flatbuffers.Builder} builder\n" "@param {flatbuffers.Builder} builder\n"
"@returns {flatbuffers.Offset}"); "@returns {flatbuffers.Offset}");
code += object_name + ".end" + struct_def.name;
code += " = function(builder) {\n"; if (lang_.language == IDLOptions::kTs) {
code += "static end" + struct_def.name;
code += "(builder:flatbuffers.Builder):flatbuffers.Offset {\n";
} else {
code += object_name + ".end" + struct_def.name;
code += " = function(builder) {\n";
}
code += " var offset = builder.endObject();\n"; code += " var offset = builder.endObject();\n";
for (auto it = struct_def.fields.vec.begin(); for (auto it = struct_def.fields.vec.begin();
it != struct_def.fields.vec.end(); ++it) { it != struct_def.fields.vec.end(); ++it) {
@@ -751,8 +1118,15 @@ void GenStruct(const Parser &parser, StructDef &struct_def, std::string *code_pt
GenDocComment(code_ptr, GenDocComment(code_ptr,
"@param {flatbuffers.Builder} builder\n" "@param {flatbuffers.Builder} builder\n"
"@param {flatbuffers.Offset} offset"); "@param {flatbuffers.Offset} offset");
code += object_name + ".finish" + struct_def.name + "Buffer";
code += " = function(builder, offset) {\n"; if (lang_.language == IDLOptions::kTs) {
code += "static finish" + struct_def.name + "Buffer";
code += "(builder:flatbuffers.Builder, offset:flatbuffers.Offset) {\n";
} else {
code += object_name + ".finish" + struct_def.name + "Buffer";
code += " = function(builder, offset) {\n";
}
code += " builder.finish(offset"; code += " builder.finish(offset";
if (!parser_.file_identifier_.empty()) { if (!parser_.file_identifier_.empty()) {
code += ", '" + parser_.file_identifier_ + "'"; code += ", '" + parser_.file_identifier_ + "'";
@@ -761,6 +1135,10 @@ void GenStruct(const Parser &parser, StructDef &struct_def, std::string *code_pt
code += "};\n\n"; code += "};\n\n";
} }
} }
if (lang_.language == IDLOptions::kTs) {
code += "}\n}\n";
}
} }
}; };
} // namespace js } // namespace js
@@ -774,15 +1152,19 @@ bool GenerateJS(const Parser &parser, const std::string &path,
std::string JSMakeRule(const Parser &parser, std::string JSMakeRule(const Parser &parser,
const std::string &path, const std::string &path,
const std::string &file_name) { const std::string &file_name) {
assert(parser.opts.lang <= IDLOptions::kMAX);
const auto &lang = GetJsLangParams(parser.opts.lang);
std::string filebase = flatbuffers::StripPath( std::string filebase = flatbuffers::StripPath(
flatbuffers::StripExtension(file_name)); flatbuffers::StripExtension(file_name));
std::string make_rule = GeneratedFileName(path, filebase) + ": "; std::string make_rule = GeneratedFileName(path, filebase, lang) + ": ";
auto included_files = parser.GetIncludedFilesRecursive(file_name); auto included_files = parser.GetIncludedFilesRecursive(file_name);
for (auto it = included_files.begin(); for (auto it = included_files.begin();
it != included_files.end(); ++it) { it != included_files.end(); ++it) {
make_rule += " " + *it; make_rule += " " + *it;
} }
return make_rule; return make_rule;
} }
} // namespace flatbuffers } // namespace flatbuffers

View File

@@ -66,7 +66,7 @@ namespace php {
const bool needs_imports, std::string *code_ptr) { const bool needs_imports, std::string *code_ptr) {
std::string &code = *code_ptr; std::string &code = *code_ptr;
code += "<?php\n"; code += "<?php\n";
code = code + "// " + FlatBuffersGeneratedWarning(); code = code + "// " + FlatBuffersGeneratedWarning() + "\n\n";
code += "namespace " + name_space_name + ";\n\n"; code += "namespace " + name_space_name + ";\n\n";
if (needs_imports) { if (needs_imports) {

View File

@@ -630,7 +630,7 @@ class PythonGenerator : public BaseGenerator {
void BeginFile(const std::string name_space_name, const bool needs_imports, void BeginFile(const std::string name_space_name, const bool needs_imports,
std::string *code_ptr) { std::string *code_ptr) {
std::string &code = *code_ptr; std::string &code = *code_ptr;
code = code + "# " + FlatBuffersGeneratedWarning(); code = code + "# " + FlatBuffersGeneratedWarning() + "\n\n";
code += "# namespace: " + name_space_name + "\n\n"; code += "# namespace: " + name_space_name + "\n\n";
if (needs_imports) { if (needs_imports) {
code += "import flatbuffers\n\n"; code += "import flatbuffers\n\n";

View File

@@ -19,6 +19,7 @@
#include "flatbuffers/flatbuffers.h" #include "flatbuffers/flatbuffers.h"
#include "flatbuffers/idl.h" #include "flatbuffers/idl.h"
#include "flatbuffers/util.h" #include "flatbuffers/util.h"
#include "flatbuffers/flexbuffers.h"
namespace flatbuffers { namespace flatbuffers {
@@ -49,7 +50,7 @@ void OutputIdentifier(const std::string &name, const IDLOptions &opts,
// for a single FlatBuffer value into JSON format. // for a single FlatBuffer value into JSON format.
// The general case for scalars: // The general case for scalars:
template<typename T> bool Print(T val, Type type, int /*indent*/, template<typename T> bool Print(T val, Type type, int /*indent*/,
StructDef * /*union_sd*/, Type * /*union_type*/,
const IDLOptions &opts, const IDLOptions &opts,
std::string *_text) { std::string *_text) {
std::string &text = *_text; std::string &text = *_text;
@@ -79,7 +80,7 @@ template<typename T> bool PrintVector(const Vector<T> &v, Type type,
text += NewLine(opts); text += NewLine(opts);
for (uoffset_t i = 0; i < v.size(); i++) { for (uoffset_t i = 0; i < v.size(); i++) {
if (i) { if (i) {
text += ","; if (!opts.protobuf_ascii_alike) text += ",";
text += NewLine(opts); text += NewLine(opts);
} }
text.append(indent + Indent(opts), ' '); text.append(indent + Indent(opts), ' ');
@@ -101,90 +102,19 @@ template<typename T> bool PrintVector(const Vector<T> &v, Type type,
return true; return true;
} }
static bool EscapeString(const String &s, std::string *_text, const IDLOptions& opts) {
std::string &text = *_text;
text += "\"";
for (uoffset_t i = 0; i < s.size(); i++) {
char c = s[i];
switch (c) {
case '\n': text += "\\n"; break;
case '\t': text += "\\t"; break;
case '\r': text += "\\r"; break;
case '\b': text += "\\b"; break;
case '\f': text += "\\f"; break;
case '\"': text += "\\\""; break;
case '\\': text += "\\\\"; break;
default:
if (c >= ' ' && c <= '~') {
text += c;
} else {
// Not printable ASCII data. Let's see if it's valid UTF-8 first:
const char *utf8 = s.c_str() + i;
int ucc = FromUTF8(&utf8);
if (ucc < 0) {
if (opts.allow_non_utf8) {
text += "\\x";
text += IntToStringHex(static_cast<uint8_t>(c), 2);
} else {
// There are two cases here:
//
// 1) We reached here by parsing an IDL file. In that case,
// we previously checked for non-UTF-8, so we shouldn't reach
// here.
//
// 2) We reached here by someone calling GenerateText()
// on a previously-serialized flatbuffer. The data might have
// non-UTF-8 Strings, or might be corrupt.
//
// In both cases, we have to give up and inform the caller
// they have no JSON.
return false;
}
} else {
if (ucc <= 0xFFFF) {
// Parses as Unicode within JSON's \uXXXX range, so use that.
text += "\\u";
text += IntToStringHex(ucc, 4);
} else if (ucc <= 0x10FFFF) {
// Encode Unicode SMP values to a surrogate pair using two \u escapes.
uint32_t base = ucc - 0x10000;
auto high_surrogate = (base >> 10) + 0xD800;
auto low_surrogate = (base & 0x03FF) + 0xDC00;
text += "\\u";
text += IntToStringHex(high_surrogate, 4);
text += "\\u";
text += IntToStringHex(low_surrogate, 4);
}
// Skip past characters recognized.
i = static_cast<uoffset_t>(utf8 - s.c_str() - 1);
}
}
break;
}
}
text += "\"";
return true;
}
// Specialization of Print above for pointer types. // Specialization of Print above for pointer types.
template<> bool Print<const void *>(const void *val, template<> bool Print<const void *>(const void *val,
Type type, int indent, Type type, int indent,
StructDef *union_sd, Type *union_type,
const IDLOptions &opts, const IDLOptions &opts,
std::string *_text) { std::string *_text) {
switch (type.base_type) { switch (type.base_type) {
case BASE_TYPE_UNION: case BASE_TYPE_UNION:
// If this assert hits, you have an corrupt buffer, a union type field // If this assert hits, you have an corrupt buffer, a union type field
// was not present or was out of range. // was not present or was out of range.
assert(union_sd); assert(union_type);
if (!GenStruct(*union_sd, return Print<const void *>(val, *union_type, indent, nullptr, opts,
reinterpret_cast<const Table *>(val), _text);
indent,
opts,
_text)) {
return false;
}
break;
case BASE_TYPE_STRUCT: case BASE_TYPE_STRUCT:
if (!GenStruct(*type.struct_def, if (!GenStruct(*type.struct_def,
reinterpret_cast<const Table *>(val), reinterpret_cast<const Table *>(val),
@@ -195,7 +125,8 @@ template<> bool Print<const void *>(const void *val,
} }
break; break;
case BASE_TYPE_STRING: { case BASE_TYPE_STRING: {
if (!EscapeString(*reinterpret_cast<const String *>(val), _text, opts)) { auto s = reinterpret_cast<const String *>(val);
if (!EscapeString(s->c_str(), s->Length(), _text, opts.allow_non_utf8)) {
return false; return false;
} }
break; break;
@@ -236,7 +167,7 @@ template<typename T> static bool GenField(const FieldDef &fd,
// Generate text for non-scalar field. // Generate text for non-scalar field.
static bool GenFieldOffset(const FieldDef &fd, const Table *table, bool fixed, static bool GenFieldOffset(const FieldDef &fd, const Table *table, bool fixed,
int indent, StructDef *union_sd, int indent, Type *union_type,
const IDLOptions &opts, std::string *_text) { const IDLOptions &opts, std::string *_text) {
const void *val = nullptr; const void *val = nullptr;
if (fixed) { if (fixed) {
@@ -244,12 +175,17 @@ static bool GenFieldOffset(const FieldDef &fd, const Table *table, bool fixed,
assert(IsStruct(fd.value.type)); assert(IsStruct(fd.value.type));
val = reinterpret_cast<const Struct *>(table)-> val = reinterpret_cast<const Struct *>(table)->
GetStruct<const void *>(fd.value.offset); GetStruct<const void *>(fd.value.offset);
} else if (fd.flexbuffer) {
auto vec = table->GetPointer<const Vector<uint8_t> *>(fd.value.offset);
auto root = flexbuffers::GetRoot(vec->data(), vec->size());
root.ToString(true, false, *_text);
return true;
} else { } else {
val = IsStruct(fd.value.type) val = IsStruct(fd.value.type)
? table->GetStruct<const void *>(fd.value.offset) ? table->GetStruct<const void *>(fd.value.offset)
: table->GetPointer<const void *>(fd.value.offset); : table->GetPointer<const void *>(fd.value.offset);
} }
return Print(val, fd.value.type, indent, union_sd, opts, _text); return Print(val, fd.value.type, indent, union_type, opts, _text);
} }
// Generate text for a struct or table, values separated by commas, indented, // Generate text for a struct or table, values separated by commas, indented,
@@ -260,7 +196,7 @@ static bool GenStruct(const StructDef &struct_def, const Table *table,
std::string &text = *_text; std::string &text = *_text;
text += "{"; text += "{";
int fieldout = 0; int fieldout = 0;
StructDef *union_sd = nullptr; Type *union_type = nullptr;
for (auto it = struct_def.fields.vec.begin(); for (auto it = struct_def.fields.vec.begin();
it != struct_def.fields.vec.end(); it != struct_def.fields.vec.end();
++it) { ++it) {
@@ -271,12 +207,15 @@ static bool GenStruct(const StructDef &struct_def, const Table *table,
!fd.deprecated; !fd.deprecated;
if (is_present || output_anyway) { if (is_present || output_anyway) {
if (fieldout++) { if (fieldout++) {
text += ","; if (!opts.protobuf_ascii_alike) text += ",";
} }
text += NewLine(opts); text += NewLine(opts);
text.append(indent + Indent(opts), ' '); text.append(indent + Indent(opts), ' ');
OutputIdentifier(fd.name, opts, _text); OutputIdentifier(fd.name, opts, _text);
text += ": "; if (!opts.protobuf_ascii_alike ||
(fd.value.type.base_type != BASE_TYPE_STRUCT &&
fd.value.type.base_type != BASE_TYPE_VECTOR)) text += ":";
text += " ";
if (is_present) { if (is_present) {
switch (fd.value.type.base_type) { switch (fd.value.type.base_type) {
#define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, \ #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, \
@@ -296,7 +235,7 @@ static bool GenStruct(const StructDef &struct_def, const Table *table,
FLATBUFFERS_GEN_TYPES_POINTER(FLATBUFFERS_TD) FLATBUFFERS_GEN_TYPES_POINTER(FLATBUFFERS_TD)
#undef FLATBUFFERS_TD #undef FLATBUFFERS_TD
if (!GenFieldOffset(fd, table, struct_def.fixed, indent + Indent(opts), if (!GenFieldOffset(fd, table, struct_def.fixed, indent + Indent(opts),
union_sd, opts, _text)) { union_type, opts, _text)) {
return false; return false;
} }
break; break;
@@ -305,7 +244,7 @@ static bool GenStruct(const StructDef &struct_def, const Table *table,
auto enum_val = fd.value.type.enum_def->ReverseLookup( auto enum_val = fd.value.type.enum_def->ReverseLookup(
table->GetField<uint8_t>(fd.value.offset, 0)); table->GetField<uint8_t>(fd.value.offset, 0));
assert(enum_val); assert(enum_val);
union_sd = enum_val->struct_def; union_type = &enum_val->union_type;
} }
} }
else else

View File

@@ -86,26 +86,29 @@ CheckedError Parser::Error(const std::string &msg) {
inline CheckedError NoError() { return CheckedError(false); } inline CheckedError NoError() { return CheckedError(false); }
inline std::string OutOfRangeErrorMsg(int64_t val, const std::string &op,
int64_t limit) {
const std::string cause = NumToString(val) + op + NumToString(limit);
return "constant does not fit (" + cause + ")";
}
// Ensure that integer values we parse fit inside the declared integer type. // Ensure that integer values we parse fit inside the declared integer type.
CheckedError Parser::CheckBitsFit(int64_t val, size_t bits) { CheckedError Parser::CheckInRange(int64_t val, int64_t min, int64_t max) {
// Left-shifting a 64-bit value by 64 bits or more is undefined if (val < min)
// behavior (C99 6.5.7), so check *before* we shift. return Error(OutOfRangeErrorMsg(val, " < ", min));
if (bits < 64) { else if (val > max)
// Bits we allow to be used. return Error(OutOfRangeErrorMsg(val, " > ", max));
auto mask = static_cast<int64_t>((1ull << bits) - 1); else
if ((val & ~mask) != 0 && // Positive or unsigned. return NoError();
(val | mask) != -1) // Negative.
return Error("constant does not fit in a " + NumToString(bits) +
"-bit field");
}
return NoError();
} }
// atot: templated version of atoi/atof: convert a string to an instance of T. // atot: templated version of atoi/atof: convert a string to an instance of T.
template<typename T> inline CheckedError atot(const char *s, Parser &parser, template<typename T> inline CheckedError atot(const char *s, Parser &parser,
T *val) { T *val) {
int64_t i = StringToInt(s); int64_t i = StringToInt(s);
ECHECK(parser.CheckBitsFit(i, sizeof(T) * 8)); const int64_t min = std::numeric_limits<T>::min();
const int64_t max = std::numeric_limits<T>::max();
ECHECK(parser.CheckInRange(i, min, max));
*val = (T)i; *val = (T)i;
return NoError(); return NoError();
} }
@@ -598,6 +601,10 @@ CheckedError Parser::AddField(StructDef &struct_def, const std::string &name,
CheckedError Parser::ParseField(StructDef &struct_def) { CheckedError Parser::ParseField(StructDef &struct_def) {
std::string name = attribute_; std::string name = attribute_;
if (name == struct_def.name)
return Error("field name can not be the same as table/struct name");
std::vector<std::string> dc = doc_comment_; std::vector<std::string> dc = doc_comment_;
EXPECT(kTokenIdentifier); EXPECT(kTokenIdentifier);
EXPECT(':'); EXPECT(':');
@@ -718,6 +725,15 @@ CheckedError Parser::ParseField(StructDef &struct_def) {
LookupCreateStruct(nested->constant); LookupCreateStruct(nested->constant);
} }
if (field->attributes.Lookup("flexbuffer")) {
field->flexbuffer = true;
uses_flexbuffers_ = true;
if (field->value.type.base_type != BASE_TYPE_VECTOR ||
field->value.type.element != BASE_TYPE_UCHAR)
return Error(
"flexbuffer attribute may only apply to a vector of ubyte");
}
if (typefield) { if (typefield) {
// If this field is a union, and it has a manually assigned id, // If this field is a union, and it has a manually assigned id,
// the automatically added type field should have an id as well (of N - 1). // the automatically added type field should have an id as well (of N - 1).
@@ -735,6 +751,18 @@ CheckedError Parser::ParseField(StructDef &struct_def) {
return NoError(); return NoError();
} }
CheckedError Parser::ParseString(Value &val) {
auto s = attribute_;
EXPECT(kTokenStringConstant);
val.constant = NumToString(builder_.CreateString(s).o);
return NoError();
}
CheckedError Parser::ParseComma() {
if (!opts.protobuf_ascii_alike) EXPECT(',');
return NoError();
}
CheckedError Parser::ParseAnyValue(Value &val, FieldDef *field, CheckedError Parser::ParseAnyValue(Value &val, FieldDef *field,
size_t parent_fieldn, size_t parent_fieldn,
const StructDef *parent_struct_def) { const StructDef *parent_struct_def) {
@@ -763,7 +791,7 @@ CheckedError Parser::ParseAnyValue(Value &val, FieldDef *field,
// Remember where we are in the source file, so we can come back here. // Remember where we are in the source file, so we can come back here.
auto backup = *static_cast<ParserState *>(this); auto backup = *static_cast<ParserState *>(this);
ECHECK(SkipAnyJsonValue()); // The table. ECHECK(SkipAnyJsonValue()); // The table.
EXPECT(','); ECHECK(ParseComma());
auto next_name = attribute_; auto next_name = attribute_;
if (Is(kTokenStringConstant)) { if (Is(kTokenStringConstant)) {
NEXT(); NEXT();
@@ -784,20 +812,30 @@ CheckedError Parser::ParseAnyValue(Value &val, FieldDef *field,
ECHECK(atot(constant.c_str(), *this, &enum_idx)); ECHECK(atot(constant.c_str(), *this, &enum_idx));
auto enum_val = val.type.enum_def->ReverseLookup(enum_idx); auto enum_val = val.type.enum_def->ReverseLookup(enum_idx);
if (!enum_val) return Error("illegal type id for: " + field->name); if (!enum_val) return Error("illegal type id for: " + field->name);
ECHECK(ParseTable(*enum_val->struct_def, &val.constant, nullptr)); if (enum_val->union_type.base_type == BASE_TYPE_STRUCT) {
ECHECK(ParseTable(*enum_val->union_type.struct_def, &val.constant,
nullptr));
if (enum_val->union_type.struct_def->fixed) {
// All BASE_TYPE_UNION values are offsets, so turn this into one.
SerializeStruct(*enum_val->union_type.struct_def, val);
builder_.ClearOffsets();
val.constant = NumToString(builder_.GetSize());
}
} else if (enum_val->union_type.base_type == BASE_TYPE_STRING) {
ECHECK(ParseString(val));
} else {
assert(false);
}
break; break;
} }
case BASE_TYPE_STRUCT: case BASE_TYPE_STRUCT:
ECHECK(ParseTable(*val.type.struct_def, &val.constant, nullptr)); ECHECK(ParseTable(*val.type.struct_def, &val.constant, nullptr));
break; break;
case BASE_TYPE_STRING: { case BASE_TYPE_STRING: {
auto s = attribute_; ECHECK(ParseString(val));
EXPECT(kTokenStringConstant);
val.constant = NumToString(builder_.CreateString(s).o);
break; break;
} }
case BASE_TYPE_VECTOR: { case BASE_TYPE_VECTOR: {
EXPECT('[');
uoffset_t off; uoffset_t off;
ECHECK(ParseVector(val.type.VectorType(), &off)); ECHECK(ParseVector(val.type.VectorType(), &off));
val.constant = NumToString(off); val.constant = NumToString(off);
@@ -830,33 +868,74 @@ void Parser::SerializeStruct(const StructDef &struct_def, const Value &val) {
builder_.AddStructOffset(val.offset, builder_.GetSize()); builder_.AddStructOffset(val.offset, builder_.GetSize());
} }
CheckedError Parser::ParseTableDelimiters(size_t &fieldn,
const StructDef *struct_def,
const std::function<CheckedError(const std::string &name)> &body) {
// We allow tables both as JSON object{ .. } with field names
// or vector[..] with all fields in order
char terminator = '}';
bool is_nested_vector = struct_def && Is('[');
if (is_nested_vector) {
NEXT();
terminator = ']';
} else {
EXPECT('{');
}
for (;;) {
if ((!opts.strict_json || !fieldn) && Is(terminator)) break;
std::string name;
if (is_nested_vector) {
if (fieldn > struct_def->fields.vec.size()) {
return Error("too many unnamed fields in nested array");
}
name = struct_def->fields.vec[fieldn]->name;
} else {
name = attribute_;
if (Is(kTokenStringConstant)) {
NEXT();
} else {
EXPECT(opts.strict_json ? kTokenStringConstant : kTokenIdentifier);
}
if (!opts.protobuf_ascii_alike || !(Is('{') || Is('['))) EXPECT(':');
}
ECHECK(body(name));
if (Is(terminator)) break;
ECHECK(ParseComma());
}
NEXT();
if (is_nested_vector && fieldn != struct_def->fields.vec.size()) {
return Error("wrong number of unnamed fields in table vector");
}
return NoError();
}
CheckedError Parser::ParseTable(const StructDef &struct_def, std::string *value, CheckedError Parser::ParseTable(const StructDef &struct_def, std::string *value,
uoffset_t *ovalue) { uoffset_t *ovalue) {
EXPECT('{');
size_t fieldn = 0; size_t fieldn = 0;
for (;;) { auto err = ParseTableDelimiters(fieldn, &struct_def,
if ((!opts.strict_json || !fieldn) && Is('}')) { NEXT(); break; } [&](const std::string &name) -> CheckedError {
std::string name = attribute_;
if (Is(kTokenStringConstant)) {
NEXT();
} else {
EXPECT(opts.strict_json ? kTokenStringConstant : kTokenIdentifier);
}
auto field = struct_def.fields.Lookup(name); auto field = struct_def.fields.Lookup(name);
if (!field) { if (!field) {
if (!opts.skip_unexpected_fields_in_json) { if (!opts.skip_unexpected_fields_in_json) {
return Error("unknown field: " + name); return Error("unknown field: " + name);
} else { } else {
EXPECT(':');
ECHECK(SkipAnyJsonValue()); ECHECK(SkipAnyJsonValue());
} }
} else { } else {
EXPECT(':');
if (Is(kTokenNull)) { if (Is(kTokenNull)) {
NEXT(); // Ignore this field. NEXT(); // Ignore this field.
} else { } else {
Value val = field->value; Value val = field->value;
ECHECK(ParseAnyValue(val, field, fieldn, &struct_def)); if (field->flexbuffer) {
flexbuffers::Builder builder(1024,
flexbuffers::BUILDER_FLAG_SHARE_ALL);
ECHECK(ParseFlexBufferValue(&builder));
builder.Finish();
auto off = builder_.CreateVector(builder.GetBuffer());
val.constant = NumToString(off.o);
} else {
ECHECK(ParseAnyValue(val, field, fieldn, &struct_def));
}
// Hardcoded insertion-sort with error-check. // Hardcoded insertion-sort with error-check.
// If fields are specified in order, then this loop exits immediately. // If fields are specified in order, then this loop exits immediately.
auto elem = field_stack_.rbegin(); auto elem = field_stack_.rbegin();
@@ -872,8 +951,31 @@ CheckedError Parser::ParseTable(const StructDef &struct_def, std::string *value,
fieldn++; fieldn++;
} }
} }
if (Is('}')) { NEXT(); break; } return NoError();
EXPECT(','); });
ECHECK(err);
// Check if all required fields are parsed.
for (auto field_it = struct_def.fields.vec.begin();
field_it != struct_def.fields.vec.end();
++field_it) {
auto required_field = *field_it;
if (!required_field->required) {
continue;
}
bool found = false;
for (auto pf_it = field_stack_.end() - fieldn;
pf_it != field_stack_.end();
++pf_it) {
auto parsed_field = pf_it->second;
if (parsed_field == required_field) {
found = true;
break;
}
}
if (!found) {
return Error("required field is missing: " + required_field->name + " in " + struct_def.name);
}
} }
if (struct_def.fixed && fieldn != struct_def.fields.vec.size()) if (struct_def.fixed && fieldn != struct_def.fields.vec.size())
@@ -951,22 +1053,34 @@ CheckedError Parser::ParseTable(const StructDef &struct_def, std::string *value,
return NoError(); return NoError();
} }
CheckedError Parser::ParseVector(const Type &type, uoffset_t *ovalue) { CheckedError Parser::ParseVectorDelimiters(size_t &count,
int count = 0; const std::function<CheckedError()> &body) {
EXPECT('[');
for (;;) { for (;;) {
if ((!opts.strict_json || !count) && Is(']')) { NEXT(); break; } if ((!opts.strict_json || !count) && Is(']')) break;
ECHECK(body());
count++;
if (Is(']')) break;
ECHECK(ParseComma());
}
NEXT();
return NoError();
}
CheckedError Parser::ParseVector(const Type &type, uoffset_t *ovalue) {
size_t count = 0;
auto err = ParseVectorDelimiters(count, [&]() -> CheckedError {
Value val; Value val;
val.type = type; val.type = type;
ECHECK(ParseAnyValue(val, nullptr, 0, nullptr)); ECHECK(ParseAnyValue(val, nullptr, 0, nullptr));
field_stack_.push_back(std::make_pair(val, nullptr)); field_stack_.push_back(std::make_pair(val, nullptr));
count++; return NoError();
if (Is(']')) { NEXT(); break; } });
EXPECT(','); ECHECK(err);
}
builder_.StartVector(count * InlineSize(type) / InlineAlignment(type), builder_.StartVector(count * InlineSize(type) / InlineAlignment(type),
InlineAlignment(type)); InlineAlignment(type));
for (int i = 0; i < count; i++) { for (size_t i = 0; i < count; i++) {
// start at the back, since we're building the data backwards. // start at the back, since we're building the data backwards.
auto &val = field_stack_.back().first; auto &val = field_stack_.back().first;
switch (val.type.base_type) { switch (val.type.base_type) {
@@ -1077,14 +1191,24 @@ CheckedError Parser::ParseHash(Value &e, FieldDef* field) {
assert(field); assert(field);
Value *hash_name = field->attributes.Lookup("hash"); Value *hash_name = field->attributes.Lookup("hash");
switch (e.type.base_type) { switch (e.type.base_type) {
case BASE_TYPE_INT: case BASE_TYPE_INT: {
auto hash = FindHashFunction32(hash_name->constant.c_str());
int32_t hashed_value = static_cast<int32_t>(hash(attribute_.c_str()));
e.constant = NumToString(hashed_value);
break;
}
case BASE_TYPE_UINT: { case BASE_TYPE_UINT: {
auto hash = FindHashFunction32(hash_name->constant.c_str()); auto hash = FindHashFunction32(hash_name->constant.c_str());
uint32_t hashed_value = hash(attribute_.c_str()); uint32_t hashed_value = hash(attribute_.c_str());
e.constant = NumToString(hashed_value); e.constant = NumToString(hashed_value);
break; break;
} }
case BASE_TYPE_LONG: case BASE_TYPE_LONG: {
auto hash = FindHashFunction64(hash_name->constant.c_str());
int64_t hashed_value = static_cast<int64_t>(hash(attribute_.c_str()));
e.constant = NumToString(hashed_value);
break;
}
case BASE_TYPE_ULONG: { case BASE_TYPE_ULONG: {
auto hash = FindHashFunction64(hash_name->constant.c_str()); auto hash = FindHashFunction64(hash_name->constant.c_str());
uint64_t hashed_value = hash(attribute_.c_str()); uint64_t hashed_value = hash(attribute_.c_str());
@@ -1098,6 +1222,11 @@ CheckedError Parser::ParseHash(Value &e, FieldDef* field) {
return NoError(); return NoError();
} }
CheckedError Parser::TokenError() {
return Error("cannot parse value starting with: " +
TokenToStringId(token_));
}
CheckedError Parser::ParseSingleValue(Value &e) { CheckedError Parser::ParseSingleValue(Value &e) {
// First see if this could be a conversion function: // First see if this could be a conversion function:
if (token_ == kTokenIdentifier && *cursor_ == '(') { if (token_ == kTokenIdentifier && *cursor_ == '(') {
@@ -1164,9 +1293,7 @@ CheckedError Parser::ParseSingleValue(Value &e) {
e, e,
BASE_TYPE_STRING, BASE_TYPE_STRING,
&match)); &match));
if (!match) if (!match) return TokenError();
return Error("cannot parse value starting with: " +
TokenToStringId(token_));
} }
return NoError(); return NoError();
} }
@@ -1290,7 +1417,16 @@ CheckedError Parser::ParseEnum(bool is_union, EnumDef **dest) {
return Error("enum value already exists: " + value_name); return Error("enum value already exists: " + value_name);
ev.doc_comment = value_comment; ev.doc_comment = value_comment;
if (is_union) { if (is_union) {
ev.struct_def = LookupCreateStruct(full_name); if (Is(':')) {
NEXT();
ECHECK(ParseType(ev.union_type));
if (ev.union_type.base_type != BASE_TYPE_STRUCT &&
ev.union_type.base_type != BASE_TYPE_STRING)
return Error("union value type may only be table/struct/string");
enum_def.uses_type_aliases = true;
} else {
ev.union_type = Type(BASE_TYPE_STRUCT, LookupCreateStruct(full_name));
}
} }
if (Is('=')) { if (Is('=')) {
NEXT(); NEXT();
@@ -1300,6 +1436,10 @@ CheckedError Parser::ParseEnum(bool is_union, EnumDef **dest) {
enum_def.vals.vec[prevsize - 1]->value >= ev.value) enum_def.vals.vec[prevsize - 1]->value >= ev.value)
return Error("enum values must be specified in ascending order"); return Error("enum values must be specified in ascending order");
} }
if (is_union) {
if (ev.value < 0 || ev.value >= 256)
return Error("union enum value must fit in a ubyte");
}
if (opts.proto_mode && Is('[')) { if (opts.proto_mode && Is('[')) {
NEXT(); NEXT();
// ignore attributes on enums. // ignore attributes on enums.
@@ -1335,7 +1475,7 @@ CheckedError Parser::StartStruct(const std::string &name, StructDef **dest) {
struct_def.file = file_being_parsed_; struct_def.file = file_being_parsed_;
// Move this struct to the back of the vector just in case it was predeclared, // Move this struct to the back of the vector just in case it was predeclared,
// to preserve declaration order. // to preserve declaration order.
*remove(structs_.vec.begin(), structs_.vec.end(), &struct_def) = &struct_def; *std::remove(structs_.vec.begin(), structs_.vec.end(), &struct_def) = &struct_def;
*dest = &struct_def; *dest = &struct_def;
return NoError(); return NoError();
} }
@@ -1780,14 +1920,21 @@ CheckedError Parser::ParseTypeFromProtoType(Type *type) {
CheckedError Parser::SkipAnyJsonValue() { CheckedError Parser::SkipAnyJsonValue() {
switch (token_) { switch (token_) {
case '{': case '{': {
ECHECK(SkipJsonObject()); size_t fieldn = 0;
break; return ParseTableDelimiters(fieldn, nullptr,
[&](const std::string &) -> CheckedError {
ECHECK(SkipAnyJsonValue());
fieldn++;
return NoError();
});
}
case '[': {
size_t count = 0;
return ParseVectorDelimiters(count, [&]() { return SkipAnyJsonValue(); });
}
case kTokenStringConstant: case kTokenStringConstant:
ECHECK(SkipJsonString()); EXPECT(kTokenStringConstant);
break;
case '[':
ECHECK(SkipJsonArray());
break; break;
case kTokenIntegerConstant: case kTokenIntegerConstant:
EXPECT(kTokenIntegerConstant); EXPECT(kTokenIntegerConstant);
@@ -1796,84 +1943,98 @@ CheckedError Parser::SkipAnyJsonValue() {
EXPECT(kTokenFloatConstant); EXPECT(kTokenFloatConstant);
break; break;
default: default:
return Error(std::string("Unexpected token:") + std::string(1, static_cast<char>(token_))); return TokenError();
} }
return NoError(); return NoError();
} }
CheckedError Parser::SkipJsonObject() { CheckedError Parser::ParseFlexBufferValue(flexbuffers::Builder *builder) {
EXPECT('{'); switch (token_) {
size_t fieldn = 0; case '{': {
auto start = builder->StartMap();
for (;;) { size_t fieldn = 0;
if ((!opts.strict_json || !fieldn) && Is('}')) break; auto err = ParseTableDelimiters(fieldn, nullptr,
[&](const std::string &name) -> CheckedError {
if (!Is(kTokenStringConstant)) { builder->Key(name);
EXPECT(opts.strict_json ? kTokenStringConstant : kTokenIdentifier); ECHECK(ParseFlexBufferValue(builder));
fieldn++;
return NoError();
});
ECHECK(err);
builder->EndMap(start);
break;
} }
else { case '[':{
NEXT(); auto start = builder->StartVector();
size_t count = 0;
ECHECK(ParseVectorDelimiters(count, [&]() {
return ParseFlexBufferValue(builder);
}));
builder->EndVector(start, false, false);
break;
} }
case kTokenStringConstant:
EXPECT(':'); builder->String(attribute_);
ECHECK(SkipAnyJsonValue()); EXPECT(kTokenStringConstant);
fieldn++; break;
case kTokenIntegerConstant:
if (Is('}')) break; builder->Int(StringToInt(attribute_.c_str()));
EXPECT(','); EXPECT(kTokenIntegerConstant);
break;
case kTokenFloatConstant:
builder->Double(strtod(attribute_.c_str(), nullptr));
EXPECT(kTokenFloatConstant);
break;
default:
return TokenError();
} }
NEXT();
return NoError(); return NoError();
} }
CheckedError Parser::SkipJsonArray() { bool Parser::ParseFlexBuffer(const char *source, const char *source_filename,
EXPECT('['); flexbuffers::Builder *builder) {
auto ok = !StartParseFile(source, source_filename).Check() &&
for (;;) { !ParseFlexBufferValue(builder).Check();
if (Is(']')) break; if (ok) builder->Finish();
return ok;
ECHECK(SkipAnyJsonValue());
if (Is(']')) break;
EXPECT(',');
}
NEXT();
return NoError();
}
CheckedError Parser::SkipJsonString() {
EXPECT(kTokenStringConstant);
return NoError();
} }
bool Parser::Parse(const char *source, const char **include_paths, bool Parser::Parse(const char *source, const char **include_paths,
const char *source_filename) { const char *source_filename) {
return !DoParse(source, include_paths, source_filename).Check(); return !DoParse(source, include_paths, source_filename, nullptr).Check();
}
CheckedError Parser::StartParseFile(const char *source, const char *source_filename) {
file_being_parsed_ = source_filename ? source_filename : "";
source_ = cursor_ = source;
line_ = 1;
error_.clear();
ECHECK(SkipByteOrderMark());
NEXT();
if (Is(kTokenEof))
return Error("input file is empty");
return NoError();
} }
CheckedError Parser::DoParse(const char *source, const char **include_paths, CheckedError Parser::DoParse(const char *source, const char **include_paths,
const char *source_filename) { const char *source_filename,
file_being_parsed_ = source_filename ? source_filename : ""; const char *include_filename) {
if (source_filename && if (source_filename &&
included_files_.find(source_filename) == included_files_.end()) { included_files_.find(source_filename) == included_files_.end()) {
included_files_[source_filename] = true; included_files_[source_filename] = include_filename ? include_filename : "";
files_included_per_file_[source_filename] = std::set<std::string>(); files_included_per_file_[source_filename] = std::set<std::string>();
} }
if (!include_paths) { if (!include_paths) {
static const char *current_directory[] = { "", nullptr }; static const char *current_directory[] = { "", nullptr };
include_paths = current_directory; include_paths = current_directory;
} }
source_ = cursor_ = source;
line_ = 1;
error_.clear();
field_stack_.clear(); field_stack_.clear();
builder_.Clear(); builder_.Clear();
// Start with a blank namespace just in case this file doesn't have one. // Start with a blank namespace just in case this file doesn't have one.
namespaces_.push_back(new Namespace()); namespaces_.push_back(new Namespace());
ECHECK(SkipByteOrderMark());
NEXT(); ECHECK(StartParseFile(source, source_filename));
// Includes must come before type declarations: // Includes must come before type declarations:
for (;;) { for (;;) {
// Parse pre-include proto statements if any: // Parse pre-include proto statements if any:
@@ -1891,7 +2052,7 @@ CheckedError Parser::DoParse(const char *source, const char **include_paths,
Is(kTokenIdentifier))) { Is(kTokenIdentifier))) {
NEXT(); NEXT();
if (opts.proto_mode && attribute_ == "public") NEXT(); if (opts.proto_mode && attribute_ == "public") NEXT();
auto name = attribute_; auto name = flatbuffers::PosixPath(attribute_.c_str());
EXPECT(kTokenStringConstant); EXPECT(kTokenStringConstant);
// Look for the file in include_paths. // Look for the file in include_paths.
std::string filepath; std::string filepath;
@@ -1909,7 +2070,8 @@ CheckedError Parser::DoParse(const char *source, const char **include_paths,
std::string contents; std::string contents;
if (!LoadFile(filepath.c_str(), true, &contents)) if (!LoadFile(filepath.c_str(), true, &contents))
return Error("unable to load include file: " + name); return Error("unable to load include file: " + name);
ECHECK(DoParse(contents.c_str(), include_paths, filepath.c_str())); ECHECK(DoParse(contents.c_str(), include_paths, filepath.c_str(),
name.c_str()));
// We generally do not want to output code for any included files: // We generally do not want to output code for any included files:
if (!opts.generate_all) MarkGenerated(); if (!opts.generate_all) MarkGenerated();
// This is the easiest way to continue this file after an include: // This is the easiest way to continue this file after an include:
@@ -1919,7 +2081,7 @@ CheckedError Parser::DoParse(const char *source, const char **include_paths,
// entered into included_files_. // entered into included_files_.
// This is recursive, but only go as deep as the number of include // This is recursive, but only go as deep as the number of include
// statements. // statements.
return DoParse(source, include_paths, source_filename); return DoParse(source, include_paths, source_filename, include_filename);
} }
EXPECT(';'); EXPECT(';');
} else { } else {
@@ -1990,6 +2152,8 @@ CheckedError Parser::DoParse(const char *source, const char **include_paths,
return Error("type referenced but not defined: " + (*it)->name); return Error("type referenced but not defined: " + (*it)->name);
} }
} }
// This check has to happen here and not earlier, because only now do we
// know for sure what the type of these are.
for (auto it = enums_.vec.begin(); it != enums_.vec.end(); ++it) { for (auto it = enums_.vec.begin(); it != enums_.vec.end(); ++it) {
auto &enum_def = **it; auto &enum_def = **it;
if (enum_def.is_union) { if (enum_def.is_union) {
@@ -1997,8 +2161,11 @@ CheckedError Parser::DoParse(const char *source, const char **include_paths,
val_it != enum_def.vals.vec.end(); val_it != enum_def.vals.vec.end();
++val_it) { ++val_it) {
auto &val = **val_it; auto &val = **val_it;
if (val.struct_def && val.struct_def->fixed) if (opts.lang_to_generate != IDLOptions::kCpp &&
return Error("only tables can be union elements: " + val.name); val.union_type.struct_def && val.union_type.struct_def->fixed)
return Error(
"only tables can be union elements in the generated language: "
+ val.name);
} }
} }
} }
@@ -2141,9 +2308,11 @@ Offset<reflection::EnumVal> EnumVal::Serialize(FlatBufferBuilder *builder) const
return reflection::CreateEnumVal(*builder, return reflection::CreateEnumVal(*builder,
builder->CreateString(name), builder->CreateString(name),
value, value,
struct_def union_type.struct_def
? struct_def->serialized_location ? union_type.struct_def->
: 0); serialized_location
: 0,
union_type.Serialize(builder));
} }
Offset<reflection::Type> Type::Serialize(FlatBufferBuilder *builder) const { Offset<reflection::Type> Type::Serialize(FlatBufferBuilder *builder) const {

View File

@@ -87,8 +87,11 @@ std::string GetAnyValueS(reflection::BaseType type, const uint8_t *data,
auto &fielddef = **it; auto &fielddef = **it;
if (!table_field->CheckField(fielddef.offset())) continue; if (!table_field->CheckField(fielddef.offset())) continue;
auto val = GetAnyFieldS(*table_field, fielddef, schema); auto val = GetAnyFieldS(*table_field, fielddef, schema);
if (fielddef.type()->base_type() == reflection::String) if (fielddef.type()->base_type() == reflection::String) {
val = "\"" + val + "\""; // Doesn't deal with escape codes etc. std::string esc;
flatbuffers::EscapeString(val.c_str(), val.length(), &esc, true);
val = esc;
}
s += fielddef.name()->str(); s += fielddef.name()->str();
s += ": "; s += ": ";
s += val; s += val;
@@ -420,8 +423,8 @@ Offset<const Table *> CopyTable(FlatBufferBuilder &fbb,
offset = fbb.CreateVector(elements).o; offset = fbb.CreateVector(elements).o;
break; break;
} }
// FALL-THRU:
} }
// FALL-THRU
default: { // Scalars and structs. default: { // Scalars and structs.
auto element_size = GetTypeSize(element_base_type); auto element_size = GetTypeSize(element_base_type);
if (elemobjectdef && elemobjectdef->is_struct()) if (elemobjectdef && elemobjectdef->is_struct())
@@ -458,8 +461,8 @@ Offset<const Table *> CopyTable(FlatBufferBuilder &fbb,
subobjectdef.bytesize()); subobjectdef.bytesize());
break; break;
} }
// else: FALL-THRU:
} }
// ELSE FALL-THRU
case reflection::Union: case reflection::Union:
case reflection::String: case reflection::String:
case reflection::Vector: case reflection::Vector:

View File

@@ -80,6 +80,9 @@
<Compile Include="..\MyGame\Example\Vec3.cs"> <Compile Include="..\MyGame\Example\Vec3.cs">
<Link>MyGame\Example\Vec3.cs</Link> <Link>MyGame\Example\Vec3.cs</Link>
</Compile> </Compile>
<Compile Include="..\MyGame\Example\Ability.cs">
<Link>MyGame\Example\Ability.cs</Link>
</Compile>
<Compile Include="..\namespace_test\NamespaceA\NamespaceB\EnumInNestedNS.cs"> <Compile Include="..\namespace_test\NamespaceA\NamespaceB\EnumInNestedNS.cs">
<Link>NamespaceA\NamespaceB\EnumInNestedNS.cs</Link> <Link>NamespaceA\NamespaceB\EnumInNestedNS.cs</Link>
</Compile> </Compile>

View File

@@ -50,7 +50,7 @@ namespace FlatBuffers.Test
Monster.StartMonster(fbb); Monster.StartMonster(fbb);
Monster.AddName(fbb, names[2]); Monster.AddName(fbb, names[2]);
off[2] = Monster.EndMonster(fbb); off[2] = Monster.EndMonster(fbb);
var sortMons = Monster.CreateMySortedVectorOfTables(fbb, off); var sortMons = Monster.CreateSortedVectorOfMonster(fbb, off);
// We set up the same values as monsterdata.json: // We set up the same values as monsterdata.json:
@@ -123,9 +123,9 @@ namespace FlatBuffers.Test
Assert.AreEqual(monster.Testarrayoftables(2).Value.Name, "Wilma"); Assert.AreEqual(monster.Testarrayoftables(2).Value.Name, "Wilma");
// Example of searching for a table by the key // Example of searching for a table by the key
Assert.IsTrue(Monster.LookupByKey(sortMons, "Frodo", fbb.DataBuffer) != null); Assert.IsTrue(monster.TestarrayoftablesByKey("Frodo") != null);
Assert.IsTrue(Monster.LookupByKey(sortMons, "Barney", fbb.DataBuffer) != null); Assert.IsTrue(monster.TestarrayoftablesByKey("Barney") != null);
Assert.IsTrue(Monster.LookupByKey(sortMons, "Wilma", fbb.DataBuffer)!= null); Assert.IsTrue(monster.TestarrayoftablesByKey("Wilma") != null);
// testType is an existing field and mutating it should succeed // testType is an existing field and mutating it should succeed
Assert.AreEqual(monster.TestType, Any.Monster); Assert.AreEqual(monster.TestType, Any.Monster);

View File

@@ -0,0 +1,9 @@
#!/bin/sh
# Testing C# on Linux using Mono.
mcs -out:fbnettest.exe ../../net/FlatBuffers/*.cs ../MyGame/Example/*.cs FlatBuffersTestClassAttribute.cs FlatBuffersTestMethodAttribute.cs Assert.cs FlatBuffersExampleTests.cs Program.cs ByteBufferTests.cs FlatBufferBuilderTests.cs FlatBuffersFuzzTests.cs FuzzTestData.cs Lcg.cs TestTable.cs
./fbnettest.exe
rm fbnettest.exe
rm Resources/monsterdata_cstest.mon

View File

@@ -20,7 +20,7 @@ go_path=${test_dir}/go_gen
go_src=${go_path}/src go_src=${go_path}/src
# Emit Go code for the example schema in the test dir: # Emit Go code for the example schema in the test dir:
../flatc -g monster_test.fbs ../flatc -g -I include_test monster_test.fbs
# Go requires a particular layout of files in order to link multiple packages. # Go requires a particular layout of files in order to link multiple packages.
# Copy flatbuffer Go files to their own package directories to compile the # Copy flatbuffer Go files to their own package directories to compile the

View File

@@ -3,7 +3,7 @@ var assert = require('assert');
var fs = require('fs'); var fs = require('fs');
var flatbuffers = require('../js/flatbuffers').flatbuffers; var flatbuffers = require('../js/flatbuffers').flatbuffers;
var MyGame = require('./monster_test_generated').MyGame; var MyGame = require(process.argv[2]).MyGame;
function main() { function main() {
@@ -67,7 +67,7 @@ function main() {
// Tests mutation first. This will verify that we did not trample any other // Tests mutation first. This will verify that we did not trample any other
// part of the byte buffer. // part of the byte buffer.
testMutation(fbb.dataBuffer()); testMutation(fbb.dataBuffer());
testBuffer(fbb.dataBuffer()); testBuffer(fbb.dataBuffer());
test64bit(); test64bit();
@@ -156,7 +156,8 @@ function test64bit() {
var mon2 = MyGame.Example.Monster.endMonster(fbb); var mon2 = MyGame.Example.Monster.endMonster(fbb);
MyGame.Example.Stat.startStat(fbb); MyGame.Example.Stat.startStat(fbb);
MyGame.Example.Stat.addVal(fbb, new flatbuffers.Long(0x12345678, 0x23456789)); // 2541551405100253985 = 0x87654321(low part) + 0x23456789 * 0x100000000(high part);
MyGame.Example.Stat.addVal(fbb, new flatbuffers.Long(0x87654321, 0x23456789)); // the low part is Uint32
var stat = MyGame.Example.Stat.endStat(fbb); var stat = MyGame.Example.Stat.endStat(fbb);
MyGame.Example.Monster.startMonster(fbb); MyGame.Example.Monster.startMonster(fbb);
@@ -177,8 +178,7 @@ function test64bit() {
var stat = mon.testempty(); var stat = mon.testempty();
assert.strictEqual(stat != null, true); assert.strictEqual(stat != null, true);
assert.strictEqual(stat.val() != null, true); assert.strictEqual(stat.val() != null, true);
assert.strictEqual(stat.val().low, 0x12345678); assert.strictEqual(stat.val().toFloat64(), 2541551405100253985);
assert.strictEqual(stat.val().high, 0x23456789);
var mon2 = mon.enemy(); var mon2 = mon.enemy();
assert.strictEqual(mon2 != null, true); assert.strictEqual(mon2 != null, true);

View File

@@ -15,5 +15,5 @@
# limitations under the License. # limitations under the License.
pushd "$(dirname $0)" >/dev/null pushd "$(dirname $0)" >/dev/null
../flatc -b monster_test.fbs unicode_test.json ../flatc -b -I include_test monster_test.fbs unicode_test.json
node JavaScriptTest node JavaScriptTest ./monster_test_generated

View File

@@ -63,7 +63,7 @@ class JavaTest {
Monster.addName(fbb, names[2]); Monster.addName(fbb, names[2]);
off[2] = Monster.endMonster(fbb); off[2] = Monster.endMonster(fbb);
int sortMons = fbb.createSortedVectorOfTables(new Monster(), off); int sortMons = fbb.createSortedVectorOfTables(new Monster(), off);
// We set up the same values as monsterdata.json: // We set up the same values as monsterdata.json:
int str = fbb.createString("MyMonster"); int str = fbb.createString("MyMonster");
@@ -135,16 +135,16 @@ class JavaTest {
// the mana field should retain its default value // the mana field should retain its default value
TestEq(monster.mutateMana((short)10), false); TestEq(monster.mutateMana((short)10), false);
TestEq(monster.mana(), (short)150); TestEq(monster.mana(), (short)150);
// Accessing a vector of sorted by the key tables // Accessing a vector of sorted by the key tables
TestEq(monster.testarrayoftables(0).name(), "Barney"); TestEq(monster.testarrayoftables(0).name(), "Barney");
TestEq(monster.testarrayoftables(1).name(), "Frodo"); TestEq(monster.testarrayoftables(1).name(), "Frodo");
TestEq(monster.testarrayoftables(2).name(), "Wilma"); TestEq(monster.testarrayoftables(2).name(), "Wilma");
// Example of searching for a table by the key // Example of searching for a table by the key
TestEq(Monster.lookupByKey(sortMons, "Frodo", fbb.dataBuffer()).name(), "Frodo"); TestEq(monster.testarrayoftablesByKey("Frodo").name(), "Frodo");
TestEq(Monster.lookupByKey(sortMons, "Barney", fbb.dataBuffer()).name(), "Barney"); TestEq(monster.testarrayoftablesByKey("Barney").name(), "Barney");
TestEq(Monster.lookupByKey(sortMons, "Wilma", fbb.dataBuffer()).name(), "Wilma"); TestEq(monster.testarrayoftablesByKey("Wilma").name(), "Wilma");
// testType is an existing field and mutating it should succeed // testType is an existing field and mutating it should succeed
TestEq(monster.testType(), (byte)Any.Monster); TestEq(monster.testType(), (byte)Any.Monster);
@@ -201,7 +201,7 @@ class JavaTest {
static void TestBuffer(ByteBuffer bb) { static void TestBuffer(ByteBuffer bb) {
TestEq(Monster.MonsterBufferHasIdentifier(bb), true); TestEq(Monster.MonsterBufferHasIdentifier(bb), true);
Monster monster = Monster.getRootAsMonster(bb); Monster monster = Monster.getRootAsMonster(bb);
TestEq(monster.hp(), (short)80); TestEq(monster.hp(), (short)80);
@@ -259,25 +259,25 @@ class JavaTest {
TestEq(monster.testhashu32Fnv1(), Integer.MAX_VALUE + 1L); TestEq(monster.testhashu32Fnv1(), Integer.MAX_VALUE + 1L);
} }
static void TestNamespaceNesting() { static void TestNamespaceNesting() {
// reference / manipulate these to verify compilation // reference / manipulate these to verify compilation
FlatBufferBuilder fbb = new FlatBufferBuilder(1); FlatBufferBuilder fbb = new FlatBufferBuilder(1);
TableInNestedNS.startTableInNestedNS(fbb); TableInNestedNS.startTableInNestedNS(fbb);
TableInNestedNS.addFoo(fbb, 1234); TableInNestedNS.addFoo(fbb, 1234);
int nestedTableOff = TableInNestedNS.endTableInNestedNS(fbb); int nestedTableOff = TableInNestedNS.endTableInNestedNS(fbb);
TableInFirstNS.startTableInFirstNS(fbb); TableInFirstNS.startTableInFirstNS(fbb);
TableInFirstNS.addFooTable(fbb, nestedTableOff); TableInFirstNS.addFooTable(fbb, nestedTableOff);
int off = TableInFirstNS.endTableInFirstNS(fbb); int off = TableInFirstNS.endTableInFirstNS(fbb);
} }
static void TestNestedFlatBuffer() { static void TestNestedFlatBuffer() {
final String nestedMonsterName = "NestedMonsterName"; final String nestedMonsterName = "NestedMonsterName";
final short nestedMonsterHp = 600; final short nestedMonsterHp = 600;
final short nestedMonsterMana = 1024; final short nestedMonsterMana = 1024;
FlatBufferBuilder fbb1 = new FlatBufferBuilder(16); FlatBufferBuilder fbb1 = new FlatBufferBuilder(16);
int str1 = fbb1.createString(nestedMonsterName); int str1 = fbb1.createString(nestedMonsterName);
Monster.startMonster(fbb1); Monster.startMonster(fbb1);
@@ -288,8 +288,8 @@ class JavaTest {
Monster.finishMonsterBuffer(fbb1, monster1); Monster.finishMonsterBuffer(fbb1, monster1);
byte[] fbb1Bytes = fbb1.sizedByteArray(); byte[] fbb1Bytes = fbb1.sizedByteArray();
fbb1 = null; fbb1 = null;
FlatBufferBuilder fbb2 = new FlatBufferBuilder(16); FlatBufferBuilder fbb2 = new FlatBufferBuilder(16);
int str2 = fbb2.createString("My Monster"); int str2 = fbb2.createString("My Monster");
int nestedBuffer = Monster.createTestnestedflatbufferVector(fbb2, fbb1Bytes); int nestedBuffer = Monster.createTestnestedflatbufferVector(fbb2, fbb1Bytes);
Monster.startMonster(fbb2); Monster.startMonster(fbb2);
@@ -299,7 +299,7 @@ class JavaTest {
Monster.addTestnestedflatbuffer(fbb2, nestedBuffer); Monster.addTestnestedflatbuffer(fbb2, nestedBuffer);
int monster = Monster.endMonster(fbb2); int monster = Monster.endMonster(fbb2);
Monster.finishMonsterBuffer(fbb2, monster); Monster.finishMonsterBuffer(fbb2, monster);
// Now test the data extracted from the nested buffer // Now test the data extracted from the nested buffer
Monster mons = Monster.getRootAsMonster(fbb2.dataBuffer()); Monster mons = Monster.getRootAsMonster(fbb2.dataBuffer());
Monster nestedMonster = mons.testnestedflatbufferAsMonster(); Monster nestedMonster = mons.testnestedflatbufferAsMonster();

View File

@@ -14,31 +14,30 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
set -o errexit
echo Compile then run the Java test. echo Compile then run the Java test.
java -version java -version
testdir=$(readlink -fn `dirname $0`) testdir="$(readlink -fn "$(dirname "$0")")"
thisdir=$(readlink -fn `pwd`)
targetdir=${testdir}/target targetdir="${testdir}/target"
if [[ "$testdir" != "$thisdir" ]]; then
echo error: must be run from inside the ${testdir} directory
echo you ran it from ${thisdir}
exit 1
fi
find .. -type f -name "*.class" -exec rm {} \;
if [[ -e "${targetdir}" ]]; then if [[ -e "${targetdir}" ]]; then
echo "clean target" echo "cleaning target"
rm -rf ${targetdir} rm -rf "${targetdir}"
fi fi
mkdir ${targetdir} mkdir -v "${targetdir}"
javac -d ${targetdir} -classpath ${testdir}/../java:${testdir}:${testdir}/namespace_test JavaTest.java if ! find "${testdir}/../java" -type f -name "*.class" -delete; then
java -classpath ${targetdir} JavaTest echo "failed to clean .class files from java directory" >&2
exit 1
fi
rm -rf ${targetdir} javac -d "${targetdir}" -classpath "${testdir}/../java:${testdir}:${testdir}/namespace_test" "${testdir}/JavaTest.java"
(cd "${testdir}" && java -classpath "${targetdir}" JavaTest )
rm -rf "${targetdir}"

View File

@@ -0,0 +1,32 @@
// <auto-generated>
// automatically generated by the FlatBuffers compiler, do not modify
// </auto-generated>
namespace MyGame.Example
{
using global::System;
using global::FlatBuffers;
public struct Ability : IFlatbufferObject
{
private Struct __p;
public ByteBuffer ByteBuffer { get { return __p.bb; } }
public void __init(int _i, ByteBuffer _bb) { __p.bb_pos = _i; __p.bb = _bb; }
public Ability __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; }
public uint Id { get { return __p.bb.GetUint(__p.bb_pos + 0); } }
public void MutateId(uint id) { __p.bb.PutUint(__p.bb_pos + 0, id); }
public uint Distance { get { return __p.bb.GetUint(__p.bb_pos + 4); } }
public void MutateDistance(uint distance) { __p.bb.PutUint(__p.bb_pos + 4, distance); }
public static Offset<Ability> CreateAbility(FlatBufferBuilder builder, uint Id, uint Distance) {
builder.Prep(4, 8);
builder.PutUint(Distance);
builder.PutUint(Id);
return new Offset<Ability>(builder.Offset);
}
};
}

View File

@@ -0,0 +1,41 @@
// automatically generated by the FlatBuffers compiler, do not modify
package Example
import (
flatbuffers "github.com/google/flatbuffers/go"
)
type Ability struct {
_tab flatbuffers.Struct
}
func (rcv *Ability) Init(buf []byte, i flatbuffers.UOffsetT) {
rcv._tab.Bytes = buf
rcv._tab.Pos = i
}
func (rcv *Ability) Table() flatbuffers.Table {
return rcv._tab.Table
}
func (rcv *Ability) Id() uint32 {
return rcv._tab.GetUint32(rcv._tab.Pos + flatbuffers.UOffsetT(0))
}
func (rcv *Ability) MutateId(n uint32) bool {
return rcv._tab.MutateUint32(rcv._tab.Pos+flatbuffers.UOffsetT(0), n)
}
func (rcv *Ability) Distance() uint32 {
return rcv._tab.GetUint32(rcv._tab.Pos + flatbuffers.UOffsetT(4))
}
func (rcv *Ability) MutateDistance(n uint32) bool {
return rcv._tab.MutateUint32(rcv._tab.Pos+flatbuffers.UOffsetT(4), n)
}
func CreateAbility(builder *flatbuffers.Builder, id uint32, distance uint32) flatbuffers.UOffsetT {
builder.Prep(4, 8)
builder.PrependUint32(distance)
builder.PrependUint32(id)
return builder.Offset()
}

View File

@@ -0,0 +1,27 @@
// automatically generated by the FlatBuffers compiler, do not modify
package MyGame.Example;
import java.nio.*;
import java.lang.*;
import java.util.*;
import com.google.flatbuffers.*;
@SuppressWarnings("unused")
public final class Ability extends Struct {
public void __init(int _i, ByteBuffer _bb) { bb_pos = _i; bb = _bb; }
public Ability __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; }
public long id() { return (long)bb.getInt(bb_pos + 0) & 0xFFFFFFFFL; }
public void mutateId(long id) { bb.putInt(bb_pos + 0, (int)id); }
public long distance() { return (long)bb.getInt(bb_pos + 4) & 0xFFFFFFFFL; }
public void mutateDistance(long distance) { bb.putInt(bb_pos + 4, (int)distance); }
public static int createAbility(FlatBufferBuilder builder, long id, long distance) {
builder.prep(4, 8);
builder.putInt((int)distance);
builder.putInt((int)id);
return builder.offset();
}
}

View File

@@ -0,0 +1,52 @@
<?php
// automatically generated by the FlatBuffers compiler, do not modify
namespace MyGame\Example;
use \Google\FlatBuffers\Struct;
use \Google\FlatBuffers\Table;
use \Google\FlatBuffers\ByteBuffer;
use \Google\FlatBuffers\FlatBufferBuilder;
class Ability extends Struct
{
/**
* @param int $_i offset
* @param ByteBuffer $_bb
* @return Ability
**/
public function init($_i, ByteBuffer $_bb)
{
$this->bb_pos = $_i;
$this->bb = $_bb;
return $this;
}
/**
* @return uint
*/
public function GetId()
{
return $this->bb->getUint($this->bb_pos + 0);
}
/**
* @return uint
*/
public function GetDistance()
{
return $this->bb->getUint($this->bb_pos + 4);
}
/**
* @return int offset
*/
public static function createAbility(FlatBufferBuilder $builder, $id, $distance)
{
$builder->prep(4, 8);
$builder->putUint($distance);
$builder->putUint($id);
return $builder->offset();
}
}

View File

@@ -0,0 +1,23 @@
# automatically generated by the FlatBuffers compiler, do not modify
# namespace: Example
import flatbuffers
class Ability(object):
__slots__ = ['_tab']
# Ability
def Init(self, buf, pos):
self._tab = flatbuffers.table.Table(buf, pos)
# Ability
def Id(self): return self._tab.Get(flatbuffers.number_types.Uint32Flags, self._tab.Pos + flatbuffers.number_types.UOffsetTFlags.py_type(0))
# Ability
def Distance(self): return self._tab.Get(flatbuffers.number_types.Uint32Flags, self._tab.Pos + flatbuffers.number_types.UOffsetTFlags.py_type(4))
def CreateAbility(builder, id, distance):
builder.Prep(4, 8)
builder.PrependUint32(distance)
builder.PrependUint32(id)
return builder.Offset()

View File

@@ -1,4 +1,6 @@
// automatically generated by the FlatBuffers compiler, do not modify // <auto-generated>
// automatically generated by the FlatBuffers compiler, do not modify
// </auto-generated>
namespace MyGame.Example namespace MyGame.Example
{ {

View File

@@ -1,4 +1,6 @@
// automatically generated by the FlatBuffers compiler, do not modify // <auto-generated>
// automatically generated by the FlatBuffers compiler, do not modify
// </auto-generated>
namespace MyGame.Example namespace MyGame.Example
{ {

View File

@@ -1,10 +1,12 @@
// automatically generated by the FlatBuffers compiler, do not modify // <auto-generated>
// automatically generated by the FlatBuffers compiler, do not modify
// </auto-generated>
namespace MyGame.Example namespace MyGame.Example
{ {
using System; using global::System;
using FlatBuffers; using global::FlatBuffers;
/// an example documentation comment: monster object /// an example documentation comment: monster object
public struct Monster : IFlatbufferObject public struct Monster : IFlatbufferObject
@@ -41,6 +43,7 @@ public struct Monster : IFlatbufferObject
/// multiline too /// multiline too
public Monster? Testarrayoftables(int j) { int o = __p.__offset(26); return o != 0 ? (Monster?)(new Monster()).__assign(__p.__indirect(__p.__vector(o) + j * 4), __p.bb) : null; } public Monster? Testarrayoftables(int j) { int o = __p.__offset(26); return o != 0 ? (Monster?)(new Monster()).__assign(__p.__indirect(__p.__vector(o) + j * 4), __p.bb) : null; }
public int TestarrayoftablesLength { get { int o = __p.__offset(26); return o != 0 ? __p.__vector_len(o) : 0; } } public int TestarrayoftablesLength { get { int o = __p.__offset(26); return o != 0 ? __p.__vector_len(o) : 0; } }
public Monster? TestarrayoftablesByKey(string key) { int o = __p.__offset(26); return o != 0 ? Monster.__lookup_by_key(__p.__vector(o), key, __p.bb) : null; }
public Monster? Enemy { get { int o = __p.__offset(28); return o != 0 ? (Monster?)(new Monster()).__assign(__p.__indirect(o + __p.bb_pos), __p.bb) : null; } } public Monster? Enemy { get { int o = __p.__offset(28); return o != 0 ? (Monster?)(new Monster()).__assign(__p.__indirect(o + __p.bb_pos), __p.bb) : null; } }
public byte Testnestedflatbuffer(int j) { int o = __p.__offset(30); return o != 0 ? __p.bb.Get(__p.__vector(o) + j * 1) : (byte)0; } public byte Testnestedflatbuffer(int j) { int o = __p.__offset(30); return o != 0 ? __p.bb.Get(__p.__vector(o) + j * 1) : (byte)0; }
public int TestnestedflatbufferLength { get { int o = __p.__offset(30); return o != 0 ? __p.__vector_len(o) : 0; } } public int TestnestedflatbufferLength { get { int o = __p.__offset(30); return o != 0 ? __p.__vector_len(o) : 0; } }
@@ -78,8 +81,14 @@ public struct Monster : IFlatbufferObject
public bool MutateTestf3(float testf3) { int o = __p.__offset(58); if (o != 0) { __p.bb.PutFloat(o + __p.bb_pos, testf3); return true; } else { return false; } } public bool MutateTestf3(float testf3) { int o = __p.__offset(58); if (o != 0) { __p.bb.PutFloat(o + __p.bb_pos, testf3); return true; } else { return false; } }
public string Testarrayofstring2(int j) { int o = __p.__offset(60); return o != 0 ? __p.__string(__p.__vector(o) + j * 4) : null; } public string Testarrayofstring2(int j) { int o = __p.__offset(60); return o != 0 ? __p.__string(__p.__vector(o) + j * 4) : null; }
public int Testarrayofstring2Length { get { int o = __p.__offset(60); return o != 0 ? __p.__vector_len(o) : 0; } } public int Testarrayofstring2Length { get { int o = __p.__offset(60); return o != 0 ? __p.__vector_len(o) : 0; } }
public Ability? Testarrayofsortedstruct(int j) { int o = __p.__offset(62); return o != 0 ? (Ability?)(new Ability()).__assign(__p.__vector(o) + j * 8, __p.bb) : null; }
public int TestarrayofsortedstructLength { get { int o = __p.__offset(62); return o != 0 ? __p.__vector_len(o) : 0; } }
public byte Flex(int j) { int o = __p.__offset(64); return o != 0 ? __p.bb.Get(__p.__vector(o) + j * 1) : (byte)0; }
public int FlexLength { get { int o = __p.__offset(64); return o != 0 ? __p.__vector_len(o) : 0; } }
public ArraySegment<byte>? GetFlexBytes() { return __p.__vector_as_arraysegment(64); }
public bool MutateFlex(int j, byte flex) { int o = __p.__offset(64); if (o != 0) { __p.bb.Put(__p.__vector(o) + j * 1, flex); return true; } else { return false; } }
public static void StartMonster(FlatBufferBuilder builder) { builder.StartObject(29); } public static void StartMonster(FlatBufferBuilder builder) { builder.StartObject(31); }
public static void AddPos(FlatBufferBuilder builder, Offset<Vec3> posOffset) { builder.AddStruct(0, posOffset.Value, 0); } public static void AddPos(FlatBufferBuilder builder, Offset<Vec3> posOffset) { builder.AddStruct(0, posOffset.Value, 0); }
public static void AddMana(FlatBufferBuilder builder, short mana) { builder.AddShort(1, mana, 150); } public static void AddMana(FlatBufferBuilder builder, short mana) { builder.AddShort(1, mana, 150); }
public static void AddHp(FlatBufferBuilder builder, short hp) { builder.AddShort(2, hp, 100); } public static void AddHp(FlatBufferBuilder builder, short hp) { builder.AddShort(2, hp, 100); }
@@ -121,6 +130,11 @@ public struct Monster : IFlatbufferObject
public static void AddTestarrayofstring2(FlatBufferBuilder builder, VectorOffset testarrayofstring2Offset) { builder.AddOffset(28, testarrayofstring2Offset.Value, 0); } public static void AddTestarrayofstring2(FlatBufferBuilder builder, VectorOffset testarrayofstring2Offset) { builder.AddOffset(28, testarrayofstring2Offset.Value, 0); }
public static VectorOffset CreateTestarrayofstring2Vector(FlatBufferBuilder builder, StringOffset[] data) { builder.StartVector(4, data.Length, 4); for (int i = data.Length - 1; i >= 0; i--) builder.AddOffset(data[i].Value); return builder.EndVector(); } public static VectorOffset CreateTestarrayofstring2Vector(FlatBufferBuilder builder, StringOffset[] data) { builder.StartVector(4, data.Length, 4); for (int i = data.Length - 1; i >= 0; i--) builder.AddOffset(data[i].Value); return builder.EndVector(); }
public static void StartTestarrayofstring2Vector(FlatBufferBuilder builder, int numElems) { builder.StartVector(4, numElems, 4); } public static void StartTestarrayofstring2Vector(FlatBufferBuilder builder, int numElems) { builder.StartVector(4, numElems, 4); }
public static void AddTestarrayofsortedstruct(FlatBufferBuilder builder, VectorOffset testarrayofsortedstructOffset) { builder.AddOffset(29, testarrayofsortedstructOffset.Value, 0); }
public static void StartTestarrayofsortedstructVector(FlatBufferBuilder builder, int numElems) { builder.StartVector(8, numElems, 4); }
public static void AddFlex(FlatBufferBuilder builder, VectorOffset flexOffset) { builder.AddOffset(30, flexOffset.Value, 0); }
public static VectorOffset CreateFlexVector(FlatBufferBuilder builder, byte[] data) { builder.StartVector(1, data.Length, 1); for (int i = data.Length - 1; i >= 0; i--) builder.AddByte(data[i]); return builder.EndVector(); }
public static void StartFlexVector(FlatBufferBuilder builder, int numElems) { builder.StartVector(1, numElems, 1); }
public static Offset<Monster> EndMonster(FlatBufferBuilder builder) { public static Offset<Monster> EndMonster(FlatBufferBuilder builder) {
int o = builder.EndObject(); int o = builder.EndObject();
builder.Required(o, 10); // name builder.Required(o, 10); // name
@@ -128,17 +142,15 @@ public struct Monster : IFlatbufferObject
} }
public static void FinishMonsterBuffer(FlatBufferBuilder builder, Offset<Monster> offset) { builder.Finish(offset.Value, "MONS"); } public static void FinishMonsterBuffer(FlatBufferBuilder builder, Offset<Monster> offset) { builder.Finish(offset.Value, "MONS"); }
public static VectorOffset CreateMySortedVectorOfTables(FlatBufferBuilder builder, Offset<Monster>[] offsets) { public static VectorOffset CreateSortedVectorOfMonster(FlatBufferBuilder builder, Offset<Monster>[] offsets) {
Array.Sort(offsets, (Offset<Monster> o1, Offset<Monster> o2) => Table.CompareStrings(Table.__offset(10, o1.Value, builder.DataBuffer), Table.__offset(10, o2.Value, builder.DataBuffer), builder.DataBuffer)); Array.Sort(offsets, (Offset<Monster> o1, Offset<Monster> o2) => Table.CompareStrings(Table.__offset(10, o1.Value, builder.DataBuffer), Table.__offset(10, o2.Value, builder.DataBuffer), builder.DataBuffer));
return builder.CreateVectorOfTables(offsets); return builder.CreateVectorOfTables(offsets);
} }
public static Monster? LookupByKey(VectorOffset vectorOffset, string key, ByteBuffer bb) { public static Monster? __lookup_by_key(int vectorLocation, string key, ByteBuffer bb) {
byte[] byteKey = System.Text.Encoding.UTF8.GetBytes(key); byte[] byteKey = System.Text.Encoding.UTF8.GetBytes(key);
int vectorLocation = bb.Length - vectorOffset.Value; int span = bb.GetInt(vectorLocation - 4);
int span = bb.GetInt(vectorLocation);
int start = 0; int start = 0;
vectorLocation += 4;
while (span != 0) { while (span != 0) {
int middle = span / 2; int middle = span / 2;
int tableOffset = Table.__indirect(vectorLocation + 4 * (start + middle), bb); int tableOffset = Table.__indirect(vectorLocation + 4 * (start + middle), bb);

View File

@@ -419,8 +419,52 @@ func (rcv *Monster) Testarrayofstring2Length() int {
return 0 return 0
} }
func (rcv *Monster) Testarrayofsortedstruct(obj *Ability, j int) bool {
o := flatbuffers.UOffsetT(rcv._tab.Offset(62))
if o != 0 {
x := rcv._tab.Vector(o)
x += flatbuffers.UOffsetT(j) * 8
obj.Init(rcv._tab.Bytes, x)
return true
}
return false
}
func (rcv *Monster) TestarrayofsortedstructLength() int {
o := flatbuffers.UOffsetT(rcv._tab.Offset(62))
if o != 0 {
return rcv._tab.VectorLen(o)
}
return 0
}
func (rcv *Monster) Flex(j int) byte {
o := flatbuffers.UOffsetT(rcv._tab.Offset(64))
if o != 0 {
a := rcv._tab.Vector(o)
return rcv._tab.GetByte(a + flatbuffers.UOffsetT(j*1))
}
return 0
}
func (rcv *Monster) FlexLength() int {
o := flatbuffers.UOffsetT(rcv._tab.Offset(64))
if o != 0 {
return rcv._tab.VectorLen(o)
}
return 0
}
func (rcv *Monster) FlexBytes() []byte {
o := flatbuffers.UOffsetT(rcv._tab.Offset(64))
if o != 0 {
return rcv._tab.ByteVector(o + rcv._tab.Pos)
}
return nil
}
func MonsterStart(builder *flatbuffers.Builder) { func MonsterStart(builder *flatbuffers.Builder) {
builder.StartObject(29) builder.StartObject(31)
} }
func MonsterAddPos(builder *flatbuffers.Builder, pos flatbuffers.UOffsetT) { func MonsterAddPos(builder *flatbuffers.Builder, pos flatbuffers.UOffsetT) {
builder.PrependStructSlot(0, flatbuffers.UOffsetT(pos), 0) builder.PrependStructSlot(0, flatbuffers.UOffsetT(pos), 0)
@@ -527,6 +571,18 @@ func MonsterAddTestarrayofstring2(builder *flatbuffers.Builder, testarrayofstrin
func MonsterStartTestarrayofstring2Vector(builder *flatbuffers.Builder, numElems int) flatbuffers.UOffsetT { func MonsterStartTestarrayofstring2Vector(builder *flatbuffers.Builder, numElems int) flatbuffers.UOffsetT {
return builder.StartVector(4, numElems, 4) return builder.StartVector(4, numElems, 4)
} }
func MonsterAddTestarrayofsortedstruct(builder *flatbuffers.Builder, testarrayofsortedstruct flatbuffers.UOffsetT) {
builder.PrependUOffsetTSlot(29, flatbuffers.UOffsetT(testarrayofsortedstruct), 0)
}
func MonsterStartTestarrayofsortedstructVector(builder *flatbuffers.Builder, numElems int) flatbuffers.UOffsetT {
return builder.StartVector(8, numElems, 4)
}
func MonsterAddFlex(builder *flatbuffers.Builder, flex flatbuffers.UOffsetT) {
builder.PrependUOffsetTSlot(30, flatbuffers.UOffsetT(flex), 0)
}
func MonsterStartFlexVector(builder *flatbuffers.Builder, numElems int) flatbuffers.UOffsetT {
return builder.StartVector(1, numElems, 1)
}
func MonsterEnd(builder *flatbuffers.Builder) flatbuffers.UOffsetT { func MonsterEnd(builder *flatbuffers.Builder) flatbuffers.UOffsetT {
return builder.EndObject() return builder.EndObject()
} }

View File

@@ -47,6 +47,7 @@ public final class Monster extends Table {
public Monster testarrayoftables(int j) { return testarrayoftables(new Monster(), j); } public Monster testarrayoftables(int j) { return testarrayoftables(new Monster(), j); }
public Monster testarrayoftables(Monster obj, int j) { int o = __offset(26); return o != 0 ? obj.__assign(__indirect(__vector(o) + j * 4), bb) : null; } public Monster testarrayoftables(Monster obj, int j) { int o = __offset(26); return o != 0 ? obj.__assign(__indirect(__vector(o) + j * 4), bb) : null; }
public int testarrayoftablesLength() { int o = __offset(26); return o != 0 ? __vector_len(o) : 0; } public int testarrayoftablesLength() { int o = __offset(26); return o != 0 ? __vector_len(o) : 0; }
public Monster testarrayoftablesByKey(String key) { int o = __offset(26); return o != 0 ? Monster.__lookup_by_key(__vector(o), key, bb) : null; }
public Monster enemy() { return enemy(new Monster()); } public Monster enemy() { return enemy(new Monster()); }
public Monster enemy(Monster obj) { int o = __offset(28); return o != 0 ? obj.__assign(__indirect(o + bb_pos), bb) : null; } public Monster enemy(Monster obj) { int o = __offset(28); return o != 0 ? obj.__assign(__indirect(o + bb_pos), bb) : null; }
public int testnestedflatbuffer(int j) { int o = __offset(30); return o != 0 ? bb.get(__vector(o) + j * 1) & 0xFF : 0; } public int testnestedflatbuffer(int j) { int o = __offset(30); return o != 0 ? bb.get(__vector(o) + j * 1) & 0xFF : 0; }
@@ -87,8 +88,15 @@ public final class Monster extends Table {
public boolean mutateTestf3(float testf3) { int o = __offset(58); if (o != 0) { bb.putFloat(o + bb_pos, testf3); return true; } else { return false; } } public boolean mutateTestf3(float testf3) { int o = __offset(58); if (o != 0) { bb.putFloat(o + bb_pos, testf3); return true; } else { return false; } }
public String testarrayofstring2(int j) { int o = __offset(60); return o != 0 ? __string(__vector(o) + j * 4) : null; } public String testarrayofstring2(int j) { int o = __offset(60); return o != 0 ? __string(__vector(o) + j * 4) : null; }
public int testarrayofstring2Length() { int o = __offset(60); return o != 0 ? __vector_len(o) : 0; } public int testarrayofstring2Length() { int o = __offset(60); return o != 0 ? __vector_len(o) : 0; }
public Ability testarrayofsortedstruct(int j) { return testarrayofsortedstruct(new Ability(), j); }
public Ability testarrayofsortedstruct(Ability obj, int j) { int o = __offset(62); return o != 0 ? obj.__assign(__vector(o) + j * 8, bb) : null; }
public int testarrayofsortedstructLength() { int o = __offset(62); return o != 0 ? __vector_len(o) : 0; }
public int flex(int j) { int o = __offset(64); return o != 0 ? bb.get(__vector(o) + j * 1) & 0xFF : 0; }
public int flexLength() { int o = __offset(64); return o != 0 ? __vector_len(o) : 0; }
public ByteBuffer flexAsByteBuffer() { return __vector_as_bytebuffer(64, 1); }
public boolean mutateFlex(int j, int flex) { int o = __offset(64); if (o != 0) { bb.put(__vector(o) + j * 1, (byte)flex); return true; } else { return false; } }
public static void startMonster(FlatBufferBuilder builder) { builder.startObject(29); } public static void startMonster(FlatBufferBuilder builder) { builder.startObject(31); }
public static void addPos(FlatBufferBuilder builder, int posOffset) { builder.addStruct(0, posOffset, 0); } public static void addPos(FlatBufferBuilder builder, int posOffset) { builder.addStruct(0, posOffset, 0); }
public static void addMana(FlatBufferBuilder builder, short mana) { builder.addShort(1, mana, 150); } public static void addMana(FlatBufferBuilder builder, short mana) { builder.addShort(1, mana, 150); }
public static void addHp(FlatBufferBuilder builder, short hp) { builder.addShort(2, hp, 100); } public static void addHp(FlatBufferBuilder builder, short hp) { builder.addShort(2, hp, 100); }
@@ -130,6 +138,11 @@ public final class Monster extends Table {
public static void addTestarrayofstring2(FlatBufferBuilder builder, int testarrayofstring2Offset) { builder.addOffset(28, testarrayofstring2Offset, 0); } public static void addTestarrayofstring2(FlatBufferBuilder builder, int testarrayofstring2Offset) { builder.addOffset(28, testarrayofstring2Offset, 0); }
public static int createTestarrayofstring2Vector(FlatBufferBuilder builder, int[] data) { builder.startVector(4, data.length, 4); for (int i = data.length - 1; i >= 0; i--) builder.addOffset(data[i]); return builder.endVector(); } public static int createTestarrayofstring2Vector(FlatBufferBuilder builder, int[] data) { builder.startVector(4, data.length, 4); for (int i = data.length - 1; i >= 0; i--) builder.addOffset(data[i]); return builder.endVector(); }
public static void startTestarrayofstring2Vector(FlatBufferBuilder builder, int numElems) { builder.startVector(4, numElems, 4); } public static void startTestarrayofstring2Vector(FlatBufferBuilder builder, int numElems) { builder.startVector(4, numElems, 4); }
public static void addTestarrayofsortedstruct(FlatBufferBuilder builder, int testarrayofsortedstructOffset) { builder.addOffset(29, testarrayofsortedstructOffset, 0); }
public static void startTestarrayofsortedstructVector(FlatBufferBuilder builder, int numElems) { builder.startVector(8, numElems, 4); }
public static void addFlex(FlatBufferBuilder builder, int flexOffset) { builder.addOffset(30, flexOffset, 0); }
public static int createFlexVector(FlatBufferBuilder builder, byte[] data) { builder.startVector(1, data.length, 1); for (int i = data.length - 1; i >= 0; i--) builder.addByte(data[i]); return builder.endVector(); }
public static void startFlexVector(FlatBufferBuilder builder, int numElems) { builder.startVector(1, numElems, 1); }
public static int endMonster(FlatBufferBuilder builder) { public static int endMonster(FlatBufferBuilder builder) {
int o = builder.endObject(); int o = builder.endObject();
builder.required(o, 10); // name builder.required(o, 10); // name
@@ -140,12 +153,10 @@ public final class Monster extends Table {
@Override @Override
protected int keysCompare(Integer o1, Integer o2, ByteBuffer _bb) { return compareStrings(__offset(10, o1, _bb), __offset(10, o2, _bb), _bb); } protected int keysCompare(Integer o1, Integer o2, ByteBuffer _bb) { return compareStrings(__offset(10, o1, _bb), __offset(10, o2, _bb), _bb); }
public static Monster lookupByKey(int vectorOffset, String key, ByteBuffer bb) { public static Monster __lookup_by_key(int vectorLocation, String key, ByteBuffer bb) {
byte[] byteKey = key.getBytes(Table.UTF8_CHARSET.get()); byte[] byteKey = key.getBytes(Table.UTF8_CHARSET.get());
int vectorLocation = bb.array().length - vectorOffset; int span = bb.getInt(vectorLocation - 4);
int span = bb.getInt(vectorLocation);
int start = 0; int start = 0;
vectorLocation += 4;
while (span != 0) { while (span != 0) {
int middle = span / 2; int middle = span / 2;
int tableOffset = __indirect(vectorLocation + 4 * (start + middle), bb); int tableOffset = __indirect(vectorLocation + 4 * (start + middle), bb);

View File

@@ -379,22 +379,68 @@ class Monster extends Table
return $o != 0 ? $this->__vector_len($o) : 0; return $o != 0 ? $this->__vector_len($o) : 0;
} }
/**
* @returnVectorOffset
*/
public function getTestarrayofsortedstruct($j)
{
$o = $this->__offset(62);
$obj = new Ability();
return $o != 0 ? $obj->init($this->__vector($o) + $j *8, $this->bb) : null;
}
/**
* @return int
*/
public function getTestarrayofsortedstructLength()
{
$o = $this->__offset(62);
return $o != 0 ? $this->__vector_len($o) : 0;
}
/**
* @param int offset
* @return byte
*/
public function getFlex($j)
{
$o = $this->__offset(64);
return $o != 0 ? $this->bb->getByte($this->__vector($o) + $j * 1) : 0;
}
/**
* @return int
*/
public function getFlexLength()
{
$o = $this->__offset(64);
return $o != 0 ? $this->__vector_len($o) : 0;
}
/**
* @return string
*/
public function getFlexBytes()
{
return $this->__vector_as_bytes(64);
}
/** /**
* @param FlatBufferBuilder $builder * @param FlatBufferBuilder $builder
* @return void * @return void
*/ */
public static function startMonster(FlatBufferBuilder $builder) public static function startMonster(FlatBufferBuilder $builder)
{ {
$builder->StartObject(29); $builder->StartObject(31);
} }
/** /**
* @param FlatBufferBuilder $builder * @param FlatBufferBuilder $builder
* @return Monster * @return Monster
*/ */
public static function createMonster(FlatBufferBuilder $builder, $pos, $mana, $hp, $name, $inventory, $color, $test_type, $test, $test4, $testarrayofstring, $testarrayoftables, $enemy, $testnestedflatbuffer, $testempty, $testbool, $testhashs32_fnv1, $testhashu32_fnv1, $testhashs64_fnv1, $testhashu64_fnv1, $testhashs32_fnv1a, $testhashu32_fnv1a, $testhashs64_fnv1a, $testhashu64_fnv1a, $testarrayofbools, $testf, $testf2, $testf3, $testarrayofstring2) public static function createMonster(FlatBufferBuilder $builder, $pos, $mana, $hp, $name, $inventory, $color, $test_type, $test, $test4, $testarrayofstring, $testarrayoftables, $enemy, $testnestedflatbuffer, $testempty, $testbool, $testhashs32_fnv1, $testhashu32_fnv1, $testhashs64_fnv1, $testhashu64_fnv1, $testhashs32_fnv1a, $testhashu32_fnv1a, $testhashs64_fnv1a, $testhashu64_fnv1a, $testarrayofbools, $testf, $testf2, $testf3, $testarrayofstring2, $testarrayofsortedstruct, $flex)
{ {
$builder->startObject(29); $builder->startObject(31);
self::addPos($builder, $pos); self::addPos($builder, $pos);
self::addMana($builder, $mana); self::addMana($builder, $mana);
self::addHp($builder, $hp); self::addHp($builder, $hp);
@@ -423,6 +469,8 @@ class Monster extends Table
self::addTestf2($builder, $testf2); self::addTestf2($builder, $testf2);
self::addTestf3($builder, $testf3); self::addTestf3($builder, $testf3);
self::addTestarrayofstring2($builder, $testarrayofstring2); self::addTestarrayofstring2($builder, $testarrayofstring2);
self::addTestarrayofsortedstruct($builder, $testarrayofsortedstruct);
self::addFlex($builder, $flex);
$o = $builder->endObject(); $o = $builder->endObject();
$builder->required($o, 10); // name $builder->required($o, 10); // name
return $o; return $o;
@@ -871,6 +919,74 @@ class Monster extends Table
$builder->startVector(4, $numElems, 4); $builder->startVector(4, $numElems, 4);
} }
/**
* @param FlatBufferBuilder $builder
* @param VectorOffset
* @return void
*/
public static function addTestarrayofsortedstruct(FlatBufferBuilder $builder, $testarrayofsortedstruct)
{
$builder->addOffsetX(29, $testarrayofsortedstruct, 0);
}
/**
* @param FlatBufferBuilder $builder
* @param array offset array
* @return int vector offset
*/
public static function createTestarrayofsortedstructVector(FlatBufferBuilder $builder, array $data)
{
$builder->startVector(8, count($data), 4);
for ($i = count($data) - 1; $i >= 0; $i--) {
$builder->addOffset($data[$i]);
}
return $builder->endVector();
}
/**
* @param FlatBufferBuilder $builder
* @param int $numElems
* @return void
*/
public static function startTestarrayofsortedstructVector(FlatBufferBuilder $builder, $numElems)
{
$builder->startVector(8, $numElems, 4);
}
/**
* @param FlatBufferBuilder $builder
* @param VectorOffset
* @return void
*/
public static function addFlex(FlatBufferBuilder $builder, $flex)
{
$builder->addOffsetX(30, $flex, 0);
}
/**
* @param FlatBufferBuilder $builder
* @param array offset array
* @return int vector offset
*/
public static function createFlexVector(FlatBufferBuilder $builder, array $data)
{
$builder->startVector(1, count($data), 1);
for ($i = count($data) - 1; $i >= 0; $i--) {
$builder->addByte($data[$i]);
}
return $builder->endVector();
}
/**
* @param FlatBufferBuilder $builder
* @param int $numElems
* @return void
*/
public static function startFlexVector(FlatBufferBuilder $builder, $numElems)
{
$builder->startVector(1, $numElems, 1);
}
/** /**
* @param FlatBufferBuilder $builder * @param FlatBufferBuilder $builder
* @return int table offset * @return int table offset

View File

@@ -297,7 +297,41 @@ class Monster(object):
return self._tab.VectorLen(o) return self._tab.VectorLen(o)
return 0 return 0
def MonsterStart(builder): builder.StartObject(29) # Monster
def Testarrayofsortedstruct(self, j):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(62))
if o != 0:
x = self._tab.Vector(o)
x += flatbuffers.number_types.UOffsetTFlags.py_type(j) * 8
from .Ability import Ability
obj = Ability()
obj.Init(self._tab.Bytes, x)
return obj
return None
# Monster
def TestarrayofsortedstructLength(self):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(62))
if o != 0:
return self._tab.VectorLen(o)
return 0
# Monster
def Flex(self, j):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(64))
if o != 0:
a = self._tab.Vector(o)
return self._tab.Get(flatbuffers.number_types.Uint8Flags, a + flatbuffers.number_types.UOffsetTFlags.py_type(j * 1))
return 0
# Monster
def FlexLength(self):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(64))
if o != 0:
return self._tab.VectorLen(o)
return 0
def MonsterStart(builder): builder.StartObject(31)
def MonsterAddPos(builder, pos): builder.PrependStructSlot(0, flatbuffers.number_types.UOffsetTFlags.py_type(pos), 0) def MonsterAddPos(builder, pos): builder.PrependStructSlot(0, flatbuffers.number_types.UOffsetTFlags.py_type(pos), 0)
def MonsterAddMana(builder, mana): builder.PrependInt16Slot(1, mana, 150) def MonsterAddMana(builder, mana): builder.PrependInt16Slot(1, mana, 150)
def MonsterAddHp(builder, hp): builder.PrependInt16Slot(2, hp, 100) def MonsterAddHp(builder, hp): builder.PrependInt16Slot(2, hp, 100)
@@ -333,4 +367,8 @@ def MonsterAddTestf2(builder, testf2): builder.PrependFloat32Slot(26, testf2, 3.
def MonsterAddTestf3(builder, testf3): builder.PrependFloat32Slot(27, testf3, 0.0) def MonsterAddTestf3(builder, testf3): builder.PrependFloat32Slot(27, testf3, 0.0)
def MonsterAddTestarrayofstring2(builder, testarrayofstring2): builder.PrependUOffsetTRelativeSlot(28, flatbuffers.number_types.UOffsetTFlags.py_type(testarrayofstring2), 0) def MonsterAddTestarrayofstring2(builder, testarrayofstring2): builder.PrependUOffsetTRelativeSlot(28, flatbuffers.number_types.UOffsetTFlags.py_type(testarrayofstring2), 0)
def MonsterStartTestarrayofstring2Vector(builder, numElems): return builder.StartVector(4, numElems, 4) def MonsterStartTestarrayofstring2Vector(builder, numElems): return builder.StartVector(4, numElems, 4)
def MonsterAddTestarrayofsortedstruct(builder, testarrayofsortedstruct): builder.PrependUOffsetTRelativeSlot(29, flatbuffers.number_types.UOffsetTFlags.py_type(testarrayofsortedstruct), 0)
def MonsterStartTestarrayofsortedstructVector(builder, numElems): return builder.StartVector(8, numElems, 4)
def MonsterAddFlex(builder, flex): builder.PrependUOffsetTRelativeSlot(30, flatbuffers.number_types.UOffsetTFlags.py_type(flex), 0)
def MonsterStartFlexVector(builder, numElems): return builder.StartVector(1, numElems, 1)
def MonsterEnd(builder): return builder.EndObject() def MonsterEnd(builder): return builder.EndObject()

View File

@@ -1,10 +1,12 @@
// automatically generated by the FlatBuffers compiler, do not modify // <auto-generated>
// automatically generated by the FlatBuffers compiler, do not modify
// </auto-generated>
namespace MyGame.Example namespace MyGame.Example
{ {
using System; using global::System;
using FlatBuffers; using global::FlatBuffers;
public struct Stat : IFlatbufferObject public struct Stat : IFlatbufferObject
{ {

View File

@@ -1,10 +1,12 @@
// automatically generated by the FlatBuffers compiler, do not modify // <auto-generated>
// automatically generated by the FlatBuffers compiler, do not modify
// </auto-generated>
namespace MyGame.Example namespace MyGame.Example
{ {
using System; using global::System;
using FlatBuffers; using global::FlatBuffers;
public struct Test : IFlatbufferObject public struct Test : IFlatbufferObject
{ {

View File

@@ -1,10 +1,12 @@
// automatically generated by the FlatBuffers compiler, do not modify // <auto-generated>
// automatically generated by the FlatBuffers compiler, do not modify
// </auto-generated>
namespace MyGame.Example namespace MyGame.Example
{ {
using System; using global::System;
using FlatBuffers; using global::FlatBuffers;
public partial struct TestSimpleTableWithEnum : IFlatbufferObject public partial struct TestSimpleTableWithEnum : IFlatbufferObject
{ {

View File

@@ -1,10 +1,12 @@
// automatically generated by the FlatBuffers compiler, do not modify // <auto-generated>
// automatically generated by the FlatBuffers compiler, do not modify
// </auto-generated>
namespace MyGame.Example namespace MyGame.Example
{ {
using System; using global::System;
using FlatBuffers; using global::FlatBuffers;
public struct Vec3 : IFlatbufferObject public struct Vec3 : IFlatbufferObject
{ {

View File

@@ -1,10 +1,12 @@
// automatically generated by the FlatBuffers compiler, do not modify // <auto-generated>
// automatically generated by the FlatBuffers compiler, do not modify
// </auto-generated>
namespace MyGame.Example2 namespace MyGame.Example2
{ {
using System; using global::System;
using FlatBuffers; using global::FlatBuffers;
public struct Monster : IFlatbufferObject public struct Monster : IFlatbufferObject
{ {

View File

@@ -20,7 +20,7 @@ gen_code_path=${test_dir}
runtime_library_dir=${test_dir}/../python runtime_library_dir=${test_dir}/../python
# Emit Python code for the example schema in the test dir: # Emit Python code for the example schema in the test dir:
${test_dir}/../flatc -p -o ${gen_code_path} monster_test.fbs ${test_dir}/../flatc -p -o ${gen_code_path} -I include_test monster_test.fbs
# Syntax: run_tests <interpreter> <benchmark vtable dedupes> # Syntax: run_tests <interpreter> <benchmark vtable dedupes>
# <benchmark read count> <benchmark build count> # <benchmark read count> <benchmark build count>

43
tests/TestAll.sh Normal file
View File

@@ -0,0 +1,43 @@
echo "************************ Java:"
sh JavaTest.sh
echo "************************ Go:"
sh GoTest.sh
echo "************************ Python:"
sh PythonTest.sh
echo "************************ JavaScript:"
sh JavaScriptTest.sh
echo "************************ TypeScript:"
sh TypeScriptTest.sh
echo "************************ C++:"
cd ..
./flattests
cd tests
echo "************************ C#:"
cd FlatBuffers.Test
sh NetTest.sh
cd ..
echo "************************ PHP:"
php phpTest.php
echo "************************ C:"
echo "(in a different repo)"
echo "************************ Swift:"
echo "(in a different repo)"

23
tests/TypeScriptTest.sh Executable file
View File

@@ -0,0 +1,23 @@
#!/bin/sh
#
# 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.
pushd "$(dirname $0)" >/dev/null
../flatc --ts --no-fb-import --gen-mutable -o ts -I include_test monster_test.fbs
../flatc -b -I include_test monster_test.fbs unicode_test.json
npm install @types/flatbuffers
tsc --strict --noUnusedParameters --noUnusedLocals --noImplicitReturns --strictNullChecks ts/monster_test_generated.ts
npm uninstall @types/flatbuffers
node JavaScriptTest ./ts/monster_test_generated

View File

@@ -15,6 +15,6 @@
set buildtype=Release set buildtype=Release
if "%1"=="-b" set buildtype=%2 if "%1"=="-b" set buildtype=%2
..\%buildtype%\flatc.exe --cpp --java --csharp --go --binary --python --js --php --grpc --gen-mutable --gen-object-api --no-includes monster_test.fbs monsterdata_test.json ..\%buildtype%\flatc.exe --cpp --java --csharp --go --binary --python --js --php --grpc --gen-mutable --gen-object-api --no-includes -I include_test monster_test.fbs monsterdata_test.json
..\%buildtype%\flatc.exe --cpp --java --csharp --go --binary --python --js --php --gen-mutable -o namespace_test namespace_test\namespace_test1.fbs namespace_test\namespace_test2.fbs ..\%buildtype%\flatc.exe --cpp --java --csharp --go --binary --python --js --php --gen-mutable -o namespace_test namespace_test\namespace_test1.fbs namespace_test\namespace_test2.fbs
..\%buildtype%\flatc.exe --binary --schema monster_test.fbs ..\%buildtype%\flatc.exe --binary --schema -I include_test monster_test.fbs

View File

@@ -14,11 +14,10 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
../flatc --cpp --java --csharp --go --binary --python --js --php --grpc --gen-mutable --gen-object-api --no-includes monster_test.fbs monsterdata_test.json ../flatc --cpp --java --csharp --go --binary --python --js --ts --php --grpc --gen-mutable --gen-object-api --no-includes --no-fb-import -I include_test monster_test.fbs monsterdata_test.json
../flatc --cpp --java --csharp --go --binary --python --js --php --gen-mutable -o namespace_test namespace_test/namespace_test1.fbs namespace_test/namespace_test2.fbs ../flatc --cpp --java --csharp --go --binary --python --js --ts --php --gen-mutable --no-fb-import -o namespace_test namespace_test/namespace_test1.fbs namespace_test/namespace_test2.fbs
../flatc --cpp -o union_vector ./union_vector/union_vector.fbs ../flatc --cpp --gen-mutable --gen-object-api -o union_vector ./union_vector/union_vector.fbs
../flatc -b --schema --bfbs-comments monster_test.fbs ../flatc -b --schema --bfbs-comments -I include_test monster_test.fbs
cd ../samples cd ../samples
../flatc --cpp --gen-mutable --gen-object-api monster.fbs ../flatc --cpp --gen-mutable --gen-object-api monster.fbs
cd ../reflection cd ../reflection
sh generate_code.sh

View File

@@ -0,0 +1,5 @@
include "sub/include_test2.fbs";
include "sub/include_test2.fbs"; // should be skipped
include "include_test1.fbs"; // should be skipped

View File

@@ -1,4 +1,4 @@
include "include_test2.fbs"; // should be skipped include "sub/include_test2.fbs"; // should be skipped
namespace MyGame.OtherNameSpace; namespace MyGame.OtherNameSpace;

View File

@@ -1,5 +0,0 @@
include "include_test2.fbs";
include "include_test2.fbs"; // should be skipped
include "include_test1.fbs"; // should be skipped

Binary file not shown.

View File

@@ -29,6 +29,11 @@ struct Vec3 (force_align: 16) {
test3:Test; test3:Test;
} }
struct Ability {
id:uint(key);
distance:uint;
}
table Stat { table Stat {
id:string; id:string;
val:long; val:long;
@@ -50,6 +55,7 @@ table Monster {
testarrayofstring:[string] (id: 10); testarrayofstring:[string] (id: 10);
testarrayofstring2:[string] (id: 28); testarrayofstring2:[string] (id: 28);
testarrayofbools:[bool] (id: 24); testarrayofbools:[bool] (id: 24);
testarrayofsortedstruct:[Ability] (id: 29);
enemy:MyGame.Example.Monster (id:12); // Test referring by full namespace. enemy:MyGame.Example.Monster (id:12); // Test referring by full namespace.
test:Any (id: 8); test:Any (id: 8);
test4:[Test] (id: 9); test4:[Test] (id: 9);
@@ -67,6 +73,7 @@ table Monster {
testf:float = 3.14159 (id:25); testf:float = 3.14159 (id:25);
testf2:float = 3 (id:26); testf2:float = 3 (id:26);
testf3:float (id:27); testf3:float (id:27);
flex:[ubyte] (id:30, flexbuffer);
} }
rpc_service MonsterStorage { rpc_service MonsterStorage {

View File

@@ -1,4 +1,4 @@
// Generated by the gRPC protobuf plugin. // Generated by the gRPC C++ plugin.
// If you make any local change, they will be lost. // If you make any local change, they will be lost.
// source: monster_test // source: monster_test
@@ -13,7 +13,6 @@
#include <grpc++/impl/codegen/rpc_service_method.h> #include <grpc++/impl/codegen/rpc_service_method.h>
#include <grpc++/impl/codegen/service_type.h> #include <grpc++/impl/codegen/service_type.h>
#include <grpc++/impl/codegen/sync_stream.h> #include <grpc++/impl/codegen/sync_stream.h>
namespace MyGame { namespace MyGame {
namespace Example { namespace Example {
@@ -32,47 +31,46 @@ MonsterStorage::Stub::Stub(const std::shared_ptr< ::grpc::ChannelInterface>& cha
, rpcmethod_Retrieve_(MonsterStorage_method_names[1], ::grpc::RpcMethod::SERVER_STREAMING, channel) , rpcmethod_Retrieve_(MonsterStorage_method_names[1], ::grpc::RpcMethod::SERVER_STREAMING, channel)
{} {}
::grpc::Status MonsterStorage::Stub::Store(::grpc::ClientContext* context, const flatbuffers::BufferRef<Monster>& request, flatbuffers::BufferRef<Stat>* response) { ::grpc::Status MonsterStorage::Stub::Store(::grpc::ClientContext* context, const flatbuffers::grpc::Message<Monster>& request, flatbuffers::grpc::Message<Stat>* response) {
return ::grpc::BlockingUnaryCall(channel_.get(), rpcmethod_Store_, context, request, response); return ::grpc::BlockingUnaryCall(channel_.get(), rpcmethod_Store_, context, request, response);
} }
::grpc::ClientAsyncResponseReader< flatbuffers::BufferRef<Stat>>* MonsterStorage::Stub::AsyncStoreRaw(::grpc::ClientContext* context, const flatbuffers::BufferRef<Monster>& request, ::grpc::CompletionQueue* cq) { ::grpc::ClientAsyncResponseReader< flatbuffers::grpc::Message<Stat>>* MonsterStorage::Stub::AsyncStoreRaw(::grpc::ClientContext* context, const flatbuffers::grpc::Message<Monster>& request, ::grpc::CompletionQueue* cq) {
return new ::grpc::ClientAsyncResponseReader< flatbuffers::BufferRef<Stat>>(channel_.get(), cq, rpcmethod_Store_, context, request); return ::grpc::ClientAsyncResponseReader< flatbuffers::grpc::Message<Stat>>::Create(channel_.get(), cq, rpcmethod_Store_, context, request);
} }
::grpc::ClientReader< flatbuffers::BufferRef<Monster>>* MonsterStorage::Stub::RetrieveRaw(::grpc::ClientContext* context, const flatbuffers::BufferRef<Stat>& request) { ::grpc::ClientReader< flatbuffers::grpc::Message<Monster>>* MonsterStorage::Stub::RetrieveRaw(::grpc::ClientContext* context, const flatbuffers::grpc::Message<Stat>& request) {
return new ::grpc::ClientReader< flatbuffers::BufferRef<Monster>>(channel_.get(), rpcmethod_Retrieve_, context, request); return new ::grpc::ClientReader< flatbuffers::grpc::Message<Monster>>(channel_.get(), rpcmethod_Retrieve_, context, request);
} }
::grpc::ClientAsyncReader< flatbuffers::BufferRef<Monster>>* MonsterStorage::Stub::AsyncRetrieveRaw(::grpc::ClientContext* context, const flatbuffers::BufferRef<Stat>& request, ::grpc::CompletionQueue* cq, void* tag) { ::grpc::ClientAsyncReader< flatbuffers::grpc::Message<Monster>>* MonsterStorage::Stub::AsyncRetrieveRaw(::grpc::ClientContext* context, const flatbuffers::grpc::Message<Stat>& request, ::grpc::CompletionQueue* cq, void* tag) {
return new ::grpc::ClientAsyncReader< flatbuffers::BufferRef<Monster>>(channel_.get(), cq, rpcmethod_Retrieve_, context, request, tag); return ::grpc::ClientAsyncReader< flatbuffers::grpc::Message<Monster>>::Create(channel_.get(), cq, rpcmethod_Retrieve_, context, request, tag);
} }
MonsterStorage::Service::Service() { MonsterStorage::Service::Service() {
(void)MonsterStorage_method_names;
AddMethod(new ::grpc::RpcServiceMethod( AddMethod(new ::grpc::RpcServiceMethod(
MonsterStorage_method_names[0], MonsterStorage_method_names[0],
::grpc::RpcMethod::NORMAL_RPC, ::grpc::RpcMethod::NORMAL_RPC,
new ::grpc::RpcMethodHandler< MonsterStorage::Service, flatbuffers::BufferRef<Monster>, flatbuffers::BufferRef<Stat>>( new ::grpc::RpcMethodHandler< MonsterStorage::Service, flatbuffers::grpc::Message<Monster>, flatbuffers::grpc::Message<Stat>>(
std::mem_fn(&MonsterStorage::Service::Store), this))); std::mem_fn(&MonsterStorage::Service::Store), this)));
AddMethod(new ::grpc::RpcServiceMethod( AddMethod(new ::grpc::RpcServiceMethod(
MonsterStorage_method_names[1], MonsterStorage_method_names[1],
::grpc::RpcMethod::SERVER_STREAMING, ::grpc::RpcMethod::SERVER_STREAMING,
new ::grpc::ServerStreamingHandler< MonsterStorage::Service, flatbuffers::BufferRef<Stat>, flatbuffers::BufferRef<Monster>>( new ::grpc::ServerStreamingHandler< MonsterStorage::Service, flatbuffers::grpc::Message<Stat>, flatbuffers::grpc::Message<Monster>>(
std::mem_fn(&MonsterStorage::Service::Retrieve), this))); std::mem_fn(&MonsterStorage::Service::Retrieve), this)));
} }
MonsterStorage::Service::~Service() { MonsterStorage::Service::~Service() {
} }
::grpc::Status MonsterStorage::Service::Store(::grpc::ServerContext* context, const flatbuffers::BufferRef<Monster>* request, flatbuffers::BufferRef<Stat>* response) { ::grpc::Status MonsterStorage::Service::Store(::grpc::ServerContext* context, const flatbuffers::grpc::Message<Monster>* request, flatbuffers::grpc::Message<Stat>* response) {
(void) context; (void) context;
(void) request; (void) request;
(void) response; (void) response;
return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "");
} }
::grpc::Status MonsterStorage::Service::Retrieve(::grpc::ServerContext* context, const flatbuffers::BufferRef<Stat>* request, ::grpc::ServerWriter< flatbuffers::BufferRef<Monster>>* writer) { ::grpc::Status MonsterStorage::Service::Retrieve(::grpc::ServerContext* context, const flatbuffers::grpc::Message<Stat>* request, ::grpc::ServerWriter< flatbuffers::grpc::Message<Monster>>* writer) {
(void) context; (void) context;
(void) request; (void) request;
(void) writer; (void) writer;

View File

@@ -1,14 +1,16 @@
// Generated by the gRPC protobuf plugin. // Generated by the gRPC C++ plugin.
// If you make any local change, they will be lost. // If you make any local change, they will be lost.
// source: monster_test // source: monster_test
#ifndef GRPC_monster_5ftest__INCLUDED #ifndef GRPC_monster_5ftest__INCLUDED
#define GRPC_monster_5ftest__INCLUDED #define GRPC_monster_5ftest__INCLUDED
#include "monster_test_generated.h"
#include "flatbuffers/grpc.h" #include "flatbuffers/grpc.h"
#include "monster_test_generated.h"
#include <grpc++/impl/codegen/async_stream.h> #include <grpc++/impl/codegen/async_stream.h>
#include <grpc++/impl/codegen/async_unary_call.h> #include <grpc++/impl/codegen/async_unary_call.h>
#include <grpc++/impl/codegen/method_handler_impl.h>
#include <grpc++/impl/codegen/proto_utils.h>
#include <grpc++/impl/codegen/rpc_method.h> #include <grpc++/impl/codegen/rpc_method.h>
#include <grpc++/impl/codegen/service_type.h> #include <grpc++/impl/codegen/service_type.h>
#include <grpc++/impl/codegen/status.h> #include <grpc++/impl/codegen/status.h>
@@ -26,45 +28,48 @@ class ServerContext;
namespace MyGame { namespace MyGame {
namespace Example { namespace Example {
class MonsterStorage GRPC_FINAL { class MonsterStorage final {
public: public:
static constexpr char const* service_full_name() {
return "MyGame.Example.MonsterStorage";
}
class StubInterface { class StubInterface {
public: public:
virtual ~StubInterface() {} virtual ~StubInterface() {}
virtual ::grpc::Status Store(::grpc::ClientContext* context, const flatbuffers::BufferRef<Monster>& request, flatbuffers::BufferRef<Stat>* response) = 0; virtual ::grpc::Status Store(::grpc::ClientContext* context, const flatbuffers::grpc::Message<Monster>& request, flatbuffers::grpc::Message<Stat>* response) = 0;
std::unique_ptr< ::grpc::ClientAsyncResponseReaderInterface< flatbuffers::BufferRef<Stat>>> AsyncStore(::grpc::ClientContext* context, const flatbuffers::BufferRef<Monster>& request, ::grpc::CompletionQueue* cq) { std::unique_ptr< ::grpc::ClientAsyncResponseReaderInterface< flatbuffers::grpc::Message<Stat>>> AsyncStore(::grpc::ClientContext* context, const flatbuffers::grpc::Message<Monster>& request, ::grpc::CompletionQueue* cq) {
return std::unique_ptr< ::grpc::ClientAsyncResponseReaderInterface< flatbuffers::BufferRef<Stat>>>(AsyncStoreRaw(context, request, cq)); return std::unique_ptr< ::grpc::ClientAsyncResponseReaderInterface< flatbuffers::grpc::Message<Stat>>>(AsyncStoreRaw(context, request, cq));
} }
std::unique_ptr< ::grpc::ClientReaderInterface< flatbuffers::BufferRef<Monster>>> Retrieve(::grpc::ClientContext* context, const flatbuffers::BufferRef<Stat>& request) { std::unique_ptr< ::grpc::ClientReaderInterface< flatbuffers::grpc::Message<Monster>>> Retrieve(::grpc::ClientContext* context, const flatbuffers::grpc::Message<Stat>& request) {
return std::unique_ptr< ::grpc::ClientReaderInterface< flatbuffers::BufferRef<Monster>>>(RetrieveRaw(context, request)); return std::unique_ptr< ::grpc::ClientReaderInterface< flatbuffers::grpc::Message<Monster>>>(RetrieveRaw(context, request));
} }
std::unique_ptr< ::grpc::ClientAsyncReaderInterface< flatbuffers::BufferRef<Monster>>> AsyncRetrieve(::grpc::ClientContext* context, const flatbuffers::BufferRef<Stat>& request, ::grpc::CompletionQueue* cq, void* tag) { std::unique_ptr< ::grpc::ClientAsyncReaderInterface< flatbuffers::grpc::Message<Monster>>> AsyncRetrieve(::grpc::ClientContext* context, const flatbuffers::grpc::Message<Stat>& request, ::grpc::CompletionQueue* cq, void* tag) {
return std::unique_ptr< ::grpc::ClientAsyncReaderInterface< flatbuffers::BufferRef<Monster>>>(AsyncRetrieveRaw(context, request, cq, tag)); return std::unique_ptr< ::grpc::ClientAsyncReaderInterface< flatbuffers::grpc::Message<Monster>>>(AsyncRetrieveRaw(context, request, cq, tag));
} }
private: private:
virtual ::grpc::ClientAsyncResponseReaderInterface< flatbuffers::BufferRef<Stat>>* AsyncStoreRaw(::grpc::ClientContext* context, const flatbuffers::BufferRef<Monster>& request, ::grpc::CompletionQueue* cq) = 0; virtual ::grpc::ClientAsyncResponseReaderInterface< flatbuffers::grpc::Message<Stat>>* AsyncStoreRaw(::grpc::ClientContext* context, const flatbuffers::grpc::Message<Monster>& request, ::grpc::CompletionQueue* cq) = 0;
virtual ::grpc::ClientReaderInterface< flatbuffers::BufferRef<Monster>>* RetrieveRaw(::grpc::ClientContext* context, const flatbuffers::BufferRef<Stat>& request) = 0; virtual ::grpc::ClientReaderInterface< flatbuffers::grpc::Message<Monster>>* RetrieveRaw(::grpc::ClientContext* context, const flatbuffers::grpc::Message<Stat>& request) = 0;
virtual ::grpc::ClientAsyncReaderInterface< flatbuffers::BufferRef<Monster>>* AsyncRetrieveRaw(::grpc::ClientContext* context, const flatbuffers::BufferRef<Stat>& request, ::grpc::CompletionQueue* cq, void* tag) = 0; virtual ::grpc::ClientAsyncReaderInterface< flatbuffers::grpc::Message<Monster>>* AsyncRetrieveRaw(::grpc::ClientContext* context, const flatbuffers::grpc::Message<Stat>& request, ::grpc::CompletionQueue* cq, void* tag) = 0;
}; };
class Stub GRPC_FINAL : public StubInterface { class Stub final : public StubInterface {
public: public:
Stub(const std::shared_ptr< ::grpc::ChannelInterface>& channel); Stub(const std::shared_ptr< ::grpc::ChannelInterface>& channel);
::grpc::Status Store(::grpc::ClientContext* context, const flatbuffers::BufferRef<Monster>& request, flatbuffers::BufferRef<Stat>* response) GRPC_OVERRIDE; ::grpc::Status Store(::grpc::ClientContext* context, const flatbuffers::grpc::Message<Monster>& request, flatbuffers::grpc::Message<Stat>* response) override;
std::unique_ptr< ::grpc::ClientAsyncResponseReader< flatbuffers::BufferRef<Stat>>> AsyncStore(::grpc::ClientContext* context, const flatbuffers::BufferRef<Monster>& request, ::grpc::CompletionQueue* cq) { std::unique_ptr< ::grpc::ClientAsyncResponseReader< flatbuffers::grpc::Message<Stat>>> AsyncStore(::grpc::ClientContext* context, const flatbuffers::grpc::Message<Monster>& request, ::grpc::CompletionQueue* cq) {
return std::unique_ptr< ::grpc::ClientAsyncResponseReader< flatbuffers::BufferRef<Stat>>>(AsyncStoreRaw(context, request, cq)); return std::unique_ptr< ::grpc::ClientAsyncResponseReader< flatbuffers::grpc::Message<Stat>>>(AsyncStoreRaw(context, request, cq));
} }
std::unique_ptr< ::grpc::ClientReader< flatbuffers::BufferRef<Monster>>> Retrieve(::grpc::ClientContext* context, const flatbuffers::BufferRef<Stat>& request) { std::unique_ptr< ::grpc::ClientReader< flatbuffers::grpc::Message<Monster>>> Retrieve(::grpc::ClientContext* context, const flatbuffers::grpc::Message<Stat>& request) {
return std::unique_ptr< ::grpc::ClientReader< flatbuffers::BufferRef<Monster>>>(RetrieveRaw(context, request)); return std::unique_ptr< ::grpc::ClientReader< flatbuffers::grpc::Message<Monster>>>(RetrieveRaw(context, request));
} }
std::unique_ptr< ::grpc::ClientAsyncReader< flatbuffers::BufferRef<Monster>>> AsyncRetrieve(::grpc::ClientContext* context, const flatbuffers::BufferRef<Stat>& request, ::grpc::CompletionQueue* cq, void* tag) { std::unique_ptr< ::grpc::ClientAsyncReader< flatbuffers::grpc::Message<Monster>>> AsyncRetrieve(::grpc::ClientContext* context, const flatbuffers::grpc::Message<Stat>& request, ::grpc::CompletionQueue* cq, void* tag) {
return std::unique_ptr< ::grpc::ClientAsyncReader< flatbuffers::BufferRef<Monster>>>(AsyncRetrieveRaw(context, request, cq, tag)); return std::unique_ptr< ::grpc::ClientAsyncReader< flatbuffers::grpc::Message<Monster>>>(AsyncRetrieveRaw(context, request, cq, tag));
} }
private: private:
std::shared_ptr< ::grpc::ChannelInterface> channel_; std::shared_ptr< ::grpc::ChannelInterface> channel_;
::grpc::ClientAsyncResponseReader< flatbuffers::BufferRef<Stat>>* AsyncStoreRaw(::grpc::ClientContext* context, const flatbuffers::BufferRef<Monster>& request, ::grpc::CompletionQueue* cq) GRPC_OVERRIDE; ::grpc::ClientAsyncResponseReader< flatbuffers::grpc::Message<Stat>>* AsyncStoreRaw(::grpc::ClientContext* context, const flatbuffers::grpc::Message<Monster>& request, ::grpc::CompletionQueue* cq) override;
::grpc::ClientReader< flatbuffers::BufferRef<Monster>>* RetrieveRaw(::grpc::ClientContext* context, const flatbuffers::BufferRef<Stat>& request) GRPC_OVERRIDE; ::grpc::ClientReader< flatbuffers::grpc::Message<Monster>>* RetrieveRaw(::grpc::ClientContext* context, const flatbuffers::grpc::Message<Stat>& request) override;
::grpc::ClientAsyncReader< flatbuffers::BufferRef<Monster>>* AsyncRetrieveRaw(::grpc::ClientContext* context, const flatbuffers::BufferRef<Stat>& request, ::grpc::CompletionQueue* cq, void* tag) GRPC_OVERRIDE; ::grpc::ClientAsyncReader< flatbuffers::grpc::Message<Monster>>* AsyncRetrieveRaw(::grpc::ClientContext* context, const flatbuffers::grpc::Message<Stat>& request, ::grpc::CompletionQueue* cq, void* tag) override;
const ::grpc::RpcMethod rpcmethod_Store_; const ::grpc::RpcMethod rpcmethod_Store_;
const ::grpc::RpcMethod rpcmethod_Retrieve_; const ::grpc::RpcMethod rpcmethod_Retrieve_;
}; };
@@ -74,8 +79,8 @@ class MonsterStorage GRPC_FINAL {
public: public:
Service(); Service();
virtual ~Service(); virtual ~Service();
virtual ::grpc::Status Store(::grpc::ServerContext* context, const flatbuffers::BufferRef<Monster>* request, flatbuffers::BufferRef<Stat>* response); virtual ::grpc::Status Store(::grpc::ServerContext* context, const flatbuffers::grpc::Message<Monster>* request, flatbuffers::grpc::Message<Stat>* response);
virtual ::grpc::Status Retrieve(::grpc::ServerContext* context, const flatbuffers::BufferRef<Stat>* request, ::grpc::ServerWriter< flatbuffers::BufferRef<Monster>>* writer); virtual ::grpc::Status Retrieve(::grpc::ServerContext* context, const flatbuffers::grpc::Message<Stat>* request, ::grpc::ServerWriter< flatbuffers::grpc::Message<Monster>>* writer);
}; };
template <class BaseClass> template <class BaseClass>
class WithAsyncMethod_Store : public BaseClass { class WithAsyncMethod_Store : public BaseClass {
@@ -85,15 +90,15 @@ class MonsterStorage GRPC_FINAL {
WithAsyncMethod_Store() { WithAsyncMethod_Store() {
::grpc::Service::MarkMethodAsync(0); ::grpc::Service::MarkMethodAsync(0);
} }
~WithAsyncMethod_Store() GRPC_OVERRIDE { ~WithAsyncMethod_Store() override {
BaseClassMustBeDerivedFromService(this); BaseClassMustBeDerivedFromService(this);
} }
// disable synchronous version of this method // disable synchronous version of this method
::grpc::Status Store(::grpc::ServerContext* context, const flatbuffers::BufferRef<Monster>* request, flatbuffers::BufferRef<Stat>* response) GRPC_FINAL GRPC_OVERRIDE { ::grpc::Status Store(::grpc::ServerContext* context, const flatbuffers::grpc::Message<Monster>* request, flatbuffers::grpc::Message<Stat>* response) final override {
abort(); abort();
return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "");
} }
void RequestStore(::grpc::ServerContext* context, flatbuffers::BufferRef<Monster>* request, ::grpc::ServerAsyncResponseWriter< flatbuffers::BufferRef<Stat>>* response, ::grpc::CompletionQueue* new_call_cq, ::grpc::ServerCompletionQueue* notification_cq, void *tag) { void RequestStore(::grpc::ServerContext* context, flatbuffers::grpc::Message<Monster>* request, ::grpc::ServerAsyncResponseWriter< flatbuffers::grpc::Message<Stat>>* response, ::grpc::CompletionQueue* new_call_cq, ::grpc::ServerCompletionQueue* notification_cq, void *tag) {
::grpc::Service::RequestAsyncUnary(0, context, request, response, new_call_cq, notification_cq, tag); ::grpc::Service::RequestAsyncUnary(0, context, request, response, new_call_cq, notification_cq, tag);
} }
}; };
@@ -105,15 +110,15 @@ class MonsterStorage GRPC_FINAL {
WithAsyncMethod_Retrieve() { WithAsyncMethod_Retrieve() {
::grpc::Service::MarkMethodAsync(1); ::grpc::Service::MarkMethodAsync(1);
} }
~WithAsyncMethod_Retrieve() GRPC_OVERRIDE { ~WithAsyncMethod_Retrieve() override {
BaseClassMustBeDerivedFromService(this); BaseClassMustBeDerivedFromService(this);
} }
// disable synchronous version of this method // disable synchronous version of this method
::grpc::Status Retrieve(::grpc::ServerContext* context, const flatbuffers::BufferRef<Stat>* request, ::grpc::ServerWriter< flatbuffers::BufferRef<Monster>>* writer) GRPC_FINAL GRPC_OVERRIDE { ::grpc::Status Retrieve(::grpc::ServerContext* context, const flatbuffers::grpc::Message<Stat>* request, ::grpc::ServerWriter< flatbuffers::grpc::Message<Monster>>* writer) final override {
abort(); abort();
return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "");
} }
void RequestRetrieve(::grpc::ServerContext* context, flatbuffers::BufferRef<Stat>* request, ::grpc::ServerAsyncWriter< flatbuffers::BufferRef<Monster>>* writer, ::grpc::CompletionQueue* new_call_cq, ::grpc::ServerCompletionQueue* notification_cq, void *tag) { void RequestRetrieve(::grpc::ServerContext* context, flatbuffers::grpc::Message<Stat>* request, ::grpc::ServerAsyncWriter< flatbuffers::grpc::Message<Monster>>* writer, ::grpc::CompletionQueue* new_call_cq, ::grpc::ServerCompletionQueue* notification_cq, void *tag) {
::grpc::Service::RequestAsyncServerStreaming(1, context, request, writer, new_call_cq, notification_cq, tag); ::grpc::Service::RequestAsyncServerStreaming(1, context, request, writer, new_call_cq, notification_cq, tag);
} }
}; };
@@ -126,11 +131,11 @@ class MonsterStorage GRPC_FINAL {
WithGenericMethod_Store() { WithGenericMethod_Store() {
::grpc::Service::MarkMethodGeneric(0); ::grpc::Service::MarkMethodGeneric(0);
} }
~WithGenericMethod_Store() GRPC_OVERRIDE { ~WithGenericMethod_Store() override {
BaseClassMustBeDerivedFromService(this); BaseClassMustBeDerivedFromService(this);
} }
// disable synchronous version of this method // disable synchronous version of this method
::grpc::Status Store(::grpc::ServerContext* context, const flatbuffers::BufferRef<Monster>* request, flatbuffers::BufferRef<Stat>* response) GRPC_FINAL GRPC_OVERRIDE { ::grpc::Status Store(::grpc::ServerContext* context, const flatbuffers::grpc::Message<Monster>* request, flatbuffers::grpc::Message<Stat>* response) final override {
abort(); abort();
return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "");
} }
@@ -143,15 +148,58 @@ class MonsterStorage GRPC_FINAL {
WithGenericMethod_Retrieve() { WithGenericMethod_Retrieve() {
::grpc::Service::MarkMethodGeneric(1); ::grpc::Service::MarkMethodGeneric(1);
} }
~WithGenericMethod_Retrieve() GRPC_OVERRIDE { ~WithGenericMethod_Retrieve() override {
BaseClassMustBeDerivedFromService(this); BaseClassMustBeDerivedFromService(this);
} }
// disable synchronous version of this method // disable synchronous version of this method
::grpc::Status Retrieve(::grpc::ServerContext* context, const flatbuffers::BufferRef<Stat>* request, ::grpc::ServerWriter< flatbuffers::BufferRef<Monster>>* writer) GRPC_FINAL GRPC_OVERRIDE { ::grpc::Status Retrieve(::grpc::ServerContext* context, const flatbuffers::grpc::Message<Stat>* request, ::grpc::ServerWriter< flatbuffers::grpc::Message<Monster>>* writer) final override {
abort(); abort();
return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "");
} }
}; };
template <class BaseClass>
class WithStreamedUnaryMethod_Store : public BaseClass {
private:
void BaseClassMustBeDerivedFromService(const Service *service) {}
public:
WithStreamedUnaryMethod_Store() {
::grpc::Service::MarkMethodStreamed(0,
new ::grpc::StreamedUnaryHandler< flatbuffers::grpc::Message<Monster>, flatbuffers::grpc::Message<Stat>>(std::bind(&WithStreamedUnaryMethod_Store<BaseClass>::StreamedStore, this, std::placeholders::_1, std::placeholders::_2)));
}
~WithStreamedUnaryMethod_Store() override {
BaseClassMustBeDerivedFromService(this);
}
// disable regular version of this method
::grpc::Status Store(::grpc::ServerContext* context, const flatbuffers::grpc::Message<Monster>* request, flatbuffers::grpc::Message<Stat>* response) final override {
abort();
return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "");
}
// replace default version of method with streamed unary
virtual ::grpc::Status StreamedStore(::grpc::ServerContext* context, ::grpc::ServerUnaryStreamer< flatbuffers::grpc::Message<Monster>,flatbuffers::grpc::Message<Stat>>* server_unary_streamer) = 0;
};
typedef WithStreamedUnaryMethod_Store< Service > StreamedUnaryService;
template <class BaseClass>
class WithSplitStreamingMethod_Retrieve : public BaseClass {
private:
void BaseClassMustBeDerivedFromService(const Service *service) {}
public:
WithSplitStreamingMethod_Retrieve() {
::grpc::Service::MarkMethodStreamed(1,
new ::grpc::SplitServerStreamingHandler< flatbuffers::grpc::Message<Stat>, flatbuffers::grpc::Message<Monster>>(std::bind(&WithSplitStreamingMethod_Retrieve<BaseClass>::StreamedRetrieve, this, std::placeholders::_1, std::placeholders::_2)));
}
~WithSplitStreamingMethod_Retrieve() override {
BaseClassMustBeDerivedFromService(this);
}
// disable regular version of this method
::grpc::Status Retrieve(::grpc::ServerContext* context, const flatbuffers::grpc::Message<Stat>* request, ::grpc::ServerWriter< flatbuffers::grpc::Message<Monster>>* writer) final override {
abort();
return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "");
}
// replace default version of method with split streamed
virtual ::grpc::Status StreamedRetrieve(::grpc::ServerContext* context, ::grpc::ServerSplitStreamer< flatbuffers::grpc::Message<Stat>,flatbuffers::grpc::Message<Monster>>* server_split_streamer) = 0;
};
typedef WithSplitStreamingMethod_Retrieve< Service > SplitStreamedService;
typedef WithStreamedUnaryMethod_Store< WithSplitStreamingMethod_Retrieve< Service > > StreamedService;
}; };
} // namespace Example } // namespace Example

View File

@@ -5,6 +5,7 @@
#define FLATBUFFERS_GENERATED_MONSTERTEST_MYGAME_EXAMPLE_H_ #define FLATBUFFERS_GENERATED_MONSTERTEST_MYGAME_EXAMPLE_H_
#include "flatbuffers/flatbuffers.h" #include "flatbuffers/flatbuffers.h"
#include "flatbuffers/flexbuffers.h"
namespace MyGame { namespace MyGame {
namespace Example2 { namespace Example2 {
@@ -23,6 +24,8 @@ struct TestSimpleTableWithEnumT;
struct Vec3; struct Vec3;
struct Ability;
struct Stat; struct Stat;
struct StatT; struct StatT;
@@ -37,6 +40,15 @@ enum Color {
Color_ANY = 11 Color_ANY = 11
}; };
inline Color (&EnumValuesColor())[3] {
static Color values[] = {
Color_Red,
Color_Green,
Color_Blue
};
return values;
}
inline const char **EnumNamesColor() { inline const char **EnumNamesColor() {
static const char *names[] = { static const char *names[] = {
"Red", "Red",
@@ -66,6 +78,16 @@ enum Any {
Any_MAX = Any_MyGame_Example2_Monster Any_MAX = Any_MyGame_Example2_Monster
}; };
inline Any (&EnumValuesAny())[4] {
static Any values[] = {
Any_NONE,
Any_Monster,
Any_TestSimpleTableWithEnum,
Any_MyGame_Example2_Monster
};
return values;
}
inline const char **EnumNamesAny() { inline const char **EnumNamesAny() {
static const char *names[] = { static const char *names[] = {
"NONE", "NONE",
@@ -100,40 +122,44 @@ template<> struct AnyTraits<MyGame::Example2::Monster> {
struct AnyUnion { struct AnyUnion {
Any type; Any type;
flatbuffers::NativeTable *table; void *value;
AnyUnion() : type(Any_NONE), table(nullptr) {} AnyUnion() : type(Any_NONE), value(nullptr) {}
AnyUnion(AnyUnion&& u): AnyUnion(AnyUnion&& u) FLATBUFFERS_NOEXCEPT :
type(std::move(u.type)), table(std::move(u.table)) {} type(Any_NONE), value(nullptr)
AnyUnion(const AnyUnion &); { std::swap(type, u.type); std::swap(value, u.value); }
AnyUnion &operator=(const AnyUnion &); AnyUnion(const AnyUnion &) FLATBUFFERS_NOEXCEPT;
AnyUnion &operator=(const AnyUnion &u) FLATBUFFERS_NOEXCEPT
{ AnyUnion t(u); std::swap(type, t.type); std::swap(value, t.value); return *this; }
AnyUnion &operator=(AnyUnion &&u) FLATBUFFERS_NOEXCEPT
{ std::swap(type, u.type); std::swap(value, u.value); return *this; }
~AnyUnion() { Reset(); } ~AnyUnion() { Reset(); }
void Reset(); void Reset();
template <typename T> template <typename T>
void Set(T&& value) { void Set(T&& val) {
Reset(); Reset();
type = AnyTraits<typename T::TableType>::enum_value; type = AnyTraits<typename T::TableType>::enum_value;
if (type != Any_NONE) { if (type != Any_NONE) {
table = new T(std::forward<T>(value)); value = new T(std::forward<T>(val));
} }
} }
static flatbuffers::NativeTable *UnPack(const void *obj, Any type, const flatbuffers::resolver_function_t *resolver); static void *UnPack(const void *obj, Any type, const flatbuffers::resolver_function_t *resolver);
flatbuffers::Offset<void> Pack(flatbuffers::FlatBufferBuilder &_fbb, const flatbuffers::rehasher_function_t *_rehasher = nullptr) const; flatbuffers::Offset<void> Pack(flatbuffers::FlatBufferBuilder &_fbb, const flatbuffers::rehasher_function_t *_rehasher = nullptr) const;
MonsterT *AsMonster() { MonsterT *AsMonster() {
return type == Any_Monster ? return type == Any_Monster ?
reinterpret_cast<MonsterT *>(table) : nullptr; reinterpret_cast<MonsterT *>(value) : nullptr;
} }
TestSimpleTableWithEnumT *AsTestSimpleTableWithEnum() { TestSimpleTableWithEnumT *AsTestSimpleTableWithEnum() {
return type == Any_TestSimpleTableWithEnum ? return type == Any_TestSimpleTableWithEnum ?
reinterpret_cast<TestSimpleTableWithEnumT *>(table) : nullptr; reinterpret_cast<TestSimpleTableWithEnumT *>(value) : nullptr;
} }
MyGame::Example2::MonsterT *AsMyGame_Example2_Monster() { MyGame::Example2::MonsterT *AsMyGame_Example2_Monster() {
return type == Any_MyGame_Example2_Monster ? return type == Any_MyGame_Example2_Monster ?
reinterpret_cast<MyGame::Example2::MonsterT *>(table) : nullptr; reinterpret_cast<MyGame::Example2::MonsterT *>(value) : nullptr;
} }
}; };
@@ -240,12 +266,50 @@ MANUALLY_ALIGNED_STRUCT(16) Vec3 FLATBUFFERS_FINAL_CLASS {
const Test &test3() const { const Test &test3() const {
return test3_; return test3_;
} }
const Test &mutable_test3() { Test &mutable_test3() {
return test3_; return test3_;
} }
}; };
STRUCT_END(Vec3, 32); STRUCT_END(Vec3, 32);
MANUALLY_ALIGNED_STRUCT(4) Ability FLATBUFFERS_FINAL_CLASS {
private:
uint32_t id_;
uint32_t distance_;
public:
Ability() {
memset(this, 0, sizeof(Ability));
}
Ability(const Ability &_o) {
memcpy(this, &_o, sizeof(Ability));
}
Ability(uint32_t _id, uint32_t _distance)
: id_(flatbuffers::EndianScalar(_id)),
distance_(flatbuffers::EndianScalar(_distance)) {
}
uint32_t id() const {
return flatbuffers::EndianScalar(id_);
}
void mutate_id(uint32_t _id) {
flatbuffers::WriteScalar(&id_, _id);
}
bool KeyCompareLessThan(const Ability *o) const {
return id() < o->id();
}
int KeyCompareWithValue(uint32_t val) const {
const auto key = id();
return static_cast<int>(key > val) - static_cast<int>(key < val);
}
uint32_t distance() const {
return flatbuffers::EndianScalar(distance_);
}
void mutate_distance(uint32_t _distance) {
flatbuffers::WriteScalar(&distance_, _distance);
}
};
STRUCT_END(Ability, 8);
} // namespace Example } // namespace Example
namespace Example2 { namespace Example2 {
@@ -311,7 +375,7 @@ struct TestSimpleTableWithEnum FLATBUFFERS_FINAL_CLASS : private flatbuffers::Ta
return static_cast<Color>(GetField<int8_t>(VT_COLOR, 2)); return static_cast<Color>(GetField<int8_t>(VT_COLOR, 2));
} }
bool mutate_color(Color _color) { bool mutate_color(Color _color) {
return SetField(VT_COLOR, static_cast<int8_t>(_color)); return SetField<int8_t>(VT_COLOR, static_cast<int8_t>(_color), 2);
} }
bool Verify(flatbuffers::Verifier &verifier) const { bool Verify(flatbuffers::Verifier &verifier) const {
return VerifyTableStart(verifier) && return VerifyTableStart(verifier) &&
@@ -379,17 +443,17 @@ struct Stat FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
return GetField<int64_t>(VT_VAL, 0); return GetField<int64_t>(VT_VAL, 0);
} }
bool mutate_val(int64_t _val) { bool mutate_val(int64_t _val) {
return SetField(VT_VAL, _val); return SetField<int64_t>(VT_VAL, _val, 0);
} }
uint16_t count() const { uint16_t count() const {
return GetField<uint16_t>(VT_COUNT, 0); return GetField<uint16_t>(VT_COUNT, 0);
} }
bool mutate_count(uint16_t _count) { bool mutate_count(uint16_t _count) {
return SetField(VT_COUNT, _count); return SetField<uint16_t>(VT_COUNT, _count, 0);
} }
bool Verify(flatbuffers::Verifier &verifier) const { bool Verify(flatbuffers::Verifier &verifier) const {
return VerifyTableStart(verifier) && return VerifyTableStart(verifier) &&
VerifyField<flatbuffers::uoffset_t>(verifier, VT_ID) && VerifyOffset(verifier, VT_ID) &&
verifier.Verify(id()) && verifier.Verify(id()) &&
VerifyField<int64_t>(verifier, VT_VAL) && VerifyField<int64_t>(verifier, VT_VAL) &&
VerifyField<uint16_t>(verifier, VT_COUNT) && VerifyField<uint16_t>(verifier, VT_COUNT) &&
@@ -479,6 +543,8 @@ struct MonsterT : public flatbuffers::NativeTable {
float testf2; float testf2;
float testf3; float testf3;
std::vector<std::string> testarrayofstring2; std::vector<std::string> testarrayofstring2;
std::vector<Ability> testarrayofsortedstruct;
std::vector<uint8_t> flex;
MonsterT() MonsterT()
: mana(150), : mana(150),
hp(100), hp(100),
@@ -529,7 +595,9 @@ struct Monster FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
VT_TESTF = 54, VT_TESTF = 54,
VT_TESTF2 = 56, VT_TESTF2 = 56,
VT_TESTF3 = 58, VT_TESTF3 = 58,
VT_TESTARRAYOFSTRING2 = 60 VT_TESTARRAYOFSTRING2 = 60,
VT_TESTARRAYOFSORTEDSTRUCT = 62,
VT_FLEX = 64
}; };
const Vec3 *pos() const { const Vec3 *pos() const {
return GetStruct<const Vec3 *>(VT_POS); return GetStruct<const Vec3 *>(VT_POS);
@@ -541,13 +609,13 @@ struct Monster FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
return GetField<int16_t>(VT_MANA, 150); return GetField<int16_t>(VT_MANA, 150);
} }
bool mutate_mana(int16_t _mana) { bool mutate_mana(int16_t _mana) {
return SetField(VT_MANA, _mana); return SetField<int16_t>(VT_MANA, _mana, 150);
} }
int16_t hp() const { int16_t hp() const {
return GetField<int16_t>(VT_HP, 100); return GetField<int16_t>(VT_HP, 100);
} }
bool mutate_hp(int16_t _hp) { bool mutate_hp(int16_t _hp) {
return SetField(VT_HP, _hp); return SetField<int16_t>(VT_HP, _hp, 100);
} }
const flatbuffers::String *name() const { const flatbuffers::String *name() const {
return GetPointer<const flatbuffers::String *>(VT_NAME); return GetPointer<const flatbuffers::String *>(VT_NAME);
@@ -571,17 +639,27 @@ struct Monster FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
return static_cast<Color>(GetField<int8_t>(VT_COLOR, 8)); return static_cast<Color>(GetField<int8_t>(VT_COLOR, 8));
} }
bool mutate_color(Color _color) { bool mutate_color(Color _color) {
return SetField(VT_COLOR, static_cast<int8_t>(_color)); return SetField<int8_t>(VT_COLOR, static_cast<int8_t>(_color), 8);
} }
Any test_type() const { Any test_type() const {
return static_cast<Any>(GetField<uint8_t>(VT_TEST_TYPE, 0)); return static_cast<Any>(GetField<uint8_t>(VT_TEST_TYPE, 0));
} }
bool mutate_test_type(Any _test_type) { bool mutate_test_type(Any _test_type) {
return SetField(VT_TEST_TYPE, static_cast<uint8_t>(_test_type)); return SetField<uint8_t>(VT_TEST_TYPE, static_cast<uint8_t>(_test_type), 0);
} }
const void *test() const { const void *test() const {
return GetPointer<const void *>(VT_TEST); return GetPointer<const void *>(VT_TEST);
} }
template<typename T> const T *test_as() const;
const Monster *test_as_Monster() const {
return test_type() == Any_Monster ? static_cast<const Monster *>(test()) : nullptr;
}
const TestSimpleTableWithEnum *test_as_TestSimpleTableWithEnum() const {
return test_type() == Any_TestSimpleTableWithEnum ? static_cast<const TestSimpleTableWithEnum *>(test()) : nullptr;
}
const MyGame::Example2::Monster *test_as_MyGame_Example2_Monster() const {
return test_type() == Any_MyGame_Example2_Monster ? static_cast<const MyGame::Example2::Monster *>(test()) : nullptr;
}
void *mutable_test() { void *mutable_test() {
return GetPointer<void *>(VT_TEST); return GetPointer<void *>(VT_TEST);
} }
@@ -618,7 +696,7 @@ struct Monster FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
return GetPointer<flatbuffers::Vector<uint8_t> *>(VT_TESTNESTEDFLATBUFFER); return GetPointer<flatbuffers::Vector<uint8_t> *>(VT_TESTNESTEDFLATBUFFER);
} }
const MyGame::Example::Monster *testnestedflatbuffer_nested_root() const { const MyGame::Example::Monster *testnestedflatbuffer_nested_root() const {
const uint8_t* data = testnestedflatbuffer()->Data(); auto data = testnestedflatbuffer()->Data();
return flatbuffers::GetRoot<MyGame::Example::Monster>(data); return flatbuffers::GetRoot<MyGame::Example::Monster>(data);
} }
const Stat *testempty() const { const Stat *testempty() const {
@@ -631,55 +709,55 @@ struct Monster FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
return GetField<uint8_t>(VT_TESTBOOL, 0) != 0; return GetField<uint8_t>(VT_TESTBOOL, 0) != 0;
} }
bool mutate_testbool(bool _testbool) { bool mutate_testbool(bool _testbool) {
return SetField(VT_TESTBOOL, static_cast<uint8_t>(_testbool)); return SetField<uint8_t>(VT_TESTBOOL, static_cast<uint8_t>(_testbool), 0);
} }
int32_t testhashs32_fnv1() const { int32_t testhashs32_fnv1() const {
return GetField<int32_t>(VT_TESTHASHS32_FNV1, 0); return GetField<int32_t>(VT_TESTHASHS32_FNV1, 0);
} }
bool mutate_testhashs32_fnv1(int32_t _testhashs32_fnv1) { bool mutate_testhashs32_fnv1(int32_t _testhashs32_fnv1) {
return SetField(VT_TESTHASHS32_FNV1, _testhashs32_fnv1); return SetField<int32_t>(VT_TESTHASHS32_FNV1, _testhashs32_fnv1, 0);
} }
uint32_t testhashu32_fnv1() const { uint32_t testhashu32_fnv1() const {
return GetField<uint32_t>(VT_TESTHASHU32_FNV1, 0); return GetField<uint32_t>(VT_TESTHASHU32_FNV1, 0);
} }
bool mutate_testhashu32_fnv1(uint32_t _testhashu32_fnv1) { bool mutate_testhashu32_fnv1(uint32_t _testhashu32_fnv1) {
return SetField(VT_TESTHASHU32_FNV1, _testhashu32_fnv1); return SetField<uint32_t>(VT_TESTHASHU32_FNV1, _testhashu32_fnv1, 0);
} }
int64_t testhashs64_fnv1() const { int64_t testhashs64_fnv1() const {
return GetField<int64_t>(VT_TESTHASHS64_FNV1, 0); return GetField<int64_t>(VT_TESTHASHS64_FNV1, 0);
} }
bool mutate_testhashs64_fnv1(int64_t _testhashs64_fnv1) { bool mutate_testhashs64_fnv1(int64_t _testhashs64_fnv1) {
return SetField(VT_TESTHASHS64_FNV1, _testhashs64_fnv1); return SetField<int64_t>(VT_TESTHASHS64_FNV1, _testhashs64_fnv1, 0);
} }
uint64_t testhashu64_fnv1() const { uint64_t testhashu64_fnv1() const {
return GetField<uint64_t>(VT_TESTHASHU64_FNV1, 0); return GetField<uint64_t>(VT_TESTHASHU64_FNV1, 0);
} }
bool mutate_testhashu64_fnv1(uint64_t _testhashu64_fnv1) { bool mutate_testhashu64_fnv1(uint64_t _testhashu64_fnv1) {
return SetField(VT_TESTHASHU64_FNV1, _testhashu64_fnv1); return SetField<uint64_t>(VT_TESTHASHU64_FNV1, _testhashu64_fnv1, 0);
} }
int32_t testhashs32_fnv1a() const { int32_t testhashs32_fnv1a() const {
return GetField<int32_t>(VT_TESTHASHS32_FNV1A, 0); return GetField<int32_t>(VT_TESTHASHS32_FNV1A, 0);
} }
bool mutate_testhashs32_fnv1a(int32_t _testhashs32_fnv1a) { bool mutate_testhashs32_fnv1a(int32_t _testhashs32_fnv1a) {
return SetField(VT_TESTHASHS32_FNV1A, _testhashs32_fnv1a); return SetField<int32_t>(VT_TESTHASHS32_FNV1A, _testhashs32_fnv1a, 0);
} }
uint32_t testhashu32_fnv1a() const { uint32_t testhashu32_fnv1a() const {
return GetField<uint32_t>(VT_TESTHASHU32_FNV1A, 0); return GetField<uint32_t>(VT_TESTHASHU32_FNV1A, 0);
} }
bool mutate_testhashu32_fnv1a(uint32_t _testhashu32_fnv1a) { bool mutate_testhashu32_fnv1a(uint32_t _testhashu32_fnv1a) {
return SetField(VT_TESTHASHU32_FNV1A, _testhashu32_fnv1a); return SetField<uint32_t>(VT_TESTHASHU32_FNV1A, _testhashu32_fnv1a, 0);
} }
int64_t testhashs64_fnv1a() const { int64_t testhashs64_fnv1a() const {
return GetField<int64_t>(VT_TESTHASHS64_FNV1A, 0); return GetField<int64_t>(VT_TESTHASHS64_FNV1A, 0);
} }
bool mutate_testhashs64_fnv1a(int64_t _testhashs64_fnv1a) { bool mutate_testhashs64_fnv1a(int64_t _testhashs64_fnv1a) {
return SetField(VT_TESTHASHS64_FNV1A, _testhashs64_fnv1a); return SetField<int64_t>(VT_TESTHASHS64_FNV1A, _testhashs64_fnv1a, 0);
} }
uint64_t testhashu64_fnv1a() const { uint64_t testhashu64_fnv1a() const {
return GetField<uint64_t>(VT_TESTHASHU64_FNV1A, 0); return GetField<uint64_t>(VT_TESTHASHU64_FNV1A, 0);
} }
bool mutate_testhashu64_fnv1a(uint64_t _testhashu64_fnv1a) { bool mutate_testhashu64_fnv1a(uint64_t _testhashu64_fnv1a) {
return SetField(VT_TESTHASHU64_FNV1A, _testhashu64_fnv1a); return SetField<uint64_t>(VT_TESTHASHU64_FNV1A, _testhashu64_fnv1a, 0);
} }
const flatbuffers::Vector<uint8_t> *testarrayofbools() const { const flatbuffers::Vector<uint8_t> *testarrayofbools() const {
return GetPointer<const flatbuffers::Vector<uint8_t> *>(VT_TESTARRAYOFBOOLS); return GetPointer<const flatbuffers::Vector<uint8_t> *>(VT_TESTARRAYOFBOOLS);
@@ -691,19 +769,19 @@ struct Monster FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
return GetField<float>(VT_TESTF, 3.14159f); return GetField<float>(VT_TESTF, 3.14159f);
} }
bool mutate_testf(float _testf) { bool mutate_testf(float _testf) {
return SetField(VT_TESTF, _testf); return SetField<float>(VT_TESTF, _testf, 3.14159f);
} }
float testf2() const { float testf2() const {
return GetField<float>(VT_TESTF2, 3.0f); return GetField<float>(VT_TESTF2, 3.0f);
} }
bool mutate_testf2(float _testf2) { bool mutate_testf2(float _testf2) {
return SetField(VT_TESTF2, _testf2); return SetField<float>(VT_TESTF2, _testf2, 3.0f);
} }
float testf3() const { float testf3() const {
return GetField<float>(VT_TESTF3, 0.0f); return GetField<float>(VT_TESTF3, 0.0f);
} }
bool mutate_testf3(float _testf3) { bool mutate_testf3(float _testf3) {
return SetField(VT_TESTF3, _testf3); return SetField<float>(VT_TESTF3, _testf3, 0.0f);
} }
const flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>> *testarrayofstring2() const { const flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>> *testarrayofstring2() const {
return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>> *>(VT_TESTARRAYOFSTRING2); return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>> *>(VT_TESTARRAYOFSTRING2);
@@ -711,32 +789,48 @@ struct Monster FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>> *mutable_testarrayofstring2() { flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>> *mutable_testarrayofstring2() {
return GetPointer<flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>> *>(VT_TESTARRAYOFSTRING2); return GetPointer<flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>> *>(VT_TESTARRAYOFSTRING2);
} }
const flatbuffers::Vector<const Ability *> *testarrayofsortedstruct() const {
return GetPointer<const flatbuffers::Vector<const Ability *> *>(VT_TESTARRAYOFSORTEDSTRUCT);
}
flatbuffers::Vector<const Ability *> *mutable_testarrayofsortedstruct() {
return GetPointer<flatbuffers::Vector<const Ability *> *>(VT_TESTARRAYOFSORTEDSTRUCT);
}
const flatbuffers::Vector<uint8_t> *flex() const {
return GetPointer<const flatbuffers::Vector<uint8_t> *>(VT_FLEX);
}
flatbuffers::Vector<uint8_t> *mutable_flex() {
return GetPointer<flatbuffers::Vector<uint8_t> *>(VT_FLEX);
}
flexbuffers::Reference flex_flexbuffer_root() const {
auto v = flex();
return flexbuffers::GetRoot(v->Data(), v->size());
}
bool Verify(flatbuffers::Verifier &verifier) const { bool Verify(flatbuffers::Verifier &verifier) const {
return VerifyTableStart(verifier) && return VerifyTableStart(verifier) &&
VerifyField<Vec3>(verifier, VT_POS) && VerifyField<Vec3>(verifier, VT_POS) &&
VerifyField<int16_t>(verifier, VT_MANA) && VerifyField<int16_t>(verifier, VT_MANA) &&
VerifyField<int16_t>(verifier, VT_HP) && VerifyField<int16_t>(verifier, VT_HP) &&
VerifyFieldRequired<flatbuffers::uoffset_t>(verifier, VT_NAME) && VerifyOffsetRequired(verifier, VT_NAME) &&
verifier.Verify(name()) && verifier.Verify(name()) &&
VerifyField<flatbuffers::uoffset_t>(verifier, VT_INVENTORY) && VerifyOffset(verifier, VT_INVENTORY) &&
verifier.Verify(inventory()) && verifier.Verify(inventory()) &&
VerifyField<int8_t>(verifier, VT_COLOR) && VerifyField<int8_t>(verifier, VT_COLOR) &&
VerifyField<uint8_t>(verifier, VT_TEST_TYPE) && VerifyField<uint8_t>(verifier, VT_TEST_TYPE) &&
VerifyField<flatbuffers::uoffset_t>(verifier, VT_TEST) && VerifyOffset(verifier, VT_TEST) &&
VerifyAny(verifier, test(), test_type()) && VerifyAny(verifier, test(), test_type()) &&
VerifyField<flatbuffers::uoffset_t>(verifier, VT_TEST4) && VerifyOffset(verifier, VT_TEST4) &&
verifier.Verify(test4()) && verifier.Verify(test4()) &&
VerifyField<flatbuffers::uoffset_t>(verifier, VT_TESTARRAYOFSTRING) && VerifyOffset(verifier, VT_TESTARRAYOFSTRING) &&
verifier.Verify(testarrayofstring()) && verifier.Verify(testarrayofstring()) &&
verifier.VerifyVectorOfStrings(testarrayofstring()) && verifier.VerifyVectorOfStrings(testarrayofstring()) &&
VerifyField<flatbuffers::uoffset_t>(verifier, VT_TESTARRAYOFTABLES) && VerifyOffset(verifier, VT_TESTARRAYOFTABLES) &&
verifier.Verify(testarrayoftables()) && verifier.Verify(testarrayoftables()) &&
verifier.VerifyVectorOfTables(testarrayoftables()) && verifier.VerifyVectorOfTables(testarrayoftables()) &&
VerifyField<flatbuffers::uoffset_t>(verifier, VT_ENEMY) && VerifyOffset(verifier, VT_ENEMY) &&
verifier.VerifyTable(enemy()) && verifier.VerifyTable(enemy()) &&
VerifyField<flatbuffers::uoffset_t>(verifier, VT_TESTNESTEDFLATBUFFER) && VerifyOffset(verifier, VT_TESTNESTEDFLATBUFFER) &&
verifier.Verify(testnestedflatbuffer()) && verifier.Verify(testnestedflatbuffer()) &&
VerifyField<flatbuffers::uoffset_t>(verifier, VT_TESTEMPTY) && VerifyOffset(verifier, VT_TESTEMPTY) &&
verifier.VerifyTable(testempty()) && verifier.VerifyTable(testempty()) &&
VerifyField<uint8_t>(verifier, VT_TESTBOOL) && VerifyField<uint8_t>(verifier, VT_TESTBOOL) &&
VerifyField<int32_t>(verifier, VT_TESTHASHS32_FNV1) && VerifyField<int32_t>(verifier, VT_TESTHASHS32_FNV1) &&
@@ -747,14 +841,18 @@ struct Monster FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
VerifyField<uint32_t>(verifier, VT_TESTHASHU32_FNV1A) && VerifyField<uint32_t>(verifier, VT_TESTHASHU32_FNV1A) &&
VerifyField<int64_t>(verifier, VT_TESTHASHS64_FNV1A) && VerifyField<int64_t>(verifier, VT_TESTHASHS64_FNV1A) &&
VerifyField<uint64_t>(verifier, VT_TESTHASHU64_FNV1A) && VerifyField<uint64_t>(verifier, VT_TESTHASHU64_FNV1A) &&
VerifyField<flatbuffers::uoffset_t>(verifier, VT_TESTARRAYOFBOOLS) && VerifyOffset(verifier, VT_TESTARRAYOFBOOLS) &&
verifier.Verify(testarrayofbools()) && verifier.Verify(testarrayofbools()) &&
VerifyField<float>(verifier, VT_TESTF) && VerifyField<float>(verifier, VT_TESTF) &&
VerifyField<float>(verifier, VT_TESTF2) && VerifyField<float>(verifier, VT_TESTF2) &&
VerifyField<float>(verifier, VT_TESTF3) && VerifyField<float>(verifier, VT_TESTF3) &&
VerifyField<flatbuffers::uoffset_t>(verifier, VT_TESTARRAYOFSTRING2) && VerifyOffset(verifier, VT_TESTARRAYOFSTRING2) &&
verifier.Verify(testarrayofstring2()) && verifier.Verify(testarrayofstring2()) &&
verifier.VerifyVectorOfStrings(testarrayofstring2()) && verifier.VerifyVectorOfStrings(testarrayofstring2()) &&
VerifyOffset(verifier, VT_TESTARRAYOFSORTEDSTRUCT) &&
verifier.Verify(testarrayofsortedstruct()) &&
VerifyOffset(verifier, VT_FLEX) &&
verifier.Verify(flex()) &&
verifier.EndTable(); verifier.EndTable();
} }
MonsterT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; MonsterT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const;
@@ -762,6 +860,18 @@ struct Monster FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
static flatbuffers::Offset<Monster> Pack(flatbuffers::FlatBufferBuilder &_fbb, const MonsterT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); static flatbuffers::Offset<Monster> Pack(flatbuffers::FlatBufferBuilder &_fbb, const MonsterT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr);
}; };
template<> inline const Monster *Monster::test_as<Monster>() const {
return test_as_Monster();
}
template<> inline const TestSimpleTableWithEnum *Monster::test_as<TestSimpleTableWithEnum>() const {
return test_as_TestSimpleTableWithEnum();
}
template<> inline const MyGame::Example2::Monster *Monster::test_as<MyGame::Example2::Monster>() const {
return test_as_MyGame_Example2_Monster();
}
struct MonsterBuilder { struct MonsterBuilder {
flatbuffers::FlatBufferBuilder &fbb_; flatbuffers::FlatBufferBuilder &fbb_;
flatbuffers::uoffset_t start_; flatbuffers::uoffset_t start_;
@@ -849,13 +959,19 @@ struct MonsterBuilder {
void add_testarrayofstring2(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>>> testarrayofstring2) { void add_testarrayofstring2(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>>> testarrayofstring2) {
fbb_.AddOffset(Monster::VT_TESTARRAYOFSTRING2, testarrayofstring2); fbb_.AddOffset(Monster::VT_TESTARRAYOFSTRING2, testarrayofstring2);
} }
void add_testarrayofsortedstruct(flatbuffers::Offset<flatbuffers::Vector<const Ability *>> testarrayofsortedstruct) {
fbb_.AddOffset(Monster::VT_TESTARRAYOFSORTEDSTRUCT, testarrayofsortedstruct);
}
void add_flex(flatbuffers::Offset<flatbuffers::Vector<uint8_t>> flex) {
fbb_.AddOffset(Monster::VT_FLEX, flex);
}
MonsterBuilder(flatbuffers::FlatBufferBuilder &_fbb) MonsterBuilder(flatbuffers::FlatBufferBuilder &_fbb)
: fbb_(_fbb) { : fbb_(_fbb) {
start_ = fbb_.StartTable(); start_ = fbb_.StartTable();
} }
MonsterBuilder &operator=(const MonsterBuilder &); MonsterBuilder &operator=(const MonsterBuilder &);
flatbuffers::Offset<Monster> Finish() { flatbuffers::Offset<Monster> Finish() {
const auto end = fbb_.EndTable(start_, 29); const auto end = fbb_.EndTable(start_, 31);
auto o = flatbuffers::Offset<Monster>(end); auto o = flatbuffers::Offset<Monster>(end);
fbb_.Required(o, Monster::VT_NAME); fbb_.Required(o, Monster::VT_NAME);
return o; return o;
@@ -891,12 +1007,16 @@ inline flatbuffers::Offset<Monster> CreateMonster(
float testf = 3.14159f, float testf = 3.14159f,
float testf2 = 3.0f, float testf2 = 3.0f,
float testf3 = 0.0f, float testf3 = 0.0f,
flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>>> testarrayofstring2 = 0) { flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>>> testarrayofstring2 = 0,
flatbuffers::Offset<flatbuffers::Vector<const Ability *>> testarrayofsortedstruct = 0,
flatbuffers::Offset<flatbuffers::Vector<uint8_t>> flex = 0) {
MonsterBuilder builder_(_fbb); MonsterBuilder builder_(_fbb);
builder_.add_testhashu64_fnv1a(testhashu64_fnv1a); builder_.add_testhashu64_fnv1a(testhashu64_fnv1a);
builder_.add_testhashs64_fnv1a(testhashs64_fnv1a); builder_.add_testhashs64_fnv1a(testhashs64_fnv1a);
builder_.add_testhashu64_fnv1(testhashu64_fnv1); builder_.add_testhashu64_fnv1(testhashu64_fnv1);
builder_.add_testhashs64_fnv1(testhashs64_fnv1); builder_.add_testhashs64_fnv1(testhashs64_fnv1);
builder_.add_flex(flex);
builder_.add_testarrayofsortedstruct(testarrayofsortedstruct);
builder_.add_testarrayofstring2(testarrayofstring2); builder_.add_testarrayofstring2(testarrayofstring2);
builder_.add_testf3(testf3); builder_.add_testf3(testf3);
builder_.add_testf2(testf2); builder_.add_testf2(testf2);
@@ -953,7 +1073,9 @@ inline flatbuffers::Offset<Monster> CreateMonsterDirect(
float testf = 3.14159f, float testf = 3.14159f,
float testf2 = 3.0f, float testf2 = 3.0f,
float testf3 = 0.0f, float testf3 = 0.0f,
const std::vector<flatbuffers::Offset<flatbuffers::String>> *testarrayofstring2 = nullptr) { const std::vector<flatbuffers::Offset<flatbuffers::String>> *testarrayofstring2 = nullptr,
const std::vector<const Ability *> *testarrayofsortedstruct = nullptr,
const std::vector<uint8_t> *flex = nullptr) {
return MyGame::Example::CreateMonster( return MyGame::Example::CreateMonster(
_fbb, _fbb,
pos, pos,
@@ -983,7 +1105,9 @@ inline flatbuffers::Offset<Monster> CreateMonsterDirect(
testf, testf,
testf2, testf2,
testf3, testf3,
testarrayofstring2 ? _fbb.CreateVector<flatbuffers::Offset<flatbuffers::String>>(*testarrayofstring2) : 0); testarrayofstring2 ? _fbb.CreateVector<flatbuffers::Offset<flatbuffers::String>>(*testarrayofstring2) : 0,
testarrayofsortedstruct ? _fbb.CreateVector<const Ability *>(*testarrayofsortedstruct) : 0,
flex ? _fbb.CreateVector<uint8_t>(*flex) : 0);
} }
flatbuffers::Offset<Monster> CreateMonster(flatbuffers::FlatBufferBuilder &_fbb, const MonsterT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); flatbuffers::Offset<Monster> CreateMonster(flatbuffers::FlatBufferBuilder &_fbb, const MonsterT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr);
@@ -1087,15 +1211,15 @@ inline void Monster::UnPackTo(MonsterT *_o, const flatbuffers::resolver_function
{ auto _e = mana(); _o->mana = _e; }; { auto _e = mana(); _o->mana = _e; };
{ auto _e = hp(); _o->hp = _e; }; { auto _e = hp(); _o->hp = _e; };
{ auto _e = name(); if (_e) _o->name = _e->str(); }; { auto _e = name(); if (_e) _o->name = _e->str(); };
{ auto _e = inventory(); if (_e) for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->inventory.push_back(_e->Get(_i)); } }; { auto _e = inventory(); if (_e) { _o->inventory.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->inventory[_i] = _e->Get(_i); } } };
{ auto _e = color(); _o->color = _e; }; { auto _e = color(); _o->color = _e; };
{ auto _e = test_type(); _o->test.type = _e; }; { auto _e = test_type(); _o->test.type = _e; };
{ auto _e = test(); if (_e) _o->test.table = AnyUnion::UnPack(_e, test_type(),_resolver); }; { auto _e = test(); if (_e) _o->test.value = AnyUnion::UnPack(_e, test_type(), _resolver); };
{ auto _e = test4(); if (_e) for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->test4.push_back(*_e->Get(_i)); } }; { auto _e = test4(); if (_e) { _o->test4.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->test4[_i] = *_e->Get(_i); } } };
{ auto _e = testarrayofstring(); if (_e) for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->testarrayofstring.push_back(_e->Get(_i)->str()); } }; { auto _e = testarrayofstring(); if (_e) { _o->testarrayofstring.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->testarrayofstring[_i] = _e->Get(_i)->str(); } } };
{ auto _e = testarrayoftables(); if (_e) for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->testarrayoftables.push_back(std::unique_ptr<MonsterT>(_e->Get(_i)->UnPack(_resolver))); } }; { auto _e = testarrayoftables(); if (_e) { _o->testarrayoftables.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->testarrayoftables[_i] = std::unique_ptr<MonsterT>(_e->Get(_i)->UnPack(_resolver)); } } };
{ auto _e = enemy(); if (_e) _o->enemy = std::unique_ptr<MonsterT>(_e->UnPack(_resolver)); }; { auto _e = enemy(); if (_e) _o->enemy = std::unique_ptr<MonsterT>(_e->UnPack(_resolver)); };
{ auto _e = testnestedflatbuffer(); if (_e) for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->testnestedflatbuffer.push_back(_e->Get(_i)); } }; { auto _e = testnestedflatbuffer(); if (_e) { _o->testnestedflatbuffer.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->testnestedflatbuffer[_i] = _e->Get(_i); } } };
{ auto _e = testempty(); if (_e) _o->testempty = std::unique_ptr<StatT>(_e->UnPack(_resolver)); }; { auto _e = testempty(); if (_e) _o->testempty = std::unique_ptr<StatT>(_e->UnPack(_resolver)); };
{ auto _e = testbool(); _o->testbool = _e; }; { auto _e = testbool(); _o->testbool = _e; };
{ auto _e = testhashs32_fnv1(); _o->testhashs32_fnv1 = _e; }; { auto _e = testhashs32_fnv1(); _o->testhashs32_fnv1 = _e; };
@@ -1106,11 +1230,13 @@ inline void Monster::UnPackTo(MonsterT *_o, const flatbuffers::resolver_function
{ auto _e = testhashu32_fnv1a(); if (_resolver) (*_resolver)(reinterpret_cast<void **>(&_o->testhashu32_fnv1a), static_cast<flatbuffers::hash_value_t>(_e)); else _o->testhashu32_fnv1a = nullptr; }; { auto _e = testhashu32_fnv1a(); if (_resolver) (*_resolver)(reinterpret_cast<void **>(&_o->testhashu32_fnv1a), static_cast<flatbuffers::hash_value_t>(_e)); else _o->testhashu32_fnv1a = nullptr; };
{ auto _e = testhashs64_fnv1a(); _o->testhashs64_fnv1a = _e; }; { auto _e = testhashs64_fnv1a(); _o->testhashs64_fnv1a = _e; };
{ auto _e = testhashu64_fnv1a(); _o->testhashu64_fnv1a = _e; }; { auto _e = testhashu64_fnv1a(); _o->testhashu64_fnv1a = _e; };
{ auto _e = testarrayofbools(); if (_e) for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->testarrayofbools.push_back(_e->Get(_i) != 0); } }; { auto _e = testarrayofbools(); if (_e) { _o->testarrayofbools.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->testarrayofbools[_i] = _e->Get(_i) != 0; } } };
{ auto _e = testf(); _o->testf = _e; }; { auto _e = testf(); _o->testf = _e; };
{ auto _e = testf2(); _o->testf2 = _e; }; { auto _e = testf2(); _o->testf2 = _e; };
{ auto _e = testf3(); _o->testf3 = _e; }; { auto _e = testf3(); _o->testf3 = _e; };
{ auto _e = testarrayofstring2(); if (_e) for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->testarrayofstring2.push_back(_e->Get(_i)->str()); } }; { auto _e = testarrayofstring2(); if (_e) { _o->testarrayofstring2.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->testarrayofstring2[_i] = _e->Get(_i)->str(); } } };
{ auto _e = testarrayofsortedstruct(); if (_e) { _o->testarrayofsortedstruct.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->testarrayofsortedstruct[_i] = *_e->Get(_i); } } };
{ auto _e = flex(); if (_e) { _o->flex.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->flex[_i] = _e->Get(_i); } } };
} }
inline flatbuffers::Offset<Monster> Monster::Pack(flatbuffers::FlatBufferBuilder &_fbb, const MonsterT* _o, const flatbuffers::rehasher_function_t *_rehasher) { inline flatbuffers::Offset<Monster> Monster::Pack(flatbuffers::FlatBufferBuilder &_fbb, const MonsterT* _o, const flatbuffers::rehasher_function_t *_rehasher) {
@@ -1148,6 +1274,8 @@ inline flatbuffers::Offset<Monster> CreateMonster(flatbuffers::FlatBufferBuilder
auto _testf2 = _o->testf2; auto _testf2 = _o->testf2;
auto _testf3 = _o->testf3; auto _testf3 = _o->testf3;
auto _testarrayofstring2 = _o->testarrayofstring2.size() ? _fbb.CreateVectorOfStrings(_o->testarrayofstring2) : 0; auto _testarrayofstring2 = _o->testarrayofstring2.size() ? _fbb.CreateVectorOfStrings(_o->testarrayofstring2) : 0;
auto _testarrayofsortedstruct = _o->testarrayofsortedstruct.size() ? _fbb.CreateVectorOfStructs(_o->testarrayofsortedstruct) : 0;
auto _flex = _o->flex.size() ? _fbb.CreateVector(_o->flex) : 0;
return MyGame::Example::CreateMonster( return MyGame::Example::CreateMonster(
_fbb, _fbb,
_pos, _pos,
@@ -1177,7 +1305,9 @@ inline flatbuffers::Offset<Monster> CreateMonster(flatbuffers::FlatBufferBuilder
_testf, _testf,
_testf2, _testf2,
_testf3, _testf3,
_testarrayofstring2); _testarrayofstring2,
_testarrayofsortedstruct,
_flex);
} }
inline bool VerifyAny(flatbuffers::Verifier &verifier, const void *obj, Any type) { inline bool VerifyAny(flatbuffers::Verifier &verifier, const void *obj, Any type) {
@@ -1212,7 +1342,7 @@ inline bool VerifyAnyVector(flatbuffers::Verifier &verifier, const flatbuffers::
return true; return true;
} }
inline flatbuffers::NativeTable *AnyUnion::UnPack(const void *obj, Any type, const flatbuffers::resolver_function_t *resolver) { inline void *AnyUnion::UnPack(const void *obj, Any type, const flatbuffers::resolver_function_t *resolver) {
switch (type) { switch (type) {
case Any_Monster: { case Any_Monster: {
auto ptr = reinterpret_cast<const Monster *>(obj); auto ptr = reinterpret_cast<const Monster *>(obj);
@@ -1233,41 +1363,60 @@ inline flatbuffers::NativeTable *AnyUnion::UnPack(const void *obj, Any type, con
inline flatbuffers::Offset<void> AnyUnion::Pack(flatbuffers::FlatBufferBuilder &_fbb, const flatbuffers::rehasher_function_t *_rehasher) const { inline flatbuffers::Offset<void> AnyUnion::Pack(flatbuffers::FlatBufferBuilder &_fbb, const flatbuffers::rehasher_function_t *_rehasher) const {
switch (type) { switch (type) {
case Any_Monster: { case Any_Monster: {
auto ptr = reinterpret_cast<const MonsterT *>(table); auto ptr = reinterpret_cast<const MonsterT *>(value);
return CreateMonster(_fbb, ptr, _rehasher).Union(); return CreateMonster(_fbb, ptr, _rehasher).Union();
} }
case Any_TestSimpleTableWithEnum: { case Any_TestSimpleTableWithEnum: {
auto ptr = reinterpret_cast<const TestSimpleTableWithEnumT *>(table); auto ptr = reinterpret_cast<const TestSimpleTableWithEnumT *>(value);
return CreateTestSimpleTableWithEnum(_fbb, ptr, _rehasher).Union(); return CreateTestSimpleTableWithEnum(_fbb, ptr, _rehasher).Union();
} }
case Any_MyGame_Example2_Monster: { case Any_MyGame_Example2_Monster: {
auto ptr = reinterpret_cast<const MyGame::Example2::MonsterT *>(table); auto ptr = reinterpret_cast<const MyGame::Example2::MonsterT *>(value);
return CreateMonster(_fbb, ptr, _rehasher).Union(); return CreateMonster(_fbb, ptr, _rehasher).Union();
} }
default: return 0; default: return 0;
} }
} }
inline AnyUnion::AnyUnion(const AnyUnion &u) FLATBUFFERS_NOEXCEPT : type(u.type), value(nullptr) {
switch (type) {
case Any_Monster: {
assert(false); // MonsterT not copyable.
break;
}
case Any_TestSimpleTableWithEnum: {
value = new TestSimpleTableWithEnumT(*reinterpret_cast<TestSimpleTableWithEnumT *>(u.value));
break;
}
case Any_MyGame_Example2_Monster: {
value = new MyGame::Example2::MonsterT(*reinterpret_cast<MyGame::Example2::MonsterT *>(u.value));
break;
}
default:
break;
}
}
inline void AnyUnion::Reset() { inline void AnyUnion::Reset() {
switch (type) { switch (type) {
case Any_Monster: { case Any_Monster: {
auto ptr = reinterpret_cast<MonsterT *>(table); auto ptr = reinterpret_cast<MonsterT *>(value);
delete ptr; delete ptr;
break; break;
} }
case Any_TestSimpleTableWithEnum: { case Any_TestSimpleTableWithEnum: {
auto ptr = reinterpret_cast<TestSimpleTableWithEnumT *>(table); auto ptr = reinterpret_cast<TestSimpleTableWithEnumT *>(value);
delete ptr; delete ptr;
break; break;
} }
case Any_MyGame_Example2_Monster: { case Any_MyGame_Example2_Monster: {
auto ptr = reinterpret_cast<MyGame::Example2::MonsterT *>(table); auto ptr = reinterpret_cast<MyGame::Example2::MonsterT *>(value);
delete ptr; delete ptr;
break; break;
} }
default: break; default: break;
} }
table = nullptr; value = nullptr;
type = Any_NONE; type = Any_NONE;
} }

View File

@@ -398,7 +398,7 @@ MyGame.Example.Vec3.prototype.mutate_test2 = function(value) {
/** /**
* @param {MyGame.Example.Test=} obj * @param {MyGame.Example.Test=} obj
* @returns {MyGame.Example.Test} * @returns {MyGame.Example.Test|null}
*/ */
MyGame.Example.Vec3.prototype.test3 = function(obj) { MyGame.Example.Vec3.prototype.test3 = function(obj) {
return (obj || new MyGame.Example.Test).__init(this.bb_pos + 26, this.bb); return (obj || new MyGame.Example.Test).__init(this.bb_pos + 26, this.bb);
@@ -432,6 +432,89 @@ MyGame.Example.Vec3.createVec3 = function(builder, x, y, z, test1, test2, test3_
return builder.offset(); return builder.offset();
}; };
/**
* @constructor
*/
MyGame.Example.Ability = function() {
/**
* @type {flatbuffers.ByteBuffer}
*/
this.bb = null;
/**
* @type {number}
*/
this.bb_pos = 0;
};
/**
* @param {number} i
* @param {flatbuffers.ByteBuffer} bb
* @returns {MyGame.Example.Ability}
*/
MyGame.Example.Ability.prototype.__init = function(i, bb) {
this.bb_pos = i;
this.bb = bb;
return this;
};
/**
* @returns {number}
*/
MyGame.Example.Ability.prototype.id = function() {
return this.bb.readUint32(this.bb_pos);
};
/**
* @param {number} value
* @returns {boolean}
*/
MyGame.Example.Ability.prototype.mutate_id = function(value) {
var offset = this.bb.__offset(this.bb_pos, 0);
if (offset === 0) {
return false;
}
this.bb.writeUint32(this.bb_pos + offset, value);
return true;
};
/**
* @returns {number}
*/
MyGame.Example.Ability.prototype.distance = function() {
return this.bb.readUint32(this.bb_pos + 4);
};
/**
* @param {number} value
* @returns {boolean}
*/
MyGame.Example.Ability.prototype.mutate_distance = function(value) {
var offset = this.bb.__offset(this.bb_pos, 4);
if (offset === 0) {
return false;
}
this.bb.writeUint32(this.bb_pos + offset, value);
return true;
};
/**
* @param {flatbuffers.Builder} builder
* @param {number} id
* @param {number} distance
* @returns {flatbuffers.Offset}
*/
MyGame.Example.Ability.createAbility = function(builder, id, distance) {
builder.prep(4, 8);
builder.writeInt32(distance);
builder.writeInt32(id);
return builder.offset();
};
/** /**
* @constructor * @constructor
*/ */
@@ -469,7 +552,7 @@ MyGame.Example.Stat.getRootAsStat = function(bb, obj) {
/** /**
* @param {flatbuffers.Encoding=} optionalEncoding * @param {flatbuffers.Encoding=} optionalEncoding
* @returns {string|Uint8Array} * @returns {string|Uint8Array|null}
*/ */
MyGame.Example.Stat.prototype.id = function(optionalEncoding) { MyGame.Example.Stat.prototype.id = function(optionalEncoding) {
var offset = this.bb.__offset(this.bb_pos, 4); var offset = this.bb.__offset(this.bb_pos, 4);
@@ -609,7 +692,7 @@ MyGame.Example.Monster.bufferHasIdentifier = function(bb) {
/** /**
* @param {MyGame.Example.Vec3=} obj * @param {MyGame.Example.Vec3=} obj
* @returns {MyGame.Example.Vec3} * @returns {MyGame.Example.Vec3|null}
*/ */
MyGame.Example.Monster.prototype.pos = function(obj) { MyGame.Example.Monster.prototype.pos = function(obj) {
var offset = this.bb.__offset(this.bb_pos, 4); var offset = this.bb.__offset(this.bb_pos, 4);
@@ -664,7 +747,7 @@ MyGame.Example.Monster.prototype.mutate_hp = function(value) {
/** /**
* @param {flatbuffers.Encoding=} optionalEncoding * @param {flatbuffers.Encoding=} optionalEncoding
* @returns {string|Uint8Array} * @returns {string|Uint8Array|null}
*/ */
MyGame.Example.Monster.prototype.name = function(optionalEncoding) { MyGame.Example.Monster.prototype.name = function(optionalEncoding) {
var offset = this.bb.__offset(this.bb_pos, 10); var offset = this.bb.__offset(this.bb_pos, 10);
@@ -810,7 +893,7 @@ MyGame.Example.Monster.prototype.testarrayoftablesLength = function() {
/** /**
* @param {MyGame.Example.Monster=} obj * @param {MyGame.Example.Monster=} obj
* @returns {MyGame.Example.Monster} * @returns {MyGame.Example.Monster|null}
*/ */
MyGame.Example.Monster.prototype.enemy = function(obj) { MyGame.Example.Monster.prototype.enemy = function(obj) {
var offset = this.bb.__offset(this.bb_pos, 28); var offset = this.bb.__offset(this.bb_pos, 28);
@@ -844,7 +927,7 @@ MyGame.Example.Monster.prototype.testnestedflatbufferArray = function() {
/** /**
* @param {MyGame.Example.Stat=} obj * @param {MyGame.Example.Stat=} obj
* @returns {MyGame.Example.Stat} * @returns {MyGame.Example.Stat|null}
*/ */
MyGame.Example.Monster.prototype.testempty = function(obj) { MyGame.Example.Monster.prototype.testempty = function(obj) {
var offset = this.bb.__offset(this.bb_pos, 32); var offset = this.bb.__offset(this.bb_pos, 32);
@@ -1170,11 +1253,54 @@ MyGame.Example.Monster.prototype.testarrayofstring2Length = function() {
return offset ? this.bb.__vector_len(this.bb_pos + offset) : 0; return offset ? this.bb.__vector_len(this.bb_pos + offset) : 0;
}; };
/**
* @param {number} index
* @param {MyGame.Example.Ability=} obj
* @returns {MyGame.Example.Ability}
*/
MyGame.Example.Monster.prototype.testarrayofsortedstruct = function(index, obj) {
var offset = this.bb.__offset(this.bb_pos, 62);
return offset ? (obj || new MyGame.Example.Ability).__init(this.bb.__vector(this.bb_pos + offset) + index * 8, this.bb) : null;
};
/**
* @returns {number}
*/
MyGame.Example.Monster.prototype.testarrayofsortedstructLength = function() {
var offset = this.bb.__offset(this.bb_pos, 62);
return offset ? this.bb.__vector_len(this.bb_pos + offset) : 0;
};
/**
* @param {number} index
* @returns {number}
*/
MyGame.Example.Monster.prototype.flex = function(index) {
var offset = this.bb.__offset(this.bb_pos, 64);
return offset ? this.bb.readUint8(this.bb.__vector(this.bb_pos + offset) + index) : 0;
};
/**
* @returns {number}
*/
MyGame.Example.Monster.prototype.flexLength = function() {
var offset = this.bb.__offset(this.bb_pos, 64);
return offset ? this.bb.__vector_len(this.bb_pos + offset) : 0;
};
/**
* @returns {Uint8Array}
*/
MyGame.Example.Monster.prototype.flexArray = function() {
var offset = this.bb.__offset(this.bb_pos, 64);
return offset ? new Uint8Array(this.bb.bytes().buffer, this.bb.bytes().byteOffset + this.bb.__vector(this.bb_pos + offset), this.bb.__vector_len(this.bb_pos + offset)) : null;
};
/** /**
* @param {flatbuffers.Builder} builder * @param {flatbuffers.Builder} builder
*/ */
MyGame.Example.Monster.startMonster = function(builder) { MyGame.Example.Monster.startMonster = function(builder) {
builder.startObject(29); builder.startObject(31);
}; };
/** /**
@@ -1535,6 +1661,51 @@ MyGame.Example.Monster.startTestarrayofstring2Vector = function(builder, numElem
builder.startVector(4, numElems, 4); builder.startVector(4, numElems, 4);
}; };
/**
* @param {flatbuffers.Builder} builder
* @param {flatbuffers.Offset} testarrayofsortedstructOffset
*/
MyGame.Example.Monster.addTestarrayofsortedstruct = function(builder, testarrayofsortedstructOffset) {
builder.addFieldOffset(29, testarrayofsortedstructOffset, 0);
};
/**
* @param {flatbuffers.Builder} builder
* @param {number} numElems
*/
MyGame.Example.Monster.startTestarrayofsortedstructVector = function(builder, numElems) {
builder.startVector(8, numElems, 4);
};
/**
* @param {flatbuffers.Builder} builder
* @param {flatbuffers.Offset} flexOffset
*/
MyGame.Example.Monster.addFlex = function(builder, flexOffset) {
builder.addFieldOffset(30, flexOffset, 0);
};
/**
* @param {flatbuffers.Builder} builder
* @param {Array.<number>} data
* @returns {flatbuffers.Offset}
*/
MyGame.Example.Monster.createFlexVector = function(builder, data) {
builder.startVector(1, data.length, 1);
for (var i = data.length - 1; i >= 0; i--) {
builder.addInt8(data[i]);
}
return builder.endVector();
};
/**
* @param {flatbuffers.Builder} builder
* @param {number} numElems
*/
MyGame.Example.Monster.startFlexVector = function(builder, numElems) {
builder.startVector(1, numElems, 1);
};
/** /**
* @param {flatbuffers.Builder} builder * @param {flatbuffers.Builder} builder
* @returns {flatbuffers.Offset} * @returns {flatbuffers.Offset}

File diff suppressed because it is too large Load Diff

Binary file not shown.

View File

@@ -1,13 +1,13 @@
{ {
pos: { pos: {
x: 1, x: 1.0,
y: 2, y: 2.0,
z: 3, z: 3.0,
test1: 3, test1: 3.0,
test2: Green, test2: Green,
test3: { test3: {
a: 5, a: 10,
b: 6 b: 20
} }
}, },
hp: 80, hp: 80,
@@ -17,7 +17,12 @@
1, 1,
2, 2,
3, 3,
4 4,
5,
6,
7,
8,
9
], ],
test_type: Monster, test_type: Monster,
test: { test: {
@@ -34,8 +39,22 @@
} }
], ],
testarrayofstring: [ testarrayofstring: [
"test1", "bob",
"test2" "fred",
"bob",
"fred"
],
testarrayoftables: [
{
hp: 1000,
name: "Barney"
},
{
name: "Fred"
},
{
name: "Wilma"
}
], ],
testhashs32_fnv1: -579221183, testhashs32_fnv1: -579221183,
testhashu32_fnv1: 3715746113, testhashu32_fnv1: 3715746113,
@@ -44,5 +63,6 @@
testhashs32_fnv1a: -1904106383, testhashs32_fnv1a: -1904106383,
testhashu32_fnv1a: 2390860913, testhashu32_fnv1a: 2390860913,
testhashs64_fnv1a: 4898026182817603057, testhashs64_fnv1a: 4898026182817603057,
testhashu64_fnv1a: 4898026182817603057 testhashu64_fnv1a: 4898026182817603057,
flex: 1234
} }

Binary file not shown.

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