forked from BigfootDev/flatbuffers
Compare commits
199 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
34aea4361f | ||
|
|
be1ad33910 | ||
|
|
0cf04ad9d5 | ||
|
|
fe483fa380 | ||
|
|
8a8dc4e111 | ||
|
|
7e803c410c | ||
|
|
1336d26252 | ||
|
|
853f7033e0 | ||
|
|
e2c7196ea8 | ||
|
|
61fe2a4fac | ||
|
|
d233b38008 | ||
|
|
ca52bfefc0 | ||
|
|
2edb1dcdda | ||
|
|
6eb031de9a | ||
|
|
5f2af34e02 | ||
|
|
f3f113b24a | ||
|
|
6bb0a728d3 | ||
|
|
97face1527 | ||
|
|
f2627e16ac | ||
|
|
01bac38c84 | ||
|
|
a1b5f565d9 | ||
|
|
0780a7db24 | ||
|
|
9234ddcf11 | ||
|
|
6d9a226f75 | ||
|
|
b0fd1a8c66 | ||
|
|
a0e5d78353 | ||
|
|
bc8a1608a8 | ||
|
|
30e7d16104 | ||
|
|
9c3920d0ab | ||
|
|
5b4acf809e | ||
|
|
86fb05d320 | ||
|
|
5e4739184f | ||
|
|
971a68110e | ||
|
|
7a6b2bf521 | ||
|
|
03e2899985 | ||
|
|
72a99abfb7 | ||
|
|
21a8121982 | ||
|
|
28920aff8f | ||
|
|
77b22aed5a | ||
|
|
cc25516d3e | ||
|
|
1d444f63d3 | ||
|
|
5fa00630af | ||
|
|
97af3d798b | ||
|
|
bb736091f3 | ||
|
|
d5b4db0692 | ||
|
|
5808f7fb03 | ||
|
|
42611f9a83 | ||
|
|
1f0bd12851 | ||
|
|
321a1c9dc0 | ||
|
|
ac1015e3c4 | ||
|
|
513958ea72 | ||
|
|
2f2e4cced4 | ||
|
|
f779962e3e | ||
|
|
69776b9e7e | ||
|
|
00d726fc4c | ||
|
|
ad0f48d7e7 | ||
|
|
801e1b7699 | ||
|
|
432e7582c6 | ||
|
|
d76113100a | ||
|
|
dca33ddb75 | ||
|
|
76744a4345 | ||
|
|
b4e91091ec | ||
|
|
d5f5d382eb | ||
|
|
ffddbdc7ab | ||
|
|
46bb05d952 | ||
|
|
7cc72e4b11 | ||
|
|
a6a3f59253 | ||
|
|
8a58aafda1 | ||
|
|
8dc1641c8a | ||
|
|
4b27c92910 | ||
|
|
7fe281295f | ||
|
|
917ff81b46 | ||
|
|
8a2cc7cc4e | ||
|
|
a64d968473 | ||
|
|
a2b1bfc107 | ||
|
|
f2b3705c2c | ||
|
|
3282a84e30 | ||
|
|
89a68942ac | ||
|
|
360c34467c | ||
|
|
265e43faf0 | ||
|
|
f064a6cc60 | ||
|
|
7fead0f140 | ||
|
|
d6f14b704f | ||
|
|
a892322203 | ||
|
|
2e2063cbeb | ||
|
|
625c989875 | ||
|
|
f20204180d | ||
|
|
0e85eeef2c | ||
|
|
b0fa5e0f42 | ||
|
|
25a15950f5 | ||
|
|
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 |
0
.gitattributes
vendored
Executable file → Normal file
0
.gitattributes
vendored
Executable file → Normal file
15
.gitignore
vendored
Executable file → Normal file
15
.gitignore
vendored
Executable file → Normal file
@@ -5,6 +5,7 @@
|
||||
*.o.d
|
||||
*.class
|
||||
*.a
|
||||
*.swp
|
||||
*~
|
||||
*.vcxproj
|
||||
*.vcxproj.filters
|
||||
@@ -43,11 +44,14 @@ flatsampletext.exe
|
||||
grpctest
|
||||
grpctest.exe
|
||||
snapshot.sh
|
||||
tags
|
||||
tests/go_gen
|
||||
tests/monsterdata_java_wire.mon
|
||||
tests/monsterdata_go_wire.mon
|
||||
tests/monsterdata_javascript_wire.mon
|
||||
tests/unicode_test.mon
|
||||
tests/ts/
|
||||
tests/php/
|
||||
CMakeLists.txt.user
|
||||
CMakeScripts/**
|
||||
CTestTestfile.cmake
|
||||
@@ -66,3 +70,14 @@ build/VS2010/FlatBuffers.opensdf
|
||||
build/VS2010/ipch/**/*.ipch
|
||||
*.so
|
||||
Testing/Temporary
|
||||
.cproject
|
||||
.settings/
|
||||
.project
|
||||
net/**/obj
|
||||
node_modules/
|
||||
android/.externalNativeBuild/
|
||||
android/.gradle/
|
||||
android/build/
|
||||
samples/android/.externalNativeBuild/
|
||||
samples/android/.gradle/
|
||||
samples/android/build/
|
||||
|
||||
81
.travis.yml
81
.travis.yml
@@ -1,31 +1,58 @@
|
||||
language: cpp
|
||||
|
||||
os:
|
||||
- linux
|
||||
- osx
|
||||
|
||||
compiler:
|
||||
- gcc
|
||||
#- clang
|
||||
|
||||
env:
|
||||
matrix:
|
||||
- BUILD_TYPE=Debug BIICODE=false
|
||||
- BUILD_TYPE=Release BIICODE=false
|
||||
# biicode .deb files no longer available.
|
||||
# - BUILD_TYPE=Release BIICODE=true
|
||||
# - BUILD_TYPE=Debug BIICODE=true
|
||||
global:
|
||||
# Set at the root level as this is ignored when set under matrix.env.
|
||||
- GCC_VERSION="4.9"
|
||||
matrix:
|
||||
include:
|
||||
- language: cpp
|
||||
os:
|
||||
- linux
|
||||
- osx
|
||||
|
||||
compiler:
|
||||
- gcc
|
||||
#- clang
|
||||
|
||||
env:
|
||||
matrix:
|
||||
- BUILD_TYPE=Debug BIICODE=false
|
||||
- BUILD_TYPE=Release BIICODE=false
|
||||
# biicode .deb files no longer available.
|
||||
# - BUILD_TYPE=Release BIICODE=true
|
||||
# - BUILD_TYPE=Debug BIICODE=true
|
||||
|
||||
before_install:
|
||||
- if [ "$TRAVIS_OS_NAME" == "linux" ]; then sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test; fi
|
||||
- if [ "$TRAVIS_OS_NAME" == "linux" ]; then sudo apt-get update -qq; fi
|
||||
- if [ "$TRAVIS_OS_NAME" == "linux" ]; then sudo apt-get install -qq g++-$GCC_VERSION; fi
|
||||
- if [ "$TRAVIS_OS_NAME" == "linux" ]; then sudo apt-get install -qq gcc-$GCC_VERSION; fi
|
||||
- if [ "$TRAVIS_OS_NAME" == "linux" ]; then sudo ln -s -v -f $(which g++-$GCC_VERSION) /usr/bin/g++; fi
|
||||
- if [ "$TRAVIS_OS_NAME" == "linux" ]; then sudo ln -s -v -f $(which gcc-$GCC_VERSION) /usr/bin/gcc; fi
|
||||
|
||||
script:
|
||||
- if [ "$BIICODE" == "false" ]; then cmake -DCMAKE_BUILD_TYPE=$BUILD_TYPE . && make && make test; fi
|
||||
- if [ "$BIICODE" == "true" ] && [ "$TRAVIS_OS_NAME" == "linux" ]; then ./biicode/support/bii-travis.sh $BUILD_TYPE; fi
|
||||
|
||||
before_install:
|
||||
- if [ "$TRAVIS_OS_NAME" == "linux" ]; then sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test; fi
|
||||
- if [ "$TRAVIS_OS_NAME" == "linux" ]; then sudo apt-get update -qq; fi
|
||||
- if [ "$TRAVIS_OS_NAME" == "linux" ]; then sudo apt-get install -qq g++-$GCC_VERSION; fi
|
||||
- if [ "$TRAVIS_OS_NAME" == "linux" ]; then sudo apt-get install -qq gcc-$GCC_VERSION; fi
|
||||
- if [ "$TRAVIS_OS_NAME" == "linux" ]; then sudo ln -s -v -f $(which g++-$GCC_VERSION) /usr/bin/g++; fi
|
||||
- if [ "$TRAVIS_OS_NAME" == "linux" ]; then sudo ln -s -v -f $(which gcc-$GCC_VERSION) /usr/bin/gcc; fi
|
||||
|
||||
script:
|
||||
- if [ "$BIICODE" == "false" ]; then cmake -DCMAKE_BUILD_TYPE=$BUILD_TYPE . && make && make test; fi
|
||||
- if [ "$BIICODE" == "true" ] && [ "$TRAVIS_OS_NAME" == "linux" ]; then ./biicode/support/bii-travis.sh $BUILD_TYPE; fi
|
||||
- language: android
|
||||
sudo: true
|
||||
android:
|
||||
components:
|
||||
- tools
|
||||
- platform-tools
|
||||
- build-tools-25.0.2
|
||||
- android-25
|
||||
- extra-android-m2repository
|
||||
compiler:
|
||||
- gcc
|
||||
before_install:
|
||||
- git clone https://github.com/urho3d/android-ndk.git $HOME/android-ndk-root
|
||||
- export ANDROID_NDK_HOME=$HOME/android-ndk-root
|
||||
# Setup environment for Linux build which is required to build the sample.
|
||||
- if [ "$TRAVIS_OS_NAME" == "linux" ]; then sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test; fi
|
||||
- if [ "$TRAVIS_OS_NAME" == "linux" ]; then sudo apt-get update -qq; fi
|
||||
- if [ "$TRAVIS_OS_NAME" == "linux" ]; then sudo apt-get install -qq g++-$GCC_VERSION; fi
|
||||
- if [ "$TRAVIS_OS_NAME" == "linux" ]; then sudo apt-get install -qq gcc-$GCC_VERSION; fi
|
||||
- if [ "$TRAVIS_OS_NAME" == "linux" ]; then sudo ln -s -v -f $(which g++-$GCC_VERSION) /usr/bin/g++; fi
|
||||
- if [ "$TRAVIS_OS_NAME" == "linux" ]; then sudo ln -s -v -f $(which gcc-$GCC_VERSION) /usr/bin/gcc; fi
|
||||
script:
|
||||
- failed=0; for build_gradle in $(git ls-files | grep build.gradle); do ( cd "$(dirname "${build_gradle}")" && ./gradlew build ) || failed=1; done; exit $((failed))
|
||||
|
||||
4
CMake/FlatbuffersConfig.cmake
Normal file
4
CMake/FlatbuffersConfig.cmake
Normal file
@@ -0,0 +1,4 @@
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/FlatbuffersTargets.cmake" OPTIONAL)
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/FlatcTargets.cmake" OPTIONAL)
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/FlatbuffersSharedTargets.cmake" OPTIONAL)
|
||||
|
||||
@@ -24,13 +24,17 @@ 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/stl_emulation.h
|
||||
include/flatbuffers/flexbuffers.h
|
||||
include/flatbuffers/registry.h
|
||||
include/flatbuffers/minireflect.h
|
||||
src/code_generators.cpp
|
||||
src/idl_parser.cpp
|
||||
src/idl_gen_text.cpp
|
||||
@@ -48,6 +52,7 @@ set(FlatBuffers_Compiler_SRCS
|
||||
src/idl_gen_python.cpp
|
||||
src/idl_gen_fbs.cpp
|
||||
src/idl_gen_grpc.cpp
|
||||
src/idl_gen_json_schema.cpp
|
||||
src/flatc.cpp
|
||||
src/flatc_main.cpp
|
||||
grpc/src/compiler/schema_interface.h
|
||||
@@ -102,7 +107,7 @@ if(EXISTS "${CMAKE_TOOLCHAIN_FILE}")
|
||||
# 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
|
||||
@@ -126,9 +131,13 @@ elseif(CMAKE_COMPILER_IS_GNUCXX)
|
||||
|
||||
elseif(${CMAKE_CXX_COMPILER_ID} MATCHES "Clang")
|
||||
set(CMAKE_CXX_FLAGS
|
||||
"${CMAKE_CXX_FLAGS} -std=c++0x -stdlib=libc++ -Wall -pedantic -Werror \
|
||||
-Wextra")
|
||||
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()
|
||||
@@ -138,6 +147,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)
|
||||
@@ -163,6 +177,10 @@ 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)
|
||||
@@ -171,7 +189,16 @@ endif()
|
||||
|
||||
if(FLATBUFFERS_BUILD_SHAREDLIB)
|
||||
add_library(flatbuffers_shared SHARED ${FlatBuffers_Library_SRCS})
|
||||
set_target_properties(flatbuffers_shared PROPERTIES OUTPUT_NAME flatbuffers)
|
||||
|
||||
# Shared object version: "major.minor.micro"
|
||||
# - micro updated every release when there is no API/ABI changes
|
||||
# - minor updated when there are additions in API/ABI
|
||||
# - major (ABI number) updated when there are changes in ABI (or removals)
|
||||
set(FlatBuffers_Library_SONAME_MAJOR "1")
|
||||
set(FlatBuffers_Library_SONAME_FULL "${FlatBuffers_Library_SONAME_MAJOR}.8.0")
|
||||
set_target_properties(flatbuffers_shared PROPERTIES OUTPUT_NAME flatbuffers
|
||||
SOVERSION "${FlatBuffers_Library_SONAME_MAJOR}"
|
||||
VERSION "${FlatBuffers_Library_SONAME_FULL}")
|
||||
endif()
|
||||
|
||||
function(compile_flatbuffers_schema_to_cpp SRC_FBS)
|
||||
@@ -181,6 +208,9 @@ 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}"
|
||||
--cpp-ptr-type flatbuffers::unique_ptr # Used to test with C++98 STLs
|
||||
--reflect-names
|
||||
-I "${CMAKE_CURRENT_SOURCE_DIR}/tests/include_test"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/${SRC_FBS}"
|
||||
DEPENDS flatc)
|
||||
endfunction()
|
||||
@@ -211,22 +241,67 @@ 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 grpc_unsecure pthread dl)
|
||||
endif()
|
||||
|
||||
if(FLATBUFFERS_INSTALL)
|
||||
install(DIRECTORY include/flatbuffers DESTINATION include)
|
||||
include(GNUInstallDirs)
|
||||
|
||||
install(DIRECTORY include/flatbuffers DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
|
||||
|
||||
set(FB_CMAKE_DIR "${CMAKE_INSTALL_LIBDIR}/cmake/flatbuffers")
|
||||
|
||||
install(
|
||||
FILES "CMake/FlatbuffersConfig.cmake"
|
||||
DESTINATION ${FB_CMAKE_DIR}
|
||||
)
|
||||
|
||||
if(FLATBUFFERS_BUILD_FLATLIB)
|
||||
install(TARGETS flatbuffers DESTINATION lib)
|
||||
install(
|
||||
TARGETS flatbuffers EXPORT FlatbuffersTargets
|
||||
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
)
|
||||
|
||||
install(EXPORT FlatbuffersTargets
|
||||
FILE FlatbuffersTargets.cmake
|
||||
NAMESPACE flatbuffers::
|
||||
DESTINATION ${FB_CMAKE_DIR}
|
||||
)
|
||||
endif()
|
||||
|
||||
if(FLATBUFFERS_BUILD_FLATC)
|
||||
install(TARGETS flatc DESTINATION bin)
|
||||
install(
|
||||
TARGETS flatc EXPORT FlatcTargets
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||
CONFIGURATIONS Release
|
||||
)
|
||||
|
||||
install(
|
||||
EXPORT FlatcTargets
|
||||
FILE FlatcTargets.cmake
|
||||
NAMESPACE flatbuffers::
|
||||
DESTINATION ${FB_CMAKE_DIR}
|
||||
CONFIGURATIONS Release
|
||||
)
|
||||
endif()
|
||||
|
||||
if(FLATBUFFERS_BUILD_SHAREDLIB)
|
||||
install(TARGETS flatbuffers_shared DESTINATION lib)
|
||||
install(
|
||||
TARGETS flatbuffers_shared EXPORT FlatbuffersSharedTargets
|
||||
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
)
|
||||
|
||||
install(
|
||||
EXPORT FlatbuffersSharedTargets
|
||||
FILE FlatbuffersSharedTargets.cmake
|
||||
NAMESPACE flatbuffers::
|
||||
DESTINATION ${FB_CMAKE_DIR}
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
|
||||
0
android/.project
Executable file → Normal file
0
android/.project
Executable file → Normal file
11
android/AndroidManifest.xml
Executable file → Normal file
11
android/AndroidManifest.xml
Executable file → Normal file
@@ -17,17 +17,14 @@
|
||||
-->
|
||||
<!-- BEGIN_INCLUDE(manifest) -->
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.example.FlatBufferTest"
|
||||
android:versionCode="1"
|
||||
android:versionName="1.0">
|
||||
package="com.example.FlatBufferTest">
|
||||
|
||||
<uses-feature android:glEsVersion="0x00020000"></uses-feature>
|
||||
<!-- This is the platform API where NativeActivity was introduced. -->
|
||||
<uses-sdk android:minSdkVersion="9" />
|
||||
|
||||
<!-- This .apk has no Java code itself, so set hasCode to false. -->
|
||||
<application android:label="@string/app_name" android:hasCode="false">
|
||||
|
||||
<application android:label="@string/app_name"
|
||||
android:hasCode="false"
|
||||
android:allowBackup="false">
|
||||
<!-- Our activity is the built-in NativeActivity framework class.
|
||||
This will take care of integrating with our NDK code. -->
|
||||
<activity android:name="android.app.NativeActivity"
|
||||
|
||||
108
android/build.gradle
Normal file
108
android/build.gradle
Normal file
@@ -0,0 +1,108 @@
|
||||
// Copyright (c) 2017 Google, Inc.
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied
|
||||
// warranty. In no event will the authors be held liable for any damages
|
||||
// arising from the use of this software.
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it
|
||||
// freely, subject to the following restrictions:
|
||||
// 1. The origin of this software must not be misrepresented; you must not
|
||||
// claim that you wrote the original software. If you use this software
|
||||
// in a product, an acknowledgment in the product documentation would be
|
||||
// appreciated but is not required.
|
||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
||||
// misrepresented as being the original software.
|
||||
// 3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
buildscript {
|
||||
repositories {
|
||||
jcenter()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:2.3.0'
|
||||
}
|
||||
}
|
||||
|
||||
allprojects {
|
||||
repositories {
|
||||
jcenter()
|
||||
}
|
||||
}
|
||||
|
||||
apply plugin: 'com.android.application'
|
||||
|
||||
android {
|
||||
compileSdkVersion 25
|
||||
buildToolsVersion '25.0.2'
|
||||
|
||||
sourceSets {
|
||||
main {
|
||||
manifest.srcFile 'AndroidManifest.xml'
|
||||
res.srcDirs = ['res']
|
||||
}
|
||||
}
|
||||
|
||||
externalNativeBuild {
|
||||
ndkBuild {
|
||||
path "jni/Android.mk"
|
||||
}
|
||||
}
|
||||
|
||||
defaultConfig {
|
||||
applicationId 'com.example.FlatBufferTest'
|
||||
// This is the platform API where NativeActivity was introduced.
|
||||
minSdkVersion 9
|
||||
targetSdkVersion 25
|
||||
versionCode 1
|
||||
versionName "1.0"
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled false
|
||||
}
|
||||
}
|
||||
|
||||
externalNativeBuild {
|
||||
ndkBuild {
|
||||
targets "FlatBufferTest"
|
||||
arguments "-j" + Runtime.getRuntime().availableProcessors()
|
||||
abiFilters "armeabi", "armeabi-v7a", "arm64-v8a", "x86", "x86_64"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
lintOptions {
|
||||
abortOnError false
|
||||
}
|
||||
|
||||
// Build with each STL variant.
|
||||
productFlavors {
|
||||
stlport {
|
||||
applicationIdSuffix ".stlport"
|
||||
versionNameSuffix "-stlport"
|
||||
externalNativeBuild {
|
||||
ndkBuild {
|
||||
arguments "APP_STL=stlport_static"
|
||||
}
|
||||
}
|
||||
}
|
||||
gnustl {
|
||||
applicationIdSuffix ".gnustl"
|
||||
versionNameSuffix "-gnustl"
|
||||
externalNativeBuild {
|
||||
ndkBuild {
|
||||
arguments "APP_STL=gnustl_static"
|
||||
}
|
||||
}
|
||||
}
|
||||
libcpp {
|
||||
applicationIdSuffix ".libcpp"
|
||||
versionNameSuffix "-libcpp"
|
||||
externalNativeBuild {
|
||||
ndkBuild {
|
||||
arguments "APP_STL=c++_static"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,511 +0,0 @@
|
||||
#!/bin/bash -eu
|
||||
#
|
||||
# Copyright (c) 2013 Google, Inc.
|
||||
#
|
||||
# This software is provided 'as-is', without any express or implied
|
||||
# warranty. In no event will the authors be held liable for any damages
|
||||
# arising from the use of this software.
|
||||
# Permission is granted to anyone to use this software for any purpose,
|
||||
# including commercial applications, and to alter it and redistribute it
|
||||
# freely, subject to the following restrictions:
|
||||
# 1. The origin of this software must not be misrepresented; you must not
|
||||
# claim that you wrote the original software. If you use this software
|
||||
# in a product, an acknowledgment in the product documentation would be
|
||||
# appreciated but is not required.
|
||||
# 2. Altered source versions must be plainly marked as such, and must not be
|
||||
# misrepresented as being the original software.
|
||||
# 3. This notice may not be removed or altered from any source distribution.
|
||||
#
|
||||
# Build, deploy, debug / execute a native Android package based upon
|
||||
# NativeActivity.
|
||||
|
||||
declare -r script_directory=$(dirname $0)
|
||||
declare -r android_root=${script_directory}/../../../../../../
|
||||
declare -r script_name=$(basename $0)
|
||||
declare -r android_manifest=AndroidManifest.xml
|
||||
declare -r os_name=$(uname -s)
|
||||
|
||||
# Minimum Android target version supported by this project.
|
||||
: ${BUILDAPK_ANDROID_TARGET_MINVERSION:=10}
|
||||
# Directory containing the Android SDK
|
||||
# (http://developer.android.com/sdk/index.html).
|
||||
: ${ANDROID_SDK_HOME:=}
|
||||
# Directory containing the Android NDK
|
||||
# (http://developer.android.com/tools/sdk/ndk/index.html).
|
||||
: ${NDK_HOME:=}
|
||||
|
||||
# Display script help and exit.
|
||||
usage() {
|
||||
echo "
|
||||
Build the Android package in the current directory and deploy it to a
|
||||
connected device.
|
||||
|
||||
Usage: ${script_name} \\
|
||||
[ADB_DEVICE=serial_number] [BUILD=0] [DEPLOY=0] [RUN_DEBUGGER=1] \
|
||||
[LAUNCH=0] [SWIG_BIN=swig_binary_directory] [SWIG_LIB=swig_include_directory] [ndk-build arguments ...]
|
||||
|
||||
ADB_DEVICE=serial_number:
|
||||
serial_number specifies the device to deploy the built apk to if multiple
|
||||
Android devices are connected to the host.
|
||||
BUILD=0:
|
||||
Disables the build of the package.
|
||||
DEPLOY=0:
|
||||
Disables the deployment of the built apk to the Android device.
|
||||
RUN_DEBUGGER=1:
|
||||
Launches the application in gdb after it has been deployed. To debug in
|
||||
gdb, NDK_DEBUG=1 must also be specified on the command line to build a
|
||||
debug apk.
|
||||
LAUNCH=0:
|
||||
Disable the launch of the apk on the Android device.
|
||||
SWIG_BIN=swig_binary_directory:
|
||||
The directory where the SWIG binary lives. No need to set this if SWIG is
|
||||
installed and point to from your PATH variable.
|
||||
SWIG_LIB=swig_include_directory:
|
||||
The directory where SWIG shared include files are, usually obtainable from
|
||||
commandline with \"swig -swiglib\". No need to set this if SWIG is installed
|
||||
and point to from your PATH variable.
|
||||
ndk-build arguments...:
|
||||
Additional arguments for ndk-build. See ndk-build -h for more information.
|
||||
" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Get the number of CPU cores present on the host.
|
||||
get_number_of_cores() {
|
||||
case ${os_name} in
|
||||
Darwin)
|
||||
sysctl hw.ncpu | awk '{ print $2 }'
|
||||
;;
|
||||
CYGWIN*|Linux)
|
||||
awk '/^processor/ { n=$3 } END { print n + 1 }' /proc/cpuinfo
|
||||
;;
|
||||
*)
|
||||
echo 1
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
# Get the package name from an AndroidManifest.xml file.
|
||||
get_package_name_from_manifest() {
|
||||
xmllint --xpath 'string(/manifest/@package)' "${1}"
|
||||
}
|
||||
|
||||
# Get the library name from an AndroidManifest.xml file.
|
||||
get_library_name_from_manifest() {
|
||||
echo "\
|
||||
setns android=http://schemas.android.com/apk/res/android
|
||||
xpath string(/manifest/application/activity\
|
||||
[@android:name=\"android.app.NativeActivity\"]/meta-data\
|
||||
[@android:name=\"android.app.lib_name\"]/@android:value)" |
|
||||
xmllint --shell "${1}" | awk '/Object is a string/ { print $NF }'
|
||||
}
|
||||
|
||||
# Get the number of Android devices connected to the system.
|
||||
get_number_of_devices_connected() {
|
||||
adb devices -l | \
|
||||
awk '/^..*$/ { if (p) { print $0 } }
|
||||
/List of devices attached/ { p = 1 }' | \
|
||||
wc -l
|
||||
return ${PIPESTATUS[0]}
|
||||
}
|
||||
|
||||
# Kill a process and its' children. This is provided for cygwin which
|
||||
# doesn't ship with pkill.
|
||||
kill_process_group() {
|
||||
local parent_pid="${1}"
|
||||
local child_pid=
|
||||
for child_pid in $(ps -f | \
|
||||
awk '{ if ($3 == '"${parent_pid}"') { print $2 } }'); do
|
||||
kill_process_group "${child_pid}"
|
||||
done
|
||||
kill "${parent_pid}" 2>/dev/null
|
||||
}
|
||||
|
||||
# Find and run "adb".
|
||||
adb() {
|
||||
local adb_path=
|
||||
for path in "$(which adb 2>/dev/null)" \
|
||||
"${ANDROID_SDK_HOME}/sdk/platform-tools/adb" \
|
||||
"${android_root}/prebuilts/sdk/platform-tools/adb"; do
|
||||
if [[ -e "${path}" ]]; then
|
||||
adb_path="${path}"
|
||||
break
|
||||
fi
|
||||
done
|
||||
if [[ "${adb_path}" == "" ]]; then
|
||||
echo -e "Unable to find adb." \
|
||||
"\nAdd the Android ADT sdk/platform-tools directory to the" \
|
||||
"PATH." >&2
|
||||
exit 1
|
||||
fi
|
||||
"${adb_path}" "$@"
|
||||
}
|
||||
|
||||
# Find and run "android".
|
||||
android() {
|
||||
local android_executable=android
|
||||
if echo "${os_name}" | grep -q CYGWIN; then
|
||||
android_executable=android.bat
|
||||
fi
|
||||
local android_path=
|
||||
for path in "$(which ${android_executable})" \
|
||||
"${ANDROID_SDK_HOME}/sdk/tools/${android_executable}" \
|
||||
"${android_root}/prebuilts/sdk/tools/${android_executable}"; do
|
||||
if [[ -e "${path}" ]]; then
|
||||
android_path="${path}"
|
||||
break
|
||||
fi
|
||||
done
|
||||
if [[ "${android_path}" == "" ]]; then
|
||||
echo -e "Unable to find android tool." \
|
||||
"\nAdd the Android ADT sdk/tools directory to the PATH." >&2
|
||||
exit 1
|
||||
fi
|
||||
# Make sure ant is installed.
|
||||
if [[ "$(which ant)" == "" ]]; then
|
||||
echo -e "Unable to find ant." \
|
||||
"\nPlease install ant and add to the PATH." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
"${android_path}" "$@"
|
||||
}
|
||||
|
||||
# Find and run "ndk-build"
|
||||
ndkbuild() {
|
||||
local ndkbuild_path=
|
||||
for path in "$(which ndk-build 2>/dev/null)" \
|
||||
"${NDK_HOME}/ndk-build" \
|
||||
"${android_root}/prebuilts/ndk/current/ndk-build"; do
|
||||
if [[ -e "${path}" ]]; then
|
||||
ndkbuild_path="${path}"
|
||||
break
|
||||
fi
|
||||
done
|
||||
if [[ "${ndkbuild_path}" == "" ]]; then
|
||||
echo -e "Unable to find ndk-build." \
|
||||
"\nAdd the Android NDK directory to the PATH." >&2
|
||||
exit 1
|
||||
fi
|
||||
"${ndkbuild_path}" "$@"
|
||||
}
|
||||
|
||||
# Get file modification time of $1 in seconds since the epoch.
|
||||
stat_mtime() {
|
||||
local filename="${1}"
|
||||
case ${os_name} in
|
||||
Darwin) stat -f%m "${filename}" 2>/dev/null || echo 0 ;;
|
||||
*) stat -c%Y "${filename}" 2>/dev/null || echo 0 ;;
|
||||
esac
|
||||
}
|
||||
|
||||
# Build the native (C/C++) build targets in the current directory.
|
||||
build_native_targets() {
|
||||
# Save the list of output modules in the install directory so that it's
|
||||
# possible to restore their timestamps after the build is complete. This
|
||||
# works around a bug in ndk/build/core/setup-app.mk which results in the
|
||||
# unconditional execution of the clean-installed-binaries rule.
|
||||
restore_libraries="$(find libs -type f 2>/dev/null | \
|
||||
sed -E 's@^libs/(.*)@\1@')"
|
||||
|
||||
# Build native code.
|
||||
ndkbuild -j$(get_number_of_cores) "$@"
|
||||
|
||||
# Restore installed libraries.
|
||||
# Obviously this is a nasty hack (along with ${restore_libraries} above) as
|
||||
# it assumes it knows where the NDK will be placing output files.
|
||||
(
|
||||
IFS=$'\n'
|
||||
for libpath in ${restore_libraries}; do
|
||||
source_library="obj/local/${libpath}"
|
||||
target_library="libs/${libpath}"
|
||||
if [[ -e "${source_library}" ]]; then
|
||||
cp -a "${source_library}" "${target_library}"
|
||||
fi
|
||||
done
|
||||
)
|
||||
}
|
||||
|
||||
# Select the oldest installed android build target that is at least as new as
|
||||
# BUILDAPK_ANDROID_TARGET_MINVERSION. If a suitable build target isn't found,
|
||||
# this function prints an error message and exits with an error.
|
||||
select_android_build_target() {
|
||||
local -r android_targets_installed=$( \
|
||||
android list targets | \
|
||||
awk -F'"' '/^id:.*android/ { print $2 }')
|
||||
local android_build_target=
|
||||
for android_target in $(echo "${android_targets_installed}" | \
|
||||
awk -F- '{ print $2 }' | sort -n); do
|
||||
local isNumber='^[0-9]+$'
|
||||
# skip preview API releases e.g. 'android-L'
|
||||
if [[ $android_target =~ $isNumber ]]; then
|
||||
if [[ $((android_target)) -ge \
|
||||
$((BUILDAPK_ANDROID_TARGET_MINVERSION)) ]]; then
|
||||
android_build_target="android-${android_target}"
|
||||
break
|
||||
fi
|
||||
# else
|
||||
# The API version is a letter, so skip it.
|
||||
fi
|
||||
done
|
||||
if [[ "${android_build_target}" == "" ]]; then
|
||||
echo -e \
|
||||
"Found installed Android targets:" \
|
||||
"$(echo ${android_targets_installed} | sed 's/ /\n /g;s/^/\n /;')" \
|
||||
"\nAndroid SDK platform" \
|
||||
"android-$((BUILDAPK_ANDROID_TARGET_MINVERSION))" \
|
||||
"must be installed to build this project." \
|
||||
"\nUse the \"android\" application to install API" \
|
||||
"$((BUILDAPK_ANDROID_TARGET_MINVERSION)) or newer." >&2
|
||||
exit 1
|
||||
fi
|
||||
echo "${android_build_target}"
|
||||
}
|
||||
|
||||
# Sign unsigned apk $1 and write the result to $2 with key store file $3 and
|
||||
# password $4.
|
||||
# If a key store file $3 and password $4 aren't specified, a temporary
|
||||
# (60 day) key is generated and used to sign the package.
|
||||
sign_apk() {
|
||||
local unsigned_apk="${1}"
|
||||
local signed_apk="${2}"
|
||||
if [[ $(stat_mtime "${unsigned_apk}") -gt \
|
||||
$(stat_mtime "${signed_apk}") ]]; then
|
||||
local -r key_alias=$(basename ${signed_apk} .apk)
|
||||
local keystore="${3}"
|
||||
local key_password="${4}"
|
||||
[[ "${keystore}" == "" ]] && keystore="${unsigned_apk}.keystore"
|
||||
[[ "${key_password}" == "" ]] && \
|
||||
key_password="${key_alias}123456"
|
||||
if [[ ! -e ${keystore} ]]; then
|
||||
keytool -genkey -v -dname "cn=, ou=${key_alias}, o=fpl" \
|
||||
-storepass ${key_password} \
|
||||
-keypass ${key_password} -keystore ${keystore} \
|
||||
-alias ${key_alias} -keyalg RSA -keysize 2048 -validity 60
|
||||
fi
|
||||
cp "${unsigned_apk}" "${signed_apk}"
|
||||
jarsigner -verbose -sigalg SHA1withRSA -digestalg SHA1 \
|
||||
-keystore ${keystore} -storepass ${key_password} \
|
||||
-keypass ${key_password} "${signed_apk}" ${key_alias}
|
||||
fi
|
||||
}
|
||||
|
||||
# Build the apk $1 for package filename $2 in the current directory using the
|
||||
# ant build target $3.
|
||||
build_apk() {
|
||||
local -r output_apk="${1}"
|
||||
local -r package_filename="${2}"
|
||||
local -r ant_target="${3}"
|
||||
# Get the list of installed android targets and select the oldest target
|
||||
# that is at least as new as BUILDAPK_ANDROID_TARGET_MINVERSION.
|
||||
local -r android_build_target=$(select_android_build_target)
|
||||
[[ "${android_build_target}" == "" ]] && exit 1
|
||||
echo "Building ${output_apk} for target ${android_build_target}" >&2
|
||||
|
||||
# Create / update build.xml and local.properties files.
|
||||
if [[ $(stat_mtime "${android_manifest}") -gt \
|
||||
$(stat_mtime build.xml) ]]; then
|
||||
android update project --target "${android_build_target}" \
|
||||
-n ${package_filename} --path .
|
||||
fi
|
||||
|
||||
# Use ant to build the apk.
|
||||
ant -quiet ${ant_target}
|
||||
|
||||
# Sign release apks with a temporary key as these packages will not be
|
||||
# redistributed.
|
||||
local unsigned_apk="bin/${package_filename}-${ant_target}-unsigned.apk"
|
||||
if [[ "${ant_target}" == "release" ]]; then
|
||||
sign_apk "${unsigned_apk}" "${output_apk}" "" ""
|
||||
fi
|
||||
}
|
||||
|
||||
# Uninstall package $1 and install apk $2 on device $3 where $3 is "-s device"
|
||||
# or an empty string. If $3 is an empty string adb will fail when multiple
|
||||
# devices are connected to the host system.
|
||||
install_apk() {
|
||||
local -r uninstall_package_name="${1}"
|
||||
local -r install_apk="${2}"
|
||||
local -r adb_device="${3}"
|
||||
# Uninstall the package if it's already installed.
|
||||
adb ${adb_device} uninstall "${uninstall_package_name}" 1>&2 > /dev/null || \
|
||||
true # no error check
|
||||
|
||||
# Install the apk.
|
||||
# NOTE: The following works around adb not returning an error code when
|
||||
# it fails to install an apk.
|
||||
echo "Install ${install_apk}" >&2
|
||||
local -r adb_install_result=$(adb ${adb_device} install "${install_apk}")
|
||||
echo "${adb_install_result}"
|
||||
if echo "${adb_install_result}" | grep -qF 'Failure ['; then
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Launch previously installed package $1 on device $2.
|
||||
# If $2 is an empty string adb will fail when multiple devices are connected
|
||||
# to the host system.
|
||||
launch_package() {
|
||||
(
|
||||
# Determine the SDK version of Android on the device.
|
||||
local -r android_sdk_version=$(
|
||||
adb ${adb_device} shell cat system/build.prop | \
|
||||
awk -F= '/ro.build.version.sdk/ {
|
||||
v=$2; sub(/[ \r\n]/, "", v); print v
|
||||
}')
|
||||
|
||||
# Clear logs from previous runs.
|
||||
# Note that logcat does not just 'tail' the logs, it dumps the entire log
|
||||
# history.
|
||||
adb ${adb_device} logcat -c
|
||||
|
||||
local finished_msg='Displayed '"${package_name}"
|
||||
local timeout_msg='Activity destroy timeout.*'"${package_name}"
|
||||
# Maximum time to wait before stopping log monitoring. 0 = infinity.
|
||||
local launch_timeout=0
|
||||
# If this is a Gingerbread device, kill log monitoring after 10 seconds.
|
||||
if [[ $((android_sdk_version)) -le 10 ]]; then
|
||||
launch_timeout=10
|
||||
fi
|
||||
# Display logcat in the background.
|
||||
# Stop displaying the log when the app launch / execution completes or the
|
||||
# logcat
|
||||
(
|
||||
adb ${adb_device} logcat | \
|
||||
awk "
|
||||
{
|
||||
print \$0
|
||||
}
|
||||
|
||||
/ActivityManager.*: ${finished_msg}/ {
|
||||
exit 0
|
||||
}
|
||||
|
||||
/ActivityManager.*: ${timeout_msg}/ {
|
||||
exit 0
|
||||
}" &
|
||||
adb_logcat_pid=$!;
|
||||
if [[ $((launch_timeout)) -gt 0 ]]; then
|
||||
sleep $((launch_timeout));
|
||||
kill ${adb_logcat_pid};
|
||||
else
|
||||
wait ${adb_logcat_pid};
|
||||
fi
|
||||
) &
|
||||
logcat_pid=$!
|
||||
# Kill adb logcat if this shell exits.
|
||||
trap "kill_process_group ${logcat_pid}" SIGINT SIGTERM EXIT
|
||||
|
||||
# If the SDK is newer than 10, "am" supports stopping an activity.
|
||||
adb_stop_activity=
|
||||
if [[ $((android_sdk_version)) -gt 10 ]]; then
|
||||
adb_stop_activity=-S
|
||||
fi
|
||||
|
||||
# Launch the activity and wait for it to complete.
|
||||
adb ${adb_device} shell am start ${adb_stop_activity} -n \
|
||||
${package_name}/android.app.NativeActivity
|
||||
|
||||
wait "${logcat_pid}"
|
||||
)
|
||||
}
|
||||
|
||||
# See usage().
|
||||
main() {
|
||||
# Parse arguments for this script.
|
||||
local adb_device=
|
||||
local ant_target=release
|
||||
local disable_deploy=0
|
||||
local disable_build=0
|
||||
local run_debugger=0
|
||||
local launch=1
|
||||
local build_package=1
|
||||
for opt; do
|
||||
case ${opt} in
|
||||
# NDK_DEBUG=0 tells ndk-build to build this as debuggable but to not
|
||||
# modify the underlying code whereas NDK_DEBUG=1 also builds as debuggable
|
||||
# but does modify the code
|
||||
NDK_DEBUG=1) ant_target=debug ;;
|
||||
NDK_DEBUG=0) ant_target=debug ;;
|
||||
ADB_DEVICE*) adb_device="$(\
|
||||
echo "${opt}" | sed -E 's/^ADB_DEVICE=([^ ]+)$/-s \1/;t;s/.*//')" ;;
|
||||
BUILD=0) disable_build=1 ;;
|
||||
DEPLOY=0) disable_deploy=1 ;;
|
||||
RUN_DEBUGGER=1) run_debugger=1 ;;
|
||||
LAUNCH=0) launch=0 ;;
|
||||
clean) build_package=0 disable_deploy=1 launch=0 ;;
|
||||
-h|--help|help) usage ;;
|
||||
esac
|
||||
done
|
||||
|
||||
# If a target device hasn't been specified and multiple devices are connected
|
||||
# to the host machine, display an error.
|
||||
local -r devices_connected=$(get_number_of_devices_connected)
|
||||
if [[ "${adb_device}" == "" && $((devices_connected)) -gt 1 && \
|
||||
($((disable_deploy)) -eq 0 || $((launch)) -ne 0 || \
|
||||
$((run_debugger)) -ne 0) ]]; then
|
||||
if [[ $((disable_deploy)) -ne 0 ]]; then
|
||||
echo "Deployment enabled, disable using DEPLOY=0" >&2
|
||||
fi
|
||||
if [[ $((launch)) -ne 0 ]]; then
|
||||
echo "Launch enabled." >&2
|
||||
fi
|
||||
if [[ $((disable_deploy)) -eq 0 ]]; then
|
||||
echo "Deployment enabled." >&2
|
||||
fi
|
||||
if [[ $((run_debugger)) -ne 0 ]]; then
|
||||
echo "Debugger launch enabled." >&2
|
||||
fi
|
||||
echo "
|
||||
Multiple Android devices are connected to this host. Either disable deployment
|
||||
and execution of the built .apk using:
|
||||
\"${script_name} DEPLOY=0 LAUNCH=0\"
|
||||
|
||||
or specify a device to deploy to using:
|
||||
\"${script_name} ADB_DEVICE=\${device_serial}\".
|
||||
|
||||
The Android devices connected to this machine are:
|
||||
$(adb devices -l)
|
||||
" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ $((disable_build)) -eq 0 ]]; then
|
||||
# Build the native target.
|
||||
build_native_targets "$@"
|
||||
fi
|
||||
|
||||
# Get the package name from the manifest.
|
||||
local -r package_name=$(get_package_name_from_manifest "${android_manifest}")
|
||||
if [[ "${package_name}" == "" ]]; then
|
||||
echo -e "No package name specified in ${android_manifest},"\
|
||||
"skipping apk build, deploy"
|
||||
"\nand launch steps." >&2
|
||||
exit 0
|
||||
fi
|
||||
local -r package_basename=${package_name/*./}
|
||||
local package_filename=$(get_library_name_from_manifest ${android_manifest})
|
||||
[[ "${package_filename}" == "" ]] && package_filename="${package_basename}"
|
||||
|
||||
# Output apk name.
|
||||
local -r output_apk="bin/${package_filename}-${ant_target}.apk"
|
||||
|
||||
if [[ $((disable_build)) -eq 0 && $((build_package)) -eq 1 ]]; then
|
||||
# Build the apk.
|
||||
build_apk "${output_apk}" "${package_filename}" "${ant_target}"
|
||||
fi
|
||||
|
||||
# Deploy to the device.
|
||||
if [[ $((disable_deploy)) -eq 0 ]]; then
|
||||
install_apk "${package_name}" "${output_apk}" "${adb_device}"
|
||||
fi
|
||||
|
||||
if [[ "${ant_target}" == "debug" && $((run_debugger)) -eq 1 ]]; then
|
||||
# Start debugging.
|
||||
ndk-gdb ${adb_device} --start
|
||||
elif [[ $((launch)) -eq 1 ]]; then
|
||||
launch_package "${package_name}" "${adb_device}"
|
||||
fi
|
||||
}
|
||||
|
||||
main "$@"
|
||||
BIN
android/gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
BIN
android/gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
Binary file not shown.
6
android/gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
6
android/gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
#Mon Jun 19 11:54:59 PDT 2017
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-4.0-all.zip
|
||||
172
android/gradlew
vendored
Executable file
172
android/gradlew
vendored
Executable file
@@ -0,0 +1,172 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
##############################################################################
|
||||
##
|
||||
## Gradle start up script for UN*X
|
||||
##
|
||||
##############################################################################
|
||||
|
||||
# Attempt to set APP_HOME
|
||||
# Resolve links: $0 may be a link
|
||||
PRG="$0"
|
||||
# Need this for relative symlinks.
|
||||
while [ -h "$PRG" ] ; do
|
||||
ls=`ls -ld "$PRG"`
|
||||
link=`expr "$ls" : '.*-> \(.*\)$'`
|
||||
if expr "$link" : '/.*' > /dev/null; then
|
||||
PRG="$link"
|
||||
else
|
||||
PRG=`dirname "$PRG"`"/$link"
|
||||
fi
|
||||
done
|
||||
SAVED="`pwd`"
|
||||
cd "`dirname \"$PRG\"`/" >/dev/null
|
||||
APP_HOME="`pwd -P`"
|
||||
cd "$SAVED" >/dev/null
|
||||
|
||||
APP_NAME="Gradle"
|
||||
APP_BASE_NAME=`basename "$0"`
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS=""
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD="maximum"
|
||||
|
||||
warn () {
|
||||
echo "$*"
|
||||
}
|
||||
|
||||
die () {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
exit 1
|
||||
}
|
||||
|
||||
# OS specific support (must be 'true' or 'false').
|
||||
cygwin=false
|
||||
msys=false
|
||||
darwin=false
|
||||
nonstop=false
|
||||
case "`uname`" in
|
||||
CYGWIN* )
|
||||
cygwin=true
|
||||
;;
|
||||
Darwin* )
|
||||
darwin=true
|
||||
;;
|
||||
MINGW* )
|
||||
msys=true
|
||||
;;
|
||||
NONSTOP* )
|
||||
nonstop=true
|
||||
;;
|
||||
esac
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
|
||||
# Determine the Java command to use to start the JVM.
|
||||
if [ -n "$JAVA_HOME" ] ; then
|
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||
# IBM's JDK on AIX uses strange locations for the executables
|
||||
JAVACMD="$JAVA_HOME/jre/sh/java"
|
||||
else
|
||||
JAVACMD="$JAVA_HOME/bin/java"
|
||||
fi
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
else
|
||||
JAVACMD="java"
|
||||
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
|
||||
MAX_FD_LIMIT=`ulimit -H -n`
|
||||
if [ $? -eq 0 ] ; then
|
||||
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
|
||||
MAX_FD="$MAX_FD_LIMIT"
|
||||
fi
|
||||
ulimit -n $MAX_FD
|
||||
if [ $? -ne 0 ] ; then
|
||||
warn "Could not set maximum file descriptor limit: $MAX_FD"
|
||||
fi
|
||||
else
|
||||
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
|
||||
fi
|
||||
fi
|
||||
|
||||
# For Darwin, add options to specify how the application appears in the dock
|
||||
if $darwin; then
|
||||
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
|
||||
fi
|
||||
|
||||
# For Cygwin, switch paths to Windows format before running java
|
||||
if $cygwin ; then
|
||||
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
||||
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
||||
JAVACMD=`cygpath --unix "$JAVACMD"`
|
||||
|
||||
# We build the pattern for arguments to be converted via cygpath
|
||||
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
|
||||
SEP=""
|
||||
for dir in $ROOTDIRSRAW ; do
|
||||
ROOTDIRS="$ROOTDIRS$SEP$dir"
|
||||
SEP="|"
|
||||
done
|
||||
OURCYGPATTERN="(^($ROOTDIRS))"
|
||||
# Add a user-defined pattern to the cygpath arguments
|
||||
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
|
||||
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
|
||||
fi
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
i=0
|
||||
for arg in "$@" ; do
|
||||
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
|
||||
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
|
||||
|
||||
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
|
||||
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
|
||||
else
|
||||
eval `echo args$i`="\"$arg\""
|
||||
fi
|
||||
i=$((i+1))
|
||||
done
|
||||
case $i in
|
||||
(0) set -- ;;
|
||||
(1) set -- "$args0" ;;
|
||||
(2) set -- "$args0" "$args1" ;;
|
||||
(3) set -- "$args0" "$args1" "$args2" ;;
|
||||
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
|
||||
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
|
||||
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
|
||||
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
|
||||
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
|
||||
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# Escape application args
|
||||
save () {
|
||||
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
|
||||
echo " "
|
||||
}
|
||||
APP_ARGS=$(save "$@")
|
||||
|
||||
# Collect all arguments for the java command, following the shell quoting and substitution rules
|
||||
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
|
||||
|
||||
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
|
||||
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
|
||||
cd "$(dirname "$0")"
|
||||
fi
|
||||
|
||||
exec "$JAVACMD" "$@"
|
||||
84
android/gradlew.bat
vendored
Normal file
84
android/gradlew.bat
vendored
Normal file
@@ -0,0 +1,84 @@
|
||||
@if "%DEBUG%" == "" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@rem Gradle startup script for Windows
|
||||
@rem
|
||||
@rem ##########################################################################
|
||||
|
||||
@rem Set local scope for the variables with windows NT shell
|
||||
if "%OS%"=="Windows_NT" setlocal
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%" == "" set DIRNAME=.
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
set DEFAULT_JVM_OPTS=
|
||||
|
||||
@rem Find java.exe
|
||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if "%ERRORLEVEL%" == "0" goto init
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:findJavaFromJavaHome
|
||||
set JAVA_HOME=%JAVA_HOME:"=%
|
||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||
|
||||
if exist "%JAVA_EXE%" goto init
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:init
|
||||
@rem Get command-line arguments, handling Windows variants
|
||||
|
||||
if not "%OS%" == "Windows_NT" goto win9xME_args
|
||||
|
||||
:win9xME_args
|
||||
@rem Slurp the command line arguments.
|
||||
set CMD_LINE_ARGS=
|
||||
set _SKIP=2
|
||||
|
||||
:win9xME_args_slurp
|
||||
if "x%~1" == "x" goto execute
|
||||
|
||||
set CMD_LINE_ARGS=%*
|
||||
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if "%ERRORLEVEL%"=="0" goto mainEnd
|
||||
|
||||
:fail
|
||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||
rem the _cmd.exe /c_ return code!
|
||||
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
|
||||
exit /b 1
|
||||
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
||||
|
||||
:omega
|
||||
3
android/jni/Android.mk
Executable file → Normal file
3
android/jni/Android.mk
Executable file → Normal file
@@ -39,6 +39,7 @@ LOCAL_SRC_FILES := src/idl_parser.cpp \
|
||||
src/util.cpp \
|
||||
src/code_generators.cpp
|
||||
LOCAL_STATIC_LIBRARIES := flatbuffers
|
||||
LOCAL_ARM_MODE := arm
|
||||
include $(BUILD_STATIC_LIBRARY)
|
||||
|
||||
# FlatBuffers test
|
||||
@@ -48,7 +49,7 @@ LOCAL_SRC_FILES := android/jni/main.cpp \
|
||||
tests/test.cpp \
|
||||
src/idl_gen_fbs.cpp \
|
||||
src/idl_gen_general.cpp
|
||||
LOCAL_LDLIBS := -llog -landroid
|
||||
LOCAL_LDLIBS := -llog -landroid -latomic
|
||||
LOCAL_STATIC_LIBRARIES := android_native_app_glue flatbuffers_extra
|
||||
LOCAL_ARM_MODE := arm
|
||||
include $(BUILD_SHARED_LIBRARY)
|
||||
|
||||
6
android/jni/Application.mk
Executable file → Normal file
6
android/jni/Application.mk
Executable file → Normal file
@@ -13,10 +13,8 @@
|
||||
# 2. Altered source versions must be plainly marked as such, and must not be
|
||||
# misrepresented as being the original software.
|
||||
# 3. This notice may not be removed or altered from any source distribution.
|
||||
APP_PLATFORM := android-10
|
||||
APP_PLATFORM := android-9
|
||||
APP_PROJECT_PATH := $(call my-dir)/..
|
||||
APP_STL := gnustl_static
|
||||
|
||||
APP_STL ?= stlport_static
|
||||
APP_ABI := armeabi-v7a
|
||||
|
||||
APP_CPPFLAGS += -std=c++11
|
||||
|
||||
0
android/jni/build_flatc.bat
Executable file → Normal file
0
android/jni/build_flatc.bat
Executable file → Normal file
0
android/res/values/strings.xml
Executable file → Normal file
0
android/res/values/strings.xml
Executable file → Normal file
51
appveyor.yml
51
appveyor.yml
@@ -4,6 +4,17 @@ branches:
|
||||
|
||||
os: Visual Studio 2015
|
||||
|
||||
environment:
|
||||
|
||||
global:
|
||||
# Workaround for https://github.com/conda/conda-build/issues/636
|
||||
PYTHONIOENCODING: UTF-8
|
||||
CONDA_INSTALL_LOCN: "C:\\Miniconda35-x64"
|
||||
|
||||
matrix:
|
||||
- CMAKE_VS_VERSION: "10 2010"
|
||||
- CMAKE_VS_VERSION: "14 2015"
|
||||
|
||||
platform:
|
||||
- x86
|
||||
- x64
|
||||
@@ -13,7 +24,7 @@ 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"
|
||||
|
||||
@@ -21,17 +32,41 @@ build:
|
||||
project: ALL_BUILD.vcxproj
|
||||
verbosity: minimal
|
||||
|
||||
install:
|
||||
- set PATH=%CONDA_INSTALL_LOCN%;%CONDA_INSTALL_LOCN%\scripts;%PATH%;
|
||||
|
||||
test_script:
|
||||
- rem "---------------- C++ -----------------"
|
||||
- "%CONFIGURATION%\\flattests.exe"
|
||||
- rem "---------------- Java -----------------"
|
||||
- "cd tests"
|
||||
- rem "Building all code"
|
||||
- generate_code.bat -b %CONFIGURATION%
|
||||
- 7z a GeneratedMyGameCode.zip MyGame\
|
||||
- rem "---------------- C++ -----------------"
|
||||
- "cd .."
|
||||
- "%CONFIGURATION%\\flattests.exe"
|
||||
- "cd tests"
|
||||
- rem "---------------- Java -----------------"
|
||||
- "java -version"
|
||||
- "JavaTest.bat"
|
||||
- rem "---------------- JS -----------------"
|
||||
- "node --version"
|
||||
- "..\\%CONFIGURATION%\\flatc -b monster_test.fbs unicode_test.json"
|
||||
- "node JavaScriptTest"
|
||||
- "..\\%CONFIGURATION%\\flatc -b -I include_test monster_test.fbs unicode_test.json"
|
||||
- "node JavaScriptTest ./monster_test_generated"
|
||||
- rem "-------------- Python ---------------"
|
||||
- where python
|
||||
- python --version
|
||||
- where pip
|
||||
- pip --version
|
||||
- where conda
|
||||
- conda --version
|
||||
- rem "installing flatbuffers python library"
|
||||
- pip install ../python
|
||||
- rem "testing without installing Numpy"
|
||||
- python py_test.py 0 0 0
|
||||
- rem "testing after installing Numpy - disabled"
|
||||
# FIXME: This has a LOT of unnecessary dependencies and makes the tests fail
|
||||
# with timeouts.
|
||||
# - conda install --yes numpy
|
||||
# - python py_test.py 0 0 0
|
||||
- rem "---------------- C# -----------------"
|
||||
# Have to compile this here rather than in "build" above because AppVeyor only
|
||||
# supports building one project??
|
||||
@@ -42,5 +77,7 @@ test_script:
|
||||
- "cd ..\\.."
|
||||
|
||||
artifacts:
|
||||
- path: $(CONFIGURATION)\\flatc.exe
|
||||
- path: $(CONFIGURATION)\flatc.exe
|
||||
name: flatc.exe
|
||||
- path: tests\GeneratedMyGameCode.zip
|
||||
name: GeneratedMyGameCode.zip
|
||||
|
||||
0
docs/footer.html
Executable file → Normal file
0
docs/footer.html
Executable file → Normal file
2
docs/source/Benchmarks.md
Executable file → Normal file
2
docs/source/Benchmarks.md
Executable file → Normal file
@@ -1,4 +1,4 @@
|
||||
Benchmarks {#flatbuffers_benchmarks}
|
||||
C++ Benchmarks {#flatbuffers_benchmarks}
|
||||
==========
|
||||
|
||||
Comparing against other serialization solutions, running on Windows 7
|
||||
|
||||
0
docs/source/Building.md
Executable file → Normal file
0
docs/source/Building.md
Executable file → Normal file
@@ -1 +1 @@
|
||||
../../CONTRIBUTING
|
||||
../../CONTRIBUTING.md
|
||||
7
docs/source/Compiler.md
Executable file → Normal file
7
docs/source/Compiler.md
Executable file → Normal file
@@ -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.
|
||||
|
||||
@@ -123,5 +123,10 @@ Additional options:
|
||||
- `--include-prefix PATH` : Prefix this path to any generated include
|
||||
statements.
|
||||
|
||||
- `--keep-prefix` : Keep original prefix of schema include statement.
|
||||
|
||||
- `--reflect-types` : Add minimal type reflection to code generation.
|
||||
- `--reflect-names` : Add minimal type/name reflection.
|
||||
|
||||
NOTE: short-form options for generators are deprecated, use the long form
|
||||
whenever possible.
|
||||
|
||||
51
docs/source/CppUsage.md
Executable file → Normal file
51
docs/source/CppUsage.md
Executable file → Normal file
@@ -200,6 +200,15 @@ pointer type (`my_ptr<T>`), or by specifying `naked` as the type to get `T *`
|
||||
pointers. Unlike the smart pointers, naked pointers do not manage memory for
|
||||
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
|
||||
@@ -222,6 +231,30 @@ schema, as well as a lot of helper functions.
|
||||
And example of usage, for the time being, can be found in
|
||||
`test.cpp/ReflectionTest()`.
|
||||
|
||||
## Mini Reflection
|
||||
|
||||
A more limited form of reflection is available for direct inclusion in
|
||||
generated code, which doesn't any (binary) schema access at all. It was designed
|
||||
to keep the overhead of reflection as low as possible (on the order of 2-6
|
||||
bytes per field added to your executable), but doesn't contain all the
|
||||
information the (binary) schema contains.
|
||||
|
||||
You add this information to your generated code by specifying `--reflect-types`
|
||||
(or instead `--reflect-names` if you also want field / enum names).
|
||||
|
||||
You can now use this information, for example to print a FlatBuffer to text:
|
||||
|
||||
auto s = flatbuffers::FlatBufferToString(flatbuf, MonsterTypeTable());
|
||||
|
||||
`MonsterTypeTable()` is declared in the generated code for each type. The
|
||||
string produced is very similar to the JSON produced by the `Parser` based
|
||||
text generator.
|
||||
|
||||
You'll need `flatbuffers/minireflect.h` for this functionality. In there is also
|
||||
a convenient visitor/iterator so you can write your own output / functionality
|
||||
based on the mini reflection tables without having to know the FlatBuffers or
|
||||
reflection encoding.
|
||||
|
||||
## Storing maps / dictionaries in a FlatBuffer
|
||||
|
||||
FlatBuffers doesn't support maps natively, but there is support to
|
||||
@@ -402,4 +435,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>
|
||||
|
||||
@@ -128,6 +128,16 @@ A description of how FlexBuffers are encoded is in the
|
||||
[internals](@ref flatbuffers_internals) 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
|
||||
|
||||
25
docs/source/Grammar.md
Executable file → Normal file
25
docs/source/Grammar.md
Executable file → Normal file
@@ -4,7 +4,7 @@ Grammar of the schema language {#flatbuffers_grammar}
|
||||
schema = include*
|
||||
( namespace\_decl | type\_decl | enum\_decl | root\_decl |
|
||||
file_extension_decl | file_identifier_decl |
|
||||
attribute\_decl | object )*
|
||||
attribute\_decl | rpc\_decl | object )*
|
||||
|
||||
include = `include` string\_constant `;`
|
||||
|
||||
@@ -14,16 +14,22 @@ attribute\_decl = `attribute` string\_constant `;`
|
||||
|
||||
type\_decl = ( `table` | `struct` ) ident metadata `{` field\_decl+ `}`
|
||||
|
||||
enum\_decl = ( `enum` | `union` ) ident [ `:` type ] metadata `{` commasep(
|
||||
enumval\_decl ) `}`
|
||||
enum\_decl = ( `enum` ident [ `:` type ] | `union` ident ) metadata `{`
|
||||
commasep( enumval\_decl ) `}`
|
||||
|
||||
root\_decl = `root_type` ident `;`
|
||||
|
||||
field\_decl = ident `:` type [ `=` scalar ] metadata `;`
|
||||
|
||||
rpc\_decl = `rpc_service` ident `{` rpc\_method+ `}`
|
||||
|
||||
rpc\_method = ident `(` ident `)` `:` ident metadata `;`
|
||||
|
||||
type = `bool` | `byte` | `ubyte` | `short` | `ushort` | `int` | `uint` |
|
||||
`float` | `long` | `ulong` | `double`
|
||||
| `string` | `[` type `]` | ident
|
||||
`float` | `long` | `ulong` | `double` |
|
||||
`int8` | `uint8` | `int16` | `uint16` | `int32` | `uint32`| `int64` | `uint64` |
|
||||
`float32` | `float64` |
|
||||
`string` | `[` type `]` | ident
|
||||
|
||||
enumval\_decl = ident [ `=` integer\_constant ]
|
||||
|
||||
@@ -43,6 +49,11 @@ file_extension_decl = `file_extension` string\_constant `;`
|
||||
|
||||
file_identifier_decl = `file_identifier` string\_constant `;`
|
||||
|
||||
integer\_constant = -?[0-9]+ | `true` | `false`
|
||||
integer\_constant = `-?[0-9]+` | `true` | `false`
|
||||
|
||||
float\_constant = `-?[0-9]+.[0-9]+((e|E)(+|-)?[0-9]+)?`
|
||||
|
||||
string\_constant = `\".*?\"`
|
||||
|
||||
ident = `[a-zA-Z_][a-zA-Z0-9_]*`
|
||||
|
||||
float\_constant = -?[0-9]+.[0-9]+((e|E)(+|-)?[0-9]+)?
|
||||
|
||||
22
docs/source/Internals.md
Executable file → Normal file
22
docs/source/Internals.md
Executable file → Normal file
@@ -292,6 +292,12 @@ 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.
|
||||
|
||||
### Additional reading.
|
||||
|
||||
The author of the C language implementation has made a similar
|
||||
[document](https://github.com/dvidelabs/flatcc/blob/master/doc/binary-format.md#flatbuffers-binary-format)
|
||||
that may further help clarify the format.
|
||||
|
||||
# FlexBuffers
|
||||
|
||||
The [schema-less](@ref flexbuffers) version of FlatBuffers have their
|
||||
@@ -368,6 +374,10 @@ 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.
|
||||
|
||||
### Booleans and Nulls
|
||||
|
||||
Booleans (`TYPE_BOOL`) and nulls (`TYPE_NULL`) are encoded as inlined unsigned integers.
|
||||
|
||||
### Blobs, Strings and Keys.
|
||||
|
||||
A blob (`TYPE_BLOB`) is encoded similar to a vector, with one difference: the
|
||||
@@ -408,19 +418,19 @@ 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.
|
||||
allow it to be treated as its own individual 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
|
||||
0 : uint8_t 'b', 'a', 'r', 0
|
||||
4 : uint8_t 'f', 'o', 'o', 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
|
||||
9 : uint8_t 9, 6 // offsets to bar_key and foo_key
|
||||
11: uint8_t 2, 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
|
||||
14: uint8_t 14, 13 // values
|
||||
16: uint8_t 4, 4 // types
|
||||
|
||||
### The root
|
||||
|
||||
19
docs/source/JavaCsharpUsage.md
Executable file → Normal file
19
docs/source/JavaCsharpUsage.md
Executable file → Normal file
@@ -139,7 +139,7 @@ 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
|
||||
- Designate one of the fields in a table as the "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.
|
||||
@@ -147,19 +147,20 @@ To use it:
|
||||
array.
|
||||
- Instead of calling standard generated method,
|
||||
e.g.: `Monster.createTestarrayoftablesVector`,
|
||||
call `CreateMySortedVectorOfTables` in C# or
|
||||
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 `LookupByKey`
|
||||
to access elements of the vector, e.g.:
|
||||
`Monster.lookupByKey(tablesVectorOffset, "Frodo", dataBuffer)`,
|
||||
- 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.
|
||||
`LookupByKey` performs a binary search, so should have a similar speed to
|
||||
`Dictionary`, though may be faster because of better caching. `LookupByKey`
|
||||
only works if the vector has been sorted, it will likely not find elements
|
||||
if it hasn't been sorted.
|
||||
`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
|
||||
|
||||
|
||||
0
docs/source/JavaScriptUsage.md
Executable file → Normal file
0
docs/source/JavaScriptUsage.md
Executable file → Normal file
27
docs/source/PythonUsage.md
Executable file → Normal file
27
docs/source/PythonUsage.md
Executable file → Normal file
@@ -64,6 +64,33 @@ Now you can access values like this:
|
||||
pos = monster.Pos()
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
## Support for Numpy arrays
|
||||
|
||||
The Flatbuffers python library also has support for accessing scalar
|
||||
vectors as numpy arrays. This can be orders of magnitude faster than
|
||||
iterating over the vector one element at a time, and is particularly
|
||||
useful when unpacking large nested flatbuffers. The generated code for
|
||||
a scalar vector will have a method `<vector name>AsNumpy()`. In the
|
||||
case of the Monster example, you could access the inventory vector
|
||||
like this:
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.py}
|
||||
inventory = monster.InventoryAsNumpy()
|
||||
# inventory is a numpy array of type np.dtype('uint8')
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
instead of
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.py}
|
||||
inventory = []
|
||||
for i in range(monster.InventoryLength()):
|
||||
inventory.append(int(monster.Inventory(i)))
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Numpy is not a requirement. If numpy is not installed on your system,
|
||||
then attempting to access one of the `*asNumpy()` methods will result
|
||||
in a `NumpyRequiredForThisFeature` exception.
|
||||
|
||||
## Text Parsing
|
||||
|
||||
There currently is no support for parsing text (Schema's and JSON) directly
|
||||
|
||||
27
docs/source/Schemas.md
Executable file → Normal file
27
docs/source/Schemas.md
Executable file → Normal file
@@ -84,15 +84,19 @@ parent object, and use no virtual table).
|
||||
|
||||
### Types
|
||||
|
||||
Built-in scalar types are:
|
||||
Built-in scalar types are
|
||||
|
||||
- 8 bit: `byte`, `ubyte`, `bool`
|
||||
- 8 bit: `byte` (`int8`), `ubyte` (`uint8`), `bool`
|
||||
|
||||
- 16 bit: `short`, `ushort`
|
||||
- 16 bit: `short` (`int16`), `ushort` (`uint16`)
|
||||
|
||||
- 32 bit: `int`, `uint`, `float`
|
||||
- 32 bit: `int` (`int32`), `uint` (`uint32`), `float` (`float32`)
|
||||
|
||||
- 64 bit: `long`, `ulong`, `double`
|
||||
- 64 bit: `long` (`int64`), `ulong` (`uint64`), `double` (`float64`)
|
||||
|
||||
The type names in parentheses are alias names such that for example
|
||||
`uint8` can be used in place of `ubyte`, and `int32` can be used in
|
||||
place of `int` without affecting code generation.
|
||||
|
||||
Built-in non-scalar types:
|
||||
|
||||
@@ -278,7 +282,10 @@ Current understood attributes:
|
||||
IDs allow the fields to be placed in any order in the schema.
|
||||
When a new field is added to the schema it must use the next available ID.
|
||||
- `deprecated` (on a field): do not generate accessors for this field
|
||||
anymore, code should stop using this data.
|
||||
anymore, code should stop using this data. Old data may still contain this
|
||||
field, but it won't be accessible anymore by newer code. Note that if you
|
||||
deprecate a field that was previous required, old code may fail to validate
|
||||
new data (when using the optional verifier).
|
||||
- `required` (on a non-scalar table field): this field must always be set.
|
||||
By default, all fields are optional, i.e. may be left out. This is
|
||||
desirable, as it helps with forwards/backwards compatibility, and
|
||||
@@ -288,7 +295,10 @@ Current understood attributes:
|
||||
constructs FlatBuffers to ensure this field is initialized, so the reading
|
||||
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.
|
||||
the verifier will fail on buffers that have missing required fields. Note
|
||||
that if you add this attribute to an existing field, this will only be
|
||||
valid if existing data always contains this field / existing code always
|
||||
writes this field.
|
||||
- `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
|
||||
@@ -302,6 +312,9 @@ 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.
|
||||
|
||||
0
docs/source/Support.md
Executable file → Normal file
0
docs/source/Support.md
Executable file → Normal file
@@ -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 {
|
||||
@@ -209,12 +210,21 @@ The `Weapon` table is a sub-table used within our FlatBuffer. It is
|
||||
used twice: once within the `Monster` table and once within the `Equipment`
|
||||
enum. For our `Monster`, it is used to populate a `vector of tables` via the
|
||||
`weapons` field within our `Monster`. It is also the only table referenced by
|
||||
the `Equipment` enum.
|
||||
the `Equipment` union.
|
||||
|
||||
The last part of the `schema` is the `root_type`. The root type declares what
|
||||
will be the root table for the serialized data. In our case, the root type is
|
||||
our `Monster` table.
|
||||
|
||||
The scalar types can also use alias type names such as `int16` instead
|
||||
of `short` and `float32` instead of `float`. Thus we could also write
|
||||
the `Weapon` table as:
|
||||
|
||||
table Weapon {
|
||||
name:string;
|
||||
damage:int16;
|
||||
}
|
||||
|
||||
#### More Information About Schemas
|
||||
|
||||
You can find a complete guide to writing `schema` files in the
|
||||
@@ -603,7 +613,7 @@ traversal. This is generally easy to do on any tree structures.
|
||||
|
||||
// Create a `vector` representing the inventory of the Orc. Each number
|
||||
// could correspond to an item that can be claimed after he is slain.
|
||||
unsigned char treasure = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
|
||||
unsigned char treasure[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
|
||||
auto inventory = builder.CreateVector(treasure, 10);
|
||||
~~~
|
||||
</div>
|
||||
@@ -709,6 +719,10 @@ adding fields to our monster.
|
||||
other `vector`s), collect their offsets into a temporary data structure, and
|
||||
then create an additional `vector` containing their offsets.*
|
||||
|
||||
If instead of creating a vector from an existing array you serialize elements
|
||||
individually one by one, take care to note that this happens in reverse order,
|
||||
as buffers are built back to front.
|
||||
|
||||
For example, take a look at the two `Weapon`s that we created earlier (`Sword`
|
||||
and `Axe`). These are both FlatBuffer `table`s, whose offsets we now store in
|
||||
memory. Therefore we can create a FlatBuffer `vector` to contain these
|
||||
@@ -799,6 +813,70 @@ elements by calling a lambda. For the common case of `std::vector<std::string>`
|
||||
there's also `CreateVectorOfStrings`.
|
||||
</div>
|
||||
|
||||
Note that vectors of structs are serialized differently from tables, since
|
||||
structs are stored in-line in the vector. For example, to create a vector
|
||||
for the `path` field above:
|
||||
|
||||
<div class="language-cpp">
|
||||
~~~{.cpp}
|
||||
Vec3 points[] = { Vec3(1.0f, 2.0f, 3.0f), Vec3(4.0f, 5.0f, 6.0f) };
|
||||
auto path = builder.CreateVectorOfStructs(points, 2);
|
||||
~~~
|
||||
</div>
|
||||
<div class="language-java">
|
||||
~~~{.java}
|
||||
Monster.startPathVector(fbb, 2);
|
||||
Vec3.createVec3(builder, 1.0f, 2.0f, 3.0f);
|
||||
Vec3.createVec3(builder, 4.0f, 5.0f, 6.0f);
|
||||
int path = fbb.endVector();
|
||||
~~~
|
||||
</div>
|
||||
<div class="language-csharp">
|
||||
~~~{.cs}
|
||||
Monster.StartPathVector(fbb, 2);
|
||||
Vec3.CreateVec3(builder, 1.0f, 2.0f, 3.0f);
|
||||
Vec3.CreateVec3(builder, 4.0f, 5.0f, 6.0f);
|
||||
var path = fbb.EndVector();
|
||||
~~~
|
||||
</div>
|
||||
<div class="language-go">
|
||||
~~~{.go}
|
||||
sample.MonsterStartPathVector(builder, 2)
|
||||
sample.CreateVec3(builder, 1.0, 2.0, 3.0)
|
||||
sample.CreateVec3(builder, 4.0, 5.0, 6.0)
|
||||
path := builder.EndVector(2)
|
||||
~~~
|
||||
</div>
|
||||
<div class="language-python">
|
||||
~~~{.py}
|
||||
MyGame.Sample.Monster.MonsterStartPathVector(builder, 2)
|
||||
MyGame.Sample.Vec3.CreateVec3(builder, 1.0, 2.0, 3.0)
|
||||
MyGame.Sample.Vec3.CreateVec3(builder, 4.0, 5.0, 6.0)
|
||||
path = builder.EndVector(2)
|
||||
~~~
|
||||
</div>
|
||||
<div class="language-javascript">
|
||||
~~~{.js}
|
||||
MyGame.Sample.Monster.startPathVector(builder, 2);
|
||||
MyGame.Sample.Vec3.createVec3(builder, 1.0, 2.0, 3.0);
|
||||
MyGame.Sample.Vec3.createVec3(builder, 4.0, 5.0, 6.0);
|
||||
var path = builder.endVector();
|
||||
~~~
|
||||
</div>
|
||||
<div class="language-php">
|
||||
~~~{.php}
|
||||
\MyGame\Example\Monster::StartPathVector($builder, 2);
|
||||
\MyGame\Sample\Vec3::CreateVec3($builder, 1.0, 2.0, 3.0);
|
||||
\MyGame\Sample\Vec3::CreateVec3($builder, 1.0, 2.0, 3.0);
|
||||
$path = $builder->endVector();
|
||||
~~~
|
||||
</div>
|
||||
<div class="language-c">
|
||||
~~~{.c}
|
||||
// TBD
|
||||
~~~
|
||||
</div>
|
||||
|
||||
We have now serialized the non-scalar components of the orc, so we
|
||||
can serialize the monster itself:
|
||||
|
||||
@@ -812,7 +890,7 @@ can serialize the monster itself:
|
||||
// to set all fields.
|
||||
auto orc = CreateMonster(builder, Vec3(1.0f, 2.0f, 3.0f), mana, hp, name,
|
||||
inventory, Color_Red, weapons, Equipment_Weapon,
|
||||
axe.Union());
|
||||
axe.Union(), path);
|
||||
~~~
|
||||
</div>
|
||||
<div class="language-java">
|
||||
@@ -827,6 +905,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>
|
||||
@@ -842,6 +921,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>
|
||||
@@ -857,6 +937,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>
|
||||
@@ -875,6 +956,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>
|
||||
@@ -891,6 +973,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>
|
||||
@@ -907,6 +990,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>
|
||||
@@ -921,7 +1005,7 @@ can serialize the monster itself:
|
||||
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>
|
||||
|
||||
@@ -929,10 +1013,10 @@ Note how we create `Vec3` struct in-line in the table. Unlike tables, structs
|
||||
are simple combinations of scalars that are always stored inline, just like
|
||||
scalars themselves.
|
||||
|
||||
**Important**: you should not nest tables or any other objects, which is why
|
||||
we created all the strings/vectors/tables that this monster refers to before
|
||||
`start`. If you try to create any of them between `start` and `end`, you
|
||||
will get an assert/exception/panic depending on your language.
|
||||
**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
|
||||
@@ -953,13 +1037,14 @@ a bit more flexibility.
|
||||
// manually.
|
||||
MonsterBuilder monster_builder(builder);
|
||||
monster_builder.add_pos(&pos);
|
||||
auto pos = Vec3(1.0f, 2.0f, 3.0f);
|
||||
monster_builder.add_hp(hp);
|
||||
monster_builder.add_name(name);
|
||||
monster_builder.add_inventory(inventory);
|
||||
monster_builder.add_color(Color_Red);
|
||||
monster_builder.add_weapons(weapons);
|
||||
monster_builder.add_equipped_type(Equipment_Weapon);
|
||||
monster_builder.add_equpped(axe);
|
||||
monster_builder.add_equpped(axe.Union());
|
||||
auto orc = monster_builder.Finish();
|
||||
~~~
|
||||
</div>
|
||||
@@ -1091,7 +1176,7 @@ appropriate `finish` method.
|
||||
<div class="language-javascript">
|
||||
~~~{.js}
|
||||
// Call `finish()` to instruct the builder that this monster is complete.
|
||||
builder.finish(orc); // You could also call `MyGame.Example.Monster.finishMonsterBuffer(builder,
|
||||
builder.finish(orc); // You could also call `MyGame.Sample.Monster.finishMonsterBuffer(builder,
|
||||
// orc);`.
|
||||
~~~
|
||||
</div>
|
||||
@@ -1309,6 +1394,8 @@ won't work**
|
||||
|
||||
// `monster` is of type `Monster *`.
|
||||
// Note: root object pointers are NOT the same as `buffer_pointer`.
|
||||
// `GetMonster` is a convenience function that calls `GetRoot<Monster>`,
|
||||
// the latter is also available for non-root types.
|
||||
~~~
|
||||
</div>
|
||||
<div class="language-java">
|
||||
@@ -1470,10 +1557,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">
|
||||
@@ -1547,7 +1634,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">
|
||||
@@ -1604,8 +1691,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">
|
||||
@@ -1687,8 +1774,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
|
||||
|
||||
0
docs/source/WhitePaper.md
Executable file → Normal file
0
docs/source/WhitePaper.md
Executable file → Normal file
7
docs/source/doxyfile
Executable file → Normal file
7
docs/source/doxyfile
Executable file → Normal file
@@ -765,6 +765,7 @@ INPUT = "FlatBuffers.md" \
|
||||
"../../CONTRIBUTING.md" \
|
||||
"Tutorial.md" \
|
||||
"GoApi.md" \
|
||||
"gRPC/CppUsage.md" \
|
||||
"groups" \
|
||||
"../../java/com/google/flatbuffers" \
|
||||
"../../python/flatbuffers/builder.py" \
|
||||
@@ -883,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
|
||||
|
||||
@@ -39,6 +39,10 @@
|
||||
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
|
||||
@@ -110,6 +110,11 @@ func (b *Builder) WriteVtable() (n UOffsetT) {
|
||||
objectOffset := b.Offset()
|
||||
existingVtable := UOffsetT(0)
|
||||
|
||||
// Trim vtable of trailing zeroes.
|
||||
i := len(b.vtable) - 1;
|
||||
for ; i >= 0 && b.vtable[i] == 0; i-- {}
|
||||
b.vtable = b.vtable[:i + 1];
|
||||
|
||||
// Search backwards through existing vtables, because similar vtables
|
||||
// are likely to have been recently appended. See
|
||||
// BenchmarkVtableDeduplication for a case in which this heuristic
|
||||
|
||||
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,8 +41,20 @@
|
||||
#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
|
||||
#endif
|
||||
|
||||
namespace grpc {
|
||||
|
||||
typedef GRPC_CUSTOM_STRING string;
|
||||
|
||||
} // namespace grpc
|
||||
|
||||
namespace grpc_cpp_generator {
|
||||
|
||||
// Contains all the parameters that are parsed from the command line.
|
||||
@@ -53,31 +65,73 @@ struct Parameters {
|
||||
bool use_system_headers;
|
||||
// Prefix to any grpc include
|
||||
grpc::string grpc_search_path;
|
||||
// Generate GMOCK code to facilitate unit testing.
|
||||
bool generate_mock_code;
|
||||
};
|
||||
|
||||
// Return the prologue of the generated header file.
|
||||
grpc::string GetHeaderPrologue(grpc_generator::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(grpc_generator::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(grpc_generator::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(grpc_generator::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(grpc_generator::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(grpc_generator::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(grpc_generator::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(grpc_generator::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
|
||||
|
||||
|
||||
@@ -44,6 +44,14 @@ grpc::string as_string(T 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
|
||||
@@ -70,8 +78,8 @@ void GenerateImports(grpc_generator::File *file, grpc_generator::Printer *printe
|
||||
printer->Print("//If you make any local changes, they will be lost\n");
|
||||
printer->Print(vars, "//source: $filename$\n\n");
|
||||
printer->Print(vars, "package $Package$\n\n");
|
||||
if (file->additional_imports() != "") {
|
||||
printer->Print(file->additional_imports().c_str());
|
||||
if (file->additional_headers() != "") {
|
||||
printer->Print(file->additional_headers().c_str());
|
||||
printer->Print("\n\n");
|
||||
}
|
||||
printer->Print("import (\n");
|
||||
@@ -86,11 +94,11 @@ void GenerateImports(grpc_generator::File *file, grpc_generator::Printer *printe
|
||||
void GenerateServerMethodSignature(const grpc_generator::Method *method, grpc_generator::Printer *printer,
|
||||
std::map<grpc::string, grpc::string> vars) {
|
||||
vars["Method"] = exportName(method->name());
|
||||
vars["Request"] = method->input_name();
|
||||
vars["Response"] = (vars["CustomMethodIO"] == "") ? method->output_name() : vars["CustomMethodIO"];
|
||||
vars["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 (method->ServerOnlyStreaming()) {
|
||||
} else if (ServerOnlyStreaming(method)) {
|
||||
printer->Print(vars, "$Method$(*$Request$, $Service$_$Method$Server) error");
|
||||
} else {
|
||||
printer->Print(vars, "$Method$($Service$_$Method$Server) error");
|
||||
@@ -100,8 +108,8 @@ void GenerateServerMethodSignature(const grpc_generator::Method *method, grpc_ge
|
||||
void GenerateServerMethod(const grpc_generator::Method *method, grpc_generator::Printer *printer,
|
||||
std::map<grpc::string, grpc::string> vars) {
|
||||
vars["Method"] = exportName(method->name());
|
||||
vars["Request"] = method->input_name();
|
||||
vars["Response"] = (vars["CustomMethodIO"] == "") ? method->output_name() : vars["CustomMethodIO"];
|
||||
vars["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()) {
|
||||
@@ -129,7 +137,7 @@ void GenerateServerMethod(const grpc_generator::Method *method, grpc_generator::
|
||||
vars["StreamType"] = vars["ServiceUnexported"] + vars["Method"] + "Server";
|
||||
printer->Print(vars, "func $Handler$(srv interface{}, stream $grpc$.ServerStream) error {\n");
|
||||
printer->Indent();
|
||||
if (method->ServerOnlyStreaming()) {
|
||||
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");
|
||||
@@ -139,9 +147,9 @@ void GenerateServerMethod(const grpc_generator::Method *method, grpc_generator::
|
||||
printer->Outdent();
|
||||
printer->Print("}\n\n");
|
||||
|
||||
bool genSend = method->BidiStreaming() || method->ServerOnlyStreaming();
|
||||
bool genRecv = method->BidiStreaming() || method->ClientOnlyStreaming();
|
||||
bool genSendAndClose = method->ClientOnlyStreaming();
|
||||
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();
|
||||
@@ -194,12 +202,12 @@ void GenerateServerMethod(const grpc_generator::Method *method, grpc_generator::
|
||||
void GenerateClientMethodSignature(const grpc_generator::Method *method, grpc_generator::Printer *printer,
|
||||
std::map<grpc::string, grpc::string> vars) {
|
||||
vars["Method"] = exportName(method->name());
|
||||
vars["Request"] = ", in *" + ((vars["CustomMethodIO"] == "") ? method->input_name() : vars["CustomMethodIO"]);
|
||||
if (method->ClientOnlyStreaming() || method->BidiStreaming()) {
|
||||
vars["Request"] = ", in *" + ((vars["CustomMethodIO"] == "") ? method->get_input_type_name() : vars["CustomMethodIO"]);
|
||||
if (ClientOnlyStreaming(method) || method->BidiStreaming()) {
|
||||
vars["Request"] = "";
|
||||
}
|
||||
vars["Response"] = "* " + method->output_name();
|
||||
if (method->ClientOnlyStreaming() || method->BidiStreaming() || method->ServerOnlyStreaming()) {
|
||||
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)");
|
||||
@@ -213,8 +221,8 @@ void GenerateClientMethod(const grpc_generator::Method *method, grpc_generator::
|
||||
printer->Print(" {\n");
|
||||
printer->Indent();
|
||||
vars["Method"] = exportName(method->name());
|
||||
vars["Request"] = (vars["CustomMethodIO"] == "") ? method->input_name() : vars["CustomMethodIO"];
|
||||
vars["Response"] = method->output_name();
|
||||
vars["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");
|
||||
@@ -230,7 +238,7 @@ void GenerateClientMethod(const grpc_generator::Method *method, grpc_generator::
|
||||
printer->Print("if err != nil { return nil, err }\n");
|
||||
|
||||
printer->Print(vars, "x := &$StreamType${stream}\n");
|
||||
if (method->ServerOnlyStreaming()) {
|
||||
if (ServerOnlyStreaming(method)) {
|
||||
printer->Print("if err := x.ClientStream.SendMsg(in); err != nil { return nil, err }\n");
|
||||
printer->Print("if err := x.ClientStream.CloseSend(); err != nil { return nil, err }\n");
|
||||
}
|
||||
@@ -238,9 +246,9 @@ void GenerateClientMethod(const grpc_generator::Method *method, grpc_generator::
|
||||
printer->Outdent();
|
||||
printer->Print("}\n\n");
|
||||
|
||||
bool genSend = method->BidiStreaming() || method->ClientOnlyStreaming();
|
||||
bool genRecv = method->BidiStreaming() || method->ServerOnlyStreaming();
|
||||
bool genCloseAndRecv = method->ClientOnlyStreaming();
|
||||
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");
|
||||
@@ -396,9 +404,9 @@ void GenerateService(const grpc_generator::Service *service, grpc_generator::Pri
|
||||
printer->Indent();
|
||||
printer->Print(vars, "StreamName: \"$Method$\",\n");
|
||||
printer->Print(vars, "Handler: $Handler$, \n");
|
||||
if (method->ClientOnlyStreaming()) {
|
||||
if (ClientOnlyStreaming(method.get())) {
|
||||
printer->Print("ClientStreams: true,\n");
|
||||
} else if (method->ServerOnlyStreaming()) {
|
||||
} else if (ServerOnlyStreaming(method.get())) {
|
||||
printer->Print("ServerStreams: true,\n");
|
||||
} else {
|
||||
printer->Print("ServerStreams: true,\n");
|
||||
|
||||
@@ -43,12 +43,12 @@
|
||||
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;
|
||||
//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;
|
||||
//Package name for the service
|
||||
grpc::string package_name;
|
||||
};
|
||||
|
||||
// Return the source of the generated service file.
|
||||
|
||||
@@ -34,79 +34,93 @@
|
||||
#ifndef GRPC_INTERNAL_COMPILER_SCHEMA_INTERFACE_H
|
||||
#define GRPC_INTERNAL_COMPILER_SCHEMA_INTERFACE_H
|
||||
|
||||
#include <map>
|
||||
#include "src/compiler/config.h"
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#ifndef GRPC_CUSTOM_STRING
|
||||
#include <string>
|
||||
#define GRPC_CUSTOM_STRING std::string
|
||||
#endif
|
||||
#ifndef GRPC_CUSTOM_STRING
|
||||
#include <string>
|
||||
#define GRPC_CUSTOM_STRING std::string
|
||||
#endif
|
||||
|
||||
namespace grpc {
|
||||
|
||||
typedef GRPC_CUSTOM_STRING string;
|
||||
typedef GRPC_CUSTOM_STRING string;
|
||||
|
||||
} // namespace grpc
|
||||
|
||||
namespace grpc_generator {
|
||||
|
||||
// An abstract interface representing a method.
|
||||
struct Method {
|
||||
virtual ~Method() {}
|
||||
// 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;
|
||||
};
|
||||
|
||||
virtual grpc::string name() const = 0;
|
||||
// An abstract interface representing a method.
|
||||
struct Method : public CommentHolder {
|
||||
virtual ~Method() {}
|
||||
|
||||
virtual grpc::string input_type_name() const = 0;
|
||||
virtual grpc::string output_type_name() const = 0;
|
||||
virtual grpc::string input_name() const = 0;
|
||||
virtual grpc::string output_name() const = 0;
|
||||
virtual grpc::string name() const = 0;
|
||||
|
||||
virtual bool NoStreaming() const = 0;
|
||||
virtual bool ClientOnlyStreaming() const = 0;
|
||||
virtual bool ServerOnlyStreaming() const = 0;
|
||||
virtual bool BidiStreaming() const = 0;
|
||||
};
|
||||
virtual grpc::string input_type_name() const = 0;
|
||||
virtual grpc::string output_type_name() const = 0;
|
||||
|
||||
// An abstract interface representing a service.
|
||||
struct Service {
|
||||
virtual ~Service() {}
|
||||
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 name() const = 0;
|
||||
virtual grpc::string get_input_type_name() const = 0;
|
||||
virtual grpc::string get_output_type_name() const = 0;
|
||||
virtual bool NoStreaming() const = 0;
|
||||
virtual bool ClientStreaming() const = 0;
|
||||
virtual bool ServerStreaming() const = 0;
|
||||
virtual bool BidiStreaming() const = 0;
|
||||
};
|
||||
|
||||
virtual int method_count() const = 0;
|
||||
virtual std::unique_ptr<const Method> method(int i) const = 0;
|
||||
};
|
||||
// An abstract interface representing a service.
|
||||
struct Service : public CommentHolder {
|
||||
virtual ~Service() {}
|
||||
|
||||
struct Printer {
|
||||
virtual ~Printer() {}
|
||||
virtual grpc::string name() const = 0;
|
||||
|
||||
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;
|
||||
};
|
||||
virtual int method_count() const = 0;
|
||||
virtual std::unique_ptr<const Method> method(int i) const = 0;
|
||||
};
|
||||
|
||||
// An interface that allows the source generated to be output using various
|
||||
// libraries/idls/serializers.
|
||||
struct File {
|
||||
virtual ~File() {}
|
||||
struct Printer {
|
||||
virtual ~Printer() {}
|
||||
|
||||
virtual grpc::string filename() const = 0;
|
||||
virtual grpc::string filename_without_ext() const = 0;
|
||||
virtual grpc::string message_header_ext() const = 0;
|
||||
virtual grpc::string service_header_ext() const = 0;
|
||||
virtual grpc::string package() const = 0;
|
||||
virtual std::vector<grpc::string> package_parts() const = 0;
|
||||
virtual grpc::string additional_headers() const = 0;
|
||||
virtual grpc::string additional_imports() const = 0;
|
||||
virtual 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;
|
||||
};
|
||||
|
||||
virtual int service_count() const = 0;
|
||||
virtual std::unique_ptr<const Service> service(int i) const = 0;
|
||||
// An interface that allows the source generated to be output using various
|
||||
// libraries/idls/serializers.
|
||||
struct File : public CommentHolder {
|
||||
virtual ~File() {}
|
||||
|
||||
virtual std::unique_ptr<Printer> CreatePrinter(grpc::string *str) const = 0;
|
||||
};
|
||||
} // namespace grpc_generator
|
||||
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
|
||||
|
||||
@@ -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,
|
||||
::grpc::ServerWriter< flatbuffers::BufferRef<Monster>>* writer)
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
233
include/flatbuffers/base.h
Normal file
233
include/flatbuffers/base.h
Normal file
@@ -0,0 +1,233 @@
|
||||
#ifndef FLATBUFFERS_BASE_H_
|
||||
#define FLATBUFFERS_BASE_H_
|
||||
|
||||
#if defined(FLATBUFFERS_MEMORY_LEAK_TRACKING) && \
|
||||
defined(_MSC_VER) && defined(_DEBUG)
|
||||
#define _CRTDBG_MAP_ALLOC
|
||||
#endif
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#ifndef ARDUINO
|
||||
#include <cstdint>
|
||||
#endif
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
|
||||
#if defined(FLATBUFFERS_MEMORY_LEAK_TRACKING) && \
|
||||
defined(_MSC_VER) && defined(_DEBUG)
|
||||
#include <crtdbg.h>
|
||||
#define DEBUG_NEW new(_NORMAL_BLOCK, __FILE__, __LINE__)
|
||||
#define new DEBUG_NEW
|
||||
#endif
|
||||
|
||||
#if defined(ARDUINO) && !defined(ARDUINOSTL_M_H)
|
||||
#include <utility.h>
|
||||
#else
|
||||
#include <utility>
|
||||
#endif
|
||||
|
||||
#include <string>
|
||||
#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
|
||||
|
||||
#include "flatbuffers/stl_emulation.h"
|
||||
|
||||
/// @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 8
|
||||
#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 EndianSwap(T t) {
|
||||
#if defined(_MSC_VER)
|
||||
#define FLATBUFFERS_BYTESWAP16 _byteswap_ushort
|
||||
#define FLATBUFFERS_BYTESWAP32 _byteswap_ulong
|
||||
#define FLATBUFFERS_BYTESWAP64 _byteswap_uint64
|
||||
#else
|
||||
#if defined(__GNUC__) && __GNUC__ * 100 + __GNUC_MINOR__ < 408 && !defined(__clang__)
|
||||
// __builtin_bswap16 was missing prior to GCC 4.8.
|
||||
#define FLATBUFFERS_BYTESWAP16(x) \
|
||||
static_cast<uint16_t>(__builtin_bswap32(static_cast<uint32_t>(x) << 16))
|
||||
#else
|
||||
#define FLATBUFFERS_BYTESWAP16 __builtin_bswap16
|
||||
#endif
|
||||
#define FLATBUFFERS_BYTESWAP32 __builtin_bswap32
|
||||
#define FLATBUFFERS_BYTESWAP64 __builtin_bswap64
|
||||
#endif
|
||||
if (sizeof(T) == 1) { // Compile-time if-then's.
|
||||
return t;
|
||||
} else if (sizeof(T) == 2) {
|
||||
union { T t; uint16_t i; } u;
|
||||
u.t = t;
|
||||
u.i = FLATBUFFERS_BYTESWAP16(u.i);
|
||||
return u.t;
|
||||
} else if (sizeof(T) == 4) {
|
||||
union { T t; uint32_t i; } u;
|
||||
u.t = t;
|
||||
u.i = FLATBUFFERS_BYTESWAP32(u.i);
|
||||
return u.t;
|
||||
} else if (sizeof(T) == 8) {
|
||||
union { T t; uint64_t i; } u;
|
||||
u.t = t;
|
||||
u.i = FLATBUFFERS_BYTESWAP64(u.i);
|
||||
return u.t;
|
||||
} else {
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
} // namespace flatbuffers
|
||||
#endif // FLATBUFFERS_BASE_H_
|
||||
@@ -95,8 +95,6 @@ class BaseGenerator {
|
||||
|
||||
static const char *FlatBuffersGeneratedWarning();
|
||||
|
||||
bool IsEverythingGenerated() const;
|
||||
|
||||
static std::string FullNamespace(const char *separator, const Namespace &ns);
|
||||
|
||||
static std::string LastNamespacePart(const Namespace &ns);
|
||||
@@ -114,6 +112,8 @@ class BaseGenerator {
|
||||
|
||||
std::string WrapInNameSpace(const Definition &def) const;
|
||||
|
||||
std::string GetNameSpace(const Definition &def) const;
|
||||
|
||||
const Parser &parser_;
|
||||
const std::string &path_;
|
||||
const std::string &file_name_;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -42,6 +42,7 @@ class FlatCompiler {
|
||||
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;
|
||||
|
||||
@@ -17,14 +17,21 @@
|
||||
#ifndef FLATBUFFERS_FLEXBUFFERS_H_
|
||||
#define FLATBUFFERS_FLEXBUFFERS_H_
|
||||
|
||||
#include <map>
|
||||
// Used to select STL variant.
|
||||
#include "flatbuffers/base.h"
|
||||
// We use the basic binary writing functions from the regular FlatBuffers.
|
||||
#include "flatbuffers/flatbuffers.h"
|
||||
#include "flatbuffers/util.h"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#include <intrin.h>
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable: 4127) // C4127: conditional expression is constant
|
||||
#endif
|
||||
|
||||
namespace flexbuffers {
|
||||
|
||||
class Reference;
|
||||
@@ -69,23 +76,25 @@ enum Type {
|
||||
TYPE_VECTOR_UINT4 = 23,
|
||||
TYPE_VECTOR_FLOAT4 = 24,
|
||||
TYPE_BLOB = 25,
|
||||
TYPE_BOOL = 26,
|
||||
TYPE_VECTOR_BOOL = 36, // To Allow the same type of conversion of type to vector type
|
||||
};
|
||||
|
||||
inline bool IsInline(Type t) { return t <= TYPE_FLOAT; }
|
||||
inline bool IsInline(Type t) { return t <= TYPE_FLOAT || t == TYPE_BOOL; }
|
||||
|
||||
inline bool IsTypedVectorElementType(Type t) {
|
||||
return t >= TYPE_INT && t <= TYPE_STRING;
|
||||
return (t >= TYPE_INT && t <= TYPE_STRING) || t == TYPE_BOOL;
|
||||
}
|
||||
|
||||
inline bool IsTypedVector(Type t) {
|
||||
return t >= TYPE_VECTOR_INT && t <= TYPE_VECTOR_STRING;
|
||||
return (t >= TYPE_VECTOR_INT && t <= TYPE_VECTOR_STRING) || t == TYPE_VECTOR_BOOL;
|
||||
}
|
||||
|
||||
inline bool IsFixedTypedVector(Type t) {
|
||||
return t >= TYPE_VECTOR_INT2 && t <= TYPE_VECTOR_FLOAT4;
|
||||
}
|
||||
|
||||
inline Type ToTypedVector(Type t, int fixed_len = 0) {
|
||||
inline Type ToTypedVector(Type t, size_t fixed_len = 0) {
|
||||
assert(IsTypedVectorElementType(t));
|
||||
switch (fixed_len) {
|
||||
case 0: return static_cast<Type>(t - TYPE_INT + TYPE_VECTOR_INT);
|
||||
@@ -104,7 +113,7 @@ inline Type ToTypedVectorElementType(Type t) {
|
||||
inline Type ToFixedTypedVectorElementType(Type t, uint8_t *len) {
|
||||
assert(IsFixedTypedVector(t));
|
||||
auto fixed_type = t - TYPE_VECTOR_INT2;
|
||||
*len = fixed_type / 3 + 2; // 3 types each, starting from length 2.
|
||||
*len = static_cast<uint8_t>(fixed_type / 3 + 2); // 3 types each, starting from length 2.
|
||||
return static_cast<Type>(fixed_type % 3 + TYPE_INT);
|
||||
}
|
||||
|
||||
@@ -155,7 +164,7 @@ inline double ReadDouble(const uint8_t *data, uint8_t byte_width) {
|
||||
byte_width);
|
||||
}
|
||||
|
||||
const uint8_t *Indirect(const uint8_t *offset, uint8_t byte_width) {
|
||||
inline const uint8_t *Indirect(const uint8_t *offset, uint8_t byte_width) {
|
||||
return offset - ReadUInt64(offset, byte_width);
|
||||
}
|
||||
|
||||
@@ -163,7 +172,7 @@ template<typename T> const uint8_t *Indirect(const uint8_t *offset) {
|
||||
return offset - flatbuffers::ReadScalar<T>(offset);
|
||||
}
|
||||
|
||||
static BitWidth WidthU(uint64_t u) {
|
||||
inline BitWidth WidthU(uint64_t u) {
|
||||
#define FLATBUFFERS_GET_FIELD_BIT_WIDTH(value, width) { \
|
||||
if (!((u) & ~((1ULL << (width)) - 1ULL))) return BIT_WIDTH_##width; \
|
||||
}
|
||||
@@ -174,12 +183,12 @@ static BitWidth WidthU(uint64_t u) {
|
||||
return BIT_WIDTH_64;
|
||||
}
|
||||
|
||||
static BitWidth WidthI(int64_t i) {
|
||||
inline BitWidth WidthI(int64_t i) {
|
||||
auto u = static_cast<uint64_t>(i) << 1;
|
||||
return WidthU(i >= 0 ? u : ~u);
|
||||
}
|
||||
|
||||
static BitWidth WidthF(double f) {
|
||||
inline BitWidth WidthF(double f) {
|
||||
return static_cast<double>(static_cast<float>(f)) == f ? BIT_WIDTH_32
|
||||
: BIT_WIDTH_64;
|
||||
}
|
||||
@@ -212,6 +221,7 @@ class String : public Sized {
|
||||
|
||||
size_t length() const { return size(); }
|
||||
const char *c_str() const { return reinterpret_cast<const char *>(data_); }
|
||||
std::string str() const { return std::string(c_str(), length()); }
|
||||
|
||||
static String EmptyString() {
|
||||
static const uint8_t empty_string[] = { 0/*len*/, 0/*terminator*/ };
|
||||
@@ -222,14 +232,15 @@ class String : public Sized {
|
||||
|
||||
class Blob : public Sized {
|
||||
public:
|
||||
Blob(const uint8_t *data, uint8_t byte_width)
|
||||
: Sized(data, byte_width) {}
|
||||
Blob(const uint8_t *data_buf, uint8_t byte_width)
|
||||
: Sized(data_buf, byte_width) {}
|
||||
|
||||
static Blob EmptyBlob() {
|
||||
static const uint8_t empty_blob[] = { 0/*len*/ };
|
||||
return Blob(empty_blob + 1, 1);
|
||||
}
|
||||
bool IsTheEmptyBlob() const { return data_ == EmptyBlob().data_; }
|
||||
const uint8_t *data() const { return data_; }
|
||||
};
|
||||
|
||||
class Vector : public Sized {
|
||||
@@ -340,6 +351,7 @@ class Reference {
|
||||
Type GetType() const { return type_; }
|
||||
|
||||
bool IsNull() const { return type_ == TYPE_NULL; }
|
||||
bool IsBool() const { return type_ == TYPE_BOOL; }
|
||||
bool IsInt() const { return type_ == TYPE_INT ||
|
||||
type_ == TYPE_INDIRECT_INT; }
|
||||
bool IsUInt() const { return type_ == TYPE_UINT||
|
||||
@@ -352,6 +364,11 @@ class Reference {
|
||||
bool IsKey() const { return type_ == TYPE_KEY; }
|
||||
bool IsVector() const { return type_ == TYPE_VECTOR || type_ == TYPE_MAP; }
|
||||
bool IsMap() const { return type_ == TYPE_MAP; }
|
||||
bool IsBlob() const { return type_ == TYPE_BLOB; }
|
||||
|
||||
bool AsBool() const {
|
||||
return (type_ == TYPE_BOOL ? ReadUInt64(data_, parent_width_) : AsUInt64()) != 0;
|
||||
}
|
||||
|
||||
// Reads any type as a int64_t. Never fails, does most sensible conversion.
|
||||
// Truncates floats, strings are attempted to be parsed for a number,
|
||||
@@ -371,6 +388,7 @@ class Reference {
|
||||
case TYPE_NULL: return 0;
|
||||
case TYPE_STRING: return flatbuffers::StringToInt(AsString().c_str());
|
||||
case TYPE_VECTOR: return static_cast<int64_t>(AsVector().size());
|
||||
case TYPE_BOOL: return ReadInt64(data_, parent_width_);
|
||||
default:
|
||||
// Convert other things to int.
|
||||
return 0;
|
||||
@@ -398,6 +416,7 @@ class Reference {
|
||||
case TYPE_NULL: return 0;
|
||||
case TYPE_STRING: return flatbuffers::StringToUInt(AsString().c_str());
|
||||
case TYPE_VECTOR: return static_cast<uint64_t>(AsVector().size());
|
||||
case TYPE_BOOL: return ReadUInt64(data_, parent_width_);
|
||||
default:
|
||||
// Convert other things to uint.
|
||||
return 0;
|
||||
@@ -425,6 +444,8 @@ class Reference {
|
||||
case TYPE_NULL: return 0.0;
|
||||
case TYPE_STRING: return strtod(AsString().c_str(), nullptr);
|
||||
case TYPE_VECTOR: return static_cast<double>(AsVector().size());
|
||||
case TYPE_BOOL: return static_cast<double>(
|
||||
ReadUInt64(data_, parent_width_));
|
||||
default:
|
||||
// Convert strings and other things to float.
|
||||
return 0;
|
||||
@@ -451,25 +472,63 @@ class Reference {
|
||||
}
|
||||
|
||||
// Unlike AsString(), this will convert any type to a std::string.
|
||||
std::string ToString() const {
|
||||
std::string ToString() {
|
||||
std::string s;
|
||||
ToString(false, false, s);
|
||||
return s;
|
||||
}
|
||||
|
||||
// Convert any type to a JSON-like string. strings_quoted determines if
|
||||
// string values at the top level receive "" quotes (inside other values
|
||||
// they always do). keys_quoted determines if keys are quoted, at any level.
|
||||
// TODO(wvo): add further options to have indentation/newlines.
|
||||
void ToString(bool strings_quoted, bool keys_quoted, std::string &s) const {
|
||||
if (type_ == TYPE_STRING) {
|
||||
return String(Indirect(), byte_width_).c_str();
|
||||
String str(Indirect(), byte_width_);
|
||||
if (strings_quoted) {
|
||||
flatbuffers::EscapeString(str.c_str(), str.length(), &s, true);
|
||||
} else {
|
||||
s.append(str.c_str(), str.length());
|
||||
}
|
||||
} else if (IsKey()) {
|
||||
return AsKey();
|
||||
auto str = AsKey();
|
||||
if (keys_quoted) {
|
||||
flatbuffers::EscapeString(str, strlen(str), &s, true);
|
||||
} else {
|
||||
s += str;
|
||||
}
|
||||
} else if (IsInt()) {
|
||||
return flatbuffers::NumToString(AsInt64());
|
||||
s += flatbuffers::NumToString(AsInt64());
|
||||
} else if (IsUInt()) {
|
||||
return flatbuffers::NumToString(AsUInt64());
|
||||
s += flatbuffers::NumToString(AsUInt64());
|
||||
} else if (IsFloat()) {
|
||||
return flatbuffers::NumToString(AsDouble());
|
||||
s += flatbuffers::NumToString(AsDouble());
|
||||
} else if (IsNull()) {
|
||||
return "null";
|
||||
s += "null";
|
||||
} else if (IsBool()) {
|
||||
s += AsBool() ? "true" : "false";
|
||||
} else if (IsMap()) {
|
||||
return "{..}"; // TODO: show elements.
|
||||
s += "{ ";
|
||||
auto m = AsMap();
|
||||
auto keys = m.Keys();
|
||||
auto vals = m.Values();
|
||||
for (size_t i = 0; i < keys.size(); i++) {
|
||||
keys[i].ToString(true, keys_quoted, s);
|
||||
s += ": ";
|
||||
vals[i].ToString(true, keys_quoted, s);
|
||||
if (i < keys.size() - 1) s += ", ";
|
||||
}
|
||||
s += " }";
|
||||
} else if (IsVector()) {
|
||||
return "[..]"; // TODO: show elements.
|
||||
s += "[ ";
|
||||
auto v = AsVector();
|
||||
for (size_t i = 0; i < v.size(); i++) {
|
||||
v[i].ToString(true, keys_quoted, s);
|
||||
if (i < v.size() - 1) s += ", ";
|
||||
}
|
||||
s += " ]";
|
||||
} else {
|
||||
return "(?)";
|
||||
s += "(?)";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -520,6 +579,8 @@ class Reference {
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T> T As();
|
||||
|
||||
// Experimental: Mutation functions.
|
||||
// These allow scalars in an already created buffer to be updated in-place.
|
||||
// Since by default scalars are stored in the smallest possible space,
|
||||
@@ -542,6 +603,10 @@ class Reference {
|
||||
}
|
||||
}
|
||||
|
||||
bool MutateBool(bool b) {
|
||||
return type_ == TYPE_BOOL && Mutate(data_, b, parent_width_, BIT_WIDTH_8);
|
||||
}
|
||||
|
||||
bool MutateUInt(uint64_t u) {
|
||||
if (type_ == TYPE_UINT) {
|
||||
return Mutate(data_, u, parent_width_, WidthU(u));
|
||||
@@ -601,7 +666,7 @@ class Reference {
|
||||
|
||||
template<typename T> bool Mutate(const uint8_t *dest, T t, size_t byte_width,
|
||||
BitWidth value_width) {
|
||||
auto fits = (1U << value_width) <= byte_width;
|
||||
auto fits = static_cast<size_t>(static_cast<size_t>(1U) << value_width) <= byte_width;
|
||||
if (fits) {
|
||||
t = flatbuffers::EndianScalar(t);
|
||||
memcpy(const_cast<uint8_t *>(dest), &t, byte_width);
|
||||
@@ -625,6 +690,31 @@ class Reference {
|
||||
Type type_;
|
||||
};
|
||||
|
||||
// Template specialization for As().
|
||||
template<> inline bool Reference::As<bool>() { return AsBool(); }
|
||||
|
||||
template<> inline int8_t Reference::As<int8_t>() { return AsInt8(); }
|
||||
template<> inline int16_t Reference::As<int16_t>() { return AsInt16(); }
|
||||
template<> inline int32_t Reference::As<int32_t>() { return AsInt32(); }
|
||||
template<> inline int64_t Reference::As<int64_t>() { return AsInt64(); }
|
||||
|
||||
template<> inline uint8_t Reference::As<uint8_t>() { return AsUInt8(); }
|
||||
template<> inline uint16_t Reference::As<uint16_t>() { return AsUInt16(); }
|
||||
template<> inline uint32_t Reference::As<uint32_t>() { return AsUInt32(); }
|
||||
template<> inline uint64_t Reference::As<uint64_t>() { return AsUInt64(); }
|
||||
|
||||
template<> inline double Reference::As<double>() { return AsDouble(); }
|
||||
template<> inline float Reference::As<float>() { return AsFloat(); }
|
||||
|
||||
template<> inline String Reference::As<String>() { return AsString(); }
|
||||
template<> inline std::string Reference::As<std::string>() { return AsString().str(); }
|
||||
|
||||
template<> inline Blob Reference::As<Blob>() { return AsBlob(); }
|
||||
template<> inline Vector Reference::As<Vector>() { return AsVector(); }
|
||||
template<> inline TypedVector Reference::As<TypedVector>() { return AsTypedVector(); }
|
||||
template<> inline FixedTypedVector Reference::As<FixedTypedVector>() { return AsFixedTypedVector(); }
|
||||
template<> inline Map Reference::As<Map>() { return AsMap(); }
|
||||
|
||||
inline uint8_t PackedType(BitWidth bit_width, Type type) {
|
||||
return static_cast<uint8_t>(bit_width | (type << 2));
|
||||
}
|
||||
@@ -701,7 +791,7 @@ inline Reference GetRoot(const uint8_t *buffer, size_t size) {
|
||||
}
|
||||
|
||||
inline Reference GetRoot(const std::vector<uint8_t> &buffer) {
|
||||
return GetRoot(buffer.data(), buffer.size());
|
||||
return GetRoot(flatbuffers::vector_data(buffer), buffer.size());
|
||||
}
|
||||
|
||||
// Flags that configure how the Builder behaves.
|
||||
@@ -740,6 +830,22 @@ class Builder FLATBUFFERS_FINAL_CLASS {
|
||||
return buf_;
|
||||
}
|
||||
|
||||
// Size of the buffer. Does not include unfinished values.
|
||||
size_t GetSize() const {
|
||||
return buf_.size();
|
||||
}
|
||||
|
||||
// Reset all state so we can re-use the buffer.
|
||||
void Clear() {
|
||||
buf_.clear();
|
||||
stack_.clear();
|
||||
finished_ = false;
|
||||
// flags_ remains as-is;
|
||||
force_min_bit_width_ = BIT_WIDTH_8;
|
||||
key_pool.clear();
|
||||
string_pool.clear();
|
||||
}
|
||||
|
||||
// All value constructing functions below have two versions: one that
|
||||
// takes a key (for placement inside a map) and one that doesn't (for inside
|
||||
// vectors and elsewhere).
|
||||
@@ -759,7 +865,7 @@ class Builder FLATBUFFERS_FINAL_CLASS {
|
||||
void Double(double f) { stack_.push_back(Value(f)); }
|
||||
void Double(const char *key, double d) { Key(key); Double(d); }
|
||||
|
||||
void Bool(bool b) { Int(static_cast<int64_t>(b)); }
|
||||
void Bool(bool b) { stack_.push_back(Value(b)); }
|
||||
void Bool(const char *key, bool b) { Key(key); Bool(b); }
|
||||
|
||||
void IndirectInt(int64_t i) {
|
||||
@@ -860,7 +966,7 @@ class Builder FLATBUFFERS_FINAL_CLASS {
|
||||
return CreateBlob(data, len, 0, TYPE_BLOB);
|
||||
}
|
||||
size_t Blob(const std::vector<uint8_t> &v) {
|
||||
return CreateBlob(v.data(), v.size(), 0, TYPE_BLOB);
|
||||
return CreateBlob(flatbuffers::vector_data(v), v.size(), 0, TYPE_BLOB);
|
||||
}
|
||||
|
||||
// TODO(wvo): support all the FlexBuffer types (like flexbuffers::String),
|
||||
@@ -904,11 +1010,15 @@ class Builder FLATBUFFERS_FINAL_CLASS {
|
||||
// step automatically when appliccable, and encourage people to write in
|
||||
// sorted fashion.
|
||||
// std::sort is typically already a lot faster on sorted data though.
|
||||
auto dict = reinterpret_cast<TwoValue *>(stack_.data() + start);
|
||||
auto dict =
|
||||
reinterpret_cast<TwoValue *>(flatbuffers::vector_data(stack_) +
|
||||
start);
|
||||
std::sort(dict, dict + len,
|
||||
[&](const TwoValue &a, const TwoValue &b) -> bool {
|
||||
auto as = reinterpret_cast<const char *>(buf_.data() + a.key.u_);
|
||||
auto bs = reinterpret_cast<const char *>(buf_.data() + b.key.u_);
|
||||
auto as = reinterpret_cast<const char *>(
|
||||
flatbuffers::vector_data(buf_) + a.key.u_);
|
||||
auto bs = reinterpret_cast<const char *>(
|
||||
flatbuffers::vector_data(buf_) + b.key.u_);
|
||||
auto comp = strcmp(as, bs);
|
||||
// If this assertion hits, you've added two keys with the same value to
|
||||
// this map.
|
||||
@@ -933,13 +1043,25 @@ class Builder FLATBUFFERS_FINAL_CLASS {
|
||||
f();
|
||||
return EndVector(start, false, false);
|
||||
}
|
||||
template <typename F, typename T> size_t Vector(F f, T &state) {
|
||||
auto start = StartVector();
|
||||
f(state);
|
||||
return EndVector(start, false, false);
|
||||
}
|
||||
template<typename F> size_t Vector(const char *key, F f) {
|
||||
auto start = StartVector(key);
|
||||
f();
|
||||
return EndVector(start, false, false);
|
||||
}
|
||||
template <typename F, typename T> size_t Vector(const char *key, F f,
|
||||
T &state) {
|
||||
auto start = StartVector(key);
|
||||
f(state);
|
||||
return EndVector(start, false, false);
|
||||
}
|
||||
|
||||
template<typename T> void Vector(const T *elems, size_t len) {
|
||||
if (std::is_scalar<T>::value) {
|
||||
if (flatbuffers::is_scalar<T>::value) {
|
||||
// This path should be a lot quicker and use less space.
|
||||
ScalarVector(elems, len, false);
|
||||
} else {
|
||||
@@ -954,7 +1076,7 @@ class Builder FLATBUFFERS_FINAL_CLASS {
|
||||
Vector(elems, len);
|
||||
}
|
||||
template<typename T> void Vector(const std::vector<T> &vec) {
|
||||
Vector(vec.data(), vec.size());
|
||||
Vector(flatbuffers::vector_data(vec), vec.size());
|
||||
}
|
||||
|
||||
template<typename F> size_t TypedVector(F f) {
|
||||
@@ -962,18 +1084,29 @@ class Builder FLATBUFFERS_FINAL_CLASS {
|
||||
f();
|
||||
return EndVector(start, true, false);
|
||||
}
|
||||
template <typename F, typename T> size_t TypedVector(F f, T &state) {
|
||||
auto start = StartVector();
|
||||
f(state);
|
||||
return EndVector(start, true, false);
|
||||
}
|
||||
template<typename F> size_t TypedVector(const char *key, F f) {
|
||||
auto start = StartVector(key);
|
||||
f();
|
||||
return EndVector(start, true, false);
|
||||
}
|
||||
template <typename F, typename T> size_t TypedVector(const char *key, F f,
|
||||
T &state) {
|
||||
auto start = StartVector(key);
|
||||
f(state);
|
||||
return EndVector(start, true, false);
|
||||
}
|
||||
|
||||
template<typename T> size_t FixedTypedVector(const T *elems, size_t len) {
|
||||
// We only support a few fixed vector lengths. Anything bigger use a
|
||||
// regular typed vector.
|
||||
assert(len >= 2 && len <= 4);
|
||||
// And only scalar values.
|
||||
assert(std::is_scalar<T>::value);
|
||||
assert(flatbuffers::is_scalar<T>::value);
|
||||
return ScalarVector(elems, len, true);
|
||||
}
|
||||
|
||||
@@ -988,11 +1121,22 @@ class Builder FLATBUFFERS_FINAL_CLASS {
|
||||
f();
|
||||
return EndMap(start);
|
||||
}
|
||||
template <typename F, typename T> size_t Map(F f, T &state) {
|
||||
auto start = StartMap();
|
||||
f(state);
|
||||
return EndMap(start);
|
||||
}
|
||||
template<typename F> size_t Map(const char *key, F f) {
|
||||
auto start = StartMap(key);
|
||||
f();
|
||||
return EndMap(start);
|
||||
}
|
||||
template <typename F, typename T> size_t Map(const char *key, F f,
|
||||
T &state) {
|
||||
auto start = StartMap(key);
|
||||
f(state);
|
||||
return EndMap(start);
|
||||
}
|
||||
template<typename T> void Map(const std::map<std::string, T> &map) {
|
||||
auto start = StartMap();
|
||||
for (auto it = map.begin(); it != map.end(); ++it)
|
||||
@@ -1072,7 +1216,7 @@ class Builder FLATBUFFERS_FINAL_CLASS {
|
||||
auto byte_width = 1U << alignment;
|
||||
buf_.insert(buf_.end(), flatbuffers::PaddingBytes(buf_.size(), byte_width),
|
||||
0);
|
||||
return byte_width;
|
||||
return static_cast<uint8_t>(byte_width);
|
||||
}
|
||||
|
||||
void WriteBytes(const void *val, size_t size) {
|
||||
@@ -1081,8 +1225,8 @@ class Builder FLATBUFFERS_FINAL_CLASS {
|
||||
reinterpret_cast<const uint8_t *>(val) + size);
|
||||
}
|
||||
|
||||
// For values T >= byte_width
|
||||
template<typename T> void Write(T val, uint8_t byte_width) {
|
||||
template<typename T> void Write(T val, size_t byte_width) {
|
||||
assert(sizeof(T) >= byte_width);
|
||||
val = flatbuffers::EndianScalar(val);
|
||||
WriteBytes(&val, byte_width);
|
||||
}
|
||||
@@ -1121,10 +1265,11 @@ class Builder FLATBUFFERS_FINAL_CLASS {
|
||||
}
|
||||
|
||||
template<typename T> static Type GetScalarType() {
|
||||
assert(std::is_scalar<T>::value);
|
||||
return std::is_floating_point<T>::value
|
||||
assert(flatbuffers::is_scalar<T>::value);
|
||||
return flatbuffers::is_floating_point<T>::value
|
||||
? TYPE_FLOAT
|
||||
: (std::is_unsigned<T>::value ? TYPE_UINT : TYPE_INT);
|
||||
: flatbuffers::is_same<T, bool>::value ? TYPE_BOOL
|
||||
: (flatbuffers::is_unsigned<T>::value ? TYPE_UINT : TYPE_INT);
|
||||
}
|
||||
|
||||
struct Value {
|
||||
@@ -1141,6 +1286,8 @@ class Builder FLATBUFFERS_FINAL_CLASS {
|
||||
|
||||
Value() : i_(0), type_(TYPE_NULL), min_bit_width_(BIT_WIDTH_8) {}
|
||||
|
||||
Value(bool b) : u_(static_cast<uint64_t>(b)), type_(TYPE_BOOL), min_bit_width_(BIT_WIDTH_8) {}
|
||||
|
||||
Value(int64_t i, Type t, BitWidth bw)
|
||||
: i_(i), type_(t), min_bit_width_(bw) {}
|
||||
Value(uint64_t u, Type t, BitWidth bw)
|
||||
@@ -1176,7 +1323,8 @@ class Builder FLATBUFFERS_FINAL_CLASS {
|
||||
auto offset = offset_loc - u_;
|
||||
// Does it fit?
|
||||
auto bit_width = WidthU(offset);
|
||||
if (1U << bit_width == byte_width) return bit_width;
|
||||
if (static_cast<size_t>(static_cast<size_t>(1U) << bit_width) == byte_width)
|
||||
return bit_width;
|
||||
}
|
||||
assert(false); // Must match one of the sizes above.
|
||||
return BIT_WIDTH_64;
|
||||
@@ -1185,7 +1333,7 @@ class Builder FLATBUFFERS_FINAL_CLASS {
|
||||
|
||||
BitWidth StoredWidth(BitWidth parent_bit_width_ = BIT_WIDTH_8) const {
|
||||
if (IsInline(type_)) {
|
||||
return std::max(min_bit_width_, parent_bit_width_);
|
||||
return (std::max)(min_bit_width_, parent_bit_width_);
|
||||
} else {
|
||||
return min_bit_width_;
|
||||
}
|
||||
@@ -1198,6 +1346,7 @@ class Builder FLATBUFFERS_FINAL_CLASS {
|
||||
case TYPE_INT:
|
||||
Write(val.i_, byte_width);
|
||||
break;
|
||||
case TYPE_BOOL:
|
||||
case TYPE_UINT:
|
||||
Write(val.u_, byte_width);
|
||||
break;
|
||||
@@ -1231,7 +1380,7 @@ class Builder FLATBUFFERS_FINAL_CLASS {
|
||||
// TODO: instead of asserting, could write vector with larger elements
|
||||
// instead, though that would be wasteful.
|
||||
assert(WidthU(len) <= bit_width);
|
||||
if (!fixed) Write(len, byte_width);
|
||||
if (!fixed) Write<uint64_t>(len, byte_width);
|
||||
auto vloc = buf_.size();
|
||||
for (size_t i = 0; i < len; i++) Write(elems[i], byte_width);
|
||||
stack_.push_back(Value(static_cast<uint64_t>(vloc),
|
||||
@@ -1243,19 +1392,19 @@ class Builder FLATBUFFERS_FINAL_CLASS {
|
||||
Value CreateVector(size_t start, size_t vec_len, size_t step, bool typed,
|
||||
bool fixed, const Value *keys = nullptr) {
|
||||
// Figure out smallest bit width we can store this vector with.
|
||||
auto bit_width = std::max(force_min_bit_width_, WidthU(vec_len));
|
||||
auto bit_width = (std::max)(force_min_bit_width_, WidthU(vec_len));
|
||||
auto prefix_elems = 1;
|
||||
if (keys) {
|
||||
// If this vector is part of a map, we will pre-fix an offset to the keys
|
||||
// to this vector.
|
||||
bit_width = std::max(bit_width, keys->ElemWidth(buf_.size(), 0));
|
||||
bit_width = (std::max)(bit_width, keys->ElemWidth(buf_.size(), 0));
|
||||
prefix_elems += 2;
|
||||
}
|
||||
Type vector_type = TYPE_KEY;
|
||||
// Check bit widths and types for all elements.
|
||||
for (size_t i = start; i < stack_.size(); i += step) {
|
||||
auto elem_width = stack_[i].ElemWidth(buf_.size(), i + prefix_elems);
|
||||
bit_width = std::max(bit_width, elem_width);
|
||||
bit_width = (std::max)(bit_width, elem_width);
|
||||
if (typed) {
|
||||
if (i == start) {
|
||||
vector_type = stack_[i].type_;
|
||||
@@ -1273,9 +1422,9 @@ class Builder FLATBUFFERS_FINAL_CLASS {
|
||||
// Write vector. First the keys width/offset if available, and size.
|
||||
if (keys) {
|
||||
WriteOffset(keys->u_, byte_width);
|
||||
Write(1U << keys->min_bit_width_, byte_width);
|
||||
Write<uint64_t>(1ULL << keys->min_bit_width_, byte_width);
|
||||
}
|
||||
if (!fixed) Write(vec_len, byte_width);
|
||||
if (!fixed) Write<uint64_t>(vec_len, byte_width);
|
||||
// Then the actual data.
|
||||
auto vloc = buf_.size();
|
||||
for (size_t i = start; i < stack_.size(); i += step) {
|
||||
@@ -1310,9 +1459,11 @@ class Builder FLATBUFFERS_FINAL_CLASS {
|
||||
|
||||
struct KeyOffsetCompare {
|
||||
KeyOffsetCompare(const std::vector<uint8_t> &buf) : buf_(&buf) {}
|
||||
bool operator() (size_t a, size_t b) const {
|
||||
auto stra = reinterpret_cast<const char *>(buf_->data() + a);
|
||||
auto strb = reinterpret_cast<const char *>(buf_->data() + b);
|
||||
bool operator()(size_t a, size_t b) const {
|
||||
auto stra =
|
||||
reinterpret_cast<const char *>(flatbuffers::vector_data(*buf_) + a);
|
||||
auto strb =
|
||||
reinterpret_cast<const char *>(flatbuffers::vector_data(*buf_) + b);
|
||||
return strcmp(stra, strb) < 0;
|
||||
}
|
||||
const std::vector<uint8_t> *buf_;
|
||||
@@ -1321,10 +1472,12 @@ class Builder FLATBUFFERS_FINAL_CLASS {
|
||||
typedef std::pair<size_t, size_t> StringOffset;
|
||||
struct StringOffsetCompare {
|
||||
StringOffsetCompare(const std::vector<uint8_t> &buf) : buf_(&buf) {}
|
||||
bool operator() (const StringOffset &a, const StringOffset &b) const {
|
||||
auto stra = reinterpret_cast<const char *>(buf_->data() + a.first);
|
||||
auto strb = reinterpret_cast<const char *>(buf_->data() + b.first);
|
||||
return strncmp(stra, strb, std::min(a.second, b.second) + 1) < 0;
|
||||
bool operator()(const StringOffset &a, const StringOffset &b) const {
|
||||
auto stra = reinterpret_cast<const char *>(flatbuffers::vector_data(*buf_) +
|
||||
a.first);
|
||||
auto strb = reinterpret_cast<const char *>(flatbuffers::vector_data(*buf_) +
|
||||
b.first);
|
||||
return strncmp(stra, strb, (std::min)(a.second, b.second) + 1) < 0;
|
||||
}
|
||||
const std::vector<uint8_t> *buf_;
|
||||
};
|
||||
@@ -1338,4 +1491,8 @@ class Builder FLATBUFFERS_FINAL_CLASS {
|
||||
|
||||
} // namespace flexbuffers
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
#endif // FLATBUFFERS_FLEXBUFFERS_H_
|
||||
|
||||
@@ -19,49 +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.
|
||||
static grpc::Status Deserialize(grpc_byte_buffer *buffer, T *msg) {
|
||||
// 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);
|
||||
// Deserialize by pulling the
|
||||
static grpc::Status Deserialize(grpc_byte_buffer *buffer,
|
||||
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
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -20,11 +20,16 @@
|
||||
#include <map>
|
||||
#include <stack>
|
||||
#include <memory>
|
||||
#include <functional>
|
||||
|
||||
#include "flatbuffers/base.h"
|
||||
#include "flatbuffers/flatbuffers.h"
|
||||
#include "flatbuffers/hash.h"
|
||||
#include "flatbuffers/reflection.h"
|
||||
#include "flatbuffers/flexbuffers.h"
|
||||
|
||||
#if !defined(FLATBUFFERS_CPP98_STL)
|
||||
#include <functional>
|
||||
#endif // !defined(FLATBUFFERS_CPP98_STL)
|
||||
|
||||
// This file defines the data types representing a parsed IDL (Interface
|
||||
// Definition Language) / schema file.
|
||||
@@ -104,6 +109,7 @@ 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; }
|
||||
inline bool IsBool (BaseType t) { return t == BASE_TYPE_BOOL; }
|
||||
|
||||
extern const char *const kTypeNames[];
|
||||
extern const char kTypeSizes[];
|
||||
@@ -163,7 +169,7 @@ template<typename T> class SymbolTable {
|
||||
}
|
||||
|
||||
bool Add(const std::string &name, T *e) {
|
||||
vec.emplace_back(e);
|
||||
vector_emplace_back(&vec, e);
|
||||
auto it = dict.find(name);
|
||||
if (it != dict.end()) return true;
|
||||
dict[name] = e;
|
||||
@@ -193,7 +199,8 @@ template<typename T> class SymbolTable {
|
||||
|
||||
// A name space, as set in the schema.
|
||||
struct Namespace {
|
||||
std::vector<std::string> components;
|
||||
Namespace() : from_table(0) {}
|
||||
|
||||
|
||||
// Given a (potentally unqualified) name, return the "fully qualified" name
|
||||
// which has a full namespaced descriptor.
|
||||
@@ -201,12 +208,15 @@ struct Namespace {
|
||||
// the current namespace has.
|
||||
std::string GetFullyQualifiedName(const std::string &name,
|
||||
size_t max_components = 1000) const;
|
||||
|
||||
std::vector<std::string> components;
|
||||
size_t from_table; // Part of the namespace corresponds to a message/table.
|
||||
};
|
||||
|
||||
// Base class for all definition types (fields, structs_, enums_).
|
||||
struct Definition {
|
||||
Definition() : generated(false), defined_namespace(nullptr),
|
||||
serialized_location(0), index(-1) {}
|
||||
serialized_location(0), index(-1), refcount(1) {}
|
||||
|
||||
flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<
|
||||
reflection::KeyValue>>>
|
||||
@@ -223,21 +233,26 @@ struct Definition {
|
||||
// For use with Serialize()
|
||||
uoffset_t serialized_location;
|
||||
int index; // Inside the vector it is stored.
|
||||
int refcount;
|
||||
};
|
||||
|
||||
struct FieldDef : public Definition {
|
||||
FieldDef() : deprecated(false), required(false), key(false), padding(0) {}
|
||||
FieldDef() : deprecated(false), required(false), key(false),
|
||||
native_inline(false), flexbuffer(false), nested_flatbuffer(NULL),
|
||||
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.
|
||||
StructDef *nested_flatbuffer; // This field contains nested FlatBuffer data.
|
||||
size_t padding; // Bytes to always pad after this field.
|
||||
};
|
||||
|
||||
@@ -261,12 +276,15 @@ struct StructDef : public Definition {
|
||||
const Parser &parser) const;
|
||||
|
||||
SymbolTable<FieldDef> fields;
|
||||
|
||||
bool fixed; // If it's struct, not a table.
|
||||
bool predecl; // If it's used before it was defined.
|
||||
bool sortbysize; // Whether fields come in the declaration or size order.
|
||||
bool has_key; // It has a key field.
|
||||
size_t minalign; // What the whole object needs to be aligned to.
|
||||
size_t bytesize; // Size if fixed.
|
||||
|
||||
flatbuffers::unique_ptr<std::string> original_location;
|
||||
};
|
||||
|
||||
inline bool IsStruct(const Type &type) {
|
||||
@@ -283,18 +301,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 &&
|
||||
@@ -312,6 +330,7 @@ struct EnumDef : public Definition {
|
||||
|
||||
SymbolTable<EnumVal> vals;
|
||||
bool is_union;
|
||||
bool uses_type_aliases;
|
||||
Type underlying_type;
|
||||
};
|
||||
|
||||
@@ -350,13 +369,22 @@ struct IDLOptions {
|
||||
bool generate_all;
|
||||
bool skip_unexpected_fields_in_json;
|
||||
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 gen_nullable;
|
||||
std::string object_prefix;
|
||||
std::string object_suffix;
|
||||
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_import;
|
||||
std::string go_namespace;
|
||||
bool reexport_ts_modules;
|
||||
bool protobuf_ascii_alike;
|
||||
|
||||
// Possible options for the more general generator below.
|
||||
enum Language {
|
||||
@@ -369,11 +397,17 @@ struct IDLOptions {
|
||||
kPhp = 1 << 6,
|
||||
kJson = 1 << 7,
|
||||
kBinary = 1 << 8,
|
||||
kTs = 1 << 9,
|
||||
kJsonSchema = 1 << 10,
|
||||
kMAX
|
||||
};
|
||||
|
||||
Language lang;
|
||||
|
||||
enum MiniReflect { kNone, kTypes, kTypesAndNames };
|
||||
|
||||
MiniReflect mini_reflect;
|
||||
|
||||
// The corresponding language bit will be set if a language is included
|
||||
// for code generation.
|
||||
unsigned long lang_to_generate;
|
||||
@@ -392,13 +426,19 @@ struct IDLOptions {
|
||||
generate_all(false),
|
||||
skip_unexpected_fields_in_json(false),
|
||||
generate_name_strings(false),
|
||||
escape_proto_identifiers(false),
|
||||
generate_object_based_api(false),
|
||||
cpp_object_api_pointer_type("std::unique_ptr"),
|
||||
gen_nullable(false),
|
||||
object_suffix("T"),
|
||||
union_value_namespacing(true),
|
||||
allow_non_utf8(false),
|
||||
keep_include_path(false),
|
||||
binary_schema_comments(false),
|
||||
skip_flatbuffers_import(false),
|
||||
reexport_ts_modules(true),
|
||||
protobuf_ascii_alike(false),
|
||||
lang(IDLOptions::kJava),
|
||||
mini_reflect(IDLOptions::kNone),
|
||||
lang_to_generate(0) {}
|
||||
};
|
||||
|
||||
@@ -459,12 +499,17 @@ class CheckedError {
|
||||
class Parser : public ParserState {
|
||||
public:
|
||||
explicit Parser(const IDLOptions &options = IDLOptions())
|
||||
: root_struct_def_(nullptr),
|
||||
: current_namespace_(nullptr),
|
||||
empty_namespace_(nullptr),
|
||||
root_struct_def_(nullptr),
|
||||
opts(options),
|
||||
uses_flexbuffers_(false),
|
||||
source_(nullptr),
|
||||
anonymous_counter(0) {
|
||||
// Just in case none are declared:
|
||||
namespaces_.push_back(new Namespace());
|
||||
// Start out with the empty namespace being current.
|
||||
empty_namespace_ = new Namespace();
|
||||
namespaces_.push_back(empty_namespace_);
|
||||
current_namespace_ = empty_namespace_;
|
||||
known_attributes_["deprecated"] = true;
|
||||
known_attributes_["required"] = true;
|
||||
known_attributes_["key"] = true;
|
||||
@@ -479,9 +524,11 @@ class Parser : public ParserState {
|
||||
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() {
|
||||
@@ -499,6 +546,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);
|
||||
|
||||
@@ -521,14 +570,24 @@ 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);
|
||||
|
||||
StructDef *LookupStruct(const std::string &id) const;
|
||||
|
||||
private:
|
||||
void Message(const std::string &msg);
|
||||
void Warning(const std::string &msg);
|
||||
FLATBUFFERS_CHECKED_ERROR Error(const std::string &msg);
|
||||
FLATBUFFERS_CHECKED_ERROR ParseHexNum(int nibbles, uint64_t *val);
|
||||
FLATBUFFERS_CHECKED_ERROR Next();
|
||||
FLATBUFFERS_CHECKED_ERROR SkipByteOrderMark();
|
||||
bool Is(int t);
|
||||
bool IsIdent(const char *id);
|
||||
FLATBUFFERS_CHECKED_ERROR Expect(int t);
|
||||
std::string TokenToStringId(int t);
|
||||
EnumDef *LookupEnum(const std::string &id);
|
||||
@@ -540,18 +599,46 @@ 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);
|
||||
#if defined(FLATBUFFERS_CPP98_STL)
|
||||
typedef CheckedError (*ParseTableDelimitersBody)(
|
||||
const std::string &name, size_t &fieldn, const StructDef *struct_def,
|
||||
void *state);
|
||||
#else
|
||||
typedef std::function<CheckedError(const std::string&, size_t&,
|
||||
const StructDef*, void*)>
|
||||
ParseTableDelimitersBody;
|
||||
#endif // defined(FLATBUFFERS_CPP98_STL)
|
||||
FLATBUFFERS_CHECKED_ERROR ParseTableDelimiters(size_t &fieldn,
|
||||
const StructDef *struct_def,
|
||||
ParseTableDelimitersBody body,
|
||||
void *state);
|
||||
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);
|
||||
#if defined(FLATBUFFERS_CPP98_STL)
|
||||
typedef CheckedError (*ParseVectorDelimitersBody)(size_t &count,
|
||||
void *state);
|
||||
#else
|
||||
typedef std::function<CheckedError(size_t&, void*)>
|
||||
ParseVectorDelimitersBody;
|
||||
#endif // defined(FLATBUFFERS_CPP98_STL)
|
||||
FLATBUFFERS_CHECKED_ERROR ParseVectorDelimiters(
|
||||
size_t &count, ParseVectorDelimitersBody body, void *state);
|
||||
FLATBUFFERS_CHECKED_ERROR ParseVector(const Type &type, uoffset_t *ovalue);
|
||||
FLATBUFFERS_CHECKED_ERROR ParseNestedFlatbuffer(Value &val, FieldDef *field,
|
||||
size_t fieldn,
|
||||
const StructDef *parent_struct_def);
|
||||
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,
|
||||
@@ -571,23 +658,32 @@ 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 DoParse(const char *_source,
|
||||
FLATBUFFERS_CHECKED_ERROR ParseFlexBufferValue(flexbuffers::Builder *builder);
|
||||
FLATBUFFERS_CHECKED_ERROR StartParseFile(const char *source,
|
||||
const char *source_filename);
|
||||
FLATBUFFERS_CHECKED_ERROR ParseRoot(const char *_source,
|
||||
const char **include_paths,
|
||||
const char *source_filename);
|
||||
FLATBUFFERS_CHECKED_ERROR DoParse(const char *_source,
|
||||
const char **include_paths,
|
||||
const char *source_filename,
|
||||
const char *include_filename);
|
||||
FLATBUFFERS_CHECKED_ERROR CheckClash(std::vector<FieldDef*> &fields,
|
||||
StructDef *struct_def,
|
||||
const char *suffix,
|
||||
BaseType baseType);
|
||||
|
||||
bool SupportsVectorOfUnions() const;
|
||||
Namespace *UniqueNamespace(Namespace *ns);
|
||||
|
||||
public:
|
||||
SymbolTable<Type> types_;
|
||||
SymbolTable<StructDef> structs_;
|
||||
SymbolTable<EnumDef> enums_;
|
||||
SymbolTable<ServiceDef> services_;
|
||||
std::vector<Namespace *> namespaces_;
|
||||
Namespace *current_namespace_;
|
||||
Namespace *empty_namespace_;
|
||||
std::string error_; // User readable error_ if Parse() == false
|
||||
|
||||
FlatBufferBuilder builder_; // any data contained in the file
|
||||
@@ -595,13 +691,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_;
|
||||
@@ -647,7 +744,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,
|
||||
@@ -678,6 +775,12 @@ extern bool GeneratePython(const Parser &parser,
|
||||
const std::string &path,
|
||||
const std::string &file_name);
|
||||
|
||||
// Generate Json schema file
|
||||
// See idl_gen_json_schema.cpp.
|
||||
extern bool GenerateJsonSchema(const Parser &parser,
|
||||
const std::string &path,
|
||||
const std::string &file_name);
|
||||
|
||||
// Generate C# files from the definitions in the Parser object.
|
||||
// See idl_gen_csharp.cpp.
|
||||
extern bool GenerateCSharp(const Parser &parser,
|
||||
@@ -698,7 +801,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,
|
||||
@@ -743,4 +846,3 @@ bool GenerateGoGRPC(const Parser &parser,
|
||||
} // namespace flatbuffers
|
||||
|
||||
#endif // FLATBUFFERS_IDL_H_
|
||||
|
||||
|
||||
352
include/flatbuffers/minireflect.h
Normal file
352
include/flatbuffers/minireflect.h
Normal file
@@ -0,0 +1,352 @@
|
||||
/*
|
||||
* 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_MINIREFLECT_H_
|
||||
#define FLATBUFFERS_MINIREFLECT_H_
|
||||
|
||||
#include "flatbuffers/flatbuffers.h"
|
||||
#include "flatbuffers/util.h"
|
||||
|
||||
namespace flatbuffers {
|
||||
|
||||
// Utilities that can be used with the "mini reflection" tables present
|
||||
// in generated code with --reflect-types (only types) or --reflect-names
|
||||
// (also names).
|
||||
// This allows basic reflection functionality such as pretty-printing
|
||||
// that does not require the use of the schema parser or loading of binary
|
||||
// schema files at runtime (reflection.h).
|
||||
|
||||
// For any of the functions below that take `const TypeTable *`, you pass
|
||||
// `FooTypeTable()` if the type of the root is `Foo`.
|
||||
|
||||
// First, a generic iterator that can be used by multiple algorithms.
|
||||
|
||||
struct IterationVisitor {
|
||||
// These mark the scope of a table or struct.
|
||||
virtual void StartSequence() {}
|
||||
virtual void EndSequence() {}
|
||||
// Called for each field regardless of wether it is present or not.
|
||||
// If not present, val == nullptr. set_idx is the index of all set fields.
|
||||
virtual void Field(size_t /*field_idx*/, size_t /*set_idx*/,
|
||||
ElementaryType /*type*/, bool /*is_vector*/,
|
||||
const TypeTable * /*type_table*/, const char * /*name*/,
|
||||
const uint8_t * /*val*/) {}
|
||||
// Called for a value that is actually present, after a field, or as part
|
||||
// of a vector.
|
||||
virtual void UType(uint8_t, const char *) {}
|
||||
virtual void Bool(bool) {}
|
||||
virtual void Char(int8_t, const char *) {}
|
||||
virtual void UChar(uint8_t, const char *) {}
|
||||
virtual void Short(int16_t, const char *) {}
|
||||
virtual void UShort(uint16_t, const char *) {}
|
||||
virtual void Int(int32_t, const char *) {}
|
||||
virtual void UInt(uint32_t, const char *) {}
|
||||
virtual void Long(int64_t) {}
|
||||
virtual void ULong(uint64_t) {}
|
||||
virtual void Float(float) {}
|
||||
virtual void Double(double) {}
|
||||
virtual void String(const String *) {}
|
||||
virtual void Unknown(const uint8_t *) {} // From a future version.
|
||||
// These mark the scope of a vector.
|
||||
virtual void StartVector() {}
|
||||
virtual void EndVector() {}
|
||||
virtual void Element(size_t /*i*/, ElementaryType /*type*/,
|
||||
const TypeTable * /*type_table*/,
|
||||
const uint8_t * /*val*/)
|
||||
{}
|
||||
virtual ~IterationVisitor() {}
|
||||
};
|
||||
|
||||
inline size_t InlineSize(ElementaryType type, const TypeTable *type_table) {
|
||||
switch (type) {
|
||||
case ET_UTYPE:
|
||||
case ET_BOOL:
|
||||
case ET_CHAR:
|
||||
case ET_UCHAR:
|
||||
return 1;
|
||||
case ET_SHORT:
|
||||
case ET_USHORT:
|
||||
return 2;
|
||||
case ET_INT:
|
||||
case ET_UINT:
|
||||
case ET_FLOAT:
|
||||
case ET_STRING:
|
||||
return 4;
|
||||
case ET_LONG:
|
||||
case ET_ULONG:
|
||||
case ET_DOUBLE:
|
||||
return 8;
|
||||
case ET_SEQUENCE:
|
||||
switch (type_table->st) {
|
||||
case ST_TABLE:
|
||||
case ST_UNION:
|
||||
return 4;
|
||||
case ST_STRUCT:
|
||||
return type_table->values[type_table->num_elems];
|
||||
default:
|
||||
assert(false);
|
||||
return 1;
|
||||
}
|
||||
default:
|
||||
assert(false);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
inline int32_t LookupEnum(int32_t enum_val, const int32_t *values,
|
||||
size_t num_values) {
|
||||
if (!values) return enum_val;
|
||||
for (size_t i = 0; i < num_values; i++) {
|
||||
if (enum_val == values[i]) return static_cast<int32_t>(i);
|
||||
}
|
||||
return -1; // Unknown enum value.
|
||||
}
|
||||
|
||||
template<typename T> const char *EnumName(T tval, const TypeTable *type_table) {
|
||||
if (!type_table || !type_table->names) return nullptr;
|
||||
auto i = LookupEnum(static_cast<int32_t>(tval), type_table->values,
|
||||
type_table->num_elems);
|
||||
if (i >= 0 && i < static_cast<int32_t>(type_table->num_elems)) {
|
||||
return type_table->names[i];
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void IterateObject(const uint8_t *obj, const TypeTable *type_table,
|
||||
IterationVisitor *visitor);
|
||||
|
||||
inline void IterateValue(ElementaryType type, const uint8_t *val,
|
||||
const TypeTable *type_table,
|
||||
const uint8_t *prev_val,
|
||||
soffset_t vector_index,
|
||||
IterationVisitor *visitor) {
|
||||
switch (type) {
|
||||
case ET_UTYPE: {
|
||||
auto tval = *reinterpret_cast<const uint8_t *>(val);
|
||||
visitor->UType(tval, EnumName(tval, type_table));
|
||||
break;
|
||||
}
|
||||
case ET_BOOL: {
|
||||
visitor->Bool(*reinterpret_cast<const uint8_t *>(val) != 0);
|
||||
break;
|
||||
}
|
||||
case ET_CHAR: {
|
||||
auto tval = *reinterpret_cast<const int8_t *>(val);
|
||||
visitor->Char(tval, EnumName(tval, type_table));
|
||||
break;
|
||||
}
|
||||
case ET_UCHAR: {
|
||||
auto tval = *reinterpret_cast<const uint8_t *>(val);
|
||||
visitor->UChar(tval, EnumName(tval, type_table));
|
||||
break;
|
||||
}
|
||||
case ET_SHORT: {
|
||||
auto tval = *reinterpret_cast<const int16_t *>(val);
|
||||
visitor->Short(tval, EnumName(tval, type_table));
|
||||
break;
|
||||
}
|
||||
case ET_USHORT: {
|
||||
auto tval = *reinterpret_cast<const uint16_t *>(val);
|
||||
visitor->UShort(tval, EnumName(tval, type_table));
|
||||
break;
|
||||
}
|
||||
case ET_INT: {
|
||||
auto tval = *reinterpret_cast<const int32_t *>(val);
|
||||
visitor->Int(tval, EnumName(tval, type_table));
|
||||
break;
|
||||
}
|
||||
case ET_UINT: {
|
||||
auto tval = *reinterpret_cast<const uint32_t *>(val);
|
||||
visitor->UInt(tval, EnumName(tval, type_table));
|
||||
break;
|
||||
}
|
||||
case ET_LONG: {
|
||||
visitor->Long(*reinterpret_cast<const int64_t *>(val));
|
||||
break;
|
||||
}
|
||||
case ET_ULONG: {
|
||||
visitor->ULong(*reinterpret_cast<const uint64_t *>(val));
|
||||
break;
|
||||
}
|
||||
case ET_FLOAT: {
|
||||
visitor->Float(*reinterpret_cast<const float *>(val));
|
||||
break;
|
||||
}
|
||||
case ET_DOUBLE: {
|
||||
visitor->Double(*reinterpret_cast<const double *>(val));
|
||||
break;
|
||||
}
|
||||
case ET_STRING: {
|
||||
val += ReadScalar<uoffset_t>(val);
|
||||
visitor->String(reinterpret_cast<const String *>(val));
|
||||
break;
|
||||
}
|
||||
case ET_SEQUENCE: {
|
||||
switch (type_table->st) {
|
||||
case ST_TABLE:
|
||||
val += ReadScalar<uoffset_t>(val);
|
||||
IterateObject(val, type_table, visitor);
|
||||
break;
|
||||
case ST_STRUCT:
|
||||
IterateObject(val, type_table, visitor);
|
||||
break;
|
||||
case ST_UNION: {
|
||||
val += ReadScalar<uoffset_t>(val);
|
||||
assert(prev_val);
|
||||
auto union_type = *prev_val; // Always a uint8_t.
|
||||
if (vector_index >= 0) {
|
||||
auto type_vec = reinterpret_cast<const Vector<uint8_t> *>(prev_val);
|
||||
union_type = type_vec->Get(static_cast<uoffset_t>(vector_index));
|
||||
}
|
||||
auto type_code_idx = LookupEnum(union_type, type_table->values,
|
||||
type_table->num_elems);
|
||||
if (type_code_idx >= 0 && type_code_idx <
|
||||
static_cast<int32_t>(type_table->num_elems)) {
|
||||
auto type_code = type_table->type_codes[type_code_idx];
|
||||
switch (type_code.base_type) {
|
||||
case ET_SEQUENCE: {
|
||||
auto ref = type_table->type_refs[type_code.sequence_ref]();
|
||||
IterateObject(val, ref, visitor);
|
||||
break;
|
||||
}
|
||||
case ET_STRING:
|
||||
visitor->String(reinterpret_cast<const String *>(val));
|
||||
break;
|
||||
default:
|
||||
visitor->Unknown(val);
|
||||
}
|
||||
} else {
|
||||
visitor->Unknown(val);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ST_ENUM:
|
||||
assert(false);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
visitor->Unknown(val);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline void IterateObject(const uint8_t *obj, const TypeTable *type_table,
|
||||
IterationVisitor *visitor) {
|
||||
visitor->StartSequence();
|
||||
const uint8_t *prev_val = nullptr;
|
||||
size_t set_idx = 0;
|
||||
for (size_t i = 0; i < type_table->num_elems; i++) {
|
||||
auto type_code = type_table->type_codes[i];
|
||||
auto type = static_cast<ElementaryType>(type_code.base_type);
|
||||
auto is_vector = type_code.is_vector != 0;
|
||||
auto ref_idx = type_code.sequence_ref;
|
||||
const TypeTable *ref = nullptr;
|
||||
if (ref_idx >= 0) {
|
||||
ref = type_table->type_refs[ref_idx]();
|
||||
}
|
||||
auto name = type_table->names ? type_table->names[i] : nullptr;
|
||||
const uint8_t *val = nullptr;
|
||||
if (type_table->st == ST_TABLE) {
|
||||
val = reinterpret_cast<const Table *>(obj)->GetAddressOf(
|
||||
FieldIndexToOffset(static_cast<voffset_t>(i)));
|
||||
} else {
|
||||
val = obj + type_table->values[i];
|
||||
}
|
||||
visitor->Field(i, set_idx, type, is_vector, ref, name, val);
|
||||
if (val) {
|
||||
set_idx++;
|
||||
if (is_vector) {
|
||||
val += ReadScalar<uoffset_t>(val);
|
||||
auto vec = reinterpret_cast<const Vector<uint8_t> *>(val);
|
||||
visitor->StartVector();
|
||||
auto elem_ptr = vec->Data();
|
||||
for (size_t j = 0; j < vec->size(); j++) {
|
||||
visitor->Element(j, type, ref, elem_ptr);
|
||||
IterateValue(type, elem_ptr, ref, prev_val, static_cast<soffset_t>(j),
|
||||
visitor);
|
||||
elem_ptr += InlineSize(type, ref);
|
||||
}
|
||||
visitor->EndVector();
|
||||
} else {
|
||||
IterateValue(type, val, ref, prev_val, -1, visitor);
|
||||
}
|
||||
}
|
||||
prev_val = val;
|
||||
}
|
||||
visitor->EndSequence();
|
||||
}
|
||||
|
||||
inline void IterateFlatBuffer(const uint8_t *buffer,
|
||||
const TypeTable *type_table,
|
||||
IterationVisitor *callback) {
|
||||
IterateObject(GetRoot<uint8_t>(buffer), type_table, callback);
|
||||
}
|
||||
|
||||
// Outputting a Flatbuffer to a string. Tries to conform as close to JSON /
|
||||
// the output generated by idl_gen_text.cpp.
|
||||
|
||||
struct ToStringVisitor : public IterationVisitor {
|
||||
std::string s;
|
||||
void StartSequence() { s += "{ "; }
|
||||
void EndSequence() { s += " }"; }
|
||||
void Field(size_t /*field_idx*/, size_t set_idx, ElementaryType /*type*/,
|
||||
bool /*is_vector*/, const TypeTable * /*type_table*/,
|
||||
const char *name, const uint8_t *val) {
|
||||
if (!val) return;
|
||||
if (set_idx) s += ", ";
|
||||
if (name) { s += name; s += ": "; }
|
||||
}
|
||||
template<typename T> void Named(T x, const char *name) {
|
||||
if (name) s+= name;
|
||||
else s+= NumToString(x);
|
||||
}
|
||||
void UType(uint8_t x, const char *name) { Named(x, name); }
|
||||
void Bool(bool x) { s+= x ? "true" : "false"; }
|
||||
void Char(int8_t x, const char *name) { Named(x, name); }
|
||||
void UChar(uint8_t x, const char *name) { Named(x, name); }
|
||||
void Short(int16_t x, const char *name) { Named(x, name); }
|
||||
void UShort(uint16_t x, const char *name) { Named(x, name); }
|
||||
void Int(int32_t x, const char *name) { Named(x, name); }
|
||||
void UInt(uint32_t x, const char *name) { Named(x, name); }
|
||||
void Long(int64_t x) { s+= NumToString(x); }
|
||||
void ULong(uint64_t x) { s+= NumToString(x); }
|
||||
void Float(float x) { s+= NumToString(x); }
|
||||
void Double(double x) { s+= NumToString(x); }
|
||||
void String(const struct String *str) {
|
||||
EscapeString(str->c_str(), str->size(), &s, true);
|
||||
}
|
||||
void Unknown(const uint8_t *) { s += "(?)"; }
|
||||
void StartVector() { s += "[ "; }
|
||||
void EndVector() { s += " ]"; }
|
||||
void Element(size_t i, ElementaryType /*type*/,
|
||||
const TypeTable * /*type_table*/, const uint8_t * /*val*/) {
|
||||
if (i) s += ", ";
|
||||
}
|
||||
};
|
||||
|
||||
inline std::string FlatBufferToString(const uint8_t *buffer,
|
||||
const TypeTable *type_table) {
|
||||
ToStringVisitor tostring_visitor;
|
||||
IterateFlatBuffer(buffer, type_table, &tostring_visitor);
|
||||
return tostring_visitor.s;
|
||||
}
|
||||
|
||||
} // namespace flatbuffers
|
||||
|
||||
#endif // FLATBUFFERS_MINIREFLECT_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) {
|
||||
@@ -242,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
|
||||
@@ -258,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;
|
||||
}
|
||||
@@ -267,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;
|
||||
}
|
||||
@@ -329,12 +361,13 @@ template<typename T, typename U> class pointer_inside_vector {
|
||||
public:
|
||||
pointer_inside_vector(T *ptr, std::vector<U> &vec)
|
||||
: offset_(reinterpret_cast<uint8_t *>(ptr) -
|
||||
reinterpret_cast<uint8_t *>(vec.data())),
|
||||
reinterpret_cast<uint8_t *>(flatbuffers::vector_data(vec))),
|
||||
vec_(vec) {}
|
||||
|
||||
T *operator*() const {
|
||||
return reinterpret_cast<T *>(
|
||||
reinterpret_cast<uint8_t *>(vec_.data()) + offset_);
|
||||
reinterpret_cast<uint8_t *>(
|
||||
flatbuffers::vector_data(vec_)) + offset_);
|
||||
}
|
||||
T *operator->() const {
|
||||
return operator*();
|
||||
@@ -386,7 +419,6 @@ uint8_t *ResizeAnyVector(const reflection::Schema &schema, uoffset_t newsize,
|
||||
uoffset_t elem_size, std::vector<uint8_t> *flatbuf,
|
||||
const reflection::Object *root_table = nullptr);
|
||||
|
||||
#ifndef FLATBUFFERS_CPP98_STL
|
||||
template <typename T>
|
||||
void ResizeVector(const reflection::Schema &schema, uoffset_t newsize, T val,
|
||||
const Vector<T> *vec, std::vector<uint8_t> *flatbuf,
|
||||
@@ -400,7 +432,7 @@ void ResizeVector(const reflection::Schema &schema, uoffset_t newsize, T val,
|
||||
// Set new elements to "val".
|
||||
for (int i = 0; i < delta_elem; i++) {
|
||||
auto loc = newelems + i * sizeof(T);
|
||||
auto is_scalar = std::is_scalar<T>::value;
|
||||
auto is_scalar = flatbuffers::is_scalar<T>::value;
|
||||
if (is_scalar) {
|
||||
WriteScalar(loc, val);
|
||||
} else { // struct
|
||||
@@ -408,7 +440,6 @@ void ResizeVector(const reflection::Schema &schema, uoffset_t newsize, T val,
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// Adds any new data (in the form of a new FlatBuffer) to an existing
|
||||
// FlatBuffer. This can be used when any of the above methods are not
|
||||
|
||||
@@ -42,6 +42,29 @@ enum BaseType {
|
||||
Union = 16
|
||||
};
|
||||
|
||||
inline BaseType (&EnumValuesBaseType())[17] {
|
||||
static BaseType values[] = {
|
||||
None,
|
||||
UType,
|
||||
Bool,
|
||||
Byte,
|
||||
UByte,
|
||||
Short,
|
||||
UShort,
|
||||
Int,
|
||||
UInt,
|
||||
Long,
|
||||
ULong,
|
||||
Float,
|
||||
Double,
|
||||
String,
|
||||
Vector,
|
||||
Obj,
|
||||
Union
|
||||
};
|
||||
return values;
|
||||
}
|
||||
|
||||
inline const char **EnumNamesBaseType() {
|
||||
static const char *names[] = {
|
||||
"None",
|
||||
@@ -113,7 +136,7 @@ struct TypeBuilder {
|
||||
}
|
||||
TypeBuilder &operator=(const TypeBuilder &);
|
||||
flatbuffers::Offset<Type> Finish() {
|
||||
const auto end = fbb_.EndTable(start_, 3);
|
||||
const auto end = fbb_.EndTable(start_);
|
||||
auto o = flatbuffers::Offset<Type>(end);
|
||||
return o;
|
||||
}
|
||||
@@ -150,9 +173,9 @@ struct KeyValue FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
|
||||
}
|
||||
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();
|
||||
}
|
||||
@@ -173,7 +196,7 @@ struct KeyValueBuilder {
|
||||
}
|
||||
KeyValueBuilder &operator=(const KeyValueBuilder &);
|
||||
flatbuffers::Offset<KeyValue> Finish() {
|
||||
const auto end = fbb_.EndTable(start_, 2);
|
||||
const auto end = fbb_.EndTable(start_);
|
||||
auto o = flatbuffers::Offset<KeyValue>(end);
|
||||
fbb_.Required(o, KeyValue::VT_KEY);
|
||||
return o;
|
||||
@@ -204,7 +227,8 @@ 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);
|
||||
@@ -228,13 +252,18 @@ struct EnumVal FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
|
||||
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();
|
||||
}
|
||||
};
|
||||
@@ -251,13 +280,16 @@ struct EnumValBuilder {
|
||||
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() {
|
||||
const auto end = fbb_.EndTable(start_, 3);
|
||||
const auto end = fbb_.EndTable(start_);
|
||||
auto o = flatbuffers::Offset<EnumVal>(end);
|
||||
fbb_.Required(o, EnumVal::VT_NAME);
|
||||
return o;
|
||||
@@ -268,9 +300,11 @@ 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();
|
||||
@@ -280,12 +314,14 @@ inline flatbuffers::Offset<EnumVal> CreateEnumValDirect(
|
||||
flatbuffers::FlatBufferBuilder &_fbb,
|
||||
const char *name = nullptr,
|
||||
int64_t value = 0,
|
||||
flatbuffers::Offset<Object> object = 0) {
|
||||
flatbuffers::Offset<Object> object = 0,
|
||||
flatbuffers::Offset<Type> union_type = 0) {
|
||||
return reflection::CreateEnumVal(
|
||||
_fbb,
|
||||
name ? _fbb.CreateString(name) : 0,
|
||||
value,
|
||||
object);
|
||||
object,
|
||||
union_type);
|
||||
}
|
||||
|
||||
struct Enum FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
|
||||
@@ -323,18 +359,18 @@ struct Enum FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
|
||||
}
|
||||
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()) &&
|
||||
VerifyField<flatbuffers::uoffset_t>(verifier, VT_DOCUMENTATION) &&
|
||||
VerifyOffset(verifier, VT_DOCUMENTATION) &&
|
||||
verifier.Verify(documentation()) &&
|
||||
verifier.VerifyVectorOfStrings(documentation()) &&
|
||||
verifier.EndTable();
|
||||
@@ -368,7 +404,7 @@ struct EnumBuilder {
|
||||
}
|
||||
EnumBuilder &operator=(const EnumBuilder &);
|
||||
flatbuffers::Offset<Enum> Finish() {
|
||||
const auto end = fbb_.EndTable(start_, 6);
|
||||
const auto end = fbb_.EndTable(start_);
|
||||
auto o = flatbuffers::Offset<Enum>(end);
|
||||
fbb_.Required(o, Enum::VT_NAME);
|
||||
fbb_.Required(o, Enum::VT_VALUES);
|
||||
@@ -468,9 +504,9 @@ struct Field FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
|
||||
}
|
||||
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) &&
|
||||
@@ -479,10 +515,10 @@ 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()) &&
|
||||
VerifyField<flatbuffers::uoffset_t>(verifier, VT_DOCUMENTATION) &&
|
||||
VerifyOffset(verifier, VT_DOCUMENTATION) &&
|
||||
verifier.Verify(documentation()) &&
|
||||
verifier.VerifyVectorOfStrings(documentation()) &&
|
||||
verifier.EndTable();
|
||||
@@ -531,7 +567,7 @@ struct FieldBuilder {
|
||||
}
|
||||
FieldBuilder &operator=(const FieldBuilder &);
|
||||
flatbuffers::Offset<Field> Finish() {
|
||||
const auto end = fbb_.EndTable(start_, 11);
|
||||
const auto end = fbb_.EndTable(start_);
|
||||
auto o = flatbuffers::Offset<Field>(end);
|
||||
fbb_.Required(o, Field::VT_NAME);
|
||||
fbb_.Required(o, Field::VT_TYPE);
|
||||
@@ -634,18 +670,18 @@ struct Object FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
|
||||
}
|
||||
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()) &&
|
||||
VerifyField<flatbuffers::uoffset_t>(verifier, VT_DOCUMENTATION) &&
|
||||
VerifyOffset(verifier, VT_DOCUMENTATION) &&
|
||||
verifier.Verify(documentation()) &&
|
||||
verifier.VerifyVectorOfStrings(documentation()) &&
|
||||
verifier.EndTable();
|
||||
@@ -682,7 +718,7 @@ struct ObjectBuilder {
|
||||
}
|
||||
ObjectBuilder &operator=(const ObjectBuilder &);
|
||||
flatbuffers::Offset<Object> Finish() {
|
||||
const auto end = fbb_.EndTable(start_, 7);
|
||||
const auto end = fbb_.EndTable(start_);
|
||||
auto o = flatbuffers::Offset<Object>(end);
|
||||
fbb_.Required(o, Object::VT_NAME);
|
||||
fbb_.Required(o, Object::VT_FIELDS);
|
||||
@@ -755,17 +791,17 @@ struct Schema FLATBUFFERS_FINAL_CLASS : private flatbuffers::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();
|
||||
}
|
||||
@@ -795,7 +831,7 @@ struct SchemaBuilder {
|
||||
}
|
||||
SchemaBuilder &operator=(const SchemaBuilder &);
|
||||
flatbuffers::Offset<Schema> Finish() {
|
||||
const auto end = fbb_.EndTable(start_, 5);
|
||||
const auto end = fbb_.EndTable(start_);
|
||||
auto o = flatbuffers::Offset<Schema>(end);
|
||||
fbb_.Required(o, Schema::VT_OBJECTS);
|
||||
fbb_.Required(o, Schema::VT_ENUMS);
|
||||
|
||||
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(), vector_data(include_paths_),
|
||||
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_
|
||||
222
include/flatbuffers/stl_emulation.h
Normal file
222
include/flatbuffers/stl_emulation.h
Normal file
@@ -0,0 +1,222 @@
|
||||
/*
|
||||
* 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_STL_EMULATION_H_
|
||||
#define FLATBUFFERS_STL_EMULATION_H_
|
||||
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <limits>
|
||||
|
||||
#if defined(_STLPORT_VERSION) && !defined(FLATBUFFERS_CPP98_STL)
|
||||
#define FLATBUFFERS_CPP98_STL
|
||||
#endif // defined(_STLPORT_VERSION) && !defined(FLATBUFFERS_CPP98_STL)
|
||||
|
||||
#if defined(FLATBUFFERS_CPP98_STL)
|
||||
#include <cctype>
|
||||
#endif // defined(FLATBUFFERS_CPP98_STL)
|
||||
|
||||
// This header provides backwards compatibility for C++98 STLs like stlport.
|
||||
namespace flatbuffers {
|
||||
|
||||
// Retrieve ::back() from a string in a way that is compatible with pre C++11
|
||||
// STLs (e.g stlport).
|
||||
inline char string_back(const std::string &value) {
|
||||
return value[value.length() - 1];
|
||||
}
|
||||
|
||||
// Helper method that retrieves ::data() from a vector in a way that is
|
||||
// compatible with pre C++11 STLs (e.g stlport).
|
||||
template <typename T> inline T *vector_data(std::vector<T> &vector) {
|
||||
// In some debug environments, operator[] does bounds checking, so &vector[0]
|
||||
// can't be used.
|
||||
return &(*vector.begin());
|
||||
}
|
||||
|
||||
template <typename T> inline const T *vector_data(
|
||||
const std::vector<T> &vector) {
|
||||
return &(*vector.begin());
|
||||
}
|
||||
|
||||
template <typename T, typename V>
|
||||
inline void vector_emplace_back(std::vector<T> *vector, V &&data) {
|
||||
#if defined(FLATBUFFERS_CPP98_STL)
|
||||
vector->push_back(data);
|
||||
#else
|
||||
vector->emplace_back(std::forward<V>(data));
|
||||
#endif // defined(FLATBUFFERS_CPP98_STL)
|
||||
}
|
||||
|
||||
#ifndef FLATBUFFERS_CPP98_STL
|
||||
#if !(defined(_MSC_VER) && _MSC_VER <= 1700 /* MSVC2012 */)
|
||||
template <typename T>
|
||||
using numeric_limits = std::numeric_limits<T>;
|
||||
#else
|
||||
template <typename T> class numeric_limits :
|
||||
public std::numeric_limits<T> {};
|
||||
#endif // !(defined(_MSC_VER) && _MSC_VER <= 1700 /* MSVC2012 */)
|
||||
#else
|
||||
template <typename T> class numeric_limits :
|
||||
public std::numeric_limits<T> {};
|
||||
|
||||
template <> class numeric_limits<unsigned long long> {
|
||||
public:
|
||||
static unsigned long long min() { return 0ULL; }
|
||||
static unsigned long long max() { return ~0ULL; }
|
||||
};
|
||||
|
||||
template <> class numeric_limits<long long> {
|
||||
public:
|
||||
static long long min() {
|
||||
return static_cast<long long>(1ULL << ((sizeof(long long) << 3) - 1));
|
||||
}
|
||||
static long long max() {
|
||||
return static_cast<long long>(
|
||||
(1ULL << ((sizeof(long long) << 3) - 1)) - 1);
|
||||
}
|
||||
};
|
||||
#endif // FLATBUFFERS_CPP98_STL
|
||||
|
||||
#if !(defined(_MSC_VER) && _MSC_VER <= 1700 /* MSVC2012 */)
|
||||
#ifndef FLATBUFFERS_CPP98_STL
|
||||
template <typename T> using is_scalar = std::is_scalar<T>;
|
||||
template <typename T, typename U> using is_same = std::is_same<T,U>;
|
||||
template <typename T> using is_floating_point = std::is_floating_point<T>;
|
||||
template <typename T> using is_unsigned = std::is_unsigned<T>;
|
||||
#else
|
||||
// Map C++ TR1 templates defined by stlport.
|
||||
template <typename T> using is_scalar = std::tr1::is_scalar<T>;
|
||||
template <typename T, typename U> using is_same = std::tr1::is_same<T,U>;
|
||||
template <typename T> using is_floating_point =
|
||||
std::tr1::is_floating_point<T>;
|
||||
template <typename T> using is_unsigned = std::tr1::is_unsigned<T>;
|
||||
#endif // !FLATBUFFERS_CPP98_STL
|
||||
#else
|
||||
// MSVC 2010 doesn't support C++11 aliases.
|
||||
template <typename T> struct is_scalar : public std::is_scalar<T> {};
|
||||
template <typename T, typename U> struct is_same : public std::is_same<T,U> {};
|
||||
template <typename T> struct is_floating_point :
|
||||
public std::is_floating_point<T> {};
|
||||
template <typename T> struct is_unsigned : public std::is_unsigned<T> {};
|
||||
#endif // !(defined(_MSC_VER) && _MSC_VER <= 1700 /* MSVC2012 */)
|
||||
|
||||
#ifndef FLATBUFFERS_CPP98_STL
|
||||
#if !(defined(_MSC_VER) && _MSC_VER <= 1700 /* MSVC2012 */)
|
||||
template <class T> using unique_ptr = std::unique_ptr<T>;
|
||||
#else
|
||||
// MSVC 2010 doesn't support C++11 aliases.
|
||||
// We're manually "aliasing" the class here as we want to bring unique_ptr
|
||||
// into the flatbuffers namespace. We have unique_ptr in the flatbuffers
|
||||
// namespace we have a completely independent implemenation (see below)
|
||||
// for C++98 STL implementations.
|
||||
template <class T> class unique_ptr : public std::unique_ptr<T> {
|
||||
public:
|
||||
unique_ptr() {}
|
||||
explicit unique_ptr(T* p) : std::unique_ptr<T>(p) {}
|
||||
unique_ptr(std::unique_ptr<T>&& u) { *this = std::move(u); }
|
||||
unique_ptr(unique_ptr&& u) { *this = std::move(u); }
|
||||
unique_ptr& operator=(std::unique_ptr<T>&& u) {
|
||||
std::unique_ptr<T>::reset(u.release());
|
||||
return *this;
|
||||
}
|
||||
unique_ptr& operator=(unique_ptr&& u) {
|
||||
std::unique_ptr<T>::reset(u.release());
|
||||
return *this;
|
||||
}
|
||||
unique_ptr& operator=(T* p) {
|
||||
return std::unique_ptr<T>::operator=(p);
|
||||
}
|
||||
};
|
||||
#endif // !(defined(_MSC_VER) && _MSC_VER <= 1700 /* MSVC2012 */)
|
||||
#else
|
||||
// Very limited implementation of unique_ptr.
|
||||
// This is provided simply to allow the C++ code generated from the default
|
||||
// settings to function in C++98 environments with no modifications.
|
||||
template <class T> class unique_ptr {
|
||||
public:
|
||||
typedef T element_type;
|
||||
|
||||
unique_ptr() : ptr_(nullptr) {}
|
||||
explicit unique_ptr(T* p) : ptr_(p) {}
|
||||
unique_ptr(unique_ptr&& u) : ptr_(nullptr) { reset(u.release()); }
|
||||
unique_ptr(const unique_ptr& u) : ptr_(nullptr) {
|
||||
reset(const_cast<unique_ptr*>(&u)->release());
|
||||
}
|
||||
~unique_ptr() { reset(); }
|
||||
|
||||
unique_ptr& operator=(const unique_ptr& u) {
|
||||
reset(const_cast<unique_ptr*>(&u)->release());
|
||||
return *this;
|
||||
}
|
||||
|
||||
unique_ptr& operator=(unique_ptr&& u) {
|
||||
reset(u.release());
|
||||
return *this;
|
||||
}
|
||||
|
||||
unique_ptr& operator=(T* p) {
|
||||
reset(p);
|
||||
return *this;
|
||||
}
|
||||
|
||||
const T& operator*() const { return *ptr_; }
|
||||
T* operator->() const { return ptr_; }
|
||||
T* get() const noexcept { return ptr_; }
|
||||
explicit operator bool() const { return ptr_ != nullptr; }
|
||||
|
||||
// modifiers
|
||||
T* release() {
|
||||
T* value = ptr_;
|
||||
ptr_ = nullptr;
|
||||
return value;
|
||||
}
|
||||
|
||||
void reset(T* p = nullptr) {
|
||||
T* value = ptr_;
|
||||
ptr_ = p;
|
||||
if (value) delete value;
|
||||
}
|
||||
|
||||
void swap(unique_ptr& u) {
|
||||
T* temp_ptr = ptr_;
|
||||
ptr_ = u.ptr_;
|
||||
u.ptr_ = temp_ptr;
|
||||
}
|
||||
|
||||
private:
|
||||
T* ptr_;
|
||||
};
|
||||
|
||||
template <class T> bool operator==(const unique_ptr<T>& x,
|
||||
const unique_ptr<T>& y) {
|
||||
return x.get() == y.get();
|
||||
}
|
||||
|
||||
template <class T, class D> bool operator==(const unique_ptr<T>& x,
|
||||
const D* y) {
|
||||
return static_cast<D*>(x.get()) == y;
|
||||
}
|
||||
|
||||
template <class T> bool operator==(const unique_ptr<T>& x, intptr_t y) {
|
||||
return reinterpret_cast<intptr_t>(x.get()) == y;
|
||||
}
|
||||
#endif // !FLATBUFFERS_CPP98_STL
|
||||
|
||||
} // namespace flatbuffers
|
||||
|
||||
#endif // FLATBUFFERS_STL_EMULATION_H_
|
||||
@@ -40,7 +40,8 @@
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "flatbuffers/flatbuffers.h"
|
||||
#include "flatbuffers/base.h"
|
||||
|
||||
|
||||
namespace flatbuffers {
|
||||
|
||||
@@ -59,6 +60,20 @@ template<> inline std::string NumToString<signed char>(signed char t) {
|
||||
template<> inline std::string NumToString<unsigned char>(unsigned char t) {
|
||||
return NumToString(static_cast<int>(t));
|
||||
}
|
||||
#if defined(FLATBUFFERS_CPP98_STL)
|
||||
template <> inline std::string NumToString<long long>(long long t) {
|
||||
char buf[21]; // (log((1 << 63) - 1) / log(10)) + 2
|
||||
snprintf(buf, sizeof(buf), "%lld", t);
|
||||
return std::string(buf);
|
||||
}
|
||||
|
||||
template <> inline std::string NumToString<unsigned long long>(
|
||||
unsigned long long t) {
|
||||
char buf[22]; // (log((1 << 63) - 1) / log(10)) + 1
|
||||
snprintf(buf, sizeof(buf), "%llu", t);
|
||||
return std::string(buf);
|
||||
}
|
||||
#endif // defined(FLATBUFFERS_CPP98_STL)
|
||||
|
||||
// Special versions for floats/doubles.
|
||||
template<> inline std::string NumToString<double>(double t) {
|
||||
@@ -71,9 +86,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;
|
||||
}
|
||||
@@ -157,16 +171,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) {
|
||||
@@ -197,13 +215,25 @@ 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()) {
|
||||
char filepath_last_character = string_back(filepath);
|
||||
if (filepath_last_character == kPathSeparatorWindows) {
|
||||
filepath_last_character = kPathSeparator;
|
||||
} else if (filepath_last_character != 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) {
|
||||
@@ -345,6 +375,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_
|
||||
|
||||
@@ -18,13 +18,13 @@ package com.google.flatbuffers;
|
||||
|
||||
import static com.google.flatbuffers.Constants.*;
|
||||
|
||||
import java.nio.CharBuffer;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.*;
|
||||
import java.nio.charset.CharacterCodingException;
|
||||
import java.nio.charset.CharsetEncoder;
|
||||
import java.nio.charset.CoderResult;
|
||||
import java.util.Arrays;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.charset.Charset;
|
||||
|
||||
/// @file
|
||||
@@ -52,26 +52,51 @@ public class FlatBufferBuilder {
|
||||
boolean force_defaults = false; // False omits default values from the serialized data.
|
||||
CharsetEncoder encoder = utf8charset.newEncoder();
|
||||
ByteBuffer dst;
|
||||
ByteBufferFactory bb_factory; // Factory for allocating the internal buffer
|
||||
/// @endcond
|
||||
|
||||
/**
|
||||
* Start with a buffer of size `initial_size`, then grow as required.
|
||||
*
|
||||
* @param initial_size The initial size of the internal buffer to use.
|
||||
* @param bb_factory The factory to be used for allocating the internal buffer
|
||||
*/
|
||||
public FlatBufferBuilder(int initial_size, ByteBufferFactory bb_factory) {
|
||||
if (initial_size <= 0) initial_size = 1;
|
||||
space = initial_size;
|
||||
this.bb_factory = bb_factory;
|
||||
bb = bb_factory.newByteBuffer(initial_size);
|
||||
}
|
||||
|
||||
/**
|
||||
* Start with a buffer of size `initial_size`, then grow as required.
|
||||
*
|
||||
* @param initial_size The initial size of the internal buffer to use.
|
||||
*/
|
||||
public FlatBufferBuilder(int initial_size) {
|
||||
if (initial_size <= 0) initial_size = 1;
|
||||
space = initial_size;
|
||||
bb = newByteBuffer(initial_size);
|
||||
this(initial_size, new HeapByteBufferFactory());
|
||||
}
|
||||
|
||||
/**
|
||||
* Start with a buffer of 1KiB, then grow as required.
|
||||
*/
|
||||
/**
|
||||
* Start with a buffer of 1KiB, then grow as required.
|
||||
*/
|
||||
public FlatBufferBuilder() {
|
||||
this(1024);
|
||||
}
|
||||
|
||||
/**
|
||||
* Alternative constructor allowing reuse of {@link ByteBuffer}s. The builder
|
||||
* can still grow the buffer as necessary. User classes should make sure
|
||||
* to call {@link #dataBuffer()} to obtain the resulting encoded message.
|
||||
*
|
||||
* @param existing_bb The byte buffer to reuse.
|
||||
* @param bb_factory The factory to be used for allocating a new internal buffer if
|
||||
* the existing buffer needs to grow
|
||||
*/
|
||||
public FlatBufferBuilder(ByteBuffer existing_bb, ByteBufferFactory bb_factory) {
|
||||
init(existing_bb, bb_factory);
|
||||
}
|
||||
|
||||
/**
|
||||
* Alternative constructor allowing reuse of {@link ByteBuffer}s. The builder
|
||||
* can still grow the buffer as necessary. User classes should make sure
|
||||
@@ -80,7 +105,7 @@ public class FlatBufferBuilder {
|
||||
* @param existing_bb The byte buffer to reuse.
|
||||
*/
|
||||
public FlatBufferBuilder(ByteBuffer existing_bb) {
|
||||
init(existing_bb);
|
||||
init(existing_bb, new HeapByteBufferFactory());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -89,9 +114,12 @@ public class FlatBufferBuilder {
|
||||
* objects that have been allocated for temporary storage.
|
||||
*
|
||||
* @param existing_bb The byte buffer to reuse.
|
||||
* @param bb_factory The factory to be used for allocating a new internal buffer if
|
||||
* the existing buffer needs to grow
|
||||
* @return Returns `this`.
|
||||
*/
|
||||
public FlatBufferBuilder init(ByteBuffer existing_bb){
|
||||
public FlatBufferBuilder init(ByteBuffer existing_bb, ByteBufferFactory bb_factory){
|
||||
this.bb_factory = bb_factory;
|
||||
bb = existing_bb;
|
||||
bb.clear();
|
||||
bb.order(ByteOrder.LITTLE_ENDIAN);
|
||||
@@ -106,17 +134,53 @@ public class FlatBufferBuilder {
|
||||
return this;
|
||||
}
|
||||
|
||||
/// @cond FLATBUFFERS_INTERNAL
|
||||
/**
|
||||
* Create a `ByteBuffer` with a given capacity.
|
||||
* An interface that provides a user of the FlatBufferBuilder class the ability to specify
|
||||
* the method in which the internal buffer gets allocated. This allows for alternatives
|
||||
* to the default behavior, which is to allocate memory for a new byte-array
|
||||
* backed `ByteBuffer` array inside the JVM.
|
||||
*
|
||||
* @param capacity The size of the `ByteBuffer` to allocate.
|
||||
* @return Returns the new `ByteBuffer` that was allocated.
|
||||
* The FlatBufferBuilder class contains the HeapByteBufferFactory class to
|
||||
* preserve the default behavior in the event that the user does not provide
|
||||
* their own implementation of this interface.
|
||||
*/
|
||||
static ByteBuffer newByteBuffer(int capacity) {
|
||||
ByteBuffer newbb = ByteBuffer.allocate(capacity);
|
||||
newbb.order(ByteOrder.LITTLE_ENDIAN);
|
||||
return newbb;
|
||||
public interface ByteBufferFactory {
|
||||
/**
|
||||
* Create a `ByteBuffer` with a given capacity.
|
||||
*
|
||||
* @param capacity The size of the `ByteBuffer` to allocate.
|
||||
* @return Returns the new `ByteBuffer` that was allocated.
|
||||
*/
|
||||
ByteBuffer newByteBuffer(int capacity);
|
||||
}
|
||||
|
||||
/**
|
||||
* An implementation of the ByteBufferFactory interface that is used when
|
||||
* one is not provided by the user.
|
||||
*
|
||||
* Allocate memory for a new byte-array backed `ByteBuffer` array inside the JVM.
|
||||
*/
|
||||
public static final class HeapByteBufferFactory implements ByteBufferFactory {
|
||||
@Override
|
||||
public ByteBuffer newByteBuffer(int capacity) {
|
||||
return ByteBuffer.allocate(capacity).order(ByteOrder.LITTLE_ENDIAN);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -124,16 +188,17 @@ public class FlatBufferBuilder {
|
||||
* end of the new buffer (since we build the buffer backwards).
|
||||
*
|
||||
* @param bb The current buffer with the existing data.
|
||||
* @param bb_factory The factory to be used for allocating the new internal buffer
|
||||
* @return A new byte buffer with the old data copied copied to it. The data is
|
||||
* located at the end of the buffer.
|
||||
*/
|
||||
static ByteBuffer growByteBuffer(ByteBuffer bb) {
|
||||
static ByteBuffer growByteBuffer(ByteBuffer bb, ByteBufferFactory bb_factory) {
|
||||
int old_buf_size = bb.capacity();
|
||||
if ((old_buf_size & 0xC0000000) != 0) // Ensure we don't grow beyond what fits in an int.
|
||||
throw new AssertionError("FlatBuffers: cannot grow buffer beyond 2 gigabytes.");
|
||||
int new_buf_size = old_buf_size << 1;
|
||||
bb.position(0);
|
||||
ByteBuffer nbb = newByteBuffer(new_buf_size);
|
||||
ByteBuffer nbb = bb_factory.newByteBuffer(new_buf_size);
|
||||
nbb.position(new_buf_size - old_buf_size);
|
||||
nbb.put(bb);
|
||||
return nbb;
|
||||
@@ -176,7 +241,7 @@ public class FlatBufferBuilder {
|
||||
// Reallocate the buffer if needed.
|
||||
while (space < align_size + size + additional_bytes) {
|
||||
int old_buf_size = bb.capacity();
|
||||
bb = growByteBuffer(bb);
|
||||
bb = growByteBuffer(bb, bb_factory);
|
||||
space += bb.capacity() - old_buf_size;
|
||||
}
|
||||
pad(align_size);
|
||||
@@ -413,7 +478,7 @@ public class FlatBufferBuilder {
|
||||
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.
|
||||
@@ -679,7 +744,11 @@ public class FlatBufferBuilder {
|
||||
addInt(0);
|
||||
int vtableloc = offset();
|
||||
// Write out the current vtable.
|
||||
for (int i = vtable_in_use - 1; i >= 0 ; i--) {
|
||||
int i = vtable_in_use - 1;
|
||||
// Trim trailing zeroes.
|
||||
for (; i >= 0 && vtable[i] == 0; i--) {}
|
||||
int trimmed_size = i + 1;
|
||||
for (; i >= 0 ; i--) {
|
||||
// Offset relative to the start of the table.
|
||||
short off = (short)(vtable[i] != 0 ? vtableloc - vtable[i] : 0);
|
||||
addShort(off);
|
||||
@@ -687,12 +756,12 @@ public class FlatBufferBuilder {
|
||||
|
||||
final int standard_fields = 2; // The fields below:
|
||||
addShort((short)(vtableloc - object_start));
|
||||
addShort((short)((vtable_in_use + standard_fields) * SIZEOF_SHORT));
|
||||
addShort((short)((trimmed_size + standard_fields) * SIZEOF_SHORT));
|
||||
|
||||
// Search for an existing vtable that matches the current one.
|
||||
int existing_vtable = 0;
|
||||
outer_loop:
|
||||
for (int i = 0; i < num_vtables; i++) {
|
||||
for (i = 0; i < num_vtables; i++) {
|
||||
int vt1 = bb.capacity() - vtables[i];
|
||||
int vt2 = space;
|
||||
short len = bb.getShort(vt1);
|
||||
@@ -837,6 +906,41 @@ public class FlatBufferBuilder {
|
||||
public byte[] sizedByteArray() {
|
||||
return sizedByteArray(space, bb.capacity() - space);
|
||||
}
|
||||
|
||||
/**
|
||||
* A utility function to return an InputStream to the ByteBuffer data
|
||||
*
|
||||
* @return An InputStream that starts at the beginning of the ByteBuffer data
|
||||
* and can read to the end of it.
|
||||
*/
|
||||
public InputStream sizedInputStream() {
|
||||
finished();
|
||||
ByteBuffer duplicate = bb.duplicate();
|
||||
duplicate.position(space);
|
||||
duplicate.limit(bb.capacity());
|
||||
return new ByteBufferBackedInputStream(duplicate);
|
||||
}
|
||||
|
||||
/**
|
||||
* A class that allows a user to create an InputStream from a ByteBuffer.
|
||||
*/
|
||||
static class ByteBufferBackedInputStream extends InputStream {
|
||||
|
||||
ByteBuffer buf;
|
||||
|
||||
public ByteBufferBackedInputStream(ByteBuffer buf) {
|
||||
this.buf = buf;
|
||||
}
|
||||
|
||||
public int read() throws IOException {
|
||||
try {
|
||||
return buf.get() & 0xFF;
|
||||
} catch(BufferUnderflowException e) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// @}
|
||||
|
||||
@@ -68,7 +68,7 @@ public class Table {
|
||||
}
|
||||
|
||||
protected static int __offset(int vtable_offset, int offset, ByteBuffer bb) {
|
||||
int vtable = bb.array().length - offset;
|
||||
int vtable = bb.capacity() - offset;
|
||||
return bb.getShort(vtable + vtable_offset - bb.getInt(vtable)) + vtable;
|
||||
}
|
||||
|
||||
@@ -245,10 +245,9 @@ public class Table {
|
||||
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];
|
||||
if (bb.get(i + startPos_1) != bb.get(i + startPos_2))
|
||||
return bb.get(i + startPos_1) - bb.get(i + startPos_2);
|
||||
}
|
||||
return len_1 - len_2;
|
||||
}
|
||||
@@ -266,10 +265,9 @@ public class Table {
|
||||
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];
|
||||
if (bb.get(i + startPos_1) != key[i])
|
||||
return bb.get(i + startPos_1) - key[i];
|
||||
}
|
||||
return len_1 - len_2;
|
||||
}
|
||||
|
||||
@@ -115,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;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -604,23 +604,28 @@ flatbuffers.Builder.prototype.endObject = function() {
|
||||
this.addInt32(0);
|
||||
var vtableloc = this.offset();
|
||||
|
||||
// Trim trailing zeroes.
|
||||
var i = this.vtable_in_use - 1;
|
||||
for (; i >= 0 && this.vtable[i] == 0; i--) {}
|
||||
var trimmed_size = i + 1;
|
||||
|
||||
// Write out the current vtable.
|
||||
for (var i = this.vtable_in_use - 1; i >= 0; i--) {
|
||||
for (; i >= 0; i--) {
|
||||
// Offset relative to the start of the table.
|
||||
this.addInt16(this.vtable[i] != 0 ? vtableloc - this.vtable[i] : 0);
|
||||
}
|
||||
|
||||
var standard_fields = 2; // The fields below:
|
||||
this.addInt16(vtableloc - this.object_start);
|
||||
this.addInt16((this.vtable_in_use + standard_fields) * flatbuffers.SIZEOF_SHORT);
|
||||
var len = (trimmed_size + standard_fields) * flatbuffers.SIZEOF_SHORT;
|
||||
this.addInt16(len);
|
||||
|
||||
// Search for an existing vtable that matches the current one.
|
||||
var existing_vtable = 0;
|
||||
var vt1 = this.space;
|
||||
outer_loop:
|
||||
for (var i = 0; i < this.vtables.length; i++) {
|
||||
var vt1 = this.bb.capacity() - this.vtables[i];
|
||||
var vt2 = this.space;
|
||||
var len = this.bb.readInt16(vt1);
|
||||
for (i = 0; i < this.vtables.length; i++) {
|
||||
var vt2 = this.bb.capacity() - this.vtables[i];
|
||||
if (len == this.bb.readInt16(vt2)) {
|
||||
for (var j = flatbuffers.SIZEOF_SHORT; j < len; j += flatbuffers.SIZEOF_SHORT) {
|
||||
if (this.bb.readInt16(vt1 + j) != this.bb.readInt16(vt2 + j)) {
|
||||
@@ -944,9 +949,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;
|
||||
};
|
||||
|
||||
@@ -959,6 +972,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
|
||||
@@ -970,6 +992,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
|
||||
@@ -979,6 +1012,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
|
||||
|
||||
0
net/FlatBuffers/ByteBuffer.cs
Executable file → Normal file
0
net/FlatBuffers/ByteBuffer.cs
Executable file → Normal file
@@ -500,7 +500,11 @@ namespace FlatBuffers
|
||||
AddInt((int)0);
|
||||
var vtableloc = Offset;
|
||||
// Write out the current vtable.
|
||||
for (int i = _vtableSize - 1; i >= 0 ; i--) {
|
||||
int i = _vtableSize - 1;
|
||||
// Trim trailing zeroes.
|
||||
for (; i >= 0 && _vtable[i] == 0; i--) {}
|
||||
int trimmedSize = i + 1;
|
||||
for (; i >= 0 ; i--) {
|
||||
// Offset relative to the start of the table.
|
||||
short off = (short)(_vtable[i] != 0
|
||||
? vtableloc - _vtable[i]
|
||||
@@ -513,12 +517,12 @@ namespace FlatBuffers
|
||||
|
||||
const int standardFields = 2; // The fields below:
|
||||
AddShort((short)(vtableloc - _objectStart));
|
||||
AddShort((short)((_vtableSize + standardFields) *
|
||||
AddShort((short)((trimmedSize + standardFields) *
|
||||
sizeof(short)));
|
||||
|
||||
// Search for an existing vtable that matches the current one.
|
||||
int existingVtable = 0;
|
||||
for (int i = 0; i < _numVtables; i++) {
|
||||
for (i = 0; i < _numVtables; i++) {
|
||||
int vt1 = _bb.Length - _vtables[i];
|
||||
int vt2 = _space;
|
||||
short len = _bb.GetShort(vt1);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "flatbuffers",
|
||||
"version": "1.6.0",
|
||||
"version": "1.8.0",
|
||||
"description": "Memory Efficient Serialization Library",
|
||||
"files": ["js/flatbuffers.js"],
|
||||
"main": "js/flatbuffers.js",
|
||||
|
||||
@@ -596,7 +596,7 @@ class FlatbufferBuilder
|
||||
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 */
|
||||
@@ -812,14 +812,18 @@ class FlatbufferBuilder
|
||||
$this->addInt(0);
|
||||
$vtableloc = $this->offset();
|
||||
|
||||
for ($i = $this->vtable_in_use -1; $i >= 0; $i--) {
|
||||
$i = $this->vtable_in_use -1;
|
||||
// Trim trailing zeroes.
|
||||
for (; $i >= 0 && $this->vtable[$i] == 0; $i--) {}
|
||||
$trimmed_size = $i + 1;
|
||||
for (; $i >= 0; $i--) {
|
||||
$off = ($this->vtable[$i] != 0) ? $vtableloc - $this->vtable[$i] : 0;
|
||||
$this->addShort($off);
|
||||
}
|
||||
|
||||
$standard_fields = 2; // the fields below
|
||||
$this->addShort($vtableloc - $this->object_start);
|
||||
$this->addShort(($this->vtable_in_use + $standard_fields) * Constants::SIZEOF_SHORT);
|
||||
$this->addShort(($trimmed_size + $standard_fields) * Constants::SIZEOF_SHORT);
|
||||
|
||||
// search for an existing vtable that matches the current one.
|
||||
$existing_vtable = 0;
|
||||
|
||||
@@ -28,4 +28,14 @@ abstract class Struct
|
||||
* @var ByteBuffer $bb
|
||||
*/
|
||||
protected $bb;
|
||||
|
||||
public function setByteBufferPos($pos)
|
||||
{
|
||||
$this->bb_pos = $pos;
|
||||
}
|
||||
|
||||
public function setByteBuffer($bb)
|
||||
{
|
||||
$this->bb = $bb;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,6 +32,16 @@ abstract class Table
|
||||
{
|
||||
}
|
||||
|
||||
public function setByteBufferPos($pos)
|
||||
{
|
||||
$this->bb_pos = $pos;
|
||||
}
|
||||
|
||||
public function setByteBuffer($bb)
|
||||
{
|
||||
$this->bb = $bb;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns actual vtable offset
|
||||
*
|
||||
@@ -107,8 +117,8 @@ abstract class Table
|
||||
protected function __union($table, $offset)
|
||||
{
|
||||
$offset += $this->bb_pos;
|
||||
$table->bb_pos = $offset + $this->bb->getInt($offset);
|
||||
$table->bb = $this->bb;
|
||||
$table->setByteBufferPos($offset + $this->bb->getInt($offset));
|
||||
$table->setByteBuffer($this->bb);
|
||||
return $table;
|
||||
}
|
||||
|
||||
|
||||
51
pom.xml
51
pom.xml
@@ -5,17 +5,20 @@
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>com.google.flatbuffers</groupId>
|
||||
<artifactId>flatbuffers-java</artifactId>
|
||||
<version>1.6.0-SNAPSHOT</version>
|
||||
<version>1.8.0</version>
|
||||
<packaging>bundle</packaging>
|
||||
<name>FlatBuffers Java API</name>
|
||||
<description>
|
||||
Memory Efficient Serialization Library
|
||||
</description>
|
||||
|
||||
<developers>
|
||||
<developer>
|
||||
<name>Wouter van Oortmerssen</name>
|
||||
</developer>
|
||||
</developers>
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
|
||||
<url>https://github.com/google/flatbuffers</url>
|
||||
<licenses>
|
||||
<license>
|
||||
@@ -32,6 +35,12 @@
|
||||
</scm>
|
||||
<dependencies>
|
||||
</dependencies>
|
||||
<distributionManagement>
|
||||
<snapshotRepository>
|
||||
<id>ossrh</id>
|
||||
<url>https://oss.sonatype.org/content/repositories/snapshots</url>
|
||||
</snapshotRepository>
|
||||
</distributionManagement>
|
||||
<build>
|
||||
<sourceDirectory>java</sourceDirectory>
|
||||
<plugins>
|
||||
@@ -84,6 +93,42 @@
|
||||
<version>3.0.1</version>
|
||||
<extensions>true</extensions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.sonatype.plugins</groupId>
|
||||
<artifactId>nexus-staging-maven-plugin</artifactId>
|
||||
<version>1.6.7</version>
|
||||
<extensions>true</extensions>
|
||||
<configuration>
|
||||
<serverId>ossrh</serverId>
|
||||
<nexusUrl>https://oss.sonatype.org/</nexusUrl>
|
||||
<autoReleaseAfterClose>true</autoReleaseAfterClose>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-gpg-plugin</artifactId>
|
||||
<version>1.5</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>sign-artifacts</id>
|
||||
<phase>verify</phase>
|
||||
<goals>
|
||||
<goal>sign</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-release-plugin</artifactId>
|
||||
<version>2.5.3</version>
|
||||
<configuration>
|
||||
<autoVersionSubmodules>true</autoVersionSubmodules>
|
||||
<useReleaseProfile>false</useReleaseProfile>
|
||||
<releaseProfiles>release</releaseProfiles>
|
||||
<goals>deploy</goals>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
|
||||
@@ -193,6 +193,10 @@ class Builder(object):
|
||||
objectOffset = self.Offset()
|
||||
existingVtable = None
|
||||
|
||||
# Trim trailing 0 offsets.
|
||||
while self.current_vtable and self.current_vtable[-1] == 0:
|
||||
self.current_vtable.pop()
|
||||
|
||||
# Search backwards through existing vtables, because similar vtables
|
||||
# are likely to have been recently appended. See
|
||||
# BenchmarkVtableDeduplication for a case in which this heuristic
|
||||
@@ -417,6 +421,27 @@ class Builder(object):
|
||||
|
||||
return self.EndVector(len(x))
|
||||
|
||||
def CreateByteVector(self, x):
|
||||
"""CreateString writes a byte vector."""
|
||||
|
||||
self.assertNotNested()
|
||||
## @cond FLATBUFFERS_INTERNAL
|
||||
self.nested = True
|
||||
## @endcond
|
||||
|
||||
if not isinstance(x, compat.binary_types):
|
||||
raise TypeError("non-byte vector passed to CreateByteVector")
|
||||
|
||||
self.Prep(N.UOffsetTFlags.bytewidth, len(x)*N.Uint8Flags.bytewidth)
|
||||
|
||||
l = UOffsetTFlags.py_type(len(x))
|
||||
## @cond FLATBUFFERS_INTERNAL
|
||||
self.head = UOffsetTFlags.py_type(self.Head() - l)
|
||||
## @endcond
|
||||
self.Bytes[self.Head():self.Head()+l] = x
|
||||
|
||||
return self.EndVector(len(x))
|
||||
|
||||
## @cond FLATBUFFERS_INTERNAL
|
||||
def assertNested(self):
|
||||
"""
|
||||
|
||||
@@ -12,9 +12,11 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
""" A tiny version of `six` to help with backwards compability. """
|
||||
""" A tiny version of `six` to help with backwards compability. Also includes
|
||||
compatibility helpers for numpy. """
|
||||
|
||||
import sys
|
||||
import imp
|
||||
|
||||
PY2 = sys.version_info[0] == 2
|
||||
PY26 = sys.version_info[0:2] == (2, 6)
|
||||
@@ -43,4 +45,37 @@ else:
|
||||
memoryview_type = memoryview
|
||||
struct_bool_decl = "?"
|
||||
|
||||
# Helper functions to facilitate making numpy optional instead of required
|
||||
|
||||
def import_numpy():
|
||||
"""
|
||||
Returns the numpy module if it exists on the system,
|
||||
otherwise returns None.
|
||||
"""
|
||||
try:
|
||||
imp.find_module('numpy')
|
||||
numpy_exists = True
|
||||
except ImportError:
|
||||
numpy_exists = False
|
||||
|
||||
if numpy_exists:
|
||||
# We do this outside of try/except block in case numpy exists
|
||||
# but is not installed correctly. We do not want to catch an
|
||||
# incorrect installation which would manifest as an
|
||||
# ImportError.
|
||||
import numpy as np
|
||||
else:
|
||||
np = None
|
||||
|
||||
return np
|
||||
|
||||
|
||||
class NumpyRequiredForThisFeature(RuntimeError):
|
||||
"""
|
||||
Error raised when user tries to use a feature that
|
||||
requires numpy without having numpy installed.
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
# NOTE: Future Jython support may require code here (look at `six`).
|
||||
|
||||
@@ -15,13 +15,26 @@
|
||||
from . import number_types as N
|
||||
from . import packer
|
||||
from .compat import memoryview_type
|
||||
from .compat import import_numpy, NumpyRequiredForThisFeature
|
||||
|
||||
np = import_numpy()
|
||||
|
||||
def Get(packer_type, buf, head):
|
||||
""" Get decodes a value at buf[head:] using `packer_type`. """
|
||||
""" Get decodes a value at buf[head] using `packer_type`. """
|
||||
return packer_type.unpack_from(memoryview_type(buf), head)[0]
|
||||
|
||||
|
||||
def GetVectorAsNumpy(numpy_type, buf, count, offset):
|
||||
""" GetVecAsNumpy decodes values starting at buf[head] as
|
||||
`numpy_type`, where `numpy_type` is a numpy dtype. """
|
||||
if np is not None:
|
||||
# TODO: could set .flags.writeable = False to make users jump through
|
||||
# hoops before modifying...
|
||||
return np.frombuffer(buf, dtype=numpy_type, count=count, offset=offset)
|
||||
else:
|
||||
raise NumpyRequiredForThisFeature('Numpy was not found.')
|
||||
|
||||
|
||||
def Write(packer_type, buf, head, n):
|
||||
""" Write encodes `n` at buf[head:] using `packer_type`. """
|
||||
""" Write encodes `n` at buf[head] using `packer_type`. """
|
||||
packer_type.pack_into(buf, head, n)
|
||||
|
||||
@@ -16,7 +16,9 @@ import collections
|
||||
import struct
|
||||
|
||||
from . import packer
|
||||
from .compat import import_numpy, NumpyRequiredForThisFeature
|
||||
|
||||
np = import_numpy()
|
||||
|
||||
# For reference, see:
|
||||
# https://docs.python.org/2/library/ctypes.html#ctypes-fundamental-data-types-2
|
||||
@@ -170,3 +172,10 @@ def uint64_to_float64(n):
|
||||
packed = struct.pack("<1Q", n)
|
||||
(unpacked,) = struct.unpack("<1d", packed)
|
||||
return unpacked
|
||||
|
||||
|
||||
def to_numpy_type(number_type):
|
||||
if np is not None:
|
||||
return np.dtype(number_type.name).newbyteorder('<')
|
||||
else:
|
||||
raise NumpyRequiredForThisFeature('Numpy was not found.')
|
||||
|
||||
@@ -101,6 +101,18 @@ class Table(object):
|
||||
return d
|
||||
return self.Get(validator_flags, self.Pos + off)
|
||||
|
||||
def GetVectorAsNumpy(self, flags, off):
|
||||
"""
|
||||
GetVectorAsNumpy returns the vector that starts at `Vector(off)`
|
||||
as a numpy array with the type specified by `flags`. The array is
|
||||
a `view` into Bytes, so modifying the returned array will
|
||||
modify Bytes in place.
|
||||
"""
|
||||
offset = self.Vector(off)
|
||||
length = self.VectorLen(off) # TODO: length accounts for bytewidth, right?
|
||||
numpy_dtype = N.to_numpy_type(flags)
|
||||
return encode.GetVectorAsNumpy(numpy_dtype, self.Bytes, length, offset)
|
||||
|
||||
def GetVOffsetTSlot(self, slot, d):
|
||||
"""
|
||||
GetVOffsetTSlot retrieves the VOffsetT that the given vtable location
|
||||
|
||||
2
readme.md
Executable file → Normal file
2
readme.md
Executable file → Normal file
@@ -54,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 {
|
||||
|
||||
@@ -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),
|
||||
|
||||
11
samples/android/AndroidManifest.xml
Executable file → Normal file
11
samples/android/AndroidManifest.xml
Executable file → Normal file
@@ -17,17 +17,14 @@
|
||||
-->
|
||||
<!-- BEGIN_INCLUDE(manifest) -->
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.samples.FlatBufferSample"
|
||||
android:versionCode="1"
|
||||
android:versionName="1.0">
|
||||
package="com.samples.FlatBufferSample">
|
||||
|
||||
<uses-feature android:glEsVersion="0x00020000"></uses-feature>
|
||||
<!-- This is the platform API where NativeActivity was introduced. -->
|
||||
<uses-sdk android:minSdkVersion="9" />
|
||||
|
||||
<!-- This .apk has no Java code itself, so set hasCode to false. -->
|
||||
<application android:label="@string/app_name" android:hasCode="false">
|
||||
|
||||
<application android:label="@string/app_name"
|
||||
android:hasCode="false"
|
||||
android:allowBackup="false">
|
||||
<!-- Our activity is the built-in NativeActivity framework class.
|
||||
This will take care of integrating with our NDK code. -->
|
||||
<activity android:name="android.app.NativeActivity"
|
||||
|
||||
108
samples/android/build.gradle
Normal file
108
samples/android/build.gradle
Normal file
@@ -0,0 +1,108 @@
|
||||
// Copyright (c) 2017 Google, Inc.
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied
|
||||
// warranty. In no event will the authors be held liable for any damages
|
||||
// arising from the use of this software.
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it
|
||||
// freely, subject to the following restrictions:
|
||||
// 1. The origin of this software must not be misrepresented; you must not
|
||||
// claim that you wrote the original software. If you use this software
|
||||
// in a product, an acknowledgment in the product documentation would be
|
||||
// appreciated but is not required.
|
||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
||||
// misrepresented as being the original software.
|
||||
// 3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
buildscript {
|
||||
repositories {
|
||||
jcenter()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:2.3.0'
|
||||
}
|
||||
}
|
||||
|
||||
allprojects {
|
||||
repositories {
|
||||
jcenter()
|
||||
}
|
||||
}
|
||||
|
||||
apply plugin: 'com.android.application'
|
||||
|
||||
android {
|
||||
compileSdkVersion 25
|
||||
buildToolsVersion '25.0.2'
|
||||
|
||||
sourceSets {
|
||||
main {
|
||||
manifest.srcFile 'AndroidManifest.xml'
|
||||
res.srcDirs = ['res']
|
||||
}
|
||||
}
|
||||
|
||||
externalNativeBuild {
|
||||
ndkBuild {
|
||||
path "jni/Android.mk"
|
||||
}
|
||||
}
|
||||
|
||||
defaultConfig {
|
||||
applicationId 'com.samples.FlatBufferSample'
|
||||
// This is the platform API where NativeActivity was introduced.
|
||||
minSdkVersion 9
|
||||
targetSdkVersion 25
|
||||
versionCode 1
|
||||
versionName "1.0"
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled false
|
||||
}
|
||||
}
|
||||
|
||||
externalNativeBuild {
|
||||
ndkBuild {
|
||||
targets "FlatBufferSample"
|
||||
arguments "-j" + Runtime.getRuntime().availableProcessors()
|
||||
abiFilters "armeabi", "armeabi-v7a", "arm64-v8a", "x86", "x86_64"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
lintOptions {
|
||||
abortOnError false
|
||||
}
|
||||
|
||||
// Build with each STL variant.
|
||||
productFlavors {
|
||||
stlport {
|
||||
applicationIdSuffix ".stlport"
|
||||
versionNameSuffix "-stlport"
|
||||
externalNativeBuild {
|
||||
ndkBuild {
|
||||
arguments "APP_STL=stlport_static"
|
||||
}
|
||||
}
|
||||
}
|
||||
gnustl {
|
||||
applicationIdSuffix ".gnustl"
|
||||
versionNameSuffix "-gnustl"
|
||||
externalNativeBuild {
|
||||
ndkBuild {
|
||||
arguments "APP_STL=gnustl_static"
|
||||
}
|
||||
}
|
||||
}
|
||||
libcpp {
|
||||
applicationIdSuffix ".libcpp"
|
||||
versionNameSuffix "-libcpp"
|
||||
externalNativeBuild {
|
||||
ndkBuild {
|
||||
arguments "APP_STL=c++_static"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,511 +0,0 @@
|
||||
#!/bin/bash -eu
|
||||
#
|
||||
# Copyright (c) 2013 Google, Inc.
|
||||
#
|
||||
# This software is provided 'as-is', without any express or implied
|
||||
# warranty. In no event will the authors be held liable for any damages
|
||||
# arising from the use of this software.
|
||||
# Permission is granted to anyone to use this software for any purpose,
|
||||
# including commercial applications, and to alter it and redistribute it
|
||||
# freely, subject to the following restrictions:
|
||||
# 1. The origin of this software must not be misrepresented; you must not
|
||||
# claim that you wrote the original software. If you use this software
|
||||
# in a product, an acknowledgment in the product documentation would be
|
||||
# appreciated but is not required.
|
||||
# 2. Altered source versions must be plainly marked as such, and must not be
|
||||
# misrepresented as being the original software.
|
||||
# 3. This notice may not be removed or altered from any source distribution.
|
||||
#
|
||||
# Build, deploy, debug / execute a native Android package based upon
|
||||
# NativeActivity.
|
||||
|
||||
declare -r script_directory=$(dirname $0)
|
||||
declare -r android_root=${script_directory}/../../../../../../
|
||||
declare -r script_name=$(basename $0)
|
||||
declare -r android_manifest=AndroidManifest.xml
|
||||
declare -r os_name=$(uname -s)
|
||||
|
||||
# Minimum Android target version supported by this project.
|
||||
: ${BUILDAPK_ANDROID_TARGET_MINVERSION:=10}
|
||||
# Directory containing the Android SDK
|
||||
# (http://developer.android.com/sdk/index.html).
|
||||
: ${ANDROID_SDK_HOME:=}
|
||||
# Directory containing the Android NDK
|
||||
# (http://developer.android.com/tools/sdk/ndk/index.html).
|
||||
: ${NDK_HOME:=}
|
||||
|
||||
# Display script help and exit.
|
||||
usage() {
|
||||
echo "
|
||||
Build the Android package in the current directory and deploy it to a
|
||||
connected device.
|
||||
|
||||
Usage: ${script_name} \\
|
||||
[ADB_DEVICE=serial_number] [BUILD=0] [DEPLOY=0] [RUN_DEBUGGER=1] \
|
||||
[LAUNCH=0] [SWIG_BIN=swig_binary_directory] [SWIG_LIB=swig_include_directory] [ndk-build arguments ...]
|
||||
|
||||
ADB_DEVICE=serial_number:
|
||||
serial_number specifies the device to deploy the built apk to if multiple
|
||||
Android devices are connected to the host.
|
||||
BUILD=0:
|
||||
Disables the build of the package.
|
||||
DEPLOY=0:
|
||||
Disables the deployment of the built apk to the Android device.
|
||||
RUN_DEBUGGER=1:
|
||||
Launches the application in gdb after it has been deployed. To debug in
|
||||
gdb, NDK_DEBUG=1 must also be specified on the command line to build a
|
||||
debug apk.
|
||||
LAUNCH=0:
|
||||
Disable the launch of the apk on the Android device.
|
||||
SWIG_BIN=swig_binary_directory:
|
||||
The directory where the SWIG binary lives. No need to set this if SWIG is
|
||||
installed and point to from your PATH variable.
|
||||
SWIG_LIB=swig_include_directory:
|
||||
The directory where SWIG shared include files are, usually obtainable from
|
||||
commandline with \"swig -swiglib\". No need to set this if SWIG is installed
|
||||
and point to from your PATH variable.
|
||||
ndk-build arguments...:
|
||||
Additional arguments for ndk-build. See ndk-build -h for more information.
|
||||
" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Get the number of CPU cores present on the host.
|
||||
get_number_of_cores() {
|
||||
case ${os_name} in
|
||||
Darwin)
|
||||
sysctl hw.ncpu | awk '{ print $2 }'
|
||||
;;
|
||||
CYGWIN*|Linux)
|
||||
awk '/^processor/ { n=$3 } END { print n + 1 }' /proc/cpuinfo
|
||||
;;
|
||||
*)
|
||||
echo 1
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
# Get the package name from an AndroidManifest.xml file.
|
||||
get_package_name_from_manifest() {
|
||||
xmllint --xpath 'string(/manifest/@package)' "${1}"
|
||||
}
|
||||
|
||||
# Get the library name from an AndroidManifest.xml file.
|
||||
get_library_name_from_manifest() {
|
||||
echo "\
|
||||
setns android=http://schemas.android.com/apk/res/android
|
||||
xpath string(/manifest/application/activity\
|
||||
[@android:name=\"android.app.NativeActivity\"]/meta-data\
|
||||
[@android:name=\"android.app.lib_name\"]/@android:value)" |
|
||||
xmllint --shell "${1}" | awk '/Object is a string/ { print $NF }'
|
||||
}
|
||||
|
||||
# Get the number of Android devices connected to the system.
|
||||
get_number_of_devices_connected() {
|
||||
adb devices -l | \
|
||||
awk '/^..*$/ { if (p) { print $0 } }
|
||||
/List of devices attached/ { p = 1 }' | \
|
||||
wc -l
|
||||
return ${PIPESTATUS[0]}
|
||||
}
|
||||
|
||||
# Kill a process and its' children. This is provided for cygwin which
|
||||
# doesn't ship with pkill.
|
||||
kill_process_group() {
|
||||
local parent_pid="${1}"
|
||||
local child_pid=
|
||||
for child_pid in $(ps -f | \
|
||||
awk '{ if ($3 == '"${parent_pid}"') { print $2 } }'); do
|
||||
kill_process_group "${child_pid}"
|
||||
done
|
||||
kill "${parent_pid}" 2>/dev/null
|
||||
}
|
||||
|
||||
# Find and run "adb".
|
||||
adb() {
|
||||
local adb_path=
|
||||
for path in "$(which adb 2>/dev/null)" \
|
||||
"${ANDROID_SDK_HOME}/sdk/platform-tools/adb" \
|
||||
"${android_root}/prebuilts/sdk/platform-tools/adb"; do
|
||||
if [[ -e "${path}" ]]; then
|
||||
adb_path="${path}"
|
||||
break
|
||||
fi
|
||||
done
|
||||
if [[ "${adb_path}" == "" ]]; then
|
||||
echo -e "Unable to find adb." \
|
||||
"\nAdd the Android ADT sdk/platform-tools directory to the" \
|
||||
"PATH." >&2
|
||||
exit 1
|
||||
fi
|
||||
"${adb_path}" "$@"
|
||||
}
|
||||
|
||||
# Find and run "android".
|
||||
android() {
|
||||
local android_executable=android
|
||||
if echo "${os_name}" | grep -q CYGWIN; then
|
||||
android_executable=android.bat
|
||||
fi
|
||||
local android_path=
|
||||
for path in "$(which ${android_executable})" \
|
||||
"${ANDROID_SDK_HOME}/sdk/tools/${android_executable}" \
|
||||
"${android_root}/prebuilts/sdk/tools/${android_executable}"; do
|
||||
if [[ -e "${path}" ]]; then
|
||||
android_path="${path}"
|
||||
break
|
||||
fi
|
||||
done
|
||||
if [[ "${android_path}" == "" ]]; then
|
||||
echo -e "Unable to find android tool." \
|
||||
"\nAdd the Android ADT sdk/tools directory to the PATH." >&2
|
||||
exit 1
|
||||
fi
|
||||
# Make sure ant is installed.
|
||||
if [[ "$(which ant)" == "" ]]; then
|
||||
echo -e "Unable to find ant." \
|
||||
"\nPlease install ant and add to the PATH." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
"${android_path}" "$@"
|
||||
}
|
||||
|
||||
# Find and run "ndk-build"
|
||||
ndkbuild() {
|
||||
local ndkbuild_path=
|
||||
for path in "$(which ndk-build 2>/dev/null)" \
|
||||
"${NDK_HOME}/ndk-build" \
|
||||
"${android_root}/prebuilts/ndk/current/ndk-build"; do
|
||||
if [[ -e "${path}" ]]; then
|
||||
ndkbuild_path="${path}"
|
||||
break
|
||||
fi
|
||||
done
|
||||
if [[ "${ndkbuild_path}" == "" ]]; then
|
||||
echo -e "Unable to find ndk-build." \
|
||||
"\nAdd the Android NDK directory to the PATH." >&2
|
||||
exit 1
|
||||
fi
|
||||
"${ndkbuild_path}" "$@"
|
||||
}
|
||||
|
||||
# Get file modification time of $1 in seconds since the epoch.
|
||||
stat_mtime() {
|
||||
local filename="${1}"
|
||||
case ${os_name} in
|
||||
Darwin) stat -f%m "${filename}" 2>/dev/null || echo 0 ;;
|
||||
*) stat -c%Y "${filename}" 2>/dev/null || echo 0 ;;
|
||||
esac
|
||||
}
|
||||
|
||||
# Build the native (C/C++) build targets in the current directory.
|
||||
build_native_targets() {
|
||||
# Save the list of output modules in the install directory so that it's
|
||||
# possible to restore their timestamps after the build is complete. This
|
||||
# works around a bug in ndk/build/core/setup-app.mk which results in the
|
||||
# unconditional execution of the clean-installed-binaries rule.
|
||||
restore_libraries="$(find libs -type f 2>/dev/null | \
|
||||
sed -E 's@^libs/(.*)@\1@')"
|
||||
|
||||
# Build native code.
|
||||
ndkbuild -j$(get_number_of_cores) "$@"
|
||||
|
||||
# Restore installed libraries.
|
||||
# Obviously this is a nasty hack (along with ${restore_libraries} above) as
|
||||
# it assumes it knows where the NDK will be placing output files.
|
||||
(
|
||||
IFS=$'\n'
|
||||
for libpath in ${restore_libraries}; do
|
||||
source_library="obj/local/${libpath}"
|
||||
target_library="libs/${libpath}"
|
||||
if [[ -e "${source_library}" ]]; then
|
||||
cp -a "${source_library}" "${target_library}"
|
||||
fi
|
||||
done
|
||||
)
|
||||
}
|
||||
|
||||
# Select the oldest installed android build target that is at least as new as
|
||||
# BUILDAPK_ANDROID_TARGET_MINVERSION. If a suitable build target isn't found,
|
||||
# this function prints an error message and exits with an error.
|
||||
select_android_build_target() {
|
||||
local -r android_targets_installed=$( \
|
||||
android list targets | \
|
||||
awk -F'"' '/^id:.*android/ { print $2 }')
|
||||
local android_build_target=
|
||||
for android_target in $(echo "${android_targets_installed}" | \
|
||||
awk -F- '{ print $2 }' | sort -n); do
|
||||
local isNumber='^[0-9]+$'
|
||||
# skip preview API releases e.g. 'android-L'
|
||||
if [[ $android_target =~ $isNumber ]]; then
|
||||
if [[ $((android_target)) -ge \
|
||||
$((BUILDAPK_ANDROID_TARGET_MINVERSION)) ]]; then
|
||||
android_build_target="android-${android_target}"
|
||||
break
|
||||
fi
|
||||
# else
|
||||
# The API version is a letter, so skip it.
|
||||
fi
|
||||
done
|
||||
if [[ "${android_build_target}" == "" ]]; then
|
||||
echo -e \
|
||||
"Found installed Android targets:" \
|
||||
"$(echo ${android_targets_installed} | sed 's/ /\n /g;s/^/\n /;')" \
|
||||
"\nAndroid SDK platform" \
|
||||
"android-$((BUILDAPK_ANDROID_TARGET_MINVERSION))" \
|
||||
"must be installed to build this project." \
|
||||
"\nUse the \"android\" application to install API" \
|
||||
"$((BUILDAPK_ANDROID_TARGET_MINVERSION)) or newer." >&2
|
||||
exit 1
|
||||
fi
|
||||
echo "${android_build_target}"
|
||||
}
|
||||
|
||||
# Sign unsigned apk $1 and write the result to $2 with key store file $3 and
|
||||
# password $4.
|
||||
# If a key store file $3 and password $4 aren't specified, a temporary
|
||||
# (60 day) key is generated and used to sign the package.
|
||||
sign_apk() {
|
||||
local unsigned_apk="${1}"
|
||||
local signed_apk="${2}"
|
||||
if [[ $(stat_mtime "${unsigned_apk}") -gt \
|
||||
$(stat_mtime "${signed_apk}") ]]; then
|
||||
local -r key_alias=$(basename ${signed_apk} .apk)
|
||||
local keystore="${3}"
|
||||
local key_password="${4}"
|
||||
[[ "${keystore}" == "" ]] && keystore="${unsigned_apk}.keystore"
|
||||
[[ "${key_password}" == "" ]] && \
|
||||
key_password="${key_alias}123456"
|
||||
if [[ ! -e ${keystore} ]]; then
|
||||
keytool -genkey -v -dname "cn=, ou=${key_alias}, o=fpl" \
|
||||
-storepass ${key_password} \
|
||||
-keypass ${key_password} -keystore ${keystore} \
|
||||
-alias ${key_alias} -keyalg RSA -keysize 2048 -validity 60
|
||||
fi
|
||||
cp "${unsigned_apk}" "${signed_apk}"
|
||||
jarsigner -verbose -sigalg SHA1withRSA -digestalg SHA1 \
|
||||
-keystore ${keystore} -storepass ${key_password} \
|
||||
-keypass ${key_password} "${signed_apk}" ${key_alias}
|
||||
fi
|
||||
}
|
||||
|
||||
# Build the apk $1 for package filename $2 in the current directory using the
|
||||
# ant build target $3.
|
||||
build_apk() {
|
||||
local -r output_apk="${1}"
|
||||
local -r package_filename="${2}"
|
||||
local -r ant_target="${3}"
|
||||
# Get the list of installed android targets and select the oldest target
|
||||
# that is at least as new as BUILDAPK_ANDROID_TARGET_MINVERSION.
|
||||
local -r android_build_target=$(select_android_build_target)
|
||||
[[ "${android_build_target}" == "" ]] && exit 1
|
||||
echo "Building ${output_apk} for target ${android_build_target}" >&2
|
||||
|
||||
# Create / update build.xml and local.properties files.
|
||||
if [[ $(stat_mtime "${android_manifest}") -gt \
|
||||
$(stat_mtime build.xml) ]]; then
|
||||
android update project --target "${android_build_target}" \
|
||||
-n ${package_filename} --path .
|
||||
fi
|
||||
|
||||
# Use ant to build the apk.
|
||||
ant -quiet ${ant_target}
|
||||
|
||||
# Sign release apks with a temporary key as these packages will not be
|
||||
# redistributed.
|
||||
local unsigned_apk="bin/${package_filename}-${ant_target}-unsigned.apk"
|
||||
if [[ "${ant_target}" == "release" ]]; then
|
||||
sign_apk "${unsigned_apk}" "${output_apk}" "" ""
|
||||
fi
|
||||
}
|
||||
|
||||
# Uninstall package $1 and install apk $2 on device $3 where $3 is "-s device"
|
||||
# or an empty string. If $3 is an empty string adb will fail when multiple
|
||||
# devices are connected to the host system.
|
||||
install_apk() {
|
||||
local -r uninstall_package_name="${1}"
|
||||
local -r install_apk="${2}"
|
||||
local -r adb_device="${3}"
|
||||
# Uninstall the package if it's already installed.
|
||||
adb ${adb_device} uninstall "${uninstall_package_name}" 1>&2 > /dev/null || \
|
||||
true # no error check
|
||||
|
||||
# Install the apk.
|
||||
# NOTE: The following works around adb not returning an error code when
|
||||
# it fails to install an apk.
|
||||
echo "Install ${install_apk}" >&2
|
||||
local -r adb_install_result=$(adb ${adb_device} install "${install_apk}")
|
||||
echo "${adb_install_result}"
|
||||
if echo "${adb_install_result}" | grep -qF 'Failure ['; then
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Launch previously installed package $1 on device $2.
|
||||
# If $2 is an empty string adb will fail when multiple devices are connected
|
||||
# to the host system.
|
||||
launch_package() {
|
||||
(
|
||||
# Determine the SDK version of Android on the device.
|
||||
local -r android_sdk_version=$(
|
||||
adb ${adb_device} shell cat system/build.prop | \
|
||||
awk -F= '/ro.build.version.sdk/ {
|
||||
v=$2; sub(/[ \r\n]/, "", v); print v
|
||||
}')
|
||||
|
||||
# Clear logs from previous runs.
|
||||
# Note that logcat does not just 'tail' the logs, it dumps the entire log
|
||||
# history.
|
||||
adb ${adb_device} logcat -c
|
||||
|
||||
local finished_msg='Displayed '"${package_name}"
|
||||
local timeout_msg='Activity destroy timeout.*'"${package_name}"
|
||||
# Maximum time to wait before stopping log monitoring. 0 = infinity.
|
||||
local launch_timeout=0
|
||||
# If this is a Gingerbread device, kill log monitoring after 10 seconds.
|
||||
if [[ $((android_sdk_version)) -le 10 ]]; then
|
||||
launch_timeout=10
|
||||
fi
|
||||
# Display logcat in the background.
|
||||
# Stop displaying the log when the app launch / execution completes or the
|
||||
# logcat
|
||||
(
|
||||
adb ${adb_device} logcat | \
|
||||
awk "
|
||||
{
|
||||
print \$0
|
||||
}
|
||||
|
||||
/ActivityManager.*: ${finished_msg}/ {
|
||||
exit 0
|
||||
}
|
||||
|
||||
/ActivityManager.*: ${timeout_msg}/ {
|
||||
exit 0
|
||||
}" &
|
||||
adb_logcat_pid=$!;
|
||||
if [[ $((launch_timeout)) -gt 0 ]]; then
|
||||
sleep $((launch_timeout));
|
||||
kill ${adb_logcat_pid};
|
||||
else
|
||||
wait ${adb_logcat_pid};
|
||||
fi
|
||||
) &
|
||||
logcat_pid=$!
|
||||
# Kill adb logcat if this shell exits.
|
||||
trap "kill_process_group ${logcat_pid}" SIGINT SIGTERM EXIT
|
||||
|
||||
# If the SDK is newer than 10, "am" supports stopping an activity.
|
||||
adb_stop_activity=
|
||||
if [[ $((android_sdk_version)) -gt 10 ]]; then
|
||||
adb_stop_activity=-S
|
||||
fi
|
||||
|
||||
# Launch the activity and wait for it to complete.
|
||||
adb ${adb_device} shell am start ${adb_stop_activity} -n \
|
||||
${package_name}/android.app.NativeActivity
|
||||
|
||||
wait "${logcat_pid}"
|
||||
)
|
||||
}
|
||||
|
||||
# See usage().
|
||||
main() {
|
||||
# Parse arguments for this script.
|
||||
local adb_device=
|
||||
local ant_target=release
|
||||
local disable_deploy=0
|
||||
local disable_build=0
|
||||
local run_debugger=0
|
||||
local launch=1
|
||||
local build_package=1
|
||||
for opt; do
|
||||
case ${opt} in
|
||||
# NDK_DEBUG=0 tells ndk-build to build this as debuggable but to not
|
||||
# modify the underlying code whereas NDK_DEBUG=1 also builds as debuggable
|
||||
# but does modify the code
|
||||
NDK_DEBUG=1) ant_target=debug ;;
|
||||
NDK_DEBUG=0) ant_target=debug ;;
|
||||
ADB_DEVICE*) adb_device="$(\
|
||||
echo "${opt}" | sed -E 's/^ADB_DEVICE=([^ ]+)$/-s \1/;t;s/.*//')" ;;
|
||||
BUILD=0) disable_build=1 ;;
|
||||
DEPLOY=0) disable_deploy=1 ;;
|
||||
RUN_DEBUGGER=1) run_debugger=1 ;;
|
||||
LAUNCH=0) launch=0 ;;
|
||||
clean) build_package=0 disable_deploy=1 launch=0 ;;
|
||||
-h|--help|help) usage ;;
|
||||
esac
|
||||
done
|
||||
|
||||
# If a target device hasn't been specified and multiple devices are connected
|
||||
# to the host machine, display an error.
|
||||
local -r devices_connected=$(get_number_of_devices_connected)
|
||||
if [[ "${adb_device}" == "" && $((devices_connected)) -gt 1 && \
|
||||
($((disable_deploy)) -eq 0 || $((launch)) -ne 0 || \
|
||||
$((run_debugger)) -ne 0) ]]; then
|
||||
if [[ $((disable_deploy)) -ne 0 ]]; then
|
||||
echo "Deployment enabled, disable using DEPLOY=0" >&2
|
||||
fi
|
||||
if [[ $((launch)) -ne 0 ]]; then
|
||||
echo "Launch enabled." >&2
|
||||
fi
|
||||
if [[ $((disable_deploy)) -eq 0 ]]; then
|
||||
echo "Deployment enabled." >&2
|
||||
fi
|
||||
if [[ $((run_debugger)) -ne 0 ]]; then
|
||||
echo "Debugger launch enabled." >&2
|
||||
fi
|
||||
echo "
|
||||
Multiple Android devices are connected to this host. Either disable deployment
|
||||
and execution of the built .apk using:
|
||||
\"${script_name} DEPLOY=0 LAUNCH=0\"
|
||||
|
||||
or specify a device to deploy to using:
|
||||
\"${script_name} ADB_DEVICE=\${device_serial}\".
|
||||
|
||||
The Android devices connected to this machine are:
|
||||
$(adb devices -l)
|
||||
" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ $((disable_build)) -eq 0 ]]; then
|
||||
# Build the native target.
|
||||
build_native_targets "$@"
|
||||
fi
|
||||
|
||||
# Get the package name from the manifest.
|
||||
local -r package_name=$(get_package_name_from_manifest "${android_manifest}")
|
||||
if [[ "${package_name}" == "" ]]; then
|
||||
echo -e "No package name specified in ${android_manifest},"\
|
||||
"skipping apk build, deploy"
|
||||
"\nand launch steps." >&2
|
||||
exit 0
|
||||
fi
|
||||
local -r package_basename=${package_name/*./}
|
||||
local package_filename=$(get_library_name_from_manifest ${android_manifest})
|
||||
[[ "${package_filename}" == "" ]] && package_filename="${package_basename}"
|
||||
|
||||
# Output apk name.
|
||||
local -r output_apk="bin/${package_filename}-${ant_target}.apk"
|
||||
|
||||
if [[ $((disable_build)) -eq 0 && $((build_package)) -eq 1 ]]; then
|
||||
# Build the apk.
|
||||
build_apk "${output_apk}" "${package_filename}" "${ant_target}"
|
||||
fi
|
||||
|
||||
# Deploy to the device.
|
||||
if [[ $((disable_deploy)) -eq 0 ]]; then
|
||||
install_apk "${package_name}" "${output_apk}" "${adb_device}"
|
||||
fi
|
||||
|
||||
if [[ "${ant_target}" == "debug" && $((run_debugger)) -eq 1 ]]; then
|
||||
# Start debugging.
|
||||
ndk-gdb ${adb_device} --start
|
||||
elif [[ $((launch)) -eq 1 ]]; then
|
||||
launch_package "${package_name}" "${adb_device}"
|
||||
fi
|
||||
}
|
||||
|
||||
main "$@"
|
||||
BIN
samples/android/gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
BIN
samples/android/gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
Binary file not shown.
6
samples/android/gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
6
samples/android/gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
#Mon Jun 19 11:54:59 PDT 2017
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-4.0-all.zip
|
||||
172
samples/android/gradlew
vendored
Executable file
172
samples/android/gradlew
vendored
Executable file
@@ -0,0 +1,172 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
##############################################################################
|
||||
##
|
||||
## Gradle start up script for UN*X
|
||||
##
|
||||
##############################################################################
|
||||
|
||||
# Attempt to set APP_HOME
|
||||
# Resolve links: $0 may be a link
|
||||
PRG="$0"
|
||||
# Need this for relative symlinks.
|
||||
while [ -h "$PRG" ] ; do
|
||||
ls=`ls -ld "$PRG"`
|
||||
link=`expr "$ls" : '.*-> \(.*\)$'`
|
||||
if expr "$link" : '/.*' > /dev/null; then
|
||||
PRG="$link"
|
||||
else
|
||||
PRG=`dirname "$PRG"`"/$link"
|
||||
fi
|
||||
done
|
||||
SAVED="`pwd`"
|
||||
cd "`dirname \"$PRG\"`/" >/dev/null
|
||||
APP_HOME="`pwd -P`"
|
||||
cd "$SAVED" >/dev/null
|
||||
|
||||
APP_NAME="Gradle"
|
||||
APP_BASE_NAME=`basename "$0"`
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS=""
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD="maximum"
|
||||
|
||||
warn () {
|
||||
echo "$*"
|
||||
}
|
||||
|
||||
die () {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
exit 1
|
||||
}
|
||||
|
||||
# OS specific support (must be 'true' or 'false').
|
||||
cygwin=false
|
||||
msys=false
|
||||
darwin=false
|
||||
nonstop=false
|
||||
case "`uname`" in
|
||||
CYGWIN* )
|
||||
cygwin=true
|
||||
;;
|
||||
Darwin* )
|
||||
darwin=true
|
||||
;;
|
||||
MINGW* )
|
||||
msys=true
|
||||
;;
|
||||
NONSTOP* )
|
||||
nonstop=true
|
||||
;;
|
||||
esac
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
|
||||
# Determine the Java command to use to start the JVM.
|
||||
if [ -n "$JAVA_HOME" ] ; then
|
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||
# IBM's JDK on AIX uses strange locations for the executables
|
||||
JAVACMD="$JAVA_HOME/jre/sh/java"
|
||||
else
|
||||
JAVACMD="$JAVA_HOME/bin/java"
|
||||
fi
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
else
|
||||
JAVACMD="java"
|
||||
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
|
||||
MAX_FD_LIMIT=`ulimit -H -n`
|
||||
if [ $? -eq 0 ] ; then
|
||||
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
|
||||
MAX_FD="$MAX_FD_LIMIT"
|
||||
fi
|
||||
ulimit -n $MAX_FD
|
||||
if [ $? -ne 0 ] ; then
|
||||
warn "Could not set maximum file descriptor limit: $MAX_FD"
|
||||
fi
|
||||
else
|
||||
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
|
||||
fi
|
||||
fi
|
||||
|
||||
# For Darwin, add options to specify how the application appears in the dock
|
||||
if $darwin; then
|
||||
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
|
||||
fi
|
||||
|
||||
# For Cygwin, switch paths to Windows format before running java
|
||||
if $cygwin ; then
|
||||
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
||||
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
||||
JAVACMD=`cygpath --unix "$JAVACMD"`
|
||||
|
||||
# We build the pattern for arguments to be converted via cygpath
|
||||
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
|
||||
SEP=""
|
||||
for dir in $ROOTDIRSRAW ; do
|
||||
ROOTDIRS="$ROOTDIRS$SEP$dir"
|
||||
SEP="|"
|
||||
done
|
||||
OURCYGPATTERN="(^($ROOTDIRS))"
|
||||
# Add a user-defined pattern to the cygpath arguments
|
||||
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
|
||||
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
|
||||
fi
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
i=0
|
||||
for arg in "$@" ; do
|
||||
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
|
||||
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
|
||||
|
||||
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
|
||||
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
|
||||
else
|
||||
eval `echo args$i`="\"$arg\""
|
||||
fi
|
||||
i=$((i+1))
|
||||
done
|
||||
case $i in
|
||||
(0) set -- ;;
|
||||
(1) set -- "$args0" ;;
|
||||
(2) set -- "$args0" "$args1" ;;
|
||||
(3) set -- "$args0" "$args1" "$args2" ;;
|
||||
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
|
||||
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
|
||||
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
|
||||
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
|
||||
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
|
||||
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# Escape application args
|
||||
save () {
|
||||
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
|
||||
echo " "
|
||||
}
|
||||
APP_ARGS=$(save "$@")
|
||||
|
||||
# Collect all arguments for the java command, following the shell quoting and substitution rules
|
||||
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
|
||||
|
||||
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
|
||||
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
|
||||
cd "$(dirname "$0")"
|
||||
fi
|
||||
|
||||
exec "$JAVACMD" "$@"
|
||||
84
samples/android/gradlew.bat
vendored
Normal file
84
samples/android/gradlew.bat
vendored
Normal file
@@ -0,0 +1,84 @@
|
||||
@if "%DEBUG%" == "" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@rem Gradle startup script for Windows
|
||||
@rem
|
||||
@rem ##########################################################################
|
||||
|
||||
@rem Set local scope for the variables with windows NT shell
|
||||
if "%OS%"=="Windows_NT" setlocal
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%" == "" set DIRNAME=.
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
set DEFAULT_JVM_OPTS=
|
||||
|
||||
@rem Find java.exe
|
||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if "%ERRORLEVEL%" == "0" goto init
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:findJavaFromJavaHome
|
||||
set JAVA_HOME=%JAVA_HOME:"=%
|
||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||
|
||||
if exist "%JAVA_EXE%" goto init
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:init
|
||||
@rem Get command-line arguments, handling Windows variants
|
||||
|
||||
if not "%OS%" == "Windows_NT" goto win9xME_args
|
||||
|
||||
:win9xME_args
|
||||
@rem Slurp the command line arguments.
|
||||
set CMD_LINE_ARGS=
|
||||
set _SKIP=2
|
||||
|
||||
:win9xME_args_slurp
|
||||
if "x%~1" == "x" goto execute
|
||||
|
||||
set CMD_LINE_ARGS=%*
|
||||
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if "%ERRORLEVEL%"=="0" goto mainEnd
|
||||
|
||||
:fail
|
||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||
rem the _cmd.exe /c_ return code!
|
||||
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
|
||||
exit /b 1
|
||||
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
||||
|
||||
:omega
|
||||
2
samples/android/jni/Android.mk
Executable file → Normal file
2
samples/android/jni/Android.mk
Executable file → Normal file
@@ -38,7 +38,7 @@ $(info $(LOCAL_C_INCLUDES))
|
||||
LOCAL_SRC_FILES := main.cpp
|
||||
|
||||
LOCAL_CPPFLAGS := -std=c++11 -fexceptions -Wall -Wno-literal-suffix
|
||||
LOCAL_LDLIBS := -llog -landroid
|
||||
LOCAL_LDLIBS := -llog -landroid -latomic
|
||||
LOCAL_ARM_MODE := arm
|
||||
LOCAL_STATIC_LIBRARIES := android_native_app_glue flatbuffers
|
||||
|
||||
|
||||
6
samples/android/jni/Application.mk
Executable file → Normal file
6
samples/android/jni/Application.mk
Executable file → Normal file
@@ -13,10 +13,8 @@
|
||||
# 2. Altered source versions must be plainly marked as such, and must not be
|
||||
# misrepresented as being the original software.
|
||||
# 3. This notice may not be removed or altered from any source distribution.
|
||||
APP_PLATFORM := android-10
|
||||
APP_PLATFORM := android-9
|
||||
APP_PROJECT_PATH := $(call my-dir)/..
|
||||
APP_STL := gnustl_static
|
||||
|
||||
APP_STL ?= stlport_static
|
||||
APP_ABI := armeabi-v7a
|
||||
|
||||
APP_CPPFLAGS += -std=c++11
|
||||
|
||||
0
samples/android/res/values/strings.xml
Executable file → Normal file
0
samples/android/res/values/strings.xml
Executable file → Normal file
@@ -29,8 +29,7 @@ fi
|
||||
|
||||
# Execute `build_apk.sh` to build and run the android app.
|
||||
cd android
|
||||
./build_apk.sh
|
||||
./gradlew build
|
||||
|
||||
|
||||
|
||||
# Cleanup the temporary files.
|
||||
rm build.xml local.properties proguard-project.txt project.properties
|
||||
rm -rf bin libs obj
|
||||
|
||||
0
samples/monster.fbs
Executable file → Normal file
0
samples/monster.fbs
Executable file → Normal file
@@ -25,6 +25,15 @@ 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",
|
||||
@@ -47,6 +56,14 @@ enum Equipment {
|
||||
Equipment_MAX = Equipment_Weapon
|
||||
};
|
||||
|
||||
inline Equipment (&EnumValuesEquipment())[2] {
|
||||
static Equipment values[] = {
|
||||
Equipment_NONE,
|
||||
Equipment_Weapon
|
||||
};
|
||||
return values;
|
||||
}
|
||||
|
||||
inline const char **EnumNamesEquipment() {
|
||||
static const char *names[] = {
|
||||
"NONE",
|
||||
@@ -71,32 +88,42 @@ template<> struct EquipmentTraits<Weapon> {
|
||||
|
||||
struct EquipmentUnion {
|
||||
Equipment type;
|
||||
flatbuffers::NativeTable *table;
|
||||
void *value;
|
||||
|
||||
EquipmentUnion() : type(Equipment_NONE), table(nullptr) {}
|
||||
EquipmentUnion(EquipmentUnion&& u):
|
||||
type(std::move(u.type)), table(std::move(u.table)) {}
|
||||
EquipmentUnion(const EquipmentUnion &);
|
||||
EquipmentUnion &operator=(const EquipmentUnion &);
|
||||
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();
|
||||
|
||||
#ifndef FLATBUFFERS_CPP98_STL
|
||||
template <typename T>
|
||||
void Set(T&& value) {
|
||||
void Set(T&& val) {
|
||||
Reset();
|
||||
type = EquipmentTraits<typename T::TableType>::enum_value;
|
||||
if (type != Equipment_NONE) {
|
||||
table = new T(std::forward<T>(value));
|
||||
value = new T(std::forward<T>(val));
|
||||
}
|
||||
}
|
||||
#endif // FLATBUFFERS_CPP98_STL
|
||||
|
||||
static flatbuffers::NativeTable *UnPack(const void *obj, Equipment type, const flatbuffers::resolver_function_t *resolver);
|
||||
static void *UnPack(const void *obj, Equipment type, const flatbuffers::resolver_function_t *resolver);
|
||||
flatbuffers::Offset<void> Pack(flatbuffers::FlatBufferBuilder &_fbb, const flatbuffers::rehasher_function_t *_rehasher = nullptr) const;
|
||||
|
||||
WeaponT *AsWeapon() {
|
||||
return type == Equipment_Weapon ?
|
||||
reinterpret_cast<WeaponT *>(table) : nullptr;
|
||||
reinterpret_cast<WeaponT *>(value) : nullptr;
|
||||
}
|
||||
const WeaponT *AsWeapon() const {
|
||||
return type == Equipment_Weapon ?
|
||||
reinterpret_cast<const WeaponT *>(value) : nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -113,9 +140,6 @@ MANUALLY_ALIGNED_STRUCT(4) Vec3 FLATBUFFERS_FINAL_CLASS {
|
||||
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)),
|
||||
@@ -144,13 +168,13 @@ STRUCT_END(Vec3, 12);
|
||||
|
||||
struct MonsterT : public flatbuffers::NativeTable {
|
||||
typedef Monster TableType;
|
||||
std::unique_ptr<Vec3> pos;
|
||||
flatbuffers::unique_ptr<Vec3> pos;
|
||||
int16_t mana;
|
||||
int16_t hp;
|
||||
std::string name;
|
||||
std::vector<uint8_t> inventory;
|
||||
Color color;
|
||||
std::vector<std::unique_ptr<WeaponT>> weapons;
|
||||
std::vector<flatbuffers::unique_ptr<WeaponT>> weapons;
|
||||
EquipmentUnion equipped;
|
||||
MonsterT()
|
||||
: mana(150),
|
||||
@@ -182,13 +206,13 @@ struct Monster FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
|
||||
return GetField<int16_t>(VT_MANA, 150);
|
||||
}
|
||||
bool mutate_mana(int16_t _mana) {
|
||||
return SetField(VT_MANA, _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(VT_HP, _hp);
|
||||
return SetField<int16_t>(VT_HP, _hp, 100);
|
||||
}
|
||||
const flatbuffers::String *name() const {
|
||||
return GetPointer<const flatbuffers::String *>(VT_NAME);
|
||||
@@ -206,7 +230,7 @@ struct Monster FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
|
||||
return static_cast<Color>(GetField<int8_t>(VT_COLOR, 2));
|
||||
}
|
||||
bool mutate_color(Color _color) {
|
||||
return SetField(VT_COLOR, static_cast<int8_t>(_color));
|
||||
return SetField<int8_t>(VT_COLOR, static_cast<int8_t>(_color), 2);
|
||||
}
|
||||
const flatbuffers::Vector<flatbuffers::Offset<Weapon>> *weapons() const {
|
||||
return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<Weapon>> *>(VT_WEAPONS);
|
||||
@@ -218,11 +242,15 @@ struct Monster FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
|
||||
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));
|
||||
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);
|
||||
}
|
||||
@@ -231,16 +259,16 @@ struct Monster FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
|
||||
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();
|
||||
}
|
||||
@@ -249,6 +277,10 @@ struct Monster FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
|
||||
static flatbuffers::Offset<Monster> Pack(flatbuffers::FlatBufferBuilder &_fbb, const MonsterT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr);
|
||||
};
|
||||
|
||||
template<> inline const Weapon *Monster::equipped_as<Weapon>() const {
|
||||
return equipped_as_Weapon();
|
||||
}
|
||||
|
||||
struct MonsterBuilder {
|
||||
flatbuffers::FlatBufferBuilder &fbb_;
|
||||
flatbuffers::uoffset_t start_;
|
||||
@@ -279,13 +311,13 @@ struct MonsterBuilder {
|
||||
void add_equipped(flatbuffers::Offset<void> equipped) {
|
||||
fbb_.AddOffset(Monster::VT_EQUIPPED, equipped);
|
||||
}
|
||||
MonsterBuilder(flatbuffers::FlatBufferBuilder &_fbb)
|
||||
explicit MonsterBuilder(flatbuffers::FlatBufferBuilder &_fbb)
|
||||
: fbb_(_fbb) {
|
||||
start_ = fbb_.StartTable();
|
||||
}
|
||||
MonsterBuilder &operator=(const MonsterBuilder &);
|
||||
flatbuffers::Offset<Monster> Finish() {
|
||||
const auto end = fbb_.EndTable(start_, 10);
|
||||
const auto end = fbb_.EndTable(start_);
|
||||
auto o = flatbuffers::Offset<Monster>(end);
|
||||
return o;
|
||||
}
|
||||
@@ -366,11 +398,11 @@ struct Weapon FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
|
||||
return GetField<int16_t>(VT_DAMAGE, 0);
|
||||
}
|
||||
bool mutate_damage(int16_t _damage) {
|
||||
return SetField(VT_DAMAGE, _damage);
|
||||
return SetField<int16_t>(VT_DAMAGE, _damage, 0);
|
||||
}
|
||||
bool Verify(flatbuffers::Verifier &verifier) const {
|
||||
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();
|
||||
@@ -389,13 +421,13 @@ struct WeaponBuilder {
|
||||
void add_damage(int16_t damage) {
|
||||
fbb_.AddElement<int16_t>(Weapon::VT_DAMAGE, damage, 0);
|
||||
}
|
||||
WeaponBuilder(flatbuffers::FlatBufferBuilder &_fbb)
|
||||
explicit WeaponBuilder(flatbuffers::FlatBufferBuilder &_fbb)
|
||||
: fbb_(_fbb) {
|
||||
start_ = fbb_.StartTable();
|
||||
}
|
||||
WeaponBuilder &operator=(const WeaponBuilder &);
|
||||
flatbuffers::Offset<Weapon> Finish() {
|
||||
const auto end = fbb_.EndTable(start_, 2);
|
||||
const auto end = fbb_.EndTable(start_);
|
||||
auto o = flatbuffers::Offset<Weapon>(end);
|
||||
return o;
|
||||
}
|
||||
@@ -432,15 +464,15 @@ inline MonsterT *Monster::UnPack(const flatbuffers::resolver_function_t *_resolv
|
||||
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 = pos(); if (_e) _o->pos = flatbuffers::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(std::unique_ptr<WeaponT>(_e->Get(_i)->UnPack(_resolver))); } };
|
||||
{ auto _e = weapons(); if (_e) { _o->weapons.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->weapons[_i] = flatbuffers::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(),_resolver); };
|
||||
{ auto _e = equipped(); if (_e) _o->equipped.value = EquipmentUnion::UnPack(_e, equipped_type(), _resolver); };
|
||||
}
|
||||
|
||||
inline flatbuffers::Offset<Monster> Monster::Pack(flatbuffers::FlatBufferBuilder &_fbb, const MonsterT* _o, const flatbuffers::rehasher_function_t *_rehasher) {
|
||||
@@ -450,13 +482,14 @@ inline flatbuffers::Offset<Monster> Monster::Pack(flatbuffers::FlatBufferBuilder
|
||||
inline flatbuffers::Offset<Monster> CreateMonster(flatbuffers::FlatBufferBuilder &_fbb, const MonsterT *_o, const flatbuffers::rehasher_function_t *_rehasher) {
|
||||
(void)_rehasher;
|
||||
(void)_o;
|
||||
struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const MonsterT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va;
|
||||
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 _name = _o->name.empty() ? 0 : _fbb.CreateString(_o->name);
|
||||
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 _weapons = _o->weapons.size() ? _fbb.CreateVector<flatbuffers::Offset<Weapon>> (_o->weapons.size(), [](size_t i, _VectorArgs *__va) { return CreateWeapon(*__va->__fbb, __va->__o->weapons[i].get(), __va->__rehasher); }, &_va ) : 0;
|
||||
auto _equipped_type = _o->equipped.type;
|
||||
auto _equipped = _o->equipped.Pack(_fbb);
|
||||
return MyGame::Sample::CreateMonster(
|
||||
@@ -492,7 +525,8 @@ inline flatbuffers::Offset<Weapon> Weapon::Pack(flatbuffers::FlatBufferBuilder &
|
||||
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;
|
||||
struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const WeaponT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va;
|
||||
auto _name = _o->name.empty() ? 0 : _fbb.CreateString(_o->name);
|
||||
auto _damage = _o->damage;
|
||||
return MyGame::Sample::CreateWeapon(
|
||||
_fbb,
|
||||
@@ -524,7 +558,7 @@ inline bool VerifyEquipmentVector(flatbuffers::Verifier &verifier, const flatbuf
|
||||
return true;
|
||||
}
|
||||
|
||||
inline flatbuffers::NativeTable *EquipmentUnion::UnPack(const void *obj, Equipment type, const flatbuffers::resolver_function_t *resolver) {
|
||||
inline void *EquipmentUnion::UnPack(const void *obj, Equipment type, const flatbuffers::resolver_function_t *resolver) {
|
||||
switch (type) {
|
||||
case Equipment_Weapon: {
|
||||
auto ptr = reinterpret_cast<const Weapon *>(obj);
|
||||
@@ -537,26 +571,151 @@ inline flatbuffers::NativeTable *EquipmentUnion::UnPack(const void *obj, Equipme
|
||||
inline flatbuffers::Offset<void> EquipmentUnion::Pack(flatbuffers::FlatBufferBuilder &_fbb, const flatbuffers::rehasher_function_t *_rehasher) const {
|
||||
switch (type) {
|
||||
case Equipment_Weapon: {
|
||||
auto ptr = reinterpret_cast<const WeaponT *>(table);
|
||||
auto ptr = reinterpret_cast<const WeaponT *>(value);
|
||||
return CreateWeapon(_fbb, ptr, _rehasher).Union();
|
||||
}
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
inline EquipmentUnion::EquipmentUnion(const EquipmentUnion &u) FLATBUFFERS_NOEXCEPT : type(u.type), value(nullptr) {
|
||||
switch (type) {
|
||||
case Equipment_Weapon: {
|
||||
value = new WeaponT(*reinterpret_cast<WeaponT *>(u.value));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
inline void EquipmentUnion::Reset() {
|
||||
switch (type) {
|
||||
case Equipment_Weapon: {
|
||||
auto ptr = reinterpret_cast<WeaponT *>(table);
|
||||
auto ptr = reinterpret_cast<WeaponT *>(value);
|
||||
delete ptr;
|
||||
break;
|
||||
}
|
||||
default: break;
|
||||
}
|
||||
table = nullptr;
|
||||
value = nullptr;
|
||||
type = Equipment_NONE;
|
||||
}
|
||||
|
||||
inline flatbuffers::TypeTable *Vec3TypeTable();
|
||||
|
||||
inline flatbuffers::TypeTable *MonsterTypeTable();
|
||||
|
||||
inline flatbuffers::TypeTable *WeaponTypeTable();
|
||||
|
||||
inline flatbuffers::TypeTable *ColorTypeTable() {
|
||||
static flatbuffers::TypeCode type_codes[] = {
|
||||
{ flatbuffers::ET_CHAR, 0, 0 },
|
||||
{ flatbuffers::ET_CHAR, 0, 0 },
|
||||
{ flatbuffers::ET_CHAR, 0, 0 }
|
||||
};
|
||||
static flatbuffers::TypeFunction type_refs[] = {
|
||||
ColorTypeTable
|
||||
};
|
||||
static const char *names[] = {
|
||||
"Red",
|
||||
"Green",
|
||||
"Blue"
|
||||
};
|
||||
static flatbuffers::TypeTable tt = {
|
||||
flatbuffers::ST_ENUM, 3, type_codes, type_refs, nullptr, names
|
||||
};
|
||||
return &tt;
|
||||
}
|
||||
|
||||
inline flatbuffers::TypeTable *EquipmentTypeTable() {
|
||||
static flatbuffers::TypeCode type_codes[] = {
|
||||
{ flatbuffers::ET_SEQUENCE, 0, -1 },
|
||||
{ flatbuffers::ET_SEQUENCE, 0, 0 }
|
||||
};
|
||||
static flatbuffers::TypeFunction type_refs[] = {
|
||||
WeaponTypeTable
|
||||
};
|
||||
static const char *names[] = {
|
||||
"NONE",
|
||||
"Weapon"
|
||||
};
|
||||
static flatbuffers::TypeTable tt = {
|
||||
flatbuffers::ST_UNION, 2, type_codes, type_refs, nullptr, names
|
||||
};
|
||||
return &tt;
|
||||
}
|
||||
|
||||
inline flatbuffers::TypeTable *Vec3TypeTable() {
|
||||
static flatbuffers::TypeCode type_codes[] = {
|
||||
{ flatbuffers::ET_FLOAT, 0, -1 },
|
||||
{ flatbuffers::ET_FLOAT, 0, -1 },
|
||||
{ flatbuffers::ET_FLOAT, 0, -1 }
|
||||
};
|
||||
static const int32_t values[] = { 0, 4, 8, 12 };
|
||||
static const char *names[] = {
|
||||
"x",
|
||||
"y",
|
||||
"z"
|
||||
};
|
||||
static flatbuffers::TypeTable tt = {
|
||||
flatbuffers::ST_STRUCT, 3, type_codes, nullptr, values, names
|
||||
};
|
||||
return &tt;
|
||||
}
|
||||
|
||||
inline flatbuffers::TypeTable *MonsterTypeTable() {
|
||||
static flatbuffers::TypeCode type_codes[] = {
|
||||
{ flatbuffers::ET_SEQUENCE, 0, 0 },
|
||||
{ flatbuffers::ET_SHORT, 0, -1 },
|
||||
{ flatbuffers::ET_SHORT, 0, -1 },
|
||||
{ flatbuffers::ET_STRING, 0, -1 },
|
||||
{ flatbuffers::ET_BOOL, 0, -1 },
|
||||
{ flatbuffers::ET_UCHAR, 1, -1 },
|
||||
{ flatbuffers::ET_CHAR, 0, 1 },
|
||||
{ flatbuffers::ET_SEQUENCE, 1, 2 },
|
||||
{ flatbuffers::ET_UTYPE, 0, 3 },
|
||||
{ flatbuffers::ET_SEQUENCE, 0, 3 }
|
||||
};
|
||||
static flatbuffers::TypeFunction type_refs[] = {
|
||||
Vec3TypeTable,
|
||||
ColorTypeTable,
|
||||
WeaponTypeTable,
|
||||
EquipmentTypeTable
|
||||
};
|
||||
static const char *names[] = {
|
||||
"pos",
|
||||
"mana",
|
||||
"hp",
|
||||
"name",
|
||||
"friendly",
|
||||
"inventory",
|
||||
"color",
|
||||
"weapons",
|
||||
"equipped_type",
|
||||
"equipped"
|
||||
};
|
||||
static flatbuffers::TypeTable tt = {
|
||||
flatbuffers::ST_TABLE, 10, type_codes, type_refs, nullptr, names
|
||||
};
|
||||
return &tt;
|
||||
}
|
||||
|
||||
inline flatbuffers::TypeTable *WeaponTypeTable() {
|
||||
static flatbuffers::TypeCode type_codes[] = {
|
||||
{ flatbuffers::ET_STRING, 0, -1 },
|
||||
{ flatbuffers::ET_SHORT, 0, -1 }
|
||||
};
|
||||
static const char *names[] = {
|
||||
"name",
|
||||
"damage"
|
||||
};
|
||||
static flatbuffers::TypeTable tt = {
|
||||
flatbuffers::ST_TABLE, 2, type_codes, nullptr, nullptr, names
|
||||
};
|
||||
return &tt;
|
||||
}
|
||||
|
||||
inline const MyGame::Sample::Monster *GetMonster(const void *buf) {
|
||||
return flatbuffers::GetRoot<MyGame::Sample::Monster>(buf);
|
||||
}
|
||||
@@ -576,10 +735,10 @@ inline void FinishMonsterBuffer(
|
||||
fbb.Finish(root);
|
||||
}
|
||||
|
||||
inline std::unique_ptr<MonsterT> UnPackMonster(
|
||||
inline flatbuffers::unique_ptr<MonsterT> UnPackMonster(
|
||||
const void *buf,
|
||||
const flatbuffers::resolver_function_t *res = nullptr) {
|
||||
return std::unique_ptr<MonsterT>(GetMonster(buf)->UnPack(res));
|
||||
return flatbuffers::unique_ptr<MonsterT>(GetMonster(buf)->UnPack(res));
|
||||
}
|
||||
|
||||
} // namespace Sample
|
||||
|
||||
0
samples/monsterdata.json
Executable file → Normal file
0
samples/monsterdata.json
Executable file → Normal file
@@ -16,8 +16,14 @@
|
||||
|
||||
#include "flatbuffers/code_generators.h"
|
||||
#include <assert.h>
|
||||
#include "flatbuffers/base.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) {
|
||||
@@ -53,7 +59,7 @@ void CodeWriter::operator+=(std::string text) {
|
||||
// Update the text to everything after the }}.
|
||||
text = text.substr(end + 2);
|
||||
}
|
||||
if (!text.empty() && text.back() == '\\') {
|
||||
if (!text.empty() && string_back(text) == '\\') {
|
||||
text.pop_back();
|
||||
stream_ << text;
|
||||
} else {
|
||||
@@ -63,7 +69,7 @@ void CodeWriter::operator+=(std::string text) {
|
||||
|
||||
const char *BaseGenerator::FlatBuffersGeneratedWarning() {
|
||||
return "automatically generated by the FlatBuffers compiler,"
|
||||
" do not modify\n\n";
|
||||
" do not modify";
|
||||
}
|
||||
|
||||
std::string BaseGenerator::NamespaceDir(const Parser &parser,
|
||||
@@ -84,18 +90,6 @@ std::string BaseGenerator::NamespaceDir(const Namespace &ns) const {
|
||||
return BaseGenerator::NamespaceDir(parser_, path_, ns);
|
||||
}
|
||||
|
||||
bool BaseGenerator::IsEverythingGenerated() const {
|
||||
for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
|
||||
++it) {
|
||||
if (!(*it)->generated) return false;
|
||||
}
|
||||
for (auto it = parser_.structs_.vec.begin();
|
||||
it != parser_.structs_.vec.end(); ++it) {
|
||||
if (!(*it)->generated) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string BaseGenerator::FullNamespace(const char *separator,
|
||||
const Namespace &ns) {
|
||||
std::string namespace_name;
|
||||
@@ -130,6 +124,20 @@ 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 ((it + 1) != 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) {
|
||||
@@ -156,3 +164,7 @@ void GenComment(const std::vector<std::string> &dc, std::string *code_ptr,
|
||||
}
|
||||
|
||||
} // namespace flatbuffers
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
254
src/flatc.cpp
254
src/flatc.cpp
@@ -16,7 +16,9 @@
|
||||
|
||||
#include "flatbuffers/flatc.h"
|
||||
|
||||
#define FLATC_VERSION "1.6.0 (" __DATE__ ")"
|
||||
#include <list>
|
||||
|
||||
#define FLATC_VERSION "1.8.0 (" __DATE__ ")"
|
||||
|
||||
namespace flatbuffers {
|
||||
|
||||
@@ -46,7 +48,7 @@ void FlatCompiler::Error(const std::string &err, bool usage,
|
||||
|
||||
std::string FlatCompiler::GetUsageString(const char* program_name) const {
|
||||
std::stringstream ss;
|
||||
ss << "Usageaa: " << program_name << " [OPTION]... FILE... [-- FILE...]\n";
|
||||
ss << "Usage: " << program_name << " [OPTION]... FILE... [-- FILE...]\n";
|
||||
for (size_t i = 0; i < params_.num_generators; ++i) {
|
||||
const Generator& g = params_.generators[i];
|
||||
|
||||
@@ -81,13 +83,21 @@ std::string FlatCompiler::GetUsageString(const char* program_name) const {
|
||||
" --no-includes Don\'t generate include statements for included\n"
|
||||
" schemas the generated file depends on (C++).\n"
|
||||
" --gen-mutable Generate accessors that can mutate buffers in-place.\n"
|
||||
" --gen-onefile Generate single output file for C#.\n"
|
||||
" --gen-onefile Generate single output file for C# and Go.\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"
|
||||
" --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"
|
||||
" --gen-nullable Add Clang _Nullable for C++ pointer. or @Nullable for Java\n"
|
||||
" --object-prefix Customise class prefix for C++ object-based API.\n"
|
||||
" --object-suffix Customise class suffix for C++ object-based API.\n"
|
||||
" Default value is \"T\"\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"
|
||||
" --go-import Generate the overrided import for flatbuffers in Golang.\n"
|
||||
" (default is \"github.com/google/flatbuffers/go\")\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"
|
||||
@@ -100,8 +110,13 @@ std::string FlatCompiler::GetUsageString(const char* program_name) const {
|
||||
" PATH \n"
|
||||
" --include-prefix Prefix this path to any generated include statements.\n"
|
||||
" PATH\n"
|
||||
"FILEs may be schemas, or JSON files (conforming to preceding schema)\n"
|
||||
"FILEs after the -- must be binary flatbuffer format files.\n"
|
||||
" --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"
|
||||
" --reflect-types Add minimal type reflection to code generation.\n"
|
||||
" --reflect-names Add minimal type/name reflection.\n"
|
||||
"FILEs may be schemas (must end in .fbs), or JSON files (conforming to preceding\n"
|
||||
"schema). 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: " << program_name << " -c -b schema1.fbs schema2.fbs data.json\n";
|
||||
@@ -122,6 +137,7 @@ int FlatCompiler::Compile(int argc, const char** argv) {
|
||||
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);
|
||||
@@ -135,21 +151,29 @@ int FlatCompiler::Compile(int argc, const char** argv) {
|
||||
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);
|
||||
conform_include_directories.push_back(argv[argi]);
|
||||
include_directories_storage.push_back(
|
||||
flatbuffers::PosixPath(argv[argi]));
|
||||
conform_include_directories.push_back(
|
||||
include_directories_storage.back().c_str());
|
||||
} else if (arg == "--include-prefix") {
|
||||
if (++argi >= argc) Error("missing path following" + arg, true);
|
||||
opts.include_prefix = argv[argi];
|
||||
if (opts.include_prefix.back() != '/' &&
|
||||
opts.include_prefix.back() != '\\') opts.include_prefix += "/";
|
||||
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") {
|
||||
@@ -158,6 +182,12 @@ int FlatCompiler::Compile(int argc, const char** argv) {
|
||||
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 == "--go-import") {
|
||||
if (++argi >= argc) Error("missing golang import" + arg, true);
|
||||
opts.go_import = argv[argi];
|
||||
} else if(arg == "--defaults-json") {
|
||||
opts.output_default_scalars_in_json = true;
|
||||
} else if (arg == "--unknown-json") {
|
||||
@@ -178,6 +208,17 @@ int FlatCompiler::Compile(int argc, const char** argv) {
|
||||
} 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-nullable") {
|
||||
opts.gen_nullable = true;
|
||||
} else if (arg == "--object-prefix") {
|
||||
if (++argi >= argc) Error("missing prefix following" + arg, true);
|
||||
opts.object_prefix = argv[argi];
|
||||
} else if (arg == "--object-suffix") {
|
||||
if (++argi >= argc) Error("missing suffix following" + arg, true);
|
||||
opts.object_suffix = argv[argi];
|
||||
} else if(arg == "--gen-all") {
|
||||
opts.generate_all = true;
|
||||
opts.include_dependence_headers = false;
|
||||
@@ -194,8 +235,6 @@ int FlatCompiler::Compile(int argc, const char** argv) {
|
||||
binary_files_from = filenames.size();
|
||||
} else if(arg == "--proto") {
|
||||
opts.proto_mode = true;
|
||||
} else if(arg == "--escape-proto-ids") {
|
||||
opts.escape_proto_identifiers = true;
|
||||
} else if(arg == "--schema") {
|
||||
schema_binary = true;
|
||||
} else if(arg == "-M") {
|
||||
@@ -207,6 +246,14 @@ int FlatCompiler::Compile(int argc, const char** argv) {
|
||||
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 if(arg == "--reflect-types") {
|
||||
opts.mini_reflect = IDLOptions::kTypes;
|
||||
} else if(arg == "--reflect-names") {
|
||||
opts.mini_reflect = IDLOptions::kTypesAndNames;
|
||||
} else {
|
||||
for (size_t i = 0; i < params_.num_generators; ++i) {
|
||||
if (arg == params_.generators[i].generator_opt_long ||
|
||||
@@ -222,7 +269,7 @@ int FlatCompiler::Compile(int argc, const char** argv) {
|
||||
found:;
|
||||
}
|
||||
} else {
|
||||
filenames.push_back(argv[argi]);
|
||||
filenames.push_back(flatbuffers::PosixPath(argv[argi]));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -249,101 +296,110 @@ int FlatCompiler::Compile(int argc, const char** argv) {
|
||||
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) {
|
||||
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 \"" +
|
||||
*file_it +
|
||||
"\" matches the schema, use --raw-binary to read this file"
|
||||
" anyway.");
|
||||
} else if (!flatbuffers::BufferHasIdentifier(contents.c_str(),
|
||||
parser->file_identifier_.c_str())) {
|
||||
Error("binary \"" +
|
||||
*file_it +
|
||||
"\" 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: " + *file_it, true);
|
||||
}
|
||||
auto is_schema = flatbuffers::GetExtension(*file_it) == "fbs";
|
||||
if (is_schema) {
|
||||
// If we're processing multiple schemas, make sure to start each
|
||||
// one from scratch. If it depends on previous schemas it must do
|
||||
// so explicitly using an include.
|
||||
parser.reset(new flatbuffers::Parser(opts));
|
||||
}
|
||||
ParseFile(*parser.get(), *file_it, contents, include_directories);
|
||||
if (is_schema && !conform_to_schema.empty()) {
|
||||
auto err = parser->ConformTo(conform_parser);
|
||||
if (!err.empty()) Error("schemas don\'t conform: " + err);
|
||||
}
|
||||
if (schema_binary) {
|
||||
parser->Serialize();
|
||||
parser->file_extension_ = reflection::SchemaExtension();
|
||||
bool is_binary = static_cast<size_t>(file_it - filenames.begin()) >=
|
||||
binary_files_from;
|
||||
auto ext = flatbuffers::GetExtension(filename);
|
||||
auto is_schema = ext == "fbs" || ext == "proto";
|
||||
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 && !parser->builder_.GetSize()) {
|
||||
// If a file doesn't end in .fbs, it must be json/binary. Ensure we
|
||||
// didn't just parse a schema with a different extension.
|
||||
Error("input file is neither json nor a .fbs (schema) file: " +
|
||||
filename, true);
|
||||
}
|
||||
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 < 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].generate(*parser.get(), output_path, filebase)) {
|
||||
Error(std::string("Unable to generate ") +
|
||||
params_.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 = params_.generators[i].make_rule(
|
||||
*parser.get(), output_path, *file_it);
|
||||
if (!make_rule.empty())
|
||||
printf("%s\n", flatbuffers::WordWrap(
|
||||
make_rule, 80, " ", " \\").c_str());
|
||||
}
|
||||
if (grpc_enabled) {
|
||||
if (params_.generators[i].generateGRPC != nullptr) {
|
||||
if (!params_.generators[i].generateGRPC(*parser.get(), output_path,
|
||||
filebase)) {
|
||||
Error(std::string("Unable to generate GRPC interface for") +
|
||||
params_.generators[i].lang_name);
|
||||
}
|
||||
} else {
|
||||
Warn(std::string("GRPC interface generator not implemented for ")
|
||||
+ params_.generators[i].lang_name);
|
||||
}
|
||||
Warn(std::string("GRPC interface generator not implemented for ")
|
||||
+ params_.generators[i].lang_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (opts.proto_mode) GenerateFBS(*parser.get(), output_path, filebase);
|
||||
if (opts.proto_mode) GenerateFBS(*parser.get(), output_path, filebase);
|
||||
|
||||
// We do not want to generate code for the definitions in this file
|
||||
// in any files coming up next.
|
||||
parser->MarkGenerated();
|
||||
// We do not want to generate code for the definitions in this file
|
||||
// in any files coming up next.
|
||||
parser->MarkGenerated();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -46,52 +46,62 @@ int main(int argc, const char *argv[]) {
|
||||
g_program_name = argv[0];
|
||||
|
||||
const flatbuffers::FlatCompiler::Generator generators[] = {
|
||||
{ flatbuffers::GenerateBinary, "-b", "--binary", "binary",
|
||||
{ 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",
|
||||
{ flatbuffers::GenerateTextFile, "-t", "--json", "text", false,
|
||||
nullptr,
|
||||
flatbuffers::IDLOptions::kJson,
|
||||
"Generate text output for any data definitions",
|
||||
flatbuffers::TextMakeRule },
|
||||
{ flatbuffers::GenerateCPP, "-c", "--cpp", "C++",
|
||||
{ flatbuffers::GenerateCPP, "-c", "--cpp", "C++", true,
|
||||
flatbuffers::GenerateCppGRPC,
|
||||
flatbuffers::IDLOptions::kCpp,
|
||||
"Generate C++ headers for tables/structs",
|
||||
flatbuffers::CPPMakeRule },
|
||||
{ flatbuffers::GenerateGo, "-g", "--go", "Go",
|
||||
{ flatbuffers::GenerateGo, "-g", "--go", "Go", true,
|
||||
flatbuffers::GenerateGoGRPC,
|
||||
flatbuffers::IDLOptions::kGo,
|
||||
"Generate Go files for tables/structs",
|
||||
flatbuffers::GeneralMakeRule },
|
||||
{ flatbuffers::GenerateGeneral, "-j", "--java", "Java",
|
||||
{ flatbuffers::GenerateGeneral, "-j", "--java", "Java", true,
|
||||
nullptr,
|
||||
flatbuffers::IDLOptions::kJava,
|
||||
"Generate Java classes for tables/structs",
|
||||
flatbuffers::GeneralMakeRule },
|
||||
{ flatbuffers::GenerateJS, "-s", "--js", "JavaScript",
|
||||
{ flatbuffers::GenerateJS, "-s", "--js", "JavaScript", true,
|
||||
nullptr,
|
||||
flatbuffers::IDLOptions::kJs,
|
||||
"Generate JavaScript code for tables/structs",
|
||||
flatbuffers::JSMakeRule },
|
||||
{ flatbuffers::GenerateGeneral, "-n", "--csharp", "C#",
|
||||
{ flatbuffers::GenerateJS, "-T", "--ts", "TypeScript", true,
|
||||
nullptr,
|
||||
flatbuffers::IDLOptions::kTs,
|
||||
"Generate TypeScript code for tables/structs",
|
||||
flatbuffers::JSMakeRule },
|
||||
{ flatbuffers::GenerateGeneral, "-n", "--csharp", "C#", true,
|
||||
nullptr,
|
||||
flatbuffers::IDLOptions::kCSharp,
|
||||
"Generate C# classes for tables/structs",
|
||||
flatbuffers::GeneralMakeRule },
|
||||
{ flatbuffers::GeneratePython, "-p", "--python", "Python",
|
||||
{ flatbuffers::GeneratePython, "-p", "--python", "Python", true,
|
||||
nullptr,
|
||||
flatbuffers::IDLOptions::kPython,
|
||||
"Generate Python files for tables/structs",
|
||||
flatbuffers::GeneralMakeRule },
|
||||
{ flatbuffers::GeneratePhp, nullptr, "--php", "PHP",
|
||||
{ flatbuffers::GeneratePhp, nullptr, "--php", "PHP", true,
|
||||
nullptr,
|
||||
flatbuffers::IDLOptions::kPhp,
|
||||
"Generate PHP files for tables/structs",
|
||||
flatbuffers::GeneralMakeRule },
|
||||
};
|
||||
{ flatbuffers::GenerateJsonSchema, nullptr, "--jsonschema", "JsonSchema", true,
|
||||
nullptr,
|
||||
flatbuffers::IDLOptions::kJsonSchema,
|
||||
"Generate Json schema",
|
||||
flatbuffers::GeneralMakeRule },
|
||||
};
|
||||
|
||||
flatbuffers::FlatCompiler::InitParams params;
|
||||
params.generators = generators;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -23,18 +23,20 @@
|
||||
|
||||
namespace flatbuffers {
|
||||
|
||||
static std::string GenType(const Type &type) {
|
||||
static std::string GenType(const Type &type, bool underlying = false) {
|
||||
switch (type.base_type) {
|
||||
case BASE_TYPE_STRUCT:
|
||||
return type.struct_def->defined_namespace->GetFullyQualifiedName(
|
||||
type.struct_def->name);
|
||||
case BASE_TYPE_UNION:
|
||||
return type.enum_def->defined_namespace->GetFullyQualifiedName(
|
||||
type.enum_def->name);
|
||||
case BASE_TYPE_VECTOR:
|
||||
return "[" + GenType(type.VectorType()) + "]";
|
||||
default:
|
||||
return kTypeNames[type.base_type];
|
||||
if (type.enum_def && !underlying) {
|
||||
return type.enum_def->defined_namespace->GetFullyQualifiedName(
|
||||
type.enum_def->name);
|
||||
} else {
|
||||
return kTypeNames[type.base_type];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,14 +56,13 @@ static void GenNameSpace(const Namespace &name_space, std::string *_schema,
|
||||
|
||||
// Generate a flatbuffer schema from the Parser's internal representation.
|
||||
std::string GenerateFBS(const Parser &parser, const std::string &file_name) {
|
||||
// Proto namespaces may clash with table names, so we have to prefix all:
|
||||
if (!parser.opts.escape_proto_identifiers) {
|
||||
for (auto it = parser.namespaces_.begin(); it != parser.namespaces_.end();
|
||||
++it) {
|
||||
for (auto comp = (*it)->components.begin(); comp != (*it)->components.end();
|
||||
++comp) {
|
||||
(*comp) = "_" + (*comp);
|
||||
}
|
||||
// Proto namespaces may clash with table names, escape the ones that were
|
||||
// generated from a table:
|
||||
for (auto it = parser.namespaces_.begin(); it != parser.namespaces_.end();
|
||||
++it) {
|
||||
auto &ns = **it;
|
||||
for (size_t i = 0; i < ns.from_table; i++) {
|
||||
ns.components[ns.components.size() - 1 - i] += "_";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,12 +73,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
|
||||
@@ -90,7 +91,7 @@ std::string GenerateFBS(const Parser &parser, const std::string &file_name) {
|
||||
GenNameSpace(*enum_def.defined_namespace, &schema, &last_namespace);
|
||||
GenComment(enum_def.doc_comment, &schema, nullptr);
|
||||
schema += "enum " + enum_def.name + " : ";
|
||||
schema += GenType(enum_def.underlying_type) + " {\n";
|
||||
schema += GenType(enum_def.underlying_type, true) + " {\n";
|
||||
for (auto it = enum_def.vals.vec.begin();
|
||||
it != enum_def.vals.vec.end(); ++it) {
|
||||
auto &ev = **it;
|
||||
@@ -109,11 +110,13 @@ std::string GenerateFBS(const Parser &parser, const std::string &file_name) {
|
||||
for (auto field_it = struct_def.fields.vec.begin();
|
||||
field_it != struct_def.fields.vec.end(); ++field_it) {
|
||||
auto &field = **field_it;
|
||||
GenComment(field.doc_comment, &schema, nullptr, " ");
|
||||
schema += " " + field.name + ":" + GenType(field.value.type);
|
||||
if (field.value.constant != "0") schema += " = " + field.value.constant;
|
||||
if (field.required) schema += " (required)";
|
||||
schema += ";\n";
|
||||
if (field.value.type.base_type != BASE_TYPE_UTYPE) {
|
||||
GenComment(field.doc_comment, &schema, nullptr, " ");
|
||||
schema += " " + field.name + ":" + GenType(field.value.type);
|
||||
if (field.value.constant != "0") schema += " = " + field.value.constant;
|
||||
if (field.required) schema += " (required)";
|
||||
schema += ";\n";
|
||||
}
|
||||
}
|
||||
schema += "}\n\n";
|
||||
}
|
||||
|
||||
@@ -20,7 +20,10 @@
|
||||
#include "flatbuffers/idl.h"
|
||||
#include "flatbuffers/util.h"
|
||||
#include "flatbuffers/code_generators.h"
|
||||
#include <algorithm>
|
||||
|
||||
#if defined(FLATBUFFERS_CPP98_STL)
|
||||
#include <cctype>
|
||||
#endif // defined(FLATBUFFERS_CPP98_STL)
|
||||
|
||||
namespace flatbuffers {
|
||||
|
||||
@@ -67,6 +70,7 @@ struct LanguageParameters {
|
||||
std::string accessor_prefix_static;
|
||||
std::string optional_suffix;
|
||||
std::string includes;
|
||||
std::string class_annotation;
|
||||
CommentConfig comment_config;
|
||||
};
|
||||
|
||||
@@ -96,8 +100,8 @@ const LanguageParameters& GetLangParams(IDLOptions::Language lang) {
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"import java.nio.*;\nimport java.lang.*;\nimport java.util.*;\n"
|
||||
"import com.google.flatbuffers.*;\n\n@SuppressWarnings(\"unused\")\n",
|
||||
"import java.nio.*;\nimport java.lang.*;\nimport java.util.*;\nimport com.google.flatbuffers.*;\n",
|
||||
"\n@SuppressWarnings(\"unused\")\n",
|
||||
{
|
||||
"/**",
|
||||
" *",
|
||||
@@ -128,7 +132,8 @@ const LanguageParameters& GetLangParams(IDLOptions::Language lang) {
|
||||
"__p.",
|
||||
"Table.",
|
||||
"?",
|
||||
"using System;\nusing FlatBuffers;\n\n",
|
||||
"using global::System;\nusing global::FlatBuffers;\n\n",
|
||||
"",
|
||||
{
|
||||
nullptr,
|
||||
"///",
|
||||
@@ -158,7 +163,7 @@ class GeneralGenerator : public BaseGenerator {
|
||||
GeneralGenerator &operator=(const GeneralGenerator &);
|
||||
bool generate() {
|
||||
std::string one_file_code;
|
||||
cur_name_space_ = parser_.namespaces_.back();
|
||||
cur_name_space_ = parser_.current_namespace_;
|
||||
|
||||
for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
|
||||
++it) {
|
||||
@@ -191,7 +196,7 @@ class GeneralGenerator : public BaseGenerator {
|
||||
}
|
||||
|
||||
if (parser_.opts.one_file) {
|
||||
return SaveType(file_name_, *parser_.namespaces_.back(),
|
||||
return SaveType(file_name_, *parser_.current_namespace_,
|
||||
one_file_code, true);
|
||||
}
|
||||
return true;
|
||||
@@ -204,13 +209,26 @@ class GeneralGenerator : public BaseGenerator {
|
||||
if (!classcode.length()) return true;
|
||||
|
||||
std::string code;
|
||||
code = code + "// " + FlatBuffersGeneratedWarning();
|
||||
if (lang_.language == IDLOptions::kCSharp) {
|
||||
code = "// <auto-generated>\n"
|
||||
"// " + std::string(FlatBuffersGeneratedWarning()) + "\n"
|
||||
"// </auto-generated>\n\n";
|
||||
} else {
|
||||
code = "// " + std::string(FlatBuffersGeneratedWarning()) + "\n\n";
|
||||
}
|
||||
|
||||
std::string namespace_name = FullNamespace(".", ns);
|
||||
if (!namespace_name.empty()) {
|
||||
code += lang_.namespace_ident + namespace_name + lang_.namespace_begin;
|
||||
code += "\n\n";
|
||||
}
|
||||
if (needs_includes) code += lang_.includes;
|
||||
if (needs_includes) {
|
||||
code += lang_.includes;
|
||||
if (parser_.opts.gen_nullable) {
|
||||
code += "\nimport javax.annotation.Nullable;\n";
|
||||
}
|
||||
code += lang_.class_annotation;
|
||||
}
|
||||
code += classcode;
|
||||
if (!namespace_name.empty()) code += lang_.namespace_end;
|
||||
auto filename = NamespaceDir(ns) + defname + lang_.file_extension;
|
||||
@@ -225,20 +243,28 @@ class GeneralGenerator : public BaseGenerator {
|
||||
: upper);
|
||||
}
|
||||
|
||||
std::string GenNullableAnnotation(const Type& t) {
|
||||
return lang_.language == IDLOptions::kJava
|
||||
&& parser_.opts.gen_nullable
|
||||
&& !IsScalar(DestinationType(t, true).base_type) ? " @Nullable ": "";
|
||||
}
|
||||
|
||||
static bool IsEnum(const Type& type) {
|
||||
return type.enum_def != nullptr && IsInteger(type.base_type);
|
||||
}
|
||||
|
||||
std::string GenTypeBasic(const Type &type, bool enableLangOverrides) {
|
||||
static const char *java_typename[] = {
|
||||
#define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \
|
||||
#define FLATBUFFERS_TD(ENUM, IDLTYPE, \
|
||||
CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \
|
||||
#JTYPE,
|
||||
FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
|
||||
#undef FLATBUFFERS_TD
|
||||
};
|
||||
|
||||
static const char *csharp_typename[] = {
|
||||
#define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \
|
||||
#define FLATBUFFERS_TD(ENUM, IDLTYPE, \
|
||||
CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \
|
||||
#NTYPE,
|
||||
FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
|
||||
#undef FLATBUFFERS_TD
|
||||
@@ -301,7 +327,7 @@ Type DestinationType(const Type &type, bool vectorelem) {
|
||||
case BASE_TYPE_VECTOR:
|
||||
if (vectorelem)
|
||||
return DestinationType(type.VectorType(), vectorelem);
|
||||
// else fall thru:
|
||||
// else fall thru
|
||||
default: return type;
|
||||
}
|
||||
}
|
||||
@@ -348,7 +374,7 @@ std::string DestinationMask(const Type &type, bool vectorelem) {
|
||||
case BASE_TYPE_VECTOR:
|
||||
if (vectorelem)
|
||||
return DestinationMask(type.VectorType(), vectorelem);
|
||||
// else fall thru:
|
||||
// else fall thru
|
||||
default: return "";
|
||||
}
|
||||
}
|
||||
@@ -587,6 +613,22 @@ std::string GenGetter(const Type &type) {
|
||||
}
|
||||
}
|
||||
|
||||
// Returns the function name that is able to read a value of the given type.
|
||||
std::string GenGetterForLookupByKey(flatbuffers::FieldDef *key_field,
|
||||
const std::string &data_buffer,
|
||||
const char *num = nullptr) {
|
||||
auto type = key_field->value.type;
|
||||
auto dest_mask = DestinationMask(type, true);
|
||||
auto dest_cast = DestinationCast(type);
|
||||
auto getter = data_buffer + "." + FunctionStart('G') + "et";
|
||||
if (GenTypeBasic(type, false) != "byte") {
|
||||
getter += MakeCamel(GenTypeBasic(type, false));
|
||||
}
|
||||
getter = dest_cast + getter + "(" + GenOffsetGetter(key_field, num) + ")"
|
||||
+ dest_mask;
|
||||
return getter;
|
||||
}
|
||||
|
||||
// Direct mutation is only allowed for scalar fields.
|
||||
// Hence a setter method will only be generated for such fields.
|
||||
std::string GenSetter(const Type &type) {
|
||||
@@ -668,7 +710,7 @@ void GenStructBody(const StructDef &struct_def, std::string *code_ptr,
|
||||
std::string GenByteBufferLength(const char *bb_name) {
|
||||
std::string bb_len = bb_name;
|
||||
if (lang_.language == IDLOptions::kCSharp) bb_len += ".Length";
|
||||
else bb_len += ".array().length";
|
||||
else bb_len += ".capacity()";
|
||||
return bb_len;
|
||||
}
|
||||
|
||||
@@ -699,12 +741,11 @@ std::string GenLookupKeyGetter(flatbuffers::FieldDef *key_field) {
|
||||
key_getter += GenOffsetGetter(key_field);
|
||||
key_getter += ", byteKey, bb);\n";
|
||||
} else {
|
||||
auto get_val = GenGetter(key_field->value.type) +
|
||||
"(" + GenOffsetGetter(key_field) + ")";
|
||||
auto get_val = GenGetterForLookupByKey(key_field, "bb");
|
||||
if (lang_.language == IDLOptions::kCSharp) {
|
||||
key_getter += "int comp = " + get_val + ".CompareTo(key);\n";
|
||||
} else {
|
||||
key_getter += GenTypeGet(key_field->value.type) + " val = ";
|
||||
key_getter += GenTypeNameDest(key_field->value.type) + " val = ";
|
||||
key_getter += get_val + ";\n";
|
||||
key_getter += " int comp = val > key ? 1 : val < key ? -1 : 0;\n";
|
||||
}
|
||||
@@ -728,20 +769,17 @@ std::string GenKeyGetter(flatbuffers::FieldDef *key_field) {
|
||||
key_getter += ";";
|
||||
}
|
||||
else {
|
||||
auto field_getter = data_buffer + GenGetter(key_field->value.type).substr(2) +
|
||||
"(" + GenOffsetGetter(key_field, "o1") + ")";
|
||||
auto field_getter = GenGetterForLookupByKey(key_field, data_buffer, "o1");
|
||||
if (lang_.language == IDLOptions::kCSharp) {
|
||||
key_getter += field_getter;
|
||||
field_getter = data_buffer + GenGetter(key_field->value.type).substr(2) +
|
||||
"(" + GenOffsetGetter(key_field, "o2") + ")";
|
||||
field_getter = GenGetterForLookupByKey(key_field, data_buffer, "o2");
|
||||
key_getter += ".CompareTo(" + field_getter + ")";
|
||||
}
|
||||
else {
|
||||
key_getter += "\n " + GenTypeGet(key_field->value.type) + " val_1 = ";
|
||||
key_getter += field_getter + ";\n " + GenTypeGet(key_field->value.type);
|
||||
key_getter += "\n " + GenTypeNameDest(key_field->value.type) + " val_1 = ";
|
||||
key_getter += field_getter + ";\n " + GenTypeNameDest(key_field->value.type);
|
||||
key_getter += " val_2 = ";
|
||||
field_getter = data_buffer + GenGetter(key_field->value.type).substr(2) +
|
||||
"(" + GenOffsetGetter(key_field, "o2") + ")";
|
||||
field_getter = GenGetterForLookupByKey(key_field, data_buffer, "o2");
|
||||
key_getter += field_getter + ";\n";
|
||||
key_getter += " return val_1 > val_2 ? 1 : val_1 < val_2 ? -1 : 0;\n ";
|
||||
}
|
||||
@@ -845,7 +883,8 @@ void GenStruct(StructDef &struct_def, std::string *code_ptr) {
|
||||
std::string dest_mask = DestinationMask(field.value.type, true);
|
||||
std::string dest_cast = DestinationCast(field.value.type);
|
||||
std::string src_cast = SourceCast(field.value.type);
|
||||
std::string method_start = " public " + type_name_dest + optional + " " +
|
||||
std::string method_start = " public " + GenNullableAnnotation(field.value.type) +
|
||||
type_name_dest + optional + " " +
|
||||
MakeCamel(field.name, lang_.first_camel_upper);
|
||||
std::string obj = lang_.language == IDLOptions::kCSharp
|
||||
? "(new " + type_name + "())"
|
||||
@@ -993,6 +1032,26 @@ void GenStruct(StructDef &struct_def, std::string *code_ptr) {
|
||||
code += lang_.accessor_prefix + "__vector_len(o) : 0; ";
|
||||
code += lang_.getter_suffix;
|
||||
code += "}\n";
|
||||
// See if we should generate a by-key accessor.
|
||||
if (field.value.type.element == BASE_TYPE_STRUCT &&
|
||||
!field.value.type.struct_def->fixed) {
|
||||
auto &sd = *field.value.type.struct_def;
|
||||
auto &fields = sd.fields.vec;
|
||||
for (auto kit = fields.begin(); kit != fields.end(); ++kit) {
|
||||
auto &key_field = **kit;
|
||||
if (key_field.key) {
|
||||
code += " public " + sd.name + lang_.optional_suffix + " ";
|
||||
code += MakeCamel(field.name, lang_.first_camel_upper) + "ByKey(";
|
||||
code += GenTypeNameDest(key_field.value.type) + " key)";
|
||||
code += offset_prefix;
|
||||
code += sd.name + ".__lookup_by_key(";
|
||||
code += lang_.accessor_prefix + "__vector(o), key, ";
|
||||
code += lang_.accessor_prefix + "bb) : null; ";
|
||||
code += "}\n";
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Generate a ByteBuffer accessor for strings & vectors of scalars.
|
||||
if ((field.value.type.base_type == BASE_TYPE_VECTOR &&
|
||||
@@ -1023,28 +1082,24 @@ void GenStruct(StructDef &struct_def, std::string *code_ptr) {
|
||||
}
|
||||
}
|
||||
// generate object accessors if is nested_flatbuffer
|
||||
auto nested = field.attributes.Lookup("nested_flatbuffer");
|
||||
if (nested) {
|
||||
auto nested_qualified_name =
|
||||
parser_.namespaces_.back()->GetFullyQualifiedName(nested->constant);
|
||||
auto nested_type = parser_.structs_.Lookup(nested_qualified_name);
|
||||
auto nested_type_name = WrapInNameSpace(*nested_type);
|
||||
auto nestedMethodName = MakeCamel(field.name, lang_.first_camel_upper)
|
||||
if (field.nested_flatbuffer) {
|
||||
auto nested_type_name = WrapInNameSpace(*field.nested_flatbuffer);
|
||||
auto nested_method_name = MakeCamel(field.name, lang_.first_camel_upper)
|
||||
+ "As" + nested_type_name;
|
||||
auto getNestedMethodName = nestedMethodName;
|
||||
auto get_nested_method_name = nested_method_name;
|
||||
if (lang_.language == IDLOptions::kCSharp) {
|
||||
getNestedMethodName = "Get" + nestedMethodName;
|
||||
get_nested_method_name = "Get" + nested_method_name;
|
||||
conditional_cast = "(" + nested_type_name + lang_.optional_suffix + ")";
|
||||
}
|
||||
if (lang_.language != IDLOptions::kCSharp) {
|
||||
code += " public " + nested_type_name + lang_.optional_suffix + " ";
|
||||
code += nestedMethodName + "() { return ";
|
||||
code += getNestedMethodName + "(new " + nested_type_name + "()); }\n";
|
||||
code += nested_method_name + "() { return ";
|
||||
code += get_nested_method_name + "(new " + nested_type_name + "()); }\n";
|
||||
} else {
|
||||
obj = "(new " + nested_type_name + "())";
|
||||
}
|
||||
code += " public " + nested_type_name + lang_.optional_suffix + " ";
|
||||
code += getNestedMethodName + "(";
|
||||
code += get_nested_method_name + "(";
|
||||
if (lang_.language != IDLOptions::kCSharp)
|
||||
code += nested_type_name + " obj";
|
||||
code += ") { int o = " + lang_.accessor_prefix + "__offset(";
|
||||
@@ -1127,7 +1182,9 @@ void GenStruct(StructDef &struct_def, std::string *code_ptr) {
|
||||
num_fields++;
|
||||
}
|
||||
}
|
||||
if (has_no_struct_fields && num_fields) {
|
||||
// JVM specifications restrict default constructor params to be < 255.
|
||||
// Longs and doubles take up 2 units, so we set the limit to be < 127.
|
||||
if (has_no_struct_fields && num_fields && num_fields < 127) {
|
||||
// Generate a table constructor of the form:
|
||||
// public static int createName(FlatBufferBuilder builder, args...)
|
||||
code += " public static " + GenOffsetType(struct_def) + " ";
|
||||
@@ -1279,7 +1336,9 @@ void GenStruct(StructDef &struct_def, std::string *code_ptr) {
|
||||
code += "); }\n";
|
||||
}
|
||||
}
|
||||
if (struct_def.has_key) {
|
||||
// Only generate key compare function for table,
|
||||
// because `key_field` is not set for struct
|
||||
if (struct_def.has_key && !struct_def.fixed) {
|
||||
if (lang_.language == IDLOptions::kJava) {
|
||||
code += "\n @Override\n protected int keysCompare(";
|
||||
code += "Integer o1, Integer o2, ByteBuffer _bb) {";
|
||||
@@ -1288,7 +1347,8 @@ void GenStruct(StructDef &struct_def, std::string *code_ptr) {
|
||||
}
|
||||
else {
|
||||
code += "\n public static VectorOffset ";
|
||||
code += "CreateMySortedVectorOfTables(FlatBufferBuilder builder, ";
|
||||
code += "CreateSortedVectorOf" + struct_def.name;
|
||||
code += "(FlatBufferBuilder builder, ";
|
||||
code += "Offset<" + struct_def.name + ">";
|
||||
code += "[] offsets) {\n";
|
||||
code += " Array.Sort(offsets, (Offset<" + struct_def.name +
|
||||
@@ -1298,8 +1358,8 @@ void GenStruct(StructDef &struct_def, std::string *code_ptr) {
|
||||
}
|
||||
|
||||
code += "\n public static " + struct_def.name + lang_.optional_suffix;
|
||||
code += " " + FunctionStart('L') + "ookupByKey(" + GenVectorOffsetType();
|
||||
code += " vectorOffset, " + GenTypeGet(key_field->value.type);
|
||||
code += " __lookup_by_key(int vectorLocation, ";
|
||||
code += GenTypeNameDest(key_field->value.type);
|
||||
code += " key, ByteBuffer bb) {\n";
|
||||
if (key_field->value.type.base_type == BASE_TYPE_STRING) {
|
||||
code += " byte[] byteKey = ";
|
||||
@@ -1308,13 +1368,9 @@ void GenStruct(StructDef &struct_def, std::string *code_ptr) {
|
||||
else
|
||||
code += "System.Text.Encoding.UTF8.GetBytes(key);\n";
|
||||
}
|
||||
code += " int vectorLocation = " + GenByteBufferLength("bb");
|
||||
code += " - vectorOffset";
|
||||
if (lang_.language == IDLOptions::kCSharp) code += ".Value";
|
||||
code += ";\n int span = ";
|
||||
code += "bb." + FunctionStart('G') + "etInt(vectorLocation);\n";
|
||||
code += " int span = ";
|
||||
code += "bb." + FunctionStart('G') + "etInt(vectorLocation - 4);\n";
|
||||
code += " int start = 0;\n";
|
||||
code += " vectorLocation += 4;\n";
|
||||
code += " while (span != 0) {\n";
|
||||
code += " int middle = span / 2;\n";
|
||||
code += GenLookupKeyGetter(key_field);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user