mirror of
https://github.com/google/flatbuffers.git
synced 2026-06-02 04:04:19 +00:00
Compare commits
290 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6f94fb51b1 | ||
|
|
57f3752d5e | ||
|
|
f52f848b95 | ||
|
|
3c3742a54a | ||
|
|
f325cce6fd | ||
|
|
88a85ffbbd | ||
|
|
35cbd23f63 | ||
|
|
210a1ab969 | ||
|
|
90c8ded449 | ||
|
|
8f864aad7b | ||
|
|
dddd0865cb | ||
|
|
0a81eb6463 | ||
|
|
b1740688bf | ||
|
|
86b505e412 | ||
|
|
da67c0a71f | ||
|
|
dadd1a926e | ||
|
|
01c50d57a6 | ||
|
|
e9f1f4d9b7 | ||
|
|
dd05f3249a | ||
|
|
43611fcc0b | ||
|
|
642254bee6 | ||
|
|
22743ca45a | ||
|
|
fb87c0d3c6 | ||
|
|
398ae0cb6b | ||
|
|
aaf5598a03 | ||
|
|
3d2cf554d7 | ||
|
|
55dec4d2f8 | ||
|
|
0f5f7faa9f | ||
|
|
90daabd5b1 | ||
|
|
262e1d7bf9 | ||
|
|
c559eb451e | ||
|
|
6a7ec85e83 | ||
|
|
81ecc98e02 | ||
|
|
9aeeddf5ac | ||
|
|
c7bfe06c54 | ||
|
|
349a391208 | ||
|
|
9d01bfaea3 | ||
|
|
cfbab31fb1 | ||
|
|
cb2481efdc | ||
|
|
d7ac3788e8 | ||
|
|
a0a313b101 | ||
|
|
93c0960c3a | ||
|
|
04d734d6d2 | ||
|
|
8468ea1ab4 | ||
|
|
0920d663d5 | ||
|
|
bbb72f0b73 | ||
|
|
8f8a27d6e5 | ||
|
|
86777bd66b | ||
|
|
8b92122f33 | ||
|
|
e93a5652d0 | ||
|
|
0c80b3a7cc | ||
|
|
f52ddfbd68 | ||
|
|
808b44f87a | ||
|
|
340d1a3447 | ||
|
|
ba20d9bff3 | ||
|
|
370693a200 | ||
|
|
33932ceea4 | ||
|
|
fb03f78fb4 | ||
|
|
523f3833eb | ||
|
|
46497e4f9a | ||
|
|
b627b7c6c6 | ||
|
|
e093f72d00 | ||
|
|
728bb64fed | ||
|
|
a07f0d428d | ||
|
|
b90d4e049d | ||
|
|
b0752e179b | ||
|
|
1fc12e0e5b | ||
|
|
e6fa7b1133 | ||
|
|
28e7dbd3d3 | ||
|
|
adc50051e0 | ||
|
|
2aec880347 | ||
|
|
238a8ebb15 | ||
|
|
86992476da | ||
|
|
751aeabc80 | ||
|
|
b4bb1b103f | ||
|
|
cffd187fc7 | ||
|
|
ccfa317486 | ||
|
|
a5cc2092a6 | ||
|
|
89041a1686 | ||
|
|
7a36419f24 | ||
|
|
281284fa5d | ||
|
|
1a27c7017a | ||
|
|
b8f5f84437 | ||
|
|
f2071e4f80 | ||
|
|
9c25ecdcd1 | ||
|
|
1beed12e59 | ||
|
|
4cd71d67f1 | ||
|
|
d9bc5ec047 | ||
|
|
c04c143cf0 | ||
|
|
c6aae45364 | ||
|
|
7f2a1c90d5 | ||
|
|
f5387387de | ||
|
|
e7e4dc755d | ||
|
|
b8224809ad | ||
|
|
bb22fb5756 | ||
|
|
ff274771ba | ||
|
|
15bf626191 | ||
|
|
ac106e835c | ||
|
|
640b525e83 | ||
|
|
0b379211dc | ||
|
|
bb223da258 | ||
|
|
17c5f89d4f | ||
|
|
695d26183a | ||
|
|
f5120a2aaf | ||
|
|
037314a059 | ||
|
|
ebcfbbadf0 | ||
|
|
6561c7a31f | ||
|
|
a6d98fb067 | ||
|
|
3a2d3a232f | ||
|
|
cebdad4d23 | ||
|
|
d798100be9 | ||
|
|
1fb6b9ee6f | ||
|
|
2d6e8f096b | ||
|
|
ec8038cc3d | ||
|
|
2df3d1c965 | ||
|
|
2272229983 | ||
|
|
b7bfecb4ee | ||
|
|
c7c4bbfce2 | ||
|
|
d7ba17dfe5 | ||
|
|
60b11435e6 | ||
|
|
ed2110d7b3 | ||
|
|
a9514de978 | ||
|
|
c57ab92e60 | ||
|
|
f878024d0b | ||
|
|
aac6be1153 | ||
|
|
dabe030890 | ||
|
|
29574282a2 | ||
|
|
2dd6ba57d1 | ||
|
|
6cc2307c71 | ||
|
|
74c8c7137a | ||
|
|
f9055ff9a7 | ||
|
|
9b3d8b318a | ||
|
|
87e29b25de | ||
|
|
f7bc9bd51b | ||
|
|
3dee617c86 | ||
|
|
2fb25e2bb3 | ||
|
|
b395359b6e | ||
|
|
fd61d70205 | ||
|
|
4f4495a693 | ||
|
|
68bbe983e9 | ||
|
|
bbef92c17d | ||
|
|
25c884158f | ||
|
|
3f936c5655 | ||
|
|
42a265b419 | ||
|
|
4bc4979acc | ||
|
|
b095367d17 | ||
|
|
eac2905568 | ||
|
|
12fd0c6838 | ||
|
|
19101826a8 | ||
|
|
7b94eab2b1 | ||
|
|
1a21b54560 | ||
|
|
b55f18649a | ||
|
|
e2373668d9 | ||
|
|
8c1a723ba5 | ||
|
|
ab7949dc16 | ||
|
|
2c4dce5ba7 | ||
|
|
cc84240098 | ||
|
|
b29ba4c70c | ||
|
|
fea6b525ee | ||
|
|
69dc71b5ed | ||
|
|
1a89682251 | ||
|
|
5fd0fefab6 | ||
|
|
f8a964d2b0 | ||
|
|
84033ae035 | ||
|
|
b9efbf6a3d | ||
|
|
13194ececa | ||
|
|
9ec9303abb | ||
|
|
03ee3db240 | ||
|
|
cf825b8819 | ||
|
|
377a8ba6b2 | ||
|
|
13cf6e66e3 | ||
|
|
81b6bacead | ||
|
|
e6fa14a08d | ||
|
|
c66683f27f | ||
|
|
6d6271db2f | ||
|
|
ab76c57ec8 | ||
|
|
d1e8899310 | ||
|
|
ccba2edb7c | ||
|
|
2a7a44be33 | ||
|
|
6301da75d1 | ||
|
|
059661b9ac | ||
|
|
dc5975ba7a | ||
|
|
0de4f3f75b | ||
|
|
b59aafc659 | ||
|
|
92a6ae93fa | ||
|
|
a31ddd2bb3 | ||
|
|
bc2ec7119b | ||
|
|
641b397f8b | ||
|
|
d342918790 | ||
|
|
c4377390a8 | ||
|
|
5608be0f96 | ||
|
|
dbecdf209d | ||
|
|
c05803bf96 | ||
|
|
d298adc4e6 | ||
|
|
c2050aa0e3 | ||
|
|
290e9f270b | ||
|
|
76ae10df42 | ||
|
|
cf0d7829a6 | ||
|
|
af21b9064d | ||
|
|
e31fbb0b23 | ||
|
|
43ba7c6369 | ||
|
|
dae513e0e7 | ||
|
|
d8944e45a2 | ||
|
|
5b5fcbfc00 | ||
|
|
6862b2ff08 | ||
|
|
22e87071dd | ||
|
|
606098cac8 | ||
|
|
b5c622762b | ||
|
|
2beb985fcc | ||
|
|
fd97404c51 | ||
|
|
d9fe4e2769 | ||
|
|
424fc0c3ac | ||
|
|
c81239f6ea | ||
|
|
b830dac266 | ||
|
|
dc38f93ca8 | ||
|
|
f9025eeb52 | ||
|
|
486c048a0d | ||
|
|
ab51b03093 | ||
|
|
dc2fa215b8 | ||
|
|
199157e8f4 | ||
|
|
520d68449f | ||
|
|
b075b8c49d | ||
|
|
f6c1a1ebcf | ||
|
|
c4aede2268 | ||
|
|
4a43c2bb2c | ||
|
|
b2e55c556e | ||
|
|
df0991b7de | ||
|
|
3368407aff | ||
|
|
25f3f358a0 | ||
|
|
00e8aa87b3 | ||
|
|
09ee46a83e | ||
|
|
02dfa64a89 | ||
|
|
f136570417 | ||
|
|
b6ba322a04 | ||
|
|
4b79ff5351 | ||
|
|
edd77ae2f3 | ||
|
|
985de211af | ||
|
|
8e3fa336eb | ||
|
|
582fd90c4a | ||
|
|
a15659e9f8 | ||
|
|
afd230af8d | ||
|
|
52ca75506a | ||
|
|
3bb9b839b8 | ||
|
|
5e7bfd0461 | ||
|
|
d05d114523 | ||
|
|
722b903f89 | ||
|
|
2ff6152204 | ||
|
|
98f9af8ecc | ||
|
|
481d332e72 | ||
|
|
1a18122e3f | ||
|
|
ee56418cef | ||
|
|
e1f8037cb5 | ||
|
|
ea9ee4c99e | ||
|
|
4026117ba1 | ||
|
|
49ee30a207 | ||
|
|
7c69c5dc3d | ||
|
|
223ebebbeb | ||
|
|
f96eb472b3 | ||
|
|
c1b0abe079 | ||
|
|
b04e21db16 | ||
|
|
756050b62c | ||
|
|
ef67a58410 | ||
|
|
2da0821286 | ||
|
|
928effd198 | ||
|
|
2e7806ede0 | ||
|
|
67967476b2 | ||
|
|
79d127c863 | ||
|
|
4f3e1c2831 | ||
|
|
199a49b5b3 | ||
|
|
96ab6ade5a | ||
|
|
9f16090f90 | ||
|
|
63b240ec7b | ||
|
|
c4ba502f57 | ||
|
|
94d5643f97 | ||
|
|
f0d91fa143 | ||
|
|
726a5f523e | ||
|
|
fa74ce6d16 | ||
|
|
8fdced4e11 | ||
|
|
9031597f49 | ||
|
|
dc7f5bc0d8 | ||
|
|
867dfc5957 | ||
|
|
52acb4b347 | ||
|
|
4c861daa3e | ||
|
|
b7a26d73ee | ||
|
|
1ba4d3c4c7 | ||
|
|
06c1ad5a73 | ||
|
|
38b3893211 | ||
|
|
36daedf35f | ||
|
|
247388a20c | ||
|
|
4802e8a285 |
12
.github/ISSUE_TEMPLATE.md
vendored
Normal file
12
.github/ISSUE_TEMPLATE.md
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
Thank you for submitting an issue!
|
||||
|
||||
Please make sure you include the names of the affected language(s), compiler version(s), operating system version(s), and FlatBuffers version(s) in your issue title.
|
||||
|
||||
This helps us get the correct maintainers to look at your issue. Here are examples of good titles:
|
||||
|
||||
- Crash when accessing FlatBuffer [C++, gcc 4.8, OS X, master]
|
||||
- Flatc converts a protobuf 'bytes' field to 'string' in fbs schema file [all languages, FlatBuffers 1.4]
|
||||
|
||||
Include other details as appropriate.
|
||||
|
||||
Thanks!
|
||||
16
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
16
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
Thank you for submitting a PR!
|
||||
|
||||
Please make sure you include the names of the affected language(s) in your PR title.
|
||||
This helps us get the correct maintainers to look at your issue.
|
||||
|
||||
If you make changes to any of the code generators, be sure to run
|
||||
`cd tests && sh generate_code.sh` (or equivalent .bat) and include the generated
|
||||
code changes in the PR. This allows us to better see the effect of the PR.
|
||||
|
||||
If your PR includes C++ code, please adhere to the Google C++ Style Guide,
|
||||
and don't forget we try to support older compilers (e.g. VS2010, GCC 4.6.3),
|
||||
so only some C++11 support is available.
|
||||
|
||||
Include other details as appropriate.
|
||||
|
||||
Thanks!
|
||||
8
.gitignore
vendored
8
.gitignore
vendored
@@ -48,6 +48,7 @@ tests/monsterdata_java_wire.mon
|
||||
tests/monsterdata_go_wire.mon
|
||||
tests/monsterdata_javascript_wire.mon
|
||||
tests/unicode_test.mon
|
||||
tests/ts/
|
||||
CMakeLists.txt.user
|
||||
CMakeScripts/**
|
||||
CTestTestfile.cmake
|
||||
@@ -64,3 +65,10 @@ target
|
||||
build/VS2010/FlatBuffers.sdf
|
||||
build/VS2010/FlatBuffers.opensdf
|
||||
build/VS2010/ipch/**/*.ipch
|
||||
*.so
|
||||
Testing/Temporary
|
||||
.cproject
|
||||
.settings/
|
||||
.project
|
||||
net/**/obj
|
||||
node_modules/
|
||||
|
||||
57
CMake/PackageDebian.cmake
Normal file
57
CMake/PackageDebian.cmake
Normal file
@@ -0,0 +1,57 @@
|
||||
# ------------------- Debianization ---------------------
|
||||
if (UNIX)
|
||||
|
||||
# Set build environment
|
||||
SET(CPACK_GENERATOR "TGZ;DEB")
|
||||
SET(CPACK_SOURCE_TGZ "ON")
|
||||
|
||||
# Common package information
|
||||
SET(CPACK_PACKAGE_DESCRIPTION_SUMMARY
|
||||
"FlatBuffers is an efficient cross platform serialization library for C++, with support for Java, C# and Go. It was created at Google specifically for game development and other performance-critical applications.")
|
||||
SET(CPACK_DEBIAN_PACKAGE_HOMEPAGE "https://github.com/google/flatbuffers")
|
||||
SET(CPACK_DEBIAN_PACKAGE_MAINTAINER "Vitaly Isaev <vitalyisaev2@gmail.com>")
|
||||
|
||||
# Derive package version from git
|
||||
EXECUTE_PROCESS(
|
||||
COMMAND date +%Y%m%d
|
||||
OUTPUT_VARIABLE DATE
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
EXECUTE_PROCESS(
|
||||
COMMAND git describe
|
||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
||||
OUTPUT_VARIABLE GIT_DESCRIBE_DIRTY
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
string(REGEX REPLACE "^v([0-9]+)\\..*" "\\1" VERSION_MAJOR "${GIT_DESCRIBE_DIRTY}")
|
||||
string(REGEX REPLACE "^v[0-9]+\\.([0-9]+).*" "\\1" VERSION_MINOR "${GIT_DESCRIBE_DIRTY}")
|
||||
string(REGEX REPLACE "^v[0-9]+\\.[0-9]+\\.([0-9]+).*" "\\1" VERSION_PATCH "${GIT_DESCRIBE_DIRTY}")
|
||||
string(REGEX REPLACE "^v[0-9]+\\.[0-9]+\\.[0-9]+\\-([0-9]+).*" "\\1" VERSION_COMMIT "${GIT_DESCRIBE_DIRTY}")
|
||||
SET(CPACK_PACKAGE_VERSION_MAJOR ${VERSION_MAJOR})
|
||||
SET(CPACK_PACKAGE_VERSION_MINOR ${VERSION_MINOR})
|
||||
SET(CPACK_PACKAGE_VERSION_PATCH ${VERSION_PATCH})
|
||||
SET(CPACK_PACKAGE_VERSION "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}-${VERSION_COMMIT}")
|
||||
SET(CPACK_DEBIAN_PACKAGE_VERSION "${CPACK_PACKAGE_VERSION}")
|
||||
|
||||
# Derive architecture
|
||||
IF(NOT CPACK_DEBIAN_PACKAGE_ARCHITECTURE)
|
||||
FIND_PROGRAM(DPKG_CMD dpkg)
|
||||
IF(NOT DPKG_CMD)
|
||||
MESSAGE(STATUS "Can not find dpkg in your path, default to i386.")
|
||||
SET(CPACK_DEBIAN_PACKAGE_ARCHITECTURE i386)
|
||||
ENDIF(NOT DPKG_CMD)
|
||||
EXECUTE_PROCESS(COMMAND "${DPKG_CMD}" --print-architecture
|
||||
OUTPUT_VARIABLE CPACK_DEBIAN_PACKAGE_ARCHITECTURE
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
ENDIF(NOT CPACK_DEBIAN_PACKAGE_ARCHITECTURE)
|
||||
|
||||
# Package name
|
||||
SET(CPACK_DEBIAN_PACKAGE_NAME "flatbuffers")
|
||||
SET(CPACK_RESOURCE_FILE_LICENSE ${CMAKE_SOURCE_DIR}/LICENSE.txt)
|
||||
SET(CPACK_PACKAGE_FILE_NAME
|
||||
"${CPACK_DEBIAN_PACKAGE_NAME}_${CPACK_DEBIAN_PACKAGE_VERSION}_${CPACK_DEBIAN_PACKAGE_ARCHITECTURE}")
|
||||
|
||||
endif(UNIX)
|
||||
|
||||
INCLUDE(CPack)
|
||||
@@ -12,6 +12,9 @@ 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)
|
||||
option(FLATBUFFERS_BUILD_SHAREDLIB
|
||||
"Enable the build of the flatbuffers shared library"
|
||||
OFF)
|
||||
|
||||
if(NOT FLATBUFFERS_BUILD_FLATC AND FLATBUFFERS_BUILD_TESTS)
|
||||
message(WARNING
|
||||
@@ -21,12 +24,16 @@ endif()
|
||||
|
||||
set(FlatBuffers_Library_SRCS
|
||||
include/flatbuffers/code_generators.h
|
||||
include/flatbuffers/base.h
|
||||
include/flatbuffers/flatbuffers.h
|
||||
include/flatbuffers/hash.h
|
||||
include/flatbuffers/idl.h
|
||||
include/flatbuffers/util.h
|
||||
include/flatbuffers/reflection.h
|
||||
include/flatbuffers/reflection_generated.h
|
||||
include/flatbuffers/flexbuffers.h
|
||||
include/flatbuffers/registry.h
|
||||
src/code_generators.cpp
|
||||
src/idl_parser.cpp
|
||||
src/idl_gen_text.cpp
|
||||
src/reflection.cpp
|
||||
@@ -44,8 +51,12 @@ set(FlatBuffers_Compiler_SRCS
|
||||
src/idl_gen_fbs.cpp
|
||||
src/idl_gen_grpc.cpp
|
||||
src/flatc.cpp
|
||||
src/flatc_main.cpp
|
||||
grpc/src/compiler/schema_interface.h
|
||||
grpc/src/compiler/cpp_generator.h
|
||||
grpc/src/compiler/cpp_generator.cc
|
||||
grpc/src/compiler/go_generator.h
|
||||
grpc/src/compiler/go_generator.cc
|
||||
)
|
||||
|
||||
set(FlatHash_SRCS
|
||||
@@ -56,7 +67,6 @@ set(FlatHash_SRCS
|
||||
set(FlatBuffers_Tests_SRCS
|
||||
${FlatBuffers_Library_SRCS}
|
||||
src/idl_gen_fbs.cpp
|
||||
src/idl_gen_general.cpp
|
||||
tests/test.cpp
|
||||
# file generate by running compiler on tests/monster_test.fbs
|
||||
${CMAKE_CURRENT_BINARY_DIR}/tests/monster_test_generated.h
|
||||
@@ -70,13 +80,7 @@ set(FlatBuffers_Sample_Binary_SRCS
|
||||
)
|
||||
|
||||
set(FlatBuffers_Sample_Text_SRCS
|
||||
include/flatbuffers/flatbuffers.h
|
||||
include/flatbuffers/hash.h
|
||||
include/flatbuffers/idl.h
|
||||
include/flatbuffers/util.h
|
||||
src/idl_parser.cpp
|
||||
src/idl_gen_text.cpp
|
||||
src/util.cpp
|
||||
${FlatBuffers_Library_SRCS}
|
||||
samples/sample_text.cpp
|
||||
# file generated by running compiler on samples/monster.fbs
|
||||
${CMAKE_CURRENT_BINARY_DIR}/samples/monster_generated.h
|
||||
@@ -95,9 +99,12 @@ set(FlatBuffers_GRPCTest_SRCS
|
||||
# source_group(Compiler FILES ${FlatBuffers_Compiler_SRCS})
|
||||
# source_group(Tests FILES ${FlatBuffers_Tests_SRCS})
|
||||
|
||||
if(APPLE)
|
||||
if(EXISTS "${CMAKE_TOOLCHAIN_FILE}")
|
||||
# do not apply any global settings if the toolchain
|
||||
# is being configured externally
|
||||
elseif(APPLE)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -stdlib=libc++")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -pedantic -Werror -Wextra")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -pedantic -Werror -Wextra -Wno-unused-parameter")
|
||||
elseif(CMAKE_COMPILER_IS_GNUCXX)
|
||||
if(CYGWIN)
|
||||
set(CMAKE_CXX_FLAGS
|
||||
@@ -110,7 +117,8 @@ elseif(CMAKE_COMPILER_IS_GNUCXX)
|
||||
"${CMAKE_CXX_FLAGS} -Wall -pedantic -Werror -Wextra -Werror=shadow")
|
||||
if (GCC_VERSION VERSION_GREATER 4.4)
|
||||
set(CMAKE_CXX_FLAGS
|
||||
"${CMAKE_CXX_FLAGS} -Wunused-result -Werror=unused-result")
|
||||
"${CMAKE_CXX_FLAGS} -Wunused-result -Werror=unused-result \
|
||||
-Wunused-parameter -Werror=unused-parameter")
|
||||
endif()
|
||||
|
||||
# Certain platforms such as ARM do not use signed chars by default
|
||||
@@ -118,11 +126,16 @@ elseif(CMAKE_COMPILER_IS_GNUCXX)
|
||||
set(CMAKE_CXX_FLAGS
|
||||
"${CMAKE_CXX_FLAGS} -fsigned-char")
|
||||
|
||||
elseif("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
|
||||
elseif(${CMAKE_CXX_COMPILER_ID} MATCHES "Clang")
|
||||
set(CMAKE_CXX_FLAGS
|
||||
"${CMAKE_CXX_FLAGS} -std=c++0x -stdlib=libc++ -Wall -pedantic -Werror \
|
||||
-Wextra")
|
||||
if(NOT "${CMAKE_SYSTEM_NAME}" MATCHES "FreeBSD")
|
||||
"${CMAKE_CXX_FLAGS} -std=c++0x -Wall -pedantic -Werror \
|
||||
-Wextra -Wno-unused-parameter")
|
||||
if(NOT "${CMAKE_SYSTEM_NAME}" MATCHES "Linux")
|
||||
set(CMAKE_CXX_FLAGS
|
||||
"${CMAKE_CXX_FLAGS} -stdlib=libc++")
|
||||
endif()
|
||||
if(NOT ("${CMAKE_SYSTEM_NAME}" MATCHES "FreeBSD" OR
|
||||
"${CMAKE_SYSTEM_NAME}" MATCHES "Linux"))
|
||||
set(CMAKE_EXE_LINKER_FLAGS
|
||||
"${CMAKE_EXE_LINKER_FLAGS} -lc++abi")
|
||||
endif()
|
||||
@@ -132,6 +145,11 @@ elseif("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
|
||||
set(CMAKE_CXX_FLAGS
|
||||
"${CMAKE_CXX_FLAGS} -fsigned-char")
|
||||
|
||||
elseif(MSVC)
|
||||
# Visual Studio pedantic build settings
|
||||
# warning C4512: assignment operator could not be generated
|
||||
# warning C4316: object allocated on the heap may not be aligned
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4 /WX /wd4512 /wd4316")
|
||||
endif()
|
||||
|
||||
if(FLATBUFFERS_CODE_COVERAGE)
|
||||
@@ -157,12 +175,21 @@ if(FLATBUFFERS_BUILD_FLATC)
|
||||
if(NOT FLATBUFFERS_FLATC_EXECUTABLE)
|
||||
set(FLATBUFFERS_FLATC_EXECUTABLE $<TARGET_FILE:flatc>)
|
||||
endif()
|
||||
if(MSVC)
|
||||
# Make flatc.exe not depend on runtime dlls for easy distribution.
|
||||
target_compile_options(flatc PUBLIC $<$<CONFIG:Release>:/MT>)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(FLATBUFFERS_BUILD_FLATHASH)
|
||||
add_executable(flathash ${FlatHash_SRCS})
|
||||
endif()
|
||||
|
||||
if(FLATBUFFERS_BUILD_SHAREDLIB)
|
||||
add_library(flatbuffers_shared SHARED ${FlatBuffers_Library_SRCS})
|
||||
set_target_properties(flatbuffers_shared PROPERTIES OUTPUT_NAME flatbuffers)
|
||||
endif()
|
||||
|
||||
function(compile_flatbuffers_schema_to_cpp SRC_FBS)
|
||||
get_filename_component(SRC_FBS_DIR ${SRC_FBS} PATH)
|
||||
string(REGEX REPLACE "\\.fbs$" "_generated.h" GEN_HEADER ${SRC_FBS})
|
||||
@@ -170,6 +197,7 @@ function(compile_flatbuffers_schema_to_cpp SRC_FBS)
|
||||
OUTPUT ${GEN_HEADER}
|
||||
COMMAND "${FLATBUFFERS_FLATC_EXECUTABLE}" -c --no-includes --gen-mutable
|
||||
--gen-object-api -o "${SRC_FBS_DIR}"
|
||||
-I "${CMAKE_CURRENT_SOURCE_DIR}/tests/include_test"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/${SRC_FBS}"
|
||||
DEPENDS flatc)
|
||||
endfunction()
|
||||
@@ -188,6 +216,9 @@ if(FLATBUFFERS_BUILD_TESTS)
|
||||
compile_flatbuffers_schema_to_cpp(tests/monster_test.fbs)
|
||||
include_directories(${CMAKE_CURRENT_BINARY_DIR}/tests)
|
||||
add_executable(flattests ${FlatBuffers_Tests_SRCS})
|
||||
set_property(TARGET flattests
|
||||
PROPERTY COMPILE_DEFINITIONS FLATBUFFERS_TRACK_VERIFIER_BUFFER_SIZE
|
||||
FLATBUFFERS_DEBUG_VERIFICATION_FAILURE=1)
|
||||
|
||||
compile_flatbuffers_schema_to_cpp(samples/monster.fbs)
|
||||
include_directories(${CMAKE_CURRENT_BINARY_DIR}/samples)
|
||||
@@ -197,10 +228,10 @@ endif()
|
||||
|
||||
if(FLATBUFFERS_BUILD_GRPCTEST)
|
||||
if(CMAKE_COMPILER_IS_GNUCXX)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-unused-parameter")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-unused-parameter -Wno-shadow")
|
||||
endif()
|
||||
add_executable(grpctest ${FlatBuffers_GRPCTest_SRCS})
|
||||
target_link_libraries(grpctest grpc++_unsecure grpc pthread dl)
|
||||
target_link_libraries(grpctest grpc++_unsecure pthread dl)
|
||||
endif()
|
||||
|
||||
if(FLATBUFFERS_INSTALL)
|
||||
@@ -211,6 +242,9 @@ if(FLATBUFFERS_INSTALL)
|
||||
if(FLATBUFFERS_BUILD_FLATC)
|
||||
install(TARGETS flatc DESTINATION bin)
|
||||
endif()
|
||||
if(FLATBUFFERS_BUILD_SHAREDLIB)
|
||||
install(TARGETS flatbuffers_shared DESTINATION lib)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(FLATBUFFERS_BUILD_TESTS)
|
||||
@@ -222,3 +256,7 @@ if(FLATBUFFERS_BUILD_TESTS)
|
||||
endif()
|
||||
|
||||
include(CMake/BuildFlatBuffers.cmake)
|
||||
|
||||
if(FLATBUFFERS_PACKAGE_DEBIAN)
|
||||
include(CMake/PackageDebian.cmake)
|
||||
endif()
|
||||
|
||||
@@ -25,7 +25,7 @@ use Github pull requests for this purpose.
|
||||
|
||||
Some tips for good pull requests:
|
||||
* Use our code
|
||||
[style guide](http://google-styleguide.googlecode.com/svn/trunk/cppguide.html).
|
||||
[style guide](https://google.github.io/styleguide/cppguide.html).
|
||||
When in doubt, try to stay true to the existing code of the project.
|
||||
* Write a descriptive commit message. What problem are you solving and what
|
||||
are the consequences? Where and what did you test? Some good tips:
|
||||
|
||||
@@ -24,7 +24,9 @@ LOCAL_PATH := $(call realpath-portable,$(LOCAL_PATH))
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := flatbuffers
|
||||
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/include
|
||||
LOCAL_EXPORT_CPPFLAGS := -std=c++11 -fexceptions -Wall -Wno-literal-suffix
|
||||
LOCAL_EXPORT_CPPFLAGS := -std=c++11 -fexceptions -Wall \
|
||||
-DFLATBUFFERS_TRACK_VERIFIER_BUFFER_SIZE
|
||||
|
||||
include $(BUILD_STATIC_LIBRARY)
|
||||
|
||||
# static library that additionally includes text parsing/generation/reflection
|
||||
@@ -34,7 +36,8 @@ LOCAL_MODULE := flatbuffers_extra
|
||||
LOCAL_SRC_FILES := src/idl_parser.cpp \
|
||||
src/idl_gen_text.cpp \
|
||||
src/reflection.cpp \
|
||||
src/util.cpp
|
||||
src/util.cpp \
|
||||
src/code_generators.cpp
|
||||
LOCAL_STATIC_LIBRARIES := flatbuffers
|
||||
include $(BUILD_STATIC_LIBRARY)
|
||||
|
||||
|
||||
37
appveyor.yml
37
appveyor.yml
@@ -4,6 +4,11 @@ branches:
|
||||
|
||||
os: Visual Studio 2015
|
||||
|
||||
environment:
|
||||
matrix:
|
||||
- CMAKE_VS_VERSION: "10 2010"
|
||||
- CMAKE_VS_VERSION: "14 2015"
|
||||
|
||||
platform:
|
||||
- x86
|
||||
- x64
|
||||
@@ -13,14 +18,34 @@ configuration:
|
||||
- Release
|
||||
|
||||
before_build:
|
||||
- cmake -G"Visual Studio 10 2010"
|
||||
- cmake -G"Visual Studio %CMAKE_VS_VERSION%"
|
||||
# This cuts down on a lot of noise generated by xamarin warnings.
|
||||
- del "C:\Program Files (x86)\MSBuild\14.0\Microsoft.Common.targets\ImportAfter\Xamarin.Common.targets"
|
||||
|
||||
build:
|
||||
project: ALL_BUILD.vcxproj
|
||||
verbosity: minimal
|
||||
|
||||
#test_script:
|
||||
# - Debug/flattests.exe
|
||||
test_script:
|
||||
- rem "---------------- C++ -----------------"
|
||||
- "%CONFIGURATION%\\flattests.exe"
|
||||
- rem "---------------- Java -----------------"
|
||||
- "cd tests"
|
||||
- "java -version"
|
||||
- "JavaTest.bat"
|
||||
- rem "---------------- JS -----------------"
|
||||
- "node --version"
|
||||
- "..\\%CONFIGURATION%\\flatc -b -I include_test monster_test.fbs unicode_test.json"
|
||||
- "node JavaScriptTest ./monster_test_generated"
|
||||
- rem "---------------- C# -----------------"
|
||||
# Have to compile this here rather than in "build" above because AppVeyor only
|
||||
# supports building one project??
|
||||
- "cd FlatBuffers.Test"
|
||||
- "msbuild.exe /property:Configuration=Release;OutputPath=tempcs /verbosity:minimal FlatBuffers.Test.csproj"
|
||||
- "tempcs\\FlatBuffers.Test.exe"
|
||||
# TODO: add more languages.
|
||||
- "cd ..\\.."
|
||||
|
||||
#artifacts:
|
||||
# - path: Release/flatc.exe
|
||||
# name: flatc.exe
|
||||
artifacts:
|
||||
- path: $(CONFIGURATION)\\flatc.exe
|
||||
name: flatc.exe
|
||||
|
||||
@@ -1 +1 @@
|
||||
../../CONTRIBUTING
|
||||
../../CONTRIBUTING.md
|
||||
@@ -29,7 +29,7 @@ For any schema input files, one or more generators can be specified:
|
||||
|
||||
- `--python`, `-p`: Generate Python code.
|
||||
|
||||
- `--javascript`, `-s`: Generate JavaScript code.
|
||||
- `--js`, `-s`: Generate JavaScript code.
|
||||
|
||||
- `--php`: Generate PHP code.
|
||||
|
||||
@@ -93,6 +93,12 @@ Additional options:
|
||||
output (by default the case for C++ and JS), all code will end up in
|
||||
this one file.
|
||||
|
||||
- `--no-js-exports` : Removes Node.js style export lines (useful for JS)
|
||||
|
||||
- `--goog-js-export` : Uses goog.exportsSymbol and goog.exportsProperty
|
||||
instead of Node.js style exporting. Needed for compatibility with the
|
||||
Google closure compiler (useful for JS).
|
||||
|
||||
- `--raw-binary` : Allow binaries without a file_indentifier to be read.
|
||||
This may crash flatc given a mismatched schema.
|
||||
|
||||
@@ -108,9 +114,16 @@ Additional options:
|
||||
to the reflection/reflection.fbs schema. Loading this binary file is the
|
||||
basis for reflection functionality.
|
||||
|
||||
- `--bfbs-comments`: Add doc comments to the binary schema files.
|
||||
|
||||
- `--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.
|
||||
|
||||
- `--include-prefix PATH` : Prefix this path to any generated include
|
||||
statements.
|
||||
|
||||
- `--keep-prefix` : Keep original prefix of schema include statement.
|
||||
|
||||
NOTE: short-form options for generators are deprecated, use the long form
|
||||
whenever possible.
|
||||
|
||||
@@ -85,7 +85,7 @@ 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.
|
||||
## Object based API. {#flatbuffers_cpp_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
|
||||
@@ -99,13 +99,116 @@ construction, access and mutation.
|
||||
To use:
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
|
||||
auto monsterobj = GetMonster(buffer)->UnPack();
|
||||
// Autogenerated class from table Monster.
|
||||
MonsterT monsterobj;
|
||||
|
||||
// Deserialize from buffer into object.
|
||||
UnPackTo(&monsterobj, flatbuffer);
|
||||
|
||||
// Update object directly like a C++ class instance.
|
||||
cout << monsterobj->name; // This is now a std::string!
|
||||
monsterobj->name = "Bob"; // Change the name.
|
||||
|
||||
// Serialize into new flatbuffer.
|
||||
FlatBufferBuilder fbb;
|
||||
CreateMonster(fbb, monsterobj.get()); // Serialize into new buffer.
|
||||
Pack(fbb, &monsterobj);
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The following attributes are specific to the object-based API code generation:
|
||||
|
||||
- `native_inline` (on a field): Because FlatBuffer tables and structs are
|
||||
optionally present in a given buffer, they are best represented as pointers
|
||||
(specifically std::unique_ptrs) in the native class since they can be null.
|
||||
This attribute changes the member declaration to use the type directly
|
||||
rather than wrapped in a unique_ptr.
|
||||
|
||||
- `native_default`: "value" (on a field): For members that are declared
|
||||
"native_inline", the value specified with this attribute will be included
|
||||
verbatim in the class constructor initializer list for this member.
|
||||
|
||||
- `native_type`' "type" (on a struct): In some cases, a more optimal C++ data
|
||||
type exists for a given struct. For example, the following schema:
|
||||
|
||||
struct Vec2 {
|
||||
x: float;
|
||||
y: float;
|
||||
}
|
||||
|
||||
generates the following Object-Based API class:
|
||||
|
||||
struct Vec2T : flatbuffers::NativeTable {
|
||||
float x;
|
||||
float y;
|
||||
};
|
||||
|
||||
However, it can be useful to instead use a user-defined C++ type since it
|
||||
can provide more functionality, eg.
|
||||
|
||||
struct vector2 {
|
||||
float x = 0, y = 0;
|
||||
vector2 operator+(vector2 rhs) const { ... }
|
||||
vector2 operator-(vector2 rhs) const { ... }
|
||||
float length() const { ... }
|
||||
// etc.
|
||||
};
|
||||
|
||||
The `native_type` attribute will replace the usage of the generated class
|
||||
with the given type. So, continuing with the example, the generated
|
||||
code would use |vector2| in place of |Vec2T| for all generated code.
|
||||
|
||||
However, becuase the native_type is unknown to flatbuffers, the user must
|
||||
provide the following functions to aide in the serialization process:
|
||||
|
||||
namespace flatbuffers {
|
||||
FlatbufferStruct Pack(const native_type& obj);
|
||||
native_type UnPack(const FlatbufferStruct& obj);
|
||||
}
|
||||
|
||||
Finally, the following top-level attribute
|
||||
|
||||
- native_include: "path" (at file level): Because the `native_type` attribute
|
||||
can be used to introduce types that are unknown to flatbuffers, it may be
|
||||
necessary to include "external" header files in the generated code. This
|
||||
attribute can be used to directly add an #include directive to the top of
|
||||
the generated code that includes the specified path directly.
|
||||
|
||||
# External references.
|
||||
|
||||
An additional feature of the object API is the ability to allow you to load
|
||||
multiple independent FlatBuffers, and have them refer to eachothers objects
|
||||
using hashes which are then represented as typed pointers in the object API.
|
||||
|
||||
To make this work have a field in the objects you want to referred to which is
|
||||
using the string hashing feature (see `hash` attribute in the
|
||||
[schema](@ref flatbuffers_guide_writing_schema) documentation). Then you have
|
||||
a similar hash in the field referring to it, along with a `cpp_type`
|
||||
attribute specifying the C++ type this will refer to (this can be any C++
|
||||
type, and will get a `*` added).
|
||||
|
||||
Then, in JSON or however you create these buffers, make sure they use the
|
||||
same string (or hash).
|
||||
|
||||
When you call `UnPack` (or `Create`), you'll need a function that maps from
|
||||
hash to the object (see `resolver_function_t` for details).
|
||||
|
||||
# Using different pointer types.
|
||||
|
||||
By default the object tree is built out of `std::unique_ptr`, but you can
|
||||
influence this either globally (using the `--cpp-ptr-type` argument to
|
||||
`flatc`) or per field (using the `cpp_ptr_type` attribute) to by any smart
|
||||
pointer type (`my_ptr<T>`), or by specifying `naked` as the type to get `T *`
|
||||
pointers. Unlike the smart pointers, naked pointers do not manage memory for
|
||||
you, so you'll have to manage their lifecycles manually.
|
||||
|
||||
|
||||
# Using different string type.
|
||||
|
||||
By default the object tree is built out of `std::string`, but you can
|
||||
influence this either globally (using the `--cpp-str-type` argument to
|
||||
`flatc`) or per field using the `cpp_str_type` attribute.
|
||||
|
||||
The type must support T::c_str() and T::length() as member functions.
|
||||
|
||||
## Reflection (& Resizing)
|
||||
|
||||
There is experimental support for reflection in FlatBuffers, allowing you to
|
||||
@@ -308,4 +411,22 @@ manually wrap it in synchronisation primites. There's no automatic way to
|
||||
accomplish this, by design, as we feel multithreaded construction
|
||||
of a single buffer will be rare, and synchronisation overhead would be costly.
|
||||
|
||||
## Advanced union features
|
||||
|
||||
The C++ implementation currently supports vectors of unions (i.e. you can
|
||||
declare a field as `[T]` where `T` is a union type instead of a table type). It
|
||||
also supports structs and strings in unions, besides tables.
|
||||
|
||||
For an example of these features, see `tests/union_vector`, and
|
||||
`UnionVectorTest` in `test.cpp`.
|
||||
|
||||
Since these features haven't been ported to other languages yet, if you
|
||||
choose to use them, you won't be able to use these buffers in other languages
|
||||
(`flatc` will refuse to compile a schema that uses these features).
|
||||
|
||||
These features reduce the amount of "table wrapping" that was previously
|
||||
needed to use unions.
|
||||
|
||||
To use scalars, simply wrap them in a struct.
|
||||
|
||||
<br>
|
||||
|
||||
@@ -78,6 +78,9 @@ inefficiency, but also forces you to write *more* code to access data
|
||||
In this context, it is only a better choice for systems that have very
|
||||
little to no information ahead of time about what data needs to be stored.
|
||||
|
||||
If you do need to store data that doesn't fit a schema, FlatBuffers also
|
||||
offers a schema-less (self-describing) version!
|
||||
|
||||
Read more about the "why" of FlatBuffers in the
|
||||
[white paper](@ref flatbuffers_white_paper).
|
||||
|
||||
@@ -138,6 +141,8 @@ sections provide a more in-depth usage guide.
|
||||
using FlatBuffers.
|
||||
- A [white paper](@ref flatbuffers_white_paper) explaining the "why" of
|
||||
FlatBuffers.
|
||||
- How to use the [schema-less](@ref flexbuffers) version of
|
||||
FlatBuffers.
|
||||
- A description of the [internals](@ref flatbuffers_internals) of FlatBuffers.
|
||||
- A formal [grammar](@ref flatbuffers_grammar) of the schema language.
|
||||
|
||||
|
||||
166
docs/source/FlexBuffers.md
Normal file
166
docs/source/FlexBuffers.md
Normal file
@@ -0,0 +1,166 @@
|
||||
FlexBuffers {#flexbuffers}
|
||||
==========
|
||||
|
||||
FlatBuffers was designed around schemas, because when you want maximum
|
||||
performance and data consistency, strong typing is helpful.
|
||||
|
||||
There are however times when you want to store data that doesn't fit a
|
||||
schema, because you can't know ahead of time what all needs to be stored.
|
||||
|
||||
For this, FlatBuffers has a dedicated format, called FlexBuffers.
|
||||
This is a binary format that can be used in conjunction
|
||||
with FlatBuffers (by storing a part of a buffer in FlexBuffers
|
||||
format), or also as its own independent serialization format.
|
||||
|
||||
While it loses the strong typing, you retain the most unique advantage
|
||||
FlatBuffers has over other serialization formats (schema-based or not):
|
||||
FlexBuffers can also be accessed without parsing / copying / object allocation.
|
||||
This is a huge win in efficiency / memory friendly-ness, and allows unique
|
||||
use cases such as mmap-ing large amounts of free-form data.
|
||||
|
||||
FlexBuffers' design and implementation allows for a very compact encoding,
|
||||
combining automatic pooling of strings with automatic sizing of containers to
|
||||
their smallest possible representation (8/16/32/64 bits). Many values and
|
||||
offsets can be encoded in just 8 bits. While a schema-less representation is
|
||||
usually more bulky because of the need to be self-descriptive, FlexBuffers
|
||||
generates smaller binaries for many cases than regular FlatBuffers.
|
||||
|
||||
FlexBuffers is still slower than regular FlatBuffers though, so we recommend to
|
||||
only use it if you need it.
|
||||
|
||||
|
||||
# Usage
|
||||
|
||||
This is for C++, other languages may follow.
|
||||
|
||||
Include the header `flexbuffers.h`, which in turn depends on `flatbuffers.h`
|
||||
and `util.h`.
|
||||
|
||||
To create a buffer:
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
|
||||
flexbuffers::Builder fbb;
|
||||
fbb.Int(13);
|
||||
fbb.Finish();
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
You create any value, followed by `Finish`. Unlike FlatBuffers which requires
|
||||
the root value to be a table, here any value can be the root, including a lonely
|
||||
int value.
|
||||
|
||||
You can now access the `std::vector<uint8_t>` that contains the encoded value
|
||||
as `fbb.GetBuffer()`. Write it, send it, or store it in a parent FlatBuffer. In
|
||||
this case, the buffer is just 3 bytes in size.
|
||||
|
||||
To read this value back, you could just say:
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
|
||||
auto root = flexbuffers::GetRoot(my_buffer);
|
||||
int64_t i = root.AsInt64();
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
FlexBuffers stores ints only as big as needed, so it doesn't differentiate
|
||||
between different sizes of ints. You can ask for the 64 bit version,
|
||||
regardless of what you put in. In fact, since you demand to read the root
|
||||
as an int, if you supply a buffer that actually contains a float, or a
|
||||
string with numbers in it, it will convert it for you on the fly as well,
|
||||
or return 0 if it can't. If instead you actually want to know what is inside
|
||||
the buffer before you access it, you can call `root.GetType()` or `root.IsInt()`
|
||||
etc.
|
||||
|
||||
Here's a slightly more complex value you could write instead of `fbb.Int` above:
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
|
||||
fbb.Map([&]() {
|
||||
fbb.Vector("vec", [&]() {
|
||||
fbb.Int(-100);
|
||||
fbb.String("Fred");
|
||||
fbb.IndirectFloat(4.0f);
|
||||
});
|
||||
fbb.UInt("foo", 100);
|
||||
});
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
This stores the equivalent of the JSON value
|
||||
`{ vec: [ -100, "Fred", 4.0 ], foo: 100 }`. The root is a dictionary that has
|
||||
just two key-value pairs, with keys `vec` and `foo`. Unlike FlatBuffers, it
|
||||
actually has to store these keys in the buffer (which it does only once if
|
||||
you store multiple such objects, by pooling key values), but also unlike
|
||||
FlatBuffers it has no restriction on the keys (fields) that you use.
|
||||
|
||||
The map constructor uses a C++11 Lambda to group its children, but you can
|
||||
also use more conventional start/end calls if you prefer.
|
||||
|
||||
The first value in the map is a vector. You'll notice that unlike FlatBuffers,
|
||||
you can use mixed types. There is also a `TypedVector` variant that only
|
||||
allows a single type, and uses a bit less memory.
|
||||
|
||||
`IndirectFloat` is an interesting feature that allows you to store values
|
||||
by offset rather than inline. Though that doesn't make any visible change
|
||||
to the user, the consequence is that large values (especially doubles or
|
||||
64 bit ints) that occur more than once can be shared. Another use case is
|
||||
inside of vectors, where the largest element makes up the size of all elements
|
||||
(e.g. a single double forces all elements to 64bit), so storing a lot of small
|
||||
integers together with a double is more efficient if the double is indirect.
|
||||
|
||||
Accessing it:
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
|
||||
auto map = flexbuffers::GetRoot(my_buffer).AsMap();
|
||||
map.size(); // 2
|
||||
auto vec = map["vec"].AsVector();
|
||||
vec.size(); // 3
|
||||
vec[0].AsInt64(); // -100;
|
||||
vec[1].AsString().c_str(); // "Fred";
|
||||
vec[1].AsInt64(); // 0 (Number parsing failed).
|
||||
vec[2].AsDouble(); // 4.0
|
||||
vec[2].AsString().IsTheEmptyString(); // true (Wrong Type).
|
||||
vec[2].AsString().c_str(); // "" (This still works though).
|
||||
vec[2].ToString().c_str(); // "4" (Or have it converted).
|
||||
map["foo"].AsUInt8(); // 100
|
||||
map["unknown"].IsNull(); // true
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
||||
# Binary encoding
|
||||
|
||||
A description of how FlexBuffers are encoded is in the
|
||||
[internals](Internals.md#flexbuffers) document.
|
||||
|
||||
|
||||
# Nesting inside a FlatBuffer
|
||||
|
||||
You can mark a field as containing a FlexBuffer, e.g.
|
||||
|
||||
a:[ubyte] (flexbuffer);
|
||||
|
||||
A special accessor will be generated that allows you to access the root value
|
||||
directly, e.g. `a_flexbuffer_root().AsInt64()`.
|
||||
|
||||
|
||||
# Efficiency tips
|
||||
|
||||
* Vectors generally are a lot more efficient than maps, so prefer them over maps
|
||||
when possible for small objects. Instead of a map with keys `x`, `y` and `z`,
|
||||
use a vector. Better yet, use a typed vector. Or even better, use a fixed
|
||||
size typed vector.
|
||||
* Maps are backwards compatible with vectors, and can be iterated as such.
|
||||
You can iterate either just the values (`map.Values()`), or in parallel with
|
||||
the keys vector (`map.Keys()`). If you intend
|
||||
to access most or all elements, this is faster than looking up each element
|
||||
by key, since that involves a binary search of the key vector.
|
||||
* When possible, don't mix values that require a big bit width (such as double)
|
||||
in a large vector of smaller values, since all elements will take on this
|
||||
width. Use `IndirectDouble` when this is a possibility. Note that
|
||||
integers automatically use the smallest width possible, i.e. if you ask
|
||||
to serialize an int64_t whose value is actually small, you will use less
|
||||
bits. Doubles are represented as floats whenever possible losslessly, but
|
||||
this is only possible for few values.
|
||||
Since nested vectors/maps are stored over offsets, they typically don't
|
||||
affect the vector width.
|
||||
* To store large arrays of byte data, use a blob. If you'd use a typed
|
||||
vector, the bit width of the size field may make it use more space than
|
||||
expected, and may not be compatible with `memcpy`.
|
||||
Similarly, large arrays of (u)int16_t may be better off stored as a
|
||||
binary blob if their size could exceed 64k elements.
|
||||
Construction and use are otherwise similar to strings.
|
||||
@@ -292,4 +292,148 @@ flexibility in which of the children of root object to write first (though in
|
||||
this case there's only one string), and what order to write the fields in.
|
||||
Different orders may also cause different alignments to happen.
|
||||
|
||||
# FlexBuffers
|
||||
|
||||
The [schema-less](@ref flexbuffers) version of FlatBuffers have their
|
||||
own encoding, detailed here.
|
||||
|
||||
It shares many properties mentioned above, in that all data is accessed
|
||||
over offsets, all scalars are aligned to their own size, and
|
||||
all data is always stored in little endian format.
|
||||
|
||||
One difference is that FlexBuffers are built front to back, so children are
|
||||
stored before parents, and the root of the data starts at the last byte.
|
||||
|
||||
Another difference is that scalar data is stored with a variable number of bits
|
||||
(8/16/32/64). The current width is always determined by the *parent*, i.e. if
|
||||
the scalar sits in a vector, the vector determines the bit width for all
|
||||
elements at once. Selecting the minimum bit width for a particular vector is
|
||||
something the encoder does automatically and thus is typically of no concern
|
||||
to the user, though being aware of this feature (and not sticking a double in
|
||||
the same vector as a bunch of byte sized elements) is helpful for efficiency.
|
||||
|
||||
Unlike FlatBuffers there is only one kind of offset, and that is an unsigned
|
||||
integer indicating the number of bytes in a negative direction from the address
|
||||
of itself (where the offset is stored).
|
||||
|
||||
### Vectors
|
||||
|
||||
The representation of the vector is at the core of how FlexBuffers works (since
|
||||
maps are really just a combination of 2 vectors), so it is worth starting there.
|
||||
|
||||
As mentioned, a vector is governed by a single bit width (supplied by its
|
||||
parent). This includes the size field. For example, a vector that stores the
|
||||
integer values `1, 2, 3` is encoded as follows:
|
||||
|
||||
uint8_t 3, 1, 2, 3, 4, 4, 4
|
||||
|
||||
The first `3` is the size field, and is placed before the vector (an offset
|
||||
from the parent to this vector points to the first element, not the size
|
||||
field, so the size field is effectively at index -1).
|
||||
Since this is an untyped vector `SL_VECTOR`, it is followed by 3 type
|
||||
bytes (one per element of the vector), which are always following the vector,
|
||||
and are always a uint8_t even if the vector is made up of bigger scalars.
|
||||
|
||||
### Types
|
||||
|
||||
A type byte is made up of 2 components (see flexbuffers.h for exact values):
|
||||
|
||||
* 2 lower bits representing the bit-width of the child (8, 16, 32, 64).
|
||||
This is only used if the child is accessed over an offset, such as a child
|
||||
vector. It is ignored for inline types.
|
||||
* 6 bits representing the actual type (see flexbuffers.h).
|
||||
|
||||
Thus, in this example `4` means 8 bit child (value 0, unused, since the value is
|
||||
in-line), type `SL_INT` (value 1).
|
||||
|
||||
### Typed Vectors
|
||||
|
||||
These are like the Vectors above, but omit the type bytes. The type is instead
|
||||
determined by the vector type supplied by the parent. Typed vectors are only
|
||||
available for a subset of types for which these savings can be significant,
|
||||
namely inline signed/unsigned integers (`TYPE_VECTOR_INT` / `TYPE_VECTOR_UINT`),
|
||||
floats (`TYPE_VECTOR_FLOAT`), and keys (`TYPE_VECTOR_KEY`, see below).
|
||||
|
||||
Additionally, for scalars, there are fixed length vectors of sizes 2 / 3 / 4
|
||||
that don't store the size (`TYPE_VECTOR_INT2` etc.), for an additional savings
|
||||
in space when storing common vector or color data.
|
||||
|
||||
### Scalars
|
||||
|
||||
FlexBuffers supports integers (`TYPE_INT` and `TYPE_UINT`) and floats
|
||||
(`TYPE_FLOAT`), available in the bit-widths mentioned above. They can be stored
|
||||
both inline and over an offset (`TYPE_INDIRECT_*`).
|
||||
|
||||
The offset version is useful to encode costly 64bit (or even 32bit) quantities
|
||||
into vectors / maps of smaller sizes, and to share / repeat a value multiple
|
||||
times.
|
||||
|
||||
### Blobs, Strings and Keys.
|
||||
|
||||
A blob (`TYPE_BLOB`) is encoded similar to a vector, with one difference: the
|
||||
elements are always `uint8_t`. The parent bit width only determines the width of
|
||||
the size field, allowing blobs to be large without the elements being large.
|
||||
|
||||
Strings (`TYPE_STRING`) are similar to blobs, except they have an additional 0
|
||||
termination byte for convenience, and they MUST be UTF-8 encoded (since an
|
||||
accessor in a language that does not support pointers to UTF-8 data may have to
|
||||
convert them to a native string type).
|
||||
|
||||
A "Key" (`TYPE_KEY`) is similar to a string, but doesn't store the size
|
||||
field. They're so named because they are used with maps, which don't care
|
||||
for the size, and can thus be even more compact. Unlike strings, keys cannot
|
||||
contain bytes of value 0 as part of their data (size can only be determined by
|
||||
`strlen`), so while you can use them outside the context of maps if you so
|
||||
desire, you're usually better off with strings.
|
||||
|
||||
### Maps
|
||||
|
||||
A map (`TYPE_MAP`) is like an (untyped) vector, but with 2 prefixes before the
|
||||
size field:
|
||||
|
||||
| index | field |
|
||||
| ----: | :----------------------------------------------------------- |
|
||||
| -3 | An offset to the keys vector (may be shared between tables). |
|
||||
| -2 | Byte width of the keys vector. |
|
||||
| -1 | Size (from here on it is compatible with `TYPE_VECTOR`) |
|
||||
| 0 | Elements. |
|
||||
| Size | Types. |
|
||||
|
||||
Since a map is otherwise the same as a vector, it can be iterated like
|
||||
a vector (which is probably faster than lookup by key).
|
||||
|
||||
The keys vector is a typed vector of keys. Both the keys and corresponding
|
||||
values *have* to be stored in sorted order (as determined by `strcmp`), such
|
||||
that lookups can be made using binary search.
|
||||
|
||||
The reason the key vector is a seperate structure from the value vector is
|
||||
such that it can be shared between multiple value vectors, and also to
|
||||
allow it to be treated as its own indivual vector in code.
|
||||
|
||||
An example map { foo: 13, bar: 14 } would be encoded as:
|
||||
|
||||
0 : uint8_t 'f', 'o', 'o', 0
|
||||
4 : uint8_t 'b', 'a', 'r', 0
|
||||
8 : uint8_t 2 // key vector of size 2
|
||||
// key vector offset points here
|
||||
9 : uint8_t 9, 6 // offsets to foo_key and bar_key
|
||||
11: uint8_t 3, 1 // offset to key vector, and its byte width
|
||||
13: uint8_t 2 // value vector of size
|
||||
// value vector offset points here
|
||||
14: uint8_t 13, 14 // values
|
||||
16: uint8_t 4, 4 // types
|
||||
|
||||
### The root
|
||||
|
||||
As mentioned, the root starts at the end of the buffer.
|
||||
The last uint8_t is the width in bytes of the root (normally the parent
|
||||
determines the width, but the root has no parent). The uint8_t before this is
|
||||
the type of the root, and the bytes before that are the root value (of the
|
||||
number of bytes specified by the last byte).
|
||||
|
||||
So for example, the integer value `13` as root would be:
|
||||
|
||||
uint8_t 13, 4, 1 // Value, type, root byte width.
|
||||
|
||||
|
||||
<br>
|
||||
|
||||
@@ -131,6 +131,37 @@ object are prefixed with `Get`, e.g.:
|
||||
monster.GetPos(preconstructedPos);
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
## Storing dictionaries in a FlatBuffer
|
||||
|
||||
FlatBuffers doesn't support dictionaries natively, but there is support to
|
||||
emulate their behavior with vectors and binary search, which means you
|
||||
can have fast lookups directly from a FlatBuffer without having to unpack
|
||||
your data into a `Dictionary` or similar.
|
||||
|
||||
To use it:
|
||||
- Designate one of the fields in a table as they "key" field. You do this
|
||||
by setting the `key` attribute on this field, e.g.
|
||||
`name:string (key)`.
|
||||
You may only have one key field, and it must be of string or scalar type.
|
||||
- Write out tables of this type as usual, collect their offsets in an
|
||||
array.
|
||||
- Instead of calling standard generated method,
|
||||
e.g.: `Monster.createTestarrayoftablesVector`,
|
||||
call `CreateSortedVectorOfMonster` in C# or
|
||||
`createSortedVectorOfTables` (from the `FlatBufferBuilder` object) in Java,
|
||||
which will first sort all offsets such that the tables they refer to
|
||||
are sorted by the key field, then serialize it.
|
||||
- Now when you're accessing the FlatBuffer, you can use
|
||||
the `ByKey` accessor to access elements of the vector, e.g.:
|
||||
`monster.testarrayoftablesByKey("Frodo")` in Java or
|
||||
`monster.TestarrayoftablesByKey("Frodo")` in C#,
|
||||
which returns an object of the corresponding table type,
|
||||
or `null` if not found.
|
||||
`ByKey` performs a binary search, so should have a similar
|
||||
speed to `Dictionary`, though may be faster because of better caching.
|
||||
`ByKey` only works if the vector has been sorted, it will
|
||||
likely not find elements if it hasn't been sorted.
|
||||
|
||||
## Text parsing
|
||||
|
||||
There currently is no support for parsing text (Schema's and JSON) directly
|
||||
|
||||
@@ -158,6 +158,10 @@ If you have a need to distinguish between different FlatBuffers in a more
|
||||
open-ended way, for example for use as files, see the file identification
|
||||
feature below.
|
||||
|
||||
There is an experimental support only in C++ for a vector of unions
|
||||
(and types). In the example IDL file above, use [Any] to add a
|
||||
vector of Any to Monster table.
|
||||
|
||||
### Namespaces
|
||||
|
||||
These will generate the corresponding namespace in C++ for all helper
|
||||
@@ -285,9 +289,6 @@ Current understood attributes:
|
||||
code may access it directly, without checking for NULL. If the constructing
|
||||
code does not initialize this field, they will get an assert, and also
|
||||
the verifier will fail on buffers that have missing required fields.
|
||||
- `original_order` (on a table): since elements in a table do not need
|
||||
to be stored in any particular order, they are often optimized for
|
||||
space by sorting them to size. This attribute stops that from happening.
|
||||
- `force_align: size` (on a struct): force the alignment of this struct
|
||||
to be something higher than what it is naturally aligned to. Causes
|
||||
these structs to be aligned to that amount inside a buffer, IF that
|
||||
@@ -301,9 +302,24 @@ Current understood attributes:
|
||||
(which must be a vector of ubyte) contains flatbuffer data, for which the
|
||||
root type is given by `table_name`. The generated code will then produce
|
||||
a convenient accessor for the nested FlatBuffer.
|
||||
- `flexbuffer` (on a field): this indicates that the field
|
||||
(which must be a vector of ubyte) contains flexbuffer data. The generated
|
||||
code will then produce a convenient accessor for the FlexBuffer root.
|
||||
- `key` (on a field): this field is meant to be used as a key when sorting
|
||||
a vector of the type of table it sits in. Can be used for in-place
|
||||
binary search.
|
||||
- `hash` (on a field). This is an (un)signed 32/64 bit integer field, whose
|
||||
value during JSON parsing is allowed to be a string, which will then be
|
||||
stored as its hash. The value of attribute is the hashing algorithm to
|
||||
use, one of `fnv1_32` `fnv1_64` `fnv1a_32` `fnv1a_64`.
|
||||
- `original_order` (on a table): since elements in a table do not need
|
||||
to be stored in any particular order, they are often optimized for
|
||||
space by sorting them to size. This attribute stops that from happening.
|
||||
There should generally not be any reason to use this flag.
|
||||
- 'native_*'. Several attributes have been added to support the [C++ object
|
||||
Based API](@ref flatbuffers_cpp_object_based_api). All such attributes
|
||||
are prefixed with the term "native_".
|
||||
|
||||
|
||||
## JSON Parsing
|
||||
|
||||
@@ -359,6 +375,66 @@ When parsing JSON, it recognizes the following escape codes in strings:
|
||||
It also generates these escape codes back again when generating JSON from a
|
||||
binary representation.
|
||||
|
||||
## Guidelines
|
||||
|
||||
### Efficiency
|
||||
|
||||
FlatBuffers is all about efficiency, but to realize that efficiency you
|
||||
require an efficient schema. There are usually multiple choices on
|
||||
how to represent data that have vastly different size characteristics.
|
||||
|
||||
It is very common nowadays to represent any kind of data as dictionaries
|
||||
(as in e.g. JSON), because of its flexibility and extensibility. While
|
||||
it is possible to emulate this in FlatBuffers (as a vector
|
||||
of tables with key and value(s)), this is a bad match for a strongly
|
||||
typed system like FlatBuffers, leading to relatively large binaries.
|
||||
FlatBuffer tables are more flexible than classes/structs in most systems,
|
||||
since having a large number of fields only few of which are actually
|
||||
used is still efficient. You should thus try to organize your data
|
||||
as much as possible such that you can use tables where you might be
|
||||
tempted to use a dictionary.
|
||||
|
||||
Similarly, strings as values should only be used when they are
|
||||
truely open-ended. If you can, always use an enum instead.
|
||||
|
||||
FlatBuffers doesn't have inheritance, so the way to represent a set
|
||||
of related data structures is a union. Unions do have a cost however,
|
||||
so an alternative to a union is to have a single table that has
|
||||
all the fields of all the data structures you are trying to
|
||||
represent, if they are relatively similar / share many fields.
|
||||
Again, this is efficient because optional fields are cheap.
|
||||
|
||||
FlatBuffers supports the full range of integer sizes, so try to pick
|
||||
the smallest size needed, rather than defaulting to int/long.
|
||||
|
||||
Remember that you can share data (refer to the same string/table
|
||||
within a buffer), so factoring out repeating data into its own
|
||||
data structure may be worth it.
|
||||
|
||||
### Style guide
|
||||
|
||||
Identifiers in a schema are meant to translate to many different programming
|
||||
languages, so using the style of your "main" language is generally a bad idea.
|
||||
|
||||
For this reason, below is a suggested style guide to adhere to, to keep schemas
|
||||
consistent for interoperation regardless of the target language.
|
||||
|
||||
Where possible, the code generators for specific languages will generate
|
||||
identifiers that adhere to the language style, based on the schema identifiers.
|
||||
|
||||
- Table, struct, enum and rpc names (types): UpperCamelCase.
|
||||
- Table and struct field names: snake_case. This is translated to lowerCamelCase
|
||||
automatically for some languages, e.g. Java.
|
||||
- Enum values: UpperCamelCase.
|
||||
- namespaces: UpperCamelCase.
|
||||
|
||||
Formatting (this is less important, but still worth adhering to):
|
||||
|
||||
- Opening brace: on the same line as the start of the declaration.
|
||||
- Spacing: Indent by 2 spaces. None around `:` for types, on both sides for `=`.
|
||||
|
||||
For an example, see the schema at the top of this file.
|
||||
|
||||
## Gotchas
|
||||
|
||||
### Schemas and version control
|
||||
|
||||
@@ -160,6 +160,7 @@ the `schema` that defines the template for our monsters:
|
||||
color:Color = Blue; // Enum.
|
||||
weapons:[Weapon]; // Vector of tables.
|
||||
equipped:Equipment; // Union.
|
||||
path:[Vec3]; // Vector of structs.
|
||||
}
|
||||
|
||||
table Weapon {
|
||||
@@ -399,55 +400,56 @@ The first step is to import/include the library, generated files, etc.
|
||||
|
||||
Now we are ready to start building some buffers. In order to start, we need
|
||||
to create an instance of the `FlatBufferBuilder`, which will contain the buffer
|
||||
as it grows:
|
||||
as it grows. You can pass an initial size of the buffer (here 1024 bytes),
|
||||
which will grow automatically if needed:
|
||||
|
||||
<div class="language-cpp">
|
||||
~~~{.cpp}
|
||||
// Create a `FlatBufferBuilder`, which will be used to create our
|
||||
// monsters' FlatBuffers.
|
||||
flatbuffers::FlatBufferBuilder builder;
|
||||
flatbuffers::FlatBufferBuilder builder(1024);
|
||||
~~~
|
||||
</div>
|
||||
<div class="language-java">
|
||||
~~~{.java}
|
||||
// Create a `FlatBufferBuilder`, which will be used to create our
|
||||
// monsters' FlatBuffers.
|
||||
FlatBufferBuilder builder = new FlatBufferBuilder(0);
|
||||
FlatBufferBuilder builder = new FlatBufferBuilder(1024);
|
||||
~~~
|
||||
</div>
|
||||
<div class="language-csharp">
|
||||
~~~{.cs}
|
||||
// Create a `FlatBufferBuilder`, which will be used to create our
|
||||
// monsters' FlatBuffers.
|
||||
var builder = new FlatBufferBuilder(1);
|
||||
var builder = new FlatBufferBuilder(1024);
|
||||
~~~
|
||||
</div>
|
||||
<div class="language-go">
|
||||
~~~{.go}
|
||||
// Create a `FlatBufferBuilder`, which will be used to create our
|
||||
// monsters' FlatBuffers.
|
||||
builder := flatbuffers.NewBuilder(0)
|
||||
builder := flatbuffers.NewBuilder(1024)
|
||||
~~~
|
||||
</div>
|
||||
<div class="language-python">
|
||||
~~~{.py}
|
||||
# Create a `FlatBufferBuilder`, which will be used to create our
|
||||
# monsters' FlatBuffers.
|
||||
builder = flatbuffers.Builder(0)
|
||||
builder = flatbuffers.Builder(1024)
|
||||
~~~
|
||||
</div>
|
||||
<div class="language-javascript">
|
||||
~~~{.js}
|
||||
// Create a `flatbuffer.Builder`, which will be used to create our
|
||||
// monsters' FlatBuffers.
|
||||
var builder = new flatbuffers.Builder(1);
|
||||
var builder = new flatbuffers.Builder(1024);
|
||||
~~~
|
||||
</div>
|
||||
<div class="language-php">
|
||||
~~~{.php}
|
||||
// Create a `FlatBufferBuilder`, which will be used to create our
|
||||
// monsters' FlatBuffers.
|
||||
$builder = new Google\FlatBuffers\FlatbufferBuilder(0);
|
||||
$builder = new Google\FlatBuffers\FlatbufferBuilder(1024);
|
||||
~~~
|
||||
</div>
|
||||
<div class="language-c">
|
||||
@@ -798,55 +800,67 @@ 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:
|
||||
Note that vectors of structs are serialized differently from tables, since
|
||||
structs are stored in-line in the vector. For example, to create a vector
|
||||
for the `path` field above:
|
||||
|
||||
<div class="language-cpp">
|
||||
~~~{.cpp}
|
||||
// Create a `Vec3`, representing the Orc's position in 3-D space.
|
||||
auto pos = Vec3(1.0f, 2.0f, 3.0f);
|
||||
Vec3 points[] = { Vec3(1.0f, 2.0f, 3.0f), Vec3(4.0f, 5.0f, 6.0f) };
|
||||
auto path = fbb.CreateVectorOfStructs(points, 2);
|
||||
~~~
|
||||
</div>
|
||||
<div class="language-java">
|
||||
~~~{.java}
|
||||
// Create a `Vec3`, representing the Orc's position in 3-D space.
|
||||
int pos = Vec3.createVec3(builder, 1.0f, 2.0f, 3.0f);
|
||||
Monster.startPathVector(fbb, 2);
|
||||
Vec3.createVec3(builder, 1.0f, 2.0f, 3.0f);
|
||||
Vec3.createVec3(builder, 4.0f, 5.0f, 6.0f);
|
||||
int path = fbb.endVector();
|
||||
~~~
|
||||
</div>
|
||||
<div class="language-csharp">
|
||||
~~~{.cs}
|
||||
// Create a `Vec3`, representing the Orc's position in 3-D space.
|
||||
var pos = Vec3.CreateVec3(builder, 1.0f, 2.0f, 3.0f);
|
||||
Monster.StartPathVector(fbb, 2);
|
||||
Vec3.CreateVec3(builder, 1.0f, 2.0f, 3.0f);
|
||||
Vec3.CreateVec3(builder, 4.0f, 5.0f, 6.0f);
|
||||
var path = fbb.EndVector();
|
||||
~~~
|
||||
</div>
|
||||
<div class="language-go">
|
||||
~~~{.go}
|
||||
// Create a `Vec3`, representing the Orc's position in 3-D space.
|
||||
pos := sample.CreateVec3(builder, 1.0, 2.0, 3.0)
|
||||
sample.MonsterStartPathVector(builder, 2)
|
||||
sample.CreateVec3(builder, 1.0, 2.0, 3.0)
|
||||
sample.CreateVec3(builder, 4.0, 5.0, 6.0)
|
||||
path := builder.EndVector(2)
|
||||
~~~
|
||||
</div>
|
||||
<div class="language-python">
|
||||
~~~{.py}
|
||||
# Create a `Vec3`, representing the Orc's position in 3-D space.
|
||||
pos = MyGame.Sample.Vec3.CreateVec3(builder, 1.0, 2.0, 3.0)
|
||||
MyGame.Example.Monster.MonsterStartPathVector(builder, 2)
|
||||
MyGame.Sample.Vec3.CreateVec3(builder, 1.0, 2.0, 3.0)
|
||||
MyGame.Sample.Vec3.CreateVec3(builder, 4.0, 5.0, 6.0)
|
||||
path = builder.EndVector(2)
|
||||
~~~
|
||||
</div>
|
||||
<div class="language-javascript">
|
||||
~~~{.js}
|
||||
// Create a `Vec3`, representing the Orc's position in 3-D space.
|
||||
var pos = MyGame.Sample.Vec3.createVec3(builder, 1.0, 2.0, 3.0);
|
||||
MyGame.Example.Monster.startPathVector(builder, 2);
|
||||
MyGame.Sample.Vec3.createVec3(builder, 1.0, 2.0, 3.0);
|
||||
MyGame.Sample.Vec3.createVec3(builder, 4.0, 5.0, 6.0);
|
||||
var path = builder.endVector();
|
||||
~~~
|
||||
</div>
|
||||
<div class="language-php">
|
||||
~~~{.js}
|
||||
// Create a `Vec3`, representing the Orc's position in 3-D space.
|
||||
$pos = \MyGame\Sample\Vec3::CreateVec3($builder, 1.0, 2.0, 3.0);
|
||||
~~~{.php}
|
||||
\MyGame\Example\Monster::StartPathVector($builder, 2);
|
||||
\MyGame\Sample\Vec3::CreateVec3($builder, 1.0, 2.0, 3.0);
|
||||
\MyGame\Sample\Vec3::CreateVec3($builder, 1.0, 2.0, 3.0);
|
||||
$path = $builder->endVector();
|
||||
~~~
|
||||
</div>
|
||||
<div class="language-c">
|
||||
~~~{.c}
|
||||
// Create a `Vec3`, representing the Orc's position in 3-D space.
|
||||
ns(Vec3_t) pos = { 1.0f, 2.0f, 3.0f };
|
||||
// TBD
|
||||
~~~
|
||||
</div>
|
||||
|
||||
@@ -861,15 +875,16 @@ can serialize the monster itself:
|
||||
|
||||
// Finally, create the monster using the `CreateMonster` helper function
|
||||
// to set all fields.
|
||||
auto orc = CreateMonster(builder, &pos, mana, hp, name, inventory, Color_Red,
|
||||
weapons, Equipment_Weapon, axe.Union());
|
||||
auto orc = CreateMonster(builder, Vec3(1.0f, 2.0f, 3.0f), mana, hp, name,
|
||||
inventory, Color_Red, weapons, Equipment_Weapon,
|
||||
axe.Union(), path);
|
||||
~~~
|
||||
</div>
|
||||
<div class="language-java">
|
||||
~~~{.java}
|
||||
// Create our monster using `startMonster()` and `endMonster()`.
|
||||
Monster.startMonster(builder);
|
||||
Monster.addPos(builder, pos);
|
||||
Monster.addPos(builder, Vec3.createVec3(builder, 1.0f, 2.0f, 3.0f));
|
||||
Monster.addName(builder, name);
|
||||
Monster.addColor(builder, Color.Red);
|
||||
Monster.addHp(builder, (short)300);
|
||||
@@ -877,6 +892,7 @@ can serialize the monster itself:
|
||||
Monster.addWeapons(builder, weapons);
|
||||
Monster.addEquippedType(builder, Equipment.Weapon);
|
||||
Monster.addEquipped(builder, axe);
|
||||
Monster.addPath(builder, path);
|
||||
int orc = Monster.endMonster(builder);
|
||||
~~~
|
||||
</div>
|
||||
@@ -884,7 +900,7 @@ can serialize the monster itself:
|
||||
~~~{.cs}
|
||||
// Create our monster using `StartMonster()` and `EndMonster()`.
|
||||
Monster.StartMonster(builder);
|
||||
Monster.AddPos(builder, pos);
|
||||
Monster.AddPos(builder, Vec3.CreateVec3(builder, 1.0f, 2.0f, 3.0f));
|
||||
Monster.AddHp(builder, (short)300);
|
||||
Monster.AddName(builder, name);
|
||||
Monster.AddInventory(builder, inv);
|
||||
@@ -892,6 +908,7 @@ can serialize the monster itself:
|
||||
Monster.AddWeapons(builder, weapons);
|
||||
Monster.AddEquippedType(builder, Equipment.Weapon);
|
||||
Monster.AddEquipped(builder, axe.Value); // Axe
|
||||
Monster.AddPath(builder, path);
|
||||
var orc = Monster.EndMonster(builder);
|
||||
~~~
|
||||
</div>
|
||||
@@ -899,7 +916,7 @@ can serialize the monster itself:
|
||||
~~~{.go}
|
||||
// Create our monster using `MonsterStart()` and `MonsterEnd()`.
|
||||
sample.MonsterStart(builder)
|
||||
sample.MonsterAddPos(builder, pos)
|
||||
sample.MonsterAddPos(builder, sample.CreateVec3(builder, 1.0, 2.0, 3.0))
|
||||
sample.MonsterAddHp(builder, 300)
|
||||
sample.MonsterAddName(builder, name)
|
||||
sample.MonsterAddInventory(builder, inv)
|
||||
@@ -907,6 +924,7 @@ can serialize the monster itself:
|
||||
sample.MonsterAddWeapons(builder, weapons)
|
||||
sample.MonsterAddEquippedType(builder, sample.EquipmentWeapon)
|
||||
sample.MonsterAddEquipped(builder, axe)
|
||||
sample.MonsterAddPath(builder, path)
|
||||
orc := sample.MonsterEnd(builder)
|
||||
~~~
|
||||
</div>
|
||||
@@ -914,7 +932,8 @@ can serialize the monster itself:
|
||||
~~~{.py}
|
||||
# Create our monster by using `MonsterStart()` and `MonsterEnd()`.
|
||||
MyGame.Sample.Monster.MonsterStart(builder)
|
||||
MyGame.Sample.Monster.MonsterAddPos(builder, pos)
|
||||
MyGame.Sample.Monster.MonsterAddPos(builder,
|
||||
MyGame.Sample.Vec3.CreateVec3(builder, 1.0, 2.0, 3.0))
|
||||
MyGame.Sample.Monster.MonsterAddHp(builder, 300)
|
||||
MyGame.Sample.Monster.MonsterAddName(builder, name)
|
||||
MyGame.Sample.Monster.MonsterAddInventory(builder, inv)
|
||||
@@ -924,6 +943,7 @@ can serialize the monster itself:
|
||||
MyGame.Sample.Monster.MonsterAddEquippedType(
|
||||
builder, MyGame.Sample.Equipment.Equipment().Weapon)
|
||||
MyGame.Sample.Monster.MonsterAddEquipped(builder, axe)
|
||||
MyGame.Sample.Monster.MonsterAddPath(builder, path)
|
||||
orc = MyGame.Sample.Monster.MonsterEnd(builder)
|
||||
~~~
|
||||
</div>
|
||||
@@ -931,7 +951,8 @@ can serialize the monster itself:
|
||||
~~~{.js}
|
||||
// Create our monster by using `startMonster()` and `endMonster()`.
|
||||
MyGame.Sample.Monster.startMonster(builder);
|
||||
MyGame.Sample.Monster.addPos(builder, pos);
|
||||
MyGame.Sample.Monster.addPos(builder,
|
||||
MyGame.Sample.Vec3.createVec3(builder, 1.0, 2.0, 3.0));
|
||||
MyGame.Sample.Monster.addHp(builder, 300);
|
||||
MyGame.Sample.Monster.addColor(builder, MyGame.Sample.Color.Red)
|
||||
MyGame.Sample.Monster.addName(builder, name);
|
||||
@@ -939,6 +960,7 @@ can serialize the monster itself:
|
||||
MyGame.Sample.Monster.addWeapons(builder, weapons);
|
||||
MyGame.Sample.Monster.addEquippedType(builder, MyGame.Sample.Equipment.Weapon);
|
||||
MyGame.Sample.Monster.addEquipped(builder, axe);
|
||||
MyGame.Sample.Monster.addPath(builder, path);
|
||||
var orc = MyGame.Sample.Monster.endMonster(builder);
|
||||
~~~
|
||||
</div>
|
||||
@@ -946,7 +968,8 @@ can serialize the monster itself:
|
||||
~~~{.php}
|
||||
// Create our monster by using `StartMonster()` and `EndMonster()`.
|
||||
\MyGame\Sample\Monster::StartMonster($builder);
|
||||
\MyGame\Sample\Monster::AddPos($builder, $pos);
|
||||
\MyGame\Sample\Monster::AddPos($builder,
|
||||
\MyGame\Sample\Vec3::CreateVec3($builder, 1.0, 2.0, 3.0));
|
||||
\MyGame\Sample\Monster::AddHp($builder, 300);
|
||||
\MyGame\Sample\Monster::AddName($builder, $name);
|
||||
\MyGame\Sample\Monster::AddInventory($builder, $inv);
|
||||
@@ -954,6 +977,7 @@ can serialize the monster itself:
|
||||
\MyGame\Sample\Monster::AddWeapons($builder, $weapons);
|
||||
\MyGame\Sample\Monster::AddEquippedType($builder, \MyGame\Sample\Equipment::Weapon);
|
||||
\MyGame\Sample\Monster::AddEquipped($builder, $axe);
|
||||
\MyGame\Sample\Monster::AddPath($builder, $path);
|
||||
$orc = \MyGame\Sample\Monster::EndMonster($builder);
|
||||
~~~
|
||||
</div>
|
||||
@@ -966,11 +990,21 @@ can serialize the monster itself:
|
||||
// Define an equipment union. `create` calls in C has a single
|
||||
// argument for unions where C++ has both a type and a data argument.
|
||||
ns(Equipment_union_ref_t) equipped = ns(Equipment_as_Weapon(axe));
|
||||
ns(Vec3_t) pos = { 1.0f, 2.0f, 3.0f };
|
||||
ns(Monster_create_as_root(B, &pos, mana, hp, name, inventory, ns(Color_Red),
|
||||
weapons, equipped));
|
||||
weapons, equipped, path));
|
||||
~~~
|
||||
</div>
|
||||
|
||||
Note how we create `Vec3` struct in-line in the table. Unlike tables, structs
|
||||
are simple combinations of scalars that are always stored inline, just like
|
||||
scalars themselves.
|
||||
|
||||
**Important**: Unlike structs, you should not nest tables or other objects,
|
||||
which is why we created all the strings/vectors/tables that this monster refers
|
||||
to before `start`. If you try to create any of them between `start` and `end`,
|
||||
you will get an assert/exception/panic depending on your language.
|
||||
|
||||
*Note: Since we are passing `150` as the `mana` field, which happens to be the
|
||||
default value, the field will not actually be written to the buffer, since the
|
||||
default value will be returned on query anyway. This is a nice space savings,
|
||||
@@ -1231,6 +1265,11 @@ like so:
|
||||
~~~
|
||||
</div>
|
||||
|
||||
Now you can write the bytes to a file, send them over the network..
|
||||
**Make sure your file mode (or tranfer protocol) is set to BINARY, not text.**
|
||||
If you transfer a FlatBuffer in text mode, the buffer will be corrupted,
|
||||
which will lead to hard to find problems when you read the buffer.
|
||||
|
||||
#### Reading Orc FlatBuffers
|
||||
|
||||
Now that we have successfully created an `Orc` FlatBuffer, the monster data can
|
||||
@@ -1326,92 +1365,82 @@ before:
|
||||
~~~
|
||||
</div>
|
||||
|
||||
Then, assuming you have a variable containing to the bytes of data from disk,
|
||||
network, etc., you can create a monster from this data:
|
||||
Then, assuming you have a buffer of bytes received from disk,
|
||||
network, etc., you can create start accessing the buffer like so:
|
||||
|
||||
**Again, make sure you read the bytes in BINARY mode, otherwise the code below
|
||||
won't work**
|
||||
|
||||
<div class="language-cpp">
|
||||
~~~{.cpp}
|
||||
// We can access the buffer we just made directly. Pretend this came over a
|
||||
// network, was read off of disk, etc.
|
||||
auto buffer_pointer = builder.GetBufferPointer();
|
||||
uint8_t *buffer_pointer = /* the data you just read */;
|
||||
|
||||
// Deserialize the data from the buffer.
|
||||
// Get a pointer to the root object inside the buffer.
|
||||
auto monster = GetMonster(buffer_pointer);
|
||||
|
||||
// `monster` is of type`Monster *`, and points to somewhere inside the buffer.
|
||||
|
||||
// `monster` is of type `Monster *`.
|
||||
// Note: root object pointers are NOT the same as `buffer_pointer`.
|
||||
~~~
|
||||
</div>
|
||||
<div class="language-java">
|
||||
~~~{.java}
|
||||
// We can access the buffer we just made directly. Pretend this came over a
|
||||
// network, was read off of disk, etc.
|
||||
java.nio.ByteBuffer buf = builder.dataBuffer();
|
||||
byte[] bytes = /* the data you just read */
|
||||
java.nio.ByteBuffer buf = java.nio.ByteBuffer.wrap(bytes);
|
||||
|
||||
// Deserialize the data from the buffer.
|
||||
// Get an accessor to the root object inside the buffer.
|
||||
Monster monster = Monster.getRootAsMonster(buf);
|
||||
~~~
|
||||
</div>
|
||||
<div class="language-csharp">
|
||||
~~~{.cs}
|
||||
// We can access the buffer we just made directly. Pretend this came over a
|
||||
// network, was read off of disk, etc.
|
||||
var buf = builder.DataBuffer;
|
||||
byte[] bytes = /* the data you just read */
|
||||
var buf = new ByteBuffer(bytes);
|
||||
|
||||
// Deserialize the data from the buffer.
|
||||
// Get an accessor to the root object inside the buffer.
|
||||
var monster = Monster.GetRootAsMonster(buf);
|
||||
~~~
|
||||
</div>
|
||||
<div class="language-go">
|
||||
~~~{.go}
|
||||
// We can access the buffer we just made directly. Pretend this came over a
|
||||
// network, was read off of disk, etc.
|
||||
buf := builder.FinishedBytes()
|
||||
var buf []byte = /* the data you just read */
|
||||
|
||||
// Deserialize the data from the buffer.
|
||||
// Get an accessor to the root object inside the buffer.
|
||||
monster := sample.GetRootAsMonster(buf, 0)
|
||||
|
||||
// Note: We use `0` for the offset here, since we got the data using the
|
||||
// `builder.FinishedBytes()` method. This simulates the data you would
|
||||
// store/receive in your FlatBuffer. If you wanted to read from the
|
||||
// `builder.Bytes` directly, you would need to pass in the offset of
|
||||
// `builder.Head()`, as the builder actually constructs the buffer backwards.
|
||||
// Note: We use `0` for the offset here, which is typical for most buffers
|
||||
// you would read. If you wanted to read from `builder.Bytes` directly, you
|
||||
// would need to pass in the offset of `builder.Head()`, as the builder
|
||||
// constructs the buffer backwards, so may not start at offset 0.
|
||||
~~~
|
||||
</div>
|
||||
<div class="language-python">
|
||||
~~~{.py}
|
||||
# We can access the buffer we just made directly. Pretend this came over a
|
||||
# network, was read off of disk, etc.
|
||||
buf = builder.Output()
|
||||
buf = /* the data you just read, in an object of type "bytearray" */
|
||||
|
||||
# Deserialize the data from the buffer.
|
||||
// Get an accessor to the root object inside the buffer.
|
||||
monster = MyGame.Sample.Monster.Monster.GetRootAsMonster(buf, 0)
|
||||
|
||||
# Note: We use `0` for the offset here, since we got the data using the
|
||||
# `builder.Output()` method. This simulates the data you would store/receive
|
||||
# in your FlatBuffer. If you wanted to read from the `builder.Bytes` directly,
|
||||
# Note: We use `0` for the offset here, which is typical for most buffers
|
||||
# you would read. If you wanted to read from the `builder.Bytes` directly,
|
||||
# you would need to pass in the offset of `builder.Head()`, as the builder
|
||||
# actually constructs the buffer backwards.
|
||||
# constructs the buffer backwards, so may not start at offset 0.
|
||||
~~~
|
||||
</div>
|
||||
<div class="language-javascript">
|
||||
~~~{.js}
|
||||
// We can access the buffer we just made directly. Pretend this came over a
|
||||
// network, was read off of disk, etc.
|
||||
var buf = builder.dataBuffer();
|
||||
var bytes = /* the data you just read, in an object of type "Uint8Array" */
|
||||
var buf = new flatbuffers.ByteBuffer(bytes);
|
||||
|
||||
// Deserialize the data from the buffer.
|
||||
// Get an accessor to the root object inside the buffer.
|
||||
var monster = MyGame.Sample.Monster.getRootAsMonster(buf);
|
||||
~~~
|
||||
</div>
|
||||
<div class="language-php">
|
||||
~~~{.php}
|
||||
// We can access the buffer we just made directly. Pretend this came over a
|
||||
// network, was read off of disk, etc.
|
||||
$buf = $builder->dataBuffer();
|
||||
$bytes = /* the data you just read, in a string */
|
||||
$buf = Google\FlatBuffers\ByteBuffer::wrap($bytes);
|
||||
|
||||
// Deserialize the data from the buffer.
|
||||
// Get an accessor to the root object inside the buffer.
|
||||
$monster = \MyGame\Sample\Monster::GetRootAsMonster($buf);
|
||||
~~~
|
||||
</div>
|
||||
@@ -1512,10 +1541,10 @@ To access sub-objects, in the case of our `pos`, which is a `Vec3`:
|
||||
</div>
|
||||
<div class="language-csharp">
|
||||
~~~{.cs}
|
||||
var pos = monster.Pos
|
||||
var x = pos.X
|
||||
var y = pos.Y
|
||||
var z = pos.Z
|
||||
var pos = monster.Pos.Value;
|
||||
var x = pos.X;
|
||||
var y = pos.Y;
|
||||
var z = pos.Z;
|
||||
~~~
|
||||
</div>
|
||||
<div class="language-go">
|
||||
@@ -1589,7 +1618,7 @@ FlatBuffers `vector`.
|
||||
<div class="language-csharp">
|
||||
~~~{.cs}
|
||||
int invLength = monster.InventoryLength;
|
||||
var thirdItem = monster.GetInventory(2);
|
||||
var thirdItem = monster.Inventory(2);
|
||||
~~~
|
||||
</div>
|
||||
<div class="language-go">
|
||||
@@ -1646,8 +1675,8 @@ except your need to handle the result as a FlatBuffer `table`:
|
||||
<div class="language-csharp">
|
||||
~~~{.cs}
|
||||
int weaponsLength = monster.WeaponsLength;
|
||||
var secondWeaponName = monster.GetWeapons(1).Name;
|
||||
var secondWeaponDamage = monster.GetWeapons(1).Damage;
|
||||
var secondWeaponName = monster.Weapons(1).Name;
|
||||
var secondWeaponDamage = monster.Weapons(1).Damage;
|
||||
~~~
|
||||
</div>
|
||||
<div class="language-go">
|
||||
@@ -1729,8 +1758,7 @@ We can access the type to dynamically cast the data as needed (since the
|
||||
var unionType = monster.EquippedType;
|
||||
|
||||
if (unionType == Equipment.Weapon) {
|
||||
var weapon = (Weapon)monster.GetEquipped(new Weapon()); // Requires explicit cast
|
||||
// to `Weapon`.
|
||||
var weapon = monster.Equipped<Weapon>().Value;
|
||||
|
||||
var weaponName = weapon.Name; // "Axe"
|
||||
var weaponDamage = weapon.Damage; // 5
|
||||
|
||||
@@ -759,11 +759,13 @@ INPUT = "FlatBuffers.md" \
|
||||
"Support.md" \
|
||||
"Benchmarks.md" \
|
||||
"WhitePaper.md" \
|
||||
"FlexBuffers.md" \
|
||||
"Internals.md" \
|
||||
"Grammar.md" \
|
||||
"../../CONTRIBUTING.md" \
|
||||
"Tutorial.md" \
|
||||
"GoApi.md" \
|
||||
"gRPC/CppUsage.md" \
|
||||
"groups" \
|
||||
"../../java/com/google/flatbuffers" \
|
||||
"../../python/flatbuffers/builder.py" \
|
||||
@@ -882,21 +884,21 @@ EXCLUDE_SYMBOLS =
|
||||
# that contain example code fragments that are included (see the \include
|
||||
# command).
|
||||
|
||||
EXAMPLE_PATH = "GoApi_generated.txt"
|
||||
EXAMPLE_PATH = "GoApi_generated.txt" "../../grpc/samples"
|
||||
|
||||
# If the value of the EXAMPLE_PATH tag contains directories, you can use the
|
||||
# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and
|
||||
# *.h) to filter out the source-files in the directories. If left blank all
|
||||
# files are included.
|
||||
|
||||
EXAMPLE_PATTERNS = *
|
||||
EXAMPLE_PATTERNS = *.cpp *.h *.txt *.fbs
|
||||
|
||||
# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
|
||||
# searched for input files to be used with the \include or \dontinclude commands
|
||||
# irrespective of the value of the RECURSIVE tag.
|
||||
# The default value is: NO.
|
||||
|
||||
EXAMPLE_RECURSIVE = NO
|
||||
EXAMPLE_RECURSIVE = YES
|
||||
|
||||
# The IMAGE_PATH tag can be used to specify one or more files or directories
|
||||
# that contain images that are to be included in the documentation (see the
|
||||
|
||||
@@ -37,6 +37,12 @@
|
||||
title="Use in PHP"/>
|
||||
<tab type="user" url="@ref flatbuffers_guide_use_python"
|
||||
title="Use in Python"/>
|
||||
<tab type="user" url="@ref flexbuffers"
|
||||
title="Schema-less version"/>
|
||||
<tab type="usergroup" url="" title="gRPC">
|
||||
<tab type="user" url="@ref flatbuffers_grpc_guide_use_cpp"
|
||||
title="Use in C++"/>
|
||||
</tab>
|
||||
</tab>
|
||||
<tab type="user" url="@ref flatbuffers_support"
|
||||
title="Platform / Language / Feature support"/>
|
||||
|
||||
29
docs/source/gRPC/CppUsage.md
Normal file
29
docs/source/gRPC/CppUsage.md
Normal file
@@ -0,0 +1,29 @@
|
||||
Use in C++ {#flatbuffers_grpc_guide_use_cpp}
|
||||
==========
|
||||
|
||||
## Before you get started
|
||||
|
||||
Before diving into the FlatBuffers gRPC usage in C++, you should already be
|
||||
familiar with the following:
|
||||
|
||||
- FlatBuffers as a serialization format
|
||||
- [gRPC](http://www.grpc.io/docs/) usage
|
||||
|
||||
## Using the FlatBuffers gRPC C++ library
|
||||
|
||||
NOTE: The examples below are also in the `grpc/samples/greeter` directory.
|
||||
|
||||
We will illustrate usage with the following schema:
|
||||
|
||||
@include grpc/samples/greeter/greeter.fbs
|
||||
|
||||
When we run `flatc`, we pass in the `--grpc` option and generage an additional
|
||||
`greeter.grpc.fb.h` and `greeter.grpc.fb.cc`.
|
||||
|
||||
Example server code looks like this:
|
||||
|
||||
@include grpc/samples/greeter/server.cpp
|
||||
|
||||
Example client code looks like this:
|
||||
|
||||
@include grpc/samples/greeter/client.cpp
|
||||
23
go/grpc.go
Normal file
23
go/grpc.go
Normal file
@@ -0,0 +1,23 @@
|
||||
package flatbuffers
|
||||
|
||||
// Codec implements gRPC-go Codec which is used to encode and decode messages.
|
||||
var Codec = "flatbuffers"
|
||||
|
||||
type FlatbuffersCodec struct{}
|
||||
|
||||
func (FlatbuffersCodec) Marshal(v interface{}) ([]byte, error) {
|
||||
return v.(*Builder).FinishedBytes(), nil
|
||||
}
|
||||
|
||||
func (FlatbuffersCodec) Unmarshal(data []byte, v interface{}) error {
|
||||
v.(flatbuffersInit).Init(data, GetUOffsetT(data))
|
||||
return nil
|
||||
}
|
||||
|
||||
func (FlatbuffersCodec) String() string {
|
||||
return Codec
|
||||
}
|
||||
|
||||
type flatbuffersInit interface {
|
||||
Init(data []byte, i UOffsetT)
|
||||
}
|
||||
13
go/lib.go
Normal file
13
go/lib.go
Normal file
@@ -0,0 +1,13 @@
|
||||
package flatbuffers
|
||||
|
||||
// FlatBuffer is the interface that represents a flatbuffer.
|
||||
type FlatBuffer interface {
|
||||
Table() Table
|
||||
Init(buf []byte, i UOffsetT)
|
||||
}
|
||||
|
||||
// GetRootAs is a generic helper to initialize a FlatBuffer with the provided buffer bytes and its data offset.
|
||||
func GetRootAs(buf []byte, offset UOffsetT, fb FlatBuffer) {
|
||||
n := GetUOffsetT(buf[offset:])
|
||||
fb.Init(buf, n+offset)
|
||||
}
|
||||
@@ -1,47 +1,52 @@
|
||||
package flatbuffers
|
||||
|
||||
import "unsafe"
|
||||
import (
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
var (
|
||||
const (
|
||||
// See http://golang.org/ref/spec#Numeric_types
|
||||
|
||||
// SizeUint8 is the byte size of a uint8.
|
||||
SizeUint8 = int(unsafe.Sizeof(uint8(0)))
|
||||
SizeUint8 = 1
|
||||
// SizeUint16 is the byte size of a uint16.
|
||||
SizeUint16 = int(unsafe.Sizeof(uint16(0)))
|
||||
SizeUint16 = 2
|
||||
// SizeUint32 is the byte size of a uint32.
|
||||
SizeUint32 = int(unsafe.Sizeof(uint32(0)))
|
||||
SizeUint32 = 4
|
||||
// SizeUint64 is the byte size of a uint64.
|
||||
SizeUint64 = int(unsafe.Sizeof(uint64(0)))
|
||||
SizeUint64 = 8
|
||||
|
||||
// SizeInt8 is the byte size of a int8.
|
||||
SizeInt8 = int(unsafe.Sizeof(int8(0)))
|
||||
// SizeInt8 is the byte size of a int8.
|
||||
SizeInt8 = 1
|
||||
// SizeInt16 is the byte size of a int16.
|
||||
SizeInt16 = int(unsafe.Sizeof(int16(0)))
|
||||
SizeInt16 = 2
|
||||
// SizeInt32 is the byte size of a int32.
|
||||
SizeInt32 = int(unsafe.Sizeof(int32(0)))
|
||||
SizeInt32 = 4
|
||||
// SizeInt64 is the byte size of a int64.
|
||||
SizeInt64 = int(unsafe.Sizeof(int64(0)))
|
||||
SizeInt64 = 8
|
||||
|
||||
// SizeFloat32 is the byte size of a float32.
|
||||
SizeFloat32 = int(unsafe.Sizeof(float32(0)))
|
||||
SizeFloat32 = 4
|
||||
// SizeFloat64 is the byte size of a float64.
|
||||
SizeFloat64 = int(unsafe.Sizeof(float64(0)))
|
||||
SizeFloat64 = 8
|
||||
|
||||
// SizeByte is the byte size of a byte.
|
||||
// The `byte` type is aliased (by Go definition) to uint8.
|
||||
SizeByte = SizeUint8
|
||||
SizeByte = 1
|
||||
|
||||
// SizeBool is the byte size of a bool.
|
||||
// The `bool` type is aliased (by flatbuffers convention) to uint8.
|
||||
SizeBool = SizeUint8
|
||||
SizeBool = 1
|
||||
|
||||
// SizeSOffsetT is the byte size of an SOffsetT.
|
||||
SizeSOffsetT = int(unsafe.Sizeof(SOffsetT(0)))
|
||||
// The `SOffsetT` type is aliased (by flatbuffers convention) to int32.
|
||||
SizeSOffsetT = 4
|
||||
// SizeUOffsetT is the byte size of an UOffsetT.
|
||||
SizeUOffsetT = int(unsafe.Sizeof(UOffsetT(0)))
|
||||
// The `UOffsetT` type is aliased (by flatbuffers convention) to uint32.
|
||||
SizeUOffsetT = 4
|
||||
// SizeVOffsetT is the byte size of an VOffsetT.
|
||||
SizeVOffsetT = int(unsafe.Sizeof(VOffsetT(0)))
|
||||
// The `VOffsetT` type is aliased (by flatbuffers convention) to uint16.
|
||||
SizeVOffsetT = 2
|
||||
)
|
||||
|
||||
// byteSliceToString converts a []byte to string without a heap allocation.
|
||||
@@ -10,7 +10,7 @@ type Table struct {
|
||||
|
||||
// Offset provides access into the Table's vtable.
|
||||
//
|
||||
// Deprecated fields are ignored by checking against the vtable's length.
|
||||
// Fields which are deprecated are ignored by checking against the vtable's length.
|
||||
func (t *Table) Offset(vtableOffset VOffsetT) VOffsetT {
|
||||
vtable := UOffsetT(SOffsetT(t.Pos) - t.GetSOffsetT(t.Pos))
|
||||
if vtableOffset < t.GetVOffsetT(vtable) {
|
||||
|
||||
14
grpc/samples/greeter/Makefile
Normal file
14
grpc/samples/greeter/Makefile
Normal file
@@ -0,0 +1,14 @@
|
||||
CXXFLAGS ?= -I../../../include
|
||||
LDFLAGS ?=
|
||||
|
||||
.PHONY: all
|
||||
all: server client
|
||||
|
||||
greeter_generated.h: greeter.fbs
|
||||
flatc --grpc --cpp $<
|
||||
|
||||
server: server.cpp greeter.grpc.fb.cc greeter_generated.h greeter.grpc.fb.h
|
||||
g++ -std=c++11 -O2 $(CXXFLAGS) $(LDFLAGS) -lgpr -lgrpc -lgrpc++ server.cpp greeter.grpc.fb.cc -o $@
|
||||
|
||||
client: client.cpp greeter.grpc.fb.cc greeter_generated.h greeter.grpc.fb.h
|
||||
g++ -std=c++11 -O2 $(CXXFLAGS) $(LDFLAGS) -lgpr -lgrpc -lgrpc++ client.cpp greeter.grpc.fb.cc -o $@
|
||||
85
grpc/samples/greeter/client.cpp
Normal file
85
grpc/samples/greeter/client.cpp
Normal file
@@ -0,0 +1,85 @@
|
||||
#include "greeter.grpc.fb.h"
|
||||
#include "greeter_generated.h"
|
||||
|
||||
#include <grpc++/grpc++.h>
|
||||
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
class GreeterClient {
|
||||
public:
|
||||
GreeterClient(std::shared_ptr<grpc::Channel> channel)
|
||||
: stub_(Greeter::NewStub(channel)) {}
|
||||
|
||||
std::string SayHello(const std::string &name) {
|
||||
flatbuffers::grpc::MessageBuilder mb;
|
||||
auto name_offset = mb.CreateString(name);
|
||||
auto request_offset = CreateHelloRequest(mb, name_offset);
|
||||
mb.Finish(request_offset);
|
||||
auto request_msg = mb.ReleaseMessage<HelloRequest>();
|
||||
|
||||
flatbuffers::grpc::Message<HelloReply> response_msg;
|
||||
|
||||
grpc::ClientContext context;
|
||||
|
||||
auto status = stub_->SayHello(&context, request_msg, &response_msg);
|
||||
if (status.ok()) {
|
||||
const HelloReply *response = response_msg.GetRoot();
|
||||
return response->message()->str();
|
||||
} else {
|
||||
std::cerr << status.error_code() << ": " << status.error_message()
|
||||
<< std::endl;
|
||||
return "RPC failed";
|
||||
}
|
||||
}
|
||||
|
||||
void SayManyHellos(const std::string &name, int num_greetings,
|
||||
std::function<void(const std::string &)> callback) {
|
||||
flatbuffers::grpc::MessageBuilder mb;
|
||||
auto name_offset = mb.CreateString(name);
|
||||
auto request_offset =
|
||||
CreateManyHellosRequest(mb, name_offset, num_greetings);
|
||||
mb.Finish(request_offset);
|
||||
auto request_msg = mb.ReleaseMessage<ManyHellosRequest>();
|
||||
|
||||
flatbuffers::grpc::Message<HelloReply> response_msg;
|
||||
|
||||
grpc::ClientContext context;
|
||||
|
||||
auto stream = stub_->SayManyHellos(&context, request_msg);
|
||||
while (stream->Read(&response_msg)) {
|
||||
const HelloReply *response = response_msg.GetRoot();
|
||||
callback(response->message()->str());
|
||||
}
|
||||
auto status = stream->Finish();
|
||||
if (!status.ok()) {
|
||||
std::cerr << status.error_code() << ": " << status.error_message()
|
||||
<< std::endl;
|
||||
callback("RPC failed");
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
std::unique_ptr<Greeter::Stub> stub_;
|
||||
};
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
std::string server_address("localhost:50051");
|
||||
|
||||
auto channel =
|
||||
grpc::CreateChannel(server_address, grpc::InsecureChannelCredentials());
|
||||
GreeterClient greeter(channel);
|
||||
|
||||
std::string name("world");
|
||||
|
||||
std::string message = greeter.SayHello(name);
|
||||
std::cerr << "Greeter received: " << message << std::endl;
|
||||
|
||||
int num_greetings = 10;
|
||||
greeter.SayManyHellos(name, num_greetings, [](const std::string &message) {
|
||||
std::cerr << "Greeter received: " << message << std::endl;
|
||||
});
|
||||
|
||||
return 0;
|
||||
}
|
||||
17
grpc/samples/greeter/greeter.fbs
Normal file
17
grpc/samples/greeter/greeter.fbs
Normal file
@@ -0,0 +1,17 @@
|
||||
table HelloReply {
|
||||
message:string;
|
||||
}
|
||||
|
||||
table HelloRequest {
|
||||
name:string;
|
||||
}
|
||||
|
||||
table ManyHellosRequest {
|
||||
name:string;
|
||||
num_greetings:int;
|
||||
}
|
||||
|
||||
rpc_service Greeter {
|
||||
SayHello(HelloRequest):HelloReply;
|
||||
SayManyHellos(ManyHellosRequest):HelloReply (streaming: "server");
|
||||
}
|
||||
80
grpc/samples/greeter/server.cpp
Normal file
80
grpc/samples/greeter/server.cpp
Normal file
@@ -0,0 +1,80 @@
|
||||
#include "greeter.grpc.fb.h"
|
||||
#include "greeter_generated.h"
|
||||
|
||||
#include <grpc++/grpc++.h>
|
||||
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
class GreeterServiceImpl final : public Greeter::Service {
|
||||
virtual grpc::Status SayHello(
|
||||
grpc::ServerContext *context,
|
||||
const flatbuffers::grpc::Message<HelloRequest> *request_msg,
|
||||
flatbuffers::grpc::Message<HelloReply> *response_msg) override {
|
||||
// flatbuffers::grpc::MessageBuilder mb_;
|
||||
// We call GetRoot to "parse" the message. Verification is already
|
||||
// performed by default. See the notes below for more details.
|
||||
const HelloRequest *request = request_msg->GetRoot();
|
||||
|
||||
// Fields are retrieved as usual with FlatBuffers
|
||||
const std::string &name = request->name()->str();
|
||||
|
||||
// `flatbuffers::grpc::MessageBuilder` is a `FlatBufferBuilder` with a
|
||||
// special allocator for efficient gRPC buffer transfer, but otherwise
|
||||
// usage is the same as usual.
|
||||
auto msg_offset = mb_.CreateString("Hello, " + name);
|
||||
auto hello_offset = CreateHelloReply(mb_, msg_offset);
|
||||
mb_.Finish(hello_offset);
|
||||
|
||||
// The `ReleaseMessage<T>()` function detaches the message from the
|
||||
// builder, so we can transfer the resopnse to gRPC while simultaneously
|
||||
// detaching that memory buffer from the builer.
|
||||
*response_msg = mb_.ReleaseMessage<HelloReply>();
|
||||
assert(response_msg->Verify());
|
||||
|
||||
// Return an OK status.
|
||||
return grpc::Status::OK;
|
||||
}
|
||||
|
||||
virtual grpc::Status SayManyHellos(
|
||||
grpc::ServerContext *context,
|
||||
const flatbuffers::grpc::Message<ManyHellosRequest> *request_msg,
|
||||
grpc::ServerWriter<flatbuffers::grpc::Message<HelloReply>> *writer)
|
||||
override {
|
||||
// The streaming usage below is simply a combination of standard gRPC
|
||||
// streaming with the FlatBuffers usage shown above.
|
||||
const ManyHellosRequest *request = request_msg->GetRoot();
|
||||
const std::string &name = request->name()->str();
|
||||
int num_greetings = request->num_greetings();
|
||||
|
||||
for (int i = 0; i < num_greetings; i++) {
|
||||
auto msg_offset = mb_.CreateString("Many hellos, " + name);
|
||||
auto hello_offset = CreateHelloReply(mb_, msg_offset);
|
||||
mb_.Finish(hello_offset);
|
||||
writer->Write(mb_.ReleaseMessage<HelloReply>());
|
||||
}
|
||||
|
||||
return grpc::Status::OK;
|
||||
}
|
||||
|
||||
flatbuffers::grpc::MessageBuilder mb_;
|
||||
};
|
||||
|
||||
void RunServer() {
|
||||
std::string server_address("0.0.0.0:50051");
|
||||
GreeterServiceImpl service;
|
||||
|
||||
grpc::ServerBuilder builder;
|
||||
builder.AddListeningPort(server_address, grpc::InsecureServerCredentials());
|
||||
builder.RegisterService(&service);
|
||||
std::unique_ptr<grpc::Server> server(builder.BuildAndStart());
|
||||
std::cerr << "Server listening on " << server_address << std::endl;
|
||||
|
||||
server->Wait();
|
||||
}
|
||||
|
||||
int main(int argc, const char *argv[]) {
|
||||
RunServer();
|
||||
return 0;
|
||||
}
|
||||
40
grpc/src/compiler/config.h
Normal file
40
grpc/src/compiler/config.h
Normal file
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
*
|
||||
* Copyright 2015, Google Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following disclaimer
|
||||
* in the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* * Neither the name of Google Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SRC_COMPILER_CONFIG_H
|
||||
#define SRC_COMPILER_CONFIG_H
|
||||
|
||||
// This file is here only because schema_interface.h, which is copied from gRPC,
|
||||
// includes it. There is nothing for Flatbuffers to configure.
|
||||
|
||||
#endif // SRC_COMPILER_CONFIG_H
|
||||
File diff suppressed because it is too large
Load Diff
@@ -41,6 +41,9 @@
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "src/compiler/config.h"
|
||||
#include "src/compiler/schema_interface.h"
|
||||
|
||||
#ifndef GRPC_CUSTOM_STRING
|
||||
#include <string>
|
||||
#define GRPC_CUSTOM_STRING std::string
|
||||
@@ -62,85 +65,73 @@ struct Parameters {
|
||||
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;
|
||||
// Generate GMOCK code to facilitate unit testing.
|
||||
bool generate_mock_code;
|
||||
};
|
||||
|
||||
// Return the prologue of the generated header file.
|
||||
grpc::string GetHeaderPrologue(File *file, const Parameters ¶ms);
|
||||
grpc::string GetHeaderPrologue(grpc_generator::File *file,
|
||||
const Parameters ¶ms);
|
||||
|
||||
// Return the includes needed for generated header file.
|
||||
grpc::string GetHeaderIncludes(File *file, const Parameters ¶ms);
|
||||
grpc::string GetHeaderIncludes(grpc_generator::File *file,
|
||||
const Parameters ¶ms);
|
||||
|
||||
// Return the includes needed for generated source file.
|
||||
grpc::string GetSourceIncludes(File *file, const Parameters ¶ms);
|
||||
grpc::string GetSourceIncludes(grpc_generator::File *file,
|
||||
const Parameters ¶ms);
|
||||
|
||||
// Return the epilogue of the generated header file.
|
||||
grpc::string GetHeaderEpilogue(File *file, const Parameters ¶ms);
|
||||
grpc::string GetHeaderEpilogue(grpc_generator::File *file,
|
||||
const Parameters ¶ms);
|
||||
|
||||
// Return the prologue of the generated source file.
|
||||
grpc::string GetSourcePrologue(File *file, const Parameters ¶ms);
|
||||
grpc::string GetSourcePrologue(grpc_generator::File *file,
|
||||
const Parameters ¶ms);
|
||||
|
||||
// Return the services for generated header file.
|
||||
grpc::string GetHeaderServices(File *file, const Parameters ¶ms);
|
||||
grpc::string GetHeaderServices(grpc_generator::File *file,
|
||||
const Parameters ¶ms);
|
||||
|
||||
// Return the services for generated source file.
|
||||
grpc::string GetSourceServices(File *file, const Parameters ¶ms);
|
||||
grpc::string GetSourceServices(grpc_generator::File *file,
|
||||
const Parameters ¶ms);
|
||||
|
||||
// Return the epilogue of the generated source file.
|
||||
grpc::string GetSourceEpilogue(File *file, const Parameters ¶ms);
|
||||
grpc::string GetSourceEpilogue(grpc_generator::File *file,
|
||||
const Parameters ¶ms);
|
||||
|
||||
// Return the prologue of the generated mock file.
|
||||
grpc::string GetMockPrologue(grpc_generator::File *file,
|
||||
const Parameters ¶ms);
|
||||
|
||||
// Return the includes needed for generated mock file.
|
||||
grpc::string GetMockIncludes(grpc_generator::File *file,
|
||||
const Parameters ¶ms);
|
||||
|
||||
// Return the services for generated mock file.
|
||||
grpc::string GetMockServices(grpc_generator::File *file,
|
||||
const Parameters ¶ms);
|
||||
|
||||
// Return the epilogue of generated mock file.
|
||||
grpc::string GetMockEpilogue(grpc_generator::File *file,
|
||||
const Parameters ¶ms);
|
||||
|
||||
// Return the prologue of the generated mock file.
|
||||
grpc::string GetMockPrologue(grpc_generator::File *file,
|
||||
const Parameters ¶ms);
|
||||
|
||||
// Return the includes needed for generated mock file.
|
||||
grpc::string GetMockIncludes(grpc_generator::File *file,
|
||||
const Parameters ¶ms);
|
||||
|
||||
// Return the services for generated mock file.
|
||||
grpc::string GetMockServices(grpc_generator::File *file,
|
||||
const Parameters ¶ms);
|
||||
|
||||
// Return the epilogue of generated mock file.
|
||||
grpc::string GetMockEpilogue(grpc_generator::File *file,
|
||||
const Parameters ¶ms);
|
||||
|
||||
} // namespace grpc_cpp_generator
|
||||
|
||||
|
||||
445
grpc/src/compiler/go_generator.cc
Normal file
445
grpc/src/compiler/go_generator.cc
Normal file
@@ -0,0 +1,445 @@
|
||||
/*
|
||||
*
|
||||
* Copyright 2015, Google Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following disclaimer
|
||||
* in the documentation AN/or other materials provided with the
|
||||
* distribution.
|
||||
* * Neither the name of Google Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <map>
|
||||
#include <cctype>
|
||||
#include <sstream>
|
||||
|
||||
#include "src/compiler/go_generator.h"
|
||||
|
||||
template <class T>
|
||||
grpc::string as_string(T x) {
|
||||
std::ostringstream out;
|
||||
out << x;
|
||||
return out.str();
|
||||
}
|
||||
|
||||
inline bool ClientOnlyStreaming(const grpc_generator::Method *method) {
|
||||
return method->ClientStreaming() && !method->ServerStreaming();
|
||||
}
|
||||
|
||||
inline bool ServerOnlyStreaming(const grpc_generator::Method *method) {
|
||||
return !method->ClientStreaming() && method->ServerStreaming();
|
||||
}
|
||||
|
||||
namespace grpc_go_generator {
|
||||
|
||||
// Returns string with first letter to lowerCase
|
||||
grpc::string unexportName(grpc::string s) {
|
||||
if (s.empty())
|
||||
return s;
|
||||
s[0] = static_cast<char>(std::tolower(s[0]));
|
||||
return s;
|
||||
}
|
||||
|
||||
// Returns string with first letter to uppercase
|
||||
grpc::string exportName(grpc::string s) {
|
||||
if (s.empty())
|
||||
return s;
|
||||
s[0] = static_cast<char>(std::toupper(s[0]));
|
||||
return s;
|
||||
}
|
||||
|
||||
// Generates imports for the service
|
||||
void GenerateImports(grpc_generator::File *file, grpc_generator::Printer *printer,
|
||||
std::map<grpc::string, grpc::string> vars) {
|
||||
vars["filename"] = file->filename();
|
||||
printer->Print("//Generated by gRPC Go plugin\n");
|
||||
printer->Print("//If you make any local changes, they will be lost\n");
|
||||
printer->Print(vars, "//source: $filename$\n\n");
|
||||
printer->Print(vars, "package $Package$\n\n");
|
||||
if (file->additional_headers() != "") {
|
||||
printer->Print(file->additional_headers().c_str());
|
||||
printer->Print("\n\n");
|
||||
}
|
||||
printer->Print("import (\n");
|
||||
printer->Indent();
|
||||
printer->Print(vars, "$context$ \"golang.org/x/net/context\"\n");
|
||||
printer->Print(vars, "$grpc$ \"google.golang.org/grpc\"\n");
|
||||
printer->Outdent();
|
||||
printer->Print(")\n\n");
|
||||
}
|
||||
|
||||
// Generates Server method signature source
|
||||
void GenerateServerMethodSignature(const grpc_generator::Method *method, grpc_generator::Printer *printer,
|
||||
std::map<grpc::string, grpc::string> vars) {
|
||||
vars["Method"] = exportName(method->name());
|
||||
vars["Request"] = method->get_input_type_name();
|
||||
vars["Response"] = (vars["CustomMethodIO"] == "") ? method->get_output_type_name() : vars["CustomMethodIO"];
|
||||
if (method->NoStreaming()) {
|
||||
printer->Print(vars, "$Method$($context$.Context, *$Request$) (*$Response$, error)");
|
||||
} else if (ServerOnlyStreaming(method)) {
|
||||
printer->Print(vars, "$Method$(*$Request$, $Service$_$Method$Server) error");
|
||||
} else {
|
||||
printer->Print(vars, "$Method$($Service$_$Method$Server) error");
|
||||
}
|
||||
}
|
||||
|
||||
void GenerateServerMethod(const grpc_generator::Method *method, grpc_generator::Printer *printer,
|
||||
std::map<grpc::string, grpc::string> vars) {
|
||||
vars["Method"] = exportName(method->name());
|
||||
vars["Request"] = method->get_input_type_name();
|
||||
vars["Response"] = (vars["CustomMethodIO"] == "") ? method->get_output_type_name() : vars["CustomMethodIO"];
|
||||
vars["FullMethodName"] = "/" + vars["Package"] + "." + vars["Service"] + "/" + vars["Method"];
|
||||
vars["Handler"] = "_" + vars["Service"] + "_" + vars["Method"] + "_Handler";
|
||||
if (method->NoStreaming()) {
|
||||
printer->Print(vars, "func $Handler$(srv interface{}, ctx $context$.Context,\n\tdec func(interface{}) error, interceptor $grpc$.UnaryServerInterceptor) (interface{}, error) {\n");
|
||||
printer->Indent();
|
||||
printer->Print(vars, "in := new($Request$)\n");
|
||||
printer->Print("if err := dec(in); err != nil { return nil, err }\n");
|
||||
printer->Print(vars, "if interceptor == nil { return srv.($Service$Server).$Method$(ctx, in) }\n");
|
||||
printer->Print(vars, "info := &$grpc$.UnaryServerInfo{\n");
|
||||
printer->Indent();
|
||||
printer->Print("Server: srv,\n");
|
||||
printer->Print(vars, "FullMethod: \"$FullMethodName$\",\n");
|
||||
printer->Outdent();
|
||||
printer->Print("}\n\n");
|
||||
printer->Print(vars, "handler := func(ctx $context$.Context, req interface{}) (interface{}, error) {\n");
|
||||
printer->Indent();
|
||||
printer->Print(vars, "return srv.($Service$Server).$Method$(ctx, req.(* $Request$))\n");
|
||||
printer->Outdent();
|
||||
printer->Print("}\n");
|
||||
printer->Print("return interceptor(ctx, in, info, handler)\n");
|
||||
printer->Outdent();
|
||||
printer->Print("}\n\n");
|
||||
return;
|
||||
}
|
||||
vars["StreamType"] = vars["ServiceUnexported"] + vars["Method"] + "Server";
|
||||
printer->Print(vars, "func $Handler$(srv interface{}, stream $grpc$.ServerStream) error {\n");
|
||||
printer->Indent();
|
||||
if (ServerOnlyStreaming(method)) {
|
||||
printer->Print(vars, "m := new($Request$)\n");
|
||||
printer->Print(vars, "if err := stream.RecvMsg(m); err != nil { return err }\n");
|
||||
printer->Print(vars, "return srv.($Service$Server).$Method$(m, &$StreamType${stream})\n");
|
||||
} else {
|
||||
printer->Print(vars, "return srv.($Service$Server).$Method$(&$StreamType${stream})\n");
|
||||
}
|
||||
printer->Outdent();
|
||||
printer->Print("}\n\n");
|
||||
|
||||
bool genSend = method->BidiStreaming() || ServerOnlyStreaming(method);
|
||||
bool genRecv = method->BidiStreaming() || ClientOnlyStreaming(method);
|
||||
bool genSendAndClose = ClientOnlyStreaming(method);
|
||||
|
||||
printer->Print(vars, "type $Service$_$Method$Server interface { \n");
|
||||
printer->Indent();
|
||||
if (genSend) {
|
||||
printer->Print(vars, "Send(* $Response$) error\n");
|
||||
}
|
||||
if (genRecv) {
|
||||
printer->Print(vars, "Recv() (* $Request$, error)\n");
|
||||
}
|
||||
if (genSendAndClose) {
|
||||
printer->Print(vars, "SendAndClose(* $Response$) error\n");
|
||||
}
|
||||
printer->Print(vars, "$grpc$.ServerStream\n");
|
||||
printer->Outdent();
|
||||
printer->Print("}\n\n");
|
||||
|
||||
printer->Print(vars, "type $StreamType$ struct {\n");
|
||||
printer->Indent();
|
||||
printer->Print(vars, "$grpc$.ServerStream\n");
|
||||
printer->Outdent();
|
||||
printer->Print("}\n\n");
|
||||
|
||||
if (genSend) {
|
||||
printer->Print(vars, "func (x *$StreamType$) Send(m *$Response$) error {\n");
|
||||
printer->Indent();
|
||||
printer->Print("return x.ServerStream.SendMsg(m)\n");
|
||||
printer->Outdent();
|
||||
printer->Print("}\n\n");
|
||||
}
|
||||
if (genRecv) {
|
||||
printer->Print(vars, "func (x *$StreamType$) Recv() (*$Request$, error) {\n");
|
||||
printer->Indent();
|
||||
printer->Print(vars, "m := new($Request$)\n");
|
||||
printer->Print("if err := x.ServerStream.RecvMsg(m); err != nil { return nil, err }\n");
|
||||
printer->Print("return m, nil\n");
|
||||
printer->Outdent();
|
||||
printer->Print("}\n\n");
|
||||
}
|
||||
if (genSendAndClose) {
|
||||
printer->Print(vars, "func (x *$StreamType$) SendAndClose(m *$Response$) error {\n");
|
||||
printer->Indent();
|
||||
printer->Print("return x.ServerStream.SendMsg(m)\n");
|
||||
printer->Outdent();
|
||||
printer->Print("}\n\n");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Generates Client method signature source
|
||||
void GenerateClientMethodSignature(const grpc_generator::Method *method, grpc_generator::Printer *printer,
|
||||
std::map<grpc::string, grpc::string> vars) {
|
||||
vars["Method"] = exportName(method->name());
|
||||
vars["Request"] = ", in *" + ((vars["CustomMethodIO"] == "") ? method->get_input_type_name() : vars["CustomMethodIO"]);
|
||||
if (ClientOnlyStreaming(method) || method->BidiStreaming()) {
|
||||
vars["Request"] = "";
|
||||
}
|
||||
vars["Response"] = "* " + method->get_output_type_name();
|
||||
if (ClientOnlyStreaming(method) || method->BidiStreaming() || ServerOnlyStreaming(method)) {
|
||||
vars["Response"] = vars["Service"] + "_" + vars["Method"] + "Client" ;
|
||||
}
|
||||
printer->Print(vars, "$Method$(ctx $context$.Context$Request$, \n\topts... $grpc$.CallOption) ($Response$, error)");
|
||||
}
|
||||
|
||||
// Generates Client method source
|
||||
void GenerateClientMethod(const grpc_generator::Method *method, grpc_generator::Printer *printer,
|
||||
std::map<grpc::string, grpc::string> vars) {
|
||||
printer->Print(vars, "func (c *$ServiceUnexported$Client) ");
|
||||
GenerateClientMethodSignature(method, printer, vars);
|
||||
printer->Print(" {\n");
|
||||
printer->Indent();
|
||||
vars["Method"] = exportName(method->name());
|
||||
vars["Request"] = (vars["CustomMethodIO"] == "") ? method->get_input_type_name() : vars["CustomMethodIO"];
|
||||
vars["Response"] = method->get_output_type_name();
|
||||
vars["FullMethodName"] = "/" + vars["Package"] + "." + vars["Service"] + "/" + vars["Method"];
|
||||
if (method->NoStreaming()) {
|
||||
printer->Print(vars, "out := new($Response$)\n");
|
||||
printer->Print(vars, "err := $grpc$.Invoke(ctx, \"$FullMethodName$\", in, out, c.cc, opts...)\n");
|
||||
printer->Print("if err != nil { return nil, err }\n");
|
||||
printer->Print("return out, nil\n");
|
||||
printer->Outdent();
|
||||
printer->Print("}\n\n");
|
||||
return;
|
||||
}
|
||||
vars["StreamType"] = vars["ServiceUnexported"] + vars["Method"] + "Client";
|
||||
printer->Print(vars, "stream, err := $grpc$.NewClientStream(ctx, &$MethodDesc$, c.cc, \"$FullMethodName$\", opts...)\n");
|
||||
printer->Print("if err != nil { return nil, err }\n");
|
||||
|
||||
printer->Print(vars, "x := &$StreamType${stream}\n");
|
||||
if (ServerOnlyStreaming(method)) {
|
||||
printer->Print("if err := x.ClientStream.SendMsg(in); err != nil { return nil, err }\n");
|
||||
printer->Print("if err := x.ClientStream.CloseSend(); err != nil { return nil, err }\n");
|
||||
}
|
||||
printer->Print("return x,nil\n");
|
||||
printer->Outdent();
|
||||
printer->Print("}\n\n");
|
||||
|
||||
bool genSend = method->BidiStreaming() || ClientOnlyStreaming(method);
|
||||
bool genRecv = method->BidiStreaming() || ServerOnlyStreaming(method);
|
||||
bool genCloseAndRecv = ClientOnlyStreaming(method);
|
||||
|
||||
//Stream interface
|
||||
printer->Print(vars, "type $Service$_$Method$Client interface {\n");
|
||||
printer->Indent();
|
||||
if (genSend) {
|
||||
printer->Print(vars, "Send(*$Request$) error\n");
|
||||
}
|
||||
if (genRecv) {
|
||||
printer->Print(vars, "Recv() (*$Response$, error)\n");
|
||||
}
|
||||
if (genCloseAndRecv) {
|
||||
printer->Print(vars, "CloseAndRecv() (*$Response$, error)\n");
|
||||
}
|
||||
printer->Print(vars, "$grpc$.ClientStream\n");
|
||||
printer->Outdent();
|
||||
printer->Print("}\n\n");
|
||||
|
||||
//Stream Client
|
||||
printer->Print(vars, "type $StreamType$ struct{\n");
|
||||
printer->Indent();
|
||||
printer->Print(vars, "$grpc$.ClientStream\n");
|
||||
printer->Outdent();
|
||||
printer->Print("}\n\n");
|
||||
|
||||
if (genSend) {
|
||||
printer->Print(vars, "func (x *$StreamType$) Send(m *$Request$) error {\n");
|
||||
printer->Indent();
|
||||
printer->Print("return x.ClientStream.SendMsg(m)\n");
|
||||
printer->Outdent();
|
||||
printer->Print("}\n\n");
|
||||
}
|
||||
|
||||
if (genRecv) {
|
||||
printer->Print(vars, "func (x *$StreamType$) Recv() (*$Response$, error) {\n");
|
||||
printer->Indent();
|
||||
printer->Print(vars, "m := new($Response$)\n");
|
||||
printer->Print("if err := x.ClientStream.RecvMsg(m); err != nil { return nil, err }\n");
|
||||
printer->Print("return m, nil\n");
|
||||
printer->Outdent();
|
||||
printer->Print("}\n\n");
|
||||
}
|
||||
|
||||
if (genCloseAndRecv) {
|
||||
printer->Print(vars, "func (x *$StreamType$) CloseAndRecv() (*$Response$, error) {\n");
|
||||
printer->Indent();
|
||||
printer->Print("if err := x.ClientStream.CloseSend(); err != nil { return nil, err }\n");
|
||||
printer->Print(vars, "m := new ($Response$)\n");
|
||||
printer->Print("if err := x.ClientStream.RecvMsg(m); err != nil { return nil, err }\n");
|
||||
printer->Print("return m, nil\n");
|
||||
printer->Outdent();
|
||||
printer->Print("}\n\n");
|
||||
}
|
||||
}
|
||||
|
||||
// Generates client API for the service
|
||||
void GenerateService(const grpc_generator::Service *service, grpc_generator::Printer* printer,
|
||||
std::map<grpc::string, grpc::string> vars) {
|
||||
vars["Service"] = exportName(service->name());
|
||||
// Client Interface
|
||||
printer->Print(vars, "// Client API for $Service$ service\n");
|
||||
printer->Print(vars, "type $Service$Client interface{\n");
|
||||
printer->Indent();
|
||||
for (int i = 0; i < service->method_count(); i++) {
|
||||
GenerateClientMethodSignature(service->method(i).get(), printer, vars);
|
||||
printer->Print("\n");
|
||||
}
|
||||
printer->Outdent();
|
||||
printer->Print("}\n\n");
|
||||
|
||||
// Client structure
|
||||
vars["ServiceUnexported"] = unexportName(vars["Service"]);
|
||||
printer->Print(vars, "type $ServiceUnexported$Client struct {\n");
|
||||
printer->Indent();
|
||||
printer->Print(vars, "cc *$grpc$.ClientConn\n");
|
||||
printer->Outdent();
|
||||
printer->Print("}\n\n");
|
||||
|
||||
// NewClient
|
||||
printer->Print(vars, "func New$Service$Client(cc *$grpc$.ClientConn) $Service$Client {\n");
|
||||
printer->Indent();
|
||||
printer->Print(vars, "return &$ServiceUnexported$Client{cc}");
|
||||
printer->Outdent();
|
||||
printer->Print("\n}\n\n");
|
||||
|
||||
int unary_methods = 0, streaming_methods = 0;
|
||||
vars["ServiceDesc"] = "_" + vars["Service"] + "_serviceDesc";
|
||||
for (int i = 0; i < service->method_count(); i++) {
|
||||
auto method = service->method(i);
|
||||
if (method->NoStreaming()) {
|
||||
vars["MethodDesc"] = vars["ServiceDesc"] + ".Method[" + as_string(unary_methods) + "]";
|
||||
unary_methods++;
|
||||
} else {
|
||||
vars["MethodDesc"] = vars["ServiceDesc"] + ".Streams[" + as_string(streaming_methods) + "]";
|
||||
streaming_methods++;
|
||||
}
|
||||
GenerateClientMethod(method.get(), printer, vars);
|
||||
}
|
||||
|
||||
//Server Interface
|
||||
printer->Print(vars, "// Server API for $Service$ service\n");
|
||||
printer->Print(vars, "type $Service$Server interface {\n");
|
||||
printer->Indent();
|
||||
for (int i = 0; i < service->method_count(); i++) {
|
||||
GenerateServerMethodSignature(service->method(i).get(), printer, vars);
|
||||
printer->Print("\n");
|
||||
}
|
||||
printer->Outdent();
|
||||
printer->Print("}\n\n");
|
||||
|
||||
// Server registration.
|
||||
printer->Print(vars, "func Register$Service$Server(s *$grpc$.Server, srv $Service$Server) {\n");
|
||||
printer->Indent();
|
||||
printer->Print(vars, "s.RegisterService(&$ServiceDesc$, srv)\n");
|
||||
printer->Outdent();
|
||||
printer->Print("}\n\n");
|
||||
|
||||
for (int i = 0; i < service->method_count(); i++) {
|
||||
GenerateServerMethod(service->method(i).get(), printer, vars);
|
||||
printer->Print("\n");
|
||||
}
|
||||
|
||||
|
||||
//Service Descriptor
|
||||
printer->Print(vars, "var $ServiceDesc$ = $grpc$.ServiceDesc{\n");
|
||||
printer->Indent();
|
||||
printer->Print(vars, "ServiceName: \"$Package$.$Service$\",\n");
|
||||
printer->Print(vars, "HandlerType: (*$Service$Server)(nil),\n");
|
||||
printer->Print(vars, "Methods: []$grpc$.MethodDesc{\n");
|
||||
printer->Indent();
|
||||
for (int i = 0; i < service->method_count(); i++) {
|
||||
auto method = service->method(i);
|
||||
vars["Method"] = method->name();
|
||||
vars["Handler"] = "_" + vars["Service"] + "_" + vars["Method"] + "_Handler";
|
||||
if (method->NoStreaming()) {
|
||||
printer->Print("{\n");
|
||||
printer->Indent();
|
||||
printer->Print(vars, "MethodName: \"$Method$\",\n");
|
||||
printer->Print(vars, "Handler: $Handler$, \n");
|
||||
printer->Outdent();
|
||||
printer->Print("},\n");
|
||||
}
|
||||
}
|
||||
printer->Outdent();
|
||||
printer->Print("},\n");
|
||||
printer->Print(vars, "Streams: []$grpc$.StreamDesc{\n");
|
||||
printer->Indent();
|
||||
for (int i = 0; i < service->method_count(); i++) {
|
||||
auto method = service->method(i);
|
||||
vars["Method"] = method->name();
|
||||
vars["Handler"] = "_" + vars["Service"] + "_" + vars["Method"] + "_Handler";
|
||||
if (!method->NoStreaming()) {
|
||||
printer->Print("{\n");
|
||||
printer->Indent();
|
||||
printer->Print(vars, "StreamName: \"$Method$\",\n");
|
||||
printer->Print(vars, "Handler: $Handler$, \n");
|
||||
if (ClientOnlyStreaming(method.get())) {
|
||||
printer->Print("ClientStreams: true,\n");
|
||||
} else if (ServerOnlyStreaming(method.get())) {
|
||||
printer->Print("ServerStreams: true,\n");
|
||||
} else {
|
||||
printer->Print("ServerStreams: true,\n");
|
||||
printer->Print("ClientStreams: true,\n");
|
||||
}
|
||||
printer->Outdent();
|
||||
printer->Print("},\n");
|
||||
}
|
||||
}
|
||||
printer->Outdent();
|
||||
printer->Print("},\n");
|
||||
printer->Outdent();
|
||||
printer->Print("}\n\n");
|
||||
|
||||
}
|
||||
|
||||
|
||||
// Returns source for the service
|
||||
grpc::string GenerateServiceSource(grpc_generator::File *file,
|
||||
const grpc_generator::Service *service,
|
||||
grpc_go_generator::Parameters *parameters) {
|
||||
grpc::string out;
|
||||
auto p = file->CreatePrinter(&out);
|
||||
auto printer = p.get();
|
||||
std::map<grpc::string, grpc::string> vars;
|
||||
vars["Package"] = parameters->package_name;
|
||||
vars["grpc"] = "grpc";
|
||||
vars["context"] = "context";
|
||||
GenerateImports(file, printer, vars);
|
||||
if (parameters->custom_method_io_type != "") {
|
||||
vars["CustomMethodIO"] = parameters->custom_method_io_type;
|
||||
}
|
||||
GenerateService(service, printer, vars);
|
||||
return out;
|
||||
}
|
||||
}// Namespace grpc_go_generator
|
||||
61
grpc/src/compiler/go_generator.h
Normal file
61
grpc/src/compiler/go_generator.h
Normal file
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
*
|
||||
* Copyright 2015, Google Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following disclaimer
|
||||
* in the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* * Neither the name of Google Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef GRPC_INTERNAL_COMPILER_GO_GENERATOR_H
|
||||
#define GRPC_INTERNAL_COMPILER_GO_GENERATOR_H
|
||||
|
||||
//go generator is used to generate GRPC code for serialization system, such as flatbuffers
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "src/compiler/schema_interface.h"
|
||||
|
||||
namespace grpc_go_generator {
|
||||
|
||||
struct Parameters {
|
||||
//Defines the custom parameter types for methods
|
||||
//eg: flatbuffers uses flatbuffers.Builder as input for the client and output for the server
|
||||
grpc::string custom_method_io_type;
|
||||
|
||||
//Package name for the service
|
||||
grpc::string package_name;
|
||||
};
|
||||
|
||||
// Return the source of the generated service file.
|
||||
grpc::string GenerateServiceSource(grpc_generator::File *file,
|
||||
const grpc_generator::Service *service,
|
||||
grpc_go_generator::Parameters *parameters);
|
||||
|
||||
}
|
||||
|
||||
#endif // GRPC_INTERNAL_COMPILER_GO_GENERATOR_H
|
||||
126
grpc/src/compiler/schema_interface.h
Normal file
126
grpc/src/compiler/schema_interface.h
Normal file
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
*
|
||||
* Copyright 2015, Google Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following disclaimer
|
||||
* in the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* * Neither the name of Google Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef GRPC_INTERNAL_COMPILER_SCHEMA_INTERFACE_H
|
||||
#define GRPC_INTERNAL_COMPILER_SCHEMA_INTERFACE_H
|
||||
|
||||
#include "src/compiler/config.h"
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#ifndef GRPC_CUSTOM_STRING
|
||||
#include <string>
|
||||
#define GRPC_CUSTOM_STRING std::string
|
||||
#endif
|
||||
|
||||
namespace grpc {
|
||||
|
||||
typedef GRPC_CUSTOM_STRING string;
|
||||
|
||||
} // namespace grpc
|
||||
|
||||
namespace grpc_generator {
|
||||
|
||||
// A common interface for objects having comments in the source.
|
||||
// Return formatted comments to be inserted in generated code.
|
||||
struct CommentHolder {
|
||||
virtual ~CommentHolder() {}
|
||||
virtual grpc::string GetLeadingComments(const grpc::string prefix) const = 0;
|
||||
virtual grpc::string GetTrailingComments(const grpc::string prefix) const = 0;
|
||||
virtual std::vector<grpc::string> GetAllComments() const = 0;
|
||||
};
|
||||
|
||||
// An abstract interface representing a method.
|
||||
struct Method : public CommentHolder {
|
||||
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 get_module_and_message_path_input(
|
||||
grpc::string *str, grpc::string generator_file_name,
|
||||
bool generate_in_pb2_grpc, grpc::string import_prefix) const = 0;
|
||||
virtual bool get_module_and_message_path_output(
|
||||
grpc::string *str, grpc::string generator_file_name,
|
||||
bool generate_in_pb2_grpc, grpc::string import_prefix) const = 0;
|
||||
|
||||
virtual grpc::string get_input_type_name() const = 0;
|
||||
virtual grpc::string get_output_type_name() const = 0;
|
||||
virtual bool NoStreaming() const = 0;
|
||||
virtual bool ClientStreaming() const = 0;
|
||||
virtual bool ServerStreaming() const = 0;
|
||||
virtual bool BidiStreaming() const = 0;
|
||||
};
|
||||
|
||||
// An abstract interface representing a service.
|
||||
struct Service : public CommentHolder {
|
||||
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 : public CommentHolder {
|
||||
virtual ~File() {}
|
||||
|
||||
virtual grpc::string filename() const = 0;
|
||||
virtual grpc::string filename_without_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;
|
||||
};
|
||||
} // namespace grpc_generator
|
||||
|
||||
#endif // GRPC_INTERNAL_COMPILER_SCHEMA_INTERFACE_H
|
||||
93
grpc/tests/go_test.go
Normal file
93
grpc/tests/go_test.go
Normal file
@@ -0,0 +1,93 @@
|
||||
package testing
|
||||
|
||||
import (
|
||||
"../../tests/MyGame/Example"
|
||||
|
||||
"net"
|
||||
"testing"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
"google.golang.org/grpc"
|
||||
)
|
||||
|
||||
type server struct{}
|
||||
|
||||
// test used to send and receive in grpc methods
|
||||
var test = "Flatbuffers"
|
||||
var addr = "0.0.0.0:50051"
|
||||
|
||||
// gRPC server store method
|
||||
func (s *server) Store(context context.Context, in *Example.Monster) (*flatbuffers.Builder, error) {
|
||||
b := flatbuffers.NewBuilder(0)
|
||||
i := b.CreateString(test)
|
||||
Example.StatStart(b)
|
||||
Example.StatAddId(b, i)
|
||||
b.Finish(Example.StatEnd(b))
|
||||
return b, nil
|
||||
|
||||
}
|
||||
|
||||
// gRPC server retrieve method
|
||||
func (s *server) Retrieve(context context.Context, in *Example.Stat) (*flatbuffers.Builder, error) {
|
||||
b := flatbuffers.NewBuilder(0)
|
||||
i := b.CreateString(test)
|
||||
Example.MonsterStart(b)
|
||||
Example.MonsterAddName(b, i)
|
||||
b.Finish(Example.MonsterEnd(b))
|
||||
return b, nil
|
||||
}
|
||||
|
||||
func StoreClient(c Example.MonsterStorageClient, t *testing.T) {
|
||||
b := flatbuffers.NewBuilder(0)
|
||||
i := b.CreateString(test)
|
||||
Example.MonsterStart(b)
|
||||
Example.MonsterAddName(b, i)
|
||||
b.Finish(Example.MonsterEnd(b))
|
||||
out, err := c.Store(context.Background(), b)
|
||||
if err != nil {
|
||||
t.Fatalf("Store client failed: %v", err)
|
||||
}
|
||||
if string(out.Id()) != test {
|
||||
t.Errorf("StoreClient failed: expected=%s, got=%s\n", test, out.Id())
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
func RetrieveClient(c Example.MonsterStorageClient, t *testing.T) {
|
||||
b := flatbuffers.NewBuilder(0)
|
||||
i := b.CreateString(test)
|
||||
Example.StatStart(b)
|
||||
Example.StatAddId(b, i)
|
||||
b.Finish(Example.StatEnd(b))
|
||||
out, err := c.Retrieve(context.Background(), b)
|
||||
if err != nil {
|
||||
t.Fatalf("Retrieve client failed: %v", err)
|
||||
}
|
||||
if string(out.Name()) != test {
|
||||
t.Errorf("RetrieveClient failed: expected=%s, got=%s\n", test, out.Name())
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
func TestGRPC(t *testing.T) {
|
||||
lis, err := net.Listen("tcp", addr)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to listen: %v", err)
|
||||
}
|
||||
ser := grpc.NewServer(grpc.CustomCodec(flatbuffers.FlatbuffersCodec{}))
|
||||
Example.RegisterMonsterStorageServer(ser, &server{})
|
||||
go func() {
|
||||
if err := ser.Serve(lis); err != nil {
|
||||
t.Fatalf("Failed to serve: %v", err)
|
||||
t.FailNow()
|
||||
}
|
||||
}()
|
||||
conn, err := grpc.Dial(addr, grpc.WithInsecure(), grpc.WithCodec(flatbuffers.FlatbuffersCodec{}))
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to connect: %v", err)
|
||||
}
|
||||
defer conn.Close()
|
||||
client := Example.NewMonsterStorageClient(conn)
|
||||
StoreClient(client, t)
|
||||
RetrieveClient(client, t)
|
||||
}
|
||||
@@ -27,31 +27,41 @@ using namespace MyGame::Example;
|
||||
// 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)
|
||||
const flatbuffers::grpc::Message<Monster> *request,
|
||||
flatbuffers::grpc::Message<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());
|
||||
// Transfer ownership of the message to gRPC
|
||||
*response = fbb_.ReleaseMessage<Stat>();
|
||||
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;
|
||||
const flatbuffers::grpc::Message<Stat> *request,
|
||||
::grpc::ServerWriter< flatbuffers::grpc::Message<Monster>>* writer)
|
||||
override {
|
||||
|
||||
for (int i=0; i<10; i++) {
|
||||
fbb_.Clear();
|
||||
// Create 10 monsters for resposne.
|
||||
auto monster_offset =
|
||||
CreateMonster(fbb_, 0, 0, 0, fbb_.CreateString(
|
||||
request->GetRoot()->id()->str() + " No." + std::to_string(i)));
|
||||
fbb_.Finish(monster_offset);
|
||||
|
||||
flatbuffers::grpc::Message<Monster> monster = fbb_.ReleaseMessage<Monster>();
|
||||
|
||||
// Send monster to client using streaming.
|
||||
writer->Write(monster);
|
||||
}
|
||||
return grpc::Status::OK;
|
||||
}
|
||||
|
||||
private:
|
||||
flatbuffers::FlatBufferBuilder fbb_;
|
||||
flatbuffers::grpc::MessageBuilder fbb_;
|
||||
};
|
||||
|
||||
// Track the server instance, so we can terminate it later.
|
||||
@@ -93,25 +103,55 @@ int main(int /*argc*/, const char * /*argv*/[]) {
|
||||
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;
|
||||
flatbuffers::grpc::MessageBuilder fbb;
|
||||
{
|
||||
grpc::ClientContext context;
|
||||
// Build a request with the name set.
|
||||
auto monster_offset = CreateMonster(fbb, 0, 0, 0, fbb.CreateString("Fred"));
|
||||
fbb.Finish(monster_offset);
|
||||
auto request = fbb.ReleaseMessage<Monster>();
|
||||
flatbuffers::grpc::Message<Stat> response;
|
||||
|
||||
// The actual RPC.
|
||||
auto status = stub->Store(&context, request, &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;
|
||||
if (status.ok()) {
|
||||
auto resp = response.GetRoot()->id();
|
||||
std::cout << "RPC response: " << resp->str() << std::endl;
|
||||
} else {
|
||||
std::cout << "RPC failed" << std::endl;
|
||||
}
|
||||
}
|
||||
{
|
||||
grpc::ClientContext context;
|
||||
fbb.Clear();
|
||||
auto stat_offset = CreateStat(fbb, fbb.CreateString("Fred"));
|
||||
fbb.Finish(stat_offset);
|
||||
auto request = fbb.ReleaseMessage<Stat>();
|
||||
|
||||
flatbuffers::grpc::Message<Monster> response;
|
||||
auto stream = stub->Retrieve(&context, request);
|
||||
while (stream->Read(&response)) {
|
||||
auto resp = response.GetRoot()->name();
|
||||
std::cout << "RPC Streaming response: " << resp->str() << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
#if !FLATBUFFERS_GRPC_DISABLE_AUTO_VERIFICATION
|
||||
{
|
||||
// Test that an invalid request errors out correctly
|
||||
grpc::ClientContext context;
|
||||
flatbuffers::grpc::Message<Monster> request; // simulate invalid message
|
||||
flatbuffers::grpc::Message<Stat> response;
|
||||
auto status = stub->Store(&context, request, &response);
|
||||
// The rpc status should be INTERNAL to indicate a verification error. This
|
||||
// matches the protobuf gRPC status code for an unparseable message.
|
||||
assert(!status.ok());
|
||||
assert(status.error_code() == ::grpc::StatusCode::INTERNAL);
|
||||
assert(strcmp(status.error_message().c_str(), "Message verification failed") == 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
server_instance->Shutdown();
|
||||
|
||||
@@ -121,4 +161,3 @@ int main(int /*argc*/, const char * /*argv*/[]) {
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
177
include/flatbuffers/base.h
Normal file
177
include/flatbuffers/base.h
Normal file
@@ -0,0 +1,177 @@
|
||||
#ifndef FLATBUFFERS_BASE_H_
|
||||
#define FLATBUFFERS_BASE_H_
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#ifndef ARDUINO
|
||||
#include <cstdint>
|
||||
#endif
|
||||
#include <cstddef>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#ifndef ARDUINO
|
||||
#include <utility>
|
||||
#else
|
||||
#include <utility.h>
|
||||
#endif
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
#include <set>
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
#include <memory>
|
||||
|
||||
#ifdef _STLPORT_VERSION
|
||||
#define FLATBUFFERS_CPP98_STL
|
||||
#endif
|
||||
#ifndef FLATBUFFERS_CPP98_STL
|
||||
#include <functional>
|
||||
#endif
|
||||
|
||||
/// @cond FLATBUFFERS_INTERNAL
|
||||
#if __cplusplus <= 199711L && \
|
||||
(!defined(_MSC_VER) || _MSC_VER < 1600) && \
|
||||
(!defined(__GNUC__) || \
|
||||
(__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__ < 40400))
|
||||
#error A C++11 compatible compiler with support for the auto typing is \
|
||||
required for FlatBuffers.
|
||||
#error __cplusplus _MSC_VER __GNUC__ __GNUC_MINOR__ __GNUC_PATCHLEVEL__
|
||||
#endif
|
||||
|
||||
#if !defined(__clang__) && \
|
||||
defined(__GNUC__) && \
|
||||
(__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__ < 40600)
|
||||
// Backwards compatability for g++ 4.4, and 4.5 which don't have the nullptr
|
||||
// and constexpr keywords. Note the __clang__ check is needed, because clang
|
||||
// presents itself as an older GNUC compiler.
|
||||
#ifndef nullptr_t
|
||||
const class nullptr_t {
|
||||
public:
|
||||
template<class T> inline operator T*() const { return 0; }
|
||||
private:
|
||||
void operator&() const;
|
||||
} nullptr = {};
|
||||
#endif
|
||||
#ifndef constexpr
|
||||
#define constexpr const
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// The wire format uses a little endian encoding (since that's efficient for
|
||||
// the common platforms).
|
||||
#if defined(__s390x__)
|
||||
#define FLATBUFFERS_LITTLEENDIAN 0
|
||||
#endif // __s390x__
|
||||
#if !defined(FLATBUFFERS_LITTLEENDIAN)
|
||||
#if defined(__GNUC__) || defined(__clang__)
|
||||
#ifdef __BIG_ENDIAN__
|
||||
#define FLATBUFFERS_LITTLEENDIAN 0
|
||||
#else
|
||||
#define FLATBUFFERS_LITTLEENDIAN 1
|
||||
#endif // __BIG_ENDIAN__
|
||||
#elif defined(_MSC_VER)
|
||||
#if defined(_M_PPC)
|
||||
#define FLATBUFFERS_LITTLEENDIAN 0
|
||||
#else
|
||||
#define FLATBUFFERS_LITTLEENDIAN 1
|
||||
#endif
|
||||
#else
|
||||
#error Unable to determine endianness, define FLATBUFFERS_LITTLEENDIAN.
|
||||
#endif
|
||||
#endif // !defined(FLATBUFFERS_LITTLEENDIAN)
|
||||
|
||||
#define FLATBUFFERS_VERSION_MAJOR 1
|
||||
#define FLATBUFFERS_VERSION_MINOR 7
|
||||
#define FLATBUFFERS_VERSION_REVISION 0
|
||||
#define FLATBUFFERS_STRING_EXPAND(X) #X
|
||||
#define FLATBUFFERS_STRING(X) FLATBUFFERS_STRING_EXPAND(X)
|
||||
|
||||
#if (!defined(_MSC_VER) || _MSC_VER > 1600) && \
|
||||
(!defined(__GNUC__) || (__GNUC__ * 100 + __GNUC_MINOR__ >= 407))
|
||||
#define FLATBUFFERS_FINAL_CLASS final
|
||||
#define FLATBUFFERS_OVERRIDE override
|
||||
#else
|
||||
#define FLATBUFFERS_FINAL_CLASS
|
||||
#define FLATBUFFERS_OVERRIDE
|
||||
#endif
|
||||
|
||||
#if (!defined(_MSC_VER) || _MSC_VER >= 1900) && \
|
||||
(!defined(__GNUC__) || (__GNUC__ * 100 + __GNUC_MINOR__ >= 406))
|
||||
#define FLATBUFFERS_CONSTEXPR constexpr
|
||||
#else
|
||||
#define FLATBUFFERS_CONSTEXPR
|
||||
#endif
|
||||
|
||||
#if defined(__GXX_EXPERIMENTAL_CXX0X__) && __GNUC__ * 10 + __GNUC_MINOR__ >= 46 || \
|
||||
defined(_MSC_FULL_VER) && _MSC_FULL_VER >= 190023026
|
||||
#define FLATBUFFERS_NOEXCEPT noexcept
|
||||
#else
|
||||
#define FLATBUFFERS_NOEXCEPT
|
||||
#endif
|
||||
|
||||
// NOTE: the FLATBUFFERS_DELETE_FUNC macro may change the access mode to
|
||||
// private, so be sure to put it at the end or reset access mode explicitly.
|
||||
#if (!defined(_MSC_VER) || _MSC_FULL_VER >= 180020827) && \
|
||||
(!defined(__GNUC__) || (__GNUC__ * 100 + __GNUC_MINOR__ >= 404))
|
||||
#define FLATBUFFERS_DELETE_FUNC(func) func = delete;
|
||||
#else
|
||||
#define FLATBUFFERS_DELETE_FUNC(func) private: func;
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable: 4127) // C4127: conditional expression is constant
|
||||
#endif
|
||||
|
||||
/// @endcond
|
||||
|
||||
/// @file
|
||||
namespace flatbuffers {
|
||||
|
||||
/// @cond FLATBUFFERS_INTERNAL
|
||||
// Our default offset / size type, 32bit on purpose on 64bit systems.
|
||||
// Also, using a consistent offset type maintains compatibility of serialized
|
||||
// offset values between 32bit and 64bit systems.
|
||||
typedef uint32_t uoffset_t;
|
||||
|
||||
// Signed offsets for references that can go in both directions.
|
||||
typedef int32_t soffset_t;
|
||||
|
||||
// Offset/index used in v-tables, can be changed to uint8_t in
|
||||
// format forks to save a bit of space if desired.
|
||||
typedef uint16_t voffset_t;
|
||||
|
||||
typedef uintmax_t largest_scalar_t;
|
||||
|
||||
// In 32bits, this evaluates to 2GB - 1
|
||||
#define FLATBUFFERS_MAX_BUFFER_SIZE ((1ULL << (sizeof(soffset_t) * 8 - 1)) - 1)
|
||||
|
||||
// We support aligning the contents of buffers up to this size.
|
||||
#define FLATBUFFERS_MAX_ALIGNMENT 16
|
||||
|
||||
template<typename T> T EndianScalar(T t) {
|
||||
#if FLATBUFFERS_LITTLEENDIAN
|
||||
return t;
|
||||
#else
|
||||
return EndianSwap(t);
|
||||
#endif
|
||||
}
|
||||
|
||||
template<typename T> T ReadScalar(const void *p) {
|
||||
return EndianScalar(*reinterpret_cast<const T *>(p));
|
||||
}
|
||||
|
||||
template<typename T> void WriteScalar(void *p, T t) {
|
||||
*reinterpret_cast<T *>(p) = EndianScalar(t);
|
||||
}
|
||||
|
||||
// Computes how many bytes you'd have to pad to be able to write an
|
||||
// "scalar_size" scalar if the buffer had grown to "buf_size" (downwards in
|
||||
// memory).
|
||||
inline size_t PaddingBytes(size_t buf_size, size_t scalar_size) {
|
||||
return ((~buf_size) + 1) & (scalar_size - 1);
|
||||
}
|
||||
|
||||
}
|
||||
#endif // FLATBUFFERS_BASE_H_
|
||||
@@ -17,25 +17,63 @@
|
||||
#ifndef FLATBUFFERS_CODE_GENERATORS_H_
|
||||
#define FLATBUFFERS_CODE_GENERATORS_H_
|
||||
|
||||
#include <map>
|
||||
#include <sstream>
|
||||
#include "flatbuffers/idl.h"
|
||||
|
||||
namespace flatbuffers {
|
||||
|
||||
// Utility class to assist in generating code through use of text templates.
|
||||
//
|
||||
// Example code:
|
||||
// CodeWriter code;
|
||||
// code.SetValue("NAME", "Foo");
|
||||
// code += "void {{NAME}}() { printf("%s", "{{NAME}}"); }";
|
||||
// code.SetValue("NAME", "Bar");
|
||||
// code += "void {{NAME}}() { printf("%s", "{{NAME}}"); }";
|
||||
// std::cout << code.ToString() << std::endl;
|
||||
//
|
||||
// Output:
|
||||
// void Foo() { printf("%s", "Foo"); }
|
||||
// void Bar() { printf("%s", "Bar"); }
|
||||
class CodeWriter {
|
||||
public:
|
||||
CodeWriter() {}
|
||||
|
||||
// Clears the current "written" code.
|
||||
void Clear() {
|
||||
stream_.str("");
|
||||
stream_.clear();
|
||||
}
|
||||
|
||||
// Associates a key with a value. All subsequent calls to operator+=, where
|
||||
// the specified key is contained in {{ and }} delimiters will be replaced by
|
||||
// the given value.
|
||||
void SetValue(const std::string& key, const std::string& value) {
|
||||
value_map_[key] = value;
|
||||
}
|
||||
|
||||
// Appends the given text to the generated code as well as a newline
|
||||
// character. Any text within {{ and }} delimeters is replaced by values
|
||||
// previously stored in the CodeWriter by calling SetValue above. The newline
|
||||
// will be suppressed if the text ends with the \\ character.
|
||||
void operator+=(std::string text);
|
||||
|
||||
// Returns the current contents of the CodeWriter as a std::string.
|
||||
std::string ToString() const { return stream_.str(); }
|
||||
|
||||
private:
|
||||
std::map<std::string, std::string> value_map_;
|
||||
std::stringstream stream_;
|
||||
};
|
||||
|
||||
class BaseGenerator {
|
||||
public:
|
||||
virtual bool generate() = 0;
|
||||
|
||||
static const std::string NamespaceDir(const Parser &parser,
|
||||
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 = ns.components;
|
||||
for (auto it = namespaces.begin(); it != namespaces.end(); ++it) {
|
||||
namespace_dir += *it + kPathSeparator;
|
||||
EnsureDirExists(namespace_dir.c_str());
|
||||
}
|
||||
return namespace_dir;
|
||||
}
|
||||
static std::string NamespaceDir(const Parser &parser,
|
||||
const std::string &path,
|
||||
const Namespace &ns);
|
||||
|
||||
protected:
|
||||
BaseGenerator(const Parser &parser, const std::string &path,
|
||||
@@ -46,71 +84,35 @@ class BaseGenerator {
|
||||
path_(path),
|
||||
file_name_(file_name),
|
||||
qualifying_start_(qualifying_start),
|
||||
qualifying_separator_(qualifying_separator){};
|
||||
virtual ~BaseGenerator(){};
|
||||
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);
|
||||
}
|
||||
std::string NamespaceDir(const Namespace &ns) const;
|
||||
|
||||
const char *FlatBuffersGeneratedWarning() {
|
||||
return "automatically generated by the FlatBuffers compiler,"
|
||||
" do not modify\n\n";
|
||||
}
|
||||
static const char *FlatBuffersGeneratedWarning();
|
||||
|
||||
bool IsEverythingGenerated() {
|
||||
for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
|
||||
++it) {
|
||||
if (!(*it)->generated) return false;
|
||||
}
|
||||
for (auto it = parser_.structs_.vec.begin();
|
||||
it != parser_.structs_.vec.end(); ++it) {
|
||||
if (!(*it)->generated) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
static std::string FullNamespace(const char *separator, const Namespace &ns);
|
||||
|
||||
std::string FullNamespace(const char *separator, const Namespace &ns) {
|
||||
std::string namespace_name;
|
||||
auto &namespaces = ns.components;
|
||||
for (auto it = namespaces.begin(); it != namespaces.end(); ++it) {
|
||||
if (namespace_name.length()) namespace_name += separator;
|
||||
namespace_name += *it;
|
||||
}
|
||||
return namespace_name;
|
||||
}
|
||||
|
||||
const std::string LastNamespacePart(const Namespace &ns) {
|
||||
auto &namespaces = ns.components;
|
||||
if (namespaces.size())
|
||||
return *(namespaces.end() - 1);
|
||||
else
|
||||
return std::string("");
|
||||
}
|
||||
static std::string LastNamespacePart(const Namespace &ns);
|
||||
|
||||
// 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; }
|
||||
virtual const Namespace *CurrentNameSpace() const { 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 Namespace *ns,
|
||||
const std::string &name) const;
|
||||
|
||||
std::string WrapInNameSpace(const Definition &def) {
|
||||
return WrapInNameSpace(def.defined_namespace, def.name);
|
||||
}
|
||||
std::string WrapInNameSpace(const Definition &def) const;
|
||||
|
||||
std::string GetNameSpace(const Definition &def) const;
|
||||
|
||||
const Parser &parser_;
|
||||
const std::string &path_;
|
||||
@@ -119,6 +121,17 @@ class BaseGenerator {
|
||||
const std::string qualifying_separator_;
|
||||
};
|
||||
|
||||
struct CommentConfig {
|
||||
const char *first_line;
|
||||
const char *content_line_prefix;
|
||||
const char *last_line;
|
||||
};
|
||||
|
||||
extern void GenComment(const std::vector<std::string> &dc,
|
||||
std::string *code_ptr,
|
||||
const CommentConfig *config,
|
||||
const char *prefix = "");
|
||||
|
||||
} // namespace flatbuffers
|
||||
|
||||
#endif // FLATBUFFERS_CODE_GENERATORS_H_
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
97
include/flatbuffers/flatc.h
Normal file
97
include/flatbuffers/flatc.h
Normal file
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
* Copyright 2017 Google Inc. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "flatbuffers/flatbuffers.h"
|
||||
#include "flatbuffers/idl.h"
|
||||
#include "flatbuffers/util.h"
|
||||
#include <functional>
|
||||
#include <limits>
|
||||
#include <string>
|
||||
|
||||
#ifndef FLATC_H_
|
||||
#define FLATC_H_
|
||||
|
||||
namespace flatbuffers {
|
||||
|
||||
class FlatCompiler {
|
||||
public:
|
||||
// Output generator for the various programming languages and formats we
|
||||
// support.
|
||||
struct Generator {
|
||||
typedef bool (*GenerateFn)(const flatbuffers::Parser &parser,
|
||||
const std::string &path,
|
||||
const std::string &file_name);
|
||||
typedef std::string (*MakeRuleFn)(const flatbuffers::Parser &parser,
|
||||
const std::string &path,
|
||||
const std::string &file_name);
|
||||
|
||||
GenerateFn generate;
|
||||
const char *generator_opt_short;
|
||||
const char *generator_opt_long;
|
||||
const char *lang_name;
|
||||
bool schema_only;
|
||||
GenerateFn generateGRPC;
|
||||
flatbuffers::IDLOptions::Language lang;
|
||||
const char *generator_help;
|
||||
MakeRuleFn make_rule;
|
||||
};
|
||||
|
||||
typedef void (*WarnFn)(const FlatCompiler *flatc,
|
||||
const std::string &warn,
|
||||
bool show_exe_name);
|
||||
|
||||
typedef void (*ErrorFn)(const FlatCompiler *flatc,
|
||||
const std::string &err,
|
||||
bool usage, bool show_exe_name);
|
||||
|
||||
// Parameters required to initialize the FlatCompiler.
|
||||
struct InitParams {
|
||||
InitParams()
|
||||
: generators(nullptr),
|
||||
num_generators(0),
|
||||
warn_fn(nullptr),
|
||||
error_fn(nullptr) {}
|
||||
|
||||
const Generator* generators;
|
||||
size_t num_generators;
|
||||
WarnFn warn_fn;
|
||||
ErrorFn error_fn;
|
||||
};
|
||||
|
||||
explicit FlatCompiler(const InitParams& params) : params_(params) {}
|
||||
|
||||
int Compile(int argc, const char** argv);
|
||||
|
||||
std::string GetUsageString(const char* program_name) const;
|
||||
|
||||
private:
|
||||
void ParseFile(flatbuffers::Parser &parser,
|
||||
const std::string &filename,
|
||||
const std::string &contents,
|
||||
std::vector<const char *> &include_directories) const;
|
||||
|
||||
void Warn(const std::string &warn, bool show_exe_name = true) const;
|
||||
|
||||
void Error(const std::string &err, bool usage = true,
|
||||
bool show_exe_name = true) const;
|
||||
|
||||
InitParams params_;
|
||||
};
|
||||
|
||||
|
||||
} // namespace flatbuffers
|
||||
|
||||
#endif // FLATC_H_
|
||||
1399
include/flatbuffers/flexbuffers.h
Normal file
1399
include/flatbuffers/flexbuffers.h
Normal file
File diff suppressed because it is too large
Load Diff
@@ -19,51 +19,234 @@
|
||||
|
||||
// Helper functionality to glue FlatBuffers and GRPC.
|
||||
|
||||
#include "flatbuffers/flatbuffers.h"
|
||||
#include "grpc++/support/byte_buffer.h"
|
||||
#include "grpc/byte_buffer_reader.h"
|
||||
|
||||
namespace flatbuffers {
|
||||
namespace grpc {
|
||||
|
||||
// Message is a typed wrapper around a buffer that manages the underlying
|
||||
// `grpc_slice` and also provides flatbuffers-specific helpers such as `Verify`
|
||||
// and `GetRoot`. Since it is backed by a `grpc_slice`, the underlying buffer
|
||||
// is refcounted and ownership is be managed automatically.
|
||||
template <class T>
|
||||
class Message {
|
||||
public:
|
||||
Message() : slice_(grpc_empty_slice()) {}
|
||||
|
||||
Message(grpc_slice slice, bool add_ref)
|
||||
: slice_(add_ref ? grpc_slice_ref(slice) : slice) {}
|
||||
|
||||
Message &operator=(const Message &other) = delete;
|
||||
|
||||
Message(Message &&other) : slice_(other.slice_) {
|
||||
other.slice_ = grpc_empty_slice();
|
||||
}
|
||||
|
||||
Message(const Message &other) = delete;
|
||||
|
||||
Message &operator=(Message &&other) {
|
||||
grpc_slice_unref(slice_);
|
||||
slice_ = other.slice_;
|
||||
other.slice_ = grpc_empty_slice();
|
||||
return *this;
|
||||
}
|
||||
|
||||
~Message() { grpc_slice_unref(slice_); }
|
||||
|
||||
const uint8_t *mutable_data() const { return GRPC_SLICE_START_PTR(slice_); }
|
||||
|
||||
const uint8_t *data() const { return GRPC_SLICE_START_PTR(slice_); }
|
||||
|
||||
size_t size() const { return GRPC_SLICE_LENGTH(slice_); }
|
||||
|
||||
bool Verify() const {
|
||||
Verifier verifier(data(), size());
|
||||
return verifier.VerifyBuffer<T>(nullptr);
|
||||
}
|
||||
|
||||
T *GetMutableRoot() { return flatbuffers::GetMutableRoot<T>(mutable_data()); }
|
||||
|
||||
const T *GetRoot() const { return flatbuffers::GetRoot<T>(data()); }
|
||||
|
||||
// This is only intended for serializer use, or if you know what you're doing
|
||||
const grpc_slice &BorrowSlice() const { return slice_; }
|
||||
|
||||
private:
|
||||
grpc_slice slice_;
|
||||
};
|
||||
|
||||
class MessageBuilder;
|
||||
|
||||
// SliceAllocator is a gRPC-specific allocator that uses the `grpc_slice`
|
||||
// refcounted slices to manage memory ownership. This makes it easy and
|
||||
// efficient to transfer buffers to gRPC.
|
||||
class SliceAllocator : public Allocator {
|
||||
public:
|
||||
SliceAllocator() : slice_(grpc_empty_slice()) {}
|
||||
|
||||
SliceAllocator(const SliceAllocator &other) = delete;
|
||||
SliceAllocator &operator=(const SliceAllocator &other) = delete;
|
||||
|
||||
virtual ~SliceAllocator() { grpc_slice_unref(slice_); }
|
||||
|
||||
virtual uint8_t *allocate(size_t size) override {
|
||||
assert(GRPC_SLICE_IS_EMPTY(slice_));
|
||||
slice_ = grpc_slice_malloc(size);
|
||||
return GRPC_SLICE_START_PTR(slice_);
|
||||
}
|
||||
|
||||
virtual void deallocate(uint8_t *p, size_t size) override {
|
||||
assert(p == GRPC_SLICE_START_PTR(slice_));
|
||||
assert(size == GRPC_SLICE_LENGTH(slice_));
|
||||
grpc_slice_unref(slice_);
|
||||
slice_ = grpc_empty_slice();
|
||||
}
|
||||
|
||||
virtual uint8_t *reallocate_downward(uint8_t *old_p, size_t old_size,
|
||||
size_t new_size) override {
|
||||
assert(old_p == GRPC_SLICE_START_PTR(slice_));
|
||||
assert(old_size == GRPC_SLICE_LENGTH(slice_));
|
||||
assert(new_size > old_size);
|
||||
grpc_slice old_slice = slice_;
|
||||
grpc_slice new_slice = grpc_slice_malloc(new_size);
|
||||
uint8_t *new_p = GRPC_SLICE_START_PTR(new_slice);
|
||||
memcpy(new_p + (new_size - old_size), old_p, old_size);
|
||||
slice_ = new_slice;
|
||||
grpc_slice_unref(old_slice);
|
||||
return new_p;
|
||||
}
|
||||
|
||||
private:
|
||||
grpc_slice &get_slice(uint8_t *p, size_t size) {
|
||||
assert(p == GRPC_SLICE_START_PTR(slice_));
|
||||
assert(size == GRPC_SLICE_LENGTH(slice_));
|
||||
return slice_;
|
||||
}
|
||||
|
||||
grpc_slice slice_;
|
||||
|
||||
friend class MessageBuilder;
|
||||
};
|
||||
|
||||
// SliceAllocatorMember is a hack to ensure that the MessageBuilder's
|
||||
// slice_allocator_ member is constructed before the FlatBufferBuilder, since
|
||||
// the allocator is used in the FlatBufferBuilder ctor.
|
||||
namespace detail {
|
||||
struct SliceAllocatorMember {
|
||||
SliceAllocator slice_allocator_;
|
||||
};
|
||||
}
|
||||
|
||||
// MessageBuilder is a gRPC-specific FlatBufferBuilder that uses SliceAllocator
|
||||
// to allocate gRPC buffers.
|
||||
class MessageBuilder : private detail::SliceAllocatorMember,
|
||||
public FlatBufferBuilder {
|
||||
public:
|
||||
explicit MessageBuilder(uoffset_t initial_size = 1024)
|
||||
: FlatBufferBuilder(initial_size, &slice_allocator_, false) {}
|
||||
|
||||
MessageBuilder(const MessageBuilder &other) = delete;
|
||||
MessageBuilder &operator=(const MessageBuilder &other) = delete;
|
||||
|
||||
~MessageBuilder() {}
|
||||
|
||||
// GetMessage extracts the subslice of the buffer corresponding to the
|
||||
// flatbuffers-encoded region and wraps it in a `Message<T>` to handle buffer
|
||||
// ownership.
|
||||
template <class T>
|
||||
Message<T> GetMessage() {
|
||||
auto buf_data = buf_.buf(); // pointer to memory
|
||||
auto buf_size = buf_.capacity(); // size of memory
|
||||
auto msg_data = buf_.data(); // pointer to msg
|
||||
auto msg_size = buf_.size(); // size of msg
|
||||
// Do some sanity checks on data/size
|
||||
assert(msg_data);
|
||||
assert(msg_size);
|
||||
assert(msg_data >= buf_data);
|
||||
assert(msg_data + msg_size <= buf_data + buf_size);
|
||||
// Calculate offsets from the buffer start
|
||||
auto begin = msg_data - buf_data;
|
||||
auto end = begin + msg_size;
|
||||
// Get the slice we are working with (no refcount change)
|
||||
grpc_slice slice = slice_allocator_.get_slice(buf_data, buf_size);
|
||||
// Extract a subslice of the existing slice (increment refcount)
|
||||
grpc_slice subslice = grpc_slice_sub(slice, begin, end);
|
||||
// Wrap the subslice in a `Message<T>`, but don't increment refcount
|
||||
Message<T> msg(subslice, false);
|
||||
return msg;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
Message<T> ReleaseMessage() {
|
||||
Message<T> msg = GetMessage<T>();
|
||||
Reset();
|
||||
return msg;
|
||||
}
|
||||
|
||||
private:
|
||||
// SliceAllocator slice_allocator_; // part of SliceAllocatorMember
|
||||
};
|
||||
|
||||
} // namespace grpc
|
||||
} // namespace flatbuffers
|
||||
|
||||
namespace grpc {
|
||||
|
||||
template <class T>
|
||||
class SerializationTraits<T, typename std::enable_if<std::is_base_of<
|
||||
flatbuffers::BufferRefBase, T>::value>::type> {
|
||||
class SerializationTraits<flatbuffers::grpc::Message<T>> {
|
||||
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);
|
||||
static grpc::Status Serialize(const flatbuffers::grpc::Message<T> &msg,
|
||||
grpc_byte_buffer **buffer, bool *own_buffer) {
|
||||
// We are passed in a `Message<T>`, which is a wrapper around a
|
||||
// `grpc_slice`. We extract it here using `BorrowSlice()`. The const cast
|
||||
// is necesary because the `grpc_raw_byte_buffer_create` func expects
|
||||
// non-const slices in order to increment their refcounts.
|
||||
grpc_slice *slice = const_cast<grpc_slice *>(&msg.BorrowSlice());
|
||||
// Now use `grpc_raw_byte_buffer_create` to package the single slice into a
|
||||
// `grpc_byte_buffer`, incrementing the refcount in the process.
|
||||
*buffer = grpc_raw_byte_buffer_create(slice, 1);
|
||||
*own_buffer = true;
|
||||
return grpc::Status();
|
||||
return grpc::Status::OK;
|
||||
}
|
||||
|
||||
// There is no de-serialization step in FlatBuffers, so we just receive
|
||||
// the data from GRPC.
|
||||
// Deserialize by pulling the
|
||||
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);
|
||||
flatbuffers::grpc::Message<T> *msg) {
|
||||
if (!buffer) {
|
||||
return ::grpc::Status(::grpc::StatusCode::INTERNAL, "No payload");
|
||||
}
|
||||
// Check if this is a single uncompressed slice.
|
||||
if ((buffer->type == GRPC_BB_RAW) &&
|
||||
(buffer->data.raw.compression == GRPC_COMPRESS_NONE) &&
|
||||
(buffer->data.raw.slice_buffer.count == 1)) {
|
||||
// If it is, then we can reference the `grpc_slice` directly.
|
||||
grpc_slice slice = buffer->data.raw.slice_buffer.slices[0];
|
||||
// We wrap a `Message<T>` around the slice, incrementing the refcount.
|
||||
*msg = flatbuffers::grpc::Message<T>(slice, true);
|
||||
} else {
|
||||
// Otherwise, we need to use `grpc_byte_buffer_reader_readall` to read
|
||||
// `buffer` into a single contiguous `grpc_slice`. The gRPC reader gives
|
||||
// us back a new slice with the refcount already incremented.
|
||||
grpc_byte_buffer_reader reader;
|
||||
grpc_byte_buffer_reader_init(&reader, buffer);
|
||||
grpc_slice slice = grpc_byte_buffer_reader_readall(&reader);
|
||||
grpc_byte_buffer_reader_destroy(&reader);
|
||||
// We wrap a `Message<T>` around the slice, but dont increment refcount
|
||||
*msg = flatbuffers::grpc::Message<T>(slice, false);
|
||||
}
|
||||
GPR_ASSERT(current == msg->buf + msg->len);
|
||||
grpc_byte_buffer_reader_destroy(&reader);
|
||||
grpc_byte_buffer_destroy(buffer);
|
||||
return grpc::Status();
|
||||
#if FLATBUFFERS_GRPC_DISABLE_AUTO_VERIFICATION
|
||||
return ::grpc::Status::OK;
|
||||
#else
|
||||
if (msg->Verify()) {
|
||||
return ::grpc::Status::OK;
|
||||
} else {
|
||||
return ::grpc::Status(::grpc::StatusCode::INTERNAL,
|
||||
"Message verification failed");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include "flatbuffers/flatbuffers.h"
|
||||
#include "flatbuffers/hash.h"
|
||||
#include "flatbuffers/reflection.h"
|
||||
#include "flatbuffers/flexbuffers.h"
|
||||
|
||||
// This file defines the data types representing a parsed IDL (Interface
|
||||
// Definition Language) / schema file.
|
||||
@@ -102,6 +103,8 @@ inline bool IsInteger(BaseType t) { return t >= BASE_TYPE_UTYPE &&
|
||||
t <= BASE_TYPE_ULONG; }
|
||||
inline bool IsFloat (BaseType t) { return t == BASE_TYPE_FLOAT ||
|
||||
t == BASE_TYPE_DOUBLE; }
|
||||
inline bool IsLong (BaseType t) { return t == BASE_TYPE_LONG ||
|
||||
t == BASE_TYPE_ULONG; }
|
||||
|
||||
extern const char *const kTypeNames[];
|
||||
extern const char kTypeSizes[];
|
||||
@@ -224,16 +227,20 @@ struct Definition {
|
||||
};
|
||||
|
||||
struct FieldDef : public Definition {
|
||||
FieldDef() : deprecated(false), required(false), key(false), padding(0) {}
|
||||
FieldDef() : deprecated(false), required(false), key(false),
|
||||
flexbuffer(false), padding(0) {}
|
||||
|
||||
Offset<reflection::Field> Serialize(FlatBufferBuilder *builder, uint16_t id,
|
||||
const Parser &parser) const;
|
||||
|
||||
Value value;
|
||||
bool deprecated; // Field is allowed to be present in old data, but can't be
|
||||
bool deprecated; // Field is allowed to be present in old data, but can't be.
|
||||
// written in new data nor accessed in new code.
|
||||
bool required; // Field must always be present.
|
||||
bool key; // Field functions as a key for creating sorted vectors.
|
||||
bool native_inline; // Field will be defined inline (instead of as a pointer)
|
||||
// for native tables if field is a struct.
|
||||
bool flexbuffer; // This field contains FlexBuffer data.
|
||||
size_t padding; // Bytes to always pad after this field.
|
||||
};
|
||||
|
||||
@@ -279,18 +286,18 @@ inline size_t InlineAlignment(const Type &type) {
|
||||
|
||||
struct EnumVal {
|
||||
EnumVal(const std::string &_name, int64_t _val)
|
||||
: name(_name), value(_val), struct_def(nullptr) {}
|
||||
: name(_name), value(_val) {}
|
||||
|
||||
Offset<reflection::EnumVal> Serialize(FlatBufferBuilder *builder) const;
|
||||
|
||||
std::string name;
|
||||
std::vector<std::string> doc_comment;
|
||||
int64_t value;
|
||||
StructDef *struct_def; // only set if this is a union
|
||||
Type union_type;
|
||||
};
|
||||
|
||||
struct EnumDef : public Definition {
|
||||
EnumDef() : is_union(false) {}
|
||||
EnumDef() : is_union(false), uses_type_aliases(false) {}
|
||||
|
||||
EnumVal *ReverseLookup(int enum_idx, bool skip_union_default = true) {
|
||||
for (auto it = vals.vec.begin() + static_cast<int>(is_union &&
|
||||
@@ -308,6 +315,7 @@ struct EnumDef : public Definition {
|
||||
|
||||
SymbolTable<EnumVal> vals;
|
||||
bool is_union;
|
||||
bool uses_type_aliases;
|
||||
Type underlying_type;
|
||||
};
|
||||
|
||||
@@ -333,6 +341,7 @@ struct ServiceDef : public Definition {
|
||||
struct IDLOptions {
|
||||
bool strict_json;
|
||||
bool skip_js_exports;
|
||||
bool use_goog_js_export_format;
|
||||
bool output_default_scalars_in_json;
|
||||
int indent_step;
|
||||
bool output_enum_identifiers;
|
||||
@@ -347,17 +356,43 @@ struct IDLOptions {
|
||||
bool generate_name_strings;
|
||||
bool escape_proto_identifiers;
|
||||
bool generate_object_based_api;
|
||||
std::string cpp_object_api_pointer_type;
|
||||
std::string cpp_object_api_string_type;
|
||||
bool union_value_namespacing;
|
||||
bool allow_non_utf8;
|
||||
std::string include_prefix;
|
||||
bool keep_include_path;
|
||||
bool binary_schema_comments;
|
||||
bool skip_flatbuffers_import;
|
||||
std::string go_namespace;
|
||||
bool reexport_ts_modules;
|
||||
bool protobuf_ascii_alike;
|
||||
|
||||
// Possible options for the more general generator below.
|
||||
enum Language { kJava, kCSharp, kGo, kMAX };
|
||||
enum Language {
|
||||
kJava = 1 << 0,
|
||||
kCSharp = 1 << 1,
|
||||
kGo = 1 << 2,
|
||||
kCpp = 1 << 3,
|
||||
kJs = 1 << 4,
|
||||
kPython = 1 << 5,
|
||||
kPhp = 1 << 6,
|
||||
kJson = 1 << 7,
|
||||
kBinary = 1 << 8,
|
||||
kTs = 1 << 9,
|
||||
kMAX
|
||||
};
|
||||
|
||||
Language lang;
|
||||
|
||||
// The corresponding language bit will be set if a language is included
|
||||
// for code generation.
|
||||
unsigned long lang_to_generate;
|
||||
|
||||
IDLOptions()
|
||||
: strict_json(false),
|
||||
skip_js_exports(false),
|
||||
use_goog_js_export_format(false),
|
||||
output_default_scalars_in_json(false),
|
||||
indent_step(2),
|
||||
output_enum_identifiers(true), prefixed_enums(true), scoped_enums(false),
|
||||
@@ -370,9 +405,16 @@ struct IDLOptions {
|
||||
generate_name_strings(false),
|
||||
escape_proto_identifiers(false),
|
||||
generate_object_based_api(false),
|
||||
cpp_object_api_pointer_type("std::unique_ptr"),
|
||||
union_value_namespacing(true),
|
||||
allow_non_utf8(false),
|
||||
lang(IDLOptions::kJava) {}
|
||||
keep_include_path(false),
|
||||
binary_schema_comments(false),
|
||||
skip_flatbuffers_import(false),
|
||||
reexport_ts_modules(true),
|
||||
protobuf_ascii_alike(false),
|
||||
lang(IDLOptions::kJava),
|
||||
lang_to_generate(0) {}
|
||||
};
|
||||
|
||||
// This encapsulates where the parser is in the current source file.
|
||||
@@ -434,6 +476,7 @@ class Parser : public ParserState {
|
||||
explicit Parser(const IDLOptions &options = IDLOptions())
|
||||
: root_struct_def_(nullptr),
|
||||
opts(options),
|
||||
uses_flexbuffers_(false),
|
||||
source_(nullptr),
|
||||
anonymous_counter(0) {
|
||||
// Just in case none are declared:
|
||||
@@ -450,6 +493,13 @@ class Parser : public ParserState {
|
||||
known_attributes_["csharp_partial"] = true;
|
||||
known_attributes_["streaming"] = true;
|
||||
known_attributes_["idempotent"] = true;
|
||||
known_attributes_["cpp_type"] = true;
|
||||
known_attributes_["cpp_ptr_type"] = true;
|
||||
known_attributes_["cpp_str_type"] = true;
|
||||
known_attributes_["native_inline"] = true;
|
||||
known_attributes_["native_type"] = true;
|
||||
known_attributes_["native_default"] = true;
|
||||
known_attributes_["flexbuffer"] = true;
|
||||
}
|
||||
|
||||
~Parser() {
|
||||
@@ -467,6 +517,8 @@ class Parser : public ParserState {
|
||||
// directory.
|
||||
// If the source was loaded from a file and isn't an include file,
|
||||
// supply its name in source_filename.
|
||||
// All paths specified in this call must be in posix format, if you accept
|
||||
// paths from user input, please call PosixPath on them first.
|
||||
bool Parse(const char *_source, const char **include_paths = nullptr,
|
||||
const char *source_filename = nullptr);
|
||||
|
||||
@@ -489,11 +541,16 @@ class Parser : public ParserState {
|
||||
// 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);
|
||||
// Similar to Parse(), but now only accepts JSON to be parsed into a
|
||||
// FlexBuffer.
|
||||
bool ParseFlexBuffer(const char *source, const char *source_filename,
|
||||
flexbuffers::Builder *builder);
|
||||
|
||||
FLATBUFFERS_CHECKED_ERROR CheckInRange(int64_t val, int64_t min, int64_t max);
|
||||
|
||||
private:
|
||||
FLATBUFFERS_CHECKED_ERROR Error(const std::string &msg);
|
||||
FLATBUFFERS_CHECKED_ERROR ParseHexNum(int nibbles, int64_t *val);
|
||||
FLATBUFFERS_CHECKED_ERROR ParseHexNum(int nibbles, uint64_t *val);
|
||||
FLATBUFFERS_CHECKED_ERROR Next();
|
||||
FLATBUFFERS_CHECKED_ERROR SkipByteOrderMark();
|
||||
bool Is(int t);
|
||||
@@ -508,18 +565,26 @@ private:
|
||||
const std::string &name, const Type &type,
|
||||
FieldDef **dest);
|
||||
FLATBUFFERS_CHECKED_ERROR ParseField(StructDef &struct_def);
|
||||
FLATBUFFERS_CHECKED_ERROR ParseString(Value &val);
|
||||
FLATBUFFERS_CHECKED_ERROR ParseComma();
|
||||
FLATBUFFERS_CHECKED_ERROR ParseAnyValue(Value &val, FieldDef *field,
|
||||
size_t parent_fieldn,
|
||||
const StructDef *parent_struct_def);
|
||||
FLATBUFFERS_CHECKED_ERROR ParseTableDelimiters(size_t &fieldn,
|
||||
const StructDef *struct_def,
|
||||
const std::function<CheckedError(const std::string &name)> &body);
|
||||
FLATBUFFERS_CHECKED_ERROR ParseTable(const StructDef &struct_def,
|
||||
std::string *value, uoffset_t *ovalue);
|
||||
void SerializeStruct(const StructDef &struct_def, const Value &val);
|
||||
void AddVector(bool sortbysize, int count);
|
||||
FLATBUFFERS_CHECKED_ERROR ParseVectorDelimiters(size_t &count,
|
||||
const std::function<CheckedError()> &body);
|
||||
FLATBUFFERS_CHECKED_ERROR ParseVector(const Type &type, uoffset_t *ovalue);
|
||||
FLATBUFFERS_CHECKED_ERROR ParseMetaData(SymbolTable<Value> *attributes);
|
||||
FLATBUFFERS_CHECKED_ERROR TryTypedValue(int dtoken, bool check, Value &e,
|
||||
BaseType req, bool *destmatch);
|
||||
FLATBUFFERS_CHECKED_ERROR ParseHash(Value &e, FieldDef* field);
|
||||
FLATBUFFERS_CHECKED_ERROR TokenError();
|
||||
FLATBUFFERS_CHECKED_ERROR ParseSingleValue(Value &e);
|
||||
FLATBUFFERS_CHECKED_ERROR ParseEnumFromString(Type &type, int64_t *result);
|
||||
StructDef *LookupCreateStruct(const std::string &name,
|
||||
@@ -539,18 +604,20 @@ private:
|
||||
FLATBUFFERS_CHECKED_ERROR ParseProtoCurliesOrIdent();
|
||||
FLATBUFFERS_CHECKED_ERROR ParseTypeFromProtoType(Type *type);
|
||||
FLATBUFFERS_CHECKED_ERROR SkipAnyJsonValue();
|
||||
FLATBUFFERS_CHECKED_ERROR SkipJsonObject();
|
||||
FLATBUFFERS_CHECKED_ERROR SkipJsonArray();
|
||||
FLATBUFFERS_CHECKED_ERROR SkipJsonString();
|
||||
FLATBUFFERS_CHECKED_ERROR ParseFlexBufferValue(flexbuffers::Builder *builder);
|
||||
FLATBUFFERS_CHECKED_ERROR StartParseFile(const char *source,
|
||||
const char *source_filename);
|
||||
FLATBUFFERS_CHECKED_ERROR DoParse(const char *_source,
|
||||
const char **include_paths,
|
||||
const char *source_filename);
|
||||
const char *source_filename,
|
||||
const char *include_filename);
|
||||
FLATBUFFERS_CHECKED_ERROR CheckClash(std::vector<FieldDef*> &fields,
|
||||
StructDef *struct_def,
|
||||
const char *suffix,
|
||||
BaseType baseType);
|
||||
|
||||
public:
|
||||
SymbolTable<Type> types_;
|
||||
SymbolTable<StructDef> structs_;
|
||||
SymbolTable<EnumDef> enums_;
|
||||
SymbolTable<ServiceDef> services_;
|
||||
@@ -562,12 +629,14 @@ private:
|
||||
std::string file_identifier_;
|
||||
std::string file_extension_;
|
||||
|
||||
std::map<std::string, bool> included_files_;
|
||||
std::map<std::string, std::string> included_files_;
|
||||
std::map<std::string, std::set<std::string>> files_included_per_file_;
|
||||
std::vector<std::string> native_included_files_;
|
||||
|
||||
std::map<std::string, bool> known_attributes_;
|
||||
|
||||
IDLOptions opts;
|
||||
bool uses_flexbuffers_;
|
||||
|
||||
private:
|
||||
const char *source_;
|
||||
@@ -583,20 +652,15 @@ private:
|
||||
|
||||
extern std::string MakeCamel(const std::string &in, bool first = true);
|
||||
|
||||
struct CommentConfig;
|
||||
|
||||
extern void GenComment(const std::vector<std::string> &dc,
|
||||
std::string *code_ptr,
|
||||
const CommentConfig *config,
|
||||
const char *prefix = "");
|
||||
|
||||
// Generate text (JSON) from a given FlatBuffer, and a given Parser
|
||||
// object that has been populated with the corresponding schema.
|
||||
// If ident_step is 0, no indentation will be generated. Additionally,
|
||||
// if it is less than 0, no linefeeds will be generated either.
|
||||
// See idl_gen_text.cpp.
|
||||
// strict_json adds "quotes" around field names if true.
|
||||
extern void GenerateText(const Parser &parser,
|
||||
// If the flatbuffer cannot be encoded in JSON (e.g., it contains non-UTF-8
|
||||
// byte arrays in String values), returns false.
|
||||
extern bool GenerateText(const Parser &parser,
|
||||
const void *flatbuffer,
|
||||
std::string *text);
|
||||
extern bool GenerateTextFile(const Parser &parser,
|
||||
@@ -618,7 +682,7 @@ extern bool GenerateCPP(const Parser &parser,
|
||||
const std::string &path,
|
||||
const std::string &file_name);
|
||||
|
||||
// Generate JavaScript code from the definitions in the Parser object.
|
||||
// Generate JavaScript or TypeScript code from the definitions in the Parser object.
|
||||
// See idl_gen_js.
|
||||
extern std::string GenerateJS(const Parser &parser);
|
||||
extern bool GenerateJS(const Parser &parser,
|
||||
@@ -640,8 +704,8 @@ extern bool GenerateJava(const Parser &parser,
|
||||
// Generate Php code from the definitions in the Parser object.
|
||||
// See idl_gen_php.
|
||||
extern bool GeneratePhp(const Parser &parser,
|
||||
const std::string &path,
|
||||
const std::string &file_name);
|
||||
const std::string &path,
|
||||
const std::string &file_name);
|
||||
|
||||
// Generate Python files from the definitions in the Parser object.
|
||||
// See idl_gen_python.cpp.
|
||||
@@ -669,7 +733,7 @@ extern bool GenerateFBS(const Parser &parser,
|
||||
const std::string &path,
|
||||
const std::string &file_name);
|
||||
|
||||
// Generate a make rule for the generated JavaScript code.
|
||||
// Generate a make rule for the generated JavaScript or TypeScript code.
|
||||
// See idl_gen_js.cpp.
|
||||
extern std::string JSMakeRule(const Parser &parser,
|
||||
const std::string &path,
|
||||
@@ -699,13 +763,18 @@ extern std::string BinaryMakeRule(const Parser &parser,
|
||||
const std::string &path,
|
||||
const std::string &file_name);
|
||||
|
||||
// Generate GRPC interfaces.
|
||||
// Generate GRPC Cpp interfaces.
|
||||
// See idl_gen_grpc.cpp.
|
||||
bool GenerateGRPC(const Parser &parser,
|
||||
const std::string &path,
|
||||
const std::string &file_name);
|
||||
bool GenerateCppGRPC(const Parser &parser,
|
||||
const std::string &path,
|
||||
const std::string &file_name);
|
||||
|
||||
// Generate GRPC Go interfaces.
|
||||
// See idl_gen_grpc.cpp.
|
||||
bool GenerateGoGRPC(const Parser &parser,
|
||||
const std::string &path,
|
||||
const std::string &file_name);
|
||||
|
||||
} // namespace flatbuffers
|
||||
|
||||
#endif // FLATBUFFERS_IDL_H_
|
||||
|
||||
|
||||
@@ -30,6 +30,15 @@ namespace flatbuffers {
|
||||
|
||||
// ------------------------- GETTERS -------------------------
|
||||
|
||||
inline bool IsScalar (reflection::BaseType t) { return t >= reflection::UType &&
|
||||
t <= reflection::Double; }
|
||||
inline bool IsInteger(reflection::BaseType t) { return t >= reflection::UType &&
|
||||
t <= reflection::ULong; }
|
||||
inline bool IsFloat (reflection::BaseType t) { return t == reflection::Float ||
|
||||
t == reflection::Double; }
|
||||
inline bool IsLong (reflection::BaseType t) { return t == reflection::Long ||
|
||||
t == reflection::ULong; }
|
||||
|
||||
// Size of a basic type, don't use with structs.
|
||||
inline size_t GetTypeSize(reflection::BaseType base_type) {
|
||||
// This needs to correspond to the BaseType enum.
|
||||
@@ -58,6 +67,18 @@ inline const Table *GetAnyRoot(const uint8_t *flatbuf) {
|
||||
return GetRoot<Table>(flatbuf);
|
||||
}
|
||||
|
||||
// Get a field's default, if you know it's an integer, and its exact type.
|
||||
template<typename T> T GetFieldDefaultI(const reflection::Field &field) {
|
||||
assert(sizeof(T) == GetTypeSize(field.type()->base_type()));
|
||||
return static_cast<T>(field.default_integer());
|
||||
}
|
||||
|
||||
// Get a field's default, if you know it's floating point and its exact type.
|
||||
template<typename T> T GetFieldDefaultF(const reflection::Field &field) {
|
||||
assert(sizeof(T) == GetTypeSize(field.type()->base_type()));
|
||||
return static_cast<T>(field.default_real());
|
||||
}
|
||||
|
||||
// Get a field, if you know it's an integer, and its exact type.
|
||||
template<typename T> T GetFieldI(const Table &table,
|
||||
const reflection::Field &field) {
|
||||
@@ -105,6 +126,22 @@ inline Table *GetFieldT(const Table &table,
|
||||
return table.GetPointer<Table *>(field.offset());
|
||||
}
|
||||
|
||||
// Get a field, if you know it's a struct.
|
||||
inline const Struct *GetFieldStruct(const Table &table,
|
||||
const reflection::Field &field) {
|
||||
// TODO: This does NOT check if the field is a table or struct, but we'd need
|
||||
// access to the schema to check the is_struct flag.
|
||||
assert(field.type()->base_type() == reflection::Obj);
|
||||
return table.GetStruct<const Struct *>(field.offset());
|
||||
}
|
||||
|
||||
// Get a structure's field, if you know it's a struct.
|
||||
inline const Struct *GetFieldStruct(const Struct &structure,
|
||||
const reflection::Field &field) {
|
||||
assert(field.type()->base_type() == reflection::Obj);
|
||||
return structure.GetStruct<const Struct *>(field.offset());
|
||||
}
|
||||
|
||||
// Raw helper functions used below: get any value in memory as a 64bit int, a
|
||||
// double or a string.
|
||||
// All scalars get static_cast to an int64_t, strings use strtoull, every other
|
||||
@@ -226,8 +263,19 @@ template<typename T> T *GetAnyFieldAddressOf(const Struct &st,
|
||||
// Set any scalar field, if you know its exact type.
|
||||
template<typename T> bool SetField(Table *table, const reflection::Field &field,
|
||||
T val) {
|
||||
assert(sizeof(T) == GetTypeSize(field.type()->base_type()));
|
||||
return table->SetField(field.offset(), val);
|
||||
reflection::BaseType type = field.type()->base_type();
|
||||
if (!IsScalar(type)) {
|
||||
return false;
|
||||
}
|
||||
assert(sizeof(T) == GetTypeSize(type));
|
||||
T def;
|
||||
if (IsInteger(type)) {
|
||||
def = GetFieldDefaultI<T>(field);
|
||||
} else {
|
||||
assert(IsFloat(type));
|
||||
def = GetFieldDefaultF<T>(field);
|
||||
}
|
||||
return table->SetField(field.offset(), val, def);
|
||||
}
|
||||
|
||||
// Raw helper functions used below: set any value in memory as a 64bit int, a
|
||||
@@ -242,7 +290,7 @@ void SetAnyValueS(reflection::BaseType type, uint8_t *data, const char *val);
|
||||
inline bool SetAnyFieldI(Table *table, const reflection::Field &field,
|
||||
int64_t val) {
|
||||
auto field_ptr = table->GetAddressOf(field.offset());
|
||||
if (!field_ptr) return false;
|
||||
if (!field_ptr) return val == GetFieldDefaultI<int64_t>(field);
|
||||
SetAnyValueI(field.type()->base_type(), field_ptr, val);
|
||||
return true;
|
||||
}
|
||||
@@ -251,7 +299,7 @@ inline bool SetAnyFieldI(Table *table, const reflection::Field &field,
|
||||
inline bool SetAnyFieldF(Table *table, const reflection::Field &field,
|
||||
double val) {
|
||||
auto field_ptr = table->GetAddressOf(field.offset());
|
||||
if (!field_ptr) return false;
|
||||
if (!field_ptr) return val == GetFieldDefaultF<double>(field);
|
||||
SetAnyValueF(field.type()->base_type(), field_ptr, val);
|
||||
return true;
|
||||
}
|
||||
@@ -428,6 +476,15 @@ Offset<const Table *> CopyTable(FlatBufferBuilder &fbb,
|
||||
const Table &table,
|
||||
bool use_string_pooling = false);
|
||||
|
||||
// Verifies the provided flatbuffer using reflection.
|
||||
// root should point to the root type for this flatbuffer.
|
||||
// buf should point to the start of flatbuffer data.
|
||||
// length specifies the size of the flatbuffer data.
|
||||
bool Verify(const reflection::Schema &schema,
|
||||
const reflection::Object &root,
|
||||
const uint8_t *buf,
|
||||
size_t length);
|
||||
|
||||
} // namespace flatbuffers
|
||||
|
||||
#endif // FLATBUFFERS_REFLECTION_H_
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
// automatically generated by the FlatBuffers compiler, do not modify
|
||||
|
||||
|
||||
#ifndef FLATBUFFERS_GENERATED_REFLECTION_REFLECTION_H_
|
||||
#define FLATBUFFERS_GENERATED_REFLECTION_REFLECTION_H_
|
||||
|
||||
@@ -38,15 +39,37 @@ enum BaseType {
|
||||
String = 13,
|
||||
Vector = 14,
|
||||
Obj = 15,
|
||||
Union = 16,
|
||||
Union = 16
|
||||
};
|
||||
|
||||
inline const char **EnumNamesBaseType() {
|
||||
static const char *names[] = { "None", "UType", "Bool", "Byte", "UByte", "Short", "UShort", "Int", "UInt", "Long", "ULong", "Float", "Double", "String", "Vector", "Obj", "Union", nullptr };
|
||||
static const char *names[] = {
|
||||
"None",
|
||||
"UType",
|
||||
"Bool",
|
||||
"Byte",
|
||||
"UByte",
|
||||
"Short",
|
||||
"UShort",
|
||||
"Int",
|
||||
"UInt",
|
||||
"Long",
|
||||
"ULong",
|
||||
"Float",
|
||||
"Double",
|
||||
"String",
|
||||
"Vector",
|
||||
"Obj",
|
||||
"Union",
|
||||
nullptr
|
||||
};
|
||||
return names;
|
||||
}
|
||||
|
||||
inline const char *EnumNameBaseType(BaseType e) { return EnumNamesBaseType()[static_cast<int>(e)]; }
|
||||
inline const char *EnumNameBaseType(BaseType e) {
|
||||
const size_t index = static_cast<int>(e);
|
||||
return EnumNamesBaseType()[index];
|
||||
}
|
||||
|
||||
struct Type FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
|
||||
enum {
|
||||
@@ -54,9 +77,15 @@ struct Type FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
|
||||
VT_ELEMENT = 6,
|
||||
VT_INDEX = 8
|
||||
};
|
||||
BaseType base_type() const { return static_cast<BaseType>(GetField<int8_t>(VT_BASE_TYPE, 0)); }
|
||||
BaseType element() const { return static_cast<BaseType>(GetField<int8_t>(VT_ELEMENT, 0)); }
|
||||
int32_t index() const { return GetField<int32_t>(VT_INDEX, -1); }
|
||||
BaseType base_type() const {
|
||||
return static_cast<BaseType>(GetField<int8_t>(VT_BASE_TYPE, 0));
|
||||
}
|
||||
BaseType element() const {
|
||||
return static_cast<BaseType>(GetField<int8_t>(VT_ELEMENT, 0));
|
||||
}
|
||||
int32_t index() const {
|
||||
return GetField<int32_t>(VT_INDEX, -1);
|
||||
}
|
||||
bool Verify(flatbuffers::Verifier &verifier) const {
|
||||
return VerifyTableStart(verifier) &&
|
||||
VerifyField<int8_t>(verifier, VT_BASE_TYPE) &&
|
||||
@@ -69,18 +98,29 @@ struct Type FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
|
||||
struct TypeBuilder {
|
||||
flatbuffers::FlatBufferBuilder &fbb_;
|
||||
flatbuffers::uoffset_t start_;
|
||||
void add_base_type(BaseType base_type) { fbb_.AddElement<int8_t>(Type::VT_BASE_TYPE, static_cast<int8_t>(base_type), 0); }
|
||||
void add_element(BaseType element) { fbb_.AddElement<int8_t>(Type::VT_ELEMENT, static_cast<int8_t>(element), 0); }
|
||||
void add_index(int32_t index) { fbb_.AddElement<int32_t>(Type::VT_INDEX, index, -1); }
|
||||
TypeBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) { start_ = fbb_.StartTable(); }
|
||||
void add_base_type(BaseType base_type) {
|
||||
fbb_.AddElement<int8_t>(Type::VT_BASE_TYPE, static_cast<int8_t>(base_type), 0);
|
||||
}
|
||||
void add_element(BaseType element) {
|
||||
fbb_.AddElement<int8_t>(Type::VT_ELEMENT, static_cast<int8_t>(element), 0);
|
||||
}
|
||||
void add_index(int32_t index) {
|
||||
fbb_.AddElement<int32_t>(Type::VT_INDEX, index, -1);
|
||||
}
|
||||
TypeBuilder(flatbuffers::FlatBufferBuilder &_fbb)
|
||||
: fbb_(_fbb) {
|
||||
start_ = fbb_.StartTable();
|
||||
}
|
||||
TypeBuilder &operator=(const TypeBuilder &);
|
||||
flatbuffers::Offset<Type> Finish() {
|
||||
auto o = flatbuffers::Offset<Type>(fbb_.EndTable(start_, 3));
|
||||
const auto end = fbb_.EndTable(start_, 3);
|
||||
auto o = flatbuffers::Offset<Type>(end);
|
||||
return o;
|
||||
}
|
||||
};
|
||||
|
||||
inline flatbuffers::Offset<Type> CreateType(flatbuffers::FlatBufferBuilder &_fbb,
|
||||
inline flatbuffers::Offset<Type> CreateType(
|
||||
flatbuffers::FlatBufferBuilder &_fbb,
|
||||
BaseType base_type = None,
|
||||
BaseType element = None,
|
||||
int32_t index = -1) {
|
||||
@@ -96,15 +136,23 @@ struct KeyValue FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
|
||||
VT_KEY = 4,
|
||||
VT_VALUE = 6
|
||||
};
|
||||
const flatbuffers::String *key() const { return GetPointer<const flatbuffers::String *>(VT_KEY); }
|
||||
bool KeyCompareLessThan(const KeyValue *o) const { return *key() < *o->key(); }
|
||||
int KeyCompareWithValue(const char *val) const { return strcmp(key()->c_str(), val); }
|
||||
const flatbuffers::String *value() const { return GetPointer<const flatbuffers::String *>(VT_VALUE); }
|
||||
const flatbuffers::String *key() const {
|
||||
return GetPointer<const flatbuffers::String *>(VT_KEY);
|
||||
}
|
||||
bool KeyCompareLessThan(const KeyValue *o) const {
|
||||
return *key() < *o->key();
|
||||
}
|
||||
int KeyCompareWithValue(const char *val) const {
|
||||
return strcmp(key()->c_str(), val);
|
||||
}
|
||||
const flatbuffers::String *value() const {
|
||||
return GetPointer<const flatbuffers::String *>(VT_VALUE);
|
||||
}
|
||||
bool Verify(flatbuffers::Verifier &verifier) const {
|
||||
return VerifyTableStart(verifier) &&
|
||||
VerifyFieldRequired<flatbuffers::uoffset_t>(verifier, VT_KEY) &&
|
||||
VerifyOffsetRequired(verifier, VT_KEY) &&
|
||||
verifier.Verify(key()) &&
|
||||
VerifyField<flatbuffers::uoffset_t>(verifier, VT_VALUE) &&
|
||||
VerifyOffset(verifier, VT_VALUE) &&
|
||||
verifier.Verify(value()) &&
|
||||
verifier.EndTable();
|
||||
}
|
||||
@@ -113,18 +161,27 @@ struct KeyValue FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
|
||||
struct KeyValueBuilder {
|
||||
flatbuffers::FlatBufferBuilder &fbb_;
|
||||
flatbuffers::uoffset_t start_;
|
||||
void add_key(flatbuffers::Offset<flatbuffers::String> key) { fbb_.AddOffset(KeyValue::VT_KEY, key); }
|
||||
void add_value(flatbuffers::Offset<flatbuffers::String> value) { fbb_.AddOffset(KeyValue::VT_VALUE, value); }
|
||||
KeyValueBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) { start_ = fbb_.StartTable(); }
|
||||
void add_key(flatbuffers::Offset<flatbuffers::String> key) {
|
||||
fbb_.AddOffset(KeyValue::VT_KEY, key);
|
||||
}
|
||||
void add_value(flatbuffers::Offset<flatbuffers::String> value) {
|
||||
fbb_.AddOffset(KeyValue::VT_VALUE, value);
|
||||
}
|
||||
KeyValueBuilder(flatbuffers::FlatBufferBuilder &_fbb)
|
||||
: fbb_(_fbb) {
|
||||
start_ = fbb_.StartTable();
|
||||
}
|
||||
KeyValueBuilder &operator=(const KeyValueBuilder &);
|
||||
flatbuffers::Offset<KeyValue> Finish() {
|
||||
auto o = flatbuffers::Offset<KeyValue>(fbb_.EndTable(start_, 2));
|
||||
fbb_.Required(o, KeyValue::VT_KEY); // key
|
||||
const auto end = fbb_.EndTable(start_, 2);
|
||||
auto o = flatbuffers::Offset<KeyValue>(end);
|
||||
fbb_.Required(o, KeyValue::VT_KEY);
|
||||
return o;
|
||||
}
|
||||
};
|
||||
|
||||
inline flatbuffers::Offset<KeyValue> CreateKeyValue(flatbuffers::FlatBufferBuilder &_fbb,
|
||||
inline flatbuffers::Offset<KeyValue> CreateKeyValue(
|
||||
flatbuffers::FlatBufferBuilder &_fbb,
|
||||
flatbuffers::Offset<flatbuffers::String> key = 0,
|
||||
flatbuffers::Offset<flatbuffers::String> value = 0) {
|
||||
KeyValueBuilder builder_(_fbb);
|
||||
@@ -133,30 +190,57 @@ inline flatbuffers::Offset<KeyValue> CreateKeyValue(flatbuffers::FlatBufferBuild
|
||||
return builder_.Finish();
|
||||
}
|
||||
|
||||
inline flatbuffers::Offset<KeyValue> CreateKeyValueDirect(flatbuffers::FlatBufferBuilder &_fbb,
|
||||
inline flatbuffers::Offset<KeyValue> CreateKeyValueDirect(
|
||||
flatbuffers::FlatBufferBuilder &_fbb,
|
||||
const char *key = nullptr,
|
||||
const char *value = nullptr) {
|
||||
return CreateKeyValue(_fbb, key ? _fbb.CreateString(key) : 0, value ? _fbb.CreateString(value) : 0);
|
||||
return reflection::CreateKeyValue(
|
||||
_fbb,
|
||||
key ? _fbb.CreateString(key) : 0,
|
||||
value ? _fbb.CreateString(value) : 0);
|
||||
}
|
||||
|
||||
struct EnumVal FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
|
||||
enum {
|
||||
VT_NAME = 4,
|
||||
VT_VALUE = 6,
|
||||
VT_OBJECT = 8
|
||||
VT_OBJECT = 8,
|
||||
VT_UNION_TYPE = 10
|
||||
};
|
||||
const flatbuffers::String *name() const { return GetPointer<const flatbuffers::String *>(VT_NAME); }
|
||||
int64_t value() const { return GetField<int64_t>(VT_VALUE, 0); }
|
||||
bool KeyCompareLessThan(const EnumVal *o) const { return value() < o->value(); }
|
||||
int KeyCompareWithValue(int64_t val) const { return value() < val ? -1 : value() > val; }
|
||||
const Object *object() const { return GetPointer<const Object *>(VT_OBJECT); }
|
||||
const flatbuffers::String *name() const {
|
||||
return GetPointer<const flatbuffers::String *>(VT_NAME);
|
||||
}
|
||||
int64_t value() const {
|
||||
return GetField<int64_t>(VT_VALUE, 0);
|
||||
}
|
||||
bool KeyCompareLessThan(const EnumVal *o) const {
|
||||
return value() < o->value();
|
||||
}
|
||||
int KeyCompareWithValue(int64_t val) const {
|
||||
const auto key = value();
|
||||
if (key < val) {
|
||||
return -1;
|
||||
} else if (key > val) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
const Object *object() const {
|
||||
return GetPointer<const Object *>(VT_OBJECT);
|
||||
}
|
||||
const Type *union_type() const {
|
||||
return GetPointer<const Type *>(VT_UNION_TYPE);
|
||||
}
|
||||
bool Verify(flatbuffers::Verifier &verifier) const {
|
||||
return VerifyTableStart(verifier) &&
|
||||
VerifyFieldRequired<flatbuffers::uoffset_t>(verifier, VT_NAME) &&
|
||||
VerifyOffsetRequired(verifier, VT_NAME) &&
|
||||
verifier.Verify(name()) &&
|
||||
VerifyField<int64_t>(verifier, VT_VALUE) &&
|
||||
VerifyField<flatbuffers::uoffset_t>(verifier, VT_OBJECT) &&
|
||||
VerifyOffset(verifier, VT_OBJECT) &&
|
||||
verifier.VerifyTable(object()) &&
|
||||
VerifyOffset(verifier, VT_UNION_TYPE) &&
|
||||
verifier.VerifyTable(union_type()) &&
|
||||
verifier.EndTable();
|
||||
}
|
||||
};
|
||||
@@ -164,34 +248,57 @@ struct EnumVal FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
|
||||
struct EnumValBuilder {
|
||||
flatbuffers::FlatBufferBuilder &fbb_;
|
||||
flatbuffers::uoffset_t start_;
|
||||
void add_name(flatbuffers::Offset<flatbuffers::String> name) { fbb_.AddOffset(EnumVal::VT_NAME, name); }
|
||||
void add_value(int64_t value) { fbb_.AddElement<int64_t>(EnumVal::VT_VALUE, value, 0); }
|
||||
void add_object(flatbuffers::Offset<Object> object) { fbb_.AddOffset(EnumVal::VT_OBJECT, object); }
|
||||
EnumValBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) { start_ = fbb_.StartTable(); }
|
||||
void add_name(flatbuffers::Offset<flatbuffers::String> name) {
|
||||
fbb_.AddOffset(EnumVal::VT_NAME, name);
|
||||
}
|
||||
void add_value(int64_t value) {
|
||||
fbb_.AddElement<int64_t>(EnumVal::VT_VALUE, value, 0);
|
||||
}
|
||||
void add_object(flatbuffers::Offset<Object> object) {
|
||||
fbb_.AddOffset(EnumVal::VT_OBJECT, object);
|
||||
}
|
||||
void add_union_type(flatbuffers::Offset<Type> union_type) {
|
||||
fbb_.AddOffset(EnumVal::VT_UNION_TYPE, union_type);
|
||||
}
|
||||
EnumValBuilder(flatbuffers::FlatBufferBuilder &_fbb)
|
||||
: fbb_(_fbb) {
|
||||
start_ = fbb_.StartTable();
|
||||
}
|
||||
EnumValBuilder &operator=(const EnumValBuilder &);
|
||||
flatbuffers::Offset<EnumVal> Finish() {
|
||||
auto o = flatbuffers::Offset<EnumVal>(fbb_.EndTable(start_, 3));
|
||||
fbb_.Required(o, EnumVal::VT_NAME); // name
|
||||
const auto end = fbb_.EndTable(start_, 4);
|
||||
auto o = flatbuffers::Offset<EnumVal>(end);
|
||||
fbb_.Required(o, EnumVal::VT_NAME);
|
||||
return o;
|
||||
}
|
||||
};
|
||||
|
||||
inline flatbuffers::Offset<EnumVal> CreateEnumVal(flatbuffers::FlatBufferBuilder &_fbb,
|
||||
inline flatbuffers::Offset<EnumVal> CreateEnumVal(
|
||||
flatbuffers::FlatBufferBuilder &_fbb,
|
||||
flatbuffers::Offset<flatbuffers::String> name = 0,
|
||||
int64_t value = 0,
|
||||
flatbuffers::Offset<Object> object = 0) {
|
||||
flatbuffers::Offset<Object> object = 0,
|
||||
flatbuffers::Offset<Type> union_type = 0) {
|
||||
EnumValBuilder builder_(_fbb);
|
||||
builder_.add_value(value);
|
||||
builder_.add_union_type(union_type);
|
||||
builder_.add_object(object);
|
||||
builder_.add_name(name);
|
||||
return builder_.Finish();
|
||||
}
|
||||
|
||||
inline flatbuffers::Offset<EnumVal> CreateEnumValDirect(flatbuffers::FlatBufferBuilder &_fbb,
|
||||
inline flatbuffers::Offset<EnumVal> CreateEnumValDirect(
|
||||
flatbuffers::FlatBufferBuilder &_fbb,
|
||||
const char *name = nullptr,
|
||||
int64_t value = 0,
|
||||
flatbuffers::Offset<Object> object = 0) {
|
||||
return CreateEnumVal(_fbb, name ? _fbb.CreateString(name) : 0, value, object);
|
||||
flatbuffers::Offset<Object> object = 0,
|
||||
flatbuffers::Offset<Type> union_type = 0) {
|
||||
return reflection::CreateEnumVal(
|
||||
_fbb,
|
||||
name ? _fbb.CreateString(name) : 0,
|
||||
value,
|
||||
object,
|
||||
union_type);
|
||||
}
|
||||
|
||||
struct Enum FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
|
||||
@@ -200,28 +307,49 @@ struct Enum FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
|
||||
VT_VALUES = 6,
|
||||
VT_IS_UNION = 8,
|
||||
VT_UNDERLYING_TYPE = 10,
|
||||
VT_ATTRIBUTES = 12
|
||||
VT_ATTRIBUTES = 12,
|
||||
VT_DOCUMENTATION = 14
|
||||
};
|
||||
const flatbuffers::String *name() const { return GetPointer<const flatbuffers::String *>(VT_NAME); }
|
||||
bool KeyCompareLessThan(const Enum *o) const { return *name() < *o->name(); }
|
||||
int KeyCompareWithValue(const char *val) const { return strcmp(name()->c_str(), val); }
|
||||
const flatbuffers::Vector<flatbuffers::Offset<EnumVal>> *values() const { return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<EnumVal>> *>(VT_VALUES); }
|
||||
bool is_union() const { return GetField<uint8_t>(VT_IS_UNION, 0) != 0; }
|
||||
const Type *underlying_type() const { return GetPointer<const Type *>(VT_UNDERLYING_TYPE); }
|
||||
const flatbuffers::Vector<flatbuffers::Offset<KeyValue>> *attributes() const { return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<KeyValue>> *>(VT_ATTRIBUTES); }
|
||||
const flatbuffers::String *name() const {
|
||||
return GetPointer<const flatbuffers::String *>(VT_NAME);
|
||||
}
|
||||
bool KeyCompareLessThan(const Enum *o) const {
|
||||
return *name() < *o->name();
|
||||
}
|
||||
int KeyCompareWithValue(const char *val) const {
|
||||
return strcmp(name()->c_str(), val);
|
||||
}
|
||||
const flatbuffers::Vector<flatbuffers::Offset<EnumVal>> *values() const {
|
||||
return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<EnumVal>> *>(VT_VALUES);
|
||||
}
|
||||
bool is_union() const {
|
||||
return GetField<uint8_t>(VT_IS_UNION, 0) != 0;
|
||||
}
|
||||
const Type *underlying_type() const {
|
||||
return GetPointer<const Type *>(VT_UNDERLYING_TYPE);
|
||||
}
|
||||
const flatbuffers::Vector<flatbuffers::Offset<KeyValue>> *attributes() const {
|
||||
return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<KeyValue>> *>(VT_ATTRIBUTES);
|
||||
}
|
||||
const flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>> *documentation() const {
|
||||
return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>> *>(VT_DOCUMENTATION);
|
||||
}
|
||||
bool Verify(flatbuffers::Verifier &verifier) const {
|
||||
return VerifyTableStart(verifier) &&
|
||||
VerifyFieldRequired<flatbuffers::uoffset_t>(verifier, VT_NAME) &&
|
||||
VerifyOffsetRequired(verifier, VT_NAME) &&
|
||||
verifier.Verify(name()) &&
|
||||
VerifyFieldRequired<flatbuffers::uoffset_t>(verifier, VT_VALUES) &&
|
||||
VerifyOffsetRequired(verifier, VT_VALUES) &&
|
||||
verifier.Verify(values()) &&
|
||||
verifier.VerifyVectorOfTables(values()) &&
|
||||
VerifyField<uint8_t>(verifier, VT_IS_UNION) &&
|
||||
VerifyFieldRequired<flatbuffers::uoffset_t>(verifier, VT_UNDERLYING_TYPE) &&
|
||||
VerifyOffsetRequired(verifier, VT_UNDERLYING_TYPE) &&
|
||||
verifier.VerifyTable(underlying_type()) &&
|
||||
VerifyField<flatbuffers::uoffset_t>(verifier, VT_ATTRIBUTES) &&
|
||||
VerifyOffset(verifier, VT_ATTRIBUTES) &&
|
||||
verifier.Verify(attributes()) &&
|
||||
verifier.VerifyVectorOfTables(attributes()) &&
|
||||
VerifyOffset(verifier, VT_DOCUMENTATION) &&
|
||||
verifier.Verify(documentation()) &&
|
||||
verifier.VerifyVectorOfStrings(documentation()) &&
|
||||
verifier.EndTable();
|
||||
}
|
||||
};
|
||||
@@ -229,29 +357,49 @@ struct Enum FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
|
||||
struct EnumBuilder {
|
||||
flatbuffers::FlatBufferBuilder &fbb_;
|
||||
flatbuffers::uoffset_t start_;
|
||||
void add_name(flatbuffers::Offset<flatbuffers::String> name) { fbb_.AddOffset(Enum::VT_NAME, name); }
|
||||
void add_values(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<EnumVal>>> values) { fbb_.AddOffset(Enum::VT_VALUES, values); }
|
||||
void add_is_union(bool is_union) { fbb_.AddElement<uint8_t>(Enum::VT_IS_UNION, static_cast<uint8_t>(is_union), 0); }
|
||||
void add_underlying_type(flatbuffers::Offset<Type> underlying_type) { fbb_.AddOffset(Enum::VT_UNDERLYING_TYPE, underlying_type); }
|
||||
void add_attributes(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<KeyValue>>> attributes) { fbb_.AddOffset(Enum::VT_ATTRIBUTES, attributes); }
|
||||
EnumBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) { start_ = fbb_.StartTable(); }
|
||||
void add_name(flatbuffers::Offset<flatbuffers::String> name) {
|
||||
fbb_.AddOffset(Enum::VT_NAME, name);
|
||||
}
|
||||
void add_values(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<EnumVal>>> values) {
|
||||
fbb_.AddOffset(Enum::VT_VALUES, values);
|
||||
}
|
||||
void add_is_union(bool is_union) {
|
||||
fbb_.AddElement<uint8_t>(Enum::VT_IS_UNION, static_cast<uint8_t>(is_union), 0);
|
||||
}
|
||||
void add_underlying_type(flatbuffers::Offset<Type> underlying_type) {
|
||||
fbb_.AddOffset(Enum::VT_UNDERLYING_TYPE, underlying_type);
|
||||
}
|
||||
void add_attributes(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<KeyValue>>> attributes) {
|
||||
fbb_.AddOffset(Enum::VT_ATTRIBUTES, attributes);
|
||||
}
|
||||
void add_documentation(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>>> documentation) {
|
||||
fbb_.AddOffset(Enum::VT_DOCUMENTATION, documentation);
|
||||
}
|
||||
EnumBuilder(flatbuffers::FlatBufferBuilder &_fbb)
|
||||
: fbb_(_fbb) {
|
||||
start_ = fbb_.StartTable();
|
||||
}
|
||||
EnumBuilder &operator=(const EnumBuilder &);
|
||||
flatbuffers::Offset<Enum> Finish() {
|
||||
auto o = flatbuffers::Offset<Enum>(fbb_.EndTable(start_, 5));
|
||||
fbb_.Required(o, Enum::VT_NAME); // name
|
||||
fbb_.Required(o, Enum::VT_VALUES); // values
|
||||
fbb_.Required(o, Enum::VT_UNDERLYING_TYPE); // underlying_type
|
||||
const auto end = fbb_.EndTable(start_, 6);
|
||||
auto o = flatbuffers::Offset<Enum>(end);
|
||||
fbb_.Required(o, Enum::VT_NAME);
|
||||
fbb_.Required(o, Enum::VT_VALUES);
|
||||
fbb_.Required(o, Enum::VT_UNDERLYING_TYPE);
|
||||
return o;
|
||||
}
|
||||
};
|
||||
|
||||
inline flatbuffers::Offset<Enum> CreateEnum(flatbuffers::FlatBufferBuilder &_fbb,
|
||||
inline flatbuffers::Offset<Enum> CreateEnum(
|
||||
flatbuffers::FlatBufferBuilder &_fbb,
|
||||
flatbuffers::Offset<flatbuffers::String> name = 0,
|
||||
flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<EnumVal>>> values = 0,
|
||||
bool is_union = false,
|
||||
flatbuffers::Offset<Type> underlying_type = 0,
|
||||
flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<KeyValue>>> attributes = 0) {
|
||||
flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<KeyValue>>> attributes = 0,
|
||||
flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>>> documentation = 0) {
|
||||
EnumBuilder builder_(_fbb);
|
||||
builder_.add_documentation(documentation);
|
||||
builder_.add_attributes(attributes);
|
||||
builder_.add_underlying_type(underlying_type);
|
||||
builder_.add_values(values);
|
||||
@@ -260,13 +408,22 @@ inline flatbuffers::Offset<Enum> CreateEnum(flatbuffers::FlatBufferBuilder &_fbb
|
||||
return builder_.Finish();
|
||||
}
|
||||
|
||||
inline flatbuffers::Offset<Enum> CreateEnumDirect(flatbuffers::FlatBufferBuilder &_fbb,
|
||||
inline flatbuffers::Offset<Enum> CreateEnumDirect(
|
||||
flatbuffers::FlatBufferBuilder &_fbb,
|
||||
const char *name = nullptr,
|
||||
const std::vector<flatbuffers::Offset<EnumVal>> *values = nullptr,
|
||||
bool is_union = false,
|
||||
flatbuffers::Offset<Type> underlying_type = 0,
|
||||
const std::vector<flatbuffers::Offset<KeyValue>> *attributes = nullptr) {
|
||||
return CreateEnum(_fbb, name ? _fbb.CreateString(name) : 0, values ? _fbb.CreateVector<flatbuffers::Offset<EnumVal>>(*values) : 0, is_union, underlying_type, attributes ? _fbb.CreateVector<flatbuffers::Offset<KeyValue>>(*attributes) : 0);
|
||||
const std::vector<flatbuffers::Offset<KeyValue>> *attributes = nullptr,
|
||||
const std::vector<flatbuffers::Offset<flatbuffers::String>> *documentation = nullptr) {
|
||||
return reflection::CreateEnum(
|
||||
_fbb,
|
||||
name ? _fbb.CreateString(name) : 0,
|
||||
values ? _fbb.CreateVector<flatbuffers::Offset<EnumVal>>(*values) : 0,
|
||||
is_union,
|
||||
underlying_type,
|
||||
attributes ? _fbb.CreateVector<flatbuffers::Offset<KeyValue>>(*attributes) : 0,
|
||||
documentation ? _fbb.CreateVector<flatbuffers::Offset<flatbuffers::String>>(*documentation) : 0);
|
||||
}
|
||||
|
||||
struct Field FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
|
||||
@@ -280,25 +437,53 @@ struct Field FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
|
||||
VT_DEPRECATED = 16,
|
||||
VT_REQUIRED = 18,
|
||||
VT_KEY = 20,
|
||||
VT_ATTRIBUTES = 22
|
||||
VT_ATTRIBUTES = 22,
|
||||
VT_DOCUMENTATION = 24
|
||||
};
|
||||
const flatbuffers::String *name() const { return GetPointer<const flatbuffers::String *>(VT_NAME); }
|
||||
bool KeyCompareLessThan(const Field *o) const { return *name() < *o->name(); }
|
||||
int KeyCompareWithValue(const char *val) const { return strcmp(name()->c_str(), val); }
|
||||
const Type *type() const { return GetPointer<const Type *>(VT_TYPE); }
|
||||
uint16_t id() const { return GetField<uint16_t>(VT_ID, 0); }
|
||||
uint16_t offset() const { return GetField<uint16_t>(VT_OFFSET, 0); }
|
||||
int64_t default_integer() const { return GetField<int64_t>(VT_DEFAULT_INTEGER, 0); }
|
||||
double default_real() const { return GetField<double>(VT_DEFAULT_REAL, 0.0); }
|
||||
bool deprecated() const { return GetField<uint8_t>(VT_DEPRECATED, 0) != 0; }
|
||||
bool required() const { return GetField<uint8_t>(VT_REQUIRED, 0) != 0; }
|
||||
bool key() const { return GetField<uint8_t>(VT_KEY, 0) != 0; }
|
||||
const flatbuffers::Vector<flatbuffers::Offset<KeyValue>> *attributes() const { return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<KeyValue>> *>(VT_ATTRIBUTES); }
|
||||
const flatbuffers::String *name() const {
|
||||
return GetPointer<const flatbuffers::String *>(VT_NAME);
|
||||
}
|
||||
bool KeyCompareLessThan(const Field *o) const {
|
||||
return *name() < *o->name();
|
||||
}
|
||||
int KeyCompareWithValue(const char *val) const {
|
||||
return strcmp(name()->c_str(), val);
|
||||
}
|
||||
const Type *type() const {
|
||||
return GetPointer<const Type *>(VT_TYPE);
|
||||
}
|
||||
uint16_t id() const {
|
||||
return GetField<uint16_t>(VT_ID, 0);
|
||||
}
|
||||
uint16_t offset() const {
|
||||
return GetField<uint16_t>(VT_OFFSET, 0);
|
||||
}
|
||||
int64_t default_integer() const {
|
||||
return GetField<int64_t>(VT_DEFAULT_INTEGER, 0);
|
||||
}
|
||||
double default_real() const {
|
||||
return GetField<double>(VT_DEFAULT_REAL, 0.0);
|
||||
}
|
||||
bool deprecated() const {
|
||||
return GetField<uint8_t>(VT_DEPRECATED, 0) != 0;
|
||||
}
|
||||
bool required() const {
|
||||
return GetField<uint8_t>(VT_REQUIRED, 0) != 0;
|
||||
}
|
||||
bool key() const {
|
||||
return GetField<uint8_t>(VT_KEY, 0) != 0;
|
||||
}
|
||||
const flatbuffers::Vector<flatbuffers::Offset<KeyValue>> *attributes() const {
|
||||
return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<KeyValue>> *>(VT_ATTRIBUTES);
|
||||
}
|
||||
const flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>> *documentation() const {
|
||||
return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>> *>(VT_DOCUMENTATION);
|
||||
}
|
||||
bool Verify(flatbuffers::Verifier &verifier) const {
|
||||
return VerifyTableStart(verifier) &&
|
||||
VerifyFieldRequired<flatbuffers::uoffset_t>(verifier, VT_NAME) &&
|
||||
VerifyOffsetRequired(verifier, VT_NAME) &&
|
||||
verifier.Verify(name()) &&
|
||||
VerifyFieldRequired<flatbuffers::uoffset_t>(verifier, VT_TYPE) &&
|
||||
VerifyOffsetRequired(verifier, VT_TYPE) &&
|
||||
verifier.VerifyTable(type()) &&
|
||||
VerifyField<uint16_t>(verifier, VT_ID) &&
|
||||
VerifyField<uint16_t>(verifier, VT_OFFSET) &&
|
||||
@@ -307,9 +492,12 @@ struct Field FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
|
||||
VerifyField<uint8_t>(verifier, VT_DEPRECATED) &&
|
||||
VerifyField<uint8_t>(verifier, VT_REQUIRED) &&
|
||||
VerifyField<uint8_t>(verifier, VT_KEY) &&
|
||||
VerifyField<flatbuffers::uoffset_t>(verifier, VT_ATTRIBUTES) &&
|
||||
VerifyOffset(verifier, VT_ATTRIBUTES) &&
|
||||
verifier.Verify(attributes()) &&
|
||||
verifier.VerifyVectorOfTables(attributes()) &&
|
||||
VerifyOffset(verifier, VT_DOCUMENTATION) &&
|
||||
verifier.Verify(documentation()) &&
|
||||
verifier.VerifyVectorOfStrings(documentation()) &&
|
||||
verifier.EndTable();
|
||||
}
|
||||
};
|
||||
@@ -317,27 +505,55 @@ struct Field FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
|
||||
struct FieldBuilder {
|
||||
flatbuffers::FlatBufferBuilder &fbb_;
|
||||
flatbuffers::uoffset_t start_;
|
||||
void add_name(flatbuffers::Offset<flatbuffers::String> name) { fbb_.AddOffset(Field::VT_NAME, name); }
|
||||
void add_type(flatbuffers::Offset<Type> type) { fbb_.AddOffset(Field::VT_TYPE, type); }
|
||||
void add_id(uint16_t id) { fbb_.AddElement<uint16_t>(Field::VT_ID, id, 0); }
|
||||
void add_offset(uint16_t offset) { fbb_.AddElement<uint16_t>(Field::VT_OFFSET, offset, 0); }
|
||||
void add_default_integer(int64_t default_integer) { fbb_.AddElement<int64_t>(Field::VT_DEFAULT_INTEGER, default_integer, 0); }
|
||||
void add_default_real(double default_real) { fbb_.AddElement<double>(Field::VT_DEFAULT_REAL, default_real, 0.0); }
|
||||
void add_deprecated(bool deprecated) { fbb_.AddElement<uint8_t>(Field::VT_DEPRECATED, static_cast<uint8_t>(deprecated), 0); }
|
||||
void add_required(bool required) { fbb_.AddElement<uint8_t>(Field::VT_REQUIRED, static_cast<uint8_t>(required), 0); }
|
||||
void add_key(bool key) { fbb_.AddElement<uint8_t>(Field::VT_KEY, static_cast<uint8_t>(key), 0); }
|
||||
void add_attributes(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<KeyValue>>> attributes) { fbb_.AddOffset(Field::VT_ATTRIBUTES, attributes); }
|
||||
FieldBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) { start_ = fbb_.StartTable(); }
|
||||
void add_name(flatbuffers::Offset<flatbuffers::String> name) {
|
||||
fbb_.AddOffset(Field::VT_NAME, name);
|
||||
}
|
||||
void add_type(flatbuffers::Offset<Type> type) {
|
||||
fbb_.AddOffset(Field::VT_TYPE, type);
|
||||
}
|
||||
void add_id(uint16_t id) {
|
||||
fbb_.AddElement<uint16_t>(Field::VT_ID, id, 0);
|
||||
}
|
||||
void add_offset(uint16_t offset) {
|
||||
fbb_.AddElement<uint16_t>(Field::VT_OFFSET, offset, 0);
|
||||
}
|
||||
void add_default_integer(int64_t default_integer) {
|
||||
fbb_.AddElement<int64_t>(Field::VT_DEFAULT_INTEGER, default_integer, 0);
|
||||
}
|
||||
void add_default_real(double default_real) {
|
||||
fbb_.AddElement<double>(Field::VT_DEFAULT_REAL, default_real, 0.0);
|
||||
}
|
||||
void add_deprecated(bool deprecated) {
|
||||
fbb_.AddElement<uint8_t>(Field::VT_DEPRECATED, static_cast<uint8_t>(deprecated), 0);
|
||||
}
|
||||
void add_required(bool required) {
|
||||
fbb_.AddElement<uint8_t>(Field::VT_REQUIRED, static_cast<uint8_t>(required), 0);
|
||||
}
|
||||
void add_key(bool key) {
|
||||
fbb_.AddElement<uint8_t>(Field::VT_KEY, static_cast<uint8_t>(key), 0);
|
||||
}
|
||||
void add_attributes(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<KeyValue>>> attributes) {
|
||||
fbb_.AddOffset(Field::VT_ATTRIBUTES, attributes);
|
||||
}
|
||||
void add_documentation(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>>> documentation) {
|
||||
fbb_.AddOffset(Field::VT_DOCUMENTATION, documentation);
|
||||
}
|
||||
FieldBuilder(flatbuffers::FlatBufferBuilder &_fbb)
|
||||
: fbb_(_fbb) {
|
||||
start_ = fbb_.StartTable();
|
||||
}
|
||||
FieldBuilder &operator=(const FieldBuilder &);
|
||||
flatbuffers::Offset<Field> Finish() {
|
||||
auto o = flatbuffers::Offset<Field>(fbb_.EndTable(start_, 10));
|
||||
fbb_.Required(o, Field::VT_NAME); // name
|
||||
fbb_.Required(o, Field::VT_TYPE); // type
|
||||
const auto end = fbb_.EndTable(start_, 11);
|
||||
auto o = flatbuffers::Offset<Field>(end);
|
||||
fbb_.Required(o, Field::VT_NAME);
|
||||
fbb_.Required(o, Field::VT_TYPE);
|
||||
return o;
|
||||
}
|
||||
};
|
||||
|
||||
inline flatbuffers::Offset<Field> CreateField(flatbuffers::FlatBufferBuilder &_fbb,
|
||||
inline flatbuffers::Offset<Field> CreateField(
|
||||
flatbuffers::FlatBufferBuilder &_fbb,
|
||||
flatbuffers::Offset<flatbuffers::String> name = 0,
|
||||
flatbuffers::Offset<Type> type = 0,
|
||||
uint16_t id = 0,
|
||||
@@ -347,10 +563,12 @@ inline flatbuffers::Offset<Field> CreateField(flatbuffers::FlatBufferBuilder &_f
|
||||
bool deprecated = false,
|
||||
bool required = false,
|
||||
bool key = false,
|
||||
flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<KeyValue>>> attributes = 0) {
|
||||
flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<KeyValue>>> attributes = 0,
|
||||
flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>>> documentation = 0) {
|
||||
FieldBuilder builder_(_fbb);
|
||||
builder_.add_default_real(default_real);
|
||||
builder_.add_default_integer(default_integer);
|
||||
builder_.add_documentation(documentation);
|
||||
builder_.add_attributes(attributes);
|
||||
builder_.add_type(type);
|
||||
builder_.add_name(name);
|
||||
@@ -362,7 +580,8 @@ inline flatbuffers::Offset<Field> CreateField(flatbuffers::FlatBufferBuilder &_f
|
||||
return builder_.Finish();
|
||||
}
|
||||
|
||||
inline flatbuffers::Offset<Field> CreateFieldDirect(flatbuffers::FlatBufferBuilder &_fbb,
|
||||
inline flatbuffers::Offset<Field> CreateFieldDirect(
|
||||
flatbuffers::FlatBufferBuilder &_fbb,
|
||||
const char *name = nullptr,
|
||||
flatbuffers::Offset<Type> type = 0,
|
||||
uint16_t id = 0,
|
||||
@@ -372,8 +591,21 @@ inline flatbuffers::Offset<Field> CreateFieldDirect(flatbuffers::FlatBufferBuild
|
||||
bool deprecated = false,
|
||||
bool required = false,
|
||||
bool key = false,
|
||||
const std::vector<flatbuffers::Offset<KeyValue>> *attributes = nullptr) {
|
||||
return CreateField(_fbb, name ? _fbb.CreateString(name) : 0, type, id, offset, default_integer, default_real, deprecated, required, key, attributes ? _fbb.CreateVector<flatbuffers::Offset<KeyValue>>(*attributes) : 0);
|
||||
const std::vector<flatbuffers::Offset<KeyValue>> *attributes = nullptr,
|
||||
const std::vector<flatbuffers::Offset<flatbuffers::String>> *documentation = nullptr) {
|
||||
return reflection::CreateField(
|
||||
_fbb,
|
||||
name ? _fbb.CreateString(name) : 0,
|
||||
type,
|
||||
id,
|
||||
offset,
|
||||
default_integer,
|
||||
default_real,
|
||||
deprecated,
|
||||
required,
|
||||
key,
|
||||
attributes ? _fbb.CreateVector<flatbuffers::Offset<KeyValue>>(*attributes) : 0,
|
||||
documentation ? _fbb.CreateVector<flatbuffers::Offset<flatbuffers::String>>(*documentation) : 0);
|
||||
}
|
||||
|
||||
struct Object FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
|
||||
@@ -383,29 +615,52 @@ struct Object FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
|
||||
VT_IS_STRUCT = 8,
|
||||
VT_MINALIGN = 10,
|
||||
VT_BYTESIZE = 12,
|
||||
VT_ATTRIBUTES = 14
|
||||
VT_ATTRIBUTES = 14,
|
||||
VT_DOCUMENTATION = 16
|
||||
};
|
||||
const flatbuffers::String *name() const { return GetPointer<const flatbuffers::String *>(VT_NAME); }
|
||||
bool KeyCompareLessThan(const Object *o) const { return *name() < *o->name(); }
|
||||
int KeyCompareWithValue(const char *val) const { return strcmp(name()->c_str(), val); }
|
||||
const flatbuffers::Vector<flatbuffers::Offset<Field>> *fields() const { return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<Field>> *>(VT_FIELDS); }
|
||||
bool is_struct() const { return GetField<uint8_t>(VT_IS_STRUCT, 0) != 0; }
|
||||
int32_t minalign() const { return GetField<int32_t>(VT_MINALIGN, 0); }
|
||||
int32_t bytesize() const { return GetField<int32_t>(VT_BYTESIZE, 0); }
|
||||
const flatbuffers::Vector<flatbuffers::Offset<KeyValue>> *attributes() const { return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<KeyValue>> *>(VT_ATTRIBUTES); }
|
||||
const flatbuffers::String *name() const {
|
||||
return GetPointer<const flatbuffers::String *>(VT_NAME);
|
||||
}
|
||||
bool KeyCompareLessThan(const Object *o) const {
|
||||
return *name() < *o->name();
|
||||
}
|
||||
int KeyCompareWithValue(const char *val) const {
|
||||
return strcmp(name()->c_str(), val);
|
||||
}
|
||||
const flatbuffers::Vector<flatbuffers::Offset<Field>> *fields() const {
|
||||
return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<Field>> *>(VT_FIELDS);
|
||||
}
|
||||
bool is_struct() const {
|
||||
return GetField<uint8_t>(VT_IS_STRUCT, 0) != 0;
|
||||
}
|
||||
int32_t minalign() const {
|
||||
return GetField<int32_t>(VT_MINALIGN, 0);
|
||||
}
|
||||
int32_t bytesize() const {
|
||||
return GetField<int32_t>(VT_BYTESIZE, 0);
|
||||
}
|
||||
const flatbuffers::Vector<flatbuffers::Offset<KeyValue>> *attributes() const {
|
||||
return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<KeyValue>> *>(VT_ATTRIBUTES);
|
||||
}
|
||||
const flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>> *documentation() const {
|
||||
return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>> *>(VT_DOCUMENTATION);
|
||||
}
|
||||
bool Verify(flatbuffers::Verifier &verifier) const {
|
||||
return VerifyTableStart(verifier) &&
|
||||
VerifyFieldRequired<flatbuffers::uoffset_t>(verifier, VT_NAME) &&
|
||||
VerifyOffsetRequired(verifier, VT_NAME) &&
|
||||
verifier.Verify(name()) &&
|
||||
VerifyFieldRequired<flatbuffers::uoffset_t>(verifier, VT_FIELDS) &&
|
||||
VerifyOffsetRequired(verifier, VT_FIELDS) &&
|
||||
verifier.Verify(fields()) &&
|
||||
verifier.VerifyVectorOfTables(fields()) &&
|
||||
VerifyField<uint8_t>(verifier, VT_IS_STRUCT) &&
|
||||
VerifyField<int32_t>(verifier, VT_MINALIGN) &&
|
||||
VerifyField<int32_t>(verifier, VT_BYTESIZE) &&
|
||||
VerifyField<flatbuffers::uoffset_t>(verifier, VT_ATTRIBUTES) &&
|
||||
VerifyOffset(verifier, VT_ATTRIBUTES) &&
|
||||
verifier.Verify(attributes()) &&
|
||||
verifier.VerifyVectorOfTables(attributes()) &&
|
||||
VerifyOffset(verifier, VT_DOCUMENTATION) &&
|
||||
verifier.Verify(documentation()) &&
|
||||
verifier.VerifyVectorOfStrings(documentation()) &&
|
||||
verifier.EndTable();
|
||||
}
|
||||
};
|
||||
@@ -413,30 +668,52 @@ struct Object FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
|
||||
struct ObjectBuilder {
|
||||
flatbuffers::FlatBufferBuilder &fbb_;
|
||||
flatbuffers::uoffset_t start_;
|
||||
void add_name(flatbuffers::Offset<flatbuffers::String> name) { fbb_.AddOffset(Object::VT_NAME, name); }
|
||||
void add_fields(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<Field>>> fields) { fbb_.AddOffset(Object::VT_FIELDS, fields); }
|
||||
void add_is_struct(bool is_struct) { fbb_.AddElement<uint8_t>(Object::VT_IS_STRUCT, static_cast<uint8_t>(is_struct), 0); }
|
||||
void add_minalign(int32_t minalign) { fbb_.AddElement<int32_t>(Object::VT_MINALIGN, minalign, 0); }
|
||||
void add_bytesize(int32_t bytesize) { fbb_.AddElement<int32_t>(Object::VT_BYTESIZE, bytesize, 0); }
|
||||
void add_attributes(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<KeyValue>>> attributes) { fbb_.AddOffset(Object::VT_ATTRIBUTES, attributes); }
|
||||
ObjectBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) { start_ = fbb_.StartTable(); }
|
||||
void add_name(flatbuffers::Offset<flatbuffers::String> name) {
|
||||
fbb_.AddOffset(Object::VT_NAME, name);
|
||||
}
|
||||
void add_fields(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<Field>>> fields) {
|
||||
fbb_.AddOffset(Object::VT_FIELDS, fields);
|
||||
}
|
||||
void add_is_struct(bool is_struct) {
|
||||
fbb_.AddElement<uint8_t>(Object::VT_IS_STRUCT, static_cast<uint8_t>(is_struct), 0);
|
||||
}
|
||||
void add_minalign(int32_t minalign) {
|
||||
fbb_.AddElement<int32_t>(Object::VT_MINALIGN, minalign, 0);
|
||||
}
|
||||
void add_bytesize(int32_t bytesize) {
|
||||
fbb_.AddElement<int32_t>(Object::VT_BYTESIZE, bytesize, 0);
|
||||
}
|
||||
void add_attributes(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<KeyValue>>> attributes) {
|
||||
fbb_.AddOffset(Object::VT_ATTRIBUTES, attributes);
|
||||
}
|
||||
void add_documentation(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>>> documentation) {
|
||||
fbb_.AddOffset(Object::VT_DOCUMENTATION, documentation);
|
||||
}
|
||||
ObjectBuilder(flatbuffers::FlatBufferBuilder &_fbb)
|
||||
: fbb_(_fbb) {
|
||||
start_ = fbb_.StartTable();
|
||||
}
|
||||
ObjectBuilder &operator=(const ObjectBuilder &);
|
||||
flatbuffers::Offset<Object> Finish() {
|
||||
auto o = flatbuffers::Offset<Object>(fbb_.EndTable(start_, 6));
|
||||
fbb_.Required(o, Object::VT_NAME); // name
|
||||
fbb_.Required(o, Object::VT_FIELDS); // fields
|
||||
const auto end = fbb_.EndTable(start_, 7);
|
||||
auto o = flatbuffers::Offset<Object>(end);
|
||||
fbb_.Required(o, Object::VT_NAME);
|
||||
fbb_.Required(o, Object::VT_FIELDS);
|
||||
return o;
|
||||
}
|
||||
};
|
||||
|
||||
inline flatbuffers::Offset<Object> CreateObject(flatbuffers::FlatBufferBuilder &_fbb,
|
||||
inline flatbuffers::Offset<Object> CreateObject(
|
||||
flatbuffers::FlatBufferBuilder &_fbb,
|
||||
flatbuffers::Offset<flatbuffers::String> name = 0,
|
||||
flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<Field>>> fields = 0,
|
||||
bool is_struct = false,
|
||||
int32_t minalign = 0,
|
||||
int32_t bytesize = 0,
|
||||
flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<KeyValue>>> attributes = 0) {
|
||||
flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<KeyValue>>> attributes = 0,
|
||||
flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>>> documentation = 0) {
|
||||
ObjectBuilder builder_(_fbb);
|
||||
builder_.add_documentation(documentation);
|
||||
builder_.add_attributes(attributes);
|
||||
builder_.add_bytesize(bytesize);
|
||||
builder_.add_minalign(minalign);
|
||||
@@ -446,14 +723,24 @@ inline flatbuffers::Offset<Object> CreateObject(flatbuffers::FlatBufferBuilder &
|
||||
return builder_.Finish();
|
||||
}
|
||||
|
||||
inline flatbuffers::Offset<Object> CreateObjectDirect(flatbuffers::FlatBufferBuilder &_fbb,
|
||||
inline flatbuffers::Offset<Object> CreateObjectDirect(
|
||||
flatbuffers::FlatBufferBuilder &_fbb,
|
||||
const char *name = nullptr,
|
||||
const std::vector<flatbuffers::Offset<Field>> *fields = nullptr,
|
||||
bool is_struct = false,
|
||||
int32_t minalign = 0,
|
||||
int32_t bytesize = 0,
|
||||
const std::vector<flatbuffers::Offset<KeyValue>> *attributes = nullptr) {
|
||||
return CreateObject(_fbb, name ? _fbb.CreateString(name) : 0, fields ? _fbb.CreateVector<flatbuffers::Offset<Field>>(*fields) : 0, is_struct, minalign, bytesize, attributes ? _fbb.CreateVector<flatbuffers::Offset<KeyValue>>(*attributes) : 0);
|
||||
const std::vector<flatbuffers::Offset<KeyValue>> *attributes = nullptr,
|
||||
const std::vector<flatbuffers::Offset<flatbuffers::String>> *documentation = nullptr) {
|
||||
return reflection::CreateObject(
|
||||
_fbb,
|
||||
name ? _fbb.CreateString(name) : 0,
|
||||
fields ? _fbb.CreateVector<flatbuffers::Offset<Field>>(*fields) : 0,
|
||||
is_struct,
|
||||
minalign,
|
||||
bytesize,
|
||||
attributes ? _fbb.CreateVector<flatbuffers::Offset<KeyValue>>(*attributes) : 0,
|
||||
documentation ? _fbb.CreateVector<flatbuffers::Offset<flatbuffers::String>>(*documentation) : 0);
|
||||
}
|
||||
|
||||
struct Schema FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
|
||||
@@ -464,24 +751,34 @@ struct Schema FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
|
||||
VT_FILE_EXT = 10,
|
||||
VT_ROOT_TABLE = 12
|
||||
};
|
||||
const flatbuffers::Vector<flatbuffers::Offset<Object>> *objects() const { return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<Object>> *>(VT_OBJECTS); }
|
||||
const flatbuffers::Vector<flatbuffers::Offset<Enum>> *enums() const { return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<Enum>> *>(VT_ENUMS); }
|
||||
const flatbuffers::String *file_ident() const { return GetPointer<const flatbuffers::String *>(VT_FILE_IDENT); }
|
||||
const flatbuffers::String *file_ext() const { return GetPointer<const flatbuffers::String *>(VT_FILE_EXT); }
|
||||
const Object *root_table() const { return GetPointer<const Object *>(VT_ROOT_TABLE); }
|
||||
const flatbuffers::Vector<flatbuffers::Offset<Object>> *objects() const {
|
||||
return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<Object>> *>(VT_OBJECTS);
|
||||
}
|
||||
const flatbuffers::Vector<flatbuffers::Offset<Enum>> *enums() const {
|
||||
return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<Enum>> *>(VT_ENUMS);
|
||||
}
|
||||
const flatbuffers::String *file_ident() const {
|
||||
return GetPointer<const flatbuffers::String *>(VT_FILE_IDENT);
|
||||
}
|
||||
const flatbuffers::String *file_ext() const {
|
||||
return GetPointer<const flatbuffers::String *>(VT_FILE_EXT);
|
||||
}
|
||||
const Object *root_table() const {
|
||||
return GetPointer<const Object *>(VT_ROOT_TABLE);
|
||||
}
|
||||
bool Verify(flatbuffers::Verifier &verifier) const {
|
||||
return VerifyTableStart(verifier) &&
|
||||
VerifyFieldRequired<flatbuffers::uoffset_t>(verifier, VT_OBJECTS) &&
|
||||
VerifyOffsetRequired(verifier, VT_OBJECTS) &&
|
||||
verifier.Verify(objects()) &&
|
||||
verifier.VerifyVectorOfTables(objects()) &&
|
||||
VerifyFieldRequired<flatbuffers::uoffset_t>(verifier, VT_ENUMS) &&
|
||||
VerifyOffsetRequired(verifier, VT_ENUMS) &&
|
||||
verifier.Verify(enums()) &&
|
||||
verifier.VerifyVectorOfTables(enums()) &&
|
||||
VerifyField<flatbuffers::uoffset_t>(verifier, VT_FILE_IDENT) &&
|
||||
VerifyOffset(verifier, VT_FILE_IDENT) &&
|
||||
verifier.Verify(file_ident()) &&
|
||||
VerifyField<flatbuffers::uoffset_t>(verifier, VT_FILE_EXT) &&
|
||||
VerifyOffset(verifier, VT_FILE_EXT) &&
|
||||
verifier.Verify(file_ext()) &&
|
||||
VerifyField<flatbuffers::uoffset_t>(verifier, VT_ROOT_TABLE) &&
|
||||
VerifyOffset(verifier, VT_ROOT_TABLE) &&
|
||||
verifier.VerifyTable(root_table()) &&
|
||||
verifier.EndTable();
|
||||
}
|
||||
@@ -490,22 +787,37 @@ struct Schema FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
|
||||
struct SchemaBuilder {
|
||||
flatbuffers::FlatBufferBuilder &fbb_;
|
||||
flatbuffers::uoffset_t start_;
|
||||
void add_objects(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<Object>>> objects) { fbb_.AddOffset(Schema::VT_OBJECTS, objects); }
|
||||
void add_enums(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<Enum>>> enums) { fbb_.AddOffset(Schema::VT_ENUMS, enums); }
|
||||
void add_file_ident(flatbuffers::Offset<flatbuffers::String> file_ident) { fbb_.AddOffset(Schema::VT_FILE_IDENT, file_ident); }
|
||||
void add_file_ext(flatbuffers::Offset<flatbuffers::String> file_ext) { fbb_.AddOffset(Schema::VT_FILE_EXT, file_ext); }
|
||||
void add_root_table(flatbuffers::Offset<Object> root_table) { fbb_.AddOffset(Schema::VT_ROOT_TABLE, root_table); }
|
||||
SchemaBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) { start_ = fbb_.StartTable(); }
|
||||
void add_objects(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<Object>>> objects) {
|
||||
fbb_.AddOffset(Schema::VT_OBJECTS, objects);
|
||||
}
|
||||
void add_enums(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<Enum>>> enums) {
|
||||
fbb_.AddOffset(Schema::VT_ENUMS, enums);
|
||||
}
|
||||
void add_file_ident(flatbuffers::Offset<flatbuffers::String> file_ident) {
|
||||
fbb_.AddOffset(Schema::VT_FILE_IDENT, file_ident);
|
||||
}
|
||||
void add_file_ext(flatbuffers::Offset<flatbuffers::String> file_ext) {
|
||||
fbb_.AddOffset(Schema::VT_FILE_EXT, file_ext);
|
||||
}
|
||||
void add_root_table(flatbuffers::Offset<Object> root_table) {
|
||||
fbb_.AddOffset(Schema::VT_ROOT_TABLE, root_table);
|
||||
}
|
||||
SchemaBuilder(flatbuffers::FlatBufferBuilder &_fbb)
|
||||
: fbb_(_fbb) {
|
||||
start_ = fbb_.StartTable();
|
||||
}
|
||||
SchemaBuilder &operator=(const SchemaBuilder &);
|
||||
flatbuffers::Offset<Schema> Finish() {
|
||||
auto o = flatbuffers::Offset<Schema>(fbb_.EndTable(start_, 5));
|
||||
fbb_.Required(o, Schema::VT_OBJECTS); // objects
|
||||
fbb_.Required(o, Schema::VT_ENUMS); // enums
|
||||
const auto end = fbb_.EndTable(start_, 5);
|
||||
auto o = flatbuffers::Offset<Schema>(end);
|
||||
fbb_.Required(o, Schema::VT_OBJECTS);
|
||||
fbb_.Required(o, Schema::VT_ENUMS);
|
||||
return o;
|
||||
}
|
||||
};
|
||||
|
||||
inline flatbuffers::Offset<Schema> CreateSchema(flatbuffers::FlatBufferBuilder &_fbb,
|
||||
inline flatbuffers::Offset<Schema> CreateSchema(
|
||||
flatbuffers::FlatBufferBuilder &_fbb,
|
||||
flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<Object>>> objects = 0,
|
||||
flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<Enum>>> enums = 0,
|
||||
flatbuffers::Offset<flatbuffers::String> file_ident = 0,
|
||||
@@ -520,26 +832,49 @@ inline flatbuffers::Offset<Schema> CreateSchema(flatbuffers::FlatBufferBuilder &
|
||||
return builder_.Finish();
|
||||
}
|
||||
|
||||
inline flatbuffers::Offset<Schema> CreateSchemaDirect(flatbuffers::FlatBufferBuilder &_fbb,
|
||||
inline flatbuffers::Offset<Schema> CreateSchemaDirect(
|
||||
flatbuffers::FlatBufferBuilder &_fbb,
|
||||
const std::vector<flatbuffers::Offset<Object>> *objects = nullptr,
|
||||
const std::vector<flatbuffers::Offset<Enum>> *enums = nullptr,
|
||||
const char *file_ident = nullptr,
|
||||
const char *file_ext = nullptr,
|
||||
flatbuffers::Offset<Object> root_table = 0) {
|
||||
return CreateSchema(_fbb, objects ? _fbb.CreateVector<flatbuffers::Offset<Object>>(*objects) : 0, enums ? _fbb.CreateVector<flatbuffers::Offset<Enum>>(*enums) : 0, file_ident ? _fbb.CreateString(file_ident) : 0, file_ext ? _fbb.CreateString(file_ext) : 0, root_table);
|
||||
return reflection::CreateSchema(
|
||||
_fbb,
|
||||
objects ? _fbb.CreateVector<flatbuffers::Offset<Object>>(*objects) : 0,
|
||||
enums ? _fbb.CreateVector<flatbuffers::Offset<Enum>>(*enums) : 0,
|
||||
file_ident ? _fbb.CreateString(file_ident) : 0,
|
||||
file_ext ? _fbb.CreateString(file_ext) : 0,
|
||||
root_table);
|
||||
}
|
||||
|
||||
inline const reflection::Schema *GetSchema(const void *buf) { return flatbuffers::GetRoot<reflection::Schema>(buf); }
|
||||
inline const reflection::Schema *GetSchema(const void *buf) {
|
||||
return flatbuffers::GetRoot<reflection::Schema>(buf);
|
||||
}
|
||||
|
||||
inline const char *SchemaIdentifier() { return "BFBS"; }
|
||||
inline const char *SchemaIdentifier() {
|
||||
return "BFBS";
|
||||
}
|
||||
|
||||
inline bool SchemaBufferHasIdentifier(const void *buf) { return flatbuffers::BufferHasIdentifier(buf, SchemaIdentifier()); }
|
||||
inline bool SchemaBufferHasIdentifier(const void *buf) {
|
||||
return flatbuffers::BufferHasIdentifier(
|
||||
buf, SchemaIdentifier());
|
||||
}
|
||||
|
||||
inline bool VerifySchemaBuffer(flatbuffers::Verifier &verifier) { return verifier.VerifyBuffer<reflection::Schema>(SchemaIdentifier()); }
|
||||
inline bool VerifySchemaBuffer(
|
||||
flatbuffers::Verifier &verifier) {
|
||||
return verifier.VerifyBuffer<reflection::Schema>(SchemaIdentifier());
|
||||
}
|
||||
|
||||
inline const char *SchemaExtension() { return "bfbs"; }
|
||||
inline const char *SchemaExtension() {
|
||||
return "bfbs";
|
||||
}
|
||||
|
||||
inline void FinishSchemaBuffer(flatbuffers::FlatBufferBuilder &fbb, flatbuffers::Offset<reflection::Schema> root) { fbb.Finish(root, SchemaIdentifier()); }
|
||||
inline void FinishSchemaBuffer(
|
||||
flatbuffers::FlatBufferBuilder &fbb,
|
||||
flatbuffers::Offset<reflection::Schema> root) {
|
||||
fbb.Finish(root, SchemaIdentifier());
|
||||
}
|
||||
|
||||
} // namespace reflection
|
||||
|
||||
|
||||
131
include/flatbuffers/registry.h
Normal file
131
include/flatbuffers/registry.h
Normal file
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
* Copyright 2017 Google Inc. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef FLATBUFFERS_REGISTRY_H_
|
||||
#define FLATBUFFERS_REGISTRY_H_
|
||||
|
||||
#include "flatbuffers/idl.h"
|
||||
|
||||
namespace flatbuffers {
|
||||
|
||||
// Convenience class to easily parse or generate text for arbitrary FlatBuffers.
|
||||
// Simply pre-populate it with all schema filenames that may be in use, and
|
||||
// This class will look them up using the file_identifier declared in the
|
||||
// schema.
|
||||
class Registry {
|
||||
public:
|
||||
// Call this for all schemas that may be in use. The identifier has
|
||||
// a function in the generated code, e.g. MonsterIdentifier().
|
||||
void Register(const char *file_identifier, const char *schema_path) {
|
||||
Schema schema;
|
||||
schema.path_ = schema_path;
|
||||
schemas_[file_identifier] = schema;
|
||||
}
|
||||
|
||||
// Generate text from an arbitrary FlatBuffer by looking up its
|
||||
// file_identifier in the registry.
|
||||
bool FlatBufferToText(const uint8_t *flatbuf, size_t len,
|
||||
std::string *dest) {
|
||||
// Get the identifier out of the buffer.
|
||||
// If the buffer is truncated, exit.
|
||||
if (len < sizeof(uoffset_t) +
|
||||
FlatBufferBuilder::kFileIdentifierLength) {
|
||||
lasterror_ = "buffer truncated";
|
||||
return false;
|
||||
}
|
||||
std::string ident(reinterpret_cast<const char *>(flatbuf) +
|
||||
sizeof(uoffset_t),
|
||||
FlatBufferBuilder::kFileIdentifierLength);
|
||||
// Load and parse the schema.
|
||||
Parser parser;
|
||||
if (!LoadSchema(ident, &parser)) return false;
|
||||
// Now we're ready to generate text.
|
||||
if (!GenerateText(parser, flatbuf, dest)) {
|
||||
lasterror_ = "unable to generate text for FlatBuffer binary";
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Converts a binary buffer to text using one of the schemas in the registry,
|
||||
// use the file_identifier to indicate which.
|
||||
// If DetachedBuffer::data() is null then parsing failed.
|
||||
DetachedBuffer TextToFlatBuffer(const char *text,
|
||||
const char *file_identifier) {
|
||||
// Load and parse the schema.
|
||||
Parser parser;
|
||||
if (!LoadSchema(file_identifier, &parser)) return DetachedBuffer();
|
||||
// Parse the text.
|
||||
if (!parser.Parse(text)) {
|
||||
lasterror_ = parser.error_;
|
||||
return DetachedBuffer();
|
||||
}
|
||||
// We have a valid FlatBuffer. Detach it from the builder and return.
|
||||
return parser.builder_.ReleaseBufferPointer();
|
||||
}
|
||||
|
||||
// Modify any parsing / output options used by the other functions.
|
||||
void SetOptions(const IDLOptions &opts) { opts_ = opts; }
|
||||
|
||||
// If schemas used contain include statements, call this function for every
|
||||
// directory the parser should search them for.
|
||||
void AddIncludeDirectory(const char *path) {
|
||||
include_paths_.push_back(path);
|
||||
}
|
||||
|
||||
// Returns a human readable error if any of the above functions fail.
|
||||
const std::string &GetLastError() { return lasterror_; }
|
||||
|
||||
private:
|
||||
bool LoadSchema(const std::string &ident, Parser *parser) {
|
||||
// Find the schema, if not, exit.
|
||||
auto it = schemas_.find(ident);
|
||||
if (it == schemas_.end()) {
|
||||
// Don't attach the identifier, since it may not be human readable.
|
||||
lasterror_ = "identifier for this buffer not in the registry";
|
||||
return false;
|
||||
}
|
||||
auto &schema = it->second;
|
||||
// Load the schema from disk. If not, exit.
|
||||
std::string schematext;
|
||||
if (!LoadFile(schema.path_.c_str(), false, &schematext)) {
|
||||
lasterror_ = "could not load schema: " + schema.path_;
|
||||
return false;
|
||||
}
|
||||
// Parse schema.
|
||||
parser->opts = opts_;
|
||||
if (!parser->Parse(schematext.c_str(), include_paths_.data(),
|
||||
schema.path_.c_str())) {
|
||||
lasterror_ = parser->error_;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
struct Schema {
|
||||
std::string path_;
|
||||
// TODO(wvo) optionally cache schema file or parsed schema here.
|
||||
};
|
||||
|
||||
std::string lasterror_;
|
||||
IDLOptions opts_;
|
||||
std::vector<const char *> include_paths_;
|
||||
std::map<std::string, Schema> schemas_;
|
||||
};
|
||||
|
||||
} // namespace flatbuffers
|
||||
|
||||
#endif // FLATBUFFERS_REGISTRY_H_
|
||||
@@ -40,7 +40,8 @@
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "flatbuffers/flatbuffers.h"
|
||||
#include "flatbuffers/base.h"
|
||||
|
||||
|
||||
namespace flatbuffers {
|
||||
|
||||
@@ -71,9 +72,8 @@ template<> inline std::string NumToString<double>(double t) {
|
||||
// Sadly, std::fixed turns "1" into "1.00000", so here we undo that.
|
||||
auto p = s.find_last_not_of('0');
|
||||
if (p != std::string::npos) {
|
||||
s.resize(p + 1); // Strip trailing zeroes.
|
||||
if (s[s.size() - 1] == '.')
|
||||
s.erase(s.size() - 1, 1); // Strip '.' if a whole number.
|
||||
// Strip trailing zeroes. If it is a whole number, keep one zero.
|
||||
s.resize(p + (s[p] == '.' ? 2 : 1));
|
||||
}
|
||||
return s;
|
||||
}
|
||||
@@ -95,20 +95,22 @@ inline std::string IntToStringHex(int i, int xdigits) {
|
||||
}
|
||||
|
||||
// Portable implementation of strtoll().
|
||||
inline int64_t StringToInt(const char *str, int base = 10) {
|
||||
inline int64_t StringToInt(const char *str, char **endptr = nullptr,
|
||||
int base = 10) {
|
||||
#ifdef _MSC_VER
|
||||
return _strtoi64(str, nullptr, base);
|
||||
return _strtoi64(str, endptr, base);
|
||||
#else
|
||||
return strtoll(str, nullptr, base);
|
||||
return strtoll(str, endptr, base);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Portable implementation of strtoull().
|
||||
inline int64_t StringToUInt(const char *str, int base = 10) {
|
||||
inline uint64_t StringToUInt(const char *str, char **endptr = nullptr,
|
||||
int base = 10) {
|
||||
#ifdef _MSC_VER
|
||||
return _strtoui64(str, nullptr, base);
|
||||
return _strtoui64(str, endptr, base);
|
||||
#else
|
||||
return strtoull(str, nullptr, base);
|
||||
return strtoull(str, endptr, base);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -155,16 +157,20 @@ inline bool SaveFile(const char *name, const std::string &buf, bool binary) {
|
||||
return SaveFile(name, buf.c_str(), buf.size(), binary);
|
||||
}
|
||||
|
||||
// Functionality for minimalistic portable path handling:
|
||||
// Functionality for minimalistic portable path handling.
|
||||
|
||||
static const char kPosixPathSeparator = '/';
|
||||
#ifdef _WIN32
|
||||
static const char kPathSeparator = '\\';
|
||||
// The functions below behave correctly regardless of whether posix ('/') or
|
||||
// Windows ('/' or '\\') separators are used.
|
||||
|
||||
// Any new separators inserted are always posix.
|
||||
|
||||
// We internally store paths in posix format ('/'). Paths supplied
|
||||
// by the user should go through PosixPath to ensure correct behavior
|
||||
// on Windows when paths are string-compared.
|
||||
|
||||
static const char kPathSeparator = '/';
|
||||
static const char kPathSeparatorWindows = '\\';
|
||||
static const char *PathSeparatorSet = "\\/"; // Intentionally no ':'
|
||||
#else
|
||||
static const char kPathSeparator = kPosixPathSeparator;
|
||||
static const char *PathSeparatorSet = "/";
|
||||
#endif // _WIN32
|
||||
|
||||
// Returns the path with the extension, if any, removed.
|
||||
inline std::string StripExtension(const std::string &filepath) {
|
||||
@@ -195,13 +201,24 @@ inline std::string StripFileName(const std::string &filepath) {
|
||||
inline std::string ConCatPathFileName(const std::string &path,
|
||||
const std::string &filename) {
|
||||
std::string filepath = path;
|
||||
if (path.length() && path[path.size() - 1] != kPathSeparator &&
|
||||
path[path.size() - 1] != kPosixPathSeparator)
|
||||
filepath += kPathSeparator;
|
||||
if (filepath.length()) {
|
||||
if (filepath.back() == kPathSeparatorWindows) {
|
||||
filepath.back() = kPathSeparator;
|
||||
} else if (filepath.back() != kPathSeparator) {
|
||||
filepath += kPathSeparator;
|
||||
}
|
||||
}
|
||||
filepath += filename;
|
||||
return filepath;
|
||||
}
|
||||
|
||||
// Replaces any '\\' separators with '/'
|
||||
inline std::string PosixPath(const char *path) {
|
||||
std::string p = path;
|
||||
std::replace(p.begin(), p.end(), '\\', '/');
|
||||
return p;
|
||||
}
|
||||
|
||||
// This function ensure a directory exists, by recursively
|
||||
// creating dirs for any parts of the path that don't exist yet.
|
||||
inline void EnsureDirExists(const std::string &filepath) {
|
||||
@@ -343,6 +360,72 @@ inline std::string WordWrap(const std::string in, size_t max_length,
|
||||
return wrapped;
|
||||
}
|
||||
|
||||
inline bool EscapeString(const char *s, size_t length, std::string *_text,
|
||||
bool allow_non_utf8) {
|
||||
std::string &text = *_text;
|
||||
text += "\"";
|
||||
for (uoffset_t i = 0; i < length; i++) {
|
||||
char c = s[i];
|
||||
switch (c) {
|
||||
case '\n': text += "\\n"; break;
|
||||
case '\t': text += "\\t"; break;
|
||||
case '\r': text += "\\r"; break;
|
||||
case '\b': text += "\\b"; break;
|
||||
case '\f': text += "\\f"; break;
|
||||
case '\"': text += "\\\""; break;
|
||||
case '\\': text += "\\\\"; break;
|
||||
default:
|
||||
if (c >= ' ' && c <= '~') {
|
||||
text += c;
|
||||
} else {
|
||||
// Not printable ASCII data. Let's see if it's valid UTF-8 first:
|
||||
const char *utf8 = s + i;
|
||||
int ucc = FromUTF8(&utf8);
|
||||
if (ucc < 0) {
|
||||
if (allow_non_utf8) {
|
||||
text += "\\x";
|
||||
text += IntToStringHex(static_cast<uint8_t>(c), 2);
|
||||
} else {
|
||||
// There are two cases here:
|
||||
//
|
||||
// 1) We reached here by parsing an IDL file. In that case,
|
||||
// we previously checked for non-UTF-8, so we shouldn't reach
|
||||
// here.
|
||||
//
|
||||
// 2) We reached here by someone calling GenerateText()
|
||||
// on a previously-serialized flatbuffer. The data might have
|
||||
// non-UTF-8 Strings, or might be corrupt.
|
||||
//
|
||||
// In both cases, we have to give up and inform the caller
|
||||
// they have no JSON.
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (ucc <= 0xFFFF) {
|
||||
// Parses as Unicode within JSON's \uXXXX range, so use that.
|
||||
text += "\\u";
|
||||
text += IntToStringHex(ucc, 4);
|
||||
} else if (ucc <= 0x10FFFF) {
|
||||
// Encode Unicode SMP values to a surrogate pair using two \u escapes.
|
||||
uint32_t base = ucc - 0x10000;
|
||||
auto high_surrogate = (base >> 10) + 0xD800;
|
||||
auto low_surrogate = (base & 0x03FF) + 0xDC00;
|
||||
text += "\\u";
|
||||
text += IntToStringHex(high_surrogate, 4);
|
||||
text += "\\u";
|
||||
text += IntToStringHex(low_surrogate, 4);
|
||||
}
|
||||
// Skip past characters recognized.
|
||||
i = static_cast<uoffset_t>(utf8 - s - 1);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
text += "\"";
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace flatbuffers
|
||||
|
||||
#endif // FLATBUFFERS_UTIL_H_
|
||||
|
||||
@@ -106,6 +106,22 @@ public class FlatBufferBuilder {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the FlatBufferBuilder by purging all data that it holds.
|
||||
*/
|
||||
public void clear(){
|
||||
space = bb.capacity();
|
||||
bb.clear();
|
||||
minalign = 1;
|
||||
while(vtable_in_use > 0) vtable[--vtable_in_use] = 0;
|
||||
vtable_in_use = 0;
|
||||
nested = false;
|
||||
finished = false;
|
||||
object_start = 0;
|
||||
num_vtables = 0;
|
||||
vector_num_elems = 0;
|
||||
}
|
||||
|
||||
/// @cond FLATBUFFERS_INTERNAL
|
||||
/**
|
||||
* Create a `ByteBuffer` with a given capacity.
|
||||
@@ -367,6 +383,53 @@ public class FlatBufferBuilder {
|
||||
}
|
||||
/// @endcond
|
||||
|
||||
/**
|
||||
* Create a new array/vector and return a ByteBuffer to be filled later.
|
||||
* Call {@link #endVector} after this method to get an offset to the beginning
|
||||
* of vector.
|
||||
*
|
||||
* @param elem_size the size of each element in bytes.
|
||||
* @param num_elems number of elements in the vector.
|
||||
* @param alignment byte alignment.
|
||||
* @return ByteBuffer with position and limit set to the space allocated for the array.
|
||||
*/
|
||||
public ByteBuffer createUnintializedVector(int elem_size, int num_elems, int alignment) {
|
||||
int length = elem_size * num_elems;
|
||||
startVector(elem_size, num_elems, alignment);
|
||||
|
||||
bb.position(space -= length);
|
||||
|
||||
// Slice and limit the copy vector to point to the 'array'
|
||||
ByteBuffer copy = bb.slice().order(ByteOrder.LITTLE_ENDIAN);
|
||||
copy.limit(length);
|
||||
return copy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a vector of tables.
|
||||
*
|
||||
* @param offsets Offsets of the tables.
|
||||
* @return Returns offset of the vector.
|
||||
*/
|
||||
public int createVectorOfTables(int[] offsets) {
|
||||
notNested();
|
||||
startVector(Constants.SIZEOF_INT, offsets.length, Constants.SIZEOF_INT);
|
||||
for(int i = offsets.length - 1; i >= 0; i--) addOffset(offsets[i]);
|
||||
return endVector();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a vector of sorted by the key tables.
|
||||
*
|
||||
* @param obj Instance of the table subclass.
|
||||
* @param offsets Offsets of the tables.
|
||||
* @return Returns offset of the sorted vector.
|
||||
*/
|
||||
public <T extends Table> int createSortedVectorOfTables(T obj, int[] offsets) {
|
||||
obj.sortTables(offsets, bb);
|
||||
return createVectorOfTables(offsets);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode the string `s` in the buffer using UTF-8. If {@code s} is
|
||||
* already a {@link CharBuffer}, this method is allocation free.
|
||||
@@ -413,6 +476,20 @@ public class FlatBufferBuilder {
|
||||
return endVector();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a byte array in the buffer.
|
||||
*
|
||||
* @param arr A source array with data
|
||||
* @return The offset in the buffer where the encoded array starts.
|
||||
*/
|
||||
public int createByteVector(byte[] arr) {
|
||||
int length = arr.length;
|
||||
startVector(1, length, 1);
|
||||
bb.position(space -= length);
|
||||
bb.put(arr);
|
||||
return endVector();
|
||||
}
|
||||
|
||||
/// @cond FLATBUFFERS_INTERNAL
|
||||
/**
|
||||
* Should not be accessing the final buffer before it is finished.
|
||||
|
||||
@@ -37,6 +37,12 @@ public class Table {
|
||||
return Charset.forName("UTF-8").newDecoder();
|
||||
}
|
||||
};
|
||||
public final static ThreadLocal<Charset> UTF8_CHARSET = new ThreadLocal<Charset>() {
|
||||
@Override
|
||||
protected Charset initialValue() {
|
||||
return Charset.forName("UTF-8");
|
||||
}
|
||||
};
|
||||
private final static ThreadLocal<CharBuffer> CHAR_BUFFER = new ThreadLocal<CharBuffer>();
|
||||
/** Used to hold the position of the `bb` buffer. */
|
||||
protected int bb_pos;
|
||||
@@ -61,6 +67,11 @@ public class Table {
|
||||
return vtable_offset < bb.getShort(vtable) ? bb.getShort(vtable + vtable_offset) : 0;
|
||||
}
|
||||
|
||||
protected static int __offset(int vtable_offset, int offset, ByteBuffer bb) {
|
||||
int vtable = bb.array().length - offset;
|
||||
return bb.getShort(vtable + vtable_offset - bb.getInt(vtable)) + vtable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a relative offset.
|
||||
*
|
||||
@@ -71,6 +82,10 @@ public class Table {
|
||||
return offset + bb.getInt(offset);
|
||||
}
|
||||
|
||||
protected static int __indirect(int offset, ByteBuffer bb) {
|
||||
return offset + bb.getInt(offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a Java `String` from UTF-8 data stored inside the FlatBuffer.
|
||||
*
|
||||
@@ -188,6 +203,76 @@ public class Table {
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sort tables by the key.
|
||||
*
|
||||
* @param offsets An 'int' indexes of the tables into the bb.
|
||||
* @param bb A {@code ByteBuffer} to get the tables.
|
||||
*/
|
||||
protected void sortTables(int[] offsets, final ByteBuffer bb) {
|
||||
Integer[] off = new Integer[offsets.length];
|
||||
for (int i = 0; i < offsets.length; i++) off[i] = offsets[i];
|
||||
java.util.Arrays.sort(off, new java.util.Comparator<Integer>() {
|
||||
public int compare(Integer o1, Integer o2) {
|
||||
return keysCompare(o1, o2, bb);
|
||||
}
|
||||
});
|
||||
for (int i = 0; i < offsets.length; i++) offsets[i] = off[i];
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare two tables by the key.
|
||||
*
|
||||
* @param o1 An 'Integer' index of the first key into the bb.
|
||||
* @param o2 An 'Integer' index of the second key into the bb.
|
||||
* @param bb A {@code ByteBuffer} to get the keys.
|
||||
*/
|
||||
protected int keysCompare(Integer o1, Integer o2, ByteBuffer bb) { return 0; }
|
||||
|
||||
/**
|
||||
* Compare two strings in the buffer.
|
||||
*
|
||||
* @param offset_1 An 'int' index of the first string into the bb.
|
||||
* @param offset_2 An 'int' index of the second string into the bb.
|
||||
* @param bb A {@code ByteBuffer} to get the strings.
|
||||
*/
|
||||
protected static int compareStrings(int offset_1, int offset_2, ByteBuffer bb) {
|
||||
offset_1 += bb.getInt(offset_1);
|
||||
offset_2 += bb.getInt(offset_2);
|
||||
int len_1 = bb.getInt(offset_1);
|
||||
int len_2 = bb.getInt(offset_2);
|
||||
int startPos_1 = offset_1 + SIZEOF_INT;
|
||||
int startPos_2 = offset_2 + SIZEOF_INT;
|
||||
int len = Math.min(len_1, len_2);
|
||||
byte[] bbArray = bb.array();
|
||||
for(int i = 0; i < len; i++) {
|
||||
if (bbArray[i + startPos_1] != bbArray[i + startPos_2])
|
||||
return bbArray[i + startPos_1] - bbArray[i + startPos_2];
|
||||
}
|
||||
return len_1 - len_2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare string from the buffer with the 'String' object.
|
||||
*
|
||||
* @param offset_1 An 'int' index of the first string into the bb.
|
||||
* @param key Second string as a byte array.
|
||||
* @param bb A {@code ByteBuffer} to get the first string.
|
||||
*/
|
||||
protected static int compareStrings(int offset_1, byte[] key, ByteBuffer bb) {
|
||||
offset_1 += bb.getInt(offset_1);
|
||||
int len_1 = bb.getInt(offset_1);
|
||||
int len_2 = key.length;
|
||||
int startPos_1 = offset_1 + Constants.SIZEOF_INT;
|
||||
int len = Math.min(len_1, len_2);
|
||||
byte[] bbArray = bb.array();
|
||||
for (int i = 0; i < len; i++) {
|
||||
if (bbArray[i + startPos_1] != key[i])
|
||||
return bbArray[i + startPos_1] - key[i];
|
||||
}
|
||||
return len_1 - len_2;
|
||||
}
|
||||
}
|
||||
|
||||
/// @endcond
|
||||
|
||||
@@ -2,6 +2,15 @@
|
||||
/// @addtogroup flatbuffers_javascript_api
|
||||
/// @{
|
||||
/// @cond FLATBUFFERS_INTERNAL
|
||||
|
||||
/**
|
||||
* @fileoverview
|
||||
*
|
||||
* Need to suppress 'global this' error so the Node.js export line doesn't cause
|
||||
* closure compile to error out.
|
||||
* @suppress {globalThis}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @const
|
||||
* @namespace
|
||||
@@ -75,8 +84,8 @@ flatbuffers.isLittleEndian = new Uint16Array(new Uint8Array([1, 0]).buffer)[0] =
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
* @param {number} high
|
||||
* @param {number} low
|
||||
* @param {number} high
|
||||
*/
|
||||
flatbuffers.Long = function(low, high) {
|
||||
/**
|
||||
@@ -93,8 +102,8 @@ flatbuffers.Long = function(low, high) {
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {number} high
|
||||
* @param {number} low
|
||||
* @param {number} high
|
||||
* @returns {flatbuffers.Long}
|
||||
*/
|
||||
flatbuffers.Long.create = function(low, high) {
|
||||
@@ -106,7 +115,7 @@ flatbuffers.Long.create = function(low, high) {
|
||||
* @returns {number}
|
||||
*/
|
||||
flatbuffers.Long.prototype.toFloat64 = function() {
|
||||
return this.low + this.high * 0x100000000;
|
||||
return (this.low >>> 0) + this.high * 0x100000000;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -129,11 +138,13 @@ flatbuffers.Long.ZERO = new flatbuffers.Long(0, 0);
|
||||
* Create a FlatBufferBuilder.
|
||||
*
|
||||
* @constructor
|
||||
* @param {number=} initial_size
|
||||
* @param {number=} opt_initial_size
|
||||
*/
|
||||
flatbuffers.Builder = function(initial_size) {
|
||||
if (!initial_size) {
|
||||
initial_size = 1024;
|
||||
flatbuffers.Builder = function(opt_initial_size) {
|
||||
if (!opt_initial_size) {
|
||||
var initial_size = 1024;
|
||||
} else {
|
||||
var initial_size = opt_initial_size;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -528,6 +539,10 @@ flatbuffers.Builder.prototype.offset = function() {
|
||||
* @param {flatbuffers.ByteBuffer} bb The current buffer with the existing data
|
||||
* @returns {flatbuffers.ByteBuffer} A new byte buffer with the old data copied
|
||||
* to it. The data is located at the end of the buffer.
|
||||
*
|
||||
* uint8Array.set() formally takes {Array<number>|ArrayBufferView}, so to pass
|
||||
* it a uint8Array we need to suppress the type check:
|
||||
* @suppress {checkTypes}
|
||||
*/
|
||||
flatbuffers.Builder.growByteBuffer = function(bb) {
|
||||
var old_buf_size = bb.capacity();
|
||||
@@ -642,10 +657,11 @@ outer_loop:
|
||||
* Finalize a buffer, poiting to the given `root_table`.
|
||||
*
|
||||
* @param {flatbuffers.Offset} root_table
|
||||
* @param {string=} file_identifier
|
||||
* @param {string=} opt_file_identifier
|
||||
*/
|
||||
flatbuffers.Builder.prototype.finish = function(root_table, file_identifier) {
|
||||
if (file_identifier) {
|
||||
flatbuffers.Builder.prototype.finish = function(root_table, opt_file_identifier) {
|
||||
if (opt_file_identifier) {
|
||||
var file_identifier = opt_file_identifier;
|
||||
this.prep(this.minalign, flatbuffers.SIZEOF_INT +
|
||||
flatbuffers.FILE_IDENTIFIER_LENGTH);
|
||||
if (file_identifier.length != flatbuffers.FILE_IDENTIFIER_LENGTH) {
|
||||
@@ -928,9 +944,17 @@ flatbuffers.ByteBuffer.prototype.readFloat64 = function(offset) {
|
||||
|
||||
/**
|
||||
* @param {number} offset
|
||||
* @param {number} value
|
||||
* @param {number|boolean} value
|
||||
*/
|
||||
flatbuffers.ByteBuffer.prototype.writeInt8 = function(offset, value) {
|
||||
this.bytes_[offset] = /** @type {number} */(value);
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {number} offset
|
||||
* @param {number} value
|
||||
*/
|
||||
flatbuffers.ByteBuffer.prototype.writeUint8 = function(offset, value) {
|
||||
this.bytes_[offset] = value;
|
||||
};
|
||||
|
||||
@@ -943,6 +967,15 @@ flatbuffers.ByteBuffer.prototype.writeInt16 = function(offset, value) {
|
||||
this.bytes_[offset + 1] = value >> 8;
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {number} offset
|
||||
* @param {number} value
|
||||
*/
|
||||
flatbuffers.ByteBuffer.prototype.writeUint16 = function(offset, value) {
|
||||
this.bytes_[offset] = value;
|
||||
this.bytes_[offset + 1] = value >> 8;
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {number} offset
|
||||
* @param {number} value
|
||||
@@ -954,6 +987,17 @@ flatbuffers.ByteBuffer.prototype.writeInt32 = function(offset, value) {
|
||||
this.bytes_[offset + 3] = value >> 24;
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {number} offset
|
||||
* @param {number} value
|
||||
*/
|
||||
flatbuffers.ByteBuffer.prototype.writeUint32 = function(offset, value) {
|
||||
this.bytes_[offset] = value;
|
||||
this.bytes_[offset + 1] = value >> 8;
|
||||
this.bytes_[offset + 2] = value >> 16;
|
||||
this.bytes_[offset + 3] = value >> 24;
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {number} offset
|
||||
* @param {flatbuffers.Long} value
|
||||
@@ -963,6 +1007,15 @@ flatbuffers.ByteBuffer.prototype.writeInt64 = function(offset, value) {
|
||||
this.writeInt32(offset + 4, value.high);
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {number} offset
|
||||
* @param {flatbuffers.Long} value
|
||||
*/
|
||||
flatbuffers.ByteBuffer.prototype.writeUint64 = function(offset, value) {
|
||||
this.writeUint32(offset, value.low);
|
||||
this.writeUint32(offset + 4, value.high);
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {number} offset
|
||||
* @param {number} value
|
||||
@@ -1018,10 +1071,10 @@ flatbuffers.ByteBuffer.prototype.__union = function(t, offset) {
|
||||
* FlatBuffer later on.
|
||||
*
|
||||
* @param {number} offset
|
||||
* @param {flatbuffers.Encoding=} optionalEncoding Defaults to UTF16_STRING
|
||||
* @param {flatbuffers.Encoding=} opt_encoding Defaults to UTF16_STRING
|
||||
* @returns {string|Uint8Array}
|
||||
*/
|
||||
flatbuffers.ByteBuffer.prototype.__string = function(offset, optionalEncoding) {
|
||||
flatbuffers.ByteBuffer.prototype.__string = function(offset, opt_encoding) {
|
||||
offset += this.readInt32(offset);
|
||||
|
||||
var length = this.readInt32(offset);
|
||||
@@ -1030,7 +1083,7 @@ flatbuffers.ByteBuffer.prototype.__string = function(offset, optionalEncoding) {
|
||||
|
||||
offset += flatbuffers.SIZEOF_INT;
|
||||
|
||||
if (optionalEncoding === flatbuffers.Encoding.UTF8_BYTES) {
|
||||
if (opt_encoding === flatbuffers.Encoding.UTF8_BYTES) {
|
||||
return this.bytes_.subarray(offset, offset + length);
|
||||
}
|
||||
|
||||
|
||||
@@ -14,7 +14,20 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
//#define UNSAFE_BYTEBUFFER // uncomment this line to use faster ByteBuffer
|
||||
// There are 2 #defines that have an impact on performance of this ByteBuffer implementation
|
||||
//
|
||||
// UNSAFE_BYTEBUFFER
|
||||
// This will use unsafe code to manipulate the underlying byte array. This
|
||||
// can yield a reasonable performance increase.
|
||||
//
|
||||
// BYTEBUFFER_NO_BOUNDS_CHECK
|
||||
// This will disable the bounds check asserts to the byte array. This can
|
||||
// yield a small performance gain in normal code..
|
||||
//
|
||||
// Using UNSAFE_BYTEBUFFER and BYTEBUFFER_NO_BOUNDS_CHECK together can yield a
|
||||
// performance gain of ~15% for some operations, however doing so is potentially
|
||||
// dangerous. Do so at your own risk!
|
||||
//
|
||||
|
||||
using System;
|
||||
|
||||
@@ -22,9 +35,6 @@ namespace FlatBuffers
|
||||
{
|
||||
/// <summary>
|
||||
/// Class to mimic Java's ByteBuffer which is used heavily in Flatbuffers.
|
||||
/// If your execution environment allows unsafe code, you should enable
|
||||
/// unsafe code in your project and #define UNSAFE_BYTEBUFFER to use a
|
||||
/// MUCH faster version of ByteBuffer.
|
||||
/// </summary>
|
||||
public class ByteBuffer
|
||||
{
|
||||
@@ -126,11 +136,14 @@ namespace FlatBuffers
|
||||
}
|
||||
#endif // !UNSAFE_BYTEBUFFER
|
||||
|
||||
|
||||
private void AssertOffsetAndLength(int offset, int length)
|
||||
{
|
||||
#if !BYTEBUFFER_NO_BOUNDS_CHECK
|
||||
if (offset < 0 ||
|
||||
offset > _buffer.Length - length)
|
||||
throw new ArgumentOutOfRangeException();
|
||||
#endif
|
||||
}
|
||||
|
||||
public void PutSbyte(int offset, sbyte value)
|
||||
@@ -200,7 +213,6 @@ namespace FlatBuffers
|
||||
public unsafe void PutUlong(int offset, ulong value)
|
||||
{
|
||||
AssertOffsetAndLength(offset, sizeof(ulong));
|
||||
|
||||
fixed (byte* ptr = _buffer)
|
||||
{
|
||||
*(ulong*)(ptr + offset) = BitConverter.IsLittleEndian
|
||||
|
||||
@@ -296,6 +296,18 @@ namespace FlatBuffers
|
||||
return new VectorOffset(Offset);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a vector of tables.
|
||||
/// </summary>
|
||||
/// <param name="offsets">Offsets of the tables.</param>
|
||||
public VectorOffset CreateVectorOfTables<T>(Offset<T>[] offsets) where T : struct
|
||||
{
|
||||
NotNested();
|
||||
StartVector(sizeof(int), offsets.Length, sizeof(int));
|
||||
for (int i = offsets.Length - 1; i >= 0; i--) AddOffset(offsets[i].Value);
|
||||
return EndVector();
|
||||
}
|
||||
|
||||
/// @cond FLATBUFFERS_INTENRAL
|
||||
public void Nested(int obj)
|
||||
{
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
<Compile Include="ByteBuffer.cs" />
|
||||
<Compile Include="FlatBufferBuilder.cs" />
|
||||
<Compile Include="FlatBufferConstants.cs" />
|
||||
<Compile Include="IFlatbufferObject.cs" />
|
||||
<Compile Include="Offset.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Struct.cs" />
|
||||
|
||||
28
net/FlatBuffers/IFlatbufferObject.cs
Normal file
28
net/FlatBuffers/IFlatbufferObject.cs
Normal file
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright 2014 Google Inc. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
namespace FlatBuffers
|
||||
{
|
||||
/// <summary>
|
||||
/// This is the base for both structs and tables.
|
||||
/// </summary>
|
||||
public interface IFlatbufferObject
|
||||
{
|
||||
void __init(int _i, ByteBuffer _bb);
|
||||
|
||||
ByteBuffer ByteBuffer { get; }
|
||||
}
|
||||
}
|
||||
@@ -19,7 +19,7 @@ namespace FlatBuffers
|
||||
/// <summary>
|
||||
/// Offset class for typesafe assignments.
|
||||
/// </summary>
|
||||
public struct Offset<T> where T : class
|
||||
public struct Offset<T> where T : struct
|
||||
{
|
||||
public int Value;
|
||||
public Offset(int value)
|
||||
|
||||
@@ -19,9 +19,9 @@ namespace FlatBuffers
|
||||
/// <summary>
|
||||
/// All structs in the generated code derive from this class, and add their own accessors.
|
||||
/// </summary>
|
||||
public abstract class Struct
|
||||
public struct Struct
|
||||
{
|
||||
protected int bb_pos;
|
||||
protected ByteBuffer bb;
|
||||
public int bb_pos;
|
||||
public ByteBuffer bb;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,31 +20,42 @@ using System.Text;
|
||||
namespace FlatBuffers
|
||||
{
|
||||
/// <summary>
|
||||
/// All tables in the generated code derive from this class, and add their own accessors.
|
||||
/// All tables in the generated code derive from this struct, and add their own accessors.
|
||||
/// </summary>
|
||||
public abstract class Table
|
||||
public struct Table
|
||||
{
|
||||
protected int bb_pos;
|
||||
protected ByteBuffer bb;
|
||||
public int bb_pos;
|
||||
public ByteBuffer bb;
|
||||
|
||||
public ByteBuffer ByteBuffer { get { return bb; } }
|
||||
|
||||
// Look up a field in the vtable, return an offset into the object, or 0 if the field is not
|
||||
// present.
|
||||
protected int __offset(int vtableOffset)
|
||||
public int __offset(int vtableOffset)
|
||||
{
|
||||
int vtable = bb_pos - bb.GetInt(bb_pos);
|
||||
return vtableOffset < bb.GetShort(vtable) ? (int)bb.GetShort(vtable + vtableOffset) : 0;
|
||||
}
|
||||
|
||||
public static int __offset(int vtableOffset, int offset, ByteBuffer bb)
|
||||
{
|
||||
int vtable = bb.Length - offset;
|
||||
return (int)bb.GetShort(vtable + vtableOffset - bb.GetInt(vtable)) + vtable;
|
||||
}
|
||||
|
||||
// Retrieve the relative offset stored at "offset"
|
||||
protected int __indirect(int offset)
|
||||
public int __indirect(int offset)
|
||||
{
|
||||
return offset + bb.GetInt(offset);
|
||||
}
|
||||
|
||||
public static int __indirect(int offset, ByteBuffer bb)
|
||||
{
|
||||
return offset + bb.GetInt(offset);
|
||||
}
|
||||
|
||||
// Create a .NET String from UTF-8 data stored inside the flatbuffer.
|
||||
protected string __string(int offset)
|
||||
public string __string(int offset)
|
||||
{
|
||||
offset += bb.GetInt(offset);
|
||||
var len = bb.GetInt(offset);
|
||||
@@ -53,7 +64,7 @@ namespace FlatBuffers
|
||||
}
|
||||
|
||||
// Get the length of a vector whose offset is stored at "offset" in this object.
|
||||
protected int __vector_len(int offset)
|
||||
public int __vector_len(int offset)
|
||||
{
|
||||
offset += bb_pos;
|
||||
offset += bb.GetInt(offset);
|
||||
@@ -61,7 +72,7 @@ namespace FlatBuffers
|
||||
}
|
||||
|
||||
// Get the start of data of a vector whose offset is stored at "offset" in this object.
|
||||
protected int __vector(int offset)
|
||||
public int __vector(int offset)
|
||||
{
|
||||
offset += bb_pos;
|
||||
return offset + bb.GetInt(offset) + sizeof(int); // data starts after the length
|
||||
@@ -70,7 +81,8 @@ namespace FlatBuffers
|
||||
// Get the data of a vector whoses offset is stored at "offset" in this object as an
|
||||
// ArraySegment<byte>. If the vector is not present in the ByteBuffer,
|
||||
// then a null value will be returned.
|
||||
protected ArraySegment<byte>? __vector_as_arraysegment(int offset) {
|
||||
public ArraySegment<byte>? __vector_as_arraysegment(int offset)
|
||||
{
|
||||
var o = this.__offset(offset);
|
||||
if (0 == o)
|
||||
{
|
||||
@@ -83,15 +95,15 @@ namespace FlatBuffers
|
||||
}
|
||||
|
||||
// Initialize any Table-derived type to point to the union at the given offset.
|
||||
protected TTable __union<TTable>(TTable t, int offset) where TTable : Table
|
||||
public T __union<T>(int offset) where T : struct, IFlatbufferObject
|
||||
{
|
||||
offset += bb_pos;
|
||||
t.bb_pos = offset + bb.GetInt(offset);
|
||||
t.bb = bb;
|
||||
T t = new T();
|
||||
t.__init(offset + bb.GetInt(offset), bb);
|
||||
return t;
|
||||
}
|
||||
|
||||
protected static bool __has_identifier(ByteBuffer bb, string ident)
|
||||
public static bool __has_identifier(ByteBuffer bb, string ident)
|
||||
{
|
||||
if (ident.Length != FlatBufferConstants.FileIdentifierLength)
|
||||
throw new ArgumentException("FlatBuffers: file identifier must be length " + FlatBufferConstants.FileIdentifierLength, "ident");
|
||||
@@ -104,6 +116,38 @@ namespace FlatBuffers
|
||||
return true;
|
||||
}
|
||||
|
||||
// Compare strings in the ByteBuffer.
|
||||
public static int CompareStrings(int offset_1, int offset_2, ByteBuffer bb)
|
||||
{
|
||||
offset_1 += bb.GetInt(offset_1);
|
||||
offset_2 += bb.GetInt(offset_2);
|
||||
var len_1 = bb.GetInt(offset_1);
|
||||
var len_2 = bb.GetInt(offset_2);
|
||||
var startPos_1 = offset_1 + sizeof(int);
|
||||
var startPos_2 = offset_2 + sizeof(int);
|
||||
var len = Math.Min(len_1, len_2);
|
||||
byte[] bbArray = bb.Data;
|
||||
for(int i = 0; i < len; i++) {
|
||||
if (bbArray[i + startPos_1] != bbArray[i + startPos_2])
|
||||
return bbArray[i + startPos_1] - bbArray[i + startPos_2];
|
||||
}
|
||||
return len_1 - len_2;
|
||||
}
|
||||
|
||||
// Compare string from the ByteBuffer with the string object
|
||||
public static int CompareStrings(int offset_1, byte[] key, ByteBuffer bb)
|
||||
{
|
||||
offset_1 += bb.GetInt(offset_1);
|
||||
var len_1 = bb.GetInt(offset_1);
|
||||
var len_2 = key.Length;
|
||||
var startPos_1 = offset_1 + sizeof(int);
|
||||
var len = Math.Min(len_1, len_2);
|
||||
byte[] bbArray = bb.Data;
|
||||
for (int i = 0; i < len; i++) {
|
||||
if (bbArray[i + startPos_1] != key[i])
|
||||
return bbArray[i + startPos_1] - key[i];
|
||||
}
|
||||
return len_1 - len_2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
27
package.json
Normal file
27
package.json
Normal file
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"name": "flatbuffers",
|
||||
"version": "1.7.0",
|
||||
"description": "Memory Efficient Serialization Library",
|
||||
"files": ["js/flatbuffers.js"],
|
||||
"main": "js/flatbuffers.js",
|
||||
"directories": {
|
||||
"doc": "docs",
|
||||
"test": "tests"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "tests/JavaScriptTest.sh"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/google/flatbuffers.git"
|
||||
},
|
||||
"keywords": [
|
||||
"flatbuffers"
|
||||
],
|
||||
"author": "The FlatBuffers project",
|
||||
"license": "SEE LICENSE IN LICENSE.txt",
|
||||
"bugs": {
|
||||
"url": "https://github.com/google/flatbuffers/issues"
|
||||
},
|
||||
"homepage": "https://google.github.io/flatbuffers/"
|
||||
}
|
||||
@@ -593,6 +593,10 @@ class FlatbufferBuilder
|
||||
|
||||
protected function is_utf8($bytes)
|
||||
{
|
||||
if (function_exists('mb_detect_encoding')) {
|
||||
return (bool) mb_detect_encoding($bytes, 'UTF-8', true);
|
||||
}
|
||||
|
||||
$len = strlen($bytes);
|
||||
if ($len < 1) {
|
||||
/* NOTE: always return 1 when passed string is null */
|
||||
|
||||
2
pom.xml
2
pom.xml
@@ -5,7 +5,7 @@
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>com.google.flatbuffers</groupId>
|
||||
<artifactId>flatbuffers-java</artifactId>
|
||||
<version>1.4.0-SNAPSHOT</version>
|
||||
<version>1.7.0-SNAPSHOT</version>
|
||||
<packaging>bundle</packaging>
|
||||
<name>FlatBuffers Java API</name>
|
||||
<description>
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
 FlatBuffers
|
||||
===========
|
||||
|
||||
[](https://gitter.im/google/flatbuffers?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||
[](https://travis-ci.org/google/flatbuffers) [](https://ci.appveyor.com/project/gwvo/flatbuffers)
|
||||
|
||||
**FlatBuffers** is an efficient cross platform serialization library for games and
|
||||
@@ -52,6 +54,6 @@ you would leave it in.
|
||||
[`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
|
||||
[stackoverflow.com]: http://www.stackoverflow.com
|
||||
[stackoverflow.com]: http://stackoverflow.com/search?q=flatbuffers
|
||||
[landing page]: http://google.github.io/flatbuffers
|
||||
[LICENSE]: https://github.com/google/flatbuffers/blob/master/LICENSE.txt
|
||||
|
||||
@@ -42,7 +42,8 @@ table KeyValue {
|
||||
table EnumVal {
|
||||
name:string (required);
|
||||
value:long (key);
|
||||
object:Object; // Only if part of a union.
|
||||
object:Object; // Will be deprecated in favor of union_type in the future.
|
||||
union_type:Type;
|
||||
}
|
||||
|
||||
table Enum {
|
||||
@@ -51,6 +52,7 @@ table Enum {
|
||||
is_union:bool = false;
|
||||
underlying_type:Type (required);
|
||||
attributes:[KeyValue];
|
||||
documentation:[string];
|
||||
}
|
||||
|
||||
table Field {
|
||||
@@ -64,6 +66,7 @@ table Field {
|
||||
required:bool = false;
|
||||
key:bool = false;
|
||||
attributes:[KeyValue];
|
||||
documentation:[string];
|
||||
}
|
||||
|
||||
table Object { // Used for both tables and structs.
|
||||
@@ -73,6 +76,7 @@ table Object { // Used for both tables and structs.
|
||||
minalign:int;
|
||||
bytesize:int; // For structs.
|
||||
attributes:[KeyValue];
|
||||
documentation:[string];
|
||||
}
|
||||
|
||||
table Schema {
|
||||
|
||||
@@ -81,22 +81,19 @@ class SampleBinary
|
||||
Assert(monster.Color == Color.Red, "monster.Color", Convert.ToString(monster.Color),
|
||||
Convert.ToString(Color.Red));
|
||||
|
||||
// C# also allows you to use performance-enhanced methods to fill an object that has already
|
||||
// been created. These functions are prefixed with "Get". For example: `monster.GetPos()`.
|
||||
var myAlreadyCreatedVector = new Vec3();
|
||||
monster.GetPos(myAlreadyCreatedVector); // Instead of `var myNewVec3 = monster.Pos`.
|
||||
Assert(myAlreadyCreatedVector.X == 1.0f, "myAlreadyCreatedVector.X",
|
||||
Convert.ToString(myAlreadyCreatedVector.X), Convert.ToString(1.0f));
|
||||
Assert(myAlreadyCreatedVector.Y == 2.0f, "myAlreadyCreatedVector.Y",
|
||||
Convert.ToString(myAlreadyCreatedVector.Y), Convert.ToString(2.0f));
|
||||
Assert(myAlreadyCreatedVector.Z == 3.0f, "myAlreadyCreatedVector.Z",
|
||||
Convert.ToString(myAlreadyCreatedVector.Z), Convert.ToString(3.0f));
|
||||
var vec = monster.Pos.Value;
|
||||
Assert(vec.X == 1.0f, "vec.X",
|
||||
Convert.ToString(vec.X), Convert.ToString(1.0f));
|
||||
Assert(vec.Y == 2.0f, "vec.Y",
|
||||
Convert.ToString(vec.Y), Convert.ToString(2.0f));
|
||||
Assert(vec.Z == 3.0f, "vec.Z",
|
||||
Convert.ToString(vec.Z), Convert.ToString(3.0f));
|
||||
|
||||
// Get and test the `Inventory` FlatBuffer `vector`.
|
||||
for (int i = 0; i < monster.InventoryLength; i++)
|
||||
{
|
||||
Assert(monster.GetInventory(i) == i, "monster.GetInventory",
|
||||
Convert.ToString(monster.GetInventory(i)), Convert.ToString(i));
|
||||
Assert(monster.Inventory(i) == i, "monster.Inventory",
|
||||
Convert.ToString(monster.Inventory(i)), Convert.ToString(i));
|
||||
}
|
||||
|
||||
// Get and test the `Weapons` FlatBuffer `vector` of `table`s.
|
||||
@@ -104,17 +101,17 @@ class SampleBinary
|
||||
var expectedWeaponDamages = new short[] {3, 5};
|
||||
for (int i = 0; i < monster.WeaponsLength; i++)
|
||||
{
|
||||
Assert(monster.GetWeapons(i).Name.Equals(expectedWeaponNames[i], StringComparison.Ordinal),
|
||||
"monster.GetWeapons", monster.GetWeapons(i).Name, expectedWeaponNames[i]);
|
||||
Assert(monster.GetWeapons(i).Damage == expectedWeaponDamages[i], "monster.GetWeapons",
|
||||
Convert.ToString(monster.GetWeapons(i).Damage),
|
||||
Assert(monster.Weapons(i).Value.Name.Equals(expectedWeaponNames[i], StringComparison.Ordinal),
|
||||
"monster.Weapons", monster.Weapons(i).Value.Name, expectedWeaponNames[i]);
|
||||
Assert(monster.Weapons(i).Value.Damage == expectedWeaponDamages[i], "monster.GetWeapons",
|
||||
Convert.ToString(monster.Weapons(i).Value.Damage),
|
||||
Convert.ToString(expectedWeaponDamages[i]));
|
||||
}
|
||||
|
||||
// Get and test the `Equipped` FlatBuffer `union`.
|
||||
Assert(monster.EquippedType == Equipment.Weapon, "monster.EquippedType",
|
||||
Convert.ToString(monster.EquippedType), Convert.ToString(Equipment.Weapon));
|
||||
var equipped = (Weapon)monster.GetEquipped(new Weapon());
|
||||
var equipped = monster.Equipped<Weapon>().Value;
|
||||
Assert(equipped.Name.Equals("Axe", StringComparison.Ordinal), "equipped.Name", equipped.Name,
|
||||
"Axe");
|
||||
Assert(equipped.Damage == 5, "equipped.Damage", Convert.ToString(equipped.Damage),
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
// automatically generated by the FlatBuffers compiler, do not modify
|
||||
|
||||
|
||||
#ifndef FLATBUFFERS_GENERATED_MONSTER_MYGAME_SAMPLE_H_
|
||||
#define FLATBUFFERS_GENERATED_MONSTER_MYGAME_SAMPLE_H_
|
||||
|
||||
@@ -24,12 +25,29 @@ enum Color {
|
||||
Color_MAX = Color_Blue
|
||||
};
|
||||
|
||||
inline Color (&EnumValuesColor())[3] {
|
||||
static Color values[] = {
|
||||
Color_Red,
|
||||
Color_Green,
|
||||
Color_Blue
|
||||
};
|
||||
return values;
|
||||
}
|
||||
|
||||
inline const char **EnumNamesColor() {
|
||||
static const char *names[] = { "Red", "Green", "Blue", nullptr };
|
||||
static const char *names[] = {
|
||||
"Red",
|
||||
"Green",
|
||||
"Blue",
|
||||
nullptr
|
||||
};
|
||||
return names;
|
||||
}
|
||||
|
||||
inline const char *EnumNameColor(Color e) { return EnumNamesColor()[static_cast<int>(e)]; }
|
||||
inline const char *EnumNameColor(Color e) {
|
||||
const size_t index = static_cast<int>(e);
|
||||
return EnumNamesColor()[index];
|
||||
}
|
||||
|
||||
enum Equipment {
|
||||
Equipment_NONE = 0,
|
||||
@@ -38,29 +56,73 @@ 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 Equipment (&EnumValuesEquipment())[2] {
|
||||
static Equipment values[] = {
|
||||
Equipment_NONE,
|
||||
Equipment_Weapon
|
||||
};
|
||||
return values;
|
||||
}
|
||||
|
||||
inline const char **EnumNamesEquipment() {
|
||||
static const char *names[] = { "NONE", "Weapon", nullptr };
|
||||
static const char *names[] = {
|
||||
"NONE",
|
||||
"Weapon",
|
||||
nullptr
|
||||
};
|
||||
return names;
|
||||
}
|
||||
|
||||
inline const char *EnumNameEquipment(Equipment e) { return EnumNamesEquipment()[static_cast<int>(e)]; }
|
||||
inline const char *EnumNameEquipment(Equipment e) {
|
||||
const size_t index = static_cast<int>(e);
|
||||
return EnumNamesEquipment()[index];
|
||||
}
|
||||
|
||||
inline bool VerifyEquipment(flatbuffers::Verifier &verifier, const void *union_obj, Equipment type);
|
||||
template<typename T> struct EquipmentTraits {
|
||||
static const Equipment enum_value = Equipment_NONE;
|
||||
};
|
||||
|
||||
template<> struct EquipmentTraits<Weapon> {
|
||||
static const Equipment enum_value = Equipment_Weapon;
|
||||
};
|
||||
|
||||
struct EquipmentUnion {
|
||||
Equipment type;
|
||||
void *value;
|
||||
|
||||
EquipmentUnion() : type(Equipment_NONE), value(nullptr) {}
|
||||
EquipmentUnion(EquipmentUnion&& u) FLATBUFFERS_NOEXCEPT :
|
||||
type(Equipment_NONE), value(nullptr)
|
||||
{ std::swap(type, u.type); std::swap(value, u.value); }
|
||||
EquipmentUnion(const EquipmentUnion &) FLATBUFFERS_NOEXCEPT;
|
||||
EquipmentUnion &operator=(const EquipmentUnion &u) FLATBUFFERS_NOEXCEPT
|
||||
{ EquipmentUnion t(u); std::swap(type, t.type); std::swap(value, t.value); return *this; }
|
||||
EquipmentUnion &operator=(EquipmentUnion &&u) FLATBUFFERS_NOEXCEPT
|
||||
{ std::swap(type, u.type); std::swap(value, u.value); return *this; }
|
||||
~EquipmentUnion() { Reset(); }
|
||||
|
||||
void Reset();
|
||||
|
||||
template <typename T>
|
||||
void Set(T&& val) {
|
||||
Reset();
|
||||
type = EquipmentTraits<typename T::TableType>::enum_value;
|
||||
if (type != Equipment_NONE) {
|
||||
value = new T(std::forward<T>(val));
|
||||
}
|
||||
}
|
||||
|
||||
static void *UnPack(const void *obj, Equipment type, const flatbuffers::resolver_function_t *resolver);
|
||||
flatbuffers::Offset<void> Pack(flatbuffers::FlatBufferBuilder &_fbb, const flatbuffers::rehasher_function_t *_rehasher = nullptr) const;
|
||||
|
||||
WeaponT *AsWeapon() {
|
||||
return type == Equipment_Weapon ?
|
||||
reinterpret_cast<WeaponT *>(value) : nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
bool VerifyEquipment(flatbuffers::Verifier &verifier, const void *obj, Equipment type);
|
||||
bool VerifyEquipmentVector(flatbuffers::Verifier &verifier, const flatbuffers::Vector<flatbuffers::Offset<void>> *values, const flatbuffers::Vector<uint8_t> *types);
|
||||
|
||||
MANUALLY_ALIGNED_STRUCT(4) Vec3 FLATBUFFERS_FINAL_CLASS {
|
||||
private:
|
||||
@@ -69,21 +131,40 @@ 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() {
|
||||
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)) { }
|
||||
|
||||
float x() const { return flatbuffers::EndianScalar(x_); }
|
||||
void mutate_x(float _x) { flatbuffers::WriteScalar(&x_, _x); }
|
||||
float y() const { return flatbuffers::EndianScalar(y_); }
|
||||
void mutate_y(float _y) { flatbuffers::WriteScalar(&y_, _y); }
|
||||
float z() const { return flatbuffers::EndianScalar(z_); }
|
||||
void mutate_z(float _z) { flatbuffers::WriteScalar(&z_, _z); }
|
||||
: x_(flatbuffers::EndianScalar(_x)),
|
||||
y_(flatbuffers::EndianScalar(_y)),
|
||||
z_(flatbuffers::EndianScalar(_z)) {
|
||||
}
|
||||
float x() const {
|
||||
return flatbuffers::EndianScalar(x_);
|
||||
}
|
||||
void mutate_x(float _x) {
|
||||
flatbuffers::WriteScalar(&x_, _x);
|
||||
}
|
||||
float y() const {
|
||||
return flatbuffers::EndianScalar(y_);
|
||||
}
|
||||
void mutate_y(float _y) {
|
||||
flatbuffers::WriteScalar(&y_, _y);
|
||||
}
|
||||
float z() const {
|
||||
return flatbuffers::EndianScalar(z_);
|
||||
}
|
||||
void mutate_z(float _z) {
|
||||
flatbuffers::WriteScalar(&z_, _z);
|
||||
}
|
||||
};
|
||||
STRUCT_END(Vec3, 12);
|
||||
|
||||
struct MonsterT : public flatbuffers::NativeTable {
|
||||
typedef Monster TableType;
|
||||
std::unique_ptr<Vec3> pos;
|
||||
int16_t mana;
|
||||
int16_t hp;
|
||||
@@ -92,9 +173,15 @@ struct MonsterT : public flatbuffers::NativeTable {
|
||||
Color color;
|
||||
std::vector<std::unique_ptr<WeaponT>> weapons;
|
||||
EquipmentUnion equipped;
|
||||
MonsterT()
|
||||
: mana(150),
|
||||
hp(100),
|
||||
color(Color_Blue) {
|
||||
}
|
||||
};
|
||||
|
||||
struct Monster FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
|
||||
typedef MonsterT NativeTableType;
|
||||
enum {
|
||||
VT_POS = 4,
|
||||
VT_MANA = 6,
|
||||
@@ -106,66 +193,135 @@ struct Monster FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
|
||||
VT_EQUIPPED_TYPE = 20,
|
||||
VT_EQUIPPED = 22
|
||||
};
|
||||
const Vec3 *pos() const { return GetStruct<const Vec3 *>(VT_POS); }
|
||||
Vec3 *mutable_pos() { return GetStruct<Vec3 *>(VT_POS); }
|
||||
int16_t mana() const { return GetField<int16_t>(VT_MANA, 150); }
|
||||
bool mutate_mana(int16_t _mana) { return SetField(VT_MANA, _mana); }
|
||||
int16_t hp() const { return GetField<int16_t>(VT_HP, 100); }
|
||||
bool mutate_hp(int16_t _hp) { return SetField(VT_HP, _hp); }
|
||||
const flatbuffers::String *name() const { return GetPointer<const flatbuffers::String *>(VT_NAME); }
|
||||
flatbuffers::String *mutable_name() { return GetPointer<flatbuffers::String *>(VT_NAME); }
|
||||
const flatbuffers::Vector<uint8_t> *inventory() const { return GetPointer<const flatbuffers::Vector<uint8_t> *>(VT_INVENTORY); }
|
||||
flatbuffers::Vector<uint8_t> *mutable_inventory() { return GetPointer<flatbuffers::Vector<uint8_t> *>(VT_INVENTORY); }
|
||||
Color color() const { return static_cast<Color>(GetField<int8_t>(VT_COLOR, 2)); }
|
||||
bool mutate_color(Color _color) { return SetField(VT_COLOR, static_cast<int8_t>(_color)); }
|
||||
const flatbuffers::Vector<flatbuffers::Offset<Weapon>> *weapons() const { return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<Weapon>> *>(VT_WEAPONS); }
|
||||
flatbuffers::Vector<flatbuffers::Offset<Weapon>> *mutable_weapons() { return GetPointer<flatbuffers::Vector<flatbuffers::Offset<Weapon>> *>(VT_WEAPONS); }
|
||||
Equipment equipped_type() const { return static_cast<Equipment>(GetField<uint8_t>(VT_EQUIPPED_TYPE, 0)); }
|
||||
bool mutate_equipped_type(Equipment _equipped_type) { return SetField(VT_EQUIPPED_TYPE, static_cast<uint8_t>(_equipped_type)); }
|
||||
const void *equipped() const { return GetPointer<const void *>(VT_EQUIPPED); }
|
||||
void *mutable_equipped() { return GetPointer<void *>(VT_EQUIPPED); }
|
||||
const Vec3 *pos() const {
|
||||
return GetStruct<const Vec3 *>(VT_POS);
|
||||
}
|
||||
Vec3 *mutable_pos() {
|
||||
return GetStruct<Vec3 *>(VT_POS);
|
||||
}
|
||||
int16_t mana() const {
|
||||
return GetField<int16_t>(VT_MANA, 150);
|
||||
}
|
||||
bool mutate_mana(int16_t _mana) {
|
||||
return SetField<int16_t>(VT_MANA, _mana, 150);
|
||||
}
|
||||
int16_t hp() const {
|
||||
return GetField<int16_t>(VT_HP, 100);
|
||||
}
|
||||
bool mutate_hp(int16_t _hp) {
|
||||
return SetField<int16_t>(VT_HP, _hp, 100);
|
||||
}
|
||||
const flatbuffers::String *name() const {
|
||||
return GetPointer<const flatbuffers::String *>(VT_NAME);
|
||||
}
|
||||
flatbuffers::String *mutable_name() {
|
||||
return GetPointer<flatbuffers::String *>(VT_NAME);
|
||||
}
|
||||
const flatbuffers::Vector<uint8_t> *inventory() const {
|
||||
return GetPointer<const flatbuffers::Vector<uint8_t> *>(VT_INVENTORY);
|
||||
}
|
||||
flatbuffers::Vector<uint8_t> *mutable_inventory() {
|
||||
return GetPointer<flatbuffers::Vector<uint8_t> *>(VT_INVENTORY);
|
||||
}
|
||||
Color color() const {
|
||||
return static_cast<Color>(GetField<int8_t>(VT_COLOR, 2));
|
||||
}
|
||||
bool mutate_color(Color _color) {
|
||||
return SetField<int8_t>(VT_COLOR, static_cast<int8_t>(_color), 2);
|
||||
}
|
||||
const flatbuffers::Vector<flatbuffers::Offset<Weapon>> *weapons() const {
|
||||
return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<Weapon>> *>(VT_WEAPONS);
|
||||
}
|
||||
flatbuffers::Vector<flatbuffers::Offset<Weapon>> *mutable_weapons() {
|
||||
return GetPointer<flatbuffers::Vector<flatbuffers::Offset<Weapon>> *>(VT_WEAPONS);
|
||||
}
|
||||
Equipment equipped_type() const {
|
||||
return static_cast<Equipment>(GetField<uint8_t>(VT_EQUIPPED_TYPE, 0));
|
||||
}
|
||||
bool mutate_equipped_type(Equipment _equipped_type) {
|
||||
return SetField<uint8_t>(VT_EQUIPPED_TYPE, static_cast<uint8_t>(_equipped_type), 0);
|
||||
}
|
||||
const void *equipped() const {
|
||||
return GetPointer<const void *>(VT_EQUIPPED);
|
||||
}
|
||||
template<typename T> const T *equipped_as() const;
|
||||
const Weapon *equipped_as_Weapon() const {
|
||||
return equipped_type() == Equipment_Weapon ? static_cast<const Weapon *>(equipped()) : nullptr;
|
||||
}
|
||||
void *mutable_equipped() {
|
||||
return GetPointer<void *>(VT_EQUIPPED);
|
||||
}
|
||||
bool Verify(flatbuffers::Verifier &verifier) const {
|
||||
return VerifyTableStart(verifier) &&
|
||||
VerifyField<Vec3>(verifier, VT_POS) &&
|
||||
VerifyField<int16_t>(verifier, VT_MANA) &&
|
||||
VerifyField<int16_t>(verifier, VT_HP) &&
|
||||
VerifyField<flatbuffers::uoffset_t>(verifier, VT_NAME) &&
|
||||
VerifyOffset(verifier, VT_NAME) &&
|
||||
verifier.Verify(name()) &&
|
||||
VerifyField<flatbuffers::uoffset_t>(verifier, VT_INVENTORY) &&
|
||||
VerifyOffset(verifier, VT_INVENTORY) &&
|
||||
verifier.Verify(inventory()) &&
|
||||
VerifyField<int8_t>(verifier, VT_COLOR) &&
|
||||
VerifyField<flatbuffers::uoffset_t>(verifier, VT_WEAPONS) &&
|
||||
VerifyOffset(verifier, VT_WEAPONS) &&
|
||||
verifier.Verify(weapons()) &&
|
||||
verifier.VerifyVectorOfTables(weapons()) &&
|
||||
VerifyField<uint8_t>(verifier, VT_EQUIPPED_TYPE) &&
|
||||
VerifyField<flatbuffers::uoffset_t>(verifier, VT_EQUIPPED) &&
|
||||
VerifyOffset(verifier, VT_EQUIPPED) &&
|
||||
VerifyEquipment(verifier, equipped(), equipped_type()) &&
|
||||
verifier.EndTable();
|
||||
}
|
||||
std::unique_ptr<MonsterT> UnPack() const;
|
||||
MonsterT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const;
|
||||
void UnPackTo(MonsterT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const;
|
||||
static flatbuffers::Offset<Monster> Pack(flatbuffers::FlatBufferBuilder &_fbb, const MonsterT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr);
|
||||
};
|
||||
|
||||
template<> inline const Weapon *Monster::equipped_as<Weapon>() const {
|
||||
return equipped_as_Weapon();
|
||||
}
|
||||
|
||||
struct MonsterBuilder {
|
||||
flatbuffers::FlatBufferBuilder &fbb_;
|
||||
flatbuffers::uoffset_t start_;
|
||||
void add_pos(const Vec3 *pos) { fbb_.AddStruct(Monster::VT_POS, pos); }
|
||||
void add_mana(int16_t mana) { fbb_.AddElement<int16_t>(Monster::VT_MANA, mana, 150); }
|
||||
void add_hp(int16_t hp) { fbb_.AddElement<int16_t>(Monster::VT_HP, hp, 100); }
|
||||
void add_name(flatbuffers::Offset<flatbuffers::String> name) { fbb_.AddOffset(Monster::VT_NAME, name); }
|
||||
void add_inventory(flatbuffers::Offset<flatbuffers::Vector<uint8_t>> inventory) { fbb_.AddOffset(Monster::VT_INVENTORY, inventory); }
|
||||
void add_color(Color color) { fbb_.AddElement<int8_t>(Monster::VT_COLOR, static_cast<int8_t>(color), 2); }
|
||||
void add_weapons(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<Weapon>>> weapons) { fbb_.AddOffset(Monster::VT_WEAPONS, weapons); }
|
||||
void add_equipped_type(Equipment equipped_type) { fbb_.AddElement<uint8_t>(Monster::VT_EQUIPPED_TYPE, static_cast<uint8_t>(equipped_type), 0); }
|
||||
void add_equipped(flatbuffers::Offset<void> equipped) { fbb_.AddOffset(Monster::VT_EQUIPPED, equipped); }
|
||||
MonsterBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) { start_ = fbb_.StartTable(); }
|
||||
void add_pos(const Vec3 *pos) {
|
||||
fbb_.AddStruct(Monster::VT_POS, pos);
|
||||
}
|
||||
void add_mana(int16_t mana) {
|
||||
fbb_.AddElement<int16_t>(Monster::VT_MANA, mana, 150);
|
||||
}
|
||||
void add_hp(int16_t hp) {
|
||||
fbb_.AddElement<int16_t>(Monster::VT_HP, hp, 100);
|
||||
}
|
||||
void add_name(flatbuffers::Offset<flatbuffers::String> name) {
|
||||
fbb_.AddOffset(Monster::VT_NAME, name);
|
||||
}
|
||||
void add_inventory(flatbuffers::Offset<flatbuffers::Vector<uint8_t>> inventory) {
|
||||
fbb_.AddOffset(Monster::VT_INVENTORY, inventory);
|
||||
}
|
||||
void add_color(Color color) {
|
||||
fbb_.AddElement<int8_t>(Monster::VT_COLOR, static_cast<int8_t>(color), 2);
|
||||
}
|
||||
void add_weapons(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<Weapon>>> weapons) {
|
||||
fbb_.AddOffset(Monster::VT_WEAPONS, weapons);
|
||||
}
|
||||
void add_equipped_type(Equipment equipped_type) {
|
||||
fbb_.AddElement<uint8_t>(Monster::VT_EQUIPPED_TYPE, static_cast<uint8_t>(equipped_type), 0);
|
||||
}
|
||||
void add_equipped(flatbuffers::Offset<void> equipped) {
|
||||
fbb_.AddOffset(Monster::VT_EQUIPPED, equipped);
|
||||
}
|
||||
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_, 10));
|
||||
const auto end = fbb_.EndTable(start_, 10);
|
||||
auto o = flatbuffers::Offset<Monster>(end);
|
||||
return o;
|
||||
}
|
||||
};
|
||||
|
||||
inline flatbuffers::Offset<Monster> CreateMonster(flatbuffers::FlatBufferBuilder &_fbb,
|
||||
inline flatbuffers::Offset<Monster> CreateMonster(
|
||||
flatbuffers::FlatBufferBuilder &_fbb,
|
||||
const Vec3 *pos = 0,
|
||||
int16_t mana = 150,
|
||||
int16_t hp = 100,
|
||||
@@ -188,7 +344,8 @@ inline flatbuffers::Offset<Monster> CreateMonster(flatbuffers::FlatBufferBuilder
|
||||
return builder_.Finish();
|
||||
}
|
||||
|
||||
inline flatbuffers::Offset<Monster> CreateMonsterDirect(flatbuffers::FlatBufferBuilder &_fbb,
|
||||
inline flatbuffers::Offset<Monster> CreateMonsterDirect(
|
||||
flatbuffers::FlatBufferBuilder &_fbb,
|
||||
const Vec3 *pos = 0,
|
||||
int16_t mana = 150,
|
||||
int16_t hp = 100,
|
||||
@@ -198,49 +355,83 @@ inline flatbuffers::Offset<Monster> CreateMonsterDirect(flatbuffers::FlatBufferB
|
||||
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 ? _fbb.CreateString(name) : 0, inventory ? _fbb.CreateVector<uint8_t>(*inventory) : 0, color, weapons ? _fbb.CreateVector<flatbuffers::Offset<Weapon>>(*weapons) : 0, equipped_type, equipped);
|
||||
return MyGame::Sample::CreateMonster(
|
||||
_fbb,
|
||||
pos,
|
||||
mana,
|
||||
hp,
|
||||
name ? _fbb.CreateString(name) : 0,
|
||||
inventory ? _fbb.CreateVector<uint8_t>(*inventory) : 0,
|
||||
color,
|
||||
weapons ? _fbb.CreateVector<flatbuffers::Offset<Weapon>>(*weapons) : 0,
|
||||
equipped_type,
|
||||
equipped);
|
||||
}
|
||||
|
||||
inline flatbuffers::Offset<Monster> CreateMonster(flatbuffers::FlatBufferBuilder &_fbb, const MonsterT *_o);
|
||||
flatbuffers::Offset<Monster> CreateMonster(flatbuffers::FlatBufferBuilder &_fbb, const MonsterT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr);
|
||||
|
||||
struct WeaponT : public flatbuffers::NativeTable {
|
||||
typedef Weapon TableType;
|
||||
std::string name;
|
||||
int16_t damage;
|
||||
WeaponT()
|
||||
: damage(0) {
|
||||
}
|
||||
};
|
||||
|
||||
struct Weapon FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
|
||||
typedef WeaponT NativeTableType;
|
||||
enum {
|
||||
VT_NAME = 4,
|
||||
VT_DAMAGE = 6
|
||||
};
|
||||
const flatbuffers::String *name() const { return GetPointer<const flatbuffers::String *>(VT_NAME); }
|
||||
flatbuffers::String *mutable_name() { return GetPointer<flatbuffers::String *>(VT_NAME); }
|
||||
int16_t damage() const { return GetField<int16_t>(VT_DAMAGE, 0); }
|
||||
bool mutate_damage(int16_t _damage) { return SetField(VT_DAMAGE, _damage); }
|
||||
const flatbuffers::String *name() const {
|
||||
return GetPointer<const flatbuffers::String *>(VT_NAME);
|
||||
}
|
||||
flatbuffers::String *mutable_name() {
|
||||
return GetPointer<flatbuffers::String *>(VT_NAME);
|
||||
}
|
||||
int16_t damage() const {
|
||||
return GetField<int16_t>(VT_DAMAGE, 0);
|
||||
}
|
||||
bool mutate_damage(int16_t _damage) {
|
||||
return SetField<int16_t>(VT_DAMAGE, _damage, 0);
|
||||
}
|
||||
bool Verify(flatbuffers::Verifier &verifier) const {
|
||||
return VerifyTableStart(verifier) &&
|
||||
VerifyField<flatbuffers::uoffset_t>(verifier, VT_NAME) &&
|
||||
VerifyOffset(verifier, VT_NAME) &&
|
||||
verifier.Verify(name()) &&
|
||||
VerifyField<int16_t>(verifier, VT_DAMAGE) &&
|
||||
verifier.EndTable();
|
||||
}
|
||||
std::unique_ptr<WeaponT> UnPack() const;
|
||||
WeaponT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const;
|
||||
void UnPackTo(WeaponT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const;
|
||||
static flatbuffers::Offset<Weapon> Pack(flatbuffers::FlatBufferBuilder &_fbb, const WeaponT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr);
|
||||
};
|
||||
|
||||
struct WeaponBuilder {
|
||||
flatbuffers::FlatBufferBuilder &fbb_;
|
||||
flatbuffers::uoffset_t start_;
|
||||
void add_name(flatbuffers::Offset<flatbuffers::String> name) { fbb_.AddOffset(Weapon::VT_NAME, name); }
|
||||
void add_damage(int16_t damage) { fbb_.AddElement<int16_t>(Weapon::VT_DAMAGE, damage, 0); }
|
||||
WeaponBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) { start_ = fbb_.StartTable(); }
|
||||
void add_name(flatbuffers::Offset<flatbuffers::String> name) {
|
||||
fbb_.AddOffset(Weapon::VT_NAME, name);
|
||||
}
|
||||
void add_damage(int16_t damage) {
|
||||
fbb_.AddElement<int16_t>(Weapon::VT_DAMAGE, damage, 0);
|
||||
}
|
||||
WeaponBuilder(flatbuffers::FlatBufferBuilder &_fbb)
|
||||
: fbb_(_fbb) {
|
||||
start_ = fbb_.StartTable();
|
||||
}
|
||||
WeaponBuilder &operator=(const WeaponBuilder &);
|
||||
flatbuffers::Offset<Weapon> Finish() {
|
||||
auto o = flatbuffers::Offset<Weapon>(fbb_.EndTable(start_, 2));
|
||||
const auto end = fbb_.EndTable(start_, 2);
|
||||
auto o = flatbuffers::Offset<Weapon>(end);
|
||||
return o;
|
||||
}
|
||||
};
|
||||
|
||||
inline flatbuffers::Offset<Weapon> CreateWeapon(flatbuffers::FlatBufferBuilder &_fbb,
|
||||
inline flatbuffers::Offset<Weapon> CreateWeapon(
|
||||
flatbuffers::FlatBufferBuilder &_fbb,
|
||||
flatbuffers::Offset<flatbuffers::String> name = 0,
|
||||
int16_t damage = 0) {
|
||||
WeaponBuilder builder_(_fbb);
|
||||
@@ -249,92 +440,187 @@ inline flatbuffers::Offset<Weapon> CreateWeapon(flatbuffers::FlatBufferBuilder &
|
||||
return builder_.Finish();
|
||||
}
|
||||
|
||||
inline flatbuffers::Offset<Weapon> CreateWeaponDirect(flatbuffers::FlatBufferBuilder &_fbb,
|
||||
inline flatbuffers::Offset<Weapon> CreateWeaponDirect(
|
||||
flatbuffers::FlatBufferBuilder &_fbb,
|
||||
const char *name = nullptr,
|
||||
int16_t damage = 0) {
|
||||
return CreateWeapon(_fbb, name ? _fbb.CreateString(name) : 0, damage);
|
||||
return MyGame::Sample::CreateWeapon(
|
||||
_fbb,
|
||||
name ? _fbb.CreateString(name) : 0,
|
||||
damage);
|
||||
}
|
||||
|
||||
inline flatbuffers::Offset<Weapon> CreateWeapon(flatbuffers::FlatBufferBuilder &_fbb, const WeaponT *_o);
|
||||
flatbuffers::Offset<Weapon> CreateWeapon(flatbuffers::FlatBufferBuilder &_fbb, const WeaponT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr);
|
||||
|
||||
inline std::unique_ptr<MonsterT> Monster::UnPack() const {
|
||||
inline MonsterT *Monster::UnPack(const flatbuffers::resolver_function_t *_resolver) const {
|
||||
auto _o = new MonsterT();
|
||||
UnPackTo(_o, _resolver);
|
||||
return _o;
|
||||
}
|
||||
|
||||
inline void Monster::UnPackTo(MonsterT *_o, const flatbuffers::resolver_function_t *_resolver) const {
|
||||
(void)_o;
|
||||
(void)_resolver;
|
||||
{ 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 = inventory(); if (_e) { _o->inventory.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->inventory[_i] = _e->Get(_i); } } };
|
||||
{ auto _e = color(); _o->color = _e; };
|
||||
{ auto _e = weapons(); if (_e) { for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->weapons.push_back(_e->Get(_i)->UnPack()); } } };
|
||||
{ auto _e = weapons(); if (_e) { _o->weapons.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->weapons[_i] = std::unique_ptr<WeaponT>(_e->Get(_i)->UnPack(_resolver)); } } };
|
||||
{ auto _e = equipped_type(); _o->equipped.type = _e; };
|
||||
{ auto _e = equipped(); if (_e) _o->equipped.table = EquipmentUnion::UnPack(_e, equipped_type()); };
|
||||
return std::unique_ptr<MonsterT>(_o);
|
||||
{ auto _e = equipped(); if (_e) _o->equipped.value = EquipmentUnion::UnPack(_e, equipped_type(), _resolver); };
|
||||
}
|
||||
|
||||
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 flatbuffers::Offset<Monster> Monster::Pack(flatbuffers::FlatBufferBuilder &_fbb, const MonsterT* _o, const flatbuffers::rehasher_function_t *_rehasher) {
|
||||
return CreateMonster(_fbb, _o, _rehasher);
|
||||
}
|
||||
|
||||
inline std::unique_ptr<WeaponT> Weapon::UnPack() const {
|
||||
inline flatbuffers::Offset<Monster> CreateMonster(flatbuffers::FlatBufferBuilder &_fbb, const MonsterT *_o, const flatbuffers::rehasher_function_t *_rehasher) {
|
||||
(void)_rehasher;
|
||||
(void)_o;
|
||||
auto _pos = _o->pos ? _o->pos.get() : 0;
|
||||
auto _mana = _o->mana;
|
||||
auto _hp = _o->hp;
|
||||
auto _name = _o->name.size() ? _fbb.CreateString(_o->name) : 0;
|
||||
auto _inventory = _o->inventory.size() ? _fbb.CreateVector(_o->inventory) : 0;
|
||||
auto _color = _o->color;
|
||||
auto _weapons = _o->weapons.size() ? _fbb.CreateVector<flatbuffers::Offset<Weapon>>(_o->weapons.size(), [&](size_t i) { return CreateWeapon(_fbb, _o->weapons[i].get(), _rehasher); }) : 0;
|
||||
auto _equipped_type = _o->equipped.type;
|
||||
auto _equipped = _o->equipped.Pack(_fbb);
|
||||
return MyGame::Sample::CreateMonster(
|
||||
_fbb,
|
||||
_pos,
|
||||
_mana,
|
||||
_hp,
|
||||
_name,
|
||||
_inventory,
|
||||
_color,
|
||||
_weapons,
|
||||
_equipped_type,
|
||||
_equipped);
|
||||
}
|
||||
|
||||
inline WeaponT *Weapon::UnPack(const flatbuffers::resolver_function_t *_resolver) const {
|
||||
auto _o = new WeaponT();
|
||||
UnPackTo(_o, _resolver);
|
||||
return _o;
|
||||
}
|
||||
|
||||
inline void Weapon::UnPackTo(WeaponT *_o, const flatbuffers::resolver_function_t *_resolver) const {
|
||||
(void)_o;
|
||||
(void)_resolver;
|
||||
{ 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 flatbuffers::Offset<Weapon> Weapon::Pack(flatbuffers::FlatBufferBuilder &_fbb, const WeaponT* _o, const flatbuffers::rehasher_function_t *_rehasher) {
|
||||
return CreateWeapon(_fbb, _o, _rehasher);
|
||||
}
|
||||
|
||||
inline bool VerifyEquipment(flatbuffers::Verifier &verifier, const void *union_obj, Equipment type) {
|
||||
inline flatbuffers::Offset<Weapon> CreateWeapon(flatbuffers::FlatBufferBuilder &_fbb, const WeaponT *_o, const flatbuffers::rehasher_function_t *_rehasher) {
|
||||
(void)_rehasher;
|
||||
(void)_o;
|
||||
auto _name = _o->name.size() ? _fbb.CreateString(_o->name) : 0;
|
||||
auto _damage = _o->damage;
|
||||
return MyGame::Sample::CreateWeapon(
|
||||
_fbb,
|
||||
_name,
|
||||
_damage);
|
||||
}
|
||||
|
||||
inline bool VerifyEquipment(flatbuffers::Verifier &verifier, const void *obj, Equipment type) {
|
||||
switch (type) {
|
||||
case Equipment_NONE: return true;
|
||||
case Equipment_Weapon: return verifier.VerifyTable(reinterpret_cast<const Weapon *>(union_obj));
|
||||
case Equipment_NONE: {
|
||||
return true;
|
||||
}
|
||||
case Equipment_Weapon: {
|
||||
auto ptr = reinterpret_cast<const Weapon *>(obj);
|
||||
return verifier.VerifyTable(ptr);
|
||||
}
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
|
||||
inline flatbuffers::NativeTable *EquipmentUnion::UnPack(const void *union_obj, Equipment type) {
|
||||
inline bool VerifyEquipmentVector(flatbuffers::Verifier &verifier, const flatbuffers::Vector<flatbuffers::Offset<void>> *values, const flatbuffers::Vector<uint8_t> *types) {
|
||||
if (values->size() != types->size()) return false;
|
||||
for (flatbuffers::uoffset_t i = 0; i < values->size(); ++i) {
|
||||
if (!VerifyEquipment(
|
||||
verifier, values->Get(i), types->GetEnum<Equipment>(i))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
inline void *EquipmentUnion::UnPack(const void *obj, Equipment type, const flatbuffers::resolver_function_t *resolver) {
|
||||
switch (type) {
|
||||
case Equipment_NONE: return nullptr;
|
||||
case Equipment_Weapon: return reinterpret_cast<const Weapon *>(union_obj)->UnPack().release();
|
||||
case Equipment_Weapon: {
|
||||
auto ptr = reinterpret_cast<const Weapon *>(obj);
|
||||
return ptr->UnPack(resolver);
|
||||
}
|
||||
default: return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
inline flatbuffers::Offset<void> EquipmentUnion::Pack(flatbuffers::FlatBufferBuilder &_fbb) const {
|
||||
inline flatbuffers::Offset<void> EquipmentUnion::Pack(flatbuffers::FlatBufferBuilder &_fbb, const flatbuffers::rehasher_function_t *_rehasher) const {
|
||||
switch (type) {
|
||||
case Equipment_NONE: return 0;
|
||||
case Equipment_Weapon: return CreateWeapon(_fbb, reinterpret_cast<const WeaponT *>(table)).Union();
|
||||
case Equipment_Weapon: {
|
||||
auto ptr = reinterpret_cast<const WeaponT *>(value);
|
||||
return CreateWeapon(_fbb, ptr, _rehasher).Union();
|
||||
}
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
inline EquipmentUnion::~EquipmentUnion() {
|
||||
inline EquipmentUnion::EquipmentUnion(const EquipmentUnion &u) FLATBUFFERS_NOEXCEPT : type(u.type), value(nullptr) {
|
||||
switch (type) {
|
||||
case Equipment_Weapon: delete reinterpret_cast<WeaponT *>(table); break;
|
||||
default:;
|
||||
case Equipment_Weapon: {
|
||||
value = new WeaponT(*reinterpret_cast<WeaponT *>(u.value));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
inline const MyGame::Sample::Monster *GetMonster(const void *buf) { return flatbuffers::GetRoot<MyGame::Sample::Monster>(buf); }
|
||||
inline void EquipmentUnion::Reset() {
|
||||
switch (type) {
|
||||
case Equipment_Weapon: {
|
||||
auto ptr = reinterpret_cast<WeaponT *>(value);
|
||||
delete ptr;
|
||||
break;
|
||||
}
|
||||
default: break;
|
||||
}
|
||||
value = nullptr;
|
||||
type = Equipment_NONE;
|
||||
}
|
||||
|
||||
inline Monster *GetMutableMonster(void *buf) { return flatbuffers::GetMutableRoot<Monster>(buf); }
|
||||
inline const MyGame::Sample::Monster *GetMonster(const void *buf) {
|
||||
return flatbuffers::GetRoot<MyGame::Sample::Monster>(buf);
|
||||
}
|
||||
|
||||
inline bool VerifyMonsterBuffer(flatbuffers::Verifier &verifier) { return verifier.VerifyBuffer<MyGame::Sample::Monster>(nullptr); }
|
||||
inline Monster *GetMutableMonster(void *buf) {
|
||||
return flatbuffers::GetMutableRoot<Monster>(buf);
|
||||
}
|
||||
|
||||
inline void FinishMonsterBuffer(flatbuffers::FlatBufferBuilder &fbb, flatbuffers::Offset<MyGame::Sample::Monster> root) { fbb.Finish(root); }
|
||||
inline bool VerifyMonsterBuffer(
|
||||
flatbuffers::Verifier &verifier) {
|
||||
return verifier.VerifyBuffer<MyGame::Sample::Monster>(nullptr);
|
||||
}
|
||||
|
||||
inline void FinishMonsterBuffer(
|
||||
flatbuffers::FlatBufferBuilder &fbb,
|
||||
flatbuffers::Offset<MyGame::Sample::Monster> root) {
|
||||
fbb.Finish(root);
|
||||
}
|
||||
|
||||
inline std::unique_ptr<MonsterT> UnPackMonster(
|
||||
const void *buf,
|
||||
const flatbuffers::resolver_function_t *res = nullptr) {
|
||||
return std::unique_ptr<MonsterT>(GetMonster(buf)->UnPack(res));
|
||||
}
|
||||
|
||||
} // namespace Sample
|
||||
} // namespace MyGame
|
||||
|
||||
@@ -5,5 +5,21 @@
|
||||
z: 3
|
||||
},
|
||||
hp: 300,
|
||||
name: "Orc"
|
||||
name: "Orc",
|
||||
weapons:[
|
||||
{
|
||||
name: "axe",
|
||||
damage:100
|
||||
},
|
||||
{
|
||||
name: "bow",
|
||||
damage:90
|
||||
}
|
||||
],
|
||||
equipped_type: "Weapon",
|
||||
equipped:
|
||||
{
|
||||
name: "bow",
|
||||
damage:90
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,147 +19,147 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
flatbuffers "github.com/google/flatbuffers/go"
|
||||
"fmt"
|
||||
"strconv"
|
||||
sample "MyGame/Sample"
|
||||
sample "MyGame/Sample"
|
||||
"fmt"
|
||||
flatbuffers "github.com/google/flatbuffers/go"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// Example how to use Flatbuffers to create and read binary buffers.
|
||||
func main() {
|
||||
builder := flatbuffers.NewBuilder(0)
|
||||
builder := flatbuffers.NewBuilder(0)
|
||||
|
||||
// Create some weapons for our Monster ("Sword" and "Axe").
|
||||
weaponOne := builder.CreateString("Sword")
|
||||
weaponTwo := builder.CreateString("Axe")
|
||||
// Create some weapons for our Monster ("Sword" and "Axe").
|
||||
weaponOne := builder.CreateString("Sword")
|
||||
weaponTwo := builder.CreateString("Axe")
|
||||
|
||||
sample.WeaponStart(builder)
|
||||
sample.WeaponAddName(builder, weaponOne)
|
||||
sample.WeaponAddDamage(builder, 3)
|
||||
sword := sample.WeaponEnd(builder)
|
||||
sample.WeaponStart(builder)
|
||||
sample.WeaponAddName(builder, weaponOne)
|
||||
sample.WeaponAddDamage(builder, 3)
|
||||
sword := sample.WeaponEnd(builder)
|
||||
|
||||
sample.WeaponStart(builder)
|
||||
sample.WeaponAddName(builder, weaponTwo)
|
||||
sample.WeaponAddDamage(builder, 5)
|
||||
axe := sample.WeaponEnd(builder)
|
||||
sample.WeaponStart(builder)
|
||||
sample.WeaponAddName(builder, weaponTwo)
|
||||
sample.WeaponAddDamage(builder, 5)
|
||||
axe := sample.WeaponEnd(builder)
|
||||
|
||||
// Serialize the FlatBuffer data.
|
||||
name := builder.CreateString("Orc")
|
||||
// Serialize the FlatBuffer data.
|
||||
name := builder.CreateString("Orc")
|
||||
|
||||
sample.MonsterStartInventoryVector(builder, 10)
|
||||
// Note: Since we prepend the bytes, this loop iterates in reverse.
|
||||
for i := 9; i >= 0; i-- {
|
||||
builder.PrependByte(byte(i))
|
||||
}
|
||||
inv := builder.EndVector(10)
|
||||
sample.MonsterStartInventoryVector(builder, 10)
|
||||
// Note: Since we prepend the bytes, this loop iterates in reverse.
|
||||
for i := 9; i >= 0; i-- {
|
||||
builder.PrependByte(byte(i))
|
||||
}
|
||||
inv := builder.EndVector(10)
|
||||
|
||||
sample.MonsterStartWeaponsVector(builder, 2)
|
||||
// Note: Since we prepend the weapons, prepend in reverse order.
|
||||
builder.PrependUOffsetT(axe)
|
||||
builder.PrependUOffsetT(sword)
|
||||
weapons := builder.EndVector(2)
|
||||
sample.MonsterStartWeaponsVector(builder, 2)
|
||||
// Note: Since we prepend the weapons, prepend in reverse order.
|
||||
builder.PrependUOffsetT(axe)
|
||||
builder.PrependUOffsetT(sword)
|
||||
weapons := builder.EndVector(2)
|
||||
|
||||
pos := sample.CreateVec3(builder, 1.0, 2.0, 3.0)
|
||||
pos := sample.CreateVec3(builder, 1.0, 2.0, 3.0)
|
||||
|
||||
sample.MonsterStart(builder)
|
||||
sample.MonsterAddPos(builder, pos)
|
||||
sample.MonsterAddHp(builder, 300)
|
||||
sample.MonsterAddName(builder, name)
|
||||
sample.MonsterAddInventory(builder, inv)
|
||||
sample.MonsterAddColor(builder, sample.ColorRed)
|
||||
sample.MonsterAddWeapons(builder, weapons)
|
||||
sample.MonsterAddEquippedType(builder, sample.EquipmentWeapon)
|
||||
sample.MonsterAddEquipped(builder, axe)
|
||||
orc := sample.MonsterEnd(builder)
|
||||
sample.MonsterStart(builder)
|
||||
sample.MonsterAddPos(builder, pos)
|
||||
sample.MonsterAddHp(builder, 300)
|
||||
sample.MonsterAddName(builder, name)
|
||||
sample.MonsterAddInventory(builder, inv)
|
||||
sample.MonsterAddColor(builder, sample.ColorRed)
|
||||
sample.MonsterAddWeapons(builder, weapons)
|
||||
sample.MonsterAddEquippedType(builder, sample.EquipmentWeapon)
|
||||
sample.MonsterAddEquipped(builder, axe)
|
||||
orc := sample.MonsterEnd(builder)
|
||||
|
||||
builder.Finish(orc)
|
||||
builder.Finish(orc)
|
||||
|
||||
// We now have a FlatBuffer that we could store on disk or send over a network.
|
||||
// We now have a FlatBuffer that we could store on disk or send over a network.
|
||||
|
||||
// ...Saving to file or sending over a network code goes here...
|
||||
// ...Saving to file or sending over a network code goes here...
|
||||
|
||||
// Instead, we are going to access this buffer right away (as if we just received it).
|
||||
// Instead, we are going to access this buffer right away (as if we just received it).
|
||||
|
||||
buf := builder.FinishedBytes()
|
||||
buf := builder.FinishedBytes()
|
||||
|
||||
// Note: We use `0` for the offset here, since we got the data using the
|
||||
// `builder.FinishedBytes()` method. This simulates the data you would store/receive in your
|
||||
// FlatBuffer. If you wanted to read from the `builder.Bytes` directly, you would need to
|
||||
// pass in the offset of `builder.Head()`, as the builder actually constructs the buffer
|
||||
// backwards.
|
||||
monster := sample.GetRootAsMonster(buf, 0)
|
||||
// Note: We use `0` for the offset here, since we got the data using the
|
||||
// `builder.FinishedBytes()` method. This simulates the data you would store/receive in your
|
||||
// FlatBuffer. If you wanted to read from the `builder.Bytes` directly, you would need to
|
||||
// pass in the offset of `builder.Head()`, as the builder actually constructs the buffer
|
||||
// backwards.
|
||||
monster := sample.GetRootAsMonster(buf, 0)
|
||||
|
||||
// Note: We did not set the `mana` field explicitly, so we get the
|
||||
// default value.
|
||||
assert(monster.Mana() == 150, "`monster.Mana()`", strconv.Itoa(int(monster.Mana())), "150")
|
||||
assert(monster.Hp() == 300, "`monster.Hp()`", strconv.Itoa(int(monster.Hp())), "300")
|
||||
assert(string(monster.Name()) == "Orc", "`string(monster.Name())`", string(monster.Name()),
|
||||
"\"Orc\"")
|
||||
assert(monster.Color() == sample.ColorRed, "`monster.Color()`",
|
||||
strconv.Itoa(int(monster.Color())), strconv.Itoa(int(sample.ColorRed)))
|
||||
// Note: We did not set the `mana` field explicitly, so we get the
|
||||
// default value.
|
||||
assert(monster.Mana() == 150, "`monster.Mana()`", strconv.Itoa(int(monster.Mana())), "150")
|
||||
assert(monster.Hp() == 300, "`monster.Hp()`", strconv.Itoa(int(monster.Hp())), "300")
|
||||
assert(string(monster.Name()) == "Orc", "`string(monster.Name())`", string(monster.Name()),
|
||||
"\"Orc\"")
|
||||
assert(monster.Color() == sample.ColorRed, "`monster.Color()`",
|
||||
strconv.Itoa(int(monster.Color())), strconv.Itoa(int(sample.ColorRed)))
|
||||
|
||||
// Note: Whenever you access a new object, like in `Pos()`, a new temporary accessor object
|
||||
// gets created. If your code is very performance sensitive, you can pass in a pointer to an
|
||||
// existing `Vec3` instead of `nil`. This allows you to reuse it across many calls to reduce
|
||||
// the amount of object allocation/garbage collection.
|
||||
assert(monster.Pos(nil).X() == 1.0, "`monster.Pos(nil).X()`",
|
||||
strconv.FormatFloat(float64(monster.Pos(nil).X()), 'f', 1, 32), "1.0")
|
||||
assert(monster.Pos(nil).Y() == 2.0, "`monster.Pos(nil).Y()`",
|
||||
strconv.FormatFloat(float64(monster.Pos(nil).Y()), 'f', 1, 32), "2.0")
|
||||
assert(monster.Pos(nil).Z() == 3.0, "`monster.Pos(nil).Z()`",
|
||||
strconv.FormatFloat(float64(monster.Pos(nil).Z()), 'f', 1, 32), "3.0")
|
||||
// Note: Whenever you access a new object, like in `Pos()`, a new temporary accessor object
|
||||
// gets created. If your code is very performance sensitive, you can pass in a pointer to an
|
||||
// existing `Vec3` instead of `nil`. This allows you to reuse it across many calls to reduce
|
||||
// the amount of object allocation/garbage collection.
|
||||
assert(monster.Pos(nil).X() == 1.0, "`monster.Pos(nil).X()`",
|
||||
strconv.FormatFloat(float64(monster.Pos(nil).X()), 'f', 1, 32), "1.0")
|
||||
assert(monster.Pos(nil).Y() == 2.0, "`monster.Pos(nil).Y()`",
|
||||
strconv.FormatFloat(float64(monster.Pos(nil).Y()), 'f', 1, 32), "2.0")
|
||||
assert(monster.Pos(nil).Z() == 3.0, "`monster.Pos(nil).Z()`",
|
||||
strconv.FormatFloat(float64(monster.Pos(nil).Z()), 'f', 1, 32), "3.0")
|
||||
|
||||
// For vectors, like `Inventory`, they have a method suffixed with 'Length' that can be used
|
||||
// to query the length of the vector. You can index the vector by passing an index value
|
||||
// into the accessor.
|
||||
for i := 0; i < monster.InventoryLength(); i++ {
|
||||
assert(monster.Inventory(i) == byte(i), "`monster.Inventory(i)`",
|
||||
strconv.Itoa(int(monster.Inventory(i))), strconv.Itoa(int(byte(i))))
|
||||
}
|
||||
// For vectors, like `Inventory`, they have a method suffixed with 'Length' that can be used
|
||||
// to query the length of the vector. You can index the vector by passing an index value
|
||||
// into the accessor.
|
||||
for i := 0; i < monster.InventoryLength(); i++ {
|
||||
assert(monster.Inventory(i) == byte(i), "`monster.Inventory(i)`",
|
||||
strconv.Itoa(int(monster.Inventory(i))), strconv.Itoa(int(byte(i))))
|
||||
}
|
||||
|
||||
expectedWeaponNames := []string{"Sword", "Axe"}
|
||||
expectedWeaponDamages := []int{3, 5}
|
||||
weapon := new(sample.Weapon) // We need a `sample.Weapon` to pass into `monster.Weapons()`
|
||||
// to capture the output of that function.
|
||||
for i := 0; i < monster.WeaponsLength(); i++ {
|
||||
if monster.Weapons(weapon, i) {
|
||||
assert(string(weapon.Name()) == expectedWeaponNames[i], "`weapon.Name()`",
|
||||
string(weapon.Name()), expectedWeaponNames[i])
|
||||
assert(int(weapon.Damage()) == expectedWeaponDamages[i],
|
||||
"`weapon.Damage()`", strconv.Itoa(int(weapon.Damage())),
|
||||
strconv.Itoa(expectedWeaponDamages[i]))
|
||||
}
|
||||
}
|
||||
expectedWeaponNames := []string{"Sword", "Axe"}
|
||||
expectedWeaponDamages := []int{3, 5}
|
||||
weapon := new(sample.Weapon) // We need a `sample.Weapon` to pass into `monster.Weapons()`
|
||||
// to capture the output of that function.
|
||||
for i := 0; i < monster.WeaponsLength(); i++ {
|
||||
if monster.Weapons(weapon, i) {
|
||||
assert(string(weapon.Name()) == expectedWeaponNames[i], "`weapon.Name()`",
|
||||
string(weapon.Name()), expectedWeaponNames[i])
|
||||
assert(int(weapon.Damage()) == expectedWeaponDamages[i],
|
||||
"`weapon.Damage()`", strconv.Itoa(int(weapon.Damage())),
|
||||
strconv.Itoa(expectedWeaponDamages[i]))
|
||||
}
|
||||
}
|
||||
|
||||
// For FlatBuffer `union`s, you can get the type of the union, as well as the union
|
||||
// data itself.
|
||||
assert(monster.EquippedType() == sample.EquipmentWeapon, "`monster.EquippedType()`",
|
||||
strconv.Itoa(int(monster.EquippedType())), strconv.Itoa(int(sample.EquipmentWeapon)))
|
||||
// For FlatBuffer `union`s, you can get the type of the union, as well as the union
|
||||
// data itself.
|
||||
assert(monster.EquippedType() == sample.EquipmentWeapon, "`monster.EquippedType()`",
|
||||
strconv.Itoa(int(monster.EquippedType())), strconv.Itoa(int(sample.EquipmentWeapon)))
|
||||
|
||||
unionTable := new(flatbuffers.Table)
|
||||
if monster.Equipped(unionTable) {
|
||||
// An example of how you can appropriately convert the table depending on the
|
||||
// FlatBuffer `union` type. You could add `else if` and `else` clauses to handle
|
||||
// other FlatBuffer `union` types for this field. (Similarly, this could be
|
||||
// done in a switch statement.)
|
||||
if monster.EquippedType() == sample.EquipmentWeapon {
|
||||
unionWeapon := new(sample.Weapon)
|
||||
unionWeapon.Init(unionTable.Bytes, unionTable.Pos)
|
||||
unionTable := new(flatbuffers.Table)
|
||||
if monster.Equipped(unionTable) {
|
||||
// An example of how you can appropriately convert the table depending on the
|
||||
// FlatBuffer `union` type. You could add `else if` and `else` clauses to handle
|
||||
// other FlatBuffer `union` types for this field. (Similarly, this could be
|
||||
// done in a switch statement.)
|
||||
if monster.EquippedType() == sample.EquipmentWeapon {
|
||||
unionWeapon := new(sample.Weapon)
|
||||
unionWeapon.Init(unionTable.Bytes, unionTable.Pos)
|
||||
|
||||
assert(string(unionWeapon.Name()) == "Axe", "`unionWeapon.Name()`",
|
||||
string(unionWeapon.Name()), "Axe")
|
||||
assert(int(unionWeapon.Damage()) == 5, "`unionWeapon.Damage()`",
|
||||
strconv.Itoa(int(unionWeapon.Damage())), strconv.Itoa(5))
|
||||
}
|
||||
}
|
||||
assert(string(unionWeapon.Name()) == "Axe", "`unionWeapon.Name()`",
|
||||
string(unionWeapon.Name()), "Axe")
|
||||
assert(int(unionWeapon.Damage()) == 5, "`unionWeapon.Damage()`",
|
||||
strconv.Itoa(int(unionWeapon.Damage())), strconv.Itoa(5))
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Printf("The FlatBuffer was successfully created and verified!\n")
|
||||
fmt.Printf("The FlatBuffer was successfully created and verified!\n")
|
||||
}
|
||||
|
||||
// A helper function to print out if an assertion failed.
|
||||
func assert(assertPassed bool, codeExecuted string, actualValue string, expectedValue string) {
|
||||
if assertPassed == false {
|
||||
panic("Assert failed! " + codeExecuted + " (" + actualValue +
|
||||
") was not equal to " + expectedValue + ".")
|
||||
}
|
||||
if assertPassed == false {
|
||||
panic("Assert failed! " + codeExecuted + " (" + actualValue +
|
||||
") was not equal to " + expectedValue + ".")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,7 +46,10 @@ int main(int /*argc*/, const char * /*argv*/[]) {
|
||||
// to ensure it is correct, we now generate text back from the binary,
|
||||
// and compare the two:
|
||||
std::string jsongen;
|
||||
GenerateText(parser, parser.builder_.GetBufferPointer(), &jsongen);
|
||||
if (!GenerateText(parser, parser.builder_.GetBufferPointer(), &jsongen)) {
|
||||
printf("Couldn't serialize parsed data to JSON!\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (jsongen != jsonfile) {
|
||||
printf("%s----------------\n%s", jsongen.c_str(), jsonfile.c_str());
|
||||
|
||||
170
src/code_generators.cpp
Normal file
170
src/code_generators.cpp
Normal file
@@ -0,0 +1,170 @@
|
||||
/*
|
||||
* Copyright 2016 Google Inc. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "flatbuffers/code_generators.h"
|
||||
#include <assert.h>
|
||||
#include "flatbuffers/util.h"
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable: 4127) // C4127: conditional expression is constant
|
||||
#endif
|
||||
|
||||
namespace flatbuffers {
|
||||
|
||||
void CodeWriter::operator+=(std::string text) {
|
||||
|
||||
while (true) {
|
||||
auto begin = text.find("{{");
|
||||
if (begin == std::string::npos) {
|
||||
break;
|
||||
}
|
||||
|
||||
auto end = text.find("}}");
|
||||
if (end == std::string::npos || end < begin) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Write all the text before the first {{ into the stream.
|
||||
stream_.write(text.c_str(), begin);
|
||||
|
||||
// The key is between the {{ and }}.
|
||||
const std::string key = text.substr(begin + 2, end - begin - 2);
|
||||
|
||||
// Find the value associated with the key. If it exists, write the
|
||||
// value into the stream, otherwise write the key itself into the stream.
|
||||
auto iter = value_map_.find(key);
|
||||
if (iter != value_map_.end()) {
|
||||
const std::string &value = iter->second;
|
||||
stream_ << value;
|
||||
} else {
|
||||
assert(false && "could not find key");
|
||||
stream_ << key;
|
||||
}
|
||||
|
||||
// Update the text to everything after the }}.
|
||||
text = text.substr(end + 2);
|
||||
}
|
||||
if (!text.empty() && text.back() == '\\') {
|
||||
text.pop_back();
|
||||
stream_ << text;
|
||||
} else {
|
||||
stream_ << text << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
const char *BaseGenerator::FlatBuffersGeneratedWarning() {
|
||||
return "automatically generated by the FlatBuffers compiler,"
|
||||
" do not modify";
|
||||
}
|
||||
|
||||
std::string BaseGenerator::NamespaceDir(const Parser &parser,
|
||||
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 = ns.components;
|
||||
for (auto it = namespaces.begin(); it != namespaces.end(); ++it) {
|
||||
namespace_dir += *it + kPathSeparator;
|
||||
EnsureDirExists(namespace_dir.c_str());
|
||||
}
|
||||
return namespace_dir;
|
||||
}
|
||||
|
||||
std::string BaseGenerator::NamespaceDir(const Namespace &ns) const {
|
||||
return BaseGenerator::NamespaceDir(parser_, path_, ns);
|
||||
}
|
||||
|
||||
std::string BaseGenerator::FullNamespace(const char *separator,
|
||||
const Namespace &ns) {
|
||||
std::string namespace_name;
|
||||
auto &namespaces = ns.components;
|
||||
for (auto it = namespaces.begin(); it != namespaces.end(); ++it) {
|
||||
if (namespace_name.length()) namespace_name += separator;
|
||||
namespace_name += *it;
|
||||
}
|
||||
return namespace_name;
|
||||
}
|
||||
|
||||
std::string BaseGenerator::LastNamespacePart(const Namespace &ns) {
|
||||
if (!ns.components.empty())
|
||||
return ns.components.back();
|
||||
else
|
||||
return std::string("");
|
||||
}
|
||||
|
||||
// Ensure that a type is prefixed with its namespace whenever it is used
|
||||
// outside of its namespace.
|
||||
std::string BaseGenerator::WrapInNameSpace(const Namespace *ns,
|
||||
const std::string &name) const {
|
||||
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 BaseGenerator::WrapInNameSpace(const Definition &def) const {
|
||||
return WrapInNameSpace(def.defined_namespace, def.name);
|
||||
}
|
||||
|
||||
std::string BaseGenerator::GetNameSpace(const Definition &def) const {
|
||||
const Namespace *ns = def.defined_namespace;
|
||||
if (CurrentNameSpace() == ns) return "";
|
||||
std::string qualified_name = qualifying_start_;
|
||||
for (auto it = ns->components.begin(); it != ns->components.end(); ++it) {
|
||||
qualified_name += *it;
|
||||
if (std::next(it) != ns->components.end()) {
|
||||
qualified_name += qualifying_separator_;
|
||||
}
|
||||
}
|
||||
|
||||
return qualified_name;
|
||||
}
|
||||
|
||||
// Generate a documentation comment, if available.
|
||||
void GenComment(const std::vector<std::string> &dc, std::string *code_ptr,
|
||||
const CommentConfig *config, const char *prefix) {
|
||||
if (dc.begin() == dc.end()) {
|
||||
// Don't output empty comment blocks with 0 lines of comment content.
|
||||
return;
|
||||
}
|
||||
|
||||
std::string &code = *code_ptr;
|
||||
if (config != nullptr && config->first_line != nullptr) {
|
||||
code += std::string(prefix) + std::string(config->first_line) + "\n";
|
||||
}
|
||||
std::string line_prefix = std::string(prefix) +
|
||||
((config != nullptr && config->content_line_prefix != nullptr) ?
|
||||
config->content_line_prefix : "///");
|
||||
for (auto it = dc.begin();
|
||||
it != dc.end();
|
||||
++it) {
|
||||
code += line_prefix + *it + "\n";
|
||||
}
|
||||
if (config != nullptr && config->last_line != nullptr) {
|
||||
code += std::string(prefix) + std::string(config->last_line) + "\n";
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace flatbuffers
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
394
src/flatc.cpp
394
src/flatc.cpp
@@ -14,92 +14,52 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "flatbuffers/flatbuffers.h"
|
||||
#include "flatbuffers/idl.h"
|
||||
#include "flatbuffers/util.h"
|
||||
#include <limits>
|
||||
#include "flatbuffers/flatc.h"
|
||||
|
||||
#define FLATC_VERSION "1.4.0 (" __DATE__ ")"
|
||||
#include <list>
|
||||
|
||||
static void Error(const std::string &err, bool usage = false,
|
||||
bool show_exe_name = true);
|
||||
#define FLATC_VERSION "1.7.0 (" __DATE__ ")"
|
||||
|
||||
// This struct allows us to create a table of all possible output generators
|
||||
// for the various programming languages and formats we support.
|
||||
struct Generator {
|
||||
bool (*generate)(const flatbuffers::Parser &parser,
|
||||
const std::string &path,
|
||||
const std::string &file_name);
|
||||
const char *generator_opt_short;
|
||||
const char *generator_opt_long;
|
||||
const char *lang_name;
|
||||
flatbuffers::IDLOptions::Language lang;
|
||||
const char *generator_help;
|
||||
namespace flatbuffers {
|
||||
|
||||
std::string (*make_rule)(const flatbuffers::Parser &parser,
|
||||
const std::string &path,
|
||||
const std::string &file_name);
|
||||
};
|
||||
void FlatCompiler::ParseFile(
|
||||
flatbuffers::Parser &parser,
|
||||
const std::string &filename,
|
||||
const std::string &contents,
|
||||
std::vector<const char *> &include_directories) const {
|
||||
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();
|
||||
}
|
||||
|
||||
const Generator generators[] = {
|
||||
{ flatbuffers::GenerateBinary, "-b", "--binary", "binary",
|
||||
flatbuffers::IDLOptions::kMAX,
|
||||
"Generate wire format binaries for any data definitions",
|
||||
flatbuffers::BinaryMakeRule },
|
||||
{ flatbuffers::GenerateTextFile, "-t", "--json", "text",
|
||||
flatbuffers::IDLOptions::kMAX,
|
||||
"Generate text output for any data definitions",
|
||||
flatbuffers::TextMakeRule },
|
||||
{ flatbuffers::GenerateCPP, "-c", "--cpp", "C++",
|
||||
flatbuffers::IDLOptions::kMAX,
|
||||
"Generate C++ headers for tables/structs",
|
||||
flatbuffers::CPPMakeRule },
|
||||
{ flatbuffers::GenerateGo, "-g", "--go", "Go",
|
||||
flatbuffers::IDLOptions::kGo,
|
||||
"Generate Go files for tables/structs",
|
||||
flatbuffers::GeneralMakeRule },
|
||||
{ flatbuffers::GenerateGeneral, "-j", "--java", "Java",
|
||||
flatbuffers::IDLOptions::kJava,
|
||||
"Generate Java classes for tables/structs",
|
||||
flatbuffers::GeneralMakeRule },
|
||||
{ flatbuffers::GenerateJS, "-s", "--js", "JavaScript",
|
||||
flatbuffers::IDLOptions::kMAX,
|
||||
"Generate JavaScript code for tables/structs",
|
||||
flatbuffers::JSMakeRule },
|
||||
{ flatbuffers::GenerateGeneral, "-n", "--csharp", "C#",
|
||||
flatbuffers::IDLOptions::kCSharp,
|
||||
"Generate C# classes for tables/structs",
|
||||
flatbuffers::GeneralMakeRule },
|
||||
{ flatbuffers::GeneratePython, "-p", "--python", "Python",
|
||||
flatbuffers::IDLOptions::kMAX,
|
||||
"Generate Python files for tables/structs",
|
||||
flatbuffers::GeneralMakeRule },
|
||||
{ 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 },
|
||||
};
|
||||
void FlatCompiler::Warn(const std::string &warn, bool show_exe_name) const {
|
||||
params_.warn_fn(this, warn, show_exe_name);
|
||||
}
|
||||
|
||||
const char *g_program_name = nullptr;
|
||||
flatbuffers::Parser *g_parser = nullptr;
|
||||
void FlatCompiler::Error(const std::string &err, bool usage,
|
||||
bool show_exe_name) const {
|
||||
params_.error_fn(this, err, usage, show_exe_name);
|
||||
}
|
||||
|
||||
static void Error(const std::string &err, bool usage, bool show_exe_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", 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,
|
||||
generators[i].generator_opt_short
|
||||
? generators[i].generator_opt_short
|
||||
: " ",
|
||||
generators[i].generator_help);
|
||||
printf(
|
||||
std::string FlatCompiler::GetUsageString(const char* program_name) const {
|
||||
std::stringstream ss;
|
||||
ss << "Usage: " << program_name << " [OPTION]... FILE... [-- FILE...]\n";
|
||||
for (size_t i = 0; i < params_.num_generators; ++i) {
|
||||
const Generator& g = params_.generators[i];
|
||||
|
||||
std::stringstream full_name;
|
||||
full_name << std::setw(12) << std::left << g.generator_opt_long;
|
||||
const char *name = g.generator_opt_short ? g.generator_opt_short : " ";
|
||||
const char *help = g.generator_help;
|
||||
|
||||
ss << " " << full_name.str() << " " << name << " " << help << ".\n";
|
||||
}
|
||||
ss <<
|
||||
" -o PATH Prefix PATH to all generated files.\n"
|
||||
" -I PATH Search for includes in the specified path.\n"
|
||||
" -M Print make rules for generated files.\n"
|
||||
@@ -126,71 +86,98 @@ static void Error(const std::string &err, bool usage, bool show_exe_name) {
|
||||
" --gen-onefile Generate single output file for C#.\n"
|
||||
" --gen-name-strings Generate type name functions for C++.\n"
|
||||
" --escape-proto-ids Disable appending '_' in namespaces names.\n"
|
||||
" --gen-object-api Generate an additional object-based API\n"
|
||||
" --gen-object-api Generate an additional object-based API.\n"
|
||||
" --cpp-ptr-type T Set object API pointer type (default std::unique_ptr)\n"
|
||||
" --cpp-str-type T Set object API string type (default std::string)\n"
|
||||
" T::c_str() and T::length() must be supported\n"
|
||||
" --no-js-exports Removes Node.js style export lines in JS.\n"
|
||||
" --goog-js-export Uses goog.exports* for closure compiler exporting in JS.\n"
|
||||
" --go-namespace Generate the overrided namespace in Golang.\n"
|
||||
" --raw-binary Allow binaries without file_indentifier to be read.\n"
|
||||
" This may crash flatc given a mismatched schema.\n"
|
||||
" --proto Input is a .proto, translate to .fbs.\n"
|
||||
" --grpc Generate GRPC interfaces for the specified languages\n"
|
||||
" --schema Serialize schemas instead of JSON (use with -b)\n"
|
||||
" --bfbs-comments Add doc comments to the binary schema files.\n"
|
||||
" --conform FILE Specify a schema the following schemas should be\n"
|
||||
" an evolution of. Gives errors if not.\n"
|
||||
" --conform-includes Include path for the schema given with --conform\n"
|
||||
" PATH \n"
|
||||
" --include-prefix Prefix this path to any generated include statements.\n"
|
||||
" PATH\n"
|
||||
" --keep-prefix Keep original prefix of schema include statement.\n"
|
||||
" --no-fb-import Don't include flatbuffers import statement for TypeScript.\n"
|
||||
" --no-ts-reexport Don't re-export imported dependencies for TypeScript.\n"
|
||||
"FILEs may be schemas, or JSON files (conforming to preceding schema)\n"
|
||||
"FILEs 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",
|
||||
g_program_name);
|
||||
"example: " << program_name << " -c -b schema1.fbs schema2.fbs data.json\n";
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
int FlatCompiler::Compile(int argc, const char** argv) {
|
||||
if (params_.generators == nullptr || params_.num_generators == 0) {
|
||||
return 0;
|
||||
}
|
||||
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[]) {
|
||||
g_program_name = argv[0];
|
||||
flatbuffers::IDLOptions opts;
|
||||
std::string output_path;
|
||||
const size_t num_generators = sizeof(generators) / sizeof(generators[0]);
|
||||
bool generator_enabled[num_generators] = { false };
|
||||
|
||||
bool any_generator = false;
|
||||
bool print_make_rules = false;
|
||||
bool raw_binary = false;
|
||||
bool schema_binary = false;
|
||||
bool grpc_enabled = false;
|
||||
std::vector<std::string> filenames;
|
||||
std::list<std::string> include_directories_storage;
|
||||
std::vector<const char *> include_directories;
|
||||
std::vector<const char *> conform_include_directories;
|
||||
std::vector<bool> generator_enabled(params_.num_generators, false);
|
||||
size_t binary_files_from = std::numeric_limits<size_t>::max();
|
||||
std::string conform_to_schema;
|
||||
for (int argi = 1; argi < argc; argi++) {
|
||||
|
||||
for (int argi = 0; argi < argc; argi++) {
|
||||
std::string arg = argv[argi];
|
||||
if (arg[0] == '-') {
|
||||
if (filenames.size() && arg[1] != '-')
|
||||
Error("invalid option location: " + arg, true);
|
||||
if (arg == "-o") {
|
||||
if (++argi >= argc) Error("missing path following: " + arg, true);
|
||||
output_path = flatbuffers::ConCatPathFileName(argv[argi], "");
|
||||
output_path = flatbuffers::ConCatPathFileName(
|
||||
flatbuffers::PosixPath(argv[argi]), "");
|
||||
} else if(arg == "-I") {
|
||||
if (++argi >= argc) Error("missing path following" + arg, true);
|
||||
include_directories.push_back(argv[argi]);
|
||||
include_directories_storage.push_back(
|
||||
flatbuffers::PosixPath(argv[argi]));
|
||||
include_directories.push_back(
|
||||
include_directories_storage.back().c_str());
|
||||
} else if(arg == "--conform") {
|
||||
if (++argi >= argc) Error("missing path following" + arg, true);
|
||||
conform_to_schema = argv[argi];
|
||||
conform_to_schema = flatbuffers::PosixPath(argv[argi]);
|
||||
} else if (arg == "--conform-includes") {
|
||||
if (++argi >= argc) Error("missing path following" + arg, true);
|
||||
include_directories_storage.push_back(
|
||||
flatbuffers::PosixPath(argv[argi]));
|
||||
conform_include_directories.push_back(
|
||||
include_directories_storage.back().c_str());
|
||||
} else if (arg == "--include-prefix") {
|
||||
if (++argi >= argc) Error("missing path following" + arg, true);
|
||||
opts.include_prefix = flatbuffers::ConCatPathFileName(
|
||||
flatbuffers::PosixPath(argv[argi]), "");
|
||||
} else if(arg == "--keep-prefix") {
|
||||
opts.keep_include_path = true;
|
||||
} else if(arg == "--strict-json") {
|
||||
opts.strict_json = true;
|
||||
} else if(arg == "--allow-non-utf8") {
|
||||
opts.allow_non_utf8 = true;
|
||||
} else if(arg == "--no-js-exports") {
|
||||
opts.skip_js_exports = true;
|
||||
} else if(arg == "--goog-js-export") {
|
||||
opts.use_goog_js_export_format = true;
|
||||
} else if(arg == "--go-namespace") {
|
||||
if (++argi >= argc) Error("missing golang namespace" + arg, true);
|
||||
opts.go_namespace = argv[argi];
|
||||
} else if(arg == "--defaults-json") {
|
||||
opts.output_default_scalars_in_json = true;
|
||||
} else if (arg == "--unknown-json") {
|
||||
@@ -208,6 +195,12 @@ int main(int argc, const char *argv[]) {
|
||||
opts.generate_name_strings = true;
|
||||
} else if(arg == "--gen-object-api") {
|
||||
opts.generate_object_based_api = true;
|
||||
} else if (arg == "--cpp-ptr-type") {
|
||||
if (++argi >= argc) Error("missing type following" + arg, true);
|
||||
opts.cpp_object_api_pointer_type = argv[argi];
|
||||
} else if (arg == "--cpp-str-type") {
|
||||
if (++argi >= argc) Error("missing type following" + arg, true);
|
||||
opts.cpp_object_api_string_type = argv[argi];
|
||||
} else if(arg == "--gen-all") {
|
||||
opts.generate_all = true;
|
||||
opts.include_dependence_headers = false;
|
||||
@@ -233,21 +226,30 @@ int main(int argc, const char *argv[]) {
|
||||
} else if(arg == "--version") {
|
||||
printf("flatc version %s\n", FLATC_VERSION);
|
||||
exit(0);
|
||||
} else if(arg == "--grpc") {
|
||||
grpc_enabled = true;
|
||||
} else if(arg == "--bfbs-comments") {
|
||||
opts.binary_schema_comments = true;
|
||||
} else if(arg == "--no-fb-import") {
|
||||
opts.skip_flatbuffers_import = true;
|
||||
} else if(arg == "--no-ts-reexport") {
|
||||
opts.reexport_ts_modules = false;
|
||||
} else {
|
||||
for (size_t i = 0; i < num_generators; ++i) {
|
||||
if (arg == generators[i].generator_opt_long ||
|
||||
(generators[i].generator_opt_short &&
|
||||
arg == generators[i].generator_opt_short)) {
|
||||
for (size_t i = 0; i < params_.num_generators; ++i) {
|
||||
if (arg == params_.generators[i].generator_opt_long ||
|
||||
(params_.generators[i].generator_opt_short &&
|
||||
arg == params_.generators[i].generator_opt_short)) {
|
||||
generator_enabled[i] = true;
|
||||
any_generator = true;
|
||||
opts.lang_to_generate |= params_.generators[i].lang;
|
||||
goto found;
|
||||
}
|
||||
}
|
||||
Error("unknown commandline argument" + arg, true);
|
||||
Error("unknown commandline argument: " + arg, true);
|
||||
found:;
|
||||
}
|
||||
} else {
|
||||
filenames.push_back(argv[argi]);
|
||||
filenames.push_back(flatbuffers::PosixPath(argv[argi]));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -265,100 +267,114 @@ int main(int argc, const char *argv[]) {
|
||||
std::string contents;
|
||||
if (!flatbuffers::LoadFile(conform_to_schema.c_str(), true, &contents))
|
||||
Error("unable to load schema: " + conform_to_schema);
|
||||
ParseFile(conform_parser, conform_to_schema, contents, include_directories);
|
||||
ParseFile(conform_parser, conform_to_schema, contents,
|
||||
conform_include_directories);
|
||||
}
|
||||
|
||||
// Now process the files:
|
||||
g_parser = new flatbuffers::Parser(opts);
|
||||
std::unique_ptr<flatbuffers::Parser> parser(new flatbuffers::Parser(opts));
|
||||
|
||||
for (auto file_it = filenames.begin();
|
||||
file_it != filenames.end();
|
||||
++file_it) {
|
||||
std::string contents;
|
||||
if (!flatbuffers::LoadFile(file_it->c_str(), true, &contents))
|
||||
Error("unable to load file: " + *file_it);
|
||||
auto &filename = *file_it;
|
||||
std::string contents;
|
||||
if (!flatbuffers::LoadFile(filename.c_str(), true, &contents))
|
||||
Error("unable to load file: " + filename);
|
||||
|
||||
bool is_binary = static_cast<size_t>(file_it - filenames.begin()) >=
|
||||
binary_files_from;
|
||||
if (is_binary) {
|
||||
g_parser->builder_.Clear();
|
||||
g_parser->builder_.PushFlatBuffer(
|
||||
reinterpret_cast<const uint8_t *>(contents.c_str()),
|
||||
contents.length());
|
||||
if (!raw_binary) {
|
||||
// Generally reading binaries that do not correspond to the schema
|
||||
// will crash, and sadly there's no way around that when the binary
|
||||
// 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 (!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(),
|
||||
g_parser->file_identifier_.c_str())) {
|
||||
Error("binary \"" +
|
||||
*file_it +
|
||||
"\" does not have expected file_identifier \"" +
|
||||
g_parser->file_identifier_ +
|
||||
"\", use --raw-binary to read this file anyway.");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Check if file contains 0 bytes.
|
||||
if (contents.length() != strlen(contents.c_str())) {
|
||||
Error("input file appears to be binary: " + *file_it, true);
|
||||
}
|
||||
auto is_schema = flatbuffers::GetExtension(*file_it) == "fbs";
|
||||
if (is_schema) {
|
||||
// If we're processing multiple schemas, make sure to start each
|
||||
// one from scratch. If it depends on previous schemas it must do
|
||||
// so explicitly using an include.
|
||||
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);
|
||||
}
|
||||
if (schema_binary) {
|
||||
g_parser->Serialize();
|
||||
g_parser->file_extension_ = reflection::SchemaExtension();
|
||||
bool is_binary = static_cast<size_t>(file_it - filenames.begin()) >=
|
||||
binary_files_from;
|
||||
auto is_schema = flatbuffers::GetExtension(filename) == "fbs";
|
||||
if (is_binary) {
|
||||
parser->builder_.Clear();
|
||||
parser->builder_.PushFlatBuffer(
|
||||
reinterpret_cast<const uint8_t *>(contents.c_str()),
|
||||
contents.length());
|
||||
if (!raw_binary) {
|
||||
// Generally reading binaries that do not correspond to the schema
|
||||
// will crash, and sadly there's no way around that when the binary
|
||||
// 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()) {
|
||||
Error("current schema has no file_identifier: cannot test if \"" +
|
||||
filename +
|
||||
"\" matches the schema, use --raw-binary to read this file"
|
||||
" anyway.");
|
||||
} else if (!flatbuffers::BufferHasIdentifier(contents.c_str(),
|
||||
parser->file_identifier_.c_str())) {
|
||||
Error("binary \"" +
|
||||
filename +
|
||||
"\" does not have expected file_identifier \"" +
|
||||
parser->file_identifier_ +
|
||||
"\", use --raw-binary to read this file anyway.");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Check if file contains 0 bytes.
|
||||
if (contents.length() != strlen(contents.c_str())) {
|
||||
Error("input file appears to be binary: " + filename, true);
|
||||
}
|
||||
if (is_schema) {
|
||||
// If we're processing multiple schemas, make sure to start each
|
||||
// one from scratch. If it depends on previous schemas it must do
|
||||
// so explicitly using an include.
|
||||
parser.reset(new flatbuffers::Parser(opts));
|
||||
}
|
||||
ParseFile(*parser.get(), filename, contents, include_directories);
|
||||
if (is_schema && !conform_to_schema.empty()) {
|
||||
auto err = parser->ConformTo(conform_parser);
|
||||
if (!err.empty()) Error("schemas don\'t conform: " + err);
|
||||
}
|
||||
if (schema_binary) {
|
||||
parser->Serialize();
|
||||
parser->file_extension_ = reflection::SchemaExtension();
|
||||
}
|
||||
}
|
||||
|
||||
std::string filebase = flatbuffers::StripPath(
|
||||
flatbuffers::StripExtension(*file_it));
|
||||
std::string filebase = flatbuffers::StripPath(
|
||||
flatbuffers::StripExtension(filename));
|
||||
|
||||
for (size_t i = 0; i < num_generators; ++i) {
|
||||
g_parser->opts.lang = generators[i].lang;
|
||||
if (generator_enabled[i]) {
|
||||
if (!print_make_rules) {
|
||||
flatbuffers::EnsureDirExists(output_path);
|
||||
if (!generators[i].generate(*g_parser, output_path, filebase)) {
|
||||
Error(std::string("Unable to generate ") +
|
||||
generators[i].lang_name +
|
||||
" for " +
|
||||
filebase);
|
||||
for (size_t i = 0; i < params_.num_generators; ++i) {
|
||||
parser->opts.lang = params_.generators[i].lang;
|
||||
if (generator_enabled[i]) {
|
||||
if (!print_make_rules) {
|
||||
flatbuffers::EnsureDirExists(output_path);
|
||||
if ((!params_.generators[i].schema_only || is_schema) &&
|
||||
!params_.generators[i].generate(*parser.get(), output_path, filebase)) {
|
||||
Error(std::string("Unable to generate ") +
|
||||
params_.generators[i].lang_name +
|
||||
" for " +
|
||||
filebase);
|
||||
}
|
||||
} else {
|
||||
std::string make_rule = params_.generators[i].make_rule(
|
||||
*parser.get(), output_path, filename);
|
||||
if (!make_rule.empty())
|
||||
printf("%s\n", flatbuffers::WordWrap(
|
||||
make_rule, 80, " ", " \\").c_str());
|
||||
}
|
||||
if (grpc_enabled) {
|
||||
if (params_.generators[i].generateGRPC != nullptr) {
|
||||
if (!params_.generators[i].generateGRPC(*parser.get(), output_path,
|
||||
filebase)) {
|
||||
Error(std::string("Unable to generate GRPC interface for") +
|
||||
params_.generators[i].lang_name);
|
||||
}
|
||||
} else {
|
||||
std::string make_rule = generators[i].make_rule(
|
||||
*g_parser, output_path, *file_it);
|
||||
if (!make_rule.empty())
|
||||
printf("%s\n", flatbuffers::WordWrap(
|
||||
make_rule, 80, " ", " \\").c_str());
|
||||
Warn(std::string("GRPC interface generator not implemented for ")
|
||||
+ params_.generators[i].lang_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (opts.proto_mode) GenerateFBS(*g_parser, output_path, filebase);
|
||||
if (opts.proto_mode) GenerateFBS(*parser.get(), output_path, filebase);
|
||||
|
||||
// We do not want to generate code for the definitions in this file
|
||||
// in any files coming up next.
|
||||
g_parser->MarkGenerated();
|
||||
// We do not want to generate code for the definitions in this file
|
||||
// in any files coming up next.
|
||||
parser->MarkGenerated();
|
||||
}
|
||||
|
||||
delete g_parser;
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace flatbuffers
|
||||
|
||||
109
src/flatc_main.cpp
Normal file
109
src/flatc_main.cpp
Normal file
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* Copyright 2017 Google Inc. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "flatbuffers/flatc.h"
|
||||
|
||||
static const char *g_program_name = nullptr;
|
||||
|
||||
static void Warn(const flatbuffers::FlatCompiler *flatc,
|
||||
const std::string &warn,
|
||||
bool show_exe_name) {
|
||||
(void)flatc;
|
||||
if (show_exe_name) {
|
||||
printf("%s: ", g_program_name);
|
||||
}
|
||||
printf("warning: %s\n", warn.c_str());
|
||||
}
|
||||
|
||||
static void Error(const flatbuffers::FlatCompiler *flatc,
|
||||
const std::string &err,
|
||||
bool usage,
|
||||
bool show_exe_name) {
|
||||
if (show_exe_name) {
|
||||
printf("%s: ", g_program_name);
|
||||
}
|
||||
printf("error: %s\n", err.c_str());
|
||||
if (usage) {
|
||||
printf("%s", flatc->GetUsageString(g_program_name).c_str());
|
||||
}
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int main(int argc, const char *argv[]) {
|
||||
g_program_name = argv[0];
|
||||
|
||||
const flatbuffers::FlatCompiler::Generator generators[] = {
|
||||
{ flatbuffers::GenerateBinary, "-b", "--binary", "binary", false,
|
||||
nullptr,
|
||||
flatbuffers::IDLOptions::kBinary,
|
||||
"Generate wire format binaries for any data definitions",
|
||||
flatbuffers::BinaryMakeRule },
|
||||
{ flatbuffers::GenerateTextFile, "-t", "--json", "text", false,
|
||||
nullptr,
|
||||
flatbuffers::IDLOptions::kJson,
|
||||
"Generate text output for any data definitions",
|
||||
flatbuffers::TextMakeRule },
|
||||
{ flatbuffers::GenerateCPP, "-c", "--cpp", "C++", true,
|
||||
flatbuffers::GenerateCppGRPC,
|
||||
flatbuffers::IDLOptions::kCpp,
|
||||
"Generate C++ headers for tables/structs",
|
||||
flatbuffers::CPPMakeRule },
|
||||
{ flatbuffers::GenerateGo, "-g", "--go", "Go", true,
|
||||
flatbuffers::GenerateGoGRPC,
|
||||
flatbuffers::IDLOptions::kGo,
|
||||
"Generate Go files for tables/structs",
|
||||
flatbuffers::GeneralMakeRule },
|
||||
{ flatbuffers::GenerateGeneral, "-j", "--java", "Java", true,
|
||||
nullptr,
|
||||
flatbuffers::IDLOptions::kJava,
|
||||
"Generate Java classes for tables/structs",
|
||||
flatbuffers::GeneralMakeRule },
|
||||
{ flatbuffers::GenerateJS, "-s", "--js", "JavaScript", true,
|
||||
nullptr,
|
||||
flatbuffers::IDLOptions::kJs,
|
||||
"Generate JavaScript code for tables/structs",
|
||||
flatbuffers::JSMakeRule },
|
||||
{ flatbuffers::GenerateJS, "-T", "--ts", "TypeScript", true,
|
||||
nullptr,
|
||||
flatbuffers::IDLOptions::kTs,
|
||||
"Generate TypeScript code for tables/structs",
|
||||
flatbuffers::JSMakeRule },
|
||||
{ flatbuffers::GenerateGeneral, "-n", "--csharp", "C#", true,
|
||||
nullptr,
|
||||
flatbuffers::IDLOptions::kCSharp,
|
||||
"Generate C# classes for tables/structs",
|
||||
flatbuffers::GeneralMakeRule },
|
||||
{ flatbuffers::GeneratePython, "-p", "--python", "Python", true,
|
||||
nullptr,
|
||||
flatbuffers::IDLOptions::kPython,
|
||||
"Generate Python files for tables/structs",
|
||||
flatbuffers::GeneralMakeRule },
|
||||
{ flatbuffers::GeneratePhp, nullptr, "--php", "PHP", true,
|
||||
nullptr,
|
||||
flatbuffers::IDLOptions::kPhp,
|
||||
"Generate PHP files for tables/structs",
|
||||
flatbuffers::GeneralMakeRule },
|
||||
};
|
||||
|
||||
flatbuffers::FlatCompiler::InitParams params;
|
||||
params.generators = generators;
|
||||
params.num_generators = sizeof(generators) / sizeof(generators[0]);
|
||||
params.warn_fn = Warn;
|
||||
params.error_fn = Error;
|
||||
|
||||
flatbuffers::FlatCompiler flatc(params);
|
||||
return flatc.Compile(argc - 1, argv + 1);
|
||||
}
|
||||
2568
src/idl_gen_cpp.cpp
2568
src/idl_gen_cpp.cpp
File diff suppressed because it is too large
Load Diff
@@ -19,6 +19,7 @@
|
||||
#include "flatbuffers/flatbuffers.h"
|
||||
#include "flatbuffers/idl.h"
|
||||
#include "flatbuffers/util.h"
|
||||
#include "flatbuffers/code_generators.h"
|
||||
|
||||
namespace flatbuffers {
|
||||
|
||||
@@ -71,12 +72,12 @@ std::string GenerateFBS(const Parser &parser, const std::string &file_name) {
|
||||
int num_includes = 0;
|
||||
for (auto it = parser.included_files_.begin();
|
||||
it != parser.included_files_.end(); ++it) {
|
||||
if (it->second.empty())
|
||||
continue;
|
||||
auto basename = flatbuffers::StripPath(
|
||||
flatbuffers::StripExtension(it->first));
|
||||
if (basename != file_name) {
|
||||
schema += "include \"" + basename + ".fbs\";\n";
|
||||
num_includes++;
|
||||
}
|
||||
flatbuffers::StripExtension(it->second));
|
||||
schema += "include \"" + basename + ".fbs\";\n";
|
||||
num_includes++;
|
||||
}
|
||||
if (num_includes) schema += "\n";
|
||||
#endif
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -17,6 +17,7 @@
|
||||
// independent from idl_parser, since this code is not needed for most clients
|
||||
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
|
||||
#include "flatbuffers/flatbuffers.h"
|
||||
#include "flatbuffers/idl.h"
|
||||
@@ -35,6 +36,13 @@
|
||||
namespace flatbuffers {
|
||||
namespace go {
|
||||
|
||||
// see https://golang.org/ref/spec#Keywords
|
||||
static const char *g_golang_keywords[] = {
|
||||
"break", "default", "func", "interface", "select", "case", "defer", "go",
|
||||
"map", "struct", "chan", "else", "goto", "package", "switch", "const",
|
||||
"fallthrough", "if", "range", "type", "continue", "for", "import", "return", "var",
|
||||
};
|
||||
|
||||
static std::string GenGetter(const Type &type);
|
||||
static std::string GenMethod(const FieldDef &field);
|
||||
static void GenStructBuilder(const StructDef &struct_def,
|
||||
@@ -43,6 +51,15 @@ static void GenReceiver(const StructDef &struct_def, std::string *code_ptr);
|
||||
static std::string GenTypeBasic(const Type &type);
|
||||
static std::string GenTypeGet(const Type &type);
|
||||
static std::string TypeName(const FieldDef &field);
|
||||
static std::string GoIdentity(const std::string& name) {
|
||||
for (size_t i=0; i<sizeof(g_golang_keywords)/sizeof(g_golang_keywords[0]); i++) {
|
||||
if (name == g_golang_keywords[i]) {
|
||||
return MakeCamel(name + "_", false);
|
||||
}
|
||||
}
|
||||
|
||||
return MakeCamel(name, false);
|
||||
}
|
||||
|
||||
|
||||
// Most field accessors need to retrieve and test the field offset first,
|
||||
@@ -144,6 +161,23 @@ static void InitializeExisting(const StructDef &struct_def,
|
||||
code += "}\n\n";
|
||||
}
|
||||
|
||||
// Implement the table accessor
|
||||
static void GenTableAccessor(const StructDef &struct_def,
|
||||
std::string *code_ptr) {
|
||||
std::string &code = *code_ptr;
|
||||
|
||||
GenReceiver(struct_def, code_ptr);
|
||||
code += " Table() flatbuffers.Table ";
|
||||
code += "{\n";
|
||||
|
||||
if (struct_def.fixed) {
|
||||
code += "\treturn rcv._tab.Table\n";
|
||||
} else {
|
||||
code += "\treturn rcv._tab\n";
|
||||
}
|
||||
code += "}\n\n";
|
||||
}
|
||||
|
||||
// Get the length of a vector.
|
||||
static void GetVectorLen(const StructDef &struct_def,
|
||||
const FieldDef &field,
|
||||
@@ -288,9 +322,6 @@ static void GetMemberOfVectorOfStruct(const StructDef &struct_def,
|
||||
if (!(vectortype.struct_def->fixed)) {
|
||||
code += "\t\tx = rcv._tab.Indirect(x)\n";
|
||||
}
|
||||
code += "\t\tif obj == nil {\n";
|
||||
code += "\t\t\tobj = new(" + TypeName(field) + ")\n";
|
||||
code += "\t\t}\n";
|
||||
code += "\t\tobj.Init(rcv._tab.Bytes, x)\n";
|
||||
code += "\t\treturn true\n\t}\n";
|
||||
code += "\treturn false\n";
|
||||
@@ -354,7 +385,7 @@ static void StructBuilderArgs(const StructDef &struct_def,
|
||||
} else {
|
||||
std::string &code = *code_ptr;
|
||||
code += (std::string)", " + nameprefix;
|
||||
code += MakeCamel(field.name, false);
|
||||
code += GoIdentity(field.name);
|
||||
code += " " + GenTypeBasic(field.value.type);
|
||||
}
|
||||
}
|
||||
@@ -386,7 +417,7 @@ static void StructBuilderBody(const StructDef &struct_def,
|
||||
code_ptr);
|
||||
} else {
|
||||
code += "\tbuilder.Prepend" + GenMethod(field) + "(";
|
||||
code += nameprefix + MakeCamel(field.name, false) + ")\n";
|
||||
code += nameprefix + GoIdentity(field.name) + ")\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -416,7 +447,7 @@ static void BuildFieldOfTable(const StructDef &struct_def,
|
||||
std::string &code = *code_ptr;
|
||||
code += "func " + struct_def.name + "Add" + MakeCamel(field.name);
|
||||
code += "(builder *flatbuffers.Builder, ";
|
||||
code += MakeCamel(field.name, false) + " ";
|
||||
code += GoIdentity(field.name) + " ";
|
||||
if (!IsScalar(field.value.type.base_type) && (!struct_def.fixed)) {
|
||||
code += "flatbuffers.UOffsetT";
|
||||
} else {
|
||||
@@ -429,9 +460,9 @@ static void BuildFieldOfTable(const StructDef &struct_def,
|
||||
if (!IsScalar(field.value.type.base_type) && (!struct_def.fixed)) {
|
||||
code += "flatbuffers.UOffsetT";
|
||||
code += "(";
|
||||
code += MakeCamel(field.name, false) + ")";
|
||||
code += GoIdentity(field.name) + ")";
|
||||
} else {
|
||||
code += MakeCamel(field.name, false);
|
||||
code += GoIdentity(field.name);
|
||||
}
|
||||
code += ", " + field.value.constant;
|
||||
code += ")\n}\n";
|
||||
@@ -594,6 +625,10 @@ static void GenStruct(const StructDef &struct_def,
|
||||
// Generate the Init method that sets the field in a pre-existing
|
||||
// accessor object. This is to allow object reuse.
|
||||
InitializeExisting(struct_def, code_ptr);
|
||||
// Generate _tab accessor
|
||||
GenTableAccessor(struct_def, code_ptr);
|
||||
|
||||
// Generate struct fields accessors
|
||||
for (auto it = struct_def.fields.vec.begin();
|
||||
it != struct_def.fields.vec.end();
|
||||
++it) {
|
||||
@@ -604,6 +639,7 @@ static void GenStruct(const StructDef &struct_def,
|
||||
GenStructMutator(struct_def, field, code_ptr);
|
||||
}
|
||||
|
||||
// Generate builders
|
||||
if (struct_def.fixed) {
|
||||
// create a struct constructor function
|
||||
GenStructBuilder(struct_def, code_ptr);
|
||||
@@ -705,9 +741,15 @@ static void GenStructBuilder(const StructDef &struct_def,
|
||||
class GoGenerator : public BaseGenerator {
|
||||
public:
|
||||
GoGenerator(const Parser &parser, const std::string &path,
|
||||
const std::string &file_name)
|
||||
: BaseGenerator(parser, path, file_name, "" /* not used*/,
|
||||
"" /* not used */){};
|
||||
const std::string &file_name, const std::string &go_namespace)
|
||||
: BaseGenerator(parser, path, file_name, "" /* not used*/, "" /* not used */) {
|
||||
std::istringstream iss(go_namespace);
|
||||
std::string component;
|
||||
while (std::getline(iss, component, '.')) {
|
||||
go_namespace_.components.push_back(component);
|
||||
}
|
||||
}
|
||||
|
||||
bool generate() {
|
||||
for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
|
||||
++it) {
|
||||
@@ -731,7 +773,7 @@ class GoGenerator : public BaseGenerator {
|
||||
void BeginFile(const std::string name_space_name, const bool needs_imports,
|
||||
std::string *code_ptr) {
|
||||
std::string &code = *code_ptr;
|
||||
code = code + "// " + FlatBuffersGeneratedWarning();
|
||||
code = code + "// " + FlatBuffersGeneratedWarning() + "\n\n";
|
||||
code += "package " + name_space_name + "\n\n";
|
||||
if (needs_imports) {
|
||||
code += "import (\n";
|
||||
@@ -745,19 +787,22 @@ class GoGenerator : public BaseGenerator {
|
||||
bool needs_imports) {
|
||||
if (!classcode.length()) return true;
|
||||
|
||||
Namespace& ns = go_namespace_.components.empty() ? *def.defined_namespace : go_namespace_;
|
||||
std::string code = "";
|
||||
BeginFile(LastNamespacePart(*def.defined_namespace), needs_imports, &code);
|
||||
BeginFile(LastNamespacePart(ns), needs_imports, &code);
|
||||
code += classcode;
|
||||
std::string filename =
|
||||
NamespaceDir(*def.defined_namespace) + def.name + ".go";
|
||||
NamespaceDir(ns) + def.name + ".go";
|
||||
return SaveFile(filename.c_str(), code, false);
|
||||
}
|
||||
|
||||
Namespace go_namespace_;
|
||||
};
|
||||
} // namespace go
|
||||
|
||||
bool GenerateGo(const Parser &parser, const std::string &path,
|
||||
const std::string &file_name) {
|
||||
go::GoGenerator generator(parser, path, file_name);
|
||||
go::GoGenerator generator(parser, path, file_name, parser.opts.go_namespace);
|
||||
return generator.generate();
|
||||
}
|
||||
|
||||
|
||||
@@ -19,12 +19,19 @@
|
||||
#include "flatbuffers/flatbuffers.h"
|
||||
#include "flatbuffers/idl.h"
|
||||
#include "flatbuffers/util.h"
|
||||
#include "flatbuffers/code_generators.h"
|
||||
|
||||
#include "src/compiler/cpp_generator.h"
|
||||
#include "src/compiler/go_generator.h"
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable: 4512) // C4512: 'class' : assignment operator could not be generated
|
||||
#endif
|
||||
|
||||
namespace flatbuffers {
|
||||
|
||||
class FlatBufMethod : public grpc_cpp_generator::Method {
|
||||
class FlatBufMethod : public grpc_generator::Method {
|
||||
public:
|
||||
enum Streaming { kNone, kClient, kServer, kBiDi };
|
||||
|
||||
@@ -39,22 +46,52 @@ class FlatBufMethod : public grpc_cpp_generator::Method {
|
||||
}
|
||||
}
|
||||
|
||||
grpc::string GetLeadingComments(const grpc::string) const {
|
||||
return "";
|
||||
}
|
||||
grpc::string GetTrailingComments(const grpc::string) const {
|
||||
return "";
|
||||
}
|
||||
std::vector<grpc::string> GetAllComments() const {
|
||||
return std::vector<grpc::string>();
|
||||
}
|
||||
|
||||
std::string name() const { return method_->name; }
|
||||
|
||||
std::string GRPCType(const StructDef &sd) const {
|
||||
return "flatbuffers::BufferRef<" + sd.name + ">";
|
||||
return "flatbuffers::grpc::Message<" + sd.name + ">";
|
||||
}
|
||||
|
||||
std::string get_input_type_name() const {
|
||||
return (*method_->request).name;
|
||||
}
|
||||
std::string get_output_type_name() const {
|
||||
return (*method_->response).name;
|
||||
}
|
||||
|
||||
bool get_module_and_message_path_input(
|
||||
grpc::string * /*str*/, grpc::string /*generator_file_name*/,
|
||||
bool /*generate_in_pb2_grpc*/, grpc::string /*import_prefix*/) const {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool get_module_and_message_path_output(
|
||||
grpc::string * /*str*/, grpc::string /*generator_file_name*/,
|
||||
bool /*generate_in_pb2_grpc*/, grpc::string /*import_prefix*/) const {
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string input_type_name() const {
|
||||
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 ClientStreaming() const { return streaming_ == kClient; }
|
||||
bool ServerStreaming() const { return streaming_ == kServer; }
|
||||
bool BidiStreaming() const { return streaming_ == kBiDi; }
|
||||
|
||||
private:
|
||||
@@ -62,18 +99,28 @@ class FlatBufMethod : public grpc_cpp_generator::Method {
|
||||
Streaming streaming_;
|
||||
};
|
||||
|
||||
class FlatBufService : public grpc_cpp_generator::Service {
|
||||
class FlatBufService : public grpc_generator::Service {
|
||||
public:
|
||||
FlatBufService(const ServiceDef *service) : service_(service) {}
|
||||
|
||||
grpc::string GetLeadingComments(const grpc::string) const {
|
||||
return "";
|
||||
}
|
||||
grpc::string GetTrailingComments(const grpc::string) const {
|
||||
return "";
|
||||
}
|
||||
std::vector<grpc::string> GetAllComments() const {
|
||||
return std::vector<grpc::string>();
|
||||
}
|
||||
|
||||
std::string name() const { return service_->name; }
|
||||
|
||||
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>(
|
||||
std::unique_ptr<const grpc_generator::Method> method(int i) const {
|
||||
return std::unique_ptr<const grpc_generator::Method>(
|
||||
new FlatBufMethod(service_->calls.vec[i]));
|
||||
};
|
||||
|
||||
@@ -81,7 +128,7 @@ class FlatBufService : public grpc_cpp_generator::Service {
|
||||
const ServiceDef *service_;
|
||||
};
|
||||
|
||||
class FlatBufPrinter : public grpc_cpp_generator::Printer {
|
||||
class FlatBufPrinter : public grpc_generator::Printer {
|
||||
public:
|
||||
FlatBufPrinter(std::string *str)
|
||||
: str_(str), escape_char_('$'), indent_(0) {}
|
||||
@@ -107,6 +154,9 @@ class FlatBufPrinter : public grpc_cpp_generator::Printer {
|
||||
}
|
||||
|
||||
void Print(const char *s) {
|
||||
if (s == nullptr || std::strlen(s) == 0) {
|
||||
return;
|
||||
}
|
||||
// Add this string, but for each part separated by \n, add indentation.
|
||||
for (;;) {
|
||||
// Current indentation.
|
||||
@@ -133,12 +183,28 @@ class FlatBufPrinter : public grpc_cpp_generator::Printer {
|
||||
int indent_;
|
||||
};
|
||||
|
||||
class FlatBufFile : public grpc_cpp_generator::File {
|
||||
class FlatBufFile : public grpc_generator::File {
|
||||
public:
|
||||
FlatBufFile(const Parser &parser, const std::string &file_name)
|
||||
: parser_(parser), file_name_(file_name) {}
|
||||
enum Language {
|
||||
kLanguageGo,
|
||||
kLanguageCpp
|
||||
};
|
||||
|
||||
FlatBufFile(
|
||||
const Parser &parser, const std::string &file_name, Language language)
|
||||
: parser_(parser), file_name_(file_name), language_(language) {}
|
||||
FlatBufFile &operator=(const FlatBufFile &);
|
||||
|
||||
grpc::string GetLeadingComments(const grpc::string) const {
|
||||
return "";
|
||||
}
|
||||
grpc::string GetTrailingComments(const grpc::string) const {
|
||||
return "";
|
||||
}
|
||||
std::vector<grpc::string> GetAllComments() const {
|
||||
return std::vector<grpc::string>();
|
||||
}
|
||||
|
||||
std::string filename() const { return file_name_; }
|
||||
std::string filename_without_ext() const {
|
||||
return StripExtension(file_name_);
|
||||
@@ -156,30 +222,79 @@ class FlatBufFile : public grpc_cpp_generator::File {
|
||||
}
|
||||
|
||||
std::string additional_headers() const {
|
||||
return "#include \"flatbuffers/grpc.h\"\n";
|
||||
switch (language_) {
|
||||
case kLanguageCpp: {
|
||||
return "#include \"flatbuffers/grpc.h\"\n";
|
||||
}
|
||||
case kLanguageGo: {
|
||||
return "import \"github.com/google/flatbuffers/go\"";
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
int service_count() const {
|
||||
return static_cast<int>(parser_.services_.vec.size());
|
||||
};
|
||||
|
||||
std::unique_ptr<const grpc_cpp_generator::Service> service(int i) const {
|
||||
return std::unique_ptr<const grpc_cpp_generator::Service> (
|
||||
std::unique_ptr<const grpc_generator::Service> service(int i) const {
|
||||
return std::unique_ptr<const grpc_generator::Service> (
|
||||
new FlatBufService(parser_.services_.vec[i]));
|
||||
}
|
||||
|
||||
std::unique_ptr<grpc_cpp_generator::Printer> CreatePrinter(std::string *str) const {
|
||||
return std::unique_ptr<grpc_cpp_generator::Printer>(
|
||||
std::unique_ptr<grpc_generator::Printer> CreatePrinter(std::string *str) const {
|
||||
return std::unique_ptr<grpc_generator::Printer>(
|
||||
new FlatBufPrinter(str));
|
||||
}
|
||||
|
||||
private:
|
||||
const Parser &parser_;
|
||||
const std::string &file_name_;
|
||||
const Language language_;
|
||||
};
|
||||
|
||||
bool GenerateGRPC(const Parser &parser,
|
||||
const std::string &/*path*/,
|
||||
class GoGRPCGenerator : public flatbuffers::BaseGenerator {
|
||||
public:
|
||||
GoGRPCGenerator(const Parser &parser, const std::string &path,
|
||||
const std::string &file_name)
|
||||
: BaseGenerator(parser, path, file_name, "", "" /*Unused*/),
|
||||
parser_(parser), path_(path), file_name_(file_name) {}
|
||||
|
||||
bool generate() {
|
||||
FlatBufFile file(parser_, file_name_, FlatBufFile::kLanguageGo);
|
||||
grpc_go_generator::Parameters p;
|
||||
p.custom_method_io_type = "flatbuffers.Builder";
|
||||
for (int i = 0; i < file.service_count(); i++) {
|
||||
auto service = file.service(i);
|
||||
const Definition *def = parser_.services_.vec[i];
|
||||
p.package_name = LastNamespacePart(*(def->defined_namespace));
|
||||
std::string output = grpc_go_generator::GenerateServiceSource(&file, service.get(), &p);
|
||||
std::string filename = NamespaceDir(*def->defined_namespace) + def->name + "_grpc.go";
|
||||
if (!flatbuffers::SaveFile(filename.c_str(), output, false))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
protected:
|
||||
const Parser &parser_;
|
||||
const std::string &path_, &file_name_;
|
||||
};
|
||||
|
||||
bool GenerateGoGRPC(const Parser &parser,
|
||||
const std::string &path,
|
||||
const std::string &file_name) {
|
||||
int nservices = 0;
|
||||
for (auto it = parser.services_.vec.begin();
|
||||
it != parser.services_.vec.end(); ++it) {
|
||||
if (!(*it)->generated) nservices++;
|
||||
}
|
||||
if (!nservices) return true;
|
||||
return GoGRPCGenerator(parser, path, file_name).generate();
|
||||
}
|
||||
|
||||
bool GenerateCppGRPC(const Parser &parser,
|
||||
const std::string &path,
|
||||
const std::string &file_name) {
|
||||
|
||||
int nservices = 0;
|
||||
@@ -193,7 +308,7 @@ bool GenerateGRPC(const Parser &parser,
|
||||
// TODO(wvo): make the other parameters in this struct configurable.
|
||||
generator_parameters.use_system_headers = true;
|
||||
|
||||
FlatBufFile fbfile(parser, file_name);
|
||||
FlatBufFile fbfile(parser, file_name, FlatBufFile::kLanguageCpp);
|
||||
|
||||
std::string header_code =
|
||||
grpc_cpp_generator::GetHeaderPrologue(&fbfile, generator_parameters) +
|
||||
@@ -207,11 +322,15 @@ bool GenerateGRPC(const Parser &parser,
|
||||
grpc_cpp_generator::GetSourceServices(&fbfile, generator_parameters) +
|
||||
grpc_cpp_generator::GetSourceEpilogue(&fbfile, generator_parameters);
|
||||
|
||||
return flatbuffers::SaveFile((file_name + ".grpc.fb.h").c_str(),
|
||||
return flatbuffers::SaveFile((path + file_name + ".grpc.fb.h").c_str(),
|
||||
header_code, false) &&
|
||||
flatbuffers::SaveFile((file_name + ".grpc.fb.cc").c_str(),
|
||||
flatbuffers::SaveFile((path + file_name + ".grpc.fb.cc").c_str(),
|
||||
source_code, false);
|
||||
}
|
||||
|
||||
} // namespace flatbuffers
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
|
||||
@@ -15,6 +15,9 @@
|
||||
*/
|
||||
|
||||
// independent from idl_parser, since this code is not needed for most clients
|
||||
#include <unordered_set>
|
||||
#include <unordered_map>
|
||||
#include <cassert>
|
||||
|
||||
#include "flatbuffers/flatbuffers.h"
|
||||
#include "flatbuffers/idl.h"
|
||||
@@ -23,9 +26,43 @@
|
||||
|
||||
namespace flatbuffers {
|
||||
|
||||
const std::string kGeneratedFileNamePostfix = "_generated";
|
||||
|
||||
struct JsLanguageParameters {
|
||||
IDLOptions::Language language;
|
||||
std::string file_extension;
|
||||
};
|
||||
|
||||
struct ReexportDescription {
|
||||
std::string symbol;
|
||||
std::string source_namespace;
|
||||
std::string target_namespace;
|
||||
};
|
||||
|
||||
const JsLanguageParameters& GetJsLangParams(IDLOptions::Language lang) {
|
||||
static JsLanguageParameters js_language_parameters[] = {
|
||||
{
|
||||
IDLOptions::kJs,
|
||||
".js",
|
||||
},
|
||||
{
|
||||
IDLOptions::kTs,
|
||||
".ts",
|
||||
},
|
||||
};
|
||||
|
||||
if (lang == IDLOptions::kJs) {
|
||||
return js_language_parameters[0];
|
||||
} else {
|
||||
assert(lang == IDLOptions::kTs);
|
||||
return js_language_parameters[1];
|
||||
}
|
||||
}
|
||||
|
||||
static std::string GeneratedFileName(const std::string &path,
|
||||
const std::string &file_name) {
|
||||
return path + file_name + "_generated.js";
|
||||
const std::string &file_name,
|
||||
const JsLanguageParameters &lang) {
|
||||
return path + file_name + kGeneratedFileNamePostfix + lang.file_extension;
|
||||
}
|
||||
|
||||
namespace js {
|
||||
@@ -33,56 +70,127 @@ namespace js {
|
||||
// and tables) and output them to a single file.
|
||||
class JsGenerator : public BaseGenerator {
|
||||
public:
|
||||
typedef std::unordered_set<std::string> imported_fileset;
|
||||
typedef std::unordered_multimap<std::string, ReexportDescription>
|
||||
reexport_map;
|
||||
|
||||
JsGenerator(const Parser &parser, const std::string &path,
|
||||
const std::string &file_name)
|
||||
: BaseGenerator(parser, path, file_name, "", "."){};
|
||||
: BaseGenerator(parser, path, file_name, "", "."),
|
||||
lang_(GetJsLangParams(parser_.opts.lang))
|
||||
{
|
||||
};
|
||||
// Iterate through all definitions we haven't generate code for (enums,
|
||||
// structs, and tables) and output them to a single file.
|
||||
bool generate() {
|
||||
if (IsEverythingGenerated()) return true;
|
||||
imported_fileset imported_files;
|
||||
reexport_map reexports;
|
||||
|
||||
std::string enum_code, struct_code, exports_code, code;
|
||||
generateEnums(&enum_code, &exports_code);
|
||||
generateStructs(&struct_code, &exports_code);
|
||||
std::string enum_code, struct_code, import_code, exports_code, code;
|
||||
generateEnums(&enum_code, &exports_code, reexports);
|
||||
generateStructs(&struct_code, &exports_code, imported_files);
|
||||
generateImportDependencies(&import_code, imported_files);
|
||||
generateReexports(&import_code, reexports, imported_files);
|
||||
|
||||
code = code + "// " + FlatBuffersGeneratedWarning();
|
||||
code = code + "// " + FlatBuffersGeneratedWarning() + "\n\n";
|
||||
|
||||
// Generate code for all the namespace declarations.
|
||||
GenNamespaces(&code, &exports_code);
|
||||
|
||||
// Output the main declaration code from above.
|
||||
code += import_code;
|
||||
|
||||
code += enum_code;
|
||||
code += struct_code;
|
||||
|
||||
if (!exports_code.empty() && !parser_.opts.skip_js_exports) {
|
||||
if (lang_.language == IDLOptions::kJs && !exports_code.empty() &&
|
||||
!parser_.opts.skip_js_exports) {
|
||||
code += "// Exports for Node.js and RequireJS\n";
|
||||
code += exports_code;
|
||||
}
|
||||
|
||||
return SaveFile(GeneratedFileName(path_, file_name_).c_str(), code, false);
|
||||
return SaveFile(GeneratedFileName(path_, file_name_, lang_).c_str(), code,
|
||||
false);
|
||||
}
|
||||
|
||||
private:
|
||||
JsLanguageParameters lang_;
|
||||
|
||||
// Generate code for imports
|
||||
void generateImportDependencies(std::string *code_ptr,
|
||||
const imported_fileset &imported_files) {
|
||||
std::string &code = *code_ptr;
|
||||
for (auto it = imported_files.begin(); it != imported_files.end(); ++it) {
|
||||
const auto &file = *it;
|
||||
const auto basename =
|
||||
flatbuffers::StripPath(flatbuffers::StripExtension(file));
|
||||
if (basename != file_name_) {
|
||||
const auto file_name = basename + kGeneratedFileNamePostfix;
|
||||
code += GenPrefixedImport(file, file_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Generate reexports, which might not have been explicitly imported using the
|
||||
// "export import" trick
|
||||
void generateReexports(std::string *code_ptr,
|
||||
const reexport_map &reexports,
|
||||
imported_fileset imported_files) {
|
||||
if (!parser_.opts.reexport_ts_modules ||
|
||||
lang_.language != IDLOptions::kTs) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::string &code = *code_ptr;
|
||||
for (auto it = reexports.begin(); it != reexports.end(); ++it) {
|
||||
const auto &file = *it;
|
||||
const auto basename =
|
||||
flatbuffers::StripPath(flatbuffers::StripExtension(file.first));
|
||||
if (basename != file_name_) {
|
||||
const auto file_name = basename + kGeneratedFileNamePostfix;
|
||||
|
||||
if (imported_files.find(file.first) == imported_files.end()) {
|
||||
code += GenPrefixedImport(file.first, file_name);
|
||||
imported_files.emplace(file.first);
|
||||
}
|
||||
|
||||
code += "export namespace " + file.second.target_namespace + " { \n";
|
||||
code += "export import " + file.second.symbol + " = ";
|
||||
code += GenFileNamespacePrefix(file.first) + "." +
|
||||
file.second.source_namespace + "." + file.second.symbol +
|
||||
"; }\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Generate code for all enums.
|
||||
void generateEnums(std::string *enum_code_ptr,
|
||||
std::string *exports_code_ptr) {
|
||||
std::string *exports_code_ptr,
|
||||
reexport_map &reexports) {
|
||||
for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
|
||||
++it) {
|
||||
auto &enum_def = **it;
|
||||
GenEnum(enum_def, enum_code_ptr, exports_code_ptr);
|
||||
GenEnum(enum_def, enum_code_ptr, exports_code_ptr, reexports);
|
||||
}
|
||||
}
|
||||
|
||||
// Generate code for all structs.
|
||||
void generateStructs(std::string *decl_code_ptr,
|
||||
std::string *exports_code_ptr) {
|
||||
std::string *exports_code_ptr,
|
||||
imported_fileset &imported_files) {
|
||||
for (auto it = parser_.structs_.vec.begin();
|
||||
it != parser_.structs_.vec.end(); ++it) {
|
||||
auto &struct_def = **it;
|
||||
GenStruct(parser_, struct_def, decl_code_ptr, exports_code_ptr);
|
||||
GenStruct(parser_, struct_def, decl_code_ptr, exports_code_ptr,
|
||||
imported_files);
|
||||
}
|
||||
}
|
||||
void GenNamespaces(std::string *code_ptr, std::string *exports_ptr) {
|
||||
if (lang_.language == IDLOptions::kTs &&
|
||||
parser_.opts.skip_flatbuffers_import) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::set<std::string> namespaces;
|
||||
|
||||
for (auto it = parser_.namespaces_.begin();
|
||||
@@ -110,12 +218,23 @@ class JsGenerator : public BaseGenerator {
|
||||
std::string &exports = *exports_ptr;
|
||||
for (auto it = sorted_namespaces.begin();
|
||||
it != sorted_namespaces.end(); it++) {
|
||||
code += "/**\n * @const\n * @namespace\n */\n";
|
||||
if (it->find('.') == std::string::npos) {
|
||||
code += "var ";
|
||||
exports += "this." + *it + " = " + *it + ";\n";
|
||||
if (lang_.language == IDLOptions::kTs) {
|
||||
if (it->find('.') == std::string::npos) {
|
||||
code += "import { flatbuffers } from \"./flatbuffers\"\n";
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
code += "/**\n * @const\n * @namespace\n */\n";
|
||||
if (it->find('.') == std::string::npos) {
|
||||
code += "var ";
|
||||
if(parser_.opts.use_goog_js_export_format) {
|
||||
exports += "goog.exportSymbol('" + *it + "', " + *it + ");\n";
|
||||
} else {
|
||||
exports += "this." + *it + " = " + *it + ";\n";
|
||||
}
|
||||
}
|
||||
code += *it + " = " + *it + " || {};\n\n";
|
||||
}
|
||||
code += *it + " = " + *it + " || {};\n\n";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -165,16 +284,26 @@ static void GenDocComment(std::string *code_ptr,
|
||||
|
||||
// Generate an enum declaration and an enum string lookup table.
|
||||
void GenEnum(EnumDef &enum_def, std::string *code_ptr,
|
||||
std::string *exports_ptr) {
|
||||
std::string *exports_ptr, reexport_map &reexports) {
|
||||
if (enum_def.generated) return;
|
||||
std::string &code = *code_ptr;
|
||||
std::string &exports = *exports_ptr;
|
||||
GenDocComment(enum_def.doc_comment, code_ptr, "@enum");
|
||||
if (enum_def.defined_namespace->components.empty()) {
|
||||
code += "var ";
|
||||
exports += "this." + enum_def.name + " = " + enum_def.name + ";\n";
|
||||
if (lang_.language == IDLOptions::kTs) {
|
||||
code += "export namespace " + GetNameSpace(enum_def) + "{\n" +
|
||||
"export enum " + enum_def.name + "{\n";
|
||||
} else {
|
||||
if (enum_def.defined_namespace->components.empty()) {
|
||||
code += "var ";
|
||||
if(parser_.opts.use_goog_js_export_format) {
|
||||
exports += "goog.exportSymbol('" + enum_def.name + "', " +
|
||||
enum_def.name + ");\n";
|
||||
} else {
|
||||
exports += "this." + enum_def.name + " = " + enum_def.name + ";\n";
|
||||
}
|
||||
}
|
||||
code += WrapInNameSpace(enum_def) + " = {\n";
|
||||
}
|
||||
code += WrapInNameSpace(enum_def) + " = {\n";
|
||||
for (auto it = enum_def.vals.vec.begin();
|
||||
it != enum_def.vals.vec.end(); ++it) {
|
||||
auto &ev = **it;
|
||||
@@ -184,10 +313,27 @@ void GenEnum(EnumDef &enum_def, std::string *code_ptr,
|
||||
}
|
||||
GenDocComment(ev.doc_comment, code_ptr, "", " ");
|
||||
}
|
||||
code += " " + ev.name + ": " + NumToString(ev.value);
|
||||
code += " " + ev.name;
|
||||
code += lang_.language == IDLOptions::kTs ? "= " : ": ";
|
||||
code += NumToString(ev.value);
|
||||
code += (it + 1) != enum_def.vals.vec.end() ? ",\n" : "\n";
|
||||
|
||||
if (ev.union_type.struct_def) {
|
||||
ReexportDescription desc = {
|
||||
ev.name,
|
||||
GetNameSpace(*ev.union_type.struct_def),
|
||||
GetNameSpace(enum_def)
|
||||
};
|
||||
reexports.insert(std::make_pair(ev.union_type.struct_def->file,
|
||||
std::move(desc)));
|
||||
}
|
||||
}
|
||||
|
||||
if (lang_.language == IDLOptions::kTs) {
|
||||
code += "}};\n\n";
|
||||
} else {
|
||||
code += "};\n\n";
|
||||
}
|
||||
code += "};\n\n";
|
||||
}
|
||||
|
||||
static std::string GenType(const Type &type) {
|
||||
@@ -235,7 +381,15 @@ 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)) {
|
||||
return WrapInNameSpace(*value.type.enum_def) + "." + val->name;
|
||||
if (lang_.language == IDLOptions::kTs) {
|
||||
return GenPrefixedTypeName(WrapInNameSpace(*value.type.enum_def),
|
||||
value.type.enum_def->file) + "." + val->name;
|
||||
} else {
|
||||
return WrapInNameSpace(*value.type.enum_def) + "." + val->name;
|
||||
}
|
||||
} else {
|
||||
return "/** @type {" + WrapInNameSpace(*value.type.enum_def) + "} */ ("
|
||||
+ value.constant + ")";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -258,13 +412,16 @@ std::string GenDefaultValue(const Value &value, const std::string &context) {
|
||||
}
|
||||
}
|
||||
|
||||
std::string GenTypeName(const Type &type, bool input) {
|
||||
std::string GenTypeName(const Type &type, bool input, bool allowNull = false) {
|
||||
if (!input) {
|
||||
if (type.base_type == BASE_TYPE_STRING) {
|
||||
return "string|Uint8Array";
|
||||
}
|
||||
if (type.base_type == BASE_TYPE_STRUCT) {
|
||||
return WrapInNameSpace(*type.struct_def);
|
||||
if (type.base_type == BASE_TYPE_STRING || type.base_type == BASE_TYPE_STRUCT) {
|
||||
std::string name;
|
||||
if (type.base_type == BASE_TYPE_STRING) {
|
||||
name = "string|Uint8Array";
|
||||
} else {
|
||||
name = WrapInNameSpace(*type.struct_def);
|
||||
}
|
||||
return (allowNull) ? (name + "|null") : (name);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -310,6 +467,28 @@ static std::string MaybeScale(T value) {
|
||||
return value != 1 ? " * " + NumToString(value) : "";
|
||||
}
|
||||
|
||||
static std::string GenFileNamespacePrefix(const std::string &file) {
|
||||
return "NS" + std::to_string(
|
||||
static_cast<unsigned long long>(std::hash<std::string>()(file)));
|
||||
}
|
||||
|
||||
static std::string GenPrefixedImport(const std::string &full_file_name,
|
||||
const std::string &base_file_name) {
|
||||
return "import * as "+ GenFileNamespacePrefix(full_file_name) +
|
||||
" from \"./" + base_file_name + "\";\n";
|
||||
}
|
||||
|
||||
// Adds a source-dependent prefix, for of import * statements.
|
||||
std::string GenPrefixedTypeName(const std::string &typeName,
|
||||
const std::string &file) {
|
||||
const auto basename =
|
||||
flatbuffers::StripPath(flatbuffers::StripExtension(file));
|
||||
if (basename == file_name_) {
|
||||
return typeName;
|
||||
}
|
||||
return GenFileNamespacePrefix(file) + "." + typeName;
|
||||
}
|
||||
|
||||
void GenStructArgs(const StructDef &struct_def,
|
||||
std::string *annotations,
|
||||
std::string *arguments,
|
||||
@@ -326,7 +505,13 @@ void GenStructArgs(const StructDef &struct_def,
|
||||
} else {
|
||||
*annotations += "@param {" + GenTypeName(field.value.type, true);
|
||||
*annotations += "} " + nameprefix + field.name + "\n";
|
||||
*arguments += ", " + nameprefix + field.name;
|
||||
|
||||
if (lang_.language == IDLOptions::kTs) {
|
||||
*arguments += ", " + nameprefix + field.name + ": " +
|
||||
GenTypeName(field.value.type, true);
|
||||
} else {
|
||||
*arguments += ", " + nameprefix + field.name;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -361,32 +546,59 @@ static void GenStructBody(const StructDef &struct_def,
|
||||
}
|
||||
|
||||
// Generate an accessor struct with constructor for a flatbuffers struct.
|
||||
void GenStruct(const Parser &parser, StructDef &struct_def, std::string *code_ptr, std::string *exports_ptr) {
|
||||
void GenStruct(const Parser &parser, StructDef &struct_def,
|
||||
std::string *code_ptr, std::string *exports_ptr,
|
||||
imported_fileset &imported_files) {
|
||||
if (struct_def.generated) return;
|
||||
std::string &code = *code_ptr;
|
||||
std::string &exports = *exports_ptr;
|
||||
|
||||
std::string object_name;
|
||||
|
||||
// Emit constructor
|
||||
bool isStatement = struct_def.defined_namespace->components.empty();
|
||||
std::string object_name = WrapInNameSpace(struct_def);
|
||||
GenDocComment(struct_def.doc_comment, code_ptr, "@constructor");
|
||||
if (isStatement) {
|
||||
exports += "this." + struct_def.name + " = " + struct_def.name + ";\n";
|
||||
code += "function " + object_name;
|
||||
if (lang_.language == IDLOptions::kTs) {
|
||||
object_name = struct_def.name;
|
||||
std::string object_namespace = GetNameSpace(struct_def);
|
||||
GenDocComment(struct_def.doc_comment, code_ptr, "@constructor");
|
||||
code += "export namespace " + object_namespace + "{\n";
|
||||
code += "export class " + struct_def.name;
|
||||
code += " {\n";
|
||||
code += " /**\n";
|
||||
code += " * @type {flatbuffers.ByteBuffer}\n";
|
||||
code += " */\n";
|
||||
code += " bb: flatbuffers.ByteBuffer;\n";
|
||||
code += "\n";
|
||||
code += " /**\n";
|
||||
code += " * @type {number}\n";
|
||||
code += " */\n";
|
||||
code += " bb_pos:number = 0;\n";
|
||||
} else {
|
||||
code += object_name + " = function";
|
||||
bool isStatement = struct_def.defined_namespace->components.empty();
|
||||
object_name = WrapInNameSpace(struct_def);
|
||||
GenDocComment(struct_def.doc_comment, code_ptr, "@constructor");
|
||||
if (isStatement) {
|
||||
if(parser_.opts.use_goog_js_export_format) {
|
||||
exports += "goog.exportSymbol('" + struct_def.name + "', " +
|
||||
struct_def.name + ");\n";
|
||||
} else {
|
||||
exports += "this." + struct_def.name + " = " + struct_def.name + ";\n";
|
||||
}
|
||||
code += "function " + object_name;
|
||||
} else {
|
||||
code += object_name + " = function";
|
||||
}
|
||||
code += "() {\n";
|
||||
code += " /**\n";
|
||||
code += " * @type {flatbuffers.ByteBuffer}\n";
|
||||
code += " */\n";
|
||||
code += " this.bb = null;\n";
|
||||
code += "\n";
|
||||
code += " /**\n";
|
||||
code += " * @type {number}\n";
|
||||
code += " */\n";
|
||||
code += " this.bb_pos = 0;\n";
|
||||
code += isStatement ? "}\n\n" : "};\n\n";
|
||||
}
|
||||
code += "() {\n";
|
||||
code += " /**\n";
|
||||
code += " * @type {flatbuffers.ByteBuffer}\n";
|
||||
code += " */\n";
|
||||
code += " this.bb = null;\n";
|
||||
code += "\n";
|
||||
code += " /**\n";
|
||||
code += " * @type {number}\n";
|
||||
code += " */\n";
|
||||
code += " this.bb_pos = 0;\n";
|
||||
code += isStatement ? "}\n\n" : "};\n\n";
|
||||
|
||||
// Generate the __init method that sets the field in a pre-existing
|
||||
// accessor object. This is to allow object reuse.
|
||||
@@ -395,7 +607,14 @@ void GenStruct(const Parser &parser, StructDef &struct_def, std::string *code_pt
|
||||
code += " * @param {flatbuffers.ByteBuffer} bb\n";
|
||||
code += " * @returns {" + object_name + "}\n";
|
||||
code += " */\n";
|
||||
code += object_name + ".prototype.__init = function(i, bb) {\n";
|
||||
|
||||
if (lang_.language == IDLOptions::kTs) {
|
||||
code += "__init(i:number, bb:flatbuffers.ByteBuffer):" + object_name +
|
||||
" {\n";
|
||||
} else {
|
||||
code += object_name + ".prototype.__init = function(i, bb) {\n";
|
||||
}
|
||||
|
||||
code += " this.bb_pos = i;\n";
|
||||
code += " this.bb = bb;\n";
|
||||
code += " return this;\n";
|
||||
@@ -408,8 +627,14 @@ void GenStruct(const Parser &parser, StructDef &struct_def, std::string *code_pt
|
||||
"@param {flatbuffers.ByteBuffer} bb\n"
|
||||
"@param {" + object_name + "=} obj\n"
|
||||
"@returns {" + object_name + "}");
|
||||
code += object_name + ".getRootAs" + struct_def.name;
|
||||
code += " = function(bb, obj) {\n";
|
||||
if (lang_.language == IDLOptions::kTs) {
|
||||
code += "static getRootAs" + struct_def.name;
|
||||
code += "(bb:flatbuffers.ByteBuffer, obj?:" + object_name + "):" +
|
||||
object_name + " {\n";
|
||||
} else {
|
||||
code += object_name + ".getRootAs" + struct_def.name;
|
||||
code += " = function(bb, obj) {\n";
|
||||
}
|
||||
code += " return (obj || new " + object_name;
|
||||
code += ").__init(bb.readInt32(bb.position()) + bb.position(), bb);\n";
|
||||
code += "};\n\n";
|
||||
@@ -420,7 +645,13 @@ void GenStruct(const Parser &parser, StructDef &struct_def, std::string *code_pt
|
||||
GenDocComment(code_ptr,
|
||||
"@param {flatbuffers.ByteBuffer} bb\n"
|
||||
"@returns {boolean}");
|
||||
code += object_name + ".bufferHasIdentifier = function(bb) {\n";
|
||||
if (lang_.language == IDLOptions::kTs) {
|
||||
code +=
|
||||
"static bufferHasIdentifier(bb:flatbuffers.ByteBuffer):boolean {\n";
|
||||
} else {
|
||||
code += object_name + ".bufferHasIdentifier = function(bb) {\n";
|
||||
}
|
||||
|
||||
code += " return bb.__has_identifier('" + parser_.file_identifier_;
|
||||
code += "');\n};\n\n";
|
||||
}
|
||||
@@ -440,13 +671,33 @@ void GenStruct(const Parser &parser, StructDef &struct_def, std::string *code_pt
|
||||
GenDocComment(field.doc_comment, code_ptr,
|
||||
std::string(field.value.type.base_type == BASE_TYPE_STRING ?
|
||||
"@param {flatbuffers.Encoding=} optionalEncoding\n" : "") +
|
||||
"@returns {" + GenTypeName(field.value.type, false) + "}");
|
||||
code += object_name + ".prototype." + MakeCamel(field.name, false);
|
||||
code += " = function(";
|
||||
if (field.value.type.base_type == BASE_TYPE_STRING) {
|
||||
code += "optionalEncoding";
|
||||
"@returns {" + GenTypeName(field.value.type, false, true) + "}");
|
||||
if (lang_.language == IDLOptions::kTs) {
|
||||
std::string prefix = MakeCamel(field.name, false) + "(";
|
||||
if (field.value.type.base_type == BASE_TYPE_STRING) {
|
||||
code += prefix + "):string|null\n";
|
||||
code += prefix + "optionalEncoding:flatbuffers.Encoding"+"):" +
|
||||
GenTypeName(field.value.type, false, true)+"\n";
|
||||
code += prefix + "optionalEncoding?:any";
|
||||
} else {
|
||||
code += prefix;
|
||||
}
|
||||
if (field.value.type.enum_def) {
|
||||
code += "):" +
|
||||
GenPrefixedTypeName(GenTypeName(field.value.type, false, true),
|
||||
field.value.type.enum_def->file) + " {\n";
|
||||
} else {
|
||||
code += "):" + GenTypeName(field.value.type, false, true) + " {\n";
|
||||
}
|
||||
} else {
|
||||
code += object_name + ".prototype." + MakeCamel(field.name, false);
|
||||
code += " = function(";
|
||||
if (field.value.type.base_type == BASE_TYPE_STRING) {
|
||||
code += "optionalEncoding";
|
||||
}
|
||||
code += ") {\n";
|
||||
}
|
||||
code += ") {\n";
|
||||
|
||||
if (struct_def.fixed) {
|
||||
code += " return " + GenGetter(field.value.type, "(this.bb_pos" +
|
||||
MaybeAdd(field.value.offset) + ")") + ";\n";
|
||||
@@ -467,9 +718,16 @@ void GenStruct(const Parser &parser, StructDef &struct_def, std::string *code_pt
|
||||
case BASE_TYPE_STRUCT: {
|
||||
auto type = WrapInNameSpace(*field.value.type.struct_def);
|
||||
GenDocComment(field.doc_comment, code_ptr,
|
||||
"@param {" + type + "=} obj\n@returns {" + type + "}");
|
||||
code += object_name + ".prototype." + MakeCamel(field.name, false);
|
||||
code += " = function(obj) {\n";
|
||||
"@param {" + type + "=} obj\n@returns {" + type + "|null}");
|
||||
if (lang_.language == IDLOptions::kTs) {
|
||||
type = GenPrefixedTypeName(type, field.value.type.struct_def->file);
|
||||
code += MakeCamel(field.name, false);
|
||||
code += "(obj?:" + type + "):" + type + "|null {\n";
|
||||
} else {
|
||||
code += object_name + ".prototype." + MakeCamel(field.name, false);
|
||||
code += " = function(obj) {\n";
|
||||
}
|
||||
|
||||
if (struct_def.fixed) {
|
||||
code += " return (obj || new " + type;
|
||||
code += ").__init(this.bb_pos";
|
||||
@@ -481,6 +739,11 @@ void GenStruct(const Parser &parser, StructDef &struct_def, std::string *code_pt
|
||||
: "this.bb.__indirect(this.bb_pos + offset)";
|
||||
code += ", this.bb) : null;\n";
|
||||
}
|
||||
|
||||
if (lang_.language == IDLOptions::kTs) {
|
||||
imported_files.insert(field.value.type.struct_def->file);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -498,14 +761,34 @@ void GenStruct(const Parser &parser, StructDef &struct_def, std::string *code_pt
|
||||
}
|
||||
GenDocComment(field.doc_comment, code_ptr, args +
|
||||
"@returns {" + vectortypename + "}");
|
||||
code += object_name + ".prototype." + MakeCamel(field.name, false);
|
||||
code += " = function(index";
|
||||
if (vectortype.base_type == BASE_TYPE_STRUCT) {
|
||||
code += ", obj";
|
||||
} else if (vectortype.base_type == BASE_TYPE_STRING) {
|
||||
code += ", optionalEncoding";
|
||||
if (lang_.language == IDLOptions::kTs) {
|
||||
std::string prefix = MakeCamel(field.name, false);
|
||||
prefix += "(index: number";
|
||||
if (vectortype.base_type == BASE_TYPE_STRUCT) {
|
||||
vectortypename = GenPrefixedTypeName(vectortypename,
|
||||
vectortype.struct_def->file);
|
||||
code += prefix + ", obj?:" + vectortypename;
|
||||
imported_files.insert(vectortype.struct_def->file);
|
||||
} else if (vectortype.base_type == BASE_TYPE_STRING) {
|
||||
code += prefix + "):string\n";
|
||||
code += prefix + ",optionalEncoding:flatbuffers.Encoding" + "):" +
|
||||
vectortypename + "\n";
|
||||
code += prefix + ",optionalEncoding?:any";
|
||||
} else {
|
||||
code += prefix;
|
||||
}
|
||||
code += "):" + vectortypename + "|null {\n";
|
||||
} else {
|
||||
code += object_name + ".prototype." + MakeCamel(field.name, false);
|
||||
code += " = function(index";
|
||||
if (vectortype.base_type == BASE_TYPE_STRUCT) {
|
||||
code += ", obj";
|
||||
} else if (vectortype.base_type == BASE_TYPE_STRING) {
|
||||
code += ", optionalEncoding";
|
||||
}
|
||||
code += ") {\n";
|
||||
}
|
||||
code += ") {\n";
|
||||
|
||||
if (vectortype.base_type == BASE_TYPE_STRUCT) {
|
||||
code += offset_prefix + "(obj || new " + vectortypename;
|
||||
code += ").__init(";
|
||||
@@ -526,7 +809,13 @@ void GenStruct(const Parser &parser, StructDef &struct_def, std::string *code_pt
|
||||
field.value.type.element == BASE_TYPE_ULONG) {
|
||||
code += "this.bb.createLong(0, 0)";
|
||||
} else if (IsScalar(field.value.type.element)) {
|
||||
code += "0";
|
||||
if (field.value.type.enum_def) {
|
||||
code += "/** @type {" +
|
||||
WrapInNameSpace(*field.value.type.enum_def) + "} */ (" +
|
||||
field.value.constant + ")";
|
||||
} else {
|
||||
code += "0";
|
||||
}
|
||||
} else {
|
||||
code += "null";
|
||||
}
|
||||
@@ -538,8 +827,14 @@ void GenStruct(const Parser &parser, StructDef &struct_def, std::string *code_pt
|
||||
GenDocComment(field.doc_comment, code_ptr,
|
||||
"@param {flatbuffers.Table} obj\n"
|
||||
"@returns {?flatbuffers.Table}");
|
||||
code += object_name + ".prototype." + MakeCamel(field.name, false);
|
||||
code += " = function(obj) {\n";
|
||||
if (lang_.language == IDLOptions::kTs) {
|
||||
code += MakeCamel(field.name, false);
|
||||
code += "<T extends flatbuffers.Table>(obj:T):T|null {\n";
|
||||
} else {
|
||||
code += object_name + ".prototype." + MakeCamel(field.name, false);
|
||||
code += " = function(obj) {\n";
|
||||
}
|
||||
|
||||
code += offset_prefix + GenGetter(field.value.type,
|
||||
"(obj, this.bb_pos + offset)") + " : null;\n";
|
||||
break;
|
||||
@@ -550,39 +845,102 @@ void GenStruct(const Parser &parser, StructDef &struct_def, std::string *code_pt
|
||||
}
|
||||
code += "};\n\n";
|
||||
|
||||
if(parser_.opts.use_goog_js_export_format) {
|
||||
exports += "goog.exportProperty(" + object_name + ".prototype, '" +
|
||||
MakeCamel(field.name, false) + "', " + object_name + ".prototype." +
|
||||
MakeCamel(field.name, false) + ");\n";
|
||||
}
|
||||
|
||||
// Adds the mutable scalar value to the output
|
||||
if (IsScalar(field.value.type.base_type) && parser.opts.mutable_buffer) {
|
||||
std::string annotations = "@param {" + GenTypeName(field.value.type, true) + "} value\n";
|
||||
std::string annotations =
|
||||
"@param {" + GenTypeName(field.value.type, true) + "} value\n";
|
||||
GenDocComment(code_ptr, annotations +
|
||||
"@returns {boolean}");
|
||||
|
||||
code += object_name + ".prototype.mutate_" + field.name + " = function(value) {\n";
|
||||
code += " var offset = this.bb.__offset(this.bb_pos, " + NumToString(field.value.offset) + ")\n\n";
|
||||
if (lang_.language == IDLOptions::kTs) {
|
||||
std::string type;
|
||||
if (field.value.type.enum_def) {
|
||||
type = GenPrefixedTypeName(GenTypeName(field.value.type, true),
|
||||
field.value.type.enum_def->file);
|
||||
} else {
|
||||
type = GenTypeName(field.value.type, true);
|
||||
}
|
||||
|
||||
code += "mutate_" + field.name + "(value:" + type + "):boolean {\n";
|
||||
} else {
|
||||
code += object_name + ".prototype.mutate_" + field.name +
|
||||
" = function(value) {\n";
|
||||
}
|
||||
|
||||
code += " var offset = this.bb.__offset(this.bb_pos, " +
|
||||
NumToString(field.value.offset) + ");\n\n";
|
||||
code += " if (offset === 0) {\n";
|
||||
code += " return false;\n";
|
||||
code += " }\n\n";
|
||||
code += " this.bb.write" + MakeCamel(GenType(field.value.type)) + "(this.bb_pos + offset, value);\n";
|
||||
|
||||
// special case for bools, which are treated as uint8
|
||||
code += " this.bb.write" + MakeCamel(GenType(field.value.type)) +
|
||||
"(this.bb_pos + offset, ";
|
||||
if (field.value.type.base_type == BASE_TYPE_BOOL &&
|
||||
lang_.language == IDLOptions::kTs) {
|
||||
code += "+";
|
||||
}
|
||||
|
||||
code += "value);\n";
|
||||
code += " return true;\n";
|
||||
code += "}\n\n";
|
||||
code += "};\n\n";
|
||||
|
||||
if(parser_.opts.use_goog_js_export_format) {
|
||||
exports += "goog.exportProperty(" + object_name +
|
||||
".prototype, 'mutate_" + field.name + "', " + object_name +
|
||||
".prototype.mutate_" + field.name + ");\n";
|
||||
}
|
||||
}
|
||||
|
||||
// Emit vector helpers
|
||||
if (field.value.type.base_type == BASE_TYPE_VECTOR) {
|
||||
// Emit a length helper
|
||||
GenDocComment(code_ptr, "@returns {number}");
|
||||
code += object_name + ".prototype." + MakeCamel(field.name, false);
|
||||
code += "Length = function() {\n" + offset_prefix;
|
||||
if (lang_.language == IDLOptions::kTs) {
|
||||
code += MakeCamel(field.name, false);
|
||||
code += "Length():number {\n" + offset_prefix;
|
||||
} else {
|
||||
code += object_name + ".prototype." + MakeCamel(field.name, false);
|
||||
code += "Length = function() {\n" + offset_prefix;
|
||||
}
|
||||
|
||||
code += "this.bb.__vector_len(this.bb_pos + offset) : 0;\n};\n\n";
|
||||
|
||||
if(parser_.opts.use_goog_js_export_format) {
|
||||
exports += "goog.exportProperty(" + object_name + ".prototype, '" +
|
||||
MakeCamel(field.name, false) + "Length', " + object_name +
|
||||
".prototype." + MakeCamel(field.name, false) + "Length);\n";
|
||||
}
|
||||
|
||||
// For scalar types, emit a typed array helper
|
||||
auto vectorType = field.value.type.VectorType();
|
||||
if (IsScalar(vectorType.base_type)) {
|
||||
if (IsScalar(vectorType.base_type) && !IsLong(vectorType.base_type)) {
|
||||
GenDocComment(code_ptr, "@returns {" + GenType(vectorType) + "Array}");
|
||||
code += object_name + ".prototype." + MakeCamel(field.name, false);
|
||||
code += "Array = function() {\n" + offset_prefix;
|
||||
|
||||
if (lang_.language == IDLOptions::kTs) {
|
||||
code += MakeCamel(field.name, false);
|
||||
code += "Array():" + GenType(vectorType) + "Array|null {\n" +
|
||||
offset_prefix;
|
||||
} else {
|
||||
code += object_name + ".prototype." + MakeCamel(field.name, false);
|
||||
code += "Array = function() {\n" + offset_prefix;
|
||||
}
|
||||
|
||||
code += "new " + GenType(vectorType) + "Array(this.bb.bytes().buffer, "
|
||||
"this.bb.__vector(this.bb_pos + offset), "
|
||||
"this.bb.bytes().byteOffset + this.bb.__vector(this.bb_pos + offset), "
|
||||
"this.bb.__vector_len(this.bb_pos + offset)) : null;\n};\n\n";
|
||||
|
||||
if(parser_.opts.use_goog_js_export_format) {
|
||||
exports += "goog.exportProperty(" + object_name + ".prototype, '" +
|
||||
MakeCamel(field.name, false) + "Array', " + object_name +
|
||||
".prototype." + MakeCamel(field.name, false) + "Array);\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -594,16 +952,30 @@ void GenStruct(const Parser &parser, StructDef &struct_def, std::string *code_pt
|
||||
GenStructArgs(struct_def, &annotations, &arguments, "");
|
||||
GenDocComment(code_ptr, annotations +
|
||||
"@returns {flatbuffers.Offset}");
|
||||
code += object_name + ".create" + struct_def.name + " = function(builder";
|
||||
code += arguments + ") {\n";
|
||||
|
||||
if (lang_.language == IDLOptions::kTs) {
|
||||
code += "static create" + struct_def.name + "(builder:flatbuffers.Builder";
|
||||
code += arguments + "):flatbuffers.Offset {\n";
|
||||
} else {
|
||||
code += object_name + ".create" + struct_def.name + " = function(builder";
|
||||
code += arguments + ") {\n";
|
||||
}
|
||||
|
||||
GenStructBody(struct_def, &code, "");
|
||||
code += " return builder.offset();\n};\n\n";
|
||||
} else {
|
||||
// Generate a method to start building a new object
|
||||
GenDocComment(code_ptr,
|
||||
"@param {flatbuffers.Builder} builder");
|
||||
code += object_name + ".start" + struct_def.name;
|
||||
code += " = function(builder) {\n";
|
||||
|
||||
if (lang_.language == IDLOptions::kTs) {
|
||||
code += "static start" + struct_def.name;
|
||||
code += "(builder:flatbuffers.Builder) {\n";
|
||||
} else {
|
||||
code += object_name + ".start" + struct_def.name;
|
||||
code += " = function(builder) {\n";
|
||||
}
|
||||
|
||||
code += " builder.startObject(" + NumToString(
|
||||
struct_def.fields.vec.size()) + ");\n";
|
||||
code += "};\n\n";
|
||||
@@ -623,8 +995,24 @@ void GenStruct(const Parser &parser, StructDef &struct_def, std::string *code_pt
|
||||
"@param {flatbuffers.Builder} builder\n"
|
||||
"@param {" + GenTypeName(field.value.type, true) + "} " +
|
||||
argname);
|
||||
code += object_name + ".add" + MakeCamel(field.name);
|
||||
code += " = function(builder, " + argname + ") {\n";
|
||||
|
||||
if (lang_.language == IDLOptions::kTs) {
|
||||
std::string argType;
|
||||
if (field.value.type.enum_def) {
|
||||
argType = GenPrefixedTypeName(GenTypeName(field.value.type, true),
|
||||
field.value.type.enum_def->file);
|
||||
} else {
|
||||
argType = GenTypeName(field.value.type, true);
|
||||
}
|
||||
|
||||
code += "static add" + MakeCamel(field.name);
|
||||
code += "(builder:flatbuffers.Builder, " + argname + ":" + argType +
|
||||
") {\n";
|
||||
} else {
|
||||
code += object_name + ".add" + MakeCamel(field.name);
|
||||
code += " = function(builder, " + argname + ") {\n";
|
||||
}
|
||||
|
||||
code += " builder.addField" + GenWriteMethod(field.value.type) + "(";
|
||||
code += NumToString(it - struct_def.fields.vec.begin()) + ", ";
|
||||
if (field.value.type.base_type == BASE_TYPE_BOOL) {
|
||||
@@ -653,8 +1041,20 @@ void GenStruct(const Parser &parser, StructDef &struct_def, std::string *code_pt
|
||||
"@param {Array.<" + GenTypeName(vector_type, true) +
|
||||
">} data\n"
|
||||
"@returns {flatbuffers.Offset}");
|
||||
code += object_name + ".create" + MakeCamel(field.name);
|
||||
code += "Vector = function(builder, data) {\n";
|
||||
|
||||
if (lang_.language == IDLOptions::kTs) {
|
||||
code += "static create" + MakeCamel(field.name);
|
||||
std::string type = GenTypeName(vector_type, true) + "[]";
|
||||
if (type == "number[]") {
|
||||
type += " | Uint8Array";
|
||||
}
|
||||
code += "Vector(builder:flatbuffers.Builder, data:" + type +
|
||||
"):flatbuffers.Offset {\n";
|
||||
} else {
|
||||
code += object_name + ".create" + MakeCamel(field.name);
|
||||
code += "Vector = function(builder, data) {\n";
|
||||
}
|
||||
|
||||
code += " builder.startVector(" + NumToString(elem_size);
|
||||
code += ", data.length, " + NumToString(alignment) + ");\n";
|
||||
code += " for (var i = data.length - 1; i >= 0; i--) {\n";
|
||||
@@ -672,8 +1072,15 @@ void GenStruct(const Parser &parser, StructDef &struct_def, std::string *code_pt
|
||||
GenDocComment(code_ptr,
|
||||
"@param {flatbuffers.Builder} builder\n"
|
||||
"@param {number} numElems");
|
||||
code += object_name + ".start" + MakeCamel(field.name);
|
||||
code += "Vector = function(builder, numElems) {\n";
|
||||
|
||||
if (lang_.language == IDLOptions::kTs) {
|
||||
code += "static start" + MakeCamel(field.name);
|
||||
code += "Vector(builder:flatbuffers.Builder, numElems:number) {\n";
|
||||
} else {
|
||||
code += object_name + ".start" + MakeCamel(field.name);
|
||||
code += "Vector = function(builder, numElems) {\n";
|
||||
}
|
||||
|
||||
code += " builder.startVector(" + NumToString(elem_size);
|
||||
code += ", numElems, " + NumToString(alignment) + ");\n";
|
||||
code += "};\n\n";
|
||||
@@ -684,8 +1091,15 @@ void GenStruct(const Parser &parser, StructDef &struct_def, std::string *code_pt
|
||||
GenDocComment(code_ptr,
|
||||
"@param {flatbuffers.Builder} builder\n"
|
||||
"@returns {flatbuffers.Offset}");
|
||||
code += object_name + ".end" + struct_def.name;
|
||||
code += " = function(builder) {\n";
|
||||
|
||||
if (lang_.language == IDLOptions::kTs) {
|
||||
code += "static end" + struct_def.name;
|
||||
code += "(builder:flatbuffers.Builder):flatbuffers.Offset {\n";
|
||||
} else {
|
||||
code += object_name + ".end" + struct_def.name;
|
||||
code += " = function(builder) {\n";
|
||||
}
|
||||
|
||||
code += " var offset = builder.endObject();\n";
|
||||
for (auto it = struct_def.fields.vec.begin();
|
||||
it != struct_def.fields.vec.end(); ++it) {
|
||||
@@ -704,8 +1118,15 @@ void GenStruct(const Parser &parser, StructDef &struct_def, std::string *code_pt
|
||||
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";
|
||||
|
||||
if (lang_.language == IDLOptions::kTs) {
|
||||
code += "static finish" + struct_def.name + "Buffer";
|
||||
code += "(builder:flatbuffers.Builder, offset:flatbuffers.Offset) {\n";
|
||||
} else {
|
||||
code += object_name + ".finish" + struct_def.name + "Buffer";
|
||||
code += " = function(builder, offset) {\n";
|
||||
}
|
||||
|
||||
code += " builder.finish(offset";
|
||||
if (!parser_.file_identifier_.empty()) {
|
||||
code += ", '" + parser_.file_identifier_ + "'";
|
||||
@@ -714,6 +1135,10 @@ void GenStruct(const Parser &parser, StructDef &struct_def, std::string *code_pt
|
||||
code += "};\n\n";
|
||||
}
|
||||
}
|
||||
|
||||
if (lang_.language == IDLOptions::kTs) {
|
||||
code += "}\n}\n";
|
||||
}
|
||||
}
|
||||
};
|
||||
} // namespace js
|
||||
@@ -727,15 +1152,19 @@ bool GenerateJS(const Parser &parser, const std::string &path,
|
||||
std::string JSMakeRule(const Parser &parser,
|
||||
const std::string &path,
|
||||
const std::string &file_name) {
|
||||
assert(parser.opts.lang <= IDLOptions::kMAX);
|
||||
const auto &lang = GetJsLangParams(parser.opts.lang);
|
||||
|
||||
std::string filebase = flatbuffers::StripPath(
|
||||
flatbuffers::StripExtension(file_name));
|
||||
std::string make_rule = GeneratedFileName(path, filebase) + ": ";
|
||||
std::string make_rule = GeneratedFileName(path, filebase, lang) + ": ";
|
||||
|
||||
auto included_files = parser.GetIncludedFilesRecursive(file_name);
|
||||
for (auto it = included_files.begin();
|
||||
it != included_files.end(); ++it) {
|
||||
make_rule += " " + *it;
|
||||
}
|
||||
return make_rule;
|
||||
return make_rule;
|
||||
}
|
||||
|
||||
} // namespace flatbuffers
|
||||
|
||||
@@ -66,7 +66,7 @@ namespace php {
|
||||
const bool needs_imports, std::string *code_ptr) {
|
||||
std::string &code = *code_ptr;
|
||||
code += "<?php\n";
|
||||
code = code + "// " + FlatBuffersGeneratedWarning();
|
||||
code = code + "// " + FlatBuffersGeneratedWarning() + "\n\n";
|
||||
code += "namespace " + name_space_name + ";\n\n";
|
||||
|
||||
if (needs_imports) {
|
||||
@@ -89,10 +89,10 @@ namespace php {
|
||||
code += classcode;
|
||||
|
||||
std::string filename = NamespaceDir(*def.defined_namespace) +
|
||||
kPathSeparator + def.name + ".php";
|
||||
def.name + ".php";
|
||||
return SaveFile(filename.c_str(), code, false);
|
||||
}
|
||||
|
||||
|
||||
// Begin a class declaration.
|
||||
static void BeginClass(const StructDef &struct_def, std::string *code_ptr) {
|
||||
std::string &code = *code_ptr;
|
||||
@@ -955,7 +955,7 @@ namespace php {
|
||||
code += Indent + Indent + "return $builder->offset();\n";
|
||||
code += Indent + "}\n";
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
} // namespace php
|
||||
|
||||
|
||||
@@ -630,7 +630,7 @@ class PythonGenerator : public BaseGenerator {
|
||||
void BeginFile(const std::string name_space_name, const bool needs_imports,
|
||||
std::string *code_ptr) {
|
||||
std::string &code = *code_ptr;
|
||||
code = code + "# " + FlatBuffersGeneratedWarning();
|
||||
code = code + "# " + FlatBuffersGeneratedWarning() + "\n\n";
|
||||
code += "# namespace: " + name_space_name + "\n\n";
|
||||
if (needs_imports) {
|
||||
code += "import flatbuffers\n\n";
|
||||
@@ -655,7 +655,7 @@ class PythonGenerator : public BaseGenerator {
|
||||
BeginFile(LastNamespacePart(*def.defined_namespace), needs_imports, &code);
|
||||
code += classcode;
|
||||
std::string filename = NamespaceDir(*def.defined_namespace) +
|
||||
kPathSeparator + def.name + ".py";
|
||||
def.name + ".py";
|
||||
return SaveFile(filename.c_str(), code, false);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -19,10 +19,11 @@
|
||||
#include "flatbuffers/flatbuffers.h"
|
||||
#include "flatbuffers/idl.h"
|
||||
#include "flatbuffers/util.h"
|
||||
#include "flatbuffers/flexbuffers.h"
|
||||
|
||||
namespace flatbuffers {
|
||||
|
||||
static void GenStruct(const StructDef &struct_def, const Table *table,
|
||||
static bool GenStruct(const StructDef &struct_def, const Table *table,
|
||||
int indent, const IDLOptions &opts,
|
||||
std::string *_text);
|
||||
|
||||
@@ -48,8 +49,8 @@ void OutputIdentifier(const std::string &name, const IDLOptions &opts,
|
||||
// Print (and its template specialization below for pointers) generate text
|
||||
// for a single FlatBuffer value into JSON format.
|
||||
// The general case for scalars:
|
||||
template<typename T> void Print(T val, Type type, int /*indent*/,
|
||||
StructDef * /*union_sd*/,
|
||||
template<typename T> bool Print(T val, Type type, int /*indent*/,
|
||||
Type * /*union_type*/,
|
||||
const IDLOptions &opts,
|
||||
std::string *_text) {
|
||||
std::string &text = *_text;
|
||||
@@ -57,7 +58,7 @@ template<typename T> void Print(T val, Type type, int /*indent*/,
|
||||
auto enum_val = type.enum_def->ReverseLookup(static_cast<int>(val));
|
||||
if (enum_val) {
|
||||
OutputIdentifier(enum_val->name, opts, _text);
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,10 +67,12 @@ template<typename T> void Print(T val, Type type, int /*indent*/,
|
||||
} else {
|
||||
text += NumToString(val);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Print a vector a sequence of JSON values, comma separated, wrapped in "[]".
|
||||
template<typename T> void PrintVector(const Vector<T> &v, Type type,
|
||||
template<typename T> bool PrintVector(const Vector<T> &v, Type type,
|
||||
int indent, const IDLOptions &opts,
|
||||
std::string *_text) {
|
||||
std::string &text = *_text;
|
||||
@@ -77,102 +80,55 @@ template<typename T> void PrintVector(const Vector<T> &v, Type type,
|
||||
text += NewLine(opts);
|
||||
for (uoffset_t i = 0; i < v.size(); i++) {
|
||||
if (i) {
|
||||
text += ",";
|
||||
if (!opts.protobuf_ascii_alike) text += ",";
|
||||
text += NewLine(opts);
|
||||
}
|
||||
text.append(indent + Indent(opts), ' ');
|
||||
if (IsStruct(type))
|
||||
Print(v.GetStructFromOffset(i * type.struct_def->bytesize), type,
|
||||
indent + Indent(opts), nullptr, opts, _text);
|
||||
else
|
||||
Print(v[i], type, indent + Indent(opts), nullptr,
|
||||
opts, _text);
|
||||
if (IsStruct(type)) {
|
||||
if (!Print(v.GetStructFromOffset(i * type.struct_def->bytesize), type,
|
||||
indent + Indent(opts), nullptr, opts, _text)) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (!Print(v[i], type, indent + Indent(opts), nullptr,
|
||||
opts, _text)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
text += NewLine(opts);
|
||||
text.append(indent, ' ');
|
||||
text += "]";
|
||||
}
|
||||
|
||||
static void EscapeString(const String &s, std::string *_text, const IDLOptions& opts) {
|
||||
std::string &text = *_text;
|
||||
text += "\"";
|
||||
for (uoffset_t i = 0; i < s.size(); i++) {
|
||||
char c = s[i];
|
||||
switch (c) {
|
||||
case '\n': text += "\\n"; break;
|
||||
case '\t': text += "\\t"; break;
|
||||
case '\r': text += "\\r"; break;
|
||||
case '\b': text += "\\b"; break;
|
||||
case '\f': text += "\\f"; break;
|
||||
case '\"': text += "\\\""; break;
|
||||
case '\\': text += "\\\\"; break;
|
||||
default:
|
||||
if (c >= ' ' && c <= '~') {
|
||||
text += c;
|
||||
} else {
|
||||
// Not printable ASCII data. Let's see if it's valid UTF-8 first:
|
||||
const char *utf8 = s.c_str() + i;
|
||||
int ucc = FromUTF8(&utf8);
|
||||
if (ucc < 0) {
|
||||
if (opts.allow_non_utf8) {
|
||||
text += "\\x";
|
||||
text += IntToStringHex(static_cast<uint8_t>(c), 2);
|
||||
} else {
|
||||
// We previously checked for non-UTF-8 and returned a parse error,
|
||||
// so we shouldn't reach here.
|
||||
assert(0);
|
||||
}
|
||||
} else {
|
||||
if (ucc <= 0xFFFF) {
|
||||
// Parses as Unicode within JSON's \uXXXX range, so use that.
|
||||
text += "\\u";
|
||||
text += IntToStringHex(ucc, 4);
|
||||
} else if (ucc <= 0x10FFFF) {
|
||||
// Encode Unicode SMP values to a surrogate pair using two \u escapes.
|
||||
uint32_t base = ucc - 0x10000;
|
||||
uint16_t highSurrogate = (base >> 10) + 0xD800;
|
||||
uint16_t lowSurrogate = (base & 0x03FF) + 0xDC00;
|
||||
text += "\\u";
|
||||
text += IntToStringHex(highSurrogate, 4);
|
||||
text += "\\u";
|
||||
text += IntToStringHex(lowSurrogate, 4);
|
||||
}
|
||||
// Skip past characters recognized.
|
||||
i = static_cast<uoffset_t>(utf8 - s.c_str() - 1);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
text += "\"";
|
||||
return true;
|
||||
}
|
||||
|
||||
// Specialization of Print above for pointer types.
|
||||
template<> void Print<const void *>(const void *val,
|
||||
template<> bool Print<const void *>(const void *val,
|
||||
Type type, int indent,
|
||||
StructDef *union_sd,
|
||||
Type *union_type,
|
||||
const IDLOptions &opts,
|
||||
std::string *_text) {
|
||||
switch (type.base_type) {
|
||||
case BASE_TYPE_UNION:
|
||||
// If this assert hits, you have an corrupt buffer, a union type field
|
||||
// was not present or was out of range.
|
||||
assert(union_sd);
|
||||
GenStruct(*union_sd,
|
||||
reinterpret_cast<const Table *>(val),
|
||||
indent,
|
||||
opts,
|
||||
_text);
|
||||
break;
|
||||
assert(union_type);
|
||||
return Print<const void *>(val, *union_type, indent, nullptr, opts,
|
||||
_text);
|
||||
case BASE_TYPE_STRUCT:
|
||||
GenStruct(*type.struct_def,
|
||||
reinterpret_cast<const Table *>(val),
|
||||
indent,
|
||||
opts,
|
||||
_text);
|
||||
if (!GenStruct(*type.struct_def,
|
||||
reinterpret_cast<const Table *>(val),
|
||||
indent,
|
||||
opts,
|
||||
_text)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case BASE_TYPE_STRING: {
|
||||
EscapeString(*reinterpret_cast<const String *>(val), _text, opts);
|
||||
auto s = reinterpret_cast<const String *>(val);
|
||||
if (!EscapeString(s->c_str(), s->Length(), _text, opts.allow_non_utf8)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case BASE_TYPE_VECTOR:
|
||||
@@ -182,32 +138,36 @@ template<> void Print<const void *>(const void *val,
|
||||
#define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, \
|
||||
PTYPE) \
|
||||
case BASE_TYPE_ ## ENUM: \
|
||||
PrintVector<CTYPE>( \
|
||||
*reinterpret_cast<const Vector<CTYPE> *>(val), \
|
||||
type, indent, opts, _text); break;
|
||||
if (!PrintVector<CTYPE>( \
|
||||
*reinterpret_cast<const Vector<CTYPE> *>(val), \
|
||||
type, indent, opts, _text)) { \
|
||||
return false; \
|
||||
} \
|
||||
break;
|
||||
FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
|
||||
#undef FLATBUFFERS_TD
|
||||
}
|
||||
break;
|
||||
default: assert(0);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Generate text for a scalar field.
|
||||
template<typename T> static void GenField(const FieldDef &fd,
|
||||
template<typename T> static bool GenField(const FieldDef &fd,
|
||||
const Table *table, bool fixed,
|
||||
const IDLOptions &opts,
|
||||
int indent,
|
||||
std::string *_text) {
|
||||
Print(fixed ?
|
||||
return Print(fixed ?
|
||||
reinterpret_cast<const Struct *>(table)->GetField<T>(fd.value.offset) :
|
||||
table->GetField<T>(fd.value.offset, 0), fd.value.type, indent, nullptr,
|
||||
opts, _text);
|
||||
}
|
||||
|
||||
// Generate text for non-scalar field.
|
||||
static void GenFieldOffset(const FieldDef &fd, const Table *table, bool fixed,
|
||||
int indent, StructDef *union_sd,
|
||||
static bool GenFieldOffset(const FieldDef &fd, const Table *table, bool fixed,
|
||||
int indent, Type *union_type,
|
||||
const IDLOptions &opts, std::string *_text) {
|
||||
const void *val = nullptr;
|
||||
if (fixed) {
|
||||
@@ -215,23 +175,28 @@ static void GenFieldOffset(const FieldDef &fd, const Table *table, bool fixed,
|
||||
assert(IsStruct(fd.value.type));
|
||||
val = reinterpret_cast<const Struct *>(table)->
|
||||
GetStruct<const void *>(fd.value.offset);
|
||||
} else if (fd.flexbuffer) {
|
||||
auto vec = table->GetPointer<const Vector<uint8_t> *>(fd.value.offset);
|
||||
auto root = flexbuffers::GetRoot(vec->data(), vec->size());
|
||||
root.ToString(true, false, *_text);
|
||||
return true;
|
||||
} else {
|
||||
val = IsStruct(fd.value.type)
|
||||
? table->GetStruct<const void *>(fd.value.offset)
|
||||
: table->GetPointer<const void *>(fd.value.offset);
|
||||
}
|
||||
Print(val, fd.value.type, indent, union_sd, opts, _text);
|
||||
return Print(val, fd.value.type, indent, union_type, opts, _text);
|
||||
}
|
||||
|
||||
// Generate text for a struct or table, values separated by commas, indented,
|
||||
// and bracketed by "{}"
|
||||
static void GenStruct(const StructDef &struct_def, const Table *table,
|
||||
static bool GenStruct(const StructDef &struct_def, const Table *table,
|
||||
int indent, const IDLOptions &opts,
|
||||
std::string *_text) {
|
||||
std::string &text = *_text;
|
||||
text += "{";
|
||||
int fieldout = 0;
|
||||
StructDef *union_sd = nullptr;
|
||||
Type *union_type = nullptr;
|
||||
for (auto it = struct_def.fields.vec.begin();
|
||||
it != struct_def.fields.vec.end();
|
||||
++it) {
|
||||
@@ -242,19 +207,24 @@ static void GenStruct(const StructDef &struct_def, const Table *table,
|
||||
!fd.deprecated;
|
||||
if (is_present || output_anyway) {
|
||||
if (fieldout++) {
|
||||
text += ",";
|
||||
if (!opts.protobuf_ascii_alike) text += ",";
|
||||
}
|
||||
text += NewLine(opts);
|
||||
text.append(indent + Indent(opts), ' ');
|
||||
OutputIdentifier(fd.name, opts, _text);
|
||||
text += ": ";
|
||||
if (!opts.protobuf_ascii_alike ||
|
||||
(fd.value.type.base_type != BASE_TYPE_STRUCT &&
|
||||
fd.value.type.base_type != BASE_TYPE_VECTOR)) text += ":";
|
||||
text += " ";
|
||||
if (is_present) {
|
||||
switch (fd.value.type.base_type) {
|
||||
#define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, \
|
||||
PTYPE) \
|
||||
case BASE_TYPE_ ## ENUM: \
|
||||
GenField<CTYPE>(fd, table, struct_def.fixed, \
|
||||
opts, indent + Indent(opts), _text); \
|
||||
if (!GenField<CTYPE>(fd, table, struct_def.fixed, \
|
||||
opts, indent + Indent(opts), _text)) { \
|
||||
return false; \
|
||||
} \
|
||||
break;
|
||||
FLATBUFFERS_GEN_TYPES_SCALAR(FLATBUFFERS_TD)
|
||||
#undef FLATBUFFERS_TD
|
||||
@@ -264,15 +234,17 @@ static void GenStruct(const StructDef &struct_def, const Table *table,
|
||||
case BASE_TYPE_ ## ENUM:
|
||||
FLATBUFFERS_GEN_TYPES_POINTER(FLATBUFFERS_TD)
|
||||
#undef FLATBUFFERS_TD
|
||||
GenFieldOffset(fd, table, struct_def.fixed, indent + Indent(opts),
|
||||
union_sd, opts, _text);
|
||||
if (!GenFieldOffset(fd, table, struct_def.fixed, indent + Indent(opts),
|
||||
union_type, opts, _text)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (fd.value.type.base_type == BASE_TYPE_UTYPE) {
|
||||
auto enum_val = fd.value.type.enum_def->ReverseLookup(
|
||||
table->GetField<uint8_t>(fd.value.offset, 0));
|
||||
assert(enum_val);
|
||||
union_sd = enum_val->struct_def;
|
||||
union_type = &enum_val->union_type;
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -284,20 +256,24 @@ static void GenStruct(const StructDef &struct_def, const Table *table,
|
||||
text += NewLine(opts);
|
||||
text.append(indent, ' ');
|
||||
text += "}";
|
||||
return true;
|
||||
}
|
||||
|
||||
// Generate a text representation of a flatbuffer in JSON format.
|
||||
void GenerateText(const Parser &parser, const void *flatbuffer,
|
||||
bool GenerateText(const Parser &parser, const void *flatbuffer,
|
||||
std::string *_text) {
|
||||
std::string &text = *_text;
|
||||
assert(parser.root_struct_def_); // call SetRootType()
|
||||
text.reserve(1024); // Reduce amount of inevitable reallocs.
|
||||
GenStruct(*parser.root_struct_def_,
|
||||
GetRoot<Table>(flatbuffer),
|
||||
0,
|
||||
parser.opts,
|
||||
_text);
|
||||
if (!GenStruct(*parser.root_struct_def_,
|
||||
GetRoot<Table>(flatbuffer),
|
||||
0,
|
||||
parser.opts,
|
||||
_text)) {
|
||||
return false;
|
||||
}
|
||||
text += NewLine(parser.opts);
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string TextFileName(const std::string &path,
|
||||
@@ -310,7 +286,9 @@ bool GenerateTextFile(const Parser &parser,
|
||||
const std::string &file_name) {
|
||||
if (!parser.builder_.GetSize() || !parser.root_struct_def_) return true;
|
||||
std::string text;
|
||||
GenerateText(parser, parser.builder_.GetBufferPointer(), &text);
|
||||
if (!GenerateText(parser, parser.builder_.GetBufferPointer(), &text)) {
|
||||
return false;
|
||||
}
|
||||
return flatbuffers::SaveFile(TextFileName(path, file_name).c_str(),
|
||||
text,
|
||||
false);
|
||||
|
||||
@@ -86,29 +86,38 @@ CheckedError Parser::Error(const std::string &msg) {
|
||||
|
||||
inline CheckedError NoError() { return CheckedError(false); }
|
||||
|
||||
inline std::string OutOfRangeErrorMsg(int64_t val, const std::string &op,
|
||||
int64_t limit) {
|
||||
const std::string cause = NumToString(val) + op + NumToString(limit);
|
||||
return "constant does not fit (" + cause + ")";
|
||||
}
|
||||
|
||||
// Ensure that integer values we parse fit inside the declared integer type.
|
||||
CheckedError Parser::CheckBitsFit(int64_t val, size_t bits) {
|
||||
// Left-shifting a 64-bit value by 64 bits or more is undefined
|
||||
// behavior (C99 6.5.7), so check *before* we shift.
|
||||
if (bits < 64) {
|
||||
// Bits we allow to be used.
|
||||
auto mask = static_cast<int64_t>((1ull << bits) - 1);
|
||||
if ((val & ~mask) != 0 && // Positive or unsigned.
|
||||
(val | mask) != -1) // Negative.
|
||||
return Error("constant does not fit in a " + NumToString(bits) +
|
||||
"-bit field");
|
||||
}
|
||||
return NoError();
|
||||
CheckedError Parser::CheckInRange(int64_t val, int64_t min, int64_t max) {
|
||||
if (val < min)
|
||||
return Error(OutOfRangeErrorMsg(val, " < ", min));
|
||||
else if (val > max)
|
||||
return Error(OutOfRangeErrorMsg(val, " > ", max));
|
||||
else
|
||||
return NoError();
|
||||
}
|
||||
|
||||
// atot: templated version of atoi/atof: convert a string to an instance of T.
|
||||
template<typename T> inline CheckedError atot(const char *s, Parser &parser,
|
||||
T *val) {
|
||||
int64_t i = StringToInt(s);
|
||||
ECHECK(parser.CheckBitsFit(i, sizeof(T) * 8));
|
||||
const int64_t min = std::numeric_limits<T>::min();
|
||||
const int64_t max = std::numeric_limits<T>::max();
|
||||
ECHECK(parser.CheckInRange(i, min, max));
|
||||
*val = (T)i;
|
||||
return NoError();
|
||||
}
|
||||
template<> inline CheckedError atot<uint64_t>(const char *s, Parser &parser,
|
||||
uint64_t *val) {
|
||||
(void)parser;
|
||||
*val = StringToUInt(s);
|
||||
return NoError();
|
||||
}
|
||||
template<> inline CheckedError atot<bool>(const char *s, Parser &parser,
|
||||
bool *val) {
|
||||
(void)parser;
|
||||
@@ -149,8 +158,7 @@ std::string Namespace::GetFullyQualifiedName(const std::string &name,
|
||||
}
|
||||
stream << components[i];
|
||||
}
|
||||
|
||||
stream << "." << name;
|
||||
if (name.length()) stream << "." << name;
|
||||
return stream.str();
|
||||
}
|
||||
|
||||
@@ -175,7 +183,8 @@ std::string Namespace::GetFullyQualifiedName(const std::string &name,
|
||||
TD(Include, 269, "include") \
|
||||
TD(Attribute, 270, "attribute") \
|
||||
TD(Null, 271, "null") \
|
||||
TD(Service, 272, "rpc_service")
|
||||
TD(Service, 272, "rpc_service") \
|
||||
TD(NativeInclude, 273, "native_include")
|
||||
#ifdef __GNUC__
|
||||
__extension__ // Stop GCC complaining about trailing comma with -Wpendantic.
|
||||
#endif
|
||||
@@ -213,13 +222,13 @@ std::string Parser::TokenToStringId(int t) {
|
||||
}
|
||||
|
||||
// Parses exactly nibbles worth of hex digits into a number, or error.
|
||||
CheckedError Parser::ParseHexNum(int nibbles, int64_t *val) {
|
||||
CheckedError Parser::ParseHexNum(int nibbles, uint64_t *val) {
|
||||
for (int i = 0; i < nibbles; i++)
|
||||
if (!isxdigit(static_cast<const unsigned char>(cursor_[i])))
|
||||
return Error("escape code must be followed by " + NumToString(nibbles) +
|
||||
" hex digits");
|
||||
std::string target(cursor_, cursor_ + nibbles);
|
||||
*val = StringToUInt(target.c_str(), 16);
|
||||
*val = StringToUInt(target.c_str(), nullptr, 16);
|
||||
cursor_ += nibbles;
|
||||
return NoError();
|
||||
}
|
||||
@@ -280,14 +289,14 @@ CheckedError Parser::Next() {
|
||||
case '/': attribute_ += '/'; cursor_++; break;
|
||||
case 'x': { // Not in the JSON standard
|
||||
cursor_++;
|
||||
int64_t val;
|
||||
uint64_t val;
|
||||
ECHECK(ParseHexNum(2, &val));
|
||||
attribute_ += static_cast<char>(val);
|
||||
break;
|
||||
}
|
||||
case 'u': {
|
||||
cursor_++;
|
||||
int64_t val;
|
||||
uint64_t val;
|
||||
ECHECK(ParseHexNum(4, &val));
|
||||
if (val >= 0xD800 && val <= 0xDBFF) {
|
||||
if (unicode_high_surrogate != -1) {
|
||||
@@ -352,6 +361,7 @@ CheckedError Parser::Next() {
|
||||
cursor_++;
|
||||
// TODO: make nested.
|
||||
while (*cursor_ != '*' || cursor_[1] != '/') {
|
||||
if (*cursor_ == '\n') line_++;
|
||||
if (!*cursor_) return Error("end of file in comment");
|
||||
cursor_++;
|
||||
}
|
||||
@@ -432,12 +442,17 @@ CheckedError Parser::Next() {
|
||||
token_ = kTokenService;
|
||||
return NoError();
|
||||
}
|
||||
if (attribute_ == "native_include") {
|
||||
token_ = kTokenNativeInclude;
|
||||
return NoError();
|
||||
}
|
||||
// If not, it is a user-defined identifier:
|
||||
token_ = kTokenIdentifier;
|
||||
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')) {
|
||||
if (c == '-' && *cursor_ == '0' &&
|
||||
(cursor_[1] == 'x' || cursor_[1] == 'X')) {
|
||||
++start;
|
||||
++cursor_;
|
||||
attribute_.append(&c, &c + 1);
|
||||
@@ -447,7 +462,8 @@ CheckedError Parser::Next() {
|
||||
cursor_++;
|
||||
while (isxdigit(static_cast<unsigned char>(*cursor_))) cursor_++;
|
||||
attribute_.append(start + 2, cursor_);
|
||||
attribute_ = NumToString(StringToUInt(attribute_.c_str(), 16));
|
||||
attribute_ = NumToString(static_cast<int64_t>(
|
||||
StringToUInt(attribute_.c_str(), nullptr, 16)));
|
||||
token_ = kTokenIntegerConstant;
|
||||
return NoError();
|
||||
}
|
||||
@@ -549,12 +565,6 @@ CheckedError Parser::ParseType(Type &type) {
|
||||
return Error(
|
||||
"nested vector types not supported (wrap in table first).");
|
||||
}
|
||||
if (subtype.base_type == BASE_TYPE_UNION) {
|
||||
// We could support this if we stored a struct of 2 elements per
|
||||
// union element.
|
||||
return Error(
|
||||
"vector of union types not supported (wrap in table first).");
|
||||
}
|
||||
type = Type(BASE_TYPE_VECTOR, subtype.struct_def, subtype.enum_def);
|
||||
type.element = subtype.base_type;
|
||||
EXPECT(']');
|
||||
@@ -591,6 +601,10 @@ CheckedError Parser::AddField(StructDef &struct_def, const std::string &name,
|
||||
|
||||
CheckedError Parser::ParseField(StructDef &struct_def) {
|
||||
std::string name = attribute_;
|
||||
|
||||
if (name == struct_def.name)
|
||||
return Error("field name can not be the same as table/struct name");
|
||||
|
||||
std::vector<std::string> dc = doc_comment_;
|
||||
EXPECT(kTokenIdentifier);
|
||||
EXPECT(':');
|
||||
@@ -606,6 +620,19 @@ CheckedError Parser::ParseField(StructDef &struct_def) {
|
||||
// with a special suffix.
|
||||
ECHECK(AddField(struct_def, name + UnionTypeFieldSuffix(),
|
||||
type.enum_def->underlying_type, &typefield));
|
||||
} else if (type.base_type == BASE_TYPE_VECTOR &&
|
||||
type.element == BASE_TYPE_UNION) {
|
||||
// Only cpp supports the union vector feature so far.
|
||||
if (opts.lang_to_generate != IDLOptions::kCpp) {
|
||||
return Error("Vectors of unions are not yet supported in all "
|
||||
"the specified programming languages.");
|
||||
}
|
||||
// For vector of union fields, add a second auto-generated vector field to
|
||||
// hold the types, with a special suffix.
|
||||
Type union_vector(BASE_TYPE_VECTOR, nullptr, type.enum_def);
|
||||
union_vector.element = BASE_TYPE_UTYPE;
|
||||
ECHECK(AddField(struct_def, name + UnionTypeFieldSuffix(),
|
||||
union_vector, &typefield));
|
||||
}
|
||||
|
||||
FieldDef *field;
|
||||
@@ -657,6 +684,11 @@ CheckedError Parser::ParseField(StructDef &struct_def) {
|
||||
"only int, uint, long and ulong data types support hashing.");
|
||||
}
|
||||
}
|
||||
auto cpp_type = field->attributes.Lookup("cpp_type");
|
||||
if (cpp_type) {
|
||||
if (!hash_name)
|
||||
return Error("cpp_type can only be used with a hashed field");
|
||||
}
|
||||
if (field->deprecated && struct_def.fixed)
|
||||
return Error("can't deprecate fields in a struct");
|
||||
field->required = field->attributes.Lookup("required") != nullptr;
|
||||
@@ -674,6 +706,11 @@ CheckedError Parser::ParseField(StructDef &struct_def) {
|
||||
return Error("'key' field must be string or scalar type");
|
||||
}
|
||||
}
|
||||
|
||||
field->native_inline = field->attributes.Lookup("native_inline") != nullptr;
|
||||
if (field->native_inline && !IsStruct(field->value.type))
|
||||
return Error("native_inline can only be defined on structs'");
|
||||
|
||||
auto nested = field->attributes.Lookup("nested_flatbuffer");
|
||||
if (nested) {
|
||||
if (nested->type.base_type != BASE_TYPE_STRING)
|
||||
@@ -688,6 +725,15 @@ CheckedError Parser::ParseField(StructDef &struct_def) {
|
||||
LookupCreateStruct(nested->constant);
|
||||
}
|
||||
|
||||
if (field->attributes.Lookup("flexbuffer")) {
|
||||
field->flexbuffer = true;
|
||||
uses_flexbuffers_ = true;
|
||||
if (field->value.type.base_type != BASE_TYPE_VECTOR ||
|
||||
field->value.type.element != BASE_TYPE_UCHAR)
|
||||
return Error(
|
||||
"flexbuffer attribute may only apply to a vector of ubyte");
|
||||
}
|
||||
|
||||
if (typefield) {
|
||||
// If this field is a union, and it has a manually assigned id,
|
||||
// the automatically added type field should have an id as well (of N - 1).
|
||||
@@ -705,6 +751,18 @@ CheckedError Parser::ParseField(StructDef &struct_def) {
|
||||
return NoError();
|
||||
}
|
||||
|
||||
CheckedError Parser::ParseString(Value &val) {
|
||||
auto s = attribute_;
|
||||
EXPECT(kTokenStringConstant);
|
||||
val.constant = NumToString(builder_.CreateString(s).o);
|
||||
return NoError();
|
||||
}
|
||||
|
||||
CheckedError Parser::ParseComma() {
|
||||
if (!opts.protobuf_ascii_alike) EXPECT(',');
|
||||
return NoError();
|
||||
}
|
||||
|
||||
CheckedError Parser::ParseAnyValue(Value &val, FieldDef *field,
|
||||
size_t parent_fieldn,
|
||||
const StructDef *parent_struct_def) {
|
||||
@@ -712,8 +770,17 @@ CheckedError Parser::ParseAnyValue(Value &val, FieldDef *field,
|
||||
case BASE_TYPE_UNION: {
|
||||
assert(field);
|
||||
std::string constant;
|
||||
if (!parent_fieldn ||
|
||||
field_stack_.back().second->value.type.base_type != BASE_TYPE_UTYPE) {
|
||||
// Find corresponding type field we may have already parsed.
|
||||
for (auto elem = field_stack_.rbegin();
|
||||
elem != field_stack_.rbegin() + parent_fieldn; ++elem) {
|
||||
auto &type = elem->second->value.type;
|
||||
if (type.base_type == BASE_TYPE_UTYPE &&
|
||||
type.enum_def == val.type.enum_def) {
|
||||
constant = elem->first.constant;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (constant.empty()) {
|
||||
// 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.
|
||||
@@ -724,7 +791,7 @@ CheckedError Parser::ParseAnyValue(Value &val, FieldDef *field,
|
||||
// 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(',');
|
||||
ECHECK(ParseComma());
|
||||
auto next_name = attribute_;
|
||||
if (Is(kTokenStringConstant)) {
|
||||
NEXT();
|
||||
@@ -740,27 +807,35 @@ CheckedError Parser::ParseAnyValue(Value &val, FieldDef *field,
|
||||
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(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));
|
||||
if (enum_val->union_type.base_type == BASE_TYPE_STRUCT) {
|
||||
ECHECK(ParseTable(*enum_val->union_type.struct_def, &val.constant,
|
||||
nullptr));
|
||||
if (enum_val->union_type.struct_def->fixed) {
|
||||
// All BASE_TYPE_UNION values are offsets, so turn this into one.
|
||||
SerializeStruct(*enum_val->union_type.struct_def, val);
|
||||
builder_.ClearOffsets();
|
||||
val.constant = NumToString(builder_.GetSize());
|
||||
}
|
||||
} else if (enum_val->union_type.base_type == BASE_TYPE_STRING) {
|
||||
ECHECK(ParseString(val));
|
||||
} else {
|
||||
assert(false);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case BASE_TYPE_STRUCT:
|
||||
ECHECK(ParseTable(*val.type.struct_def, &val.constant, nullptr));
|
||||
break;
|
||||
case BASE_TYPE_STRING: {
|
||||
auto s = attribute_;
|
||||
EXPECT(kTokenStringConstant);
|
||||
val.constant = NumToString(builder_.CreateString(s).o);
|
||||
ECHECK(ParseString(val));
|
||||
break;
|
||||
}
|
||||
case BASE_TYPE_VECTOR: {
|
||||
EXPECT('[');
|
||||
uoffset_t off;
|
||||
ECHECK(ParseVector(val.type.VectorType(), &off));
|
||||
val.constant = NumToString(off);
|
||||
@@ -793,48 +868,114 @@ void Parser::SerializeStruct(const StructDef &struct_def, const Value &val) {
|
||||
builder_.AddStructOffset(val.offset, builder_.GetSize());
|
||||
}
|
||||
|
||||
CheckedError Parser::ParseTableDelimiters(size_t &fieldn,
|
||||
const StructDef *struct_def,
|
||||
const std::function<CheckedError(const std::string &name)> &body) {
|
||||
// We allow tables both as JSON object{ .. } with field names
|
||||
// or vector[..] with all fields in order
|
||||
char terminator = '}';
|
||||
bool is_nested_vector = struct_def && Is('[');
|
||||
if (is_nested_vector) {
|
||||
NEXT();
|
||||
terminator = ']';
|
||||
} else {
|
||||
EXPECT('{');
|
||||
}
|
||||
for (;;) {
|
||||
if ((!opts.strict_json || !fieldn) && Is(terminator)) break;
|
||||
std::string name;
|
||||
if (is_nested_vector) {
|
||||
if (fieldn > struct_def->fields.vec.size()) {
|
||||
return Error("too many unnamed fields in nested array");
|
||||
}
|
||||
name = struct_def->fields.vec[fieldn]->name;
|
||||
} else {
|
||||
name = attribute_;
|
||||
if (Is(kTokenStringConstant)) {
|
||||
NEXT();
|
||||
} else {
|
||||
EXPECT(opts.strict_json ? kTokenStringConstant : kTokenIdentifier);
|
||||
}
|
||||
if (!opts.protobuf_ascii_alike || !(Is('{') || Is('['))) EXPECT(':');
|
||||
}
|
||||
ECHECK(body(name));
|
||||
if (Is(terminator)) break;
|
||||
ECHECK(ParseComma());
|
||||
}
|
||||
NEXT();
|
||||
if (is_nested_vector && fieldn != struct_def->fields.vec.size()) {
|
||||
return Error("wrong number of unnamed fields in table vector");
|
||||
}
|
||||
return NoError();
|
||||
}
|
||||
|
||||
CheckedError Parser::ParseTable(const StructDef &struct_def, std::string *value,
|
||||
uoffset_t *ovalue) {
|
||||
EXPECT('{');
|
||||
size_t fieldn = 0;
|
||||
for (;;) {
|
||||
if ((!opts.strict_json || !fieldn) && Is('}')) { NEXT(); break; }
|
||||
std::string name = attribute_;
|
||||
if (Is(kTokenStringConstant)) {
|
||||
NEXT();
|
||||
} else {
|
||||
EXPECT(opts.strict_json ? kTokenStringConstant : kTokenIdentifier);
|
||||
}
|
||||
auto err = ParseTableDelimiters(fieldn, &struct_def,
|
||||
[&](const std::string &name) -> CheckedError {
|
||||
auto field = struct_def.fields.Lookup(name);
|
||||
if (!field) {
|
||||
if (!opts.skip_unexpected_fields_in_json) {
|
||||
return Error("unknown field: " + name);
|
||||
} else {
|
||||
EXPECT(':');
|
||||
ECHECK(SkipAnyJsonValue());
|
||||
}
|
||||
} else {
|
||||
EXPECT(':');
|
||||
if (Is(kTokenNull)) {
|
||||
NEXT(); // Ignore this field.
|
||||
} else {
|
||||
Value val = field->value;
|
||||
ECHECK(ParseAnyValue(val, field, fieldn, &struct_def));
|
||||
size_t i = field_stack_.size();
|
||||
if (field->flexbuffer) {
|
||||
flexbuffers::Builder builder(1024,
|
||||
flexbuffers::BUILDER_FLAG_SHARE_ALL);
|
||||
ECHECK(ParseFlexBufferValue(&builder));
|
||||
builder.Finish();
|
||||
auto off = builder_.CreateVector(builder.GetBuffer());
|
||||
val.constant = NumToString(off.o);
|
||||
} else {
|
||||
ECHECK(ParseAnyValue(val, field, fieldn, &struct_def));
|
||||
}
|
||||
// Hardcoded insertion-sort with error-check.
|
||||
// If fields are specified in order, then this loop exits immediately.
|
||||
for (; i > field_stack_.size() - fieldn; i--) {
|
||||
auto existing_field = field_stack_[i - 1].second;
|
||||
auto elem = field_stack_.rbegin();
|
||||
for (; elem != field_stack_.rbegin() + fieldn; ++elem) {
|
||||
auto existing_field = elem->second;
|
||||
if (existing_field == field)
|
||||
return Error("field set more than once: " + field->name);
|
||||
if (existing_field->value.offset < field->value.offset) break;
|
||||
}
|
||||
field_stack_.insert(field_stack_.begin() + i, std::make_pair(val, field));
|
||||
// Note: elem points to before the insertion point, thus .base() points
|
||||
// to the correct spot.
|
||||
field_stack_.insert(elem.base(), std::make_pair(val, field));
|
||||
fieldn++;
|
||||
}
|
||||
}
|
||||
if (Is('}')) { NEXT(); break; }
|
||||
EXPECT(',');
|
||||
return NoError();
|
||||
});
|
||||
ECHECK(err);
|
||||
|
||||
// Check if all required fields are parsed.
|
||||
for (auto field_it = struct_def.fields.vec.begin();
|
||||
field_it != struct_def.fields.vec.end();
|
||||
++field_it) {
|
||||
auto required_field = *field_it;
|
||||
if (!required_field->required) {
|
||||
continue;
|
||||
}
|
||||
bool found = false;
|
||||
for (auto pf_it = field_stack_.end() - fieldn;
|
||||
pf_it != field_stack_.end();
|
||||
++pf_it) {
|
||||
auto parsed_field = pf_it->second;
|
||||
if (parsed_field == required_field) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
return Error("required field is missing: " + required_field->name + " in " + struct_def.name);
|
||||
}
|
||||
}
|
||||
|
||||
if (struct_def.fixed && fieldn != struct_def.fields.vec.size())
|
||||
@@ -912,22 +1053,34 @@ CheckedError Parser::ParseTable(const StructDef &struct_def, std::string *value,
|
||||
return NoError();
|
||||
}
|
||||
|
||||
CheckedError Parser::ParseVector(const Type &type, uoffset_t *ovalue) {
|
||||
int count = 0;
|
||||
CheckedError Parser::ParseVectorDelimiters(size_t &count,
|
||||
const std::function<CheckedError()> &body) {
|
||||
EXPECT('[');
|
||||
for (;;) {
|
||||
if ((!opts.strict_json || !count) && Is(']')) { NEXT(); break; }
|
||||
if ((!opts.strict_json || !count) && Is(']')) break;
|
||||
ECHECK(body());
|
||||
count++;
|
||||
if (Is(']')) break;
|
||||
ECHECK(ParseComma());
|
||||
}
|
||||
NEXT();
|
||||
return NoError();
|
||||
}
|
||||
|
||||
CheckedError Parser::ParseVector(const Type &type, uoffset_t *ovalue) {
|
||||
size_t count = 0;
|
||||
auto err = ParseVectorDelimiters(count, [&]() -> CheckedError {
|
||||
Value val;
|
||||
val.type = type;
|
||||
ECHECK(ParseAnyValue(val, nullptr, 0, nullptr));
|
||||
field_stack_.push_back(std::make_pair(val, nullptr));
|
||||
count++;
|
||||
if (Is(']')) { NEXT(); break; }
|
||||
EXPECT(',');
|
||||
}
|
||||
return NoError();
|
||||
});
|
||||
ECHECK(err);
|
||||
|
||||
builder_.StartVector(count * InlineSize(type) / InlineAlignment(type),
|
||||
InlineAlignment(type));
|
||||
for (int i = 0; i < count; i++) {
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
// start at the back, since we're building the data backwards.
|
||||
auto &val = field_stack_.back().first;
|
||||
switch (val.type.base_type) {
|
||||
@@ -1038,14 +1191,24 @@ CheckedError Parser::ParseHash(Value &e, FieldDef* field) {
|
||||
assert(field);
|
||||
Value *hash_name = field->attributes.Lookup("hash");
|
||||
switch (e.type.base_type) {
|
||||
case BASE_TYPE_INT:
|
||||
case BASE_TYPE_INT: {
|
||||
auto hash = FindHashFunction32(hash_name->constant.c_str());
|
||||
int32_t hashed_value = static_cast<int32_t>(hash(attribute_.c_str()));
|
||||
e.constant = NumToString(hashed_value);
|
||||
break;
|
||||
}
|
||||
case BASE_TYPE_UINT: {
|
||||
auto hash = FindHashFunction32(hash_name->constant.c_str());
|
||||
uint32_t hashed_value = hash(attribute_.c_str());
|
||||
e.constant = NumToString(hashed_value);
|
||||
break;
|
||||
}
|
||||
case BASE_TYPE_LONG:
|
||||
case BASE_TYPE_LONG: {
|
||||
auto hash = FindHashFunction64(hash_name->constant.c_str());
|
||||
int64_t hashed_value = static_cast<int64_t>(hash(attribute_.c_str()));
|
||||
e.constant = NumToString(hashed_value);
|
||||
break;
|
||||
}
|
||||
case BASE_TYPE_ULONG: {
|
||||
auto hash = FindHashFunction64(hash_name->constant.c_str());
|
||||
uint64_t hashed_value = hash(attribute_.c_str());
|
||||
@@ -1059,6 +1222,11 @@ CheckedError Parser::ParseHash(Value &e, FieldDef* field) {
|
||||
return NoError();
|
||||
}
|
||||
|
||||
CheckedError Parser::TokenError() {
|
||||
return Error("cannot parse value starting with: " +
|
||||
TokenToStringId(token_));
|
||||
}
|
||||
|
||||
CheckedError Parser::ParseSingleValue(Value &e) {
|
||||
// First see if this could be a conversion function:
|
||||
if (token_ == kTokenIdentifier && *cursor_ == '(') {
|
||||
@@ -1093,10 +1261,15 @@ CheckedError Parser::ParseSingleValue(Value &e) {
|
||||
NEXT();
|
||||
} else { // Numeric constant in string.
|
||||
if (IsInteger(e.type.base_type)) {
|
||||
// TODO(wvo): do we want to check for garbage after the number?
|
||||
e.constant = NumToString(StringToInt(attribute_.c_str()));
|
||||
char *end;
|
||||
e.constant = NumToString(StringToInt(attribute_.c_str(), &end));
|
||||
if (*end)
|
||||
return Error("invalid integer: " + attribute_);
|
||||
} else if (IsFloat(e.type.base_type)) {
|
||||
e.constant = NumToString(strtod(attribute_.c_str(), nullptr));
|
||||
char *end;
|
||||
e.constant = NumToString(strtod(attribute_.c_str(), &end));
|
||||
if (*end)
|
||||
return Error("invalid float: " + attribute_);
|
||||
} else {
|
||||
assert(0); // Shouldn't happen, we covered all types.
|
||||
e.constant = "0";
|
||||
@@ -1120,9 +1293,7 @@ CheckedError Parser::ParseSingleValue(Value &e) {
|
||||
e,
|
||||
BASE_TYPE_STRING,
|
||||
&match));
|
||||
if (!match)
|
||||
return Error("cannot parse value starting with: " +
|
||||
TokenToStringId(token_));
|
||||
if (!match) return TokenError();
|
||||
}
|
||||
return NoError();
|
||||
}
|
||||
@@ -1246,7 +1417,16 @@ CheckedError Parser::ParseEnum(bool is_union, EnumDef **dest) {
|
||||
return Error("enum value already exists: " + value_name);
|
||||
ev.doc_comment = value_comment;
|
||||
if (is_union) {
|
||||
ev.struct_def = LookupCreateStruct(full_name);
|
||||
if (Is(':')) {
|
||||
NEXT();
|
||||
ECHECK(ParseType(ev.union_type));
|
||||
if (ev.union_type.base_type != BASE_TYPE_STRUCT &&
|
||||
ev.union_type.base_type != BASE_TYPE_STRING)
|
||||
return Error("union value type may only be table/struct/string");
|
||||
enum_def.uses_type_aliases = true;
|
||||
} else {
|
||||
ev.union_type = Type(BASE_TYPE_STRUCT, LookupCreateStruct(full_name));
|
||||
}
|
||||
}
|
||||
if (Is('=')) {
|
||||
NEXT();
|
||||
@@ -1256,6 +1436,10 @@ CheckedError Parser::ParseEnum(bool is_union, EnumDef **dest) {
|
||||
enum_def.vals.vec[prevsize - 1]->value >= ev.value)
|
||||
return Error("enum values must be specified in ascending order");
|
||||
}
|
||||
if (is_union) {
|
||||
if (ev.value < 0 || ev.value >= 256)
|
||||
return Error("union enum value must fit in a ubyte");
|
||||
}
|
||||
if (opts.proto_mode && Is('[')) {
|
||||
NEXT();
|
||||
// ignore attributes on enums.
|
||||
@@ -1278,6 +1462,8 @@ CheckedError Parser::ParseEnum(bool is_union, EnumDef **dest) {
|
||||
}
|
||||
}
|
||||
if (dest) *dest = &enum_def;
|
||||
types_.Add(namespaces_.back()->GetFullyQualifiedName(enum_def.name),
|
||||
new Type(BASE_TYPE_UNION, nullptr, &enum_def));
|
||||
return NoError();
|
||||
}
|
||||
|
||||
@@ -1289,7 +1475,7 @@ CheckedError Parser::StartStruct(const std::string &name, StructDef **dest) {
|
||||
struct_def.file = file_being_parsed_;
|
||||
// Move this struct to the back of the vector just in case it was predeclared,
|
||||
// to preserve declaration order.
|
||||
*remove(structs_.vec.begin(), structs_.vec.end(), &struct_def) = &struct_def;
|
||||
*std::remove(structs_.vec.begin(), structs_.vec.end(), &struct_def) = &struct_def;
|
||||
*dest = &struct_def;
|
||||
return NoError();
|
||||
}
|
||||
@@ -1341,10 +1527,11 @@ CheckedError Parser::ParseDecl() {
|
||||
auto align = static_cast<size_t>(atoi(force_align->constant.c_str()));
|
||||
if (force_align->type.base_type != BASE_TYPE_INT ||
|
||||
align < struct_def->minalign ||
|
||||
align > 16 ||
|
||||
align > FLATBUFFERS_MAX_ALIGNMENT ||
|
||||
align & (align - 1))
|
||||
return Error("force_align must be a power of two integer ranging from the"
|
||||
"struct\'s natural alignment to 16");
|
||||
"struct\'s natural alignment to " +
|
||||
NumToString(FLATBUFFERS_MAX_ALIGNMENT));
|
||||
struct_def->minalign = align;
|
||||
}
|
||||
struct_def->PadLastField(struct_def->minalign);
|
||||
@@ -1382,6 +1569,8 @@ CheckedError Parser::ParseDecl() {
|
||||
ECHECK(CheckClash(fields, struct_def, "_byte_vector", BASE_TYPE_STRING));
|
||||
ECHECK(CheckClash(fields, struct_def, "ByteVector", BASE_TYPE_STRING));
|
||||
EXPECT('}');
|
||||
types_.Add(namespaces_.back()->GetFullyQualifiedName(struct_def->name),
|
||||
new Type(BASE_TYPE_STRUCT, struct_def, nullptr));
|
||||
return NoError();
|
||||
}
|
||||
|
||||
@@ -1731,14 +1920,21 @@ CheckedError Parser::ParseTypeFromProtoType(Type *type) {
|
||||
|
||||
CheckedError Parser::SkipAnyJsonValue() {
|
||||
switch (token_) {
|
||||
case '{':
|
||||
ECHECK(SkipJsonObject());
|
||||
break;
|
||||
case '{': {
|
||||
size_t fieldn = 0;
|
||||
return ParseTableDelimiters(fieldn, nullptr,
|
||||
[&](const std::string &) -> CheckedError {
|
||||
ECHECK(SkipAnyJsonValue());
|
||||
fieldn++;
|
||||
return NoError();
|
||||
});
|
||||
}
|
||||
case '[': {
|
||||
size_t count = 0;
|
||||
return ParseVectorDelimiters(count, [&]() { return SkipAnyJsonValue(); });
|
||||
}
|
||||
case kTokenStringConstant:
|
||||
ECHECK(SkipJsonString());
|
||||
break;
|
||||
case '[':
|
||||
ECHECK(SkipJsonArray());
|
||||
EXPECT(kTokenStringConstant);
|
||||
break;
|
||||
case kTokenIntegerConstant:
|
||||
EXPECT(kTokenIntegerConstant);
|
||||
@@ -1747,83 +1943,98 @@ CheckedError Parser::SkipAnyJsonValue() {
|
||||
EXPECT(kTokenFloatConstant);
|
||||
break;
|
||||
default:
|
||||
return Error(std::string("Unexpected token:") + std::string(1, static_cast<char>(token_)));
|
||||
return TokenError();
|
||||
}
|
||||
return NoError();
|
||||
}
|
||||
|
||||
CheckedError Parser::SkipJsonObject() {
|
||||
EXPECT('{');
|
||||
size_t fieldn = 0;
|
||||
|
||||
for (;;) {
|
||||
if ((!opts.strict_json || !fieldn) && Is('}')) break;
|
||||
|
||||
if (!Is(kTokenStringConstant)) {
|
||||
EXPECT(opts.strict_json ? kTokenStringConstant : kTokenIdentifier);
|
||||
CheckedError Parser::ParseFlexBufferValue(flexbuffers::Builder *builder) {
|
||||
switch (token_) {
|
||||
case '{': {
|
||||
auto start = builder->StartMap();
|
||||
size_t fieldn = 0;
|
||||
auto err = ParseTableDelimiters(fieldn, nullptr,
|
||||
[&](const std::string &name) -> CheckedError {
|
||||
builder->Key(name);
|
||||
ECHECK(ParseFlexBufferValue(builder));
|
||||
fieldn++;
|
||||
return NoError();
|
||||
});
|
||||
ECHECK(err);
|
||||
builder->EndMap(start);
|
||||
break;
|
||||
}
|
||||
else {
|
||||
NEXT();
|
||||
case '[':{
|
||||
auto start = builder->StartVector();
|
||||
size_t count = 0;
|
||||
ECHECK(ParseVectorDelimiters(count, [&]() {
|
||||
return ParseFlexBufferValue(builder);
|
||||
}));
|
||||
builder->EndVector(start, false, false);
|
||||
break;
|
||||
}
|
||||
|
||||
EXPECT(':');
|
||||
ECHECK(SkipAnyJsonValue());
|
||||
fieldn++;
|
||||
|
||||
if (Is('}')) break;
|
||||
EXPECT(',');
|
||||
case kTokenStringConstant:
|
||||
builder->String(attribute_);
|
||||
EXPECT(kTokenStringConstant);
|
||||
break;
|
||||
case kTokenIntegerConstant:
|
||||
builder->Int(StringToInt(attribute_.c_str()));
|
||||
EXPECT(kTokenIntegerConstant);
|
||||
break;
|
||||
case kTokenFloatConstant:
|
||||
builder->Double(strtod(attribute_.c_str(), nullptr));
|
||||
EXPECT(kTokenFloatConstant);
|
||||
break;
|
||||
default:
|
||||
return TokenError();
|
||||
}
|
||||
|
||||
NEXT();
|
||||
return NoError();
|
||||
}
|
||||
|
||||
CheckedError Parser::SkipJsonArray() {
|
||||
EXPECT('[');
|
||||
|
||||
for (;;) {
|
||||
if (Is(']')) break;
|
||||
|
||||
ECHECK(SkipAnyJsonValue());
|
||||
|
||||
if (Is(']')) break;
|
||||
EXPECT(',');
|
||||
}
|
||||
|
||||
NEXT();
|
||||
return NoError();
|
||||
}
|
||||
|
||||
CheckedError Parser::SkipJsonString() {
|
||||
EXPECT(kTokenStringConstant);
|
||||
return NoError();
|
||||
bool Parser::ParseFlexBuffer(const char *source, const char *source_filename,
|
||||
flexbuffers::Builder *builder) {
|
||||
auto ok = !StartParseFile(source, source_filename).Check() &&
|
||||
!ParseFlexBufferValue(builder).Check();
|
||||
if (ok) builder->Finish();
|
||||
return ok;
|
||||
}
|
||||
|
||||
bool Parser::Parse(const char *source, const char **include_paths,
|
||||
const char *source_filename) {
|
||||
return !DoParse(source, include_paths, source_filename).Check();
|
||||
return !DoParse(source, include_paths, source_filename, nullptr).Check();
|
||||
}
|
||||
|
||||
CheckedError Parser::StartParseFile(const char *source, const char *source_filename) {
|
||||
file_being_parsed_ = source_filename ? source_filename : "";
|
||||
source_ = cursor_ = source;
|
||||
line_ = 1;
|
||||
error_.clear();
|
||||
ECHECK(SkipByteOrderMark());
|
||||
NEXT();
|
||||
if (Is(kTokenEof))
|
||||
return Error("input file is empty");
|
||||
return NoError();
|
||||
}
|
||||
|
||||
CheckedError Parser::DoParse(const char *source, const char **include_paths,
|
||||
const char *source_filename) {
|
||||
file_being_parsed_ = source_filename ? source_filename : "";
|
||||
const char *source_filename,
|
||||
const char *include_filename) {
|
||||
if (source_filename &&
|
||||
included_files_.find(source_filename) == included_files_.end()) {
|
||||
included_files_[source_filename] = true;
|
||||
included_files_[source_filename] = include_filename ? include_filename : "";
|
||||
files_included_per_file_[source_filename] = std::set<std::string>();
|
||||
}
|
||||
if (!include_paths) {
|
||||
static const char *current_directory[] = { "", nullptr };
|
||||
include_paths = current_directory;
|
||||
}
|
||||
source_ = cursor_ = source;
|
||||
line_ = 1;
|
||||
error_.clear();
|
||||
field_stack_.clear();
|
||||
builder_.Clear();
|
||||
// Start with a blank namespace just in case this file doesn't have one.
|
||||
namespaces_.push_back(new Namespace());
|
||||
ECHECK(SkipByteOrderMark());
|
||||
NEXT();
|
||||
|
||||
ECHECK(StartParseFile(source, source_filename));
|
||||
|
||||
// Includes must come before type declarations:
|
||||
for (;;) {
|
||||
// Parse pre-include proto statements if any:
|
||||
@@ -1831,13 +2042,17 @@ CheckedError Parser::DoParse(const char *source, const char **include_paths,
|
||||
(attribute_ == "option" || attribute_ == "syntax" ||
|
||||
attribute_ == "package")) {
|
||||
ECHECK(ParseProtoDecl());
|
||||
} else if (Is(kTokenNativeInclude)) {
|
||||
NEXT();
|
||||
native_included_files_.emplace_back(attribute_);
|
||||
EXPECT(kTokenStringConstant);
|
||||
} else if (Is(kTokenInclude) ||
|
||||
(opts.proto_mode &&
|
||||
attribute_ == "import" &&
|
||||
Is(kTokenIdentifier))) {
|
||||
NEXT();
|
||||
if (opts.proto_mode && attribute_ == "public") NEXT();
|
||||
auto name = attribute_;
|
||||
auto name = flatbuffers::PosixPath(attribute_.c_str());
|
||||
EXPECT(kTokenStringConstant);
|
||||
// Look for the file in include_paths.
|
||||
std::string filepath;
|
||||
@@ -1855,7 +2070,8 @@ CheckedError Parser::DoParse(const char *source, const char **include_paths,
|
||||
std::string contents;
|
||||
if (!LoadFile(filepath.c_str(), true, &contents))
|
||||
return Error("unable to load include file: " + name);
|
||||
ECHECK(DoParse(contents.c_str(), include_paths, filepath.c_str()));
|
||||
ECHECK(DoParse(contents.c_str(), include_paths, filepath.c_str(),
|
||||
name.c_str()));
|
||||
// We generally do not want to output code for any included files:
|
||||
if (!opts.generate_all) MarkGenerated();
|
||||
// This is the easiest way to continue this file after an include:
|
||||
@@ -1865,7 +2081,7 @@ CheckedError Parser::DoParse(const char *source, const char **include_paths,
|
||||
// entered into included_files_.
|
||||
// This is recursive, but only go as deep as the number of include
|
||||
// statements.
|
||||
return DoParse(source, include_paths, source_filename);
|
||||
return DoParse(source, include_paths, source_filename, include_filename);
|
||||
}
|
||||
EXPECT(';');
|
||||
} else {
|
||||
@@ -1936,6 +2152,8 @@ CheckedError Parser::DoParse(const char *source, const char **include_paths,
|
||||
return Error("type referenced but not defined: " + (*it)->name);
|
||||
}
|
||||
}
|
||||
// This check has to happen here and not earlier, because only now do we
|
||||
// know for sure what the type of these are.
|
||||
for (auto it = enums_.vec.begin(); it != enums_.vec.end(); ++it) {
|
||||
auto &enum_def = **it;
|
||||
if (enum_def.is_union) {
|
||||
@@ -1943,8 +2161,11 @@ CheckedError Parser::DoParse(const char *source, const char **include_paths,
|
||||
val_it != enum_def.vals.vec.end();
|
||||
++val_it) {
|
||||
auto &val = **val_it;
|
||||
if (val.struct_def && val.struct_def->fixed)
|
||||
return Error("only tables can be union elements: " + val.name);
|
||||
if (opts.lang_to_generate != IDLOptions::kCpp &&
|
||||
val.union_type.struct_def && val.union_type.struct_def->fixed)
|
||||
return Error(
|
||||
"only tables can be union elements in the generated language: "
|
||||
+ val.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1977,7 +2198,8 @@ std::set<std::string> Parser::GetIncludedFilesRecursive(
|
||||
// Schema serialization functionality:
|
||||
|
||||
template<typename T> bool compareName(const T* a, const T* b) {
|
||||
return a->name < b->name;
|
||||
return a->defined_namespace->GetFullyQualifiedName(a->name)
|
||||
< b->defined_namespace->GetFullyQualifiedName(b->name);
|
||||
}
|
||||
|
||||
template<typename T> void AssignIndices(const std::vector<T *> &defvec) {
|
||||
@@ -2023,14 +2245,19 @@ Offset<reflection::Object> StructDef::Serialize(FlatBufferBuilder *builder,
|
||||
(*it)->Serialize(builder,
|
||||
static_cast<uint16_t>(it - fields.vec.begin()), parser));
|
||||
}
|
||||
auto qualified_name = defined_namespace->GetFullyQualifiedName(name);
|
||||
return reflection::CreateObject(*builder,
|
||||
builder->CreateString(name),
|
||||
builder->CreateString(qualified_name),
|
||||
builder->CreateVectorOfSortedTables(
|
||||
&field_offsets),
|
||||
fixed,
|
||||
static_cast<int>(minalign),
|
||||
static_cast<int>(bytesize),
|
||||
SerializeAttributes(builder, parser));
|
||||
SerializeAttributes(builder, parser),
|
||||
parser.opts.binary_schema_comments
|
||||
? builder->CreateVectorOfStrings(
|
||||
doc_comment)
|
||||
: 0);
|
||||
}
|
||||
|
||||
Offset<reflection::Field> FieldDef::Serialize(FlatBufferBuilder *builder,
|
||||
@@ -2050,7 +2277,10 @@ Offset<reflection::Field> FieldDef::Serialize(FlatBufferBuilder *builder,
|
||||
deprecated,
|
||||
required,
|
||||
key,
|
||||
SerializeAttributes(builder, parser));
|
||||
SerializeAttributes(builder, parser),
|
||||
parser.opts.binary_schema_comments
|
||||
? builder->CreateVectorOfStrings(doc_comment)
|
||||
: 0);
|
||||
// TODO: value.constant is almost always "0", we could save quite a bit of
|
||||
// space by sharing it. Same for common values of value.type.
|
||||
}
|
||||
@@ -2061,12 +2291,16 @@ Offset<reflection::Enum> EnumDef::Serialize(FlatBufferBuilder *builder,
|
||||
for (auto it = vals.vec.begin(); it != vals.vec.end(); ++it) {
|
||||
enumval_offsets.push_back((*it)->Serialize(builder));
|
||||
}
|
||||
auto qualified_name = defined_namespace->GetFullyQualifiedName(name);
|
||||
return reflection::CreateEnum(*builder,
|
||||
builder->CreateString(name),
|
||||
builder->CreateString(qualified_name),
|
||||
builder->CreateVector(enumval_offsets),
|
||||
is_union,
|
||||
underlying_type.Serialize(builder),
|
||||
SerializeAttributes(builder, parser));
|
||||
SerializeAttributes(builder, parser),
|
||||
parser.opts.binary_schema_comments
|
||||
? builder->CreateVectorOfStrings(doc_comment)
|
||||
: 0);
|
||||
}
|
||||
|
||||
Offset<reflection::EnumVal> EnumVal::Serialize(FlatBufferBuilder *builder) const
|
||||
@@ -2074,9 +2308,11 @@ Offset<reflection::EnumVal> EnumVal::Serialize(FlatBufferBuilder *builder) const
|
||||
return reflection::CreateEnumVal(*builder,
|
||||
builder->CreateString(name),
|
||||
value,
|
||||
struct_def
|
||||
? struct_def->serialized_location
|
||||
: 0);
|
||||
union_type.struct_def
|
||||
? union_type.struct_def->
|
||||
serialized_location
|
||||
: 0,
|
||||
union_type.Serialize(builder));
|
||||
}
|
||||
|
||||
Offset<reflection::Type> Type::Serialize(FlatBufferBuilder *builder) const {
|
||||
|
||||
@@ -87,8 +87,11 @@ std::string GetAnyValueS(reflection::BaseType type, const uint8_t *data,
|
||||
auto &fielddef = **it;
|
||||
if (!table_field->CheckField(fielddef.offset())) continue;
|
||||
auto val = GetAnyFieldS(*table_field, fielddef, schema);
|
||||
if (fielddef.type()->base_type() == reflection::String)
|
||||
val = "\"" + val + "\""; // Doesn't deal with escape codes etc.
|
||||
if (fielddef.type()->base_type() == reflection::String) {
|
||||
std::string esc;
|
||||
flatbuffers::EscapeString(val.c_str(), val.length(), &esc, true);
|
||||
val = esc;
|
||||
}
|
||||
s += fielddef.name()->str();
|
||||
s += ": ";
|
||||
s += val;
|
||||
@@ -180,7 +183,8 @@ class ResizeContext {
|
||||
// Check if the range between first (lower address) and second straddles
|
||||
// the insertion point. If it does, change the offset at offsetloc (of
|
||||
// type T, with direction D).
|
||||
template<typename T, int D> void Straddle(void *first, void *second,
|
||||
template<typename T, int D> void Straddle(const void *first,
|
||||
const void *second,
|
||||
void *offsetloc) {
|
||||
if (first <= startptr_ && second >= startptr_) {
|
||||
WriteScalar<T>(offsetloc, ReadScalar<T>(offsetloc) + delta_ * D);
|
||||
@@ -194,9 +198,9 @@ class ResizeContext {
|
||||
// resize actually happens.
|
||||
// This must be checked for every offset, since we can't know which offsets
|
||||
// will straddle and which won't.
|
||||
uint8_t &DagCheck(void *offsetloc) {
|
||||
auto dag_idx = reinterpret_cast<uoffset_t *>(offsetloc) -
|
||||
reinterpret_cast<uoffset_t *>(buf_.data());
|
||||
uint8_t &DagCheck(const void *offsetloc) {
|
||||
auto dag_idx = reinterpret_cast<const uoffset_t *>(offsetloc) -
|
||||
reinterpret_cast<const uoffset_t *>(buf_.data());
|
||||
return dag_check_[dag_idx];
|
||||
}
|
||||
|
||||
@@ -419,8 +423,8 @@ Offset<const Table *> CopyTable(FlatBufferBuilder &fbb,
|
||||
offset = fbb.CreateVector(elements).o;
|
||||
break;
|
||||
}
|
||||
// FALL-THRU:
|
||||
}
|
||||
// FALL-THRU
|
||||
default: { // Scalars and structs.
|
||||
auto element_size = GetTypeSize(element_base_type);
|
||||
if (elemobjectdef && elemobjectdef->is_struct())
|
||||
@@ -457,8 +461,8 @@ Offset<const Table *> CopyTable(FlatBufferBuilder &fbb,
|
||||
subobjectdef.bytesize());
|
||||
break;
|
||||
}
|
||||
// else: FALL-THRU:
|
||||
}
|
||||
// ELSE FALL-THRU
|
||||
case reflection::Union:
|
||||
case reflection::String:
|
||||
case reflection::Vector:
|
||||
@@ -480,4 +484,230 @@ Offset<const Table *> CopyTable(FlatBufferBuilder &fbb,
|
||||
}
|
||||
}
|
||||
|
||||
bool VerifyStruct(flatbuffers::Verifier &v,
|
||||
const flatbuffers::Table &parent_table,
|
||||
voffset_t field_offset,
|
||||
const reflection::Object &obj,
|
||||
bool required) {
|
||||
auto offset = parent_table.GetOptionalFieldOffset(field_offset);
|
||||
if (required && !offset) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return !offset || v.Verify(reinterpret_cast<const uint8_t*>(&parent_table)
|
||||
+ offset, obj.bytesize());
|
||||
}
|
||||
|
||||
bool VerifyVectorOfStructs(flatbuffers::Verifier &v,
|
||||
const flatbuffers::Table &parent_table,
|
||||
voffset_t field_offset,
|
||||
const reflection::Object &obj,
|
||||
bool required) {
|
||||
auto p = parent_table.GetPointer<const uint8_t*>(field_offset);
|
||||
const uint8_t* end;
|
||||
if (required && !p) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return !p || v.VerifyVector(p, obj.bytesize(), &end);
|
||||
}
|
||||
|
||||
// forward declare to resolve cyclic deps between VerifyObject and VerifyVector
|
||||
bool VerifyObject(flatbuffers::Verifier &v,
|
||||
const reflection::Schema &schema,
|
||||
const reflection::Object &obj,
|
||||
const flatbuffers::Table *table,
|
||||
bool isRequired);
|
||||
|
||||
bool VerifyVector(flatbuffers::Verifier &v,
|
||||
const reflection::Schema &schema,
|
||||
const flatbuffers::Table &table,
|
||||
const reflection::Field &vec_field) {
|
||||
assert(vec_field.type()->base_type() == reflection::Vector);
|
||||
if (!table.VerifyField<uoffset_t>(v, vec_field.offset()))
|
||||
return false;
|
||||
|
||||
switch (vec_field.type()->element()) {
|
||||
case reflection::None:
|
||||
assert(false);
|
||||
break;
|
||||
case reflection::UType:
|
||||
return v.Verify(flatbuffers::GetFieldV<uint8_t>(table, vec_field));
|
||||
case reflection::Bool:
|
||||
case reflection::Byte:
|
||||
case reflection::UByte:
|
||||
return v.Verify(flatbuffers::GetFieldV<int8_t>(table, vec_field));
|
||||
case reflection::Short:
|
||||
case reflection::UShort:
|
||||
return v.Verify(flatbuffers::GetFieldV<int16_t>(table, vec_field));
|
||||
case reflection::Int:
|
||||
case reflection::UInt:
|
||||
return v.Verify(flatbuffers::GetFieldV<int32_t>(table, vec_field));
|
||||
case reflection::Long:
|
||||
case reflection::ULong:
|
||||
return v.Verify(flatbuffers::GetFieldV<int64_t>(table, vec_field));
|
||||
case reflection::Float:
|
||||
return v.Verify(flatbuffers::GetFieldV<float>(table, vec_field));
|
||||
case reflection::Double:
|
||||
return v.Verify(flatbuffers::GetFieldV<double>(table, vec_field));
|
||||
case reflection::String: {
|
||||
auto vecString =
|
||||
flatbuffers::GetFieldV<flatbuffers::
|
||||
Offset<flatbuffers::String>>(table, vec_field);
|
||||
if (v.Verify(vecString) && v.VerifyVectorOfStrings(vecString)) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
case reflection::Vector:
|
||||
assert(false);
|
||||
break;
|
||||
case reflection::Obj: {
|
||||
auto obj = schema.objects()->Get(vec_field.type()->index());
|
||||
if (obj->is_struct()) {
|
||||
if (!VerifyVectorOfStructs(v, table, vec_field.offset(), *obj,
|
||||
vec_field.required())) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
auto vec =
|
||||
flatbuffers::GetFieldV<flatbuffers::
|
||||
Offset<flatbuffers::Table>>(table, vec_field);
|
||||
if (!v.Verify(vec))
|
||||
return false;
|
||||
if (vec) {
|
||||
for (uoffset_t j = 0; j < vec->size(); j++) {
|
||||
if (!VerifyObject(v, schema, *obj, vec->Get(j), true)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
case reflection::Union:
|
||||
assert(false);
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool VerifyObject(flatbuffers::Verifier &v,
|
||||
const reflection::Schema &schema,
|
||||
const reflection::Object &obj,
|
||||
const flatbuffers::Table *table,
|
||||
bool required) {
|
||||
if (!table) {
|
||||
if (!required)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!table->VerifyTableStart(v))
|
||||
return false;
|
||||
|
||||
for (uoffset_t i = 0; i < obj.fields()->size(); i++) {
|
||||
auto field_def = obj.fields()->Get(i);
|
||||
switch (field_def->type()->base_type()) {
|
||||
case reflection::None:
|
||||
assert(false);
|
||||
break;
|
||||
case reflection::UType:
|
||||
if (!table->VerifyField<uint8_t>(v, field_def->offset()))
|
||||
return false;
|
||||
break;
|
||||
case reflection::Bool:
|
||||
case reflection::Byte:
|
||||
case reflection::UByte:
|
||||
if (!table->VerifyField<int8_t>(v, field_def->offset()))
|
||||
return false;
|
||||
break;
|
||||
case reflection::Short:
|
||||
case reflection::UShort:
|
||||
if (!table->VerifyField<int16_t>(v, field_def->offset()))
|
||||
return false;
|
||||
break;
|
||||
case reflection::Int:
|
||||
case reflection::UInt:
|
||||
if (!table->VerifyField<int32_t>(v, field_def->offset()))
|
||||
return false;
|
||||
break;
|
||||
case reflection::Long:
|
||||
case reflection::ULong:
|
||||
if (!table->VerifyField<int64_t>(v, field_def->offset()))
|
||||
return false;
|
||||
break;
|
||||
case reflection::Float:
|
||||
if (!table->VerifyField<float>(v, field_def->offset()))
|
||||
return false;
|
||||
break;
|
||||
case reflection::Double:
|
||||
if (!table->VerifyField<double>(v, field_def->offset()))
|
||||
return false;
|
||||
break;
|
||||
case reflection::String:
|
||||
if (!table->VerifyField<uoffset_t>(v, field_def->offset()) ||
|
||||
!v.Verify(flatbuffers::GetFieldS(*table, *field_def))) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case reflection::Vector:
|
||||
if (!VerifyVector(v, schema, *table, *field_def))
|
||||
return false;
|
||||
break;
|
||||
case reflection::Obj: {
|
||||
auto child_obj = schema.objects()->Get(field_def->type()->index());
|
||||
if (child_obj->is_struct()) {
|
||||
if (!VerifyStruct(v, *table, field_def->offset(), *child_obj,
|
||||
field_def->required())) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (!VerifyObject(v, schema, *child_obj,
|
||||
flatbuffers::GetFieldT(*table, *field_def),
|
||||
field_def->required())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case reflection::Union: {
|
||||
// get union type from the prev field
|
||||
voffset_t utype_offset = field_def->offset() - sizeof(voffset_t);
|
||||
auto utype = table->GetField<uint8_t>(utype_offset, 0);
|
||||
if (utype != 0) {
|
||||
// Means we have this union field present
|
||||
auto fb_enum = schema.enums()->Get(field_def->type()->index());
|
||||
auto child_obj = fb_enum->values()->Get(utype)->object();
|
||||
if (!VerifyObject(v, schema, *child_obj,
|
||||
flatbuffers::GetFieldT(*table, *field_def),
|
||||
field_def->required())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
assert(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Verify(const reflection::Schema &schema,
|
||||
const reflection::Object &root,
|
||||
const uint8_t *buf,
|
||||
size_t length) {
|
||||
Verifier v(buf, length);
|
||||
return VerifyObject(v, schema, root, flatbuffers::GetAnyRoot(buf), true);
|
||||
}
|
||||
|
||||
} // namespace flatbuffers
|
||||
|
||||
@@ -40,6 +40,7 @@ namespace FlatBuffers.Test
|
||||
Assert.AreEqual((byte)99, buffer[0]);
|
||||
}
|
||||
|
||||
#if !BYTEBUFFER_NO_BOUNDS_CHECK
|
||||
[FlatBuffersTestMethod]
|
||||
public void ByteBuffer_PutByteCannotPutAtOffsetPastLength()
|
||||
{
|
||||
@@ -47,6 +48,7 @@ namespace FlatBuffers.Test
|
||||
var uut = new ByteBuffer(buffer);
|
||||
Assert.Throws<ArgumentOutOfRangeException>(() => uut.PutByte(1, 99));
|
||||
}
|
||||
#endif
|
||||
|
||||
[FlatBuffersTestMethod]
|
||||
public void ByteBuffer_PutShortPopulatesBufferCorrectly()
|
||||
@@ -60,6 +62,7 @@ namespace FlatBuffers.Test
|
||||
Assert.AreEqual((byte)0, buffer[1]);
|
||||
}
|
||||
|
||||
#if !BYTEBUFFER_NO_BOUNDS_CHECK
|
||||
[FlatBuffersTestMethod]
|
||||
public void ByteBuffer_PutShortCannotPutAtOffsetPastLength()
|
||||
{
|
||||
@@ -67,7 +70,9 @@ namespace FlatBuffers.Test
|
||||
var uut = new ByteBuffer(buffer);
|
||||
Assert.Throws<ArgumentOutOfRangeException>(() => uut.PutShort(2, 99));
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !BYTEBUFFER_NO_BOUNDS_CHECK
|
||||
[FlatBuffersTestMethod]
|
||||
public void ByteBuffer_PutShortChecksLength()
|
||||
{
|
||||
@@ -83,6 +88,7 @@ namespace FlatBuffers.Test
|
||||
var uut = new ByteBuffer(buffer);
|
||||
Assert.Throws<ArgumentOutOfRangeException>(() => uut.PutShort(1, 99));
|
||||
}
|
||||
#endif
|
||||
|
||||
[FlatBuffersTestMethod]
|
||||
public void ByteBuffer_PutIntPopulatesBufferCorrectly()
|
||||
@@ -98,6 +104,7 @@ namespace FlatBuffers.Test
|
||||
Assert.AreEqual(0x0A, buffer[3]);
|
||||
}
|
||||
|
||||
#if !BYTEBUFFER_NO_BOUNDS_CHECK
|
||||
[FlatBuffersTestMethod]
|
||||
public void ByteBuffer_PutIntCannotPutAtOffsetPastLength()
|
||||
{
|
||||
@@ -121,6 +128,7 @@ namespace FlatBuffers.Test
|
||||
var uut = new ByteBuffer(buffer);
|
||||
Assert.Throws<ArgumentOutOfRangeException>(() => uut.PutInt(2, 0x0A0B0C0D));
|
||||
}
|
||||
#endif
|
||||
|
||||
[FlatBuffersTestMethod]
|
||||
public void ByteBuffer_PutLongPopulatesBufferCorrectly()
|
||||
@@ -140,6 +148,7 @@ namespace FlatBuffers.Test
|
||||
Assert.AreEqual(0x01, buffer[7]);
|
||||
}
|
||||
|
||||
#if !BYTEBUFFER_NO_BOUNDS_CHECK
|
||||
[FlatBuffersTestMethod]
|
||||
public void ByteBuffer_PutLongCannotPutAtOffsetPastLength()
|
||||
{
|
||||
@@ -163,6 +172,7 @@ namespace FlatBuffers.Test
|
||||
var uut = new ByteBuffer(buffer);
|
||||
Assert.Throws<ArgumentOutOfRangeException>(() => uut.PutLong(2, 0x010203040A0B0C0D));
|
||||
}
|
||||
#endif
|
||||
|
||||
[FlatBuffersTestMethod]
|
||||
public void ByteBuffer_GetByteReturnsCorrectData()
|
||||
@@ -173,6 +183,7 @@ namespace FlatBuffers.Test
|
||||
Assert.AreEqual((byte)99, uut.Get(0));
|
||||
}
|
||||
|
||||
#if !BYTEBUFFER_NO_BOUNDS_CHECK
|
||||
[FlatBuffersTestMethod]
|
||||
public void ByteBuffer_GetByteChecksOffset()
|
||||
{
|
||||
@@ -180,6 +191,7 @@ namespace FlatBuffers.Test
|
||||
var uut = new ByteBuffer(buffer);
|
||||
Assert.Throws<ArgumentOutOfRangeException>(()=>uut.Get(1));
|
||||
}
|
||||
#endif
|
||||
|
||||
[FlatBuffersTestMethod]
|
||||
public void ByteBuffer_GetShortReturnsCorrectData()
|
||||
@@ -191,6 +203,7 @@ namespace FlatBuffers.Test
|
||||
Assert.AreEqual(1, uut.GetShort(0));
|
||||
}
|
||||
|
||||
#if !BYTEBUFFER_NO_BOUNDS_CHECK
|
||||
[FlatBuffersTestMethod]
|
||||
public void ByteBuffer_GetShortChecksOffset()
|
||||
{
|
||||
@@ -206,6 +219,7 @@ namespace FlatBuffers.Test
|
||||
var uut = new ByteBuffer(buffer);
|
||||
Assert.Throws<ArgumentOutOfRangeException>(() => uut.GetShort(1));
|
||||
}
|
||||
#endif
|
||||
|
||||
[FlatBuffersTestMethod]
|
||||
public void ByteBuffer_GetIntReturnsCorrectData()
|
||||
@@ -219,6 +233,7 @@ namespace FlatBuffers.Test
|
||||
Assert.AreEqual(0x0A0B0C0D, uut.GetInt(0));
|
||||
}
|
||||
|
||||
#if !BYTEBUFFER_NO_BOUNDS_CHECK
|
||||
[FlatBuffersTestMethod]
|
||||
public void ByteBuffer_GetIntChecksOffset()
|
||||
{
|
||||
@@ -234,6 +249,7 @@ namespace FlatBuffers.Test
|
||||
var uut = new ByteBuffer(buffer);
|
||||
Assert.Throws<ArgumentOutOfRangeException>(() => uut.GetInt(0));
|
||||
}
|
||||
#endif
|
||||
|
||||
[FlatBuffersTestMethod]
|
||||
public void ByteBuffer_GetLongReturnsCorrectData()
|
||||
@@ -251,6 +267,7 @@ namespace FlatBuffers.Test
|
||||
Assert.AreEqual(0x010203040A0B0C0D, uut.GetLong(0));
|
||||
}
|
||||
|
||||
#if !BYTEBUFFER_NO_BOUNDS_CHECK
|
||||
[FlatBuffersTestMethod]
|
||||
public void ByteBuffer_GetLongChecksOffset()
|
||||
{
|
||||
@@ -266,6 +283,7 @@ namespace FlatBuffers.Test
|
||||
var uut = new ByteBuffer(buffer);
|
||||
Assert.Throws<ArgumentOutOfRangeException>(() => uut.GetLong(0));
|
||||
}
|
||||
#endif
|
||||
|
||||
[FlatBuffersTestMethod]
|
||||
public void ByteBuffer_ReverseBytesUshort()
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
@@ -41,6 +41,9 @@
|
||||
<Compile Include="..\..\net\FlatBuffers\ByteBuffer.cs">
|
||||
<Link>FlatBuffers\ByteBuffer.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\..\net\FlatBuffers\IFlatbufferObject.cs">
|
||||
<Link>FlatBuffers\IFlatbufferObject.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\..\net\FlatBuffers\Offset.cs">
|
||||
<Link>FlatBuffers\Offset.cs</Link>
|
||||
</Compile>
|
||||
@@ -77,6 +80,9 @@
|
||||
<Compile Include="..\MyGame\Example\Vec3.cs">
|
||||
<Link>MyGame\Example\Vec3.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\MyGame\Example\Ability.cs">
|
||||
<Link>MyGame\Example\Ability.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\namespace_test\NamespaceA\NamespaceB\EnumInNestedNS.cs">
|
||||
<Link>NamespaceA\NamespaceB\EnumInNestedNS.cs</Link>
|
||||
</Compile>
|
||||
@@ -116,4 +122,4 @@
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
||||
</Project>
|
||||
|
||||
@@ -39,6 +39,19 @@ namespace FlatBuffers.Test
|
||||
// better for performance.
|
||||
var fbb = new FlatBufferBuilder(1);
|
||||
|
||||
StringOffset[] names = { fbb.CreateString("Frodo"), fbb.CreateString("Barney"), fbb.CreateString("Wilma") };
|
||||
Offset<Monster>[] off = new Offset<Monster>[3];
|
||||
Monster.StartMonster(fbb);
|
||||
Monster.AddName(fbb, names[0]);
|
||||
off[0] = Monster.EndMonster(fbb);
|
||||
Monster.StartMonster(fbb);
|
||||
Monster.AddName(fbb, names[1]);
|
||||
off[1] = Monster.EndMonster(fbb);
|
||||
Monster.StartMonster(fbb);
|
||||
Monster.AddName(fbb, names[2]);
|
||||
off[2] = Monster.EndMonster(fbb);
|
||||
var sortMons = Monster.CreateSortedVectorOfMonster(fbb, off);
|
||||
|
||||
// We set up the same values as monsterdata.json:
|
||||
|
||||
var str = fbb.CreateString("MyMonster");
|
||||
@@ -79,6 +92,7 @@ namespace FlatBuffers.Test
|
||||
Monster.AddTest4(fbb, test4);
|
||||
Monster.AddTestarrayofstring(fbb, testArrayOfString);
|
||||
Monster.AddTestbool(fbb, false);
|
||||
Monster.AddTestarrayoftables(fbb, sortMons);
|
||||
var mon = Monster.EndMonster(fbb);
|
||||
|
||||
Monster.FinishMonsterBuffer(fbb, mon);
|
||||
@@ -103,6 +117,16 @@ namespace FlatBuffers.Test
|
||||
Assert.AreEqual(monster.MutateMana((short)10), false);
|
||||
Assert.AreEqual(monster.Mana, (short)150);
|
||||
|
||||
// Accessing a vector of sorted by the key tables
|
||||
Assert.AreEqual(monster.Testarrayoftables(0).Value.Name, "Barney");
|
||||
Assert.AreEqual(monster.Testarrayoftables(1).Value.Name, "Frodo");
|
||||
Assert.AreEqual(monster.Testarrayoftables(2).Value.Name, "Wilma");
|
||||
|
||||
// Example of searching for a table by the key
|
||||
Assert.IsTrue(monster.TestarrayoftablesByKey("Frodo") != null);
|
||||
Assert.IsTrue(monster.TestarrayoftablesByKey("Barney") != null);
|
||||
Assert.IsTrue(monster.TestarrayoftablesByKey("Wilma") != null);
|
||||
|
||||
// testType is an existing field and mutating it should succeed
|
||||
Assert.AreEqual(monster.TestType, Any.Monster);
|
||||
Assert.AreEqual(monster.MutateTestType(Any.NONE), true);
|
||||
@@ -119,7 +143,7 @@ namespace FlatBuffers.Test
|
||||
|
||||
for (int i = 0; i < monster.InventoryLength; i++)
|
||||
{
|
||||
Assert.AreEqual(monster.GetInventory(i), i + 1);
|
||||
Assert.AreEqual(monster.Inventory(i), i + 1);
|
||||
}
|
||||
|
||||
//reverse mutation
|
||||
@@ -130,7 +154,7 @@ namespace FlatBuffers.Test
|
||||
Assert.AreEqual(monster.MutateInventory(4, 4), true);
|
||||
|
||||
// get a struct field and edit one of its fields
|
||||
Vec3 pos = monster.Pos;
|
||||
Vec3 pos = (Vec3)monster.Pos;
|
||||
Assert.AreEqual(pos.X, 1.0f);
|
||||
pos.MutateX(55.0f);
|
||||
Assert.AreEqual(pos.X, 55.0f);
|
||||
@@ -148,21 +172,20 @@ namespace FlatBuffers.Test
|
||||
Assert.AreEqual(150, monster.Mana);
|
||||
Assert.AreEqual("MyMonster", monster.Name);
|
||||
|
||||
var pos = monster.Pos;
|
||||
var pos = monster.Pos.Value;
|
||||
Assert.AreEqual(1.0f, pos.X);
|
||||
Assert.AreEqual(2.0f, pos.Y);
|
||||
Assert.AreEqual(3.0f, pos.Z);
|
||||
|
||||
Assert.AreEqual(3.0f, pos.Test1);
|
||||
Assert.AreEqual(Color.Green, pos.Test2);
|
||||
var t = pos.Test3;
|
||||
var t = (MyGame.Example.Test)pos.Test3;
|
||||
Assert.AreEqual((short)5, t.A);
|
||||
Assert.AreEqual((sbyte)6, t.B);
|
||||
|
||||
Assert.AreEqual(Any.Monster, monster.TestType);
|
||||
|
||||
var monster2 = new Monster();
|
||||
Assert.IsTrue(monster.GetTest(monster2) != null);
|
||||
var monster2 = monster.Test<Monster>().Value;
|
||||
Assert.AreEqual("Fred", monster2.Name);
|
||||
|
||||
|
||||
@@ -170,19 +193,19 @@ namespace FlatBuffers.Test
|
||||
var invsum = 0;
|
||||
for (var i = 0; i < monster.InventoryLength; i++)
|
||||
{
|
||||
invsum += monster.GetInventory(i);
|
||||
invsum += monster.Inventory(i);
|
||||
}
|
||||
Assert.AreEqual(10, invsum);
|
||||
|
||||
var test0 = monster.GetTest4(0);
|
||||
var test1 = monster.GetTest4(1);
|
||||
var test0 = monster.Test4(0).Value;
|
||||
var test1 = monster.Test4(1).Value;
|
||||
Assert.AreEqual(2, monster.Test4Length);
|
||||
|
||||
Assert.AreEqual(100, test0.A + test0.B + test1.A + test1.B);
|
||||
|
||||
Assert.AreEqual(2, monster.TestarrayofstringLength);
|
||||
Assert.AreEqual("test1", monster.GetTestarrayofstring(0));
|
||||
Assert.AreEqual("test2", monster.GetTestarrayofstring(1));
|
||||
Assert.AreEqual("test1", monster.Testarrayofstring(0));
|
||||
Assert.AreEqual("test2", monster.Testarrayofstring(1));
|
||||
|
||||
Assert.AreEqual(false, monster.Testbool);
|
||||
|
||||
@@ -245,10 +268,10 @@ namespace FlatBuffers.Test
|
||||
Monster.AddTestnestedflatbuffer(fbb2, nestedBuffer);
|
||||
var monster = Monster.EndMonster(fbb2);
|
||||
Monster.FinishMonsterBuffer(fbb2, monster);
|
||||
|
||||
|
||||
// Now test the data extracted from the nested buffer
|
||||
var mons = Monster.GetRootAsMonster(fbb2.DataBuffer);
|
||||
var nestedMonster = mons.TestnestedflatbufferAsMonster();
|
||||
var nestedMonster = mons.GetTestnestedflatbufferAsMonster().Value;
|
||||
|
||||
Assert.AreEqual(nestedMonsterMana, nestedMonster.Mana);
|
||||
Assert.AreEqual(nestedMonsterHp, nestedMonster.Hp);
|
||||
|
||||
9
tests/FlatBuffers.Test/NetTest.sh
Normal file
9
tests/FlatBuffers.Test/NetTest.sh
Normal file
@@ -0,0 +1,9 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Testing C# on Linux using Mono.
|
||||
|
||||
mcs -out:fbnettest.exe ../../net/FlatBuffers/*.cs ../MyGame/Example/*.cs FlatBuffersTestClassAttribute.cs FlatBuffersTestMethodAttribute.cs Assert.cs FlatBuffersExampleTests.cs Program.cs ByteBufferTests.cs FlatBufferBuilderTests.cs FlatBuffersFuzzTests.cs FuzzTestData.cs Lcg.cs TestTable.cs
|
||||
./fbnettest.exe
|
||||
rm fbnettest.exe
|
||||
rm Resources/monsterdata_cstest.mon
|
||||
|
||||
@@ -19,133 +19,135 @@ namespace FlatBuffers.Test
|
||||
/// <summary>
|
||||
/// A test Table object that gives easy access to the slot data
|
||||
/// </summary>
|
||||
internal class TestTable : Table
|
||||
internal struct TestTable
|
||||
{
|
||||
Table t;
|
||||
|
||||
public TestTable(ByteBuffer bb, int pos)
|
||||
{
|
||||
base.bb = bb;
|
||||
base.bb_pos = pos;
|
||||
t.bb = bb;
|
||||
t.bb_pos = pos;
|
||||
}
|
||||
|
||||
public bool GetSlot(int slot, bool def)
|
||||
{
|
||||
var off = base.__offset(slot);
|
||||
var off = t.__offset(slot);
|
||||
|
||||
if (off == 0)
|
||||
{
|
||||
return def;
|
||||
}
|
||||
return bb.GetSbyte(bb_pos + off) != 0;
|
||||
return t.bb.GetSbyte(t.bb_pos + off) != 0;
|
||||
}
|
||||
|
||||
public sbyte GetSlot(int slot, sbyte def)
|
||||
{
|
||||
var off = base.__offset(slot);
|
||||
var off = t.__offset(slot);
|
||||
|
||||
if (off == 0)
|
||||
{
|
||||
return def;
|
||||
}
|
||||
return bb.GetSbyte(bb_pos + off);
|
||||
return t.bb.GetSbyte(t.bb_pos + off);
|
||||
}
|
||||
|
||||
public byte GetSlot(int slot, byte def)
|
||||
{
|
||||
var off = base.__offset(slot);
|
||||
var off = t.__offset(slot);
|
||||
|
||||
if (off == 0)
|
||||
{
|
||||
return def;
|
||||
}
|
||||
return bb.Get(bb_pos + off);
|
||||
return t.bb.Get(t.bb_pos + off);
|
||||
}
|
||||
|
||||
public short GetSlot(int slot, short def)
|
||||
{
|
||||
var off = base.__offset(slot);
|
||||
var off = t.__offset(slot);
|
||||
|
||||
if (off == 0)
|
||||
{
|
||||
return def;
|
||||
}
|
||||
return bb.GetShort(bb_pos + off);
|
||||
return t.bb.GetShort(t.bb_pos + off);
|
||||
}
|
||||
|
||||
public ushort GetSlot(int slot, ushort def)
|
||||
{
|
||||
var off = base.__offset(slot);
|
||||
var off = t.__offset(slot);
|
||||
|
||||
if (off == 0)
|
||||
{
|
||||
return def;
|
||||
}
|
||||
return bb.GetUshort(bb_pos + off);
|
||||
return t.bb.GetUshort(t.bb_pos + off);
|
||||
}
|
||||
|
||||
public int GetSlot(int slot, int def)
|
||||
{
|
||||
var off = base.__offset(slot);
|
||||
var off = t.__offset(slot);
|
||||
|
||||
if (off == 0)
|
||||
{
|
||||
return def;
|
||||
}
|
||||
return bb.GetInt(bb_pos + off);
|
||||
return t.bb.GetInt(t.bb_pos + off);
|
||||
}
|
||||
|
||||
public uint GetSlot(int slot, uint def)
|
||||
{
|
||||
var off = base.__offset(slot);
|
||||
var off = t.__offset(slot);
|
||||
|
||||
if (off == 0)
|
||||
{
|
||||
return def;
|
||||
}
|
||||
return bb.GetUint(bb_pos + off);
|
||||
return t.bb.GetUint(t.bb_pos + off);
|
||||
}
|
||||
|
||||
public long GetSlot(int slot, long def)
|
||||
{
|
||||
var off = base.__offset(slot);
|
||||
var off = t.__offset(slot);
|
||||
|
||||
if (off == 0)
|
||||
{
|
||||
return def;
|
||||
}
|
||||
return bb.GetLong(bb_pos + off);
|
||||
return t.bb.GetLong(t.bb_pos + off);
|
||||
}
|
||||
|
||||
public ulong GetSlot(int slot, ulong def)
|
||||
{
|
||||
var off = base.__offset(slot);
|
||||
var off = t.__offset(slot);
|
||||
|
||||
if (off == 0)
|
||||
{
|
||||
return def;
|
||||
}
|
||||
return bb.GetUlong(bb_pos + off);
|
||||
return t.bb.GetUlong(t.bb_pos + off);
|
||||
}
|
||||
|
||||
public float GetSlot(int slot, float def)
|
||||
{
|
||||
var off = base.__offset(slot);
|
||||
var off = t.__offset(slot);
|
||||
|
||||
if (off == 0)
|
||||
{
|
||||
return def;
|
||||
}
|
||||
return bb.GetFloat(bb_pos + off);
|
||||
return t.bb.GetFloat(t.bb_pos + off);
|
||||
}
|
||||
|
||||
public double GetSlot(int slot, double def)
|
||||
{
|
||||
var off = base.__offset(slot);
|
||||
var off = t.__offset(slot);
|
||||
|
||||
if (off == 0)
|
||||
{
|
||||
return def;
|
||||
}
|
||||
return bb.GetDouble(bb_pos + off);
|
||||
return t.bb.GetDouble(t.bb_pos + off);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ go_path=${test_dir}/go_gen
|
||||
go_src=${go_path}/src
|
||||
|
||||
# Emit Go code for the example schema in the test dir:
|
||||
../flatc -g monster_test.fbs
|
||||
../flatc -g -I include_test monster_test.fbs
|
||||
|
||||
# Go requires a particular layout of files in order to link multiple packages.
|
||||
# Copy flatbuffer Go files to their own package directories to compile the
|
||||
|
||||
@@ -3,7 +3,7 @@ var assert = require('assert');
|
||||
var fs = require('fs');
|
||||
|
||||
var flatbuffers = require('../js/flatbuffers').flatbuffers;
|
||||
var MyGame = require('./monster_test_generated').MyGame;
|
||||
var MyGame = require(process.argv[2]).MyGame;
|
||||
|
||||
function main() {
|
||||
|
||||
@@ -67,7 +67,7 @@ function main() {
|
||||
// Tests mutation first. This will verify that we did not trample any other
|
||||
// part of the byte buffer.
|
||||
testMutation(fbb.dataBuffer());
|
||||
|
||||
|
||||
testBuffer(fbb.dataBuffer());
|
||||
|
||||
test64bit();
|
||||
@@ -156,7 +156,8 @@ function test64bit() {
|
||||
var mon2 = MyGame.Example.Monster.endMonster(fbb);
|
||||
|
||||
MyGame.Example.Stat.startStat(fbb);
|
||||
MyGame.Example.Stat.addVal(fbb, new flatbuffers.Long(0x12345678, 0x23456789));
|
||||
// 2541551405100253985 = 0x87654321(low part) + 0x23456789 * 0x100000000(high part);
|
||||
MyGame.Example.Stat.addVal(fbb, new flatbuffers.Long(0x87654321, 0x23456789)); // the low part is Uint32
|
||||
var stat = MyGame.Example.Stat.endStat(fbb);
|
||||
|
||||
MyGame.Example.Monster.startMonster(fbb);
|
||||
@@ -177,8 +178,7 @@ function test64bit() {
|
||||
var stat = mon.testempty();
|
||||
assert.strictEqual(stat != null, true);
|
||||
assert.strictEqual(stat.val() != null, true);
|
||||
assert.strictEqual(stat.val().low, 0x12345678);
|
||||
assert.strictEqual(stat.val().high, 0x23456789);
|
||||
assert.strictEqual(stat.val().toFloat64(), 2541551405100253985);
|
||||
|
||||
var mon2 = mon.enemy();
|
||||
assert.strictEqual(mon2 != null, true);
|
||||
|
||||
@@ -15,5 +15,5 @@
|
||||
# limitations under the License.
|
||||
|
||||
pushd "$(dirname $0)" >/dev/null
|
||||
../flatc -b monster_test.fbs unicode_test.json
|
||||
node JavaScriptTest
|
||||
../flatc -b -I include_test monster_test.fbs unicode_test.json
|
||||
node JavaScriptTest ./monster_test_generated
|
||||
|
||||
@@ -51,6 +51,19 @@ class JavaTest {
|
||||
// better for performance.
|
||||
FlatBufferBuilder fbb = new FlatBufferBuilder(1);
|
||||
|
||||
int[] names = {fbb.createString("Frodo"), fbb.createString("Barney"), fbb.createString("Wilma")};
|
||||
int[] off = new int[3];
|
||||
Monster.startMonster(fbb);
|
||||
Monster.addName(fbb, names[0]);
|
||||
off[0] = Monster.endMonster(fbb);
|
||||
Monster.startMonster(fbb);
|
||||
Monster.addName(fbb, names[1]);
|
||||
off[1] = Monster.endMonster(fbb);
|
||||
Monster.startMonster(fbb);
|
||||
Monster.addName(fbb, names[2]);
|
||||
off[2] = Monster.endMonster(fbb);
|
||||
int sortMons = fbb.createSortedVectorOfTables(new Monster(), off);
|
||||
|
||||
// We set up the same values as monsterdata.json:
|
||||
|
||||
int str = fbb.createString("MyMonster");
|
||||
@@ -84,6 +97,7 @@ class JavaTest {
|
||||
Monster.addTestarrayofstring(fbb, testArrayOfString);
|
||||
Monster.addTestbool(fbb, false);
|
||||
Monster.addTesthashu32Fnv1(fbb, Integer.MAX_VALUE + 1L);
|
||||
Monster.addTestarrayoftables(fbb, sortMons);
|
||||
int mon = Monster.endMonster(fbb);
|
||||
|
||||
Monster.finishMonsterBuffer(fbb, mon);
|
||||
@@ -122,6 +136,16 @@ class JavaTest {
|
||||
TestEq(monster.mutateMana((short)10), false);
|
||||
TestEq(monster.mana(), (short)150);
|
||||
|
||||
// Accessing a vector of sorted by the key tables
|
||||
TestEq(monster.testarrayoftables(0).name(), "Barney");
|
||||
TestEq(monster.testarrayoftables(1).name(), "Frodo");
|
||||
TestEq(monster.testarrayoftables(2).name(), "Wilma");
|
||||
|
||||
// Example of searching for a table by the key
|
||||
TestEq(monster.testarrayoftablesByKey("Frodo").name(), "Frodo");
|
||||
TestEq(monster.testarrayoftablesByKey("Barney").name(), "Barney");
|
||||
TestEq(monster.testarrayoftablesByKey("Wilma").name(), "Wilma");
|
||||
|
||||
// testType is an existing field and mutating it should succeed
|
||||
TestEq(monster.testType(), (byte)Any.Monster);
|
||||
TestEq(monster.mutateTestType(Any.NONE), true);
|
||||
@@ -161,6 +185,10 @@ class JavaTest {
|
||||
|
||||
TestNestedFlatBuffer();
|
||||
|
||||
TestCreateByteVector();
|
||||
|
||||
TestCreateUninitializedVector();
|
||||
|
||||
System.out.println("FlatBuffers test: completed successfully");
|
||||
}
|
||||
|
||||
@@ -173,7 +201,7 @@ class JavaTest {
|
||||
|
||||
static void TestBuffer(ByteBuffer bb) {
|
||||
TestEq(Monster.MonsterBufferHasIdentifier(bb), true);
|
||||
|
||||
|
||||
Monster monster = Monster.getRootAsMonster(bb);
|
||||
|
||||
TestEq(monster.hp(), (short)80);
|
||||
@@ -231,25 +259,25 @@ class JavaTest {
|
||||
|
||||
TestEq(monster.testhashu32Fnv1(), Integer.MAX_VALUE + 1L);
|
||||
}
|
||||
|
||||
|
||||
static void TestNamespaceNesting() {
|
||||
// reference / manipulate these to verify compilation
|
||||
FlatBufferBuilder fbb = new FlatBufferBuilder(1);
|
||||
|
||||
|
||||
TableInNestedNS.startTableInNestedNS(fbb);
|
||||
TableInNestedNS.addFoo(fbb, 1234);
|
||||
int nestedTableOff = TableInNestedNS.endTableInNestedNS(fbb);
|
||||
|
||||
TableInFirstNS.startTableInFirstNS(fbb);
|
||||
|
||||
TableInFirstNS.startTableInFirstNS(fbb);
|
||||
TableInFirstNS.addFooTable(fbb, nestedTableOff);
|
||||
int off = TableInFirstNS.endTableInFirstNS(fbb);
|
||||
}
|
||||
|
||||
|
||||
static void TestNestedFlatBuffer() {
|
||||
final String nestedMonsterName = "NestedMonsterName";
|
||||
final short nestedMonsterHp = 600;
|
||||
final short nestedMonsterMana = 1024;
|
||||
|
||||
|
||||
FlatBufferBuilder fbb1 = new FlatBufferBuilder(16);
|
||||
int str1 = fbb1.createString(nestedMonsterName);
|
||||
Monster.startMonster(fbb1);
|
||||
@@ -260,8 +288,8 @@ class JavaTest {
|
||||
Monster.finishMonsterBuffer(fbb1, monster1);
|
||||
byte[] fbb1Bytes = fbb1.sizedByteArray();
|
||||
fbb1 = null;
|
||||
|
||||
FlatBufferBuilder fbb2 = new FlatBufferBuilder(16);
|
||||
|
||||
FlatBufferBuilder fbb2 = new FlatBufferBuilder(16);
|
||||
int str2 = fbb2.createString("My Monster");
|
||||
int nestedBuffer = Monster.createTestnestedflatbufferVector(fbb2, fbb1Bytes);
|
||||
Monster.startMonster(fbb2);
|
||||
@@ -271,7 +299,7 @@ class JavaTest {
|
||||
Monster.addTestnestedflatbuffer(fbb2, nestedBuffer);
|
||||
int monster = Monster.endMonster(fbb2);
|
||||
Monster.finishMonsterBuffer(fbb2, monster);
|
||||
|
||||
|
||||
// Now test the data extracted from the nested buffer
|
||||
Monster mons = Monster.getRootAsMonster(fbb2.dataBuffer());
|
||||
Monster nestedMonster = mons.testnestedflatbufferAsMonster();
|
||||
@@ -281,6 +309,44 @@ class JavaTest {
|
||||
TestEq(nestedMonsterName, nestedMonster.name());
|
||||
}
|
||||
|
||||
static void TestCreateByteVector() {
|
||||
FlatBufferBuilder fbb = new FlatBufferBuilder(16);
|
||||
int str = fbb.createString("MyMonster");
|
||||
byte[] inventory = new byte[] { 0, 1, 2, 3, 4 };
|
||||
int vec = fbb.createByteVector(inventory);
|
||||
Monster.startMonster(fbb);
|
||||
Monster.addInventory(fbb, vec);
|
||||
Monster.addName(fbb, str);
|
||||
int monster1 = Monster.endMonster(fbb);
|
||||
Monster.finishMonsterBuffer(fbb, monster1);
|
||||
Monster monsterObject = Monster.getRootAsMonster(fbb.dataBuffer());
|
||||
|
||||
TestEq(monsterObject.inventory(1), (int)inventory[1]);
|
||||
TestEq(monsterObject.inventoryLength(), inventory.length);
|
||||
TestEq(ByteBuffer.wrap(inventory), monsterObject.inventoryAsByteBuffer());
|
||||
}
|
||||
|
||||
static void TestCreateUninitializedVector() {
|
||||
FlatBufferBuilder fbb = new FlatBufferBuilder(16);
|
||||
int str = fbb.createString("MyMonster");
|
||||
byte[] inventory = new byte[] { 0, 1, 2, 3, 4 };
|
||||
ByteBuffer bb = fbb.createUnintializedVector(1, inventory.length, 1);
|
||||
for (byte i:inventory) {
|
||||
bb.put(i);
|
||||
}
|
||||
int vec = fbb.endVector();
|
||||
Monster.startMonster(fbb);
|
||||
Monster.addInventory(fbb, vec);
|
||||
Monster.addName(fbb, str);
|
||||
int monster1 = Monster.endMonster(fbb);
|
||||
Monster.finishMonsterBuffer(fbb, monster1);
|
||||
Monster monsterObject = Monster.getRootAsMonster(fbb.dataBuffer());
|
||||
|
||||
TestEq(monsterObject.inventory(1), (int)inventory[1]);
|
||||
TestEq(monsterObject.inventoryLength(), inventory.length);
|
||||
TestEq(ByteBuffer.wrap(inventory), monsterObject.inventoryAsByteBuffer());
|
||||
}
|
||||
|
||||
static <T> void TestEq(T a, T b) {
|
||||
if (!a.equals(b)) {
|
||||
System.out.println("" + a.getClass().getName() + " " + b.getClass().getName());
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/bin/sh
|
||||
#!/bin/bash
|
||||
#
|
||||
# Copyright 2014 Google Inc. All rights reserved.
|
||||
#
|
||||
@@ -14,16 +14,30 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
set -o errexit
|
||||
|
||||
echo Compile then run the Java test.
|
||||
|
||||
testdir=$(readlink -fn `dirname $0`)
|
||||
thisdir=$(readlink -fn `pwd`)
|
||||
java -version
|
||||
|
||||
if [[ "$testdir" != "$thisdir" ]]; then
|
||||
echo error: must be run from inside the ${testdir} directory
|
||||
echo you ran it from ${thisdir}
|
||||
exit 1
|
||||
testdir="$(readlink -fn "$(dirname "$0")")"
|
||||
|
||||
targetdir="${testdir}/target"
|
||||
|
||||
if [[ -e "${targetdir}" ]]; then
|
||||
echo "cleaning target"
|
||||
rm -rf "${targetdir}"
|
||||
fi
|
||||
|
||||
javac -classpath ${testdir}/../java:${testdir}:${testdir}/namespace_test JavaTest.java
|
||||
java -classpath ${testdir}/../java:${testdir}:${testdir}/namespace_test JavaTest
|
||||
mkdir -v "${targetdir}"
|
||||
|
||||
if ! find "${testdir}/../java" -type f -name "*.class" -delete; then
|
||||
echo "failed to clean .class files from java directory" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
javac -d "${targetdir}" -classpath "${testdir}/../java:${testdir}:${testdir}/namespace_test" "${testdir}/JavaTest.java"
|
||||
|
||||
(cd "${testdir}" && java -classpath "${targetdir}" JavaTest )
|
||||
|
||||
rm -rf "${targetdir}"
|
||||
|
||||
32
tests/MyGame/Example/Ability.cs
Normal file
32
tests/MyGame/Example/Ability.cs
Normal file
@@ -0,0 +1,32 @@
|
||||
// <auto-generated>
|
||||
// automatically generated by the FlatBuffers compiler, do not modify
|
||||
// </auto-generated>
|
||||
|
||||
namespace MyGame.Example
|
||||
{
|
||||
|
||||
using global::System;
|
||||
using global::FlatBuffers;
|
||||
|
||||
public struct Ability : IFlatbufferObject
|
||||
{
|
||||
private Struct __p;
|
||||
public ByteBuffer ByteBuffer { get { return __p.bb; } }
|
||||
public void __init(int _i, ByteBuffer _bb) { __p.bb_pos = _i; __p.bb = _bb; }
|
||||
public Ability __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; }
|
||||
|
||||
public uint Id { get { return __p.bb.GetUint(__p.bb_pos + 0); } }
|
||||
public void MutateId(uint id) { __p.bb.PutUint(__p.bb_pos + 0, id); }
|
||||
public uint Distance { get { return __p.bb.GetUint(__p.bb_pos + 4); } }
|
||||
public void MutateDistance(uint distance) { __p.bb.PutUint(__p.bb_pos + 4, distance); }
|
||||
|
||||
public static Offset<Ability> CreateAbility(FlatBufferBuilder builder, uint Id, uint Distance) {
|
||||
builder.Prep(4, 8);
|
||||
builder.PutUint(Distance);
|
||||
builder.PutUint(Id);
|
||||
return new Offset<Ability>(builder.Offset);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
41
tests/MyGame/Example/Ability.go
Normal file
41
tests/MyGame/Example/Ability.go
Normal file
@@ -0,0 +1,41 @@
|
||||
// automatically generated by the FlatBuffers compiler, do not modify
|
||||
|
||||
package Example
|
||||
|
||||
import (
|
||||
flatbuffers "github.com/google/flatbuffers/go"
|
||||
)
|
||||
|
||||
type Ability struct {
|
||||
_tab flatbuffers.Struct
|
||||
}
|
||||
|
||||
func (rcv *Ability) Init(buf []byte, i flatbuffers.UOffsetT) {
|
||||
rcv._tab.Bytes = buf
|
||||
rcv._tab.Pos = i
|
||||
}
|
||||
|
||||
func (rcv *Ability) Table() flatbuffers.Table {
|
||||
return rcv._tab.Table
|
||||
}
|
||||
|
||||
func (rcv *Ability) Id() uint32 {
|
||||
return rcv._tab.GetUint32(rcv._tab.Pos + flatbuffers.UOffsetT(0))
|
||||
}
|
||||
func (rcv *Ability) MutateId(n uint32) bool {
|
||||
return rcv._tab.MutateUint32(rcv._tab.Pos+flatbuffers.UOffsetT(0), n)
|
||||
}
|
||||
|
||||
func (rcv *Ability) Distance() uint32 {
|
||||
return rcv._tab.GetUint32(rcv._tab.Pos + flatbuffers.UOffsetT(4))
|
||||
}
|
||||
func (rcv *Ability) MutateDistance(n uint32) bool {
|
||||
return rcv._tab.MutateUint32(rcv._tab.Pos+flatbuffers.UOffsetT(4), n)
|
||||
}
|
||||
|
||||
func CreateAbility(builder *flatbuffers.Builder, id uint32, distance uint32) flatbuffers.UOffsetT {
|
||||
builder.Prep(4, 8)
|
||||
builder.PrependUint32(distance)
|
||||
builder.PrependUint32(id)
|
||||
return builder.Offset()
|
||||
}
|
||||
27
tests/MyGame/Example/Ability.java
Normal file
27
tests/MyGame/Example/Ability.java
Normal file
@@ -0,0 +1,27 @@
|
||||
// automatically generated by the FlatBuffers compiler, do not modify
|
||||
|
||||
package MyGame.Example;
|
||||
|
||||
import java.nio.*;
|
||||
import java.lang.*;
|
||||
import java.util.*;
|
||||
import com.google.flatbuffers.*;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public final class Ability extends Struct {
|
||||
public void __init(int _i, ByteBuffer _bb) { bb_pos = _i; bb = _bb; }
|
||||
public Ability __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; }
|
||||
|
||||
public long id() { return (long)bb.getInt(bb_pos + 0) & 0xFFFFFFFFL; }
|
||||
public void mutateId(long id) { bb.putInt(bb_pos + 0, (int)id); }
|
||||
public long distance() { return (long)bb.getInt(bb_pos + 4) & 0xFFFFFFFFL; }
|
||||
public void mutateDistance(long distance) { bb.putInt(bb_pos + 4, (int)distance); }
|
||||
|
||||
public static int createAbility(FlatBufferBuilder builder, long id, long distance) {
|
||||
builder.prep(4, 8);
|
||||
builder.putInt((int)distance);
|
||||
builder.putInt((int)id);
|
||||
return builder.offset();
|
||||
}
|
||||
}
|
||||
|
||||
52
tests/MyGame/Example/Ability.php
Normal file
52
tests/MyGame/Example/Ability.php
Normal file
@@ -0,0 +1,52 @@
|
||||
<?php
|
||||
// automatically generated by the FlatBuffers compiler, do not modify
|
||||
|
||||
namespace MyGame\Example;
|
||||
|
||||
use \Google\FlatBuffers\Struct;
|
||||
use \Google\FlatBuffers\Table;
|
||||
use \Google\FlatBuffers\ByteBuffer;
|
||||
use \Google\FlatBuffers\FlatBufferBuilder;
|
||||
|
||||
class Ability extends Struct
|
||||
{
|
||||
/**
|
||||
* @param int $_i offset
|
||||
* @param ByteBuffer $_bb
|
||||
* @return Ability
|
||||
**/
|
||||
public function init($_i, ByteBuffer $_bb)
|
||||
{
|
||||
$this->bb_pos = $_i;
|
||||
$this->bb = $_bb;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return uint
|
||||
*/
|
||||
public function GetId()
|
||||
{
|
||||
return $this->bb->getUint($this->bb_pos + 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return uint
|
||||
*/
|
||||
public function GetDistance()
|
||||
{
|
||||
return $this->bb->getUint($this->bb_pos + 4);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return int offset
|
||||
*/
|
||||
public static function createAbility(FlatBufferBuilder $builder, $id, $distance)
|
||||
{
|
||||
$builder->prep(4, 8);
|
||||
$builder->putUint($distance);
|
||||
$builder->putUint($id);
|
||||
return $builder->offset();
|
||||
}
|
||||
}
|
||||
23
tests/MyGame/Example/Ability.py
Normal file
23
tests/MyGame/Example/Ability.py
Normal file
@@ -0,0 +1,23 @@
|
||||
# automatically generated by the FlatBuffers compiler, do not modify
|
||||
|
||||
# namespace: Example
|
||||
|
||||
import flatbuffers
|
||||
|
||||
class Ability(object):
|
||||
__slots__ = ['_tab']
|
||||
|
||||
# Ability
|
||||
def Init(self, buf, pos):
|
||||
self._tab = flatbuffers.table.Table(buf, pos)
|
||||
|
||||
# Ability
|
||||
def Id(self): return self._tab.Get(flatbuffers.number_types.Uint32Flags, self._tab.Pos + flatbuffers.number_types.UOffsetTFlags.py_type(0))
|
||||
# Ability
|
||||
def Distance(self): return self._tab.Get(flatbuffers.number_types.Uint32Flags, self._tab.Pos + flatbuffers.number_types.UOffsetTFlags.py_type(4))
|
||||
|
||||
def CreateAbility(builder, id, distance):
|
||||
builder.Prep(4, 8)
|
||||
builder.PrependUint32(distance)
|
||||
builder.PrependUint32(id)
|
||||
return builder.Offset()
|
||||
@@ -1,4 +1,6 @@
|
||||
// automatically generated by the FlatBuffers compiler, do not modify
|
||||
// <auto-generated>
|
||||
// automatically generated by the FlatBuffers compiler, do not modify
|
||||
// </auto-generated>
|
||||
|
||||
namespace MyGame.Example
|
||||
{
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
// automatically generated by the FlatBuffers compiler, do not modify
|
||||
// <auto-generated>
|
||||
// automatically generated by the FlatBuffers compiler, do not modify
|
||||
// </auto-generated>
|
||||
|
||||
namespace MyGame.Example
|
||||
{
|
||||
|
||||
@@ -1,87 +1,94 @@
|
||||
// automatically generated by the FlatBuffers compiler, do not modify
|
||||
// <auto-generated>
|
||||
// automatically generated by the FlatBuffers compiler, do not modify
|
||||
// </auto-generated>
|
||||
|
||||
namespace MyGame.Example
|
||||
{
|
||||
|
||||
using System;
|
||||
using FlatBuffers;
|
||||
using global::System;
|
||||
using global::FlatBuffers;
|
||||
|
||||
/// an example documentation comment: monster object
|
||||
public sealed class Monster : Table {
|
||||
public struct Monster : IFlatbufferObject
|
||||
{
|
||||
private Table __p;
|
||||
public ByteBuffer ByteBuffer { get { return __p.bb; } }
|
||||
public static Monster GetRootAsMonster(ByteBuffer _bb) { return GetRootAsMonster(_bb, new Monster()); }
|
||||
public static Monster GetRootAsMonster(ByteBuffer _bb, Monster obj) { return (obj.__init(_bb.GetInt(_bb.Position) + _bb.Position, _bb)); }
|
||||
public static bool MonsterBufferHasIdentifier(ByteBuffer _bb) { return __has_identifier(_bb, "MONS"); }
|
||||
public Monster __init(int _i, ByteBuffer _bb) { bb_pos = _i; bb = _bb; return this; }
|
||||
public static Monster GetRootAsMonster(ByteBuffer _bb, Monster obj) { return (obj.__assign(_bb.GetInt(_bb.Position) + _bb.Position, _bb)); }
|
||||
public static bool MonsterBufferHasIdentifier(ByteBuffer _bb) { return Table.__has_identifier(_bb, "MONS"); }
|
||||
public void __init(int _i, ByteBuffer _bb) { __p.bb_pos = _i; __p.bb = _bb; }
|
||||
public Monster __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; }
|
||||
|
||||
public Vec3 Pos { get { return GetPos(new Vec3()); } }
|
||||
public Vec3 GetPos(Vec3 obj) { int o = __offset(4); return o != 0 ? obj.__init(o + bb_pos, bb) : null; }
|
||||
public short Mana { get { int o = __offset(6); return o != 0 ? bb.GetShort(o + bb_pos) : (short)150; } }
|
||||
public bool MutateMana(short mana) { int o = __offset(6); if (o != 0) { bb.PutShort(o + bb_pos, mana); return true; } else { return false; } }
|
||||
public short Hp { get { int o = __offset(8); return o != 0 ? bb.GetShort(o + bb_pos) : (short)100; } }
|
||||
public bool MutateHp(short hp) { int o = __offset(8); if (o != 0) { bb.PutShort(o + bb_pos, hp); return true; } else { return false; } }
|
||||
public string Name { get { int o = __offset(10); return o != 0 ? __string(o + bb_pos) : null; } }
|
||||
public ArraySegment<byte>? GetNameBytes() { return __vector_as_arraysegment(10); }
|
||||
public byte GetInventory(int j) { int o = __offset(14); return o != 0 ? bb.Get(__vector(o) + j * 1) : (byte)0; }
|
||||
public int InventoryLength { get { int o = __offset(14); return o != 0 ? __vector_len(o) : 0; } }
|
||||
public ArraySegment<byte>? GetInventoryBytes() { return __vector_as_arraysegment(14); }
|
||||
public bool MutateInventory(int j, byte inventory) { int o = __offset(14); if (o != 0) { bb.Put(__vector(o) + j * 1, inventory); return true; } else { return false; } }
|
||||
public Color Color { get { int o = __offset(16); return o != 0 ? (Color)bb.GetSbyte(o + bb_pos) : Color.Blue; } }
|
||||
public bool MutateColor(Color color) { int o = __offset(16); if (o != 0) { bb.PutSbyte(o + bb_pos, (sbyte)color); return true; } else { return false; } }
|
||||
public Any TestType { get { int o = __offset(18); return o != 0 ? (Any)bb.Get(o + bb_pos) : Any.NONE; } }
|
||||
public bool MutateTestType(Any test_type) { int o = __offset(18); if (o != 0) { bb.Put(o + bb_pos, (byte)test_type); return true; } else { return false; } }
|
||||
public TTable GetTest<TTable>(TTable obj) where TTable : Table { int o = __offset(20); return o != 0 ? __union(obj, o) : null; }
|
||||
public Test GetTest4(int j) { return GetTest4(new Test(), j); }
|
||||
public Test GetTest4(Test obj, int j) { int o = __offset(22); return o != 0 ? obj.__init(__vector(o) + j * 4, bb) : null; }
|
||||
public int Test4Length { get { int o = __offset(22); return o != 0 ? __vector_len(o) : 0; } }
|
||||
public string GetTestarrayofstring(int j) { int o = __offset(24); return o != 0 ? __string(__vector(o) + j * 4) : null; }
|
||||
public int TestarrayofstringLength { get { int o = __offset(24); return o != 0 ? __vector_len(o) : 0; } }
|
||||
public Vec3? Pos { get { int o = __p.__offset(4); return o != 0 ? (Vec3?)(new Vec3()).__assign(o + __p.bb_pos, __p.bb) : null; } }
|
||||
public short Mana { get { int o = __p.__offset(6); return o != 0 ? __p.bb.GetShort(o + __p.bb_pos) : (short)150; } }
|
||||
public bool MutateMana(short mana) { int o = __p.__offset(6); if (o != 0) { __p.bb.PutShort(o + __p.bb_pos, mana); return true; } else { return false; } }
|
||||
public short Hp { get { int o = __p.__offset(8); return o != 0 ? __p.bb.GetShort(o + __p.bb_pos) : (short)100; } }
|
||||
public bool MutateHp(short hp) { int o = __p.__offset(8); if (o != 0) { __p.bb.PutShort(o + __p.bb_pos, hp); return true; } else { return false; } }
|
||||
public string Name { get { int o = __p.__offset(10); return o != 0 ? __p.__string(o + __p.bb_pos) : null; } }
|
||||
public ArraySegment<byte>? GetNameBytes() { return __p.__vector_as_arraysegment(10); }
|
||||
public byte Inventory(int j) { int o = __p.__offset(14); return o != 0 ? __p.bb.Get(__p.__vector(o) + j * 1) : (byte)0; }
|
||||
public int InventoryLength { get { int o = __p.__offset(14); return o != 0 ? __p.__vector_len(o) : 0; } }
|
||||
public ArraySegment<byte>? GetInventoryBytes() { return __p.__vector_as_arraysegment(14); }
|
||||
public bool MutateInventory(int j, byte inventory) { int o = __p.__offset(14); if (o != 0) { __p.bb.Put(__p.__vector(o) + j * 1, inventory); return true; } else { return false; } }
|
||||
public Color Color { get { int o = __p.__offset(16); return o != 0 ? (Color)__p.bb.GetSbyte(o + __p.bb_pos) : Color.Blue; } }
|
||||
public bool MutateColor(Color color) { int o = __p.__offset(16); if (o != 0) { __p.bb.PutSbyte(o + __p.bb_pos, (sbyte)color); return true; } else { return false; } }
|
||||
public Any TestType { get { int o = __p.__offset(18); return o != 0 ? (Any)__p.bb.Get(o + __p.bb_pos) : Any.NONE; } }
|
||||
public bool MutateTestType(Any test_type) { int o = __p.__offset(18); if (o != 0) { __p.bb.Put(o + __p.bb_pos, (byte)test_type); return true; } else { return false; } }
|
||||
public TTable? Test<TTable>() where TTable : struct, IFlatbufferObject { int o = __p.__offset(20); return o != 0 ? (TTable?)__p.__union<TTable>(o) : null; }
|
||||
public Test? Test4(int j) { int o = __p.__offset(22); return o != 0 ? (Test?)(new Test()).__assign(__p.__vector(o) + j * 4, __p.bb) : null; }
|
||||
public int Test4Length { get { int o = __p.__offset(22); return o != 0 ? __p.__vector_len(o) : 0; } }
|
||||
public string Testarrayofstring(int j) { int o = __p.__offset(24); return o != 0 ? __p.__string(__p.__vector(o) + j * 4) : null; }
|
||||
public int TestarrayofstringLength { get { int o = __p.__offset(24); return o != 0 ? __p.__vector_len(o) : 0; } }
|
||||
/// an example documentation comment: this will end up in the generated code
|
||||
/// multiline too
|
||||
public Monster GetTestarrayoftables(int j) { return GetTestarrayoftables(new Monster(), j); }
|
||||
public Monster GetTestarrayoftables(Monster obj, int j) { int o = __offset(26); return o != 0 ? obj.__init(__indirect(__vector(o) + j * 4), bb) : null; }
|
||||
public int TestarrayoftablesLength { get { int o = __offset(26); return o != 0 ? __vector_len(o) : 0; } }
|
||||
public Monster Enemy { get { return GetEnemy(new Monster()); } }
|
||||
public Monster GetEnemy(Monster obj) { int o = __offset(28); return o != 0 ? obj.__init(__indirect(o + bb_pos), bb) : null; }
|
||||
public byte GetTestnestedflatbuffer(int j) { int o = __offset(30); return o != 0 ? bb.Get(__vector(o) + j * 1) : (byte)0; }
|
||||
public int TestnestedflatbufferLength { get { int o = __offset(30); return o != 0 ? __vector_len(o) : 0; } }
|
||||
public ArraySegment<byte>? GetTestnestedflatbufferBytes() { return __vector_as_arraysegment(30); }
|
||||
public Monster TestnestedflatbufferAsMonster() { return GetTestnestedflatbufferAsMonster(new Monster()); }
|
||||
public Monster GetTestnestedflatbufferAsMonster(Monster obj) { int o = __offset(30); return o != 0 ? obj.__init(__indirect(__vector(o)), bb) : null; }
|
||||
public bool MutateTestnestedflatbuffer(int j, byte testnestedflatbuffer) { int o = __offset(30); if (o != 0) { bb.Put(__vector(o) + j * 1, testnestedflatbuffer); return true; } else { return false; } }
|
||||
public Stat Testempty { get { return GetTestempty(new Stat()); } }
|
||||
public Stat GetTestempty(Stat obj) { int o = __offset(32); return o != 0 ? obj.__init(__indirect(o + bb_pos), bb) : null; }
|
||||
public bool Testbool { get { int o = __offset(34); return o != 0 ? 0!=bb.Get(o + bb_pos) : (bool)false; } }
|
||||
public bool MutateTestbool(bool testbool) { int o = __offset(34); if (o != 0) { bb.Put(o + bb_pos, (byte)(testbool ? 1 : 0)); return true; } else { return false; } }
|
||||
public int Testhashs32Fnv1 { get { int o = __offset(36); return o != 0 ? bb.GetInt(o + bb_pos) : (int)0; } }
|
||||
public bool MutateTesthashs32Fnv1(int testhashs32_fnv1) { int o = __offset(36); if (o != 0) { bb.PutInt(o + bb_pos, testhashs32_fnv1); return true; } else { return false; } }
|
||||
public uint Testhashu32Fnv1 { get { int o = __offset(38); return o != 0 ? bb.GetUint(o + bb_pos) : (uint)0; } }
|
||||
public bool MutateTesthashu32Fnv1(uint testhashu32_fnv1) { int o = __offset(38); if (o != 0) { bb.PutUint(o + bb_pos, testhashu32_fnv1); return true; } else { return false; } }
|
||||
public long Testhashs64Fnv1 { get { int o = __offset(40); return o != 0 ? bb.GetLong(o + bb_pos) : (long)0; } }
|
||||
public bool MutateTesthashs64Fnv1(long testhashs64_fnv1) { int o = __offset(40); if (o != 0) { bb.PutLong(o + bb_pos, testhashs64_fnv1); return true; } else { return false; } }
|
||||
public ulong Testhashu64Fnv1 { get { int o = __offset(42); return o != 0 ? bb.GetUlong(o + bb_pos) : (ulong)0; } }
|
||||
public bool MutateTesthashu64Fnv1(ulong testhashu64_fnv1) { int o = __offset(42); if (o != 0) { bb.PutUlong(o + bb_pos, testhashu64_fnv1); return true; } else { return false; } }
|
||||
public int Testhashs32Fnv1a { get { int o = __offset(44); return o != 0 ? bb.GetInt(o + bb_pos) : (int)0; } }
|
||||
public bool MutateTesthashs32Fnv1a(int testhashs32_fnv1a) { int o = __offset(44); if (o != 0) { bb.PutInt(o + bb_pos, testhashs32_fnv1a); return true; } else { return false; } }
|
||||
public uint Testhashu32Fnv1a { get { int o = __offset(46); return o != 0 ? bb.GetUint(o + bb_pos) : (uint)0; } }
|
||||
public bool MutateTesthashu32Fnv1a(uint testhashu32_fnv1a) { int o = __offset(46); if (o != 0) { bb.PutUint(o + bb_pos, testhashu32_fnv1a); return true; } else { return false; } }
|
||||
public long Testhashs64Fnv1a { get { int o = __offset(48); return o != 0 ? bb.GetLong(o + bb_pos) : (long)0; } }
|
||||
public bool MutateTesthashs64Fnv1a(long testhashs64_fnv1a) { int o = __offset(48); if (o != 0) { bb.PutLong(o + bb_pos, testhashs64_fnv1a); return true; } else { return false; } }
|
||||
public ulong Testhashu64Fnv1a { get { int o = __offset(50); return o != 0 ? bb.GetUlong(o + bb_pos) : (ulong)0; } }
|
||||
public bool MutateTesthashu64Fnv1a(ulong testhashu64_fnv1a) { int o = __offset(50); if (o != 0) { bb.PutUlong(o + bb_pos, testhashu64_fnv1a); return true; } else { return false; } }
|
||||
public bool GetTestarrayofbools(int j) { int o = __offset(52); return o != 0 ? 0!=bb.Get(__vector(o) + j * 1) : false; }
|
||||
public int TestarrayofboolsLength { get { int o = __offset(52); return o != 0 ? __vector_len(o) : 0; } }
|
||||
public ArraySegment<byte>? GetTestarrayofboolsBytes() { return __vector_as_arraysegment(52); }
|
||||
public bool MutateTestarrayofbools(int j, bool testarrayofbools) { int o = __offset(52); if (o != 0) { bb.Put(__vector(o) + j * 1, (byte)(testarrayofbools ? 1 : 0)); return true; } else { return false; } }
|
||||
public float Testf { get { int o = __offset(54); return o != 0 ? bb.GetFloat(o + bb_pos) : (float)3.14159f; } }
|
||||
public bool MutateTestf(float testf) { int o = __offset(54); if (o != 0) { bb.PutFloat(o + bb_pos, testf); return true; } else { return false; } }
|
||||
public float Testf2 { get { int o = __offset(56); return o != 0 ? bb.GetFloat(o + bb_pos) : (float)3.0f; } }
|
||||
public bool MutateTestf2(float testf2) { int o = __offset(56); if (o != 0) { bb.PutFloat(o + bb_pos, testf2); return true; } else { return false; } }
|
||||
public float Testf3 { get { int o = __offset(58); return o != 0 ? bb.GetFloat(o + bb_pos) : (float)0.0f; } }
|
||||
public bool MutateTestf3(float testf3) { int o = __offset(58); if (o != 0) { bb.PutFloat(o + bb_pos, testf3); return true; } else { return false; } }
|
||||
public string GetTestarrayofstring2(int j) { int o = __offset(60); return o != 0 ? __string(__vector(o) + j * 4) : null; }
|
||||
public int Testarrayofstring2Length { get { int o = __offset(60); return o != 0 ? __vector_len(o) : 0; } }
|
||||
public Monster? Testarrayoftables(int j) { int o = __p.__offset(26); return o != 0 ? (Monster?)(new Monster()).__assign(__p.__indirect(__p.__vector(o) + j * 4), __p.bb) : null; }
|
||||
public int TestarrayoftablesLength { get { int o = __p.__offset(26); return o != 0 ? __p.__vector_len(o) : 0; } }
|
||||
public Monster? TestarrayoftablesByKey(string key) { int o = __p.__offset(26); return o != 0 ? Monster.__lookup_by_key(__p.__vector(o), key, __p.bb) : null; }
|
||||
public Monster? Enemy { get { int o = __p.__offset(28); return o != 0 ? (Monster?)(new Monster()).__assign(__p.__indirect(o + __p.bb_pos), __p.bb) : null; } }
|
||||
public byte Testnestedflatbuffer(int j) { int o = __p.__offset(30); return o != 0 ? __p.bb.Get(__p.__vector(o) + j * 1) : (byte)0; }
|
||||
public int TestnestedflatbufferLength { get { int o = __p.__offset(30); return o != 0 ? __p.__vector_len(o) : 0; } }
|
||||
public ArraySegment<byte>? GetTestnestedflatbufferBytes() { return __p.__vector_as_arraysegment(30); }
|
||||
public Monster? GetTestnestedflatbufferAsMonster() { int o = __p.__offset(30); return o != 0 ? (Monster?)(new Monster()).__assign(__p.__indirect(__p.__vector(o)), __p.bb) : null; }
|
||||
public bool MutateTestnestedflatbuffer(int j, byte testnestedflatbuffer) { int o = __p.__offset(30); if (o != 0) { __p.bb.Put(__p.__vector(o) + j * 1, testnestedflatbuffer); return true; } else { return false; } }
|
||||
public Stat? Testempty { get { int o = __p.__offset(32); return o != 0 ? (Stat?)(new Stat()).__assign(__p.__indirect(o + __p.bb_pos), __p.bb) : null; } }
|
||||
public bool Testbool { get { int o = __p.__offset(34); return o != 0 ? 0!=__p.bb.Get(o + __p.bb_pos) : (bool)false; } }
|
||||
public bool MutateTestbool(bool testbool) { int o = __p.__offset(34); if (o != 0) { __p.bb.Put(o + __p.bb_pos, (byte)(testbool ? 1 : 0)); return true; } else { return false; } }
|
||||
public int Testhashs32Fnv1 { get { int o = __p.__offset(36); return o != 0 ? __p.bb.GetInt(o + __p.bb_pos) : (int)0; } }
|
||||
public bool MutateTesthashs32Fnv1(int testhashs32_fnv1) { int o = __p.__offset(36); if (o != 0) { __p.bb.PutInt(o + __p.bb_pos, testhashs32_fnv1); return true; } else { return false; } }
|
||||
public uint Testhashu32Fnv1 { get { int o = __p.__offset(38); return o != 0 ? __p.bb.GetUint(o + __p.bb_pos) : (uint)0; } }
|
||||
public bool MutateTesthashu32Fnv1(uint testhashu32_fnv1) { int o = __p.__offset(38); if (o != 0) { __p.bb.PutUint(o + __p.bb_pos, testhashu32_fnv1); return true; } else { return false; } }
|
||||
public long Testhashs64Fnv1 { get { int o = __p.__offset(40); return o != 0 ? __p.bb.GetLong(o + __p.bb_pos) : (long)0; } }
|
||||
public bool MutateTesthashs64Fnv1(long testhashs64_fnv1) { int o = __p.__offset(40); if (o != 0) { __p.bb.PutLong(o + __p.bb_pos, testhashs64_fnv1); return true; } else { return false; } }
|
||||
public ulong Testhashu64Fnv1 { get { int o = __p.__offset(42); return o != 0 ? __p.bb.GetUlong(o + __p.bb_pos) : (ulong)0; } }
|
||||
public bool MutateTesthashu64Fnv1(ulong testhashu64_fnv1) { int o = __p.__offset(42); if (o != 0) { __p.bb.PutUlong(o + __p.bb_pos, testhashu64_fnv1); return true; } else { return false; } }
|
||||
public int Testhashs32Fnv1a { get { int o = __p.__offset(44); return o != 0 ? __p.bb.GetInt(o + __p.bb_pos) : (int)0; } }
|
||||
public bool MutateTesthashs32Fnv1a(int testhashs32_fnv1a) { int o = __p.__offset(44); if (o != 0) { __p.bb.PutInt(o + __p.bb_pos, testhashs32_fnv1a); return true; } else { return false; } }
|
||||
public uint Testhashu32Fnv1a { get { int o = __p.__offset(46); return o != 0 ? __p.bb.GetUint(o + __p.bb_pos) : (uint)0; } }
|
||||
public bool MutateTesthashu32Fnv1a(uint testhashu32_fnv1a) { int o = __p.__offset(46); if (o != 0) { __p.bb.PutUint(o + __p.bb_pos, testhashu32_fnv1a); return true; } else { return false; } }
|
||||
public long Testhashs64Fnv1a { get { int o = __p.__offset(48); return o != 0 ? __p.bb.GetLong(o + __p.bb_pos) : (long)0; } }
|
||||
public bool MutateTesthashs64Fnv1a(long testhashs64_fnv1a) { int o = __p.__offset(48); if (o != 0) { __p.bb.PutLong(o + __p.bb_pos, testhashs64_fnv1a); return true; } else { return false; } }
|
||||
public ulong Testhashu64Fnv1a { get { int o = __p.__offset(50); return o != 0 ? __p.bb.GetUlong(o + __p.bb_pos) : (ulong)0; } }
|
||||
public bool MutateTesthashu64Fnv1a(ulong testhashu64_fnv1a) { int o = __p.__offset(50); if (o != 0) { __p.bb.PutUlong(o + __p.bb_pos, testhashu64_fnv1a); return true; } else { return false; } }
|
||||
public bool Testarrayofbools(int j) { int o = __p.__offset(52); return o != 0 ? 0!=__p.bb.Get(__p.__vector(o) + j * 1) : false; }
|
||||
public int TestarrayofboolsLength { get { int o = __p.__offset(52); return o != 0 ? __p.__vector_len(o) : 0; } }
|
||||
public ArraySegment<byte>? GetTestarrayofboolsBytes() { return __p.__vector_as_arraysegment(52); }
|
||||
public bool MutateTestarrayofbools(int j, bool testarrayofbools) { int o = __p.__offset(52); if (o != 0) { __p.bb.Put(__p.__vector(o) + j * 1, (byte)(testarrayofbools ? 1 : 0)); return true; } else { return false; } }
|
||||
public float Testf { get { int o = __p.__offset(54); return o != 0 ? __p.bb.GetFloat(o + __p.bb_pos) : (float)3.14159f; } }
|
||||
public bool MutateTestf(float testf) { int o = __p.__offset(54); if (o != 0) { __p.bb.PutFloat(o + __p.bb_pos, testf); return true; } else { return false; } }
|
||||
public float Testf2 { get { int o = __p.__offset(56); return o != 0 ? __p.bb.GetFloat(o + __p.bb_pos) : (float)3.0f; } }
|
||||
public bool MutateTestf2(float testf2) { int o = __p.__offset(56); if (o != 0) { __p.bb.PutFloat(o + __p.bb_pos, testf2); return true; } else { return false; } }
|
||||
public float Testf3 { get { int o = __p.__offset(58); return o != 0 ? __p.bb.GetFloat(o + __p.bb_pos) : (float)0.0f; } }
|
||||
public bool MutateTestf3(float testf3) { int o = __p.__offset(58); if (o != 0) { __p.bb.PutFloat(o + __p.bb_pos, testf3); return true; } else { return false; } }
|
||||
public string Testarrayofstring2(int j) { int o = __p.__offset(60); return o != 0 ? __p.__string(__p.__vector(o) + j * 4) : null; }
|
||||
public int Testarrayofstring2Length { get { int o = __p.__offset(60); return o != 0 ? __p.__vector_len(o) : 0; } }
|
||||
public Ability? Testarrayofsortedstruct(int j) { int o = __p.__offset(62); return o != 0 ? (Ability?)(new Ability()).__assign(__p.__vector(o) + j * 8, __p.bb) : null; }
|
||||
public int TestarrayofsortedstructLength { get { int o = __p.__offset(62); return o != 0 ? __p.__vector_len(o) : 0; } }
|
||||
public byte Flex(int j) { int o = __p.__offset(64); return o != 0 ? __p.bb.Get(__p.__vector(o) + j * 1) : (byte)0; }
|
||||
public int FlexLength { get { int o = __p.__offset(64); return o != 0 ? __p.__vector_len(o) : 0; } }
|
||||
public ArraySegment<byte>? GetFlexBytes() { return __p.__vector_as_arraysegment(64); }
|
||||
public bool MutateFlex(int j, byte flex) { int o = __p.__offset(64); if (o != 0) { __p.bb.Put(__p.__vector(o) + j * 1, flex); return true; } else { return false; } }
|
||||
|
||||
public static void StartMonster(FlatBufferBuilder builder) { builder.StartObject(29); }
|
||||
public static void StartMonster(FlatBufferBuilder builder) { builder.StartObject(31); }
|
||||
public static void AddPos(FlatBufferBuilder builder, Offset<Vec3> posOffset) { builder.AddStruct(0, posOffset.Value, 0); }
|
||||
public static void AddMana(FlatBufferBuilder builder, short mana) { builder.AddShort(1, mana, 150); }
|
||||
public static void AddHp(FlatBufferBuilder builder, short hp) { builder.AddShort(2, hp, 100); }
|
||||
@@ -123,12 +130,43 @@ public sealed class Monster : Table {
|
||||
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 void AddTestarrayofsortedstruct(FlatBufferBuilder builder, VectorOffset testarrayofsortedstructOffset) { builder.AddOffset(29, testarrayofsortedstructOffset.Value, 0); }
|
||||
public static void StartTestarrayofsortedstructVector(FlatBufferBuilder builder, int numElems) { builder.StartVector(8, numElems, 4); }
|
||||
public static void AddFlex(FlatBufferBuilder builder, VectorOffset flexOffset) { builder.AddOffset(30, flexOffset.Value, 0); }
|
||||
public static VectorOffset CreateFlexVector(FlatBufferBuilder builder, byte[] data) { builder.StartVector(1, data.Length, 1); for (int i = data.Length - 1; i >= 0; i--) builder.AddByte(data[i]); return builder.EndVector(); }
|
||||
public static void StartFlexVector(FlatBufferBuilder builder, int numElems) { builder.StartVector(1, numElems, 1); }
|
||||
public static Offset<Monster> EndMonster(FlatBufferBuilder builder) {
|
||||
int o = builder.EndObject();
|
||||
builder.Required(o, 10); // name
|
||||
return new Offset<Monster>(o);
|
||||
}
|
||||
public static void FinishMonsterBuffer(FlatBufferBuilder builder, Offset<Monster> offset) { builder.Finish(offset.Value, "MONS"); }
|
||||
|
||||
public static VectorOffset CreateSortedVectorOfMonster(FlatBufferBuilder builder, Offset<Monster>[] offsets) {
|
||||
Array.Sort(offsets, (Offset<Monster> o1, Offset<Monster> o2) => Table.CompareStrings(Table.__offset(10, o1.Value, builder.DataBuffer), Table.__offset(10, o2.Value, builder.DataBuffer), builder.DataBuffer));
|
||||
return builder.CreateVectorOfTables(offsets);
|
||||
}
|
||||
|
||||
public static Monster? __lookup_by_key(int vectorLocation, string key, ByteBuffer bb) {
|
||||
byte[] byteKey = System.Text.Encoding.UTF8.GetBytes(key);
|
||||
int span = bb.GetInt(vectorLocation - 4);
|
||||
int start = 0;
|
||||
while (span != 0) {
|
||||
int middle = span / 2;
|
||||
int tableOffset = Table.__indirect(vectorLocation + 4 * (start + middle), bb);
|
||||
int comp = Table.CompareStrings(Table.__offset(10, bb.Length - tableOffset, bb), byteKey, bb);
|
||||
if (comp > 0) {
|
||||
span = middle;
|
||||
} else if (comp < 0) {
|
||||
middle++;
|
||||
start += middle;
|
||||
span -= middle;
|
||||
} else {
|
||||
return new Monster().__assign(tableOffset, bb);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -23,6 +23,10 @@ func (rcv *Monster) Init(buf []byte, i flatbuffers.UOffsetT) {
|
||||
rcv._tab.Pos = i
|
||||
}
|
||||
|
||||
func (rcv *Monster) Table() flatbuffers.Table {
|
||||
return rcv._tab
|
||||
}
|
||||
|
||||
func (rcv *Monster) Pos(obj *Vec3) *Vec3 {
|
||||
o := flatbuffers.UOffsetT(rcv._tab.Offset(4))
|
||||
if o != 0 {
|
||||
@@ -131,9 +135,6 @@ func (rcv *Monster) Test4(obj *Test, j int) bool {
|
||||
if o != 0 {
|
||||
x := rcv._tab.Vector(o)
|
||||
x += flatbuffers.UOffsetT(j) * 4
|
||||
if obj == nil {
|
||||
obj = new(Test)
|
||||
}
|
||||
obj.Init(rcv._tab.Bytes, x)
|
||||
return true
|
||||
}
|
||||
@@ -173,9 +174,6 @@ func (rcv *Monster) Testarrayoftables(obj *Monster, j int) bool {
|
||||
x := rcv._tab.Vector(o)
|
||||
x += flatbuffers.UOffsetT(j) * 4
|
||||
x = rcv._tab.Indirect(x)
|
||||
if obj == nil {
|
||||
obj = new(Monster)
|
||||
}
|
||||
obj.Init(rcv._tab.Bytes, x)
|
||||
return true
|
||||
}
|
||||
@@ -421,8 +419,52 @@ func (rcv *Monster) Testarrayofstring2Length() int {
|
||||
return 0
|
||||
}
|
||||
|
||||
func (rcv *Monster) Testarrayofsortedstruct(obj *Ability, j int) bool {
|
||||
o := flatbuffers.UOffsetT(rcv._tab.Offset(62))
|
||||
if o != 0 {
|
||||
x := rcv._tab.Vector(o)
|
||||
x += flatbuffers.UOffsetT(j) * 8
|
||||
obj.Init(rcv._tab.Bytes, x)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (rcv *Monster) TestarrayofsortedstructLength() int {
|
||||
o := flatbuffers.UOffsetT(rcv._tab.Offset(62))
|
||||
if o != 0 {
|
||||
return rcv._tab.VectorLen(o)
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (rcv *Monster) Flex(j int) byte {
|
||||
o := flatbuffers.UOffsetT(rcv._tab.Offset(64))
|
||||
if o != 0 {
|
||||
a := rcv._tab.Vector(o)
|
||||
return rcv._tab.GetByte(a + flatbuffers.UOffsetT(j*1))
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (rcv *Monster) FlexLength() int {
|
||||
o := flatbuffers.UOffsetT(rcv._tab.Offset(64))
|
||||
if o != 0 {
|
||||
return rcv._tab.VectorLen(o)
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (rcv *Monster) FlexBytes() []byte {
|
||||
o := flatbuffers.UOffsetT(rcv._tab.Offset(64))
|
||||
if o != 0 {
|
||||
return rcv._tab.ByteVector(o + rcv._tab.Pos)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func MonsterStart(builder *flatbuffers.Builder) {
|
||||
builder.StartObject(29)
|
||||
builder.StartObject(31)
|
||||
}
|
||||
func MonsterAddPos(builder *flatbuffers.Builder, pos flatbuffers.UOffsetT) {
|
||||
builder.PrependStructSlot(0, flatbuffers.UOffsetT(pos), 0)
|
||||
@@ -529,6 +571,18 @@ func MonsterAddTestarrayofstring2(builder *flatbuffers.Builder, testarrayofstrin
|
||||
func MonsterStartTestarrayofstring2Vector(builder *flatbuffers.Builder, numElems int) flatbuffers.UOffsetT {
|
||||
return builder.StartVector(4, numElems, 4)
|
||||
}
|
||||
func MonsterAddTestarrayofsortedstruct(builder *flatbuffers.Builder, testarrayofsortedstruct flatbuffers.UOffsetT) {
|
||||
builder.PrependUOffsetTSlot(29, flatbuffers.UOffsetT(testarrayofsortedstruct), 0)
|
||||
}
|
||||
func MonsterStartTestarrayofsortedstructVector(builder *flatbuffers.Builder, numElems int) flatbuffers.UOffsetT {
|
||||
return builder.StartVector(8, numElems, 4)
|
||||
}
|
||||
func MonsterAddFlex(builder *flatbuffers.Builder, flex flatbuffers.UOffsetT) {
|
||||
builder.PrependUOffsetTSlot(30, flatbuffers.UOffsetT(flex), 0)
|
||||
}
|
||||
func MonsterStartFlexVector(builder *flatbuffers.Builder, numElems int) flatbuffers.UOffsetT {
|
||||
return builder.StartVector(1, numElems, 1)
|
||||
}
|
||||
func MonsterEnd(builder *flatbuffers.Builder) flatbuffers.UOffsetT {
|
||||
return builder.EndObject()
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user