diff --git a/.gitignore b/.gitignore
index 6f3894d06..e07fbae9a 100755
--- a/.gitignore
+++ b/.gitignore
@@ -40,6 +40,8 @@ flatsamplebinary
flatsamplebinary.exe
flatsampletext
flatsampletext.exe
+grpctest
+grpctest.exe
snapshot.sh
tests/go_gen
tests/monsterdata_java_wire.mon
@@ -55,9 +57,10 @@ build/Xcode/FlatBuffers.xcodeproj/xcuserdata/**
FlatBuffers.xcodeproj/
java/.idea
java/*.iml
-java/target
-**/*.pyc
.idea
+*.iml
+target
+**/*.pyc
build/VS2010/FlatBuffers.sdf
build/VS2010/FlatBuffers.opensdf
build/VS2010/ipch/**/*.ipch
diff --git a/CMakeLists.txt b/CMakeLists.txt
index c2dd95085..a72b62715 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -6,8 +6,10 @@ project(FlatBuffers)
option(FLATBUFFERS_CODE_COVERAGE "Enable the code coverage build option." OFF)
option(FLATBUFFERS_BUILD_TESTS "Enable the build of tests and samples." ON)
option(FLATBUFFERS_INSTALL "Enable the installation of targets." ON)
-option(FLATBUFFERS_BUILD_FLATLIB "Enable the build of the flatbuffers library" ON)
-option(FLATBUFFERS_BUILD_FLATC "Enable the build of the flatbuffers compiler" ON)
+option(FLATBUFFERS_BUILD_FLATLIB "Enable the build of the flatbuffers library"
+ ON)
+option(FLATBUFFERS_BUILD_FLATC "Enable the build of the flatbuffers compiler"
+ ON)
option(FLATBUFFERS_BUILD_FLATHASH "Enable the build of flathash" ON)
option(FLATBUFFERS_BUILD_GRPCTEST "Enable the build of grpctest" OFF)
@@ -95,7 +97,8 @@ set(FlatBuffers_GRPCTest_SRCS
if(APPLE)
set(CMAKE_CXX_FLAGS
- "${CMAKE_CXX_FLAGS} -std=c++11 -stdlib=libc++ -Wall -pedantic -Werror -Wextra")
+ "${CMAKE_CXX_FLAGS} -std=c++11 -stdlib=libc++ -Wall -pedantic -Werror \
+ -Wextra")
elseif(CMAKE_COMPILER_IS_GNUCXX)
if(CYGWIN)
set(CMAKE_CXX_FLAGS
@@ -118,7 +121,8 @@ elseif(CMAKE_COMPILER_IS_GNUCXX)
elseif("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
set(CMAKE_CXX_FLAGS
- "${CMAKE_CXX_FLAGS} -std=c++0x -stdlib=libc++ -Wall -pedantic -Werror -Wextra")
+ "${CMAKE_CXX_FLAGS} -std=c++0x -stdlib=libc++ -Wall -pedantic -Werror \
+ -Wextra")
if(NOT "${CMAKE_SYSTEM_NAME}" MATCHES "FreeBSD")
set(CMAKE_EXE_LINKER_FLAGS
"${CMAKE_EXE_LINKER_FLAGS} -lc++abi")
@@ -165,7 +169,9 @@ function(compile_flatbuffers_schema_to_cpp SRC_FBS)
string(REGEX REPLACE "\\.fbs$" "_generated.h" GEN_HEADER ${SRC_FBS})
add_custom_command(
OUTPUT ${GEN_HEADER}
- COMMAND "${FLATBUFFERS_FLATC_EXECUTABLE}" -c --no-includes --gen-mutable -o "${SRC_FBS_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/${SRC_FBS}"
+ COMMAND "${FLATBUFFERS_FLATC_EXECUTABLE}" -c --no-includes --gen-mutable
+ --gen-object-api -o "${SRC_FBS_DIR}"
+ "${CMAKE_CURRENT_SOURCE_DIR}/${SRC_FBS}"
DEPENDS flatc)
endfunction()
@@ -174,7 +180,8 @@ function(compile_flatbuffers_schema_to_binary SRC_FBS)
string(REGEX REPLACE "\\.fbs$" ".bfbs" GEN_BINARY_SCHEMA ${SRC_FBS})
add_custom_command(
OUTPUT ${GEN_BINARY_SCHEMA}
- COMMAND "${FLATBUFFERS_FLATC_EXECUTABLE}" -b --schema -o "${SRC_FBS_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/${SRC_FBS}"
+ COMMAND "${FLATBUFFERS_FLATC_EXECUTABLE}" -b --schema -o "${SRC_FBS_DIR}"
+ "${CMAKE_CURRENT_SOURCE_DIR}/${SRC_FBS}"
DEPENDS flatc)
endfunction()
diff --git a/CONTRIBUTING b/CONTRIBUTING.md
similarity index 100%
rename from CONTRIBUTING
rename to CONTRIBUTING.md
diff --git a/build_ide/VS2010/flatc.vcxproj b/build_ide/VS2010/flatc.vcxproj
index 31cd01345..5aef2384a 100755
--- a/build_ide/VS2010/flatc.vcxproj
+++ b/build_ide/VS2010/flatc.vcxproj
@@ -81,7 +81,7 @@
- ../../include;%(AdditionalIncludeDirectories)
+ ../../include;../../grpc;%(AdditionalIncludeDirectories)
EnableFastChecks
CompileAsCpp
ProgramDatabase
@@ -127,7 +127,7 @@
- ../../include;%(AdditionalIncludeDirectories)
+ ../../include;../../grpc;%(AdditionalIncludeDirectories)
EnableFastChecks
CompileAsCpp
ProgramDatabase
@@ -173,7 +173,7 @@
- ../../include;%(AdditionalIncludeDirectories)
+ ../../include;../../grpc;%(AdditionalIncludeDirectories)
CompileAsCpp
Sync
AnySuitable
@@ -219,7 +219,7 @@
- ../../include;%(AdditionalIncludeDirectories)
+ ../../include;../../grpc;%(AdditionalIncludeDirectories)
CompileAsCpp
Sync
AnySuitable
@@ -263,6 +263,8 @@
+
+
diff --git a/build_ide/VS2010/flatc.vcxproj.user b/build_ide/VS2010/flatc.vcxproj.user
index 5ef05f7e3..1132b8ab9 100755
--- a/build_ide/VS2010/flatc.vcxproj.user
+++ b/build_ide/VS2010/flatc.vcxproj.user
@@ -3,7 +3,7 @@
..\..\tests
WindowsLocalDebugger
- -j -c -n -g --php --no-includes --gen-mutable monster_test.fbs
+ -j -c -n -g --php --no-includes --gen-mutable --gen-object-api monster_test.fbs
..\..
diff --git a/build_ide/Xcode/FlatBuffers.xcodeproj/project.pbxproj b/build_ide/Xcode/FlatBuffers.xcodeproj/project.pbxproj
index ee18e9e29..e67f73565 100644
--- a/build_ide/Xcode/FlatBuffers.xcodeproj/project.pbxproj
+++ b/build_ide/Xcode/FlatBuffers.xcodeproj/project.pbxproj
@@ -11,10 +11,12 @@
5AC48C391ACA9A0A008132C5 /* idl_gen_general.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8CD8717A19CB937D0012A827 /* idl_gen_general.cpp */; };
61823BBC53544106B6DBC38E /* idl_parser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3709AC883348409592530AE6 /* idl_parser.cpp */; settings = {COMPILER_FLAGS = ""; }; };
61FF3C34FBEC4819A1C30F92 /* sample_text.cpp in Sources */ = {isa = PBXBuildFile; fileRef = ECCEBFFA6977404F858F9739 /* sample_text.cpp */; settings = {COMPILER_FLAGS = ""; }; };
- 8C2AAE0A1CB338A8000CC78D /* util.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8C2AAE091CB338A8000CC78D /* util.cpp */; settings = {ASSET_TAGS = (); }; };
- 8C2AAE0B1CB338CD000CC78D /* util.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8C2AAE091CB338A8000CC78D /* util.cpp */; settings = {ASSET_TAGS = (); }; };
- 8C2AAE0C1CB338CE000CC78D /* util.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8C2AAE091CB338A8000CC78D /* util.cpp */; settings = {ASSET_TAGS = (); }; };
+ 8C2AAE0A1CB338A8000CC78D /* util.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8C2AAE091CB338A8000CC78D /* util.cpp */; };
+ 8C2AAE0B1CB338CD000CC78D /* util.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8C2AAE091CB338A8000CC78D /* util.cpp */; };
+ 8C2AAE0C1CB338CE000CC78D /* util.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8C2AAE091CB338A8000CC78D /* util.cpp */; };
8C303C591975D6A700D7C1C5 /* idl_gen_go.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8C303C581975D6A700D7C1C5 /* idl_gen_go.cpp */; };
+ 8C547D661D3FF05C00AE7A25 /* idl_gen_grpc.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8C547D651D3FF05C00AE7A25 /* idl_gen_grpc.cpp */; };
+ 8C547D681D3FF07D00AE7A25 /* cpp_generator.cc in Sources */ = {isa = PBXBuildFile; fileRef = 8C547D671D3FF07D00AE7A25 /* cpp_generator.cc */; };
8C6905FD19F835B400CB8866 /* idl_gen_fbs.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8C6905EC19F8357300CB8866 /* idl_gen_fbs.cpp */; };
8C78573E1BD5AE2C00C53C34 /* idl_gen_js.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8C78573D1BD5AE2C00C53C34 /* idl_gen_js.cpp */; };
8C8774631B703D4800E693F5 /* reflection.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8C8774621B703D4800E693F5 /* reflection.cpp */; };
@@ -43,6 +45,8 @@
6AD24EEB3D024825A37741FF /* test.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = test.cpp; path = tests/test.cpp; sourceTree = SOURCE_ROOT; };
8C2AAE091CB338A8000CC78D /* util.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = util.cpp; path = src/util.cpp; sourceTree = ""; };
8C303C581975D6A700D7C1C5 /* idl_gen_go.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = idl_gen_go.cpp; path = src/idl_gen_go.cpp; sourceTree = ""; };
+ 8C547D651D3FF05C00AE7A25 /* idl_gen_grpc.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = idl_gen_grpc.cpp; path = src/idl_gen_grpc.cpp; sourceTree = ""; };
+ 8C547D671D3FF07D00AE7A25 /* cpp_generator.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = cpp_generator.cc; path = grpc/src/compiler/cpp_generator.cc; sourceTree = ""; };
8C6905EC19F8357300CB8866 /* idl_gen_fbs.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = idl_gen_fbs.cpp; path = src/idl_gen_fbs.cpp; sourceTree = ""; };
8C78573D1BD5AE2C00C53C34 /* idl_gen_js.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = idl_gen_js.cpp; path = src/idl_gen_js.cpp; sourceTree = ""; };
8C8774621B703D4800E693F5 /* reflection.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = reflection.cpp; path = src/reflection.cpp; sourceTree = ""; };
@@ -62,6 +66,8 @@
28237E300FE042DEADA302D3 /* Source Files */ = {
isa = PBXGroup;
children = (
+ 8C547D671D3FF07D00AE7A25 /* cpp_generator.cc */,
+ 8C547D651D3FF05C00AE7A25 /* idl_gen_grpc.cpp */,
8C2AAE091CB338A8000CC78D /* util.cpp */,
D2DA271C1BFFBC06000F9168 /* idl_gen_php.cpp */,
8C78573D1BD5AE2C00C53C34 /* idl_gen_js.cpp */,
@@ -267,12 +273,14 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
+ 8C547D681D3FF07D00AE7A25 /* cpp_generator.cc in Sources */,
8C303C591975D6A700D7C1C5 /* idl_gen_go.cpp in Sources */,
AA9BACF55EB3456BA2F633BB /* flatc.cpp in Sources */,
BE03D7B0C9584DD58B50ED34 /* idl_gen_cpp.cpp in Sources */,
AD71FEBEE4E846529002C1F0 /* idl_gen_text.cpp in Sources */,
8C2AAE0A1CB338A8000CC78D /* util.cpp in Sources */,
8C8774641B703E1200E693F5 /* idl_gen_fbs.cpp in Sources */,
+ 8C547D661D3FF05C00AE7A25 /* idl_gen_grpc.cpp in Sources */,
A9C9A99F719A4ED58DC2D2FC /* idl_parser.cpp in Sources */,
8CA854B31B04244A00040A06 /* idl_gen_python.cpp in Sources */,
8CD8717B19CB937D0012A827 /* idl_gen_general.cpp in Sources */,
@@ -715,7 +723,10 @@
GCC_OPTIMIZATION_LEVEL = 3;
GCC_PREPROCESSOR_DEFINITIONS = "'CMAKE_INTDIR=\"$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)\"'";
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
- HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/include";
+ HEADER_SEARCH_PATHS = (
+ "$(PROJECT_DIR)/include",
+ "$(PROJECT_DIR)/grpc",
+ );
INSTALL_PATH = "";
LIBRARY_SEARCH_PATHS = "";
OTHER_CFLAGS = (
@@ -754,7 +765,10 @@
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = "'CMAKE_INTDIR=\"$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)\"'";
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
- HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/include";
+ HEADER_SEARCH_PATHS = (
+ "$(PROJECT_DIR)/include",
+ "$(PROJECT_DIR)/grpc",
+ );
INSTALL_PATH = "";
LIBRARY_SEARCH_PATHS = "";
OTHER_CFLAGS = " -std=c++0x";
@@ -787,7 +801,10 @@
GCC_OPTIMIZATION_LEVEL = 2;
GCC_PREPROCESSOR_DEFINITIONS = "'CMAKE_INTDIR=\"$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)\"'";
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
- HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/include";
+ HEADER_SEARCH_PATHS = (
+ "$(PROJECT_DIR)/include",
+ "$(PROJECT_DIR)/grpc",
+ );
INSTALL_PATH = "";
LIBRARY_SEARCH_PATHS = "";
OTHER_CFLAGS = (
@@ -919,7 +936,10 @@
GCC_OPTIMIZATION_LEVEL = s;
GCC_PREPROCESSOR_DEFINITIONS = "'CMAKE_INTDIR=\"$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)\"'";
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
- HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/include";
+ HEADER_SEARCH_PATHS = (
+ "$(PROJECT_DIR)/include",
+ "$(PROJECT_DIR)/grpc",
+ );
INSTALL_PATH = "";
LIBRARY_SEARCH_PATHS = "";
OTHER_CFLAGS = (
diff --git a/docs/source/Compiler.md b/docs/source/Compiler.md
index ad584c739..b71b8c46d 100755
--- a/docs/source/Compiler.md
+++ b/docs/source/Compiler.md
@@ -81,6 +81,11 @@ Additional options:
- `--gen-mutable` : Generate additional non-const accessors for mutating
FlatBuffers in-place.
+ `--gen-object-api` : Generate an additional object-based API. This API is
+ more convenient for object construction and mutation than the base API,
+ at the cost of efficiency (object allocation). Recommended only to be used
+ if other options are insufficient.
+
- `--gen-onefile` : Generate single output file (useful for C#)
- `--gen-all`: Generate not just code for the current schema files, but
@@ -103,5 +108,9 @@ Additional options:
to the reflection/reflection.fbs schema. Loading this binary file is the
basis for reflection functionality.
+- `--conform FILE` : Specify a schema the following schemas should be
+ an evolution of. Gives errors if not. Useful to check if schema
+ modifications don't break schema evolution rules.
+
NOTE: short-form options for generators are deprecated, use the long form
whenever possible.
diff --git a/docs/source/CppUsage.md b/docs/source/CppUsage.md
index d4abe66e4..060432b01 100755
--- a/docs/source/CppUsage.md
+++ b/docs/source/CppUsage.md
@@ -85,6 +85,27 @@ convenient accessors for all fields, e.g. `hp()`, `mana()`, etc:
*Note: That we never stored a `mana` value, so it will return the default.*
+## Object based API.
+
+FlatBuffers is all about memory efficiency, which is why its base API is written
+around using as little as possible of it. This does make the API clumsier
+(requiring pre-order construction of all data, and making mutation harder).
+
+For times when efficiency is less important a more convenient object based API
+can be used (through `--gen-object-api`) that is able to unpack & pack a
+FlatBuffer into objects and standard STL containers, allowing for convenient
+construction, access and mutation.
+
+To use:
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
+ auto monsterobj = GetMonster(buffer)->UnPack();
+ cout << monsterobj->name; // This is now a std::string!
+ monsterobj->name = "Bob"; // Change the name.
+ FlatBufferBuilder fbb;
+ monsterobj->Pack(fbb); // Serialize into new buffer.
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
## Reflection (& Resizing)
There is experimental support for reflection in FlatBuffers, allowing you to
diff --git a/docs/source/GoUsage.md b/docs/source/GoUsage.md
index a3a0e928a..ab6ddbd82 100644
--- a/docs/source/GoUsage.md
+++ b/docs/source/GoUsage.md
@@ -67,6 +67,29 @@ Now you can access values like this:
pos := monster.Pos(nil)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+In some cases it's necessary to modify values in an existing FlatBuffer in place (without creating a copy). For this reason, scalar fields of a Flatbuffer table or struct can be mutated.
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.go}
+ monster := example.GetRootAsMonster(buf, 0)
+
+ // Set table field.
+ if ok := monster.MutateHp(10); !ok {
+ panic("failed to mutate Hp")
+ }
+
+ // Set struct field.
+ monster.Pos().MutateZ(4)
+
+ // This mutation will fail because the mana field is not available in
+ // the buffer. It should be set when creating the buffer.
+ if ok := monster.MutateMana(20); !ok {
+ panic("failed to mutate Hp")
+ }
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The term `mutate` is used instead of `set` to indicate that this is a special use case. All mutate functions return a boolean value which is false if the field we're trying to mutate is not available in the buffer.
+
## Text Parsing
There currently is no support for parsing text (Schema's and JSON) directly
diff --git a/docs/source/Tutorial.md b/docs/source/Tutorial.md
index 6f6ac9a51..100191d7a 100644
--- a/docs/source/Tutorial.md
+++ b/docs/source/Tutorial.md
@@ -727,8 +727,8 @@ offsets.
// Place the two weapons into an array, and pass it to the `createWeaponsVector()` method to
// create a FlatBuffer vector.
int[] weaps = new int[2];
- weaps[1] = sword;
- weaps[2] = axe;
+ weaps[0] = sword;
+ weaps[1] = axe;
// Pass the `weaps` array into the `createWeaponsVector()` method to create a FlatBuffer vector.
int weapons = Monster.createWeaponsVector(builder, weaps);
@@ -1881,6 +1881,9 @@ One way to solve this is to call `ForceDefaults` on a FlatBufferBuilder to
force all fields you set to actually be written. This, of course, increases the
size of the buffer somewhat, but this may be acceptable for a mutable buffer.
+If this is not sufficient, other ways of mutating FlatBuffers may be supported
+in your language through an object based API (`--gen-object-api`) or reflection.
+See the individual language documents for support.
## JSON with FlatBuffers
diff --git a/go/table.go b/go/table.go
index 976a7dba1..01d3db122 100644
--- a/go/table.go
+++ b/go/table.go
@@ -293,3 +293,213 @@ func (t *Table) GetVOffsetTSlot(slot VOffsetT, d VOffsetT) VOffsetT {
}
return VOffsetT(off)
}
+
+// MutateBool updates a bool at the given offset.
+func (t *Table) MutateBool(off UOffsetT, n bool) bool {
+ WriteBool(t.Bytes[off:], n)
+ return true
+}
+
+// MutateByte updates a Byte at the given offset.
+func (t *Table) MutateByte(off UOffsetT, n byte) bool {
+ WriteByte(t.Bytes[off:], n)
+ return true
+}
+
+// MutateUint8 updates a Uint8 at the given offset.
+func (t *Table) MutateUint8(off UOffsetT, n uint8) bool {
+ WriteUint8(t.Bytes[off:], n)
+ return true
+}
+
+// MutateUint16 updates a Uint16 at the given offset.
+func (t *Table) MutateUint16(off UOffsetT, n uint16) bool {
+ WriteUint16(t.Bytes[off:], n)
+ return true
+}
+
+// MutateUint32 updates a Uint32 at the given offset.
+func (t *Table) MutateUint32(off UOffsetT, n uint32) bool {
+ WriteUint32(t.Bytes[off:], n)
+ return true
+}
+
+// MutateUint64 updates a Uint64 at the given offset.
+func (t *Table) MutateUint64(off UOffsetT, n uint64) bool {
+ WriteUint64(t.Bytes[off:], n)
+ return true
+}
+
+// MutateInt8 updates a Int8 at the given offset.
+func (t *Table) MutateInt8(off UOffsetT, n int8) bool {
+ WriteInt8(t.Bytes[off:], n)
+ return true
+}
+
+// MutateInt16 updates a Int16 at the given offset.
+func (t *Table) MutateInt16(off UOffsetT, n int16) bool {
+ WriteInt16(t.Bytes[off:], n)
+ return true
+}
+
+// MutateInt32 updates a Int32 at the given offset.
+func (t *Table) MutateInt32(off UOffsetT, n int32) bool {
+ WriteInt32(t.Bytes[off:], n)
+ return true
+}
+
+// MutateInt64 updates a Int64 at the given offset.
+func (t *Table) MutateInt64(off UOffsetT, n int64) bool {
+ WriteInt64(t.Bytes[off:], n)
+ return true
+}
+
+// MutateFloat32 updates a Float32 at the given offset.
+func (t *Table) MutateFloat32(off UOffsetT, n float32) bool {
+ WriteFloat32(t.Bytes[off:], n)
+ return true
+}
+
+// MutateFloat64 updates a Float64 at the given offset.
+func (t *Table) MutateFloat64(off UOffsetT, n float64) bool {
+ WriteFloat64(t.Bytes[off:], n)
+ return true
+}
+
+// MutateUOffsetT updates a UOffsetT at the given offset.
+func (t *Table) MutateUOffsetT(off UOffsetT, n UOffsetT) bool {
+ WriteUOffsetT(t.Bytes[off:], n)
+ return true
+}
+
+// MutateVOffsetT updates a VOffsetT at the given offset.
+func (t *Table) MutateVOffsetT(off UOffsetT, n VOffsetT) bool {
+ WriteVOffsetT(t.Bytes[off:], n)
+ return true
+}
+
+// MutateSOffsetT updates a SOffsetT at the given offset.
+func (t *Table) MutateSOffsetT(off UOffsetT, n SOffsetT) bool {
+ WriteSOffsetT(t.Bytes[off:], n)
+ return true
+}
+
+// MutateBoolSlot updates the bool at given vtable location
+func (t *Table) MutateBoolSlot(slot VOffsetT, n bool) bool {
+ if off := t.Offset(slot); off != 0 {
+ t.MutateBool(t.Pos+UOffsetT(off), n)
+ return true
+ }
+
+ return false
+}
+
+// MutateByteSlot updates the byte at given vtable location
+func (t *Table) MutateByteSlot(slot VOffsetT, n byte) bool {
+ if off := t.Offset(slot); off != 0 {
+ t.MutateByte(t.Pos+UOffsetT(off), n)
+ return true
+ }
+
+ return false
+}
+
+// MutateInt8Slot updates the int8 at given vtable location
+func (t *Table) MutateInt8Slot(slot VOffsetT, n int8) bool {
+ if off := t.Offset(slot); off != 0 {
+ t.MutateInt8(t.Pos+UOffsetT(off), n)
+ return true
+ }
+
+ return false
+}
+
+// MutateUint8Slot updates the uint8 at given vtable location
+func (t *Table) MutateUint8Slot(slot VOffsetT, n uint8) bool {
+ if off := t.Offset(slot); off != 0 {
+ t.MutateUint8(t.Pos+UOffsetT(off), n)
+ return true
+ }
+
+ return false
+}
+
+// MutateInt16Slot updates the int16 at given vtable location
+func (t *Table) MutateInt16Slot(slot VOffsetT, n int16) bool {
+ if off := t.Offset(slot); off != 0 {
+ t.MutateInt16(t.Pos+UOffsetT(off), n)
+ return true
+ }
+
+ return false
+}
+
+// MutateUint16Slot updates the uint16 at given vtable location
+func (t *Table) MutateUint16Slot(slot VOffsetT, n uint16) bool {
+ if off := t.Offset(slot); off != 0 {
+ t.MutateUint16(t.Pos+UOffsetT(off), n)
+ return true
+ }
+
+ return false
+}
+
+// MutateInt32Slot updates the int32 at given vtable location
+func (t *Table) MutateInt32Slot(slot VOffsetT, n int32) bool {
+ if off := t.Offset(slot); off != 0 {
+ t.MutateInt32(t.Pos+UOffsetT(off), n)
+ return true
+ }
+
+ return false
+}
+
+// MutateUint32Slot updates the uint32 at given vtable location
+func (t *Table) MutateUint32Slot(slot VOffsetT, n uint32) bool {
+ if off := t.Offset(slot); off != 0 {
+ t.MutateUint32(t.Pos+UOffsetT(off), n)
+ return true
+ }
+
+ return false
+}
+
+// MutateInt64Slot updates the int64 at given vtable location
+func (t *Table) MutateInt64Slot(slot VOffsetT, n int64) bool {
+ if off := t.Offset(slot); off != 0 {
+ t.MutateInt64(t.Pos+UOffsetT(off), n)
+ return true
+ }
+
+ return false
+}
+
+// MutateUint64Slot updates the uint64 at given vtable location
+func (t *Table) MutateUint64Slot(slot VOffsetT, n uint64) bool {
+ if off := t.Offset(slot); off != 0 {
+ t.MutateUint64(t.Pos+UOffsetT(off), n)
+ return true
+ }
+
+ return false
+}
+
+// MutateFloat32Slot updates the float32 at given vtable location
+func (t *Table) MutateFloat32Slot(slot VOffsetT, n float32) bool {
+ if off := t.Offset(slot); off != 0 {
+ t.MutateFloat32(t.Pos+UOffsetT(off), n)
+ return true
+ }
+
+ return false
+}
+
+// MutateFloat64Slot updates the float64 at given vtable location
+func (t *Table) MutateFloat64Slot(slot VOffsetT, n float64) bool {
+ if off := t.Offset(slot); off != 0 {
+ t.MutateFloat64(t.Pos+UOffsetT(off), n)
+ return true
+ }
+
+ return false
+}
diff --git a/include/flatbuffers/code_generators.h b/include/flatbuffers/code_generators.h
index e7450a7a0..8b097ef7e 100644
--- a/include/flatbuffers/code_generators.h
+++ b/include/flatbuffers/code_generators.h
@@ -39,8 +39,8 @@ class BaseGenerator {
protected:
BaseGenerator(const Parser &parser, const std::string &path,
- const std::string &file_name,
- const std::string qualifying_start,
+ const std::string &file_name,
+ const std::string qualifying_start,
const std::string qualifying_separator)
: parser_(parser),
path_(path),
@@ -86,15 +86,18 @@ class BaseGenerator {
const std::string LastNamespacePart(const Namespace &ns) {
auto &namespaces = ns.components;
- if (namespaces.size()) return *(namespaces.end() - 1); else return std::string("");
+ if (namespaces.size())
+ return *(namespaces.end() - 1);
+ else
+ return std::string("");
}
// tracks the current namespace for early exit in WrapInNameSpace
- // c++, java and csharp returns a different namespace from
- // the following default (no early exit, always fully qualify),
+ // c++, java and csharp returns a different namespace from
+ // the following default (no early exit, always fully qualify),
// which works for js and php
virtual const Namespace *CurrentNameSpace() { return nullptr; }
-
+
// Ensure that a type is prefixed with its namespace whenever it is used
// outside of its namespace.
std::string WrapInNameSpace(const Namespace *ns, const std::string &name) {
diff --git a/include/flatbuffers/flatbuffers.h b/include/flatbuffers/flatbuffers.h
index 6755ec279..8cab3cd36 100644
--- a/include/flatbuffers/flatbuffers.h
+++ b/include/flatbuffers/flatbuffers.h
@@ -24,13 +24,20 @@
#include
#include
#include
+#include
#include
#include
#include
#include
-#include
#include
+#ifdef _STLPORT_VERSION
+ #define FLATBUFFERS_CPP98_STL
+#endif
+#ifndef FLATBUFFERS_CPP98_STL
+ #include
+#endif
+
/// @cond FLATBUFFERS_INTERNAL
#if __cplusplus <= 199711L && \
(!defined(_MSC_VER) || _MSC_VER < 1600) && \
@@ -123,9 +130,11 @@ typedef uintmax_t largest_scalar_t;
// In 32bits, this evaluates to 2GB - 1
#define FLATBUFFERS_MAX_BUFFER_SIZE ((1ULL << (sizeof(soffset_t) * 8 - 1)) - 1)
+#ifndef FLATBUFFERS_CPP98_STL
// Pointer to relinquished memory.
typedef std::unique_ptr>
unique_ptr_t;
+#endif
// Wrapper for uoffset_t to allow safe template specialization.
template struct Offset {
@@ -234,23 +243,19 @@ template struct IndirectHelper {
// An STL compatible iterator implementation for Vector below, effectively
// calling Get() for every element.
-template
-struct VectorIterator : public
- std::iterator < std::input_iterator_tag,
- typename std::conditional < bConst,
- const typename IndirectHelper::return_type,
- typename IndirectHelper::return_type > ::type, uoffset_t > {
+template
+struct VectorIterator
+ : public std::iterator {
- typedef std::iterator::return_type,
- typename IndirectHelper::return_type>::type, uoffset_t> super_type;
+ typedef std::iterator super_type;
public:
VectorIterator(const uint8_t *data, uoffset_t i) :
data_(data + IndirectHelper::element_stride * i) {};
VectorIterator(const VectorIterator &other) : data_(other.data_) {}
+ #ifndef FLATBUFFERS_CPP98_STL
VectorIterator(VectorIterator &&other) : data_(std::move(other.data_)) {}
+ #endif
VectorIterator &operator=(const VectorIterator &other) {
data_ = other.data_;
@@ -288,7 +293,7 @@ public:
}
VectorIterator operator++(int) {
- VectorIterator temp(data_);
+ VectorIterator temp(data_,0);
data_ += IndirectHelper::element_stride;
return temp;
}
@@ -301,8 +306,10 @@ private:
// Vector::data() assumes the vector elements start after the length field.
template class Vector {
public:
- typedef VectorIterator iterator;
- typedef VectorIterator const_iterator;
+ typedef VectorIterator::mutable_return_type>
+ iterator;
+ typedef VectorIterator::return_type>
+ const_iterator;
uoffset_t size() const { return EndianScalar(length_); }
@@ -471,6 +478,7 @@ class vector_downward {
cur_ = buf_ + reserved_;
}
+ #ifndef FLATBUFFERS_CPP98_STL
// Relinquish the pointer to the caller.
unique_ptr_t release() {
// Actually deallocate from the start of the allocated memory.
@@ -486,6 +494,7 @@ class vector_downward {
return retval;
}
+ #endif
size_t growth_policy(size_t bytes) {
return (bytes / 2) & ~(sizeof(largest_scalar_t) - 1);
@@ -562,6 +571,10 @@ inline voffset_t FieldIndexToOffset(voffset_t field_id) {
inline size_t PaddingBytes(size_t buf_size, size_t scalar_size) {
return ((~buf_size) + 1) & (scalar_size - 1);
}
+
+template const T* data(const std::vector &v) {
+ return v.empty() ? nullptr : &v.front();
+}
/// @endcond
/// @addtogroup flatbuffers_cpp_api
@@ -627,6 +640,7 @@ FLATBUFFERS_FINAL_CLASS
/// @return Returns a `uint8_t` pointer to the unfinished buffer.
uint8_t *GetCurrentBufferPointer() const { return buf_.data(); }
+ #ifndef FLATBUFFERS_CPP98_STL
/// @brief Get the released pointer to the serialized buffer.
/// @warning Do NOT attempt to use this FlatBufferBuilder afterwards!
/// @return The `unique_ptr` returned has a special allocator that knows how
@@ -637,6 +651,7 @@ FLATBUFFERS_FINAL_CLASS
Finished();
return buf_.release();
}
+ #endif
/// @cond FLATBUFFERS_INTERNAL
void Finished() const {
@@ -674,11 +689,13 @@ FLATBUFFERS_FINAL_CLASS
void PopBytes(size_t amount) { buf_.pop(amount); }
template void AssertScalarT() {
+ #ifndef FLATBUFFERS_CPP98_STL
// The code assumes power of 2 sizes and endian-swap-ability.
static_assert(std::is_scalar::value
// The Offset type is essentially a scalar but fails is_scalar.
|| sizeof(T) == sizeof(Offset),
"T must be a scalar type");
+ #endif
}
// Write a single aligned scalar to the buffer
@@ -876,7 +893,7 @@ FLATBUFFERS_FINAL_CLASS
/// @param[in] str A const pointer to a `String` struct to add to the buffer.
/// @return Returns the offset in the buffer where the string starts
Offset CreateString(const String *str) {
- return CreateString(str->c_str(), str->Length());
+ return str ? CreateString(str->c_str(), str->Length()) : 0;
}
/// @brief Store a string in the buffer, which can contain any binary data.
@@ -981,9 +998,21 @@ FLATBUFFERS_FINAL_CLASS
/// @return Returns a typed `Offset` into the serialized data indicating
/// where the vector is stored.
template Offset> CreateVector(const std::vector &v) {
- return CreateVector(v.data(), v.size());
+ return CreateVector(data(v), v.size());
}
+ // vector may be implemented using a bit-set, so we can't access it as
+ // an array. Instead, read elements manually.
+ // Background: https://isocpp.org/blog/2012/11/on-vectorbool
+ Offset> CreateVector(const std::vector &v) {
+ StartVector(v.size(), sizeof(uint8_t));
+ for (auto i = v.size(); i > 0; ) {
+ PushElement(static_cast(v[--i]));
+ }
+ return Offset>(EndVector(v.size()));
+ }
+
+ #ifndef FLATBUFFERS_CPP98_STL
/// @brief Serialize values returned by a function into a FlatBuffer `vector`.
/// This is a convenience function that takes care of iteration for you.
/// @tparam T The data type of the `std::vector` elements.
@@ -995,8 +1024,9 @@ FLATBUFFERS_FINAL_CLASS
const std::function &f) {
std::vector elems(vector_size);
for (size_t i = 0; i < vector_size; i++) elems[i] = f(i);
- return CreateVector(elems.data(), elems.size());
+ return CreateVector(elems);
}
+ #endif
/// @brief Serialize a `std::vector` into a FlatBuffer `vector`.
/// This is a convenience function for a common case.
@@ -1008,7 +1038,7 @@ FLATBUFFERS_FINAL_CLASS
const std::vector &v) {
std::vector> offsets(v.size());
for (size_t i = 0; i < v.size(); i++) offsets[i] = CreateString(v[i]);
- return CreateVector(offsets.data(), offsets.size());
+ return CreateVector(offsets);
}
/// @brief Serialize an array of structs into a FlatBuffer `vector`.
@@ -1033,7 +1063,7 @@ FLATBUFFERS_FINAL_CLASS
/// where the vector is stored.
template Offset> CreateVectorOfStructs(
const std::vector &v) {
- return CreateVectorOfStructs(v.data(), v.size());
+ return CreateVectorOfStructs(data(v), v.size());
}
/// @cond FLATBUFFERS_INTERNAL
@@ -1216,6 +1246,9 @@ class Verifier FLATBUFFERS_FINAL_CLASS {
size_t _max_tables = 1000000)
: buf_(buf), end_(buf + buf_len), depth_(0), max_depth_(_max_depth),
num_tables_(0), max_tables_(_max_tables)
+ #ifdef FLATBUFFERS_TRACK_VERIFIER_BUFFER_SIZE
+ , upper_bound_(buf)
+ #endif
{}
// Central location where any verification failures register.
@@ -1223,11 +1256,20 @@ class Verifier FLATBUFFERS_FINAL_CLASS {
#ifdef FLATBUFFERS_DEBUG_VERIFICATION_FAILURE
assert(ok);
#endif
+ #ifdef FLATBUFFERS_TRACK_VERIFIER_BUFFER_SIZE
+ if (!ok)
+ upper_bound_ = buf_;
+ #endif
return ok;
}
// Verify any range within the buffer.
bool Verify(const void *elem, size_t elem_len) const {
+ #ifdef FLATBUFFERS_TRACK_VERIFIER_BUFFER_SIZE
+ auto upper_bound = reinterpret_cast(elem) + elem_len;
+ if (upper_bound_ < upper_bound)
+ upper_bound_ = upper_bound;
+ #endif
return Check(elem_len <= (size_t) (end_ - buf_) &&
elem >= buf_ &&
elem <= end_ - elem_len);
@@ -1302,11 +1344,20 @@ class Verifier FLATBUFFERS_FINAL_CLASS {
}
// Verify this whole buffer, starting with root type T.
- template bool VerifyBuffer() {
+ template bool VerifyBuffer(const char *identifier) {
+ if (identifier && (size_t(end_ - buf_) < 2 * sizeof(flatbuffers::uoffset_t) ||
+ !BufferHasIdentifier(buf_, identifier))) {
+ return false;
+ }
+
// Call T::Verify, which must be in the generated code for this type.
return Verify(buf_) &&
reinterpret_cast(buf_ + ReadScalar(buf_))->
- Verify(*this);
+ Verify(*this)
+ #ifdef FLATBUFFERS_TRACK_VERIFIER_BUFFER_SIZE
+ && GetComputedSize()
+ #endif
+ ;
}
// Called at the start of a table to increase counters measuring data
@@ -1325,6 +1376,16 @@ class Verifier FLATBUFFERS_FINAL_CLASS {
return true;
}
+ #ifdef FLATBUFFERS_TRACK_VERIFIER_BUFFER_SIZE
+ // Returns the message size in bytes
+ size_t GetComputedSize() const {
+ uintptr_t size = upper_bound_ - buf_;
+ // Align the size to uoffset_t
+ size = (size - 1 + sizeof(uoffset_t)) & ~(sizeof(uoffset_t) - 1);
+ return (buf_ + size > end_) ? 0 : size;
+ }
+ #endif
+
private:
const uint8_t *buf_;
const uint8_t *end_;
@@ -1332,6 +1393,9 @@ class Verifier FLATBUFFERS_FINAL_CLASS {
size_t max_depth_;
size_t num_tables_;
size_t max_tables_;
+ #ifdef FLATBUFFERS_TRACK_VERIFIER_BUFFER_SIZE
+ mutable const uint8_t *upper_bound_;
+ #endif
};
// Convenient way to bundle a buffer and its length, to pass it around
@@ -1489,6 +1553,12 @@ class Table {
uint8_t data_[1];
};
+// Base class for native objects (FlatBuffer data de-serialized into native
+// C++ data structures).
+// Contains no functionality, purely documentative.
+struct NativeTable {
+};
+
// 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 dddfab25c..1f4501629 100644
--- a/include/flatbuffers/idl.h
+++ b/include/flatbuffers/idl.h
@@ -311,6 +311,14 @@ struct EnumDef : public Definition {
Type underlying_type;
};
+inline bool EqualByName(const Type &a, const Type &b) {
+ return a.base_type == b.base_type && a.element == b.element &&
+ (a.struct_def == b.struct_def ||
+ a.struct_def->name == b.struct_def->name) &&
+ (a.enum_def == b.enum_def ||
+ a.enum_def->name == b.enum_def->name);
+}
+
struct RPCCall {
std::string name;
SymbolTable attributes;
@@ -338,7 +346,8 @@ struct IDLOptions {
bool skip_unexpected_fields_in_json;
bool generate_name_strings;
bool escape_proto_identifiers;
-
+ bool generate_object_based_api;
+
// Possible options for the more general generator below.
enum Language { kJava, kCSharp, kGo, kMAX };
@@ -358,6 +367,7 @@ struct IDLOptions {
skip_unexpected_fields_in_json(false),
generate_name_strings(false),
escape_proto_identifiers(false),
+ generate_object_based_api(false),
lang(IDLOptions::kJava) {}
};
@@ -471,6 +481,10 @@ class Parser : public ParserState {
// See reflection/reflection.fbs
void Serialize();
+ // Checks that the schema represented by this parser is a safe evolution
+ // of the schema provided. Returns non-empty error on any problems.
+ std::string ConformTo(const Parser &base);
+
FLATBUFFERS_CHECKED_ERROR CheckBitsFit(int64_t val, size_t bits);
private:
diff --git a/include/flatbuffers/reflection.h b/include/flatbuffers/reflection.h
index 87091438a..ae331ce23 100644
--- a/include/flatbuffers/reflection.h
+++ b/include/flatbuffers/reflection.h
@@ -370,6 +370,7 @@ uint8_t *ResizeAnyVector(const reflection::Schema &schema, uoffset_t newsize,
uoffset_t elem_size, std::vector *flatbuf,
const reflection::Object *root_table = nullptr);
+#ifndef FLATBUFFERS_CPP98_STL
template
void ResizeVector(const reflection::Schema &schema, uoffset_t newsize, T val,
const Vector *vec, std::vector *flatbuf,
@@ -391,6 +392,7 @@ void ResizeVector(const reflection::Schema &schema, uoffset_t newsize, T val,
}
}
}
+#endif
// Adds any new data (in the form of a new FlatBuffer) to an existing
// FlatBuffer. This can be used when any of the above methods are not
diff --git a/include/flatbuffers/reflection_generated.h b/include/flatbuffers/reflection_generated.h
index da1124939..eb981857b 100644
--- a/include/flatbuffers/reflection_generated.h
+++ b/include/flatbuffers/reflection_generated.h
@@ -478,12 +478,12 @@ inline flatbuffers::Offset CreateSchema(flatbuffers::FlatBufferBuilder &
inline const reflection::Schema *GetSchema(const void *buf) { return flatbuffers::GetRoot(buf); }
-inline bool VerifySchemaBuffer(flatbuffers::Verifier &verifier) { return verifier.VerifyBuffer(); }
-
inline const char *SchemaIdentifier() { return "BFBS"; }
inline bool SchemaBufferHasIdentifier(const void *buf) { return flatbuffers::BufferHasIdentifier(buf, SchemaIdentifier()); }
+inline bool VerifySchemaBuffer(flatbuffers::Verifier &verifier) { return verifier.VerifyBuffer(SchemaIdentifier()); }
+
inline const char *SchemaExtension() { return "bfbs"; }
inline void FinishSchemaBuffer(flatbuffers::FlatBufferBuilder &fbb, flatbuffers::Offset root) { fbb.Finish(root, SchemaIdentifier()); }
diff --git a/js/flatbuffers.js b/js/flatbuffers.js
index 6c3d15cc8..511c9a216 100644
--- a/js/flatbuffers.js
+++ b/js/flatbuffers.js
@@ -2,6 +2,10 @@
/// @addtogroup flatbuffers_javascript_api
/// @{
/// @cond FLATBUFFERS_INTERNAL
+/**
+ * @const
+ * @namespace
+ */
var flatbuffers = {};
/**
diff --git a/php/FlatbufferBuilder.php b/php/FlatbufferBuilder.php
index 3738582e2..6f0ee4831 100644
--- a/php/FlatbufferBuilder.php
+++ b/php/FlatbufferBuilder.php
@@ -233,7 +233,7 @@ class FlatbufferBuilder
public function putUint($x)
{
if ($x > PHP_INT_MAX) {
- throw new \InvalidArgumentException("your platform can't handling uint correctly. use 64bit machine.");
+ throw new \InvalidArgumentException("your platform can't handle uint correctly. use 64bit machine.");
}
$this->bb->putUint($this->space -= 4, $x);
@@ -245,7 +245,7 @@ class FlatbufferBuilder
public function putLong($x)
{
if ($x > PHP_INT_MAX) {
- throw new \InvalidArgumentException("your platform can't handling long correctly. use 64bit machine.");
+ throw new \InvalidArgumentException("Your platform can't handle long correctly. Use a 64bit machine.");
}
$this->bb->putLong($this->space -= 8, $x);
@@ -257,7 +257,7 @@ class FlatbufferBuilder
public function putUlong($x)
{
if ($x > PHP_INT_MAX) {
- throw new \InvalidArgumentException("your platform can't handling ulong correctly. this is php limitations. please wait extension release.");
+ throw new \InvalidArgumentException("Your platform can't handle ulong correctly. This is a php limitation. Please wait for the extension release.");
}
$this->bb->putUlong($this->space -= 8, $x);
diff --git a/java/pom.xml b/pom.xml
similarity index 89%
rename from java/pom.xml
rename to pom.xml
index dd92b9d55..8e32feec3 100644
--- a/java/pom.xml
+++ b/pom.xml
@@ -6,7 +6,7 @@
com.google.flatbuffers
flatbuffers-java
1.3.0-SNAPSHOT
- jar
+ bundle
FlatBuffers Java API
Memory Efficient Serialization Library
@@ -33,7 +33,7 @@
- ./
+ java
maven-compiler-plugin
@@ -78,6 +78,12 @@
+
+ org.apache.felix
+ maven-bundle-plugin
+ 3.0.1
+ true
+
diff --git a/readme.md b/readme.md
index 15dd41b11..3a7f929ef 100755
--- a/readme.md
+++ b/readme.md
@@ -46,7 +46,7 @@ you would leave it in.
- [CONTRIBUTING]: http://github.com/google/flatbuffers/blob/master/CONTRIBUTING
+ [CONTRIBUTING]: http://github.com/google/flatbuffers/blob/master/CONTRIBUTING.md
[`flatbuffers` tag]: https://stackoverflow.com/questions/tagged/flatbuffers
[FlatBuffers Google Group]: https://groups.google.com/forum/#!forum/flatbuffers
[FlatBuffers Issues Tracker]: http://github.com/google/flatbuffers/issues
diff --git a/samples/monster_generated.h b/samples/monster_generated.h
index 1a16126a5..636aa3771 100644
--- a/samples/monster_generated.h
+++ b/samples/monster_generated.h
@@ -11,8 +11,10 @@ namespace Sample {
struct Vec3;
struct Monster;
+struct MonsterT;
struct Weapon;
+struct WeaponT;
enum Color {
Color_Red = 0,
@@ -36,6 +38,21 @@ enum Equipment {
Equipment_MAX = Equipment_Weapon
};
+struct EquipmentUnion {
+ Equipment type;
+
+ flatbuffers::NativeTable *table;
+ EquipmentUnion() : type(Equipment_NONE), table(nullptr) {}
+ EquipmentUnion(const EquipmentUnion &);
+ EquipmentUnion &operator=(const EquipmentUnion &);
+ ~EquipmentUnion();
+
+ static flatbuffers::NativeTable *UnPack(const void *union_obj, Equipment type);
+ flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb) const;
+
+ WeaponT *AsWeapon() { return type == Equipment_Weapon ? reinterpret_cast(table) : nullptr; }
+};
+
inline const char **EnumNamesEquipment() {
static const char *names[] = { "NONE", "Weapon", nullptr };
return names;
@@ -52,6 +69,8 @@ MANUALLY_ALIGNED_STRUCT(4) Vec3 FLATBUFFERS_FINAL_CLASS {
float z_;
public:
+ Vec3() { memset(this, 0, sizeof(Vec3)); }
+ Vec3(const Vec3 &_o) { memcpy(this, &_o, sizeof(Vec3)); }
Vec3(float _x, float _y, float _z)
: x_(flatbuffers::EndianScalar(_x)), y_(flatbuffers::EndianScalar(_y)), z_(flatbuffers::EndianScalar(_z)) { }
@@ -64,6 +83,17 @@ MANUALLY_ALIGNED_STRUCT(4) Vec3 FLATBUFFERS_FINAL_CLASS {
};
STRUCT_END(Vec3, 12);
+struct MonsterT : public flatbuffers::NativeTable {
+ std::unique_ptr pos;
+ int16_t mana;
+ int16_t hp;
+ std::string name;
+ std::vector inventory;
+ Color color;
+ std::vector> weapons;
+ EquipmentUnion equipped;
+};
+
struct Monster FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
enum {
VT_POS = 4,
@@ -112,6 +142,7 @@ struct Monster FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
VerifyEquipment(verifier, equipped(), equipped_type()) &&
verifier.EndTable();
}
+ std::unique_ptr UnPack() const;
};
struct MonsterBuilder {
@@ -135,15 +166,15 @@ struct MonsterBuilder {
};
inline flatbuffers::Offset CreateMonster(flatbuffers::FlatBufferBuilder &_fbb,
- const Vec3 *pos = 0,
- int16_t mana = 150,
- int16_t hp = 100,
- flatbuffers::Offset name = 0,
- flatbuffers::Offset> inventory = 0,
- Color color = Color_Blue,
- flatbuffers::Offset>> weapons = 0,
- Equipment equipped_type = Equipment_NONE,
- flatbuffers::Offset equipped = 0) {
+ const Vec3 *pos = 0,
+ int16_t mana = 150,
+ int16_t hp = 100,
+ flatbuffers::Offset name = 0,
+ flatbuffers::Offset> inventory = 0,
+ Color color = Color_Blue,
+ flatbuffers::Offset>> weapons = 0,
+ Equipment equipped_type = Equipment_NONE,
+ flatbuffers::Offset equipped = 0) {
MonsterBuilder builder_(_fbb);
builder_.add_equipped(equipped);
builder_.add_weapons(weapons);
@@ -157,6 +188,26 @@ inline flatbuffers::Offset CreateMonster(flatbuffers::FlatBufferBuilder
return builder_.Finish();
}
+inline flatbuffers::Offset CreateMonster(flatbuffers::FlatBufferBuilder &_fbb,
+ const Vec3 *pos = 0,
+ int16_t mana = 150,
+ int16_t hp = 100,
+ const char *name = nullptr,
+ const std::vector *inventory = nullptr,
+ Color color = Color_Blue,
+ const std::vector> *weapons = nullptr,
+ Equipment equipped_type = Equipment_NONE,
+ flatbuffers::Offset equipped = 0) {
+ return CreateMonster(_fbb, pos, mana, hp, name ? 0 : _fbb.CreateString(name), inventory ? 0 : _fbb.CreateVector(*inventory), color, weapons ? 0 : _fbb.CreateVector>(*weapons), equipped_type, equipped);
+}
+
+inline flatbuffers::Offset CreateMonster(flatbuffers::FlatBufferBuilder &_fbb, const MonsterT *_o);
+
+struct WeaponT : public flatbuffers::NativeTable {
+ std::string name;
+ int16_t damage;
+};
+
struct Weapon FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
enum {
VT_NAME = 4,
@@ -173,6 +224,7 @@ struct Weapon FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
VerifyField(verifier, VT_DAMAGE) &&
verifier.EndTable();
}
+ std::unique_ptr UnPack() const;
};
struct WeaponBuilder {
@@ -189,14 +241,62 @@ struct WeaponBuilder {
};
inline flatbuffers::Offset CreateWeapon(flatbuffers::FlatBufferBuilder &_fbb,
- flatbuffers::Offset name = 0,
- int16_t damage = 0) {
+ flatbuffers::Offset name = 0,
+ int16_t damage = 0) {
WeaponBuilder builder_(_fbb);
builder_.add_name(name);
builder_.add_damage(damage);
return builder_.Finish();
}
+inline flatbuffers::Offset CreateWeapon(flatbuffers::FlatBufferBuilder &_fbb,
+ const char *name = nullptr,
+ int16_t damage = 0) {
+ return CreateWeapon(_fbb, name ? 0 : _fbb.CreateString(name), damage);
+}
+
+inline flatbuffers::Offset CreateWeapon(flatbuffers::FlatBufferBuilder &_fbb, const WeaponT *_o);
+
+inline std::unique_ptr Monster::UnPack() const {
+ auto _o = new MonsterT();
+ { auto _e = pos(); if (_e) _o->pos = std::unique_ptr(new Vec3(*_e)); };
+ { auto _e = mana(); _o->mana = _e; };
+ { auto _e = hp(); _o->hp = _e; };
+ { auto _e = name(); if (_e) _o->name = _e->str(); };
+ { auto _e = inventory(); if (_e) { for (size_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 (size_t _i = 0; _i < _e->size(); _i++) { _o->weapons.push_back(_e->Get(_i)->UnPack()); } } };
+ { 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(_o);
+}
+
+inline flatbuffers::Offset CreateMonster(flatbuffers::FlatBufferBuilder &_fbb, const MonsterT *_o) {
+ return CreateMonster(_fbb,
+ _o->pos ? _o->pos.get() : 0,
+ _o->mana,
+ _o->hp,
+ _o->name.size() ? _fbb.CreateString(_o->name) : 0,
+ _o->inventory.size() ? _fbb.CreateVector(_o->inventory) : 0,
+ _o->color,
+ _o->weapons.size() ? _fbb.CreateVector>(_o->weapons.size(), [&](size_t i) { return CreateWeapon(_fbb, _o->weapons[i].get()); }) : 0,
+ _o->equipped.type,
+ _o->equipped.Pack(_fbb));
+}
+
+inline std::unique_ptr Weapon::UnPack() const {
+ auto _o = new WeaponT();
+ { auto _e = name(); if (_e) _o->name = _e->str(); };
+ { auto _e = damage(); _o->damage = _e; };
+ return std::unique_ptr(_o);
+}
+
+inline flatbuffers::Offset CreateWeapon(flatbuffers::FlatBufferBuilder &_fbb, const WeaponT *_o) {
+ return CreateWeapon(_fbb,
+ _o->name.size() ? _fbb.CreateString(_o->name) : 0,
+ _o->damage);
+}
+
inline bool VerifyEquipment(flatbuffers::Verifier &verifier, const void *union_obj, Equipment type) {
switch (type) {
case Equipment_NONE: return true;
@@ -205,11 +305,34 @@ inline bool VerifyEquipment(flatbuffers::Verifier &verifier, const void *union_o
}
}
+inline flatbuffers::NativeTable *EquipmentUnion::UnPack(const void *union_obj, Equipment type) {
+ switch (type) {
+ case Equipment_NONE: return nullptr;
+ case Equipment_Weapon: return reinterpret_cast(union_obj)->UnPack().release();
+ default: return nullptr;
+ }
+}
+
+inline flatbuffers::Offset EquipmentUnion::Pack(flatbuffers::FlatBufferBuilder &_fbb) const {
+ switch (type) {
+ case Equipment_NONE: return 0;
+ case Equipment_Weapon: return CreateWeapon(_fbb, reinterpret_cast(table)).Union();
+ default: return 0;
+ }
+}
+
+inline EquipmentUnion::~EquipmentUnion() {
+ switch (type) {
+ case Equipment_Weapon: delete reinterpret_cast(table); break;
+ default:;
+ }
+}
+
inline const MyGame::Sample::Monster *GetMonster(const void *buf) { return flatbuffers::GetRoot(buf); }
inline Monster *GetMutableMonster(void *buf) { return flatbuffers::GetMutableRoot(buf); }
-inline bool VerifyMonsterBuffer(flatbuffers::Verifier &verifier) { return verifier.VerifyBuffer(); }
+inline bool VerifyMonsterBuffer(flatbuffers::Verifier &verifier) { return verifier.VerifyBuffer(nullptr); }
inline void FinishMonsterBuffer(flatbuffers::FlatBufferBuilder &fbb, flatbuffers::Offset root) { fbb.Finish(root); }
diff --git a/src/flatc.cpp b/src/flatc.cpp
index d410718e3..a568bbb24 100644
--- a/src/flatc.cpp
+++ b/src/flatc.cpp
@@ -84,14 +84,14 @@ const Generator generators[] = {
flatbuffers::CPPMakeRule },
};
-const char *program_name = nullptr;
-flatbuffers::Parser *parser = nullptr;
+const char *g_program_name = nullptr;
+flatbuffers::Parser *g_parser = nullptr;
static void Error(const std::string &err, bool usage, bool show_exe_name) {
- if (show_exe_name) printf("%s: ", program_name);
+ if (show_exe_name) printf("%s: ", g_program_name);
printf("%s\n", err.c_str());
if (usage) {
- printf("usage: %s [OPTION]... FILE... [-- FILE...]\n", program_name);
+ printf("usage: %s [OPTION]... FILE... [-- FILE...]\n", g_program_name);
for (size_t i = 0; i < sizeof(generators) / sizeof(generators[0]); ++i)
printf(" %-12s %s %s.\n",
generators[i].generator_opt_long,
@@ -123,23 +123,39 @@ static void Error(const std::string &err, bool usage, bool show_exe_name) {
" --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"
" --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"
"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"
"and written to the current directory or the path given by -o.\n"
"example: %s -c -b schema1.fbs schema2.fbs data.json\n",
- program_name);
+ g_program_name);
}
- if (parser) delete parser;
+ if (g_parser) delete g_parser;
exit(1);
}
+static void ParseFile(flatbuffers::Parser &parser, const std::string &filename,
+ const std::string &contents,
+ std::vector &include_directories) {
+ auto local_include_directory = flatbuffers::StripFileName(filename);
+ include_directories.push_back(local_include_directory.c_str());
+ include_directories.push_back(nullptr);
+ if (!parser.Parse(contents.c_str(), &include_directories[0],
+ filename.c_str()))
+ Error(parser.error_, false, false);
+ include_directories.pop_back();
+ include_directories.pop_back();
+}
+
int main(int argc, const char *argv[]) {
- program_name = argv[0];
+ g_program_name = argv[0];
flatbuffers::IDLOptions opts;
std::string output_path;
const size_t num_generators = sizeof(generators) / sizeof(generators[0]);
@@ -151,6 +167,7 @@ int main(int argc, const char *argv[]) {
std::vector filenames;
std::vector include_directories;
size_t binary_files_from = std::numeric_limits::max();
+ std::string conform_to_schema;
for (int argi = 1; argi < argc; argi++) {
std::string arg = argv[argi];
if (arg[0] == '-') {
@@ -162,6 +179,9 @@ int main(int argc, const char *argv[]) {
} else if(arg == "-I") {
if (++argi >= argc) Error("missing path following" + arg, true);
include_directories.push_back(argv[argi]);
+ } else if(arg == "--conform") {
+ if (++argi >= argc) Error("missing path following" + arg, true);
+ conform_to_schema = argv[argi];
} else if(arg == "--strict-json") {
opts.strict_json = true;
} else if(arg == "--no-js-exports") {
@@ -179,6 +199,8 @@ int main(int argc, const char *argv[]) {
opts.mutable_buffer = true;
} else if(arg == "--gen-name-strings") {
opts.generate_name_strings = true;
+ } else if(arg == "--gen-object-api") {
+ opts.generate_object_based_api = true;
} else if(arg == "--gen-all") {
opts.generate_all = true;
opts.include_dependence_headers = false;
@@ -227,12 +249,20 @@ int main(int argc, const char *argv[]) {
if (opts.proto_mode) {
if (any_generator)
Error("cannot generate code directly from .proto files", true);
- } else if (!any_generator) {
+ } else if (!any_generator && conform_to_schema.empty()) {
Error("no options: specify at least one generator.", true);
}
+ flatbuffers::Parser conform_parser;
+ if (!conform_to_schema.empty()) {
+ 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);
+ }
+
// Now process the files:
- parser = new flatbuffers::Parser(opts);
+ g_parser = new flatbuffers::Parser(opts);
for (auto file_it = filenames.begin();
file_it != filenames.end();
++file_it) {
@@ -243,8 +273,8 @@ int main(int argc, const char *argv[]) {
bool is_binary = static_cast(file_it - filenames.begin()) >=
binary_files_from;
if (is_binary) {
- parser->builder_.Clear();
- parser->builder_.PushFlatBuffer(
+ g_parser->builder_.Clear();
+ g_parser->builder_.PushFlatBuffer(
reinterpret_cast(contents.c_str()),
contents.length());
if (!raw_binary) {
@@ -253,17 +283,17 @@ int main(int argc, const char *argv[]) {
// does not contain a file identifier.
// We'd expect that typically any binary used as a file would have
// such an identifier, so by default we require them to match.
- if (!parser->file_identifier_.length()) {
+ if (!g_parser->file_identifier_.length()) {
Error("current schema has no file_identifier: cannot test if \"" +
*file_it +
"\" matches the schema, use --raw-binary to read this file"
" anyway.");
} else if (!flatbuffers::BufferHasIdentifier(contents.c_str(),
- parser->file_identifier_.c_str())) {
+ g_parser->file_identifier_.c_str())) {
Error("binary \"" +
*file_it +
"\" does not have expected file_identifier \"" +
- parser->file_identifier_ +
+ g_parser->file_identifier_ +
"\", use --raw-binary to read this file anyway.");
}
}
@@ -272,36 +302,34 @@ int main(int argc, const char *argv[]) {
if (contents.length() != strlen(contents.c_str())) {
Error("input file appears to be binary: " + *file_it, true);
}
- if (flatbuffers::GetExtension(*file_it) == "fbs") {
+ auto is_schema = flatbuffers::GetExtension(*file_it) == "fbs";
+ if (is_schema) {
// If we're processing multiple schemas, make sure to start each
// one from scratch. If it depends on previous schemas it must do
// so explicitly using an include.
- delete parser;
- parser = new flatbuffers::Parser(opts);
+ delete g_parser;
+ g_parser = new flatbuffers::Parser(opts);
+ }
+ ParseFile(*g_parser, *file_it, contents, include_directories);
+ if (is_schema && !conform_to_schema.empty()) {
+ auto err = g_parser->ConformTo(conform_parser);
+ if (!err.empty()) Error("schemas don\'t conform: " + err);
}
- auto local_include_directory = flatbuffers::StripFileName(*file_it);
- include_directories.push_back(local_include_directory.c_str());
- include_directories.push_back(nullptr);
- if (!parser->Parse(contents.c_str(), &include_directories[0],
- file_it->c_str()))
- Error(parser->error_, false, false);
if (schema_binary) {
- parser->Serialize();
- parser->file_extension_ = reflection::SchemaExtension();
+ g_parser->Serialize();
+ g_parser->file_extension_ = reflection::SchemaExtension();
}
- include_directories.pop_back();
- include_directories.pop_back();
}
std::string filebase = flatbuffers::StripPath(
flatbuffers::StripExtension(*file_it));
for (size_t i = 0; i < num_generators; ++i) {
- parser->opts.lang = generators[i].lang;
+ g_parser->opts.lang = generators[i].lang;
if (generator_enabled[i]) {
if (!print_make_rules) {
flatbuffers::EnsureDirExists(output_path);
- if (!generators[i].generate(*parser, output_path, filebase)) {
+ if (!generators[i].generate(*g_parser, output_path, filebase)) {
Error(std::string("Unable to generate ") +
generators[i].lang_name +
" for " +
@@ -309,7 +337,7 @@ int main(int argc, const char *argv[]) {
}
} else {
std::string make_rule = generators[i].make_rule(
- *parser, output_path, *file_it);
+ *g_parser, output_path, *file_it);
if (!make_rule.empty())
printf("%s\n", flatbuffers::WordWrap(
make_rule, 80, " ", " \\").c_str());
@@ -317,13 +345,13 @@ int main(int argc, const char *argv[]) {
}
}
- if (opts.proto_mode) GenerateFBS(*parser, output_path, filebase);
+ if (opts.proto_mode) GenerateFBS(*g_parser, output_path, filebase);
// We do not want to generate code for the definitions in this file
// in any files coming up next.
- parser->MarkGenerated();
+ g_parser->MarkGenerated();
}
- delete parser;
+ delete g_parser;
return 0;
}
diff --git a/src/idl_gen_cpp.cpp b/src/idl_gen_cpp.cpp
index c690240d6..ad20b36cb 100644
--- a/src/idl_gen_cpp.cpp
+++ b/src/idl_gen_cpp.cpp
@@ -24,9 +24,7 @@
namespace flatbuffers {
struct IsAlnum {
- bool operator()(char c) {
- return !isalnum(c);
- }
+ bool operator()(char c) { return !isalnum(c); }
};
static std::string GeneratedFileName(const std::string &path,
@@ -39,7 +37,8 @@ class CppGenerator : public BaseGenerator {
public:
CppGenerator(const Parser &parser, const std::string &path,
const std::string &file_name)
- : BaseGenerator(parser, path, file_name, "", "::"){};
+ : BaseGenerator(parser, path, file_name, "", "::"),
+ cur_name_space_(nullptr){};
// Iterate through all definitions we haven't generate code for (enums,
// structs,
// and tables) and output them to a single file.
@@ -95,7 +94,11 @@ class CppGenerator : public BaseGenerator {
auto &struct_def = **it;
if (!struct_def.generated) {
SetNameSpace(struct_def.defined_namespace, &code);
- code += "struct " + struct_def.name + ";\n\n";
+ code += "struct " + struct_def.name + ";\n";
+ if (parser_.opts.generate_object_based_api && !struct_def.fixed) {
+ code += "struct " + NativeName(struct_def.name) + ";\n";
+ }
+ code += "\n";
}
}
@@ -126,6 +129,14 @@ class CppGenerator : public BaseGenerator {
GenTable(struct_def, &code);
}
}
+ for (auto it = parser_.structs_.vec.begin();
+ it != parser_.structs_.vec.end(); ++it) {
+ auto &struct_def = **it;
+ if (!struct_def.fixed && !struct_def.generated) {
+ SetNameSpace(struct_def.defined_namespace, &code);
+ GenTablePost(struct_def, &code);
+ }
+ }
// Generate code for union verifiers.
for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
@@ -133,7 +144,7 @@ class CppGenerator : public BaseGenerator {
auto &enum_def = **it;
if (enum_def.is_union && !enum_def.generated) {
SetNameSpace(enum_def.defined_namespace, &code);
- GenEnumPost(enum_def, &code);
+ GenUnionPost(enum_def, &code);
}
}
@@ -157,14 +168,6 @@ class CppGenerator : public BaseGenerator {
code += name + ">(buf); }\n\n";
}
- // The root verifier:
- code += "inline bool Verify";
- code += name;
- code +=
- "Buffer(flatbuffers::Verifier &verifier) { "
- "return verifier.VerifyBuffer<";
- code += cpp_qualified_name + ">(); }\n\n";
-
if (parser_.file_identifier_.length()) {
// Return the identifier
code += "inline const char *" + name;
@@ -178,6 +181,19 @@ class CppGenerator : public BaseGenerator {
code += name + "Identifier()); }\n\n";
}
+ // The root verifier:
+ code += "inline bool Verify";
+ code += name;
+ code +=
+ "Buffer(flatbuffers::Verifier &verifier) { "
+ "return verifier.VerifyBuffer<";
+ code += cpp_qualified_name + ">(";
+ if (parser_.file_identifier_.length())
+ code += name + "Identifier()";
+ else
+ code += "nullptr";
+ code += "); }\n\n";
+
if (parser_.file_extension_.length()) {
// Return the extension
code += "inline const char *" + name;
@@ -206,7 +222,7 @@ class CppGenerator : public BaseGenerator {
private:
// This tracks the current namespace so we can insert namespace declarations.
- const Namespace *cur_name_space_ = nullptr;
+ const Namespace *cur_name_space_;
const Namespace *CurrentNameSpace() { return cur_name_space_; }
@@ -225,9 +241,10 @@ class CppGenerator : public BaseGenerator {
// Return a C++ type from the table in idl.h
std::string GenTypeBasic(const Type &type, bool user_facing_type) {
static const char *ctypename[] = {
-#define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) #CTYPE,
+ #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \
+ #CTYPE,
FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
-#undef FLATBUFFERS_TD
+ #undef FLATBUFFERS_TD
};
if (user_facing_type) {
if (type.enum_def) return WrapInNameSpace(*type.enum_def);
@@ -245,9 +262,8 @@ class CppGenerator : public BaseGenerator {
case BASE_TYPE_VECTOR:
return "flatbuffers::Vector<" +
GenTypeWire(type.VectorType(), "", false) + ">";
- case BASE_TYPE_STRUCT: {
+ case BASE_TYPE_STRUCT:
return WrapInNameSpace(*type.struct_def);
- }
case BASE_TYPE_UNION:
// fall through
default:
@@ -257,30 +273,56 @@ class CppGenerator : public BaseGenerator {
// Return a C++ type for any type (scalar/pointer) specifically for
// building a flatbuffer.
- std::string GenTypeWire(const Type &type,
- const char *postfix, bool user_facing_type) {
+ std::string GenTypeWire(const Type &type, const char *postfix,
+ bool user_facing_type) {
return IsScalar(type.base_type)
? GenTypeBasic(type, user_facing_type) + postfix
- : IsStruct(type)
- ? "const " + GenTypePointer(type) + " *"
- : "flatbuffers::Offset<" + GenTypePointer(type) +
- ">" + postfix;
+ : IsStruct(type) ? "const " + GenTypePointer(type) + " *"
+ : "flatbuffers::Offset<" +
+ GenTypePointer(type) + ">" + postfix;
}
// Return a C++ type for any type (scalar/pointer) that reflects its
// serialized size.
std::string GenTypeSize(const Type &type) {
- return IsScalar(type.base_type)
- ? GenTypeBasic(type, false)
- : IsStruct(type) ? GenTypePointer(type)
- : "flatbuffers::uoffset_t";
+ return IsScalar(type.base_type) ? GenTypeBasic(type, false)
+ : IsStruct(type) ? GenTypePointer(type)
+ : "flatbuffers::uoffset_t";
+ }
+
+ // TODO(wvo): make this configurable.
+ std::string NativeName(const std::string &name) { return name + "T"; }
+
+ std::string GenTypeNative(const Type &type, bool invector) {
+ switch (type.base_type) {
+ case BASE_TYPE_STRING:
+ return "std::string";
+ case BASE_TYPE_VECTOR:
+ return "std::vector<" + GenTypeNative(type.VectorType(), true) + ">";
+ case BASE_TYPE_STRUCT:
+ if (IsStruct(type)) {
+ if (invector) {
+ return WrapInNameSpace(*type.struct_def);
+ } else {
+ return "std::unique_ptr<" +
+ WrapInNameSpace(*type.struct_def) + ">";
+ }
+ } else {
+ return "std::unique_ptr<" +
+ NativeName(WrapInNameSpace(*type.struct_def)) + ">";
+ }
+ case BASE_TYPE_UNION:
+ return type.enum_def->name + "Union";
+ default:
+ return GenTypeBasic(type, true);
+ }
}
// Return a C++ type for any type (scalar/pointer) specifically for
// using a flatbuffer.
- std::string GenTypeGet(const Type &type,
- const char *afterbasic, const char *beforeptr,
- const char *afterptr, bool user_facing_type) {
+ std::string GenTypeGet(const Type &type, const char *afterbasic,
+ const char *beforeptr, const char *afterptr,
+ bool user_facing_type) {
return IsScalar(type.base_type)
? GenTypeBasic(type, user_facing_type) + afterbasic
: beforeptr + GenTypePointer(type) + afterptr;
@@ -309,12 +351,37 @@ class CppGenerator : public BaseGenerator {
}
}
- std::string EnumSignature(EnumDef &enum_def) {
+ std::string UnionVerifySignature(EnumDef &enum_def) {
return "inline bool Verify" + enum_def.name +
- "(flatbuffers::Verifier &verifier, " + "const void *union_obj, " +
+ "(flatbuffers::Verifier &verifier, const void *union_obj, " +
enum_def.name + " type)";
}
+ std::string UnionUnPackSignature(EnumDef &enum_def, bool inclass) {
+ return (inclass ? "static " : "") +
+ std::string("flatbuffers::NativeTable *") +
+ (inclass ? "" : enum_def.name + "Union::") +
+ "UnPack(const void *union_obj, " + enum_def.name + " type)";
+ }
+
+ std::string UnionPackSignature(EnumDef &enum_def, bool inclass) {
+ return "flatbuffers::Offset " +
+ (inclass ? "" : enum_def.name + "Union::") +
+ "Pack(flatbuffers::FlatBufferBuilder &_fbb) const";
+ }
+
+ std::string TableCreateSignature(StructDef &struct_def) {
+ return "inline flatbuffers::Offset<" + struct_def.name + "> Create" +
+ struct_def.name +
+ "(flatbuffers::FlatBufferBuilder &_fbb, const " +
+ NativeName(struct_def.name) + " *_o)";
+ }
+
+ std::string TableUnPackSignature(StructDef &struct_def, bool inclass) {
+ return "std::unique_ptr<" + NativeName(struct_def.name) + "> " +
+ (inclass ? "" : struct_def.name + "::") + "UnPack() const";
+ }
+
// Generate an enum declaration and an enum string lookup table.
void GenEnum(EnumDef &enum_def, std::string *code_ptr) {
std::string &code = *code_ptr;
@@ -356,6 +423,36 @@ class CppGenerator : public BaseGenerator {
GenTypeBasic(enum_def.underlying_type, false) + ")\n";
code += "\n";
+ if (parser_.opts.generate_object_based_api && enum_def.is_union) {
+ // Generate a union type
+ code += "struct " + enum_def.name + "Union {\n";
+ 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 += "), table(nullptr) {}\n";
+ code += " " + enum_def.name + "Union(const ";
+ code += enum_def.name + "Union &);\n";
+ code += " " + enum_def.name + "Union &operator=(const ";
+ code += enum_def.name + "Union &);\n";
+ code += " ~" + enum_def.name + "Union();\n\n";
+ code += " " + UnionUnPackSignature(enum_def, true) + ";\n";
+ code += " " + UnionPackSignature(enum_def, true) + ";\n\n";
+ for (auto it = enum_def.vals.vec.begin(); it != enum_def.vals.vec.end();
+ ++it) {
+ auto &ev = **it;
+ if (ev.value) {
+ 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 += " ? reinterpret_cast<" + native_name;
+ code += " *>(table) : nullptr; }\n";
+ }
+ }
+ code += "};\n\n";
+ }
+
// Generate a generate string table for enum values.
// Problem is, if values are very sparse that could generate really big
// tables. Ideally in that case we generate a map lookup instead, but for
@@ -381,38 +478,89 @@ class CppGenerator : public BaseGenerator {
code += "()[static_cast(e)";
if (enum_def.vals.vec.front()->value) {
code += " - static_cast(";
- code +=
- GetEnumVal(enum_def, *enum_def.vals.vec.front(), parser_.opts) + ")";
+ code += GetEnumVal(enum_def, *enum_def.vals.vec.front(), parser_.opts) +
+ ")";
}
code += "]; }\n\n";
}
if (enum_def.is_union) {
- code += EnumSignature(enum_def) + ";\n\n";
+ code += UnionVerifySignature(enum_def) + ";\n\n";
}
}
- void GenEnumPost(EnumDef &enum_def, std::string *code_ptr_post) {
+ void GenUnionPost(EnumDef &enum_def, std::string *code_ptr) {
// Generate a verifier function for this union that can be called by the
// table verifier functions. It uses a switch case to select a specific
// verifier function to call, this should be safe even if the union type
// has been corrupted, since the verifiers will simply fail when called
// on the wrong type.
- std::string &code_post = *code_ptr_post;
- code_post += EnumSignature(enum_def) + " {\n switch (type) {\n";
+ std::string &code = *code_ptr;
+ code += UnionVerifySignature(enum_def) + " {\n switch (type) {\n";
for (auto it = enum_def.vals.vec.begin(); it != enum_def.vals.vec.end();
++it) {
auto &ev = **it;
- code_post += " case " + GetEnumVal(enum_def, ev, parser_.opts);
+ code += " case " + GetEnumVal(enum_def, ev, parser_.opts);
if (!ev.value) {
- code_post += ": return true;\n"; // "NONE" enum value.
+ code += ": return true;\n"; // "NONE" enum value.
} else {
- code_post += ": return verifier.VerifyTable(reinterpret_cast(union_obj));\n";
+ code += ": return verifier.VerifyTable(reinterpret_cast(union_obj));\n";
}
}
- code_post += " default: return false;\n }\n}\n\n";
+ code += " default: return false;\n }\n}\n\n";
+
+ if (parser_.opts.generate_object_based_api) {
+ // Generate a union pack & unpack function.
+ code += "inline " + UnionUnPackSignature(enum_def, false);
+ code += " {\n switch (type) {\n";
+ 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);
+ if (!ev.value) {
+ code += ": return nullptr;\n"; // "NONE" enum value.
+ } else {
+ code += ": return reinterpret_cast(union_obj)->UnPack().release();\n";
+ }
+ }
+ code += " default: return nullptr;\n }\n}\n\n";
+ code += "inline " + UnionPackSignature(enum_def, false);
+ code += " {\n switch (type) {\n";
+ 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);
+ if (!ev.value) {
+ code += ": return 0;\n"; // "NONE" enum value.
+ } else {
+ code += ": return Create" + ev.struct_def->name;
+ code += "(_fbb, reinterpret_cast(table)).Union();\n";
+ }
+ }
+ code += " default: return 0;\n }\n}\n\n";
+
+ // Generate a union destructor.
+ code += "inline " + enum_def.name + "Union::~";
+ code += enum_def.name + "Union() {\n";
+ code += " switch (type) {\n";
+ for (auto it = enum_def.vals.vec.begin(); it != enum_def.vals.vec.end();
+ ++it) {
+ auto &ev = **it;
+ if (ev.value) {
+ code += " case " + GenEnumVal(enum_def, ev.name, parser_.opts);
+ code += ": delete reinterpret_cast<";
+ code += NativeName(WrapInNameSpace(*ev.struct_def));
+ code += " *>(table); break;\n";
+ }
+ }
+ code += " default:;\n }\n}\n\n";
+ }
}
// Generates a value with optionally a cast applied if the field has a
@@ -439,8 +587,7 @@ class CppGenerator : public BaseGenerator {
return "VT_" + uname;
}
- void GenFullyQualifiedNameGetter(const std::string &name,
- std::string &code) {
+ void GenFullyQualifiedNameGetter(const std::string &name, std::string &code) {
if (parser_.opts.generate_name_strings) {
code +=
" static FLATBUFFERS_CONSTEXPR const char *GetFullyQualifiedName() "
@@ -457,9 +604,47 @@ class CppGenerator : public BaseGenerator {
: field.value.constant;
}
+ void GenSimpleParam(std::string &code, FieldDef &field) {
+ code += ",\n " + GenTypeWire(field.value.type, " ", true);
+ code += field.name + " = ";
+ if (field.value.type.enum_def && IsScalar(field.value.type.base_type)) {
+ auto ev = field.value.type.enum_def->ReverseLookup(
+ static_cast(StringToInt(field.value.constant.c_str())), false);
+ if (ev) {
+ code += WrapInNameSpace(
+ field.value.type.enum_def->defined_namespace,
+ GetEnumVal(*field.value.type.enum_def, *ev, parser_.opts));
+ } else {
+ code += GenUnderlyingCast(field, true, field.value.constant);
+ }
+ } else if (field.value.type.base_type == BASE_TYPE_BOOL) {
+ code += field.value.constant == "0" ? "false" : "true";
+ } else {
+ code += GenDefaultConstant(field);
+ }
+ }
+
// Generate an accessor struct, builder structs & function for a table.
void GenTable(StructDef &struct_def, std::string *code_ptr) {
std::string &code = *code_ptr;
+
+ if (parser_.opts.generate_object_based_api) {
+ // Generate a C++ object that can hold an unpacked version of this
+ // table.
+ code += "struct " + NativeName(struct_def.name);
+ code += " : public flatbuffers::NativeTable {\n";
+ 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";
+ }
+ }
+ code += "};\n\n";
+ }
+
// Generate an accessor struct, with methods of the form:
// type name() const { return GetField(offset, defaultval); }
GenComment(struct_def.doc_comment, code_ptr, nullptr);
@@ -498,8 +683,7 @@ class CppGenerator : public BaseGenerator {
if (!field.deprecated) { // Deprecated fields won't be accessible.
auto is_scalar = IsScalar(field.value.type.base_type);
GenComment(field.doc_comment, code_ptr, nullptr, " ");
- code += " " +
- GenTypeGet(field.value.type, " ", "const ", " *", true);
+ code += " " + GenTypeGet(field.value.type, " ", "const ", " *", true);
code += field.name + "() const { return ";
// Call a different accessor for pointers, that indirects.
auto accessor =
@@ -507,8 +691,8 @@ class CppGenerator : public BaseGenerator {
? "GetField<"
: (IsStruct(field.value.type) ? "GetStruct<" : "GetPointer<");
auto offsetstr = GenFieldOffsetName(field);
- auto call = accessor + GenTypeGet(field.value.type, "",
- "const ", " *", false) +
+ auto call = accessor +
+ GenTypeGet(field.value.type, "", "const ", " *", false) +
">(" + offsetstr;
// Default value as second arg for non-pointer types.
if (IsScalar(field.value.type.base_type))
@@ -525,8 +709,7 @@ class CppGenerator : public BaseGenerator {
code += GenUnderlyingCast(field, false, "_" + field.name);
code += "); }\n";
} else {
- auto type =
- GenTypeGet(field.value.type, " ", "", " *", true);
+ auto type = GenTypeGet(field.value.type, " ", "", " *", true);
code += " " + type + "mutable_" + field.name + "() { return ";
code += GenUnderlyingCast(field, true,
accessor + type + ">(" + offsetstr + ")");
@@ -627,7 +810,13 @@ class CppGenerator : public BaseGenerator {
}
code += prefix + "verifier.EndTable()";
code += ";\n }\n";
- code += "};\n\n";
+
+ if (parser_.opts.generate_object_based_api) {
+ // Generate the UnPack() pre declaration.
+ code += " " + TableUnPackSignature(struct_def, true) + ";\n";
+ }
+
+ code += "};\n\n"; // End of table.
// Generate a builder struct, with methods of the form:
// void add_name(type name) { fbb_.AddElement(offset, name, default);
@@ -679,6 +868,7 @@ class CppGenerator : public BaseGenerator {
// Generate a convenient CreateX function that uses the above builder
// to create a table in one go.
+ bool gen_vector_pars = false;
code += "inline flatbuffers::Offset<" + struct_def.name + "> Create";
code += struct_def.name;
code += "(flatbuffers::FlatBufferBuilder &_fbb";
@@ -686,24 +876,11 @@ class CppGenerator : public BaseGenerator {
it != struct_def.fields.vec.end(); ++it) {
auto &field = **it;
if (!field.deprecated) {
- code += ",\n " + GenTypeWire(field.value.type, " ", true);
- code += field.name + " = ";
- if (field.value.type.enum_def && IsScalar(field.value.type.base_type)) {
- auto ev = field.value.type.enum_def->ReverseLookup(
- static_cast(StringToInt(field.value.constant.c_str())),
- false);
- if (ev) {
- code += WrapInNameSpace(
- field.value.type.enum_def->defined_namespace,
- GetEnumVal(*field.value.type.enum_def, *ev, parser_.opts));
- } else {
- code += GenUnderlyingCast(field, true, field.value.constant);
- }
- } else if (field.value.type.base_type == BASE_TYPE_BOOL) {
- code += field.value.constant == "0" ? "false" : "true";
- } else {
- code += GenDefaultConstant(field);
+ if (field.value.type.base_type == BASE_TYPE_STRING ||
+ field.value.type.base_type == BASE_TYPE_VECTOR) {
+ gen_vector_pars = true;
}
+ GenSimpleParam(code, field);
}
}
code += ") {\n " + struct_def.name + "Builder builder_(_fbb);\n";
@@ -719,6 +896,212 @@ class CppGenerator : public BaseGenerator {
}
}
code += " return builder_.Finish();\n}\n\n";
+
+ // Generate a CreateX 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";
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (!field.deprecated) {
+ if (field.value.type.base_type == BASE_TYPE_STRING) {
+ code += ",\n const char *";
+ code += field.name + " = nullptr";
+ } else if (field.value.type.base_type == BASE_TYPE_VECTOR) {
+ code += ",\n const std::vector<";
+ code += GenTypeWire(field.value.type.VectorType(), "", false);
+ code += "> *" + field.name + " = nullptr";
+ } else {
+ GenSimpleParam(code, field);
+ }
+ }
+ }
+ code += ") {\n ";
+ code += "return Create";
+ code += struct_def.name;
+ code += "(_fbb";
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (!field.deprecated) {
+ if (field.value.type.base_type == BASE_TYPE_STRING) {
+ code += ", " + field.name + " ? 0 : ";
+ code += "_fbb.CreateString(" + field.name + ")";
+ } else if (field.value.type.base_type == BASE_TYPE_VECTOR) {
+ code += ", " + field.name + " ? 0 : ";
+ code += "_fbb.CreateVector<";
+ code += GenTypeWire(field.value.type.VectorType(), "", false);
+ code += ">(*" + field.name + ")";
+ } else
+ code += ", " + field.name;
+ }
+ }
+ code += ");\n}\n\n";
+ }
+
+ 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";
+ }
+ }
+
+ // 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;
+
+ if (parser_.opts.generate_object_based_api) {
+ // Generate the UnPack() method.
+ code += "inline " + TableUnPackSignature(struct_def, false) + " {\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) {
+ auto &field = **it;
+ if (!field.deprecated) {
+ auto prefix = " { auto _e = " + field.name + "(); ";
+ if (!IsScalar(field.value.type.base_type)) prefix += "if (_e) ";
+ 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<" + type.struct_def->name +
+ ">(new " + type.struct_def->name + "(*" + 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)";
+ if (field.value.type.element == BASE_TYPE_BOOL)
+ indexing += "!=0";
+ code += gen_unpack_val(field.value.type.VectorType(),
+ indexing, true);
+ code += "); } }";
+ break;
+ }
+ case BASE_TYPE_UTYPE: {
+ auto &union_field = **(it + 1);
+ assert(union_field.value.type.base_type == BASE_TYPE_UNION);
+ code += prefix + deref + union_field.name + ".type = _e;";
+ break;
+ }
+ case BASE_TYPE_UNION:
+ code += prefix + dest + ".table = ";
+ code += field.value.type.enum_def->name;
+ code += "Union::UnPack(_e, ";
+ code += field.name + UnionTypeFieldSuffix() + "());";
+ break;
+ default:
+ code += assign + gen_unpack_val(field.value.type, "_e", false);
+ code += ";";
+ break;
+ }
+ code += " };\n";
+ }
+ }
+ code += " return std::unique_ptr<" + NativeName(struct_def.name);
+ code += ">(_o);\n}\n\n";
+
+ // Generate a CreateX method that works with an unpacked C++ object.
+ code += TableCreateSignature(struct_def) + " {\n";
+ auto before_return_statement = code.size();
+ code += " return Create";
+ code += struct_def.name + "(_fbb";
+ bool any_fields = false;
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (!field.deprecated) {
+ any_fields = true;
+ auto field_name = field.name;
+ if (field.value.type.base_type == BASE_TYPE_UTYPE) {
+ field_name = field_name.substr(0, field_name.size() -
+ strlen(UnionTypeFieldSuffix()));
+ field_name += ".type";
+ }
+ auto accessor = "_o->" + field_name;
+ auto ptrprefix = accessor + " ? ";
+ auto stlprefix = accessor + ".size() ? ";
+ auto postfix = " : 0";
+ if (field.required &&
+ (field.value.type.base_type == BASE_TYPE_STRING ||
+ field.value.type.base_type == BASE_TYPE_VECTOR)) {
+ stlprefix = "";
+ postfix = "";
+ }
+ code += ",\n ";
+ switch (field.value.type.base_type) {
+ case BASE_TYPE_STRING:
+ code += stlprefix + "_fbb.CreateString(" + accessor + ")";
+ code += postfix;
+ break;
+ case BASE_TYPE_VECTOR: {
+ auto vector_type = field.value.type.VectorType();
+ code += stlprefix;
+ switch (vector_type.base_type) {
+ case BASE_TYPE_STRING:
+ code += "_fbb.CreateVectorOfStrings(" + accessor + ")";
+ break;
+ case BASE_TYPE_STRUCT:
+ if (IsStruct(vector_type)) {
+ code += "_fbb.CreateVectorOfStructs(" + accessor + ")";
+ } else {
+ code += "_fbb.CreateVectorname + ">>(" + accessor;
+ code += ".size(), [&](size_t i) { return Create";
+ code += vector_type.struct_def->name + "(_fbb, " + accessor;
+ code += "[i].get()); })";
+ }
+ break;
+ default:
+ code += "_fbb.CreateVector(" + accessor + ")";
+ break;
+ }
+ code += postfix;
+ break;
+ }
+ case BASE_TYPE_UNION:
+ code += accessor + ".Pack(_fbb)";
+ break;
+ case BASE_TYPE_STRUCT:
+ if (IsStruct(field.value.type)) {
+ code += ptrprefix + accessor + ".get()" + postfix;
+ } else {
+ code += ptrprefix + "Create";
+ code += field.value.type.struct_def->name;
+ code += "(_fbb, " + accessor + ".get())" + postfix;
+ }
+ break;
+ default:
+ code += accessor;
+ break;
+ }
+ }
+ }
+ code += ");\n}\n\n";
+ if (!any_fields) code.insert(before_return_statement, " (void)_o;\n");
+ }
}
static void GenPadding(const FieldDef &field, std::string &code,
@@ -775,6 +1158,15 @@ class CppGenerator : public BaseGenerator {
code += "\n public:\n";
GenFullyQualifiedNameGetter(struct_def.name, code);
+ // Generate a default constructor.
+ code += " " + struct_def.name + "() { memset(this, 0, sizeof(";
+ code += struct_def.name + ")); }\n";
+
+ // Generate a copy constructor.
+ code += " " + struct_def.name + "(const " + struct_def.name;
+ code += " &_o) { memcpy(this, &_o, sizeof(";
+ code += struct_def.name + ")); }\n";
+
// Generate a constructor that takes all fields as arguments.
code += " " + struct_def.name + "(";
for (auto it = struct_def.fields.vec.begin();
@@ -817,8 +1209,7 @@ class CppGenerator : public BaseGenerator {
auto &field = **it;
GenComment(field.doc_comment, code_ptr, nullptr, " ");
auto is_scalar = IsScalar(field.value.type.base_type);
- code += " " +
- GenTypeGet(field.value.type, " ", "const ", " &", true);
+ code += " " + GenTypeGet(field.value.type, " ", "const ", " &", true);
code += field.name + "() const { return ";
code += GenUnderlyingCast(
field, true, is_scalar
@@ -878,6 +1269,7 @@ class CppGenerator : public BaseGenerator {
cur_name_space_ = ns;
}
};
+
} // namespace cpp
bool GenerateCPP(const Parser &parser, const std::string &path,
@@ -886,19 +1278,16 @@ bool GenerateCPP(const Parser &parser, const std::string &path,
return generator.generate();
}
-std::string CPPMakeRule(const Parser &parser,
- const std::string &path,
+std::string CPPMakeRule(const Parser &parser, const std::string &path,
const std::string &file_name) {
- std::string filebase = flatbuffers::StripPath(
- flatbuffers::StripExtension(file_name));
+ std::string filebase =
+ flatbuffers::StripPath(flatbuffers::StripExtension(file_name));
std::string make_rule = GeneratedFileName(path, filebase) + ": ";
auto included_files = parser.GetIncludedFilesRecursive(file_name);
- for (auto it = included_files.begin();
- it != included_files.end(); ++it) {
+ for (auto it = included_files.begin(); it != included_files.end(); ++it) {
make_rule += " " + *it;
}
return make_rule;
}
} // namespace flatbuffers
-
diff --git a/src/idl_gen_general.cpp b/src/idl_gen_general.cpp
index a96609c54..7e8e8c577 100644
--- a/src/idl_gen_general.cpp
+++ b/src/idl_gen_general.cpp
@@ -193,9 +193,11 @@ class GeneralGenerator : public BaseGenerator {
public:
GeneralGenerator(const Parser &parser, const std::string &path,
const std::string &file_name)
- : BaseGenerator(parser, path, file_name, "", "."){
- assert(parser_.opts.lang <= IDLOptions::kMAX);
+ : BaseGenerator(parser, path, file_name, "", "."),
+ lang_(language_parameters[parser_.opts.lang]) {
+ assert(parser_.opts.lang <= IDLOptions::kMAX);
};
+ GeneralGenerator &operator=(const GeneralGenerator &);
bool generate() {
std::string one_file_code;
@@ -234,7 +236,7 @@ class GeneralGenerator : public BaseGenerator {
// Save out the generated code for a single class while adding
// declaration boilerplate.
- bool SaveType(const std::string &defname, const Namespace &ns,
+ bool SaveType(const std::string &defname, const Namespace &ns,
const std::string &classcode, bool needs_includes) {
if (!classcode.length()) return true;
@@ -544,7 +546,7 @@ void GenEnum(EnumDef &enum_def, std::string *code_ptr) {
// "too sparse". Change at will.
static const int kMaxSparseness = 5;
if (range / static_cast(enum_def.vals.vec.size()) < kMaxSparseness) {
- code += "\n private static";
+ code += "\n public static";
code += lang_.const_decl;
code += lang_.string_type;
code += "[] names = { ";
@@ -567,7 +569,10 @@ void GenEnum(EnumDef &enum_def, std::string *code_ptr) {
}
// Close the class
- code += "};\n\n";
+ code += "}";
+ // Java does not need the closing semi-colon on class definitions.
+ code += (lang_.language != IDLOptions::kJava) ? ";" : "";
+ code += "\n\n";
}
// Returns the function name that is able to read a value of the given type.
@@ -1125,9 +1130,12 @@ void GenStruct(StructDef &struct_def, std::string *code_ptr) {
code += "); }\n";
}
}
- code += "};\n\n";
-}
- const LanguageParameters & lang_ = language_parameters[parser_.opts.lang];
+ code += "}";
+ // Java does not need the closing semi-colon on class definitions.
+ code += (lang_.language != IDLOptions::kJava) ? ";" : "";
+ code += "\n\n";
+}
+ const LanguageParameters & lang_;
};
} // namespace general
diff --git a/src/idl_gen_go.cpp b/src/idl_gen_go.cpp
index a04b6ba20..1f6b103ea 100644
--- a/src/idl_gen_go.cpp
+++ b/src/idl_gen_go.cpp
@@ -439,7 +439,7 @@ static void GenReceiver(const StructDef &struct_def, std::string *code_ptr) {
code += "func (rcv *" + struct_def.name + ")";
}
-// Generate a struct field, conditioned on its child type(s).
+// Generate a struct field getter, conditioned on its child type(s).
static void GenStructAccessor(const StructDef &struct_def,
const FieldDef &field,
std::string *code_ptr) {
@@ -486,6 +486,48 @@ static void GenStructAccessor(const StructDef &struct_def,
}
}
+// Mutate the value of a struct's scalar.
+static void MutateScalarFieldOfStruct(const StructDef &struct_def,
+ const FieldDef &field,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ std::string type = MakeCamel(GenTypeBasic(field.value.type));
+ std::string setter = "rcv._tab.Mutate" + type;
+ GenReceiver(struct_def, code_ptr);
+ code += " Mutate" + MakeCamel(field.name);
+ code += "(n " + TypeName(field) + ") bool { return " + setter;
+ code += "(rcv._tab.Pos + flatbuffers.UOffsetT(";
+ code += NumToString(field.value.offset) + "), n) }\n\n";
+}
+
+// Mutate the value of a table's scalar.
+static void MutateScalarFieldOfTable(const StructDef &struct_def,
+ const FieldDef &field,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ std::string type = MakeCamel(GenTypeBasic(field.value.type));
+ std::string setter = "rcv._tab.Mutate" + type + "Slot";
+ GenReceiver(struct_def, code_ptr);
+ code += " Mutate" + MakeCamel(field.name);
+ code += "(n " + TypeName(field) + ") bool {\n\treturn ";
+ code += setter + "(" + NumToString(field.value.offset) + ", n)\n";
+ code += "}\n\n";
+}
+
+// Generate a struct field setter, conditioned on its child type(s).
+static void GenStructMutator(const StructDef &struct_def,
+ const FieldDef &field,
+ std::string *code_ptr) {
+ GenComment(field.doc_comment, code_ptr, nullptr, "");
+ if (IsScalar(field.value.type.base_type)) {
+ if (struct_def.fixed) {
+ MutateScalarFieldOfStruct(struct_def, field, code_ptr);
+ } else {
+ MutateScalarFieldOfTable(struct_def, field, code_ptr);
+ }
+ }
+}
+
// Generate table constructors, conditioned on its members' types.
static void GenTableBuilders(const StructDef &struct_def,
std::string *code_ptr) {
@@ -509,13 +551,12 @@ static void GenTableBuilders(const StructDef &struct_def,
// Generate struct or table methods.
static void GenStruct(const StructDef &struct_def,
- std::string *code_ptr,
- StructDef *root_struct_def) {
+ std::string *code_ptr) {
if (struct_def.generated) return;
GenComment(struct_def.doc_comment, code_ptr, nullptr);
BeginClass(struct_def, code_ptr);
- if (&struct_def == root_struct_def) {
+ if (!struct_def.fixed) {
// Generate a special accessor for the table that has been declared as
// the root type.
NewRootTypeFromBuffer(struct_def, code_ptr);
@@ -530,6 +571,7 @@ static void GenStruct(const StructDef &struct_def,
if (field.deprecated) continue;
GenStructAccessor(struct_def, field, code_ptr);
+ GenStructMutator(struct_def, field, code_ptr);
}
if (struct_def.fixed) {
@@ -638,7 +680,7 @@ class GoGenerator : public BaseGenerator {
for (auto it = parser_.structs_.vec.begin();
it != parser_.structs_.vec.end(); ++it) {
std::string declcode;
- go::GenStruct(**it, &declcode, parser_.root_struct_def_);
+ go::GenStruct(**it, &declcode);
if (!SaveType(**it, declcode, true)) return false;
}
@@ -681,4 +723,3 @@ bool GenerateGo(const Parser &parser, const std::string &path,
}
} // namespace flatbuffers
-
diff --git a/src/idl_gen_grpc.cpp b/src/idl_gen_grpc.cpp
index 2bf0e911d..6ada3e873 100644
--- a/src/idl_gen_grpc.cpp
+++ b/src/idl_gen_grpc.cpp
@@ -137,6 +137,7 @@ class FlatBufFile : public grpc_cpp_generator::File {
public:
FlatBufFile(const Parser &parser, const std::string &file_name)
: parser_(parser), file_name_(file_name) {}
+ FlatBufFile &operator=(const FlatBufFile &);
std::string filename() const { return file_name_; }
std::string filename_without_ext() const {
diff --git a/src/idl_gen_js.cpp b/src/idl_gen_js.cpp
index 32a06f1ef..d7c913e50 100644
--- a/src/idl_gen_js.cpp
+++ b/src/idl_gen_js.cpp
@@ -110,7 +110,7 @@ class JsGenerator : public BaseGenerator {
std::string &exports = *exports_ptr;
for (auto it = sorted_namespaces.begin();
it != sorted_namespaces.end(); it++) {
- code += "/**\n * @const\n*/\n";
+ code += "/**\n * @const\n * @namespace\n */\n";
if (it->find('.') == std::string::npos) {
code += "var ";
exports += "this." + *it + " = " + *it + ";\n";
diff --git a/src/idl_gen_python.cpp b/src/idl_gen_python.cpp
index 7e8dc0ebd..52944bfca 100644
--- a/src/idl_gen_python.cpp
+++ b/src/idl_gen_python.cpp
@@ -94,7 +94,7 @@ static void NewRootTypeFromBuffer(const StructDef &struct_def,
code += Indent + Indent + "x = " + struct_def.name + "()\n";
code += Indent + Indent + "x.Init(buf, n + offset)\n";
code += Indent + Indent + "return x\n";
- code += "\n\n";
+ code += "\n";
}
// Initialize an existing object with other data, to avoid an allocation.
@@ -478,13 +478,12 @@ static void GenTableBuilders(const StructDef &struct_def,
// Generate struct or table methods.
static void GenStruct(const StructDef &struct_def,
- std::string *code_ptr,
- StructDef *root_struct_def) {
+ std::string *code_ptr) {
if (struct_def.generated) return;
GenComment(struct_def.doc_comment, code_ptr, nullptr, "# ");
BeginClass(struct_def, code_ptr);
- if (&struct_def == root_struct_def) {
+ if (!struct_def.fixed) {
// Generate a special accessor for the table that has been declared as
// the root type.
NewRootTypeFromBuffer(struct_def, code_ptr);
@@ -621,7 +620,7 @@ class PythonGenerator : public BaseGenerator {
it != parser_.structs_.vec.end(); ++it) {
auto &struct_def = **it;
std::string declcode;
- GenStruct(struct_def, &declcode, parser_.root_struct_def_);
+ GenStruct(struct_def, &declcode);
if (!SaveType(struct_def, declcode, true)) return false;
}
return true;
diff --git a/src/idl_parser.cpp b/src/idl_parser.cpp
index a5f325de4..fc2136757 100644
--- a/src/idl_parser.cpp
+++ b/src/idl_parser.cpp
@@ -2093,4 +2093,57 @@ flatbuffers::OffsetGetFullyQualifiedName(struct_def.name);
+ auto struct_def_base = base.structs_.Lookup(qualified_name);
+ if (!struct_def_base) continue;
+ for (auto fit = struct_def.fields.vec.begin();
+ fit != struct_def.fields.vec.end(); ++fit) {
+ auto &field = **fit;
+ auto field_base = struct_def_base->fields.Lookup(field.name);
+ if (field_base) {
+ if (field.value.offset != field_base->value.offset)
+ return "offsets differ for field: " + field.name;
+ if (field.value.constant != field_base->value.constant)
+ return "defaults differ for field: " + field.name;
+ if (!EqualByName(field.value.type, field_base->value.type))
+ return "types differ for field: " + field.name;
+ } else {
+ // Doesn't have to exist, deleting fields is fine.
+ // But we should check if there is a field that has the same offset
+ // but is incompatible (in the case of field renaming).
+ for (auto fbit = struct_def_base->fields.vec.begin();
+ fbit != struct_def_base->fields.vec.end(); ++fbit) {
+ field_base = *fbit;
+ if (field.value.offset == field_base->value.offset) {
+ if (!EqualByName(field.value.type, field_base->value.type))
+ return "field renamed to different type: " + field.name;
+ break;
+ }
+ }
+ }
+ }
+ }
+ for (auto eit = enums_.vec.begin(); eit != enums_.vec.end(); ++eit) {
+ auto &enum_def = **eit;
+ auto qualified_name =
+ enum_def.defined_namespace->GetFullyQualifiedName(enum_def.name);
+ auto enum_def_base = base.enums_.Lookup(qualified_name);
+ if (!enum_def_base) continue;
+ for (auto evit = enum_def.vals.vec.begin();
+ evit != enum_def.vals.vec.end(); ++evit) {
+ auto &enum_val = **evit;
+ auto enum_val_base = enum_def_base->vals.Lookup(enum_val.name);
+ if (enum_val_base) {
+ if (enum_val.value != enum_val_base->value)
+ return "values differ for enum: " + enum_val.name;
+ }
+ }
+ }
+ return "";
+}
+
} // namespace flatbuffers
diff --git a/tests/MyGame/Example/Any.java b/tests/MyGame/Example/Any.java
index 25d74af55..6e4fb76ca 100644
--- a/tests/MyGame/Example/Any.java
+++ b/tests/MyGame/Example/Any.java
@@ -9,8 +9,8 @@ public final class Any {
public static final byte TestSimpleTableWithEnum = 2;
public static final byte MyGame_Example2_Monster = 3;
- private static final String[] names = { "NONE", "Monster", "TestSimpleTableWithEnum", "MyGame_Example2_Monster", };
+ public static final String[] names = { "NONE", "Monster", "TestSimpleTableWithEnum", "MyGame_Example2_Monster", };
public static String name(int e) { return names[e]; }
-};
+}
diff --git a/tests/MyGame/Example/Color.java b/tests/MyGame/Example/Color.java
index 502ec9fbf..7c113b72f 100644
--- a/tests/MyGame/Example/Color.java
+++ b/tests/MyGame/Example/Color.java
@@ -8,8 +8,8 @@ public final class Color {
public static final byte Green = 2;
public static final byte Blue = 8;
- private static final String[] names = { "Red", "Green", "", "", "", "", "", "Blue", };
+ public static final String[] names = { "Red", "Green", "", "", "", "", "", "Blue", };
public static String name(int e) { return names[e - Red]; }
-};
+}
diff --git a/tests/MyGame/Example/Monster.go b/tests/MyGame/Example/Monster.go
index 0c42f45a5..f4cd18c18 100644
--- a/tests/MyGame/Example/Monster.go
+++ b/tests/MyGame/Example/Monster.go
@@ -43,6 +43,10 @@ func (rcv *Monster) Mana() int16 {
return 150
}
+func (rcv *Monster) MutateMana(n int16) bool {
+ return rcv._tab.MutateInt16Slot(6, n)
+}
+
func (rcv *Monster) Hp() int16 {
o := flatbuffers.UOffsetT(rcv._tab.Offset(8))
if o != 0 {
@@ -51,6 +55,10 @@ func (rcv *Monster) Hp() int16 {
return 100
}
+func (rcv *Monster) MutateHp(n int16) bool {
+ return rcv._tab.MutateInt16Slot(8, n)
+}
+
func (rcv *Monster) Name() []byte {
o := flatbuffers.UOffsetT(rcv._tab.Offset(10))
if o != 0 {
@@ -92,6 +100,10 @@ func (rcv *Monster) Color() int8 {
return 8
}
+func (rcv *Monster) MutateColor(n int8) bool {
+ return rcv._tab.MutateInt8Slot(16, n)
+}
+
func (rcv *Monster) TestType() byte {
o := flatbuffers.UOffsetT(rcv._tab.Offset(18))
if o != 0 {
@@ -100,6 +112,10 @@ func (rcv *Monster) TestType() byte {
return 0
}
+func (rcv *Monster) MutateTestType(n byte) bool {
+ return rcv._tab.MutateByteSlot(18, n)
+}
+
func (rcv *Monster) Test(obj *flatbuffers.Table) bool {
o := flatbuffers.UOffsetT(rcv._tab.Offset(20))
if o != 0 {
@@ -173,6 +189,8 @@ func (rcv *Monster) TestarrayoftablesLength() int {
return 0
}
+/// an example documentation comment: this will end up in the generated code
+/// multiline too
func (rcv *Monster) Enemy(obj *Monster) *Monster {
o := flatbuffers.UOffsetT(rcv._tab.Offset(28))
if o != 0 {
@@ -232,6 +250,10 @@ func (rcv *Monster) Testbool() byte {
return 0
}
+func (rcv *Monster) MutateTestbool(n byte) bool {
+ return rcv._tab.MutateByteSlot(34, n)
+}
+
func (rcv *Monster) Testhashs32Fnv1() int32 {
o := flatbuffers.UOffsetT(rcv._tab.Offset(36))
if o != 0 {
@@ -240,6 +262,10 @@ func (rcv *Monster) Testhashs32Fnv1() int32 {
return 0
}
+func (rcv *Monster) MutateTesthashs32Fnv1(n int32) bool {
+ return rcv._tab.MutateInt32Slot(36, n)
+}
+
func (rcv *Monster) Testhashu32Fnv1() uint32 {
o := flatbuffers.UOffsetT(rcv._tab.Offset(38))
if o != 0 {
@@ -248,6 +274,10 @@ func (rcv *Monster) Testhashu32Fnv1() uint32 {
return 0
}
+func (rcv *Monster) MutateTesthashu32Fnv1(n uint32) bool {
+ return rcv._tab.MutateUint32Slot(38, n)
+}
+
func (rcv *Monster) Testhashs64Fnv1() int64 {
o := flatbuffers.UOffsetT(rcv._tab.Offset(40))
if o != 0 {
@@ -256,6 +286,10 @@ func (rcv *Monster) Testhashs64Fnv1() int64 {
return 0
}
+func (rcv *Monster) MutateTesthashs64Fnv1(n int64) bool {
+ return rcv._tab.MutateInt64Slot(40, n)
+}
+
func (rcv *Monster) Testhashu64Fnv1() uint64 {
o := flatbuffers.UOffsetT(rcv._tab.Offset(42))
if o != 0 {
@@ -264,6 +298,10 @@ func (rcv *Monster) Testhashu64Fnv1() uint64 {
return 0
}
+func (rcv *Monster) MutateTesthashu64Fnv1(n uint64) bool {
+ return rcv._tab.MutateUint64Slot(42, n)
+}
+
func (rcv *Monster) Testhashs32Fnv1a() int32 {
o := flatbuffers.UOffsetT(rcv._tab.Offset(44))
if o != 0 {
@@ -272,6 +310,10 @@ func (rcv *Monster) Testhashs32Fnv1a() int32 {
return 0
}
+func (rcv *Monster) MutateTesthashs32Fnv1a(n int32) bool {
+ return rcv._tab.MutateInt32Slot(44, n)
+}
+
func (rcv *Monster) Testhashu32Fnv1a() uint32 {
o := flatbuffers.UOffsetT(rcv._tab.Offset(46))
if o != 0 {
@@ -280,6 +322,10 @@ func (rcv *Monster) Testhashu32Fnv1a() uint32 {
return 0
}
+func (rcv *Monster) MutateTesthashu32Fnv1a(n uint32) bool {
+ return rcv._tab.MutateUint32Slot(46, n)
+}
+
func (rcv *Monster) Testhashs64Fnv1a() int64 {
o := flatbuffers.UOffsetT(rcv._tab.Offset(48))
if o != 0 {
@@ -288,6 +334,10 @@ func (rcv *Monster) Testhashs64Fnv1a() int64 {
return 0
}
+func (rcv *Monster) MutateTesthashs64Fnv1a(n int64) bool {
+ return rcv._tab.MutateInt64Slot(48, n)
+}
+
func (rcv *Monster) Testhashu64Fnv1a() uint64 {
o := flatbuffers.UOffsetT(rcv._tab.Offset(50))
if o != 0 {
@@ -296,6 +346,10 @@ func (rcv *Monster) Testhashu64Fnv1a() uint64 {
return 0
}
+func (rcv *Monster) MutateTesthashu64Fnv1a(n uint64) bool {
+ return rcv._tab.MutateUint64Slot(50, n)
+}
+
func (rcv *Monster) Testarrayofbools(j int) byte {
o := flatbuffers.UOffsetT(rcv._tab.Offset(52))
if o != 0 {
@@ -321,6 +375,10 @@ func (rcv *Monster) Testf() float32 {
return 3.14159
}
+func (rcv *Monster) MutateTestf(n float32) bool {
+ return rcv._tab.MutateFloat32Slot(54, n)
+}
+
func (rcv *Monster) Testf2() float32 {
o := flatbuffers.UOffsetT(rcv._tab.Offset(56))
if o != 0 {
@@ -329,6 +387,10 @@ func (rcv *Monster) Testf2() float32 {
return 3.0
}
+func (rcv *Monster) MutateTestf2(n float32) bool {
+ return rcv._tab.MutateFloat32Slot(56, n)
+}
+
func (rcv *Monster) Testf3() float32 {
o := flatbuffers.UOffsetT(rcv._tab.Offset(58))
if o != 0 {
@@ -337,6 +399,10 @@ func (rcv *Monster) Testf3() float32 {
return 0.0
}
+func (rcv *Monster) MutateTestf3(n float32) bool {
+ return rcv._tab.MutateFloat32Slot(58, n)
+}
+
func (rcv *Monster) Testarrayofstring2(j int) []byte {
o := flatbuffers.UOffsetT(rcv._tab.Offset(60))
if o != 0 {
diff --git a/tests/MyGame/Example/Monster.java b/tests/MyGame/Example/Monster.java
index bfd4be1c9..dc27f8447 100644
--- a/tests/MyGame/Example/Monster.java
+++ b/tests/MyGame/Example/Monster.java
@@ -135,5 +135,5 @@ public final class Monster extends Table {
return o;
}
public static void finishMonsterBuffer(FlatBufferBuilder builder, int offset) { builder.finish(offset, "MONS"); }
-};
+}
diff --git a/tests/MyGame/Example/Monster.py b/tests/MyGame/Example/Monster.py
index 9d2909e89..a7a783633 100644
--- a/tests/MyGame/Example/Monster.py
+++ b/tests/MyGame/Example/Monster.py
@@ -15,7 +15,6 @@ class Monster(object):
x.Init(buf, n + offset)
return x
-
# Monster
def Init(self, buf, pos):
self._tab = flatbuffers.table.Table(buf, pos)
diff --git a/tests/MyGame/Example/Stat.go b/tests/MyGame/Example/Stat.go
index 7c33716b4..8c56bfb07 100644
--- a/tests/MyGame/Example/Stat.go
+++ b/tests/MyGame/Example/Stat.go
@@ -9,6 +9,13 @@ type Stat struct {
_tab flatbuffers.Table
}
+func GetRootAsStat(buf []byte, offset flatbuffers.UOffsetT) *Stat {
+ n := flatbuffers.GetUOffsetT(buf[offset:])
+ x := &Stat{}
+ x.Init(buf, n + offset)
+ return x
+}
+
func (rcv *Stat) Init(buf []byte, i flatbuffers.UOffsetT) {
rcv._tab.Bytes = buf
rcv._tab.Pos = i
@@ -30,6 +37,10 @@ func (rcv *Stat) Val() int64 {
return 0
}
+func (rcv *Stat) MutateVal(n int64) bool {
+ return rcv._tab.MutateInt64Slot(6, n)
+}
+
func (rcv *Stat) Count() uint16 {
o := flatbuffers.UOffsetT(rcv._tab.Offset(8))
if o != 0 {
@@ -38,6 +49,10 @@ func (rcv *Stat) Count() uint16 {
return 0
}
+func (rcv *Stat) MutateCount(n uint16) bool {
+ return rcv._tab.MutateUint16Slot(8, n)
+}
+
func StatStart(builder *flatbuffers.Builder) { builder.StartObject(3) }
func StatAddId(builder *flatbuffers.Builder, id flatbuffers.UOffsetT) { builder.PrependUOffsetTSlot(0, flatbuffers.UOffsetT(id), 0) }
func StatAddVal(builder *flatbuffers.Builder, val int64) { builder.PrependInt64Slot(1, val, 0) }
diff --git a/tests/MyGame/Example/Stat.java b/tests/MyGame/Example/Stat.java
index 3cac509b7..cd339c62d 100644
--- a/tests/MyGame/Example/Stat.java
+++ b/tests/MyGame/Example/Stat.java
@@ -39,5 +39,5 @@ public final class Stat extends Table {
int o = builder.endObject();
return o;
}
-};
+}
diff --git a/tests/MyGame/Example/Stat.py b/tests/MyGame/Example/Stat.py
index 71577e868..b0e251d46 100644
--- a/tests/MyGame/Example/Stat.py
+++ b/tests/MyGame/Example/Stat.py
@@ -7,6 +7,13 @@ import flatbuffers
class Stat(object):
__slots__ = ['_tab']
+ @classmethod
+ def GetRootAsStat(cls, buf, offset):
+ n = flatbuffers.encode.Get(flatbuffers.packer.uoffset, buf, offset)
+ x = Stat()
+ x.Init(buf, n + offset)
+ return x
+
# Stat
def Init(self, buf, pos):
self._tab = flatbuffers.table.Table(buf, pos)
diff --git a/tests/MyGame/Example/Test.go b/tests/MyGame/Example/Test.go
index e849488d9..ee0d9aaec 100644
--- a/tests/MyGame/Example/Test.go
+++ b/tests/MyGame/Example/Test.go
@@ -15,7 +15,11 @@ func (rcv *Test) Init(buf []byte, i flatbuffers.UOffsetT) {
}
func (rcv *Test) A() int16 { return rcv._tab.GetInt16(rcv._tab.Pos + flatbuffers.UOffsetT(0)) }
+func (rcv *Test) MutateA(n int16) bool { return rcv._tab.MutateInt16(rcv._tab.Pos + flatbuffers.UOffsetT(0), n) }
+
func (rcv *Test) B() int8 { return rcv._tab.GetInt8(rcv._tab.Pos + flatbuffers.UOffsetT(2)) }
+func (rcv *Test) MutateB(n int8) bool { return rcv._tab.MutateInt8(rcv._tab.Pos + flatbuffers.UOffsetT(2), n) }
+
func CreateTest(builder *flatbuffers.Builder, a int16, b int8) flatbuffers.UOffsetT {
builder.Prep(2, 4)
diff --git a/tests/MyGame/Example/Test.java b/tests/MyGame/Example/Test.java
index 52474152f..6e33da9b3 100644
--- a/tests/MyGame/Example/Test.java
+++ b/tests/MyGame/Example/Test.java
@@ -23,5 +23,5 @@ public final class Test extends Struct {
builder.putShort(a);
return builder.offset();
}
-};
+}
diff --git a/tests/MyGame/Example/TestSimpleTableWithEnum.go b/tests/MyGame/Example/TestSimpleTableWithEnum.go
index fe9cf2dbb..96218e58b 100644
--- a/tests/MyGame/Example/TestSimpleTableWithEnum.go
+++ b/tests/MyGame/Example/TestSimpleTableWithEnum.go
@@ -9,6 +9,13 @@ type TestSimpleTableWithEnum struct {
_tab flatbuffers.Table
}
+func GetRootAsTestSimpleTableWithEnum(buf []byte, offset flatbuffers.UOffsetT) *TestSimpleTableWithEnum {
+ n := flatbuffers.GetUOffsetT(buf[offset:])
+ x := &TestSimpleTableWithEnum{}
+ x.Init(buf, n + offset)
+ return x
+}
+
func (rcv *TestSimpleTableWithEnum) Init(buf []byte, i flatbuffers.UOffsetT) {
rcv._tab.Bytes = buf
rcv._tab.Pos = i
@@ -22,6 +29,10 @@ func (rcv *TestSimpleTableWithEnum) Color() int8 {
return 2
}
+func (rcv *TestSimpleTableWithEnum) MutateColor(n int8) bool {
+ return rcv._tab.MutateInt8Slot(4, n)
+}
+
func TestSimpleTableWithEnumStart(builder *flatbuffers.Builder) { builder.StartObject(1) }
func TestSimpleTableWithEnumAddColor(builder *flatbuffers.Builder, color int8) { builder.PrependInt8Slot(0, color, 2) }
func TestSimpleTableWithEnumEnd(builder *flatbuffers.Builder) flatbuffers.UOffsetT { return builder.EndObject() }
diff --git a/tests/MyGame/Example/TestSimpleTableWithEnum.java b/tests/MyGame/Example/TestSimpleTableWithEnum.java
index 85e18c2b3..a1de020ea 100644
--- a/tests/MyGame/Example/TestSimpleTableWithEnum.java
+++ b/tests/MyGame/Example/TestSimpleTableWithEnum.java
@@ -29,5 +29,5 @@ public final class TestSimpleTableWithEnum extends Table {
int o = builder.endObject();
return o;
}
-};
+}
diff --git a/tests/MyGame/Example/TestSimpleTableWithEnum.py b/tests/MyGame/Example/TestSimpleTableWithEnum.py
index 5b9509791..8d64e971d 100644
--- a/tests/MyGame/Example/TestSimpleTableWithEnum.py
+++ b/tests/MyGame/Example/TestSimpleTableWithEnum.py
@@ -7,6 +7,13 @@ import flatbuffers
class TestSimpleTableWithEnum(object):
__slots__ = ['_tab']
+ @classmethod
+ def GetRootAsTestSimpleTableWithEnum(cls, buf, offset):
+ n = flatbuffers.encode.Get(flatbuffers.packer.uoffset, buf, offset)
+ x = TestSimpleTableWithEnum()
+ x.Init(buf, n + offset)
+ return x
+
# TestSimpleTableWithEnum
def Init(self, buf, pos):
self._tab = flatbuffers.table.Table(buf, pos)
diff --git a/tests/MyGame/Example/Vec3.go b/tests/MyGame/Example/Vec3.go
index 082945ed3..8bf97da32 100644
--- a/tests/MyGame/Example/Vec3.go
+++ b/tests/MyGame/Example/Vec3.go
@@ -15,10 +15,20 @@ func (rcv *Vec3) Init(buf []byte, i flatbuffers.UOffsetT) {
}
func (rcv *Vec3) X() float32 { return rcv._tab.GetFloat32(rcv._tab.Pos + flatbuffers.UOffsetT(0)) }
+func (rcv *Vec3) MutateX(n float32) bool { return rcv._tab.MutateFloat32(rcv._tab.Pos + flatbuffers.UOffsetT(0), n) }
+
func (rcv *Vec3) Y() float32 { return rcv._tab.GetFloat32(rcv._tab.Pos + flatbuffers.UOffsetT(4)) }
+func (rcv *Vec3) MutateY(n float32) bool { return rcv._tab.MutateFloat32(rcv._tab.Pos + flatbuffers.UOffsetT(4), n) }
+
func (rcv *Vec3) Z() float32 { return rcv._tab.GetFloat32(rcv._tab.Pos + flatbuffers.UOffsetT(8)) }
+func (rcv *Vec3) MutateZ(n float32) bool { return rcv._tab.MutateFloat32(rcv._tab.Pos + flatbuffers.UOffsetT(8), n) }
+
func (rcv *Vec3) Test1() float64 { return rcv._tab.GetFloat64(rcv._tab.Pos + flatbuffers.UOffsetT(16)) }
+func (rcv *Vec3) MutateTest1(n float64) bool { return rcv._tab.MutateFloat64(rcv._tab.Pos + flatbuffers.UOffsetT(16), n) }
+
func (rcv *Vec3) Test2() int8 { return rcv._tab.GetInt8(rcv._tab.Pos + flatbuffers.UOffsetT(24)) }
+func (rcv *Vec3) MutateTest2(n int8) bool { return rcv._tab.MutateInt8(rcv._tab.Pos + flatbuffers.UOffsetT(24), n) }
+
func (rcv *Vec3) Test3(obj *Test) *Test {
if obj == nil {
obj = new(Test)
diff --git a/tests/MyGame/Example/Vec3.java b/tests/MyGame/Example/Vec3.java
index 7ae1ce209..261947cc3 100644
--- a/tests/MyGame/Example/Vec3.java
+++ b/tests/MyGame/Example/Vec3.java
@@ -40,5 +40,5 @@ public final class Vec3 extends Struct {
builder.putFloat(x);
return builder.offset();
}
-};
+}
diff --git a/tests/MyGame/Example2/Monster.java b/tests/MyGame/Example2/Monster.java
index 6432494f3..968eee563 100644
--- a/tests/MyGame/Example2/Monster.java
+++ b/tests/MyGame/Example2/Monster.java
@@ -19,5 +19,5 @@ public final class Monster extends Table {
int o = builder.endObject();
return o;
}
-};
+}
diff --git a/tests/generate_code.bat b/tests/generate_code.bat
index 53d54707b..4b4a53531 100644
--- a/tests/generate_code.bat
+++ b/tests/generate_code.bat
@@ -12,6 +12,6 @@
:: 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 --no-includes monster_test.fbs monsterdata_test.json
+..\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
diff --git a/tests/generate_code.sh b/tests/generate_code.sh
index 3436d8586..1b347ba79 100644
--- a/tests/generate_code.sh
+++ b/tests/generate_code.sh
@@ -14,7 +14,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-../flatc --cpp --java --csharp --go --binary --python --js --php --grpc --gen-mutable --no-includes monster_test.fbs monsterdata_test.json
+../flatc --cpp --java --csharp --go --binary --python --js --php --grpc --gen-mutable --gen-object-api --no-includes monster_test.fbs monsterdata_test.json
../flatc --cpp --java --csharp --go --binary --python --js --php --gen-mutable -o namespace_test namespace_test/namespace_test1.fbs namespace_test/namespace_test2.fbs
../flatc --binary --schema monster_test.fbs
diff --git a/tests/go_test.go b/tests/go_test.go
index 9d94277f7..e4e96de8c 100644
--- a/tests/go_test.go
+++ b/tests/go_test.go
@@ -67,6 +67,7 @@ func TestAll(t *testing.T) {
// Verify that the Go FlatBuffers runtime library generates the
// expected bytes (does not use any schema):
CheckByteLayout(t.Fatalf)
+ CheckMutateMethods(t.Fatalf)
// Verify that panics are raised during exceptional conditions:
CheckNotInObjectError(t.Fatalf)
@@ -75,6 +76,9 @@ func TestAll(t *testing.T) {
CheckStructIsNotInlineError(t.Fatalf)
CheckFinishedBytesError(t.Fatalf)
+ // Verify that GetRootAs works for non-root tables
+ CheckGetRootAsForNonRootTable(t.Fatalf)
+
// Verify that using the generated Go code builds a buffer without
// returning errors:
generated, off := CheckGeneratedBuild(t.Fatalf)
@@ -82,6 +86,7 @@ func TestAll(t *testing.T) {
// Verify that the buffer generated by Go code is readable by the
// generated Go code:
CheckReadBuffer(generated, off, t.Fatalf)
+ CheckMutateBuffer(generated, off, t.Fatalf)
// Verify that the buffer generated by C++ code is readable by the
// generated Go code:
@@ -90,6 +95,7 @@ func TestAll(t *testing.T) {
t.Fatal(err)
}
CheckReadBuffer(monsterDataCpp, 0, t.Fatalf)
+ CheckMutateBuffer(monsterDataCpp, 0, t.Fatalf)
// Verify that vtables are deduplicated when written:
CheckVtableDeduplication(t.Fatalf)
@@ -280,6 +286,120 @@ func CheckReadBuffer(buf []byte, offset flatbuffers.UOffsetT, fail func(string,
}
}
+// CheckMutateBuffer checks that the given buffer can be mutated correctly
+// as the example Monster. Only available scalar values are mutated.
+func CheckMutateBuffer(org []byte, offset flatbuffers.UOffsetT, fail func(string, ...interface{})) {
+ // make a copy to mutate
+ buf := make([]byte, len(org))
+ copy(buf, org)
+
+ // load monster data from the buffer
+ monster := example.GetRootAsMonster(buf, offset)
+
+ // test case struct
+ type testcase struct {
+ field string
+ testfn func() bool
+ }
+
+ testForOriginalValues := []testcase{
+ testcase{"Hp", func() bool { return monster.Hp() == 80 }},
+ testcase{"Mana", func() bool { return monster.Mana() == 150 }},
+ testcase{"Pos.X'", func() bool { return monster.Pos(nil).X() == float32(1.0) }},
+ testcase{"Pos.Y'", func() bool { return monster.Pos(nil).Y() == float32(2.0) }},
+ testcase{"Pos.Z'", func() bool { return monster.Pos(nil).Z() == float32(3.0) }},
+ testcase{"Pos.Test1'", func() bool { return monster.Pos(nil).Test1() == float64(3.0) }},
+ testcase{"Pos.Test2'", func() bool { return monster.Pos(nil).Test2() == int8(2) }},
+ testcase{"Pos.Test3.A", func() bool { return monster.Pos(nil).Test3(nil).A() == int16(5) }},
+ testcase{"Pos.Test3.B", func() bool { return monster.Pos(nil).Test3(nil).B() == int8(6) }},
+ }
+
+ testMutability := []testcase{
+ testcase{"Hp", func() bool { return monster.MutateHp(70) }},
+ testcase{"Mana", func() bool { return !monster.MutateMana(140) }},
+ testcase{"Pos.X", func() bool { return monster.Pos(nil).MutateX(10.0) }},
+ testcase{"Pos.Y", func() bool { return monster.Pos(nil).MutateY(20.0) }},
+ testcase{"Pos.Z", func() bool { return monster.Pos(nil).MutateZ(30.0) }},
+ testcase{"Pos.Test1", func() bool { return monster.Pos(nil).MutateTest1(30.0) }},
+ testcase{"Pos.Test2", func() bool { return monster.Pos(nil).MutateTest2(20) }},
+ testcase{"Pos.Test3.A", func() bool { return monster.Pos(nil).Test3(nil).MutateA(50) }},
+ testcase{"Pos.Test3.B", func() bool { return monster.Pos(nil).Test3(nil).MutateB(60) }},
+ }
+
+ testForMutatedValues := []testcase{
+ testcase{"Hp", func() bool { return monster.Hp() == 70 }},
+ testcase{"Mana", func() bool { return monster.Mana() == 150 }},
+ testcase{"Pos.X'", func() bool { return monster.Pos(nil).X() == float32(10.0) }},
+ testcase{"Pos.Y'", func() bool { return monster.Pos(nil).Y() == float32(20.0) }},
+ testcase{"Pos.Z'", func() bool { return monster.Pos(nil).Z() == float32(30.0) }},
+ testcase{"Pos.Test1'", func() bool { return monster.Pos(nil).Test1() == float64(30.0) }},
+ testcase{"Pos.Test2'", func() bool { return monster.Pos(nil).Test2() == int8(20) }},
+ testcase{"Pos.Test3.A", func() bool { return monster.Pos(nil).Test3(nil).A() == int16(50) }},
+ testcase{"Pos.Test3.B", func() bool { return monster.Pos(nil).Test3(nil).B() == int8(60) }},
+ }
+
+ // make sure original values are okay
+ for _, t := range testForOriginalValues {
+ if !t.testfn() {
+ fail("field '" + t.field + "' doesn't have the expected original value")
+ }
+ }
+
+ // try to mutate fields and check mutability
+ for _, t := range testMutability {
+ if !t.testfn() {
+ fail(FailString("field '"+t.field+"' failed mutability test", true, false))
+ }
+ }
+
+ // test whether values have changed
+ for _, t := range testForMutatedValues {
+ if !t.testfn() {
+ fail("field '" + t.field + "' doesn't have the expected mutated value")
+ }
+ }
+
+ // make sure the buffer has changed
+ if reflect.DeepEqual(buf, org) {
+ fail("mutate buffer failed")
+ }
+
+ // To make sure the buffer has changed accordingly
+ // Read data from the buffer and verify all fields
+ monster = example.GetRootAsMonster(buf, offset)
+ for _, t := range testForMutatedValues {
+ if !t.testfn() {
+ fail("field '" + t.field + "' doesn't have the expected mutated value")
+ }
+ }
+
+ // reverting all fields to original values should
+ // re-create the original buffer. Mutate all fields
+ // back to their original values and compare buffers.
+ // This test is done to make sure mutations do not do
+ // any unnecessary changes to the buffer.
+ monster = example.GetRootAsMonster(buf, offset)
+ monster.MutateHp(80)
+ monster.Pos(nil).MutateX(1.0)
+ monster.Pos(nil).MutateY(2.0)
+ monster.Pos(nil).MutateZ(3.0)
+ monster.Pos(nil).MutateTest1(3.0)
+ monster.Pos(nil).MutateTest2(2)
+ monster.Pos(nil).Test3(nil).MutateA(5)
+ monster.Pos(nil).Test3(nil).MutateB(6)
+
+ for _, t := range testForOriginalValues {
+ if !t.testfn() {
+ fail("field '" + t.field + "' doesn't have the expected original value")
+ }
+ }
+
+ // buffer should have original values
+ if !reflect.DeepEqual(buf, org) {
+ fail("revert changes failed")
+ }
+}
+
// Low level stress/fuzz test: serialize/deserialize a variety of
// different kinds of data in different combinations
func checkFuzz(fuzzFields, fuzzObjects int, fail func(string, ...interface{})) {
@@ -964,6 +1084,31 @@ func CheckManualBuild(fail func(string, ...interface{})) ([]byte, flatbuffers.UO
return b.Bytes, b.Head()
}
+func CheckGetRootAsForNonRootTable(fail func(string, ...interface{})) {
+ b := flatbuffers.NewBuilder(0)
+ str := b.CreateString("MyStat")
+ example.StatStart(b)
+ example.StatAddId(b, str)
+ example.StatAddVal(b, 12345678)
+ example.StatAddCount(b, 12345)
+ stat_end := example.StatEnd(b)
+ b.Finish(stat_end)
+
+ stat := example.GetRootAsStat(b.Bytes, b.Head())
+
+ if got := stat.Id(); !bytes.Equal([]byte("MyStat"), got) {
+ fail(FailString("stat.Id()", "MyStat", got))
+ }
+
+ if got := stat.Val(); 12345678 != got {
+ fail(FailString("stat.Val()", 12345678, got))
+ }
+
+ if got := stat.Count(); 12345 != got {
+ fail(FailString("stat.Count()", 12345, got))
+ }
+}
+
// CheckGeneratedBuild uses generated code to build the example Monster.
func CheckGeneratedBuild(fail func(string, ...interface{})) ([]byte, flatbuffers.UOffsetT) {
b := flatbuffers.NewBuilder(0)
@@ -1248,6 +1393,151 @@ func CheckByteEquality(a, b []byte, fail func(string, ...interface{})) {
}
}
+// CheckMutateMethods checks all mutate methods one by one
+func CheckMutateMethods(fail func(string, ...interface{})) {
+ b := flatbuffers.NewBuilder(0)
+ b.StartObject(15)
+ b.PrependBoolSlot(0, true, false)
+ b.PrependByteSlot(1, 1, 0)
+ b.PrependUint8Slot(2, 2, 0)
+ b.PrependUint16Slot(3, 3, 0)
+ b.PrependUint32Slot(4, 4, 0)
+ b.PrependUint64Slot(5, 5, 0)
+ b.PrependInt8Slot(6, 6, 0)
+ b.PrependInt16Slot(7, 7, 0)
+ b.PrependInt32Slot(8, 8, 0)
+ b.PrependInt64Slot(9, 9, 0)
+ b.PrependFloat32Slot(10, 10, 0)
+ b.PrependFloat64Slot(11, 11, 0)
+
+ b.PrependUOffsetTSlot(12, 12, 0)
+ uoVal := b.Offset() - 12
+
+ b.PrependVOffsetT(13)
+ b.Slot(13)
+
+ b.PrependSOffsetT(14)
+ b.Slot(14)
+ soVal := flatbuffers.SOffsetT(b.Offset() - 14)
+
+ offset := b.EndObject()
+
+ t := &flatbuffers.Table{
+ Bytes: b.Bytes,
+ Pos: flatbuffers.UOffsetT(len(b.Bytes)) - offset,
+ }
+
+ calcVOffsetT := func(slot int) (vtableOffset flatbuffers.VOffsetT) {
+ return flatbuffers.VOffsetT((flatbuffers.VtableMetadataFields + slot) * flatbuffers.SizeVOffsetT)
+ }
+ calcUOffsetT := func(vtableOffset flatbuffers.VOffsetT) (valueOffset flatbuffers.UOffsetT) {
+ return t.Pos + flatbuffers.UOffsetT(t.Offset(vtableOffset))
+ }
+
+ type testcase struct {
+ field string
+ testfn func() bool
+ }
+
+ testForOriginalValues := []testcase{
+ testcase{"BoolSlot", func() bool { return t.GetBoolSlot(calcVOffsetT(0), true) == true }},
+ testcase{"ByteSlot", func() bool { return t.GetByteSlot(calcVOffsetT(1), 1) == 1 }},
+ testcase{"Uint8Slot", func() bool { return t.GetUint8Slot(calcVOffsetT(2), 2) == 2 }},
+ testcase{"Uint16Slot", func() bool { return t.GetUint16Slot(calcVOffsetT(3), 3) == 3 }},
+ testcase{"Uint32Slot", func() bool { return t.GetUint32Slot(calcVOffsetT(4), 4) == 4 }},
+ testcase{"Uint64Slot", func() bool { return t.GetUint64Slot(calcVOffsetT(5), 5) == 5 }},
+ testcase{"Int8Slot", func() bool { return t.GetInt8Slot(calcVOffsetT(6), 6) == 6 }},
+ testcase{"Int16Slot", func() bool { return t.GetInt16Slot(calcVOffsetT(7), 7) == 7 }},
+ testcase{"Int32Slot", func() bool { return t.GetInt32Slot(calcVOffsetT(8), 8) == 8 }},
+ testcase{"Int64Slot", func() bool { return t.GetInt64Slot(calcVOffsetT(9), 9) == 9 }},
+ testcase{"Float32Slot", func() bool { return t.GetFloat32Slot(calcVOffsetT(10), 10) == 10 }},
+ testcase{"Float64Slot", func() bool { return t.GetFloat64Slot(calcVOffsetT(11), 11) == 11 }},
+ testcase{"UOffsetTSlot", func() bool { return t.GetUOffsetT(calcUOffsetT(calcVOffsetT(12))) == uoVal }},
+ testcase{"VOffsetTSlot", func() bool { return t.GetVOffsetT(calcUOffsetT(calcVOffsetT(13))) == 13 }},
+ testcase{"SOffsetTSlot", func() bool { return t.GetSOffsetT(calcUOffsetT(calcVOffsetT(14))) == soVal }},
+ }
+
+ testMutability := []testcase{
+ testcase{"BoolSlot", func() bool { return t.MutateBoolSlot(calcVOffsetT(0), false) }},
+ testcase{"ByteSlot", func() bool { return t.MutateByteSlot(calcVOffsetT(1), 2) }},
+ testcase{"Uint8Slot", func() bool { return t.MutateUint8Slot(calcVOffsetT(2), 4) }},
+ testcase{"Uint16Slot", func() bool { return t.MutateUint16Slot(calcVOffsetT(3), 6) }},
+ testcase{"Uint32Slot", func() bool { return t.MutateUint32Slot(calcVOffsetT(4), 8) }},
+ testcase{"Uint64Slot", func() bool { return t.MutateUint64Slot(calcVOffsetT(5), 10) }},
+ testcase{"Int8Slot", func() bool { return t.MutateInt8Slot(calcVOffsetT(6), 12) }},
+ testcase{"Int16Slot", func() bool { return t.MutateInt16Slot(calcVOffsetT(7), 14) }},
+ testcase{"Int32Slot", func() bool { return t.MutateInt32Slot(calcVOffsetT(8), 16) }},
+ testcase{"Int64Slot", func() bool { return t.MutateInt64Slot(calcVOffsetT(9), 18) }},
+ testcase{"Float32Slot", func() bool { return t.MutateFloat32Slot(calcVOffsetT(10), 20) }},
+ testcase{"Float64Slot", func() bool { return t.MutateFloat64Slot(calcVOffsetT(11), 22) }},
+ testcase{"UOffsetTSlot", func() bool { return t.MutateUOffsetT(calcUOffsetT(calcVOffsetT(12)), 24) }},
+ testcase{"VOffsetTSlot", func() bool { return t.MutateVOffsetT(calcUOffsetT(calcVOffsetT(13)), 26) }},
+ testcase{"SOffsetTSlot", func() bool { return t.MutateSOffsetT(calcUOffsetT(calcVOffsetT(14)), 28) }},
+ }
+
+ testMutabilityWithoutSlot := []testcase{
+ testcase{"BoolSlot", func() bool { return t.MutateBoolSlot(calcVOffsetT(16), false) }},
+ testcase{"ByteSlot", func() bool { return t.MutateByteSlot(calcVOffsetT(16), 2) }},
+ testcase{"Uint8Slot", func() bool { return t.MutateUint8Slot(calcVOffsetT(16), 2) }},
+ testcase{"Uint16Slot", func() bool { return t.MutateUint16Slot(calcVOffsetT(16), 2) }},
+ testcase{"Uint32Slot", func() bool { return t.MutateUint32Slot(calcVOffsetT(16), 2) }},
+ testcase{"Uint64Slot", func() bool { return t.MutateUint64Slot(calcVOffsetT(16), 2) }},
+ testcase{"Int8Slot", func() bool { return t.MutateInt8Slot(calcVOffsetT(16), 2) }},
+ testcase{"Int16Slot", func() bool { return t.MutateInt16Slot(calcVOffsetT(16), 2) }},
+ testcase{"Int32Slot", func() bool { return t.MutateInt32Slot(calcVOffsetT(16), 2) }},
+ testcase{"Int64Slot", func() bool { return t.MutateInt64Slot(calcVOffsetT(16), 2) }},
+ testcase{"Float32Slot", func() bool { return t.MutateFloat32Slot(calcVOffsetT(16), 2) }},
+ testcase{"Float64Slot", func() bool { return t.MutateFloat64Slot(calcVOffsetT(16), 2) }},
+ }
+
+ testForMutatedValues := []testcase{
+ testcase{"BoolSlot", func() bool { return t.GetBoolSlot(calcVOffsetT(0), true) == false }},
+ testcase{"ByteSlot", func() bool { return t.GetByteSlot(calcVOffsetT(1), 1) == 2 }},
+ testcase{"Uint8Slot", func() bool { return t.GetUint8Slot(calcVOffsetT(2), 1) == 4 }},
+ testcase{"Uint16Slot", func() bool { return t.GetUint16Slot(calcVOffsetT(3), 1) == 6 }},
+ testcase{"Uint32Slot", func() bool { return t.GetUint32Slot(calcVOffsetT(4), 1) == 8 }},
+ testcase{"Uint64Slot", func() bool { return t.GetUint64Slot(calcVOffsetT(5), 1) == 10 }},
+ testcase{"Int8Slot", func() bool { return t.GetInt8Slot(calcVOffsetT(6), 1) == 12 }},
+ testcase{"Int16Slot", func() bool { return t.GetInt16Slot(calcVOffsetT(7), 1) == 14 }},
+ testcase{"Int32Slot", func() bool { return t.GetInt32Slot(calcVOffsetT(8), 1) == 16 }},
+ testcase{"Int64Slot", func() bool { return t.GetInt64Slot(calcVOffsetT(9), 1) == 18 }},
+ testcase{"Float32Slot", func() bool { return t.GetFloat32Slot(calcVOffsetT(10), 1) == 20 }},
+ testcase{"Float64Slot", func() bool { return t.GetFloat64Slot(calcVOffsetT(11), 1) == 22 }},
+ testcase{"UOffsetTSlot", func() bool { return t.GetUOffsetT(calcUOffsetT(calcVOffsetT(12))) == 24 }},
+ testcase{"VOffsetTSlot", func() bool { return t.GetVOffsetT(calcUOffsetT(calcVOffsetT(13))) == 26 }},
+ testcase{"SOffsetTSlot", func() bool { return t.GetSOffsetT(calcUOffsetT(calcVOffsetT(14))) == 28 }},
+ }
+
+ // make sure original values are okay
+ for _, t := range testForOriginalValues {
+ if !t.testfn() {
+ fail(t.field + "' field doesn't have the expected original value")
+ }
+ }
+
+ // try to mutate fields and check mutability
+ for _, t := range testMutability {
+ if !t.testfn() {
+ fail(FailString(t.field+"' field failed mutability test", "passed", "failed"))
+ }
+ }
+
+ // try to mutate fields and check mutability
+ // these have wrong slots so should fail
+ for _, t := range testMutabilityWithoutSlot {
+ if t.testfn() {
+ fail(FailString(t.field+"' field failed no slot mutability test", "failed", "passed"))
+ }
+ }
+
+ // test whether values have changed
+ for _, t := range testForMutatedValues {
+ if !t.testfn() {
+ fail(t.field + "' field doesn't have the expected mutated value")
+ }
+ }
+}
+
// BenchmarkVtableDeduplication measures the speed of vtable deduplication
// by creating prePop vtables, then populating b.N objects with a
// different single vtable.
diff --git a/tests/monster_test.bfbs b/tests/monster_test.bfbs
index e131ac8c2..1e8a270d8 100644
Binary files a/tests/monster_test.bfbs and b/tests/monster_test.bfbs differ
diff --git a/tests/monster_test_generated.h b/tests/monster_test_generated.h
index 50fbc28ce..49aba1133 100644
--- a/tests/monster_test_generated.h
+++ b/tests/monster_test_generated.h
@@ -9,6 +9,7 @@ namespace MyGame {
namespace Example2 {
struct Monster;
+struct MonsterT;
} // namespace Example2
@@ -17,12 +18,15 @@ namespace Example {
struct Test;
struct TestSimpleTableWithEnum;
+struct TestSimpleTableWithEnumT;
struct Vec3;
struct Stat;
+struct StatT;
struct Monster;
+struct MonsterT;
enum Color {
Color_Red = 1,
@@ -48,6 +52,23 @@ enum Any {
Any_MAX = Any_MyGame_Example2_Monster
};
+struct AnyUnion {
+ Any type;
+
+ flatbuffers::NativeTable *table;
+ AnyUnion() : type(Any_NONE), table(nullptr) {}
+ AnyUnion(const AnyUnion &);
+ AnyUnion &operator=(const AnyUnion &);
+ ~AnyUnion();
+
+ static flatbuffers::NativeTable *UnPack(const void *union_obj, Any type);
+ flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb) const;
+
+ MonsterT *AsMonster() { return type == Any_Monster ? reinterpret_cast(table) : nullptr; }
+ TestSimpleTableWithEnumT *AsTestSimpleTableWithEnum() { return type == Any_TestSimpleTableWithEnum ? reinterpret_cast(table) : nullptr; }
+ MyGame::Example2::MonsterT *AsMyGame_Example2_Monster() { return type == Any_MyGame_Example2_Monster ? reinterpret_cast(table) : nullptr; }
+};
+
inline const char **EnumNamesAny() {
static const char *names[] = { "NONE", "Monster", "TestSimpleTableWithEnum", "MyGame_Example2_Monster", nullptr };
return names;
@@ -64,6 +85,8 @@ MANUALLY_ALIGNED_STRUCT(2) Test FLATBUFFERS_FINAL_CLASS {
int8_t __padding0;
public:
+ Test() { memset(this, 0, sizeof(Test)); }
+ Test(const Test &_o) { memcpy(this, &_o, sizeof(Test)); }
Test(int16_t _a, int8_t _b)
: a_(flatbuffers::EndianScalar(_a)), b_(flatbuffers::EndianScalar(_b)), __padding0(0) { (void)__padding0; }
@@ -87,6 +110,8 @@ MANUALLY_ALIGNED_STRUCT(16) Vec3 FLATBUFFERS_FINAL_CLASS {
int16_t __padding2;
public:
+ Vec3() { memset(this, 0, sizeof(Vec3)); }
+ Vec3(const Vec3 &_o) { memcpy(this, &_o, sizeof(Vec3)); }
Vec3(float _x, float _y, float _z, double _test1, Color _test2, const Test &_test3)
: x_(flatbuffers::EndianScalar(_x)), y_(flatbuffers::EndianScalar(_y)), z_(flatbuffers::EndianScalar(_z)), __padding0(0), test1_(flatbuffers::EndianScalar(_test1)), test2_(flatbuffers::EndianScalar(static_cast(_test2))), __padding1(0), test3_(_test3), __padding2(0) { (void)__padding0; (void)__padding1; (void)__padding2; }
@@ -109,11 +134,15 @@ STRUCT_END(Vec3, 32);
namespace Example2 {
+struct MonsterT : public flatbuffers::NativeTable {
+};
+
struct Monster FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
bool Verify(flatbuffers::Verifier &verifier) const {
return VerifyTableStart(verifier) &&
verifier.EndTable();
}
+ std::unique_ptr UnPack() const;
};
struct MonsterBuilder {
@@ -132,10 +161,16 @@ inline flatbuffers::Offset CreateMonster(flatbuffers::FlatBufferBuilder
return builder_.Finish();
}
+inline flatbuffers::Offset CreateMonster(flatbuffers::FlatBufferBuilder &_fbb, const MonsterT *_o);
+
} // namespace Example2
namespace Example {
+struct TestSimpleTableWithEnumT : public flatbuffers::NativeTable {
+ Color color;
+};
+
struct TestSimpleTableWithEnum FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
enum {
VT_COLOR = 4
@@ -147,6 +182,7 @@ struct TestSimpleTableWithEnum FLATBUFFERS_FINAL_CLASS : private flatbuffers::Ta
VerifyField(verifier, VT_COLOR) &&
verifier.EndTable();
}
+ std::unique_ptr UnPack() const;
};
struct TestSimpleTableWithEnumBuilder {
@@ -162,12 +198,20 @@ struct TestSimpleTableWithEnumBuilder {
};
inline flatbuffers::Offset CreateTestSimpleTableWithEnum(flatbuffers::FlatBufferBuilder &_fbb,
- Color color = Color_Green) {
+ Color color = Color_Green) {
TestSimpleTableWithEnumBuilder builder_(_fbb);
builder_.add_color(color);
return builder_.Finish();
}
+inline flatbuffers::Offset CreateTestSimpleTableWithEnum(flatbuffers::FlatBufferBuilder &_fbb, const TestSimpleTableWithEnumT *_o);
+
+struct StatT : public flatbuffers::NativeTable {
+ std::string id;
+ int64_t val;
+ uint16_t count;
+};
+
struct Stat FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
enum {
VT_ID = 4,
@@ -188,6 +232,7 @@ struct Stat FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
VerifyField(verifier, VT_COUNT) &&
verifier.EndTable();
}
+ std::unique_ptr UnPack() const;
};
struct StatBuilder {
@@ -205,9 +250,9 @@ struct StatBuilder {
};
inline flatbuffers::Offset CreateStat(flatbuffers::FlatBufferBuilder &_fbb,
- flatbuffers::Offset id = 0,
- int64_t val = 0,
- uint16_t count = 0) {
+ flatbuffers::Offset id = 0,
+ int64_t val = 0,
+ uint16_t count = 0) {
StatBuilder builder_(_fbb);
builder_.add_val(val);
builder_.add_id(id);
@@ -215,6 +260,45 @@ inline flatbuffers::Offset CreateStat(flatbuffers::FlatBufferBuilder &_fbb
return builder_.Finish();
}
+inline flatbuffers::Offset CreateStat(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);
+}
+
+inline flatbuffers::Offset CreateStat(flatbuffers::FlatBufferBuilder &_fbb, const StatT *_o);
+
+struct MonsterT : public flatbuffers::NativeTable {
+ std::unique_ptr pos;
+ int16_t mana;
+ int16_t hp;
+ std::string name;
+ std::vector inventory;
+ Color color;
+ AnyUnion test;
+ std::vector test4;
+ std::vector testarrayofstring;
+ std::vector> testarrayoftables;
+ std::unique_ptr enemy;
+ std::vector testnestedflatbuffer;
+ std::unique_ptr testempty;
+ bool testbool;
+ int32_t testhashs32_fnv1;
+ uint32_t testhashu32_fnv1;
+ int64_t testhashs64_fnv1;
+ uint64_t testhashu64_fnv1;
+ int32_t testhashs32_fnv1a;
+ uint32_t testhashu32_fnv1a;
+ int64_t testhashs64_fnv1a;
+ uint64_t testhashu64_fnv1a;
+ std::vector testarrayofbools;
+ float testf;
+ float testf2;
+ float testf3;
+ std::vector testarrayofstring2;
+};
+
/// an example documentation comment: monster object
struct Monster FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
enum {
@@ -354,6 +438,7 @@ struct Monster FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
verifier.VerifyVectorOfStrings(testarrayofstring2()) &&
verifier.EndTable();
}
+ std::unique_ptr UnPack() const;
};
struct MonsterBuilder {
@@ -397,34 +482,34 @@ struct MonsterBuilder {
};
inline flatbuffers::Offset CreateMonster(flatbuffers::FlatBufferBuilder &_fbb,
- const Vec3 *pos = 0,
- int16_t mana = 150,
- int16_t hp = 100,
- flatbuffers::Offset name = 0,
- flatbuffers::Offset> inventory = 0,
- Color color = Color_Blue,
- Any test_type = Any_NONE,
- flatbuffers::Offset test = 0,
- flatbuffers::Offset> test4 = 0,
- flatbuffers::Offset>> testarrayofstring = 0,
- flatbuffers::Offset>> testarrayoftables = 0,
- flatbuffers::Offset enemy = 0,
- flatbuffers::Offset> testnestedflatbuffer = 0,
- flatbuffers::Offset testempty = 0,
- bool testbool = false,
- int32_t testhashs32_fnv1 = 0,
- uint32_t testhashu32_fnv1 = 0,
- int64_t testhashs64_fnv1 = 0,
- uint64_t testhashu64_fnv1 = 0,
- int32_t testhashs32_fnv1a = 0,
- uint32_t testhashu32_fnv1a = 0,
- int64_t testhashs64_fnv1a = 0,
- uint64_t testhashu64_fnv1a = 0,
- flatbuffers::Offset> testarrayofbools = 0,
- float testf = 3.14159f,
- float testf2 = 3.0f,
- float testf3 = 0.0f,
- flatbuffers::Offset>> testarrayofstring2 = 0) {
+ const Vec3 *pos = 0,
+ int16_t mana = 150,
+ int16_t hp = 100,
+ flatbuffers::Offset name = 0,
+ flatbuffers::Offset> inventory = 0,
+ Color color = Color_Blue,
+ Any test_type = Any_NONE,
+ flatbuffers::Offset test = 0,
+ flatbuffers::Offset> test4 = 0,
+ flatbuffers::Offset>> testarrayofstring = 0,
+ flatbuffers::Offset>> testarrayoftables = 0,
+ flatbuffers::Offset enemy = 0,
+ flatbuffers::Offset> testnestedflatbuffer = 0,
+ flatbuffers::Offset testempty = 0,
+ bool testbool = false,
+ int32_t testhashs32_fnv1 = 0,
+ uint32_t testhashu32_fnv1 = 0,
+ int64_t testhashs64_fnv1 = 0,
+ uint64_t testhashu64_fnv1 = 0,
+ int32_t testhashs32_fnv1a = 0,
+ uint32_t testhashu32_fnv1a = 0,
+ int64_t testhashs64_fnv1a = 0,
+ uint64_t testhashu64_fnv1a = 0,
+ flatbuffers::Offset> testarrayofbools = 0,
+ float testf = 3.14159f,
+ float testf2 = 3.0f,
+ float testf3 = 0.0f,
+ flatbuffers::Offset>> testarrayofstring2 = 0) {
MonsterBuilder builder_(_fbb);
builder_.add_testhashu64_fnv1a(testhashu64_fnv1a);
builder_.add_testhashs64_fnv1a(testhashs64_fnv1a);
@@ -457,6 +542,149 @@ inline flatbuffers::Offset CreateMonster(flatbuffers::FlatBufferBuilder
return builder_.Finish();
}
+inline flatbuffers::Offset CreateMonster(flatbuffers::FlatBufferBuilder &_fbb,
+ const Vec3 *pos = 0,
+ int16_t mana = 150,
+ int16_t hp = 100,
+ const char *name = nullptr,
+ const std::vector *inventory = nullptr,
+ Color color = Color_Blue,
+ Any test_type = Any_NONE,
+ flatbuffers::Offset test = 0,
+ const std::vector *test4 = nullptr,
+ const std::vector> *testarrayofstring = nullptr,
+ const std::vector> *testarrayoftables = nullptr,
+ flatbuffers::Offset enemy = 0,
+ const std::vector *testnestedflatbuffer = nullptr,
+ flatbuffers::Offset testempty = 0,
+ bool testbool = false,
+ int32_t testhashs32_fnv1 = 0,
+ uint32_t testhashu32_fnv1 = 0,
+ int64_t testhashs64_fnv1 = 0,
+ uint64_t testhashu64_fnv1 = 0,
+ int32_t testhashs32_fnv1a = 0,
+ uint32_t testhashu32_fnv1a = 0,
+ int64_t testhashs64_fnv1a = 0,
+ uint64_t testhashu64_fnv1a = 0,
+ const std::vector *testarrayofbools = nullptr,
+ float testf = 3.14159f,
+ float testf2 = 3.0f,
+ float testf3 = 0.0f,
+ const std::vector> *testarrayofstring2 = nullptr) {
+ return CreateMonster(_fbb, pos, mana, hp, name ? 0 : _fbb.CreateString(name), inventory ? 0 : _fbb.CreateVector(*inventory), color, test_type, test, test4 ? 0 : _fbb.CreateVector(*test4), testarrayofstring ? 0 : _fbb.CreateVector>(*testarrayofstring), testarrayoftables ? 0 : _fbb.CreateVector>(*testarrayoftables), enemy, testnestedflatbuffer ? 0 : _fbb.CreateVector(*testnestedflatbuffer), testempty, testbool, testhashs32_fnv1, testhashu32_fnv1, testhashs64_fnv1, testhashu64_fnv1, testhashs32_fnv1a, testhashu32_fnv1a, testhashs64_fnv1a, testhashu64_fnv1a, testarrayofbools ? 0 : _fbb.CreateVector(*testarrayofbools), testf, testf2, testf3, testarrayofstring2 ? 0 : _fbb.CreateVector>(*testarrayofstring2));
+}
+
+inline flatbuffers::Offset CreateMonster(flatbuffers::FlatBufferBuilder &_fbb, const MonsterT *_o);
+
+} // namespace Example
+
+namespace Example2 {
+
+inline std::unique_ptr Monster::UnPack() const {
+ auto _o = new MonsterT();
+ return std::unique_ptr(_o);
+}
+
+inline flatbuffers::Offset CreateMonster(flatbuffers::FlatBufferBuilder &_fbb, const MonsterT *_o) {
+ (void)_o;
+ return CreateMonster(_fbb);
+}
+
+} // namespace Example2
+
+namespace Example {
+
+inline std::unique_ptr TestSimpleTableWithEnum::UnPack() const {
+ auto _o = new TestSimpleTableWithEnumT();
+ { auto _e = color(); _o->color = _e; };
+ return std::unique_ptr(_o);
+}
+
+inline flatbuffers::Offset CreateTestSimpleTableWithEnum(flatbuffers::FlatBufferBuilder &_fbb, const TestSimpleTableWithEnumT *_o) {
+ return CreateTestSimpleTableWithEnum(_fbb,
+ _o->color);
+}
+
+inline std::unique_ptr Stat::UnPack() const {
+ 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(_o);
+}
+
+inline flatbuffers::Offset CreateStat(flatbuffers::FlatBufferBuilder &_fbb, const StatT *_o) {
+ return CreateStat(_fbb,
+ _o->id.size() ? _fbb.CreateString(_o->id) : 0,
+ _o->val,
+ _o->count);
+}
+
+inline std::unique_ptr Monster::UnPack() const {
+ auto _o = new MonsterT();
+ { auto _e = pos(); if (_e) _o->pos = std::unique_ptr(new Vec3(*_e)); };
+ { auto _e = mana(); _o->mana = _e; };
+ { auto _e = hp(); _o->hp = _e; };
+ { 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 = test_type(); _o->test.type = _e; };
+ { auto _e = test(); if (_e) _o->test.table = AnyUnion::UnPack(_e, test_type()); };
+ { 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 = 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 = 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 = 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); } } };
+ { auto _e = testf(); _o->testf = _e; };
+ { 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(_o);
+}
+
+inline flatbuffers::Offset CreateMonster(flatbuffers::FlatBufferBuilder &_fbb, const MonsterT *_o) {
+ return CreateMonster(_fbb,
+ _o->pos ? _o->pos.get() : 0,
+ _o->mana,
+ _o->hp,
+ _fbb.CreateString(_o->name),
+ _o->inventory.size() ? _fbb.CreateVector(_o->inventory) : 0,
+ _o->color,
+ _o->test.type,
+ _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>(_o->testarrayoftables.size(), [&](size_t i) { return CreateMonster(_fbb, _o->testarrayoftables[i].get()); }) : 0,
+ _o->enemy ? CreateMonster(_fbb, _o->enemy.get()) : 0,
+ _o->testnestedflatbuffer.size() ? _fbb.CreateVector(_o->testnestedflatbuffer) : 0,
+ _o->testempty ? CreateStat(_fbb, _o->testempty.get()) : 0,
+ _o->testbool,
+ _o->testhashs32_fnv1,
+ _o->testhashu32_fnv1,
+ _o->testhashs64_fnv1,
+ _o->testhashu64_fnv1,
+ _o->testhashs32_fnv1a,
+ _o->testhashu32_fnv1a,
+ _o->testhashs64_fnv1a,
+ _o->testhashu64_fnv1a,
+ _o->testarrayofbools.size() ? _fbb.CreateVector(_o->testarrayofbools) : 0,
+ _o->testf,
+ _o->testf2,
+ _o->testf3,
+ _o->testarrayofstring2.size() ? _fbb.CreateVectorOfStrings(_o->testarrayofstring2) : 0);
+}
+
inline bool VerifyAny(flatbuffers::Verifier &verifier, const void *union_obj, Any type) {
switch (type) {
case Any_NONE: return true;
@@ -467,16 +695,45 @@ inline bool VerifyAny(flatbuffers::Verifier &verifier, const void *union_obj, An
}
}
+inline flatbuffers::NativeTable *AnyUnion::UnPack(const void *union_obj, Any type) {
+ switch (type) {
+ case Any_NONE: return nullptr;
+ case Any_Monster: return reinterpret_cast(union_obj)->UnPack().release();
+ case Any_TestSimpleTableWithEnum: return reinterpret_cast(union_obj)->UnPack().release();
+ case Any_MyGame_Example2_Monster: return reinterpret_cast(union_obj)->UnPack().release();
+ default: return nullptr;
+ }
+}
+
+inline flatbuffers::Offset AnyUnion::Pack(flatbuffers::FlatBufferBuilder &_fbb) const {
+ switch (type) {
+ case Any_NONE: return 0;
+ case Any_Monster: return CreateMonster(_fbb, reinterpret_cast(table)).Union();
+ case Any_TestSimpleTableWithEnum: return CreateTestSimpleTableWithEnum(_fbb, reinterpret_cast(table)).Union();
+ case Any_MyGame_Example2_Monster: return CreateMonster(_fbb, reinterpret_cast(table)).Union();
+ default: return 0;
+ }
+}
+
+inline AnyUnion::~AnyUnion() {
+ switch (type) {
+ case Any_Monster: delete reinterpret_cast(table); break;
+ case Any_TestSimpleTableWithEnum: delete reinterpret_cast(table); break;
+ case Any_MyGame_Example2_Monster: delete reinterpret_cast(table); break;
+ default:;
+ }
+}
+
inline const MyGame::Example::Monster *GetMonster(const void *buf) { return flatbuffers::GetRoot(buf); }
inline Monster *GetMutableMonster(void *buf) { return flatbuffers::GetMutableRoot(buf); }
-inline bool VerifyMonsterBuffer(flatbuffers::Verifier &verifier) { return verifier.VerifyBuffer(); }
-
inline const char *MonsterIdentifier() { return "MONS"; }
inline bool MonsterBufferHasIdentifier(const void *buf) { return flatbuffers::BufferHasIdentifier(buf, MonsterIdentifier()); }
+inline bool VerifyMonsterBuffer(flatbuffers::Verifier &verifier) { return verifier.VerifyBuffer(MonsterIdentifier()); }
+
inline const char *MonsterExtension() { return "mon"; }
inline void FinishMonsterBuffer(flatbuffers::FlatBufferBuilder &fbb, flatbuffers::Offset root) { fbb.Finish(root, MonsterIdentifier()); }
diff --git a/tests/monster_test_generated.js b/tests/monster_test_generated.js
index f67e84802..7c4c28f82 100644
--- a/tests/monster_test_generated.js
+++ b/tests/monster_test_generated.js
@@ -2,22 +2,26 @@
/**
* @const
-*/
+ * @namespace
+ */
var MyGame = MyGame || {};
/**
* @const
-*/
+ * @namespace
+ */
MyGame.Example = MyGame.Example || {};
/**
* @const
-*/
+ * @namespace
+ */
MyGame.Example2 = MyGame.Example2 || {};
/**
* @const
-*/
+ * @namespace
+ */
MyGame.OtherNameSpace = MyGame.OtherNameSpace || {};
/**
diff --git a/tests/namespace_test/NamespaceA/NamespaceB/EnumInNestedNS.java b/tests/namespace_test/NamespaceA/NamespaceB/EnumInNestedNS.java
index ff5559544..e23cecc06 100644
--- a/tests/namespace_test/NamespaceA/NamespaceB/EnumInNestedNS.java
+++ b/tests/namespace_test/NamespaceA/NamespaceB/EnumInNestedNS.java
@@ -8,8 +8,8 @@ public final class EnumInNestedNS {
public static final byte B = 1;
public static final byte C = 2;
- private static final String[] names = { "A", "B", "C", };
+ public static final String[] names = { "A", "B", "C", };
public static String name(int e) { return names[e]; }
-};
+}
diff --git a/tests/namespace_test/NamespaceA/NamespaceB/StructInNestedNS.go b/tests/namespace_test/NamespaceA/NamespaceB/StructInNestedNS.go
index f3684623b..f834a721a 100644
--- a/tests/namespace_test/NamespaceA/NamespaceB/StructInNestedNS.go
+++ b/tests/namespace_test/NamespaceA/NamespaceB/StructInNestedNS.go
@@ -15,7 +15,11 @@ func (rcv *StructInNestedNS) Init(buf []byte, i flatbuffers.UOffsetT) {
}
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 CreateStructInNestedNS(builder *flatbuffers.Builder, a int32, b int32) flatbuffers.UOffsetT {
builder.Prep(4, 8)
diff --git a/tests/namespace_test/NamespaceA/NamespaceB/StructInNestedNS.java b/tests/namespace_test/NamespaceA/NamespaceB/StructInNestedNS.java
index 93f805224..fede07a02 100644
--- a/tests/namespace_test/NamespaceA/NamespaceB/StructInNestedNS.java
+++ b/tests/namespace_test/NamespaceA/NamespaceB/StructInNestedNS.java
@@ -22,5 +22,5 @@ public final class StructInNestedNS extends Struct {
builder.putInt(a);
return builder.offset();
}
-};
+}
diff --git a/tests/namespace_test/NamespaceA/NamespaceB/TableInNestedNS.go b/tests/namespace_test/NamespaceA/NamespaceB/TableInNestedNS.go
index cf2b557c6..c956fb42c 100644
--- a/tests/namespace_test/NamespaceA/NamespaceB/TableInNestedNS.go
+++ b/tests/namespace_test/NamespaceA/NamespaceB/TableInNestedNS.go
@@ -22,6 +22,10 @@ func (rcv *TableInNestedNS) Foo() int32 {
return 0
}
+func (rcv *TableInNestedNS) MutateFoo(n int32) bool {
+ 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() }
diff --git a/tests/namespace_test/NamespaceA/NamespaceB/TableInNestedNS.java b/tests/namespace_test/NamespaceA/NamespaceB/TableInNestedNS.java
index 2cfb1bacc..fc518563d 100644
--- a/tests/namespace_test/NamespaceA/NamespaceB/TableInNestedNS.java
+++ b/tests/namespace_test/NamespaceA/NamespaceB/TableInNestedNS.java
@@ -29,5 +29,5 @@ public final class TableInNestedNS extends Table {
int o = builder.endObject();
return o;
}
-};
+}
diff --git a/tests/namespace_test/NamespaceA/SecondTableInA.java b/tests/namespace_test/NamespaceA/SecondTableInA.java
index acabc3931..e6f390a9f 100644
--- a/tests/namespace_test/NamespaceA/SecondTableInA.java
+++ b/tests/namespace_test/NamespaceA/SecondTableInA.java
@@ -29,5 +29,5 @@ public final class SecondTableInA extends Table {
int o = builder.endObject();
return o;
}
-};
+}
diff --git a/tests/namespace_test/NamespaceA/TableInFirstNS.go b/tests/namespace_test/NamespaceA/TableInFirstNS.go
index 5580d5d58..0a002b3b7 100644
--- a/tests/namespace_test/NamespaceA/TableInFirstNS.go
+++ b/tests/namespace_test/NamespaceA/TableInFirstNS.go
@@ -35,6 +35,10 @@ func (rcv *TableInFirstNS) FooEnum() int8 {
return 0
}
+func (rcv *TableInFirstNS) MutateFooEnum(n int8) bool {
+ return rcv._tab.MutateInt8Slot(6, n)
+}
+
func (rcv *TableInFirstNS) FooStruct(obj *StructInNestedNS) *StructInNestedNS {
o := flatbuffers.UOffsetT(rcv._tab.Offset(8))
if o != 0 {
diff --git a/tests/namespace_test/NamespaceA/TableInFirstNS.java b/tests/namespace_test/NamespaceA/TableInFirstNS.java
index 873979307..b44df9786 100644
--- a/tests/namespace_test/NamespaceA/TableInFirstNS.java
+++ b/tests/namespace_test/NamespaceA/TableInFirstNS.java
@@ -28,5 +28,5 @@ public final class TableInFirstNS extends Table {
int o = builder.endObject();
return o;
}
-};
+}
diff --git a/tests/namespace_test/NamespaceC/TableInC.java b/tests/namespace_test/NamespaceC/TableInC.java
index cf1bca18c..19bb4cd57 100644
--- a/tests/namespace_test/NamespaceC/TableInC.java
+++ b/tests/namespace_test/NamespaceC/TableInC.java
@@ -34,5 +34,5 @@ public final class TableInC extends Table {
int o = builder.endObject();
return o;
}
-};
+}
diff --git a/tests/namespace_test/namespace_test1_generated.h b/tests/namespace_test/namespace_test1_generated.h
index 9e10eb4c1..59d4030a1 100644
--- a/tests/namespace_test/namespace_test1_generated.h
+++ b/tests/namespace_test/namespace_test1_generated.h
@@ -33,6 +33,8 @@ MANUALLY_ALIGNED_STRUCT(4) StructInNestedNS FLATBUFFERS_FINAL_CLASS {
int32_t b_;
public:
+ StructInNestedNS() { memset(this, 0, sizeof(StructInNestedNS)); }
+ StructInNestedNS(const StructInNestedNS &_o) { memcpy(this, &_o, sizeof(StructInNestedNS)); }
StructInNestedNS(int32_t _a, int32_t _b)
: a_(flatbuffers::EndianScalar(_a)), b_(flatbuffers::EndianScalar(_b)) { }
@@ -69,7 +71,7 @@ struct TableInNestedNSBuilder {
};
inline flatbuffers::Offset CreateTableInNestedNS(flatbuffers::FlatBufferBuilder &_fbb,
- int32_t foo = 0) {
+ int32_t foo = 0) {
TableInNestedNSBuilder builder_(_fbb);
builder_.add_foo(foo);
return builder_.Finish();
diff --git a/tests/namespace_test/namespace_test1_generated.js b/tests/namespace_test/namespace_test1_generated.js
index 769b523e3..e6390567f 100644
--- a/tests/namespace_test/namespace_test1_generated.js
+++ b/tests/namespace_test/namespace_test1_generated.js
@@ -2,12 +2,14 @@
/**
* @const
-*/
+ * @namespace
+ */
var NamespaceA = NamespaceA || {};
/**
* @const
-*/
+ * @namespace
+ */
NamespaceA.NamespaceB = NamespaceA.NamespaceB || {};
/**
diff --git a/tests/namespace_test/namespace_test2_generated.h b/tests/namespace_test/namespace_test2_generated.h
index 8e6b3ada8..77578bc60 100644
--- a/tests/namespace_test/namespace_test2_generated.h
+++ b/tests/namespace_test/namespace_test2_generated.h
@@ -60,9 +60,9 @@ struct TableInFirstNSBuilder {
};
inline flatbuffers::Offset CreateTableInFirstNS(flatbuffers::FlatBufferBuilder &_fbb,
- flatbuffers::Offset foo_table = 0,
- NamespaceA::NamespaceB::EnumInNestedNS foo_enum = NamespaceA::NamespaceB::EnumInNestedNS_A,
- const NamespaceA::NamespaceB::StructInNestedNS *foo_struct = 0) {
+ flatbuffers::Offset foo_table = 0,
+ NamespaceA::NamespaceB::EnumInNestedNS foo_enum = NamespaceA::NamespaceB::EnumInNestedNS_A,
+ const NamespaceA::NamespaceB::StructInNestedNS *foo_struct = 0) {
TableInFirstNSBuilder builder_(_fbb);
builder_.add_foo_struct(foo_struct);
builder_.add_foo_table(foo_table);
@@ -107,8 +107,8 @@ struct TableInCBuilder {
};
inline flatbuffers::Offset CreateTableInC(flatbuffers::FlatBufferBuilder &_fbb,
- flatbuffers::Offset