summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-x.gitignore7
-rw-r--r--CMakeLists.txt42
-rw-r--r--CONTRIBUTING.md (renamed from CONTRIBUTING)0
-rwxr-xr-xbuild_ide/VS2010/flatc.vcxproj10
-rwxr-xr-xbuild_ide/VS2010/flatc.vcxproj.user2
-rw-r--r--build_ide/Xcode/FlatBuffers.xcodeproj/project.pbxproj34
-rwxr-xr-xdocs/source/Compiler.md11
-rwxr-xr-xdocs/source/CppUsage.md21
-rw-r--r--docs/source/GoUsage.md23
-rwxr-xr-xdocs/source/Schemas.md9
-rw-r--r--docs/source/Tutorial.md17
-rw-r--r--go/table.go210
-rw-r--r--grpc/README.md11
-rw-r--r--grpc/src/compiler/cpp_generator.cc1202
-rw-r--r--grpc/src/compiler/cpp_generator.h147
-rw-r--r--grpc/tests/grpctest.cpp124
-rw-r--r--include/flatbuffers/code_generators.h52
-rw-r--r--include/flatbuffers/flatbuffers.h188
-rw-r--r--include/flatbuffers/grpc.h72
-rw-r--r--include/flatbuffers/idl.h52
-rw-r--r--include/flatbuffers/reflection.h6
-rw-r--r--include/flatbuffers/reflection_generated.h4
-rw-r--r--java/com/google/flatbuffers/Constants.java8
-rw-r--r--java/com/google/flatbuffers/FlatBufferBuilder.java28
-rw-r--r--php/FlatbufferBuilder.php6
-rw-r--r--pom.xml (renamed from java/pom.xml)10
-rwxr-xr-xreadme.md2
-rw-r--r--samples/monster_generated.h147
-rw-r--r--src/flatc.cpp105
-rw-r--r--src/idl_gen_cpp.cpp581
-rw-r--r--src/idl_gen_fbs.cpp14
-rw-r--r--src/idl_gen_general.cpp615
-rw-r--r--src/idl_gen_go.cpp54
-rw-r--r--src/idl_gen_grpc.cpp217
-rw-r--r--src/idl_gen_js.cpp168
-rw-r--r--src/idl_gen_php.cpp206
-rw-r--r--src/idl_gen_python.cpp8
-rw-r--r--src/idl_parser.cpp158
-rw-r--r--tests/MyGame/Example/Any.cs1
-rw-r--r--tests/MyGame/Example/Any.go1
-rw-r--r--tests/MyGame/Example/Any.java5
-rw-r--r--tests/MyGame/Example/Any.php2
-rw-r--r--tests/MyGame/Example/Any.py1
-rw-r--r--tests/MyGame/Example/Color.java4
-rw-r--r--tests/MyGame/Example/Monster.cs7
-rw-r--r--tests/MyGame/Example/Monster.go88
-rw-r--r--tests/MyGame/Example/Monster.java9
-rw-r--r--tests/MyGame/Example/Monster.php60
-rw-r--r--tests/MyGame/Example/Monster.py19
-rw-r--r--tests/MyGame/Example/Stat.go8
-rw-r--r--tests/MyGame/Example/Stat.java2
-rw-r--r--tests/MyGame/Example/Test.go4
-rw-r--r--tests/MyGame/Example/Test.java2
-rw-r--r--tests/MyGame/Example/TestSimpleTableWithEnum.go4
-rw-r--r--tests/MyGame/Example/TestSimpleTableWithEnum.java2
-rw-r--r--tests/MyGame/Example/Vec3.go10
-rw-r--r--tests/MyGame/Example/Vec3.java2
-rw-r--r--tests/MyGame/Example2/Monster.cs23
-rw-r--r--tests/MyGame/Example2/Monster.go18
-rw-r--r--tests/MyGame/Example2/Monster.java23
-rw-r--r--tests/MyGame/Example2/Monster.php79
-rw-r--r--tests/MyGame/Example2/Monster.py15
-rw-r--r--tests/generate_code.bat2
-rw-r--r--tests/generate_code.sh2
-rw-r--r--tests/go_test.go262
-rw-r--r--tests/monster_test.bfbsbin3008 -> 3152 bytes
-rwxr-xr-xtests/monster_test.fbs9
-rw-r--r--tests/monster_test.grpc.fb.cc85
-rw-r--r--tests/monster_test.grpc.fb.h155
-rw-r--r--tests/monster_test_generated.h379
-rw-r--r--tests/monster_test_generated.js108
-rw-r--r--tests/monsterdata_test.monbin384 -> 384 bytes
-rw-r--r--tests/namespace_test/NamespaceA/NamespaceB/EnumInNestedNS.java4
-rw-r--r--tests/namespace_test/NamespaceA/NamespaceB/StructInNestedNS.go4
-rw-r--r--tests/namespace_test/NamespaceA/NamespaceB/StructInNestedNS.java2
-rw-r--r--tests/namespace_test/NamespaceA/NamespaceB/TableInNestedNS.go4
-rw-r--r--tests/namespace_test/NamespaceA/NamespaceB/TableInNestedNS.java2
-rw-r--r--tests/namespace_test/NamespaceA/SecondTableInA.java2
-rw-r--r--tests/namespace_test/NamespaceA/TableInFirstNS.go4
-rw-r--r--tests/namespace_test/NamespaceA/TableInFirstNS.java2
-rw-r--r--tests/namespace_test/NamespaceC/TableInC.cs38
-rw-r--r--tests/namespace_test/NamespaceC/TableInC.go46
-rw-r--r--tests/namespace_test/NamespaceC/TableInC.java38
-rw-r--r--tests/namespace_test/NamespaceC/TableInC.php100
-rw-r--r--tests/namespace_test/NamespaceC/TableInC.py39
-rw-r--r--tests/namespace_test/namespace_test1_generated.h4
-rw-r--r--tests/namespace_test/namespace_test2_generated.h20
-rw-r--r--tests/py_test.py7
-rw-r--r--tests/test.cpp199
89 files changed, 5559 insertions, 918 deletions
diff --git a/.gitignore b/.gitignore
index 6f3894d0..e07fbae9 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 b1e56d6b..cfb84bae 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -6,9 +6,12 @@ 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)
if(NOT FLATBUFFERS_BUILD_FLATC AND FLATBUFFERS_BUILD_TESTS)
message(WARNING
@@ -39,7 +42,10 @@ set(FlatBuffers_Compiler_SRCS
src/idl_gen_php.cpp
src/idl_gen_python.cpp
src/idl_gen_fbs.cpp
+ src/idl_gen_grpc.cpp
src/flatc.cpp
+ grpc/src/compiler/cpp_generator.h
+ grpc/src/compiler/cpp_generator.cc
)
set(FlatHash_SRCS
@@ -76,12 +82,23 @@ set(FlatBuffers_Sample_Text_SRCS
${CMAKE_CURRENT_BINARY_DIR}/samples/monster_generated.h
)
+set(FlatBuffers_GRPCTest_SRCS
+ include/flatbuffers/flatbuffers.h
+ include/flatbuffers/grpc.h
+ tests/monster_test.grpc.fb.h
+ tests/monster_test.grpc.fb.cc
+ grpc/tests/grpctest.cpp
+ # file generated by running compiler on samples/monster.fbs
+ ${CMAKE_CURRENT_BINARY_DIR}/samples/monster_generated.h
+)
+
# source_group(Compiler FILES ${FlatBuffers_Compiler_SRCS})
# source_group(Tests FILES ${FlatBuffers_Tests_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
@@ -104,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")
@@ -129,6 +147,7 @@ if(BIICODE)
endif()
include_directories(include)
+include_directories(grpc)
if(FLATBUFFERS_BUILD_FLATLIB)
add_library(flatbuffers STATIC ${FlatBuffers_Library_SRCS})
@@ -150,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()
@@ -159,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()
@@ -174,6 +196,14 @@ if(FLATBUFFERS_BUILD_TESTS)
add_executable(flatsampletext ${FlatBuffers_Sample_Text_SRCS})
endif()
+if(FLATBUFFERS_BUILD_GRPCTEST)
+ if(CMAKE_COMPILER_IS_GNUCXX)
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-unused-parameter")
+ endif()
+ add_executable(grpctest ${FlatBuffers_GRPCTest_SRCS})
+ target_link_libraries(grpctest grpc++_unsecure grpc pthread dl)
+endif()
+
if(FLATBUFFERS_INSTALL)
install(DIRECTORY include/flatbuffers DESTINATION include)
if(FLATBUFFERS_BUILD_FLATLIB)
diff --git a/CONTRIBUTING b/CONTRIBUTING.md
index 15887529..15887529 100644
--- a/CONTRIBUTING
+++ b/CONTRIBUTING.md
diff --git a/build_ide/VS2010/flatc.vcxproj b/build_ide/VS2010/flatc.vcxproj
index 31cd0134..5aef2384 100755
--- a/build_ide/VS2010/flatc.vcxproj
+++ b/build_ide/VS2010/flatc.vcxproj
@@ -81,7 +81,7 @@
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
- <AdditionalIncludeDirectories>../../include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>../../include;../../grpc;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<CompileAs>CompileAsCpp</CompileAs>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
@@ -127,7 +127,7 @@
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
- <AdditionalIncludeDirectories>../../include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>../../include;../../grpc;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<CompileAs>CompileAsCpp</CompileAs>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
@@ -173,7 +173,7 @@
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
- <AdditionalIncludeDirectories>../../include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>../../include;../../grpc;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<CompileAs>CompileAsCpp</CompileAs>
<ExceptionHandling>Sync</ExceptionHandling>
<InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion>
@@ -219,7 +219,7 @@
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
- <AdditionalIncludeDirectories>../../include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>../../include;../../grpc;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<CompileAs>CompileAsCpp</CompileAs>
<ExceptionHandling>Sync</ExceptionHandling>
<InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion>
@@ -263,6 +263,8 @@
</ProjectReference>
</ItemDefinitionGroup>
<ItemGroup>
+ <ClCompile Include="..\..\grpc\src\compiler\cpp_generator.cc" />
+ <ClCompile Include="..\..\src\idl_gen_grpc.cpp" />
<ClCompile Include="..\..\src\util.cpp" />
<ClInclude Include="..\..\include\flatbuffers\flatbuffers.h" />
<ClInclude Include="..\..\include\flatbuffers\idl.h" />
diff --git a/build_ide/VS2010/flatc.vcxproj.user b/build_ide/VS2010/flatc.vcxproj.user
index 5ef05f7e..1132b8ab 100755
--- a/build_ide/VS2010/flatc.vcxproj.user
+++ b/build_ide/VS2010/flatc.vcxproj.user
@@ -3,7 +3,7 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LocalDebuggerWorkingDirectory>..\..\tests</LocalDebuggerWorkingDirectory>
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
- <LocalDebuggerCommandArguments>-j -c -n -g --php --no-includes --gen-mutable monster_test.fbs</LocalDebuggerCommandArguments>
+ <LocalDebuggerCommandArguments>-j -c -n -g --php --no-includes --gen-mutable --gen-object-api monster_test.fbs</LocalDebuggerCommandArguments>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LocalDebuggerWorkingDirectory>..\..</LocalDebuggerWorkingDirectory>
diff --git a/build_ide/Xcode/FlatBuffers.xcodeproj/project.pbxproj b/build_ide/Xcode/FlatBuffers.xcodeproj/project.pbxproj
index ee18e9e2..e67f7356 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 = "<group>"; };
8C303C581975D6A700D7C1C5 /* idl_gen_go.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = idl_gen_go.cpp; path = src/idl_gen_go.cpp; sourceTree = "<group>"; };
+ 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 = "<group>"; };
+ 8C547D671D3FF07D00AE7A25 /* cpp_generator.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = cpp_generator.cc; path = grpc/src/compiler/cpp_generator.cc; sourceTree = "<group>"; };
8C6905EC19F8357300CB8866 /* idl_gen_fbs.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = idl_gen_fbs.cpp; path = src/idl_gen_fbs.cpp; sourceTree = "<group>"; };
8C78573D1BD5AE2C00C53C34 /* idl_gen_js.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = idl_gen_js.cpp; path = src/idl_gen_js.cpp; sourceTree = "<group>"; };
8C8774621B703D4800E693F5 /* reflection.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = reflection.cpp; path = src/reflection.cpp; sourceTree = "<group>"; };
@@ -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 886fbd9b..b71b8c46 100755
--- a/docs/source/Compiler.md
+++ b/docs/source/Compiler.md
@@ -33,6 +33,8 @@ For any schema input files, one or more generators can be specified:
- `--php`: Generate PHP code.
+- `--grpc`: Generate RPC stub code for GRPC.
+
For any data input files:
- `--binary`, `-b` : If data is contained in this file, generate a
@@ -79,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
@@ -101,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 d4abe66e..060432b0 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 a3a0e928..ab6ddbd8 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/Schemas.md b/docs/source/Schemas.md
index 4004803d..5bcaccb3 100755
--- a/docs/source/Schemas.md
+++ b/docs/source/Schemas.md
@@ -237,7 +237,8 @@ as the response (both of which must be table types):
}
What code this produces and how it is used depends on language and RPC system
-used, FlatBuffers itself does not offer this functionality.
+used, there is preliminary support for GRPC through the `--grpc` code generator,
+see `grpc/tests` for an example.
### Comments & documentation
@@ -271,7 +272,7 @@ Current understood attributes:
the union field should have id 8, and the unions type field will
implicitly be 7.
IDs allow the fields to be placed in any order in the schema.
- When a new field is added to the schema is must use the next available ID.
+ When a new field is added to the schema it must use the next available ID.
- `deprecated` (on a field): do not generate accessors for this field
anymore, code should stop using this data.
- `required` (on a non-scalar table field): this field must always be set.
@@ -333,6 +334,10 @@ JSON:
- A field that has the value `null` (e.g. `field: null`) is intended to
have the default value for that field (thus has the same effect as if
that field wasn't specified at all).
+- It has some built in conversion functions, so you can write for example
+ `rad(180)` where ever you'd normally write `3.14159`.
+ Currently supports the following functions: `rad`, `deg`, `cos`, `sin`,
+ `tan`, `acos`, `asin`, `atan`.
When parsing JSON, it recognizes the following escape codes in strings:
diff --git a/docs/source/Tutorial.md b/docs/source/Tutorial.md
index 1e48796d..100191d7 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);
@@ -790,6 +790,14 @@ offsets.
~~~
</div>
+<div class="language-cpp">
+<br>
+Note there's additional convenience overloads of `CreateVector`, allowing you
+to work with data that's not in a `std::vector`, or allowing you to generate
+elements by calling a lambda. For the common case of `std::vector<std::string>`
+there's also `CreateVectorOfStrings`.
+</div>
+
To create a `struct`, use the `Vec3` class/struct that was generated by
the schema compiler:
@@ -1075,7 +1083,7 @@ Here is a repetition these lines, to help highlight them more clearly:
<div class="language-c">
~~~{.c}
// Add union type and data simultanously.
- ns(Monster_equipped_Weapon_add(B, axe));
+ ns(Monster_equipped_Weapon_add(B, axe));
~~~
</div>
@@ -1873,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 976a7dba..01d3db12 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/grpc/README.md b/grpc/README.md
new file mode 100644
index 00000000..13485198
--- /dev/null
+++ b/grpc/README.md
@@ -0,0 +1,11 @@
+GRPC implementation and test
+============================
+
+NOTE: files in `src/` are shared with the GRPC project, and maintained there
+(any changes should be submitted to GRPC instead). These files are copied
+from GRPC, and work with both the Protobuf and FlatBuffers code generator.
+
+`tests/` contains a GRPC specific test, you need to have built and installed
+the GRPC libraries for this to compile. This test will build using the
+`FLATBUFFERS_BUILD_GRPCTEST` option to the main FlatBuffers CMake project.
+
diff --git a/grpc/src/compiler/cpp_generator.cc b/grpc/src/compiler/cpp_generator.cc
new file mode 100644
index 00000000..9319c419
--- /dev/null
+++ b/grpc/src/compiler/cpp_generator.cc
@@ -0,0 +1,1202 @@
+/*
+ *
+ * Copyright 2015, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <map>
+
+#include "src/compiler/cpp_generator.h"
+
+#include <sstream>
+
+namespace grpc_cpp_generator {
+namespace {
+
+template <class T>
+grpc::string as_string(T x) {
+ std::ostringstream out;
+ out << x;
+ return out.str();
+}
+
+grpc::string FilenameIdentifier(const grpc::string &filename) {
+ grpc::string result;
+ for (unsigned i = 0; i < filename.size(); i++) {
+ char c = filename[i];
+ if (isalnum(c)) {
+ result.push_back(c);
+ } else {
+ static char hex[] = "0123456789abcdef";
+ result.push_back('_');
+ result.push_back(hex[(c >> 4) & 0xf]);
+ result.push_back(hex[c & 0xf]);
+ }
+ }
+ return result;
+}
+} // namespace
+
+template<class T, size_t N>
+T *array_end(T (&array)[N]) { return array + N; }
+
+void PrintIncludes(Printer *printer, const std::vector<grpc::string>& headers, const Parameters &params) {
+ std::map<grpc::string, grpc::string> vars;
+
+ vars["l"] = params.use_system_headers ? '<' : '"';
+ vars["r"] = params.use_system_headers ? '>' : '"';
+
+ if (!params.grpc_search_path.empty()) {
+ vars["l"] += params.grpc_search_path;
+ if (params.grpc_search_path.back() != '/') {
+ vars["l"] += '/';
+ }
+ }
+
+ for (auto i = headers.begin(); i != headers.end(); i++) {
+ vars["h"] = *i;
+ printer->Print(vars, "#include $l$$h$$r$\n");
+ }
+}
+
+grpc::string GetHeaderPrologue(File *file, const Parameters & /*params*/) {
+ grpc::string output;
+ {
+ // Scope the output stream so it closes and finalizes output to the string.
+ auto printer = file->CreatePrinter(&output);
+ std::map<grpc::string, grpc::string> vars;
+
+ vars["filename"] = file->filename();
+ vars["filename_identifier"] = FilenameIdentifier(file->filename());
+ vars["filename_base"] = file->filename_without_ext();
+ vars["message_header_ext"] = file->message_header_ext();
+
+ printer->Print(vars, "// Generated by the gRPC protobuf plugin.\n");
+ printer->Print(vars,
+ "// If you make any local change, they will be lost.\n");
+ printer->Print(vars, "// source: $filename$\n");
+ printer->Print(vars, "#ifndef GRPC_$filename_identifier$__INCLUDED\n");
+ printer->Print(vars, "#define GRPC_$filename_identifier$__INCLUDED\n");
+ printer->Print(vars, "\n");
+ printer->Print(vars, "#include \"$filename_base$$message_header_ext$\"\n");
+ printer->Print(vars, "\n");
+ }
+ return output;
+}
+
+grpc::string GetHeaderIncludes(File *file,
+ const Parameters &params) {
+ grpc::string output;
+ {
+ // Scope the output stream so it closes and finalizes output to the string.
+ auto printer = file->CreatePrinter(&output);
+ std::map<grpc::string, grpc::string> vars;
+
+ static const char *headers_strs[] = {
+ "grpc++/impl/codegen/async_stream.h",
+ "grpc++/impl/codegen/async_unary_call.h",
+ "grpc++/impl/codegen/proto_utils.h",
+ "grpc++/impl/codegen/rpc_method.h",
+ "grpc++/impl/codegen/service_type.h",
+ "grpc++/impl/codegen/status.h",
+ "grpc++/impl/codegen/stub_options.h",
+ "grpc++/impl/codegen/sync_stream.h"
+ };
+ std::vector<grpc::string> headers(headers_strs, array_end(headers_strs));
+ PrintIncludes(printer.get(), headers, params);
+ printer->Print(vars, "\n");
+ printer->Print(vars, "namespace grpc {\n");
+ printer->Print(vars, "class CompletionQueue;\n");
+ printer->Print(vars, "class Channel;\n");
+ printer->Print(vars, "class RpcService;\n");
+ printer->Print(vars, "class ServerCompletionQueue;\n");
+ printer->Print(vars, "class ServerContext;\n");
+ printer->Print(vars, "} // namespace grpc\n\n");
+
+ if (!file->package().empty()) {
+ std::vector<grpc::string> parts = file->package_parts();
+
+ for (auto part = parts.begin(); part != parts.end(); part++) {
+ vars["part"] = *part;
+ printer->Print(vars, "namespace $part$ {\n");
+ }
+ printer->Print(vars, "\n");
+ }
+ }
+ return output;
+}
+
+void PrintHeaderClientMethodInterfaces(
+ Printer *printer, const Method *method,
+ std::map<grpc::string, grpc::string> *vars, bool is_public) {
+ (*vars)["Method"] = method->name();
+ (*vars)["Request"] = method->input_type_name();
+ (*vars)["Response"] = method->output_type_name();
+
+ if (is_public) {
+ if (method->NoStreaming()) {
+ printer->Print(
+ *vars,
+ "virtual ::grpc::Status $Method$(::grpc::ClientContext* context, "
+ "const $Request$& request, $Response$* response) = 0;\n");
+ printer->Print(*vars,
+ "std::unique_ptr< "
+ "::grpc::ClientAsyncResponseReaderInterface< $Response$>> "
+ "Async$Method$(::grpc::ClientContext* context, "
+ "const $Request$& request, "
+ "::grpc::CompletionQueue* cq) {\n");
+ printer->Indent();
+ printer->Print(*vars,
+ "return std::unique_ptr< "
+ "::grpc::ClientAsyncResponseReaderInterface< $Response$>>("
+ "Async$Method$Raw(context, request, cq));\n");
+ printer->Outdent();
+ printer->Print("}\n");
+ } else if (method->ClientOnlyStreaming()) {
+ printer->Print(
+ *vars,
+ "std::unique_ptr< ::grpc::ClientWriterInterface< $Request$>>"
+ " $Method$("
+ "::grpc::ClientContext* context, $Response$* response) {\n");
+ printer->Indent();
+ printer->Print(
+ *vars,
+ "return std::unique_ptr< ::grpc::ClientWriterInterface< $Request$>>"
+ "($Method$Raw(context, response));\n");
+ printer->Outdent();
+ printer->Print("}\n");
+ printer->Print(
+ *vars,
+ "std::unique_ptr< ::grpc::ClientAsyncWriterInterface< $Request$>>"
+ " Async$Method$(::grpc::ClientContext* context, $Response$* "
+ "response, "
+ "::grpc::CompletionQueue* cq, void* tag) {\n");
+ printer->Indent();
+ printer->Print(*vars,
+ "return std::unique_ptr< "
+ "::grpc::ClientAsyncWriterInterface< $Request$>>("
+ "Async$Method$Raw(context, response, cq, tag));\n");
+ printer->Outdent();
+ printer->Print("}\n");
+ } else if (method->ServerOnlyStreaming()) {
+ printer->Print(
+ *vars,
+ "std::unique_ptr< ::grpc::ClientReaderInterface< $Response$>>"
+ " $Method$(::grpc::ClientContext* context, const $Request$& request)"
+ " {\n");
+ printer->Indent();
+ printer->Print(
+ *vars,
+ "return std::unique_ptr< ::grpc::ClientReaderInterface< $Response$>>"
+ "($Method$Raw(context, request));\n");
+ printer->Outdent();
+ printer->Print("}\n");
+ printer->Print(
+ *vars,
+ "std::unique_ptr< ::grpc::ClientAsyncReaderInterface< $Response$>> "
+ "Async$Method$("
+ "::grpc::ClientContext* context, const $Request$& request, "
+ "::grpc::CompletionQueue* cq, void* tag) {\n");
+ printer->Indent();
+ printer->Print(*vars,
+ "return std::unique_ptr< "
+ "::grpc::ClientAsyncReaderInterface< $Response$>>("
+ "Async$Method$Raw(context, request, cq, tag));\n");
+ printer->Outdent();
+ printer->Print("}\n");
+ } else if (method->BidiStreaming()) {
+ printer->Print(*vars,
+ "std::unique_ptr< ::grpc::ClientReaderWriterInterface< "
+ "$Request$, $Response$>> "
+ "$Method$(::grpc::ClientContext* context) {\n");
+ printer->Indent();
+ printer->Print(
+ *vars,
+ "return std::unique_ptr< "
+ "::grpc::ClientReaderWriterInterface< $Request$, $Response$>>("
+ "$Method$Raw(context));\n");
+ printer->Outdent();
+ printer->Print("}\n");
+ printer->Print(
+ *vars,
+ "std::unique_ptr< "
+ "::grpc::ClientAsyncReaderWriterInterface< $Request$, $Response$>> "
+ "Async$Method$(::grpc::ClientContext* context, "
+ "::grpc::CompletionQueue* cq, void* tag) {\n");
+ printer->Indent();
+ printer->Print(
+ *vars,
+ "return std::unique_ptr< "
+ "::grpc::ClientAsyncReaderWriterInterface< $Request$, $Response$>>("
+ "Async$Method$Raw(context, cq, tag));\n");
+ printer->Outdent();
+ printer->Print("}\n");
+ }
+ } else {
+ if (method->NoStreaming()) {
+ printer->Print(
+ *vars,
+ "virtual ::grpc::ClientAsyncResponseReaderInterface< $Response$>* "
+ "Async$Method$Raw(::grpc::ClientContext* context, "
+ "const $Request$& request, "
+ "::grpc::CompletionQueue* cq) = 0;\n");
+ } else if (method->ClientOnlyStreaming()) {
+ printer->Print(
+ *vars,
+ "virtual ::grpc::ClientWriterInterface< $Request$>*"
+ " $Method$Raw("
+ "::grpc::ClientContext* context, $Response$* response) = 0;\n");
+ printer->Print(*vars,
+ "virtual ::grpc::ClientAsyncWriterInterface< $Request$>*"
+ " Async$Method$Raw(::grpc::ClientContext* context, "
+ "$Response$* response, "
+ "::grpc::CompletionQueue* cq, void* tag) = 0;\n");
+ } else if (method->ServerOnlyStreaming()) {
+ printer->Print(
+ *vars,
+ "virtual ::grpc::ClientReaderInterface< $Response$>* $Method$Raw("
+ "::grpc::ClientContext* context, const $Request$& request) = 0;\n");
+ printer->Print(
+ *vars,
+ "virtual ::grpc::ClientAsyncReaderInterface< $Response$>* "
+ "Async$Method$Raw("
+ "::grpc::ClientContext* context, const $Request$& request, "
+ "::grpc::CompletionQueue* cq, void* tag) = 0;\n");
+ } else if (method->BidiStreaming()) {
+ printer->Print(*vars,
+ "virtual ::grpc::ClientReaderWriterInterface< $Request$, "
+ "$Response$>* "
+ "$Method$Raw(::grpc::ClientContext* context) = 0;\n");
+ printer->Print(*vars,
+ "virtual ::grpc::ClientAsyncReaderWriterInterface< "
+ "$Request$, $Response$>* "
+ "Async$Method$Raw(::grpc::ClientContext* context, "
+ "::grpc::CompletionQueue* cq, void* tag) = 0;\n");
+ }
+ }
+}
+
+void PrintHeaderClientMethod(Printer *printer,
+ const Method *method,
+ std::map<grpc::string, grpc::string> *vars,
+ bool is_public) {
+ (*vars)["Method"] = method->name();
+ (*vars)["Request"] = method->input_type_name();
+ (*vars)["Response"] = method->output_type_name();
+ if (is_public) {
+ if (method->NoStreaming()) {
+ printer->Print(
+ *vars,
+ "::grpc::Status $Method$(::grpc::ClientContext* context, "
+ "const $Request$& request, $Response$* response) GRPC_OVERRIDE;\n");
+ printer->Print(
+ *vars,
+ "std::unique_ptr< ::grpc::ClientAsyncResponseReader< $Response$>> "
+ "Async$Method$(::grpc::ClientContext* context, "
+ "const $Request$& request, "
+ "::grpc::CompletionQueue* cq) {\n");
+ printer->Indent();
+ printer->Print(*vars,
+ "return std::unique_ptr< "
+ "::grpc::ClientAsyncResponseReader< $Response$>>("
+ "Async$Method$Raw(context, request, cq));\n");
+ printer->Outdent();
+ printer->Print("}\n");
+ } else if (method->ClientOnlyStreaming()) {
+ printer->Print(
+ *vars,
+ "std::unique_ptr< ::grpc::ClientWriter< $Request$>>"
+ " $Method$("
+ "::grpc::ClientContext* context, $Response$* response) {\n");
+ printer->Indent();
+ printer->Print(*vars,
+ "return std::unique_ptr< ::grpc::ClientWriter< $Request$>>"
+ "($Method$Raw(context, response));\n");
+ printer->Outdent();
+ printer->Print("}\n");
+ printer->Print(*vars,
+ "std::unique_ptr< ::grpc::ClientAsyncWriter< $Request$>>"
+ " Async$Method$(::grpc::ClientContext* context, "
+ "$Response$* response, "
+ "::grpc::CompletionQueue* cq, void* tag) {\n");
+ printer->Indent();
+ printer->Print(
+ *vars,
+ "return std::unique_ptr< ::grpc::ClientAsyncWriter< $Request$>>("
+ "Async$Method$Raw(context, response, cq, tag));\n");
+ printer->Outdent();
+ printer->Print("}\n");
+ } else if (method->ServerOnlyStreaming()) {
+ printer->Print(
+ *vars,
+ "std::unique_ptr< ::grpc::ClientReader< $Response$>>"
+ " $Method$(::grpc::ClientContext* context, const $Request$& request)"
+ " {\n");
+ printer->Indent();
+ printer->Print(
+ *vars,
+ "return std::unique_ptr< ::grpc::ClientReader< $Response$>>"
+ "($Method$Raw(context, request));\n");
+ printer->Outdent();
+ printer->Print("}\n");
+ printer->Print(
+ *vars,
+ "std::unique_ptr< ::grpc::ClientAsyncReader< $Response$>> "
+ "Async$Method$("
+ "::grpc::ClientContext* context, const $Request$& request, "
+ "::grpc::CompletionQueue* cq, void* tag) {\n");
+ printer->Indent();
+ printer->Print(
+ *vars,
+ "return std::unique_ptr< ::grpc::ClientAsyncReader< $Response$>>("
+ "Async$Method$Raw(context, request, cq, tag));\n");
+ printer->Outdent();
+ printer->Print("}\n");
+ } else if (method->BidiStreaming()) {
+ printer->Print(
+ *vars,
+ "std::unique_ptr< ::grpc::ClientReaderWriter< $Request$, $Response$>>"
+ " $Method$(::grpc::ClientContext* context) {\n");
+ printer->Indent();
+ printer->Print(*vars,
+ "return std::unique_ptr< "
+ "::grpc::ClientReaderWriter< $Request$, $Response$>>("
+ "$Method$Raw(context));\n");
+ printer->Outdent();
+ printer->Print("}\n");
+ printer->Print(*vars,
+ "std::unique_ptr< ::grpc::ClientAsyncReaderWriter< "
+ "$Request$, $Response$>> "
+ "Async$Method$(::grpc::ClientContext* context, "
+ "::grpc::CompletionQueue* cq, void* tag) {\n");
+ printer->Indent();
+ printer->Print(*vars,
+ "return std::unique_ptr< "
+ "::grpc::ClientAsyncReaderWriter< $Request$, $Response$>>("
+ "Async$Method$Raw(context, cq, tag));\n");
+ printer->Outdent();
+ printer->Print("}\n");
+ }
+ } else {
+ if (method->NoStreaming()) {
+ printer->Print(*vars,
+ "::grpc::ClientAsyncResponseReader< $Response$>* "
+ "Async$Method$Raw(::grpc::ClientContext* context, "
+ "const $Request$& request, "
+ "::grpc::CompletionQueue* cq) GRPC_OVERRIDE;\n");
+ } else if (method->ClientOnlyStreaming()) {
+ printer->Print(*vars,
+ "::grpc::ClientWriter< $Request$>* $Method$Raw("
+ "::grpc::ClientContext* context, $Response$* response) "
+ "GRPC_OVERRIDE;\n");
+ printer->Print(
+ *vars,
+ "::grpc::ClientAsyncWriter< $Request$>* Async$Method$Raw("
+ "::grpc::ClientContext* context, $Response$* response, "
+ "::grpc::CompletionQueue* cq, void* tag) GRPC_OVERRIDE;\n");
+ } else if (method->ServerOnlyStreaming()) {
+ printer->Print(*vars,
+ "::grpc::ClientReader< $Response$>* $Method$Raw("
+ "::grpc::ClientContext* context, const $Request$& request)"
+ " GRPC_OVERRIDE;\n");
+ printer->Print(
+ *vars,
+ "::grpc::ClientAsyncReader< $Response$>* Async$Method$Raw("
+ "::grpc::ClientContext* context, const $Request$& request, "
+ "::grpc::CompletionQueue* cq, void* tag) GRPC_OVERRIDE;\n");
+ } else if (method->BidiStreaming()) {
+ printer->Print(
+ *vars,
+ "::grpc::ClientReaderWriter< $Request$, $Response$>* "
+ "$Method$Raw(::grpc::ClientContext* context) GRPC_OVERRIDE;\n");
+ printer->Print(
+ *vars,
+ "::grpc::ClientAsyncReaderWriter< $Request$, $Response$>* "
+ "Async$Method$Raw(::grpc::ClientContext* context, "
+ "::grpc::CompletionQueue* cq, void* tag) GRPC_OVERRIDE;\n");
+ }
+ }
+}
+
+void PrintHeaderClientMethodData(Printer *printer, const Method *method,
+ std::map<grpc::string, grpc::string> *vars) {
+ (*vars)["Method"] = method->name();
+ printer->Print(*vars, "const ::grpc::RpcMethod rpcmethod_$Method$_;\n");
+}
+
+void PrintHeaderServerMethodSync(Printer *printer, const Method *method,
+ std::map<grpc::string, grpc::string> *vars) {
+ (*vars)["Method"] = method->name();
+ (*vars)["Request"] = method->input_type_name();
+ (*vars)["Response"] = method->output_type_name();
+ if (method->NoStreaming()) {
+ printer->Print(*vars,
+ "virtual ::grpc::Status $Method$("
+ "::grpc::ServerContext* context, const $Request$* request, "
+ "$Response$* response);\n");
+ } else if (method->ClientOnlyStreaming()) {
+ printer->Print(*vars,
+ "virtual ::grpc::Status $Method$("
+ "::grpc::ServerContext* context, "
+ "::grpc::ServerReader< $Request$>* reader, "
+ "$Response$* response);\n");
+ } else if (method->ServerOnlyStreaming()) {
+ printer->Print(*vars,
+ "virtual ::grpc::Status $Method$("
+ "::grpc::ServerContext* context, const $Request$* request, "
+ "::grpc::ServerWriter< $Response$>* writer);\n");
+ } else if (method->BidiStreaming()) {
+ printer->Print(
+ *vars,
+ "virtual ::grpc::Status $Method$("
+ "::grpc::ServerContext* context, "
+ "::grpc::ServerReaderWriter< $Response$, $Request$>* stream);"
+ "\n");
+ }
+}
+
+void PrintHeaderServerMethodAsync(
+ Printer *printer,
+ const Method *method,
+ std::map<grpc::string, grpc::string> *vars) {
+ (*vars)["Method"] = method->name();
+ (*vars)["Request"] = method->input_type_name();
+ (*vars)["Response"] = method->output_type_name();
+ printer->Print(*vars, "template <class BaseClass>\n");
+ printer->Print(*vars,
+ "class WithAsyncMethod_$Method$ : public BaseClass {\n");
+ printer->Print(
+ " private:\n"
+ " void BaseClassMustBeDerivedFromService(const Service *service) {}\n");
+ printer->Print(" public:\n");
+ printer->Indent();
+ printer->Print(*vars,
+ "WithAsyncMethod_$Method$() {\n"
+ " ::grpc::Service::MarkMethodAsync($Idx$);\n"
+ "}\n");
+ printer->Print(*vars,
+ "~WithAsyncMethod_$Method$() GRPC_OVERRIDE {\n"
+ " BaseClassMustBeDerivedFromService(this);\n"
+ "}\n");
+ if (method->NoStreaming()) {
+ printer->Print(
+ *vars,
+ "// disable synchronous version of this method\n"
+ "::grpc::Status $Method$("
+ "::grpc::ServerContext* context, const $Request$* request, "
+ "$Response$* response) GRPC_FINAL GRPC_OVERRIDE {\n"
+ " abort();\n"
+ " return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, \"\");\n"
+ "}\n");
+ printer->Print(
+ *vars,
+ "void Request$Method$("
+ "::grpc::ServerContext* context, $Request$* request, "
+ "::grpc::ServerAsyncResponseWriter< $Response$>* response, "
+ "::grpc::CompletionQueue* new_call_cq, "
+ "::grpc::ServerCompletionQueue* notification_cq, void *tag) {\n");
+ printer->Print(*vars,
+ " ::grpc::Service::RequestAsyncUnary($Idx$, context, "
+ "request, response, new_call_cq, notification_cq, tag);\n");
+ printer->Print("}\n");
+ } else if (method->ClientOnlyStreaming()) {
+ printer->Print(
+ *vars,
+ "// disable synchronous version of this method\n"
+ "::grpc::Status $Method$("
+ "::grpc::ServerContext* context, "
+ "::grpc::ServerReader< $Request$>* reader, "
+ "$Response$* response) GRPC_FINAL GRPC_OVERRIDE {\n"
+ " abort();\n"
+ " return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, \"\");\n"
+ "}\n");
+ printer->Print(
+ *vars,
+ "void Request$Method$("
+ "::grpc::ServerContext* context, "
+ "::grpc::ServerAsyncReader< $Response$, $Request$>* reader, "
+ "::grpc::CompletionQueue* new_call_cq, "
+ "::grpc::ServerCompletionQueue* notification_cq, void *tag) {\n");
+ printer->Print(*vars,
+ " ::grpc::Service::RequestAsyncClientStreaming($Idx$, "
+ "context, reader, new_call_cq, notification_cq, tag);\n");
+ printer->Print("}\n");
+ } else if (method->ServerOnlyStreaming()) {
+ printer->Print(
+ *vars,
+ "// disable synchronous version of this method\n"
+ "::grpc::Status $Method$("
+ "::grpc::ServerContext* context, const $Request$* request, "
+ "::grpc::ServerWriter< $Response$>* writer) GRPC_FINAL GRPC_OVERRIDE "
+ "{\n"
+ " abort();\n"
+ " return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, \"\");\n"
+ "}\n");
+ printer->Print(
+ *vars,
+ "void Request$Method$("
+ "::grpc::ServerContext* context, $Request$* request, "
+ "::grpc::ServerAsyncWriter< $Response$>* writer, "
+ "::grpc::CompletionQueue* new_call_cq, "
+ "::grpc::ServerCompletionQueue* notification_cq, void *tag) {\n");
+ printer->Print(
+ *vars,
+ " ::grpc::Service::RequestAsyncServerStreaming($Idx$, "
+ "context, request, writer, new_call_cq, notification_cq, tag);\n");
+ printer->Print("}\n");
+ } else if (method->BidiStreaming()) {
+ printer->Print(
+ *vars,
+ "// disable synchronous version of this method\n"
+ "::grpc::Status $Method$("
+ "::grpc::ServerContext* context, "
+ "::grpc::ServerReaderWriter< $Response$, $Request$>* stream) "
+ "GRPC_FINAL GRPC_OVERRIDE {\n"
+ " abort();\n"
+ " return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, \"\");\n"
+ "}\n");
+ printer->Print(
+ *vars,
+ "void Request$Method$("
+ "::grpc::ServerContext* context, "
+ "::grpc::ServerAsyncReaderWriter< $Response$, $Request$>* stream, "
+ "::grpc::CompletionQueue* new_call_cq, "
+ "::grpc::ServerCompletionQueue* notification_cq, void *tag) {\n");
+ printer->Print(*vars,
+ " ::grpc::Service::RequestAsyncBidiStreaming($Idx$, "
+ "context, stream, new_call_cq, notification_cq, tag);\n");
+ printer->Print("}\n");
+ }
+ printer->Outdent();
+ printer->Print(*vars, "};\n");
+}
+
+void PrintHeaderServerMethodGeneric(
+ Printer *printer,
+ const Method *method,
+ std::map<grpc::string, grpc::string> *vars) {
+ (*vars)["Method"] = method->name();
+ (*vars)["Request"] = method->input_type_name();
+ (*vars)["Response"] = method->output_type_name();
+ printer->Print(*vars, "template <class BaseClass>\n");
+ printer->Print(*vars,
+ "class WithGenericMethod_$Method$ : public BaseClass {\n");
+ printer->Print(
+ " private:\n"
+ " void BaseClassMustBeDerivedFromService(const Service *service) {}\n");
+ printer->Print(" public:\n");
+ printer->Indent();
+ printer->Print(*vars,
+ "WithGenericMethod_$Method$() {\n"
+ " ::grpc::Service::MarkMethodGeneric($Idx$);\n"
+ "}\n");
+ printer->Print(*vars,
+ "~WithGenericMethod_$Method$() GRPC_OVERRIDE {\n"
+ " BaseClassMustBeDerivedFromService(this);\n"
+ "}\n");
+ if (method->NoStreaming()) {
+ printer->Print(
+ *vars,
+ "// disable synchronous version of this method\n"
+ "::grpc::Status $Method$("
+ "::grpc::ServerContext* context, const $Request$* request, "
+ "$Response$* response) GRPC_FINAL GRPC_OVERRIDE {\n"
+ " abort();\n"
+ " return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, \"\");\n"
+ "}\n");
+ } else if (method->ClientOnlyStreaming()) {
+ printer->Print(
+ *vars,
+ "// disable synchronous version of this method\n"
+ "::grpc::Status $Method$("
+ "::grpc::ServerContext* context, "
+ "::grpc::ServerReader< $Request$>* reader, "
+ "$Response$* response) GRPC_FINAL GRPC_OVERRIDE {\n"
+ " abort();\n"
+ " return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, \"\");\n"
+ "}\n");
+ } else if (method->ServerOnlyStreaming()) {
+ printer->Print(
+ *vars,
+ "// disable synchronous version of this method\n"
+ "::grpc::Status $Method$("
+ "::grpc::ServerContext* context, const $Request$* request, "
+ "::grpc::ServerWriter< $Response$>* writer) GRPC_FINAL GRPC_OVERRIDE "
+ "{\n"
+ " abort();\n"
+ " return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, \"\");\n"
+ "}\n");
+ } else if (method->BidiStreaming()) {
+ printer->Print(
+ *vars,
+ "// disable synchronous version of this method\n"
+ "::grpc::Status $Method$("
+ "::grpc::ServerContext* context, "
+ "::grpc::ServerReaderWriter< $Response$, $Request$>* stream) "
+ "GRPC_FINAL GRPC_OVERRIDE {\n"
+ " abort();\n"
+ " return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, \"\");\n"
+ "}\n");
+ }
+ printer->Outdent();
+ printer->Print(*vars, "};\n");
+}
+
+void PrintHeaderService(Printer *printer,
+ const Service *service,
+ std::map<grpc::string, grpc::string> *vars) {
+ (*vars)["Service"] = service->name();
+
+ printer->Print(*vars,
+ "class $Service$ GRPC_FINAL {\n"
+ " public:\n");
+ printer->Indent();
+
+ // Client side
+ printer->Print(
+ "class StubInterface {\n"
+ " public:\n");
+ printer->Indent();
+ printer->Print("virtual ~StubInterface() {}\n");
+ for (int i = 0; i < service->method_count(); ++i) {
+ PrintHeaderClientMethodInterfaces(printer, service->method(i).get(), vars, true);
+ }
+ printer->Outdent();
+ printer->Print("private:\n");
+ printer->Indent();
+ for (int i = 0; i < service->method_count(); ++i) {
+ PrintHeaderClientMethodInterfaces(printer, service->method(i).get(), vars, false);
+ }
+ printer->Outdent();
+ printer->Print("};\n");
+ printer->Print(
+ "class Stub GRPC_FINAL : public StubInterface"
+ " {\n public:\n");
+ printer->Indent();
+ printer->Print("Stub(const std::shared_ptr< ::grpc::ChannelInterface>& channel);\n");
+ for (int i = 0; i < service->method_count(); ++i) {
+ PrintHeaderClientMethod(printer, service->method(i).get(), vars, true);
+ }
+ printer->Outdent();
+ printer->Print("\n private:\n");
+ printer->Indent();
+ printer->Print("std::shared_ptr< ::grpc::ChannelInterface> channel_;\n");
+ for (int i = 0; i < service->method_count(); ++i) {
+ PrintHeaderClientMethod(printer, service->method(i).get(), vars, false);
+ }
+ for (int i = 0; i < service->method_count(); ++i) {
+ PrintHeaderClientMethodData(printer, service->method(i).get(), vars);
+ }
+ printer->Outdent();
+ printer->Print("};\n");
+ printer->Print(
+ "static std::unique_ptr<Stub> NewStub(const std::shared_ptr< "
+ "::grpc::ChannelInterface>& channel, "
+ "const ::grpc::StubOptions& options = ::grpc::StubOptions());\n");
+
+ printer->Print("\n");
+
+ // Server side - base
+ printer->Print(
+ "class Service : public ::grpc::Service {\n"
+ " public:\n");
+ printer->Indent();
+ printer->Print("Service();\n");
+ printer->Print("virtual ~Service();\n");
+ for (int i = 0; i < service->method_count(); ++i) {
+ PrintHeaderServerMethodSync(printer, service->method(i).get(), vars);
+ }
+ printer->Outdent();
+ printer->Print("};\n");
+
+ // Server side - Asynchronous
+ for (int i = 0; i < service->method_count(); ++i) {
+ (*vars)["Idx"] = as_string(i);
+ PrintHeaderServerMethodAsync(printer, service->method(i).get(), vars);
+ }
+
+ printer->Print("typedef ");
+
+ for (int i = 0; i < service->method_count(); ++i) {
+ (*vars)["method_name"] = service->method(i).get()->name();
+ printer->Print(*vars, "WithAsyncMethod_$method_name$<");
+ }
+ printer->Print("Service");
+ for (int i = 0; i < service->method_count(); ++i) {
+ printer->Print(" >");
+ }
+ printer->Print(" AsyncService;\n");
+
+ // Server side - Generic
+ for (int i = 0; i < service->method_count(); ++i) {
+ (*vars)["Idx"] = as_string(i);
+ PrintHeaderServerMethodGeneric(printer, service->method(i).get(), vars);
+ }
+
+ printer->Outdent();
+ printer->Print("};\n");
+}
+
+grpc::string GetHeaderServices(File *file,
+ const Parameters &params) {
+ grpc::string output;
+ {
+ // Scope the output stream so it closes and finalizes output to the string.
+ auto printer = file->CreatePrinter(&output);
+ std::map<grpc::string, grpc::string> vars;
+ // Package string is empty or ends with a dot. It is used to fully qualify
+ // method names.
+ vars["Package"] = file->package();
+ if (!file->package().empty()) {
+ vars["Package"].append(".");
+ }
+
+ if (!params.services_namespace.empty()) {
+ vars["services_namespace"] = params.services_namespace;
+ printer->Print(vars, "\nnamespace $services_namespace$ {\n\n");
+ }
+
+ for (int i = 0; i < file->service_count(); ++i) {
+ PrintHeaderService(printer.get(), file->service(i).get(), &vars);
+ printer->Print("\n");
+ }
+
+ if (!params.services_namespace.empty()) {
+ printer->Print(vars, "} // namespace $services_namespace$\n\n");
+ }
+ }
+ return output;
+}
+
+grpc::string GetHeaderEpilogue(File *file, const Parameters & /*params*/) {
+ grpc::string output;
+ {
+ // Scope the output stream so it closes and finalizes output to the string.
+ auto printer = file->CreatePrinter(&output);
+ std::map<grpc::string, grpc::string> vars;
+
+ vars["filename"] = file->filename();
+ vars["filename_identifier"] = FilenameIdentifier(file->filename());
+
+ if (!file->package().empty()) {
+ std::vector<grpc::string> parts = file->package_parts();
+
+ for (auto part = parts.rbegin(); part != parts.rend(); part++) {
+ vars["part"] = *part;
+ printer->Print(vars, "} // namespace $part$\n");
+ }
+ printer->Print(vars, "\n");
+ }
+
+ printer->Print(vars, "\n");
+ printer->Print(vars, "#endif // GRPC_$filename_identifier$__INCLUDED\n");
+ }
+ return output;
+}
+
+grpc::string GetSourcePrologue(File *file, const Parameters & /*params*/) {
+ grpc::string output;
+ {
+ // Scope the output stream so it closes and finalizes output to the string.
+ auto printer = file->CreatePrinter(&output);
+ std::map<grpc::string, grpc::string> vars;
+
+ vars["filename"] = file->filename();
+ vars["filename_base"] = file->filename_without_ext();
+ vars["message_header_ext"] = file->message_header_ext();
+ vars["service_header_ext"] = file->service_header_ext();
+
+ printer->Print(vars, "// Generated by the gRPC protobuf plugin.\n");
+ printer->Print(vars,
+ "// If you make any local change, they will be lost.\n");
+ printer->Print(vars, "// source: $filename$\n\n");
+ printer->Print(vars, "#include \"$filename_base$$message_header_ext$\"\n");
+ printer->Print(vars, "#include \"$filename_base$$service_header_ext$\"\n");
+ printer->Print(vars, file->additional_headers().c_str());
+ printer->Print(vars, "\n");
+ }
+ return output;
+}
+
+grpc::string GetSourceIncludes(File *file,
+ const Parameters &params) {
+ grpc::string output;
+ {
+ // Scope the output stream so it closes and finalizes output to the string.
+ auto printer = file->CreatePrinter(&output);
+ std::map<grpc::string, grpc::string> vars;
+
+ static const char *headers_strs[] = {
+ "grpc++/impl/codegen/async_stream.h",
+ "grpc++/impl/codegen/async_unary_call.h",
+ "grpc++/impl/codegen/channel_interface.h",
+ "grpc++/impl/codegen/client_unary_call.h",
+ "grpc++/impl/codegen/method_handler_impl.h",
+ "grpc++/impl/codegen/rpc_service_method.h",
+ "grpc++/impl/codegen/service_type.h",
+ "grpc++/impl/codegen/sync_stream.h"
+ };
+ std::vector<grpc::string> headers(headers_strs, array_end(headers_strs));
+ PrintIncludes(printer.get(), headers, params);
+
+ if (!file->package().empty()) {
+ std::vector<grpc::string> parts = file->package_parts();
+
+ for (auto part = parts.begin(); part != parts.end(); part++) {
+ vars["part"] = *part;
+ printer->Print(vars, "namespace $part$ {\n");
+ }
+ }
+
+ printer->Print(vars, "\n");
+ }
+ return output;
+}
+
+void PrintSourceClientMethod(Printer *printer,
+ const Method *method,
+ std::map<grpc::string, grpc::string> *vars) {
+ (*vars)["Method"] = method->name();
+ (*vars)["Request"] = method->input_type_name();
+ (*vars)["Response"] = method->output_type_name();
+ if (method->NoStreaming()) {
+ printer->Print(*vars,
+ "::grpc::Status $ns$$Service$::Stub::$Method$("
+ "::grpc::ClientContext* context, "
+ "const $Request$& request, $Response$* response) {\n");
+ printer->Print(*vars,
+ " return ::grpc::BlockingUnaryCall(channel_.get(), "
+ "rpcmethod_$Method$_, "
+ "context, request, response);\n"
+ "}\n\n");
+ printer->Print(
+ *vars,
+ "::grpc::ClientAsyncResponseReader< $Response$>* "
+ "$ns$$Service$::Stub::Async$Method$Raw(::grpc::ClientContext* context, "
+ "const $Request$& request, "
+ "::grpc::CompletionQueue* cq) {\n");
+ printer->Print(*vars,
+ " return new "
+ "::grpc::ClientAsyncResponseReader< $Response$>("
+ "channel_.get(), cq, "
+ "rpcmethod_$Method$_, "
+ "context, request);\n"
+ "}\n\n");
+ } else if (method->ClientOnlyStreaming()) {
+ printer->Print(*vars,
+ "::grpc::ClientWriter< $Request$>* "
+ "$ns$$Service$::Stub::$Method$Raw("
+ "::grpc::ClientContext* context, $Response$* response) {\n");
+ printer->Print(*vars,
+ " return new ::grpc::ClientWriter< $Request$>("
+ "channel_.get(), "
+ "rpcmethod_$Method$_, "
+ "context, response);\n"
+ "}\n\n");
+ printer->Print(*vars,
+ "::grpc::ClientAsyncWriter< $Request$>* "
+ "$ns$$Service$::Stub::Async$Method$Raw("
+ "::grpc::ClientContext* context, $Response$* response, "
+ "::grpc::CompletionQueue* cq, void* tag) {\n");
+ printer->Print(*vars,
+ " return new ::grpc::ClientAsyncWriter< $Request$>("
+ "channel_.get(), cq, "
+ "rpcmethod_$Method$_, "
+ "context, response, tag);\n"
+ "}\n\n");
+ } else if (method->ServerOnlyStreaming()) {
+ printer->Print(
+ *vars,
+ "::grpc::ClientReader< $Response$>* "
+ "$ns$$Service$::Stub::$Method$Raw("
+ "::grpc::ClientContext* context, const $Request$& request) {\n");
+ printer->Print(*vars,
+ " return new ::grpc::ClientReader< $Response$>("
+ "channel_.get(), "
+ "rpcmethod_$Method$_, "
+ "context, request);\n"
+ "}\n\n");
+ printer->Print(*vars,
+ "::grpc::ClientAsyncReader< $Response$>* "
+ "$ns$$Service$::Stub::Async$Method$Raw("
+ "::grpc::ClientContext* context, const $Request$& request, "
+ "::grpc::CompletionQueue* cq, void* tag) {\n");
+ printer->Print(*vars,
+ " return new ::grpc::ClientAsyncReader< $Response$>("
+ "channel_.get(), cq, "
+ "rpcmethod_$Method$_, "
+ "context, request, tag);\n"
+ "}\n\n");
+ } else if (method->BidiStreaming()) {
+ printer->Print(
+ *vars,
+ "::grpc::ClientReaderWriter< $Request$, $Response$>* "
+ "$ns$$Service$::Stub::$Method$Raw(::grpc::ClientContext* context) {\n");
+ printer->Print(*vars,
+ " return new ::grpc::ClientReaderWriter< "
+ "$Request$, $Response$>("
+ "channel_.get(), "
+ "rpcmethod_$Method$_, "
+ "context);\n"
+ "}\n\n");
+ printer->Print(
+ *vars,
+ "::grpc::ClientAsyncReaderWriter< $Request$, $Response$>* "
+ "$ns$$Service$::Stub::Async$Method$Raw(::grpc::ClientContext* context, "
+ "::grpc::CompletionQueue* cq, void* tag) {\n");
+ printer->Print(*vars,
+ " return new "
+ "::grpc::ClientAsyncReaderWriter< $Request$, $Response$>("
+ "channel_.get(), cq, "
+ "rpcmethod_$Method$_, "
+ "context, tag);\n"
+ "}\n\n");
+ }
+}
+
+void PrintSourceServerMethod(Printer *printer,
+ const Method *method,
+ std::map<grpc::string, grpc::string> *vars) {
+ (*vars)["Method"] = method->name();
+ (*vars)["Request"] = method->input_type_name();
+ (*vars)["Response"] = method->output_type_name();
+ if (method->NoStreaming()) {
+ printer->Print(*vars,
+ "::grpc::Status $ns$$Service$::Service::$Method$("
+ "::grpc::ServerContext* context, "
+ "const $Request$* request, $Response$* response) {\n");
+ printer->Print(" (void) context;\n");
+ printer->Print(" (void) request;\n");
+ printer->Print(" (void) response;\n");
+ printer->Print(
+ " return ::grpc::Status("
+ "::grpc::StatusCode::UNIMPLEMENTED, \"\");\n");
+ printer->Print("}\n\n");
+ } else if (method->ClientOnlyStreaming()) {
+ printer->Print(*vars,
+ "::grpc::Status $ns$$Service$::Service::$Method$("
+ "::grpc::ServerContext* context, "
+ "::grpc::ServerReader< $Request$>* reader, "
+ "$Response$* response) {\n");
+ printer->Print(" (void) context;\n");
+ printer->Print(" (void) reader;\n");
+ printer->Print(" (void) response;\n");
+ printer->Print(
+ " return ::grpc::Status("
+ "::grpc::StatusCode::UNIMPLEMENTED, \"\");\n");
+ printer->Print("}\n\n");
+ } else if (method->ServerOnlyStreaming()) {
+ printer->Print(*vars,
+ "::grpc::Status $ns$$Service$::Service::$Method$("
+ "::grpc::ServerContext* context, "
+ "const $Request$* request, "
+ "::grpc::ServerWriter< $Response$>* writer) {\n");
+ printer->Print(" (void) context;\n");
+ printer->Print(" (void) request;\n");
+ printer->Print(" (void) writer;\n");
+ printer->Print(
+ " return ::grpc::Status("
+ "::grpc::StatusCode::UNIMPLEMENTED, \"\");\n");
+ printer->Print("}\n\n");
+ } else if (method->BidiStreaming()) {
+ printer->Print(*vars,
+ "::grpc::Status $ns$$Service$::Service::$Method$("
+ "::grpc::ServerContext* context, "
+ "::grpc::ServerReaderWriter< $Response$, $Request$>* "
+ "stream) {\n");
+ printer->Print(" (void) context;\n");
+ printer->Print(" (void) stream;\n");
+ printer->Print(
+ " return ::grpc::Status("
+ "::grpc::StatusCode::UNIMPLEMENTED, \"\");\n");
+ printer->Print("}\n\n");
+ }
+}
+
+void PrintSourceService(Printer *printer,
+ const Service *service,
+ std::map<grpc::string, grpc::string> *vars) {
+ (*vars)["Service"] = service->name();
+
+ printer->Print(*vars,
+ "static const char* $prefix$$Service$_method_names[] = {\n");
+ for (int i = 0; i < service->method_count(); ++i) {
+ (*vars)["Method"] = service->method(i).get()->name();
+ printer->Print(*vars, " \"/$Package$$Service$/$Method$\",\n");
+ }
+ printer->Print(*vars, "};\n\n");
+
+ printer->Print(*vars,
+ "std::unique_ptr< $ns$$Service$::Stub> $ns$$Service$::NewStub("
+ "const std::shared_ptr< ::grpc::ChannelInterface>& channel, "
+ "const ::grpc::StubOptions& options) {\n"
+ " std::unique_ptr< $ns$$Service$::Stub> stub(new "
+ "$ns$$Service$::Stub(channel));\n"
+ " return stub;\n"
+ "}\n\n");
+ printer->Print(*vars,
+ "$ns$$Service$::Stub::Stub(const std::shared_ptr< "
+ "::grpc::ChannelInterface>& channel)\n");
+ printer->Indent();
+ printer->Print(": channel_(channel)");
+ for (int i = 0; i < service->method_count(); ++i) {
+ auto method = service->method(i);
+ (*vars)["Method"] = method->name();
+ (*vars)["Idx"] = as_string(i);
+ if (method->NoStreaming()) {
+ (*vars)["StreamingType"] = "NORMAL_RPC";
+ } else if (method->ClientOnlyStreaming()) {
+ (*vars)["StreamingType"] = "CLIENT_STREAMING";
+ } else if (method->ServerOnlyStreaming()) {
+ (*vars)["StreamingType"] = "SERVER_STREAMING";
+ } else {
+ (*vars)["StreamingType"] = "BIDI_STREAMING";
+ }
+ printer->Print(*vars,
+ ", rpcmethod_$Method$_("
+ "$prefix$$Service$_method_names[$Idx$], "
+ "::grpc::RpcMethod::$StreamingType$, "
+ "channel"
+ ")\n");
+ }
+ printer->Print("{}\n\n");
+ printer->Outdent();
+
+ for (int i = 0; i < service->method_count(); ++i) {
+ (*vars)["Idx"] = as_string(i);
+ PrintSourceClientMethod(printer, service->method(i).get(), vars);
+ }
+
+ printer->Print(*vars, "$ns$$Service$::Service::Service() {\n");
+ printer->Indent();
+ printer->Print(*vars, "(void)$prefix$$Service$_method_names;\n");
+ for (int i = 0; i < service->method_count(); ++i) {
+ auto method = service->method(i);
+ (*vars)["Idx"] = as_string(i);
+ (*vars)["Method"] = method->name();
+ (*vars)["Request"] = method->input_type_name();
+ (*vars)["Response"] = method->output_type_name();
+ if (method->NoStreaming()) {
+ printer->Print(
+ *vars,
+ "AddMethod(new ::grpc::RpcServiceMethod(\n"
+ " $prefix$$Service$_method_names[$Idx$],\n"
+ " ::grpc::RpcMethod::NORMAL_RPC,\n"
+ " new ::grpc::RpcMethodHandler< $ns$$Service$::Service, "
+ "$Request$, "
+ "$Response$>(\n"
+ " std::mem_fn(&$ns$$Service$::Service::$Method$), this)));\n");
+ } else if (method->ClientOnlyStreaming()) {
+ printer->Print(
+ *vars,
+ "AddMethod(new ::grpc::RpcServiceMethod(\n"
+ " $prefix$$Service$_method_names[$Idx$],\n"
+ " ::grpc::RpcMethod::CLIENT_STREAMING,\n"
+ " new ::grpc::ClientStreamingHandler< "
+ "$ns$$Service$::Service, $Request$, $Response$>(\n"
+ " std::mem_fn(&$ns$$Service$::Service::$Method$), this)));\n");
+ } else if (method->ServerOnlyStreaming()) {
+ printer->Print(
+ *vars,
+ "AddMethod(new ::grpc::RpcServiceMethod(\n"
+ " $prefix$$Service$_method_names[$Idx$],\n"
+ " ::grpc::RpcMethod::SERVER_STREAMING,\n"
+ " new ::grpc::ServerStreamingHandler< "
+ "$ns$$Service$::Service, $Request$, $Response$>(\n"
+ " std::mem_fn(&$ns$$Service$::Service::$Method$), this)));\n");
+ } else if (method->BidiStreaming()) {
+ printer->Print(
+ *vars,
+ "AddMethod(new ::grpc::RpcServiceMethod(\n"
+ " $prefix$$Service$_method_names[$Idx$],\n"
+ " ::grpc::RpcMethod::BIDI_STREAMING,\n"
+ " new ::grpc::BidiStreamingHandler< "
+ "$ns$$Service$::Service, $Request$, $Response$>(\n"
+ " std::mem_fn(&$ns$$Service$::Service::$Method$), this)));\n");
+ }
+ }
+ printer->Outdent();
+ printer->Print(*vars, "}\n\n");
+ printer->Print(*vars,
+ "$ns$$Service$::Service::~Service() {\n"
+ "}\n\n");
+ for (int i = 0; i < service->method_count(); ++i) {
+ (*vars)["Idx"] = as_string(i);
+ PrintSourceServerMethod(printer, service->method(i).get(), vars);
+ }
+}
+
+grpc::string GetSourceServices(File *file,
+ const Parameters &params) {
+ grpc::string output;
+ {
+ // Scope the output stream so it closes and finalizes output to the string.
+ auto printer = file->CreatePrinter(&output);
+ std::map<grpc::string, grpc::string> vars;
+ // Package string is empty or ends with a dot. It is used to fully qualify
+ // method names.
+ vars["Package"] = file->package();
+ if (!file->package().empty()) {
+ vars["Package"].append(".");
+ }
+ if (!params.services_namespace.empty()) {
+ vars["ns"] = params.services_namespace + "::";
+ vars["prefix"] = params.services_namespace;
+ } else {
+ vars["ns"] = "";
+ vars["prefix"] = "";
+ }
+
+ for (int i = 0; i < file->service_count(); ++i) {
+ PrintSourceService(printer.get(), file->service(i).get(), &vars);
+ printer->Print("\n");
+ }
+ }
+ return output;
+}
+
+grpc::string GetSourceEpilogue(File *file, const Parameters & /*params*/) {
+ grpc::string temp;
+
+ if (!file->package().empty()) {
+ std::vector<grpc::string> parts = file->package_parts();
+
+ for (auto part = parts.begin(); part != parts.end(); part++) {
+ temp.append("} // namespace ");
+ temp.append(*part);
+ temp.append("\n");
+ }
+ temp.append("\n");
+ }
+
+ return temp;
+}
+
+} // namespace grpc_cpp_generator
diff --git a/grpc/src/compiler/cpp_generator.h b/grpc/src/compiler/cpp_generator.h
new file mode 100644
index 00000000..953ddfd5
--- /dev/null
+++ b/grpc/src/compiler/cpp_generator.h
@@ -0,0 +1,147 @@
+/*
+ *
+ * Copyright 2015, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_INTERNAL_COMPILER_CPP_GENERATOR_H
+#define GRPC_INTERNAL_COMPILER_CPP_GENERATOR_H
+
+// cpp_generator.h/.cc do not directly depend on GRPC/ProtoBuf, such that they
+// can be used to generate code for other serialization systems, such as
+// FlatBuffers.
+
+#include <memory>
+#include <vector>
+
+#ifndef GRPC_CUSTOM_STRING
+#include <string>
+#define GRPC_CUSTOM_STRING std::string
+#endif
+
+namespace grpc {
+
+typedef GRPC_CUSTOM_STRING string;
+
+} // namespace grpc
+
+namespace grpc_cpp_generator {
+
+// Contains all the parameters that are parsed from the command line.
+struct Parameters {
+ // Puts the service into a namespace
+ grpc::string services_namespace;
+ // Use system includes (<>) or local includes ("")
+ bool use_system_headers;
+ // Prefix to any grpc include
+ grpc::string grpc_search_path;
+};
+
+// An abstract interface representing a method.
+struct Method {
+ virtual ~Method() {}
+
+ virtual grpc::string name() const = 0;
+
+ virtual grpc::string input_type_name() const = 0;
+ virtual grpc::string output_type_name() const = 0;
+
+ virtual bool NoStreaming() const = 0;
+ virtual bool ClientOnlyStreaming() const = 0;
+ virtual bool ServerOnlyStreaming() const = 0;
+ virtual bool BidiStreaming() const = 0;
+};
+
+// An abstract interface representing a service.
+struct Service {
+ virtual ~Service() {}
+
+ virtual grpc::string name() const = 0;
+
+ virtual int method_count() const = 0;
+ virtual std::unique_ptr<const Method> method(int i) const = 0;
+};
+
+struct Printer {
+ virtual ~Printer() {}
+
+ virtual void Print(const std::map<grpc::string, grpc::string> &vars,
+ const char *template_string) = 0;
+ virtual void Print(const char *string) = 0;
+ virtual void Indent() = 0;
+ virtual void Outdent() = 0;
+};
+
+// An interface that allows the source generated to be output using various
+// libraries/idls/serializers.
+struct File {
+ virtual ~File() {}
+
+ virtual grpc::string filename() const = 0;
+ virtual grpc::string filename_without_ext() const = 0;
+ virtual grpc::string message_header_ext() const = 0;
+ virtual grpc::string service_header_ext() const = 0;
+ virtual grpc::string package() const = 0;
+ virtual std::vector<grpc::string> package_parts() const = 0;
+ virtual grpc::string additional_headers() const = 0;
+
+ virtual int service_count() const = 0;
+ virtual std::unique_ptr<const Service> service(int i) const = 0;
+
+ virtual std::unique_ptr<Printer> CreatePrinter(grpc::string *str) const = 0;
+};
+
+// Return the prologue of the generated header file.
+grpc::string GetHeaderPrologue(File *file, const Parameters &params);
+
+// Return the includes needed for generated header file.
+grpc::string GetHeaderIncludes(File *file, const Parameters &params);
+
+// Return the includes needed for generated source file.
+grpc::string GetSourceIncludes(File *file, const Parameters &params);
+
+// Return the epilogue of the generated header file.
+grpc::string GetHeaderEpilogue(File *file, const Parameters &params);
+
+// Return the prologue of the generated source file.
+grpc::string GetSourcePrologue(File *file, const Parameters &params);
+
+// Return the services for generated header file.
+grpc::string GetHeaderServices(File *file, const Parameters &params);
+
+// Return the services for generated source file.
+grpc::string GetSourceServices(File *file, const Parameters &params);
+
+// Return the epilogue of the generated source file.
+grpc::string GetSourceEpilogue(File *file, const Parameters &params);
+
+} // namespace grpc_cpp_generator
+
+#endif // GRPC_INTERNAL_COMPILER_CPP_GENERATOR_H
diff --git a/grpc/tests/grpctest.cpp b/grpc/tests/grpctest.cpp
new file mode 100644
index 00000000..d1b53776
--- /dev/null
+++ b/grpc/tests/grpctest.cpp
@@ -0,0 +1,124 @@
+/*
+ * Copyright 2014 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <thread>
+
+#include <grpc++/grpc++.h>
+
+#include "monster_test_generated.h"
+#include "monster_test.grpc.fb.h"
+
+using namespace MyGame::Example;
+
+// The callback implementation of our server, that derives from the generated
+// code. It implements all rpcs specified in the FlatBuffers schema.
+class ServiceImpl final : public MyGame::Example::MonsterStorage::Service {
+ virtual ::grpc::Status Store(::grpc::ServerContext* context,
+ const flatbuffers::BufferRef<Monster> *request,
+ flatbuffers::BufferRef<Stat> *response)
+ override {
+ // Create a response from the incoming request name.
+ fbb_.Clear();
+ auto stat_offset = CreateStat(fbb_, fbb_.CreateString("Hello, " +
+ request->GetRoot()->name()->str()));
+ fbb_.Finish(stat_offset);
+ // Since we keep reusing the same FlatBufferBuilder, the memory it owns
+ // remains valid until the next call (this BufferRef doesn't own the
+ // memory it points to).
+ *response = flatbuffers::BufferRef<Stat>(fbb_.GetBufferPointer(),
+ fbb_.GetSize());
+ return grpc::Status::OK;
+ }
+ virtual ::grpc::Status Retrieve(::grpc::ServerContext *context,
+ const flatbuffers::BufferRef<Stat> *request,
+ flatbuffers::BufferRef<Monster> *response)
+ override {
+ assert(false); // We're not actually using this RPC.
+ return grpc::Status::CANCELLED;
+ }
+
+ private:
+ flatbuffers::FlatBufferBuilder fbb_;
+};
+
+// Track the server instance, so we can terminate it later.
+grpc::Server *server_instance = nullptr;
+// Mutex to protec this variable.
+std::mutex wait_for_server;
+std::condition_variable server_instance_cv;
+
+// This function implements the server thread.
+void RunServer() {
+ auto server_address = "0.0.0.0:50051";
+ // Callback interface we implemented above.
+ ServiceImpl service;
+ grpc::ServerBuilder builder;
+ builder.AddListeningPort(server_address, grpc::InsecureServerCredentials());
+ builder.RegisterService(&service);
+
+ // Start the server. Lock to change the variable we're changing.
+ wait_for_server.lock();
+ server_instance = builder.BuildAndStart().release();
+ wait_for_server.unlock();
+ server_instance_cv.notify_one();
+
+ std::cout << "Server listening on " << server_address << std::endl;
+ // This will block the thread and serve requests.
+ server_instance->Wait();
+}
+
+int main(int /*argc*/, const char * /*argv*/[]) {
+ // Launch server.
+ std::thread server_thread(RunServer);
+
+ // wait for server to spin up.
+ std::unique_lock<std::mutex> lock(wait_for_server);
+ while (!server_instance) server_instance_cv.wait(lock);
+
+ // Now connect the client.
+ auto channel = grpc::CreateChannel("localhost:50051",
+ grpc::InsecureChannelCredentials());
+ auto stub = MyGame::Example::MonsterStorage::NewStub(channel);
+
+ grpc::ClientContext context;
+
+ // Build a request with the name set.
+ flatbuffers::FlatBufferBuilder fbb;
+ auto monster_offset = CreateMonster(fbb, 0, 0, 0, fbb.CreateString("Fred"));
+ fbb.Finish(monster_offset);
+ auto request = flatbuffers::BufferRef<Monster>(fbb.GetBufferPointer(),
+ fbb.GetSize());
+ flatbuffers::BufferRef<Stat> response;
+
+ // The actual RPC.
+ auto status = stub->Store(&context, request, &response);
+
+ if (status.ok()) {
+ auto resp = response.GetRoot()->id();
+ std::cout << "RPC response: " << resp->str() << std::endl;
+ } else {
+ std::cout << "RPC failed" << std::endl;
+ }
+
+ server_instance->Shutdown();
+
+ server_thread.join();
+
+ delete server_instance;
+
+ return 0;
+}
+
diff --git a/include/flatbuffers/code_generators.h b/include/flatbuffers/code_generators.h
index 95fa0c1a..8b097ef7 100644
--- a/include/flatbuffers/code_generators.h
+++ b/include/flatbuffers/code_generators.h
@@ -24,11 +24,12 @@ class BaseGenerator {
virtual bool generate() = 0;
static const std::string NamespaceDir(const Parser &parser,
- const std::string &path) {
+ const std::string &path,
+ const Namespace &ns) {
EnsureDirExists(path.c_str());
if (parser.opts.one_file) return path;
std::string namespace_dir = path; // Either empty or ends in separator.
- auto &namespaces = parser.namespaces_.back()->components;
+ auto &namespaces = ns.components;
for (auto it = namespaces.begin(); it != namespaces.end(); ++it) {
namespace_dir += *it + kPathSeparator;
EnsureDirExists(namespace_dir.c_str());
@@ -38,17 +39,24 @@ class BaseGenerator {
protected:
BaseGenerator(const Parser &parser, const std::string &path,
- const std::string &file_name)
+ const std::string &file_name,
+ const std::string qualifying_start,
+ const std::string qualifying_separator)
: parser_(parser),
path_(path),
file_name_(file_name),
- namespace_dir_(BaseGenerator::NamespaceDir(parser, path)){};
+ qualifying_start_(qualifying_start),
+ qualifying_separator_(qualifying_separator){};
virtual ~BaseGenerator(){};
// No copy/assign.
BaseGenerator &operator=(const BaseGenerator &);
BaseGenerator(const BaseGenerator &);
+ const std::string NamespaceDir(const Namespace &ns) {
+ return BaseGenerator::NamespaceDir(parser_, path_, ns);
+ }
+
const char *FlatBuffersGeneratedWarning() {
return "automatically generated by the FlatBuffers compiler,"
" do not modify\n\n";
@@ -66,9 +74,9 @@ class BaseGenerator {
return true;
}
- std::string FullNamespace(const char *separator) {
+ std::string FullNamespace(const char *separator, const Namespace &ns) {
std::string namespace_name;
- auto &namespaces = parser_.namespaces_.back()->components;
+ auto &namespaces = ns.components;
for (auto it = namespaces.begin(); it != namespaces.end(); ++it) {
if (namespace_name.length()) namespace_name += separator;
namespace_name += *it;
@@ -76,15 +84,39 @@ class BaseGenerator {
return namespace_name;
}
- const std::string LastNamespacePart() {
- auto &namespaces = parser_.namespaces_.back()->components;
- if (namespaces.size()) return *(namespaces.end() - 1); else return std::string("");
+ const std::string LastNamespacePart(const Namespace &ns) {
+ auto &namespaces = ns.components;
+ 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),
+ // 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) {
+ if (CurrentNameSpace() == ns) return name;
+ std::string qualified_name = qualifying_start_;
+ for (auto it = ns->components.begin(); it != ns->components.end(); ++it)
+ qualified_name += *it + qualifying_separator_;
+ return qualified_name + name;
+ }
+
+ std::string WrapInNameSpace(const Definition &def) {
+ return WrapInNameSpace(def.defined_namespace, def.name);
}
const Parser &parser_;
const std::string &path_;
const std::string &file_name_;
- const std::string namespace_dir_;
+ const std::string qualifying_start_;
+ const std::string qualifying_separator_;
};
} // namespace flatbuffers
diff --git a/include/flatbuffers/flatbuffers.h b/include/flatbuffers/flatbuffers.h
index ff83da6d..8cab3cd3 100644
--- a/include/flatbuffers/flatbuffers.h
+++ b/include/flatbuffers/flatbuffers.h
@@ -24,28 +24,36 @@
#include <cstdlib>
#include <cstring>
#include <string>
+#include <utility>
#include <type_traits>
#include <vector>
#include <set>
#include <algorithm>
-#include <functional>
#include <memory>
+#ifdef _STLPORT_VERSION
+ #define FLATBUFFERS_CPP98_STL
+#endif
+#ifndef FLATBUFFERS_CPP98_STL
+ #include <functional>
+#endif
+
/// @cond FLATBUFFERS_INTERNAL
#if __cplusplus <= 199711L && \
(!defined(_MSC_VER) || _MSC_VER < 1600) && \
(!defined(__GNUC__) || \
(__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__ < 40400))
- #error A C++11 compatible compiler with support for the auto typing is required for FlatBuffers.
+ #error A C++11 compatible compiler with support for the auto typing is \
+ required for FlatBuffers.
#error __cplusplus _MSC_VER __GNUC__ __GNUC_MINOR__ __GNUC_PATCHLEVEL__
#endif
#if !defined(__clang__) && \
defined(__GNUC__) && \
(__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__ < 40600)
- // Backwards compatability for g++ 4.4, and 4.5 which don't have the nullptr and constexpr
- // keywords. Note the __clang__ check is needed, because clang presents itself as an older GNUC
- // compiler.
+ // Backwards compatability for g++ 4.4, and 4.5 which don't have the nullptr
+ // and constexpr keywords. Note the __clang__ check is needed, because clang
+ // presents itself as an older GNUC compiler.
#ifndef nullptr_t
const class nullptr_t {
public:
@@ -122,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<uint8_t, std::function<void(uint8_t * /* unused */)>>
unique_ptr_t;
+#endif
// Wrapper for uoffset_t to allow safe template specialization.
template<typename T> struct Offset {
@@ -233,23 +243,19 @@ template<typename T> struct IndirectHelper<const T *> {
// An STL compatible iterator implementation for Vector below, effectively
// calling Get() for every element.
-template<typename T, bool bConst>
-struct VectorIterator : public
- std::iterator < std::input_iterator_tag,
- typename std::conditional < bConst,
- const typename IndirectHelper<T>::return_type,
- typename IndirectHelper<T>::return_type > ::type, uoffset_t > {
-
- typedef std::iterator<std::input_iterator_tag,
- typename std::conditional<bConst,
- const typename IndirectHelper<T>::return_type,
- typename IndirectHelper<T>::return_type>::type, uoffset_t> super_type;
+template<typename T, typename IT>
+struct VectorIterator
+ : public std::iterator<std::input_iterator_tag, IT, uoffset_t> {
+
+ typedef std::iterator<std::input_iterator_tag, IT, uoffset_t> super_type;
public:
VectorIterator(const uint8_t *data, uoffset_t i) :
data_(data + IndirectHelper<T>::element_stride * i) {};
VectorIterator(const VectorIterator &other) : data_(other.data_) {}
+ #ifndef FLATBUFFERS_CPP98_STL
VectorIterator(VectorIterator &&other) : data_(std::move(other.data_)) {}
+ #endif
VectorIterator &operator=(const VectorIterator &other) {
data_ = other.data_;
@@ -287,7 +293,7 @@ public:
}
VectorIterator operator++(int) {
- VectorIterator temp(data_);
+ VectorIterator temp(data_,0);
data_ += IndirectHelper<T>::element_stride;
return temp;
}
@@ -300,8 +306,10 @@ private:
// Vector::data() assumes the vector elements start after the length field.
template<typename T> class Vector {
public:
- typedef VectorIterator<T, false> iterator;
- typedef VectorIterator<T, true> const_iterator;
+ typedef VectorIterator<T, typename IndirectHelper<T>::mutable_return_type>
+ iterator;
+ typedef VectorIterator<T, typename IndirectHelper<T>::return_type>
+ const_iterator;
uoffset_t size() const { return EndianScalar(length_); }
@@ -470,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.
@@ -485,6 +494,7 @@ class vector_downward {
return retval;
}
+ #endif
size_t growth_policy(size_t bytes) {
return (bytes / 2) & ~(sizeof(largest_scalar_t) - 1);
@@ -561,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 <typename T> const T* data(const std::vector<T> &v) {
+ return v.empty() ? nullptr : &v.front();
+}
/// @endcond
/// @addtogroup flatbuffers_cpp_api
@@ -626,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
@@ -636,6 +651,7 @@ FLATBUFFERS_FINAL_CLASS
Finished();
return buf_.release();
}
+ #endif
/// @cond FLATBUFFERS_INTERNAL
void Finished() const {
@@ -673,11 +689,13 @@ FLATBUFFERS_FINAL_CLASS
void PopBytes(size_t amount) { buf_.pop(amount); }
template<typename T> void AssertScalarT() {
+ #ifndef FLATBUFFERS_CPP98_STL
// The code assumes power of 2 sizes and endian-swap-ability.
static_assert(std::is_scalar<T>::value
// The Offset<T> type is essentially a scalar but fails is_scalar.
|| sizeof(T) == sizeof(Offset<void>),
"T must be a scalar type");
+ #endif
}
// Write a single aligned scalar to the buffer
@@ -875,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<String> 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.
@@ -980,7 +998,47 @@ FLATBUFFERS_FINAL_CLASS
/// @return Returns a typed `Offset` into the serialized data indicating
/// where the vector is stored.
template<typename T> Offset<Vector<T>> CreateVector(const std::vector<T> &v) {
- return CreateVector(v.data(), v.size());
+ return CreateVector(data(v), v.size());
+ }
+
+ // vector<bool> 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<Vector<uint8_t>> CreateVector(const std::vector<bool> &v) {
+ StartVector(v.size(), sizeof(uint8_t));
+ for (auto i = v.size(); i > 0; ) {
+ PushElement(static_cast<uint8_t>(v[--i]));
+ }
+ return Offset<Vector<uint8_t>>(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.
+ /// @param f A function that takes the current iteration 0..vector_size-1 and
+ /// returns any type that you can construct a FlatBuffers vector out of.
+ /// @return Returns a typed `Offset` into the serialized data indicating
+ /// where the vector is stored.
+ template<typename T> Offset<Vector<T>> CreateVector(size_t vector_size,
+ const std::function<T (size_t i)> &f) {
+ std::vector<T> elems(vector_size);
+ for (size_t i = 0; i < vector_size; i++) elems[i] = f(i);
+ return CreateVector(elems);
+ }
+ #endif
+
+ /// @brief Serialize a `std::vector<std::string>` into a FlatBuffer `vector`.
+ /// This is a convenience function for a common case.
+ /// @param v A const reference to the `std::vector` to serialize into the
+ /// buffer as a `vector`.
+ /// @return Returns a typed `Offset` into the serialized data indicating
+ /// where the vector is stored.
+ Offset<Vector<Offset<String>>> CreateVectorOfStrings(
+ const std::vector<std::string> &v) {
+ std::vector<Offset<String>> offsets(v.size());
+ for (size_t i = 0; i < v.size(); i++) offsets[i] = CreateString(v[i]);
+ return CreateVector(offsets);
}
/// @brief Serialize an array of structs into a FlatBuffer `vector`.
@@ -991,7 +1049,7 @@ FLATBUFFERS_FINAL_CLASS
/// @return Returns a typed `Offset` into the serialized data indicating
/// where the vector is stored.
template<typename T> Offset<Vector<const T *>> CreateVectorOfStructs(
- const T *v, size_t len) {
+ const T *v, size_t len) {
StartVector(len * sizeof(T) / AlignOf<T>(), AlignOf<T>());
PushBytes(reinterpret_cast<const uint8_t *>(v), sizeof(T) * len);
return Offset<Vector<const T *>>(EndVector(len));
@@ -1004,8 +1062,8 @@ FLATBUFFERS_FINAL_CLASS
/// @return Returns a typed `Offset` into the serialized data indicating
/// where the vector is stored.
template<typename T> Offset<Vector<const T *>> CreateVectorOfStructs(
- const std::vector<T> &v) {
- return CreateVectorOfStructs(v.data(), v.size());
+ const std::vector<T> &v) {
+ return CreateVectorOfStructs(data(v), v.size());
}
/// @cond FLATBUFFERS_INTERNAL
@@ -1033,7 +1091,7 @@ FLATBUFFERS_FINAL_CLASS
/// @return Returns a typed `Offset` into the serialized data indicating
/// where the vector is stored.
template<typename T> Offset<Vector<Offset<T>>> CreateVectorOfSortedTables(
- Offset<T> *v, size_t len) {
+ Offset<T> *v, size_t len) {
std::sort(v, v + len, TableKeyComparator<T>(buf_));
return CreateVector(v, len);
}
@@ -1046,7 +1104,7 @@ FLATBUFFERS_FINAL_CLASS
/// @return Returns a typed `Offset` into the serialized data indicating
/// where the vector is stored.
template<typename T> Offset<Vector<Offset<T>>> CreateVectorOfSortedTables(
- std::vector<Offset<T>> *v) {
+ std::vector<Offset<T>> *v) {
return CreateVectorOfSortedTables(v->data(), v->size());
}
@@ -1077,7 +1135,7 @@ FLATBUFFERS_FINAL_CLASS
/// written to at a later time to serialize the data into a `vector`
/// in the buffer.
template<typename T> Offset<Vector<T>> CreateUninitializedVector(
- size_t len, T **buf) {
+ size_t len, T **buf) {
return CreateUninitializedVector(len, sizeof(T),
reinterpret_cast<uint8_t **>(buf));
}
@@ -1162,13 +1220,16 @@ template<typename T> const T *GetRoot(const void *buf) {
}
/// Helpers to get a typed pointer to objects that are currently beeing built.
-/// @warning Creating new objects will lead to reallocations and invalidates the pointer!
-template<typename T> T *GetMutableTemporaryPointer(FlatBufferBuilder &fbb, Offset<T> offset) {
+/// @warning Creating new objects will lead to reallocations and invalidates
+/// the pointer!
+template<typename T> T *GetMutableTemporaryPointer(FlatBufferBuilder &fbb,
+ Offset<T> offset) {
return reinterpret_cast<T *>(fbb.GetCurrentBufferPointer() +
fbb.GetSize() - offset.o);
}
-template<typename T> const T *GetTemporaryPointer(FlatBufferBuilder &fbb, Offset<T> offset) {
+template<typename T> const T *GetTemporaryPointer(FlatBufferBuilder &fbb,
+ Offset<T> offset) {
return GetMutableTemporaryPointer<T>(fbb, offset);
}
@@ -1185,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.
@@ -1192,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<const uint8_t *>(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);
@@ -1271,11 +1344,20 @@ class Verifier FLATBUFFERS_FINAL_CLASS {
}
// Verify this whole buffer, starting with root type T.
- template<typename T> bool VerifyBuffer() {
+ template<typename T> 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<uoffset_t>(buf_) &&
reinterpret_cast<const T *>(buf_ + ReadScalar<uoffset_t>(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
@@ -1294,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_;
@@ -1301,6 +1393,32 @@ 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
+// typed by its root.
+// A BufferRef does not own its buffer.
+struct BufferRefBase {}; // for std::is_base_of
+template<typename T> struct BufferRef : BufferRefBase {
+ BufferRef() : buf(nullptr), len(0), must_free(false) {}
+ BufferRef(uint8_t *_buf, uoffset_t _len)
+ : buf(_buf), len(_len), must_free(false) {}
+
+ ~BufferRef() { if (must_free) free(buf); }
+
+ const T *GetRoot() const { return flatbuffers::GetRoot<T>(buf); }
+
+ bool Verify() {
+ Verifier verifier(buf, len);
+ return verifier.VerifyBuffer<T>();
+ }
+
+ uint8_t *buf;
+ uoffset_t len;
+ bool must_free;
};
// "structs" are flat structures that do not have an offset table, thus
@@ -1435,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/grpc.h b/include/flatbuffers/grpc.h
new file mode 100644
index 00000000..52a64408
--- /dev/null
+++ b/include/flatbuffers/grpc.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2014 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef FLATBUFFERS_GRPC_H_
+#define FLATBUFFERS_GRPC_H_
+
+// Helper functionality to glue FlatBuffers and GRPC.
+
+#include "grpc++/support/byte_buffer.h"
+#include "grpc/byte_buffer_reader.h"
+
+namespace grpc {
+
+template <class T>
+class SerializationTraits<T, typename std::enable_if<std::is_base_of<
+ flatbuffers::BufferRefBase, T>::value>::type> {
+ public:
+ // The type we're passing here is a BufferRef, which is already serialized
+ // FlatBuffer data, which then gets passed to GRPC.
+ static grpc::Status Serialize(const T& msg,
+ grpc_byte_buffer **buffer,
+ bool *own_buffer) {
+ // TODO(wvo): make this work without copying.
+ auto slice = gpr_slice_from_copied_buffer(
+ reinterpret_cast<const char *>(msg.buf), msg.len);
+ *buffer = grpc_raw_byte_buffer_create(&slice, 1);
+ *own_buffer = true;
+ return grpc::Status();
+ }
+
+ // There is no de-serialization step in FlatBuffers, so we just receive
+ // the data from GRPC.
+ static grpc::Status Deserialize(grpc_byte_buffer *buffer,
+ T *msg,
+ int max_message_size) {
+ // TODO(wvo): make this more efficient / zero copy when possible.
+ auto len = grpc_byte_buffer_length(buffer);
+ msg->buf = reinterpret_cast<uint8_t *>(malloc(len));
+ msg->len = static_cast<flatbuffers::uoffset_t>(len);
+ msg->must_free = true;
+ uint8_t *current = msg->buf;
+ grpc_byte_buffer_reader reader;
+ grpc_byte_buffer_reader_init(&reader, buffer);
+ gpr_slice slice;
+ while (grpc_byte_buffer_reader_next(&reader, &slice)) {
+ memcpy(current, GPR_SLICE_START_PTR(slice), GPR_SLICE_LENGTH(slice));
+ current += GPR_SLICE_LENGTH(slice);
+ gpr_slice_unref(slice);
+ }
+ GPR_ASSERT(current == msg->buf + msg->len);
+ grpc_byte_buffer_reader_destroy(&reader);
+ grpc_byte_buffer_destroy(buffer);
+ return grpc::Status();
+ }
+};
+
+} // namespace grpc;
+
+#endif // FLATBUFFERS_GRPC_H_
diff --git a/include/flatbuffers/idl.h b/include/flatbuffers/idl.h
index dc385efa..1f450162 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<Value> attributes;
@@ -337,6 +345,8 @@ struct IDLOptions {
bool generate_all;
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 };
@@ -356,9 +366,24 @@ struct IDLOptions {
generate_all(false),
skip_unexpected_fields_in_json(false),
generate_name_strings(false),
+ escape_proto_identifiers(false),
+ generate_object_based_api(false),
lang(IDLOptions::kJava) {}
};
+// This encapsulates where the parser is in the current source file.
+struct ParserState {
+ ParserState() : cursor_(nullptr), line_(1), token_(-1) {}
+
+ protected:
+ const char *cursor_;
+ int line_; // the current line being parsed
+ int token_;
+
+ std::string attribute_;
+ std::vector<std::string> doc_comment_;
+};
+
// A way to make error propagation less error prone by requiring values to be
// checked.
// Once you create a value of this type you must either:
@@ -400,14 +425,12 @@ class CheckedError {
#define FLATBUFFERS_CHECKED_ERROR CheckedError
#endif
-class Parser {
+class Parser : public ParserState {
public:
explicit Parser(const IDLOptions &options = IDLOptions())
: root_struct_def_(nullptr),
opts(options),
source_(nullptr),
- cursor_(nullptr),
- line_(1),
anonymous_counter(0) {
// Just in case none are declared:
namespaces_.push_back(new Namespace());
@@ -421,7 +444,7 @@ class Parser {
known_attributes_["original_order"] = true;
known_attributes_["nested_flatbuffer"] = true;
known_attributes_["csharp_partial"] = true;
- known_attributes_["stream"] = true;
+ known_attributes_["streaming"] = true;
known_attributes_["idempotent"] = true;
}
@@ -458,6 +481,10 @@ class Parser {
// 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:
@@ -478,7 +505,8 @@ private:
FieldDef **dest);
FLATBUFFERS_CHECKED_ERROR ParseField(StructDef &struct_def);
FLATBUFFERS_CHECKED_ERROR ParseAnyValue(Value &val, FieldDef *field,
- size_t parent_fieldn);
+ size_t parent_fieldn,
+ const StructDef *parent_struct_def);
FLATBUFFERS_CHECKED_ERROR ParseTable(const StructDef &struct_def,
std::string *value, uoffset_t *ovalue);
void SerializeStruct(const StructDef &struct_def, const Value &val);
@@ -538,13 +566,9 @@ private:
IDLOptions opts;
private:
- const char *source_, *cursor_;
- int line_; // the current line being parsed
- int token_;
- std::string file_being_parsed_;
+ const char *source_;
- std::string attribute_;
- std::vector<std::string> doc_comment_;
+ std::string file_being_parsed_;
std::vector<std::pair<Value, FieldDef *>> field_stack_;
@@ -671,6 +695,12 @@ extern std::string BinaryMakeRule(const Parser &parser,
const std::string &path,
const std::string &file_name);
+// Generate GRPC interfaces.
+// See idl_gen_grpc.cpp.
+bool GenerateGRPC(const Parser &parser,
+ const std::string &path,
+ const std::string &file_name);
+
} // namespace flatbuffers
#endif // FLATBUFFERS_IDL_H_
diff --git a/include/flatbuffers/reflection.h b/include/flatbuffers/reflection.h
index ababe6ad..ae331ce2 100644
--- a/include/flatbuffers/reflection.h
+++ b/include/flatbuffers/reflection.h
@@ -335,6 +335,8 @@ template<typename T, typename U> pointer_inside_vector<T, U> piv(T *ptr,
return pointer_inside_vector<T, U>(ptr, vec);
}
+inline const char *UnionTypeFieldSuffix() { return "_type"; }
+
// Helper to figure out the actual table type a union refers to.
inline const reflection::Object &GetUnionType(
const reflection::Schema &schema, const reflection::Object &parent,
@@ -342,7 +344,7 @@ inline const reflection::Object &GetUnionType(
auto enumdef = schema.enums()->Get(unionfield.type()->index());
// TODO: this is clumsy and slow, but no other way to find it?
auto type_field = parent.fields()->LookupByKey(
- (unionfield.name()->str() + "_type").c_str());
+ (unionfield.name()->str() + UnionTypeFieldSuffix()).c_str());
assert(type_field);
auto union_type = GetFieldI<uint8_t>(table, *type_field);
auto enumval = enumdef->values()->LookupByKey(union_type);
@@ -368,6 +370,7 @@ uint8_t *ResizeAnyVector(const reflection::Schema &schema, uoffset_t newsize,
uoffset_t elem_size, std::vector<uint8_t> *flatbuf,
const reflection::Object *root_table = nullptr);
+#ifndef FLATBUFFERS_CPP98_STL
template <typename T>
void ResizeVector(const reflection::Schema &schema, uoffset_t newsize, T val,
const Vector<T> *vec, std::vector<uint8_t> *flatbuf,
@@ -389,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 da112493..eb981857 100644
--- a/include/flatbuffers/reflection_generated.h
+++ b/include/flatbuffers/reflection_generated.h
@@ -478,12 +478,12 @@ inline flatbuffers::Offset<Schema> CreateSchema(flatbuffers::FlatBufferBuilder &
inline const reflection::Schema *GetSchema(const void *buf) { return flatbuffers::GetRoot<reflection::Schema>(buf); }
-inline bool VerifySchemaBuffer(flatbuffers::Verifier &verifier) { return verifier.VerifyBuffer<reflection::Schema>(); }
-
inline const char *SchemaIdentifier() { return "BFBS"; }
inline bool SchemaBufferHasIdentifier(const void *buf) { return flatbuffers::BufferHasIdentifier(buf, SchemaIdentifier()); }
+inline bool VerifySchemaBuffer(flatbuffers::Verifier &verifier) { return verifier.VerifyBuffer<reflection::Schema>(SchemaIdentifier()); }
+
inline const char *SchemaExtension() { return "bfbs"; }
inline void FinishSchemaBuffer(flatbuffers::FlatBufferBuilder &fbb, flatbuffers::Offset<reflection::Schema> root) { fbb.Finish(root, SchemaIdentifier()); }
diff --git a/java/com/google/flatbuffers/Constants.java b/java/com/google/flatbuffers/Constants.java
index ac0593ae..f5906314 100644
--- a/java/com/google/flatbuffers/Constants.java
+++ b/java/com/google/flatbuffers/Constants.java
@@ -23,10 +23,18 @@ package com.google.flatbuffers;
*/
public class Constants {
// Java doesn't seem to have these.
+ /** The number of bytes in an `byte`. */
+ static final int SIZEOF_BYTE = 1;
/** The number of bytes in a `short`. */
static final int SIZEOF_SHORT = 2;
/** The number of bytes in an `int`. */
static final int SIZEOF_INT = 4;
+ /** The number of bytes in an `float`. */
+ static final int SIZEOF_FLOAT = 4;
+ /** The number of bytes in an `long`. */
+ static final int SIZEOF_LONG = 8;
+ /** The number of bytes in an `double`. */
+ static final int SIZEOF_DOUBLE = 8;
/** The number of bytes in a file identifier. */
static final int FILE_IDENTIFIER_LENGTH = 4;
}
diff --git a/java/com/google/flatbuffers/FlatBufferBuilder.java b/java/com/google/flatbuffers/FlatBufferBuilder.java
index fecb213f..c2186fa7 100644
--- a/java/com/google/flatbuffers/FlatBufferBuilder.java
+++ b/java/com/google/flatbuffers/FlatBufferBuilder.java
@@ -188,7 +188,7 @@ public class FlatBufferBuilder {
*
* @param x A `boolean` to put into the buffer.
*/
- public void putBoolean(boolean x) { bb.put (space -= 1, (byte)(x ? 1 : 0)); }
+ public void putBoolean(boolean x) { bb.put (space -= Constants.SIZEOF_BYTE, (byte)(x ? 1 : 0)); }
/**
* Add a `byte` to the buffer, backwards from the current location. Doesn't align nor
@@ -196,7 +196,7 @@ public class FlatBufferBuilder {
*
* @param x A `byte` to put into the buffer.
*/
- public void putByte (byte x) { bb.put (space -= 1, x); }
+ public void putByte (byte x) { bb.put (space -= Constants.SIZEOF_BYTE, x); }
/**
* Add a `short` to the buffer, backwards from the current location. Doesn't align nor
@@ -204,7 +204,7 @@ public class FlatBufferBuilder {
*
* @param x A `short` to put into the buffer.
*/
- public void putShort (short x) { bb.putShort (space -= 2, x); }
+ public void putShort (short x) { bb.putShort (space -= Constants.SIZEOF_SHORT, x); }
/**
* Add an `int` to the buffer, backwards from the current location. Doesn't align nor
@@ -212,7 +212,7 @@ public class FlatBufferBuilder {
*
* @param x An `int` to put into the buffer.
*/
- public void putInt (int x) { bb.putInt (space -= 4, x); }
+ public void putInt (int x) { bb.putInt (space -= Constants.SIZEOF_INT, x); }
/**
* Add a `long` to the buffer, backwards from the current location. Doesn't align nor
@@ -220,7 +220,7 @@ public class FlatBufferBuilder {
*
* @param x A `long` to put into the buffer.
*/
- public void putLong (long x) { bb.putLong (space -= 8, x); }
+ public void putLong (long x) { bb.putLong (space -= Constants.SIZEOF_LONG, x); }
/**
* Add a `float` to the buffer, backwards from the current location. Doesn't align nor
@@ -228,7 +228,7 @@ public class FlatBufferBuilder {
*
* @param x A `float` to put into the buffer.
*/
- public void putFloat (float x) { bb.putFloat (space -= 4, x); }
+ public void putFloat (float x) { bb.putFloat (space -= Constants.SIZEOF_FLOAT, x); }
/**
* Add a `double` to the buffer, backwards from the current location. Doesn't align nor
@@ -236,7 +236,7 @@ public class FlatBufferBuilder {
*
* @param x A `double` to put into the buffer.
*/
- public void putDouble (double x) { bb.putDouble(space -= 8, x); }
+ public void putDouble (double x) { bb.putDouble(space -= Constants.SIZEOF_DOUBLE, x); }
/// @endcond
/**
@@ -244,49 +244,49 @@ public class FlatBufferBuilder {
*
* @param x A `boolean` to put into the buffer.
*/
- public void addBoolean(boolean x) { prep(1, 0); putBoolean(x); }
+ public void addBoolean(boolean x) { prep(Constants.SIZEOF_BYTE, 0); putBoolean(x); }
/**
* Add a `byte` to the buffer, properly aligned, and grows the buffer (if necessary).
*
* @param x A `byte` to put into the buffer.
*/
- public void addByte (byte x) { prep(1, 0); putByte (x); }
+ public void addByte (byte x) { prep(Constants.SIZEOF_BYTE, 0); putByte (x); }
/**
* Add a `short` to the buffer, properly aligned, and grows the buffer (if necessary).
*
* @param x A `short` to put into the buffer.
*/
- public void addShort (short x) { prep(2, 0); putShort (x); }
+ public void addShort (short x) { prep(Constants.SIZEOF_SHORT, 0); putShort (x); }
/**
* Add an `int` to the buffer, properly aligned, and grows the buffer (if necessary).
*
* @param x An `int` to put into the buffer.
*/
- public void addInt (int x) { prep(4, 0); putInt (x); }
+ public void addInt (int x) { prep(Constants.SIZEOF_INT, 0); putInt (x); }
/**
* Add a `long` to the buffer, properly aligned, and grows the buffer (if necessary).
*
* @param x A `long` to put into the buffer.
*/
- public void addLong (long x) { prep(8, 0); putLong (x); }
+ public void addLong (long x) { prep(Constants.SIZEOF_LONG, 0); putLong (x); }
/**
* Add a `float` to the buffer, properly aligned, and grows the buffer (if necessary).
*
* @param x A `float` to put into the buffer.
*/
- public void addFloat (float x) { prep(4, 0); putFloat (x); }
+ public void addFloat (float x) { prep(Constants.SIZEOF_FLOAT, 0); putFloat (x); }
/**
* Add a `double` to the buffer, properly aligned, and grows the buffer (if necessary).
*
* @param x A `double` to put into the buffer.
*/
- public void addDouble (double x) { prep(8, 0); putDouble (x); }
+ public void addDouble (double x) { prep(Constants.SIZEOF_DOUBLE, 0); putDouble (x); }
/**
* Adds on offset, relative to where it will be written.
diff --git a/php/FlatbufferBuilder.php b/php/FlatbufferBuilder.php
index 3738582e..6f0ee483 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
index dd92b9d5..8e32feec 100644
--- a/java/pom.xml
+++ b/pom.xml
@@ -6,7 +6,7 @@
<groupId>com.google.flatbuffers</groupId>
<artifactId>flatbuffers-java</artifactId>
<version>1.3.0-SNAPSHOT</version>
- <packaging>jar</packaging>
+ <packaging>bundle</packaging>
<name>FlatBuffers Java API</name>
<description>
Memory Efficient Serialization Library
@@ -33,7 +33,7 @@
<dependencies>
</dependencies>
<build>
- <sourceDirectory>./</sourceDirectory>
+ <sourceDirectory>java</sourceDirectory>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
@@ -78,6 +78,12 @@
</execution>
</executions>
</plugin>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <version>3.0.1</version>
+ <extensions>true</extensions>
+ </plugin>
</plugins>
</build>
</project>
diff --git a/readme.md b/readme.md
index 15dd41b1..3a7f929e 100755
--- a/readme.md
+++ b/readme.md
@@ -46,7 +46,7 @@ you would leave it in.
<br>
- [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 1a16126a..636aa377 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<void> Pack(flatbuffers::FlatBufferBuilder &_fbb) const;
+
+ WeaponT *AsWeapon() { return type == Equipment_Weapon ? reinterpret_cast<WeaponT *>(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<Vec3> pos;
+ int16_t mana;
+ int16_t hp;
+ std::string name;
+ std::vector<uint8_t> inventory;
+ Color color;
+ std::vector<std::unique_ptr<WeaponT>> 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<MonsterT> UnPack() const;
};
struct MonsterBuilder {
@@ -135,15 +166,15 @@ struct MonsterBuilder {
};
inline flatbuffers::Offset<Monster> CreateMonster(flatbuffers::FlatBufferBuilder &_fbb,
- const Vec3 *pos = 0,
- int16_t mana = 150,
- int16_t hp = 100,
- flatbuffers::Offset<flatbuffers::String> name = 0,
- flatbuffers::Offset<flatbuffers::Vector<uint8_t>> inventory = 0,
- Color color = Color_Blue,
- flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<Weapon>>> weapons = 0,
- Equipment equipped_type = Equipment_NONE,
- flatbuffers::Offset<void> equipped = 0) {
+ const Vec3 *pos = 0,
+ int16_t mana = 150,
+ int16_t hp = 100,
+ flatbuffers::Offset<flatbuffers::String> name = 0,
+ flatbuffers::Offset<flatbuffers::Vector<uint8_t>> inventory = 0,
+ Color color = Color_Blue,
+ flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<Weapon>>> weapons = 0,
+ Equipment equipped_type = Equipment_NONE,
+ flatbuffers::Offset<void> equipped = 0) {
MonsterBuilder builder_(_fbb);
builder_.add_equipped(equipped);
builder_.add_weapons(weapons);
@@ -157,6 +188,26 @@ inline flatbuffers::Offset<Monster> CreateMonster(flatbuffers::FlatBufferBuilder
return builder_.Finish();
}
+inline flatbuffers::Offset<Monster> CreateMonster(flatbuffers::FlatBufferBuilder &_fbb,
+ const Vec3 *pos = 0,
+ int16_t mana = 150,
+ int16_t hp = 100,
+ const char *name = nullptr,
+ const std::vector<uint8_t> *inventory = nullptr,
+ Color color = Color_Blue,
+ const std::vector<flatbuffers::Offset<Weapon>> *weapons = nullptr,
+ Equipment equipped_type = Equipment_NONE,
+ flatbuffers::Offset<void> equipped = 0) {
+ return CreateMonster(_fbb, pos, mana, hp, name ? 0 : _fbb.CreateString(name), inventory ? 0 : _fbb.CreateVector<uint8_t>(*inventory), color, weapons ? 0 : _fbb.CreateVector<flatbuffers::Offset<Weapon>>(*weapons), equipped_type, equipped);
+}
+
+inline flatbuffers::Offset<Monster> 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<int16_t>(verifier, VT_DAMAGE) &&
verifier.EndTable();
}
+ std::unique_ptr<WeaponT> UnPack() const;
};
struct WeaponBuilder {
@@ -189,14 +241,62 @@ struct WeaponBuilder {
};
inline flatbuffers::Offset<Weapon> CreateWeapon(flatbuffers::FlatBufferBuilder &_fbb,
- flatbuffers::Offset<flatbuffers::String> name = 0,
- int16_t damage = 0) {
+ flatbuffers::Offset<flatbuffers::String> name = 0,
+ int16_t damage = 0) {
WeaponBuilder builder_(_fbb);
builder_.add_name(name);
builder_.add_damage(damage);
return builder_.Finish();
}
+inline flatbuffers::Offset<Weapon> CreateWeapon(flatbuffers::FlatBufferBuilder &_fbb,
+ const char *name = nullptr,
+ int16_t damage = 0) {
+ return CreateWeapon(_fbb, name ? 0 : _fbb.CreateString(name), damage);
+}
+
+inline flatbuffers::Offset<Weapon> CreateWeapon(flatbuffers::FlatBufferBuilder &_fbb, const WeaponT *_o);
+
+inline std::unique_ptr<MonsterT> Monster::UnPack() const {
+ auto _o = new MonsterT();
+ { auto _e = pos(); if (_e) _o->pos = std::unique_ptr<Vec3>(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<MonsterT>(_o);
+}
+
+inline flatbuffers::Offset<Monster> 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<flatbuffers::Offset<Weapon>>(_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<WeaponT> 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<WeaponT>(_o);
+}
+
+inline flatbuffers::Offset<Weapon> 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<const Weapon *>(union_obj)->UnPack().release();
+ default: return nullptr;
+ }
+}
+
+inline flatbuffers::Offset<void> EquipmentUnion::Pack(flatbuffers::FlatBufferBuilder &_fbb) const {
+ switch (type) {
+ case Equipment_NONE: return 0;
+ case Equipment_Weapon: return CreateWeapon(_fbb, reinterpret_cast<const WeaponT *>(table)).Union();
+ default: return 0;
+ }
+}
+
+inline EquipmentUnion::~EquipmentUnion() {
+ switch (type) {
+ case Equipment_Weapon: delete reinterpret_cast<WeaponT *>(table); break;
+ default:;
+ }
+}
+
inline const MyGame::Sample::Monster *GetMonster(const void *buf) { return flatbuffers::GetRoot<MyGame::Sample::Monster>(buf); }
inline Monster *GetMutableMonster(void *buf) { return flatbuffers::GetMutableRoot<Monster>(buf); }
-inline bool VerifyMonsterBuffer(flatbuffers::Verifier &verifier) { return verifier.VerifyBuffer<MyGame::Sample::Monster>(); }
+inline bool VerifyMonsterBuffer(flatbuffers::Verifier &verifier) { return verifier.VerifyBuffer<MyGame::Sample::Monster>(nullptr); }
inline void FinishMonsterBuffer(flatbuffers::FlatBufferBuilder &fbb, flatbuffers::Offset<MyGame::Sample::Monster> root) { fbb.Finish(root); }
diff --git a/src/flatc.cpp b/src/flatc.cpp
index d4be151c..a568bbb2 100644
--- a/src/flatc.cpp
+++ b/src/flatc.cpp
@@ -74,20 +74,24 @@ const Generator generators[] = {
flatbuffers::IDLOptions::kMAX,
"Generate Python files for tables/structs",
flatbuffers::GeneralMakeRule },
- { flatbuffers::GeneratePhp, nullptr, "--php", "PHP",
+ { flatbuffers::GeneratePhp, nullptr, "--php", "PHP",
flatbuffers::IDLOptions::kMAX,
"Generate PHP files for tables/structs",
flatbuffers::GeneralMakeRule },
+ { flatbuffers::GenerateGRPC, nullptr, "--grpc", "GRPC",
+ flatbuffers::IDLOptions::kMAX,
+ "Generate GRPC interfaces",
+ flatbuffers::CPPMakeRule },
};
-const char *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,
@@ -116,25 +120,42 @@ static void Error(const std::string &err, bool usage, bool show_exe_name) {
" --no-includes Don\'t generate include statements for included\n"
" schemas the generated file depends on (C++).\n"
" --gen-mutable Generate accessors that can mutate buffers in-place.\n"
- " --gen-onefile Generate single output file for C#\n"
+ " --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<const char *> &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]);
@@ -146,6 +167,7 @@ int main(int argc, const char *argv[]) {
std::vector<std::string> filenames;
std::vector<const char *> include_directories;
size_t binary_files_from = std::numeric_limits<size_t>::max();
+ std::string conform_to_schema;
for (int argi = 1; argi < argc; argi++) {
std::string arg = argv[argi];
if (arg[0] == '-') {
@@ -157,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") {
@@ -174,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;
@@ -190,6 +217,8 @@ int main(int argc, const char *argv[]) {
binary_files_from = filenames.size();
} else if(arg == "--proto") {
opts.proto_mode = true;
+ } else if(arg == "--escape-proto-ids") {
+ opts.escape_proto_identifiers = true;
} else if(arg == "--schema") {
schema_binary = true;
} else if(arg == "-M") {
@@ -220,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) {
@@ -236,8 +273,8 @@ int main(int argc, const char *argv[]) {
bool is_binary = static_cast<size_t>(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<const uint8_t *>(contents.c_str()),
contents.length());
if (!raw_binary) {
@@ -246,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.");
}
}
@@ -265,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 " +
@@ -302,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());
@@ -310,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 b1402d8e..ad20b36c 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,25 +222,9 @@ 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_;
- // 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) {
- if (cur_name_space_ != ns) {
- std::string qualified_name;
- for (auto it = ns->components.begin(); it != ns->components.end(); ++it) {
- qualified_name += *it + "::";
- }
- return qualified_name + name;
- } else {
- return name;
- }
- }
-
- std::string WrapInNameSpace(const Definition &def) {
- return WrapInNameSpace(def.defined_namespace, def.name);
- }
+ const Namespace *CurrentNameSpace() { return cur_name_space_; }
// Translates a qualified name in flatbuffer text format to the same name in
// the equivalent C++ namespace.
@@ -241,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);
@@ -261,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:
@@ -273,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;
@@ -325,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<void> " +
+ (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;
@@ -372,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
@@ -397,38 +478,89 @@ class CppGenerator : public BaseGenerator {
code += "()[static_cast<int>(e)";
if (enum_def.vals.vec.front()->value) {
code += " - static_cast<int>(";
- code +=
- GetEnumVal(enum_def, *enum_def.vals.vec.front(), parser_.opts) + ")";
+ code += 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<const ";
- code_post += WrapInNameSpace(*ev.struct_def);
- code_post += " *>(union_obj));\n";
+ code += ": return verifier.VerifyTable(reinterpret_cast<const ";
+ code += WrapInNameSpace(*ev.struct_def);
+ code += " *>(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<const ";
+ code += WrapInNameSpace(*ev.struct_def);
+ code += " *>(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<const ";
+ code += NativeName(WrapInNameSpace(*ev.struct_def));
+ code += " *>(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
@@ -455,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() "
@@ -473,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<int>(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<type>(offset, defaultval); }
GenComment(struct_def.doc_comment, code_ptr, nullptr);
@@ -514,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 =
@@ -523,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))
@@ -541,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 + ")");
@@ -604,8 +771,8 @@ class CppGenerator : public BaseGenerator {
switch (field.value.type.base_type) {
case BASE_TYPE_UNION:
code += prefix + "Verify" + field.value.type.enum_def->name;
- code +=
- "(verifier, " + field.name + "(), " + field.name + "_type())";
+ code += "(verifier, " + field.name + "(), " + field.name +
+ UnionTypeFieldSuffix() + "())";
break;
case BASE_TYPE_STRUCT:
if (!field.value.type.struct_def->fixed) {
@@ -643,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<type>(offset, name, default);
@@ -695,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";
@@ -702,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<int>(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";
@@ -735,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.CreateVector<flatbuffers::Offset<";
+ code += vector_type.struct_def->name + ">>(" + 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,
@@ -791,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();
@@ -833,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
@@ -868,8 +1243,8 @@ class CppGenerator : public BaseGenerator {
// so that namespaces are properly opened and closed
void SetNameSpace(const Namespace *ns, std::string *code_ptr) {
if (cur_name_space_ == ns) return;
- // compute the size of the longest common namespace prefix.
- // if cur_name_space is A::B::C::D and ns is A::B::E::F::G,
+ // compute the size of the longest common namespace prefix.
+ // if cur_name_space is A::B::C::D and ns is A::B::E::F::G,
// the common prefix is A::B:: and we have old_size = 4, new_size = 5
// and common_prefix_size = 2
auto old_size =
@@ -881,19 +1256,20 @@ class CppGenerator : public BaseGenerator {
cur_name_space_->components[common_prefix_size])
common_prefix_size++;
// close cur_name_space in reverse order to reach the common prefix
- // in the previous example, D then C are closed
+ // in the previous example, D then C are closed
for (auto j = old_size; j > common_prefix_size; --j)
*code_ptr +=
"} // namespace " + cur_name_space_->components[j - 1] + "\n";
if (old_size != common_prefix_size) *code_ptr += "\n";
// open namespace parts to reach the ns namespace
- // in the previous example, E, then F, then G are opened
+ // in the previous example, E, then F, then G are opened
for (auto j = common_prefix_size; j != new_size; ++j)
*code_ptr += "namespace " + ns->components[j] + " {\n";
if (new_size != common_prefix_size) *code_ptr += "\n";
cur_name_space_ = ns;
}
};
+
} // namespace cpp
bool GenerateCPP(const Parser &parser, const std::string &path,
@@ -902,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_fbs.cpp b/src/idl_gen_fbs.cpp
index 00afe25d..237230e8 100644
--- a/src/idl_gen_fbs.cpp
+++ b/src/idl_gen_fbs.cpp
@@ -53,12 +53,14 @@ static void GenNameSpace(const Namespace &name_space, std::string *_schema,
// Generate a flatbuffer schema from the Parser's internal representation.
std::string GenerateFBS(const Parser &parser, const std::string &file_name) {
- // Proto namespaces may clash with table names, so we have to prefix all:
- for (auto it = parser.namespaces_.begin(); it != parser.namespaces_.end();
- ++it) {
- for (auto comp = (*it)->components.begin(); comp != (*it)->components.end();
- ++comp) {
- (*comp) = "_" + (*comp);
+ // Proto namespaces may clash with table names, so we have to prefix all:
+ if (!parser.opts.escape_proto_identifiers) {
+ for (auto it = parser.namespaces_.begin(); it != parser.namespaces_.end();
+ ++it) {
+ for (auto comp = (*it)->components.begin(); comp != (*it)->components.end();
+ ++comp) {
+ (*comp) = "_" + (*comp);
+ }
}
}
diff --git a/src/idl_gen_general.cpp b/src/idl_gen_general.cpp
index a0b837a2..7e8e8c57 100644
--- a/src/idl_gen_general.cpp
+++ b/src/idl_gen_general.cpp
@@ -188,41 +188,85 @@ static_assert(sizeof(language_parameters) / sizeof(LanguageParameters) ==
IDLOptions::kMAX,
"Please add extra elements to the arrays above.");
-static std::string FunctionStart(const LanguageParameters &lang, char upper) {
- return std::string() +
- (lang.language == IDLOptions::kJava
- ? static_cast<char>(tolower(upper))
- : upper);
-}
+namespace general {
+class GeneralGenerator : public BaseGenerator {
+ public:
+ GeneralGenerator(const Parser &parser, const std::string &path,
+ const std::string &file_name)
+ : 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;
-static bool IsEnum(const Type& type) {
- return type.enum_def != nullptr && IsInteger(type.base_type);
-}
+ for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
+ ++it) {
+ std::string enumcode;
+ auto &enum_def = **it;
+ GenEnum(enum_def, &enumcode);
+ if (parser_.opts.one_file) {
+ one_file_code += enumcode;
+ } else {
+ if (!SaveType(enum_def.name, *enum_def.defined_namespace,
+ enumcode, false)) return false;
+ }
+ }
-// Ensure that a type is prefixed with its namespace whenever it is used
-// outside of its namespace.
-static std::string WrapInNameSpace(const Parser &parser, const Namespace *ns,
- const std::string &name) {
- if (parser.namespaces_.back() != ns) {
- std::string qualified_name;
- for (auto it = ns->components.begin();
- it != ns->components.end(); ++it) {
- qualified_name += *it + ".";
- }
- return qualified_name + name;
- } else {
- return name;
- }
+ for (auto it = parser_.structs_.vec.begin();
+ it != parser_.structs_.vec.end(); ++it) {
+ std::string declcode;
+ auto &struct_def = **it;
+ GenStruct(struct_def, &declcode);
+ if (parser_.opts.one_file) {
+ one_file_code += declcode;
+ } else {
+ if (!SaveType(struct_def.name, *struct_def.defined_namespace,
+ declcode, true)) return false;
+ }
+ }
+
+ if (parser_.opts.one_file) {
+ return SaveType(file_name_, *parser_.namespaces_.back(),
+ one_file_code, true);
+ }
+ return true;
+ }
+
+ // Save out the generated code for a single class while adding
+ // declaration boilerplate.
+ bool SaveType(const std::string &defname, const Namespace &ns,
+ const std::string &classcode, bool needs_includes) {
+ if (!classcode.length()) return true;
+
+ std::string code;
+ code = code + "// " + FlatBuffersGeneratedWarning();
+ std::string namespace_name = FullNamespace(".", ns);
+ if (!namespace_name.empty()) {
+ code += lang_.namespace_ident + namespace_name + lang_.namespace_begin;
+ code += "\n\n";
+ }
+ if (needs_includes) code += lang_.includes;
+ code += classcode;
+ if (!namespace_name.empty()) code += lang_.namespace_end;
+ auto filename = NamespaceDir(ns) + defname + lang_.file_extension;
+ return SaveFile(filename.c_str(), code, false);
+ }
+
+ const Namespace *CurrentNameSpace() { return parser_.namespaces_.back(); }
+
+ std::string FunctionStart(char upper) {
+ return std::string() + (lang_.language == IDLOptions::kJava
+ ? static_cast<char>(tolower(upper))
+ : upper);
}
-static std::string WrapInNameSpace(const Parser &parser,
- const Definition &def) {
- return WrapInNameSpace(parser, def.defined_namespace, def.name);
+static bool IsEnum(const Type& type) {
+ return type.enum_def != nullptr && IsInteger(type.base_type);
}
-static std::string GenTypeBasic(const LanguageParameters &lang, const Parser &parser,
- const Type &type,
- bool enableLangOverrides) {
+std::string GenTypeBasic(const Type &type, bool enableLangOverrides) {
static const char *gtypename[] = {
#define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \
#JTYPE, #NTYPE, #GTYPE,
@@ -231,55 +275,48 @@ static std::string GenTypeBasic(const LanguageParameters &lang, const Parser &pa
};
if (enableLangOverrides) {
- if (lang.language == IDLOptions::kCSharp) {
- if (IsEnum(type)) return WrapInNameSpace(parser, *type.enum_def);
+ if (lang_.language == IDLOptions::kCSharp) {
+ if (IsEnum(type)) return WrapInNameSpace(*type.enum_def);
if (type.base_type == BASE_TYPE_STRUCT) {
- return "Offset<" + WrapInNameSpace(parser, *type.struct_def) + ">";
+ return "Offset<" + WrapInNameSpace(*type.struct_def) + ">";
}
}
}
- return gtypename[type.base_type * IDLOptions::kMAX + lang.language];
+ return gtypename[type.base_type * IDLOptions::kMAX + lang_.language];
}
-static std::string GenTypeBasic(const LanguageParameters &lang, const Parser &parser,
- const Type &type) {
- return GenTypeBasic(lang, parser, type, true);
+std::string GenTypeBasic(const Type &type) {
+ return GenTypeBasic(type, true);
}
-static std::string GenTypeGet(const LanguageParameters &lang, const Parser &parser,
- const Type &type);
-
-static std::string GenTypePointer(const LanguageParameters &lang, const Parser &parser,
- const Type &type) {
+std::string GenTypePointer(const Type &type) {
switch (type.base_type) {
case BASE_TYPE_STRING:
- return lang.string_type;
+ return lang_.string_type;
case BASE_TYPE_VECTOR:
- return GenTypeGet(lang, parser, type.VectorType());
+ return GenTypeGet(type.VectorType());
case BASE_TYPE_STRUCT:
- return WrapInNameSpace(parser, *type.struct_def);
+ return WrapInNameSpace(*type.struct_def);
case BASE_TYPE_UNION:
// Unions in C# use a generic Table-derived type for better type safety
- if (lang.language == IDLOptions::kCSharp) return "TTable";
+ if (lang_.language == IDLOptions::kCSharp) return "TTable";
// fall through
default:
return "Table";
}
}
-static std::string GenTypeGet(const LanguageParameters &lang, const Parser &parser,
- const Type &type) {
+std::string GenTypeGet(const Type &type) {
return IsScalar(type.base_type)
- ? GenTypeBasic(lang, parser, type)
- : GenTypePointer(lang, parser, type);
+ ? GenTypeBasic(type)
+ : GenTypePointer(type);
}
// Find the destination type the user wants to receive the value in (e.g.
// one size higher signed types for unsigned serialized values in Java).
-static Type DestinationType(const LanguageParameters &lang, const Parser &parser, const Type &type,
- bool vectorelem) {
- if (lang.language != IDLOptions::kJava) return type;
+Type DestinationType(const Type &type, bool vectorelem) {
+ if (lang_.language != IDLOptions::kJava) return type;
switch (type.base_type) {
// We use int for both uchar/ushort, since that generally means less casting
// than using short for uchar.
@@ -288,33 +325,31 @@ static Type DestinationType(const LanguageParameters &lang, const Parser &parser
case BASE_TYPE_UINT: return Type(BASE_TYPE_LONG);
case BASE_TYPE_VECTOR:
if (vectorelem)
- return DestinationType(lang, parser, type.VectorType(), vectorelem);
+ return DestinationType(type.VectorType(), vectorelem);
// else fall thru:
default: return type;
}
}
-static std::string GenOffsetType(const LanguageParameters &lang, const Parser &parser,
- const StructDef &struct_def) {
- if(lang.language == IDLOptions::kCSharp) {
- return "Offset<" + WrapInNameSpace(parser, struct_def) + ">";
+std::string GenOffsetType(const StructDef &struct_def) {
+ if(lang_.language == IDLOptions::kCSharp) {
+ return "Offset<" + WrapInNameSpace(struct_def) + ">";
} else {
return "int";
}
}
-static std::string GenOffsetConstruct(const LanguageParameters &lang, const Parser &parser,
- const StructDef &struct_def,
+std::string GenOffsetConstruct(const StructDef &struct_def,
const std::string &variable_name)
{
- if(lang.language == IDLOptions::kCSharp) {
- return "new Offset<" + WrapInNameSpace(parser, struct_def) + ">(" + variable_name + ")";
+ if(lang_.language == IDLOptions::kCSharp) {
+ return "new Offset<" + WrapInNameSpace(struct_def) + ">(" + variable_name + ")";
}
return variable_name;
}
-static std::string GenVectorOffsetType(const LanguageParameters &lang) {
- if(lang.language == IDLOptions::kCSharp) {
+std::string GenVectorOffsetType() {
+ if(lang_.language == IDLOptions::kCSharp) {
return "VectorOffset";
} else {
return "int";
@@ -322,34 +357,32 @@ static std::string GenVectorOffsetType(const LanguageParameters &lang) {
}
// Generate destination type name
-static std::string GenTypeNameDest(const LanguageParameters &lang, const Parser &parser, const Type &type)
+std::string GenTypeNameDest(const Type &type)
{
- return GenTypeGet(lang, parser, DestinationType(lang, parser, type, true));
+ return GenTypeGet(DestinationType(type, true));
}
// Mask to turn serialized value into destination type value.
-static std::string DestinationMask(const LanguageParameters &lang,
- const Type &type, bool vectorelem) {
- if (lang.language != IDLOptions::kJava) return "";
+std::string DestinationMask(const Type &type, bool vectorelem) {
+ if (lang_.language != IDLOptions::kJava) return "";
switch (type.base_type) {
case BASE_TYPE_UCHAR: return " & 0xFF";
case BASE_TYPE_USHORT: return " & 0xFFFF";
case BASE_TYPE_UINT: return " & 0xFFFFFFFFL";
case BASE_TYPE_VECTOR:
if (vectorelem)
- return DestinationMask(lang, type.VectorType(), vectorelem);
+ return DestinationMask(type.VectorType(), vectorelem);
// else fall thru:
default: return "";
}
}
// Casts necessary to correctly read serialized data
-static std::string DestinationCast(const LanguageParameters &lang, const Parser &parser,
- const Type &type) {
+std::string DestinationCast(const Type &type) {
if (type.base_type == BASE_TYPE_VECTOR) {
- return DestinationCast(lang, parser, type.VectorType());
+ return DestinationCast(type.VectorType());
} else {
- switch (lang.language) {
+ switch (lang_.language) {
case IDLOptions::kJava:
// Cast necessary to correctly read serialized unsigned values.
if (type.base_type == BASE_TYPE_UINT) return "(long)";
@@ -357,7 +390,7 @@ static std::string DestinationCast(const LanguageParameters &lang, const Parser
case IDLOptions::kCSharp:
// Cast from raw integral types to enum.
- if (IsEnum(type)) return "(" + WrapInNameSpace(parser, *type.enum_def) + ")";
+ if (IsEnum(type)) return "(" + WrapInNameSpace(*type.enum_def) + ")";
break;
default:
@@ -371,13 +404,11 @@ static std::string DestinationCast(const LanguageParameters &lang, const Parser
// In Java, parameters representing unsigned numbers need to be cast down to their respective type.
// For example, a long holding an unsigned int value would be cast down to int before being put onto the buffer.
// In C#, one cast directly cast an Enum to its underlying type, which is essential before putting it onto the buffer.
-static std::string SourceCast(const LanguageParameters &lang, const Parser &parser,
- const Type &type,
- bool castFromDest) {
+std::string SourceCast(const Type &type, bool castFromDest) {
if (type.base_type == BASE_TYPE_VECTOR) {
- return SourceCast(lang, parser, type.VectorType(), castFromDest);
+ return SourceCast(type.VectorType(), castFromDest);
} else {
- switch (lang.language) {
+ switch (lang_.language) {
case IDLOptions::kJava:
if (castFromDest) {
if (type.base_type == BASE_TYPE_UINT) return "(int)";
@@ -386,7 +417,7 @@ static std::string SourceCast(const LanguageParameters &lang, const Parser &pars
}
break;
case IDLOptions::kCSharp:
- if (IsEnum(type)) return "(" + GenTypeBasic(lang, parser, type, false) + ")";
+ if (IsEnum(type)) return "(" + GenTypeBasic(type, false) + ")";
break;
default:
break;
@@ -395,24 +426,20 @@ static std::string SourceCast(const LanguageParameters &lang, const Parser &pars
return "";
}
-static std::string SourceCast(const LanguageParameters &lang, const Parser &parser,
- const Type &type) {
- return SourceCast(lang, parser, type, true);
+std::string SourceCast(const Type &type) {
+ return SourceCast(type, true);
}
-static std::string SourceCastBasic(const LanguageParameters &lang, const Parser &parser,
- const Type &type,
- bool castFromDest) {
- return IsScalar(type.base_type) ? SourceCast(lang, parser, type, castFromDest) : "";
+std::string SourceCastBasic(const Type &type, bool castFromDest) {
+ return IsScalar(type.base_type) ? SourceCast(type, castFromDest) : "";
}
-static std::string SourceCastBasic(const LanguageParameters &lang, const Parser &parser,
- const Type &type) {
- return SourceCastBasic(lang, parser, type, true);
+std::string SourceCastBasic(const Type &type) {
+ return SourceCastBasic(type, true);
}
-static std::string GenEnumDefaultValue(const Parser &parser, const Value &value) {
+std::string GenEnumDefaultValue(const Value &value) {
auto enum_def = value.type.enum_def;
auto vec = enum_def->vals.vec;
auto default_value = StringToInt(value.constant.c_str());
@@ -421,7 +448,7 @@ static std::string GenEnumDefaultValue(const Parser &parser, const Value &value)
for (auto it = vec.begin(); it != vec.end(); ++it) {
auto enum_val = **it;
if (enum_val.value == default_value) {
- result = WrapInNameSpace(parser, *enum_def) + "." + enum_val.name;
+ result = WrapInNameSpace(*enum_def) + "." + enum_val.name;
break;
}
}
@@ -429,14 +456,13 @@ static std::string GenEnumDefaultValue(const Parser &parser, const Value &value)
return result;
}
-static std::string GenDefaultValue(const LanguageParameters &lang, const Parser &parser,
- const Value &value, bool enableLangOverrides) {
+std::string GenDefaultValue(const Value &value, bool enableLangOverrides) {
if (enableLangOverrides) {
// handles both enum case and vector of enum case
- if (lang.language == IDLOptions::kCSharp &&
+ if (lang_.language == IDLOptions::kCSharp &&
value.type.enum_def != nullptr &&
value.type.base_type != BASE_TYPE_UNION) {
- return GenEnumDefaultValue(parser, value);
+ return GenEnumDefaultValue(value);
}
}
switch (value.type.base_type) {
@@ -446,21 +472,19 @@ static std::string GenDefaultValue(const LanguageParameters &lang, const Parser
}
}
-static std::string GenDefaultValue(const LanguageParameters &lang, const Parser &parser,
- const Value &value) {
- return GenDefaultValue(lang, parser, value, true);
+std::string GenDefaultValue(const Value &value) {
+ return GenDefaultValue(value, true);
}
-static std::string GenDefaultValueBasic(const LanguageParameters &lang, const Parser &parser,
- const Value &value, bool enableLangOverrides) {
+std::string GenDefaultValueBasic(const Value &value, bool enableLangOverrides) {
if (!IsScalar(value.type.base_type)) {
if (enableLangOverrides) {
- if (lang.language == IDLOptions::kCSharp) {
+ if (lang_.language == IDLOptions::kCSharp) {
switch (value.type.base_type) {
case BASE_TYPE_STRING:
return "default(StringOffset)";
case BASE_TYPE_STRUCT:
- return "default(Offset<" + WrapInNameSpace(parser, *value.type.struct_def) + ">)";
+ return "default(Offset<" + WrapInNameSpace(*value.type.struct_def) + ">)";
case BASE_TYPE_VECTOR:
return "default(VectorOffset)";
default:
@@ -470,16 +494,14 @@ static std::string GenDefaultValueBasic(const LanguageParameters &lang, const Pa
}
return "0";
}
- return GenDefaultValue(lang, parser, value, enableLangOverrides);
+ return GenDefaultValue(value, enableLangOverrides);
}
-static std::string GenDefaultValueBasic(const LanguageParameters &lang, const Parser &parser,
- const Value &value) {
- return GenDefaultValueBasic(lang, parser, value, true);
+std::string GenDefaultValueBasic(const Value &value) {
+ return GenDefaultValueBasic(value, true);
}
-static void GenEnum(const LanguageParameters &lang, const Parser &parser, EnumDef &enum_def,
- std::string *code_ptr) {
+void GenEnum(EnumDef &enum_def, std::string *code_ptr) {
std::string &code = *code_ptr;
if (enum_def.generated) return;
@@ -488,33 +510,33 @@ static void GenEnum(const LanguageParameters &lang, const Parser &parser, EnumDe
// In Java, we use ints rather than the Enum feature, because we want them
// to map directly to how they're used in C/C++ and file formats.
// That, and Java Enums are expensive, and not universally liked.
- GenComment(enum_def.doc_comment, code_ptr, &lang.comment_config);
- code += std::string("public ") + lang.enum_decl + enum_def.name;
- if (lang.language == IDLOptions::kCSharp) {
- code += lang.inheritance_marker + GenTypeBasic(lang, parser, enum_def.underlying_type, false);
+ GenComment(enum_def.doc_comment, code_ptr, &lang_.comment_config);
+ code += std::string("public ") + lang_.enum_decl + enum_def.name;
+ if (lang_.language == IDLOptions::kCSharp) {
+ code += lang_.inheritance_marker + GenTypeBasic(enum_def.underlying_type, false);
}
- code += lang.open_curly;
- if (lang.language == IDLOptions::kJava) {
+ code += lang_.open_curly;
+ if (lang_.language == IDLOptions::kJava) {
code += " private " + enum_def.name + "() { }\n";
}
for (auto it = enum_def.vals.vec.begin();
it != enum_def.vals.vec.end();
++it) {
auto &ev = **it;
- GenComment(ev.doc_comment, code_ptr, &lang.comment_config, " ");
- if (lang.language != IDLOptions::kCSharp) {
+ GenComment(ev.doc_comment, code_ptr, &lang_.comment_config, " ");
+ if (lang_.language != IDLOptions::kCSharp) {
code += " public static";
- code += lang.const_decl;
- code += GenTypeBasic(lang, parser, enum_def.underlying_type, false);
+ code += lang_.const_decl;
+ code += GenTypeBasic(enum_def.underlying_type, false);
}
code += " " + ev.name + " = ";
code += NumToString(ev.value);
- code += lang.enum_separator;
+ code += lang_.enum_separator;
}
// Generate a generate string table for enum values.
// We do not do that for C# where this functionality is native.
- if (lang.language != IDLOptions::kCSharp) {
+ if (lang_.language != IDLOptions::kCSharp) {
// Problem is, if values are very sparse that could generate really big
// tables. Ideally in that case we generate a map lookup instead, but for
// the moment we simply don't output a table at all.
@@ -524,9 +546,9 @@ static void GenEnum(const LanguageParameters &lang, const Parser &parser, EnumDe
// "too sparse". Change at will.
static const int kMaxSparseness = 5;
if (range / static_cast<int64_t>(enum_def.vals.vec.size()) < kMaxSparseness) {
- code += "\n private static";
- code += lang.const_decl;
- code += lang.string_type;
+ code += "\n public static";
+ code += lang_.const_decl;
+ code += lang_.string_type;
code += "[] names = { ";
auto val = enum_def.vals.vec.front()->value;
for (auto it = enum_def.vals.vec.begin();
@@ -537,8 +559,8 @@ static void GenEnum(const LanguageParameters &lang, const Parser &parser, EnumDe
}
code += "};\n\n";
code += " public static ";
- code += lang.string_type;
- code += " " + MakeCamel("name", lang.first_camel_upper);
+ code += lang_.string_type;
+ code += " " + MakeCamel("name", lang_.first_camel_upper);
code += "(int e) { return names[e";
if (enum_def.vals.vec.front()->value)
code += " - " + enum_def.vals.vec.front()->name;
@@ -547,23 +569,25 @@ static void GenEnum(const LanguageParameters &lang, const Parser &parser, EnumDe
}
// 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.
-static std::string GenGetter(const LanguageParameters &lang, const Parser &parser,
- const Type &type) {
+std::string GenGetter(const Type &type) {
switch (type.base_type) {
case BASE_TYPE_STRING: return "__string";
case BASE_TYPE_STRUCT: return "__struct";
case BASE_TYPE_UNION: return "__union";
- case BASE_TYPE_VECTOR: return GenGetter(lang, parser, type.VectorType());
+ case BASE_TYPE_VECTOR: return GenGetter(type.VectorType());
default: {
- std::string getter = "bb." + FunctionStart(lang, 'G') + "et";
+ std::string getter = "bb." + FunctionStart('G') + "et";
if (type.base_type == BASE_TYPE_BOOL) {
getter = "0!=" + getter;
- } else if (GenTypeBasic(lang, parser, type, false) != "byte") {
- getter += MakeCamel(GenTypeBasic(lang, parser, type, false));
+ } else if (GenTypeBasic(type, false) != "byte") {
+ getter += MakeCamel(GenTypeBasic(type, false));
}
return getter;
}
@@ -572,13 +596,12 @@ static std::string GenGetter(const LanguageParameters &lang, const Parser &parse
// Direct mutation is only allowed for scalar fields.
// Hence a setter method will only be generated for such fields.
-static std::string GenSetter(const LanguageParameters &lang, const Parser &parser,
- const Type &type) {
+std::string GenSetter(const Type &type) {
if (IsScalar(type.base_type)) {
- std::string setter = "bb." + FunctionStart(lang, 'P') + "ut";
- if (GenTypeBasic(lang, parser, type, false) != "byte" &&
+ std::string setter = "bb." + FunctionStart('P') + "ut";
+ if (GenTypeBasic(type, false) != "byte" &&
type.base_type != BASE_TYPE_BOOL) {
- setter += MakeCamel(GenTypeBasic(lang, parser, type, false));
+ setter += MakeCamel(GenTypeBasic(type, false));
}
return setter;
} else {
@@ -587,17 +610,15 @@ static std::string GenSetter(const LanguageParameters &lang, const Parser &parse
}
// Returns the method name for use with add/put calls.
-static std::string GenMethod(const LanguageParameters &lang, const Parser &parser, const Type &type) {
+std::string GenMethod(const Type &type) {
return IsScalar(type.base_type)
- ? MakeCamel(GenTypeBasic(lang, parser, type, false))
+ ? MakeCamel(GenTypeBasic(type, false))
: (IsStruct(type) ? "Struct" : "Offset");
}
// Recursively generate arguments for a constructor, to deal with nested
// structs.
-static void GenStructArgs(const LanguageParameters &lang, const Parser &parser,
- const StructDef &struct_def,
- std::string *code_ptr, const char *nameprefix) {
+void GenStructArgs(const StructDef &struct_def, std::string *code_ptr, const char *nameprefix) {
std::string &code = *code_ptr;
for (auto it = struct_def.fields.vec.begin();
it != struct_def.fields.vec.end();
@@ -607,14 +628,14 @@ static void GenStructArgs(const LanguageParameters &lang, const Parser &parser,
// Generate arguments for a struct inside a struct. To ensure names
// don't clash, and to make it obvious these arguments are constructing
// a nested struct, prefix the name with the field name.
- GenStructArgs(lang, parser, *field.value.type.struct_def, code_ptr,
+ GenStructArgs(*field.value.type.struct_def, code_ptr,
(nameprefix + (field.name + "_")).c_str());
} else {
code += ", ";
- code += GenTypeBasic(lang, parser, DestinationType(lang, parser, field.value.type, false));
+ code += GenTypeBasic(DestinationType(field.value.type, false));
code += " ";
code += nameprefix;
- code += MakeCamel(field.name, lang.first_camel_upper);
+ code += MakeCamel(field.name, lang_.first_camel_upper);
}
}
}
@@ -622,36 +643,33 @@ static void GenStructArgs(const LanguageParameters &lang, const Parser &parser,
// Recusively generate struct construction statements of the form:
// builder.putType(name);
// and insert manual padding.
-static void GenStructBody(const LanguageParameters &lang, const Parser &parser,
- const StructDef &struct_def,
- std::string *code_ptr, const char *nameprefix) {
+void GenStructBody(const StructDef &struct_def, std::string *code_ptr, const char *nameprefix) {
std::string &code = *code_ptr;
- code += " builder." + FunctionStart(lang, 'P') + "rep(";
+ code += " builder." + FunctionStart('P') + "rep(";
code += NumToString(struct_def.minalign) + ", ";
code += NumToString(struct_def.bytesize) + ");\n";
for (auto it = struct_def.fields.vec.rbegin();
it != struct_def.fields.vec.rend(); ++it) {
auto &field = **it;
if (field.padding) {
- code += " builder." + FunctionStart(lang, 'P') + "ad(";
+ code += " builder." + FunctionStart('P') + "ad(";
code += NumToString(field.padding) + ");\n";
}
if (IsStruct(field.value.type)) {
- GenStructBody(lang, parser, *field.value.type.struct_def, code_ptr,
+ GenStructBody(*field.value.type.struct_def, code_ptr,
(nameprefix + (field.name + "_")).c_str());
} else {
- code += " builder." + FunctionStart(lang, 'P') + "ut";
- code += GenMethod(lang, parser, field.value.type) + "(";
- code += SourceCast(lang, parser, field.value.type);
- auto argname = nameprefix + MakeCamel(field.name, lang.first_camel_upper);
+ code += " builder." + FunctionStart('P') + "ut";
+ code += GenMethod(field.value.type) + "(";
+ code += SourceCast(field.value.type);
+ auto argname = nameprefix + MakeCamel(field.name, lang_.first_camel_upper);
code += argname;
code += ");\n";
}
}
}
-static void GenStruct(const LanguageParameters &lang, const Parser &parser,
- StructDef &struct_def, std::string *code_ptr) {
+void GenStruct(StructDef &struct_def, std::string *code_ptr) {
if (struct_def.generated) return;
std::string &code = *code_ptr;
@@ -661,23 +679,23 @@ static void GenStruct(const LanguageParameters &lang, const Parser &parser,
// public type name() {
// int o = __offset(offset); return o != 0 ? bb.getType(o + i) : default;
// }
- GenComment(struct_def.doc_comment, code_ptr, &lang.comment_config);
+ GenComment(struct_def.doc_comment, code_ptr, &lang_.comment_config);
code += "public ";
- if (lang.language == IDLOptions::kCSharp &&
+ if (lang_.language == IDLOptions::kCSharp &&
struct_def.attributes.Lookup("csharp_partial")) {
// generate a partial class for this C# struct/table
code += "partial ";
}
else {
- code += lang.unsubclassable_decl;
+ code += lang_.unsubclassable_decl;
}
- code += "class " + struct_def.name + lang.inheritance_marker;
+ code += "class " + struct_def.name + lang_.inheritance_marker;
code += struct_def.fixed ? "Struct" : "Table";
code += " {\n";
if (!struct_def.fixed) {
// Generate a special accessor for the table that when used as the root
// of a FlatBuffer
- std::string method_name = FunctionStart(lang, 'G') + "etRootAs" + struct_def.name;
+ std::string method_name = FunctionStart('G') + "etRootAs" + struct_def.name;
std::string method_signature = " public static " + struct_def.name + " " + method_name;
// create convenience method that doesn't require an existing object
@@ -686,20 +704,20 @@ static void GenStruct(const LanguageParameters &lang, const Parser &parser,
// create method that allows object reuse
code += method_signature + "(ByteBuffer _bb, " + struct_def.name + " obj) { ";
- code += lang.set_bb_byteorder;
- code += "return (obj.__init(_bb." + FunctionStart(lang, 'G');
+ code += lang_.set_bb_byteorder;
+ code += "return (obj.__init(_bb." + FunctionStart('G');
code += "etInt(_bb.";
- code += lang.get_bb_position;
+ code += lang_.get_bb_position;
code += ") + _bb.";
- code += lang.get_bb_position;
+ code += lang_.get_bb_position;
code += ", _bb)); }\n";
- if (parser.root_struct_def_ == &struct_def) {
- if (parser.file_identifier_.length()) {
+ if (parser_.root_struct_def_ == &struct_def) {
+ if (parser_.file_identifier_.length()) {
// Check if a buffer has the identifier.
code += " public static ";
- code += lang.bool_type + struct_def.name;
+ code += lang_.bool_type + struct_def.name;
code += "BufferHasIdentifier(ByteBuffer _bb) { return ";
- code += "__has_identifier(_bb, \"" + parser.file_identifier_;
+ code += "__has_identifier(_bb, \"" + parser_.file_identifier_;
code += "\"); }\n";
}
}
@@ -714,14 +732,14 @@ static void GenStruct(const LanguageParameters &lang, const Parser &parser,
++it) {
auto &field = **it;
if (field.deprecated) continue;
- GenComment(field.doc_comment, code_ptr, &lang.comment_config, " ");
- std::string type_name = GenTypeGet(lang, parser, field.value.type);
- std::string type_name_dest = GenTypeNameDest(lang, parser, field.value.type);
- std::string dest_mask = DestinationMask(lang, field.value.type, true);
- std::string dest_cast = DestinationCast(lang, parser, field.value.type);
- std::string src_cast = SourceCast(lang, parser, field.value.type);
+ GenComment(field.doc_comment, code_ptr, &lang_.comment_config, " ");
+ std::string type_name = GenTypeGet(field.value.type);
+ std::string type_name_dest = GenTypeNameDest(field.value.type);
+ std::string dest_mask = DestinationMask(field.value.type, true);
+ std::string dest_cast = DestinationCast(field.value.type);
+ std::string src_cast = SourceCast(field.value.type);
std::string method_start = " public " + type_name_dest + " " +
- MakeCamel(field.name, lang.first_camel_upper);
+ MakeCamel(field.name, lang_.first_camel_upper);
// Most field accessors need to retrieve and test the field offset first,
// this is the prefix code for that:
@@ -731,16 +749,16 @@ static void GenStruct(const LanguageParameters &lang, const Parser &parser,
// Generate the accessors that don't do object reuse.
if (field.value.type.base_type == BASE_TYPE_STRUCT) {
// Calls the accessor that takes an accessor object with a new object.
- if (lang.language == IDLOptions::kCSharp) {
+ if (lang_.language == IDLOptions::kCSharp) {
code += method_start + " { get { return Get";
- code += MakeCamel(field.name, lang.first_camel_upper);
+ code += MakeCamel(field.name, lang_.first_camel_upper);
code += "(new ";
code += type_name + "()); } }\n";
- method_start = " public " + type_name_dest + " Get" + MakeCamel(field.name, lang.first_camel_upper);
+ method_start = " public " + type_name_dest + " Get" + MakeCamel(field.name, lang_.first_camel_upper);
}
else {
code += method_start + "() { return ";
- code += MakeCamel(field.name, lang.first_camel_upper);
+ code += MakeCamel(field.name, lang_.first_camel_upper);
code += "(new ";
code += type_name + "()); }\n";
}
@@ -748,32 +766,32 @@ static void GenStruct(const LanguageParameters &lang, const Parser &parser,
field.value.type.element == BASE_TYPE_STRUCT) {
// Accessors for vectors of structs also take accessor objects, this
// generates a variant without that argument.
- if (lang.language == IDLOptions::kCSharp) {
- method_start = " public " + type_name_dest + " Get" + MakeCamel(field.name, lang.first_camel_upper);
+ if (lang_.language == IDLOptions::kCSharp) {
+ method_start = " public " + type_name_dest + " Get" + MakeCamel(field.name, lang_.first_camel_upper);
code += method_start + "(int j) { return Get";
} else {
code += method_start + "(int j) { return ";
}
- code += MakeCamel(field.name, lang.first_camel_upper);
+ code += MakeCamel(field.name, lang_.first_camel_upper);
code += "(new ";
code += type_name + "(), j); }\n";
} else if (field.value.type.base_type == BASE_TYPE_VECTOR) {
- if (lang.language == IDLOptions::kCSharp) {
- method_start = " public " + type_name_dest + " Get" + MakeCamel(field.name, lang.first_camel_upper);
+ if (lang_.language == IDLOptions::kCSharp) {
+ method_start = " public " + type_name_dest + " Get" + MakeCamel(field.name, lang_.first_camel_upper);
}
} else if (field.value.type.base_type == BASE_TYPE_UNION) {
- if (lang.language == IDLOptions::kCSharp) {
+ if (lang_.language == IDLOptions::kCSharp) {
// union types in C# use generic Table-derived type for better type safety
- method_start = " public " + type_name_dest + " Get" + MakeCamel(field.name, lang.first_camel_upper) + "<TTable>";
+ method_start = " public " + type_name_dest + " Get" + MakeCamel(field.name, lang_.first_camel_upper) + "<TTable>";
offset_prefix = " where TTable : Table" + offset_prefix;
type_name = type_name_dest;
}
}
- std::string getter = dest_cast + GenGetter(lang, parser, field.value.type);
+ std::string getter = dest_cast + GenGetter(field.value.type);
code += method_start;
std::string default_cast = "";
// only create default casts for c# scalars or vectors of scalars
- if (lang.language == IDLOptions::kCSharp &&
+ if (lang_.language == IDLOptions::kCSharp &&
(IsScalar(field.value.type.base_type) ||
(field.value.type.base_type == BASE_TYPE_VECTOR && IsScalar(field.value.type.element)))) {
// For scalars, default value will be returned by GetDefaultValue(). If the scalar is an enum, GetDefaultValue()
@@ -785,8 +803,8 @@ static void GenStruct(const LanguageParameters &lang, const Parser &parser,
}
std::string member_suffix = "";
if (IsScalar(field.value.type.base_type)) {
- code += lang.getter_prefix;
- member_suffix = lang.getter_suffix;
+ code += lang_.getter_prefix;
+ member_suffix = lang_.getter_suffix;
if (struct_def.fixed) {
code += " { return " + getter;
code += "(bb_pos + " + NumToString(field.value.offset) + ")";
@@ -794,7 +812,7 @@ static void GenStruct(const LanguageParameters &lang, const Parser &parser,
} else {
code += offset_prefix + getter;
code += "(o + bb_pos)" + dest_mask + " : " + default_cast;
- code += GenDefaultValue(lang, parser, field.value);
+ code += GenDefaultValue(field.value);
}
} else {
switch (field.value.type.base_type) {
@@ -814,8 +832,8 @@ static void GenStruct(const LanguageParameters &lang, const Parser &parser,
}
break;
case BASE_TYPE_STRING:
- code += lang.getter_prefix;
- member_suffix = lang.getter_suffix;
+ code += lang_.getter_prefix;
+ member_suffix = lang_.getter_suffix;
code += offset_prefix + getter + "(o + bb_pos) : null";
break;
case BASE_TYPE_VECTOR: {
@@ -854,22 +872,22 @@ static void GenStruct(const LanguageParameters &lang, const Parser &parser,
code += member_suffix;
code += "}\n";
if (field.value.type.base_type == BASE_TYPE_VECTOR) {
- code += " public int " + MakeCamel(field.name, lang.first_camel_upper);
+ code += " public int " + MakeCamel(field.name, lang_.first_camel_upper);
code += "Length";
- code += lang.getter_prefix;
+ code += lang_.getter_prefix;
code += offset_prefix;
code += "__vector_len(o) : 0; ";
- code += lang.getter_suffix;
+ code += lang_.getter_suffix;
code += "}\n";
}
// Generate a ByteBuffer accessor for strings & vectors of scalars.
if ((field.value.type.base_type == BASE_TYPE_VECTOR &&
IsScalar(field.value.type.VectorType().base_type)) ||
field.value.type.base_type == BASE_TYPE_STRING) {
- switch (lang.language) {
+ switch (lang_.language) {
case IDLOptions::kJava:
code += " public ByteBuffer ";
- code += MakeCamel(field.name, lang.first_camel_upper);
+ code += MakeCamel(field.name, lang_.first_camel_upper);
code += "AsByteBuffer() { return __vector_as_bytebuffer(";
code += NumToString(field.value.offset) + ", ";
code += NumToString(field.value.type.base_type == BASE_TYPE_STRING ? 1 :
@@ -878,7 +896,7 @@ static void GenStruct(const LanguageParameters &lang, const Parser &parser,
break;
case IDLOptions::kCSharp:
code += " public ArraySegment<byte>? Get";
- code += MakeCamel(field.name, lang.first_camel_upper);
+ code += MakeCamel(field.name, lang_.first_camel_upper);
code += "Bytes() { return __vector_as_arraysegment(";
code += NumToString(field.value.offset);
code += "); }\n";
@@ -891,13 +909,13 @@ static void GenStruct(const LanguageParameters &lang, const Parser &parser,
auto nested = field.attributes.Lookup("nested_flatbuffer");
if (nested) {
auto nested_qualified_name =
- parser.namespaces_.back()->GetFullyQualifiedName(nested->constant);
- auto nested_type = parser.structs_.Lookup(nested_qualified_name);
- auto nested_type_name = WrapInNameSpace(parser, *nested_type);
- auto nestedMethodName = MakeCamel(field.name, lang.first_camel_upper)
+ parser_.namespaces_.back()->GetFullyQualifiedName(nested->constant);
+ auto nested_type = parser_.structs_.Lookup(nested_qualified_name);
+ auto nested_type_name = WrapInNameSpace(*nested_type);
+ auto nestedMethodName = MakeCamel(field.name, lang_.first_camel_upper)
+ "As" + nested_type_name;
auto getNestedMethodName = nestedMethodName;
- if (lang.language == IDLOptions::kCSharp) {
+ if (lang_.language == IDLOptions::kCSharp) {
getNestedMethodName = "Get" + nestedMethodName;
}
code += " public " + nested_type_name + " ";
@@ -909,16 +927,16 @@ static void GenStruct(const LanguageParameters &lang, const Parser &parser,
code += "return o != 0 ? obj.__init(__indirect(__vector(o)), bb) : null; }\n";
}
// generate mutators for scalar fields or vectors of scalars
- if (parser.opts.mutable_buffer) {
+ if (parser_.opts.mutable_buffer) {
auto underlying_type = field.value.type.base_type == BASE_TYPE_VECTOR
? field.value.type.VectorType()
: field.value.type;
// boolean parameters have to be explicitly converted to byte representation
auto setter_parameter = underlying_type.base_type == BASE_TYPE_BOOL ? "(byte)(" + field.name + " ? 1 : 0)" : field.name;
- auto mutator_prefix = MakeCamel("mutate", lang.first_camel_upper);
+ auto mutator_prefix = MakeCamel("mutate", lang_.first_camel_upper);
//a vector mutator also needs the index of the vector element it should mutate
auto mutator_params = (field.value.type.base_type == BASE_TYPE_VECTOR ? "(int j, " : "(") +
- GenTypeNameDest(lang, parser, underlying_type) + " " +
+ GenTypeNameDest(underlying_type) + " " +
field.name + ") { ";
auto setter_index = field.value.type.base_type == BASE_TYPE_VECTOR
? "__vector(o) + j * " + NumToString(InlineSize(underlying_type))
@@ -927,15 +945,15 @@ static void GenStruct(const LanguageParameters &lang, const Parser &parser,
(field.value.type.base_type == BASE_TYPE_VECTOR &&
IsScalar(field.value.type.VectorType().base_type))) {
code += " public ";
- code += struct_def.fixed ? "void " : lang.bool_type;
+ code += struct_def.fixed ? "void " : lang_.bool_type;
code += mutator_prefix + MakeCamel(field.name, true);
code += mutator_params;
if (struct_def.fixed) {
- code += GenSetter(lang, parser, underlying_type) + "(" + setter_index + ", ";
+ code += GenSetter(underlying_type) + "(" + setter_index + ", ";
code += src_cast + setter_parameter + "); }\n";
} else {
code += "int o = __offset(" + NumToString(field.value.offset) + ");";
- code += " if (o != 0) { " + GenSetter(lang, parser, underlying_type);
+ code += " if (o != 0) { " + GenSetter(underlying_type);
code += "(" + setter_index + ", " + src_cast + setter_parameter + "); return true; } else { return false; } }\n";
}
}
@@ -944,14 +962,14 @@ static void GenStruct(const LanguageParameters &lang, const Parser &parser,
code += "\n";
if (struct_def.fixed) {
// create a struct constructor function
- code += " public static " + GenOffsetType(lang, parser, struct_def) + " ";
- code += FunctionStart(lang, 'C') + "reate";
+ code += " public static " + GenOffsetType(struct_def) + " ";
+ code += FunctionStart('C') + "reate";
code += struct_def.name + "(FlatBufferBuilder builder";
- GenStructArgs(lang, parser, struct_def, code_ptr, "");
+ GenStructArgs(struct_def, code_ptr, "");
code += ") {\n";
- GenStructBody(lang, parser, struct_def, code_ptr, "");
+ GenStructBody(struct_def, code_ptr, "");
code += " return ";
- code += GenOffsetConstruct(lang, parser, struct_def, "builder." + std::string(lang.get_fbb_offset));
+ code += GenOffsetConstruct(struct_def, "builder." + std::string(lang_.get_fbb_offset));
code += ";\n }\n";
} else {
// Generate a method that creates a table in one go. This is only possible
@@ -972,28 +990,28 @@ static void GenStruct(const LanguageParameters &lang, const Parser &parser,
if (has_no_struct_fields && num_fields) {
// Generate a table constructor of the form:
// public static int createName(FlatBufferBuilder builder, args...)
- code += " public static " + GenOffsetType(lang, parser, struct_def) + " ";
- code += FunctionStart(lang, 'C') + "reate" + struct_def.name;
+ code += " public static " + GenOffsetType(struct_def) + " ";
+ code += FunctionStart('C') + "reate" + struct_def.name;
code += "(FlatBufferBuilder builder";
for (auto it = struct_def.fields.vec.begin();
it != struct_def.fields.vec.end(); ++it) {
auto &field = **it;
if (field.deprecated) continue;
code += ",\n ";
- code += GenTypeBasic(lang, parser, DestinationType(lang, parser, field.value.type, false));
+ code += GenTypeBasic(DestinationType(field.value.type, false));
code += " ";
code += field.name;
if (!IsScalar(field.value.type.base_type)) code += "Offset";
// Java doesn't have defaults, which means this method must always
// supply all arguments, and thus won't compile when fields are added.
- if (lang.language != IDLOptions::kJava) {
+ if (lang_.language != IDLOptions::kJava) {
code += " = ";
- code += GenDefaultValueBasic(lang, parser, field.value);
+ code += GenDefaultValueBasic(field.value);
}
}
code += ") {\n builder.";
- code += FunctionStart(lang, 'S') + "tartObject(";
+ code += FunctionStart('S') + "tartObject(";
code += NumToString(struct_def.fields.vec.size()) + ");\n";
for (size_t size = struct_def.sortbysize ? sizeof(largest_scalar_t) : 1;
size;
@@ -1005,7 +1023,7 @@ static void GenStruct(const LanguageParameters &lang, const Parser &parser,
(!struct_def.sortbysize ||
size == SizeOf(field.value.type.base_type))) {
code += " " + struct_def.name + ".";
- code += FunctionStart(lang, 'A') + "dd";
+ code += FunctionStart('A') + "dd";
code += MakeCamel(field.name) + "(builder, " + field.name;
if (!IsScalar(field.value.type.base_type)) code += "Offset";
code += ");\n";
@@ -1013,7 +1031,7 @@ static void GenStruct(const LanguageParameters &lang, const Parser &parser,
}
}
code += " return " + struct_def.name + ".";
- code += FunctionStart(lang, 'E') + "nd" + struct_def.name;
+ code += FunctionStart('E') + "nd" + struct_def.name;
code += "(builder);\n }\n\n";
}
// Generate a set of static methods that allow table construction,
@@ -1021,30 +1039,30 @@ static void GenStruct(const LanguageParameters &lang, const Parser &parser,
// public static void addName(FlatBufferBuilder builder, short name)
// { builder.addShort(id, name, default); }
// Unlike the Create function, these always work.
- code += " public static void " + FunctionStart(lang, 'S') + "tart";
+ code += " public static void " + FunctionStart('S') + "tart";
code += struct_def.name;
code += "(FlatBufferBuilder builder) { builder.";
- code += FunctionStart(lang, 'S') + "tartObject(";
+ code += FunctionStart('S') + "tartObject(";
code += NumToString(struct_def.fields.vec.size()) + "); }\n";
for (auto it = struct_def.fields.vec.begin();
it != struct_def.fields.vec.end(); ++it) {
auto &field = **it;
if (field.deprecated) continue;
- code += " public static void " + FunctionStart(lang, 'A') + "dd";
+ code += " public static void " + FunctionStart('A') + "dd";
code += MakeCamel(field.name);
code += "(FlatBufferBuilder builder, ";
- code += GenTypeBasic(lang, parser, DestinationType(lang, parser, field.value.type, false));
+ code += GenTypeBasic(DestinationType(field.value.type, false));
auto argname = MakeCamel(field.name, false);
if (!IsScalar(field.value.type.base_type)) argname += "Offset";
- code += " " + argname + ") { builder." + FunctionStart(lang, 'A') + "dd";
- code += GenMethod(lang, parser, field.value.type) + "(";
+ code += " " + argname + ") { builder." + FunctionStart('A') + "dd";
+ code += GenMethod(field.value.type) + "(";
code += NumToString(it - struct_def.fields.vec.begin()) + ", ";
- code += SourceCastBasic(lang, parser, field.value.type);
+ code += SourceCastBasic(field.value.type);
code += argname;
- if(!IsScalar(field.value.type.base_type) && field.value.type.base_type != BASE_TYPE_UNION && lang.language == IDLOptions::kCSharp) {
+ if(!IsScalar(field.value.type.base_type) && field.value.type.base_type != BASE_TYPE_UNION && lang_.language == IDLOptions::kCSharp) {
code += ".Value";
}
- code += ", " + GenDefaultValue(lang, parser, field.value, false);
+ code += ", " + GenDefaultValue(field.value, false);
code += "); }\n";
if (field.value.type.base_type == BASE_TYPE_VECTOR) {
auto vector_type = field.value.type.VectorType();
@@ -1052,127 +1070,72 @@ static void GenStruct(const LanguageParameters &lang, const Parser &parser,
auto elem_size = InlineSize(vector_type);
if (!IsStruct(vector_type)) {
// Generate a method to create a vector from a Java array.
- code += " public static " + GenVectorOffsetType(lang) + " " + FunctionStart(lang, 'C') + "reate";
+ code += " public static " + GenVectorOffsetType() + " " + FunctionStart('C') + "reate";
code += MakeCamel(field.name);
code += "Vector(FlatBufferBuilder builder, ";
- code += GenTypeBasic(lang, parser, vector_type) + "[] data) ";
- code += "{ builder." + FunctionStart(lang, 'S') + "tartVector(";
+ code += GenTypeBasic(vector_type) + "[] data) ";
+ code += "{ builder." + FunctionStart('S') + "tartVector(";
code += NumToString(elem_size);
- code += ", data." + FunctionStart(lang, 'L') + "ength, ";
+ code += ", data." + FunctionStart('L') + "ength, ";
code += NumToString(alignment);
code += "); for (int i = data.";
- code += FunctionStart(lang, 'L') + "ength - 1; i >= 0; i--) builder.";
- code += FunctionStart(lang, 'A') + "dd";
- code += GenMethod(lang, parser, vector_type);
+ code += FunctionStart('L') + "ength - 1; i >= 0; i--) builder.";
+ code += FunctionStart('A') + "dd";
+ code += GenMethod(vector_type);
code += "(";
- code += SourceCastBasic(lang, parser, vector_type, false);
+ code += SourceCastBasic(vector_type, false);
code += "data[i]";
- if (lang.language == IDLOptions::kCSharp &&
+ if (lang_.language == IDLOptions::kCSharp &&
(vector_type.base_type == BASE_TYPE_STRUCT || vector_type.base_type == BASE_TYPE_STRING))
code += ".Value";
code += "); return ";
- code += "builder." + FunctionStart(lang, 'E') + "ndVector(); }\n";
+ code += "builder." + FunctionStart('E') + "ndVector(); }\n";
}
// Generate a method to start a vector, data to be added manually after.
- code += " public static void " + FunctionStart(lang, 'S') + "tart";
+ code += " public static void " + FunctionStart('S') + "tart";
code += MakeCamel(field.name);
code += "Vector(FlatBufferBuilder builder, int numElems) ";
- code += "{ builder." + FunctionStart(lang, 'S') + "tartVector(";
+ code += "{ builder." + FunctionStart('S') + "tartVector(";
code += NumToString(elem_size);
code += ", numElems, " + NumToString(alignment);
code += "); }\n";
}
}
- code += " public static " + GenOffsetType(lang, parser, struct_def) + " ";
- code += FunctionStart(lang, 'E') + "nd" + struct_def.name;
+ code += " public static " + GenOffsetType(struct_def) + " ";
+ code += FunctionStart('E') + "nd" + struct_def.name;
code += "(FlatBufferBuilder builder) {\n int o = builder.";
- code += FunctionStart(lang, 'E') + "ndObject();\n";
+ code += FunctionStart('E') + "ndObject();\n";
for (auto it = struct_def.fields.vec.begin();
it != struct_def.fields.vec.end();
++it) {
auto &field = **it;
if (!field.deprecated && field.required) {
- code += " builder." + FunctionStart(lang, 'R') + "equired(o, ";
+ code += " builder." + FunctionStart('R') + "equired(o, ";
code += NumToString(field.value.offset);
code += "); // " + field.name + "\n";
}
}
- code += " return " + GenOffsetConstruct(lang, parser, struct_def, "o") + ";\n }\n";
- if (parser.root_struct_def_ == &struct_def) {
+ code += " return " + GenOffsetConstruct(struct_def, "o") + ";\n }\n";
+ if (parser_.root_struct_def_ == &struct_def) {
code += " public static void ";
- code += FunctionStart(lang, 'F') + "inish" + struct_def.name;
- code += "Buffer(FlatBufferBuilder builder, " + GenOffsetType(lang, parser, struct_def) + " offset) {";
- code += " builder." + FunctionStart(lang, 'F') + "inish(offset";
- if (lang.language == IDLOptions::kCSharp) {
+ code += FunctionStart('F') + "inish" + struct_def.name;
+ code += "Buffer(FlatBufferBuilder builder, " + GenOffsetType(struct_def) + " offset) {";
+ code += " builder." + FunctionStart('F') + "inish(offset";
+ if (lang_.language == IDLOptions::kCSharp) {
code += ".Value";
}
- if (parser.file_identifier_.length())
- code += ", \"" + parser.file_identifier_ + "\"";
+ if (parser_.file_identifier_.length())
+ code += ", \"" + parser_.file_identifier_ + "\"";
code += "); }\n";
}
}
- code += "};\n\n";
+ code += "}";
+ // Java does not need the closing semi-colon on class definitions.
+ code += (lang_.language != IDLOptions::kJava) ? ";" : "";
+ code += "\n\n";
}
-
-namespace general {
-class GeneralGenerator : public BaseGenerator {
- public:
- GeneralGenerator(const Parser &parser, const std::string &path,
- const std::string &file_name)
- : BaseGenerator(parser, path, file_name){};
- bool generate() {
- assert(parser_.opts.lang <= IDLOptions::kMAX);
- auto lang = language_parameters[parser_.opts.lang];
- std::string one_file_code;
-
- for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
- ++it) {
- std::string enumcode;
- GenEnum(lang, parser_, **it, &enumcode);
- if (parser_.opts.one_file) {
- one_file_code += enumcode;
- } else {
- if (!SaveType(lang, (**it).name, enumcode, false)) return false;
- }
- }
-
- for (auto it = parser_.structs_.vec.begin();
- it != parser_.structs_.vec.end(); ++it) {
- std::string declcode;
- GenStruct(lang, parser_, **it, &declcode);
- if (parser_.opts.one_file) {
- one_file_code += declcode;
- } else {
- if (!SaveType(lang, (**it).name, declcode, true)) return false;
- }
- }
-
- if (parser_.opts.one_file) {
- return SaveType(lang, file_name_, one_file_code, true);
- }
- return true;
- }
-
- // Save out the generated code for a single class while adding
- // declaration boilerplate.
- bool SaveType(const LanguageParameters &lang, const std::string &defname,
- const std::string &classcode, bool needs_includes) {
- if (!classcode.length()) return true;
-
- std::string code;
- code = code + "// " + FlatBuffersGeneratedWarning();
- std::string namespace_name = FullNamespace(".");
- if (!namespace_name.empty()) {
- code += lang.namespace_ident + namespace_name + lang.namespace_begin;
- code += "\n\n";
- }
- if (needs_includes) code += lang.includes;
- code += classcode;
- if (!namespace_name.empty()) code += lang.namespace_end;
- auto filename = namespace_dir_ + defname + lang.file_extension;
- return SaveFile(filename.c_str(), code, false);
- }
+ const LanguageParameters & lang_;
};
} // namespace general
@@ -1188,19 +1151,25 @@ std::string GeneralMakeRule(const Parser &parser, const std::string &path,
auto lang = language_parameters[parser.opts.lang];
std::string make_rule;
- std::string directory =
- BaseGenerator::NamespaceDir(parser, path) + kPathSeparator;
for (auto it = parser.enums_.vec.begin(); it != parser.enums_.vec.end();
++it) {
+ auto &enum_def = **it;
if (make_rule != "") make_rule += " ";
- make_rule += directory + (**it).name + lang.file_extension;
+ std::string directory =
+ BaseGenerator::NamespaceDir(parser, path, *enum_def.defined_namespace) +
+ kPathSeparator;
+ make_rule += directory + enum_def.name + lang.file_extension;
}
for (auto it = parser.structs_.vec.begin(); it != parser.structs_.vec.end();
++it) {
+ auto &struct_def = **it;
if (make_rule != "") make_rule += " ";
- make_rule += directory + (**it).name + lang.file_extension;
+ std::string directory =
+ BaseGenerator::NamespaceDir(parser, path, *struct_def.defined_namespace) +
+ kPathSeparator;
+ make_rule += directory + struct_def.name + lang.file_extension;
}
make_rule += ": ";
diff --git a/src/idl_gen_go.cpp b/src/idl_gen_go.cpp
index 0c624240..1f6b103e 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) {
@@ -529,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) {
@@ -624,7 +667,8 @@ class GoGenerator : public BaseGenerator {
public:
GoGenerator(const Parser &parser, const std::string &path,
const std::string &file_name)
- : BaseGenerator(parser, path, file_name){};
+ : BaseGenerator(parser, path, file_name, "" /* not used*/,
+ "" /* not used */){};
bool generate() {
for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
++it) {
@@ -663,9 +707,10 @@ class GoGenerator : public BaseGenerator {
if (!classcode.length()) return true;
std::string code = "";
- BeginFile(LastNamespacePart(), needs_imports, &code);
+ BeginFile(LastNamespacePart(*def.defined_namespace), needs_imports, &code);
code += classcode;
- std::string filename = namespace_dir_ + def.name + ".go";
+ std::string filename =
+ NamespaceDir(*def.defined_namespace) + def.name + ".go";
return SaveFile(filename.c_str(), code, false);
}
};
@@ -678,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
new file mode 100644
index 00000000..6ada3e87
--- /dev/null
+++ b/src/idl_gen_grpc.cpp
@@ -0,0 +1,217 @@
+/*
+ * Copyright 2014 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// independent from idl_parser, since this code is not needed for most clients
+
+#include "flatbuffers/flatbuffers.h"
+#include "flatbuffers/idl.h"
+#include "flatbuffers/util.h"
+
+#include "src/compiler/cpp_generator.h"
+
+namespace flatbuffers {
+
+class FlatBufMethod : public grpc_cpp_generator::Method {
+ public:
+ enum Streaming { kNone, kClient, kServer, kBiDi };
+
+ FlatBufMethod(const RPCCall *method)
+ : method_(method) {
+ streaming_ = kNone;
+ auto val = method_->attributes.Lookup("streaming");
+ if (val) {
+ if (val->constant == "client") streaming_ = kClient;
+ if (val->constant == "server") streaming_ = kServer;
+ if (val->constant == "bidi") streaming_ = kBiDi;
+ }
+ }
+
+ std::string name() const { return method_->name; }
+
+ std::string GRPCType(const StructDef &sd) const {
+ return "flatbuffers::BufferRef<" + sd.name + ">";
+ }
+
+ std::string input_type_name() const {
+ return GRPCType(*method_->request);
+ }
+ std::string output_type_name() const {
+ return GRPCType(*method_->response);
+ }
+
+ bool NoStreaming() const { return streaming_ == kNone; }
+ bool ClientOnlyStreaming() const { return streaming_ == kClient; }
+ bool ServerOnlyStreaming() const { return streaming_ == kServer; }
+ bool BidiStreaming() const { return streaming_ == kBiDi; }
+
+ private:
+ const RPCCall *method_;
+ Streaming streaming_;
+};
+
+class FlatBufService : public grpc_cpp_generator::Service {
+ public:
+ FlatBufService(const ServiceDef *service) : service_(service) {}
+
+ std::string name() const { return service_->name; }
+
+ int method_count() const {
+ return static_cast<int>(service_->calls.vec.size());
+ };
+
+ std::unique_ptr<const grpc_cpp_generator::Method> method(int i) const {
+ return std::unique_ptr<const grpc_cpp_generator::Method>(
+ new FlatBufMethod(service_->calls.vec[i]));
+ };
+
+ private:
+ const ServiceDef *service_;
+};
+
+class FlatBufPrinter : public grpc_cpp_generator::Printer {
+ public:
+ FlatBufPrinter(std::string *str)
+ : str_(str), escape_char_('$'), indent_(0) {}
+
+ void Print(const std::map<std::string, std::string> &vars,
+ const char *string_template) {
+ std::string s = string_template;
+ // Replace any occurrences of strings in "vars" that are surrounded
+ // by the escape character by what they're mapped to.
+ size_t pos;
+ while ((pos = s.find(escape_char_)) != std::string::npos) {
+ // Found an escape char, must also find the closing one.
+ size_t pos2 = s.find(escape_char_, pos + 1);
+ // If placeholder not closed, ignore.
+ if (pos2 == std::string::npos) break;
+ auto it = vars.find(s.substr(pos + 1, pos2 - pos - 1));
+ // If unknown placeholder, ignore.
+ if (it == vars.end()) break;
+ // Subtitute placeholder.
+ s.replace(pos, pos2 - pos + 1, it->second);
+ }
+ Print(s.c_str());
+ }
+
+ void Print(const char *s) {
+ // Add this string, but for each part separated by \n, add indentation.
+ for (;;) {
+ // Current indentation.
+ str_->insert(str_->end(), indent_ * 2, ' ');
+ // See if this contains more than one line.
+ const char * lf = strchr(s, '\n');
+ if (lf) {
+ (*str_) += std::string(s, lf + 1);
+ s = lf + 1;
+ if (!*s) break; // Only continue if there's more lines.
+ } else {
+ (*str_) += s;
+ break;
+ }
+ }
+ }
+
+ void Indent() { indent_++; }
+ void Outdent() { indent_--; assert(indent_ >= 0); }
+
+ private:
+ std::string *str_;
+ char escape_char_;
+ int indent_;
+};
+
+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 {
+ return StripExtension(file_name_);
+ }
+
+ std::string message_header_ext() const { return "_generated.h"; }
+ std::string service_header_ext() const { return ".grpc.fb.h"; }
+
+ std::string package() const {
+ return parser_.namespaces_.back()->GetFullyQualifiedName("");
+ }
+
+ std::vector<std::string> package_parts() const {
+ return parser_.namespaces_.back()->components;
+ }
+
+ std::string additional_headers() const {
+ return "#include \"flatbuffers/grpc.h\"\n";
+ }
+
+ int service_count() const {
+ return static_cast<int>(parser_.services_.vec.size());
+ };
+
+ std::unique_ptr<const grpc_cpp_generator::Service> service(int i) const {
+ return std::unique_ptr<const grpc_cpp_generator::Service> (
+ new FlatBufService(parser_.services_.vec[i]));
+ }
+
+ std::unique_ptr<grpc_cpp_generator::Printer> CreatePrinter(std::string *str) const {
+ return std::unique_ptr<grpc_cpp_generator::Printer>(
+ new FlatBufPrinter(str));
+ }
+
+ private:
+ const Parser &parser_;
+ const std::string &file_name_;
+};
+
+bool GenerateGRPC(const Parser &parser,
+ const std::string &/*path*/,
+ const std::string &file_name) {
+
+ int nservices = 0;
+ for (auto it = parser.services_.vec.begin();
+ it != parser.services_.vec.end(); ++it) {
+ if (!(*it)->generated) nservices++;
+ }
+ if (!nservices) return true;
+
+ grpc_cpp_generator::Parameters generator_parameters;
+ // TODO(wvo): make the other parameters in this struct configurable.
+ generator_parameters.use_system_headers = true;
+
+ FlatBufFile fbfile(parser, file_name);
+
+ std::string header_code =
+ grpc_cpp_generator::GetHeaderPrologue(&fbfile, generator_parameters) +
+ grpc_cpp_generator::GetHeaderIncludes(&fbfile, generator_parameters) +
+ grpc_cpp_generator::GetHeaderServices(&fbfile, generator_parameters) +
+ grpc_cpp_generator::GetHeaderEpilogue(&fbfile, generator_parameters);
+
+ std::string source_code =
+ grpc_cpp_generator::GetSourcePrologue(&fbfile, generator_parameters) +
+ grpc_cpp_generator::GetSourceIncludes(&fbfile, generator_parameters) +
+ grpc_cpp_generator::GetSourceServices(&fbfile, generator_parameters) +
+ grpc_cpp_generator::GetSourceEpilogue(&fbfile, generator_parameters);
+
+ return flatbuffers::SaveFile((file_name + ".grpc.fb.h").c_str(),
+ header_code, false) &&
+ flatbuffers::SaveFile((file_name + ".grpc.fb.cc").c_str(),
+ source_code, false);
+}
+
+} // namespace flatbuffers
+
diff --git a/src/idl_gen_js.cpp b/src/idl_gen_js.cpp
index d724b80f..32a06f1e 100644
--- a/src/idl_gen_js.cpp
+++ b/src/idl_gen_js.cpp
@@ -22,14 +22,71 @@
#include "flatbuffers/code_generators.h"
namespace flatbuffers {
+
+static std::string GeneratedFileName(const std::string &path,
+ const std::string &file_name) {
+ return path + file_name + "_generated.js";
+}
+
namespace js {
+// Iterate through all definitions we haven't generate code for (enums, structs,
+// and tables) and output them to a single file.
+class JsGenerator : public BaseGenerator {
+ public:
+ JsGenerator(const Parser &parser, const std::string &path,
+ const std::string &file_name)
+ : BaseGenerator(parser, path, file_name, "", "."){};
+ // Iterate through all definitions we haven't generate code for (enums,
+ // structs, and tables) and output them to a single file.
+ bool generate() {
+ if (IsEverythingGenerated()) return true;
+
+ std::string enum_code, struct_code, exports_code, code;
+ generateEnums(&enum_code, &exports_code);
+ generateStructs(&struct_code, &exports_code);
+
+ code = code + "// " + FlatBuffersGeneratedWarning();
+
+ // Generate code for all the namespace declarations.
+ GenNamespaces(&code, &exports_code);
+
+ // Output the main declaration code from above.
+ code += enum_code;
+ code += struct_code;
+
+ if (!exports_code.empty() && !parser_.opts.skip_js_exports) {
+ code += "// Exports for Node.js and RequireJS\n";
+ code += exports_code;
+ }
+
+ return SaveFile(GeneratedFileName(path_, file_name_).c_str(), code, false);
+ }
+
+ private:
+ // Generate code for all enums.
+ void generateEnums(std::string *enum_code_ptr,
+ std::string *exports_code_ptr) {
+ for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
+ ++it) {
+ auto &enum_def = **it;
+ GenEnum(enum_def, enum_code_ptr, exports_code_ptr);
+ }
+ }
-static void GenNamespaces(const Parser &parser, std::string *code_ptr,
- std::string *exports_ptr) {
+ // Generate code for all structs.
+ void generateStructs(std::string *decl_code_ptr,
+ std::string *exports_code_ptr) {
+ for (auto it = parser_.structs_.vec.begin();
+ it != parser_.structs_.vec.end(); ++it) {
+ auto &struct_def = **it;
+ GenStruct(struct_def, decl_code_ptr, exports_code_ptr);
+ }
+ }
+ void GenNamespaces(std::string *code_ptr, std::string *exports_ptr) {
std::set<std::string> namespaces;
- for (auto it = parser.namespaces_.begin();
- it != parser.namespaces_.end(); ++it) {
+ for (auto it = parser_.namespaces_.begin();
+ it != parser_.namespaces_.end(); ++it) {
std::string namespace_so_far;
// Gather all parent namespaces for this namespace
@@ -62,22 +119,6 @@ static void GenNamespaces(const Parser &parser, std::string *code_ptr,
}
}
-// Ensure that a type is prefixed with its namespace whenever it is used
-// outside of its namespace.
-static std::string WrapInNameSpace(const Namespace *ns,
- const std::string &name) {
- std::string qualified_name;
- for (auto it = ns->components.begin();
- it != ns->components.end(); ++it) {
- qualified_name += *it + ".";
- }
- return qualified_name + name;
-}
-
-static std::string WrapInNameSpace(const Definition &def) {
- return WrapInNameSpace(def.defined_namespace, def.name);
-}
-
// Generate a documentation comment, if available.
static void GenDocComment(const std::vector<std::string> &dc,
std::string *code_ptr,
@@ -123,7 +164,7 @@ static void GenDocComment(std::string *code_ptr,
}
// Generate an enum declaration and an enum string lookup table.
-static void GenEnum(EnumDef &enum_def, std::string *code_ptr,
+void GenEnum(EnumDef &enum_def, std::string *code_ptr,
std::string *exports_ptr) {
if (enum_def.generated) return;
std::string &code = *code_ptr;
@@ -170,7 +211,7 @@ static std::string GenType(const Type &type) {
}
}
-static std::string GenGetter(const Type &type, const std::string &arguments) {
+std::string GenGetter(const Type &type, const std::string &arguments) {
switch (type.base_type) {
case BASE_TYPE_STRING: return "this.bb.__string" + arguments;
case BASE_TYPE_STRUCT: return "this.bb.__struct" + arguments;
@@ -190,7 +231,7 @@ static std::string GenGetter(const Type &type, const std::string &arguments) {
}
}
-static std::string GenDefaultValue(const Value &value, const std::string &context) {
+std::string GenDefaultValue(const Value &value, const std::string &context) {
if (value.type.enum_def) {
if (auto val = value.type.enum_def->ReverseLookup(
atoi(value.constant.c_str()), false)) {
@@ -217,7 +258,7 @@ static std::string GenDefaultValue(const Value &value, const std::string &contex
}
}
-static std::string GenTypeName(const Type &type, bool input) {
+std::string GenTypeName(const Type &type, bool input) {
if (!input) {
if (type.base_type == BASE_TYPE_STRING) {
return "string|Uint8Array";
@@ -269,7 +310,7 @@ static std::string MaybeScale(T value) {
return value != 1 ? " * " + NumToString(value) : "";
}
-static void GenStructArgs(const StructDef &struct_def,
+void GenStructArgs(const StructDef &struct_def,
std::string *annotations,
std::string *arguments,
const std::string &nameprefix) {
@@ -320,8 +361,7 @@ static void GenStructBody(const StructDef &struct_def,
}
// Generate an accessor struct with constructor for a flatbuffers struct.
-static void GenStruct(const Parser &parser, StructDef &struct_def,
- std::string *code_ptr, std::string *exports_ptr) {
+void GenStruct(StructDef &struct_def, std::string *code_ptr, std::string *exports_ptr) {
if (struct_def.generated) return;
std::string &code = *code_ptr;
std::string &exports = *exports_ptr;
@@ -375,13 +415,13 @@ static void GenStruct(const Parser &parser, StructDef &struct_def,
code += "};\n\n";
// Generate the identifier check method
- if (parser.root_struct_def_ == &struct_def &&
- !parser.file_identifier_.empty()) {
+ if (parser_.root_struct_def_ == &struct_def &&
+ !parser_.file_identifier_.empty()) {
GenDocComment(code_ptr,
"@param {flatbuffers.ByteBuffer} bb\n"
"@returns {boolean}");
code += object_name + ".bufferHasIdentifier = function(bb) {\n";
- code += " return bb.__has_identifier('" + parser.file_identifier_;
+ code += " return bb.__has_identifier('" + parser_.file_identifier_;
code += "');\n};\n\n";
}
}
@@ -644,83 +684,21 @@ static void GenStruct(const Parser &parser, StructDef &struct_def,
code += "};\n\n";
// Generate the method to complete buffer construction
- if (parser.root_struct_def_ == &struct_def) {
+ if (parser_.root_struct_def_ == &struct_def) {
GenDocComment(code_ptr,
"@param {flatbuffers.Builder} builder\n"
"@param {flatbuffers.Offset} offset");
code += object_name + ".finish" + struct_def.name + "Buffer";
code += " = function(builder, offset) {\n";
code += " builder.finish(offset";
- if (!parser.file_identifier_.empty()) {
- code += ", '" + parser.file_identifier_ + "'";
+ if (!parser_.file_identifier_.empty()) {
+ code += ", '" + parser_.file_identifier_ + "'";
}
code += ");\n";
code += "};\n\n";
}
}
}
-
-} // namespace js
-
-static std::string GeneratedFileName(const std::string &path,
- const std::string &file_name) {
- return path + file_name + "_generated.js";
-}
-
-namespace js {
-// Iterate through all definitions we haven't generate code for (enums, structs,
-// and tables) and output them to a single file.
-class JsGenerator : public BaseGenerator {
- public:
- JsGenerator(const Parser &parser, const std::string &path,
- const std::string &file_name)
- : BaseGenerator(parser, path, file_name){};
- // Iterate through all definitions we haven't generate code for (enums,
- // structs, and tables) and output them to a single file.
- bool generate() {
- if (IsEverythingGenerated()) return true;
-
- std::string enum_code, struct_code, exports_code, code;
- generateEnums(&enum_code, &exports_code);
- generateStructs(&struct_code, &exports_code);
-
- code = code + "// " + FlatBuffersGeneratedWarning();
-
- // Generate code for all the namespace declarations.
- GenNamespaces(parser_, &code, &exports_code);
-
- // Output the main declaration code from above.
- code += enum_code;
- code += struct_code;
-
- if (!exports_code.empty() && !parser_.opts.skip_js_exports) {
- code += "// Exports for Node.js and RequireJS\n";
- code += exports_code;
- }
-
- return SaveFile(GeneratedFileName(path_, file_name_).c_str(), code, false);
- }
-
- private:
- // Generate code for all enums.
- void generateEnums(std::string *enum_code_ptr,
- std::string *exports_code_ptr) {
- for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
- ++it) {
- auto &enum_def = **it;
- GenEnum(enum_def, enum_code_ptr, exports_code_ptr);
- }
- }
-
- // Generate code for all structs.
- void generateStructs(std::string *decl_code_ptr,
- std::string *exports_code_ptr) {
- for (auto it = parser_.structs_.vec.begin();
- it != parser_.structs_.vec.end(); ++it) {
- auto &struct_def = **it;
- GenStruct(parser_, struct_def, decl_code_ptr, exports_code_ptr);
- }
- }
};
} // namespace js
diff --git a/src/idl_gen_php.cpp b/src/idl_gen_php.cpp
index 599d5571..af3b06d5 100644
--- a/src/idl_gen_php.cpp
+++ b/src/idl_gen_php.cpp
@@ -25,35 +25,74 @@
namespace flatbuffers {
namespace php {
+ // Hardcode spaces per indentation.
+ const std::string Indent = " ";
+ class PhpGenerator : public BaseGenerator {
+ public:
+ PhpGenerator(const Parser &parser, const std::string &path,
+ const std::string &file_name)
+ : BaseGenerator(parser, path, file_name, "\\", "\\"){};
+ bool generate() {
+ if (!generateEnums()) return false;
+ if (!generateStructs()) return false;
+ return true;
+ }
- static std::string GenGetter(const Type &type);
- static std::string GenDefaultValue(const Value &value);
- static std::string GenMethod(const FieldDef &field);
- static void GenStructBuilder(const StructDef &struct_def,
- std::string *code_ptr);
- static std::string GenTypeBasic(const Type &type);
- static std::string GenTypeGet(const Type &type);
-
- // Ensure that a type is prefixed with its namespace whenever it is used
- // outside of its namespace.
- static std::string WrapInNameSpace(const Namespace *ns,
- const std::string &name) {
- std::string qualified_name = "\\";
- for (auto it = ns->components.begin();
- it != ns->components.end(); ++it) {
- qualified_name += *it + "\\";
+ private:
+ bool generateEnums() {
+ for (auto it = parser_.enums_.vec.begin();
+ it != parser_.enums_.vec.end(); ++it) {
+ auto &enum_def = **it;
+ std::string enumcode;
+ GenEnum(enum_def, &enumcode);
+ if (!SaveType(enum_def, enumcode, false)) return false;
+ }
+ return true;
}
- return qualified_name + name;
- }
- static std::string WrapInNameSpace(const Definition &def) {
- return WrapInNameSpace(def.defined_namespace, def.name);
- }
+ bool generateStructs() {
+ for (auto it = parser_.structs_.vec.begin();
+ it != parser_.structs_.vec.end(); ++it) {
+ auto &struct_def = **it;
+ std::string declcode;
+ GenStruct(struct_def, &declcode);
+ if (!SaveType(struct_def, declcode, true)) return false;
+ }
+ return true;
+ }
+ // Begin by declaring namespace and imports.
+ void BeginFile(const std::string name_space_name,
+ const bool needs_imports, std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ code += "<?php\n";
+ code = code + "// " + FlatBuffersGeneratedWarning();
+ code += "namespace " + name_space_name + ";\n\n";
- // Hardcode spaces per indentation.
- const std::string Indent = " ";
+ if (needs_imports) {
+ code += "use \\Google\\FlatBuffers\\Struct;\n";
+ code += "use \\Google\\FlatBuffers\\Table;\n";
+ code += "use \\Google\\FlatBuffers\\ByteBuffer;\n";
+ code += "use \\Google\\FlatBuffers\\FlatBufferBuilder;\n";
+ code += "\n";
+ }
+ }
+
+ // Save out the generated code for a Php Table type.
+ bool SaveType(const Definition &def, const std::string &classcode,
+ bool needs_imports) {
+ if (!classcode.length()) return true;
+
+ std::string code = "";
+ BeginFile(FullNamespace("\\", *def.defined_namespace),
+ needs_imports, &code);
+ code += classcode;
+ std::string filename = NamespaceDir(*def.defined_namespace) +
+ kPathSeparator + def.name + ".php";
+ return SaveFile(filename.c_str(), code, false);
+ }
+
// Begin a class declaration.
static void BeginClass(const StructDef &struct_def, std::string *code_ptr) {
std::string &code = *code_ptr;
@@ -189,8 +228,7 @@ namespace php {
}
// Get the value of a table's scalar.
- static void GetScalarFieldOfTable(const FieldDef &field,
- std::string *code_ptr) {
+ void GetScalarFieldOfTable(const FieldDef &field, std::string *code_ptr) {
std::string &code = *code_ptr;
std::string getter = GenGetter(field.value.type);
@@ -213,8 +251,7 @@ namespace php {
// Get a struct by initializing an existing struct.
// Specific to Struct.
- static void GetStructFieldOfStruct(const FieldDef &field,
- std::string *code_ptr) {
+ void GetStructFieldOfStruct(const FieldDef &field, std::string *code_ptr) {
std::string &code = *code_ptr;
code += Indent + "/**\n";
@@ -233,8 +270,7 @@ namespace php {
// Get a struct by initializing an existing struct.
// Specific to Table.
- static void GetStructFieldOfTable(const FieldDef &field,
- std::string *code_ptr) {
+ void GetStructFieldOfTable(const FieldDef &field, std::string *code_ptr) {
std::string &code = *code_ptr;
code += Indent + "public function get";
@@ -260,8 +296,7 @@ namespace php {
}
// Get the value of a string.
- static void GetStringField(const FieldDef &field,
- std::string *code_ptr) {
+ void GetStringField(const FieldDef &field, std::string *code_ptr) {
std::string &code = *code_ptr;
code += Indent + "public function get";
code += MakeCamel(field.name);
@@ -278,8 +313,7 @@ namespace php {
}
// Get the value of a union from an object.
- static void GetUnionField(const FieldDef &field,
- std::string *code_ptr) {
+ void GetUnionField(const FieldDef &field, std::string *code_ptr) {
std::string &code = *code_ptr;
code += Indent + "/**\n";
@@ -298,9 +332,8 @@ namespace php {
}
// Get the value of a vector's struct member.
- static void GetMemberOfVectorOfStruct(const StructDef &struct_def,
- const FieldDef &field,
- std::string *code_ptr) {
+ void GetMemberOfVectorOfStruct(const StructDef &struct_def,
+ const FieldDef &field, std::string *code_ptr) {
std::string &code = *code_ptr;
auto vectortype = field.value.type.VectorType();
@@ -362,7 +395,7 @@ namespace php {
// Get the value of a vector's non-struct member. Uses a named return
// argument to conveniently set the zero value for the result.
- static void GetMemberOfVectorOfNonStruct(const FieldDef &field,
+ void GetMemberOfVectorOfNonStruct(const FieldDef &field,
std::string *code_ptr) {
std::string &code = *code_ptr;
auto vectortype = field.value.type.VectorType();
@@ -603,9 +636,7 @@ namespace php {
}
// Get the offset of the end of a table.
- static void GetEndOffsetOnTable(const Parser &parser,
- const StructDef &struct_def,
- std::string *code_ptr) {
+ void GetEndOffsetOnTable(const StructDef &struct_def, std::string *code_ptr) {
std::string &code = *code_ptr;
@@ -632,7 +663,7 @@ namespace php {
code += Indent + Indent + "return $o;\n";
code += Indent + "}\n";
- if (parser.root_struct_def_ == &struct_def) {
+ if (parser_.root_struct_def_ == &struct_def) {
code += "\n";
code += Indent + "public static function finish";
code += struct_def.name;
@@ -640,16 +671,15 @@ namespace php {
code += Indent + "{\n";
code += Indent + Indent + "$builder->finish($offset";
- if (parser.file_identifier_.length())
- code += ", \"" + parser.file_identifier_ + "\"";
+ if (parser_.file_identifier_.length())
+ code += ", \"" + parser_.file_identifier_ + "\"";
code += ");\n";
code += Indent + "}\n";
}
}
// Generate a struct field, conditioned on its child type(s).
- static void GenStructAccessor(const StructDef &struct_def,
- const FieldDef &field,
+ void GenStructAccessor(const StructDef &struct_def, const FieldDef &field,
std::string *code_ptr) {
GenComment(field.doc_comment, code_ptr, nullptr);
@@ -696,9 +726,7 @@ namespace php {
}
// Generate table constructors, conditioned on its members' types.
- static void GenTableBuilders(const Parser &parser,
- const StructDef &struct_def,
- std::string *code_ptr) {
+ void GenTableBuilders(const StructDef &struct_def, std::string *code_ptr) {
GetStartOfTable(struct_def, code_ptr);
for (auto it = struct_def.fields.vec.begin();
@@ -725,11 +753,11 @@ namespace php {
}
}
- GetEndOffsetOnTable(parser, struct_def, code_ptr);
+ GetEndOffsetOnTable(struct_def, code_ptr);
}
// Generate struct or table methods.
- static void GenStruct(const Parser &parser, const StructDef &struct_def,
+ void GenStruct(const StructDef &struct_def,
std::string *code_ptr) {
if (struct_def.generated) return;
@@ -744,13 +772,13 @@ namespace php {
std::string &code = *code_ptr;
if (!struct_def.fixed) {
- if (parser.file_identifier_.length()) {
+ if (parser_.file_identifier_.length()) {
// Return the identifier
code += Indent + "public static function " + struct_def.name;
code += "Identifier()\n";
code += Indent + "{\n";
code += Indent + Indent + "return \"";
- code += parser.file_identifier_ + "\";\n";
+ code += parser_.file_identifier_ + "\";\n";
code += Indent + "}\n\n";
// Check if a buffer has the identifier.
@@ -763,12 +791,12 @@ namespace php {
code += Indent + "}\n\n";
}
- if (parser.file_extension_.length()) {
+ if (parser_.file_extension_.length()) {
// Return the extension
code += Indent + "public static function " + struct_def.name;
code += "Extension()\n";
code += Indent + "{\n";
- code += Indent + Indent + "return \"" + parser.file_extension_;
+ code += Indent + Indent + "return \"" + parser_.file_extension_;
code += "\";\n";
code += Indent + "}\n\n";
}
@@ -791,7 +819,7 @@ namespace php {
GenStructBuilder(struct_def, code_ptr);
} else {
// Create a set of functions that allow table construction.
- GenTableBuilders(parser, struct_def, code_ptr);
+ GenTableBuilders(struct_def, code_ptr);
}
EndClass(code_ptr);
}
@@ -859,7 +887,7 @@ namespace php {
return ctypename[type.base_type];
}
- static std::string GenDefaultValue(const Value &value) {
+ std::string GenDefaultValue(const Value &value) {
if (value.type.enum_def) {
if (auto val = value.type.enum_def->ReverseLookup(
atoi(value.constant.c_str()), false)) {
@@ -927,71 +955,7 @@ namespace php {
code += Indent + Indent + "return $builder->offset();\n";
code += Indent + "}\n";
}
-
- class PhpGenerator : public BaseGenerator {
- public:
- PhpGenerator(const Parser &parser, const std::string &path,
- const std::string &file_name)
- : BaseGenerator(parser, path, file_name){};
- bool generate() {
- if (!generateEnums()) return false;
- if (!generateStructs()) return false;
- return true;
- }
-
- private:
- bool generateEnums() {
- for (auto it = parser_.enums_.vec.begin();
- it != parser_.enums_.vec.end(); ++it) {
- auto &enum_def = **it;
- std::string enumcode;
- GenEnum(enum_def, &enumcode);
- if (!SaveType(enum_def, enumcode, false)) return false;
- }
- return true;
- }
-
- bool generateStructs() {
- for (auto it = parser_.structs_.vec.begin();
- it != parser_.structs_.vec.end(); ++it) {
- auto &struct_def = **it;
- std::string declcode;
- GenStruct(parser_, struct_def, &declcode);
- if (!SaveType(struct_def, declcode, true)) return false;
- }
- return true;
- }
-
- // Begin by declaring namespace and imports.
- void BeginFile(const std::string name_space_name,
- const bool needs_imports, std::string *code_ptr) {
- std::string &code = *code_ptr;
- code += "<?php\n";
- code = code + "// " + FlatBuffersGeneratedWarning();
- code += "namespace " + name_space_name + ";\n\n";
-
- if (needs_imports) {
- code += "use \\Google\\FlatBuffers\\Struct;\n";
- code += "use \\Google\\FlatBuffers\\Table;\n";
- code += "use \\Google\\FlatBuffers\\ByteBuffer;\n";
- code += "use \\Google\\FlatBuffers\\FlatBufferBuilder;\n";
- code += "\n";
- }
- }
-
- // Save out the generated code for a Php Table type.
- bool SaveType(const Definition &def, const std::string &classcode,
- bool needs_imports) {
- if (!classcode.length()) return true;
-
- std::string code = "";
- BeginFile(FullNamespace("\\"), needs_imports, &code);
- code += classcode;
-
- std::string filename =
- namespace_dir_ + kPathSeparator + def.name + ".php";
- return SaveFile(filename.c_str(), code, false);
- }
+
};
} // namespace php
diff --git a/src/idl_gen_python.cpp b/src/idl_gen_python.cpp
index 2917854d..52944bfc 100644
--- a/src/idl_gen_python.cpp
+++ b/src/idl_gen_python.cpp
@@ -595,7 +595,8 @@ class PythonGenerator : public BaseGenerator {
public:
PythonGenerator(const Parser &parser, const std::string &path,
const std::string &file_name)
- : BaseGenerator(parser, path, file_name){};
+ : BaseGenerator(parser, path, file_name, "" /* not used */,
+ "" /* not used */){};
bool generate() {
if (!generateEnums()) return false;
if (!generateStructs()) return false;
@@ -651,9 +652,10 @@ class PythonGenerator : public BaseGenerator {
}
std::string code = "";
- BeginFile(LastNamespacePart(), needs_imports, &code);
+ BeginFile(LastNamespacePart(*def.defined_namespace), needs_imports, &code);
code += classcode;
- std::string filename = namespace_dir_ + kPathSeparator + def.name + ".py";
+ std::string filename = NamespaceDir(*def.defined_namespace) +
+ kPathSeparator + def.name + ".py";
return SaveFile(filename.c_str(), code, false);
}
};
diff --git a/src/idl_parser.cpp b/src/idl_parser.cpp
index f5badab1..fc213675 100644
--- a/src/idl_parser.cpp
+++ b/src/idl_parser.cpp
@@ -17,6 +17,14 @@
#include <algorithm>
#include <list>
+#ifdef _WIN32
+#if !defined(_USE_MATH_DEFINES)
+#define _USE_MATH_DEFINES // For M_PI.
+#endif // !defined(_USE_MATH_DEFINES)
+#endif // _WIN32
+
+#include <math.h>
+
#include "flatbuffers/idl.h"
#include "flatbuffers/util.h"
@@ -415,6 +423,12 @@ CheckedError Parser::Next() {
return NoError();
} else if (isdigit(static_cast<unsigned char>(c)) || c == '-') {
const char *start = cursor_ - 1;
+ if (c == '-' && *cursor_ == '0' && (cursor_[1] == 'x' || cursor_[1] == 'X')) {
+ ++start;
+ ++cursor_;
+ attribute_.append(&c, &c + 1);
+ c = '0';
+ }
if (c == '0' && (*cursor_ == 'x' || *cursor_ == 'X')) {
cursor_++;
while (isxdigit(static_cast<unsigned char>(*cursor_))) cursor_++;
@@ -575,9 +589,9 @@ CheckedError Parser::ParseField(StructDef &struct_def) {
FieldDef *typefield = nullptr;
if (type.base_type == BASE_TYPE_UNION) {
// For union fields, add a second auto-generated field to hold the type,
- // with _type appended as the name.
- ECHECK(AddField(struct_def, name + "_type", type.enum_def->underlying_type,
- &typefield));
+ // with a special suffix.
+ ECHECK(AddField(struct_def, name + UnionTypeFieldSuffix(),
+ type.enum_def->underlying_type, &typefield));
}
FieldDef *field;
@@ -678,17 +692,45 @@ CheckedError Parser::ParseField(StructDef &struct_def) {
}
CheckedError Parser::ParseAnyValue(Value &val, FieldDef *field,
- size_t parent_fieldn) {
+ size_t parent_fieldn,
+ const StructDef *parent_struct_def) {
switch (val.type.base_type) {
case BASE_TYPE_UNION: {
assert(field);
+ std::string constant;
if (!parent_fieldn ||
- field_stack_.back().second->value.type.base_type != BASE_TYPE_UTYPE)
- return Error("missing type field before this union value: " +
- field->name);
+ field_stack_.back().second->value.type.base_type != BASE_TYPE_UTYPE) {
+ // We haven't seen the type field yet. Sadly a lot of JSON writers
+ // output these in alphabetical order, meaning it comes after this
+ // value. So we scan past the value to find it, then come back here.
+ auto type_name = field->name + UnionTypeFieldSuffix();
+ assert(parent_struct_def);
+ auto type_field = parent_struct_def->fields.Lookup(type_name);
+ assert(type_field); // Guaranteed by ParseField().
+ // Remember where we are in the source file, so we can come back here.
+ auto backup = *static_cast<ParserState *>(this);
+ ECHECK(SkipAnyJsonValue()); // The table.
+ EXPECT(',');
+ auto next_name = attribute_;
+ if (Is(kTokenStringConstant)) {
+ NEXT();
+ } else {
+ EXPECT(kTokenIdentifier);
+ }
+ if (next_name != type_name)
+ return Error("missing type field after this union value: " +
+ type_name);
+ EXPECT(':');
+ Value type_val = type_field->value;
+ ECHECK(ParseAnyValue(type_val, type_field, 0, nullptr));
+ constant = type_val.constant;
+ // Got the information we needed, now rewind:
+ *static_cast<ParserState *>(this) = backup;
+ } else {
+ constant = field_stack_.back().first.constant;
+ }
uint8_t enum_idx;
- ECHECK(atot(field_stack_.back().first.constant.c_str(), *this,
- &enum_idx));
+ ECHECK(atot(constant.c_str(), *this, &enum_idx));
auto enum_val = val.type.enum_def->ReverseLookup(enum_idx);
if (!enum_val) return Error("illegal type id for: " + field->name);
ECHECK(ParseTable(*enum_val->struct_def, &val.constant, nullptr));
@@ -763,7 +805,7 @@ CheckedError Parser::ParseTable(const StructDef &struct_def, std::string *value,
NEXT(); // Ignore this field.
} else {
Value val = field->value;
- ECHECK(ParseAnyValue(val, field, fieldn));
+ ECHECK(ParseAnyValue(val, field, fieldn, &struct_def));
size_t i = field_stack_.size();
// Hardcoded insertion-sort with error-check.
// If fields are specified in order, then this loop exits immediately.
@@ -862,7 +904,7 @@ CheckedError Parser::ParseVector(const Type &type, uoffset_t *ovalue) {
if ((!opts.strict_json || !count) && Is(']')) { NEXT(); break; }
Value val;
val.type = type;
- ECHECK(ParseAnyValue(val, nullptr, 0));
+ ECHECK(ParseAnyValue(val, nullptr, 0, nullptr));
field_stack_.push_back(std::make_pair(val, nullptr));
count++;
if (Is(']')) { NEXT(); break; }
@@ -1004,8 +1046,30 @@ CheckedError Parser::ParseHash(Value &e, FieldDef* field) {
}
CheckedError Parser::ParseSingleValue(Value &e) {
- // First check if this could be a string/identifier enum value:
- if (e.type.base_type != BASE_TYPE_STRING &&
+ // First see if this could be a conversion function:
+ if (token_ == kTokenIdentifier && *cursor_ == '(') {
+ auto functionname = attribute_;
+ NEXT();
+ EXPECT('(');
+ ECHECK(ParseSingleValue(e));
+ EXPECT(')');
+ #define FLATBUFFERS_FN_DOUBLE(name, op) \
+ if (functionname == name) { \
+ auto x = strtod(e.constant.c_str(), nullptr); \
+ e.constant = NumToString(op); \
+ }
+ FLATBUFFERS_FN_DOUBLE("deg", x / M_PI * 180);
+ FLATBUFFERS_FN_DOUBLE("rad", x * M_PI / 180);
+ FLATBUFFERS_FN_DOUBLE("sin", sin(x));
+ FLATBUFFERS_FN_DOUBLE("cos", cos(x));
+ FLATBUFFERS_FN_DOUBLE("tan", tan(x));
+ FLATBUFFERS_FN_DOUBLE("asin", asin(x));
+ FLATBUFFERS_FN_DOUBLE("acos", acos(x));
+ FLATBUFFERS_FN_DOUBLE("atan", atan(x));
+ // TODO(wvo): add more useful conversion functions here.
+ #undef FLATBUFFERS_FN_DOUBLE
+ // Then check if this could be a string/identifier enum value:
+ } else if (e.type.base_type != BASE_TYPE_STRING &&
e.type.base_type != BASE_TYPE_NONE &&
(token_ == kTokenIdentifier || token_ == kTokenStringConstant)) {
if (IsIdentifierStart(attribute_[0])) { // Enum value.
@@ -1150,7 +1214,13 @@ CheckedError Parser::ParseEnum(bool is_union, EnumDef **dest) {
auto full_name = value_name;
std::vector<std::string> value_comment = doc_comment_;
EXPECT(kTokenIdentifier);
- if (is_union) ECHECK(ParseNamespacing(&full_name, &value_name));
+ if (is_union) {
+ ECHECK(ParseNamespacing(&full_name, &value_name));
+ // Since we can't namespace the actual enum identifiers, turn
+ // namespace parts into part of the identifier.
+ value_name = full_name;
+ std::replace(value_name.begin(), value_name.end(), '.', '_');
+ }
auto prevsize = enum_def.vals.vec.size();
auto value = enum_def.vals.vec.size()
? enum_def.vals.vec.back()->value + 1
@@ -1288,7 +1358,8 @@ CheckedError Parser::ParseDecl() {
}
}
- ECHECK(CheckClash(fields, struct_def, "_type", BASE_TYPE_UNION));
+ ECHECK(CheckClash(fields, struct_def, UnionTypeFieldSuffix(),
+ BASE_TYPE_UNION));
ECHECK(CheckClash(fields, struct_def, "Type", BASE_TYPE_UNION));
ECHECK(CheckClash(fields, struct_def, "_length", BASE_TYPE_VECTOR));
ECHECK(CheckClash(fields, struct_def, "Length", BASE_TYPE_VECTOR));
@@ -1358,6 +1429,10 @@ void Parser::MarkGenerated() {
it != structs_.vec.end(); ++it) {
(*it)->generated = true;
}
+ for (auto it = services_.vec.begin();
+ it != services_.vec.end(); ++it) {
+ (*it)->generated = true;
+ }
}
CheckedError Parser::ParseNamespace() {
@@ -2018,4 +2093,57 @@ flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<
}
}
+std::string Parser::ConformTo(const Parser &base) {
+ for (auto sit = structs_.vec.begin(); sit != structs_.vec.end(); ++sit) {
+ auto &struct_def = **sit;
+ auto qualified_name =
+ struct_def.defined_namespace->GetFullyQualifiedName(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.cs b/tests/MyGame/Example/Any.cs
index 1f018ad8..8fdc2fca 100644
--- a/tests/MyGame/Example/Any.cs
+++ b/tests/MyGame/Example/Any.cs
@@ -8,6 +8,7 @@ public enum Any : byte
NONE = 0,
Monster = 1,
TestSimpleTableWithEnum = 2,
+ MyGame_Example2_Monster = 3,
};
diff --git a/tests/MyGame/Example/Any.go b/tests/MyGame/Example/Any.go
index 0322364c..df9f823f 100644
--- a/tests/MyGame/Example/Any.go
+++ b/tests/MyGame/Example/Any.go
@@ -6,4 +6,5 @@ const (
AnyNONE = 0
AnyMonster = 1
AnyTestSimpleTableWithEnum = 2
+ AnyMyGame_Example2_Monster = 3
)
diff --git a/tests/MyGame/Example/Any.java b/tests/MyGame/Example/Any.java
index 27dc1bcb..6e4fb76c 100644
--- a/tests/MyGame/Example/Any.java
+++ b/tests/MyGame/Example/Any.java
@@ -7,9 +7,10 @@ public final class Any {
public static final byte NONE = 0;
public static final byte Monster = 1;
public static final byte TestSimpleTableWithEnum = 2;
+ public static final byte MyGame_Example2_Monster = 3;
- private static final String[] names = { "NONE", "Monster", "TestSimpleTableWithEnum", };
+ 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/Any.php b/tests/MyGame/Example/Any.php
index f04f4ad3..da691760 100644
--- a/tests/MyGame/Example/Any.php
+++ b/tests/MyGame/Example/Any.php
@@ -8,11 +8,13 @@ class Any
const NONE = 0;
const Monster = 1;
const TestSimpleTableWithEnum = 2;
+ const MyGame_Example2_Monster = 3;
private static $names = array(
"NONE",
"Monster",
"TestSimpleTableWithEnum",
+ "MyGame_Example2_Monster",
);
public static function Name($e)
diff --git a/tests/MyGame/Example/Any.py b/tests/MyGame/Example/Any.py
index b642ede0..f1b8d519 100644
--- a/tests/MyGame/Example/Any.py
+++ b/tests/MyGame/Example/Any.py
@@ -6,4 +6,5 @@ class Any(object):
NONE = 0
Monster = 1
TestSimpleTableWithEnum = 2
+ MyGame_Example2_Monster = 3
diff --git a/tests/MyGame/Example/Color.java b/tests/MyGame/Example/Color.java
index 502ec9fb..7c113b72 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.cs b/tests/MyGame/Example/Monster.cs
index 6101f464..fdfd2b0a 100644
--- a/tests/MyGame/Example/Monster.cs
+++ b/tests/MyGame/Example/Monster.cs
@@ -78,8 +78,10 @@ public sealed class Monster : Table {
public bool MutateTestf2(float testf2) { int o = __offset(56); if (o != 0) { bb.PutFloat(o + bb_pos, testf2); return true; } else { return false; } }
public float Testf3 { get { int o = __offset(58); return o != 0 ? bb.GetFloat(o + bb_pos) : (float)0.0f; } }
public bool MutateTestf3(float testf3) { int o = __offset(58); if (o != 0) { bb.PutFloat(o + bb_pos, testf3); return true; } else { return false; } }
+ public string GetTestarrayofstring2(int j) { int o = __offset(60); return o != 0 ? __string(__vector(o) + j * 4) : null; }
+ public int Testarrayofstring2Length { get { int o = __offset(60); return o != 0 ? __vector_len(o) : 0; } }
- public static void StartMonster(FlatBufferBuilder builder) { builder.StartObject(28); }
+ public static void StartMonster(FlatBufferBuilder builder) { builder.StartObject(29); }
public static void AddPos(FlatBufferBuilder builder, Offset<Vec3> posOffset) { builder.AddStruct(0, posOffset.Value, 0); }
public static void AddMana(FlatBufferBuilder builder, short mana) { builder.AddShort(1, mana, 150); }
public static void AddHp(FlatBufferBuilder builder, short hp) { builder.AddShort(2, hp, 100); }
@@ -118,6 +120,9 @@ public sealed class Monster : Table {
public static void AddTestf(FlatBufferBuilder builder, float testf) { builder.AddFloat(25, testf, 3.14159f); }
public static void AddTestf2(FlatBufferBuilder builder, float testf2) { builder.AddFloat(26, testf2, 3.0f); }
public static void AddTestf3(FlatBufferBuilder builder, float testf3) { builder.AddFloat(27, testf3, 0.0f); }
+ public static void AddTestarrayofstring2(FlatBufferBuilder builder, VectorOffset testarrayofstring2Offset) { builder.AddOffset(28, testarrayofstring2Offset.Value, 0); }
+ public static VectorOffset CreateTestarrayofstring2Vector(FlatBufferBuilder builder, StringOffset[] data) { builder.StartVector(4, data.Length, 4); for (int i = data.Length - 1; i >= 0; i--) builder.AddOffset(data[i].Value); return builder.EndVector(); }
+ public static void StartTestarrayofstring2Vector(FlatBufferBuilder builder, int numElems) { builder.StartVector(4, numElems, 4); }
public static Offset<Monster> EndMonster(FlatBufferBuilder builder) {
int o = builder.EndObject();
builder.Required(o, 10); // name
diff --git a/tests/MyGame/Example/Monster.go b/tests/MyGame/Example/Monster.go
index fbd849e8..f4cd18c1 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,7 +399,28 @@ func (rcv *Monster) Testf3() float32 {
return 0.0
}
-func MonsterStart(builder *flatbuffers.Builder) { builder.StartObject(28) }
+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 {
+ a := rcv._tab.Vector(o)
+ return rcv._tab.ByteVector(a + flatbuffers.UOffsetT(j * 4))
+ }
+ return nil
+}
+
+func (rcv *Monster) Testarrayofstring2Length() int {
+ o := flatbuffers.UOffsetT(rcv._tab.Offset(60))
+ if o != 0 {
+ return rcv._tab.VectorLen(o)
+ }
+ return 0
+}
+
+func MonsterStart(builder *flatbuffers.Builder) { builder.StartObject(29) }
func MonsterAddPos(builder *flatbuffers.Builder, pos flatbuffers.UOffsetT) { builder.PrependStructSlot(0, flatbuffers.UOffsetT(pos), 0) }
func MonsterAddMana(builder *flatbuffers.Builder, mana int16) { builder.PrependInt16Slot(1, mana, 150) }
func MonsterAddHp(builder *flatbuffers.Builder, hp int16) { builder.PrependInt16Slot(2, hp, 100) }
@@ -377,4 +460,7 @@ func MonsterStartTestarrayofboolsVector(builder *flatbuffers.Builder, numElems i
func MonsterAddTestf(builder *flatbuffers.Builder, testf float32) { builder.PrependFloat32Slot(25, testf, 3.14159) }
func MonsterAddTestf2(builder *flatbuffers.Builder, testf2 float32) { builder.PrependFloat32Slot(26, testf2, 3.0) }
func MonsterAddTestf3(builder *flatbuffers.Builder, testf3 float32) { builder.PrependFloat32Slot(27, testf3, 0.0) }
+func MonsterAddTestarrayofstring2(builder *flatbuffers.Builder, testarrayofstring2 flatbuffers.UOffsetT) { builder.PrependUOffsetTSlot(28, flatbuffers.UOffsetT(testarrayofstring2), 0) }
+func MonsterStartTestarrayofstring2Vector(builder *flatbuffers.Builder, numElems int) flatbuffers.UOffsetT { return builder.StartVector(4, numElems, 4)
+}
func MonsterEnd(builder *flatbuffers.Builder) flatbuffers.UOffsetT { return builder.EndObject() }
diff --git a/tests/MyGame/Example/Monster.java b/tests/MyGame/Example/Monster.java
index d85e4baa..dc27f844 100644
--- a/tests/MyGame/Example/Monster.java
+++ b/tests/MyGame/Example/Monster.java
@@ -84,8 +84,10 @@ public final class Monster extends Table {
public boolean mutateTestf2(float testf2) { int o = __offset(56); if (o != 0) { bb.putFloat(o + bb_pos, testf2); return true; } else { return false; } }
public float testf3() { int o = __offset(58); return o != 0 ? bb.getFloat(o + bb_pos) : 0.0f; }
public boolean mutateTestf3(float testf3) { int o = __offset(58); if (o != 0) { bb.putFloat(o + bb_pos, testf3); return true; } else { return false; } }
+ public String testarrayofstring2(int j) { int o = __offset(60); return o != 0 ? __string(__vector(o) + j * 4) : null; }
+ public int testarrayofstring2Length() { int o = __offset(60); return o != 0 ? __vector_len(o) : 0; }
- public static void startMonster(FlatBufferBuilder builder) { builder.startObject(28); }
+ public static void startMonster(FlatBufferBuilder builder) { builder.startObject(29); }
public static void addPos(FlatBufferBuilder builder, int posOffset) { builder.addStruct(0, posOffset, 0); }
public static void addMana(FlatBufferBuilder builder, short mana) { builder.addShort(1, mana, 150); }
public static void addHp(FlatBufferBuilder builder, short hp) { builder.addShort(2, hp, 100); }
@@ -124,11 +126,14 @@ public final class Monster extends Table {
public static void addTestf(FlatBufferBuilder builder, float testf) { builder.addFloat(25, testf, 3.14159f); }
public static void addTestf2(FlatBufferBuilder builder, float testf2) { builder.addFloat(26, testf2, 3.0f); }
public static void addTestf3(FlatBufferBuilder builder, float testf3) { builder.addFloat(27, testf3, 0.0f); }
+ public static void addTestarrayofstring2(FlatBufferBuilder builder, int testarrayofstring2Offset) { builder.addOffset(28, testarrayofstring2Offset, 0); }
+ public static int createTestarrayofstring2Vector(FlatBufferBuilder builder, int[] data) { builder.startVector(4, data.length, 4); for (int i = data.length - 1; i >= 0; i--) builder.addOffset(data[i]); return builder.endVector(); }
+ public static void startTestarrayofstring2Vector(FlatBufferBuilder builder, int numElems) { builder.startVector(4, numElems, 4); }
public static int endMonster(FlatBufferBuilder builder) {
int o = builder.endObject();
builder.required(o, 10); // name
return o;
}
public static void finishMonsterBuffer(FlatBufferBuilder builder, int offset) { builder.finish(offset, "MONS"); }
-};
+}
diff --git a/tests/MyGame/Example/Monster.php b/tests/MyGame/Example/Monster.php
index 9f82d5a9..c06cffbc 100644
--- a/tests/MyGame/Example/Monster.php
+++ b/tests/MyGame/Example/Monster.php
@@ -361,21 +361,40 @@ class Monster extends Table
}
/**
+ * @param int offset
+ * @return string
+ */
+ public function getTestarrayofstring2($j)
+ {
+ $o = $this->__offset(60);
+ return $o != 0 ? $this->__string($this->__vector($o) + $j * 4) : 0;
+ }
+
+ /**
+ * @return int
+ */
+ public function getTestarrayofstring2Length()
+ {
+ $o = $this->__offset(60);
+ return $o != 0 ? $this->__vector_len($o) : 0;
+ }
+
+ /**
* @param FlatBufferBuilder $builder
* @return void
*/
public static function startMonster(FlatBufferBuilder $builder)
{
- $builder->StartObject(28);
+ $builder->StartObject(29);
}
/**
* @param FlatBufferBuilder $builder
* @return Monster
*/
- public static function createMonster(FlatBufferBuilder $builder, $pos, $mana, $hp, $name, $inventory, $color, $test_type, $test, $test4, $testarrayofstring, $testarrayoftables, $enemy, $testnestedflatbuffer, $testempty, $testbool, $testhashs32_fnv1, $testhashu32_fnv1, $testhashs64_fnv1, $testhashu64_fnv1, $testhashs32_fnv1a, $testhashu32_fnv1a, $testhashs64_fnv1a, $testhashu64_fnv1a, $testarrayofbools, $testf, $testf2, $testf3)
+ public static function createMonster(FlatBufferBuilder $builder, $pos, $mana, $hp, $name, $inventory, $color, $test_type, $test, $test4, $testarrayofstring, $testarrayoftables, $enemy, $testnestedflatbuffer, $testempty, $testbool, $testhashs32_fnv1, $testhashu32_fnv1, $testhashs64_fnv1, $testhashu64_fnv1, $testhashs32_fnv1a, $testhashu32_fnv1a, $testhashs64_fnv1a, $testhashu64_fnv1a, $testarrayofbools, $testf, $testf2, $testf3, $testarrayofstring2)
{
- $builder->startObject(28);
+ $builder->startObject(29);
self::addPos($builder, $pos);
self::addMana($builder, $mana);
self::addHp($builder, $hp);
@@ -403,6 +422,7 @@ class Monster extends Table
self::addTestf($builder, $testf);
self::addTestf2($builder, $testf2);
self::addTestf3($builder, $testf3);
+ self::addTestarrayofstring2($builder, $testarrayofstring2);
$o = $builder->endObject();
$builder->required($o, 10); // name
return $o;
@@ -819,6 +839,40 @@ class Monster extends Table
/**
* @param FlatBufferBuilder $builder
+ * @param VectorOffset
+ * @return void
+ */
+ public static function addTestarrayofstring2(FlatBufferBuilder $builder, $testarrayofstring2)
+ {
+ $builder->addOffsetX(28, $testarrayofstring2, 0);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param array offset array
+ * @return int vector offset
+ */
+ public static function createTestarrayofstring2Vector(FlatBufferBuilder $builder, array $data)
+ {
+ $builder->startVector(4, count($data), 4);
+ for ($i = count($data) - 1; $i >= 0; $i--) {
+ $builder->addOffset($data[$i]);
+ }
+ return $builder->endVector();
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param int $numElems
+ * @return void
+ */
+ public static function startTestarrayofstring2Vector(FlatBufferBuilder $builder, $numElems)
+ {
+ $builder->startVector(4, $numElems, 4);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
* @return int table offset
*/
public static function endMonster(FlatBufferBuilder $builder)
diff --git a/tests/MyGame/Example/Monster.py b/tests/MyGame/Example/Monster.py
index 40d7e8ac..a7a78363 100644
--- a/tests/MyGame/Example/Monster.py
+++ b/tests/MyGame/Example/Monster.py
@@ -282,7 +282,22 @@ class Monster(object):
return self._tab.Get(flatbuffers.number_types.Float32Flags, o + self._tab.Pos)
return 0.0
-def MonsterStart(builder): builder.StartObject(28)
+ # Monster
+ def Testarrayofstring2(self, j):
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(60))
+ if o != 0:
+ a = self._tab.Vector(o)
+ return self._tab.String(a + flatbuffers.number_types.UOffsetTFlags.py_type(j * 4))
+ return ""
+
+ # Monster
+ def Testarrayofstring2Length(self):
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(60))
+ if o != 0:
+ return self._tab.VectorLen(o)
+ return 0
+
+def MonsterStart(builder): builder.StartObject(29)
def MonsterAddPos(builder, pos): builder.PrependStructSlot(0, flatbuffers.number_types.UOffsetTFlags.py_type(pos), 0)
def MonsterAddMana(builder, mana): builder.PrependInt16Slot(1, mana, 150)
def MonsterAddHp(builder, hp): builder.PrependInt16Slot(2, hp, 100)
@@ -316,4 +331,6 @@ def MonsterStartTestarrayofboolsVector(builder, numElems): return builder.StartV
def MonsterAddTestf(builder, testf): builder.PrependFloat32Slot(25, testf, 3.14159)
def MonsterAddTestf2(builder, testf2): builder.PrependFloat32Slot(26, testf2, 3.0)
def MonsterAddTestf3(builder, testf3): builder.PrependFloat32Slot(27, testf3, 0.0)
+def MonsterAddTestarrayofstring2(builder, testarrayofstring2): builder.PrependUOffsetTRelativeSlot(28, flatbuffers.number_types.UOffsetTFlags.py_type(testarrayofstring2), 0)
+def MonsterStartTestarrayofstring2Vector(builder, numElems): return builder.StartVector(4, numElems, 4)
def MonsterEnd(builder): return builder.EndObject()
diff --git a/tests/MyGame/Example/Stat.go b/tests/MyGame/Example/Stat.go
index 1071cae8..8c56bfb0 100644
--- a/tests/MyGame/Example/Stat.go
+++ b/tests/MyGame/Example/Stat.go
@@ -37,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 {
@@ -45,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 3cac509b..cd339c62 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/Test.go b/tests/MyGame/Example/Test.go
index e849488d..ee0d9aae 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 52474152..6e33da9b 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 965c7189..96218e58 100644
--- a/tests/MyGame/Example/TestSimpleTableWithEnum.go
+++ b/tests/MyGame/Example/TestSimpleTableWithEnum.go
@@ -29,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 85e18c2b..a1de020e 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/Vec3.go b/tests/MyGame/Example/Vec3.go
index 082945ed..8bf97da3 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 7ae1ce20..261947cc 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.cs b/tests/MyGame/Example2/Monster.cs
new file mode 100644
index 00000000..e6c512ab
--- /dev/null
+++ b/tests/MyGame/Example2/Monster.cs
@@ -0,0 +1,23 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+
+namespace MyGame.Example2
+{
+
+using System;
+using FlatBuffers;
+
+public sealed class Monster : Table {
+ public static Monster GetRootAsMonster(ByteBuffer _bb) { return GetRootAsMonster(_bb, new Monster()); }
+ public static Monster GetRootAsMonster(ByteBuffer _bb, Monster obj) { return (obj.__init(_bb.GetInt(_bb.Position) + _bb.Position, _bb)); }
+ public Monster __init(int _i, ByteBuffer _bb) { bb_pos = _i; bb = _bb; return this; }
+
+
+ public static void StartMonster(FlatBufferBuilder builder) { builder.StartObject(0); }
+ public static Offset<MyGame.Example2.Monster> EndMonster(FlatBufferBuilder builder) {
+ int o = builder.EndObject();
+ return new Offset<MyGame.Example2.Monster>(o);
+ }
+};
+
+
+}
diff --git a/tests/MyGame/Example2/Monster.go b/tests/MyGame/Example2/Monster.go
new file mode 100644
index 00000000..e12b0545
--- /dev/null
+++ b/tests/MyGame/Example2/Monster.go
@@ -0,0 +1,18 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+
+package Example2
+
+import (
+ flatbuffers "github.com/google/flatbuffers/go"
+)
+type Monster struct {
+ _tab flatbuffers.Table
+}
+
+func (rcv *Monster) Init(buf []byte, i flatbuffers.UOffsetT) {
+ rcv._tab.Bytes = buf
+ rcv._tab.Pos = i
+}
+
+func MonsterStart(builder *flatbuffers.Builder) { builder.StartObject(0) }
+func MonsterEnd(builder *flatbuffers.Builder) flatbuffers.UOffsetT { return builder.EndObject() }
diff --git a/tests/MyGame/Example2/Monster.java b/tests/MyGame/Example2/Monster.java
new file mode 100644
index 00000000..968eee56
--- /dev/null
+++ b/tests/MyGame/Example2/Monster.java
@@ -0,0 +1,23 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+
+package MyGame.Example2;
+
+import java.nio.*;
+import java.lang.*;
+import java.util.*;
+import com.google.flatbuffers.*;
+
+@SuppressWarnings("unused")
+public final class Monster extends Table {
+ public static Monster getRootAsMonster(ByteBuffer _bb) { return getRootAsMonster(_bb, new Monster()); }
+ public static Monster getRootAsMonster(ByteBuffer _bb, Monster obj) { _bb.order(ByteOrder.LITTLE_ENDIAN); return (obj.__init(_bb.getInt(_bb.position()) + _bb.position(), _bb)); }
+ public Monster __init(int _i, ByteBuffer _bb) { bb_pos = _i; bb = _bb; return this; }
+
+
+ public static void startMonster(FlatBufferBuilder builder) { builder.startObject(0); }
+ public static int endMonster(FlatBufferBuilder builder) {
+ int o = builder.endObject();
+ return o;
+ }
+}
+
diff --git a/tests/MyGame/Example2/Monster.php b/tests/MyGame/Example2/Monster.php
new file mode 100644
index 00000000..b00f150e
--- /dev/null
+++ b/tests/MyGame/Example2/Monster.php
@@ -0,0 +1,79 @@
+<?php
+// automatically generated by the FlatBuffers compiler, do not modify
+
+namespace MyGame\Example2;
+
+use \Google\FlatBuffers\Struct;
+use \Google\FlatBuffers\Table;
+use \Google\FlatBuffers\ByteBuffer;
+use \Google\FlatBuffers\FlatBufferBuilder;
+
+class Monster extends Table
+{
+ /**
+ * @param ByteBuffer $bb
+ * @return Monster
+ */
+ public static function getRootAsMonster(ByteBuffer $bb)
+ {
+ $obj = new Monster();
+ return ($obj->init($bb->getInt($bb->getPosition()) + $bb->getPosition(), $bb));
+ }
+
+ public static function MonsterIdentifier()
+ {
+ return "MONS";
+ }
+
+ public static function MonsterBufferHasIdentifier(ByteBuffer $buf)
+ {
+ return self::__has_identifier($buf, self::MonsterIdentifier());
+ }
+
+ public static function MonsterExtension()
+ {
+ return "mon";
+ }
+
+ /**
+ * @param int $_i offset
+ * @param ByteBuffer $_bb
+ * @return Monster
+ **/
+ public function init($_i, ByteBuffer $_bb)
+ {
+ $this->bb_pos = $_i;
+ $this->bb = $_bb;
+ return $this;
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @return void
+ */
+ public static function startMonster(FlatBufferBuilder $builder)
+ {
+ $builder->StartObject(0);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @return Monster
+ */
+ public static function createMonster(FlatBufferBuilder $builder, )
+ {
+ $builder->startObject(0);
+ $o = $builder->endObject();
+ return $o;
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @return int table offset
+ */
+ public static function endMonster(FlatBufferBuilder $builder)
+ {
+ $o = $builder->endObject();
+ return $o;
+ }
+}
diff --git a/tests/MyGame/Example2/Monster.py b/tests/MyGame/Example2/Monster.py
new file mode 100644
index 00000000..0b98211e
--- /dev/null
+++ b/tests/MyGame/Example2/Monster.py
@@ -0,0 +1,15 @@
+# automatically generated by the FlatBuffers compiler, do not modify
+
+# namespace: Example2
+
+import flatbuffers
+
+class Monster(object):
+ __slots__ = ['_tab']
+
+ # Monster
+ def Init(self, buf, pos):
+ self._tab = flatbuffers.table.Table(buf, pos)
+
+def MonsterStart(builder): builder.StartObject(0)
+def MonsterEnd(builder): return builder.EndObject()
diff --git a/tests/generate_code.bat b/tests/generate_code.bat
index 00b16d90..4b4a5353 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 --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 b74c2bec..1b347ba7 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 --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 4d0067f4..e4e96de8 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)
@@ -85,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:
@@ -93,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)
@@ -283,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{})) {
@@ -1276,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 e16b2bd1..e131ac8c 100644
--- a/tests/monster_test.bfbs
+++ b/tests/monster_test.bfbs
Binary files differ
diff --git a/tests/monster_test.fbs b/tests/monster_test.fbs
index f302ce44..3fecd33c 100755
--- a/tests/monster_test.fbs
+++ b/tests/monster_test.fbs
@@ -2,13 +2,17 @@
include "include_test1.fbs";
+namespace MyGame.Example2;
+
+table Monster {} // Test having same name as below, but in different namespace.
+
namespace MyGame.Example;
attribute "priority";
enum Color:byte (bit_flags) { Red = 0, Green, Blue = 3, }
-union Any { Monster, TestSimpleTableWithEnum } // TODO: add more elements
+union Any { Monster, TestSimpleTableWithEnum, MyGame.Example2.Monster }
struct Test { a:short; b:byte; }
@@ -44,6 +48,7 @@ table Monster {
/// multiline too
testarrayoftables:[Monster] (id: 11);
testarrayofstring:[string] (id: 10);
+ testarrayofstring2:[string] (id: 28);
testarrayofbools:[bool] (id: 24);
enemy:MyGame.Example.Monster (id:12); // Test referring by full namespace.
test:Any (id: 8);
@@ -65,7 +70,7 @@ table Monster {
}
rpc_service MonsterStorage {
- Store(Monster):Stat (stream);
+ Store(Monster):Stat (streaming: "none");
Retrieve(Stat):Monster (idempotent);
}
diff --git a/tests/monster_test.grpc.fb.cc b/tests/monster_test.grpc.fb.cc
new file mode 100644
index 00000000..71dbd2d4
--- /dev/null
+++ b/tests/monster_test.grpc.fb.cc
@@ -0,0 +1,85 @@
+// Generated by the gRPC protobuf plugin.
+// If you make any local change, they will be lost.
+// source: monster_test
+
+#include "monster_test_generated.h"
+#include "monster_test.grpc.fb.h"
+#include "flatbuffers/grpc.h"
+
+#include <grpc++/impl/codegen/async_stream.h>
+#include <grpc++/impl/codegen/async_unary_call.h>
+#include <grpc++/impl/codegen/channel_interface.h>
+#include <grpc++/impl/codegen/client_unary_call.h>
+#include <grpc++/impl/codegen/method_handler_impl.h>
+#include <grpc++/impl/codegen/rpc_service_method.h>
+#include <grpc++/impl/codegen/service_type.h>
+#include <grpc++/impl/codegen/sync_stream.h>
+namespace MyGame {
+namespace Example {
+
+static const char* MonsterStorage_method_names[] = {
+ "/MyGame.Example..MonsterStorage/Store",
+ "/MyGame.Example..MonsterStorage/Retrieve",
+};
+
+std::unique_ptr< MonsterStorage::Stub> MonsterStorage::NewStub(const std::shared_ptr< ::grpc::ChannelInterface>& channel, const ::grpc::StubOptions& options) {
+ std::unique_ptr< MonsterStorage::Stub> stub(new MonsterStorage::Stub(channel));
+ return stub;
+}
+
+MonsterStorage::Stub::Stub(const std::shared_ptr< ::grpc::ChannelInterface>& channel)
+ : channel_(channel) , rpcmethod_Store_(MonsterStorage_method_names[0], ::grpc::RpcMethod::NORMAL_RPC, channel)
+ , rpcmethod_Retrieve_(MonsterStorage_method_names[1], ::grpc::RpcMethod::NORMAL_RPC, channel)
+ {}
+
+::grpc::Status MonsterStorage::Stub::Store(::grpc::ClientContext* context, const flatbuffers::BufferRef<Monster>& request, flatbuffers::BufferRef<Stat>* response) {
+ return ::grpc::BlockingUnaryCall(channel_.get(), rpcmethod_Store_, context, request, response);
+}
+
+::grpc::ClientAsyncResponseReader< flatbuffers::BufferRef<Stat>>* MonsterStorage::Stub::AsyncStoreRaw(::grpc::ClientContext* context, const flatbuffers::BufferRef<Monster>& request, ::grpc::CompletionQueue* cq) {
+ return new ::grpc::ClientAsyncResponseReader< flatbuffers::BufferRef<Stat>>(channel_.get(), cq, rpcmethod_Store_, context, request);
+}
+
+::grpc::Status MonsterStorage::Stub::Retrieve(::grpc::ClientContext* context, const flatbuffers::BufferRef<Stat>& request, flatbuffers::BufferRef<Monster>* response) {
+ return ::grpc::BlockingUnaryCall(channel_.get(), rpcmethod_Retrieve_, context, request, response);
+}
+
+::grpc::ClientAsyncResponseReader< flatbuffers::BufferRef<Monster>>* MonsterStorage::Stub::AsyncRetrieveRaw(::grpc::ClientContext* context, const flatbuffers::BufferRef<Stat>& request, ::grpc::CompletionQueue* cq) {
+ return new ::grpc::ClientAsyncResponseReader< flatbuffers::BufferRef<Monster>>(channel_.get(), cq, rpcmethod_Retrieve_, context, request);
+}
+
+MonsterStorage::Service::Service() {
+ (void)MonsterStorage_method_names;
+ AddMethod(new ::grpc::RpcServiceMethod(
+ MonsterStorage_method_names[0],
+ ::grpc::RpcMethod::NORMAL_RPC,
+ new ::grpc::RpcMethodHandler< MonsterStorage::Service, flatbuffers::BufferRef<Monster>, flatbuffers::BufferRef<Stat>>(
+ std::mem_fn(&MonsterStorage::Service::Store), this)));
+ AddMethod(new ::grpc::RpcServiceMethod(
+ MonsterStorage_method_names[1],
+ ::grpc::RpcMethod::NORMAL_RPC,
+ new ::grpc::RpcMethodHandler< MonsterStorage::Service, flatbuffers::BufferRef<Stat>, flatbuffers::BufferRef<Monster>>(
+ std::mem_fn(&MonsterStorage::Service::Retrieve), this)));
+}
+
+MonsterStorage::Service::~Service() {
+}
+
+::grpc::Status MonsterStorage::Service::Store(::grpc::ServerContext* context, const flatbuffers::BufferRef<Monster>* request, flatbuffers::BufferRef<Stat>* response) {
+ (void) context;
+ (void) request;
+ (void) response;
+ return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "");
+}
+
+::grpc::Status MonsterStorage::Service::Retrieve(::grpc::ServerContext* context, const flatbuffers::BufferRef<Stat>* request, flatbuffers::BufferRef<Monster>* response) {
+ (void) context;
+ (void) request;
+ (void) response;
+ return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "");
+}
+
+
+} // namespace MyGame
+} // namespace Example
+
diff --git a/tests/monster_test.grpc.fb.h b/tests/monster_test.grpc.fb.h
new file mode 100644
index 00000000..4269234f
--- /dev/null
+++ b/tests/monster_test.grpc.fb.h
@@ -0,0 +1,155 @@
+// Generated by the gRPC protobuf plugin.
+// If you make any local change, they will be lost.
+// source: monster_test
+#ifndef GRPC_monster_5ftest__INCLUDED
+#define GRPC_monster_5ftest__INCLUDED
+
+#include "monster_test_generated.h"
+
+#include <grpc++/impl/codegen/async_stream.h>
+#include <grpc++/impl/codegen/async_unary_call.h>
+#include <grpc++/impl/codegen/proto_utils.h>
+#include <grpc++/impl/codegen/rpc_method.h>
+#include <grpc++/impl/codegen/service_type.h>
+#include <grpc++/impl/codegen/status.h>
+#include <grpc++/impl/codegen/stub_options.h>
+#include <grpc++/impl/codegen/sync_stream.h>
+
+namespace grpc {
+class CompletionQueue;
+class Channel;
+class RpcService;
+class ServerCompletionQueue;
+class ServerContext;
+} // namespace grpc
+
+namespace MyGame {
+namespace Example {
+
+class MonsterStorage GRPC_FINAL {
+ public:
+ class StubInterface {
+ public:
+ virtual ~StubInterface() {}
+ virtual ::grpc::Status Store(::grpc::ClientContext* context, const flatbuffers::BufferRef<Monster>& request, flatbuffers::BufferRef<Stat>* response) = 0;
+ std::unique_ptr< ::grpc::ClientAsyncResponseReaderInterface< flatbuffers::BufferRef<Stat>>> AsyncStore(::grpc::ClientContext* context, const flatbuffers::BufferRef<Monster>& request, ::grpc::CompletionQueue* cq) {
+ return std::unique_ptr< ::grpc::ClientAsyncResponseReaderInterface< flatbuffers::BufferRef<Stat>>>(AsyncStoreRaw(context, request, cq));
+ }
+ virtual ::grpc::Status Retrieve(::grpc::ClientContext* context, const flatbuffers::BufferRef<Stat>& request, flatbuffers::BufferRef<Monster>* response) = 0;
+ std::unique_ptr< ::grpc::ClientAsyncResponseReaderInterface< flatbuffers::BufferRef<Monster>>> AsyncRetrieve(::grpc::ClientContext* context, const flatbuffers::BufferRef<Stat>& request, ::grpc::CompletionQueue* cq) {
+ return std::unique_ptr< ::grpc::ClientAsyncResponseReaderInterface< flatbuffers::BufferRef<Monster>>>(AsyncRetrieveRaw(context, request, cq));
+ }
+ private:
+ virtual ::grpc::ClientAsyncResponseReaderInterface< flatbuffers::BufferRef<Stat>>* AsyncStoreRaw(::grpc::ClientContext* context, const flatbuffers::BufferRef<Monster>& request, ::grpc::CompletionQueue* cq) = 0;
+ virtual ::grpc::ClientAsyncResponseReaderInterface< flatbuffers::BufferRef<Monster>>* AsyncRetrieveRaw(::grpc::ClientContext* context, const flatbuffers::BufferRef<Stat>& request, ::grpc::CompletionQueue* cq) = 0;
+ };
+ class Stub GRPC_FINAL : public StubInterface {
+ public:
+ Stub(const std::shared_ptr< ::grpc::ChannelInterface>& channel);
+ ::grpc::Status Store(::grpc::ClientContext* context, const flatbuffers::BufferRef<Monster>& request, flatbuffers::BufferRef<Stat>* response) GRPC_OVERRIDE;
+ std::unique_ptr< ::grpc::ClientAsyncResponseReader< flatbuffers::BufferRef<Stat>>> AsyncStore(::grpc::ClientContext* context, const flatbuffers::BufferRef<Monster>& request, ::grpc::CompletionQueue* cq) {
+ return std::unique_ptr< ::grpc::ClientAsyncResponseReader< flatbuffers::BufferRef<Stat>>>(AsyncStoreRaw(context, request, cq));
+ }
+ ::grpc::Status Retrieve(::grpc::ClientContext* context, const flatbuffers::BufferRef<Stat>& request, flatbuffers::BufferRef<Monster>* response) GRPC_OVERRIDE;
+ std::unique_ptr< ::grpc::ClientAsyncResponseReader< flatbuffers::BufferRef<Monster>>> AsyncRetrieve(::grpc::ClientContext* context, const flatbuffers::BufferRef<Stat>& request, ::grpc::CompletionQueue* cq) {
+ return std::unique_ptr< ::grpc::ClientAsyncResponseReader< flatbuffers::BufferRef<Monster>>>(AsyncRetrieveRaw(context, request, cq));
+ }
+
+ private:
+ std::shared_ptr< ::grpc::ChannelInterface> channel_;
+ ::grpc::ClientAsyncResponseReader< flatbuffers::BufferRef<Stat>>* AsyncStoreRaw(::grpc::ClientContext* context, const flatbuffers::BufferRef<Monster>& request, ::grpc::CompletionQueue* cq) GRPC_OVERRIDE;
+ ::grpc::ClientAsyncResponseReader< flatbuffers::BufferRef<Monster>>* AsyncRetrieveRaw(::grpc::ClientContext* context, const flatbuffers::BufferRef<Stat>& request, ::grpc::CompletionQueue* cq) GRPC_OVERRIDE;
+ const ::grpc::RpcMethod rpcmethod_Store_;
+ const ::grpc::RpcMethod rpcmethod_Retrieve_;
+ };
+ static std::unique_ptr<Stub> NewStub(const std::shared_ptr< ::grpc::ChannelInterface>& channel, const ::grpc::StubOptions& options = ::grpc::StubOptions());
+
+ class Service : public ::grpc::Service {
+ public:
+ Service();
+ virtual ~Service();
+ virtual ::grpc::Status Store(::grpc::ServerContext* context, const flatbuffers::BufferRef<Monster>* request, flatbuffers::BufferRef<Stat>* response);
+ virtual ::grpc::Status Retrieve(::grpc::ServerContext* context, const flatbuffers::BufferRef<Stat>* request, flatbuffers::BufferRef<Monster>* response);
+ };
+ template <class BaseClass>
+ class WithAsyncMethod_Store : public BaseClass {
+ private:
+ void BaseClassMustBeDerivedFromService(const Service *service) {}
+ public:
+ WithAsyncMethod_Store() {
+ ::grpc::Service::MarkMethodAsync(0);
+ }
+ ~WithAsyncMethod_Store() GRPC_OVERRIDE {
+ BaseClassMustBeDerivedFromService(this);
+ }
+ // disable synchronous version of this method
+ ::grpc::Status Store(::grpc::ServerContext* context, const flatbuffers::BufferRef<Monster>* request, flatbuffers::BufferRef<Stat>* response) GRPC_FINAL GRPC_OVERRIDE {
+ abort();
+ return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "");
+ }
+ void RequestStore(::grpc::ServerContext* context, flatbuffers::BufferRef<Monster>* request, ::grpc::ServerAsyncResponseWriter< flatbuffers::BufferRef<Stat>>* response, ::grpc::CompletionQueue* new_call_cq, ::grpc::ServerCompletionQueue* notification_cq, void *tag) {
+ ::grpc::Service::RequestAsyncUnary(0, context, request, response, new_call_cq, notification_cq, tag);
+ }
+ };
+ template <class BaseClass>
+ class WithAsyncMethod_Retrieve : public BaseClass {
+ private:
+ void BaseClassMustBeDerivedFromService(const Service *service) {}
+ public:
+ WithAsyncMethod_Retrieve() {
+ ::grpc::Service::MarkMethodAsync(1);
+ }
+ ~WithAsyncMethod_Retrieve() GRPC_OVERRIDE {
+ BaseClassMustBeDerivedFromService(this);
+ }
+ // disable synchronous version of this method
+ ::grpc::Status Retrieve(::grpc::ServerContext* context, const flatbuffers::BufferRef<Stat>* request, flatbuffers::BufferRef<Monster>* response) GRPC_FINAL GRPC_OVERRIDE {
+ abort();
+ return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "");
+ }
+ void RequestRetrieve(::grpc::ServerContext* context, flatbuffers::BufferRef<Stat>* request, ::grpc::ServerAsyncResponseWriter< flatbuffers::BufferRef<Monster>>* response, ::grpc::CompletionQueue* new_call_cq, ::grpc::ServerCompletionQueue* notification_cq, void *tag) {
+ ::grpc::Service::RequestAsyncUnary(1, context, request, response, new_call_cq, notification_cq, tag);
+ }
+ };
+ typedef WithAsyncMethod_Store< WithAsyncMethod_Retrieve< Service > > AsyncService;
+ template <class BaseClass>
+ class WithGenericMethod_Store : public BaseClass {
+ private:
+ void BaseClassMustBeDerivedFromService(const Service *service) {}
+ public:
+ WithGenericMethod_Store() {
+ ::grpc::Service::MarkMethodGeneric(0);
+ }
+ ~WithGenericMethod_Store() GRPC_OVERRIDE {
+ BaseClassMustBeDerivedFromService(this);
+ }
+ // disable synchronous version of this method
+ ::grpc::Status Store(::grpc::ServerContext* context, const flatbuffers::BufferRef<Monster>* request, flatbuffers::BufferRef<Stat>* response) GRPC_FINAL GRPC_OVERRIDE {
+ abort();
+ return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "");
+ }
+ };
+ template <class BaseClass>
+ class WithGenericMethod_Retrieve : public BaseClass {
+ private:
+ void BaseClassMustBeDerivedFromService(const Service *service) {}
+ public:
+ WithGenericMethod_Retrieve() {
+ ::grpc::Service::MarkMethodGeneric(1);
+ }
+ ~WithGenericMethod_Retrieve() GRPC_OVERRIDE {
+ BaseClassMustBeDerivedFromService(this);
+ }
+ // disable synchronous version of this method
+ ::grpc::Status Retrieve(::grpc::ServerContext* context, const flatbuffers::BufferRef<Stat>* request, flatbuffers::BufferRef<Monster>* response) GRPC_FINAL GRPC_OVERRIDE {
+ abort();
+ return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "");
+ }
+ };
+};
+
+} // namespace Example
+} // namespace MyGame
+
+
+#endif // GRPC_monster_5ftest__INCLUDED
diff --git a/tests/monster_test_generated.h b/tests/monster_test_generated.h
index 3da41fae..49aba113 100644
--- a/tests/monster_test_generated.h
+++ b/tests/monster_test_generated.h
@@ -6,17 +6,27 @@
#include "flatbuffers/flatbuffers.h"
namespace MyGame {
+namespace Example2 {
+
+struct Monster;
+struct MonsterT;
+
+} // namespace Example2
+
namespace Example {
struct Test;
struct TestSimpleTableWithEnum;
+struct TestSimpleTableWithEnumT;
struct Vec3;
struct Stat;
+struct StatT;
struct Monster;
+struct MonsterT;
enum Color {
Color_Red = 1,
@@ -37,12 +47,30 @@ enum Any {
Any_NONE = 0,
Any_Monster = 1,
Any_TestSimpleTableWithEnum = 2,
+ Any_MyGame_Example2_Monster = 3,
Any_MIN = Any_NONE,
- Any_MAX = Any_TestSimpleTableWithEnum
+ 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<void> Pack(flatbuffers::FlatBufferBuilder &_fbb) const;
+
+ MonsterT *AsMonster() { return type == Any_Monster ? reinterpret_cast<MonsterT *>(table) : nullptr; }
+ TestSimpleTableWithEnumT *AsTestSimpleTableWithEnum() { return type == Any_TestSimpleTableWithEnum ? reinterpret_cast<TestSimpleTableWithEnumT *>(table) : nullptr; }
+ MyGame::Example2::MonsterT *AsMyGame_Example2_Monster() { return type == Any_MyGame_Example2_Monster ? reinterpret_cast<MyGame::Example2::MonsterT *>(table) : nullptr; }
};
inline const char **EnumNamesAny() {
- static const char *names[] = { "NONE", "Monster", "TestSimpleTableWithEnum", nullptr };
+ static const char *names[] = { "NONE", "Monster", "TestSimpleTableWithEnum", "MyGame_Example2_Monster", nullptr };
return names;
}
@@ -57,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; }
@@ -80,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<int8_t>(_test2))), __padding1(0), test3_(_test3), __padding2(0) { (void)__padding0; (void)__padding1; (void)__padding2; }
@@ -98,6 +130,47 @@ MANUALLY_ALIGNED_STRUCT(16) Vec3 FLATBUFFERS_FINAL_CLASS {
};
STRUCT_END(Vec3, 32);
+} // namespace Example
+
+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<MonsterT> UnPack() const;
+};
+
+struct MonsterBuilder {
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ MonsterBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) { start_ = fbb_.StartTable(); }
+ MonsterBuilder &operator=(const MonsterBuilder &);
+ flatbuffers::Offset<Monster> Finish() {
+ auto o = flatbuffers::Offset<Monster>(fbb_.EndTable(start_, 0));
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<Monster> CreateMonster(flatbuffers::FlatBufferBuilder &_fbb) {
+ MonsterBuilder builder_(_fbb);
+ return builder_.Finish();
+}
+
+inline flatbuffers::Offset<Monster> 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
@@ -109,6 +182,7 @@ struct TestSimpleTableWithEnum FLATBUFFERS_FINAL_CLASS : private flatbuffers::Ta
VerifyField<int8_t>(verifier, VT_COLOR) &&
verifier.EndTable();
}
+ std::unique_ptr<TestSimpleTableWithEnumT> UnPack() const;
};
struct TestSimpleTableWithEnumBuilder {
@@ -124,12 +198,20 @@ struct TestSimpleTableWithEnumBuilder {
};
inline flatbuffers::Offset<TestSimpleTableWithEnum> 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<TestSimpleTableWithEnum> 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,
@@ -150,6 +232,7 @@ struct Stat FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
VerifyField<uint16_t>(verifier, VT_COUNT) &&
verifier.EndTable();
}
+ std::unique_ptr<StatT> UnPack() const;
};
struct StatBuilder {
@@ -167,9 +250,9 @@ struct StatBuilder {
};
inline flatbuffers::Offset<Stat> CreateStat(flatbuffers::FlatBufferBuilder &_fbb,
- flatbuffers::Offset<flatbuffers::String> id = 0,
- int64_t val = 0,
- uint16_t count = 0) {
+ flatbuffers::Offset<flatbuffers::String> id = 0,
+ int64_t val = 0,
+ uint16_t count = 0) {
StatBuilder builder_(_fbb);
builder_.add_val(val);
builder_.add_id(id);
@@ -177,6 +260,45 @@ inline flatbuffers::Offset<Stat> CreateStat(flatbuffers::FlatBufferBuilder &_fbb
return builder_.Finish();
}
+inline flatbuffers::Offset<Stat> 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<Stat> CreateStat(flatbuffers::FlatBufferBuilder &_fbb, const StatT *_o);
+
+struct MonsterT : public flatbuffers::NativeTable {
+ std::unique_ptr<Vec3> pos;
+ int16_t mana;
+ int16_t hp;
+ std::string name;
+ std::vector<uint8_t> inventory;
+ Color color;
+ AnyUnion test;
+ std::vector<Test> test4;
+ std::vector<std::string> testarrayofstring;
+ std::vector<std::unique_ptr<MonsterT>> testarrayoftables;
+ std::unique_ptr<MonsterT> enemy;
+ std::vector<uint8_t> testnestedflatbuffer;
+ std::unique_ptr<StatT> 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<bool> testarrayofbools;
+ float testf;
+ float testf2;
+ float testf3;
+ std::vector<std::string> testarrayofstring2;
+};
+
/// an example documentation comment: monster object
struct Monster FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
enum {
@@ -206,7 +328,8 @@ struct Monster FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
VT_TESTARRAYOFBOOLS = 52,
VT_TESTF = 54,
VT_TESTF2 = 56,
- VT_TESTF3 = 58
+ VT_TESTF3 = 58,
+ VT_TESTARRAYOFSTRING2 = 60
};
const Vec3 *pos() const { return GetStruct<const Vec3 *>(VT_POS); }
Vec3 *mutable_pos() { return GetStruct<Vec3 *>(VT_POS); }
@@ -267,6 +390,8 @@ struct Monster FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
bool mutate_testf2(float _testf2) { return SetField(VT_TESTF2, _testf2); }
float testf3() const { return GetField<float>(VT_TESTF3, 0.0f); }
bool mutate_testf3(float _testf3) { return SetField(VT_TESTF3, _testf3); }
+ const flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>> *testarrayofstring2() const { return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>> *>(VT_TESTARRAYOFSTRING2); }
+ flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>> *mutable_testarrayofstring2() { return GetPointer<flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>> *>(VT_TESTARRAYOFSTRING2); }
bool Verify(flatbuffers::Verifier &verifier) const {
return VerifyTableStart(verifier) &&
VerifyField<Vec3>(verifier, VT_POS) &&
@@ -308,8 +433,12 @@ struct Monster FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
VerifyField<float>(verifier, VT_TESTF) &&
VerifyField<float>(verifier, VT_TESTF2) &&
VerifyField<float>(verifier, VT_TESTF3) &&
+ VerifyField<flatbuffers::uoffset_t>(verifier, VT_TESTARRAYOFSTRING2) &&
+ verifier.Verify(testarrayofstring2()) &&
+ verifier.VerifyVectorOfStrings(testarrayofstring2()) &&
verifier.EndTable();
}
+ std::unique_ptr<MonsterT> UnPack() const;
};
struct MonsterBuilder {
@@ -342,48 +471,51 @@ struct MonsterBuilder {
void add_testf(float testf) { fbb_.AddElement<float>(Monster::VT_TESTF, testf, 3.14159f); }
void add_testf2(float testf2) { fbb_.AddElement<float>(Monster::VT_TESTF2, testf2, 3.0f); }
void add_testf3(float testf3) { fbb_.AddElement<float>(Monster::VT_TESTF3, testf3, 0.0f); }
+ void add_testarrayofstring2(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>>> testarrayofstring2) { fbb_.AddOffset(Monster::VT_TESTARRAYOFSTRING2, testarrayofstring2); }
MonsterBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) { start_ = fbb_.StartTable(); }
MonsterBuilder &operator=(const MonsterBuilder &);
flatbuffers::Offset<Monster> Finish() {
- auto o = flatbuffers::Offset<Monster>(fbb_.EndTable(start_, 28));
+ auto o = flatbuffers::Offset<Monster>(fbb_.EndTable(start_, 29));
fbb_.Required(o, Monster::VT_NAME); // name
return o;
}
};
inline flatbuffers::Offset<Monster> CreateMonster(flatbuffers::FlatBufferBuilder &_fbb,
- const Vec3 *pos = 0,
- int16_t mana = 150,
- int16_t hp = 100,
- flatbuffers::Offset<flatbuffers::String> name = 0,
- flatbuffers::Offset<flatbuffers::Vector<uint8_t>> inventory = 0,
- Color color = Color_Blue,
- Any test_type = Any_NONE,
- flatbuffers::Offset<void> test = 0,
- flatbuffers::Offset<flatbuffers::Vector<const Test *>> test4 = 0,
- flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>>> testarrayofstring = 0,
- flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<Monster>>> testarrayoftables = 0,
- flatbuffers::Offset<Monster> enemy = 0,
- flatbuffers::Offset<flatbuffers::Vector<uint8_t>> testnestedflatbuffer = 0,
- flatbuffers::Offset<Stat> 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<flatbuffers::Vector<uint8_t>> testarrayofbools = 0,
- float testf = 3.14159f,
- float testf2 = 3.0f,
- float testf3 = 0.0f) {
+ const Vec3 *pos = 0,
+ int16_t mana = 150,
+ int16_t hp = 100,
+ flatbuffers::Offset<flatbuffers::String> name = 0,
+ flatbuffers::Offset<flatbuffers::Vector<uint8_t>> inventory = 0,
+ Color color = Color_Blue,
+ Any test_type = Any_NONE,
+ flatbuffers::Offset<void> test = 0,
+ flatbuffers::Offset<flatbuffers::Vector<const Test *>> test4 = 0,
+ flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>>> testarrayofstring = 0,
+ flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<Monster>>> testarrayoftables = 0,
+ flatbuffers::Offset<Monster> enemy = 0,
+ flatbuffers::Offset<flatbuffers::Vector<uint8_t>> testnestedflatbuffer = 0,
+ flatbuffers::Offset<Stat> 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<flatbuffers::Vector<uint8_t>> testarrayofbools = 0,
+ float testf = 3.14159f,
+ float testf2 = 3.0f,
+ float testf3 = 0.0f,
+ flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>>> testarrayofstring2 = 0) {
MonsterBuilder builder_(_fbb);
builder_.add_testhashu64_fnv1a(testhashu64_fnv1a);
builder_.add_testhashs64_fnv1a(testhashs64_fnv1a);
builder_.add_testhashu64_fnv1(testhashu64_fnv1);
builder_.add_testhashs64_fnv1(testhashs64_fnv1);
+ builder_.add_testarrayofstring2(testarrayofstring2);
builder_.add_testf3(testf3);
builder_.add_testf2(testf2);
builder_.add_testf(testf);
@@ -410,25 +542,198 @@ inline flatbuffers::Offset<Monster> CreateMonster(flatbuffers::FlatBufferBuilder
return builder_.Finish();
}
+inline flatbuffers::Offset<Monster> CreateMonster(flatbuffers::FlatBufferBuilder &_fbb,
+ const Vec3 *pos = 0,
+ int16_t mana = 150,
+ int16_t hp = 100,
+ const char *name = nullptr,
+ const std::vector<uint8_t> *inventory = nullptr,
+ Color color = Color_Blue,
+ Any test_type = Any_NONE,
+ flatbuffers::Offset<void> test = 0,
+ const std::vector<const Test *> *test4 = nullptr,
+ const std::vector<flatbuffers::Offset<flatbuffers::String>> *testarrayofstring = nullptr,
+ const std::vector<flatbuffers::Offset<Monster>> *testarrayoftables = nullptr,
+ flatbuffers::Offset<Monster> enemy = 0,
+ const std::vector<uint8_t> *testnestedflatbuffer = nullptr,
+ flatbuffers::Offset<Stat> 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<uint8_t> *testarrayofbools = nullptr,
+ float testf = 3.14159f,
+ float testf2 = 3.0f,
+ float testf3 = 0.0f,
+ const std::vector<flatbuffers::Offset<flatbuffers::String>> *testarrayofstring2 = nullptr) {
+ return CreateMonster(_fbb, pos, mana, hp, name ? 0 : _fbb.CreateString(name), inventory ? 0 : _fbb.CreateVector<uint8_t>(*inventory), color, test_type, test, test4 ? 0 : _fbb.CreateVector<const Test *>(*test4), testarrayofstring ? 0 : _fbb.CreateVector<flatbuffers::Offset<flatbuffers::String>>(*testarrayofstring), testarrayoftables ? 0 : _fbb.CreateVector<flatbuffers::Offset<Monster>>(*testarrayoftables), enemy, testnestedflatbuffer ? 0 : _fbb.CreateVector<uint8_t>(*testnestedflatbuffer), testempty, testbool, testhashs32_fnv1, testhashu32_fnv1, testhashs64_fnv1, testhashu64_fnv1, testhashs32_fnv1a, testhashu32_fnv1a, testhashs64_fnv1a, testhashu64_fnv1a, testarrayofbools ? 0 : _fbb.CreateVector<uint8_t>(*testarrayofbools), testf, testf2, testf3, testarrayofstring2 ? 0 : _fbb.CreateVector<flatbuffers::Offset<flatbuffers::String>>(*testarrayofstring2));
+}
+
+inline flatbuffers::Offset<Monster> CreateMonster(flatbuffers::FlatBufferBuilder &_fbb, const MonsterT *_o);
+
+} // namespace Example
+
+namespace Example2 {
+
+inline std::unique_ptr<MonsterT> Monster::UnPack() const {
+ auto _o = new MonsterT();
+ return std::unique_ptr<MonsterT>(_o);
+}
+
+inline flatbuffers::Offset<Monster> CreateMonster(flatbuffers::FlatBufferBuilder &_fbb, const MonsterT *_o) {
+ (void)_o;
+ return CreateMonster(_fbb);
+}
+
+} // namespace Example2
+
+namespace Example {
+
+inline std::unique_ptr<TestSimpleTableWithEnumT> TestSimpleTableWithEnum::UnPack() const {
+ auto _o = new TestSimpleTableWithEnumT();
+ { auto _e = color(); _o->color = _e; };
+ return std::unique_ptr<TestSimpleTableWithEnumT>(_o);
+}
+
+inline flatbuffers::Offset<TestSimpleTableWithEnum> CreateTestSimpleTableWithEnum(flatbuffers::FlatBufferBuilder &_fbb, const TestSimpleTableWithEnumT *_o) {
+ return CreateTestSimpleTableWithEnum(_fbb,
+ _o->color);
+}
+
+inline std::unique_ptr<StatT> 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<StatT>(_o);
+}
+
+inline flatbuffers::Offset<Stat> 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<MonsterT> Monster::UnPack() const {
+ auto _o = new MonsterT();
+ { auto _e = pos(); if (_e) _o->pos = std::unique_ptr<Vec3>(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<MonsterT>(_o);
+}
+
+inline flatbuffers::Offset<Monster> 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<flatbuffers::Offset<Monster>>(_o->testarrayoftables.size(), [&](size_t i) { return CreateMonster(_fbb, _o->testarrayoftables[i].get()); }) : 0,
+ _o->enemy ? CreateMonster(_fbb, _o->enemy.get()) : 0,
+ _o->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;
case Any_Monster: return verifier.VerifyTable(reinterpret_cast<const Monster *>(union_obj));
case Any_TestSimpleTableWithEnum: return verifier.VerifyTable(reinterpret_cast<const TestSimpleTableWithEnum *>(union_obj));
+ case Any_MyGame_Example2_Monster: return verifier.VerifyTable(reinterpret_cast<const MyGame::Example2::Monster *>(union_obj));
default: return false;
}
}
+inline flatbuffers::NativeTable *AnyUnion::UnPack(const void *union_obj, Any type) {
+ switch (type) {
+ case Any_NONE: return nullptr;
+ case Any_Monster: return reinterpret_cast<const Monster *>(union_obj)->UnPack().release();
+ case Any_TestSimpleTableWithEnum: return reinterpret_cast<const TestSimpleTableWithEnum *>(union_obj)->UnPack().release();
+ case Any_MyGame_Example2_Monster: return reinterpret_cast<const MyGame::Example2::Monster *>(union_obj)->UnPack().release();
+ default: return nullptr;
+ }
+}
+
+inline flatbuffers::Offset<void> AnyUnion::Pack(flatbuffers::FlatBufferBuilder &_fbb) const {
+ switch (type) {
+ case Any_NONE: return 0;
+ case Any_Monster: return CreateMonster(_fbb, reinterpret_cast<const MonsterT *>(table)).Union();
+ case Any_TestSimpleTableWithEnum: return CreateTestSimpleTableWithEnum(_fbb, reinterpret_cast<const TestSimpleTableWithEnumT *>(table)).Union();
+ case Any_MyGame_Example2_Monster: return CreateMonster(_fbb, reinterpret_cast<const MyGame::Example2::MonsterT *>(table)).Union();
+ default: return 0;
+ }
+}
+
+inline AnyUnion::~AnyUnion() {
+ switch (type) {
+ case Any_Monster: delete reinterpret_cast<MonsterT *>(table); break;
+ case Any_TestSimpleTableWithEnum: delete reinterpret_cast<TestSimpleTableWithEnumT *>(table); break;
+ case Any_MyGame_Example2_Monster: delete reinterpret_cast<MyGame::Example2::MonsterT *>(table); break;
+ default:;
+ }
+}
+
inline const MyGame::Example::Monster *GetMonster(const void *buf) { return flatbuffers::GetRoot<MyGame::Example::Monster>(buf); }
inline Monster *GetMutableMonster(void *buf) { return flatbuffers::GetMutableRoot<Monster>(buf); }
-inline bool VerifyMonsterBuffer(flatbuffers::Verifier &verifier) { return verifier.VerifyBuffer<MyGame::Example::Monster>(); }
-
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<MyGame::Example::Monster>(MonsterIdentifier()); }
+
inline const char *MonsterExtension() { return "mon"; }
inline void FinishMonsterBuffer(flatbuffers::FlatBufferBuilder &fbb, flatbuffers::Offset<MyGame::Example::Monster> root) { fbb.Finish(root, MonsterIdentifier()); }
diff --git a/tests/monster_test_generated.js b/tests/monster_test_generated.js
index 8316fbc6..f67e8480 100644
--- a/tests/monster_test_generated.js
+++ b/tests/monster_test_generated.js
@@ -13,6 +13,11 @@ MyGame.Example = MyGame.Example || {};
/**
* @const
*/
+MyGame.Example2 = MyGame.Example2 || {};
+
+/**
+ * @const
+*/
MyGame.OtherNameSpace = MyGame.OtherNameSpace || {};
/**
@@ -30,7 +35,59 @@ MyGame.Example.Color = {
MyGame.Example.Any = {
NONE: 0,
Monster: 1,
- TestSimpleTableWithEnum: 2
+ TestSimpleTableWithEnum: 2,
+ MyGame_Example2_Monster: 3
+};
+
+/**
+ * @constructor
+ */
+MyGame.Example2.Monster = function() {
+ /**
+ * @type {flatbuffers.ByteBuffer}
+ */
+ this.bb = null;
+
+ /**
+ * @type {number}
+ */
+ this.bb_pos = 0;
+};
+
+/**
+ * @param {number} i
+ * @param {flatbuffers.ByteBuffer} bb
+ * @returns {MyGame.Example2.Monster}
+ */
+MyGame.Example2.Monster.prototype.__init = function(i, bb) {
+ this.bb_pos = i;
+ this.bb = bb;
+ return this;
+};
+
+/**
+ * @param {flatbuffers.ByteBuffer} bb
+ * @param {MyGame.Example2.Monster=} obj
+ * @returns {MyGame.Example2.Monster}
+ */
+MyGame.Example2.Monster.getRootAsMonster = function(bb, obj) {
+ return (obj || new MyGame.Example2.Monster).__init(bb.readInt32(bb.position()) + bb.position(), bb);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ */
+MyGame.Example2.Monster.startMonster = function(builder) {
+ builder.startObject(0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @returns {flatbuffers.Offset}
+ */
+MyGame.Example2.Monster.endMonster = function(builder) {
+ var offset = builder.endObject();
+ return offset;
};
/**
@@ -702,10 +759,28 @@ MyGame.Example.Monster.prototype.testf3 = function() {
};
/**
+ * @param {number} index
+ * @param {flatbuffers.Encoding=} optionalEncoding
+ * @returns {string|Uint8Array}
+ */
+MyGame.Example.Monster.prototype.testarrayofstring2 = function(index, optionalEncoding) {
+ var offset = this.bb.__offset(this.bb_pos, 60);
+ return offset ? this.bb.__string(this.bb.__vector(this.bb_pos + offset) + index * 4, optionalEncoding) : null;
+};
+
+/**
+ * @returns {number}
+ */
+MyGame.Example.Monster.prototype.testarrayofstring2Length = function() {
+ var offset = this.bb.__offset(this.bb_pos, 60);
+ return offset ? this.bb.__vector_len(this.bb_pos + offset) : 0;
+};
+
+/**
* @param {flatbuffers.Builder} builder
*/
MyGame.Example.Monster.startMonster = function(builder) {
- builder.startObject(28);
+ builder.startObject(29);
};
/**
@@ -1039,6 +1114,35 @@ MyGame.Example.Monster.addTestf3 = function(builder, testf3) {
/**
* @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Offset} testarrayofstring2Offset
+ */
+MyGame.Example.Monster.addTestarrayofstring2 = function(builder, testarrayofstring2Offset) {
+ builder.addFieldOffset(28, testarrayofstring2Offset, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {Array.<flatbuffers.Offset>} data
+ * @returns {flatbuffers.Offset}
+ */
+MyGame.Example.Monster.createTestarrayofstring2Vector = function(builder, data) {
+ builder.startVector(4, data.length, 4);
+ for (var i = data.length - 1; i >= 0; i--) {
+ builder.addOffset(data[i]);
+ }
+ return builder.endVector();
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} numElems
+ */
+MyGame.Example.Monster.startTestarrayofstring2Vector = function(builder, numElems) {
+ builder.startVector(4, numElems, 4);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
* @returns {flatbuffers.Offset}
*/
MyGame.Example.Monster.endMonster = function(builder) {
diff --git a/tests/monsterdata_test.mon b/tests/monsterdata_test.mon
index 7a7fbf70..01bd5279 100644
--- a/tests/monsterdata_test.mon
+++ b/tests/monsterdata_test.mon
Binary files differ
diff --git a/tests/namespace_test/NamespaceA/NamespaceB/EnumInNestedNS.java b/tests/namespace_test/NamespaceA/NamespaceB/EnumInNestedNS.java
index ff555954..e23cecc0 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 f3684623..f834a721 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 93f80522..fede07a0 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 cf2b557c..c956fb42 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 2cfb1bac..fc518563 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 acabc393..e6f390a9 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 5580d5d5..0a002b3b 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 87397930..b44df978 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.cs b/tests/namespace_test/NamespaceC/TableInC.cs
new file mode 100644
index 00000000..0f75dfec
--- /dev/null
+++ b/tests/namespace_test/NamespaceC/TableInC.cs
@@ -0,0 +1,38 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+
+namespace NamespaceC
+{
+
+using System;
+using FlatBuffers;
+
+public sealed class TableInC : Table {
+ public static TableInC GetRootAsTableInC(ByteBuffer _bb) { return GetRootAsTableInC(_bb, new TableInC()); }
+ public static TableInC GetRootAsTableInC(ByteBuffer _bb, TableInC obj) { return (obj.__init(_bb.GetInt(_bb.Position) + _bb.Position, _bb)); }
+ public TableInC __init(int _i, ByteBuffer _bb) { bb_pos = _i; bb = _bb; return this; }
+
+ public NamespaceA.TableInFirstNS ReferToA1 { get { return GetReferToA1(new NamespaceA.TableInFirstNS()); } }
+ public NamespaceA.TableInFirstNS GetReferToA1(NamespaceA.TableInFirstNS obj) { int o = __offset(4); return o != 0 ? obj.__init(__indirect(o + bb_pos), bb) : null; }
+ public SecondTableInA ReferToA2 { get { return GetReferToA2(new SecondTableInA()); } }
+ public SecondTableInA GetReferToA2(SecondTableInA obj) { int o = __offset(6); return o != 0 ? obj.__init(__indirect(o + bb_pos), bb) : null; }
+
+ public static Offset<NamespaceC.TableInC> CreateTableInC(FlatBufferBuilder builder,
+ Offset<NamespaceA.TableInFirstNS> refer_to_a1Offset = default(Offset<NamespaceA.TableInFirstNS>),
+ Offset<SecondTableInA> refer_to_a2Offset = default(Offset<SecondTableInA>)) {
+ builder.StartObject(2);
+ TableInC.AddReferToA2(builder, refer_to_a2Offset);
+ TableInC.AddReferToA1(builder, refer_to_a1Offset);
+ return TableInC.EndTableInC(builder);
+ }
+
+ public static void StartTableInC(FlatBufferBuilder builder) { builder.StartObject(2); }
+ public static void AddReferToA1(FlatBufferBuilder builder, Offset<NamespaceA.TableInFirstNS> referToA1Offset) { builder.AddOffset(0, referToA1Offset.Value, 0); }
+ public static void AddReferToA2(FlatBufferBuilder builder, Offset<SecondTableInA> referToA2Offset) { builder.AddOffset(1, referToA2Offset.Value, 0); }
+ public static Offset<NamespaceC.TableInC> EndTableInC(FlatBufferBuilder builder) {
+ int o = builder.EndObject();
+ return new Offset<NamespaceC.TableInC>(o);
+ }
+};
+
+
+}
diff --git a/tests/namespace_test/NamespaceC/TableInC.go b/tests/namespace_test/NamespaceC/TableInC.go
new file mode 100644
index 00000000..dc75c45c
--- /dev/null
+++ b/tests/namespace_test/NamespaceC/TableInC.go
@@ -0,0 +1,46 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+
+package NamespaceC
+
+import (
+ flatbuffers "github.com/google/flatbuffers/go"
+)
+type TableInC struct {
+ _tab flatbuffers.Table
+}
+
+func (rcv *TableInC) Init(buf []byte, i flatbuffers.UOffsetT) {
+ rcv._tab.Bytes = buf
+ rcv._tab.Pos = i
+}
+
+func (rcv *TableInC) ReferToA1(obj *TableInFirstNS) *TableInFirstNS {
+ o := flatbuffers.UOffsetT(rcv._tab.Offset(4))
+ if o != 0 {
+ x := rcv._tab.Indirect(o + rcv._tab.Pos)
+ if obj == nil {
+ obj = new(TableInFirstNS)
+ }
+ obj.Init(rcv._tab.Bytes, x)
+ return obj
+ }
+ return nil
+}
+
+func (rcv *TableInC) ReferToA2(obj *SecondTableInA) *SecondTableInA {
+ o := flatbuffers.UOffsetT(rcv._tab.Offset(6))
+ if o != 0 {
+ x := rcv._tab.Indirect(o + rcv._tab.Pos)
+ if obj == nil {
+ obj = new(SecondTableInA)
+ }
+ obj.Init(rcv._tab.Bytes, x)
+ return obj
+ }
+ return nil
+}
+
+func TableInCStart(builder *flatbuffers.Builder) { builder.StartObject(2) }
+func TableInCAddReferToA1(builder *flatbuffers.Builder, referToA1 flatbuffers.UOffsetT) { builder.PrependUOffsetTSlot(0, flatbuffers.UOffsetT(referToA1), 0) }
+func TableInCAddReferToA2(builder *flatbuffers.Builder, referToA2 flatbuffers.UOffsetT) { builder.PrependUOffsetTSlot(1, flatbuffers.UOffsetT(referToA2), 0) }
+func TableInCEnd(builder *flatbuffers.Builder) flatbuffers.UOffsetT { return builder.EndObject() }
diff --git a/tests/namespace_test/NamespaceC/TableInC.java b/tests/namespace_test/NamespaceC/TableInC.java
new file mode 100644
index 00000000..19bb4cd5
--- /dev/null
+++ b/tests/namespace_test/NamespaceC/TableInC.java
@@ -0,0 +1,38 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+
+package NamespaceC;
+
+import java.nio.*;
+import java.lang.*;
+import java.util.*;
+import com.google.flatbuffers.*;
+
+@SuppressWarnings("unused")
+public final class TableInC extends Table {
+ public static TableInC getRootAsTableInC(ByteBuffer _bb) { return getRootAsTableInC(_bb, new TableInC()); }
+ public static TableInC getRootAsTableInC(ByteBuffer _bb, TableInC obj) { _bb.order(ByteOrder.LITTLE_ENDIAN); return (obj.__init(_bb.getInt(_bb.position()) + _bb.position(), _bb)); }
+ public TableInC __init(int _i, ByteBuffer _bb) { bb_pos = _i; bb = _bb; return this; }
+
+ public NamespaceA.TableInFirstNS referToA1() { return referToA1(new NamespaceA.TableInFirstNS()); }
+ public NamespaceA.TableInFirstNS referToA1(NamespaceA.TableInFirstNS obj) { int o = __offset(4); return o != 0 ? obj.__init(__indirect(o + bb_pos), bb) : null; }
+ public SecondTableInA referToA2() { return referToA2(new SecondTableInA()); }
+ public SecondTableInA referToA2(SecondTableInA obj) { int o = __offset(6); return o != 0 ? obj.__init(__indirect(o + bb_pos), bb) : null; }
+
+ public static int createTableInC(FlatBufferBuilder builder,
+ int refer_to_a1Offset,
+ int refer_to_a2Offset) {
+ builder.startObject(2);
+ TableInC.addReferToA2(builder, refer_to_a2Offset);
+ TableInC.addReferToA1(builder, refer_to_a1Offset);
+ return TableInC.endTableInC(builder);
+ }
+
+ public static void startTableInC(FlatBufferBuilder builder) { builder.startObject(2); }
+ public static void addReferToA1(FlatBufferBuilder builder, int referToA1Offset) { builder.addOffset(0, referToA1Offset, 0); }
+ public static void addReferToA2(FlatBufferBuilder builder, int referToA2Offset) { builder.addOffset(1, referToA2Offset, 0); }
+ public static int endTableInC(FlatBufferBuilder builder) {
+ int o = builder.endObject();
+ return o;
+ }
+}
+
diff --git a/tests/namespace_test/NamespaceC/TableInC.php b/tests/namespace_test/NamespaceC/TableInC.php
new file mode 100644
index 00000000..116aea1f
--- /dev/null
+++ b/tests/namespace_test/NamespaceC/TableInC.php
@@ -0,0 +1,100 @@
+<?php
+// automatically generated by the FlatBuffers compiler, do not modify
+
+namespace NamespaceC;
+
+use \Google\FlatBuffers\Struct;
+use \Google\FlatBuffers\Table;
+use \Google\FlatBuffers\ByteBuffer;
+use \Google\FlatBuffers\FlatBufferBuilder;
+
+class TableInC extends Table
+{
+ /**
+ * @param ByteBuffer $bb
+ * @return TableInC
+ */
+ public static function getRootAsTableInC(ByteBuffer $bb)
+ {
+ $obj = new TableInC();
+ return ($obj->init($bb->getInt($bb->getPosition()) + $bb->getPosition(), $bb));
+ }
+
+ /**
+ * @param int $_i offset
+ * @param ByteBuffer $_bb
+ * @return TableInC
+ **/
+ public function init($_i, ByteBuffer $_bb)
+ {
+ $this->bb_pos = $_i;
+ $this->bb = $_bb;
+ return $this;
+ }
+
+ public function getReferToA1()
+ {
+ $obj = new TableInFirstNS();
+ $o = $this->__offset(4);
+ return $o != 0 ? $obj->init($this->__indirect($o + $this->bb_pos), $this->bb) : 0;
+ }
+
+ public function getReferToA2()
+ {
+ $obj = new SecondTableInA();
+ $o = $this->__offset(6);
+ return $o != 0 ? $obj->init($this->__indirect($o + $this->bb_pos), $this->bb) : 0;
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @return void
+ */
+ public static function startTableInC(FlatBufferBuilder $builder)
+ {
+ $builder->StartObject(2);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @return TableInC
+ */
+ public static function createTableInC(FlatBufferBuilder $builder, $refer_to_a1, $refer_to_a2)
+ {
+ $builder->startObject(2);
+ self::addReferToA1($builder, $refer_to_a1);
+ self::addReferToA2($builder, $refer_to_a2);
+ $o = $builder->endObject();
+ return $o;
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param int
+ * @return void
+ */
+ public static function addReferToA1(FlatBufferBuilder $builder, $referToA1)
+ {
+ $builder->addOffsetX(0, $referToA1, 0);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param int
+ * @return void
+ */
+ public static function addReferToA2(FlatBufferBuilder $builder, $referToA2)
+ {
+ $builder->addOffsetX(1, $referToA2, 0);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @return int table offset
+ */
+ public static function endTableInC(FlatBufferBuilder $builder)
+ {
+ $o = $builder->endObject();
+ return $o;
+ }
+}
diff --git a/tests/namespace_test/NamespaceC/TableInC.py b/tests/namespace_test/NamespaceC/TableInC.py
new file mode 100644
index 00000000..5a4376ed
--- /dev/null
+++ b/tests/namespace_test/NamespaceC/TableInC.py
@@ -0,0 +1,39 @@
+# automatically generated by the FlatBuffers compiler, do not modify
+
+# namespace: NamespaceC
+
+import flatbuffers
+
+class TableInC(object):
+ __slots__ = ['_tab']
+
+ # TableInC
+ def Init(self, buf, pos):
+ self._tab = flatbuffers.table.Table(buf, pos)
+
+ # TableInC
+ def ReferToA1(self):
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(4))
+ if o != 0:
+ x = self._tab.Indirect(o + self._tab.Pos)
+ from .TableInFirstNS import TableInFirstNS
+ obj = TableInFirstNS()
+ obj.Init(self._tab.Bytes, x)
+ return obj
+ return None
+
+ # TableInC
+ def ReferToA2(self):
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(6))
+ if o != 0:
+ x = self._tab.Indirect(o + self._tab.Pos)
+ from .SecondTableInA import SecondTableInA
+ obj = SecondTableInA()
+ obj.Init(self._tab.Bytes, x)
+ return obj
+ return None
+
+def TableInCStart(builder): builder.StartObject(2)
+def TableInCAddReferToA1(builder, referToA1): builder.PrependUOffsetTRelativeSlot(0, flatbuffers.number_types.UOffsetTFlags.py_type(referToA1), 0)
+def TableInCAddReferToA2(builder, referToA2): builder.PrependUOffsetTRelativeSlot(1, flatbuffers.number_types.UOffsetTFlags.py_type(referToA2), 0)
+def TableInCEnd(builder): return builder.EndObject()
diff --git a/tests/namespace_test/namespace_test1_generated.h b/tests/namespace_test/namespace_test1_generated.h
index 9e10eb4c..59d4030a 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<TableInNestedNS> 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_test2_generated.h b/tests/namespace_test/namespace_test2_generated.h
index 8e6b3ada..77578bc6 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<TableInFirstNS> CreateTableInFirstNS(flatbuffers::FlatBufferBuilder &_fbb,
- flatbuffers::Offset<NamespaceA::NamespaceB::TableInNestedNS> foo_table = 0,
- NamespaceA::NamespaceB::EnumInNestedNS foo_enum = NamespaceA::NamespaceB::EnumInNestedNS_A,
- const NamespaceA::NamespaceB::StructInNestedNS *foo_struct = 0) {
+ flatbuffers::Offset<NamespaceA::NamespaceB::TableInNestedNS> 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<TableInC> CreateTableInC(flatbuffers::FlatBufferBuilder &_fbb,
- flatbuffers::Offset<NamespaceA::TableInFirstNS> refer_to_a1 = 0,
- flatbuffers::Offset<NamespaceA::SecondTableInA> refer_to_a2 = 0) {
+ flatbuffers::Offset<NamespaceA::TableInFirstNS> refer_to_a1 = 0,
+ flatbuffers::Offset<NamespaceA::SecondTableInA> refer_to_a2 = 0) {
TableInCBuilder builder_(_fbb);
builder_.add_refer_to_a2(refer_to_a2);
builder_.add_refer_to_a1(refer_to_a1);
@@ -146,7 +146,7 @@ struct SecondTableInABuilder {
};
inline flatbuffers::Offset<SecondTableInA> CreateSecondTableInA(flatbuffers::FlatBufferBuilder &_fbb,
- flatbuffers::Offset<NamespaceC::TableInC> refer_to_c = 0) {
+ flatbuffers::Offset<NamespaceC::TableInC> refer_to_c = 0) {
SecondTableInABuilder builder_(_fbb);
builder_.add_refer_to_c(refer_to_c);
return builder_.Finish();
@@ -154,4 +154,12 @@ inline flatbuffers::Offset<SecondTableInA> CreateSecondTableInA(flatbuffers::Fla
} // namespace NamespaceA
+namespace NamespaceC {
+
+} // namespace NamespaceC
+
+namespace NamespaceA {
+
+} // namespace NamespaceA
+
#endif // FLATBUFFERS_GENERATED_NAMESPACETEST2_NAMESPACEA_H_
diff --git a/tests/py_test.py b/tests/py_test.py
index 9129de70..e6609449 100644
--- a/tests/py_test.py
+++ b/tests/py_test.py
@@ -162,9 +162,10 @@ class TestFuzz(unittest.TestCase):
''' Low level stress/fuzz test: serialize/deserialize a variety of
different kinds of data in different combinations '''
- ofInt32Bytes = compat.binary_type([0x83, 0x33, 0x33, 0x33])
- ofInt64Bytes = compat.binary_type([0x84, 0x44, 0x44, 0x44,
- 0x44, 0x44, 0x44, 0x44])
+ binary_type = compat.binary_types[0] # this will always exist
+ ofInt32Bytes = binary_type([0x83, 0x33, 0x33, 0x33])
+ ofInt64Bytes = binary_type([0x84, 0x44, 0x44, 0x44,
+ 0x44, 0x44, 0x44, 0x44])
overflowingInt32Val = flatbuffers.encode.Get(flatbuffers.packer.int32,
ofInt32Bytes, 0)
overflowingInt64Val = flatbuffers.encode.Get(flatbuffers.packer.int64,
diff --git a/tests/test.cpp b/tests/test.cpp
index ca3ea03a..6ec4e678 100644
--- a/tests/test.cpp
+++ b/tests/test.cpp
@@ -15,6 +15,7 @@
*/
#define FLATBUFFERS_DEBUG_VERIFICATION_FAILURE 1
+#define FLATBUFFERS_TRACK_VERIFIER_BUFFER_SIZE
#include "flatbuffers/flatbuffers.h"
#include "flatbuffers/idl.h"
@@ -24,7 +25,9 @@
#include "namespace_test/namespace_test1_generated.h"
#include "namespace_test/namespace_test2_generated.h"
-#include <random>
+#ifndef FLATBUFFERS_CPP98_STL
+ #include <random>
+#endif
using namespace MyGame::Example;
@@ -114,13 +117,19 @@ flatbuffers::unique_ptr_t CreateFlatBufferTest(std::string &buffer) {
mb3.add_name(wilma);
mlocs[2] = mb3.Finish();
- // Create an array of strings. Also test string pooling.
- flatbuffers::Offset<flatbuffers::String> strings[4];
- strings[0] = builder.CreateSharedString("bob");
- strings[1] = builder.CreateSharedString("fred");
- strings[2] = builder.CreateSharedString("bob");
- strings[3] = builder.CreateSharedString("fred");
- auto vecofstrings = builder.CreateVector(strings, 4);
+ // Create an array of strings. Also test string pooling, and lambdas.
+ const char *names[] = { "bob", "fred", "bob", "fred" };
+ auto vecofstrings =
+ builder.CreateVector<flatbuffers::Offset<flatbuffers::String>>(4,
+ [&](size_t i) {
+ return builder.CreateSharedString(names[i]);
+ });
+
+ // Creating vectors of strings in one convenient call.
+ std::vector<std::string> names2;
+ names2.push_back("jane");
+ names2.push_back("mary");
+ auto vecofstrings2 = builder.CreateVectorOfStrings(names2);
// Create an array of sorted tables, can be used with binary search when read:
auto vecoftables = builder.CreateVectorOfSortedTables(mlocs, 3);
@@ -128,7 +137,9 @@ flatbuffers::unique_ptr_t CreateFlatBufferTest(std::string &buffer) {
// shortcut for creating monster with all fields set:
auto mloc = CreateMonster(builder, &vec, 150, 80, name, inventory, Color_Blue,
Any_Monster, mlocs[1].Union(), // Store a union.
- testv, vecofstrings, vecoftables, 0);
+ testv, vecofstrings, vecoftables, 0, 0, 0, false,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 3.14159f, 3.0f, 0.0f,
+ vecofstrings2);
FinishMonsterBuffer(builder, mloc);
@@ -148,12 +159,30 @@ flatbuffers::unique_ptr_t CreateFlatBufferTest(std::string &buffer) {
}
// example of accessing a buffer loaded in memory:
-void AccessFlatBufferTest(const uint8_t *flatbuf, size_t length) {
+void AccessFlatBufferTest(const uint8_t *flatbuf, size_t length,
+ bool pooled = true) {
// First, verify the buffers integrity (optional)
flatbuffers::Verifier verifier(flatbuf, length);
TEST_EQ(VerifyMonsterBuffer(verifier), true);
+ std::vector<uint8_t> test_buff;
+ test_buff.resize(length * 2);
+ std::memcpy(&test_buff[0], flatbuf , length);
+ std::memcpy(&test_buff[length], flatbuf , length);
+
+ flatbuffers::Verifier verifierl(&test_buff[0], length - 1);
+ TEST_EQ(VerifyMonsterBuffer(verifierl), false);
+ TEST_EQ(verifierl.GetComputedSize(), 0);
+
+ flatbuffers::Verifier verifier1(&test_buff[0], length);
+ TEST_EQ(VerifyMonsterBuffer(verifier1), true);
+ TEST_EQ(verifier1.GetComputedSize(), length);
+
+ flatbuffers::Verifier verifier2(&test_buff[length], length);
+ TEST_EQ(VerifyMonsterBuffer(verifier2), true);
+ TEST_EQ(verifier2.GetComputedSize(), length);
+
TEST_EQ(strcmp(MonsterIdentifier(), "MONS"), 0);
TEST_EQ(MonsterBufferHasIdentifier(flatbuf), true);
TEST_EQ(strcmp(MonsterExtension(), "mon"), 0);
@@ -194,9 +223,18 @@ void AccessFlatBufferTest(const uint8_t *flatbuf, size_t length) {
TEST_EQ(vecofstrings->Length(), 4U);
TEST_EQ_STR(vecofstrings->Get(0)->c_str(), "bob");
TEST_EQ_STR(vecofstrings->Get(1)->c_str(), "fred");
- // These should have pointer equality because of string pooling.
- TEST_EQ(vecofstrings->Get(0)->c_str(), vecofstrings->Get(2)->c_str());
- TEST_EQ(vecofstrings->Get(1)->c_str(), vecofstrings->Get(3)->c_str());
+ if (pooled) {
+ // These should have pointer equality because of string pooling.
+ TEST_EQ(vecofstrings->Get(0)->c_str(), vecofstrings->Get(2)->c_str());
+ TEST_EQ(vecofstrings->Get(1)->c_str(), vecofstrings->Get(3)->c_str());
+ }
+
+ auto vecofstrings2 = monster->testarrayofstring2();
+ if (vecofstrings2) {
+ TEST_EQ(vecofstrings2->Length(), 2U);
+ TEST_EQ_STR(vecofstrings2->Get(0)->c_str(), "jane");
+ TEST_EQ_STR(vecofstrings2->Get(1)->c_str(), "mary");
+ }
// Example of accessing a vector of tables:
auto vecoftables = monster->testarrayoftables();
@@ -274,6 +312,77 @@ void MutateFlatBuffersTest(uint8_t *flatbuf, std::size_t length) {
AccessFlatBufferTest(flatbuf, length);
}
+// Unpack a FlatBuffer into objects.
+void ObjectFlatBuffersTest(uint8_t *flatbuf) {
+ // Turn a buffer into C++ objects.
+ auto monster1 = GetMonster(flatbuf)->UnPack();
+
+ // Re-serialize the data.
+ flatbuffers::FlatBufferBuilder fbb1;
+ fbb1.Finish(CreateMonster(fbb1, monster1.get()), MonsterIdentifier());
+
+ // Unpack again, and re-serialize again.
+ auto monster2 = GetMonster(fbb1.GetBufferPointer())->UnPack();
+ flatbuffers::FlatBufferBuilder fbb2;
+ fbb2.Finish(CreateMonster(fbb2, monster2.get()), MonsterIdentifier());
+
+ // Now we've gone full round-trip, the two buffers should match.
+ auto len1 = fbb1.GetSize();
+ auto len2 = fbb2.GetSize();
+ TEST_EQ(len1, len2);
+ TEST_EQ(memcmp(fbb1.GetBufferPointer(), fbb2.GetBufferPointer(),
+ len1), 0);
+
+ // Test it with the original buffer test to make sure all data survived.
+ AccessFlatBufferTest(fbb2.GetBufferPointer(), len2, false);
+
+ // Test accessing fields, similar to AccessFlatBufferTest above.
+ TEST_EQ(monster2->hp, 80);
+ TEST_EQ(monster2->mana, 150); // default
+ TEST_EQ_STR(monster2->name.c_str(), "MyMonster");
+
+ auto &pos = monster2->pos;
+ TEST_NOTNULL(pos);
+ TEST_EQ(pos->z(), 3);
+ TEST_EQ(pos->test3().a(), 10);
+ TEST_EQ(pos->test3().b(), 20);
+
+ auto &inventory = monster2->inventory;
+ TEST_EQ(inventory.size(), 10UL);
+ unsigned char inv_data[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+ for (auto it = inventory.begin(); it != inventory.end(); ++it)
+ TEST_EQ(*it, inv_data[it - inventory.begin()]);
+
+ TEST_EQ(monster2->color, Color_Blue);
+
+ auto monster3 = monster2->test.AsMonster();
+ TEST_NOTNULL(monster3);
+ TEST_EQ_STR(monster3->name.c_str(), "Fred");
+
+ auto &vecofstrings = monster2->testarrayofstring;
+ TEST_EQ(vecofstrings.size(), 4U);
+ TEST_EQ_STR(vecofstrings[0].c_str(), "bob");
+ TEST_EQ_STR(vecofstrings[1].c_str(), "fred");
+
+ auto &vecofstrings2 = monster2->testarrayofstring2;
+ TEST_EQ(vecofstrings2.size(), 2U);
+ TEST_EQ_STR(vecofstrings2[0].c_str(), "jane");
+ TEST_EQ_STR(vecofstrings2[1].c_str(), "mary");
+
+ auto &vecoftables = monster2->testarrayoftables;
+ TEST_EQ(vecoftables.size(), 3U);
+ TEST_EQ_STR(vecoftables[0]->name.c_str(), "Barney");
+ TEST_EQ(vecoftables[0]->hp, 1000);
+ TEST_EQ_STR(vecoftables[1]->name.c_str(), "Fred");
+ TEST_EQ_STR(vecoftables[2]->name.c_str(), "Wilma");
+
+ auto &tests = monster2->test4;
+ TEST_EQ(tests[0].a(), 10);
+ TEST_EQ(tests[0].b(), 20);
+ TEST_EQ(tests[1].a(), 30);
+ TEST_EQ(tests[1].b(), 40);
+}
+
// example of parsing text straight into a buffer, and generating
// text back from it:
void ParseAndGenerateTextTest() {
@@ -770,7 +879,7 @@ void ErrorTest() {
TestError("table X { Y:int; Y:int; }", "field already");
TestError("struct X { Y:string; }", "only scalar");
TestError("struct X { Y:int (deprecated); }", "deprecate");
- TestError("union Z { X } table X { Y:Z; } root_type X; { Y: {",
+ TestError("union Z { X } table X { Y:Z; } root_type X; { Y: {}, A:1 }",
"missing type field");
TestError("union Z { X } table X { Y:Z; } root_type X; { Y_type: 99, Y: {",
"type id");
@@ -801,20 +910,32 @@ void ErrorTest() {
TestError("table X { Y:byte; } root_type X; { Y:1, Y:2 }", "more than once");
}
-// Additional parser testing not covered elsewhere.
-void ScientificTest() {
+template<typename T> T TestValue(const char *json, const char *type_name) {
flatbuffers::Parser parser;
// Simple schema.
- TEST_EQ(parser.Parse("table X { Y:float; } root_type X;"), true);
+ TEST_EQ(parser.Parse(std::string("table X { Y:" + std::string(type_name) + "; } root_type X;").c_str()), true);
- // Test scientific notation numbers.
- TEST_EQ(parser.Parse("{ Y:0.0314159e+2 }"), true);
- auto root = flatbuffers::GetRoot<float>(parser.builder_.GetBufferPointer());
+ TEST_EQ(parser.Parse(json), true);
+ auto root = flatbuffers::GetRoot<T>(parser.builder_.GetBufferPointer());
// root will point to the table, which is a 32bit vtable offset followed
// by a float:
- TEST_EQ(sizeof(flatbuffers::soffset_t) == 4 && // Test assumes 32bit offsets
- fabs(root[1] - 3.14159) < 0.001, true);
+ TEST_EQ(sizeof(flatbuffers::soffset_t), 4); // Test assumes 32bit offsets
+ return root[1];
+}
+
+bool FloatCompare(float a, float b) { return fabs(a - b) < 0.001; }
+
+// Additional parser testing not covered elsewhere.
+void ValueTest() {
+ // Test scientific notation numbers.
+ TEST_EQ(FloatCompare(TestValue<float>("{ Y:0.0314159e+2 }","float"), (float)3.14159), true);
+
+ // Test conversion functions.
+ TEST_EQ(FloatCompare(TestValue<float>("{ Y:cos(rad(180)) }","float"), -1), true);
+
+ // Test negative hex constant.
+ TEST_EQ(TestValue<int>("{ Y:-0x80 }","int") == -128, true);
}
void EnumStringsTest() {
@@ -929,6 +1050,34 @@ void UnknownFieldsTest() {
TEST_EQ(jsongen == "{str: \"test\",i: 10}", true);
}
+void ParseUnionTest() {
+ // Unions must be parseable with the type field following the object.
+ flatbuffers::Parser parser;
+ TEST_EQ(parser.Parse("table T { A:int; }"
+ "union U { T }"
+ "table V { X:U; }"
+ "root_type V;"
+ "{ X:{ A:1 }, X_type: T }"), true);
+}
+
+void ConformTest() {
+ flatbuffers::Parser parser;
+ TEST_EQ(parser.Parse("table T { A:int; } enum E:byte { A }"), true);
+
+ auto test_conform = [&](const char *test, const char *expected_err) {
+ flatbuffers::Parser parser2;
+ TEST_EQ(parser2.Parse(test), true);
+ auto err = parser2.ConformTo(parser);
+ TEST_NOTNULL(strstr(err.c_str(), expected_err));
+ };
+
+ test_conform("table T { A:byte; }", "types differ for field");
+ test_conform("table T { B:int; A:int; }", "offsets differ for field");
+ test_conform("table T { A:int = 1; }", "defaults differ for field");
+ test_conform("table T { B:float; }", "field renamed to different type");
+ test_conform("enum E:byte { B, A }", "values differ for enum");
+}
+
int main(int /*argc*/, const char * /*argv*/[]) {
// Run our various test suites:
@@ -940,6 +1089,8 @@ int main(int /*argc*/, const char * /*argv*/[]) {
MutateFlatBuffersTest(flatbuf.get(), rawbuf.length());
+ ObjectFlatBuffersTest(flatbuf.get());
+
#ifndef FLATBUFFERS_NO_FILE_TESTS
ParseAndGenerateTextTest();
ReflectionTest(flatbuf.get(), rawbuf.length());
@@ -950,13 +1101,15 @@ int main(int /*argc*/, const char * /*argv*/[]) {
FuzzTest2();
ErrorTest();
- ScientificTest();
+ ValueTest();
EnumStringsTest();
IntegerOutOfRangeTest();
UnicodeTest();
UnicodeSurrogatesTest();
UnicodeInvalidSurrogatesTest();
UnknownFieldsTest();
+ ParseUnionTest();
+ ConformTest();
if (!testing_fails) {
TEST_OUTPUT_LINE("ALL TESTS PASSED");