Merge pull request #3977 from gonzaloserrano/feature/go-generic-deserialitzation
Add a generic way to deserialize a flatbuffer in Go.
diff --git a/.gitignore b/.gitignore
index e07fbae..9dfabef 100755
--- a/.gitignore
+++ b/.gitignore
@@ -64,3 +64,5 @@
build/VS2010/FlatBuffers.sdf
build/VS2010/FlatBuffers.opensdf
build/VS2010/ipch/**/*.ipch
+*.so
+Testing/Temporary
diff --git a/CMake/PackageDebian.cmake b/CMake/PackageDebian.cmake
new file mode 100644
index 0000000..ebe8931
--- /dev/null
+++ b/CMake/PackageDebian.cmake
@@ -0,0 +1,57 @@
+# ------------------- Debianization ---------------------
+if (UNIX)
+
+ # Set build environment
+ SET(CPACK_GENERATOR "TGZ;DEB")
+ SET(CPACK_SOURCE_TGZ "ON")
+
+ # Common package information
+ SET(CPACK_PACKAGE_DESCRIPTION_SUMMARY
+ "FlatBuffers is an efficient cross platform serialization library for C++, with support for Java, C# and Go. It was created at Google specifically for game development and other performance-critical applications.")
+ SET(CPACK_DEBIAN_PACKAGE_HOMEPAGE "https://github.com/google/flatbuffers")
+ SET(CPACK_DEBIAN_PACKAGE_MAINTAINER "Vitaly Isaev <vitalyisaev2@gmail.com>")
+
+ # Derive package version from git
+ EXECUTE_PROCESS(
+ COMMAND date +%Y%m%d
+ OUTPUT_VARIABLE DATE
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+ )
+ EXECUTE_PROCESS(
+ COMMAND git describe
+ WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
+ OUTPUT_VARIABLE GIT_DESCRIBE_DIRTY
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+ )
+ string(REGEX REPLACE "^v([0-9]+)\\..*" "\\1" VERSION_MAJOR "${GIT_DESCRIBE_DIRTY}")
+ string(REGEX REPLACE "^v[0-9]+\\.([0-9]+).*" "\\1" VERSION_MINOR "${GIT_DESCRIBE_DIRTY}")
+ string(REGEX REPLACE "^v[0-9]+\\.[0-9]+\\.([0-9]+).*" "\\1" VERSION_PATCH "${GIT_DESCRIBE_DIRTY}")
+ string(REGEX REPLACE "^v[0-9]+\\.[0-9]+\\.[0-9]+\\-([0-9]+).*" "\\1" VERSION_COMMIT "${GIT_DESCRIBE_DIRTY}")
+ SET(CPACK_PACKAGE_VERSION_MAJOR ${VERSION_MAJOR})
+ SET(CPACK_PACKAGE_VERSION_MINOR ${VERSION_MINOR})
+ SET(CPACK_PACKAGE_VERSION_PATCH ${VERSION_PATCH})
+ SET(CPACK_PACKAGE_VERSION "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}-${VERSION_COMMIT}")
+ SET(CPACK_DEBIAN_PACKAGE_VERSION "${CPACK_PACKAGE_VERSION}")
+
+ # Derive architecture
+ IF(NOT CPACK_DEBIAN_PACKAGE_ARCHITECTURE)
+ FIND_PROGRAM(DPKG_CMD dpkg)
+ IF(NOT DPKG_CMD)
+ MESSAGE(STATUS "Can not find dpkg in your path, default to i386.")
+ SET(CPACK_DEBIAN_PACKAGE_ARCHITECTURE i386)
+ ENDIF(NOT DPKG_CMD)
+ EXECUTE_PROCESS(COMMAND "${DPKG_CMD}" --print-architecture
+ OUTPUT_VARIABLE CPACK_DEBIAN_PACKAGE_ARCHITECTURE
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+ )
+ ENDIF(NOT CPACK_DEBIAN_PACKAGE_ARCHITECTURE)
+
+ # Package name
+ SET(CPACK_DEBIAN_PACKAGE_NAME "flatbuffers")
+ SET(CPACK_RESOURCE_FILE_LICENSE ${CMAKE_SOURCE_DIR}/LICENSE.txt)
+ SET(CPACK_PACKAGE_FILE_NAME
+ "${CPACK_DEBIAN_PACKAGE_NAME}_${CPACK_DEBIAN_PACKAGE_VERSION}_${CPACK_DEBIAN_PACKAGE_ARCHITECTURE}")
+
+endif(UNIX)
+
+INCLUDE(CPack)
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 81c9e58..7a6b370 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -12,6 +12,9 @@
ON)
option(FLATBUFFERS_BUILD_FLATHASH "Enable the build of flathash" ON)
option(FLATBUFFERS_BUILD_GRPCTEST "Enable the build of grpctest" OFF)
+option(FLATBUFFERS_BUILD_SHAREDLIB
+ "Enable the build of the flatbuffers shared library"
+ OFF)
if(NOT FLATBUFFERS_BUILD_FLATC AND FLATBUFFERS_BUILD_TESTS)
message(WARNING
@@ -44,8 +47,11 @@
src/idl_gen_fbs.cpp
src/idl_gen_grpc.cpp
src/flatc.cpp
+ grpc/src/compiler/schema_interface.h
grpc/src/compiler/cpp_generator.h
grpc/src/compiler/cpp_generator.cc
+ grpc/src/compiler/go_generator.h
+ grpc/src/compiler/go_generator.cc
)
set(FlatHash_SRCS
@@ -95,7 +101,10 @@
# source_group(Compiler FILES ${FlatBuffers_Compiler_SRCS})
# source_group(Tests FILES ${FlatBuffers_Tests_SRCS})
-if(APPLE)
+if(EXISTS "${CMAKE_TOOLCHAIN_FILE}")
+ # do not apply any global settings if the toolchain
+ # is being configured externally
+elseif(APPLE)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -stdlib=libc++")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -pedantic -Werror -Wextra")
elseif(CMAKE_COMPILER_IS_GNUCXX)
@@ -110,7 +119,8 @@
"${CMAKE_CXX_FLAGS} -Wall -pedantic -Werror -Wextra -Werror=shadow")
if (GCC_VERSION VERSION_GREATER 4.4)
set(CMAKE_CXX_FLAGS
- "${CMAKE_CXX_FLAGS} -Wunused-result -Werror=unused-result")
+ "${CMAKE_CXX_FLAGS} -Wunused-result -Werror=unused-result \
+ -Wunused-parameter -Werror=unused-parameter")
endif()
# Certain platforms such as ARM do not use signed chars by default
@@ -118,7 +128,7 @@
set(CMAKE_CXX_FLAGS
"${CMAKE_CXX_FLAGS} -fsigned-char")
-elseif("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
+elseif(${CMAKE_CXX_COMPILER_ID} MATCHES "Clang")
set(CMAKE_CXX_FLAGS
"${CMAKE_CXX_FLAGS} -std=c++0x -stdlib=libc++ -Wall -pedantic -Werror \
-Wextra")
@@ -163,6 +173,11 @@
add_executable(flathash ${FlatHash_SRCS})
endif()
+if(FLATBUFFERS_BUILD_SHAREDLIB)
+ add_library(flatbuffers_shared SHARED ${FlatBuffers_Library_SRCS})
+ set_target_properties(flatbuffers_shared PROPERTIES OUTPUT_NAME flatbuffers)
+endif()
+
function(compile_flatbuffers_schema_to_cpp SRC_FBS)
get_filename_component(SRC_FBS_DIR ${SRC_FBS} PATH)
string(REGEX REPLACE "\\.fbs$" "_generated.h" GEN_HEADER ${SRC_FBS})
@@ -211,6 +226,9 @@
if(FLATBUFFERS_BUILD_FLATC)
install(TARGETS flatc DESTINATION bin)
endif()
+ if(FLATBUFFERS_BUILD_SHAREDLIB)
+ install(TARGETS flatbuffers_shared DESTINATION lib)
+ endif()
endif()
if(FLATBUFFERS_BUILD_TESTS)
@@ -222,3 +240,7 @@
endif()
include(CMake/BuildFlatBuffers.cmake)
+
+if(FLATBUFFERS_PACKAGE_DEBIAN)
+ include(CMake/PackageDebian.cmake)
+endif()
diff --git a/docs/source/CppUsage.md b/docs/source/CppUsage.md
index 87a11c8..4a9c78e 100755
--- a/docs/source/CppUsage.md
+++ b/docs/source/CppUsage.md
@@ -99,13 +99,41 @@
To use:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
- auto monsterobj = GetMonster(buffer)->UnPack();
+ auto monsterobj = UnpackMonster(buffer);
cout << monsterobj->name; // This is now a std::string!
monsterobj->name = "Bob"; // Change the name.
FlatBufferBuilder fbb;
CreateMonster(fbb, monsterobj.get()); // Serialize into new buffer.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+# External references.
+
+An additional feature of the object API is the ability to allow you to load
+multiple independent FlatBuffers, and have them refer to eachothers objects
+using hashes which are then represented as typed pointers in the object API.
+
+To make this work have a field in the objects you want to referred to which is
+using the string hashing feature (see `hash` attribute in the
+[schema](@ref flatbuffers_guide_writing_schema) documentation). Then you have
+a similar hash in the field referring to it, along with a `cpp_type`
+attribute specifying the C++ type this will refer to (this can be any C++
+type, and will get a `*` added).
+
+Then, in JSON or however you create these buffers, make sure they use the
+same string (or hash).
+
+When you call `UnPack` (or `Create`), you'll need a function that maps from
+hash to the object (see `resolver_function_t` for details).
+
+# Using different pointer types.
+
+By default the object tree is built out of `std::unique_ptr`, but you can
+influence this either globally (using the `--cpp-ptr-type` argument to
+`flatc`) or per field (using the `cpp_ptr_type` attribute) to by any smart
+pointer type (`my_ptr<T>`), or by specifying `naked` as the type to get `T *`
+pointers. Unlike the smart pointers, naked pointers do not manage memory for
+you, so you'll have to manage their lifecycles manually.
+
## Reflection (& Resizing)
There is experimental support for reflection in FlatBuffers, allowing you to
diff --git a/docs/source/JavaCsharpUsage.md b/docs/source/JavaCsharpUsage.md
index 3af9cfa..cc58f85 100755
--- a/docs/source/JavaCsharpUsage.md
+++ b/docs/source/JavaCsharpUsage.md
@@ -131,6 +131,36 @@
monster.GetPos(preconstructedPos);
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+## Storing dictionaries in a FlatBuffer
+
+FlatBuffers doesn't support dictionaries natively, but there is support to
+emulate their behavior with vectors and binary search, which means you
+can have fast lookups directly from a FlatBuffer without having to unpack
+your data into a `Dictionary` or similar.
+
+To use it:
+- Designate one of the fields in a table as they "key" field. You do this
+ by setting the `key` attribute on this field, e.g.
+ `name:string (key)`.
+ You may only have one key field, and it must be of string or scalar type.
+- Write out tables of this type as usual, collect their offsets in an
+ array.
+- Instead of calling standard generated method,
+ e.g.: `Monster.createTestarrayoftablesVector`,
+ call `CreateMySortedVectorOfTables` in C# or
+ `createSortedVectorOfTables` (from the `FlatBufferBuilder` object) in Java,
+ which will first sort all offsets such that the tables they refer to
+ are sorted by the key field, then serialize it.
+- Now when you're accessing the FlatBuffer, you can use `LookupByKey`
+ to access elements of the vector, e.g.:
+ `Monster.lookupByKey(tablesVectorOffset, "Frodo", dataBuffer)`,
+ which returns an object of the corresponding table type,
+ or `null` if not found.
+ `LookupByKey` performs a binary search, so should have a similar speed to
+ `Dictionary`, though may be faster because of better caching. `LookupByKey`
+ only works if the vector has been sorted, it will likely not find elements
+ if it hasn't been sorted.
+
## Text parsing
There currently is no support for parsing text (Schema's and JSON) directly
diff --git a/docs/source/Schemas.md b/docs/source/Schemas.md
index 5bcaccb..f9fe486 100755
--- a/docs/source/Schemas.md
+++ b/docs/source/Schemas.md
@@ -304,6 +304,10 @@
- `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
binary search.
+- `hash` (on a field). This is an (un)signed 32/64 bit integer field, whose
+ value during JSON parsing is allowed to be a string, which will then be
+ stored as its hash. The value of attribute is the hashing algorithm to
+ use, one of `fnv1_32` `fnv1_64` `fnv1a_32` `fnv1a_64`.
## JSON Parsing
diff --git a/docs/source/Tutorial.md b/docs/source/Tutorial.md
index 100191d..7d9c6d9 100644
--- a/docs/source/Tutorial.md
+++ b/docs/source/Tutorial.md
@@ -399,55 +399,56 @@
Now we are ready to start building some buffers. In order to start, we need
to create an instance of the `FlatBufferBuilder`, which will contain the buffer
-as it grows:
+as it grows. You can pass an initial size of the buffer (here 1024 bytes),
+which will grow automatically if needed:
<div class="language-cpp">
~~~{.cpp}
// Create a `FlatBufferBuilder`, which will be used to create our
// monsters' FlatBuffers.
- flatbuffers::FlatBufferBuilder builder;
+ flatbuffers::FlatBufferBuilder builder(1024);
~~~
</div>
<div class="language-java">
~~~{.java}
// Create a `FlatBufferBuilder`, which will be used to create our
// monsters' FlatBuffers.
- FlatBufferBuilder builder = new FlatBufferBuilder(0);
+ FlatBufferBuilder builder = new FlatBufferBuilder(1024);
~~~
</div>
<div class="language-csharp">
~~~{.cs}
// Create a `FlatBufferBuilder`, which will be used to create our
// monsters' FlatBuffers.
- var builder = new FlatBufferBuilder(1);
+ var builder = new FlatBufferBuilder(1024);
~~~
</div>
<div class="language-go">
~~~{.go}
// Create a `FlatBufferBuilder`, which will be used to create our
// monsters' FlatBuffers.
- builder := flatbuffers.NewBuilder(0)
+ builder := flatbuffers.NewBuilder(1024)
~~~
</div>
<div class="language-python">
~~~{.py}
# Create a `FlatBufferBuilder`, which will be used to create our
# monsters' FlatBuffers.
- builder = flatbuffers.Builder(0)
+ builder = flatbuffers.Builder(1024)
~~~
</div>
<div class="language-javascript">
~~~{.js}
// Create a `flatbuffer.Builder`, which will be used to create our
// monsters' FlatBuffers.
- var builder = new flatbuffers.Builder(1);
+ var builder = new flatbuffers.Builder(1024);
~~~
</div>
<div class="language-php">
~~~{.php}
// Create a `FlatBufferBuilder`, which will be used to create our
// monsters' FlatBuffers.
- $builder = new Google\FlatBuffers\FlatbufferBuilder(0);
+ $builder = new Google\FlatBuffers\FlatbufferBuilder(1024);
~~~
</div>
<div class="language-c">
@@ -798,58 +799,6 @@
there's also `CreateVectorOfStrings`.
</div>
-To create a `struct`, use the `Vec3` class/struct that was generated by
-the schema compiler:
-
-<div class="language-cpp">
-~~~{.cpp}
- // Create a `Vec3`, representing the Orc's position in 3-D space.
- auto pos = Vec3(1.0f, 2.0f, 3.0f);
-~~~
-</div>
-<div class="language-java">
-~~~{.java}
- // Create a `Vec3`, representing the Orc's position in 3-D space.
- int pos = Vec3.createVec3(builder, 1.0f, 2.0f, 3.0f);
-~~~
-</div>
-<div class="language-csharp">
-~~~{.cs}
- // Create a `Vec3`, representing the Orc's position in 3-D space.
- var pos = Vec3.CreateVec3(builder, 1.0f, 2.0f, 3.0f);
-~~~
-</div>
-<div class="language-go">
-~~~{.go}
- // Create a `Vec3`, representing the Orc's position in 3-D space.
- pos := sample.CreateVec3(builder, 1.0, 2.0, 3.0)
-~~~
-</div>
-<div class="language-python">
-~~~{.py}
- # Create a `Vec3`, representing the Orc's position in 3-D space.
- pos = MyGame.Sample.Vec3.CreateVec3(builder, 1.0, 2.0, 3.0)
-~~~
-</div>
-<div class="language-javascript">
-~~~{.js}
- // Create a `Vec3`, representing the Orc's position in 3-D space.
- var pos = MyGame.Sample.Vec3.createVec3(builder, 1.0, 2.0, 3.0);
-~~~
-</div>
-<div class="language-php">
-~~~{.js}
- // Create a `Vec3`, representing the Orc's position in 3-D space.
- $pos = \MyGame\Sample\Vec3::CreateVec3($builder, 1.0, 2.0, 3.0);
-~~~
-</div>
-<div class="language-c">
-~~~{.c}
- // Create a `Vec3`, representing the Orc's position in 3-D space.
- ns(Vec3_t) pos = { 1.0f, 2.0f, 3.0f };
-~~~
-</div>
-
We have now serialized the non-scalar components of the orc, so we
can serialize the monster itself:
@@ -861,15 +810,16 @@
// Finally, create the monster using the `CreateMonster` helper function
// to set all fields.
- auto orc = CreateMonster(builder, &pos, mana, hp, name, inventory, Color_Red,
- weapons, Equipment_Weapon, axe.Union());
+ auto orc = CreateMonster(builder, Vec3(1.0f, 2.0f, 3.0f), mana, hp, name,
+ inventory, Color_Red, weapons, Equipment_Weapon,
+ axe.Union());
~~~
</div>
<div class="language-java">
~~~{.java}
// Create our monster using `startMonster()` and `endMonster()`.
Monster.startMonster(builder);
- Monster.addPos(builder, pos);
+ Monster.addPos(builder, Vec3.createVec3(builder, 1.0f, 2.0f, 3.0f));
Monster.addName(builder, name);
Monster.addColor(builder, Color.Red);
Monster.addHp(builder, (short)300);
@@ -884,7 +834,7 @@
~~~{.cs}
// Create our monster using `StartMonster()` and `EndMonster()`.
Monster.StartMonster(builder);
- Monster.AddPos(builder, pos);
+ Monster.AddPos(builder, Vec3.CreateVec3(builder, 1.0f, 2.0f, 3.0f));
Monster.AddHp(builder, (short)300);
Monster.AddName(builder, name);
Monster.AddInventory(builder, inv);
@@ -899,7 +849,7 @@
~~~{.go}
// Create our monster using `MonsterStart()` and `MonsterEnd()`.
sample.MonsterStart(builder)
- sample.MonsterAddPos(builder, pos)
+ sample.MonsterAddPos(builder, sample.CreateVec3(builder, 1.0, 2.0, 3.0))
sample.MonsterAddHp(builder, 300)
sample.MonsterAddName(builder, name)
sample.MonsterAddInventory(builder, inv)
@@ -914,7 +864,8 @@
~~~{.py}
# Create our monster by using `MonsterStart()` and `MonsterEnd()`.
MyGame.Sample.Monster.MonsterStart(builder)
- MyGame.Sample.Monster.MonsterAddPos(builder, pos)
+ MyGame.Sample.Monster.MonsterAddPos(builder,
+ MyGame.Sample.Vec3.CreateVec3(builder, 1.0, 2.0, 3.0))
MyGame.Sample.Monster.MonsterAddHp(builder, 300)
MyGame.Sample.Monster.MonsterAddName(builder, name)
MyGame.Sample.Monster.MonsterAddInventory(builder, inv)
@@ -931,7 +882,8 @@
~~~{.js}
// Create our monster by using `startMonster()` and `endMonster()`.
MyGame.Sample.Monster.startMonster(builder);
- MyGame.Sample.Monster.addPos(builder, pos);
+ MyGame.Sample.Monster.addPos(builder,
+ MyGame.Sample.Vec3.createVec3(builder, 1.0, 2.0, 3.0));
MyGame.Sample.Monster.addHp(builder, 300);
MyGame.Sample.Monster.addColor(builder, MyGame.Sample.Color.Red)
MyGame.Sample.Monster.addName(builder, name);
@@ -946,7 +898,8 @@
~~~{.php}
// Create our monster by using `StartMonster()` and `EndMonster()`.
\MyGame\Sample\Monster::StartMonster($builder);
- \MyGame\Sample\Monster::AddPos($builder, $pos);
+ \MyGame\Sample\Monster::AddPos($builder,
+ \MyGame\Sample\Vec3::CreateVec3($builder, 1.0, 2.0, 3.0));
\MyGame\Sample\Monster::AddHp($builder, 300);
\MyGame\Sample\Monster::AddName($builder, $name);
\MyGame\Sample\Monster::AddInventory($builder, $inv);
@@ -966,11 +919,21 @@
// Define an equipment union. `create` calls in C has a single
// argument for unions where C++ has both a type and a data argument.
ns(Equipment_union_ref_t) equipped = ns(Equipment_as_Weapon(axe));
+ ns(Vec3_t) pos = { 1.0f, 2.0f, 3.0f };
ns(Monster_create_as_root(B, &pos, mana, hp, name, inventory, ns(Color_Red),
weapons, equipped));
~~~
</div>
+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
+scalars themselves.
+
+**Important**: you should not nest tables or any other objects, which is why
+we created all the strings/vectors/tables that this monster refers to before
+`start`. If you try to create any of them between `start` and `end`, 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
default value, the field will not actually be written to the buffer, since the
default value will be returned on query anyway. This is a nice space savings,
@@ -1161,12 +1124,23 @@
~~~{.java}
// This must be called after `finish()`.
java.nio.ByteBuffer buf = builder.dataBuffer();
+ // The data in this ByteBuffer does NOT start at 0, but at buf.position().
+ // The number of bytes is buf.remaining().
+
+ // Alternatively this copies the above data out of the ByteBuffer for you:
+ bytes[] buf = builder.sizedByteArray();
~~~
</div>
<div class="language-csharp">
~~~{.cs}
// This must be called after `Finish()`.
var buf = builder.DataBuffer; // Of type `FlatBuffers.ByteBuffer`.
+ // The data in this ByteBuffer does NOT start at 0, but at buf.Position.
+ // The end of the data is marked by buf.Length, so the size is
+ // buf.Length - buf.Position.
+
+ // Alternatively this copies the above data out of the ByteBuffer for you:
+ bytes[] buf = builder.SizedByteArray();
~~~
</div>
<div class="language-go">
@@ -1184,13 +1158,16 @@
<div class="language-javascript">
~~~{.js}
// This must be called after `finish()`.
- var buf = builder.dataBuffer(); // Of type `flatbuffers.ByteBuffer`.
+ var buf = builder.asUint8Array(); // Of type `Uint8Array`.
~~~
</div>
<div class="language-php">
~~~{.php}
// This must be called after `finish()`.
$buf = $builder->dataBuffer(); // Of type `Google\FlatBuffers\ByteBuffer`
+ // The data in this ByteBuffer does NOT start at 0, but at buf->getPosition().
+ // The end of the data is marked by buf->capacity(), so the size is
+ // buf->capacity() - buf->getPosition().
~~~
</div>
<div class="language-c">
@@ -1217,6 +1194,11 @@
~~~
</div>
+Now you can write the bytes to a file, send them over the network..
+**Make sure your file mode (or tranfer protocol) is set to BINARY, not text.**
+If you transfer a FlatBuffer in text mode, the buffer will be corrupted,
+which will lead to hard to find problems when you read the buffer.
+
#### Reading Orc FlatBuffers
Now that we have successfully created an `Orc` FlatBuffer, the monster data can
@@ -1312,92 +1294,82 @@
~~~
</div>
-Then, assuming you have a variable containing to the bytes of data from disk,
-network, etc., you can create a monster from this data:
+Then, assuming you have a buffer of bytes received from disk,
+network, etc., you can create start accessing the buffer like so:
+
+**Again, make sure you read the bytes in BINARY mode, otherwise the code below
+won't work**
<div class="language-cpp">
~~~{.cpp}
- // We can access the buffer we just made directly. Pretend this came over a
- // network, was read off of disk, etc.
- auto buffer_pointer = builder.GetBufferPointer();
+ uint8_t *buffer_pointer = /* the data you just read */;
- // Deserialize the data from the buffer.
+ // Get a pointer to the root object inside the buffer.
auto monster = GetMonster(buffer_pointer);
- // `monster` is of type`Monster *`, and points to somewhere inside the buffer.
-
+ // `monster` is of type `Monster *`.
// Note: root object pointers are NOT the same as `buffer_pointer`.
~~~
</div>
<div class="language-java">
~~~{.java}
- // We can access the buffer we just made directly. Pretend this came over a
- // network, was read off of disk, etc.
- java.nio.ByteBuffer buf = builder.dataBuffer();
+ byte[] bytes = /* the data you just read */
+ java.nio.ByteBuffer buf = java.nio.ByteBuffer.wrap(bytes);
- // Deserialize the data from the buffer.
+ // Get an accessor to the root object inside the buffer.
Monster monster = Monster.getRootAsMonster(buf);
~~~
</div>
<div class="language-csharp">
~~~{.cs}
- // We can access the buffer we just made directly. Pretend this came over a
- // network, was read off of disk, etc.
- var buf = builder.DataBuffer;
+ byte[] bytes = /* the data you just read */
+ var buf = new ByteBuffer(bytes);
- // Deserialize the data from the buffer.
+ // Get an accessor to the root object inside the buffer.
var monster = Monster.GetRootAsMonster(buf);
~~~
</div>
<div class="language-go">
~~~{.go}
- // We can access the buffer we just made directly. Pretend this came over a
- // network, was read off of disk, etc.
- buf := builder.FinishedBytes()
+ var buf []byte = /* the data you just read */
- // Deserialize the data from the buffer.
+ // Get an accessor to the root object inside the buffer.
monster := sample.GetRootAsMonster(buf, 0)
- // Note: We use `0` for the offset here, since we got the data using the
- // `builder.FinishedBytes()` method. This simulates the data you would
- // store/receive in your FlatBuffer. If you wanted to read from the
- // `builder.Bytes` directly, you would need to pass in the offset of
- // `builder.Head()`, as the builder actually constructs the buffer backwards.
+ // Note: We use `0` for the offset here, which is typical for most buffers
+ // you would read. If you wanted to read from `builder.Bytes` directly, you
+ // would need to pass in the offset of `builder.Head()`, as the builder
+ // constructs the buffer backwards, so may not start at offset 0.
~~~
</div>
<div class="language-python">
~~~{.py}
- # We can access the buffer we just made directly. Pretend this came over a
- # network, was read off of disk, etc.
- buf = builder.Output()
+ buf = /* the data you just read, in an object of type "bytearray" */
- # Deserialize the data from the buffer.
+ // Get an accessor to the root object inside the buffer.
monster = MyGame.Sample.Monster.Monster.GetRootAsMonster(buf, 0)
- # Note: We use `0` for the offset here, since we got the data using the
- # `builder.Output()` method. This simulates the data you would store/receive
- # in your FlatBuffer. If you wanted to read from the `builder.Bytes` directly,
+ # Note: We use `0` for the offset here, which is typical for most buffers
+ # you would read. If you wanted to read from the `builder.Bytes` directly,
# you would need to pass in the offset of `builder.Head()`, as the builder
- # actually constructs the buffer backwards.
+ # constructs the buffer backwards, so may not start at offset 0.
~~~
</div>
<div class="language-javascript">
~~~{.js}
- // We can access the buffer we just made directly. Pretend this came over a
- // network, was read off of disk, etc.
- var buf = builder.dataBuffer();
+ var bytes = /* the data you just read, in an object of type "Uint8Array" */
+ var buf = new flatbuffers.ByteBuffer(bytes);
- // Deserialize the data from the buffer.
+ // Get an accessor to the root object inside the buffer.
var monster = MyGame.Sample.Monster.getRootAsMonster(buf);
~~~
</div>
<div class="language-php">
~~~{.php}
- // We can access the buffer we just made directly. Pretend this came over a
- // network, was read off of disk, etc.
- $buf = $builder->dataBuffer();
+ $bytes = /* the data you just read, in a string */
+ $buf = Google\FlatBuffers\ByteBuffer::wrap($bytes);
- // Deserialize the data from the buffer.
+ // Get an accessor to the root object inside the buffer.
$monster = \MyGame\Sample\Monster::GetRootAsMonster($buf);
~~~
</div>
diff --git a/docs/source/doxyfile b/docs/source/doxyfile
index bef63f5..db3eeac 100755
--- a/docs/source/doxyfile
+++ b/docs/source/doxyfile
@@ -761,7 +761,7 @@
"WhitePaper.md" \
"Internals.md" \
"Grammar.md" \
- "CONTRIBUTING.md" \
+ "../../CONTRIBUTING.md" \
"Tutorial.md" \
"GoApi.md" \
"groups" \
diff --git a/go/grpc.go b/go/grpc.go
new file mode 100644
index 0000000..07d374b
--- /dev/null
+++ b/go/grpc.go
@@ -0,0 +1,23 @@
+package flatbuffers
+
+// FlatbuffersCodec implements gRPC-go Codec which is used to encode and decode messages.
+var Codec string = "flatbuffers"
+
+type FlatbuffersCodec struct{}
+
+func (FlatbuffersCodec) Marshal(v interface{}) ([]byte, error) {
+ return v.(*Builder).FinishedBytes(), nil
+}
+
+func (FlatbuffersCodec) Unmarshal(data []byte, v interface{}) error {
+ v.(flatbuffersInit).Init(data, GetUOffsetT(data))
+ return nil
+}
+
+func (FlatbuffersCodec) String() string {
+ return Codec
+}
+
+type flatbuffersInit interface {
+ Init(data []byte, i UOffsetT)
+}
diff --git a/grpc/src/compiler/cpp_generator.cc b/grpc/src/compiler/cpp_generator.cc
index 9319c41..e8ad49e 100644
--- a/grpc/src/compiler/cpp_generator.cc
+++ b/grpc/src/compiler/cpp_generator.cc
@@ -67,7 +67,8 @@
template<class T, size_t N>
T *array_end(T (&array)[N]) { return array + N; }
-void PrintIncludes(Printer *printer, const std::vector<grpc::string>& headers, const Parameters ¶ms) {
+void PrintIncludes(grpc_generator::Printer *printer,
+ const std::vector<grpc::string>& headers, const Parameters ¶ms) {
std::map<grpc::string, grpc::string> vars;
vars["l"] = params.use_system_headers ? '<' : '"';
@@ -86,7 +87,7 @@
}
}
-grpc::string GetHeaderPrologue(File *file, const Parameters & /*params*/) {
+grpc::string GetHeaderPrologue(grpc_generator::File *file, const Parameters & /*params*/) {
grpc::string output;
{
// Scope the output stream so it closes and finalizes output to the string.
@@ -111,7 +112,7 @@
return output;
}
-grpc::string GetHeaderIncludes(File *file,
+grpc::string GetHeaderIncludes(grpc_generator::File *file,
const Parameters ¶ms) {
grpc::string output;
{
@@ -154,7 +155,7 @@
}
void PrintHeaderClientMethodInterfaces(
- Printer *printer, const Method *method,
+ grpc_generator::Printer *printer, const grpc_generator::Method *method,
std::map<grpc::string, grpc::string> *vars, bool is_public) {
(*vars)["Method"] = method->name();
(*vars)["Request"] = method->input_type_name();
@@ -303,8 +304,8 @@
}
}
-void PrintHeaderClientMethod(Printer *printer,
- const Method *method,
+void PrintHeaderClientMethod(grpc_generator::Printer *printer,
+ const grpc_generator::Method *method,
std::map<grpc::string, grpc::string> *vars,
bool is_public) {
(*vars)["Method"] = method->name();
@@ -445,13 +446,13 @@
}
}
-void PrintHeaderClientMethodData(Printer *printer, const Method *method,
+void PrintHeaderClientMethodData(grpc_generator::Printer *printer, const grpc_generator::Method *method,
std::map<grpc::string, grpc::string> *vars) {
(*vars)["Method"] = method->name();
printer->Print(*vars, "const ::grpc::RpcMethod rpcmethod_$Method$_;\n");
}
-void PrintHeaderServerMethodSync(Printer *printer, const Method *method,
+void PrintHeaderServerMethodSync(grpc_generator::Printer *printer, const grpc_generator::Method *method,
std::map<grpc::string, grpc::string> *vars) {
(*vars)["Method"] = method->name();
(*vars)["Request"] = method->input_type_name();
@@ -483,8 +484,8 @@
}
void PrintHeaderServerMethodAsync(
- Printer *printer,
- const Method *method,
+ grpc_generator::Printer *printer,
+ const grpc_generator::Method *method,
std::map<grpc::string, grpc::string> *vars) {
(*vars)["Method"] = method->name();
(*vars)["Request"] = method->input_type_name();
@@ -599,8 +600,8 @@
}
void PrintHeaderServerMethodGeneric(
- Printer *printer,
- const Method *method,
+ grpc_generator::Printer *printer,
+ const grpc_generator::Method *method,
std::map<grpc::string, grpc::string> *vars) {
(*vars)["Method"] = method->name();
(*vars)["Request"] = method->input_type_name();
@@ -669,8 +670,8 @@
printer->Print(*vars, "};\n");
}
-void PrintHeaderService(Printer *printer,
- const Service *service,
+void PrintHeaderService(grpc_generator::Printer *printer,
+ const grpc_generator::Service *service,
std::map<grpc::string, grpc::string> *vars) {
(*vars)["Service"] = service->name();
@@ -764,7 +765,7 @@
printer->Print("};\n");
}
-grpc::string GetHeaderServices(File *file,
+grpc::string GetHeaderServices(grpc_generator::File *file,
const Parameters ¶ms) {
grpc::string output;
{
@@ -795,7 +796,7 @@
return output;
}
-grpc::string GetHeaderEpilogue(File *file, const Parameters & /*params*/) {
+grpc::string GetHeaderEpilogue(grpc_generator::File *file, const Parameters & /*params*/) {
grpc::string output;
{
// Scope the output stream so it closes and finalizes output to the string.
@@ -821,7 +822,7 @@
return output;
}
-grpc::string GetSourcePrologue(File *file, const Parameters & /*params*/) {
+grpc::string GetSourcePrologue(grpc_generator::File *file, const Parameters & /*params*/) {
grpc::string output;
{
// Scope the output stream so it closes and finalizes output to the string.
@@ -845,7 +846,7 @@
return output;
}
-grpc::string GetSourceIncludes(File *file,
+grpc::string GetSourceIncludes(grpc_generator::File *file,
const Parameters ¶ms) {
grpc::string output;
{
@@ -880,8 +881,8 @@
return output;
}
-void PrintSourceClientMethod(Printer *printer,
- const Method *method,
+void PrintSourceClientMethod(grpc_generator::Printer *printer,
+ const grpc_generator::Method *method,
std::map<grpc::string, grpc::string> *vars) {
(*vars)["Method"] = method->name();
(*vars)["Request"] = method->input_type_name();
@@ -981,8 +982,8 @@
}
}
-void PrintSourceServerMethod(Printer *printer,
- const Method *method,
+void PrintSourceServerMethod(grpc_generator::Printer *printer,
+ const grpc_generator::Method *method,
std::map<grpc::string, grpc::string> *vars) {
(*vars)["Method"] = method->name();
(*vars)["Request"] = method->input_type_name();
@@ -1040,8 +1041,8 @@
}
}
-void PrintSourceService(Printer *printer,
- const Service *service,
+void PrintSourceService(grpc_generator::Printer *printer,
+ const grpc_generator::Service *service,
std::map<grpc::string, grpc::string> *vars) {
(*vars)["Service"] = service->name();
@@ -1153,7 +1154,7 @@
}
}
-grpc::string GetSourceServices(File *file,
+grpc::string GetSourceServices(grpc_generator::File *file,
const Parameters ¶ms) {
grpc::string output;
{
@@ -1182,7 +1183,7 @@
return output;
}
-grpc::string GetSourceEpilogue(File *file, const Parameters & /*params*/) {
+grpc::string GetSourceEpilogue(grpc_generator::File *file, const Parameters & /*params*/) {
grpc::string temp;
if (!file->package().empty()) {
diff --git a/grpc/src/compiler/cpp_generator.h b/grpc/src/compiler/cpp_generator.h
index 953ddfd..a4adee7 100644
--- a/grpc/src/compiler/cpp_generator.h
+++ b/grpc/src/compiler/cpp_generator.h
@@ -41,16 +41,7 @@
#include <memory>
#include <vector>
-#ifndef GRPC_CUSTOM_STRING
-#include <string>
-#define GRPC_CUSTOM_STRING std::string
-#endif
-
-namespace grpc {
-
-typedef GRPC_CUSTOM_STRING string;
-
-} // namespace grpc
+#include "src/compiler/schema_interface.h"
namespace grpc_cpp_generator {
@@ -64,83 +55,29 @@
grpc::string grpc_search_path;
};
-// An abstract interface representing a method.
-struct Method {
- virtual ~Method() {}
-
- virtual grpc::string name() const = 0;
-
- virtual grpc::string input_type_name() const = 0;
- virtual grpc::string output_type_name() const = 0;
-
- virtual bool NoStreaming() const = 0;
- virtual bool ClientOnlyStreaming() const = 0;
- virtual bool ServerOnlyStreaming() const = 0;
- virtual bool BidiStreaming() const = 0;
-};
-
-// An abstract interface representing a service.
-struct Service {
- virtual ~Service() {}
-
- virtual grpc::string name() const = 0;
-
- virtual int method_count() const = 0;
- virtual std::unique_ptr<const Method> method(int i) const = 0;
-};
-
-struct Printer {
- virtual ~Printer() {}
-
- virtual void Print(const std::map<grpc::string, grpc::string> &vars,
- const char *template_string) = 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
-// libraries/idls/serializers.
-struct File {
- virtual ~File() {}
-
- virtual grpc::string filename() const = 0;
- virtual grpc::string filename_without_ext() const = 0;
- virtual grpc::string message_header_ext() const = 0;
- virtual grpc::string service_header_ext() const = 0;
- 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;
-};
-
// Return the prologue of the generated header file.
-grpc::string GetHeaderPrologue(File *file, const Parameters ¶ms);
+grpc::string GetHeaderPrologue(grpc_generator::File *file, const Parameters ¶ms);
// Return the includes needed for generated header file.
-grpc::string GetHeaderIncludes(File *file, const Parameters ¶ms);
+grpc::string GetHeaderIncludes(grpc_generator::File *file, const Parameters ¶ms);
// Return the includes needed for generated source file.
-grpc::string GetSourceIncludes(File *file, const Parameters ¶ms);
+grpc::string GetSourceIncludes(grpc_generator::File *file, const Parameters ¶ms);
// Return the epilogue of the generated header file.
-grpc::string GetHeaderEpilogue(File *file, const Parameters ¶ms);
+grpc::string GetHeaderEpilogue(grpc_generator::File *file, const Parameters ¶ms);
// Return the prologue of the generated source file.
-grpc::string GetSourcePrologue(File *file, const Parameters ¶ms);
+grpc::string GetSourcePrologue(grpc_generator::File *file, const Parameters ¶ms);
// Return the services for generated header file.
-grpc::string GetHeaderServices(File *file, const Parameters ¶ms);
+grpc::string GetHeaderServices(grpc_generator::File *file, const Parameters ¶ms);
// Return the services for generated source file.
-grpc::string GetSourceServices(File *file, const Parameters ¶ms);
+grpc::string GetSourceServices(grpc_generator::File *file, const Parameters ¶ms);
// Return the epilogue of the generated source file.
-grpc::string GetSourceEpilogue(File *file, const Parameters ¶ms);
+grpc::string GetSourceEpilogue(grpc_generator::File *file, const Parameters ¶ms);
} // namespace grpc_cpp_generator
diff --git a/grpc/src/compiler/go_generator.cc b/grpc/src/compiler/go_generator.cc
new file mode 100644
index 0000000..a35e572
--- /dev/null
+++ b/grpc/src/compiler/go_generator.cc
@@ -0,0 +1,437 @@
+/*
+ *
+ * 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 AN/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.
+ *
+ */
+
+#include <map>
+#include <cctype>
+#include <sstream>
+
+#include "src/compiler/go_generator.h"
+
+template <class T>
+grpc::string as_string(T x) {
+ std::ostringstream out;
+ out << x;
+ return out.str();
+}
+
+namespace grpc_go_generator {
+
+// Returns string with first letter to lowerCase
+grpc::string unexportName(grpc::string s) {
+ if (s.size() <= 0)
+ return s;
+ s[0] = std::tolower(s[0]);
+ return s;
+}
+
+// Returns string with first letter to uppercase
+grpc::string exportName(grpc::string s) {
+ if (s.size() <= 0)
+ return s;
+ s[0] = std::toupper(s[0]);
+ return s;
+}
+
+// Generates imports for the service
+void GenerateImports(grpc_generator::File *file, grpc_generator::Printer *printer,
+ std::map<grpc::string, grpc::string> vars) {
+ vars["filename"] = file->filename();
+ printer->Print("//Generated by gRPC Go plugin\n");
+ printer->Print("//If you make any local changes, they will be lost\n");
+ printer->Print(vars, "//source: $filename$\n\n");
+ printer->Print(vars, "package $Package$\n\n");
+ if (file->additional_imports() != "") {
+ printer->Print(file->additional_imports().c_str());
+ printer->Print("\n\n");
+ }
+ printer->Print("import (\n");
+ printer->Indent();
+ printer->Print(vars, "$context$ \"golang.org/x/net/context\"\n");
+ printer->Print(vars, "$grpc$ \"google.golang.org/grpc\"\n");
+ printer->Outdent();
+ printer->Print(")\n\n");
+}
+
+// Generates Server method signature source
+void GenerateServerMethodSignature(const grpc_generator::Method *method, grpc_generator::Printer *printer,
+ std::map<grpc::string, grpc::string> vars) {
+ vars["Method"] = exportName(method->name());
+ vars["Request"] = method->input_name();
+ vars["Response"] = (vars["CustomMethodIO"] == "") ? method->output_name() : vars["CustomMethodIO"];
+ if (method->NoStreaming()) {
+ printer->Print(vars, "$Method$($context$.Context, *$Request$) (*$Response$, error)");
+ } else if (method->ServerOnlyStreaming()) {
+ printer->Print(vars, "$Method$(*$Request$, $Service$_$Method$Server) error");
+ } else {
+ printer->Print(vars, "$Method$($Service$_$Method$Server) error");
+ }
+}
+
+void GenerateServerMethod(const grpc_generator::Method *method, grpc_generator::Printer *printer,
+ std::map<grpc::string, grpc::string> vars) {
+ vars["Method"] = exportName(method->name());
+ vars["Request"] = method->input_name();
+ vars["Response"] = (vars["CustomMethodIO"] == "") ? method->output_name() : vars["CustomMethodIO"];
+ vars["FullMethodName"] = "/" + vars["Package"] + "." + vars["Service"] + "/" + vars["Method"];
+ vars["Handler"] = "_" + vars["Service"] + "_" + vars["Method"] + "_Handler";
+ if (method->NoStreaming()) {
+ printer->Print(vars, "func $Handler$(srv interface{}, ctx $context$.Context,\n\tdec func(interface{}) error, interceptor $grpc$.UnaryServerInterceptor) (interface{}, error) {\n");
+ printer->Indent();
+ printer->Print(vars, "in := new($Request$)\n");
+ printer->Print("if err := dec(in); err != nil { return nil, err }\n");
+ printer->Print(vars, "if interceptor == nil { return srv.($Service$Server).$Method$(ctx, in) }\n");
+ printer->Print(vars, "info := &$grpc$.UnaryServerInfo{\n");
+ printer->Indent();
+ printer->Print("Server: srv,\n");
+ printer->Print(vars, "FullMethod: \"$FullMethodName$\",\n");
+ printer->Outdent();
+ printer->Print("}\n\n");
+ printer->Print(vars, "handler := func(ctx $context$.Context, req interface{}) (interface{}, error) {\n");
+ printer->Indent();
+ printer->Print(vars, "return srv.($Service$Server).$Method$(ctx, req.(* $Request$))\n");
+ printer->Outdent();
+ printer->Print("}\n");
+ printer->Print("return interceptor(ctx, in, info, handler)\n");
+ printer->Outdent();
+ printer->Print("}\n\n");
+ return;
+ }
+ vars["StreamType"] = vars["ServiceUnexported"] + vars["Method"] + "Server";
+ printer->Print(vars, "func $Handler$(srv interface{}, stream $grpc$.ServerStream) error {\n");
+ printer->Indent();
+ if (method->ServerOnlyStreaming()) {
+ printer->Print(vars, "m := new($Request$)\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");
+ } else {
+ printer->Print(vars, "return srv.($Service$Server).$Method$(&$StreamType${stream})\n");
+ }
+ printer->Outdent();
+ printer->Print("}\n\n");
+
+ bool genSend = method->BidiStreaming() || method->ServerOnlyStreaming();
+ bool genRecv = method->BidiStreaming() || method->ClientOnlyStreaming();
+ bool genSendAndClose = method->ClientOnlyStreaming();
+
+ printer->Print(vars, "type $Service$_$Method$Server interface { \n");
+ printer->Indent();
+ if (genSend) {
+ printer->Print(vars, "Send(* $Response$) error\n");
+ }
+ if (genRecv) {
+ printer->Print(vars, "Recv() (* $Request$, error)\n");
+ }
+ if (genSendAndClose) {
+ printer->Print(vars, "SendAndClose(* $Response$) error\n");
+ }
+ printer->Print(vars, "$grpc$.ServerStream\n");
+ printer->Outdent();
+ printer->Print("}\n\n");
+
+ printer->Print(vars, "type $StreamType$ struct {\n");
+ printer->Indent();
+ printer->Print(vars, "$grpc$.ServerStream\n");
+ printer->Outdent();
+ printer->Print("}\n\n");
+
+ if (genSend) {
+ printer->Print(vars, "func (x *$StreamType$) Send(m *$Response$) error {\n");
+ printer->Indent();
+ printer->Print("return x.ServerStream.SendMsg(m)\n");
+ printer->Outdent();
+ printer->Print("}\n\n");
+ }
+ if (genRecv) {
+ printer->Print(vars, "func (x *$StreamType$) Recv() (*$Request$, error) {\n");
+ printer->Indent();
+ printer->Print(vars, "m := new($Request$)\n");
+ printer->Print("if err := x.ServerStream.RecvMsg(m); err != nil { return nil, err }\n");
+ printer->Print("return m, nil\n");
+ printer->Outdent();
+ printer->Print("}\n\n");
+ }
+ if (genSendAndClose) {
+ printer->Print(vars, "func (x *$StreamType$) SendAndClose(m *$Response$) error {\n");
+ printer->Indent();
+ printer->Print("return x.ServerStream.SendMsg(m)\n");
+ printer->Outdent();
+ printer->Print("}\n\n");
+ }
+
+}
+
+// Generates Client method signature source
+void GenerateClientMethodSignature(const grpc_generator::Method *method, grpc_generator::Printer *printer,
+ std::map<grpc::string, grpc::string> vars) {
+ vars["Method"] = exportName(method->name());
+ vars["Request"] = ", in *" + ((vars["CustomMethodIO"] == "") ? method->input_name() : vars["CustomMethodIO"]);
+ if (method->ClientOnlyStreaming() || method->BidiStreaming()) {
+ vars["Request"] = "";
+ }
+ vars["Response"] = "* " + method->output_name();
+ if (method->ClientOnlyStreaming() || method->BidiStreaming() || method->ServerOnlyStreaming()) {
+ vars["Response"] = vars["Service"] + "_" + vars["Method"] + "Client" ;
+ }
+ printer->Print(vars, "$Method$(ctx $context$.Context$Request$, \n\topts... $grpc$.CallOption) ($Response$, error)");
+}
+
+// Generates Client method source
+void GenerateClientMethod(const grpc_generator::Method *method, grpc_generator::Printer *printer,
+ std::map<grpc::string, grpc::string> vars) {
+ printer->Print(vars, "func (c *$ServiceUnexported$Client) ");
+ GenerateClientMethodSignature(method, printer, vars);
+ printer->Print(" {\n");
+ printer->Indent();
+ vars["Method"] = exportName(method->name());
+ vars["Request"] = (vars["CustomMethodIO"] == "") ? method->input_name() : vars["CustomMethodIO"];
+ vars["Response"] = method->output_name();
+ vars["FullMethodName"] = "/" + vars["Package"] + "." + vars["Service"] + "/" + vars["Method"];
+ if (method->NoStreaming()) {
+ printer->Print(vars, "out := new($Response$)\n");
+ printer->Print(vars, "err := $grpc$.Invoke(ctx, \"$FullMethodName$\", in, out, c.cc, opts...)\n");
+ printer->Print("if err != nil { return nil, err }\n");
+ printer->Print("return out, nil\n");
+ printer->Outdent();
+ printer->Print("}\n\n");
+ return;
+ }
+ vars["StreamType"] = vars["ServiceUnexported"] + vars["Method"] + "Client";
+ printer->Print(vars, "stream, err := $grpc$.NewClientStream(ctx, &$MethodDesc$, c.cc, \"$FullMethodName$\", opts...)\n");
+ printer->Print("if err != nil { return nil, err }\n");
+
+ printer->Print(vars, "x := &$StreamType${stream}\n");
+ if (method->ServerOnlyStreaming()) {
+ 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("return x,nil\n");
+ printer->Outdent();
+ printer->Print("}\n\n");
+
+ bool genSend = method->BidiStreaming() || method->ClientOnlyStreaming();
+ bool genRecv = method->BidiStreaming() || method->ServerOnlyStreaming();
+ bool genCloseAndRecv = method->ClientOnlyStreaming();
+
+ //Stream interface
+ printer->Print(vars, "type $Service$_$Method$Client interface {\n");
+ printer->Indent();
+ if (genSend) {
+ printer->Print(vars, "Send(*$Request$) error\n");
+ }
+ if (genRecv) {
+ printer->Print(vars, "Recv() (*$Response$, error)\n");
+ }
+ if (genCloseAndRecv) {
+ printer->Print(vars, "CloseAndRecv() (*$Response$, error)\n");
+ }
+ printer->Print(vars, "$grpc$.ClientStream\n");
+ printer->Outdent();
+ printer->Print("}\n\n");
+
+ //Stream Client
+ printer->Print(vars, "type $StreamType$ struct{\n");
+ printer->Indent();
+ printer->Print(vars, "$grpc$.ClientStream\n");
+ printer->Outdent();
+ printer->Print("}\n\n");
+
+ if (genSend) {
+ printer->Print(vars, "func (x *$StreamType$) Send(m *$Request$) error {\n");
+ printer->Indent();
+ printer->Print("return x.ClientStream.SendMsg(m)\n");
+ printer->Outdent();
+ printer->Print("}\n\n");
+ }
+
+ if (genRecv) {
+ printer->Print(vars, "func (x *$StreamType$) Recv() (*$Response$, error) {\n");
+ printer->Indent();
+ printer->Print(vars, "m := new($Response$)\n");
+ printer->Print("if err := x.ClientStream.RecvMsg(m); err != nil { return nil, err }\n");
+ printer->Print("return m, nil\n");
+ printer->Outdent();
+ printer->Print("}\n\n");
+ }
+
+ if (genCloseAndRecv) {
+ printer->Print(vars, "func (x *$StreamType$) CloseAndRecv() (*$Response$, error) {\n");
+ printer->Indent();
+ printer->Print("if err := x.ClientStream.CloseSend(); err != nil { return nil, err }\n");
+ printer->Print(vars, "m := new ($Response$)\n");
+ printer->Print("if err := x.ClientStream.RecvMsg(m); err != nil { return nil, err }\n");
+ printer->Print("return m, nil\n");
+ printer->Outdent();
+ printer->Print("}\n\n");
+ }
+}
+
+// Generates client API for the service
+void GenerateService(const grpc_generator::Service *service, grpc_generator::Printer* printer,
+ std::map<grpc::string, grpc::string> vars) {
+ vars["Service"] = exportName(service->name());
+ // Client Interface
+ printer->Print(vars, "// Client API for $Service$ service\n");
+ printer->Print(vars, "type $Service$Client interface{\n");
+ printer->Indent();
+ for (int i = 0; i < service->method_count(); i++) {
+ GenerateClientMethodSignature(service->method(i).get(), printer, vars);
+ printer->Print("\n");
+ }
+ printer->Outdent();
+ printer->Print("}\n\n");
+
+ // Client structure
+ vars["ServiceUnexported"] = unexportName(vars["Service"]);
+ printer->Print(vars, "type $ServiceUnexported$Client struct {\n");
+ printer->Indent();
+ printer->Print(vars, "cc *$grpc$.ClientConn\n");
+ printer->Outdent();
+ printer->Print("}\n\n");
+
+ // NewClient
+ printer->Print(vars, "func New$Service$Client(cc *$grpc$.ClientConn) $Service$Client {\n");
+ printer->Indent();
+ printer->Print(vars, "return &$ServiceUnexported$Client{cc}");
+ printer->Outdent();
+ printer->Print("\n}\n\n");
+
+ int unary_methods = 0, streaming_methods = 0;
+ vars["ServiceDesc"] = "_" + vars["Service"] + "_serviceDesc";
+ for (int i = 0; i < service->method_count(); i++) {
+ auto method = service->method(i);
+ if (method->NoStreaming()) {
+ vars["MethodDesc"] = vars["ServiceDesc"] + ".Method[" + as_string(unary_methods) + "]";
+ unary_methods++;
+ } else {
+ vars["MethodDesc"] = vars["ServiceDesc"] + ".Streams[" + as_string(streaming_methods) + "]";
+ streaming_methods++;
+ }
+ GenerateClientMethod(method.get(), printer, vars);
+ }
+
+ //Server Interface
+ printer->Print(vars, "// Server API for $Service$ service\n");
+ printer->Print(vars, "type $Service$Server interface {\n");
+ printer->Indent();
+ for (int i = 0; i < service->method_count(); i++) {
+ GenerateServerMethodSignature(service->method(i).get(), printer, vars);
+ printer->Print("\n");
+ }
+ printer->Outdent();
+ printer->Print("}\n\n");
+
+ // Server registration.
+ printer->Print(vars, "func Register$Service$Server(s *$grpc$.Server, srv $Service$Server) {\n");
+ printer->Indent();
+ printer->Print(vars, "s.RegisterService(&$ServiceDesc$, srv)\n");
+ printer->Outdent();
+ printer->Print("}\n\n");
+
+ for (int i = 0; i < service->method_count(); i++) {
+ GenerateServerMethod(service->method(i).get(), printer, vars);
+ printer->Print("\n");
+ }
+
+
+ //Service Descriptor
+ printer->Print(vars, "var $ServiceDesc$ = $grpc$.ServiceDesc{\n");
+ printer->Indent();
+ printer->Print(vars, "ServiceName: \"$Package$.$Service$\",\n");
+ printer->Print(vars, "HandlerType: (*$Service$Server)(nil),\n");
+ printer->Print(vars, "Methods: []$grpc$.MethodDesc{\n");
+ printer->Indent();
+ for (int i = 0; i < service->method_count(); i++) {
+ auto method = service->method(i);
+ vars["Method"] = method->name();
+ vars["Handler"] = "_" + vars["Service"] + "_" + vars["Method"] + "_Handler";
+ if (method->NoStreaming()) {
+ printer->Print("{\n");
+ printer->Indent();
+ printer->Print(vars, "MethodName: \"$Method$\",\n");
+ printer->Print(vars, "Handler: $Handler$, \n");
+ printer->Outdent();
+ printer->Print("},\n");
+ }
+ }
+ printer->Outdent();
+ printer->Print("},\n");
+ printer->Print(vars, "Streams: []$grpc$.StreamDesc{\n");
+ printer->Indent();
+ for (int i = 0; i < service->method_count(); i++) {
+ auto method = service->method(i);
+ vars["Method"] = method->name();
+ vars["Handler"] = "_" + vars["Service"] + "_" + vars["Method"] + "_Handler";
+ if (!method->NoStreaming()) {
+ printer->Print("{\n");
+ printer->Indent();
+ printer->Print(vars, "StreamName: \"$Method$\",\n");
+ printer->Print(vars, "Handler: $Handler$, \n");
+ if (method->ClientOnlyStreaming()) {
+ printer->Print("ClientStreams: true,\n");
+ } else if (method->ServerOnlyStreaming()) {
+ printer->Print("ServerStreams: true,\n");
+ } else {
+ printer->Print("ServerStreams: true,\n");
+ printer->Print("ClientStreams: true,\n");
+ }
+ printer->Outdent();
+ printer->Print("},\n");
+ }
+ }
+ printer->Outdent();
+ printer->Print("},\n");
+ printer->Outdent();
+ printer->Print("}\n\n");
+
+}
+
+
+// Returns source for the service
+grpc::string GenerateServiceSource(grpc_generator::File *file,
+ const grpc_generator::Service *service,
+ grpc_go_generator::Parameters *parameters) {
+ grpc::string out;
+ auto p = file->CreatePrinter(&out);
+ auto printer = p.get();
+ std::map<grpc::string, grpc::string> vars;
+ vars["Package"] = parameters->package_name;
+ vars["grpc"] = "grpc";
+ vars["context"] = "context";
+ GenerateImports(file, printer, vars);
+ if (parameters->custom_method_io_type != "") {
+ vars["CustomMethodIO"] = parameters->custom_method_io_type;
+ }
+ GenerateService(service, printer, vars);
+ return out;
+}
+}// Namespace grpc_go_generator
\ No newline at end of file
diff --git a/grpc/src/compiler/go_generator.h b/grpc/src/compiler/go_generator.h
new file mode 100644
index 0000000..a8f7a3d
--- /dev/null
+++ b/grpc/src/compiler/go_generator.h
@@ -0,0 +1,61 @@
+/*
+ *
+ * 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 GRPC_INTERNAL_COMPILER_GO_GENERATOR_H
+#define GRPC_INTERNAL_COMPILER_GO_GENERATOR_H
+
+//go generator is used to generate GRPC code for serialization system, such as flatbuffers
+#include <memory>
+#include <vector>
+
+#include "src/compiler/schema_interface.h"
+
+namespace grpc_go_generator {
+
+struct Parameters {
+ //Defines the custom parameter types for methods
+ //eg: flatbuffers uses flatbuffers.Builder as input for the client and output for the server
+ grpc::string custom_method_io_type;
+
+ //Package name for the service
+ grpc::string package_name;
+};
+
+// Return the source of the generated service file.
+grpc::string GenerateServiceSource(grpc_generator::File *file,
+ const grpc_generator::Service *service,
+ grpc_go_generator::Parameters *parameters);
+
+}
+
+#endif // GRPC_INTERNAL_COMPILER_GO_GENERATOR_H
diff --git a/grpc/src/compiler/schema_interface.h b/grpc/src/compiler/schema_interface.h
new file mode 100644
index 0000000..c9b7f46
--- /dev/null
+++ b/grpc/src/compiler/schema_interface.h
@@ -0,0 +1,112 @@
+/*
+ *
+ * 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 GRPC_INTERNAL_COMPILER_SCHEMA_INTERFACE_H
+#define GRPC_INTERNAL_COMPILER_SCHEMA_INTERFACE_H
+
+#include <map>
+#include <memory>
+#include <vector>
+
+ #ifndef GRPC_CUSTOM_STRING
+ #include <string>
+ #define GRPC_CUSTOM_STRING std::string
+ #endif
+
+namespace grpc {
+
+ typedef GRPC_CUSTOM_STRING string;
+
+} // namespace grpc
+
+namespace grpc_generator {
+
+ // An abstract interface representing a method.
+ struct Method {
+ virtual ~Method() {}
+
+ virtual grpc::string name() const = 0;
+
+ virtual grpc::string input_type_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 bool ClientOnlyStreaming() const = 0;
+ virtual bool ServerOnlyStreaming() const = 0;
+ virtual bool BidiStreaming() const = 0;
+ };
+
+ // An abstract interface representing a service.
+ struct Service {
+ virtual ~Service() {}
+
+ virtual grpc::string name() const = 0;
+
+ virtual int method_count() const = 0;
+ virtual std::unique_ptr<const Method> method(int i) const = 0;
+ };
+
+ struct Printer {
+ virtual ~Printer() {}
+
+ virtual void Print(const std::map<grpc::string, grpc::string> &vars,
+ const char *template_string) = 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
+ // libraries/idls/serializers.
+ struct File {
+ virtual ~File() {}
+
+ virtual grpc::string filename() const = 0;
+ virtual grpc::string filename_without_ext() const = 0;
+ virtual grpc::string message_header_ext() const = 0;
+ virtual grpc::string service_header_ext() const = 0;
+ virtual grpc::string package() const = 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;
+ 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
diff --git a/grpc/tests/go_test.go b/grpc/tests/go_test.go
new file mode 100644
index 0000000..f133692
--- /dev/null
+++ b/grpc/tests/go_test.go
@@ -0,0 +1,94 @@
+package testing
+
+import (
+ "../../tests/MyGame/Example"
+
+ "net"
+ "testing"
+
+ "github.com/google/flatbuffers/go"
+ "golang.org/x/net/context"
+ "google.golang.org/grpc"
+)
+
+type server struct{}
+
+// test used to send and receive in grpc methods
+var test string = "Flatbuffers"
+var addr string = "0.0.0.0:50051"
+
+// gRPC server store method
+func (s *server) Store(context context.Context, in *Example.Monster) (*flatbuffers.Builder, error) {
+ b := flatbuffers.NewBuilder(0)
+ i := b.CreateString(test)
+ Example.StatStart(b)
+ Example.StatAddId(b, i)
+ b.Finish(Example.StatEnd(b))
+ return b, nil
+
+}
+
+// gRPC server retrieve method
+func (s *server) Retrieve(context context.Context, in *Example.Stat) (*flatbuffers.Builder, error) {
+ b := flatbuffers.NewBuilder(0)
+ i := b.CreateString(test)
+ Example.MonsterStart(b)
+ Example.MonsterAddName(b, i)
+ b.Finish(Example.MonsterEnd(b))
+ return b, nil
+}
+
+func StoreClient(c Example.MonsterStorageClient, t *testing.T) {
+ b := flatbuffers.NewBuilder(0)
+ i := b.CreateString(test)
+ Example.MonsterStart(b)
+ Example.MonsterAddName(b, i)
+ b.Finish(Example.MonsterEnd(b))
+ out, err := c.Store(context.Background(), b)
+ if err != nil {
+ t.Fatal("Store client failed: %v", err)
+ }
+ if string(out.Id()) != test {
+ t.Errorf("StoreClient failed: expected=%s, got=%s\n", test, out.Id())
+ t.Fail()
+ }
+}
+
+func RetrieveClient(c Example.MonsterStorageClient, t *testing.T) {
+ b := flatbuffers.NewBuilder(0)
+ i := b.CreateString(test)
+ Example.StatStart(b)
+ Example.StatAddId(b, i)
+ b.Finish(Example.StatEnd(b))
+ out, err := c.Retrieve(context.Background(), b)
+ if err != nil {
+ t.Fatal("Retrieve client failed: %v", err)
+ }
+ if string(out.Name()) != test {
+ t.Errorf("RetrieveClient failed: expected=%s, got=%s\n", test, out.Name())
+ t.Fail()
+ }
+}
+
+func TestGRPC(t *testing.T) {
+ lis, err := net.Listen("tcp", addr)
+ if err != nil {
+ t.Fatalf("Failed to listen: %v", err)
+ }
+ ser := grpc.NewServer(grpc.CustomCodec(flatbuffers.FlatbuffersCodec{}))
+ Example.RegisterMonsterStorageServer(ser, &server{})
+ go func() {
+ if err := ser.Serve(lis); err != nil {
+ t.Fatalf("Failed to serve: %v", err)
+ t.FailNow()
+ }
+ }()
+ conn, err := grpc.Dial(addr, grpc.WithInsecure(), grpc.WithCodec(flatbuffers.FlatbuffersCodec{}))
+ if err != nil {
+ t.Fatal("Failed to connect: %v", err)
+ }
+ defer conn.Close()
+ client := Example.NewMonsterStorageClient(conn)
+ StoreClient(client, t)
+ RetrieveClient(client, t)
+}
diff --git a/include/flatbuffers/flatbuffers.h b/include/flatbuffers/flatbuffers.h
index 1a69082..e830c44 100644
--- a/include/flatbuffers/flatbuffers.h
+++ b/include/flatbuffers/flatbuffers.h
@@ -130,6 +130,9 @@
// 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 */)>>
@@ -153,32 +156,34 @@
template<typename T> T EndianSwap(T t) {
#if defined(_MSC_VER)
- #pragma push_macro("__builtin_bswap16")
- #pragma push_macro("__builtin_bswap32")
- #pragma push_macro("__builtin_bswap64")
- #define __builtin_bswap16 _byteswap_ushort
- #define __builtin_bswap32 _byteswap_ulong
- #define __builtin_bswap64 _byteswap_uint64
+ #define FLATBUFFERS_BYTESWAP16 _byteswap_ushort
+ #define FLATBUFFERS_BYTESWAP32 _byteswap_ulong
+ #define FLATBUFFERS_BYTESWAP64 _byteswap_uint64
+ #else
+ #if defined(__GNUC__) && __GNUC__ * 100 + __GNUC_MINOR__ < 408
+ // __builtin_bswap16 was missing prior to GCC 4.8.
+ #define FLATBUFFERS_BYTESWAP16(x) \
+ static_cast<uint16_t>(__builtin_bswap32(static_cast<uint32_t>(x) << 16))
+ #else
+ #define FLATBUFFERS_BYTESWAP16 __builtin_bswap16
+ #endif
+ #define FLATBUFFERS_BYTESWAP32 __builtin_bswap32
+ #define FLATBUFFERS_BYTESWAP64 __builtin_bswap64
#endif
if (sizeof(T) == 1) { // Compile-time if-then's.
return t;
} else if (sizeof(T) == 2) {
- auto r = __builtin_bswap16(*reinterpret_cast<uint16_t *>(&t));
+ auto r = FLATBUFFERS_BYTESWAP16(*reinterpret_cast<uint16_t *>(&t));
return *reinterpret_cast<T *>(&r);
} else if (sizeof(T) == 4) {
- auto r = __builtin_bswap32(*reinterpret_cast<uint32_t *>(&t));
+ auto r = FLATBUFFERS_BYTESWAP32(*reinterpret_cast<uint32_t *>(&t));
return *reinterpret_cast<T *>(&r);
} else if (sizeof(T) == 8) {
- auto r = __builtin_bswap64(*reinterpret_cast<uint64_t *>(&t));
+ auto r = FLATBUFFERS_BYTESWAP64(*reinterpret_cast<uint64_t *>(&t));
return *reinterpret_cast<T *>(&r);
} else {
assert(0);
}
- #if defined(_MSC_VER)
- #pragma pop_macro("__builtin_bswap16")
- #pragma pop_macro("__builtin_bswap32")
- #pragma pop_macro("__builtin_bswap64")
- #endif
}
template<typename T> T EndianScalar(T t) {
@@ -253,7 +258,7 @@
public:
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_) {}
#ifndef FLATBUFFERS_CPP98_STL
VectorIterator(VectorIterator &&other) : data_(std::move(other.data_)) {}
@@ -578,6 +583,10 @@
template <typename T> const T* data(const std::vector<T> &v) {
return v.empty() ? nullptr : &v.front();
}
+template <typename T> T* data(std::vector<T> &v) {
+ return v.empty() ? nullptr : &v.front();
+}
+
/// @endcond
/// @addtogroup flatbuffers_cpp_api
@@ -656,6 +665,16 @@
}
#endif
+ /// @brief get the minimum alignment this buffer needs to be accessed
+ /// properly. This is only known once all elements have been written (after
+ /// you call Finish()). You can use this information if you need to embed
+ /// a FlatBuffer in some other buffer, such that you can later read it
+ /// without first having to copy it into its own buffer.
+ size_t GetBufferMinAlignment() {
+ Finished();
+ return minalign_;
+ }
+
/// @cond FLATBUFFERS_INTERNAL
void Finished() const {
// If you get this assert, you're attempting to get access a buffer
@@ -1108,7 +1127,7 @@
/// where the vector is stored.
template<typename T> Offset<Vector<Offset<T>>> CreateVectorOfSortedTables(
std::vector<Offset<T>> *v) {
- return CreateVectorOfSortedTables(v->data(), v->size());
+ return CreateVectorOfSortedTables(data(*v), v->size());
}
/// @brief Specialized version of `CreateVector` for non-copying use cases.
@@ -1151,17 +1170,20 @@
/// will be prefixed with a standard FlatBuffers file header.
template<typename T> void Finish(Offset<T> root,
const char *file_identifier = nullptr) {
- NotNested();
- // This will cause the whole buffer to be aligned.
- PreAlign(sizeof(uoffset_t) + (file_identifier ? kFileIdentifierLength : 0),
- minalign_);
- if (file_identifier) {
- assert(strlen(file_identifier) == kFileIdentifierLength);
- buf_.push(reinterpret_cast<const uint8_t *>(file_identifier),
- kFileIdentifierLength);
- }
- PushElement(ReferTo(root.o)); // Location of root.
- finished = true;
+
+ Finish(root.o, file_identifier, false);
+ }
+
+ /// @brief Finish a buffer with a 32 bit size field pre-fixed (size of the
+ /// buffer following the size field). These buffers are NOT compatible
+ /// with standard buffers created by Finish, i.e. you can't call GetRoot
+ /// on them, you have to use GetSizePrefixedRoot instead.
+ /// All >32 bit quantities in this buffer will be aligned when the whole
+ /// size pre-fixed buffer is aligned.
+ /// These kinds of buffers are useful for creating a stream of FlatBuffers.
+ template<typename T> void FinishSizePrefixed(Offset<T> root,
+ const char *file_identifier = nullptr) {
+ Finish(root.o, file_identifier, true);
}
private:
@@ -1169,6 +1191,25 @@
FlatBufferBuilder(const FlatBufferBuilder &);
FlatBufferBuilder &operator=(const FlatBufferBuilder &);
+ void Finish(uoffset_t root, const char *file_identifier, bool size_prefix) {
+ NotNested();
+ // This will cause the whole buffer to be aligned.
+ PreAlign((size_prefix ? sizeof(uoffset_t) : 0) +
+ sizeof(uoffset_t) +
+ (file_identifier ? kFileIdentifierLength : 0),
+ minalign_);
+ if (file_identifier) {
+ assert(strlen(file_identifier) == kFileIdentifierLength);
+ buf_.push(reinterpret_cast<const uint8_t *>(file_identifier),
+ kFileIdentifierLength);
+ }
+ PushElement(ReferTo(root)); // Location of root.
+ if (size_prefix) {
+ PushElement(GetSize());
+ }
+ finished = true;
+ }
+
struct FieldLoc {
uoffset_t off;
voffset_t id;
@@ -1222,7 +1263,11 @@
return GetMutableRoot<T>(const_cast<void *>(buf));
}
-/// Helpers to get a typed pointer to objects that are currently beeing built.
+template<typename T> const T *GetSizePrefixedRoot(const void *buf) {
+ return GetRoot<T>(reinterpret_cast<const uint8_t *>(buf) + sizeof(uoffset_t));
+}
+
+/// Helpers to get a typed pointer to objects that are currently being built.
/// @warning Creating new objects will lead to reallocations and invalidates
/// the pointer!
template<typename T> T *GetMutableTemporaryPointer(FlatBufferBuilder &fbb,
@@ -1346,16 +1391,17 @@
return true;
}
- // Verify this whole buffer, starting with root type T.
- template<typename T> bool VerifyBuffer(const char *identifier) {
- if (identifier && (size_t(end_ - buf_) < 2 * sizeof(flatbuffers::uoffset_t) ||
- !BufferHasIdentifier(buf_, identifier))) {
+ template<typename T> bool VerifyBufferFromStart(const char *identifier,
+ const uint8_t *start) {
+ if (identifier &&
+ (size_t(end_ - start) < 2 * sizeof(flatbuffers::uoffset_t) ||
+ !BufferHasIdentifier(start, identifier))) {
return false;
}
// Call T::Verify, which must be in the generated code for this type.
- return Verify<uoffset_t>(buf_) &&
- reinterpret_cast<const T *>(buf_ + ReadScalar<uoffset_t>(buf_))->
+ return Verify<uoffset_t>(start) &&
+ reinterpret_cast<const T *>(start + ReadScalar<uoffset_t>(start))->
Verify(*this)
#ifdef FLATBUFFERS_TRACK_VERIFIER_BUFFER_SIZE
&& GetComputedSize()
@@ -1363,6 +1409,17 @@
;
}
+ // Verify this whole buffer, starting with root type T.
+ template<typename T> bool VerifyBuffer(const char *identifier) {
+ return VerifyBufferFromStart<T>(identifier, buf_);
+ }
+
+ template<typename T> bool VerifySizePrefixedBuffer(const char *identifier) {
+ return Verify<uoffset_t>(buf_) &&
+ ReadScalar<uoffset_t>(buf_) == end_ - buf_ - sizeof(uoffset_t) &&
+ VerifyBufferFromStart<T>(identifier, buf_ + sizeof(uoffset_t));
+ }
+
// Called at the start of a table to increase counters measuring data
// structure depth and amount, and possibly bails out with false if
// limits set by the constructor have been hit. Needs to be balanced
@@ -1434,11 +1491,6 @@
return ReadScalar<T>(&data_[o]);
}
- template<typename T> T GetPointer(uoffset_t o) const {
- auto p = &data_[o];
- return reinterpret_cast<T>(p + ReadScalar<uoffset_t>(p));
- }
-
template<typename T> T GetStruct(uoffset_t o) const {
return reinterpret_cast<T>(&data_[o]);
}
@@ -1454,11 +1506,15 @@
// omitted and added at will, but uses an extra indirection to read.
class Table {
public:
+ const uint8_t *GetVTable() const {
+ return data_ - ReadScalar<soffset_t>(data_);
+ }
+
// This gets the field offset for any of the functions below it, or 0
// if the field was not present.
voffset_t GetOptionalFieldOffset(voffset_t field) const {
// The vtable offset is always at the start.
- auto vtable = data_ - ReadScalar<soffset_t>(data_);
+ auto vtable = GetVTable();
// The first element is the size of the vtable (fields + type id + itself).
auto vtsize = ReadScalar<voffset_t>(vtable);
// If the field we're accessing is outside the vtable, we're reading older
@@ -1511,8 +1567,6 @@
return const_cast<Table *>(this)->GetAddressOf(field);
}
- uint8_t *GetVTable() { return data_ - ReadScalar<soffset_t>(data_); }
-
bool CheckField(voffset_t field) const {
return GetOptionalFieldOffset(field) != 0;
}
@@ -1522,7 +1576,7 @@
bool VerifyTableStart(Verifier &verifier) const {
// Check the vtable offset.
if (!verifier.Verify<soffset_t>(data_)) return false;
- auto vtable = data_ - ReadScalar<soffset_t>(data_);
+ auto vtable = GetVTable();
// Check the vtable size field, then check vtable fits in its entirety.
return verifier.VerifyComplexity() &&
verifier.Verify<voffset_t>(vtable) &&
@@ -1557,12 +1611,68 @@
uint8_t data_[1];
};
+/// @brief This can compute the start of a FlatBuffer from a root pointer, i.e.
+/// it is the opposite transformation of GetRoot().
+/// This may be useful if you want to pass on a root and have the recipient
+/// delete the buffer afterwards.
+inline const uint8_t *GetBufferStartFromRootPointer(const void *root) {
+ auto table = reinterpret_cast<const Table *>(root);
+ auto vtable = table->GetVTable();
+ // Either the vtable is before the root or after the root.
+ auto start = std::min(vtable, reinterpret_cast<const uint8_t *>(root));
+ // Align to at least sizeof(uoffset_t).
+ start = reinterpret_cast<const uint8_t *>(
+ reinterpret_cast<uintptr_t>(start) & ~(sizeof(uoffset_t) - 1));
+ // Additionally, there may be a file_identifier in the buffer, and the root
+ // offset. The buffer may have been aligned to any size between
+ // sizeof(uoffset_t) and FLATBUFFERS_MAX_ALIGNMENT (see "force_align").
+ // Sadly, the exact alignment is only known when constructing the buffer,
+ // since it depends on the presence of values with said alignment properties.
+ // So instead, we simply look at the next uoffset_t values (root,
+ // file_identifier, and alignment padding) to see which points to the root.
+ // None of the other values can "impersonate" the root since they will either
+ // be 0 or four ASCII characters.
+ static_assert(FlatBufferBuilder::kFileIdentifierLength == sizeof(uoffset_t),
+ "file_identifier is assumed to be the same size as uoffset_t");
+ for (auto possible_roots = FLATBUFFERS_MAX_ALIGNMENT / sizeof(uoffset_t) + 1;
+ possible_roots;
+ possible_roots--) {
+ start -= sizeof(uoffset_t);
+ if (ReadScalar<uoffset_t>(start) + start ==
+ reinterpret_cast<const uint8_t *>(root)) return start;
+ }
+ // We didn't find the root, either the "root" passed isn't really a root,
+ // or the buffer is corrupt.
+ // Assert, because calling this function with bad data may cause reads
+ // outside of buffer boundaries.
+ assert(false);
+ return nullptr;
+}
+
// Base class for native objects (FlatBuffer data de-serialized into native
// C++ data structures).
// Contains no functionality, purely documentative.
struct NativeTable {
};
+/// @brief Function types to be used with resolving hashes into objects and
+/// back again. The resolver gets a pointer to a field inside an object API
+/// object that is of the type specified in the schema using the attribute
+/// `cpp_type` (it is thus important whatever you write to this address
+/// matches that type). The value of this field is initially null, so you
+/// may choose to implement a delayed binding lookup using this function
+/// if you wish. The resolver does the opposite lookup, for when the object
+/// is being serialized again.
+typedef uint64_t hash_value_t;
+#ifdef FLATBUFFERS_CPP98_STL
+ typedef void (*resolver_function_t)(void **pointer_adr, hash_value_t hash);
+ typedef hash_value_t (*rehasher_function_t)(void *pointer);
+#else
+ typedef std::function<void (void **pointer_adr, hash_value_t hash)>
+ resolver_function_t;
+ typedef std::function<hash_value_t (void *pointer)> rehasher_function_t;
+#endif
+
// Helper function to test if a field is present, using any of the field
// enums in the generated code.
// `table` must be a generated table type. Since this is a template parameter,
diff --git a/include/flatbuffers/idl.h b/include/flatbuffers/idl.h
index 5909a4e..6ae8dd2 100644
--- a/include/flatbuffers/idl.h
+++ b/include/flatbuffers/idl.h
@@ -234,6 +234,8 @@
// written in new data nor accessed in new code.
bool required; // Field must always be present.
bool key; // Field functions as a key for creating sorted vectors.
+ bool native_inline; // Field will be defined inline (instead of as a pointer)
+ // for native tables if field is a struct.
size_t padding; // Bytes to always pad after this field.
};
@@ -347,6 +349,7 @@
bool generate_name_strings;
bool escape_proto_identifiers;
bool generate_object_based_api;
+ std::string cpp_object_api_pointer_type;
bool union_value_namespacing;
bool allow_non_utf8;
@@ -370,6 +373,7 @@
generate_name_strings(false),
escape_proto_identifiers(false),
generate_object_based_api(false),
+ cpp_object_api_pointer_type("std::unique_ptr"),
union_value_namespacing(true),
allow_non_utf8(false),
lang(IDLOptions::kJava) {}
@@ -450,6 +454,9 @@
known_attributes_["csharp_partial"] = true;
known_attributes_["streaming"] = true;
known_attributes_["idempotent"] = true;
+ known_attributes_["cpp_type"] = true;
+ known_attributes_["cpp_ptr_type"] = true;
+ known_attributes_["native_inline"] = true;
}
~Parser() {
@@ -596,7 +603,9 @@
// if it is less than 0, no linefeeds will be generated either.
// See idl_gen_text.cpp.
// strict_json adds "quotes" around field names if true.
-extern void GenerateText(const Parser &parser,
+// If the flatbuffer cannot be encoded in JSON (e.g., it contains non-UTF-8
+// byte arrays in String values), returns false.
+extern bool GenerateText(const Parser &parser,
const void *flatbuffer,
std::string *text);
extern bool GenerateTextFile(const Parser &parser,
@@ -640,8 +649,8 @@
// Generate Php code from the definitions in the Parser object.
// See idl_gen_php.
extern bool GeneratePhp(const Parser &parser,
- const std::string &path,
- const std::string &file_name);
+ const std::string &path,
+ const std::string &file_name);
// Generate Python files from the definitions in the Parser object.
// See idl_gen_python.cpp.
@@ -699,11 +708,17 @@
const std::string &path,
const std::string &file_name);
-// Generate GRPC interfaces.
+// Generate GRPC Cpp interfaces.
// See idl_gen_grpc.cpp.
-bool GenerateGRPC(const Parser &parser,
- const std::string &path,
- const std::string &file_name);
+bool GenerateCppGRPC(const Parser &parser,
+ const std::string &path,
+ const std::string &file_name);
+
+// Generate GRPC Go interfaces.
+// See idl_gen_grpc.cpp.
+bool GenerateGoGRPC(const Parser &parser,
+ const std::string &path,
+ const std::string &file_name);
} // namespace flatbuffers
diff --git a/include/flatbuffers/reflection_generated.h b/include/flatbuffers/reflection_generated.h
index a459aa6..b6233ff 100644
--- a/include/flatbuffers/reflection_generated.h
+++ b/include/flatbuffers/reflection_generated.h
@@ -38,7 +38,7 @@
String = 13,
Vector = 14,
Obj = 15,
- Union = 16,
+ Union = 16
};
inline const char **EnumNamesBaseType() {
@@ -133,10 +133,10 @@
return builder_.Finish();
}
-inline flatbuffers::Offset<KeyValue> CreateKeyValue(flatbuffers::FlatBufferBuilder &_fbb,
+inline flatbuffers::Offset<KeyValue> CreateKeyValueDirect(flatbuffers::FlatBufferBuilder &_fbb,
const char *key = nullptr,
const char *value = nullptr) {
- return CreateKeyValue(_fbb, key ? 0 : _fbb.CreateString(key), value ? 0 : _fbb.CreateString(value));
+ return CreateKeyValue(_fbb, key ? _fbb.CreateString(key) : 0, value ? _fbb.CreateString(value) : 0);
}
struct EnumVal FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
@@ -187,11 +187,11 @@
return builder_.Finish();
}
-inline flatbuffers::Offset<EnumVal> CreateEnumVal(flatbuffers::FlatBufferBuilder &_fbb,
+inline flatbuffers::Offset<EnumVal> CreateEnumValDirect(flatbuffers::FlatBufferBuilder &_fbb,
const char *name = nullptr,
int64_t value = 0,
flatbuffers::Offset<Object> object = 0) {
- return CreateEnumVal(_fbb, name ? 0 : _fbb.CreateString(name), value, object);
+ return CreateEnumVal(_fbb, name ? _fbb.CreateString(name) : 0, value, object);
}
struct Enum FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
@@ -260,13 +260,13 @@
return builder_.Finish();
}
-inline flatbuffers::Offset<Enum> CreateEnum(flatbuffers::FlatBufferBuilder &_fbb,
+inline flatbuffers::Offset<Enum> CreateEnumDirect(flatbuffers::FlatBufferBuilder &_fbb,
const char *name = nullptr,
const std::vector<flatbuffers::Offset<EnumVal>> *values = nullptr,
bool is_union = false,
flatbuffers::Offset<Type> underlying_type = 0,
const std::vector<flatbuffers::Offset<KeyValue>> *attributes = nullptr) {
- return CreateEnum(_fbb, name ? 0 : _fbb.CreateString(name), values ? 0 : _fbb.CreateVector<flatbuffers::Offset<EnumVal>>(*values), is_union, underlying_type, attributes ? 0 : _fbb.CreateVector<flatbuffers::Offset<KeyValue>>(*attributes));
+ return CreateEnum(_fbb, name ? _fbb.CreateString(name) : 0, values ? _fbb.CreateVector<flatbuffers::Offset<EnumVal>>(*values) : 0, is_union, underlying_type, attributes ? _fbb.CreateVector<flatbuffers::Offset<KeyValue>>(*attributes) : 0);
}
struct Field FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
@@ -362,7 +362,7 @@
return builder_.Finish();
}
-inline flatbuffers::Offset<Field> CreateField(flatbuffers::FlatBufferBuilder &_fbb,
+inline flatbuffers::Offset<Field> CreateFieldDirect(flatbuffers::FlatBufferBuilder &_fbb,
const char *name = nullptr,
flatbuffers::Offset<Type> type = 0,
uint16_t id = 0,
@@ -373,7 +373,7 @@
bool required = false,
bool key = false,
const std::vector<flatbuffers::Offset<KeyValue>> *attributes = nullptr) {
- return CreateField(_fbb, name ? 0 : _fbb.CreateString(name), type, id, offset, default_integer, default_real, deprecated, required, key, attributes ? 0 : _fbb.CreateVector<flatbuffers::Offset<KeyValue>>(*attributes));
+ return CreateField(_fbb, name ? _fbb.CreateString(name) : 0, type, id, offset, default_integer, default_real, deprecated, required, key, attributes ? _fbb.CreateVector<flatbuffers::Offset<KeyValue>>(*attributes) : 0);
}
struct Object FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
@@ -446,14 +446,14 @@
return builder_.Finish();
}
-inline flatbuffers::Offset<Object> CreateObject(flatbuffers::FlatBufferBuilder &_fbb,
+inline flatbuffers::Offset<Object> CreateObjectDirect(flatbuffers::FlatBufferBuilder &_fbb,
const char *name = nullptr,
const std::vector<flatbuffers::Offset<Field>> *fields = nullptr,
bool is_struct = false,
int32_t minalign = 0,
int32_t bytesize = 0,
const std::vector<flatbuffers::Offset<KeyValue>> *attributes = nullptr) {
- return CreateObject(_fbb, name ? 0 : _fbb.CreateString(name), fields ? 0 : _fbb.CreateVector<flatbuffers::Offset<Field>>(*fields), is_struct, minalign, bytesize, attributes ? 0 : _fbb.CreateVector<flatbuffers::Offset<KeyValue>>(*attributes));
+ return CreateObject(_fbb, name ? _fbb.CreateString(name) : 0, fields ? _fbb.CreateVector<flatbuffers::Offset<Field>>(*fields) : 0, is_struct, minalign, bytesize, attributes ? _fbb.CreateVector<flatbuffers::Offset<KeyValue>>(*attributes) : 0);
}
struct Schema FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
@@ -520,26 +520,36 @@
return builder_.Finish();
}
-inline flatbuffers::Offset<Schema> CreateSchema(flatbuffers::FlatBufferBuilder &_fbb,
+inline flatbuffers::Offset<Schema> CreateSchemaDirect(flatbuffers::FlatBufferBuilder &_fbb,
const std::vector<flatbuffers::Offset<Object>> *objects = nullptr,
const std::vector<flatbuffers::Offset<Enum>> *enums = nullptr,
const char *file_ident = nullptr,
const char *file_ext = nullptr,
flatbuffers::Offset<Object> root_table = 0) {
- return CreateSchema(_fbb, objects ? 0 : _fbb.CreateVector<flatbuffers::Offset<Object>>(*objects), enums ? 0 : _fbb.CreateVector<flatbuffers::Offset<Enum>>(*enums), file_ident ? 0 : _fbb.CreateString(file_ident), file_ext ? 0 : _fbb.CreateString(file_ext), root_table);
+ return CreateSchema(_fbb, objects ? _fbb.CreateVector<flatbuffers::Offset<Object>>(*objects) : 0, enums ? _fbb.CreateVector<flatbuffers::Offset<Enum>>(*enums) : 0, file_ident ? _fbb.CreateString(file_ident) : 0, file_ext ? _fbb.CreateString(file_ext) : 0, root_table);
}
-inline const reflection::Schema *GetSchema(const void *buf) { return flatbuffers::GetRoot<reflection::Schema>(buf); }
+inline const reflection::Schema *GetSchema(const void *buf) {
+ return flatbuffers::GetRoot<reflection::Schema>(buf);
+}
-inline const char *SchemaIdentifier() { return "BFBS"; }
+inline const char *SchemaIdentifier() {
+ return "BFBS";
+}
-inline bool SchemaBufferHasIdentifier(const void *buf) { return flatbuffers::BufferHasIdentifier(buf, SchemaIdentifier()); }
+inline bool SchemaBufferHasIdentifier(const void *buf) {
+ return flatbuffers::BufferHasIdentifier(buf, SchemaIdentifier());
+}
-inline bool VerifySchemaBuffer(flatbuffers::Verifier &verifier) { return verifier.VerifyBuffer<reflection::Schema>(SchemaIdentifier()); }
+inline bool VerifySchemaBuffer(flatbuffers::Verifier &verifier) {
+ return verifier.VerifyBuffer<reflection::Schema>(SchemaIdentifier());
+}
inline const char *SchemaExtension() { return "bfbs"; }
-inline void FinishSchemaBuffer(flatbuffers::FlatBufferBuilder &fbb, flatbuffers::Offset<reflection::Schema> root) { fbb.Finish(root, SchemaIdentifier()); }
+inline void FinishSchemaBuffer(flatbuffers::FlatBufferBuilder &fbb, flatbuffers::Offset<reflection::Schema> root) {
+ fbb.Finish(root, SchemaIdentifier());
+}
} // namespace reflection
diff --git a/include/flatbuffers/util.h b/include/flatbuffers/util.h
index baf5bdd..c6755ab 100644
--- a/include/flatbuffers/util.h
+++ b/include/flatbuffers/util.h
@@ -95,20 +95,20 @@
}
// Portable implementation of strtoll().
-inline int64_t StringToInt(const char *str, int base = 10) {
+inline int64_t StringToInt(const char *str, char **endptr = nullptr, int base = 10) {
#ifdef _MSC_VER
- return _strtoi64(str, nullptr, base);
+ return _strtoi64(str, endptr, base);
#else
- return strtoll(str, nullptr, base);
+ return strtoll(str, endptr, base);
#endif
}
// Portable implementation of strtoull().
-inline int64_t StringToUInt(const char *str, int base = 10) {
+inline int64_t StringToUInt(const char *str, char **endptr = nullptr, int base = 10) {
#ifdef _MSC_VER
- return _strtoui64(str, nullptr, base);
+ return _strtoui64(str, endptr, base);
#else
- return strtoull(str, nullptr, base);
+ return strtoull(str, endptr, base);
#endif
}
diff --git a/java/com/google/flatbuffers/FlatBufferBuilder.java b/java/com/google/flatbuffers/FlatBufferBuilder.java
index c2186fa..fd4b729 100644
--- a/java/com/google/flatbuffers/FlatBufferBuilder.java
+++ b/java/com/google/flatbuffers/FlatBufferBuilder.java
@@ -367,6 +367,53 @@
}
/// @endcond
+ /**
+ * Create a new array/vector and return a ByteBuffer to be filled later.
+ * Call {@link #endVector} after this method to get an offset to the beginning
+ * of vector.
+ *
+ * @param elem_size the size of each element in bytes.
+ * @param num_elems number of elements in the vector.
+ * @param alignment byte alignment.
+ * @return ByteBuffer with position and limit set to the space allocated for the array.
+ */
+ public ByteBuffer createUnintializedVector(int elem_size, int num_elems, int alignment) {
+ int length = elem_size * num_elems;
+ startVector(elem_size, num_elems, alignment);
+
+ bb.position(space -= length);
+
+ // Slice and limit the copy vector to point to the 'array'
+ ByteBuffer copy = bb.slice().order(ByteOrder.LITTLE_ENDIAN);
+ copy.limit(length);
+ return copy;
+ }
+
+ /**
+ * Create a vector of tables.
+ *
+ * @param offsets Offsets of the tables.
+ * @return Returns offset of the vector.
+ */
+ public int createVectorOfTables(int[] offsets) {
+ notNested();
+ startVector(Constants.SIZEOF_INT, offsets.length, Constants.SIZEOF_INT);
+ for(int i = offsets.length - 1; i >= 0; i--) addOffset(offsets[i]);
+ return endVector();
+ }
+
+ /**
+ * Create a vector of sorted by the key tables.
+ *
+ * @param obj Instance of the table subclass.
+ * @param offsets Offsets of the tables.
+ * @return Returns offset of the sorted vector.
+ */
+ public <T extends Table> int createSortedVectorOfTables(T obj, int[] offsets) {
+ obj.sortTables(offsets, bb);
+ return createVectorOfTables(offsets);
+ }
+
/**
* Encode the string `s` in the buffer using UTF-8. If {@code s} is
* already a {@link CharBuffer}, this method is allocation free.
@@ -413,6 +460,20 @@
return endVector();
}
+ /**
+ * Create a byte array in the buffer.
+ *
+ * @param arr A source array with data
+ * @return The offset in the buffer where the encoded array starts.
+ */
+ public int createByteVector(byte[] arr) {
+ int length = arr.length;
+ startVector(1, length, 1);
+ bb.position(space -= length);
+ bb.put(arr);
+ return endVector();
+ }
+
/// @cond FLATBUFFERS_INTERNAL
/**
* Should not be accessing the final buffer before it is finished.
diff --git a/java/com/google/flatbuffers/Table.java b/java/com/google/flatbuffers/Table.java
index 4087654..b853842 100644
--- a/java/com/google/flatbuffers/Table.java
+++ b/java/com/google/flatbuffers/Table.java
@@ -37,6 +37,12 @@
return Charset.forName("UTF-8").newDecoder();
}
};
+ public final static ThreadLocal<Charset> UTF8_CHARSET = new ThreadLocal<Charset>() {
+ @Override
+ protected Charset initialValue() {
+ return Charset.forName("UTF-8");
+ }
+ };
private final static ThreadLocal<CharBuffer> CHAR_BUFFER = new ThreadLocal<CharBuffer>();
/** Used to hold the position of the `bb` buffer. */
protected int bb_pos;
@@ -61,6 +67,11 @@
return vtable_offset < bb.getShort(vtable) ? bb.getShort(vtable + vtable_offset) : 0;
}
+ protected static int __offset(int vtable_offset, int offset, ByteBuffer bb) {
+ int vtable = bb.array().length - offset;
+ return bb.getShort(vtable + vtable_offset - bb.getInt(vtable)) + vtable;
+ }
+
/**
* Retrieve a relative offset.
*
@@ -71,6 +82,10 @@
return offset + bb.getInt(offset);
}
+ protected static int __indirect(int offset, ByteBuffer bb) {
+ return offset + bb.getInt(offset);
+ }
+
/**
* Create a Java `String` from UTF-8 data stored inside the FlatBuffer.
*
@@ -188,6 +203,76 @@
}
return true;
}
+
+ /**
+ * Sort tables by the key.
+ *
+ * @param offsets An 'int' indexes of the tables into the bb.
+ * @param bb A {@code ByteBuffer} to get the tables.
+ */
+ protected void sortTables(int[] offsets, final ByteBuffer bb) {
+ Integer[] off = new Integer[offsets.length];
+ for (int i = 0; i < offsets.length; i++) off[i] = offsets[i];
+ java.util.Arrays.sort(off, new java.util.Comparator<Integer>() {
+ public int compare(Integer o1, Integer o2) {
+ return keysCompare(o1, o2, bb);
+ }
+ });
+ for (int i = 0; i < offsets.length; i++) offsets[i] = off[i];
+ }
+
+ /**
+ * Compare two tables by the key.
+ *
+ * @param o1 An 'Integer' index of the first key into the bb.
+ * @param o2 An 'Integer' index of the second key into the bb.
+ * @param bb A {@code ByteBuffer} to get the keys.
+ */
+ protected int keysCompare(Integer o1, Integer o2, ByteBuffer bb) { return 0; }
+
+ /**
+ * Compare two strings in the buffer.
+ *
+ * @param offset_1 An 'int' index of the first string into the bb.
+ * @param offset_2 An 'int' index of the second string into the bb.
+ * @param bb A {@code ByteBuffer} to get the strings.
+ */
+ protected static int compareStrings(int offset_1, int offset_2, ByteBuffer bb) {
+ offset_1 += bb.getInt(offset_1);
+ offset_2 += bb.getInt(offset_2);
+ int len_1 = bb.getInt(offset_1);
+ int len_2 = bb.getInt(offset_2);
+ int startPos_1 = offset_1 + SIZEOF_INT;
+ int startPos_2 = offset_2 + SIZEOF_INT;
+ int len = Math.min(len_1, len_2);
+ byte[] bbArray = bb.array();
+ for(int i = 0; i < len; i++) {
+ if (bbArray[i + startPos_1] != bbArray[i + startPos_2])
+ return bbArray[i + startPos_1] - bbArray[i + startPos_2];
+ }
+ return len_1 - len_2;
+ }
+
+ /**
+ * Compare string from the buffer with the 'String' object.
+ *
+ * @param offset_1 An 'int' index of the first string into the bb.
+ * @param key Second string as a byte array.
+ * @param bb A {@code ByteBuffer} to get the first string.
+ */
+ protected static int compareStrings(int offset_1, byte[] key, ByteBuffer bb) {
+ offset_1 += bb.getInt(offset_1);
+ int len_1 = bb.getInt(offset_1);
+ int len_2 = key.length;
+ int startPos_1 = offset_1 + Constants.SIZEOF_INT;
+ int len = Math.min(len_1, len_2);
+ byte[] bbArray = bb.array();
+ for (int i = 0; i < len; i++) {
+ if (bbArray[i + startPos_1] != key[i])
+ return bbArray[i + startPos_1] - key[i];
+ }
+ return len_1 - len_2;
+ }
}
/// @endcond
diff --git a/js/flatbuffers.js b/js/flatbuffers.js
index 511c9a2..c1296d5 100644
--- a/js/flatbuffers.js
+++ b/js/flatbuffers.js
@@ -75,8 +75,8 @@
/**
* @constructor
- * @param {number} high
* @param {number} low
+ * @param {number} high
*/
flatbuffers.Long = function(low, high) {
/**
@@ -93,8 +93,8 @@
};
/**
- * @param {number} high
* @param {number} low
+ * @param {number} high
* @returns {flatbuffers.Long}
*/
flatbuffers.Long.create = function(low, high) {
@@ -129,11 +129,13 @@
* Create a FlatBufferBuilder.
*
* @constructor
- * @param {number=} initial_size
+ * @param {number=} opt_initial_size
*/
-flatbuffers.Builder = function(initial_size) {
- if (!initial_size) {
- initial_size = 1024;
+flatbuffers.Builder = function(opt_initial_size) {
+ if (!opt_initial_size) {
+ var initial_size = 1024;
+ } else {
+ var initial_size = opt_initial_size;
}
/**
@@ -238,9 +240,8 @@
};
/**
- * Get the ByteBuffer representing the FlatBuffer. Only call this after you've
- * called finish(). The actual data starts at the ByteBuffer's current position,
- * not necessarily at 0.
+ * Get the bytes representing the FlatBuffer. Only call this after you've
+ * called finish().
*
* @returns {Uint8Array}
*/
@@ -643,10 +644,11 @@
* Finalize a buffer, poiting to the given `root_table`.
*
* @param {flatbuffers.Offset} root_table
- * @param {string=} file_identifier
+ * @param {string=} opt_file_identifier
*/
-flatbuffers.Builder.prototype.finish = function(root_table, file_identifier) {
- if (file_identifier) {
+flatbuffers.Builder.prototype.finish = function(root_table, opt_file_identifier) {
+ if (opt_file_identifier) {
+ var file_identifier = opt_file_identifier;
this.prep(this.minalign, flatbuffers.SIZEOF_INT +
flatbuffers.FILE_IDENTIFIER_LENGTH);
if (file_identifier.length != flatbuffers.FILE_IDENTIFIER_LENGTH) {
@@ -1019,10 +1021,10 @@
* FlatBuffer later on.
*
* @param {number} offset
- * @param {flatbuffers.Encoding=} optionalEncoding Defaults to UTF16_STRING
+ * @param {flatbuffers.Encoding=} opt_encoding Defaults to UTF16_STRING
* @returns {string|Uint8Array}
*/
-flatbuffers.ByteBuffer.prototype.__string = function(offset, optionalEncoding) {
+flatbuffers.ByteBuffer.prototype.__string = function(offset, opt_encoding) {
offset += this.readInt32(offset);
var length = this.readInt32(offset);
@@ -1031,7 +1033,7 @@
offset += flatbuffers.SIZEOF_INT;
- if (optionalEncoding === flatbuffers.Encoding.UTF8_BYTES) {
+ if (opt_encoding === flatbuffers.Encoding.UTF8_BYTES) {
return this.bytes_.subarray(offset, offset + length);
}
diff --git a/net/FlatBuffers/ByteBuffer.cs b/net/FlatBuffers/ByteBuffer.cs
index 5fa1ac7..37a2c7e 100755
--- a/net/FlatBuffers/ByteBuffer.cs
+++ b/net/FlatBuffers/ByteBuffer.cs
@@ -14,7 +14,20 @@
* limitations under the License.
*/
-//#define UNSAFE_BYTEBUFFER // uncomment this line to use faster ByteBuffer
+// There are 2 #defines that have an impact on performance of this ByteBuffer implementation
+//
+// UNSAFE_BYTEBUFFER
+// This will use unsafe code to manipulate the underlying byte array. This
+// can yield a reasonable performance increase.
+//
+// BYTEBUFFER_NO_BOUNDS_CHECK
+// This will disable the bounds check asserts to the byte array. This can
+// yield a small performance gain in normal code..
+//
+// Using UNSAFE_BYTEBUFFER and BYTEBUFFER_NO_BOUNDS_CHECK together can yield a
+// performance gain of ~15% for some operations, however doing so is potentially
+// dangerous. Do so at your own risk!
+//
using System;
@@ -22,9 +35,6 @@
{
/// <summary>
/// Class to mimic Java's ByteBuffer which is used heavily in Flatbuffers.
- /// If your execution environment allows unsafe code, you should enable
- /// unsafe code in your project and #define UNSAFE_BYTEBUFFER to use a
- /// MUCH faster version of ByteBuffer.
/// </summary>
public class ByteBuffer
{
@@ -126,11 +136,14 @@
}
#endif // !UNSAFE_BYTEBUFFER
+
private void AssertOffsetAndLength(int offset, int length)
{
+ #if !BYTEBUFFER_NO_BOUNDS_CHECK
if (offset < 0 ||
offset > _buffer.Length - length)
throw new ArgumentOutOfRangeException();
+ #endif
}
public void PutSbyte(int offset, sbyte value)
@@ -200,7 +213,6 @@
public unsafe void PutUlong(int offset, ulong value)
{
AssertOffsetAndLength(offset, sizeof(ulong));
-
fixed (byte* ptr = _buffer)
{
*(ulong*)(ptr + offset) = BitConverter.IsLittleEndian
diff --git a/net/FlatBuffers/FlatBufferBuilder.cs b/net/FlatBuffers/FlatBufferBuilder.cs
index 590e6ac..b6701df 100644
--- a/net/FlatBuffers/FlatBufferBuilder.cs
+++ b/net/FlatBuffers/FlatBufferBuilder.cs
@@ -296,6 +296,18 @@
return new VectorOffset(Offset);
}
+ /// <summary>
+ /// Creates a vector of tables.
+ /// </summary>
+ /// <param name="offsets">Offsets of the tables.</param>
+ public VectorOffset CreateVectorOfTables<T>(Offset<T>[] offsets) where T : struct
+ {
+ NotNested();
+ StartVector(sizeof(int), offsets.Length, sizeof(int));
+ for (int i = offsets.Length - 1; i >= 0; i--) AddOffset(offsets[i].Value);
+ return EndVector();
+ }
+
/// @cond FLATBUFFERS_INTENRAL
public void Nested(int obj)
{
@@ -582,6 +594,8 @@
/// </summary>
/// <remarks>
/// This is typically only called after you call `Finish()`.
+ /// The actual data starts at the ByteBuffer's current position,
+ /// not necessarily at `0`.
/// </remarks>
/// <returns>
/// Returns the ByteBuffer for this FlatBuffer.
diff --git a/net/FlatBuffers/FlatBuffers.csproj b/net/FlatBuffers/FlatBuffers.csproj
index 3ae938a..2a0cf99 100644
--- a/net/FlatBuffers/FlatBuffers.csproj
+++ b/net/FlatBuffers/FlatBuffers.csproj
@@ -37,6 +37,7 @@
<Compile Include="ByteBuffer.cs" />
<Compile Include="FlatBufferBuilder.cs" />
<Compile Include="FlatBufferConstants.cs" />
+ <Compile Include="IFlatbufferObject.cs" />
<Compile Include="Offset.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Struct.cs" />
diff --git a/net/FlatBuffers/IFlatbufferObject.cs b/net/FlatBuffers/IFlatbufferObject.cs
new file mode 100644
index 0000000..6a15aba
--- /dev/null
+++ b/net/FlatBuffers/IFlatbufferObject.cs
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2014 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace FlatBuffers
+{
+ /// <summary>
+ /// This is the base for both structs and tables.
+ /// </summary>
+ public interface IFlatbufferObject
+ {
+ void __init(int _i, ByteBuffer _bb);
+
+ ByteBuffer ByteBuffer { get; }
+ }
+}
diff --git a/net/FlatBuffers/Offset.cs b/net/FlatBuffers/Offset.cs
index a1524df..2b17cec 100644
--- a/net/FlatBuffers/Offset.cs
+++ b/net/FlatBuffers/Offset.cs
@@ -19,7 +19,7 @@
/// <summary>
/// Offset class for typesafe assignments.
/// </summary>
- public struct Offset<T> where T : class
+ public struct Offset<T> where T : struct
{
public int Value;
public Offset(int value)
diff --git a/net/FlatBuffers/Struct.cs b/net/FlatBuffers/Struct.cs
index ab16f28..61da32f 100644
--- a/net/FlatBuffers/Struct.cs
+++ b/net/FlatBuffers/Struct.cs
@@ -19,9 +19,9 @@
/// <summary>
/// All structs in the generated code derive from this class, and add their own accessors.
/// </summary>
- public abstract class Struct
+ public struct Struct
{
- protected int bb_pos;
- protected ByteBuffer bb;
+ public int bb_pos;
+ public ByteBuffer bb;
}
-}
\ No newline at end of file
+}
diff --git a/net/FlatBuffers/Table.cs b/net/FlatBuffers/Table.cs
index bd5e364..55182b3 100644
--- a/net/FlatBuffers/Table.cs
+++ b/net/FlatBuffers/Table.cs
@@ -20,31 +20,42 @@
namespace FlatBuffers
{
/// <summary>
- /// All tables in the generated code derive from this class, and add their own accessors.
+ /// All tables in the generated code derive from this struct, and add their own accessors.
/// </summary>
- public abstract class Table
+ public struct Table
{
- protected int bb_pos;
- protected ByteBuffer bb;
+ public int bb_pos;
+ public ByteBuffer bb;
public ByteBuffer ByteBuffer { get { return bb; } }
// Look up a field in the vtable, return an offset into the object, or 0 if the field is not
// present.
- protected int __offset(int vtableOffset)
+ public int __offset(int vtableOffset)
{
int vtable = bb_pos - bb.GetInt(bb_pos);
return vtableOffset < bb.GetShort(vtable) ? (int)bb.GetShort(vtable + vtableOffset) : 0;
}
+ public static int __offset(int vtableOffset, int offset, ByteBuffer bb)
+ {
+ int vtable = bb.Length - offset;
+ return (int)bb.GetShort(vtable + vtableOffset - bb.GetInt(vtable)) + vtable;
+ }
+
// Retrieve the relative offset stored at "offset"
- protected int __indirect(int offset)
+ public int __indirect(int offset)
+ {
+ return offset + bb.GetInt(offset);
+ }
+
+ public static int __indirect(int offset, ByteBuffer bb)
{
return offset + bb.GetInt(offset);
}
// Create a .NET String from UTF-8 data stored inside the flatbuffer.
- protected string __string(int offset)
+ public string __string(int offset)
{
offset += bb.GetInt(offset);
var len = bb.GetInt(offset);
@@ -53,7 +64,7 @@
}
// Get the length of a vector whose offset is stored at "offset" in this object.
- protected int __vector_len(int offset)
+ public int __vector_len(int offset)
{
offset += bb_pos;
offset += bb.GetInt(offset);
@@ -61,7 +72,7 @@
}
// Get the start of data of a vector whose offset is stored at "offset" in this object.
- protected int __vector(int offset)
+ public int __vector(int offset)
{
offset += bb_pos;
return offset + bb.GetInt(offset) + sizeof(int); // data starts after the length
@@ -70,7 +81,8 @@
// Get the data of a vector whoses offset is stored at "offset" in this object as an
// ArraySegment<byte>. If the vector is not present in the ByteBuffer,
// then a null value will be returned.
- protected ArraySegment<byte>? __vector_as_arraysegment(int offset) {
+ public ArraySegment<byte>? __vector_as_arraysegment(int offset)
+ {
var o = this.__offset(offset);
if (0 == o)
{
@@ -83,15 +95,15 @@
}
// Initialize any Table-derived type to point to the union at the given offset.
- protected TTable __union<TTable>(TTable t, int offset) where TTable : Table
+ public T __union<T>(int offset) where T : struct, IFlatbufferObject
{
offset += bb_pos;
- t.bb_pos = offset + bb.GetInt(offset);
- t.bb = bb;
+ T t = new T();
+ t.__init(offset + bb.GetInt(offset), bb);
return t;
}
- protected static bool __has_identifier(ByteBuffer bb, string ident)
+ public static bool __has_identifier(ByteBuffer bb, string ident)
{
if (ident.Length != FlatBufferConstants.FileIdentifierLength)
throw new ArgumentException("FlatBuffers: file identifier must be length " + FlatBufferConstants.FileIdentifierLength, "ident");
@@ -104,6 +116,38 @@
return true;
}
+ // Compare strings in the ByteBuffer.
+ public static int CompareStrings(int offset_1, int offset_2, ByteBuffer bb)
+ {
+ offset_1 += bb.GetInt(offset_1);
+ offset_2 += bb.GetInt(offset_2);
+ var len_1 = bb.GetInt(offset_1);
+ var len_2 = bb.GetInt(offset_2);
+ var startPos_1 = offset_1 + sizeof(int);
+ var startPos_2 = offset_2 + sizeof(int);
+ var len = Math.Min(len_1, len_2);
+ byte[] bbArray = bb.Data;
+ for(int i = 0; i < len; i++) {
+ if (bbArray[i + startPos_1] != bbArray[i + startPos_2])
+ return bbArray[i + startPos_1] - bbArray[i + startPos_2];
+ }
+ return len_1 - len_2;
+ }
+ // Compare string from the ByteBuffer with the string object
+ public static int CompareStrings(int offset_1, byte[] key, ByteBuffer bb)
+ {
+ offset_1 += bb.GetInt(offset_1);
+ var len_1 = bb.GetInt(offset_1);
+ var len_2 = key.Length;
+ var startPos_1 = offset_1 + sizeof(int);
+ var len = Math.Min(len_1, len_2);
+ byte[] bbArray = bb.Data;
+ for (int i = 0; i < len; i++) {
+ if (bbArray[i + startPos_1] != key[i])
+ return bbArray[i + startPos_1] - key[i];
+ }
+ return len_1 - len_2;
+ }
}
}
diff --git a/php/FlatbufferBuilder.php b/php/FlatbufferBuilder.php
index 6f0ee48..5c18bf4 100644
--- a/php/FlatbufferBuilder.php
+++ b/php/FlatbufferBuilder.php
@@ -593,6 +593,10 @@
protected function is_utf8($bytes)
{
+ if (function_exists('mb_detect_encoding')) {
+ return (bool) mb_detect_encoding($bytes, 'UTF-8', true);
+ }
+
$len = strlen($bytes);
if ($len < 1) {
/* NOTE: always return 1 when passed string is null */
diff --git a/pom.xml b/pom.xml
index 8e32fee..86d7f53 100644
--- a/pom.xml
+++ b/pom.xml
@@ -5,7 +5,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>com.google.flatbuffers</groupId>
<artifactId>flatbuffers-java</artifactId>
- <version>1.3.0-SNAPSHOT</version>
+ <version>1.4.0-SNAPSHOT</version>
<packaging>bundle</packaging>
<name>FlatBuffers Java API</name>
<description>
diff --git a/readme.md b/readme.md
index 38bf355..8d05c31 100755
--- a/readme.md
+++ b/readme.md
@@ -1,5 +1,7 @@
 FlatBuffers
===========
+
+[](https://gitter.im/google/flatbuffers?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
[](https://travis-ci.org/google/flatbuffers) [](https://ci.appveyor.com/project/gwvo/flatbuffers)
**FlatBuffers** is an efficient cross platform serialization library for games and
diff --git a/samples/monster_generated.h b/samples/monster_generated.h
index 783d1c7..1833c62 100644
--- a/samples/monster_generated.h
+++ b/samples/monster_generated.h
@@ -47,8 +47,8 @@
EquipmentUnion &operator=(const EquipmentUnion &);
~EquipmentUnion();
- static flatbuffers::NativeTable *UnPack(const void *union_obj, Equipment type);
- flatbuffers::Offset<void> Pack(flatbuffers::FlatBufferBuilder &_fbb) const;
+ static flatbuffers::NativeTable *UnPack(const void *union_obj, Equipment type, const flatbuffers::resolver_function_t *resolver);
+ flatbuffers::Offset<void> Pack(flatbuffers::FlatBufferBuilder &_fbb, const flatbuffers::rehasher_function_t *rehasher = nullptr) const;
WeaponT *AsWeapon() { return type == Equipment_Weapon ? reinterpret_cast<WeaponT *>(table) : nullptr; }
};
@@ -60,6 +60,14 @@
inline const char *EnumNameEquipment(Equipment e) { return EnumNamesEquipment()[static_cast<int>(e)]; }
+template<typename T> struct EquipmentTraits {
+ static const Equipment enum_value = Equipment_NONE;
+};
+
+template<> struct EquipmentTraits<Weapon> {
+ static const Equipment enum_value = Equipment_Weapon;
+};
+
inline bool VerifyEquipment(flatbuffers::Verifier &verifier, const void *union_obj, Equipment type);
MANUALLY_ALIGNED_STRUCT(4) Vec3 FLATBUFFERS_FINAL_CLASS {
@@ -84,6 +92,7 @@
STRUCT_END(Vec3, 12);
struct MonsterT : public flatbuffers::NativeTable {
+ typedef Monster TableType;
std::unique_ptr<Vec3> pos;
int16_t mana;
int16_t hp;
@@ -95,6 +104,7 @@
};
struct Monster FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
+ typedef MonsterT NativeTableType;
enum {
VT_POS = 4,
VT_MANA = 6,
@@ -142,7 +152,8 @@
VerifyEquipment(verifier, equipped(), equipped_type()) &&
verifier.EndTable();
}
- std::unique_ptr<MonsterT> UnPack() const;
+ MonsterT *UnPack(const flatbuffers::resolver_function_t *resolver = nullptr) const;
+ static flatbuffers::Offset<Monster> Pack(flatbuffers::FlatBufferBuilder &_fbb, const MonsterT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr);
};
struct MonsterBuilder {
@@ -188,7 +199,7 @@
return builder_.Finish();
}
-inline flatbuffers::Offset<Monster> CreateMonster(flatbuffers::FlatBufferBuilder &_fbb,
+inline flatbuffers::Offset<Monster> CreateMonsterDirect(flatbuffers::FlatBufferBuilder &_fbb,
const Vec3 *pos = 0,
int16_t mana = 150,
int16_t hp = 100,
@@ -198,17 +209,19 @@
const std::vector<flatbuffers::Offset<Weapon>> *weapons = nullptr,
Equipment equipped_type = Equipment_NONE,
flatbuffers::Offset<void> equipped = 0) {
- return CreateMonster(_fbb, pos, mana, hp, name ? 0 : _fbb.CreateString(name), inventory ? 0 : _fbb.CreateVector<uint8_t>(*inventory), color, weapons ? 0 : _fbb.CreateVector<flatbuffers::Offset<Weapon>>(*weapons), equipped_type, equipped);
+ return CreateMonster(_fbb, pos, mana, hp, name ? _fbb.CreateString(name) : 0, inventory ? _fbb.CreateVector<uint8_t>(*inventory) : 0, color, weapons ? _fbb.CreateVector<flatbuffers::Offset<Weapon>>(*weapons) : 0, equipped_type, equipped);
}
-inline flatbuffers::Offset<Monster> CreateMonster(flatbuffers::FlatBufferBuilder &_fbb, const MonsterT *_o);
+inline flatbuffers::Offset<Monster> CreateMonster(flatbuffers::FlatBufferBuilder &_fbb, const MonsterT *_o, const flatbuffers::rehasher_function_t *rehasher = nullptr);
struct WeaponT : public flatbuffers::NativeTable {
+ typedef Weapon TableType;
std::string name;
int16_t damage;
};
struct Weapon FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
+ typedef WeaponT NativeTableType;
enum {
VT_NAME = 4,
VT_DAMAGE = 6
@@ -224,7 +237,8 @@
VerifyField<int16_t>(verifier, VT_DAMAGE) &&
verifier.EndTable();
}
- std::unique_ptr<WeaponT> UnPack() const;
+ WeaponT *UnPack(const flatbuffers::resolver_function_t *resolver = nullptr) const;
+ static flatbuffers::Offset<Weapon> Pack(flatbuffers::FlatBufferBuilder &_fbb, const WeaponT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr);
};
struct WeaponBuilder {
@@ -249,15 +263,16 @@
return builder_.Finish();
}
-inline flatbuffers::Offset<Weapon> CreateWeapon(flatbuffers::FlatBufferBuilder &_fbb,
+inline flatbuffers::Offset<Weapon> CreateWeaponDirect(flatbuffers::FlatBufferBuilder &_fbb,
const char *name = nullptr,
int16_t damage = 0) {
- return CreateWeapon(_fbb, name ? 0 : _fbb.CreateString(name), damage);
+ return CreateWeapon(_fbb, name ? _fbb.CreateString(name) : 0, damage);
}
-inline flatbuffers::Offset<Weapon> CreateWeapon(flatbuffers::FlatBufferBuilder &_fbb, const WeaponT *_o);
+inline flatbuffers::Offset<Weapon> CreateWeapon(flatbuffers::FlatBufferBuilder &_fbb, const WeaponT *_o, const flatbuffers::rehasher_function_t *rehasher = nullptr);
-inline std::unique_ptr<MonsterT> Monster::UnPack() const {
+inline MonsterT *Monster::UnPack(const flatbuffers::resolver_function_t *resolver) const {
+ (void)resolver;
auto _o = new MonsterT();
{ auto _e = pos(); if (_e) _o->pos = std::unique_ptr<Vec3>(new Vec3(*_e)); };
{ auto _e = mana(); _o->mana = _e; };
@@ -265,13 +280,18 @@
{ 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 = color(); _o->color = _e; };
- { auto _e = weapons(); if (_e) { for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->weapons.push_back(_e->Get(_i)->UnPack()); } } };
+ { 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 = equipped_type(); _o->equipped.type = _e; };
- { auto _e = equipped(); if (_e) _o->equipped.table = EquipmentUnion::UnPack(_e, equipped_type()); };
- return std::unique_ptr<MonsterT>(_o);
+ { auto _e = equipped(); if (_e) _o->equipped.table = EquipmentUnion::UnPack(_e, equipped_type(), resolver); };
+ return _o;
}
-inline flatbuffers::Offset<Monster> CreateMonster(flatbuffers::FlatBufferBuilder &_fbb, const MonsterT *_o) {
+inline flatbuffers::Offset<Monster> Monster::Pack(flatbuffers::FlatBufferBuilder &_fbb, const MonsterT* _o, const flatbuffers::rehasher_function_t *_rehasher) {
+ return CreateMonster(_fbb, _o, _rehasher);
+}
+
+inline flatbuffers::Offset<Monster> CreateMonster(flatbuffers::FlatBufferBuilder &_fbb, const MonsterT *_o, const flatbuffers::rehasher_function_t *rehasher) {
+ (void)rehasher;
return CreateMonster(_fbb,
_o->pos ? _o->pos.get() : 0,
_o->mana,
@@ -279,19 +299,25 @@
_o->name.size() ? _fbb.CreateString(_o->name) : 0,
_o->inventory.size() ? _fbb.CreateVector(_o->inventory) : 0,
_o->color,
- _o->weapons.size() ? _fbb.CreateVector<flatbuffers::Offset<Weapon>>(_o->weapons.size(), [&](size_t i) { return CreateWeapon(_fbb, _o->weapons[i].get()); }) : 0,
+ _o->weapons.size() ? _fbb.CreateVector<flatbuffers::Offset<Weapon>>(_o->weapons.size(), [&](size_t i) { return CreateWeapon(_fbb, _o->weapons[i].get(), rehasher); }) : 0,
_o->equipped.type,
_o->equipped.Pack(_fbb));
}
-inline std::unique_ptr<WeaponT> Weapon::UnPack() const {
+inline WeaponT *Weapon::UnPack(const flatbuffers::resolver_function_t *resolver) const {
+ (void)resolver;
auto _o = new WeaponT();
{ auto _e = name(); if (_e) _o->name = _e->str(); };
{ auto _e = damage(); _o->damage = _e; };
- return std::unique_ptr<WeaponT>(_o);
+ return _o;
}
-inline flatbuffers::Offset<Weapon> CreateWeapon(flatbuffers::FlatBufferBuilder &_fbb, const WeaponT *_o) {
+inline flatbuffers::Offset<Weapon> Weapon::Pack(flatbuffers::FlatBufferBuilder &_fbb, const WeaponT* _o, const flatbuffers::rehasher_function_t *_rehasher) {
+ return CreateWeapon(_fbb, _o, _rehasher);
+}
+
+inline flatbuffers::Offset<Weapon> CreateWeapon(flatbuffers::FlatBufferBuilder &_fbb, const WeaponT *_o, const flatbuffers::rehasher_function_t *rehasher) {
+ (void)rehasher;
return CreateWeapon(_fbb,
_o->name.size() ? _fbb.CreateString(_o->name) : 0,
_o->damage);
@@ -305,18 +331,18 @@
}
}
-inline flatbuffers::NativeTable *EquipmentUnion::UnPack(const void *union_obj, Equipment type) {
+inline flatbuffers::NativeTable *EquipmentUnion::UnPack(const void *union_obj, Equipment type, const flatbuffers::resolver_function_t *resolver) {
switch (type) {
case Equipment_NONE: return nullptr;
- case Equipment_Weapon: return reinterpret_cast<const Weapon *>(union_obj)->UnPack().release();
+ case Equipment_Weapon: return reinterpret_cast<const Weapon *>(union_obj)->UnPack(resolver);
default: return nullptr;
}
}
-inline flatbuffers::Offset<void> EquipmentUnion::Pack(flatbuffers::FlatBufferBuilder &_fbb) const {
+inline flatbuffers::Offset<void> EquipmentUnion::Pack(flatbuffers::FlatBufferBuilder &_fbb, const flatbuffers::rehasher_function_t *rehasher) const {
switch (type) {
case Equipment_NONE: return 0;
- case Equipment_Weapon: return CreateWeapon(_fbb, reinterpret_cast<const WeaponT *>(table)).Union();
+ case Equipment_Weapon: return CreateWeapon(_fbb, reinterpret_cast<const WeaponT *>(table), rehasher).Union();
default: return 0;
}
}
@@ -328,13 +354,25 @@
}
}
-inline const MyGame::Sample::Monster *GetMonster(const void *buf) { return flatbuffers::GetRoot<MyGame::Sample::Monster>(buf); }
+inline const MyGame::Sample::Monster *GetMonster(const void *buf) {
+ return flatbuffers::GetRoot<MyGame::Sample::Monster>(buf);
+}
-inline Monster *GetMutableMonster(void *buf) { return flatbuffers::GetMutableRoot<Monster>(buf); }
+inline Monster *GetMutableMonster(void *buf) {
+ return flatbuffers::GetMutableRoot<Monster>(buf);
+}
-inline bool VerifyMonsterBuffer(flatbuffers::Verifier &verifier) { return verifier.VerifyBuffer<MyGame::Sample::Monster>(nullptr); }
+inline bool VerifyMonsterBuffer(flatbuffers::Verifier &verifier) {
+ return verifier.VerifyBuffer<MyGame::Sample::Monster>(nullptr);
+}
-inline void FinishMonsterBuffer(flatbuffers::FlatBufferBuilder &fbb, flatbuffers::Offset<MyGame::Sample::Monster> root) { fbb.Finish(root); }
+inline void FinishMonsterBuffer(flatbuffers::FlatBufferBuilder &fbb, flatbuffers::Offset<MyGame::Sample::Monster> root) {
+ fbb.Finish(root);
+}
+
+inline std::unique_ptr<MonsterT> UnPackMonster(const void *buf, const flatbuffers::resolver_function_t *resolver = nullptr) {
+ return std::unique_ptr<MonsterT>(GetMonster(buf)->UnPack(resolver));
+}
} // namespace Sample
} // namespace MyGame
diff --git a/samples/sample_text.cpp b/samples/sample_text.cpp
index 557077d..d851120 100644
--- a/samples/sample_text.cpp
+++ b/samples/sample_text.cpp
@@ -46,7 +46,10 @@
// to ensure it is correct, we now generate text back from the binary,
// and compare the two:
std::string jsongen;
- GenerateText(parser, parser.builder_.GetBufferPointer(), &jsongen);
+ if (!GenerateText(parser, parser.builder_.GetBufferPointer(), &jsongen)) {
+ printf("Couldn't serialize parsed data to JSON!\n");
+ return 1;
+ }
if (jsongen != jsonfile) {
printf("%s----------------\n%s", jsongen.c_str(), jsonfile.c_str());
diff --git a/src/flatc.cpp b/src/flatc.cpp
index 44ce913..fae00de 100644
--- a/src/flatc.cpp
+++ b/src/flatc.cpp
@@ -19,7 +19,7 @@
#include "flatbuffers/util.h"
#include <limits>
-#define FLATC_VERSION "1.3.0 (" __DATE__ ")"
+#define FLATC_VERSION "1.4.0 (" __DATE__ ")"
static void Error(const std::string &err, bool usage = false,
bool show_exe_name = true);
@@ -33,6 +33,9 @@
const char *generator_opt_short;
const char *generator_opt_long;
const char *lang_name;
+ bool (*generateGRPC)(const flatbuffers::Parser &parser,
+ const std::string &path,
+ const std::string &file_name);
flatbuffers::IDLOptions::Language lang;
const char *generator_help;
@@ -43,45 +46,50 @@
const Generator generators[] = {
{ flatbuffers::GenerateBinary, "-b", "--binary", "binary",
+ nullptr,
flatbuffers::IDLOptions::kMAX,
"Generate wire format binaries for any data definitions",
flatbuffers::BinaryMakeRule },
{ flatbuffers::GenerateTextFile, "-t", "--json", "text",
+ nullptr,
flatbuffers::IDLOptions::kMAX,
"Generate text output for any data definitions",
flatbuffers::TextMakeRule },
{ flatbuffers::GenerateCPP, "-c", "--cpp", "C++",
+ flatbuffers::GenerateCppGRPC,
flatbuffers::IDLOptions::kMAX,
"Generate C++ headers for tables/structs",
flatbuffers::CPPMakeRule },
{ flatbuffers::GenerateGo, "-g", "--go", "Go",
+ flatbuffers::GenerateGoGRPC,
flatbuffers::IDLOptions::kGo,
"Generate Go files for tables/structs",
flatbuffers::GeneralMakeRule },
{ flatbuffers::GenerateGeneral, "-j", "--java", "Java",
+ nullptr,
flatbuffers::IDLOptions::kJava,
"Generate Java classes for tables/structs",
flatbuffers::GeneralMakeRule },
{ flatbuffers::GenerateJS, "-s", "--js", "JavaScript",
+ nullptr,
flatbuffers::IDLOptions::kMAX,
"Generate JavaScript code for tables/structs",
flatbuffers::JSMakeRule },
{ flatbuffers::GenerateGeneral, "-n", "--csharp", "C#",
+ nullptr,
flatbuffers::IDLOptions::kCSharp,
"Generate C# classes for tables/structs",
flatbuffers::GeneralMakeRule },
{ flatbuffers::GeneratePython, "-p", "--python", "Python",
+ nullptr,
flatbuffers::IDLOptions::kMAX,
"Generate Python files for tables/structs",
flatbuffers::GeneralMakeRule },
{ flatbuffers::GeneratePhp, nullptr, "--php", "PHP",
+ nullptr,
flatbuffers::IDLOptions::kMAX,
"Generate PHP files for tables/structs",
flatbuffers::GeneralMakeRule },
- { flatbuffers::GenerateGRPC, nullptr, "--grpc", "GRPC",
- flatbuffers::IDLOptions::kMAX,
- "Generate GRPC interfaces",
- flatbuffers::CPPMakeRule },
};
const char *g_program_name = nullptr;
@@ -126,13 +134,16 @@
" --gen-onefile Generate single output file for C#.\n"
" --gen-name-strings Generate type name functions for C++.\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"
" --raw-binary Allow binaries without file_indentifier to be read.\n"
" This may crash flatc given a mismatched schema.\n"
" --proto Input is a .proto, translate to .fbs.\n"
" --schema Serialize schemas instead of JSON (use with -b)\n"
" --conform FILE Specify a schema the following schemas should be\n"
" an evolution of. Gives errors if not.\n"
+ " --conform-includes Include path for the schema given with --conform\n"
+ " PATH \n"
"FILEs may be schemas, or JSON files (conforming to preceding schema)\n"
"FILEs after the -- must be binary flatbuffer format files.\n"
"Output files are named using the base file name of the input,\n"
@@ -167,8 +178,10 @@
bool print_make_rules = false;
bool raw_binary = false;
bool schema_binary = false;
+ bool grpc_enabled = false;
std::vector<std::string> filenames;
std::vector<const char *> include_directories;
+ std::vector<const char *> conform_include_directories;
size_t binary_files_from = std::numeric_limits<size_t>::max();
std::string conform_to_schema;
for (int argi = 1; argi < argc; argi++) {
@@ -185,6 +198,9 @@
} else if(arg == "--conform") {
if (++argi >= argc) Error("missing path following" + arg, true);
conform_to_schema = argv[argi];
+ } else if (arg == "--conform-includes") {
+ if (++argi >= argc) Error("missing path following" + arg, true);
+ conform_include_directories.push_back(argv[argi]);
} else if(arg == "--strict-json") {
opts.strict_json = true;
} else if(arg == "--allow-non-utf8") {
@@ -208,6 +224,9 @@
opts.generate_name_strings = true;
} else if(arg == "--gen-object-api") {
opts.generate_object_based_api = true;
+ } else if (arg == "--cpp-ptr-type") {
+ if (++argi >= argc) Error("missing type following" + arg, true);
+ opts.cpp_object_api_pointer_type = argv[argi];
} else if(arg == "--gen-all") {
opts.generate_all = true;
opts.include_dependence_headers = false;
@@ -233,6 +252,8 @@
} else if(arg == "--version") {
printf("flatc version %s\n", FLATC_VERSION);
exit(0);
+ } else if(arg == "--grpc") {
+ grpc_enabled = true;
} else {
for (size_t i = 0; i < num_generators; ++i) {
if (arg == generators[i].generator_opt_long ||
@@ -243,7 +264,7 @@
goto found;
}
}
- Error("unknown commandline argument" + arg, true);
+ Error("unknown commandline argument: " + arg, true);
found:;
}
} else {
@@ -265,7 +286,8 @@
std::string contents;
if (!flatbuffers::LoadFile(conform_to_schema.c_str(), true, &contents))
Error("unable to load schema: " + conform_to_schema);
- ParseFile(conform_parser, conform_to_schema, contents, include_directories);
+ ParseFile(conform_parser, conform_to_schema, contents,
+ conform_include_directories);
}
// Now process the files:
@@ -349,6 +371,17 @@
printf("%s\n", flatbuffers::WordWrap(
make_rule, 80, " ", " \\").c_str());
}
+ if (grpc_enabled) {
+ if (generators[i].generateGRPC != nullptr) {
+ if (!generators[i].generateGRPC(*g_parser, output_path, filebase)) {
+ Error(std::string("Unable to generate GRPC interface for") +
+ generators[i].lang_name);
+ }
+ } else {
+ Error(std::string("GRPC interface generator not implemented for ") +
+ generators[i].lang_name);
+ }
+ }
}
}
diff --git a/src/idl_gen_cpp.cpp b/src/idl_gen_cpp.cpp
index 6eaab14..8681e17 100644
--- a/src/idl_gen_cpp.cpp
+++ b/src/idl_gen_cpp.cpp
@@ -159,40 +159,40 @@
// The root datatype accessor:
code += "inline const " + cpp_qualified_name + " *Get";
code += name;
- code += "(const void *buf) { return flatbuffers::GetRoot<";
- code += cpp_qualified_name + ">(buf); }\n\n";
+ code += "(const void *buf) {\n return flatbuffers::GetRoot<";
+ code += cpp_qualified_name + ">(buf);\n}\n\n";
if (parser_.opts.mutable_buffer) {
code += "inline " + name + " *GetMutable";
code += name;
- code += "(void *buf) { return flatbuffers::GetMutableRoot<";
- code += name + ">(buf); }\n\n";
+ code += "(void *buf) {\n return flatbuffers::GetMutableRoot<";
+ code += name + ">(buf);\n}\n\n";
}
if (parser_.file_identifier_.length()) {
// Return the identifier
code += "inline const char *" + name;
- code += "Identifier() { return \"" + parser_.file_identifier_;
- code += "\"; }\n\n";
+ code += "Identifier() {\n return \"" + parser_.file_identifier_;
+ code += "\";\n}\n\n";
// Check if a buffer has the identifier.
code += "inline bool " + name;
- code += "BufferHasIdentifier(const void *buf) { return flatbuffers::";
+ code += "BufferHasIdentifier(const void *buf) {\n return flatbuffers::";
code += "BufferHasIdentifier(buf, ";
- code += name + "Identifier()); }\n\n";
+ code += name + "Identifier());\n}\n\n";
}
// The root verifier:
code += "inline bool Verify";
code += name;
code +=
- "Buffer(flatbuffers::Verifier &verifier) { "
- "return verifier.VerifyBuffer<";
+ "Buffer(flatbuffers::Verifier &verifier) {\n"
+ " return verifier.VerifyBuffer<";
code += cpp_qualified_name + ">(";
if (parser_.file_identifier_.length())
code += name + "Identifier()";
else
code += "nullptr";
- code += "); }\n\n";
+ code += ");\n}\n\n";
if (parser_.file_extension_.length()) {
// Return the extension
@@ -205,10 +205,22 @@
code += "inline void Finish" + name;
code +=
"Buffer(flatbuffers::FlatBufferBuilder &fbb, flatbuffers::Offset<";
- code += cpp_qualified_name + "> root) { fbb.Finish(root";
+ code += cpp_qualified_name + "> root) {\n fbb.Finish(root";
if (parser_.file_identifier_.length())
code += ", " + name + "Identifier()";
- code += "); }\n\n";
+ code += ");\n}\n\n";
+
+ if (parser_.opts.generate_object_based_api) {
+ // A convenient root unpack function.
+ auto native_name =
+ NativeName(WrapInNameSpace(*parser_.root_struct_def_));
+ code += "inline " + GenTypeNativePtr(native_name, nullptr, false);
+ code += " UnPack" + name;
+ code += "(const void *buf, const flatbuffers::resolver_function_t *";
+ code += "resolver = nullptr) {\n return ";
+ code += GenTypeNativePtr(native_name, nullptr, true);
+ code += "(Get" + name + "(buf)->UnPack(resolver));\n}\n\n";
+ }
}
assert(cur_name_space_);
@@ -293,23 +305,42 @@
// TODO(wvo): make this configurable.
std::string NativeName(const std::string &name) { return name + "T"; }
- std::string GenTypeNative(const Type &type, bool invector) {
+ const std::string &PtrType(const FieldDef *field) {
+ auto attr = field ? field->attributes.Lookup("cpp_ptr_type") : nullptr;
+ return attr ? attr->constant : parser_.opts.cpp_object_api_pointer_type;
+ }
+
+ std::string GenTypeNativePtr(const std::string &type, const FieldDef *field,
+ bool is_constructor) {
+ auto &ptr_type = PtrType(field);
+ if (ptr_type == "naked") return is_constructor ? "" : type + " *";
+ return ptr_type + "<" + type + ">";
+ }
+
+ std::string GenPtrGet(const FieldDef &field) {
+ auto &ptr_type = PtrType(&field);
+ return ptr_type == "naked" ? "" : ".get()";
+ }
+
+ std::string GenTypeNative(const Type &type, bool invector,
+ const FieldDef &field) {
switch (type.base_type) {
case BASE_TYPE_STRING:
return "std::string";
case BASE_TYPE_VECTOR:
- return "std::vector<" + GenTypeNative(type.VectorType(), true) + ">";
+ return "std::vector<" + GenTypeNative(type.VectorType(), true, field) +
+ ">";
case BASE_TYPE_STRUCT:
if (IsStruct(type)) {
- if (invector) {
+ if (invector || field.native_inline) {
return WrapInNameSpace(*type.struct_def);
} else {
- return "std::unique_ptr<" +
- WrapInNameSpace(*type.struct_def) + ">";
+ return GenTypeNativePtr(WrapInNameSpace(*type.struct_def), &field,
+ false);
}
} else {
- return "std::unique_ptr<" +
- NativeName(WrapInNameSpace(*type.struct_def)) + ">";
+ return GenTypeNativePtr(NativeName(WrapInNameSpace(*type.struct_def)),
+ &field, false);
}
case BASE_TYPE_UNION:
return type.enum_def->name + "Union";
@@ -333,15 +364,15 @@
return (opts.scoped_enums ? "enum class " : "enum ") + enum_def.name;
}
- static std::string GenEnumVal(const EnumDef &enum_def,
- const std::string &enum_val,
- const IDLOptions &opts) {
+ static std::string GenEnumValDecl(const EnumDef &enum_def,
+ const std::string &enum_val,
+ const IDLOptions &opts) {
return opts.prefixed_enums ? enum_def.name + "_" + enum_val : enum_val;
}
- static std::string GetEnumVal(const EnumDef &enum_def,
- const EnumVal &enum_val,
- const IDLOptions &opts) {
+ static std::string GetEnumValUse(const EnumDef &enum_def,
+ const EnumVal &enum_val,
+ const IDLOptions &opts) {
if (opts.scoped_enums) {
return enum_def.name + "::" + enum_val.name;
} else if (opts.prefixed_enums) {
@@ -361,25 +392,42 @@
return (inclass ? "static " : "") +
std::string("flatbuffers::NativeTable *") +
(inclass ? "" : enum_def.name + "Union::") +
- "UnPack(const void *union_obj, " + enum_def.name + " type)";
+ "UnPack(const void *union_obj, " + enum_def.name +
+ " type, const flatbuffers::resolver_function_t *resolver)";
}
std::string UnionPackSignature(EnumDef &enum_def, bool inclass) {
return "flatbuffers::Offset<void> " +
(inclass ? "" : enum_def.name + "Union::") +
- "Pack(flatbuffers::FlatBufferBuilder &_fbb) const";
+ "Pack(flatbuffers::FlatBufferBuilder &_fbb, " +
+ "const flatbuffers::rehasher_function_t *rehasher" +
+ (inclass ? " = nullptr" : "") + ") const";
}
- std::string TableCreateSignature(StructDef &struct_def) {
+ std::string TableCreateSignature(StructDef &struct_def, bool predecl) {
return "inline flatbuffers::Offset<" + struct_def.name + "> Create" +
struct_def.name +
"(flatbuffers::FlatBufferBuilder &_fbb, const " +
- NativeName(struct_def.name) + " *_o)";
+ NativeName(struct_def.name) +
+ " *_o, const flatbuffers::rehasher_function_t *rehasher" +
+ (predecl ? " = nullptr" : "") + ")";
+ }
+
+ std::string TablePackSignature(StructDef &struct_def, bool inclass) {
+ return std::string(inclass ? "static " : "") +
+ "flatbuffers::Offset<" + struct_def.name + "> " +
+ (inclass ? "" : struct_def.name + "::") +
+ "Pack(flatbuffers::FlatBufferBuilder &_fbb, " +
+ "const " + NativeName(struct_def.name) + "* _o, " +
+ "const flatbuffers::rehasher_function_t *_rehasher" +
+ (inclass ? " = nullptr" : "") + ")";
}
std::string TableUnPackSignature(StructDef &struct_def, bool inclass) {
- return "std::unique_ptr<" + NativeName(struct_def.name) + "> " +
- (inclass ? "" : struct_def.name + "::") + "UnPack() const";
+ return NativeName(struct_def.name) + " *" +
+ (inclass ? "" : struct_def.name + "::") +
+ "UnPack(const flatbuffers::resolver_function_t *resolver" +
+ (inclass ? " = nullptr" : "") + ") const";
}
// Generate an enum declaration and an enum string lookup table.
@@ -396,8 +444,9 @@
++it) {
auto &ev = **it;
GenComment(ev.doc_comment, code_ptr, nullptr, " ");
- code += " " + GenEnumVal(enum_def, ev.name, parser_.opts) + " = ";
- code += NumToString(ev.value) + ",\n";
+ code += " " + GenEnumValDecl(enum_def, ev.name, parser_.opts) + " = ";
+ code += NumToString(ev.value);
+ if (it != enum_def.vals.vec.end() - 1) code += ",\n";
minv = !minv || minv->value > ev.value ? &ev : minv;
maxv = !maxv || maxv->value < ev.value ? &ev : maxv;
anyv |= ev.value;
@@ -406,18 +455,18 @@
assert(minv && maxv);
if (enum_def.attributes.Lookup("bit_flags")) {
if (minv->value != 0) // If the user didn't defined NONE value
- code += " " + GenEnumVal(enum_def, "NONE", parser_.opts) + " = 0,\n";
+ code += ",\n " + GenEnumValDecl(enum_def, "NONE", parser_.opts) + " = 0";
if (maxv->value != anyv) // If the user didn't defined ANY value
- code += " " + GenEnumVal(enum_def, "ANY", parser_.opts) + " = " +
- NumToString(anyv) + "\n";
+ code += ",\n " + GenEnumValDecl(enum_def, "ANY", parser_.opts) + " = " +
+ NumToString(anyv);
} else { // MIN & MAX are useless for bit_flags
- code += " " + GenEnumVal(enum_def, "MIN", parser_.opts) + " = ";
- code += GenEnumVal(enum_def, minv->name, parser_.opts) + ",\n";
- code += " " + GenEnumVal(enum_def, "MAX", parser_.opts) + " = ";
- code += GenEnumVal(enum_def, maxv->name, parser_.opts) + "\n";
+ code += ",\n " + GenEnumValDecl(enum_def, "MIN", parser_.opts) + " = ";
+ code += GenEnumValDecl(enum_def, minv->name, parser_.opts);
+ code += ",\n " + GenEnumValDecl(enum_def, "MAX", parser_.opts) + " = ";
+ code += GenEnumValDecl(enum_def, maxv->name, parser_.opts);
}
}
- code += "};\n";
+ code += "\n};\n";
if (parser_.opts.scoped_enums && enum_def.attributes.Lookup("bit_flags"))
code += "DEFINE_BITMASK_OPERATORS(" + enum_def.name + ", " +
GenTypeBasic(enum_def.underlying_type, false) + ")\n";
@@ -429,7 +478,7 @@
code += " " + enum_def.name + " type;\n\n";
code += " flatbuffers::NativeTable *table;\n";
code += " " + enum_def.name + "Union() : type(";
- code += GenEnumVal(enum_def, "NONE", parser_.opts);
+ code += GetEnumValUse(enum_def, *enum_def.vals.Lookup("NONE"), parser_.opts);
code += "), table(nullptr) {}\n";
code += " " + enum_def.name + "Union(const ";
code += enum_def.name + "Union &);\n";
@@ -445,7 +494,7 @@
auto native_name = NativeName(WrapInNameSpace(*ev.struct_def));
code += " " + native_name + " *As";
code += ev.name + "() { return type == ";
- code += GetEnumVal(enum_def, ev, parser_.opts);
+ code += GetEnumValUse(enum_def, ev, parser_.opts);
code += " ? reinterpret_cast<" + native_name;
code += " *>(table) : nullptr; }\n";
}
@@ -478,12 +527,31 @@
code += "()[static_cast<int>(e)";
if (enum_def.vals.vec.front()->value) {
code += " - static_cast<int>(";
- code += GetEnumVal(enum_def, *enum_def.vals.vec.front(), parser_.opts) +
+ code += GetEnumValUse(enum_def, *enum_def.vals.vec.front(), parser_.opts) +
")";
}
code += "]; }\n\n";
}
+ // Generate type traits for unions to map from a type to union enum value.
+ if (enum_def.is_union) {
+ for (auto it = enum_def.vals.vec.begin();
+ it != enum_def.vals.vec.end();
+ ++it) {
+ auto &ev = **it;
+ if (it == enum_def.vals.vec.begin()) {
+ code += "template<typename T> struct " + enum_def.name + "Traits {\n";
+ }
+ else {
+ code += "template<> struct " + enum_def.name + "Traits<" +
+ WrapInNameSpace(*ev.struct_def) + "> {\n";
+ }
+ code += " static const " + enum_def.name + " enum_value = " +
+ GetEnumValUse(enum_def, ev, parser_.opts) + ";\n";
+ code += "};\n\n";
+ }
+ }
+
if (enum_def.is_union) {
code += UnionVerifySignature(enum_def) + ";\n\n";
}
@@ -500,7 +568,7 @@
for (auto it = enum_def.vals.vec.begin(); it != enum_def.vals.vec.end();
++it) {
auto &ev = **it;
- code += " case " + GetEnumVal(enum_def, ev, parser_.opts);
+ code += " case " + GetEnumValUse(enum_def, ev, parser_.opts);
if (!ev.value) {
code += ": return true;\n"; // "NONE" enum value.
} else {
@@ -518,13 +586,13 @@
for (auto it = enum_def.vals.vec.begin(); it != enum_def.vals.vec.end();
++it) {
auto &ev = **it;
- code += " case " + GetEnumVal(enum_def, ev, parser_.opts);
+ code += " case " + GetEnumValUse(enum_def, ev, parser_.opts);
if (!ev.value) {
code += ": return nullptr;\n"; // "NONE" enum value.
} else {
code += ": return reinterpret_cast<const ";
code += WrapInNameSpace(*ev.struct_def);
- code += " *>(union_obj)->UnPack().release();\n";
+ code += " *>(union_obj)->UnPack(resolver);\n";
}
}
code += " default: return nullptr;\n }\n}\n\n";
@@ -533,14 +601,14 @@
for (auto it = enum_def.vals.vec.begin(); it != enum_def.vals.vec.end();
++it) {
auto &ev = **it;
- code += " case " + GetEnumVal(enum_def, ev, parser_.opts);
+ code += " case " + GetEnumValUse(enum_def, ev, parser_.opts);
if (!ev.value) {
code += ": return 0;\n"; // "NONE" enum value.
} else {
code += ": return Create" + ev.struct_def->name;
code += "(_fbb, reinterpret_cast<const ";
code += NativeName(WrapInNameSpace(*ev.struct_def));
- code += " *>(table)).Union();\n";
+ code += " *>(table), rehasher).Union();\n";
}
}
code += " default: return 0;\n }\n}\n\n";
@@ -553,7 +621,7 @@
++it) {
auto &ev = **it;
if (ev.value) {
- code += " case " + GenEnumVal(enum_def, ev.name, parser_.opts);
+ code += " case " + GetEnumValUse(enum_def, ev, parser_.opts);
code += ": delete reinterpret_cast<";
code += NativeName(WrapInNameSpace(*ev.struct_def));
code += " *>(table); break;\n";
@@ -613,7 +681,7 @@
if (ev) {
code += WrapInNameSpace(
field.value.type.enum_def->defined_namespace,
- GetEnumVal(*field.value.type.enum_def, *ev, parser_.opts));
+ GetEnumValUse(*field.value.type.enum_def, *ev, parser_.opts));
} else {
code += GenUnderlyingCast(field, true, field.value.constant);
}
@@ -633,13 +701,18 @@
// table.
code += "struct " + NativeName(struct_def.name);
code += " : public flatbuffers::NativeTable {\n";
+ code += " typedef " + struct_def.name + " TableType;\n";
+ // Generate GetFullyQualifiedName
+ GenFullyQualifiedNameGetter(NativeName(struct_def.name), code);
for (auto it = struct_def.fields.vec.begin();
it != struct_def.fields.vec.end(); ++it) {
auto &field = **it;
if (!field.deprecated && // Deprecated fields won't be accessible.
field.value.type.base_type != BASE_TYPE_UTYPE) {
- code += " " + GenTypeNative(field.value.type, false) + " ";
- code += field.name + ";\n";
+ auto type = GenTypeNative(field.value.type, false, field);
+ auto cpp_type = field.attributes.Lookup("cpp_type");
+ code += " " + (cpp_type ? cpp_type->constant + " *" : type+ " ") +
+ field.name + ";\n";
}
}
code += "};\n\n";
@@ -651,6 +724,10 @@
code += "struct " + struct_def.name;
code += " FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table";
code += " {\n";
+ if (parser_.opts.generate_object_based_api) {
+ code += " typedef " + NativeName(struct_def.name) +
+ " NativeTableType;\n";
+ }
// Generate GetFullyQualifiedName
GenFullyQualifiedNameGetter(struct_def.name, code);
// Generate field id constants.
@@ -814,6 +891,7 @@
if (parser_.opts.generate_object_based_api) {
// Generate the UnPack() pre declaration.
code += " " + TableUnPackSignature(struct_def, true) + ";\n";
+ code += " " + TablePackSignature(struct_def, true) + ";\n";
}
code += "};\n\n"; // End of table.
@@ -897,11 +975,11 @@
}
code += " return builder_.Finish();\n}\n\n";
- // Generate a CreateX function with vector types as parameters
+ // Generate a CreateXDirect function with vector types as parameters
if (gen_vector_pars) {
code += "inline flatbuffers::Offset<" + struct_def.name + "> Create";
code += struct_def.name;
- code += "(flatbuffers::FlatBufferBuilder &_fbb";
+ code += "Direct(flatbuffers::FlatBufferBuilder &_fbb";
for (auto it = struct_def.fields.vec.begin();
it != struct_def.fields.vec.end(); ++it) {
auto &field = **it;
@@ -927,15 +1005,16 @@
auto &field = **it;
if (!field.deprecated) {
if (field.value.type.base_type == BASE_TYPE_STRING) {
- code += ", " + field.name + " ? 0 : ";
- code += "_fbb.CreateString(" + field.name + ")";
+ code += ", " + field.name + " ? ";
+ code += "_fbb.CreateString(" + field.name + ") : 0";
} else if (field.value.type.base_type == BASE_TYPE_VECTOR) {
- code += ", " + field.name + " ? 0 : ";
+ code += ", " + field.name + " ? ";
code += "_fbb.CreateVector<";
code += GenTypeWire(field.value.type.VectorType(), "", false);
- code += ">(*" + field.name + ")";
- } else
+ code += ">(*" + field.name + ") : 0";
+ } else {
code += ", " + field.name;
+ }
}
}
code += ");\n}\n\n";
@@ -944,10 +1023,36 @@
if (parser_.opts.generate_object_based_api) {
// Generate a pre-declaration for a CreateX method that works with an
// unpacked C++ object.
- code += TableCreateSignature(struct_def) + ";\n\n";
+ code += TableCreateSignature(struct_def, true) + ";\n\n";
}
}
+ std::string GenUnpackVal(const Type &type, const std::string &val,
+ bool invector, const FieldDef &afield) {
+ switch (type.base_type) {
+ case BASE_TYPE_STRING:
+ return val + "->str()";
+ case BASE_TYPE_STRUCT:
+ if (IsStruct(type)) {
+ if (invector || afield.native_inline) {
+ return "*" + val;
+ } else {
+ return GenTypeNativePtr(WrapInNameSpace(*type.struct_def),
+ &afield, true) +
+ "(new " +
+ WrapInNameSpace(*type.struct_def) + "(*" + val + "))";
+ }
+ } else {
+ return GenTypeNativePtr(NativeName(WrapInNameSpace(
+ *type.struct_def)), &afield, true) +
+ "(" + val + "->UnPack(resolver))";
+ }
+ default:
+ return val;
+ break;
+ }
+ };
+
// Generate code for tables that needs to come after the regular definition.
void GenTablePost(StructDef &struct_def, std::string *code_ptr) {
std::string &code = *code_ptr;
@@ -955,6 +1060,7 @@
if (parser_.opts.generate_object_based_api) {
// Generate the UnPack() method.
code += "inline " + TableUnPackSignature(struct_def, false) + " {\n";
+ code += " (void)resolver;\n";
code += " auto _o = new " + NativeName(struct_def.name) + "();\n";
for (auto it = struct_def.fields.vec.begin();
it != struct_def.fields.vec.end(); ++it) {
@@ -965,40 +1071,21 @@
auto deref = "_o->";
auto dest = deref + field.name;
auto assign = prefix + dest + " = ";
- auto gen_unpack_val = [&](const Type &type, const std::string &val,
- bool invector) -> std::string {
- switch (type.base_type) {
- case BASE_TYPE_STRING:
- return val + "->str()";
- case BASE_TYPE_STRUCT:
- if (IsStruct(type)) {
- if (invector) {
- return "*" + val;
- } else {
- return "std::unique_ptr<" +
- WrapInNameSpace (*type.struct_def) +
- ">(new " +
- WrapInNameSpace (*type.struct_def) + "(*" + val + "))";
- }
- } else {
- return val + "->UnPack()";
- }
- default:
- return val;
- break;
- }
- };
switch (field.value.type.base_type) {
case BASE_TYPE_VECTOR: {
code += prefix;
code += "{ for (flatbuffers::uoffset_t _i = 0;";
code += " _i < _e->size(); _i++) { ";
code += dest + ".push_back(";
- std::string indexing = "_e->Get(_i)";
+ std::string indexing;
+ if (field.value.type.enum_def) {
+ indexing += "(" + field.value.type.enum_def->name + ")";
+ }
+ indexing += "_e->Get(_i)";
if (field.value.type.element == BASE_TYPE_BOOL)
indexing += "!=0";
- code += gen_unpack_val(field.value.type.VectorType(),
- indexing, true);
+ code += GenUnpackVal(field.value.type.VectorType(),
+ indexing, true, field);
code += "); } }";
break;
}
@@ -1008,25 +1095,43 @@
code += prefix + deref + union_field.name + ".type = _e;";
break;
}
- case BASE_TYPE_UNION:
+ case BASE_TYPE_UNION: {
code += prefix + dest + ".table = ";
code += field.value.type.enum_def->name;
code += "Union::UnPack(_e, ";
- code += field.name + UnionTypeFieldSuffix() + "());";
+ code += field.name + UnionTypeFieldSuffix() + "(), resolver);";
break;
- default:
- code += assign + gen_unpack_val(field.value.type, "_e", false);
+ }
+ default: {
+ auto cpp_type = field.attributes.Lookup("cpp_type");
+ if (cpp_type) {
+ code += prefix;
+ code += "if (resolver) (*resolver)(reinterpret_cast<void **>(&";
+ code += dest;
+ code += "), static_cast<flatbuffers::hash_value_t>(_e)); else ";
+ code += dest + " = nullptr";
+ } else {
+ code += assign;
+ code += GenUnpackVal(field.value.type, "_e", false, field);
+ }
code += ";";
break;
+ }
}
code += " };\n";
}
}
- code += " return std::unique_ptr<" + NativeName(struct_def.name);
- code += ">(_o);\n}\n\n";
+ code += " return _o;\n}\n\n";
+
+ // Generate the X::Pack member function that simply calls the global
+ // CreateX function.
+ code += "inline " + TablePackSignature(struct_def, false) + " {\n";
+ code += " return Create" + struct_def.name + "(_fbb, _o, _rehasher);\n";
+ code += "}\n\n";
// Generate a CreateX method that works with an unpacked C++ object.
- code += TableCreateSignature(struct_def) + " {\n";
+ code += TableCreateSignature(struct_def, false) + " {\n";
+ code += " (void)rehasher;\n";
auto before_return_statement = code.size();
code += " return Create";
code += struct_def.name + "(_fbb";
@@ -1043,6 +1148,10 @@
field_name += ".type";
}
auto accessor = "_o->" + field_name;
+ if (field.attributes.Lookup("cpp_type"))
+ accessor = "rehasher ? static_cast<" +
+ GenTypeBasic(field.value.type, false) +
+ ">((*rehasher)(" + accessor + ")) : 0";
auto ptrprefix = accessor + " ? ";
auto stlprefix = accessor + ".size() ? ";
auto postfix = " : 0";
@@ -1070,15 +1179,27 @@
code += "_fbb.CreateVectorOfStructs(" + accessor + ")";
} else {
code += "_fbb.CreateVector<flatbuffers::Offset<";
- code += vector_type.struct_def->name + ">>(" + accessor;
+ code += WrapInNameSpace(*vector_type.struct_def) + ">>(" +
+ accessor;
code += ".size(), [&](size_t i) { return Create";
code += vector_type.struct_def->name + "(_fbb, " + accessor;
- code += "[i].get()); })";
+ code += "[i]" + GenPtrGet(field) + ", rehasher); })";
}
break;
- default:
+ case BASE_TYPE_BOOL:
code += "_fbb.CreateVector(" + accessor + ")";
break;
+ default: {
+ std::string args = accessor;
+ if (field.value.type.enum_def) {
+ const std::string basetype = GenTypeBasic(
+ field.value.type.enum_def->underlying_type, false);
+ args = "(const " + basetype + "*)" + accessor +
+ ".data(), " + accessor + ".size()";
+ }
+ code += "_fbb.CreateVector(" + args + ")";
+ break;
+ }
}
code += postfix;
break;
@@ -1088,11 +1209,16 @@
break;
case BASE_TYPE_STRUCT:
if (IsStruct(field.value.type)) {
- code += ptrprefix + accessor + ".get()" + postfix;
+ if (field.native_inline) {
+ code += "&" + accessor;
+ } else {
+ code += ptrprefix + accessor + GenPtrGet(field) + postfix;
+ }
} else {
code += ptrprefix + "Create";
code += field.value.type.struct_def->name;
- code += "(_fbb, " + accessor + ".get())" + postfix;
+ code += "(_fbb, " + accessor + GenPtrGet(field) + ", rehasher)";
+ code += postfix;
}
break;
default:
diff --git a/src/idl_gen_general.cpp b/src/idl_gen_general.cpp
index 7e8e8c5..2d8d83c 100644
--- a/src/idl_gen_general.cpp
+++ b/src/idl_gen_general.cpp
@@ -76,24 +76,28 @@
IDLOptions::Language language;
// Whether function names in the language typically start with uppercase.
bool first_camel_upper;
- const char *file_extension;
- const char *string_type;
- const char *bool_type;
- const char *open_curly;
- const char *const_decl;
- const char *unsubclassable_decl;
- const char *enum_decl;
- const char *enum_separator;
- const char *getter_prefix;
- const char *getter_suffix;
- const char *inheritance_marker;
- const char *namespace_ident;
- const char *namespace_begin;
- const char *namespace_end;
- const char *set_bb_byteorder;
- const char *get_bb_position;
- const char *get_fbb_offset;
- const char *includes;
+ std::string file_extension;
+ std::string string_type;
+ std::string bool_type;
+ std::string open_curly;
+ std::string accessor_type;
+ std::string const_decl;
+ std::string unsubclassable_decl;
+ std::string enum_decl;
+ std::string enum_separator;
+ std::string getter_prefix;
+ std::string getter_suffix;
+ std::string inheritance_marker;
+ std::string namespace_ident;
+ std::string namespace_begin;
+ std::string namespace_end;
+ std::string set_bb_byteorder;
+ std::string get_bb_position;
+ std::string get_fbb_offset;
+ std::string accessor_prefix;
+ std::string accessor_prefix_static;
+ std::string optional_suffix;
+ std::string includes;
CommentConfig comment_config;
};
@@ -105,6 +109,7 @@
"String",
"boolean ",
" {\n",
+ "class ",
" final ",
"final ",
"final class ",
@@ -118,6 +123,9 @@
"_bb.order(ByteOrder.LITTLE_ENDIAN); ",
"position()",
"offset()",
+ "",
+ "",
+ "",
"import java.nio.*;\nimport java.lang.*;\nimport java.util.*;\n"
"import com.google.flatbuffers.*;\n\n@SuppressWarnings(\"unused\")\n",
{
@@ -133,8 +141,9 @@
"string",
"bool ",
"\n{\n",
+ "struct ",
" readonly ",
- "sealed ",
+ "",
"enum ",
",\n",
" { get",
@@ -146,6 +155,9 @@
"",
"Position",
"Offset",
+ "__p.",
+ "Table.",
+ "?",
"using System;\nusing FlatBuffers;\n\n",
{
nullptr,
@@ -162,6 +174,7 @@
"string",
"bool ",
"\n{\n",
+ "class ",
"const ",
" ",
"class ",
@@ -175,6 +188,9 @@
"",
"position()",
"offset()",
+ "",
+ "",
+ "",
"import (\n\tflatbuffers \"github.com/google/flatbuffers/go\"\n)",
{
nullptr,
@@ -194,17 +210,21 @@
GeneralGenerator(const Parser &parser, const std::string &path,
const std::string &file_name)
: BaseGenerator(parser, path, file_name, "", "."),
- lang_(language_parameters[parser_.opts.lang]) {
+ lang_(language_parameters[parser_.opts.lang]),
+ cur_name_space_( nullptr ) {
assert(parser_.opts.lang <= IDLOptions::kMAX);
};
GeneralGenerator &operator=(const GeneralGenerator &);
bool generate() {
std::string one_file_code;
+ cur_name_space_ = parser_.namespaces_.back();
for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
++it) {
std::string enumcode;
auto &enum_def = **it;
+ if (!parser_.opts.one_file)
+ cur_name_space_ = enum_def.defined_namespace;
GenEnum(enum_def, &enumcode);
if (parser_.opts.one_file) {
one_file_code += enumcode;
@@ -218,6 +238,8 @@
it != parser_.structs_.vec.end(); ++it) {
std::string declcode;
auto &struct_def = **it;
+ if (!parser_.opts.one_file)
+ cur_name_space_ = struct_def.defined_namespace;
GenStruct(struct_def, &declcode);
if (parser_.opts.one_file) {
one_file_code += declcode;
@@ -237,7 +259,7 @@
// Save out the generated code for a single class while adding
// declaration boilerplate.
bool SaveType(const std::string &defname, const Namespace &ns,
- const std::string &classcode, bool needs_includes) {
+ const std::string &classcode, bool needs_includes) {
if (!classcode.length()) return true;
std::string code;
@@ -254,7 +276,7 @@
return SaveFile(filename.c_str(), code, false);
}
- const Namespace *CurrentNameSpace() { return parser_.namespaces_.back(); }
+ const Namespace *CurrentNameSpace() { return cur_name_space_; }
std::string FunctionStart(char upper) {
return std::string() + (lang_.language == IDLOptions::kJava
@@ -343,7 +365,8 @@
const std::string &variable_name)
{
if(lang_.language == IDLOptions::kCSharp) {
- return "new Offset<" + WrapInNameSpace(struct_def) + ">(" + variable_name + ")";
+ return "new Offset<" + WrapInNameSpace(struct_def) + ">(" + variable_name +
+ ")";
}
return variable_name;
}
@@ -401,9 +424,11 @@
}
// Cast statements for mutator method parameters.
-// In Java, parameters representing unsigned numbers need to be cast down to their respective type.
-// For example, a long holding an unsigned int value would be cast down to int before being put onto the buffer.
-// In C#, one cast directly cast an Enum to its underlying type, which is essential before putting it onto the buffer.
+// In Java, parameters representing unsigned numbers need to be cast down to
+// their respective type. For example, a long holding an unsigned int value
+// would be cast down to int before being put onto the buffer. In C#, one cast
+// directly cast an Enum to its underlying type, which is essential before
+// putting it onto the buffer.
std::string SourceCast(const Type &type, bool castFromDest) {
if (type.base_type == BASE_TYPE_VECTOR) {
return SourceCast(type.VectorType(), castFromDest);
@@ -465,9 +490,21 @@
return GenEnumDefaultValue(value);
}
}
+
+ auto longSuffix = lang_.language == IDLOptions::kJava ? "L" : "";
switch (value.type.base_type) {
case BASE_TYPE_FLOAT: return value.constant + "f";
case BASE_TYPE_BOOL: return value.constant == "0" ? "false" : "true";
+ case BASE_TYPE_ULONG:
+ {
+ if (lang_.language != IDLOptions::kJava)
+ return value.constant;
+ // Converts the ulong into its bits signed equivalent
+ uint64_t defaultValue = StringToUInt(value.constant.c_str());
+ return NumToString(static_cast<int64_t>(defaultValue)) + longSuffix;
+ }
+ case BASE_TYPE_UINT:
+ case BASE_TYPE_LONG: return value.constant + longSuffix;
default: return value.constant;
}
}
@@ -484,7 +521,8 @@
case BASE_TYPE_STRING:
return "default(StringOffset)";
case BASE_TYPE_STRUCT:
- return "default(Offset<" + WrapInNameSpace(*value.type.struct_def) + ">)";
+ return "default(Offset<" + WrapInNameSpace(*value.type.struct_def) +
+ ">)";
case BASE_TYPE_VECTOR:
return "default(VectorOffset)";
default:
@@ -513,7 +551,8 @@
GenComment(enum_def.doc_comment, code_ptr, &lang_.comment_config);
code += std::string("public ") + lang_.enum_decl + enum_def.name;
if (lang_.language == IDLOptions::kCSharp) {
- code += lang_.inheritance_marker + GenTypeBasic(enum_def.underlying_type, false);
+ code += lang_.inheritance_marker +
+ GenTypeBasic(enum_def.underlying_type, false);
}
code += lang_.open_curly;
if (lang_.language == IDLOptions::kJava) {
@@ -578,12 +617,13 @@
// Returns the function name that is able to read a value of the given type.
std::string GenGetter(const Type &type) {
switch (type.base_type) {
- case BASE_TYPE_STRING: return "__string";
- case BASE_TYPE_STRUCT: return "__struct";
- case BASE_TYPE_UNION: return "__union";
+ case BASE_TYPE_STRING: return lang_.accessor_prefix + "__string";
+ case BASE_TYPE_STRUCT: return lang_.accessor_prefix + "__struct";
+ case BASE_TYPE_UNION: return lang_.accessor_prefix + "__union";
case BASE_TYPE_VECTOR: return GenGetter(type.VectorType());
default: {
- std::string getter = "bb." + FunctionStart('G') + "et";
+ std::string getter =
+ lang_.accessor_prefix + "bb." + FunctionStart('G') + "et";
if (type.base_type == BASE_TYPE_BOOL) {
getter = "0!=" + getter;
} else if (GenTypeBasic(type, false) != "byte") {
@@ -598,7 +638,8 @@
// Hence a setter method will only be generated for such fields.
std::string GenSetter(const Type &type) {
if (IsScalar(type.base_type)) {
- std::string setter = "bb." + FunctionStart('P') + "ut";
+ std::string setter =
+ lang_.accessor_prefix + "bb." + FunctionStart('P') + "ut";
if (GenTypeBasic(type, false) != "byte" &&
type.base_type != BASE_TYPE_BOOL) {
setter += MakeCamel(GenTypeBasic(type, false));
@@ -618,7 +659,8 @@
// Recursively generate arguments for a constructor, to deal with nested
// structs.
-void GenStructArgs(const StructDef &struct_def, std::string *code_ptr, const char *nameprefix) {
+void GenStructArgs(const StructDef &struct_def, std::string *code_ptr,
+ const char *nameprefix) {
std::string &code = *code_ptr;
for (auto it = struct_def.fields.vec.begin();
it != struct_def.fields.vec.end();
@@ -643,7 +685,8 @@
// Recusively generate struct construction statements of the form:
// builder.putType(name);
// and insert manual padding.
-void GenStructBody(const StructDef &struct_def, std::string *code_ptr, const char *nameprefix) {
+void GenStructBody(const StructDef &struct_def, std::string *code_ptr,
+ const char *nameprefix) {
std::string &code = *code_ptr;
code += " builder." + FunctionStart('P') + "rep(";
code += NumToString(struct_def.minalign) + ", ";
@@ -669,6 +712,90 @@
}
}
+std::string GenByteBufferLength(const char *bb_name) {
+ std::string bb_len = bb_name;
+ if (lang_.language == IDLOptions::kCSharp) bb_len += ".Length";
+ else bb_len += ".array().length";
+ return bb_len;
+}
+
+std::string GenOffsetGetter(flatbuffers::FieldDef *key_field,
+ const char *num = nullptr) {
+ std::string key_offset = "";
+ key_offset += lang_.accessor_prefix_static + "__offset(" +
+ NumToString(key_field->value.offset) + ", ";
+ if (num) {
+ key_offset += num;
+ key_offset += (lang_.language == IDLOptions::kCSharp ?
+ ".Value, builder.DataBuffer)" : ", _bb)");
+ } else {
+ key_offset += GenByteBufferLength("bb");
+ key_offset += " - tableOffset, bb)";
+ }
+ return key_offset;
+}
+
+std::string GenLookupKeyGetter(flatbuffers::FieldDef *key_field) {
+ std::string key_getter = " ";
+ key_getter += "int tableOffset = " + lang_.accessor_prefix_static;
+ key_getter += "__indirect(vectorLocation + 4 * (start + middle)";
+ key_getter += ", bb);\n ";
+ if (key_field->value.type.base_type == BASE_TYPE_STRING) {
+ key_getter += "int comp = " + lang_.accessor_prefix_static;
+ key_getter += FunctionStart('C') + "ompareStrings(";
+ key_getter += GenOffsetGetter(key_field);
+ key_getter += ", byteKey, bb);\n";
+ } else {
+ auto get_val = GenGetter(key_field->value.type) +
+ "(" + GenOffsetGetter(key_field) + ")";
+ if (lang_.language == IDLOptions::kCSharp) {
+ key_getter += "int comp = " + get_val + ".CompareTo(key);\n";
+ } else {
+ key_getter += GenTypeGet(key_field->value.type) + " val = ";
+ key_getter += get_val + ";\n";
+ key_getter += " int comp = val > key ? 1 : val < key ? -1 : 0;\n";
+ }
+ }
+ return key_getter;
+}
+
+
+std::string GenKeyGetter(flatbuffers::FieldDef *key_field) {
+ std::string key_getter = "";
+ auto data_buffer = (lang_.language == IDLOptions::kCSharp) ?
+ "builder.DataBuffer" : "_bb";
+ if (key_field->value.type.base_type == BASE_TYPE_STRING) {
+ if (lang_.language == IDLOptions::kJava)
+ key_getter += " return ";
+ key_getter += lang_.accessor_prefix_static;
+ key_getter += FunctionStart('C') + "ompareStrings(";
+ key_getter += GenOffsetGetter(key_field, "o1") + ", ";
+ key_getter += GenOffsetGetter(key_field, "o2") + ", " + data_buffer + ")";
+ if (lang_.language == IDLOptions::kJava)
+ key_getter += ";";
+ }
+ else {
+ auto field_getter = data_buffer + GenGetter(key_field->value.type).substr(2) +
+ "(" + GenOffsetGetter(key_field, "o1") + ")";
+ if (lang_.language == IDLOptions::kCSharp) {
+ key_getter += field_getter;
+ field_getter = data_buffer + GenGetter(key_field->value.type).substr(2) +
+ "(" + GenOffsetGetter(key_field, "o2") + ")";
+ key_getter += ".CompareTo(" + field_getter + ")";
+ }
+ else {
+ key_getter += "\n " + GenTypeGet(key_field->value.type) + " val_1 = ";
+ key_getter += field_getter + ";\n " + GenTypeGet(key_field->value.type);
+ key_getter += " val_2 = ";
+ field_getter = data_buffer + GenGetter(key_field->value.type).substr(2) +
+ "(" + GenOffsetGetter(key_field, "o2") + ")";
+ key_getter += field_getter + ";\n";
+ key_getter += " return val_1 > val_2 ? 1 : val_1 < val_2 ? -1 : 0;\n ";
+ }
+ }
+ return key_getter;
+}
+
void GenStruct(StructDef &struct_def, std::string *code_ptr) {
if (struct_def.generated) return;
std::string &code = *code_ptr;
@@ -685,18 +812,32 @@
struct_def.attributes.Lookup("csharp_partial")) {
// generate a partial class for this C# struct/table
code += "partial ";
- }
- else {
+ } else {
code += lang_.unsubclassable_decl;
}
- code += "class " + struct_def.name + lang_.inheritance_marker;
- code += struct_def.fixed ? "Struct" : "Table";
- code += " {\n";
+ code += lang_.accessor_type + struct_def.name;
+ if (lang_.language == IDLOptions::kCSharp) {
+ code += " : IFlatbufferObject";
+ code += lang_.open_curly;
+ code += " private ";
+ code += struct_def.fixed ? "Struct" : "Table";
+ code += " __p;\n";
+
+ if (lang_.language == IDLOptions::kCSharp) {
+ code += " public ByteBuffer ByteBuffer { get { return __p.bb; } }\n";
+ }
+
+ } else {
+ code += lang_.inheritance_marker;
+ code += struct_def.fixed ? "Struct" : "Table";
+ code += lang_.open_curly;
+ }
if (!struct_def.fixed) {
// Generate a special accessor for the table that when used as the root
// of a FlatBuffer
std::string method_name = FunctionStart('G') + "etRootAs" + struct_def.name;
- std::string method_signature = " public static " + struct_def.name + " " + method_name;
+ std::string method_signature = " public static " + struct_def.name + " " +
+ method_name;
// create convenience method that doesn't require an existing object
code += method_signature + "(ByteBuffer _bb) ";
@@ -705,8 +846,7 @@
// create method that allows object reuse
code += method_signature + "(ByteBuffer _bb, " + struct_def.name + " obj) { ";
code += lang_.set_bb_byteorder;
- code += "return (obj.__init(_bb." + FunctionStart('G');
- code += "etInt(_bb.";
+ code += "return (obj.__assign(_bb." + FunctionStart('G') + "etInt(_bb.";
code += lang_.get_bb_position;
code += ") + _bb.";
code += lang_.get_bb_position;
@@ -717,16 +857,19 @@
code += " public static ";
code += lang_.bool_type + struct_def.name;
code += "BufferHasIdentifier(ByteBuffer _bb) { return ";
- code += "__has_identifier(_bb, \"" + parser_.file_identifier_;
+ code += lang_.accessor_prefix_static + "__has_identifier(_bb, \"";
+ code += parser_.file_identifier_;
code += "\"); }\n";
}
}
}
// Generate the __init method that sets the field in a pre-existing
// accessor object. This is to allow object reuse.
- code += " public " + struct_def.name;
- code += " __init(int _i, ByteBuffer _bb) ";
- code += "{ bb_pos = _i; bb = _bb; return this; }\n\n";
+ code += " public void __init(int _i, ByteBuffer _bb) ";
+ code += "{ " + lang_.accessor_prefix + "bb_pos = _i; ";
+ code += lang_.accessor_prefix + "bb = _bb; }\n";
+ code += " public " + struct_def.name + " __assign(int _i, ByteBuffer _bb) ";
+ code += "{ __init(_i, _bb); return this; }\n\n";
for (auto it = struct_def.fields.vec.begin();
it != struct_def.fields.vec.end();
++it) {
@@ -735,28 +878,35 @@
GenComment(field.doc_comment, code_ptr, &lang_.comment_config, " ");
std::string type_name = GenTypeGet(field.value.type);
std::string type_name_dest = GenTypeNameDest(field.value.type);
+ std::string conditional_cast = "";
+ std::string optional = "";
+ if (lang_.language == IDLOptions::kCSharp &&
+ !struct_def.fixed &&
+ (field.value.type.base_type == BASE_TYPE_STRUCT ||
+ field.value.type.base_type == BASE_TYPE_UNION ||
+ (field.value.type.base_type == BASE_TYPE_VECTOR &&
+ field.value.type.element == BASE_TYPE_STRUCT))) {
+ optional = lang_.optional_suffix;
+ conditional_cast = "(" + type_name_dest + optional + ")";
+ }
std::string dest_mask = DestinationMask(field.value.type, true);
std::string dest_cast = DestinationCast(field.value.type);
std::string src_cast = SourceCast(field.value.type);
- std::string method_start = " public " + type_name_dest + " " +
+ std::string method_start = " public " + type_name_dest + optional + " " +
MakeCamel(field.name, lang_.first_camel_upper);
+ std::string obj = lang_.language == IDLOptions::kCSharp
+ ? "(new " + type_name + "())"
+ : "obj";
// Most field accessors need to retrieve and test the field offset first,
// this is the prefix code for that:
- auto offset_prefix = " { int o = __offset(" +
- NumToString(field.value.offset) +
- "); return o != 0 ? ";
+ auto offset_prefix = " { int o = " + lang_.accessor_prefix + "__offset(" +
+ NumToString(field.value.offset) +
+ "); return o != 0 ? ";
// Generate the accessors that don't do object reuse.
if (field.value.type.base_type == BASE_TYPE_STRUCT) {
// Calls the accessor that takes an accessor object with a new object.
- if (lang_.language == IDLOptions::kCSharp) {
- code += method_start + " { get { return Get";
- code += MakeCamel(field.name, lang_.first_camel_upper);
- code += "(new ";
- code += type_name + "()); } }\n";
- method_start = " public " + type_name_dest + " Get" + MakeCamel(field.name, lang_.first_camel_upper);
- }
- else {
+ if (lang_.language != IDLOptions::kCSharp) {
code += method_start + "() { return ";
code += MakeCamel(field.name, lang_.first_camel_upper);
code += "(new ";
@@ -766,24 +916,16 @@
field.value.type.element == BASE_TYPE_STRUCT) {
// Accessors for vectors of structs also take accessor objects, this
// generates a variant without that argument.
- if (lang_.language == IDLOptions::kCSharp) {
- method_start = " public " + type_name_dest + " Get" + MakeCamel(field.name, lang_.first_camel_upper);
- code += method_start + "(int j) { return Get";
- } else {
+ if (lang_.language != IDLOptions::kCSharp) {
code += method_start + "(int j) { return ";
- }
- code += MakeCamel(field.name, lang_.first_camel_upper);
- code += "(new ";
- code += type_name + "(), j); }\n";
- } else if (field.value.type.base_type == BASE_TYPE_VECTOR) {
- if (lang_.language == IDLOptions::kCSharp) {
- method_start = " public " + type_name_dest + " Get" + MakeCamel(field.name, lang_.first_camel_upper);
+ code += MakeCamel(field.name, lang_.first_camel_upper);
+ code += "(new " + type_name + "(), j); }\n";
}
} else if (field.value.type.base_type == BASE_TYPE_UNION) {
if (lang_.language == IDLOptions::kCSharp) {
- // union types in C# use generic Table-derived type for better type safety
- method_start = " public " + type_name_dest + " Get" + MakeCamel(field.name, lang_.first_camel_upper) + "<TTable>";
- offset_prefix = " where TTable : Table" + offset_prefix;
+ // Union types in C# use generic Table-derived type for better type
+ // safety.
+ method_start += "<TTable>";
type_name = type_name_dest;
}
}
@@ -793,64 +935,78 @@
// only create default casts for c# scalars or vectors of scalars
if (lang_.language == IDLOptions::kCSharp &&
(IsScalar(field.value.type.base_type) ||
- (field.value.type.base_type == BASE_TYPE_VECTOR && IsScalar(field.value.type.element)))) {
- // For scalars, default value will be returned by GetDefaultValue(). If the scalar is an enum, GetDefaultValue()
- // returns an actual c# enum that doesn't need to be casted. However, default values for enum elements of
- // vectors are integer literals ("0") and are still casted for clarity.
- if (field.value.type.enum_def == nullptr || field.value.type.base_type == BASE_TYPE_VECTOR) {
+ (field.value.type.base_type == BASE_TYPE_VECTOR &&
+ IsScalar(field.value.type.element)))) {
+ // For scalars, default value will be returned by GetDefaultValue().
+ // If the scalar is an enum, GetDefaultValue() returns an actual c# enum
+ // that doesn't need to be casted. However, default values for enum
+ // elements of vectors are integer literals ("0") and are still casted
+ // for clarity.
+ if (field.value.type.enum_def == nullptr ||
+ field.value.type.base_type == BASE_TYPE_VECTOR) {
default_cast = "(" + type_name_dest + ")";
}
}
- std::string member_suffix = "";
+ std::string member_suffix = "; ";
if (IsScalar(field.value.type.base_type)) {
code += lang_.getter_prefix;
- member_suffix = lang_.getter_suffix;
+ member_suffix += lang_.getter_suffix;
if (struct_def.fixed) {
code += " { return " + getter;
- code += "(bb_pos + " + NumToString(field.value.offset) + ")";
+ code += "(" + lang_.accessor_prefix + "bb_pos + ";
+ code += NumToString(field.value.offset) + ")";
code += dest_mask;
} else {
code += offset_prefix + getter;
- code += "(o + bb_pos)" + dest_mask + " : " + default_cast;
+ code += "(o + " + lang_.accessor_prefix + "bb_pos)" + dest_mask;
+ code += " : " + default_cast;
code += GenDefaultValue(field.value);
}
} else {
switch (field.value.type.base_type) {
case BASE_TYPE_STRUCT:
- code += "(" + type_name + " obj";
- if (struct_def.fixed) {
- code += ") { return obj.__init(bb_pos + ";
- code += NumToString(field.value.offset) + ", bb)";
+ if (lang_.language != IDLOptions::kCSharp) {
+ code += "(" + type_name + " obj" + ")";
} else {
- code += ")";
- code += offset_prefix;
- code += "obj.__init(";
+ code += lang_.getter_prefix;
+ member_suffix += lang_.getter_suffix;
+ }
+ if (struct_def.fixed) {
+ code += " { return " + obj + ".__assign(" + lang_.accessor_prefix;
+ code += "bb_pos + " + NumToString(field.value.offset) + ", ";
+ code += lang_.accessor_prefix + "bb)";
+ } else {
+ code += offset_prefix + conditional_cast;
+ code += obj + ".__assign(";
code += field.value.type.struct_def->fixed
- ? "o + bb_pos"
- : "__indirect(o + bb_pos)";
- code += ", bb) : null";
+ ? "o + " + lang_.accessor_prefix + "bb_pos"
+ : lang_.accessor_prefix + "__indirect(o + " +
+ lang_.accessor_prefix + "bb_pos)";
+ code += ", " + lang_.accessor_prefix + "bb) : null";
}
break;
case BASE_TYPE_STRING:
code += lang_.getter_prefix;
- member_suffix = lang_.getter_suffix;
- code += offset_prefix + getter + "(o + bb_pos) : null";
+ member_suffix += lang_.getter_suffix;
+ code += offset_prefix + getter + "(o + " + lang_.accessor_prefix;
+ code += "bb_pos) : null";
break;
case BASE_TYPE_VECTOR: {
auto vectortype = field.value.type.VectorType();
code += "(";
if (vectortype.base_type == BASE_TYPE_STRUCT) {
- code += type_name + " obj, ";
- getter = "obj.__init";
+ if (lang_.language != IDLOptions::kCSharp)
+ code += type_name + " obj, ";
+ getter = obj + ".__assign";
}
- code += "int j)" + offset_prefix + getter +"(";
- auto index = "__vector(o) + j * " +
+ code += "int j)" + offset_prefix + conditional_cast + getter +"(";
+ auto index = lang_.accessor_prefix + "__vector(o) + j * " +
NumToString(InlineSize(vectortype));
if (vectortype.base_type == BASE_TYPE_STRUCT) {
code += vectortype.struct_def->fixed
? index
- : "__indirect(" + index + ")";
- code += ", bb";
+ : lang_.accessor_prefix + "__indirect(" + index + ")";
+ code += ", " + lang_.accessor_prefix + "bb";
} else {
code += index;
}
@@ -861,14 +1017,19 @@
break;
}
case BASE_TYPE_UNION:
- code += "(" + type_name + " obj)" + offset_prefix + getter;
- code += "(obj, o) : null";
+ if (lang_.language == IDLOptions::kCSharp) {
+ code += "() where TTable : struct, IFlatbufferObject";
+ code += offset_prefix + "(TTable?)" + getter;
+ code += "<TTable>(o) : null";
+ } else {
+ code += "(" + type_name + " obj)" + offset_prefix + getter;
+ code += "(obj, o) : null";
+ }
break;
default:
assert(0);
}
}
- code += "; ";
code += member_suffix;
code += "}\n";
if (field.value.type.base_type == BASE_TYPE_VECTOR) {
@@ -876,7 +1037,7 @@
code += "Length";
code += lang_.getter_prefix;
code += offset_prefix;
- code += "__vector_len(o) : 0; ";
+ code += lang_.accessor_prefix + "__vector_len(o) : 0; ";
code += lang_.getter_suffix;
code += "}\n";
}
@@ -888,16 +1049,19 @@
case IDLOptions::kJava:
code += " public ByteBuffer ";
code += MakeCamel(field.name, lang_.first_camel_upper);
- code += "AsByteBuffer() { return __vector_as_bytebuffer(";
+ code += "AsByteBuffer() { return ";
+ code += lang_.accessor_prefix + "__vector_as_bytebuffer(";
code += NumToString(field.value.offset) + ", ";
- code += NumToString(field.value.type.base_type == BASE_TYPE_STRING ? 1 :
- InlineSize(field.value.type.VectorType()));
+ code += NumToString(field.value.type.base_type == BASE_TYPE_STRING
+ ? 1
+ : InlineSize(field.value.type.VectorType()));
code += "); }\n";
break;
case IDLOptions::kCSharp:
code += " public ArraySegment<byte>? Get";
code += MakeCamel(field.name, lang_.first_camel_upper);
- code += "Bytes() { return __vector_as_arraysegment(";
+ code += "Bytes() { return ";
+ code += lang_.accessor_prefix + "__vector_as_arraysegment(";
code += NumToString(field.value.offset);
code += "); }\n";
break;
@@ -917,30 +1081,49 @@
auto getNestedMethodName = nestedMethodName;
if (lang_.language == IDLOptions::kCSharp) {
getNestedMethodName = "Get" + nestedMethodName;
+ conditional_cast = "(" + nested_type_name + lang_.optional_suffix + ")";
}
- code += " public " + nested_type_name + " ";
- code += nestedMethodName + "() { return ";
- code += getNestedMethodName + "(new " + nested_type_name + "()); }\n";
- code += " public " + nested_type_name + " " + getNestedMethodName;
- code += "(" + nested_type_name + " obj) { ";
- code += "int o = __offset(" + NumToString(field.value.offset) +"); ";
- code += "return o != 0 ? obj.__init(__indirect(__vector(o)), bb) : null; }\n";
+ if (lang_.language != IDLOptions::kCSharp) {
+ code += " public " + nested_type_name + lang_.optional_suffix + " ";
+ code += nestedMethodName + "() { return ";
+ code += getNestedMethodName + "(new " + nested_type_name + "()); }\n";
+ } else {
+ obj = "(new " + nested_type_name + "())";
+ }
+ code += " public " + nested_type_name + lang_.optional_suffix + " ";
+ code += getNestedMethodName + "(";
+ if (lang_.language != IDLOptions::kCSharp)
+ code += nested_type_name + " obj";
+ code += ") { int o = " + lang_.accessor_prefix + "__offset(";
+ code += NumToString(field.value.offset) +"); ";
+ code += "return o != 0 ? " + conditional_cast + obj + ".__assign(";
+ code += lang_.accessor_prefix;
+ code += "__indirect(" + lang_.accessor_prefix + "__vector(o)), ";
+ code += lang_.accessor_prefix + "bb) : null; }\n";
}
- // generate mutators for scalar fields or vectors of scalars
+ // Generate mutators for scalar fields or vectors of scalars.
if (parser_.opts.mutable_buffer) {
auto underlying_type = field.value.type.base_type == BASE_TYPE_VECTOR
? field.value.type.VectorType()
: field.value.type;
- // boolean parameters have to be explicitly converted to byte representation
- auto setter_parameter = underlying_type.base_type == BASE_TYPE_BOOL ? "(byte)(" + field.name + " ? 1 : 0)" : field.name;
+ // Boolean parameters have to be explicitly converted to byte
+ // representation.
+ auto setter_parameter = underlying_type.base_type == BASE_TYPE_BOOL
+ ? "(byte)(" + field.name + " ? 1 : 0)"
+ : field.name;
auto mutator_prefix = MakeCamel("mutate", lang_.first_camel_upper);
- //a vector mutator also needs the index of the vector element it should mutate
- auto mutator_params = (field.value.type.base_type == BASE_TYPE_VECTOR ? "(int j, " : "(") +
- GenTypeNameDest(underlying_type) + " " +
- field.name + ") { ";
+ // A vector mutator also needs the index of the vector element it should
+ // mutate.
+ auto mutator_params = (field.value.type.base_type == BASE_TYPE_VECTOR
+ ? "(int j, "
+ : "(") + GenTypeNameDest(underlying_type) + " " + field.name + ") { ";
auto setter_index = field.value.type.base_type == BASE_TYPE_VECTOR
- ? "__vector(o) + j * " + NumToString(InlineSize(underlying_type))
- : (struct_def.fixed ? "bb_pos + " + NumToString(field.value.offset) : "o + bb_pos");
+ ? lang_.accessor_prefix + "__vector(o) + j * " +
+ NumToString(InlineSize(underlying_type))
+ : (struct_def.fixed
+ ? lang_.accessor_prefix + "bb_pos + " +
+ NumToString(field.value.offset)
+ : "o + " + lang_.accessor_prefix + "bb_pos");
if (IsScalar(field.value.type.base_type) ||
(field.value.type.base_type == BASE_TYPE_VECTOR &&
IsScalar(field.value.type.VectorType().base_type))) {
@@ -952,14 +1135,17 @@
code += GenSetter(underlying_type) + "(" + setter_index + ", ";
code += src_cast + setter_parameter + "); }\n";
} else {
- code += "int o = __offset(" + NumToString(field.value.offset) + ");";
+ code += "int o = " + lang_.accessor_prefix + "__offset(";
+ code += NumToString(field.value.offset) + ");";
code += " if (o != 0) { " + GenSetter(underlying_type);
- code += "(" + setter_index + ", " + src_cast + setter_parameter + "); return true; } else { return false; } }\n";
+ code += "(" + setter_index + ", " + src_cast + setter_parameter +
+ "); return true; } else { return false; } }\n";
}
}
}
}
code += "\n";
+ flatbuffers::FieldDef *key_field = nullptr;
if (struct_def.fixed) {
// create a struct constructor function
code += " public static " + GenOffsetType(struct_def) + " ";
@@ -969,7 +1155,8 @@
code += ") {\n";
GenStructBody(struct_def, code_ptr, "");
code += " return ";
- code += GenOffsetConstruct(struct_def, "builder." + std::string(lang_.get_fbb_offset));
+ code += GenOffsetConstruct(struct_def,
+ "builder." + std::string(lang_.get_fbb_offset));
code += ";\n }\n";
} else {
// Generate a method that creates a table in one go. This is only possible
@@ -1048,6 +1235,7 @@
it != struct_def.fields.vec.end(); ++it) {
auto &field = **it;
if (field.deprecated) continue;
+ if (field.key) key_field = &field;
code += " public static void " + FunctionStart('A') + "dd";
code += MakeCamel(field.name);
code += "(FlatBufferBuilder builder, ";
@@ -1059,10 +1247,15 @@
code += NumToString(it - struct_def.fields.vec.begin()) + ", ";
code += SourceCastBasic(field.value.type);
code += argname;
- if(!IsScalar(field.value.type.base_type) && field.value.type.base_type != BASE_TYPE_UNION && lang_.language == IDLOptions::kCSharp) {
+ if (!IsScalar(field.value.type.base_type) &&
+ field.value.type.base_type != BASE_TYPE_UNION &&
+ lang_.language == IDLOptions::kCSharp) {
code += ".Value";
}
- code += ", " + GenDefaultValue(field.value, false);
+ code += ", ";
+ if (lang_.language == IDLOptions::kJava)
+ code += SourceCastBasic( field.value.type );
+ code += GenDefaultValue(field.value, false);
code += "); }\n";
if (field.value.type.base_type == BASE_TYPE_VECTOR) {
auto vector_type = field.value.type.VectorType();
@@ -1070,7 +1263,8 @@
auto elem_size = InlineSize(vector_type);
if (!IsStruct(vector_type)) {
// Generate a method to create a vector from a Java array.
- code += " public static " + GenVectorOffsetType() + " " + FunctionStart('C') + "reate";
+ code += " public static " + GenVectorOffsetType() + " ";
+ code += FunctionStart('C') + "reate";
code += MakeCamel(field.name);
code += "Vector(FlatBufferBuilder builder, ";
code += GenTypeBasic(vector_type) + "[] data) ";
@@ -1086,7 +1280,8 @@
code += SourceCastBasic(vector_type, false);
code += "data[i]";
if (lang_.language == IDLOptions::kCSharp &&
- (vector_type.base_type == BASE_TYPE_STRUCT || vector_type.base_type == BASE_TYPE_STRING))
+ (vector_type.base_type == BASE_TYPE_STRUCT ||
+ vector_type.base_type == BASE_TYPE_STRING))
code += ".Value";
code += "); return ";
code += "builder." + FunctionStart('E') + "ndVector(); }\n";
@@ -1119,7 +1314,8 @@
if (parser_.root_struct_def_ == &struct_def) {
code += " public static void ";
code += FunctionStart('F') + "inish" + struct_def.name;
- code += "Buffer(FlatBufferBuilder builder, " + GenOffsetType(struct_def) + " offset) {";
+ code += "Buffer(FlatBufferBuilder builder, " + GenOffsetType(struct_def);
+ code += " offset) {";
code += " builder." + FunctionStart('F') + "inish(offset";
if (lang_.language == IDLOptions::kCSharp) {
code += ".Value";
@@ -1130,12 +1326,66 @@
code += "); }\n";
}
}
+ if (struct_def.has_key) {
+ if (lang_.language == IDLOptions::kJava) {
+ code += "\n @Override\n protected int keysCompare(";
+ code += "Integer o1, Integer o2, ByteBuffer _bb) {";
+ code += GenKeyGetter(key_field);
+ code += " }\n";
+ }
+ else {
+ code += "\n public static VectorOffset ";
+ code += "CreateMySortedVectorOfTables(FlatBufferBuilder builder, ";
+ code += "Offset<" + struct_def.name + ">";
+ code += "[] offsets) {\n";
+ code += " Array.Sort(offsets, (Offset<" + struct_def.name +
+ "> o1, Offset<" + struct_def.name + "> o2) => " + GenKeyGetter(key_field);
+ code += ");\n";
+ code += " return builder.CreateVectorOfTables(offsets);\n }\n";
+ }
+
+ code += "\n public static " + struct_def.name + lang_.optional_suffix;
+ code += " " + FunctionStart('L') + "ookupByKey(" + GenVectorOffsetType();
+ code += " vectorOffset, " + GenTypeGet(key_field->value.type);
+ code += " key, ByteBuffer bb) {\n";
+ if (key_field->value.type.base_type == BASE_TYPE_STRING) {
+ code += " byte[] byteKey = ";
+ if (lang_.language == IDLOptions::kJava)
+ code += "key.getBytes(Table.UTF8_CHARSET.get());\n";
+ else
+ code += "System.Text.Encoding.UTF8.GetBytes(key);\n";
+ }
+ code += " int vectorLocation = " + GenByteBufferLength("bb");
+ code += " - vectorOffset";
+ if (lang_.language == IDLOptions::kCSharp) code += ".Value";
+ code += ";\n int span = ";
+ code += "bb." + FunctionStart('G') + "etInt(vectorLocation);\n";
+ code += " int start = 0;\n";
+ code += " vectorLocation += 4;\n";
+ code += " while (span != 0) {\n";
+ code += " int middle = span / 2;\n";
+ code += GenLookupKeyGetter(key_field);
+ code += " if (comp > 0) {\n";
+ code += " span = middle;\n";
+ code += " } else if (comp < 0) {\n";
+ code += " middle++;\n";
+ code += " start += middle;\n";
+ code += " span -= middle;\n";
+ code += " } else {\n";
+ code += " return new " + struct_def.name;
+ code += "().__assign(tableOffset, bb);\n";
+ code += " }\n }\n";
+ code += " return null;\n";
+ code += " }\n";
+ }
code += "}";
// Java does not need the closing semi-colon on class definitions.
code += (lang_.language != IDLOptions::kJava) ? ";" : "";
code += "\n\n";
}
const LanguageParameters & lang_;
+ // This tracks the current namespace used to determine if a type need to be prefixed by its namespace
+ const Namespace *cur_name_space_;
};
} // namespace general
@@ -1157,8 +1407,7 @@
auto &enum_def = **it;
if (make_rule != "") make_rule += " ";
std::string directory =
- BaseGenerator::NamespaceDir(parser, path, *enum_def.defined_namespace) +
- kPathSeparator;
+ BaseGenerator::NamespaceDir(parser, path, *enum_def.defined_namespace);
make_rule += directory + enum_def.name + lang.file_extension;
}
@@ -1167,8 +1416,8 @@
auto &struct_def = **it;
if (make_rule != "") make_rule += " ";
std::string directory =
- BaseGenerator::NamespaceDir(parser, path, *struct_def.defined_namespace) +
- kPathSeparator;
+ BaseGenerator::NamespaceDir(parser, path,
+ *struct_def.defined_namespace);
make_rule += directory + struct_def.name + lang.file_extension;
}
diff --git a/src/idl_gen_go.cpp b/src/idl_gen_go.cpp
index 73f930f..dadb350 100644
--- a/src/idl_gen_go.cpp
+++ b/src/idl_gen_go.cpp
@@ -305,9 +305,6 @@
if (!(vectortype.struct_def->fixed)) {
code += "\t\tx = rcv._tab.Indirect(x)\n";
}
- code += "\t\tif obj == nil {\n";
- code += "\t\t\tobj = new(" + TypeName(field) + ")\n";
- code += "\t\t}\n";
code += "\t\tobj.Init(rcv._tab.Bytes, x)\n";
code += "\t\treturn true\n\t}\n";
code += "\treturn false\n";
diff --git a/src/idl_gen_grpc.cpp b/src/idl_gen_grpc.cpp
index 6ada3e8..a540b8b 100644
--- a/src/idl_gen_grpc.cpp
+++ b/src/idl_gen_grpc.cpp
@@ -19,12 +19,14 @@
#include "flatbuffers/flatbuffers.h"
#include "flatbuffers/idl.h"
#include "flatbuffers/util.h"
+#include "flatbuffers/code_generators.h"
#include "src/compiler/cpp_generator.h"
+#include "src/compiler/go_generator.h"
namespace flatbuffers {
-class FlatBufMethod : public grpc_cpp_generator::Method {
+class FlatBufMethod : public grpc_generator::Method {
public:
enum Streaming { kNone, kClient, kServer, kBiDi };
@@ -52,6 +54,14 @@
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 ClientOnlyStreaming() const { return streaming_ == kClient; }
bool ServerOnlyStreaming() const { return streaming_ == kServer; }
@@ -62,7 +72,7 @@
Streaming streaming_;
};
-class FlatBufService : public grpc_cpp_generator::Service {
+class FlatBufService : public grpc_generator::Service {
public:
FlatBufService(const ServiceDef *service) : service_(service) {}
@@ -72,8 +82,8 @@
return static_cast<int>(service_->calls.vec.size());
};
- std::unique_ptr<const grpc_cpp_generator::Method> method(int i) const {
- return std::unique_ptr<const grpc_cpp_generator::Method>(
+ std::unique_ptr<const grpc_generator::Method> method(int i) const {
+ return std::unique_ptr<const grpc_generator::Method>(
new FlatBufMethod(service_->calls.vec[i]));
};
@@ -81,7 +91,7 @@
const ServiceDef *service_;
};
-class FlatBufPrinter : public grpc_cpp_generator::Printer {
+class FlatBufPrinter : public grpc_generator::Printer {
public:
FlatBufPrinter(std::string *str)
: str_(str), escape_char_('$'), indent_(0) {}
@@ -133,7 +143,7 @@
int indent_;
};
-class FlatBufFile : public grpc_cpp_generator::File {
+class FlatBufFile : public grpc_generator::File {
public:
FlatBufFile(const Parser &parser, const std::string &file_name)
: parser_(parser), file_name_(file_name) {}
@@ -159,17 +169,21 @@
return "#include \"flatbuffers/grpc.h\"\n";
}
+ std::string additional_imports() const {
+ return "import \"github.com/google/flatbuffers/go\"";
+ }
+
int service_count() const {
return static_cast<int>(parser_.services_.vec.size());
};
- std::unique_ptr<const grpc_cpp_generator::Service> service(int i) const {
- return std::unique_ptr<const grpc_cpp_generator::Service> (
+ std::unique_ptr<const grpc_generator::Service> service(int i) const {
+ return std::unique_ptr<const grpc_generator::Service> (
new FlatBufService(parser_.services_.vec[i]));
}
- std::unique_ptr<grpc_cpp_generator::Printer> CreatePrinter(std::string *str) const {
- return std::unique_ptr<grpc_cpp_generator::Printer>(
+ std::unique_ptr<grpc_generator::Printer> CreatePrinter(std::string *str) const {
+ return std::unique_ptr<grpc_generator::Printer>(
new FlatBufPrinter(str));
}
@@ -178,7 +192,47 @@
const std::string &file_name_;
};
-bool GenerateGRPC(const Parser &parser,
+class GoGRPCGenerator : public flatbuffers::BaseGenerator {
+ public:
+ GoGRPCGenerator(const Parser &parser, const std::string &path,
+ const std::string &file_name)
+ : BaseGenerator(parser, path, file_name, "", "" /*Unused*/),
+ parser_(parser), path_(path), file_name_(file_name) {}
+
+ bool generate() {
+ FlatBufFile file(parser_, file_name_);
+ grpc_go_generator::Parameters p;
+ p.custom_method_io_type = "flatbuffers.Builder";
+ for (int i = 0; i < file.service_count(); i++) {
+ auto service = file.service(i);
+ const Definition *def = parser_.services_.vec[i];
+ p.package_name = LastNamespacePart(*(def->defined_namespace));
+ std::string output = grpc_go_generator::GenerateServiceSource(&file, service.get(), &p);
+ std::string filename = NamespaceDir(*def->defined_namespace) + def->name + "_grpc.go";
+ if (!flatbuffers::SaveFile(filename.c_str(), output, false))
+ return false;
+ }
+ return true;
+ }
+
+ protected:
+ const Parser &parser_;
+ const std::string &path_, &file_name_;
+};
+
+bool GenerateGoGRPC(const Parser &parser,
+ const std::string &path,
+ const std::string &file_name) {
+ int nservices = 0;
+ for (auto it = parser.services_.vec.begin();
+ it != parser.services_.vec.end(); ++it) {
+ if (!(*it)->generated) nservices++;
+ }
+ if (!nservices) return true;
+ return GoGRPCGenerator(parser, path, file_name).generate();
+}
+
+bool GenerateCppGRPC(const Parser &parser,
const std::string &/*path*/,
const std::string &file_name) {
diff --git a/src/idl_gen_js.cpp b/src/idl_gen_js.cpp
index fec5780..32c660c 100644
--- a/src/idl_gen_js.cpp
+++ b/src/idl_gen_js.cpp
@@ -557,13 +557,13 @@
"@returns {boolean}");
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 += " var offset = this.bb.__offset(this.bb_pos, " + NumToString(field.value.offset) + ");\n\n";
code += " if (offset === 0) {\n";
code += " return false;\n";
code += " }\n\n";
code += " this.bb.write" + MakeCamel(GenType(field.value.type)) + "(this.bb_pos + offset, value);\n";
code += " return true;\n";
- code += "}\n\n";
+ code += "};\n\n";
}
// Emit vector helpers
@@ -581,7 +581,7 @@
code += object_name + ".prototype." + MakeCamel(field.name, false);
code += "Array = function() {\n" + offset_prefix;
code += "new " + GenType(vectorType) + "Array(this.bb.bytes().buffer, "
- "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";
}
}
diff --git a/src/idl_gen_php.cpp b/src/idl_gen_php.cpp
index af3b06d..a893f98 100644
--- a/src/idl_gen_php.cpp
+++ b/src/idl_gen_php.cpp
@@ -89,10 +89,10 @@
code += classcode;
std::string filename = NamespaceDir(*def.defined_namespace) +
- kPathSeparator + def.name + ".php";
+ def.name + ".php";
return SaveFile(filename.c_str(), code, false);
}
-
+
// Begin a class declaration.
static void BeginClass(const StructDef &struct_def, std::string *code_ptr) {
std::string &code = *code_ptr;
@@ -955,7 +955,7 @@
code += Indent + Indent + "return $builder->offset();\n";
code += Indent + "}\n";
}
-
+
};
} // namespace php
diff --git a/src/idl_gen_python.cpp b/src/idl_gen_python.cpp
index 52944bf..76fea3e 100644
--- a/src/idl_gen_python.cpp
+++ b/src/idl_gen_python.cpp
@@ -655,7 +655,7 @@
BeginFile(LastNamespacePart(*def.defined_namespace), needs_imports, &code);
code += classcode;
std::string filename = NamespaceDir(*def.defined_namespace) +
- kPathSeparator + def.name + ".py";
+ def.name + ".py";
return SaveFile(filename.c_str(), code, false);
}
};
diff --git a/src/idl_gen_text.cpp b/src/idl_gen_text.cpp
index 3e41a0a..17cd987 100644
--- a/src/idl_gen_text.cpp
+++ b/src/idl_gen_text.cpp
@@ -22,7 +22,7 @@
namespace flatbuffers {
-static void GenStruct(const StructDef &struct_def, const Table *table,
+static bool GenStruct(const StructDef &struct_def, const Table *table,
int indent, const IDLOptions &opts,
std::string *_text);
@@ -48,7 +48,7 @@
// Print (and its template specialization below for pointers) generate text
// for a single FlatBuffer value into JSON format.
// The general case for scalars:
-template<typename T> void Print(T val, Type type, int /*indent*/,
+template<typename T> bool Print(T val, Type type, int /*indent*/,
StructDef * /*union_sd*/,
const IDLOptions &opts,
std::string *_text) {
@@ -57,7 +57,7 @@
auto enum_val = type.enum_def->ReverseLookup(static_cast<int>(val));
if (enum_val) {
OutputIdentifier(enum_val->name, opts, _text);
- return;
+ return true;
}
}
@@ -66,10 +66,12 @@
} else {
text += NumToString(val);
}
+
+ return true;
}
// Print a vector a sequence of JSON values, comma separated, wrapped in "[]".
-template<typename T> void PrintVector(const Vector<T> &v, Type type,
+template<typename T> bool PrintVector(const Vector<T> &v, Type type,
int indent, const IDLOptions &opts,
std::string *_text) {
std::string &text = *_text;
@@ -81,19 +83,25 @@
text += NewLine(opts);
}
text.append(indent + Indent(opts), ' ');
- if (IsStruct(type))
- Print(v.GetStructFromOffset(i * type.struct_def->bytesize), type,
- indent + Indent(opts), nullptr, opts, _text);
- else
- Print(v[i], type, indent + Indent(opts), nullptr,
- opts, _text);
+ if (IsStruct(type)) {
+ if (!Print(v.GetStructFromOffset(i * type.struct_def->bytesize), type,
+ indent + Indent(opts), nullptr, opts, _text)) {
+ return false;
+ }
+ } else {
+ if (!Print(v[i], type, indent + Indent(opts), nullptr,
+ opts, _text)) {
+ return false;
+ }
+ }
}
text += NewLine(opts);
text.append(indent, ' ');
text += "]";
+ return true;
}
-static void EscapeString(const String &s, std::string *_text, const IDLOptions& opts) {
+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++) {
@@ -118,9 +126,19 @@
text += "\\x";
text += IntToStringHex(static_cast<uint8_t>(c), 2);
} else {
- // We previously checked for non-UTF-8 and returned a parse error,
- // so we shouldn't reach here.
- assert(0);
+ // 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) {
@@ -130,12 +148,12 @@
} else if (ucc <= 0x10FFFF) {
// Encode Unicode SMP values to a surrogate pair using two \u escapes.
uint32_t base = ucc - 0x10000;
- uint16_t highSurrogate = (base >> 10) + 0xD800;
- uint16_t lowSurrogate = (base & 0x03FF) + 0xDC00;
+ auto high_surrogate = (base >> 10) + 0xD800;
+ auto low_surrogate = (base & 0x03FF) + 0xDC00;
text += "\\u";
- text += IntToStringHex(highSurrogate, 4);
+ text += IntToStringHex(high_surrogate, 4);
text += "\\u";
- text += IntToStringHex(lowSurrogate, 4);
+ text += IntToStringHex(low_surrogate, 4);
}
// Skip past characters recognized.
i = static_cast<uoffset_t>(utf8 - s.c_str() - 1);
@@ -145,10 +163,11 @@
}
}
text += "\"";
+ return true;
}
// Specialization of Print above for pointer types.
-template<> void Print<const void *>(const void *val,
+template<> bool Print<const void *>(const void *val,
Type type, int indent,
StructDef *union_sd,
const IDLOptions &opts,
@@ -158,21 +177,27 @@
// If this assert hits, you have an corrupt buffer, a union type field
// was not present or was out of range.
assert(union_sd);
- GenStruct(*union_sd,
- reinterpret_cast<const Table *>(val),
- indent,
- opts,
- _text);
+ if (!GenStruct(*union_sd,
+ reinterpret_cast<const Table *>(val),
+ indent,
+ opts,
+ _text)) {
+ return false;
+ }
break;
case BASE_TYPE_STRUCT:
- GenStruct(*type.struct_def,
- reinterpret_cast<const Table *>(val),
- indent,
- opts,
- _text);
+ if (!GenStruct(*type.struct_def,
+ reinterpret_cast<const Table *>(val),
+ indent,
+ opts,
+ _text)) {
+ return false;
+ }
break;
case BASE_TYPE_STRING: {
- EscapeString(*reinterpret_cast<const String *>(val), _text, opts);
+ if (!EscapeString(*reinterpret_cast<const String *>(val), _text, opts)) {
+ return false;
+ }
break;
}
case BASE_TYPE_VECTOR:
@@ -182,31 +207,35 @@
#define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, \
PTYPE) \
case BASE_TYPE_ ## ENUM: \
- PrintVector<CTYPE>( \
- *reinterpret_cast<const Vector<CTYPE> *>(val), \
- type, indent, opts, _text); break;
+ if (!PrintVector<CTYPE>( \
+ *reinterpret_cast<const Vector<CTYPE> *>(val), \
+ type, indent, opts, _text)) { \
+ return false; \
+ } \
+ break;
FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
#undef FLATBUFFERS_TD
}
break;
default: assert(0);
}
+ return true;
}
// Generate text for a scalar field.
-template<typename T> static void GenField(const FieldDef &fd,
+template<typename T> static bool GenField(const FieldDef &fd,
const Table *table, bool fixed,
const IDLOptions &opts,
int indent,
std::string *_text) {
- Print(fixed ?
+ return Print(fixed ?
reinterpret_cast<const Struct *>(table)->GetField<T>(fd.value.offset) :
table->GetField<T>(fd.value.offset, 0), fd.value.type, indent, nullptr,
opts, _text);
}
// Generate text for non-scalar field.
-static void 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,
const IDLOptions &opts, std::string *_text) {
const void *val = nullptr;
@@ -220,12 +249,12 @@
? table->GetStruct<const void *>(fd.value.offset)
: table->GetPointer<const void *>(fd.value.offset);
}
- Print(val, fd.value.type, indent, union_sd, opts, _text);
+ return Print(val, fd.value.type, indent, union_sd, opts, _text);
}
// Generate text for a struct or table, values separated by commas, indented,
// and bracketed by "{}"
-static void GenStruct(const StructDef &struct_def, const Table *table,
+static bool GenStruct(const StructDef &struct_def, const Table *table,
int indent, const IDLOptions &opts,
std::string *_text) {
std::string &text = *_text;
@@ -253,8 +282,10 @@
#define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, \
PTYPE) \
case BASE_TYPE_ ## ENUM: \
- GenField<CTYPE>(fd, table, struct_def.fixed, \
- opts, indent + Indent(opts), _text); \
+ if (!GenField<CTYPE>(fd, table, struct_def.fixed, \
+ opts, indent + Indent(opts), _text)) { \
+ return false; \
+ } \
break;
FLATBUFFERS_GEN_TYPES_SCALAR(FLATBUFFERS_TD)
#undef FLATBUFFERS_TD
@@ -264,8 +295,10 @@
case BASE_TYPE_ ## ENUM:
FLATBUFFERS_GEN_TYPES_POINTER(FLATBUFFERS_TD)
#undef FLATBUFFERS_TD
- GenFieldOffset(fd, table, struct_def.fixed, indent + Indent(opts),
- union_sd, opts, _text);
+ if (!GenFieldOffset(fd, table, struct_def.fixed, indent + Indent(opts),
+ union_sd, opts, _text)) {
+ return false;
+ }
break;
}
if (fd.value.type.base_type == BASE_TYPE_UTYPE) {
@@ -284,20 +317,24 @@
text += NewLine(opts);
text.append(indent, ' ');
text += "}";
+ return true;
}
// Generate a text representation of a flatbuffer in JSON format.
-void GenerateText(const Parser &parser, const void *flatbuffer,
+bool GenerateText(const Parser &parser, const void *flatbuffer,
std::string *_text) {
std::string &text = *_text;
assert(parser.root_struct_def_); // call SetRootType()
text.reserve(1024); // Reduce amount of inevitable reallocs.
- GenStruct(*parser.root_struct_def_,
- GetRoot<Table>(flatbuffer),
- 0,
- parser.opts,
- _text);
+ if (!GenStruct(*parser.root_struct_def_,
+ GetRoot<Table>(flatbuffer),
+ 0,
+ parser.opts,
+ _text)) {
+ return false;
+ }
text += NewLine(parser.opts);
+ return true;
}
std::string TextFileName(const std::string &path,
@@ -310,7 +347,9 @@
const std::string &file_name) {
if (!parser.builder_.GetSize() || !parser.root_struct_def_) return true;
std::string text;
- GenerateText(parser, parser.builder_.GetBufferPointer(), &text);
+ if (!GenerateText(parser, parser.builder_.GetBufferPointer(), &text)) {
+ return false;
+ }
return flatbuffers::SaveFile(TextFileName(path, file_name).c_str(),
text,
false);
diff --git a/src/idl_parser.cpp b/src/idl_parser.cpp
index d845b83..ef6e1f5 100644
--- a/src/idl_parser.cpp
+++ b/src/idl_parser.cpp
@@ -219,7 +219,7 @@
return Error("escape code must be followed by " + NumToString(nibbles) +
" hex digits");
std::string target(cursor_, cursor_ + nibbles);
- *val = StringToUInt(target.c_str(), 16);
+ *val = StringToUInt(target.c_str(), nullptr, 16);
cursor_ += nibbles;
return NoError();
}
@@ -352,6 +352,7 @@
cursor_++;
// TODO: make nested.
while (*cursor_ != '*' || cursor_[1] != '/') {
+ if (*cursor_ == '\n') line_++;
if (!*cursor_) return Error("end of file in comment");
cursor_++;
}
@@ -447,7 +448,7 @@
cursor_++;
while (isxdigit(static_cast<unsigned char>(*cursor_))) cursor_++;
attribute_.append(start + 2, cursor_);
- attribute_ = NumToString(StringToUInt(attribute_.c_str(), 16));
+ attribute_ = NumToString(StringToUInt(attribute_.c_str(), nullptr, 16));
token_ = kTokenIntegerConstant;
return NoError();
}
@@ -657,6 +658,11 @@
"only int, uint, long and ulong data types support hashing.");
}
}
+ auto cpp_type = field->attributes.Lookup("cpp_type");
+ if (cpp_type) {
+ if (!hash_name)
+ return Error("cpp_type can only be used with a hashed field");
+ }
if (field->deprecated && struct_def.fixed)
return Error("can't deprecate fields in a struct");
field->required = field->attributes.Lookup("required") != nullptr;
@@ -674,6 +680,11 @@
return Error("'key' field must be string or scalar type");
}
}
+
+ field->native_inline = field->attributes.Lookup("native_inline") != nullptr;
+ if (field->native_inline && !IsStruct(field->value.type))
+ return Error("native_inline can only be defined on structs'");
+
auto nested = field->attributes.Lookup("nested_flatbuffer");
if (nested) {
if (nested->type.base_type != BASE_TYPE_STRING)
@@ -1093,10 +1104,15 @@
NEXT();
} else { // Numeric constant in string.
if (IsInteger(e.type.base_type)) {
- // TODO(wvo): do we want to check for garbage after the number?
- e.constant = NumToString(StringToInt(attribute_.c_str()));
+ char *end;
+ e.constant = NumToString(StringToInt(attribute_.c_str(), &end));
+ if (*end)
+ return Error("invalid integer: " + attribute_);
} else if (IsFloat(e.type.base_type)) {
- e.constant = NumToString(strtod(attribute_.c_str(), nullptr));
+ char *end;
+ e.constant = NumToString(strtod(attribute_.c_str(), &end));
+ if (*end)
+ return Error("invalid float: " + attribute_);
} else {
assert(0); // Shouldn't happen, we covered all types.
e.constant = "0";
@@ -1341,10 +1357,11 @@
auto align = static_cast<size_t>(atoi(force_align->constant.c_str()));
if (force_align->type.base_type != BASE_TYPE_INT ||
align < struct_def->minalign ||
- align > 16 ||
+ align > FLATBUFFERS_MAX_ALIGNMENT ||
align & (align - 1))
return Error("force_align must be a power of two integer ranging from the"
- "struct\'s natural alignment to 16");
+ "struct\'s natural alignment to " +
+ NumToString(FLATBUFFERS_MAX_ALIGNMENT));
struct_def->minalign = align;
}
struct_def->PadLastField(struct_def->minalign);
@@ -1977,7 +1994,8 @@
// Schema serialization functionality:
template<typename T> bool compareName(const T* a, const T* b) {
- return a->name < b->name;
+ return a->defined_namespace->GetFullyQualifiedName(a->name)
+ < b->defined_namespace->GetFullyQualifiedName(b->name);
}
template<typename T> void AssignIndices(const std::vector<T *> &defvec) {
@@ -2023,8 +2041,9 @@
(*it)->Serialize(builder,
static_cast<uint16_t>(it - fields.vec.begin()), parser));
}
+ auto qualified_name = defined_namespace->GetFullyQualifiedName(name);
return reflection::CreateObject(*builder,
- builder->CreateString(name),
+ builder->CreateString(qualified_name),
builder->CreateVectorOfSortedTables(
&field_offsets),
fixed,
@@ -2061,8 +2080,9 @@
for (auto it = vals.vec.begin(); it != vals.vec.end(); ++it) {
enumval_offsets.push_back((*it)->Serialize(builder));
}
+ auto qualified_name = defined_namespace->GetFullyQualifiedName(name);
return reflection::CreateEnum(*builder,
- builder->CreateString(name),
+ builder->CreateString(qualified_name),
builder->CreateVector(enumval_offsets),
is_union,
underlying_type.Serialize(builder),
diff --git a/src/reflection.cpp b/src/reflection.cpp
index 8f2fc69..e5f45dc 100644
--- a/src/reflection.cpp
+++ b/src/reflection.cpp
@@ -180,7 +180,8 @@
// Check if the range between first (lower address) and second straddles
// the insertion point. If it does, change the offset at offsetloc (of
// type T, with direction D).
- template<typename T, int D> void Straddle(void *first, void *second,
+ template<typename T, int D> void Straddle(const void *first,
+ const void *second,
void *offsetloc) {
if (first <= startptr_ && second >= startptr_) {
WriteScalar<T>(offsetloc, ReadScalar<T>(offsetloc) + delta_ * D);
@@ -194,9 +195,9 @@
// resize actually happens.
// This must be checked for every offset, since we can't know which offsets
// will straddle and which won't.
- uint8_t &DagCheck(void *offsetloc) {
- auto dag_idx = reinterpret_cast<uoffset_t *>(offsetloc) -
- reinterpret_cast<uoffset_t *>(buf_.data());
+ uint8_t &DagCheck(const void *offsetloc) {
+ auto dag_idx = reinterpret_cast<const uoffset_t *>(offsetloc) -
+ reinterpret_cast<const uoffset_t *>(buf_.data());
return dag_check_[dag_idx];
}
diff --git a/tests/FlatBuffers.Test/ByteBufferTests.cs b/tests/FlatBuffers.Test/ByteBufferTests.cs
index b86c365..3324f12 100644
--- a/tests/FlatBuffers.Test/ByteBufferTests.cs
+++ b/tests/FlatBuffers.Test/ByteBufferTests.cs
@@ -40,6 +40,7 @@
Assert.AreEqual((byte)99, buffer[0]);
}
+#if !BYTEBUFFER_NO_BOUNDS_CHECK
[FlatBuffersTestMethod]
public void ByteBuffer_PutByteCannotPutAtOffsetPastLength()
{
@@ -47,6 +48,7 @@
var uut = new ByteBuffer(buffer);
Assert.Throws<ArgumentOutOfRangeException>(() => uut.PutByte(1, 99));
}
+#endif
[FlatBuffersTestMethod]
public void ByteBuffer_PutShortPopulatesBufferCorrectly()
@@ -60,6 +62,7 @@
Assert.AreEqual((byte)0, buffer[1]);
}
+#if !BYTEBUFFER_NO_BOUNDS_CHECK
[FlatBuffersTestMethod]
public void ByteBuffer_PutShortCannotPutAtOffsetPastLength()
{
@@ -67,7 +70,9 @@
var uut = new ByteBuffer(buffer);
Assert.Throws<ArgumentOutOfRangeException>(() => uut.PutShort(2, 99));
}
+#endif
+#if !BYTEBUFFER_NO_BOUNDS_CHECK
[FlatBuffersTestMethod]
public void ByteBuffer_PutShortChecksLength()
{
@@ -83,6 +88,7 @@
var uut = new ByteBuffer(buffer);
Assert.Throws<ArgumentOutOfRangeException>(() => uut.PutShort(1, 99));
}
+#endif
[FlatBuffersTestMethod]
public void ByteBuffer_PutIntPopulatesBufferCorrectly()
@@ -98,6 +104,7 @@
Assert.AreEqual(0x0A, buffer[3]);
}
+ #if !BYTEBUFFER_NO_BOUNDS_CHECK
[FlatBuffersTestMethod]
public void ByteBuffer_PutIntCannotPutAtOffsetPastLength()
{
@@ -121,6 +128,7 @@
var uut = new ByteBuffer(buffer);
Assert.Throws<ArgumentOutOfRangeException>(() => uut.PutInt(2, 0x0A0B0C0D));
}
+#endif
[FlatBuffersTestMethod]
public void ByteBuffer_PutLongPopulatesBufferCorrectly()
@@ -140,6 +148,7 @@
Assert.AreEqual(0x01, buffer[7]);
}
+#if !BYTEBUFFER_NO_BOUNDS_CHECK
[FlatBuffersTestMethod]
public void ByteBuffer_PutLongCannotPutAtOffsetPastLength()
{
@@ -163,6 +172,7 @@
var uut = new ByteBuffer(buffer);
Assert.Throws<ArgumentOutOfRangeException>(() => uut.PutLong(2, 0x010203040A0B0C0D));
}
+#endif
[FlatBuffersTestMethod]
public void ByteBuffer_GetByteReturnsCorrectData()
@@ -173,6 +183,7 @@
Assert.AreEqual((byte)99, uut.Get(0));
}
+#if !BYTEBUFFER_NO_BOUNDS_CHECK
[FlatBuffersTestMethod]
public void ByteBuffer_GetByteChecksOffset()
{
@@ -180,6 +191,7 @@
var uut = new ByteBuffer(buffer);
Assert.Throws<ArgumentOutOfRangeException>(()=>uut.Get(1));
}
+#endif
[FlatBuffersTestMethod]
public void ByteBuffer_GetShortReturnsCorrectData()
@@ -191,6 +203,7 @@
Assert.AreEqual(1, uut.GetShort(0));
}
+#if !BYTEBUFFER_NO_BOUNDS_CHECK
[FlatBuffersTestMethod]
public void ByteBuffer_GetShortChecksOffset()
{
@@ -206,6 +219,7 @@
var uut = new ByteBuffer(buffer);
Assert.Throws<ArgumentOutOfRangeException>(() => uut.GetShort(1));
}
+#endif
[FlatBuffersTestMethod]
public void ByteBuffer_GetIntReturnsCorrectData()
@@ -219,6 +233,7 @@
Assert.AreEqual(0x0A0B0C0D, uut.GetInt(0));
}
+#if !BYTEBUFFER_NO_BOUNDS_CHECK
[FlatBuffersTestMethod]
public void ByteBuffer_GetIntChecksOffset()
{
@@ -234,6 +249,7 @@
var uut = new ByteBuffer(buffer);
Assert.Throws<ArgumentOutOfRangeException>(() => uut.GetInt(0));
}
+#endif
[FlatBuffersTestMethod]
public void ByteBuffer_GetLongReturnsCorrectData()
@@ -251,6 +267,7 @@
Assert.AreEqual(0x010203040A0B0C0D, uut.GetLong(0));
}
+#if !BYTEBUFFER_NO_BOUNDS_CHECK
[FlatBuffersTestMethod]
public void ByteBuffer_GetLongChecksOffset()
{
@@ -266,6 +283,7 @@
var uut = new ByteBuffer(buffer);
Assert.Throws<ArgumentOutOfRangeException>(() => uut.GetLong(0));
}
+#endif
[FlatBuffersTestMethod]
public void ByteBuffer_ReverseBytesUshort()
diff --git a/tests/FlatBuffers.Test/FlatBuffers.Test.csproj b/tests/FlatBuffers.Test/FlatBuffers.Test.csproj
index cc7c5cf..6e76b07 100644
--- a/tests/FlatBuffers.Test/FlatBuffers.Test.csproj
+++ b/tests/FlatBuffers.Test/FlatBuffers.Test.csproj
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
+<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
@@ -41,6 +41,9 @@
<Compile Include="..\..\net\FlatBuffers\ByteBuffer.cs">
<Link>FlatBuffers\ByteBuffer.cs</Link>
</Compile>
+ <Compile Include="..\..\net\FlatBuffers\IFlatbufferObject.cs">
+ <Link>FlatBuffers\IFlatbufferObject.cs</Link>
+ </Compile>
<Compile Include="..\..\net\FlatBuffers\Offset.cs">
<Link>FlatBuffers\Offset.cs</Link>
</Compile>
@@ -116,4 +119,4 @@
<Target Name="AfterBuild">
</Target>
-->
-</Project>
\ No newline at end of file
+</Project>
diff --git a/tests/FlatBuffers.Test/FlatBuffersExampleTests.cs b/tests/FlatBuffers.Test/FlatBuffersExampleTests.cs
index 80791dd..d032d7e 100644
--- a/tests/FlatBuffers.Test/FlatBuffersExampleTests.cs
+++ b/tests/FlatBuffers.Test/FlatBuffersExampleTests.cs
@@ -39,6 +39,19 @@
// better for performance.
var fbb = new FlatBufferBuilder(1);
+ StringOffset[] names = { fbb.CreateString("Frodo"), fbb.CreateString("Barney"), fbb.CreateString("Wilma") };
+ Offset<Monster>[] off = new Offset<Monster>[3];
+ Monster.StartMonster(fbb);
+ Monster.AddName(fbb, names[0]);
+ off[0] = Monster.EndMonster(fbb);
+ Monster.StartMonster(fbb);
+ Monster.AddName(fbb, names[1]);
+ off[1] = Monster.EndMonster(fbb);
+ Monster.StartMonster(fbb);
+ Monster.AddName(fbb, names[2]);
+ off[2] = Monster.EndMonster(fbb);
+ var sortMons = Monster.CreateMySortedVectorOfTables(fbb, off);
+
// We set up the same values as monsterdata.json:
var str = fbb.CreateString("MyMonster");
@@ -79,6 +92,7 @@
Monster.AddTest4(fbb, test4);
Monster.AddTestarrayofstring(fbb, testArrayOfString);
Monster.AddTestbool(fbb, false);
+ Monster.AddTestarrayoftables(fbb, sortMons);
var mon = Monster.EndMonster(fbb);
Monster.FinishMonsterBuffer(fbb, mon);
@@ -103,6 +117,16 @@
Assert.AreEqual(monster.MutateMana((short)10), false);
Assert.AreEqual(monster.Mana, (short)150);
+ // Accessing a vector of sorted by the key tables
+ Assert.AreEqual(monster.Testarrayoftables(0).Value.Name, "Barney");
+ Assert.AreEqual(monster.Testarrayoftables(1).Value.Name, "Frodo");
+ Assert.AreEqual(monster.Testarrayoftables(2).Value.Name, "Wilma");
+
+ // Example of searching for a table by the key
+ Assert.IsTrue(Monster.LookupByKey(sortMons, "Frodo", fbb.DataBuffer) != null);
+ Assert.IsTrue(Monster.LookupByKey(sortMons, "Barney", fbb.DataBuffer) != null);
+ Assert.IsTrue(Monster.LookupByKey(sortMons, "Wilma", fbb.DataBuffer)!= null);
+
// testType is an existing field and mutating it should succeed
Assert.AreEqual(monster.TestType, Any.Monster);
Assert.AreEqual(monster.MutateTestType(Any.NONE), true);
@@ -119,7 +143,7 @@
for (int i = 0; i < monster.InventoryLength; i++)
{
- Assert.AreEqual(monster.GetInventory(i), i + 1);
+ Assert.AreEqual(monster.Inventory(i), i + 1);
}
//reverse mutation
@@ -130,7 +154,7 @@
Assert.AreEqual(monster.MutateInventory(4, 4), true);
// get a struct field and edit one of its fields
- Vec3 pos = monster.Pos;
+ Vec3 pos = (Vec3)monster.Pos;
Assert.AreEqual(pos.X, 1.0f);
pos.MutateX(55.0f);
Assert.AreEqual(pos.X, 55.0f);
@@ -148,21 +172,20 @@
Assert.AreEqual(150, monster.Mana);
Assert.AreEqual("MyMonster", monster.Name);
- var pos = monster.Pos;
+ var pos = monster.Pos.Value;
Assert.AreEqual(1.0f, pos.X);
Assert.AreEqual(2.0f, pos.Y);
Assert.AreEqual(3.0f, pos.Z);
Assert.AreEqual(3.0f, pos.Test1);
Assert.AreEqual(Color.Green, pos.Test2);
- var t = pos.Test3;
+ var t = (MyGame.Example.Test)pos.Test3;
Assert.AreEqual((short)5, t.A);
Assert.AreEqual((sbyte)6, t.B);
Assert.AreEqual(Any.Monster, monster.TestType);
- var monster2 = new Monster();
- Assert.IsTrue(monster.GetTest(monster2) != null);
+ var monster2 = monster.Test<Monster>().Value;
Assert.AreEqual("Fred", monster2.Name);
@@ -170,19 +193,19 @@
var invsum = 0;
for (var i = 0; i < monster.InventoryLength; i++)
{
- invsum += monster.GetInventory(i);
+ invsum += monster.Inventory(i);
}
Assert.AreEqual(10, invsum);
- var test0 = monster.GetTest4(0);
- var test1 = monster.GetTest4(1);
+ var test0 = monster.Test4(0).Value;
+ var test1 = monster.Test4(1).Value;
Assert.AreEqual(2, monster.Test4Length);
Assert.AreEqual(100, test0.A + test0.B + test1.A + test1.B);
Assert.AreEqual(2, monster.TestarrayofstringLength);
- Assert.AreEqual("test1", monster.GetTestarrayofstring(0));
- Assert.AreEqual("test2", monster.GetTestarrayofstring(1));
+ Assert.AreEqual("test1", monster.Testarrayofstring(0));
+ Assert.AreEqual("test2", monster.Testarrayofstring(1));
Assert.AreEqual(false, monster.Testbool);
@@ -245,10 +268,10 @@
Monster.AddTestnestedflatbuffer(fbb2, nestedBuffer);
var monster = Monster.EndMonster(fbb2);
Monster.FinishMonsterBuffer(fbb2, monster);
-
+
// Now test the data extracted from the nested buffer
var mons = Monster.GetRootAsMonster(fbb2.DataBuffer);
- var nestedMonster = mons.TestnestedflatbufferAsMonster();
+ var nestedMonster = mons.GetTestnestedflatbufferAsMonster().Value;
Assert.AreEqual(nestedMonsterMana, nestedMonster.Mana);
Assert.AreEqual(nestedMonsterHp, nestedMonster.Hp);
diff --git a/tests/FlatBuffers.Test/TestTable.cs b/tests/FlatBuffers.Test/TestTable.cs
index c51237b..2b506b6 100644
--- a/tests/FlatBuffers.Test/TestTable.cs
+++ b/tests/FlatBuffers.Test/TestTable.cs
@@ -19,133 +19,135 @@
/// <summary>
/// A test Table object that gives easy access to the slot data
/// </summary>
- internal class TestTable : Table
+ internal struct TestTable
{
+ Table t;
+
public TestTable(ByteBuffer bb, int pos)
{
- base.bb = bb;
- base.bb_pos = pos;
+ t.bb = bb;
+ t.bb_pos = pos;
}
public bool GetSlot(int slot, bool def)
{
- var off = base.__offset(slot);
+ var off = t.__offset(slot);
if (off == 0)
{
return def;
}
- return bb.GetSbyte(bb_pos + off) != 0;
+ return t.bb.GetSbyte(t.bb_pos + off) != 0;
}
public sbyte GetSlot(int slot, sbyte def)
{
- var off = base.__offset(slot);
+ var off = t.__offset(slot);
if (off == 0)
{
return def;
}
- return bb.GetSbyte(bb_pos + off);
+ return t.bb.GetSbyte(t.bb_pos + off);
}
public byte GetSlot(int slot, byte def)
{
- var off = base.__offset(slot);
+ var off = t.__offset(slot);
if (off == 0)
{
return def;
}
- return bb.Get(bb_pos + off);
+ return t.bb.Get(t.bb_pos + off);
}
public short GetSlot(int slot, short def)
{
- var off = base.__offset(slot);
+ var off = t.__offset(slot);
if (off == 0)
{
return def;
}
- return bb.GetShort(bb_pos + off);
+ return t.bb.GetShort(t.bb_pos + off);
}
public ushort GetSlot(int slot, ushort def)
{
- var off = base.__offset(slot);
+ var off = t.__offset(slot);
if (off == 0)
{
return def;
}
- return bb.GetUshort(bb_pos + off);
+ return t.bb.GetUshort(t.bb_pos + off);
}
public int GetSlot(int slot, int def)
{
- var off = base.__offset(slot);
+ var off = t.__offset(slot);
if (off == 0)
{
return def;
}
- return bb.GetInt(bb_pos + off);
+ return t.bb.GetInt(t.bb_pos + off);
}
public uint GetSlot(int slot, uint def)
{
- var off = base.__offset(slot);
+ var off = t.__offset(slot);
if (off == 0)
{
return def;
}
- return bb.GetUint(bb_pos + off);
+ return t.bb.GetUint(t.bb_pos + off);
}
public long GetSlot(int slot, long def)
{
- var off = base.__offset(slot);
+ var off = t.__offset(slot);
if (off == 0)
{
return def;
}
- return bb.GetLong(bb_pos + off);
+ return t.bb.GetLong(t.bb_pos + off);
}
public ulong GetSlot(int slot, ulong def)
{
- var off = base.__offset(slot);
+ var off = t.__offset(slot);
if (off == 0)
{
return def;
}
- return bb.GetUlong(bb_pos + off);
+ return t.bb.GetUlong(t.bb_pos + off);
}
public float GetSlot(int slot, float def)
{
- var off = base.__offset(slot);
+ var off = t.__offset(slot);
if (off == 0)
{
return def;
}
- return bb.GetFloat(bb_pos + off);
+ return t.bb.GetFloat(t.bb_pos + off);
}
public double GetSlot(int slot, double def)
{
- var off = base.__offset(slot);
+ var off = t.__offset(slot);
if (off == 0)
{
return def;
}
- return bb.GetDouble(bb_pos + off);
+ return t.bb.GetDouble(t.bb_pos + off);
}
}
-}
\ No newline at end of file
+}
diff --git a/tests/JavaTest.java b/tests/JavaTest.java
index 154fdec..d53e973 100755
--- a/tests/JavaTest.java
+++ b/tests/JavaTest.java
@@ -51,6 +51,19 @@
// better for performance.
FlatBufferBuilder fbb = new FlatBufferBuilder(1);
+ int[] names = {fbb.createString("Frodo"), fbb.createString("Barney"), fbb.createString("Wilma")};
+ int[] off = new int[3];
+ Monster.startMonster(fbb);
+ Monster.addName(fbb, names[0]);
+ off[0] = Monster.endMonster(fbb);
+ Monster.startMonster(fbb);
+ Monster.addName(fbb, names[1]);
+ off[1] = Monster.endMonster(fbb);
+ Monster.startMonster(fbb);
+ Monster.addName(fbb, names[2]);
+ off[2] = Monster.endMonster(fbb);
+ int sortMons = fbb.createSortedVectorOfTables(new Monster(), off);
+
// We set up the same values as monsterdata.json:
int str = fbb.createString("MyMonster");
@@ -84,6 +97,7 @@
Monster.addTestarrayofstring(fbb, testArrayOfString);
Monster.addTestbool(fbb, false);
Monster.addTesthashu32Fnv1(fbb, Integer.MAX_VALUE + 1L);
+ Monster.addTestarrayoftables(fbb, sortMons);
int mon = Monster.endMonster(fbb);
Monster.finishMonsterBuffer(fbb, mon);
@@ -121,6 +135,16 @@
// the mana field should retain its default value
TestEq(monster.mutateMana((short)10), false);
TestEq(monster.mana(), (short)150);
+
+ // Accessing a vector of sorted by the key tables
+ TestEq(monster.testarrayoftables(0).name(), "Barney");
+ TestEq(monster.testarrayoftables(1).name(), "Frodo");
+ TestEq(monster.testarrayoftables(2).name(), "Wilma");
+
+ // Example of searching for a table by the key
+ TestEq(Monster.lookupByKey(sortMons, "Frodo", fbb.dataBuffer()).name(), "Frodo");
+ TestEq(Monster.lookupByKey(sortMons, "Barney", fbb.dataBuffer()).name(), "Barney");
+ TestEq(Monster.lookupByKey(sortMons, "Wilma", fbb.dataBuffer()).name(), "Wilma");
// testType is an existing field and mutating it should succeed
TestEq(monster.testType(), (byte)Any.Monster);
@@ -161,6 +185,10 @@
TestNestedFlatBuffer();
+ TestCreateByteVector();
+
+ TestCreateUninitializedVector();
+
System.out.println("FlatBuffers test: completed successfully");
}
@@ -281,6 +309,44 @@
TestEq(nestedMonsterName, nestedMonster.name());
}
+ static void TestCreateByteVector() {
+ FlatBufferBuilder fbb = new FlatBufferBuilder(16);
+ int str = fbb.createString("MyMonster");
+ byte[] inventory = new byte[] { 0, 1, 2, 3, 4 };
+ int vec = fbb.createByteVector(inventory);
+ Monster.startMonster(fbb);
+ Monster.addInventory(fbb, vec);
+ Monster.addName(fbb, str);
+ int monster1 = Monster.endMonster(fbb);
+ Monster.finishMonsterBuffer(fbb, monster1);
+ Monster monsterObject = Monster.getRootAsMonster(fbb.dataBuffer());
+
+ TestEq(monsterObject.inventory(1), (int)inventory[1]);
+ TestEq(monsterObject.inventoryLength(), inventory.length);
+ TestEq(ByteBuffer.wrap(inventory), monsterObject.inventoryAsByteBuffer());
+ }
+
+ static void TestCreateUninitializedVector() {
+ FlatBufferBuilder fbb = new FlatBufferBuilder(16);
+ int str = fbb.createString("MyMonster");
+ byte[] inventory = new byte[] { 0, 1, 2, 3, 4 };
+ ByteBuffer bb = fbb.createUnintializedVector(1, inventory.length, 1);
+ for (byte i:inventory) {
+ bb.put(i);
+ }
+ int vec = fbb.endVector();
+ Monster.startMonster(fbb);
+ Monster.addInventory(fbb, vec);
+ Monster.addName(fbb, str);
+ int monster1 = Monster.endMonster(fbb);
+ Monster.finishMonsterBuffer(fbb, monster1);
+ Monster monsterObject = Monster.getRootAsMonster(fbb.dataBuffer());
+
+ TestEq(monsterObject.inventory(1), (int)inventory[1]);
+ TestEq(monsterObject.inventoryLength(), inventory.length);
+ TestEq(ByteBuffer.wrap(inventory), monsterObject.inventoryAsByteBuffer());
+ }
+
static <T> void TestEq(T a, T b) {
if (!a.equals(b)) {
System.out.println("" + a.getClass().getName() + " " + b.getClass().getName());
diff --git a/tests/JavaTest.sh b/tests/JavaTest.sh
index 344bd1c..40e854b 100755
--- a/tests/JavaTest.sh
+++ b/tests/JavaTest.sh
@@ -1,4 +1,4 @@
-#!/bin/sh
+#!/bin/bash
#
# Copyright 2014 Google Inc. All rights reserved.
#
@@ -16,14 +16,29 @@
echo Compile then run the Java test.
+java -version
+
testdir=$(readlink -fn `dirname $0`)
thisdir=$(readlink -fn `pwd`)
+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
-javac -classpath ${testdir}/../java:${testdir}:${testdir}/namespace_test JavaTest.java
-java -classpath ${testdir}/../java:${testdir}:${testdir}/namespace_test JavaTest
+find .. -type f -name "*.class" -exec rm {} \;
+
+if [[ -e "${targetdir}" ]]; then
+ echo "clean target"
+ rm -rf ${targetdir}
+fi
+
+mkdir ${targetdir}
+
+javac -d ${targetdir} -classpath ${testdir}/../java:${testdir}:${testdir}/namespace_test JavaTest.java
+java -classpath ${targetdir} JavaTest
+
+rm -rf ${targetdir}
diff --git a/tests/MyGame/Example/Monster.cs b/tests/MyGame/Example/Monster.cs
index fdfd2b0..30f4922 100644
--- a/tests/MyGame/Example/Monster.cs
+++ b/tests/MyGame/Example/Monster.cs
@@ -7,79 +7,77 @@
using FlatBuffers;
/// an example documentation comment: monster object
-public sealed class Monster : Table {
+public struct Monster : IFlatbufferObject
+{
+ private Table __p;
+ public ByteBuffer ByteBuffer { get { return __p.bb; } }
public static Monster GetRootAsMonster(ByteBuffer _bb) { return GetRootAsMonster(_bb, new Monster()); }
- public static Monster GetRootAsMonster(ByteBuffer _bb, Monster obj) { return (obj.__init(_bb.GetInt(_bb.Position) + _bb.Position, _bb)); }
- public static bool MonsterBufferHasIdentifier(ByteBuffer _bb) { return __has_identifier(_bb, "MONS"); }
- public Monster __init(int _i, ByteBuffer _bb) { bb_pos = _i; bb = _bb; return this; }
+ public static Monster GetRootAsMonster(ByteBuffer _bb, Monster obj) { return (obj.__assign(_bb.GetInt(_bb.Position) + _bb.Position, _bb)); }
+ public static bool MonsterBufferHasIdentifier(ByteBuffer _bb) { return Table.__has_identifier(_bb, "MONS"); }
+ public void __init(int _i, ByteBuffer _bb) { __p.bb_pos = _i; __p.bb = _bb; }
+ public Monster __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; }
- public Vec3 Pos { get { return GetPos(new Vec3()); } }
- public Vec3 GetPos(Vec3 obj) { int o = __offset(4); return o != 0 ? obj.__init(o + bb_pos, bb) : null; }
- public short Mana { get { int o = __offset(6); return o != 0 ? bb.GetShort(o + bb_pos) : (short)150; } }
- public bool MutateMana(short mana) { int o = __offset(6); if (o != 0) { bb.PutShort(o + bb_pos, mana); return true; } else { return false; } }
- public short Hp { get { int o = __offset(8); return o != 0 ? bb.GetShort(o + bb_pos) : (short)100; } }
- public bool MutateHp(short hp) { int o = __offset(8); if (o != 0) { bb.PutShort(o + bb_pos, hp); return true; } else { return false; } }
- public string Name { get { int o = __offset(10); return o != 0 ? __string(o + bb_pos) : null; } }
- public ArraySegment<byte>? GetNameBytes() { return __vector_as_arraysegment(10); }
- public byte GetInventory(int j) { int o = __offset(14); return o != 0 ? bb.Get(__vector(o) + j * 1) : (byte)0; }
- public int InventoryLength { get { int o = __offset(14); return o != 0 ? __vector_len(o) : 0; } }
- public ArraySegment<byte>? GetInventoryBytes() { return __vector_as_arraysegment(14); }
- public bool MutateInventory(int j, byte inventory) { int o = __offset(14); if (o != 0) { bb.Put(__vector(o) + j * 1, inventory); return true; } else { return false; } }
- public Color Color { get { int o = __offset(16); return o != 0 ? (Color)bb.GetSbyte(o + bb_pos) : Color.Blue; } }
- public bool MutateColor(Color color) { int o = __offset(16); if (o != 0) { bb.PutSbyte(o + bb_pos, (sbyte)color); return true; } else { return false; } }
- public Any TestType { get { int o = __offset(18); return o != 0 ? (Any)bb.Get(o + bb_pos) : Any.NONE; } }
- public bool MutateTestType(Any test_type) { int o = __offset(18); if (o != 0) { bb.Put(o + bb_pos, (byte)test_type); return true; } else { return false; } }
- public TTable GetTest<TTable>(TTable obj) where TTable : Table { int o = __offset(20); return o != 0 ? __union(obj, o) : null; }
- public Test GetTest4(int j) { return GetTest4(new Test(), j); }
- public Test GetTest4(Test obj, int j) { int o = __offset(22); return o != 0 ? obj.__init(__vector(o) + j * 4, bb) : null; }
- public int Test4Length { get { int o = __offset(22); return o != 0 ? __vector_len(o) : 0; } }
- public string GetTestarrayofstring(int j) { int o = __offset(24); return o != 0 ? __string(__vector(o) + j * 4) : null; }
- public int TestarrayofstringLength { get { int o = __offset(24); return o != 0 ? __vector_len(o) : 0; } }
+ public Vec3? Pos { get { int o = __p.__offset(4); return o != 0 ? (Vec3?)(new Vec3()).__assign(o + __p.bb_pos, __p.bb) : null; } }
+ public short Mana { get { int o = __p.__offset(6); return o != 0 ? __p.bb.GetShort(o + __p.bb_pos) : (short)150; } }
+ public bool MutateMana(short mana) { int o = __p.__offset(6); if (o != 0) { __p.bb.PutShort(o + __p.bb_pos, mana); return true; } else { return false; } }
+ public short Hp { get { int o = __p.__offset(8); return o != 0 ? __p.bb.GetShort(o + __p.bb_pos) : (short)100; } }
+ public bool MutateHp(short hp) { int o = __p.__offset(8); if (o != 0) { __p.bb.PutShort(o + __p.bb_pos, hp); return true; } else { return false; } }
+ public string Name { get { int o = __p.__offset(10); return o != 0 ? __p.__string(o + __p.bb_pos) : null; } }
+ public ArraySegment<byte>? GetNameBytes() { return __p.__vector_as_arraysegment(10); }
+ public byte Inventory(int j) { int o = __p.__offset(14); return o != 0 ? __p.bb.Get(__p.__vector(o) + j * 1) : (byte)0; }
+ public int InventoryLength { get { int o = __p.__offset(14); return o != 0 ? __p.__vector_len(o) : 0; } }
+ public ArraySegment<byte>? GetInventoryBytes() { return __p.__vector_as_arraysegment(14); }
+ public bool MutateInventory(int j, byte inventory) { int o = __p.__offset(14); if (o != 0) { __p.bb.Put(__p.__vector(o) + j * 1, inventory); return true; } else { return false; } }
+ public Color Color { get { int o = __p.__offset(16); return o != 0 ? (Color)__p.bb.GetSbyte(o + __p.bb_pos) : Color.Blue; } }
+ public bool MutateColor(Color color) { int o = __p.__offset(16); if (o != 0) { __p.bb.PutSbyte(o + __p.bb_pos, (sbyte)color); return true; } else { return false; } }
+ public Any TestType { get { int o = __p.__offset(18); return o != 0 ? (Any)__p.bb.Get(o + __p.bb_pos) : Any.NONE; } }
+ public bool MutateTestType(Any test_type) { int o = __p.__offset(18); if (o != 0) { __p.bb.Put(o + __p.bb_pos, (byte)test_type); return true; } else { return false; } }
+ public TTable? Test<TTable>() where TTable : struct, IFlatbufferObject { int o = __p.__offset(20); return o != 0 ? (TTable?)__p.__union<TTable>(o) : null; }
+ public Test? Test4(int j) { int o = __p.__offset(22); return o != 0 ? (Test?)(new Test()).__assign(__p.__vector(o) + j * 4, __p.bb) : null; }
+ public int Test4Length { get { int o = __p.__offset(22); return o != 0 ? __p.__vector_len(o) : 0; } }
+ public string Testarrayofstring(int j) { int o = __p.__offset(24); return o != 0 ? __p.__string(__p.__vector(o) + j * 4) : null; }
+ public int TestarrayofstringLength { get { int o = __p.__offset(24); return o != 0 ? __p.__vector_len(o) : 0; } }
/// an example documentation comment: this will end up in the generated code
/// multiline too
- public Monster GetTestarrayoftables(int j) { return GetTestarrayoftables(new Monster(), j); }
- public Monster GetTestarrayoftables(Monster obj, int j) { int o = __offset(26); return o != 0 ? obj.__init(__indirect(__vector(o) + j * 4), bb) : null; }
- public int TestarrayoftablesLength { get { int o = __offset(26); return o != 0 ? __vector_len(o) : 0; } }
- public Monster Enemy { get { return GetEnemy(new Monster()); } }
- public Monster GetEnemy(Monster obj) { int o = __offset(28); return o != 0 ? obj.__init(__indirect(o + bb_pos), bb) : null; }
- public byte GetTestnestedflatbuffer(int j) { int o = __offset(30); return o != 0 ? bb.Get(__vector(o) + j * 1) : (byte)0; }
- public int TestnestedflatbufferLength { get { int o = __offset(30); return o != 0 ? __vector_len(o) : 0; } }
- public ArraySegment<byte>? GetTestnestedflatbufferBytes() { return __vector_as_arraysegment(30); }
- public Monster TestnestedflatbufferAsMonster() { return GetTestnestedflatbufferAsMonster(new Monster()); }
- public Monster GetTestnestedflatbufferAsMonster(Monster obj) { int o = __offset(30); return o != 0 ? obj.__init(__indirect(__vector(o)), bb) : null; }
- public bool MutateTestnestedflatbuffer(int j, byte testnestedflatbuffer) { int o = __offset(30); if (o != 0) { bb.Put(__vector(o) + j * 1, testnestedflatbuffer); return true; } else { return false; } }
- public Stat Testempty { get { return GetTestempty(new Stat()); } }
- public Stat GetTestempty(Stat obj) { int o = __offset(32); return o != 0 ? obj.__init(__indirect(o + bb_pos), bb) : null; }
- public bool Testbool { get { int o = __offset(34); return o != 0 ? 0!=bb.Get(o + bb_pos) : (bool)false; } }
- public bool MutateTestbool(bool testbool) { int o = __offset(34); if (o != 0) { bb.Put(o + bb_pos, (byte)(testbool ? 1 : 0)); return true; } else { return false; } }
- public int Testhashs32Fnv1 { get { int o = __offset(36); return o != 0 ? bb.GetInt(o + bb_pos) : (int)0; } }
- public bool MutateTesthashs32Fnv1(int testhashs32_fnv1) { int o = __offset(36); if (o != 0) { bb.PutInt(o + bb_pos, testhashs32_fnv1); return true; } else { return false; } }
- public uint Testhashu32Fnv1 { get { int o = __offset(38); return o != 0 ? bb.GetUint(o + bb_pos) : (uint)0; } }
- public bool MutateTesthashu32Fnv1(uint testhashu32_fnv1) { int o = __offset(38); if (o != 0) { bb.PutUint(o + bb_pos, testhashu32_fnv1); return true; } else { return false; } }
- public long Testhashs64Fnv1 { get { int o = __offset(40); return o != 0 ? bb.GetLong(o + bb_pos) : (long)0; } }
- public bool MutateTesthashs64Fnv1(long testhashs64_fnv1) { int o = __offset(40); if (o != 0) { bb.PutLong(o + bb_pos, testhashs64_fnv1); return true; } else { return false; } }
- public ulong Testhashu64Fnv1 { get { int o = __offset(42); return o != 0 ? bb.GetUlong(o + bb_pos) : (ulong)0; } }
- public bool MutateTesthashu64Fnv1(ulong testhashu64_fnv1) { int o = __offset(42); if (o != 0) { bb.PutUlong(o + bb_pos, testhashu64_fnv1); return true; } else { return false; } }
- public int Testhashs32Fnv1a { get { int o = __offset(44); return o != 0 ? bb.GetInt(o + bb_pos) : (int)0; } }
- public bool MutateTesthashs32Fnv1a(int testhashs32_fnv1a) { int o = __offset(44); if (o != 0) { bb.PutInt(o + bb_pos, testhashs32_fnv1a); return true; } else { return false; } }
- public uint Testhashu32Fnv1a { get { int o = __offset(46); return o != 0 ? bb.GetUint(o + bb_pos) : (uint)0; } }
- public bool MutateTesthashu32Fnv1a(uint testhashu32_fnv1a) { int o = __offset(46); if (o != 0) { bb.PutUint(o + bb_pos, testhashu32_fnv1a); return true; } else { return false; } }
- public long Testhashs64Fnv1a { get { int o = __offset(48); return o != 0 ? bb.GetLong(o + bb_pos) : (long)0; } }
- public bool MutateTesthashs64Fnv1a(long testhashs64_fnv1a) { int o = __offset(48); if (o != 0) { bb.PutLong(o + bb_pos, testhashs64_fnv1a); return true; } else { return false; } }
- public ulong Testhashu64Fnv1a { get { int o = __offset(50); return o != 0 ? bb.GetUlong(o + bb_pos) : (ulong)0; } }
- public bool MutateTesthashu64Fnv1a(ulong testhashu64_fnv1a) { int o = __offset(50); if (o != 0) { bb.PutUlong(o + bb_pos, testhashu64_fnv1a); return true; } else { return false; } }
- public bool GetTestarrayofbools(int j) { int o = __offset(52); return o != 0 ? 0!=bb.Get(__vector(o) + j * 1) : false; }
- public int TestarrayofboolsLength { get { int o = __offset(52); return o != 0 ? __vector_len(o) : 0; } }
- public ArraySegment<byte>? GetTestarrayofboolsBytes() { return __vector_as_arraysegment(52); }
- public bool MutateTestarrayofbools(int j, bool testarrayofbools) { int o = __offset(52); if (o != 0) { bb.Put(__vector(o) + j * 1, (byte)(testarrayofbools ? 1 : 0)); return true; } else { return false; } }
- public float Testf { get { int o = __offset(54); return o != 0 ? bb.GetFloat(o + bb_pos) : (float)3.14159f; } }
- public bool MutateTestf(float testf) { int o = __offset(54); if (o != 0) { bb.PutFloat(o + bb_pos, testf); return true; } else { return false; } }
- public float Testf2 { get { int o = __offset(56); return o != 0 ? bb.GetFloat(o + bb_pos) : (float)3.0f; } }
- public bool MutateTestf2(float testf2) { int o = __offset(56); if (o != 0) { bb.PutFloat(o + bb_pos, testf2); return true; } else { return false; } }
- public float Testf3 { get { int o = __offset(58); return o != 0 ? bb.GetFloat(o + bb_pos) : (float)0.0f; } }
- public bool MutateTestf3(float testf3) { int o = __offset(58); if (o != 0) { bb.PutFloat(o + bb_pos, testf3); return true; } else { return false; } }
- public string GetTestarrayofstring2(int j) { int o = __offset(60); return o != 0 ? __string(__vector(o) + j * 4) : null; }
- public int Testarrayofstring2Length { get { int o = __offset(60); return o != 0 ? __vector_len(o) : 0; } }
+ 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 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 int TestnestedflatbufferLength { get { int o = __p.__offset(30); return o != 0 ? __p.__vector_len(o) : 0; } }
+ public ArraySegment<byte>? GetTestnestedflatbufferBytes() { return __p.__vector_as_arraysegment(30); }
+ public Monster? GetTestnestedflatbufferAsMonster() { int o = __p.__offset(30); return o != 0 ? (Monster?)(new Monster()).__assign(__p.__indirect(__p.__vector(o)), __p.bb) : null; }
+ public bool MutateTestnestedflatbuffer(int j, byte testnestedflatbuffer) { int o = __p.__offset(30); if (o != 0) { __p.bb.Put(__p.__vector(o) + j * 1, testnestedflatbuffer); return true; } else { return false; } }
+ public Stat? Testempty { get { int o = __p.__offset(32); return o != 0 ? (Stat?)(new Stat()).__assign(__p.__indirect(o + __p.bb_pos), __p.bb) : null; } }
+ public bool Testbool { get { int o = __p.__offset(34); return o != 0 ? 0!=__p.bb.Get(o + __p.bb_pos) : (bool)false; } }
+ public bool MutateTestbool(bool testbool) { int o = __p.__offset(34); if (o != 0) { __p.bb.Put(o + __p.bb_pos, (byte)(testbool ? 1 : 0)); return true; } else { return false; } }
+ public int Testhashs32Fnv1 { get { int o = __p.__offset(36); return o != 0 ? __p.bb.GetInt(o + __p.bb_pos) : (int)0; } }
+ public bool MutateTesthashs32Fnv1(int testhashs32_fnv1) { int o = __p.__offset(36); if (o != 0) { __p.bb.PutInt(o + __p.bb_pos, testhashs32_fnv1); return true; } else { return false; } }
+ public uint Testhashu32Fnv1 { get { int o = __p.__offset(38); return o != 0 ? __p.bb.GetUint(o + __p.bb_pos) : (uint)0; } }
+ public bool MutateTesthashu32Fnv1(uint testhashu32_fnv1) { int o = __p.__offset(38); if (o != 0) { __p.bb.PutUint(o + __p.bb_pos, testhashu32_fnv1); return true; } else { return false; } }
+ public long Testhashs64Fnv1 { get { int o = __p.__offset(40); return o != 0 ? __p.bb.GetLong(o + __p.bb_pos) : (long)0; } }
+ public bool MutateTesthashs64Fnv1(long testhashs64_fnv1) { int o = __p.__offset(40); if (o != 0) { __p.bb.PutLong(o + __p.bb_pos, testhashs64_fnv1); return true; } else { return false; } }
+ public ulong Testhashu64Fnv1 { get { int o = __p.__offset(42); return o != 0 ? __p.bb.GetUlong(o + __p.bb_pos) : (ulong)0; } }
+ public bool MutateTesthashu64Fnv1(ulong testhashu64_fnv1) { int o = __p.__offset(42); if (o != 0) { __p.bb.PutUlong(o + __p.bb_pos, testhashu64_fnv1); return true; } else { return false; } }
+ public int Testhashs32Fnv1a { get { int o = __p.__offset(44); return o != 0 ? __p.bb.GetInt(o + __p.bb_pos) : (int)0; } }
+ public bool MutateTesthashs32Fnv1a(int testhashs32_fnv1a) { int o = __p.__offset(44); if (o != 0) { __p.bb.PutInt(o + __p.bb_pos, testhashs32_fnv1a); return true; } else { return false; } }
+ public uint Testhashu32Fnv1a { get { int o = __p.__offset(46); return o != 0 ? __p.bb.GetUint(o + __p.bb_pos) : (uint)0; } }
+ public bool MutateTesthashu32Fnv1a(uint testhashu32_fnv1a) { int o = __p.__offset(46); if (o != 0) { __p.bb.PutUint(o + __p.bb_pos, testhashu32_fnv1a); return true; } else { return false; } }
+ public long Testhashs64Fnv1a { get { int o = __p.__offset(48); return o != 0 ? __p.bb.GetLong(o + __p.bb_pos) : (long)0; } }
+ public bool MutateTesthashs64Fnv1a(long testhashs64_fnv1a) { int o = __p.__offset(48); if (o != 0) { __p.bb.PutLong(o + __p.bb_pos, testhashs64_fnv1a); return true; } else { return false; } }
+ public ulong Testhashu64Fnv1a { get { int o = __p.__offset(50); return o != 0 ? __p.bb.GetUlong(o + __p.bb_pos) : (ulong)0; } }
+ public bool MutateTesthashu64Fnv1a(ulong testhashu64_fnv1a) { int o = __p.__offset(50); if (o != 0) { __p.bb.PutUlong(o + __p.bb_pos, testhashu64_fnv1a); return true; } else { return false; } }
+ public bool Testarrayofbools(int j) { int o = __p.__offset(52); return o != 0 ? 0!=__p.bb.Get(__p.__vector(o) + j * 1) : false; }
+ public int TestarrayofboolsLength { get { int o = __p.__offset(52); return o != 0 ? __p.__vector_len(o) : 0; } }
+ public ArraySegment<byte>? GetTestarrayofboolsBytes() { return __p.__vector_as_arraysegment(52); }
+ public bool MutateTestarrayofbools(int j, bool testarrayofbools) { int o = __p.__offset(52); if (o != 0) { __p.bb.Put(__p.__vector(o) + j * 1, (byte)(testarrayofbools ? 1 : 0)); return true; } else { return false; } }
+ public float Testf { get { int o = __p.__offset(54); return o != 0 ? __p.bb.GetFloat(o + __p.bb_pos) : (float)3.14159f; } }
+ public bool MutateTestf(float testf) { int o = __p.__offset(54); if (o != 0) { __p.bb.PutFloat(o + __p.bb_pos, testf); return true; } else { return false; } }
+ public float Testf2 { get { int o = __p.__offset(56); return o != 0 ? __p.bb.GetFloat(o + __p.bb_pos) : (float)3.0f; } }
+ public bool MutateTestf2(float testf2) { int o = __p.__offset(56); if (o != 0) { __p.bb.PutFloat(o + __p.bb_pos, testf2); return true; } else { return false; } }
+ public float Testf3 { get { int o = __p.__offset(58); return o != 0 ? __p.bb.GetFloat(o + __p.bb_pos) : (float)0.0f; } }
+ 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 int Testarrayofstring2Length { get { int o = __p.__offset(60); return o != 0 ? __p.__vector_len(o) : 0; } }
public static void StartMonster(FlatBufferBuilder builder) { builder.StartObject(29); }
public static void AddPos(FlatBufferBuilder builder, Offset<Vec3> posOffset) { builder.AddStruct(0, posOffset.Value, 0); }
@@ -129,6 +127,34 @@
return new Offset<Monster>(o);
}
public static void FinishMonsterBuffer(FlatBufferBuilder builder, Offset<Monster> offset) { builder.Finish(offset.Value, "MONS"); }
+
+ public static VectorOffset CreateMySortedVectorOfTables(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));
+ return builder.CreateVectorOfTables(offsets);
+ }
+
+ public static Monster? LookupByKey(VectorOffset vectorOffset, string key, ByteBuffer bb) {
+ byte[] byteKey = System.Text.Encoding.UTF8.GetBytes(key);
+ int vectorLocation = bb.Length - vectorOffset.Value;
+ int span = bb.GetInt(vectorLocation);
+ int start = 0;
+ vectorLocation += 4;
+ while (span != 0) {
+ int middle = span / 2;
+ int tableOffset = Table.__indirect(vectorLocation + 4 * (start + middle), bb);
+ int comp = Table.CompareStrings(Table.__offset(10, bb.Length - tableOffset, bb), byteKey, bb);
+ if (comp > 0) {
+ span = middle;
+ } else if (comp < 0) {
+ middle++;
+ start += middle;
+ span -= middle;
+ } else {
+ return new Monster().__assign(tableOffset, bb);
+ }
+ }
+ return null;
+ }
};
diff --git a/tests/MyGame/Example/Monster.go b/tests/MyGame/Example/Monster.go
index 4989eb4..ba3ae0f 100644
--- a/tests/MyGame/Example/Monster.go
+++ b/tests/MyGame/Example/Monster.go
@@ -135,9 +135,6 @@
if o != 0 {
x := rcv._tab.Vector(o)
x += flatbuffers.UOffsetT(j) * 4
- if obj == nil {
- obj = new(Test)
- }
obj.Init(rcv._tab.Bytes, x)
return true
}
@@ -177,9 +174,6 @@
x := rcv._tab.Vector(o)
x += flatbuffers.UOffsetT(j) * 4
x = rcv._tab.Indirect(x)
- if obj == nil {
- obj = new(Monster)
- }
obj.Init(rcv._tab.Bytes, x)
return true
}
diff --git a/tests/MyGame/Example/Monster.java b/tests/MyGame/Example/Monster.java
index dc27f84..10a9aa4 100644
--- a/tests/MyGame/Example/Monster.java
+++ b/tests/MyGame/Example/Monster.java
@@ -13,12 +13,13 @@
*/
public final class Monster extends Table {
public static Monster getRootAsMonster(ByteBuffer _bb) { return getRootAsMonster(_bb, new Monster()); }
- public static Monster getRootAsMonster(ByteBuffer _bb, Monster obj) { _bb.order(ByteOrder.LITTLE_ENDIAN); return (obj.__init(_bb.getInt(_bb.position()) + _bb.position(), _bb)); }
+ public static Monster getRootAsMonster(ByteBuffer _bb, Monster obj) { _bb.order(ByteOrder.LITTLE_ENDIAN); return (obj.__assign(_bb.getInt(_bb.position()) + _bb.position(), _bb)); }
public static boolean MonsterBufferHasIdentifier(ByteBuffer _bb) { return __has_identifier(_bb, "MONS"); }
- public Monster __init(int _i, ByteBuffer _bb) { bb_pos = _i; bb = _bb; return this; }
+ public void __init(int _i, ByteBuffer _bb) { bb_pos = _i; bb = _bb; }
+ public Monster __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; }
public Vec3 pos() { return pos(new Vec3()); }
- public Vec3 pos(Vec3 obj) { int o = __offset(4); return o != 0 ? obj.__init(o + bb_pos, bb) : null; }
+ public Vec3 pos(Vec3 obj) { int o = __offset(4); return o != 0 ? obj.__assign(o + bb_pos, bb) : null; }
public short mana() { int o = __offset(6); return o != 0 ? bb.getShort(o + bb_pos) : 150; }
public boolean mutateMana(short mana) { int o = __offset(6); if (o != 0) { bb.putShort(o + bb_pos, mana); return true; } else { return false; } }
public short hp() { int o = __offset(8); return o != 0 ? bb.getShort(o + bb_pos) : 100; }
@@ -35,7 +36,7 @@
public boolean mutateTestType(byte test_type) { int o = __offset(18); if (o != 0) { bb.put(o + bb_pos, test_type); return true; } else { return false; } }
public Table test(Table obj) { int o = __offset(20); return o != 0 ? __union(obj, o) : null; }
public Test test4(int j) { return test4(new Test(), j); }
- public Test test4(Test obj, int j) { int o = __offset(22); return o != 0 ? obj.__init(__vector(o) + j * 4, bb) : null; }
+ public Test test4(Test obj, int j) { int o = __offset(22); return o != 0 ? obj.__assign(__vector(o) + j * 4, bb) : null; }
public int test4Length() { int o = __offset(22); return o != 0 ? __vector_len(o) : 0; }
public String testarrayofstring(int j) { int o = __offset(24); return o != 0 ? __string(__vector(o) + j * 4) : null; }
public int testarrayofstringLength() { int o = __offset(24); return o != 0 ? __vector_len(o) : 0; }
@@ -44,35 +45,35 @@
* multiline too
*/
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.__init(__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 Monster enemy() { return enemy(new Monster()); }
- public Monster enemy(Monster obj) { int o = __offset(28); return o != 0 ? obj.__init(__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 testnestedflatbufferLength() { int o = __offset(30); return o != 0 ? __vector_len(o) : 0; }
public ByteBuffer testnestedflatbufferAsByteBuffer() { return __vector_as_bytebuffer(30, 1); }
public Monster testnestedflatbufferAsMonster() { return testnestedflatbufferAsMonster(new Monster()); }
- public Monster testnestedflatbufferAsMonster(Monster obj) { int o = __offset(30); return o != 0 ? obj.__init(__indirect(__vector(o)), bb) : null; }
+ public Monster testnestedflatbufferAsMonster(Monster obj) { int o = __offset(30); return o != 0 ? obj.__assign(__indirect(__vector(o)), bb) : null; }
public boolean mutateTestnestedflatbuffer(int j, int testnestedflatbuffer) { int o = __offset(30); if (o != 0) { bb.put(__vector(o) + j * 1, (byte)testnestedflatbuffer); return true; } else { return false; } }
public Stat testempty() { return testempty(new Stat()); }
- public Stat testempty(Stat obj) { int o = __offset(32); return o != 0 ? obj.__init(__indirect(o + bb_pos), bb) : null; }
+ public Stat testempty(Stat obj) { int o = __offset(32); return o != 0 ? obj.__assign(__indirect(o + bb_pos), bb) : null; }
public boolean testbool() { int o = __offset(34); return o != 0 ? 0!=bb.get(o + bb_pos) : false; }
public boolean mutateTestbool(boolean testbool) { int o = __offset(34); if (o != 0) { bb.put(o + bb_pos, (byte)(testbool ? 1 : 0)); return true; } else { return false; } }
public int testhashs32Fnv1() { int o = __offset(36); return o != 0 ? bb.getInt(o + bb_pos) : 0; }
public boolean mutateTesthashs32Fnv1(int testhashs32_fnv1) { int o = __offset(36); if (o != 0) { bb.putInt(o + bb_pos, testhashs32_fnv1); return true; } else { return false; } }
- public long testhashu32Fnv1() { int o = __offset(38); return o != 0 ? (long)bb.getInt(o + bb_pos) & 0xFFFFFFFFL : 0; }
+ public long testhashu32Fnv1() { int o = __offset(38); return o != 0 ? (long)bb.getInt(o + bb_pos) & 0xFFFFFFFFL : 0L; }
public boolean mutateTesthashu32Fnv1(long testhashu32_fnv1) { int o = __offset(38); if (o != 0) { bb.putInt(o + bb_pos, (int)testhashu32_fnv1); return true; } else { return false; } }
- public long testhashs64Fnv1() { int o = __offset(40); return o != 0 ? bb.getLong(o + bb_pos) : 0; }
+ public long testhashs64Fnv1() { int o = __offset(40); return o != 0 ? bb.getLong(o + bb_pos) : 0L; }
public boolean mutateTesthashs64Fnv1(long testhashs64_fnv1) { int o = __offset(40); if (o != 0) { bb.putLong(o + bb_pos, testhashs64_fnv1); return true; } else { return false; } }
- public long testhashu64Fnv1() { int o = __offset(42); return o != 0 ? bb.getLong(o + bb_pos) : 0; }
+ public long testhashu64Fnv1() { int o = __offset(42); return o != 0 ? bb.getLong(o + bb_pos) : 0L; }
public boolean mutateTesthashu64Fnv1(long testhashu64_fnv1) { int o = __offset(42); if (o != 0) { bb.putLong(o + bb_pos, testhashu64_fnv1); return true; } else { return false; } }
public int testhashs32Fnv1a() { int o = __offset(44); return o != 0 ? bb.getInt(o + bb_pos) : 0; }
public boolean mutateTesthashs32Fnv1a(int testhashs32_fnv1a) { int o = __offset(44); if (o != 0) { bb.putInt(o + bb_pos, testhashs32_fnv1a); return true; } else { return false; } }
- public long testhashu32Fnv1a() { int o = __offset(46); return o != 0 ? (long)bb.getInt(o + bb_pos) & 0xFFFFFFFFL : 0; }
+ public long testhashu32Fnv1a() { int o = __offset(46); return o != 0 ? (long)bb.getInt(o + bb_pos) & 0xFFFFFFFFL : 0L; }
public boolean mutateTesthashu32Fnv1a(long testhashu32_fnv1a) { int o = __offset(46); if (o != 0) { bb.putInt(o + bb_pos, (int)testhashu32_fnv1a); return true; } else { return false; } }
- public long testhashs64Fnv1a() { int o = __offset(48); return o != 0 ? bb.getLong(o + bb_pos) : 0; }
+ public long testhashs64Fnv1a() { int o = __offset(48); return o != 0 ? bb.getLong(o + bb_pos) : 0L; }
public boolean mutateTesthashs64Fnv1a(long testhashs64_fnv1a) { int o = __offset(48); if (o != 0) { bb.putLong(o + bb_pos, testhashs64_fnv1a); return true; } else { return false; } }
- public long testhashu64Fnv1a() { int o = __offset(50); return o != 0 ? bb.getLong(o + bb_pos) : 0; }
+ public long testhashu64Fnv1a() { int o = __offset(50); return o != 0 ? bb.getLong(o + bb_pos) : 0L; }
public boolean mutateTesthashu64Fnv1a(long testhashu64_fnv1a) { int o = __offset(50); if (o != 0) { bb.putLong(o + bb_pos, testhashu64_fnv1a); return true; } else { return false; } }
public boolean testarrayofbools(int j) { int o = __offset(52); return o != 0 ? 0!=bb.get(__vector(o) + j * 1) : false; }
public int testarrayofboolsLength() { int o = __offset(52); return o != 0 ? __vector_len(o) : 0; }
@@ -113,13 +114,13 @@
public static void addTestempty(FlatBufferBuilder builder, int testemptyOffset) { builder.addOffset(14, testemptyOffset, 0); }
public static void addTestbool(FlatBufferBuilder builder, boolean testbool) { builder.addBoolean(15, testbool, false); }
public static void addTesthashs32Fnv1(FlatBufferBuilder builder, int testhashs32Fnv1) { builder.addInt(16, testhashs32Fnv1, 0); }
- public static void addTesthashu32Fnv1(FlatBufferBuilder builder, long testhashu32Fnv1) { builder.addInt(17, (int)testhashu32Fnv1, 0); }
- public static void addTesthashs64Fnv1(FlatBufferBuilder builder, long testhashs64Fnv1) { builder.addLong(18, testhashs64Fnv1, 0); }
- public static void addTesthashu64Fnv1(FlatBufferBuilder builder, long testhashu64Fnv1) { builder.addLong(19, testhashu64Fnv1, 0); }
+ public static void addTesthashu32Fnv1(FlatBufferBuilder builder, long testhashu32Fnv1) { builder.addInt(17, (int)testhashu32Fnv1, (int)0L); }
+ public static void addTesthashs64Fnv1(FlatBufferBuilder builder, long testhashs64Fnv1) { builder.addLong(18, testhashs64Fnv1, 0L); }
+ public static void addTesthashu64Fnv1(FlatBufferBuilder builder, long testhashu64Fnv1) { builder.addLong(19, testhashu64Fnv1, 0L); }
public static void addTesthashs32Fnv1a(FlatBufferBuilder builder, int testhashs32Fnv1a) { builder.addInt(20, testhashs32Fnv1a, 0); }
- public static void addTesthashu32Fnv1a(FlatBufferBuilder builder, long testhashu32Fnv1a) { builder.addInt(21, (int)testhashu32Fnv1a, 0); }
- public static void addTesthashs64Fnv1a(FlatBufferBuilder builder, long testhashs64Fnv1a) { builder.addLong(22, testhashs64Fnv1a, 0); }
- public static void addTesthashu64Fnv1a(FlatBufferBuilder builder, long testhashu64Fnv1a) { builder.addLong(23, testhashu64Fnv1a, 0); }
+ public static void addTesthashu32Fnv1a(FlatBufferBuilder builder, long testhashu32Fnv1a) { builder.addInt(21, (int)testhashu32Fnv1a, (int)0L); }
+ public static void addTesthashs64Fnv1a(FlatBufferBuilder builder, long testhashs64Fnv1a) { builder.addLong(22, testhashs64Fnv1a, 0L); }
+ public static void addTesthashu64Fnv1a(FlatBufferBuilder builder, long testhashu64Fnv1a) { builder.addLong(23, testhashu64Fnv1a, 0L); }
public static void addTestarrayofbools(FlatBufferBuilder builder, int testarrayofboolsOffset) { builder.addOffset(24, testarrayofboolsOffset, 0); }
public static int createTestarrayofboolsVector(FlatBufferBuilder builder, boolean[] data) { builder.startVector(1, data.length, 1); for (int i = data.length - 1; i >= 0; i--) builder.addBoolean(data[i]); return builder.endVector(); }
public static void startTestarrayofboolsVector(FlatBufferBuilder builder, int numElems) { builder.startVector(1, numElems, 1); }
@@ -135,5 +136,31 @@
return o;
}
public static void finishMonsterBuffer(FlatBufferBuilder builder, int offset) { builder.finish(offset, "MONS"); }
+
+ @Override
+ 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) {
+ byte[] byteKey = key.getBytes(Table.UTF8_CHARSET.get());
+ int vectorLocation = bb.array().length - vectorOffset;
+ int span = bb.getInt(vectorLocation);
+ int start = 0;
+ vectorLocation += 4;
+ while (span != 0) {
+ int middle = span / 2;
+ int tableOffset = __indirect(vectorLocation + 4 * (start + middle), bb);
+ int comp = compareStrings(__offset(10, bb.array().length - tableOffset, bb), byteKey, bb);
+ if (comp > 0) {
+ span = middle;
+ } else if (comp < 0) {
+ middle++;
+ start += middle;
+ span -= middle;
+ } else {
+ return new Monster().__assign(tableOffset, bb);
+ }
+ }
+ return null;
+ }
}
diff --git a/tests/MyGame/Example/MonsterStorage_grpc.go b/tests/MyGame/Example/MonsterStorage_grpc.go
new file mode 100644
index 0000000..8aac5c2
--- /dev/null
+++ b/tests/MyGame/Example/MonsterStorage_grpc.go
@@ -0,0 +1,106 @@
+//Generated by gRPC Go plugin
+//If you make any local changes, they will be lost
+//source: monster_test
+
+package Example
+
+import "github.com/google/flatbuffers/go"
+
+import (
+ context "golang.org/x/net/context"
+ grpc "google.golang.org/grpc"
+)
+
+// Client API for MonsterStorage service
+type MonsterStorageClient interface{
+ Store(ctx context.Context, in *flatbuffers.Builder,
+ opts... grpc.CallOption) (* Stat, error)
+ Retrieve(ctx context.Context, in *flatbuffers.Builder,
+ opts... grpc.CallOption) (* Monster, error)
+}
+
+type monsterStorageClient struct {
+ cc *grpc.ClientConn
+}
+
+func NewMonsterStorageClient(cc *grpc.ClientConn) MonsterStorageClient {
+ return &monsterStorageClient{cc}
+}
+
+func (c *monsterStorageClient) Store(ctx context.Context, in *flatbuffers.Builder,
+ opts... grpc.CallOption) (* Stat, error) {
+ out := new(Stat)
+ err := grpc.Invoke(ctx, "/Example.MonsterStorage/Store", in, out, c.cc, opts...)
+ if err != nil { return nil, err }
+ return out, nil
+}
+
+func (c *monsterStorageClient) Retrieve(ctx context.Context, in *flatbuffers.Builder,
+ opts... grpc.CallOption) (* Monster, error) {
+ out := new(Monster)
+ err := grpc.Invoke(ctx, "/Example.MonsterStorage/Retrieve", in, out, c.cc, opts...)
+ if err != nil { return nil, err }
+ return out, nil
+}
+
+// Server API for MonsterStorage service
+type MonsterStorageServer interface {
+ Store(context.Context, *Monster) (*flatbuffers.Builder, error)
+ Retrieve(context.Context, *Stat) (*flatbuffers.Builder, error)
+}
+
+func RegisterMonsterStorageServer(s *grpc.Server, srv MonsterStorageServer) {
+ s.RegisterService(&_MonsterStorage_serviceDesc, srv)
+}
+
+func _MonsterStorage_Store_Handler(srv interface{}, ctx context.Context,
+ dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(Monster)
+ if err := dec(in); err != nil { return nil, err }
+ if interceptor == nil { return srv.(MonsterStorageServer).Store(ctx, in) }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: "/Example.MonsterStorage/Store",
+ }
+
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(MonsterStorageServer).Store(ctx, req.(* Monster))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+
+func _MonsterStorage_Retrieve_Handler(srv interface{}, ctx context.Context,
+ dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(Stat)
+ if err := dec(in); err != nil { return nil, err }
+ if interceptor == nil { return srv.(MonsterStorageServer).Retrieve(ctx, in) }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: "/Example.MonsterStorage/Retrieve",
+ }
+
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(MonsterStorageServer).Retrieve(ctx, req.(* Stat))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+
+var _MonsterStorage_serviceDesc = grpc.ServiceDesc{
+ ServiceName: "Example.MonsterStorage",
+ HandlerType: (*MonsterStorageServer)(nil),
+ Methods: []grpc.MethodDesc{
+ {
+ MethodName: "Store",
+ Handler: _MonsterStorage_Store_Handler,
+ },
+ {
+ MethodName: "Retrieve",
+ Handler: _MonsterStorage_Retrieve_Handler,
+ },
+ },
+ Streams: []grpc.StreamDesc{
+ },
+}
+
diff --git a/tests/MyGame/Example/Stat.cs b/tests/MyGame/Example/Stat.cs
index 30eaee5..0fb5bd0 100644
--- a/tests/MyGame/Example/Stat.cs
+++ b/tests/MyGame/Example/Stat.cs
@@ -6,17 +6,21 @@
using System;
using FlatBuffers;
-public sealed class Stat : Table {
+public struct Stat : IFlatbufferObject
+{
+ private Table __p;
+ public ByteBuffer ByteBuffer { get { return __p.bb; } }
public static Stat GetRootAsStat(ByteBuffer _bb) { return GetRootAsStat(_bb, new Stat()); }
- public static Stat GetRootAsStat(ByteBuffer _bb, Stat obj) { return (obj.__init(_bb.GetInt(_bb.Position) + _bb.Position, _bb)); }
- public Stat __init(int _i, ByteBuffer _bb) { bb_pos = _i; bb = _bb; return this; }
+ public static Stat GetRootAsStat(ByteBuffer _bb, Stat obj) { return (obj.__assign(_bb.GetInt(_bb.Position) + _bb.Position, _bb)); }
+ public void __init(int _i, ByteBuffer _bb) { __p.bb_pos = _i; __p.bb = _bb; }
+ public Stat __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; }
- public string Id { get { int o = __offset(4); return o != 0 ? __string(o + bb_pos) : null; } }
- public ArraySegment<byte>? GetIdBytes() { return __vector_as_arraysegment(4); }
- public long Val { get { int o = __offset(6); return o != 0 ? bb.GetLong(o + bb_pos) : (long)0; } }
- public bool MutateVal(long val) { int o = __offset(6); if (o != 0) { bb.PutLong(o + bb_pos, val); return true; } else { return false; } }
- public ushort Count { get { int o = __offset(8); return o != 0 ? bb.GetUshort(o + bb_pos) : (ushort)0; } }
- public bool MutateCount(ushort count) { int o = __offset(8); if (o != 0) { bb.PutUshort(o + bb_pos, count); return true; } else { return false; } }
+ public string Id { get { int o = __p.__offset(4); return o != 0 ? __p.__string(o + __p.bb_pos) : null; } }
+ public ArraySegment<byte>? GetIdBytes() { return __p.__vector_as_arraysegment(4); }
+ public long Val { get { int o = __p.__offset(6); return o != 0 ? __p.bb.GetLong(o + __p.bb_pos) : (long)0; } }
+ public bool MutateVal(long val) { int o = __p.__offset(6); if (o != 0) { __p.bb.PutLong(o + __p.bb_pos, val); return true; } else { return false; } }
+ public ushort Count { get { int o = __p.__offset(8); return o != 0 ? __p.bb.GetUshort(o + __p.bb_pos) : (ushort)0; } }
+ public bool MutateCount(ushort count) { int o = __p.__offset(8); if (o != 0) { __p.bb.PutUshort(o + __p.bb_pos, count); return true; } else { return false; } }
public static Offset<Stat> CreateStat(FlatBufferBuilder builder,
StringOffset idOffset = default(StringOffset),
diff --git a/tests/MyGame/Example/Stat.java b/tests/MyGame/Example/Stat.java
index cd339c6..351e5b3 100644
--- a/tests/MyGame/Example/Stat.java
+++ b/tests/MyGame/Example/Stat.java
@@ -10,12 +10,13 @@
@SuppressWarnings("unused")
public final class Stat extends Table {
public static Stat getRootAsStat(ByteBuffer _bb) { return getRootAsStat(_bb, new Stat()); }
- public static Stat getRootAsStat(ByteBuffer _bb, Stat obj) { _bb.order(ByteOrder.LITTLE_ENDIAN); return (obj.__init(_bb.getInt(_bb.position()) + _bb.position(), _bb)); }
- public Stat __init(int _i, ByteBuffer _bb) { bb_pos = _i; bb = _bb; return this; }
+ public static Stat getRootAsStat(ByteBuffer _bb, Stat obj) { _bb.order(ByteOrder.LITTLE_ENDIAN); return (obj.__assign(_bb.getInt(_bb.position()) + _bb.position(), _bb)); }
+ public void __init(int _i, ByteBuffer _bb) { bb_pos = _i; bb = _bb; }
+ public Stat __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; }
public String id() { int o = __offset(4); return o != 0 ? __string(o + bb_pos) : null; }
public ByteBuffer idAsByteBuffer() { return __vector_as_bytebuffer(4, 1); }
- public long val() { int o = __offset(6); return o != 0 ? bb.getLong(o + bb_pos) : 0; }
+ public long val() { int o = __offset(6); return o != 0 ? bb.getLong(o + bb_pos) : 0L; }
public boolean mutateVal(long val) { int o = __offset(6); if (o != 0) { bb.putLong(o + bb_pos, val); return true; } else { return false; } }
public int count() { int o = __offset(8); return o != 0 ? bb.getShort(o + bb_pos) & 0xFFFF : 0; }
public boolean mutateCount(int count) { int o = __offset(8); if (o != 0) { bb.putShort(o + bb_pos, (short)count); return true; } else { return false; } }
@@ -33,8 +34,8 @@
public static void startStat(FlatBufferBuilder builder) { builder.startObject(3); }
public static void addId(FlatBufferBuilder builder, int idOffset) { builder.addOffset(0, idOffset, 0); }
- public static void addVal(FlatBufferBuilder builder, long val) { builder.addLong(1, val, 0); }
- public static void addCount(FlatBufferBuilder builder, int count) { builder.addShort(2, (short)count, 0); }
+ public static void addVal(FlatBufferBuilder builder, long val) { builder.addLong(1, val, 0L); }
+ public static void addCount(FlatBufferBuilder builder, int count) { builder.addShort(2, (short)count, (short)0); }
public static int endStat(FlatBufferBuilder builder) {
int o = builder.endObject();
return o;
diff --git a/tests/MyGame/Example/Test.cs b/tests/MyGame/Example/Test.cs
index bd82295..92c3b91 100644
--- a/tests/MyGame/Example/Test.cs
+++ b/tests/MyGame/Example/Test.cs
@@ -6,13 +6,17 @@
using System;
using FlatBuffers;
-public sealed class Test : Struct {
- public Test __init(int _i, ByteBuffer _bb) { bb_pos = _i; bb = _bb; return this; }
+public struct Test : 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 Test __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; }
- public short A { get { return bb.GetShort(bb_pos + 0); } }
- public void MutateA(short a) { bb.PutShort(bb_pos + 0, a); }
- public sbyte B { get { return bb.GetSbyte(bb_pos + 2); } }
- public void MutateB(sbyte b) { bb.PutSbyte(bb_pos + 2, b); }
+ public short A { get { return __p.bb.GetShort(__p.bb_pos + 0); } }
+ public void MutateA(short a) { __p.bb.PutShort(__p.bb_pos + 0, a); }
+ public sbyte B { get { return __p.bb.GetSbyte(__p.bb_pos + 2); } }
+ public void MutateB(sbyte b) { __p.bb.PutSbyte(__p.bb_pos + 2, b); }
public static Offset<Test> CreateTest(FlatBufferBuilder builder, short A, sbyte B) {
builder.Prep(2, 4);
diff --git a/tests/MyGame/Example/Test.java b/tests/MyGame/Example/Test.java
index 6e33da9..f584c46 100644
--- a/tests/MyGame/Example/Test.java
+++ b/tests/MyGame/Example/Test.java
@@ -9,7 +9,8 @@
@SuppressWarnings("unused")
public final class Test extends Struct {
- public Test __init(int _i, ByteBuffer _bb) { bb_pos = _i; bb = _bb; return this; }
+ public void __init(int _i, ByteBuffer _bb) { bb_pos = _i; bb = _bb; }
+ public Test __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; }
public short a() { return bb.getShort(bb_pos + 0); }
public void mutateA(short a) { bb.putShort(bb_pos + 0, a); }
diff --git a/tests/MyGame/Example/TestSimpleTableWithEnum.cs b/tests/MyGame/Example/TestSimpleTableWithEnum.cs
index 63cb9e1..bff3864 100644
--- a/tests/MyGame/Example/TestSimpleTableWithEnum.cs
+++ b/tests/MyGame/Example/TestSimpleTableWithEnum.cs
@@ -6,13 +6,17 @@
using System;
using FlatBuffers;
-public partial class TestSimpleTableWithEnum : Table {
+public partial struct TestSimpleTableWithEnum : IFlatbufferObject
+{
+ private Table __p;
+ public ByteBuffer ByteBuffer { get { return __p.bb; } }
public static TestSimpleTableWithEnum GetRootAsTestSimpleTableWithEnum(ByteBuffer _bb) { return GetRootAsTestSimpleTableWithEnum(_bb, new TestSimpleTableWithEnum()); }
- public static TestSimpleTableWithEnum GetRootAsTestSimpleTableWithEnum(ByteBuffer _bb, TestSimpleTableWithEnum obj) { return (obj.__init(_bb.GetInt(_bb.Position) + _bb.Position, _bb)); }
- public TestSimpleTableWithEnum __init(int _i, ByteBuffer _bb) { bb_pos = _i; bb = _bb; return this; }
+ public static TestSimpleTableWithEnum GetRootAsTestSimpleTableWithEnum(ByteBuffer _bb, TestSimpleTableWithEnum obj) { return (obj.__assign(_bb.GetInt(_bb.Position) + _bb.Position, _bb)); }
+ public void __init(int _i, ByteBuffer _bb) { __p.bb_pos = _i; __p.bb = _bb; }
+ public TestSimpleTableWithEnum __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; }
- public Color Color { get { int o = __offset(4); return o != 0 ? (Color)bb.GetSbyte(o + bb_pos) : Color.Green; } }
- public bool MutateColor(Color color) { int o = __offset(4); if (o != 0) { bb.PutSbyte(o + bb_pos, (sbyte)color); return true; } else { return false; } }
+ public Color Color { get { int o = __p.__offset(4); return o != 0 ? (Color)__p.bb.GetSbyte(o + __p.bb_pos) : Color.Green; } }
+ public bool MutateColor(Color color) { int o = __p.__offset(4); if (o != 0) { __p.bb.PutSbyte(o + __p.bb_pos, (sbyte)color); return true; } else { return false; } }
public static Offset<TestSimpleTableWithEnum> CreateTestSimpleTableWithEnum(FlatBufferBuilder builder,
Color color = Color.Green) {
diff --git a/tests/MyGame/Example/TestSimpleTableWithEnum.java b/tests/MyGame/Example/TestSimpleTableWithEnum.java
index a1de020..9f77b39 100644
--- a/tests/MyGame/Example/TestSimpleTableWithEnum.java
+++ b/tests/MyGame/Example/TestSimpleTableWithEnum.java
@@ -10,8 +10,9 @@
@SuppressWarnings("unused")
public final class TestSimpleTableWithEnum extends Table {
public static TestSimpleTableWithEnum getRootAsTestSimpleTableWithEnum(ByteBuffer _bb) { return getRootAsTestSimpleTableWithEnum(_bb, new TestSimpleTableWithEnum()); }
- public static TestSimpleTableWithEnum getRootAsTestSimpleTableWithEnum(ByteBuffer _bb, TestSimpleTableWithEnum obj) { _bb.order(ByteOrder.LITTLE_ENDIAN); return (obj.__init(_bb.getInt(_bb.position()) + _bb.position(), _bb)); }
- public TestSimpleTableWithEnum __init(int _i, ByteBuffer _bb) { bb_pos = _i; bb = _bb; return this; }
+ public static TestSimpleTableWithEnum getRootAsTestSimpleTableWithEnum(ByteBuffer _bb, TestSimpleTableWithEnum obj) { _bb.order(ByteOrder.LITTLE_ENDIAN); return (obj.__assign(_bb.getInt(_bb.position()) + _bb.position(), _bb)); }
+ public void __init(int _i, ByteBuffer _bb) { bb_pos = _i; bb = _bb; }
+ public TestSimpleTableWithEnum __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; }
public byte color() { int o = __offset(4); return o != 0 ? bb.get(o + bb_pos) : 2; }
public boolean mutateColor(byte color) { int o = __offset(4); if (o != 0) { bb.put(o + bb_pos, color); return true; } else { return false; } }
diff --git a/tests/MyGame/Example/Vec3.cs b/tests/MyGame/Example/Vec3.cs
index a6d21fa..0552543 100644
--- a/tests/MyGame/Example/Vec3.cs
+++ b/tests/MyGame/Example/Vec3.cs
@@ -6,21 +6,24 @@
using System;
using FlatBuffers;
-public sealed class Vec3 : Struct {
- public Vec3 __init(int _i, ByteBuffer _bb) { bb_pos = _i; bb = _bb; return this; }
+public struct Vec3 : 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 Vec3 __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; }
- public float X { get { return bb.GetFloat(bb_pos + 0); } }
- public void MutateX(float x) { bb.PutFloat(bb_pos + 0, x); }
- public float Y { get { return bb.GetFloat(bb_pos + 4); } }
- public void MutateY(float y) { bb.PutFloat(bb_pos + 4, y); }
- public float Z { get { return bb.GetFloat(bb_pos + 8); } }
- public void MutateZ(float z) { bb.PutFloat(bb_pos + 8, z); }
- public double Test1 { get { return bb.GetDouble(bb_pos + 16); } }
- public void MutateTest1(double test1) { bb.PutDouble(bb_pos + 16, test1); }
- public Color Test2 { get { return (Color)bb.GetSbyte(bb_pos + 24); } }
- public void MutateTest2(Color test2) { bb.PutSbyte(bb_pos + 24, (sbyte)test2); }
- public Test Test3 { get { return GetTest3(new Test()); } }
- public Test GetTest3(Test obj) { return obj.__init(bb_pos + 26, bb); }
+ public float X { get { return __p.bb.GetFloat(__p.bb_pos + 0); } }
+ public void MutateX(float x) { __p.bb.PutFloat(__p.bb_pos + 0, x); }
+ public float Y { get { return __p.bb.GetFloat(__p.bb_pos + 4); } }
+ public void MutateY(float y) { __p.bb.PutFloat(__p.bb_pos + 4, y); }
+ public float Z { get { return __p.bb.GetFloat(__p.bb_pos + 8); } }
+ public void MutateZ(float z) { __p.bb.PutFloat(__p.bb_pos + 8, z); }
+ public double Test1 { get { return __p.bb.GetDouble(__p.bb_pos + 16); } }
+ public void MutateTest1(double test1) { __p.bb.PutDouble(__p.bb_pos + 16, test1); }
+ public Color Test2 { get { return (Color)__p.bb.GetSbyte(__p.bb_pos + 24); } }
+ public void MutateTest2(Color test2) { __p.bb.PutSbyte(__p.bb_pos + 24, (sbyte)test2); }
+ public Test Test3 { get { return (new Test()).__assign(__p.bb_pos + 26, __p.bb); } }
public static Offset<Vec3> CreateVec3(FlatBufferBuilder builder, float X, float Y, float Z, double Test1, Color Test2, short test3_A, sbyte test3_B) {
builder.Prep(16, 32);
diff --git a/tests/MyGame/Example/Vec3.java b/tests/MyGame/Example/Vec3.java
index 261947c..6cb820b 100644
--- a/tests/MyGame/Example/Vec3.java
+++ b/tests/MyGame/Example/Vec3.java
@@ -9,7 +9,8 @@
@SuppressWarnings("unused")
public final class Vec3 extends Struct {
- public Vec3 __init(int _i, ByteBuffer _bb) { bb_pos = _i; bb = _bb; return this; }
+ public void __init(int _i, ByteBuffer _bb) { bb_pos = _i; bb = _bb; }
+ public Vec3 __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; }
public float x() { return bb.getFloat(bb_pos + 0); }
public void mutateX(float x) { bb.putFloat(bb_pos + 0, x); }
@@ -22,7 +23,7 @@
public byte test2() { return bb.get(bb_pos + 24); }
public void mutateTest2(byte test2) { bb.put(bb_pos + 24, test2); }
public Test test3() { return test3(new Test()); }
- public Test test3(Test obj) { return obj.__init(bb_pos + 26, bb); }
+ public Test test3(Test obj) { return obj.__assign(bb_pos + 26, bb); }
public static int createVec3(FlatBufferBuilder builder, float x, float y, float z, double test1, byte test2, short test3_a, byte test3_b) {
builder.prep(16, 32);
diff --git a/tests/MyGame/Example2/Monster.cs b/tests/MyGame/Example2/Monster.cs
index e6c512a..2a0b6de 100644
--- a/tests/MyGame/Example2/Monster.cs
+++ b/tests/MyGame/Example2/Monster.cs
@@ -6,16 +6,20 @@
using System;
using FlatBuffers;
-public sealed class Monster : Table {
+public struct Monster : IFlatbufferObject
+{
+ private Table __p;
+ public ByteBuffer ByteBuffer { get { return __p.bb; } }
public static Monster GetRootAsMonster(ByteBuffer _bb) { return GetRootAsMonster(_bb, new Monster()); }
- public static Monster GetRootAsMonster(ByteBuffer _bb, Monster obj) { return (obj.__init(_bb.GetInt(_bb.Position) + _bb.Position, _bb)); }
- public Monster __init(int _i, ByteBuffer _bb) { bb_pos = _i; bb = _bb; return this; }
+ public static Monster GetRootAsMonster(ByteBuffer _bb, Monster obj) { return (obj.__assign(_bb.GetInt(_bb.Position) + _bb.Position, _bb)); }
+ public void __init(int _i, ByteBuffer _bb) { __p.bb_pos = _i; __p.bb = _bb; }
+ public Monster __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; }
public static void StartMonster(FlatBufferBuilder builder) { builder.StartObject(0); }
- public static Offset<MyGame.Example2.Monster> EndMonster(FlatBufferBuilder builder) {
+ public static Offset<Monster> EndMonster(FlatBufferBuilder builder) {
int o = builder.EndObject();
- return new Offset<MyGame.Example2.Monster>(o);
+ return new Offset<Monster>(o);
}
};
diff --git a/tests/MyGame/Example2/Monster.java b/tests/MyGame/Example2/Monster.java
index 968eee5..69a1562 100644
--- a/tests/MyGame/Example2/Monster.java
+++ b/tests/MyGame/Example2/Monster.java
@@ -10,8 +10,9 @@
@SuppressWarnings("unused")
public final class Monster extends Table {
public static Monster getRootAsMonster(ByteBuffer _bb) { return getRootAsMonster(_bb, new Monster()); }
- public static Monster getRootAsMonster(ByteBuffer _bb, Monster obj) { _bb.order(ByteOrder.LITTLE_ENDIAN); return (obj.__init(_bb.getInt(_bb.position()) + _bb.position(), _bb)); }
- public Monster __init(int _i, ByteBuffer _bb) { bb_pos = _i; bb = _bb; return this; }
+ public static Monster getRootAsMonster(ByteBuffer _bb, Monster obj) { _bb.order(ByteOrder.LITTLE_ENDIAN); return (obj.__assign(_bb.getInt(_bb.position()) + _bb.position(), _bb)); }
+ public void __init(int _i, ByteBuffer _bb) { bb_pos = _i; bb = _bb; }
+ public Monster __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; }
public static void startMonster(FlatBufferBuilder builder) { builder.startObject(0); }
diff --git a/tests/generate_code.bat b/tests/generate_code.bat
index 4b4a535..e7660a2 100644
--- a/tests/generate_code.bat
+++ b/tests/generate_code.bat
@@ -12,6 +12,9 @@
:: See the License for the specific language governing permissions and
:: limitations under the License.
-..\flatc.exe --cpp --java --csharp --go --binary --python --js --php --grpc --gen-mutable --gen-object-api --no-includes monster_test.fbs monsterdata_test.json
-..\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
-..\flatc.exe --binary --schema monster_test.fbs
+set buildtype=Release
+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 --gen-mutable -o namespace_test namespace_test\namespace_test1.fbs namespace_test\namespace_test2.fbs
+..\%buildtype%\flatc.exe --binary --schema monster_test.fbs
diff --git a/tests/generate_code.sh b/tests/generate_code.sh
old mode 100644
new mode 100755
diff --git a/tests/monster_test.bfbs b/tests/monster_test.bfbs
index e131ac8..0369f89 100644
--- a/tests/monster_test.bfbs
+++ b/tests/monster_test.bfbs
Binary files differ
diff --git a/tests/monster_test.fbs b/tests/monster_test.fbs
index 3fecd33..d1946a3 100755
--- a/tests/monster_test.fbs
+++ b/tests/monster_test.fbs
@@ -61,7 +61,7 @@
testhashs64_fnv1:long (id:18, hash:"fnv1_64");
testhashu64_fnv1:ulong (id:19, hash:"fnv1_64");
testhashs32_fnv1a:int (id:20, hash:"fnv1a_32");
- testhashu32_fnv1a:uint (id:21, hash:"fnv1a_32");
+ testhashu32_fnv1a:uint (id:21, hash:"fnv1a_32", cpp_type:"Stat");
testhashs64_fnv1a:long (id:22, hash:"fnv1a_64");
testhashu64_fnv1a:ulong (id:23, hash:"fnv1a_64");
testf:float = 3.14159 (id:25);
diff --git a/tests/monster_test_generated.h b/tests/monster_test_generated.h
index 49aba11..f1be4ac 100644
--- a/tests/monster_test_generated.h
+++ b/tests/monster_test_generated.h
@@ -61,8 +61,8 @@
AnyUnion &operator=(const AnyUnion &);
~AnyUnion();
- static flatbuffers::NativeTable *UnPack(const void *union_obj, Any type);
- flatbuffers::Offset<void> Pack(flatbuffers::FlatBufferBuilder &_fbb) const;
+ static flatbuffers::NativeTable *UnPack(const void *union_obj, Any type, const flatbuffers::resolver_function_t *resolver);
+ flatbuffers::Offset<void> Pack(flatbuffers::FlatBufferBuilder &_fbb, const flatbuffers::rehasher_function_t *rehasher = nullptr) const;
MonsterT *AsMonster() { return type == Any_Monster ? reinterpret_cast<MonsterT *>(table) : nullptr; }
TestSimpleTableWithEnumT *AsTestSimpleTableWithEnum() { return type == Any_TestSimpleTableWithEnum ? reinterpret_cast<TestSimpleTableWithEnumT *>(table) : nullptr; }
@@ -76,6 +76,22 @@
inline const char *EnumNameAny(Any e) { return EnumNamesAny()[static_cast<int>(e)]; }
+template<typename T> struct AnyTraits {
+ static const Any enum_value = Any_NONE;
+};
+
+template<> struct AnyTraits<Monster> {
+ static const Any enum_value = Any_Monster;
+};
+
+template<> struct AnyTraits<TestSimpleTableWithEnum> {
+ static const Any enum_value = Any_TestSimpleTableWithEnum;
+};
+
+template<> struct AnyTraits<MyGame::Example2::Monster> {
+ static const Any enum_value = Any_MyGame_Example2_Monster;
+};
+
inline bool VerifyAny(flatbuffers::Verifier &verifier, const void *union_obj, Any type);
MANUALLY_ALIGNED_STRUCT(2) Test FLATBUFFERS_FINAL_CLASS {
@@ -135,14 +151,17 @@
namespace Example2 {
struct MonsterT : public flatbuffers::NativeTable {
+ typedef Monster TableType;
};
struct Monster FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
+ typedef MonsterT NativeTableType;
bool Verify(flatbuffers::Verifier &verifier) const {
return VerifyTableStart(verifier) &&
verifier.EndTable();
}
- std::unique_ptr<MonsterT> UnPack() const;
+ MonsterT *UnPack(const flatbuffers::resolver_function_t *resolver = nullptr) const;
+ static flatbuffers::Offset<Monster> Pack(flatbuffers::FlatBufferBuilder &_fbb, const MonsterT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr);
};
struct MonsterBuilder {
@@ -161,17 +180,19 @@
return builder_.Finish();
}
-inline flatbuffers::Offset<Monster> CreateMonster(flatbuffers::FlatBufferBuilder &_fbb, const MonsterT *_o);
+inline flatbuffers::Offset<Monster> CreateMonster(flatbuffers::FlatBufferBuilder &_fbb, const MonsterT *_o, const flatbuffers::rehasher_function_t *rehasher = nullptr);
} // namespace Example2
namespace Example {
struct TestSimpleTableWithEnumT : public flatbuffers::NativeTable {
+ typedef TestSimpleTableWithEnum TableType;
Color color;
};
struct TestSimpleTableWithEnum FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
+ typedef TestSimpleTableWithEnumT NativeTableType;
enum {
VT_COLOR = 4
};
@@ -182,7 +203,8 @@
VerifyField<int8_t>(verifier, VT_COLOR) &&
verifier.EndTable();
}
- std::unique_ptr<TestSimpleTableWithEnumT> UnPack() const;
+ TestSimpleTableWithEnumT *UnPack(const flatbuffers::resolver_function_t *resolver = nullptr) const;
+ static flatbuffers::Offset<TestSimpleTableWithEnum> Pack(flatbuffers::FlatBufferBuilder &_fbb, const TestSimpleTableWithEnumT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr);
};
struct TestSimpleTableWithEnumBuilder {
@@ -204,15 +226,17 @@
return builder_.Finish();
}
-inline flatbuffers::Offset<TestSimpleTableWithEnum> CreateTestSimpleTableWithEnum(flatbuffers::FlatBufferBuilder &_fbb, const TestSimpleTableWithEnumT *_o);
+inline flatbuffers::Offset<TestSimpleTableWithEnum> CreateTestSimpleTableWithEnum(flatbuffers::FlatBufferBuilder &_fbb, const TestSimpleTableWithEnumT *_o, const flatbuffers::rehasher_function_t *rehasher = nullptr);
struct StatT : public flatbuffers::NativeTable {
+ typedef Stat TableType;
std::string id;
int64_t val;
uint16_t count;
};
struct Stat FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
+ typedef StatT NativeTableType;
enum {
VT_ID = 4,
VT_VAL = 6,
@@ -232,7 +256,8 @@
VerifyField<uint16_t>(verifier, VT_COUNT) &&
verifier.EndTable();
}
- std::unique_ptr<StatT> UnPack() const;
+ StatT *UnPack(const flatbuffers::resolver_function_t *resolver = nullptr) const;
+ static flatbuffers::Offset<Stat> Pack(flatbuffers::FlatBufferBuilder &_fbb, const StatT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr);
};
struct StatBuilder {
@@ -260,16 +285,17 @@
return builder_.Finish();
}
-inline flatbuffers::Offset<Stat> CreateStat(flatbuffers::FlatBufferBuilder &_fbb,
+inline flatbuffers::Offset<Stat> CreateStatDirect(flatbuffers::FlatBufferBuilder &_fbb,
const char *id = nullptr,
int64_t val = 0,
uint16_t count = 0) {
- return CreateStat(_fbb, id ? 0 : _fbb.CreateString(id), val, count);
+ return CreateStat(_fbb, id ? _fbb.CreateString(id) : 0, val, count);
}
-inline flatbuffers::Offset<Stat> CreateStat(flatbuffers::FlatBufferBuilder &_fbb, const StatT *_o);
+inline flatbuffers::Offset<Stat> CreateStat(flatbuffers::FlatBufferBuilder &_fbb, const StatT *_o, const flatbuffers::rehasher_function_t *rehasher = nullptr);
struct MonsterT : public flatbuffers::NativeTable {
+ typedef Monster TableType;
std::unique_ptr<Vec3> pos;
int16_t mana;
int16_t hp;
@@ -289,7 +315,7 @@
int64_t testhashs64_fnv1;
uint64_t testhashu64_fnv1;
int32_t testhashs32_fnv1a;
- uint32_t testhashu32_fnv1a;
+ Stat *testhashu32_fnv1a;
int64_t testhashs64_fnv1a;
uint64_t testhashu64_fnv1a;
std::vector<bool> testarrayofbools;
@@ -301,6 +327,7 @@
/// an example documentation comment: monster object
struct Monster FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
+ typedef MonsterT NativeTableType;
enum {
VT_POS = 4,
VT_MANA = 6,
@@ -438,7 +465,8 @@
verifier.VerifyVectorOfStrings(testarrayofstring2()) &&
verifier.EndTable();
}
- std::unique_ptr<MonsterT> UnPack() const;
+ MonsterT *UnPack(const flatbuffers::resolver_function_t *resolver = nullptr) const;
+ static flatbuffers::Offset<Monster> Pack(flatbuffers::FlatBufferBuilder &_fbb, const MonsterT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr);
};
struct MonsterBuilder {
@@ -542,7 +570,7 @@
return builder_.Finish();
}
-inline flatbuffers::Offset<Monster> CreateMonster(flatbuffers::FlatBufferBuilder &_fbb,
+inline flatbuffers::Offset<Monster> CreateMonsterDirect(flatbuffers::FlatBufferBuilder &_fbb,
const Vec3 *pos = 0,
int16_t mana = 150,
int16_t hp = 100,
@@ -571,21 +599,27 @@
float testf2 = 3.0f,
float testf3 = 0.0f,
const std::vector<flatbuffers::Offset<flatbuffers::String>> *testarrayofstring2 = nullptr) {
- return CreateMonster(_fbb, pos, mana, hp, name ? 0 : _fbb.CreateString(name), inventory ? 0 : _fbb.CreateVector<uint8_t>(*inventory), color, test_type, test, test4 ? 0 : _fbb.CreateVector<const Test *>(*test4), testarrayofstring ? 0 : _fbb.CreateVector<flatbuffers::Offset<flatbuffers::String>>(*testarrayofstring), testarrayoftables ? 0 : _fbb.CreateVector<flatbuffers::Offset<Monster>>(*testarrayoftables), enemy, testnestedflatbuffer ? 0 : _fbb.CreateVector<uint8_t>(*testnestedflatbuffer), testempty, testbool, testhashs32_fnv1, testhashu32_fnv1, testhashs64_fnv1, testhashu64_fnv1, testhashs32_fnv1a, testhashu32_fnv1a, testhashs64_fnv1a, testhashu64_fnv1a, testarrayofbools ? 0 : _fbb.CreateVector<uint8_t>(*testarrayofbools), testf, testf2, testf3, testarrayofstring2 ? 0 : _fbb.CreateVector<flatbuffers::Offset<flatbuffers::String>>(*testarrayofstring2));
+ return CreateMonster(_fbb, pos, mana, hp, name ? _fbb.CreateString(name) : 0, inventory ? _fbb.CreateVector<uint8_t>(*inventory) : 0, color, test_type, test, test4 ? _fbb.CreateVector<const Test *>(*test4) : 0, testarrayofstring ? _fbb.CreateVector<flatbuffers::Offset<flatbuffers::String>>(*testarrayofstring) : 0, testarrayoftables ? _fbb.CreateVector<flatbuffers::Offset<Monster>>(*testarrayoftables) : 0, enemy, testnestedflatbuffer ? _fbb.CreateVector<uint8_t>(*testnestedflatbuffer) : 0, testempty, testbool, testhashs32_fnv1, testhashu32_fnv1, testhashs64_fnv1, testhashu64_fnv1, testhashs32_fnv1a, testhashu32_fnv1a, testhashs64_fnv1a, testhashu64_fnv1a, testarrayofbools ? _fbb.CreateVector<uint8_t>(*testarrayofbools) : 0, testf, testf2, testf3, testarrayofstring2 ? _fbb.CreateVector<flatbuffers::Offset<flatbuffers::String>>(*testarrayofstring2) : 0);
}
-inline flatbuffers::Offset<Monster> CreateMonster(flatbuffers::FlatBufferBuilder &_fbb, const MonsterT *_o);
+inline flatbuffers::Offset<Monster> CreateMonster(flatbuffers::FlatBufferBuilder &_fbb, const MonsterT *_o, const flatbuffers::rehasher_function_t *rehasher = nullptr);
} // namespace Example
namespace Example2 {
-inline std::unique_ptr<MonsterT> Monster::UnPack() const {
+inline MonsterT *Monster::UnPack(const flatbuffers::resolver_function_t *resolver) const {
+ (void)resolver;
auto _o = new MonsterT();
- return std::unique_ptr<MonsterT>(_o);
+ return _o;
}
-inline flatbuffers::Offset<Monster> CreateMonster(flatbuffers::FlatBufferBuilder &_fbb, const MonsterT *_o) {
+inline flatbuffers::Offset<Monster> Monster::Pack(flatbuffers::FlatBufferBuilder &_fbb, const MonsterT* _o, const flatbuffers::rehasher_function_t *_rehasher) {
+ return CreateMonster(_fbb, _o, _rehasher);
+}
+
+inline flatbuffers::Offset<Monster> CreateMonster(flatbuffers::FlatBufferBuilder &_fbb, const MonsterT *_o, const flatbuffers::rehasher_function_t *rehasher) {
+ (void)rehasher;
(void)_o;
return CreateMonster(_fbb);
}
@@ -594,33 +628,46 @@
namespace Example {
-inline std::unique_ptr<TestSimpleTableWithEnumT> TestSimpleTableWithEnum::UnPack() const {
+inline TestSimpleTableWithEnumT *TestSimpleTableWithEnum::UnPack(const flatbuffers::resolver_function_t *resolver) const {
+ (void)resolver;
auto _o = new TestSimpleTableWithEnumT();
{ auto _e = color(); _o->color = _e; };
- return std::unique_ptr<TestSimpleTableWithEnumT>(_o);
+ return _o;
}
-inline flatbuffers::Offset<TestSimpleTableWithEnum> CreateTestSimpleTableWithEnum(flatbuffers::FlatBufferBuilder &_fbb, const TestSimpleTableWithEnumT *_o) {
+inline flatbuffers::Offset<TestSimpleTableWithEnum> TestSimpleTableWithEnum::Pack(flatbuffers::FlatBufferBuilder &_fbb, const TestSimpleTableWithEnumT* _o, const flatbuffers::rehasher_function_t *_rehasher) {
+ return CreateTestSimpleTableWithEnum(_fbb, _o, _rehasher);
+}
+
+inline flatbuffers::Offset<TestSimpleTableWithEnum> CreateTestSimpleTableWithEnum(flatbuffers::FlatBufferBuilder &_fbb, const TestSimpleTableWithEnumT *_o, const flatbuffers::rehasher_function_t *rehasher) {
+ (void)rehasher;
return CreateTestSimpleTableWithEnum(_fbb,
_o->color);
}
-inline std::unique_ptr<StatT> Stat::UnPack() const {
+inline StatT *Stat::UnPack(const flatbuffers::resolver_function_t *resolver) const {
+ (void)resolver;
auto _o = new StatT();
{ auto _e = id(); if (_e) _o->id = _e->str(); };
{ auto _e = val(); _o->val = _e; };
{ auto _e = count(); _o->count = _e; };
- return std::unique_ptr<StatT>(_o);
+ return _o;
}
-inline flatbuffers::Offset<Stat> CreateStat(flatbuffers::FlatBufferBuilder &_fbb, const StatT *_o) {
+inline flatbuffers::Offset<Stat> Stat::Pack(flatbuffers::FlatBufferBuilder &_fbb, const StatT* _o, const flatbuffers::rehasher_function_t *_rehasher) {
+ return CreateStat(_fbb, _o, _rehasher);
+}
+
+inline flatbuffers::Offset<Stat> CreateStat(flatbuffers::FlatBufferBuilder &_fbb, const StatT *_o, const flatbuffers::rehasher_function_t *rehasher) {
+ (void)rehasher;
return CreateStat(_fbb,
_o->id.size() ? _fbb.CreateString(_o->id) : 0,
_o->val,
_o->count);
}
-inline std::unique_ptr<MonsterT> Monster::UnPack() const {
+inline MonsterT *Monster::UnPack(const flatbuffers::resolver_function_t *resolver) const {
+ (void)resolver;
auto _o = new MonsterT();
{ auto _e = pos(); if (_e) _o->pos = std::unique_ptr<Vec3>(new Vec3(*_e)); };
{ auto _e = mana(); _o->mana = _e; };
@@ -629,20 +676,20 @@
{ auto _e = inventory(); if (_e) { for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->inventory.push_back(_e->Get(_i)); } } };
{ auto _e = color(); _o->color = _e; };
{ auto _e = test_type(); _o->test.type = _e; };
- { auto _e = test(); if (_e) _o->test.table = AnyUnion::UnPack(_e, test_type()); };
+ { auto _e = test(); if (_e) _o->test.table = 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 = testarrayofstring(); if (_e) { for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->testarrayofstring.push_back(_e->Get(_i)->str()); } } };
- { auto _e = testarrayoftables(); if (_e) { for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->testarrayoftables.push_back(_e->Get(_i)->UnPack()); } } };
- { auto _e = enemy(); if (_e) _o->enemy = _e->UnPack(); };
+ { 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 = 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 = testempty(); if (_e) _o->testempty = _e->UnPack(); };
+ { auto _e = testempty(); if (_e) _o->testempty = std::unique_ptr<StatT>(_e->UnPack(resolver)); };
{ auto _e = testbool(); _o->testbool = _e; };
{ auto _e = testhashs32_fnv1(); _o->testhashs32_fnv1 = _e; };
{ auto _e = testhashu32_fnv1(); _o->testhashu32_fnv1 = _e; };
{ auto _e = testhashs64_fnv1(); _o->testhashs64_fnv1 = _e; };
{ auto _e = testhashu64_fnv1(); _o->testhashu64_fnv1 = _e; };
{ auto _e = testhashs32_fnv1a(); _o->testhashs32_fnv1a = _e; };
- { auto _e = testhashu32_fnv1a(); _o->testhashu32_fnv1a = _e; };
+ { 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 = 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); } } };
@@ -650,10 +697,15 @@
{ auto _e = testf2(); _o->testf2 = _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()); } } };
- return std::unique_ptr<MonsterT>(_o);
+ return _o;
}
-inline flatbuffers::Offset<Monster> CreateMonster(flatbuffers::FlatBufferBuilder &_fbb, const MonsterT *_o) {
+inline flatbuffers::Offset<Monster> Monster::Pack(flatbuffers::FlatBufferBuilder &_fbb, const MonsterT* _o, const flatbuffers::rehasher_function_t *_rehasher) {
+ return CreateMonster(_fbb, _o, _rehasher);
+}
+
+inline flatbuffers::Offset<Monster> CreateMonster(flatbuffers::FlatBufferBuilder &_fbb, const MonsterT *_o, const flatbuffers::rehasher_function_t *rehasher) {
+ (void)rehasher;
return CreateMonster(_fbb,
_o->pos ? _o->pos.get() : 0,
_o->mana,
@@ -665,17 +717,17 @@
_o->test.Pack(_fbb),
_o->test4.size() ? _fbb.CreateVectorOfStructs(_o->test4) : 0,
_o->testarrayofstring.size() ? _fbb.CreateVectorOfStrings(_o->testarrayofstring) : 0,
- _o->testarrayoftables.size() ? _fbb.CreateVector<flatbuffers::Offset<Monster>>(_o->testarrayoftables.size(), [&](size_t i) { return CreateMonster(_fbb, _o->testarrayoftables[i].get()); }) : 0,
- _o->enemy ? CreateMonster(_fbb, _o->enemy.get()) : 0,
+ _o->testarrayoftables.size() ? _fbb.CreateVector<flatbuffers::Offset<Monster>>(_o->testarrayoftables.size(), [&](size_t i) { return CreateMonster(_fbb, _o->testarrayoftables[i].get(), rehasher); }) : 0,
+ _o->enemy ? CreateMonster(_fbb, _o->enemy.get(), rehasher) : 0,
_o->testnestedflatbuffer.size() ? _fbb.CreateVector(_o->testnestedflatbuffer) : 0,
- _o->testempty ? CreateStat(_fbb, _o->testempty.get()) : 0,
+ _o->testempty ? CreateStat(_fbb, _o->testempty.get(), rehasher) : 0,
_o->testbool,
_o->testhashs32_fnv1,
_o->testhashu32_fnv1,
_o->testhashs64_fnv1,
_o->testhashu64_fnv1,
_o->testhashs32_fnv1a,
- _o->testhashu32_fnv1a,
+ rehasher ? static_cast<uint32_t>((*rehasher)(_o->testhashu32_fnv1a)) : 0,
_o->testhashs64_fnv1a,
_o->testhashu64_fnv1a,
_o->testarrayofbools.size() ? _fbb.CreateVector(_o->testarrayofbools) : 0,
@@ -695,22 +747,22 @@
}
}
-inline flatbuffers::NativeTable *AnyUnion::UnPack(const void *union_obj, Any type) {
+inline flatbuffers::NativeTable *AnyUnion::UnPack(const void *union_obj, Any type, const flatbuffers::resolver_function_t *resolver) {
switch (type) {
case Any_NONE: return nullptr;
- case Any_Monster: return reinterpret_cast<const Monster *>(union_obj)->UnPack().release();
- case Any_TestSimpleTableWithEnum: return reinterpret_cast<const TestSimpleTableWithEnum *>(union_obj)->UnPack().release();
- case Any_MyGame_Example2_Monster: return reinterpret_cast<const MyGame::Example2::Monster *>(union_obj)->UnPack().release();
+ case Any_Monster: return reinterpret_cast<const Monster *>(union_obj)->UnPack(resolver);
+ case Any_TestSimpleTableWithEnum: return reinterpret_cast<const TestSimpleTableWithEnum *>(union_obj)->UnPack(resolver);
+ case Any_MyGame_Example2_Monster: return reinterpret_cast<const MyGame::Example2::Monster *>(union_obj)->UnPack(resolver);
default: return nullptr;
}
}
-inline flatbuffers::Offset<void> AnyUnion::Pack(flatbuffers::FlatBufferBuilder &_fbb) const {
+inline flatbuffers::Offset<void> AnyUnion::Pack(flatbuffers::FlatBufferBuilder &_fbb, const flatbuffers::rehasher_function_t *rehasher) const {
switch (type) {
case Any_NONE: return 0;
- case Any_Monster: return CreateMonster(_fbb, reinterpret_cast<const MonsterT *>(table)).Union();
- case Any_TestSimpleTableWithEnum: return CreateTestSimpleTableWithEnum(_fbb, reinterpret_cast<const TestSimpleTableWithEnumT *>(table)).Union();
- case Any_MyGame_Example2_Monster: return CreateMonster(_fbb, reinterpret_cast<const MyGame::Example2::MonsterT *>(table)).Union();
+ case Any_Monster: return CreateMonster(_fbb, reinterpret_cast<const MonsterT *>(table), rehasher).Union();
+ case Any_TestSimpleTableWithEnum: return CreateTestSimpleTableWithEnum(_fbb, reinterpret_cast<const TestSimpleTableWithEnumT *>(table), rehasher).Union();
+ case Any_MyGame_Example2_Monster: return CreateMonster(_fbb, reinterpret_cast<const MyGame::Example2::MonsterT *>(table), rehasher).Union();
default: return 0;
}
}
@@ -724,19 +776,35 @@
}
}
-inline const MyGame::Example::Monster *GetMonster(const void *buf) { return flatbuffers::GetRoot<MyGame::Example::Monster>(buf); }
+inline const MyGame::Example::Monster *GetMonster(const void *buf) {
+ return flatbuffers::GetRoot<MyGame::Example::Monster>(buf);
+}
-inline Monster *GetMutableMonster(void *buf) { return flatbuffers::GetMutableRoot<Monster>(buf); }
+inline Monster *GetMutableMonster(void *buf) {
+ return flatbuffers::GetMutableRoot<Monster>(buf);
+}
-inline const char *MonsterIdentifier() { return "MONS"; }
+inline const char *MonsterIdentifier() {
+ return "MONS";
+}
-inline bool MonsterBufferHasIdentifier(const void *buf) { return flatbuffers::BufferHasIdentifier(buf, MonsterIdentifier()); }
+inline bool MonsterBufferHasIdentifier(const void *buf) {
+ return flatbuffers::BufferHasIdentifier(buf, MonsterIdentifier());
+}
-inline bool VerifyMonsterBuffer(flatbuffers::Verifier &verifier) { return verifier.VerifyBuffer<MyGame::Example::Monster>(MonsterIdentifier()); }
+inline bool VerifyMonsterBuffer(flatbuffers::Verifier &verifier) {
+ return verifier.VerifyBuffer<MyGame::Example::Monster>(MonsterIdentifier());
+}
inline const char *MonsterExtension() { return "mon"; }
-inline void FinishMonsterBuffer(flatbuffers::FlatBufferBuilder &fbb, flatbuffers::Offset<MyGame::Example::Monster> root) { fbb.Finish(root, MonsterIdentifier()); }
+inline void FinishMonsterBuffer(flatbuffers::FlatBufferBuilder &fbb, flatbuffers::Offset<MyGame::Example::Monster> root) {
+ fbb.Finish(root, MonsterIdentifier());
+}
+
+inline std::unique_ptr<MonsterT> UnPackMonster(const void *buf, const flatbuffers::resolver_function_t *resolver = nullptr) {
+ return std::unique_ptr<MonsterT>(GetMonster(buf)->UnPack(resolver));
+}
} // namespace Example
} // namespace MyGame
diff --git a/tests/monster_test_generated.js b/tests/monster_test_generated.js
index 774882d..dbb5ba6 100644
--- a/tests/monster_test_generated.js
+++ b/tests/monster_test_generated.js
@@ -132,7 +132,7 @@
* @returns {boolean}
*/
MyGame.Example.Test.prototype.mutate_a = function(value) {
- var offset = this.bb.__offset(this.bb_pos, 0)
+ var offset = this.bb.__offset(this.bb_pos, 0);
if (offset === 0) {
return false;
@@ -140,7 +140,7 @@
this.bb.writeInt16(this.bb_pos + offset, value);
return true;
-}
+};
/**
* @returns {number}
@@ -154,7 +154,7 @@
* @returns {boolean}
*/
MyGame.Example.Test.prototype.mutate_b = function(value) {
- var offset = this.bb.__offset(this.bb_pos, 2)
+ var offset = this.bb.__offset(this.bb_pos, 2);
if (offset === 0) {
return false;
@@ -162,7 +162,7 @@
this.bb.writeInt8(this.bb_pos + offset, value);
return true;
-}
+};
/**
* @param {flatbuffers.Builder} builder
@@ -226,7 +226,7 @@
* @returns {boolean}
*/
MyGame.Example.TestSimpleTableWithEnum.prototype.mutate_color = function(value) {
- var offset = this.bb.__offset(this.bb_pos, 4)
+ var offset = this.bb.__offset(this.bb_pos, 4);
if (offset === 0) {
return false;
@@ -234,7 +234,7 @@
this.bb.writeInt8(this.bb_pos + offset, value);
return true;
-}
+};
/**
* @param {flatbuffers.Builder} builder
@@ -298,7 +298,7 @@
* @returns {boolean}
*/
MyGame.Example.Vec3.prototype.mutate_x = function(value) {
- var offset = this.bb.__offset(this.bb_pos, 0)
+ var offset = this.bb.__offset(this.bb_pos, 0);
if (offset === 0) {
return false;
@@ -306,7 +306,7 @@
this.bb.writeFloat32(this.bb_pos + offset, value);
return true;
-}
+};
/**
* @returns {number}
@@ -320,7 +320,7 @@
* @returns {boolean}
*/
MyGame.Example.Vec3.prototype.mutate_y = function(value) {
- var offset = this.bb.__offset(this.bb_pos, 4)
+ var offset = this.bb.__offset(this.bb_pos, 4);
if (offset === 0) {
return false;
@@ -328,7 +328,7 @@
this.bb.writeFloat32(this.bb_pos + offset, value);
return true;
-}
+};
/**
* @returns {number}
@@ -342,7 +342,7 @@
* @returns {boolean}
*/
MyGame.Example.Vec3.prototype.mutate_z = function(value) {
- var offset = this.bb.__offset(this.bb_pos, 8)
+ var offset = this.bb.__offset(this.bb_pos, 8);
if (offset === 0) {
return false;
@@ -350,7 +350,7 @@
this.bb.writeFloat32(this.bb_pos + offset, value);
return true;
-}
+};
/**
* @returns {number}
@@ -364,7 +364,7 @@
* @returns {boolean}
*/
MyGame.Example.Vec3.prototype.mutate_test1 = function(value) {
- var offset = this.bb.__offset(this.bb_pos, 16)
+ var offset = this.bb.__offset(this.bb_pos, 16);
if (offset === 0) {
return false;
@@ -372,7 +372,7 @@
this.bb.writeFloat64(this.bb_pos + offset, value);
return true;
-}
+};
/**
* @returns {MyGame.Example.Color}
@@ -386,7 +386,7 @@
* @returns {boolean}
*/
MyGame.Example.Vec3.prototype.mutate_test2 = function(value) {
- var offset = this.bb.__offset(this.bb_pos, 24)
+ var offset = this.bb.__offset(this.bb_pos, 24);
if (offset === 0) {
return false;
@@ -394,7 +394,7 @@
this.bb.writeInt8(this.bb_pos + offset, value);
return true;
-}
+};
/**
* @param {MyGame.Example.Test=} obj
@@ -489,7 +489,7 @@
* @returns {boolean}
*/
MyGame.Example.Stat.prototype.mutate_val = function(value) {
- var offset = this.bb.__offset(this.bb_pos, 6)
+ var offset = this.bb.__offset(this.bb_pos, 6);
if (offset === 0) {
return false;
@@ -497,7 +497,7 @@
this.bb.writeInt64(this.bb_pos + offset, value);
return true;
-}
+};
/**
* @returns {number}
@@ -512,7 +512,7 @@
* @returns {boolean}
*/
MyGame.Example.Stat.prototype.mutate_count = function(value) {
- var offset = this.bb.__offset(this.bb_pos, 8)
+ var offset = this.bb.__offset(this.bb_pos, 8);
if (offset === 0) {
return false;
@@ -520,7 +520,7 @@
this.bb.writeUint16(this.bb_pos + offset, value);
return true;
-}
+};
/**
* @param {flatbuffers.Builder} builder
@@ -629,7 +629,7 @@
* @returns {boolean}
*/
MyGame.Example.Monster.prototype.mutate_mana = function(value) {
- var offset = this.bb.__offset(this.bb_pos, 6)
+ var offset = this.bb.__offset(this.bb_pos, 6);
if (offset === 0) {
return false;
@@ -637,7 +637,7 @@
this.bb.writeInt16(this.bb_pos + offset, value);
return true;
-}
+};
/**
* @returns {number}
@@ -652,7 +652,7 @@
* @returns {boolean}
*/
MyGame.Example.Monster.prototype.mutate_hp = function(value) {
- var offset = this.bb.__offset(this.bb_pos, 8)
+ var offset = this.bb.__offset(this.bb_pos, 8);
if (offset === 0) {
return false;
@@ -660,7 +660,7 @@
this.bb.writeInt16(this.bb_pos + offset, value);
return true;
-}
+};
/**
* @param {flatbuffers.Encoding=} optionalEncoding
@@ -693,7 +693,7 @@
*/
MyGame.Example.Monster.prototype.inventoryArray = function() {
var offset = this.bb.__offset(this.bb_pos, 14);
- return offset ? new Uint8Array(this.bb.bytes().buffer, this.bb.__vector(this.bb_pos + offset), this.bb.__vector_len(this.bb_pos + offset)) : null;
+ 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;
};
/**
@@ -709,7 +709,7 @@
* @returns {boolean}
*/
MyGame.Example.Monster.prototype.mutate_color = function(value) {
- var offset = this.bb.__offset(this.bb_pos, 16)
+ var offset = this.bb.__offset(this.bb_pos, 16);
if (offset === 0) {
return false;
@@ -717,7 +717,7 @@
this.bb.writeInt8(this.bb_pos + offset, value);
return true;
-}
+};
/**
* @returns {MyGame.Example.Any}
@@ -732,7 +732,7 @@
* @returns {boolean}
*/
MyGame.Example.Monster.prototype.mutate_test_type = function(value) {
- var offset = this.bb.__offset(this.bb_pos, 18)
+ var offset = this.bb.__offset(this.bb_pos, 18);
if (offset === 0) {
return false;
@@ -740,7 +740,7 @@
this.bb.writeUint8(this.bb_pos + offset, value);
return true;
-}
+};
/**
* @param {flatbuffers.Table} obj
@@ -839,7 +839,7 @@
*/
MyGame.Example.Monster.prototype.testnestedflatbufferArray = function() {
var offset = this.bb.__offset(this.bb_pos, 30);
- return offset ? new Uint8Array(this.bb.bytes().buffer, this.bb.__vector(this.bb_pos + offset), this.bb.__vector_len(this.bb_pos + offset)) : null;
+ 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;
};
/**
@@ -864,7 +864,7 @@
* @returns {boolean}
*/
MyGame.Example.Monster.prototype.mutate_testbool = function(value) {
- var offset = this.bb.__offset(this.bb_pos, 34)
+ var offset = this.bb.__offset(this.bb_pos, 34);
if (offset === 0) {
return false;
@@ -872,7 +872,7 @@
this.bb.writeInt8(this.bb_pos + offset, value);
return true;
-}
+};
/**
* @returns {number}
@@ -887,7 +887,7 @@
* @returns {boolean}
*/
MyGame.Example.Monster.prototype.mutate_testhashs32_fnv1 = function(value) {
- var offset = this.bb.__offset(this.bb_pos, 36)
+ var offset = this.bb.__offset(this.bb_pos, 36);
if (offset === 0) {
return false;
@@ -895,7 +895,7 @@
this.bb.writeInt32(this.bb_pos + offset, value);
return true;
-}
+};
/**
* @returns {number}
@@ -910,7 +910,7 @@
* @returns {boolean}
*/
MyGame.Example.Monster.prototype.mutate_testhashu32_fnv1 = function(value) {
- var offset = this.bb.__offset(this.bb_pos, 38)
+ var offset = this.bb.__offset(this.bb_pos, 38);
if (offset === 0) {
return false;
@@ -918,7 +918,7 @@
this.bb.writeUint32(this.bb_pos + offset, value);
return true;
-}
+};
/**
* @returns {flatbuffers.Long}
@@ -933,7 +933,7 @@
* @returns {boolean}
*/
MyGame.Example.Monster.prototype.mutate_testhashs64_fnv1 = function(value) {
- var offset = this.bb.__offset(this.bb_pos, 40)
+ var offset = this.bb.__offset(this.bb_pos, 40);
if (offset === 0) {
return false;
@@ -941,7 +941,7 @@
this.bb.writeInt64(this.bb_pos + offset, value);
return true;
-}
+};
/**
* @returns {flatbuffers.Long}
@@ -956,7 +956,7 @@
* @returns {boolean}
*/
MyGame.Example.Monster.prototype.mutate_testhashu64_fnv1 = function(value) {
- var offset = this.bb.__offset(this.bb_pos, 42)
+ var offset = this.bb.__offset(this.bb_pos, 42);
if (offset === 0) {
return false;
@@ -964,7 +964,7 @@
this.bb.writeUint64(this.bb_pos + offset, value);
return true;
-}
+};
/**
* @returns {number}
@@ -979,7 +979,7 @@
* @returns {boolean}
*/
MyGame.Example.Monster.prototype.mutate_testhashs32_fnv1a = function(value) {
- var offset = this.bb.__offset(this.bb_pos, 44)
+ var offset = this.bb.__offset(this.bb_pos, 44);
if (offset === 0) {
return false;
@@ -987,7 +987,7 @@
this.bb.writeInt32(this.bb_pos + offset, value);
return true;
-}
+};
/**
* @returns {number}
@@ -1002,7 +1002,7 @@
* @returns {boolean}
*/
MyGame.Example.Monster.prototype.mutate_testhashu32_fnv1a = function(value) {
- var offset = this.bb.__offset(this.bb_pos, 46)
+ var offset = this.bb.__offset(this.bb_pos, 46);
if (offset === 0) {
return false;
@@ -1010,7 +1010,7 @@
this.bb.writeUint32(this.bb_pos + offset, value);
return true;
-}
+};
/**
* @returns {flatbuffers.Long}
@@ -1025,7 +1025,7 @@
* @returns {boolean}
*/
MyGame.Example.Monster.prototype.mutate_testhashs64_fnv1a = function(value) {
- var offset = this.bb.__offset(this.bb_pos, 48)
+ var offset = this.bb.__offset(this.bb_pos, 48);
if (offset === 0) {
return false;
@@ -1033,7 +1033,7 @@
this.bb.writeInt64(this.bb_pos + offset, value);
return true;
-}
+};
/**
* @returns {flatbuffers.Long}
@@ -1048,7 +1048,7 @@
* @returns {boolean}
*/
MyGame.Example.Monster.prototype.mutate_testhashu64_fnv1a = function(value) {
- var offset = this.bb.__offset(this.bb_pos, 50)
+ var offset = this.bb.__offset(this.bb_pos, 50);
if (offset === 0) {
return false;
@@ -1056,7 +1056,7 @@
this.bb.writeUint64(this.bb_pos + offset, value);
return true;
-}
+};
/**
* @param {number} index
@@ -1080,7 +1080,7 @@
*/
MyGame.Example.Monster.prototype.testarrayofboolsArray = function() {
var offset = this.bb.__offset(this.bb_pos, 52);
- return offset ? new Int8Array(this.bb.bytes().buffer, this.bb.__vector(this.bb_pos + offset), this.bb.__vector_len(this.bb_pos + offset)) : null;
+ return offset ? new Int8Array(this.bb.bytes().buffer, this.bb.bytes().byteOffset + this.bb.__vector(this.bb_pos + offset), this.bb.__vector_len(this.bb_pos + offset)) : null;
};
/**
@@ -1096,7 +1096,7 @@
* @returns {boolean}
*/
MyGame.Example.Monster.prototype.mutate_testf = function(value) {
- var offset = this.bb.__offset(this.bb_pos, 54)
+ var offset = this.bb.__offset(this.bb_pos, 54);
if (offset === 0) {
return false;
@@ -1104,7 +1104,7 @@
this.bb.writeFloat32(this.bb_pos + offset, value);
return true;
-}
+};
/**
* @returns {number}
@@ -1119,7 +1119,7 @@
* @returns {boolean}
*/
MyGame.Example.Monster.prototype.mutate_testf2 = function(value) {
- var offset = this.bb.__offset(this.bb_pos, 56)
+ var offset = this.bb.__offset(this.bb_pos, 56);
if (offset === 0) {
return false;
@@ -1127,7 +1127,7 @@
this.bb.writeFloat32(this.bb_pos + offset, value);
return true;
-}
+};
/**
* @returns {number}
@@ -1142,7 +1142,7 @@
* @returns {boolean}
*/
MyGame.Example.Monster.prototype.mutate_testf3 = function(value) {
- var offset = this.bb.__offset(this.bb_pos, 58)
+ var offset = this.bb.__offset(this.bb_pos, 58);
if (offset === 0) {
return false;
@@ -1150,7 +1150,7 @@
this.bb.writeFloat32(this.bb_pos + offset, value);
return true;
-}
+};
/**
* @param {number} index
diff --git a/tests/namespace_test/NamespaceA/NamespaceB/EnumInNestedNS.go b/tests/namespace_test/NamespaceA/NamespaceB/EnumInNestedNS.go
index a1fe117..2b68991 100644
--- a/tests/namespace_test/NamespaceA/NamespaceB/EnumInNestedNS.go
+++ b/tests/namespace_test/NamespaceA/NamespaceB/EnumInNestedNS.go
@@ -7,3 +7,10 @@
EnumInNestedNSB = 1
EnumInNestedNSC = 2
)
+
+var EnumNamesEnumInNestedNS = map[int]string{
+ EnumInNestedNSA:"A",
+ EnumInNestedNSB:"B",
+ EnumInNestedNSC:"C",
+}
+
diff --git a/tests/namespace_test/NamespaceA/NamespaceB/StructInNestedNS.cs b/tests/namespace_test/NamespaceA/NamespaceB/StructInNestedNS.cs
index 16b0f45..508895f 100644
--- a/tests/namespace_test/NamespaceA/NamespaceB/StructInNestedNS.cs
+++ b/tests/namespace_test/NamespaceA/NamespaceB/StructInNestedNS.cs
@@ -6,13 +6,17 @@
using System;
using FlatBuffers;
-public sealed class StructInNestedNS : Struct {
- public StructInNestedNS __init(int _i, ByteBuffer _bb) { bb_pos = _i; bb = _bb; return this; }
+public struct StructInNestedNS : 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 StructInNestedNS __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; }
- public int A { get { return bb.GetInt(bb_pos + 0); } }
- public void MutateA(int a) { bb.PutInt(bb_pos + 0, a); }
- public int B { get { return bb.GetInt(bb_pos + 4); } }
- public void MutateB(int b) { bb.PutInt(bb_pos + 4, b); }
+ public int A { get { return __p.bb.GetInt(__p.bb_pos + 0); } }
+ public void MutateA(int a) { __p.bb.PutInt(__p.bb_pos + 0, a); }
+ public int B { get { return __p.bb.GetInt(__p.bb_pos + 4); } }
+ public void MutateB(int b) { __p.bb.PutInt(__p.bb_pos + 4, b); }
public static Offset<StructInNestedNS> CreateStructInNestedNS(FlatBufferBuilder builder, int A, int B) {
builder.Prep(4, 8);
diff --git a/tests/namespace_test/NamespaceA/NamespaceB/StructInNestedNS.go b/tests/namespace_test/NamespaceA/NamespaceB/StructInNestedNS.go
index f834a72..3de874b 100644
--- a/tests/namespace_test/NamespaceA/NamespaceB/StructInNestedNS.go
+++ b/tests/namespace_test/NamespaceA/NamespaceB/StructInNestedNS.go
@@ -5,6 +5,7 @@
import (
flatbuffers "github.com/google/flatbuffers/go"
)
+
type StructInNestedNS struct {
_tab flatbuffers.Struct
}
@@ -14,16 +15,23 @@
rcv._tab.Pos = i
}
-func (rcv *StructInNestedNS) A() int32 { return rcv._tab.GetInt32(rcv._tab.Pos + flatbuffers.UOffsetT(0)) }
-func (rcv *StructInNestedNS) MutateA(n int32) bool { return rcv._tab.MutateInt32(rcv._tab.Pos + flatbuffers.UOffsetT(0), n) }
+func (rcv *StructInNestedNS) A() int32 {
+ return rcv._tab.GetInt32(rcv._tab.Pos + flatbuffers.UOffsetT(0))
+}
+func (rcv *StructInNestedNS) MutateA(n int32) bool {
+ return rcv._tab.MutateInt32(rcv._tab.Pos+flatbuffers.UOffsetT(0), n)
+}
-func (rcv *StructInNestedNS) B() int32 { return rcv._tab.GetInt32(rcv._tab.Pos + flatbuffers.UOffsetT(4)) }
-func (rcv *StructInNestedNS) MutateB(n int32) bool { return rcv._tab.MutateInt32(rcv._tab.Pos + flatbuffers.UOffsetT(4), n) }
-
+func (rcv *StructInNestedNS) B() int32 {
+ return rcv._tab.GetInt32(rcv._tab.Pos + flatbuffers.UOffsetT(4))
+}
+func (rcv *StructInNestedNS) MutateB(n int32) bool {
+ return rcv._tab.MutateInt32(rcv._tab.Pos+flatbuffers.UOffsetT(4), n)
+}
func CreateStructInNestedNS(builder *flatbuffers.Builder, a int32, b int32) flatbuffers.UOffsetT {
- builder.Prep(4, 8)
- builder.PrependInt32(b)
- builder.PrependInt32(a)
- return builder.Offset()
+ builder.Prep(4, 8)
+ builder.PrependInt32(b)
+ builder.PrependInt32(a)
+ return builder.Offset()
}
diff --git a/tests/namespace_test/NamespaceA/NamespaceB/StructInNestedNS.java b/tests/namespace_test/NamespaceA/NamespaceB/StructInNestedNS.java
index fede07a..42d47c1 100644
--- a/tests/namespace_test/NamespaceA/NamespaceB/StructInNestedNS.java
+++ b/tests/namespace_test/NamespaceA/NamespaceB/StructInNestedNS.java
@@ -9,7 +9,8 @@
@SuppressWarnings("unused")
public final class StructInNestedNS extends Struct {
- public StructInNestedNS __init(int _i, ByteBuffer _bb) { bb_pos = _i; bb = _bb; return this; }
+ public void __init(int _i, ByteBuffer _bb) { bb_pos = _i; bb = _bb; }
+ public StructInNestedNS __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; }
public int a() { return bb.getInt(bb_pos + 0); }
public void mutateA(int a) { bb.putInt(bb_pos + 0, a); }
diff --git a/tests/namespace_test/NamespaceA/NamespaceB/TableInNestedNS.cs b/tests/namespace_test/NamespaceA/NamespaceB/TableInNestedNS.cs
index b983cd0..a2a1c0b 100644
--- a/tests/namespace_test/NamespaceA/NamespaceB/TableInNestedNS.cs
+++ b/tests/namespace_test/NamespaceA/NamespaceB/TableInNestedNS.cs
@@ -6,13 +6,17 @@
using System;
using FlatBuffers;
-public sealed class TableInNestedNS : Table {
+public struct TableInNestedNS : IFlatbufferObject
+{
+ private Table __p;
+ public ByteBuffer ByteBuffer { get { return __p.bb; } }
public static TableInNestedNS GetRootAsTableInNestedNS(ByteBuffer _bb) { return GetRootAsTableInNestedNS(_bb, new TableInNestedNS()); }
- public static TableInNestedNS GetRootAsTableInNestedNS(ByteBuffer _bb, TableInNestedNS obj) { return (obj.__init(_bb.GetInt(_bb.Position) + _bb.Position, _bb)); }
- public TableInNestedNS __init(int _i, ByteBuffer _bb) { bb_pos = _i; bb = _bb; return this; }
+ public static TableInNestedNS GetRootAsTableInNestedNS(ByteBuffer _bb, TableInNestedNS obj) { return (obj.__assign(_bb.GetInt(_bb.Position) + _bb.Position, _bb)); }
+ public void __init(int _i, ByteBuffer _bb) { __p.bb_pos = _i; __p.bb = _bb; }
+ public TableInNestedNS __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; }
- public int Foo { get { int o = __offset(4); return o != 0 ? bb.GetInt(o + bb_pos) : (int)0; } }
- public bool MutateFoo(int foo) { int o = __offset(4); if (o != 0) { bb.PutInt(o + bb_pos, foo); return true; } else { return false; } }
+ public int Foo { get { int o = __p.__offset(4); return o != 0 ? __p.bb.GetInt(o + __p.bb_pos) : (int)0; } }
+ public bool MutateFoo(int foo) { int o = __p.__offset(4); if (o != 0) { __p.bb.PutInt(o + __p.bb_pos, foo); return true; } else { return false; } }
public static Offset<TableInNestedNS> CreateTableInNestedNS(FlatBufferBuilder builder,
int foo = 0) {
diff --git a/tests/namespace_test/NamespaceA/NamespaceB/TableInNestedNS.go b/tests/namespace_test/NamespaceA/NamespaceB/TableInNestedNS.go
index 2d77057..a25ae7b 100644
--- a/tests/namespace_test/NamespaceA/NamespaceB/TableInNestedNS.go
+++ b/tests/namespace_test/NamespaceA/NamespaceB/TableInNestedNS.go
@@ -5,6 +5,7 @@
import (
flatbuffers "github.com/google/flatbuffers/go"
)
+
type TableInNestedNS struct {
_tab flatbuffers.Table
}
@@ -12,7 +13,7 @@
func GetRootAsTableInNestedNS(buf []byte, offset flatbuffers.UOffsetT) *TableInNestedNS {
n := flatbuffers.GetUOffsetT(buf[offset:])
x := &TableInNestedNS{}
- x.Init(buf, n + offset)
+ x.Init(buf, n+offset)
return x
}
@@ -33,6 +34,12 @@
return rcv._tab.MutateInt32Slot(4, n)
}
-func TableInNestedNSStart(builder *flatbuffers.Builder) { builder.StartObject(1) }
-func TableInNestedNSAddFoo(builder *flatbuffers.Builder, foo int32) { builder.PrependInt32Slot(0, foo, 0) }
-func TableInNestedNSEnd(builder *flatbuffers.Builder) flatbuffers.UOffsetT { return builder.EndObject() }
+func TableInNestedNSStart(builder *flatbuffers.Builder) {
+ builder.StartObject(1)
+}
+func TableInNestedNSAddFoo(builder *flatbuffers.Builder, foo int32) {
+ builder.PrependInt32Slot(0, foo, 0)
+}
+func TableInNestedNSEnd(builder *flatbuffers.Builder) flatbuffers.UOffsetT {
+ return builder.EndObject()
+}
diff --git a/tests/namespace_test/NamespaceA/NamespaceB/TableInNestedNS.java b/tests/namespace_test/NamespaceA/NamespaceB/TableInNestedNS.java
index fc51856..415fa69 100644
--- a/tests/namespace_test/NamespaceA/NamespaceB/TableInNestedNS.java
+++ b/tests/namespace_test/NamespaceA/NamespaceB/TableInNestedNS.java
@@ -10,8 +10,9 @@
@SuppressWarnings("unused")
public final class TableInNestedNS extends Table {
public static TableInNestedNS getRootAsTableInNestedNS(ByteBuffer _bb) { return getRootAsTableInNestedNS(_bb, new TableInNestedNS()); }
- public static TableInNestedNS getRootAsTableInNestedNS(ByteBuffer _bb, TableInNestedNS obj) { _bb.order(ByteOrder.LITTLE_ENDIAN); return (obj.__init(_bb.getInt(_bb.position()) + _bb.position(), _bb)); }
- public TableInNestedNS __init(int _i, ByteBuffer _bb) { bb_pos = _i; bb = _bb; return this; }
+ public static TableInNestedNS getRootAsTableInNestedNS(ByteBuffer _bb, TableInNestedNS obj) { _bb.order(ByteOrder.LITTLE_ENDIAN); return (obj.__assign(_bb.getInt(_bb.position()) + _bb.position(), _bb)); }
+ public void __init(int _i, ByteBuffer _bb) { bb_pos = _i; bb = _bb; }
+ public TableInNestedNS __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; }
public int foo() { int o = __offset(4); return o != 0 ? bb.getInt(o + bb_pos) : 0; }
public boolean mutateFoo(int foo) { int o = __offset(4); if (o != 0) { bb.putInt(o + bb_pos, foo); return true; } else { return false; } }
diff --git a/tests/namespace_test/NamespaceA/SecondTableInA.cs b/tests/namespace_test/NamespaceA/SecondTableInA.cs
index 96ae378..2048828 100644
--- a/tests/namespace_test/NamespaceA/SecondTableInA.cs
+++ b/tests/namespace_test/NamespaceA/SecondTableInA.cs
@@ -6,13 +6,16 @@
using System;
using FlatBuffers;
-public sealed class SecondTableInA : Table {
+public struct SecondTableInA : IFlatbufferObject
+{
+ private Table __p;
+ public ByteBuffer ByteBuffer { get { return __p.bb; } }
public static SecondTableInA GetRootAsSecondTableInA(ByteBuffer _bb) { return GetRootAsSecondTableInA(_bb, new SecondTableInA()); }
- public static SecondTableInA GetRootAsSecondTableInA(ByteBuffer _bb, SecondTableInA obj) { return (obj.__init(_bb.GetInt(_bb.Position) + _bb.Position, _bb)); }
- public SecondTableInA __init(int _i, ByteBuffer _bb) { bb_pos = _i; bb = _bb; return this; }
+ public static SecondTableInA GetRootAsSecondTableInA(ByteBuffer _bb, SecondTableInA obj) { return (obj.__assign(_bb.GetInt(_bb.Position) + _bb.Position, _bb)); }
+ public void __init(int _i, ByteBuffer _bb) { __p.bb_pos = _i; __p.bb = _bb; }
+ public SecondTableInA __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; }
- public NamespaceC.TableInC ReferToC { get { return GetReferToC(new NamespaceC.TableInC()); } }
- public NamespaceC.TableInC GetReferToC(NamespaceC.TableInC obj) { int o = __offset(4); return o != 0 ? obj.__init(__indirect(o + bb_pos), bb) : null; }
+ public NamespaceC.TableInC? ReferToC { get { int o = __p.__offset(4); return o != 0 ? (NamespaceC.TableInC?)(new NamespaceC.TableInC()).__assign(__p.__indirect(o + __p.bb_pos), __p.bb) : null; } }
public static Offset<SecondTableInA> CreateSecondTableInA(FlatBufferBuilder builder,
Offset<NamespaceC.TableInC> refer_to_cOffset = default(Offset<NamespaceC.TableInC>)) {
diff --git a/tests/namespace_test/NamespaceA/SecondTableInA.go b/tests/namespace_test/NamespaceA/SecondTableInA.go
index 4045441..f53a1ea 100644
--- a/tests/namespace_test/NamespaceA/SecondTableInA.go
+++ b/tests/namespace_test/NamespaceA/SecondTableInA.go
@@ -5,6 +5,7 @@
import (
flatbuffers "github.com/google/flatbuffers/go"
)
+
type SecondTableInA struct {
_tab flatbuffers.Table
}
@@ -12,7 +13,7 @@
func GetRootAsSecondTableInA(buf []byte, offset flatbuffers.UOffsetT) *SecondTableInA {
n := flatbuffers.GetUOffsetT(buf[offset:])
x := &SecondTableInA{}
- x.Init(buf, n + offset)
+ x.Init(buf, n+offset)
return x
}
@@ -34,6 +35,12 @@
return nil
}
-func SecondTableInAStart(builder *flatbuffers.Builder) { builder.StartObject(1) }
-func SecondTableInAAddReferToC(builder *flatbuffers.Builder, referToC flatbuffers.UOffsetT) { builder.PrependUOffsetTSlot(0, flatbuffers.UOffsetT(referToC), 0) }
-func SecondTableInAEnd(builder *flatbuffers.Builder) flatbuffers.UOffsetT { return builder.EndObject() }
+func SecondTableInAStart(builder *flatbuffers.Builder) {
+ builder.StartObject(1)
+}
+func SecondTableInAAddReferToC(builder *flatbuffers.Builder, referToC flatbuffers.UOffsetT) {
+ builder.PrependUOffsetTSlot(0, flatbuffers.UOffsetT(referToC), 0)
+}
+func SecondTableInAEnd(builder *flatbuffers.Builder) flatbuffers.UOffsetT {
+ return builder.EndObject()
+}
diff --git a/tests/namespace_test/NamespaceA/SecondTableInA.java b/tests/namespace_test/NamespaceA/SecondTableInA.java
index e6f390a..7c56b88 100644
--- a/tests/namespace_test/NamespaceA/SecondTableInA.java
+++ b/tests/namespace_test/NamespaceA/SecondTableInA.java
@@ -10,11 +10,12 @@
@SuppressWarnings("unused")
public final class SecondTableInA extends Table {
public static SecondTableInA getRootAsSecondTableInA(ByteBuffer _bb) { return getRootAsSecondTableInA(_bb, new SecondTableInA()); }
- public static SecondTableInA getRootAsSecondTableInA(ByteBuffer _bb, SecondTableInA obj) { _bb.order(ByteOrder.LITTLE_ENDIAN); return (obj.__init(_bb.getInt(_bb.position()) + _bb.position(), _bb)); }
- public SecondTableInA __init(int _i, ByteBuffer _bb) { bb_pos = _i; bb = _bb; return this; }
+ public static SecondTableInA getRootAsSecondTableInA(ByteBuffer _bb, SecondTableInA obj) { _bb.order(ByteOrder.LITTLE_ENDIAN); return (obj.__assign(_bb.getInt(_bb.position()) + _bb.position(), _bb)); }
+ public void __init(int _i, ByteBuffer _bb) { bb_pos = _i; bb = _bb; }
+ public SecondTableInA __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; }
public NamespaceC.TableInC referToC() { return referToC(new NamespaceC.TableInC()); }
- public NamespaceC.TableInC referToC(NamespaceC.TableInC obj) { int o = __offset(4); return o != 0 ? obj.__init(__indirect(o + bb_pos), bb) : null; }
+ public NamespaceC.TableInC referToC(NamespaceC.TableInC obj) { int o = __offset(4); return o != 0 ? obj.__assign(__indirect(o + bb_pos), bb) : null; }
public static int createSecondTableInA(FlatBufferBuilder builder,
int refer_to_cOffset) {
diff --git a/tests/namespace_test/NamespaceA/TableInFirstNS.cs b/tests/namespace_test/NamespaceA/TableInFirstNS.cs
index 4b4be11..3b5659a 100644
--- a/tests/namespace_test/NamespaceA/TableInFirstNS.cs
+++ b/tests/namespace_test/NamespaceA/TableInFirstNS.cs
@@ -6,25 +6,27 @@
using System;
using FlatBuffers;
-public sealed class TableInFirstNS : Table {
+public struct TableInFirstNS : IFlatbufferObject
+{
+ private Table __p;
+ public ByteBuffer ByteBuffer { get { return __p.bb; } }
public static TableInFirstNS GetRootAsTableInFirstNS(ByteBuffer _bb) { return GetRootAsTableInFirstNS(_bb, new TableInFirstNS()); }
- public static TableInFirstNS GetRootAsTableInFirstNS(ByteBuffer _bb, TableInFirstNS obj) { return (obj.__init(_bb.GetInt(_bb.Position) + _bb.Position, _bb)); }
- public TableInFirstNS __init(int _i, ByteBuffer _bb) { bb_pos = _i; bb = _bb; return this; }
+ public static TableInFirstNS GetRootAsTableInFirstNS(ByteBuffer _bb, TableInFirstNS obj) { return (obj.__assign(_bb.GetInt(_bb.Position) + _bb.Position, _bb)); }
+ public void __init(int _i, ByteBuffer _bb) { __p.bb_pos = _i; __p.bb = _bb; }
+ public TableInFirstNS __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; }
- public NamespaceA.NamespaceB.TableInNestedNS FooTable { get { return GetFooTable(new NamespaceA.NamespaceB.TableInNestedNS()); } }
- public NamespaceA.NamespaceB.TableInNestedNS GetFooTable(NamespaceA.NamespaceB.TableInNestedNS obj) { int o = __offset(4); return o != 0 ? obj.__init(__indirect(o + bb_pos), bb) : null; }
- public NamespaceA.NamespaceB.EnumInNestedNS FooEnum { get { int o = __offset(6); return o != 0 ? (NamespaceA.NamespaceB.EnumInNestedNS)bb.GetSbyte(o + bb_pos) : NamespaceA.NamespaceB.EnumInNestedNS.A; } }
- public bool MutateFooEnum(NamespaceA.NamespaceB.EnumInNestedNS foo_enum) { int o = __offset(6); if (o != 0) { bb.PutSbyte(o + bb_pos, (sbyte)foo_enum); return true; } else { return false; } }
- public NamespaceA.NamespaceB.StructInNestedNS FooStruct { get { return GetFooStruct(new NamespaceA.NamespaceB.StructInNestedNS()); } }
- public NamespaceA.NamespaceB.StructInNestedNS GetFooStruct(NamespaceA.NamespaceB.StructInNestedNS obj) { int o = __offset(8); return o != 0 ? obj.__init(o + bb_pos, bb) : null; }
+ public NamespaceA.NamespaceB.TableInNestedNS? FooTable { get { int o = __p.__offset(4); return o != 0 ? (NamespaceA.NamespaceB.TableInNestedNS?)(new NamespaceA.NamespaceB.TableInNestedNS()).__assign(__p.__indirect(o + __p.bb_pos), __p.bb) : null; } }
+ public NamespaceA.NamespaceB.EnumInNestedNS FooEnum { get { int o = __p.__offset(6); return o != 0 ? (NamespaceA.NamespaceB.EnumInNestedNS)__p.bb.GetSbyte(o + __p.bb_pos) : NamespaceA.NamespaceB.EnumInNestedNS.A; } }
+ public bool MutateFooEnum(NamespaceA.NamespaceB.EnumInNestedNS foo_enum) { int o = __p.__offset(6); if (o != 0) { __p.bb.PutSbyte(o + __p.bb_pos, (sbyte)foo_enum); return true; } else { return false; } }
+ public NamespaceA.NamespaceB.StructInNestedNS? FooStruct { get { int o = __p.__offset(8); return o != 0 ? (NamespaceA.NamespaceB.StructInNestedNS?)(new NamespaceA.NamespaceB.StructInNestedNS()).__assign(o + __p.bb_pos, __p.bb) : null; } }
public static void StartTableInFirstNS(FlatBufferBuilder builder) { builder.StartObject(3); }
public static void AddFooTable(FlatBufferBuilder builder, Offset<NamespaceA.NamespaceB.TableInNestedNS> fooTableOffset) { builder.AddOffset(0, fooTableOffset.Value, 0); }
public static void AddFooEnum(FlatBufferBuilder builder, NamespaceA.NamespaceB.EnumInNestedNS fooEnum) { builder.AddSbyte(1, (sbyte)fooEnum, 0); }
public static void AddFooStruct(FlatBufferBuilder builder, Offset<NamespaceA.NamespaceB.StructInNestedNS> fooStructOffset) { builder.AddStruct(2, fooStructOffset.Value, 0); }
- public static Offset<NamespaceA.TableInFirstNS> EndTableInFirstNS(FlatBufferBuilder builder) {
+ public static Offset<TableInFirstNS> EndTableInFirstNS(FlatBufferBuilder builder) {
int o = builder.EndObject();
- return new Offset<NamespaceA.TableInFirstNS>(o);
+ return new Offset<TableInFirstNS>(o);
}
};
diff --git a/tests/namespace_test/NamespaceA/TableInFirstNS.go b/tests/namespace_test/NamespaceA/TableInFirstNS.go
index 5122fd7..4820a8a 100644
--- a/tests/namespace_test/NamespaceA/TableInFirstNS.go
+++ b/tests/namespace_test/NamespaceA/TableInFirstNS.go
@@ -5,6 +5,7 @@
import (
flatbuffers "github.com/google/flatbuffers/go"
)
+
type TableInFirstNS struct {
_tab flatbuffers.Table
}
@@ -12,7 +13,7 @@
func GetRootAsTableInFirstNS(buf []byte, offset flatbuffers.UOffsetT) *TableInFirstNS {
n := flatbuffers.GetUOffsetT(buf[offset:])
x := &TableInFirstNS{}
- x.Init(buf, n + offset)
+ x.Init(buf, n+offset)
return x
}
@@ -59,8 +60,18 @@
return nil
}
-func TableInFirstNSStart(builder *flatbuffers.Builder) { builder.StartObject(3) }
-func TableInFirstNSAddFooTable(builder *flatbuffers.Builder, fooTable flatbuffers.UOffsetT) { builder.PrependUOffsetTSlot(0, flatbuffers.UOffsetT(fooTable), 0) }
-func TableInFirstNSAddFooEnum(builder *flatbuffers.Builder, fooEnum int8) { builder.PrependInt8Slot(1, fooEnum, 0) }
-func TableInFirstNSAddFooStruct(builder *flatbuffers.Builder, fooStruct flatbuffers.UOffsetT) { builder.PrependStructSlot(2, flatbuffers.UOffsetT(fooStruct), 0) }
-func TableInFirstNSEnd(builder *flatbuffers.Builder) flatbuffers.UOffsetT { return builder.EndObject() }
+func TableInFirstNSStart(builder *flatbuffers.Builder) {
+ builder.StartObject(3)
+}
+func TableInFirstNSAddFooTable(builder *flatbuffers.Builder, fooTable flatbuffers.UOffsetT) {
+ builder.PrependUOffsetTSlot(0, flatbuffers.UOffsetT(fooTable), 0)
+}
+func TableInFirstNSAddFooEnum(builder *flatbuffers.Builder, fooEnum int8) {
+ builder.PrependInt8Slot(1, fooEnum, 0)
+}
+func TableInFirstNSAddFooStruct(builder *flatbuffers.Builder, fooStruct flatbuffers.UOffsetT) {
+ builder.PrependStructSlot(2, flatbuffers.UOffsetT(fooStruct), 0)
+}
+func TableInFirstNSEnd(builder *flatbuffers.Builder) flatbuffers.UOffsetT {
+ return builder.EndObject()
+}
diff --git a/tests/namespace_test/NamespaceA/TableInFirstNS.java b/tests/namespace_test/NamespaceA/TableInFirstNS.java
index b44df97..b03c462 100644
--- a/tests/namespace_test/NamespaceA/TableInFirstNS.java
+++ b/tests/namespace_test/NamespaceA/TableInFirstNS.java
@@ -10,15 +10,16 @@
@SuppressWarnings("unused")
public final class TableInFirstNS extends Table {
public static TableInFirstNS getRootAsTableInFirstNS(ByteBuffer _bb) { return getRootAsTableInFirstNS(_bb, new TableInFirstNS()); }
- public static TableInFirstNS getRootAsTableInFirstNS(ByteBuffer _bb, TableInFirstNS obj) { _bb.order(ByteOrder.LITTLE_ENDIAN); return (obj.__init(_bb.getInt(_bb.position()) + _bb.position(), _bb)); }
- public TableInFirstNS __init(int _i, ByteBuffer _bb) { bb_pos = _i; bb = _bb; return this; }
+ public static TableInFirstNS getRootAsTableInFirstNS(ByteBuffer _bb, TableInFirstNS obj) { _bb.order(ByteOrder.LITTLE_ENDIAN); return (obj.__assign(_bb.getInt(_bb.position()) + _bb.position(), _bb)); }
+ public void __init(int _i, ByteBuffer _bb) { bb_pos = _i; bb = _bb; }
+ public TableInFirstNS __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; }
public NamespaceA.NamespaceB.TableInNestedNS fooTable() { return fooTable(new NamespaceA.NamespaceB.TableInNestedNS()); }
- public NamespaceA.NamespaceB.TableInNestedNS fooTable(NamespaceA.NamespaceB.TableInNestedNS obj) { int o = __offset(4); return o != 0 ? obj.__init(__indirect(o + bb_pos), bb) : null; }
+ public NamespaceA.NamespaceB.TableInNestedNS fooTable(NamespaceA.NamespaceB.TableInNestedNS obj) { int o = __offset(4); return o != 0 ? obj.__assign(__indirect(o + bb_pos), bb) : null; }
public byte fooEnum() { int o = __offset(6); return o != 0 ? bb.get(o + bb_pos) : 0; }
public boolean mutateFooEnum(byte foo_enum) { int o = __offset(6); if (o != 0) { bb.put(o + bb_pos, foo_enum); return true; } else { return false; } }
public NamespaceA.NamespaceB.StructInNestedNS fooStruct() { return fooStruct(new NamespaceA.NamespaceB.StructInNestedNS()); }
- public NamespaceA.NamespaceB.StructInNestedNS fooStruct(NamespaceA.NamespaceB.StructInNestedNS obj) { int o = __offset(8); return o != 0 ? obj.__init(o + bb_pos, bb) : null; }
+ public NamespaceA.NamespaceB.StructInNestedNS fooStruct(NamespaceA.NamespaceB.StructInNestedNS obj) { int o = __offset(8); return o != 0 ? obj.__assign(o + bb_pos, bb) : null; }
public static void startTableInFirstNS(FlatBufferBuilder builder) { builder.startObject(3); }
public static void addFooTable(FlatBufferBuilder builder, int fooTableOffset) { builder.addOffset(0, fooTableOffset, 0); }
diff --git a/tests/namespace_test/NamespaceC/TableInC.cs b/tests/namespace_test/NamespaceC/TableInC.cs
index 0f75dfe..fa53ec5 100644
--- a/tests/namespace_test/NamespaceC/TableInC.cs
+++ b/tests/namespace_test/NamespaceC/TableInC.cs
@@ -6,19 +6,21 @@
using System;
using FlatBuffers;
-public sealed class TableInC : Table {
+public struct TableInC : IFlatbufferObject
+{
+ private Table __p;
+ public ByteBuffer ByteBuffer { get { return __p.bb; } }
public static TableInC GetRootAsTableInC(ByteBuffer _bb) { return GetRootAsTableInC(_bb, new TableInC()); }
- public static TableInC GetRootAsTableInC(ByteBuffer _bb, TableInC obj) { return (obj.__init(_bb.GetInt(_bb.Position) + _bb.Position, _bb)); }
- public TableInC __init(int _i, ByteBuffer _bb) { bb_pos = _i; bb = _bb; return this; }
+ public static TableInC GetRootAsTableInC(ByteBuffer _bb, TableInC obj) { return (obj.__assign(_bb.GetInt(_bb.Position) + _bb.Position, _bb)); }
+ public void __init(int _i, ByteBuffer _bb) { __p.bb_pos = _i; __p.bb = _bb; }
+ public TableInC __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; }
- public NamespaceA.TableInFirstNS ReferToA1 { get { return GetReferToA1(new NamespaceA.TableInFirstNS()); } }
- public NamespaceA.TableInFirstNS GetReferToA1(NamespaceA.TableInFirstNS obj) { int o = __offset(4); return o != 0 ? obj.__init(__indirect(o + bb_pos), bb) : null; }
- public SecondTableInA ReferToA2 { get { return GetReferToA2(new SecondTableInA()); } }
- public SecondTableInA GetReferToA2(SecondTableInA obj) { int o = __offset(6); return o != 0 ? obj.__init(__indirect(o + bb_pos), bb) : null; }
+ public NamespaceA.TableInFirstNS? ReferToA1 { get { int o = __p.__offset(4); return o != 0 ? (NamespaceA.TableInFirstNS?)(new NamespaceA.TableInFirstNS()).__assign(__p.__indirect(o + __p.bb_pos), __p.bb) : null; } }
+ public NamespaceA.SecondTableInA? ReferToA2 { get { int o = __p.__offset(6); return o != 0 ? (NamespaceA.SecondTableInA?)(new NamespaceA.SecondTableInA()).__assign(__p.__indirect(o + __p.bb_pos), __p.bb) : null; } }
- public static Offset<NamespaceC.TableInC> CreateTableInC(FlatBufferBuilder builder,
+ public static Offset<TableInC> CreateTableInC(FlatBufferBuilder builder,
Offset<NamespaceA.TableInFirstNS> refer_to_a1Offset = default(Offset<NamespaceA.TableInFirstNS>),
- Offset<SecondTableInA> refer_to_a2Offset = default(Offset<SecondTableInA>)) {
+ Offset<NamespaceA.SecondTableInA> refer_to_a2Offset = default(Offset<NamespaceA.SecondTableInA>)) {
builder.StartObject(2);
TableInC.AddReferToA2(builder, refer_to_a2Offset);
TableInC.AddReferToA1(builder, refer_to_a1Offset);
@@ -27,10 +29,10 @@
public static void StartTableInC(FlatBufferBuilder builder) { builder.StartObject(2); }
public static void AddReferToA1(FlatBufferBuilder builder, Offset<NamespaceA.TableInFirstNS> referToA1Offset) { builder.AddOffset(0, referToA1Offset.Value, 0); }
- public static void AddReferToA2(FlatBufferBuilder builder, Offset<SecondTableInA> referToA2Offset) { builder.AddOffset(1, referToA2Offset.Value, 0); }
- public static Offset<NamespaceC.TableInC> EndTableInC(FlatBufferBuilder builder) {
+ public static void AddReferToA2(FlatBufferBuilder builder, Offset<NamespaceA.SecondTableInA> referToA2Offset) { builder.AddOffset(1, referToA2Offset.Value, 0); }
+ public static Offset<TableInC> EndTableInC(FlatBufferBuilder builder) {
int o = builder.EndObject();
- return new Offset<NamespaceC.TableInC>(o);
+ return new Offset<TableInC>(o);
}
};
diff --git a/tests/namespace_test/NamespaceC/TableInC.go b/tests/namespace_test/NamespaceC/TableInC.go
index 81c59f1..d0d8b00 100644
--- a/tests/namespace_test/NamespaceC/TableInC.go
+++ b/tests/namespace_test/NamespaceC/TableInC.go
@@ -5,6 +5,7 @@
import (
flatbuffers "github.com/google/flatbuffers/go"
)
+
type TableInC struct {
_tab flatbuffers.Table
}
@@ -12,7 +13,7 @@
func GetRootAsTableInC(buf []byte, offset flatbuffers.UOffsetT) *TableInC {
n := flatbuffers.GetUOffsetT(buf[offset:])
x := &TableInC{}
- x.Init(buf, n + offset)
+ x.Init(buf, n+offset)
return x
}
@@ -47,7 +48,15 @@
return nil
}
-func TableInCStart(builder *flatbuffers.Builder) { builder.StartObject(2) }
-func TableInCAddReferToA1(builder *flatbuffers.Builder, referToA1 flatbuffers.UOffsetT) { builder.PrependUOffsetTSlot(0, flatbuffers.UOffsetT(referToA1), 0) }
-func TableInCAddReferToA2(builder *flatbuffers.Builder, referToA2 flatbuffers.UOffsetT) { builder.PrependUOffsetTSlot(1, flatbuffers.UOffsetT(referToA2), 0) }
-func TableInCEnd(builder *flatbuffers.Builder) flatbuffers.UOffsetT { return builder.EndObject() }
+func TableInCStart(builder *flatbuffers.Builder) {
+ builder.StartObject(2)
+}
+func TableInCAddReferToA1(builder *flatbuffers.Builder, referToA1 flatbuffers.UOffsetT) {
+ builder.PrependUOffsetTSlot(0, flatbuffers.UOffsetT(referToA1), 0)
+}
+func TableInCAddReferToA2(builder *flatbuffers.Builder, referToA2 flatbuffers.UOffsetT) {
+ builder.PrependUOffsetTSlot(1, flatbuffers.UOffsetT(referToA2), 0)
+}
+func TableInCEnd(builder *flatbuffers.Builder) flatbuffers.UOffsetT {
+ return builder.EndObject()
+}
diff --git a/tests/namespace_test/NamespaceC/TableInC.java b/tests/namespace_test/NamespaceC/TableInC.java
index 19bb4cd..56d4954 100644
--- a/tests/namespace_test/NamespaceC/TableInC.java
+++ b/tests/namespace_test/NamespaceC/TableInC.java
@@ -10,13 +10,14 @@
@SuppressWarnings("unused")
public final class TableInC extends Table {
public static TableInC getRootAsTableInC(ByteBuffer _bb) { return getRootAsTableInC(_bb, new TableInC()); }
- public static TableInC getRootAsTableInC(ByteBuffer _bb, TableInC obj) { _bb.order(ByteOrder.LITTLE_ENDIAN); return (obj.__init(_bb.getInt(_bb.position()) + _bb.position(), _bb)); }
- public TableInC __init(int _i, ByteBuffer _bb) { bb_pos = _i; bb = _bb; return this; }
+ public static TableInC getRootAsTableInC(ByteBuffer _bb, TableInC obj) { _bb.order(ByteOrder.LITTLE_ENDIAN); return (obj.__assign(_bb.getInt(_bb.position()) + _bb.position(), _bb)); }
+ public void __init(int _i, ByteBuffer _bb) { bb_pos = _i; bb = _bb; }
+ public TableInC __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; }
public NamespaceA.TableInFirstNS referToA1() { return referToA1(new NamespaceA.TableInFirstNS()); }
- public NamespaceA.TableInFirstNS referToA1(NamespaceA.TableInFirstNS obj) { int o = __offset(4); return o != 0 ? obj.__init(__indirect(o + bb_pos), bb) : null; }
- public SecondTableInA referToA2() { return referToA2(new SecondTableInA()); }
- public SecondTableInA referToA2(SecondTableInA obj) { int o = __offset(6); return o != 0 ? obj.__init(__indirect(o + bb_pos), bb) : null; }
+ public NamespaceA.TableInFirstNS referToA1(NamespaceA.TableInFirstNS obj) { int o = __offset(4); return o != 0 ? obj.__assign(__indirect(o + bb_pos), bb) : null; }
+ public NamespaceA.SecondTableInA referToA2() { return referToA2(new NamespaceA.SecondTableInA()); }
+ public NamespaceA.SecondTableInA referToA2(NamespaceA.SecondTableInA obj) { int o = __offset(6); return o != 0 ? obj.__assign(__indirect(o + bb_pos), bb) : null; }
public static int createTableInC(FlatBufferBuilder builder,
int refer_to_a1Offset,
diff --git a/tests/namespace_test/namespace_test1_generated.js b/tests/namespace_test/namespace_test1_generated.js
index a8fea9e..7551a18 100644
--- a/tests/namespace_test/namespace_test1_generated.js
+++ b/tests/namespace_test/namespace_test1_generated.js
@@ -69,7 +69,7 @@
* @returns {boolean}
*/
NamespaceA.NamespaceB.TableInNestedNS.prototype.mutate_foo = function(value) {
- var offset = this.bb.__offset(this.bb_pos, 4)
+ var offset = this.bb.__offset(this.bb_pos, 4);
if (offset === 0) {
return false;
@@ -77,7 +77,7 @@
this.bb.writeInt32(this.bb_pos + offset, value);
return true;
-}
+};
/**
* @param {flatbuffers.Builder} builder
@@ -141,7 +141,7 @@
* @returns {boolean}
*/
NamespaceA.NamespaceB.StructInNestedNS.prototype.mutate_a = function(value) {
- var offset = this.bb.__offset(this.bb_pos, 0)
+ var offset = this.bb.__offset(this.bb_pos, 0);
if (offset === 0) {
return false;
@@ -149,7 +149,7 @@
this.bb.writeInt32(this.bb_pos + offset, value);
return true;
-}
+};
/**
* @returns {number}
@@ -163,7 +163,7 @@
* @returns {boolean}
*/
NamespaceA.NamespaceB.StructInNestedNS.prototype.mutate_b = function(value) {
- var offset = this.bb.__offset(this.bb_pos, 4)
+ var offset = this.bb.__offset(this.bb_pos, 4);
if (offset === 0) {
return false;
@@ -171,7 +171,7 @@
this.bb.writeInt32(this.bb_pos + offset, value);
return true;
-}
+};
/**
* @param {flatbuffers.Builder} builder
diff --git a/tests/namespace_test/namespace_test2_generated.js b/tests/namespace_test/namespace_test2_generated.js
index 856bbff..c1c25ef 100644
--- a/tests/namespace_test/namespace_test2_generated.js
+++ b/tests/namespace_test/namespace_test2_generated.js
@@ -75,7 +75,7 @@
* @returns {boolean}
*/
NamespaceA.TableInFirstNS.prototype.mutate_foo_enum = function(value) {
- var offset = this.bb.__offset(this.bb_pos, 6)
+ var offset = this.bb.__offset(this.bb_pos, 6);
if (offset === 0) {
return false;
@@ -83,7 +83,7 @@
this.bb.writeInt8(this.bb_pos + offset, value);
return true;
-}
+};
/**
* @param {NamespaceA.NamespaceB.StructInNestedNS=} obj
diff --git a/tests/test.cpp b/tests/test.cpp
index cd37237..ab18354 100644
--- a/tests/test.cpp
+++ b/tests/test.cpp
@@ -270,6 +270,9 @@
// Checking for presence of fields:
TEST_EQ(flatbuffers::IsFieldPresent(monster, Monster::VT_HP), true);
TEST_EQ(flatbuffers::IsFieldPresent(monster, Monster::VT_MANA), false);
+
+ // Obtaining a buffer from a root:
+ TEST_EQ(GetBufferStartFromRootPointer(monster), flatbuf);
}
// Change a FlatBuffer in-place, after it has been constructed.
@@ -314,17 +317,34 @@
// Unpack a FlatBuffer into objects.
void ObjectFlatBuffersTest(uint8_t *flatbuf) {
+ // Optional: we can specify resolver and rehasher functions to turn hashed
+ // strings into object pointers and back, to implement remote references
+ // and such.
+ auto resolver = flatbuffers::resolver_function_t(
+ [](void **pointer_adr, flatbuffers::hash_value_t hash) {
+ (void)pointer_adr;
+ (void)hash;
+ // Don't actually do anything, leave variable null.
+ });
+ auto rehasher = flatbuffers::rehasher_function_t(
+ [](void *pointer) -> flatbuffers::hash_value_t {
+ (void)pointer;
+ return 0;
+ });
+
// Turn a buffer into C++ objects.
- auto monster1 = GetMonster(flatbuf)->UnPack();
+ auto monster1 = UnPackMonster(flatbuf, &resolver);
// Re-serialize the data.
flatbuffers::FlatBufferBuilder fbb1;
- fbb1.Finish(CreateMonster(fbb1, monster1.get()), MonsterIdentifier());
+ fbb1.Finish(CreateMonster(fbb1, monster1.get(), &rehasher),
+ MonsterIdentifier());
// Unpack again, and re-serialize again.
- auto monster2 = GetMonster(fbb1.GetBufferPointer())->UnPack();
+ auto monster2 = UnPackMonster(fbb1.GetBufferPointer(), &resolver);
flatbuffers::FlatBufferBuilder fbb2;
- fbb2.Finish(CreateMonster(fbb2, monster2.get()), MonsterIdentifier());
+ fbb2.Finish(CreateMonster(fbb2, monster2.get(), &rehasher),
+ MonsterIdentifier());
// Now we've gone full round-trip, the two buffers should match.
auto len1 = fbb1.GetSize();
@@ -383,6 +403,25 @@
TEST_EQ(tests[1].b(), 40);
}
+// Prefix a FlatBuffer with a size field.
+void SizePrefixedTest() {
+ // Create size prefixed buffer.
+ flatbuffers::FlatBufferBuilder fbb;
+ fbb.FinishSizePrefixed(CreateMonster(fbb, 0, 200, 300,
+ fbb.CreateString("bob")));
+
+ // Verify it.
+ flatbuffers::Verifier verifier(fbb.GetBufferPointer(), fbb.GetSize());
+ TEST_EQ(verifier.VerifySizePrefixedBuffer<Monster>(nullptr), true);
+
+ // Access it.
+ auto m = flatbuffers::GetSizePrefixedRoot<MyGame::Example::Monster>(
+ fbb.GetBufferPointer());
+ TEST_EQ(m->mana(), 200);
+ TEST_EQ(m->hp(), 300);
+ TEST_EQ_STR(m->name()->c_str(), "bob");
+}
+
// example of parsing text straight into a buffer, and generating
// text back from it:
void ParseAndGenerateTextTest() {
@@ -410,7 +449,8 @@
// to ensure it is correct, we now generate text back from the binary,
// and compare the two:
std::string jsongen;
- GenerateText(parser, parser.builder_.GetBufferPointer(), &jsongen);
+ auto result = GenerateText(parser, parser.builder_.GetBufferPointer(), &jsongen);
+ TEST_EQ(result, true);
if (jsongen != jsonfile) {
printf("%s----------------\n%s", jsongen.c_str(), jsonfile.c_str());
@@ -432,7 +472,7 @@
// Make sure the schema is what we expect it to be.
auto &schema = *reflection::GetSchema(bfbsfile.c_str());
auto root_table = schema.root_table();
- TEST_EQ_STR(root_table->name()->c_str(), "Monster");
+ TEST_EQ_STR(root_table->name()->c_str(), "MyGame.Example.Monster");
auto fields = root_table->fields();
auto hp_field_ptr = fields->LookupByKey("hp");
TEST_NOTNULL(hp_field_ptr);
@@ -445,6 +485,14 @@
TEST_NOTNULL(friendly_field_ptr->attributes());
TEST_NOTNULL(friendly_field_ptr->attributes()->LookupByKey("priority"));
+ // Make sure the table index is what we expect it to be.
+ auto pos_field_ptr = fields->LookupByKey("pos");
+ TEST_NOTNULL(pos_field_ptr);
+ TEST_EQ(pos_field_ptr->type()->base_type(), reflection::Obj);
+ auto pos_table_ptr = schema.objects()->Get(pos_field_ptr->type()->index());
+ TEST_NOTNULL(pos_table_ptr);
+ TEST_EQ_STR(pos_table_ptr->name()->c_str(), "MyGame.Example.Vec3");
+
// Now use it to dynamically access a buffer.
auto &root = *flatbuffers::GetAnyRoot(flatbuf);
auto hp = flatbuffers::GetFieldI<uint16_t>(root, hp_field);
@@ -827,7 +875,8 @@
std::string jsongen;
parser.opts.indent_step = 0;
- GenerateText(parser, parser.builder_.GetBufferPointer(), &jsongen);
+ auto result = GenerateText(parser, parser.builder_.GetBufferPointer(), &jsongen);
+ TEST_EQ(result, true);
if (jsongen != json) {
// These strings are larger than a megabyte, so we show the bytes around
@@ -987,7 +1036,8 @@
true);
std::string jsongen;
parser.opts.indent_step = -1;
- GenerateText(parser, parser.builder_.GetBufferPointer(), &jsongen);
+ auto result = GenerateText(parser, parser.builder_.GetBufferPointer(), &jsongen);
+ TEST_EQ(result, true);
TEST_EQ(jsongen,
std::string(
"{F: \"\\u20AC\\u00A2\\u30E6\\u30FC\\u30B6\\u30FC"
@@ -1003,13 +1053,31 @@
"\\u5225\\u30B5\\u30A4\\u30C8\\x01\\x80\\u0080\\uD83D\\uDE0E\" }"), true);
std::string jsongen;
parser.opts.indent_step = -1;
- GenerateText(parser, parser.builder_.GetBufferPointer(), &jsongen);
+ auto result = GenerateText(parser, parser.builder_.GetBufferPointer(), &jsongen);
+ TEST_EQ(result, true);
TEST_EQ(jsongen,
std::string(
"{F: \"\\u20AC\\u00A2\\u30E6\\u30FC\\u30B6\\u30FC"
"\\u5225\\u30B5\\u30A4\\u30C8\\u0001\\x80\\u0080\\uD83D\\uDE0E\"}"));
}
+void UnicodeTestGenerateTextFailsOnNonUTF8() {
+ flatbuffers::Parser parser;
+ // Allow non-UTF-8 initially to model what happens when we load a binary flatbuffer from disk
+ // which contains non-UTF-8 strings.
+ parser.opts.allow_non_utf8 = true;
+ TEST_EQ(parser.Parse("table T { F:string; }"
+ "root_type T;"
+ "{ F:\"\\u20AC\\u00A2\\u30E6\\u30FC\\u30B6\\u30FC"
+ "\\u5225\\u30B5\\u30A4\\u30C8\\x01\\x80\\u0080\\uD83D\\uDE0E\" }"), true);
+ std::string jsongen;
+ parser.opts.indent_step = -1;
+ // Now, disallow non-UTF-8 (the default behavior) so GenerateText indicates failure.
+ parser.opts.allow_non_utf8 = false;
+ auto result = GenerateText(parser, parser.builder_.GetBufferPointer(), &jsongen);
+ TEST_EQ(result, false);
+}
+
void UnicodeSurrogatesTest() {
flatbuffers::Parser parser;
@@ -1157,7 +1225,8 @@
std::string jsongen;
parser.opts.indent_step = -1;
- GenerateText(parser, parser.builder_.GetBufferPointer(), &jsongen);
+ auto result = GenerateText(parser, parser.builder_.GetBufferPointer(), &jsongen);
+ TEST_EQ(result, true);
TEST_EQ(jsongen == "{str: \"test\",i: 10}", true);
}
@@ -1169,6 +1238,11 @@
"table V { X:U; }"
"root_type V;"
"{ X:{ A:1 }, X_type: T }"), true);
+ // Unions must be parsable with prefixed namespace.
+ flatbuffers::Parser parser2;
+ TEST_EQ(parser2.Parse("namespace N; table A {} namespace; union U { N.A }"
+ "table B { e:U; } root_type B;"
+ "{ e_type: N_A, e: {} }"), true);
}
void ConformTest() {
@@ -1202,6 +1276,8 @@
ObjectFlatBuffersTest(flatbuf.get());
+ SizePrefixedTest();
+
#ifndef FLATBUFFERS_NO_FILE_TESTS
ParseAndGenerateTextTest();
ReflectionTest(flatbuf.get(), rawbuf.length());
@@ -1217,6 +1293,7 @@
IntegerOutOfRangeTest();
UnicodeTest();
UnicodeTestAllowNonUTF8();
+ UnicodeTestGenerateTextFailsOnNonUTF8();
UnicodeSurrogatesTest();
UnicodeInvalidSurrogatesTest();
InvalidUTF8Test();