mirror of
https://github.com/google/flatbuffers.git
synced 2026-06-02 12:05:50 +00:00
Compare commits
212 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
40b03519c1 | ||
|
|
d236dea13d | ||
|
|
ed88f7de96 | ||
|
|
07478a6700 | ||
|
|
48ff729477 | ||
|
|
7c60937806 | ||
|
|
ace304513f | ||
|
|
1917e577a2 | ||
|
|
9c9fce96c7 | ||
|
|
525130765a | ||
|
|
d890ef9e20 | ||
|
|
9f69d79430 | ||
|
|
9d66af6efc | ||
|
|
8f1729f7df | ||
|
|
4bef5e89c4 | ||
|
|
79222bf100 | ||
|
|
c3bfefca57 | ||
|
|
00fd394d23 | ||
|
|
e1e8d53df6 | ||
|
|
57a6dd472f | ||
|
|
224e33ed09 | ||
|
|
94680f5483 | ||
|
|
b4db88808f | ||
|
|
d9db48257b | ||
|
|
e1e1bced08 | ||
|
|
b56add9520 | ||
|
|
2abe24b9dd | ||
|
|
a35c32e30f | ||
|
|
781c39c708 | ||
|
|
ff9e539cc5 | ||
|
|
feb4816610 | ||
|
|
703b790939 | ||
|
|
811a5c3389 | ||
|
|
2736711d67 | ||
|
|
edb3b9c307 | ||
|
|
477fedccd4 | ||
|
|
5de28c74f9 | ||
|
|
44261ccdf1 | ||
|
|
c02b16e195 | ||
|
|
169df65df4 | ||
|
|
af1487bcfb | ||
|
|
5db12e9907 | ||
|
|
dff07b6f31 | ||
|
|
5dd8795a10 | ||
|
|
be503cb0f2 | ||
|
|
01e06b69a5 | ||
|
|
782e05de55 | ||
|
|
82a71b18f1 | ||
|
|
aeff09d724 | ||
|
|
a5c511576f | ||
|
|
ac10873e26 | ||
|
|
9689d38bef | ||
|
|
d06b2736aa | ||
|
|
a0f3fb44e7 | ||
|
|
d97f628703 | ||
|
|
fb7f27a7c9 | ||
|
|
7bfed4b29a | ||
|
|
a170b69d5d | ||
|
|
33e4ab65e9 | ||
|
|
201699288b | ||
|
|
e9202d85bd | ||
|
|
9a1ab5006f | ||
|
|
25c99273d3 | ||
|
|
7bcbb19569 | ||
|
|
b062af4c8c | ||
|
|
0956719726 | ||
|
|
766eaad4e7 | ||
|
|
3a74c33ba5 | ||
|
|
e4c3bf3d2c | ||
|
|
7196c36842 | ||
|
|
e151160560 | ||
|
|
dac63a227e | ||
|
|
986b52d849 | ||
|
|
45cc503bbd | ||
|
|
6aeb09b297 | ||
|
|
210c0ece54 | ||
|
|
ad84b5b8fa | ||
|
|
7101224d86 | ||
|
|
6be146d67f | ||
|
|
f706a42951 | ||
|
|
e24afd838a | ||
|
|
81c2b185ef | ||
|
|
0e064e415b | ||
|
|
4998ad7365 | ||
|
|
9a30d3d0df | ||
|
|
0b761ece4d | ||
|
|
01249c1d48 | ||
|
|
588564d74f | ||
|
|
6e192fa408 | ||
|
|
12ca3e054e | ||
|
|
62af533820 | ||
|
|
b56020ad3b | ||
|
|
6e160f4c59 | ||
|
|
07e77ad0ff | ||
|
|
b6380aceac | ||
|
|
79d3cb6a6c | ||
|
|
a4de6de700 | ||
|
|
a1d801c375 | ||
|
|
f66e93cd8d | ||
|
|
59a09cb1d0 | ||
|
|
c23c620d26 | ||
|
|
4798456df6 | ||
|
|
147fbb4285 | ||
|
|
a9ae9bdcab | ||
|
|
f7d8102b35 | ||
|
|
d0e9bc6a75 | ||
|
|
d863df8683 | ||
|
|
4834634766 | ||
|
|
a4c893dbe2 | ||
|
|
8833255ed3 | ||
|
|
fb5f9456e9 | ||
|
|
0dacfbbfca | ||
|
|
47aab78233 | ||
|
|
185b9f9792 | ||
|
|
21765bea2e | ||
|
|
36c7e9a962 | ||
|
|
cb2b2be54e | ||
|
|
1c152cc72a | ||
|
|
d67661eb39 | ||
|
|
ea97e1b5e2 | ||
|
|
dca3ccf5fd | ||
|
|
ef7b3ed8f5 | ||
|
|
4d305f5922 | ||
|
|
1e6f8f5b8c | ||
|
|
c967515da5 | ||
|
|
576022c64b | ||
|
|
eab9cfbec9 | ||
|
|
ab4801a82e | ||
|
|
8df4b318bc | ||
|
|
8a98e9ad98 | ||
|
|
eee5628569 | ||
|
|
ad3fd6ecbf | ||
|
|
622b8d05cf | ||
|
|
5faa0ab1be | ||
|
|
81312c2128 | ||
|
|
1808337adc | ||
|
|
5f091c46ce | ||
|
|
a96bfdb369 | ||
|
|
ad3ebb110b | ||
|
|
929105432c | ||
|
|
40fffc8fff | ||
|
|
2f76141813 | ||
|
|
932b22f043 | ||
|
|
ecf5a6a580 | ||
|
|
788acb08d4 | ||
|
|
ddb1d5ffe4 | ||
|
|
7ba29dbe41 | ||
|
|
3b070310f0 | ||
|
|
fbe085601b | ||
|
|
36f9b1ec91 | ||
|
|
7bcd99451f | ||
|
|
2535a3aa3a | ||
|
|
0894c25f2c | ||
|
|
7810fb9ce4 | ||
|
|
c127cf78c2 | ||
|
|
6fffa2a14d | ||
|
|
2b02d330fd | ||
|
|
c8f1682e07 | ||
|
|
f64e040896 | ||
|
|
339376ba67 | ||
|
|
7a1b77322b | ||
|
|
60b6ca5850 | ||
|
|
b8681d8031 | ||
|
|
f8139b05cb | ||
|
|
776c4eb965 | ||
|
|
2746aabcf1 | ||
|
|
04a06781f5 | ||
|
|
48dfc69ee6 | ||
|
|
4d213c2d06 | ||
|
|
361bfb6764 | ||
|
|
3f96eead4c | ||
|
|
8896587faf | ||
|
|
9fa3e2f387 | ||
|
|
e5c21ec666 | ||
|
|
e11da87a24 | ||
|
|
3dd54424c0 | ||
|
|
5d68493df4 | ||
|
|
d322eec3c3 | ||
|
|
221193eaa2 | ||
|
|
f7d24f60a2 | ||
|
|
e5a1a3129d | ||
|
|
39833d7cf0 | ||
|
|
ecb27817ca | ||
|
|
f59bfdd084 | ||
|
|
0ee1b99c5d | ||
|
|
a50711ad13 | ||
|
|
249f71a12b | ||
|
|
1d138fbe07 | ||
|
|
a0bf238b09 | ||
|
|
c49c6da803 | ||
|
|
37e6efe1f9 | ||
|
|
d4d7a84e11 | ||
|
|
fc7e8af55e | ||
|
|
3ec5dddb00 | ||
|
|
f47660f510 | ||
|
|
a8d6962ac2 | ||
|
|
23f75f598e | ||
|
|
e3b432cba8 | ||
|
|
557c57eb9d | ||
|
|
9d368deb05 | ||
|
|
8b99bf614c | ||
|
|
c4a3e2f6bd | ||
|
|
803f9bba27 | ||
|
|
d756efbf76 | ||
|
|
ace7fa8094 | ||
|
|
f02646e357 | ||
|
|
0a3a09aaf3 | ||
|
|
796be3282c | ||
|
|
468124fb9b | ||
|
|
3ad853630c | ||
|
|
b8708beeec | ||
|
|
8fb6c4f764 |
12
.gitignore
vendored
12
.gitignore
vendored
@@ -19,7 +19,9 @@
|
||||
**/*.dir/**
|
||||
**/CMakeFiles/**
|
||||
**/cmake_install.cmake
|
||||
**/install_manifest.txt
|
||||
**/CMakeCache.txt
|
||||
**/CMakeTestfile.cmake
|
||||
**/Debug/**
|
||||
**/Release/**
|
||||
build.xml
|
||||
@@ -29,20 +31,30 @@ proguard-project.txt
|
||||
linklint_results
|
||||
Makefile
|
||||
flatc
|
||||
flatc.exe
|
||||
flathash
|
||||
flathash.exe
|
||||
flattests
|
||||
flattests.exe
|
||||
flatsamplebinary
|
||||
flatsamplebinary.exe
|
||||
flatsampletext
|
||||
flatsampletext.exe
|
||||
snapshot.sh
|
||||
tests/go_gen
|
||||
tests/monsterdata_java_wire.mon
|
||||
tests/monsterdata_go_wire.mon
|
||||
tests/monsterdata_javascript_wire.mon
|
||||
tests/unicode_test.mon
|
||||
CMakeLists.txt.user
|
||||
CMakeScripts/**
|
||||
CTestTestfile.cmake
|
||||
FlatBuffers.cbp
|
||||
build/Xcode/FlatBuffers.xcodeproj/project.xcworkspace/**
|
||||
build/Xcode/FlatBuffers.xcodeproj/xcuserdata/**
|
||||
FlatBuffers.xcodeproj/
|
||||
java/.idea
|
||||
java/*.iml
|
||||
java/target
|
||||
**/*.pyc
|
||||
.idea
|
||||
|
||||
30
.travis.yml
Normal file
30
.travis.yml
Normal file
@@ -0,0 +1,30 @@
|
||||
language: cpp
|
||||
|
||||
os:
|
||||
- linux
|
||||
- osx
|
||||
|
||||
compiler:
|
||||
- gcc
|
||||
#- clang
|
||||
|
||||
env:
|
||||
matrix:
|
||||
- BUILD_TYPE=Debug BIICODE=false
|
||||
- BUILD_TYPE=Release BIICODE=false
|
||||
- BUILD_TYPE=Release BIICODE=true
|
||||
- BUILD_TYPE=Debug BIICODE=true
|
||||
global:
|
||||
- GCC_VERSION="4.9"
|
||||
|
||||
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
|
||||
@@ -6,6 +6,7 @@ project(FlatBuffers)
|
||||
option(FLATBUFFERS_CODE_COVERAGE "Enable the code coverage build option." OFF)
|
||||
option(FLATBUFFERS_BUILD_TESTS "Enable the build of tests and samples." ON)
|
||||
option(FLATBUFFERS_INSTALL "Enable the installation of targets." ON)
|
||||
option(FLATBUFFERS_BUILD_FLATLIB "Enable the build of the flatbuffers library" ON)
|
||||
option(FLATBUFFERS_BUILD_FLATC "Enable the build of the flatbuffers compiler" ON)
|
||||
option(FLATBUFFERS_BUILD_FLATHASH "Enable the build of flathash" ON)
|
||||
|
||||
@@ -15,16 +16,25 @@ if(NOT FLATBUFFERS_BUILD_FLATC AND FLATBUFFERS_BUILD_TESTS)
|
||||
set(FLATBUFFERS_BUILD_TESTS OFF)
|
||||
endif()
|
||||
|
||||
set(FlatBuffers_Compiler_SRCS
|
||||
set(FlatBuffers_Library_SRCS
|
||||
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
|
||||
src/idl_parser.cpp
|
||||
src/idl_gen_text.cpp
|
||||
src/reflection.cpp
|
||||
)
|
||||
|
||||
set(FlatBuffers_Compiler_SRCS
|
||||
${FlatBuffers_Library_SRCS}
|
||||
src/idl_gen_cpp.cpp
|
||||
src/idl_gen_general.cpp
|
||||
src/idl_gen_go.cpp
|
||||
src/idl_gen_text.cpp
|
||||
src/idl_gen_js.cpp
|
||||
src/idl_gen_python.cpp
|
||||
src/idl_gen_fbs.cpp
|
||||
src/flatc.cpp
|
||||
)
|
||||
@@ -35,13 +45,9 @@ set(FlatHash_SRCS
|
||||
)
|
||||
|
||||
set(FlatBuffers_Tests_SRCS
|
||||
include/flatbuffers/flatbuffers.h
|
||||
include/flatbuffers/hash.h
|
||||
include/flatbuffers/idl.h
|
||||
include/flatbuffers/util.h
|
||||
src/idl_parser.cpp
|
||||
src/idl_gen_text.cpp
|
||||
${FlatBuffers_Library_SRCS}
|
||||
src/idl_gen_fbs.cpp
|
||||
src/idl_gen_general.cpp
|
||||
tests/test.cpp
|
||||
# file generate by running compiler on tests/monster_test.fbs
|
||||
${CMAKE_CURRENT_BINARY_DIR}/tests/monster_test_generated.h
|
||||
@@ -72,9 +78,12 @@ set(FlatBuffers_Sample_Text_SRCS
|
||||
if(APPLE)
|
||||
set(CMAKE_CXX_FLAGS
|
||||
"${CMAKE_CXX_FLAGS} -std=c++11 -stdlib=libc++ -Wall -pedantic -Werror -Wextra")
|
||||
elseif(CMAKE_COMPILER_IS_GNUCXX OR "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
|
||||
elseif(CMAKE_COMPILER_IS_GNUCXX)
|
||||
set(CMAKE_CXX_FLAGS
|
||||
"${CMAKE_CXX_FLAGS} -std=c++0x -Wall -pedantic -Werror -Wextra")
|
||||
elseif("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
|
||||
set(CMAKE_CXX_FLAGS
|
||||
"${CMAKE_CXX_FLAGS} -std=c++0x -stdlib=libc++ -Wall -pedantic -Werror -Wextra")
|
||||
endif()
|
||||
|
||||
if(FLATBUFFERS_CODE_COVERAGE)
|
||||
@@ -84,18 +93,21 @@ if(FLATBUFFERS_CODE_COVERAGE)
|
||||
endif()
|
||||
|
||||
if(BIICODE)
|
||||
# Execute biicode building
|
||||
include(CMake/biicode.cmake)
|
||||
include(biicode/cmake/biicode.cmake)
|
||||
return()
|
||||
endif(BIICODE)
|
||||
endif()
|
||||
|
||||
include_directories(include)
|
||||
|
||||
if(FLATBUFFERS_BUILD_FLATLIB)
|
||||
add_library(flatbuffers STATIC ${FlatBuffers_Library_SRCS})
|
||||
endif()
|
||||
|
||||
if(FLATBUFFERS_BUILD_FLATC)
|
||||
add_executable(flatc ${FlatBuffers_Compiler_SRCS})
|
||||
endif()
|
||||
|
||||
if(FLATBUFFERS_BUILD_FLATC)
|
||||
if(FLATBUFFERS_BUILD_FLATHASH)
|
||||
add_executable(flathash ${FlatHash_SRCS})
|
||||
endif()
|
||||
|
||||
@@ -104,7 +116,16 @@ function(compile_flatbuffers_schema_to_cpp SRC_FBS)
|
||||
string(REGEX REPLACE "\\.fbs$" "_generated.h" GEN_HEADER ${SRC_FBS})
|
||||
add_custom_command(
|
||||
OUTPUT ${GEN_HEADER}
|
||||
COMMAND flatc -c -o "${SRC_FBS_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/${SRC_FBS}"
|
||||
COMMAND flatc -c --no-includes --gen-mutable -o "${SRC_FBS_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/${SRC_FBS}"
|
||||
DEPENDS flatc)
|
||||
endfunction()
|
||||
|
||||
function(compile_flatbuffers_schema_to_binary SRC_FBS)
|
||||
get_filename_component(SRC_FBS_DIR ${SRC_FBS} PATH)
|
||||
string(REGEX REPLACE "\\.fbs$" ".bfbs" GEN_BINARY_SCHEMA ${SRC_FBS})
|
||||
add_custom_command(
|
||||
OUTPUT ${GEN_BINARY_SCHEMA}
|
||||
COMMAND flatc -b --schema -o "${SRC_FBS_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/${SRC_FBS}"
|
||||
DEPENDS flatc)
|
||||
endfunction()
|
||||
|
||||
@@ -121,6 +142,9 @@ endif()
|
||||
|
||||
if(FLATBUFFERS_INSTALL)
|
||||
install(DIRECTORY include/flatbuffers DESTINATION include)
|
||||
if(FLATBUFFERS_BUILD_FLATLIB)
|
||||
install(TARGETS flatbuffers DESTINATION lib)
|
||||
endif()
|
||||
if(FLATBUFFERS_BUILD_FLATC)
|
||||
install(TARGETS flatc DESTINATION bin)
|
||||
endif()
|
||||
|
||||
0
LICENSE.txt
Executable file → Normal file
0
LICENSE.txt
Executable file → Normal file
@@ -31,7 +31,9 @@ LOCAL_SRC_FILES := main.cpp \
|
||||
../../tests/test.cpp \
|
||||
../../src/idl_parser.cpp \
|
||||
../../src/idl_gen_text.cpp \
|
||||
../../src/idl_gen_fbs.cpp
|
||||
../../src/idl_gen_fbs.cpp \
|
||||
../../src/idl_gen_general.cpp \
|
||||
../../src/reflection.cpp
|
||||
LOCAL_LDLIBS := -llog -landroid
|
||||
LOCAL_STATIC_LIBRARIES := android_native_app_glue flatbuffers
|
||||
LOCAL_ARM_MODE := arm
|
||||
|
||||
@@ -66,6 +66,8 @@ FLATBUFFERS_FLATC_PATH?=$(FLATBUFFERS_CMAKELISTS_DIR)
|
||||
FLATBUFFERS_FLATC := $(FLATBUFFERS_FLATC_PATH)/Debug/flatc
|
||||
endif
|
||||
|
||||
FLATBUFFERS_FLATC_ARGS?=
|
||||
|
||||
# Search for cmake.
|
||||
CMAKE_ROOT := $(realpath $(LOCAL_PATH)/../../../../../../prebuilts/cmake)
|
||||
ifeq (,$(CMAKE))
|
||||
@@ -84,6 +86,14 @@ ifeq (,$(CMAKE))
|
||||
CMAKE := cmake
|
||||
endif
|
||||
|
||||
# Windows friendly portable local path.
|
||||
# GNU-make doesn't like : in paths, must use relative paths on Windows.
|
||||
ifeq (Windows,$(PROJECT_OS))
|
||||
PORTABLE_LOCAL_PATH =
|
||||
else
|
||||
PORTABLE_LOCAL_PATH = $(LOCAL_PATH)/
|
||||
endif
|
||||
|
||||
# Generate a host build rule for the flatbuffers compiler.
|
||||
ifeq (Windows,$(PROJECT_OS))
|
||||
define build_flatc_recipe
|
||||
@@ -148,13 +158,24 @@ define flatbuffers_header_build_rule
|
||||
$(eval \
|
||||
$(call flatbuffers_fbs_to_h,$(2),$(3),$(1)): $(1) $(flatc_target)
|
||||
$(call host-echo-build-step,generic,Generate) \
|
||||
$(subst $(LOCAL_PATH)/,,$(call flatbuffers_fbs_to_h,$(2),$(3),$(1)))
|
||||
$(hide) $$(FLATBUFFERS_FLATC) --gen-includes \
|
||||
$(foreach include,$(4),-I $(include)) -o $$(dir $$@) -c $$<)
|
||||
$(subst $(LOCAL_PATH)/,,$(call flatbuffers_fbs_to_h,$(2),$(3),$(1)))
|
||||
$(hide) $$(FLATBUFFERS_FLATC) $(FLATBUFFERS_FLATC_ARGS) \
|
||||
$(foreach include,$(4),-I $(include)) -o $$(dir $$@) -c $$<)
|
||||
endef
|
||||
|
||||
# $(flatbuffers_header_build_rules schema_files,schema_dir,output_dir,\
|
||||
# schema_include_dirs,src_files))
|
||||
# schema_include_dirs,src_files,[build_target],[dependencies]))
|
||||
#
|
||||
# $(1) schema_files: Space separated list of flatbuffer schema files.
|
||||
# $(2) schema_dir: Directory containing the flatbuffer schemas.
|
||||
# $(3) output_dir: Where to place the generated files.
|
||||
# $(4) schema_include_dirs: Directories to include when generating schemas.
|
||||
# $(5) src_files: Files that should depend upon the headers generated from the
|
||||
# flatbuffer schemas.
|
||||
# $(6) build_target: Name of a build target that depends upon all generated
|
||||
# headers.
|
||||
# $(7) dependencies: Space seperated list of additional build targets src_files
|
||||
# should depend upon.
|
||||
#
|
||||
# Use this in your own Android.mk file to generate build rules that will
|
||||
# generate header files for your flatbuffer schemas as well as automatically
|
||||
@@ -166,11 +187,21 @@ endef
|
||||
define flatbuffers_header_build_rules
|
||||
$(foreach schema,$(1),\
|
||||
$(call flatbuffers_header_build_rule,\
|
||||
$(schema),$(strip $(2)),$(strip $(3)),$(strip $(4))))\
|
||||
$(schema),$(strip $(2)),$(strip $(3)),$(strip $(4))))\
|
||||
$(foreach src,$(strip $(5)),\
|
||||
$(eval $(LOCAL_PATH)/$$(src): \
|
||||
$(foreach schema,$(strip $(1)),\
|
||||
$(call flatbuffers_fbs_to_h,$(strip $(2)),$(strip $(3)),$(schema)))))
|
||||
$(eval $(PORTABLE_LOCAL_PATH)$$(src): \
|
||||
$(foreach schema,$(strip $(1)),\
|
||||
$(call flatbuffers_fbs_to_h,$(strip $(2)),$(strip $(3)),$(schema)))))\
|
||||
$(if $(6),\
|
||||
$(foreach schema,$(strip $(1)),\
|
||||
$(eval $(6): \
|
||||
$(call flatbuffers_fbs_to_h,$(strip $(2)),$(strip $(3)),$(schema)))),)\
|
||||
$(if $(7),\
|
||||
$(foreach src,$(strip $(5)),\
|
||||
$(eval $(PORTABLE_LOCAL_PATH)$$(src): $(strip $(7)))),)\
|
||||
$(if $(7),\
|
||||
$(foreach dependency,$(strip $(7)),\
|
||||
$(eval $(6): $(dependency))),)
|
||||
endef
|
||||
|
||||
endif # FLATBUFFERS_INCLUDE_MK_
|
||||
|
||||
0
android/jni/main.cpp
Executable file → Normal file
0
android/jni/main.cpp
Executable file → Normal file
@@ -1,5 +1,7 @@
|
||||
# Biicode configuration file
|
||||
|
||||
[paths]
|
||||
# Local directories to look for headers (within block)
|
||||
include
|
||||
[mains]
|
||||
!android/*
|
||||
[tests]
|
||||
tests/*
|
||||
|
||||
21
biicode/README.md
Normal file
21
biicode/README.md
Normal file
@@ -0,0 +1,21 @@
|
||||
Biicode C/C++ dependency manager
|
||||
=================================
|
||||
|
||||
[](https://www.biicode.com/fenix/flatbuffers)
|
||||
|
||||
New with biicode? Check the [Getting Started Guide](http://docs.biicode.com/c++/gettingstarted.html).
|
||||
|
||||
How to build it?
|
||||
------------------
|
||||
Building it is too easy:
|
||||
|
||||
$ git clone git@github.com:google/flatbuffers.git
|
||||
$ cd flatbuffers
|
||||
$ bii init -L && bii build
|
||||
$ ./bin/any_executable
|
||||
|
||||
Or run its tests:
|
||||
|
||||
$ bii test
|
||||
|
||||
You can check [the examples/flatbuffers block](https://www.biicode.com/examples/flatbuffers).
|
||||
@@ -1,6 +1,4 @@
|
||||
# Initializes block variables
|
||||
INIT_BIICODE_BLOCK()
|
||||
|
||||
set(BII_TESTS_WORKING_DIR ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
# Copying data files to project/bin folder
|
||||
if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/samples")
|
||||
file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/samples/monster.fbs"
|
||||
@@ -14,9 +12,7 @@ if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/tests")
|
||||
"${CMAKE_RUNTIME_OUTPUT_DIRECTORY}")
|
||||
endif()
|
||||
|
||||
# Actually create targets: EXEcutables and libraries.
|
||||
ADD_BIICODE_TARGETS()
|
||||
|
||||
string(REPLACE " " ";" REPLACED_FLAGS ${CMAKE_CXX_FLAGS})
|
||||
target_compile_options(${BII_BLOCK_TARGET} INTERFACE ${REPLACED_FLAGS})
|
||||
target_include_directories(${BII_BLOCK_TARGET} INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/include)
|
||||
target_compile_options(${BII_BLOCK_TARGET} INTERFACE ${REPLACED_FLAGS})
|
||||
16
biicode/support/bii-travis.sh
Executable file
16
biicode/support/bii-travis.sh
Executable file
@@ -0,0 +1,16 @@
|
||||
#!/bin/bash
|
||||
|
||||
sudo apt-get update -qq
|
||||
sudo apt-get install libglu1-mesa-dev xorg-dev
|
||||
wget http://www.biicode.com/downloads/latest/ubuntu64
|
||||
mv ubuntu64 bii-ubuntu64.deb
|
||||
(sudo dpkg -i bii-ubuntu64.deb) && sudo apt-get -f install
|
||||
rm bii-ubuntu64.deb
|
||||
wget https://s3.amazonaws.com/biibinaries/thirdparty/cmake-3.0.2-Linux-64.tar.gz
|
||||
tar -xzf cmake-3.0.2-Linux-64.tar.gz
|
||||
sudo cp -fR cmake-3.0.2-Linux-64/* /usr
|
||||
rm -rf cmake-3.0.2-Linux-64
|
||||
rm cmake-3.0.2-Linux-64.tar.gz
|
||||
|
||||
cmake --version
|
||||
bii init -l && bii configure -DCMAKE_BUILD_TYPE=$1 && bii test
|
||||
@@ -271,6 +271,8 @@
|
||||
<ClCompile Include="..\..\src\idl_gen_go.cpp">
|
||||
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Level4</WarningLevel>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\idl_gen_js.cpp" />
|
||||
<ClCompile Include="..\..\src\idl_gen_python.cpp" />
|
||||
<ClCompile Include="..\..\src\idl_parser.cpp" />
|
||||
<ClCompile Include="..\..\src\idl_gen_cpp.cpp" />
|
||||
<ClCompile Include="..\..\src\idl_gen_text.cpp" />
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<LocalDebuggerWorkingDirectory>..\..\tests</LocalDebuggerWorkingDirectory>
|
||||
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
|
||||
<LocalDebuggerCommandArguments>-j -c -n -g -b -t monster_test.fbs monsterdata_test.golden</LocalDebuggerCommandArguments>
|
||||
<LocalDebuggerCommandArguments>-j -c -n -g --no-includes --gen-mutable monster_test.fbs</LocalDebuggerCommandArguments>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<LocalDebuggerWorkingDirectory>..\..</LocalDebuggerWorkingDirectory>
|
||||
|
||||
@@ -265,11 +265,14 @@
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\..\include\flatbuffers\flatbuffers.h" />
|
||||
<ClInclude Include="..\..\include\flatbuffers\idl.h" />
|
||||
<ClInclude Include="..\..\include\flatbuffers\reflection.h" />
|
||||
<ClInclude Include="..\..\include\flatbuffers\util.h" />
|
||||
<ClInclude Include="..\..\tests\monster_test_generated.h" />
|
||||
<ClCompile Include="..\..\src\idl_gen_fbs.cpp" />
|
||||
<ClCompile Include="..\..\src\idl_gen_general.cpp" />
|
||||
<ClCompile Include="..\..\src\idl_parser.cpp" />
|
||||
<ClCompile Include="..\..\src\idl_gen_text.cpp" />
|
||||
<ClCompile Include="..\..\src\reflection.cpp" />
|
||||
<ClCompile Include="..\..\tests\test.cpp" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
|
||||
@@ -8,11 +8,15 @@
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
1963D7D2A57344A3B1C1713F /* idl_parser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3709AC883348409592530AE6 /* idl_parser.cpp */; settings = {COMPILER_FLAGS = ""; }; };
|
||||
5AC48C391ACA9A0A008132C5 /* idl_gen_general.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8CD8717A19CB937D0012A827 /* idl_gen_general.cpp */; };
|
||||
61823BBC53544106B6DBC38E /* idl_parser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3709AC883348409592530AE6 /* idl_parser.cpp */; settings = {COMPILER_FLAGS = ""; }; };
|
||||
61FF3C34FBEC4819A1C30F92 /* sample_text.cpp in Sources */ = {isa = PBXBuildFile; fileRef = ECCEBFFA6977404F858F9739 /* sample_text.cpp */; settings = {COMPILER_FLAGS = ""; }; };
|
||||
8C303C591975D6A700D7C1C5 /* idl_gen_go.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8C303C581975D6A700D7C1C5 /* idl_gen_go.cpp */; };
|
||||
8C6905F819F835A900CB8866 /* idl_gen_fbs.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8C6905F119F835A900CB8866 /* idl_gen_fbs.cpp */; };
|
||||
8C6905FD19F835B400CB8866 /* idl_gen_fbs.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8C6905EC19F8357300CB8866 /* idl_gen_fbs.cpp */; };
|
||||
8C78573E1BD5AE2C00C53C34 /* idl_gen_js.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8C78573D1BD5AE2C00C53C34 /* idl_gen_js.cpp */; };
|
||||
8C8774631B703D4800E693F5 /* reflection.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8C8774621B703D4800E693F5 /* reflection.cpp */; };
|
||||
8C8774641B703E1200E693F5 /* idl_gen_fbs.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8C6905EC19F8357300CB8866 /* idl_gen_fbs.cpp */; };
|
||||
8CA854B31B04244A00040A06 /* idl_gen_python.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8CA854B21B04244A00040A06 /* idl_gen_python.cpp */; };
|
||||
8CD8717B19CB937D0012A827 /* idl_gen_general.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8CD8717A19CB937D0012A827 /* idl_gen_general.cpp */; };
|
||||
A9C9A99F719A4ED58DC2D2FC /* idl_parser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3709AC883348409592530AE6 /* idl_parser.cpp */; settings = {COMPILER_FLAGS = ""; }; };
|
||||
AA9BACF55EB3456BA2F633BB /* flatc.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0DFD29781D8E490284B06504 /* flatc.cpp */; settings = {COMPILER_FLAGS = ""; }; };
|
||||
@@ -31,22 +35,16 @@
|
||||
3709AC883348409592530AE6 /* idl_parser.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = idl_parser.cpp; path = src/idl_parser.cpp; sourceTree = SOURCE_ROOT; };
|
||||
3863042BCEC64791BFB48625 /* flatsamplebinary */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; path = flatsamplebinary; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
420E3BC724ED4A008D79297F /* flatsampletext */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; path = flatsampletext; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
423CA92401AE442B91546E63 /* CMakeLists.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = CMakeLists.txt; path = /Users/wvo/flatbuffers_snapshot9/CMakeLists.txt; sourceTree = "<absolute>"; };
|
||||
5EE44BFFAF8E43F485859145 /* sample_binary.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = sample_binary.cpp; path = samples/sample_binary.cpp; sourceTree = SOURCE_ROOT; };
|
||||
6AD24EEB3D024825A37741FF /* test.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = test.cpp; path = tests/test.cpp; sourceTree = SOURCE_ROOT; };
|
||||
8C303C581975D6A700D7C1C5 /* idl_gen_go.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = idl_gen_go.cpp; path = src/idl_gen_go.cpp; sourceTree = "<group>"; };
|
||||
8C6905EC19F8357300CB8866 /* idl_gen_fbs.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = idl_gen_fbs.cpp; path = src/idl_gen_fbs.cpp; sourceTree = "<group>"; };
|
||||
8C6905EF19F835A900CB8866 /* flatc.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = flatc.cpp; sourceTree = "<group>"; };
|
||||
8C6905F019F835A900CB8866 /* idl_gen_cpp.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = idl_gen_cpp.cpp; sourceTree = "<group>"; };
|
||||
8C6905F119F835A900CB8866 /* idl_gen_fbs.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = idl_gen_fbs.cpp; sourceTree = "<group>"; };
|
||||
8C6905F219F835A900CB8866 /* idl_gen_general.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = idl_gen_general.cpp; sourceTree = "<group>"; };
|
||||
8C6905F319F835A900CB8866 /* idl_gen_go.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = idl_gen_go.cpp; sourceTree = "<group>"; };
|
||||
8C6905F419F835A900CB8866 /* idl_gen_text.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = idl_gen_text.cpp; sourceTree = "<group>"; };
|
||||
8C6905F519F835A900CB8866 /* idl_parser.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = idl_parser.cpp; sourceTree = "<group>"; };
|
||||
8C78573D1BD5AE2C00C53C34 /* idl_gen_js.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = idl_gen_js.cpp; path = src/idl_gen_js.cpp; sourceTree = "<group>"; };
|
||||
8C8774621B703D4800E693F5 /* reflection.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = reflection.cpp; path = src/reflection.cpp; sourceTree = "<group>"; };
|
||||
8CA854B21B04244A00040A06 /* idl_gen_python.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = idl_gen_python.cpp; path = src/idl_gen_python.cpp; sourceTree = "<group>"; };
|
||||
8CD8717A19CB937D0012A827 /* idl_gen_general.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = idl_gen_general.cpp; path = src/idl_gen_general.cpp; sourceTree = "<group>"; };
|
||||
A13F25CDAD23435DA293690D /* flattests */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; path = flattests; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
AB70F1FBA50E4120BCF37C8D /* monster_test_generated.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = monster_test_generated.h; path = tests/monster_test_generated.h; sourceTree = SOURCE_ROOT; };
|
||||
AD3682C6E1DD4EABB822C0CC /* monster_generated.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = monster_generated.h; path = samples/monster_generated.h; sourceTree = SOURCE_ROOT; };
|
||||
C0E7B66C3FF849A0AD9A7168 /* util.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = util.h; path = include/flatbuffers/util.h; sourceTree = SOURCE_ROOT; };
|
||||
CD90A7F6B2BE4D0384294DD1 /* idl_gen_cpp.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = idl_gen_cpp.cpp; path = src/idl_gen_cpp.cpp; sourceTree = SOURCE_ROOT; };
|
||||
DD8B353D4756412195777FBA /* flatbuffers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = flatbuffers.h; path = include/flatbuffers/flatbuffers.h; sourceTree = SOURCE_ROOT; };
|
||||
@@ -55,32 +53,18 @@
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
194905BCBB5C451DB092EB08 /* Resources */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
);
|
||||
name = Resources;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
28237E300FE042DEADA302D3 /* Source Files */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
8C78573D1BD5AE2C00C53C34 /* idl_gen_js.cpp */,
|
||||
8CA854B21B04244A00040A06 /* idl_gen_python.cpp */,
|
||||
8C6905EC19F8357300CB8866 /* idl_gen_fbs.cpp */,
|
||||
8CD8717A19CB937D0012A827 /* idl_gen_general.cpp */,
|
||||
8C303C581975D6A700D7C1C5 /* idl_gen_go.cpp */,
|
||||
0DFD29781D8E490284B06504 /* flatc.cpp */,
|
||||
CD90A7F6B2BE4D0384294DD1 /* idl_gen_cpp.cpp */,
|
||||
);
|
||||
name = "Source Files";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
355DCA17961E4B2FB2C71403 /* Source Files */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
8C6905EE19F835A900CB8866 /* src */,
|
||||
F6C5D81DBF864365B12E269D /* idl_gen_text.cpp */,
|
||||
3709AC883348409592530AE6 /* idl_parser.cpp */,
|
||||
6AD24EEB3D024825A37741FF /* test.cpp */,
|
||||
CD90A7F6B2BE4D0384294DD1 /* idl_gen_cpp.cpp */,
|
||||
8C8774621B703D4800E693F5 /* reflection.cpp */,
|
||||
);
|
||||
name = "Source Files";
|
||||
sourceTree = "<group>";
|
||||
@@ -88,49 +72,17 @@
|
||||
378446B9D5EF46EF92B35E21 /* flatc */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
5FEA84E7D39645988300317C /* Header Files */,
|
||||
28237E300FE042DEADA302D3 /* Source Files */,
|
||||
0DFD29781D8E490284B06504 /* flatc.cpp */,
|
||||
);
|
||||
name = flatc;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
40E30B8480BD493EA459E9B4 /* Header Files */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
AD3682C6E1DD4EABB822C0CC /* monster_generated.h */,
|
||||
);
|
||||
name = "Header Files";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
4D1151F6FE594E40A1C177FF /* Header Files */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
);
|
||||
name = "Header Files";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
5235469653ED4BC88A6C504D /* Header Files */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
DD8B353D4756412195777FBA /* flatbuffers.h */,
|
||||
00154BD8654B4B5B9FF45FA6 /* idl.h */,
|
||||
C0E7B66C3FF849A0AD9A7168 /* util.h */,
|
||||
AB70F1FBA50E4120BCF37C8D /* monster_test_generated.h */,
|
||||
);
|
||||
name = "Header Files";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
5648A71028E14478841372D3 /* Source Files */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
5EE44BFFAF8E43F485859145 /* sample_binary.cpp */,
|
||||
);
|
||||
name = "Source Files";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
5FEA84E7D39645988300317C /* Header Files */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
DD8B353D4756412195777FBA /* flatbuffers.h */,
|
||||
00154BD8654B4B5B9FF45FA6 /* idl.h */,
|
||||
C0E7B66C3FF849A0AD9A7168 /* util.h */,
|
||||
);
|
||||
name = "Header Files";
|
||||
sourceTree = "<group>";
|
||||
@@ -138,6 +90,8 @@
|
||||
866694F9F2F7451382D236B3 /* Sources */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
28237E300FE042DEADA302D3 /* Source Files */,
|
||||
5FEA84E7D39645988300317C /* Header Files */,
|
||||
378446B9D5EF46EF92B35E21 /* flatc */,
|
||||
DB9DE41C20F349F694A488F3 /* flatsamplebinary */,
|
||||
8FA1F43C78914AE5AD04E24E /* flatsampletext */,
|
||||
@@ -149,31 +103,16 @@
|
||||
88421F5F87584EE3B67C979A /* flattests */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
5235469653ED4BC88A6C504D /* Header Files */,
|
||||
355DCA17961E4B2FB2C71403 /* Source Files */,
|
||||
AB70F1FBA50E4120BCF37C8D /* monster_test_generated.h */,
|
||||
6AD24EEB3D024825A37741FF /* test.cpp */,
|
||||
);
|
||||
name = flattests;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
8C6905EE19F835A900CB8866 /* src */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
8C6905EF19F835A900CB8866 /* flatc.cpp */,
|
||||
8C6905F019F835A900CB8866 /* idl_gen_cpp.cpp */,
|
||||
8C6905F119F835A900CB8866 /* idl_gen_fbs.cpp */,
|
||||
8C6905F219F835A900CB8866 /* idl_gen_general.cpp */,
|
||||
8C6905F319F835A900CB8866 /* idl_gen_go.cpp */,
|
||||
8C6905F419F835A900CB8866 /* idl_gen_text.cpp */,
|
||||
8C6905F519F835A900CB8866 /* idl_parser.cpp */,
|
||||
);
|
||||
path = src;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
8F5E926B72104F4194B3BD5A = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
866694F9F2F7451382D236B3 /* Sources */,
|
||||
194905BCBB5C451DB092EB08 /* Resources */,
|
||||
99CC11E382B8420AA79A8A14 /* Products */,
|
||||
);
|
||||
sourceTree = "<group>";
|
||||
@@ -181,8 +120,7 @@
|
||||
8FA1F43C78914AE5AD04E24E /* flatsampletext */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
40E30B8480BD493EA459E9B4 /* Header Files */,
|
||||
A1C826615F904FDE8F0CA154 /* Source Files */,
|
||||
ECCEBFFA6977404F858F9739 /* sample_text.cpp */,
|
||||
);
|
||||
name = flatsampletext;
|
||||
sourceTree = "<group>";
|
||||
@@ -198,20 +136,10 @@
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
A1C826615F904FDE8F0CA154 /* Source Files */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
ECCEBFFA6977404F858F9739 /* sample_text.cpp */,
|
||||
);
|
||||
name = "Source Files";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
DB9DE41C20F349F694A488F3 /* flatsamplebinary */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
4D1151F6FE594E40A1C177FF /* Header Files */,
|
||||
5648A71028E14478841372D3 /* Source Files */,
|
||||
423CA92401AE442B91546E63 /* CMakeLists.txt */,
|
||||
5EE44BFFAF8E43F485859145 /* sample_binary.cpp */,
|
||||
);
|
||||
name = flatsamplebinary;
|
||||
sourceTree = "<group>";
|
||||
@@ -286,7 +214,7 @@
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
BuildIndependentTargetsInParallel = YES;
|
||||
LastUpgradeCheck = 0510;
|
||||
LastUpgradeCheck = 0700;
|
||||
};
|
||||
buildConfigurationList = 6428BEB363AA4E03A282AA8C /* Build configuration list for PBXProject "FlatBuffers" */;
|
||||
compatibilityVersion = "Xcode 3.2";
|
||||
@@ -334,9 +262,11 @@
|
||||
AA9BACF55EB3456BA2F633BB /* flatc.cpp in Sources */,
|
||||
BE03D7B0C9584DD58B50ED34 /* idl_gen_cpp.cpp in Sources */,
|
||||
AD71FEBEE4E846529002C1F0 /* idl_gen_text.cpp in Sources */,
|
||||
8C8774641B703E1200E693F5 /* idl_gen_fbs.cpp in Sources */,
|
||||
A9C9A99F719A4ED58DC2D2FC /* idl_parser.cpp in Sources */,
|
||||
8C6905F819F835A900CB8866 /* idl_gen_fbs.cpp in Sources */,
|
||||
8CA854B31B04244A00040A06 /* idl_gen_python.cpp in Sources */,
|
||||
8CD8717B19CB937D0012A827 /* idl_gen_general.cpp in Sources */,
|
||||
8C78573E1BD5AE2C00C53C34 /* idl_gen_js.cpp in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -344,6 +274,8 @@
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
8C8774631B703D4800E693F5 /* reflection.cpp in Sources */,
|
||||
5AC48C391ACA9A0A008132C5 /* idl_gen_general.cpp in Sources */,
|
||||
8C6905FD19F835B400CB8866 /* idl_gen_fbs.cpp in Sources */,
|
||||
E0680D6B5BFD484BA9D88EE8 /* idl_gen_text.cpp in Sources */,
|
||||
61823BBC53544106B6DBC38E /* idl_parser.cpp in Sources */,
|
||||
@@ -359,7 +291,7 @@
|
||||
buildSettings = {
|
||||
CONFIGURATION_BUILD_DIR = .;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
SDKROOT = /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk;
|
||||
SDKROOT = macosx;
|
||||
SYMROOT = build;
|
||||
};
|
||||
name = RelWithDebInfo;
|
||||
@@ -367,6 +299,11 @@
|
||||
04681CC521204B3B87BB1E81 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CLANG_WARN_ASSIGN_ENUM = YES;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_IMPLICIT_SIGN_CONVERSION = NO;
|
||||
CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
EXECUTABLE_PREFIX = "";
|
||||
EXECUTABLE_SUFFIX = "";
|
||||
@@ -375,6 +312,25 @@
|
||||
GCC_OPTIMIZATION_LEVEL = 0;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = "'CMAKE_INTDIR=\"$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)\"'";
|
||||
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
|
||||
GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES;
|
||||
GCC_TREAT_INCOMPATIBLE_POINTER_TYPE_WARNINGS_AS_ERRORS = YES;
|
||||
GCC_TREAT_WARNINGS_AS_ERRORS = YES;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES;
|
||||
GCC_WARN_ABOUT_MISSING_NEWLINE = YES;
|
||||
GCC_WARN_ABOUT_MISSING_PROTOTYPES = NO;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES;
|
||||
GCC_WARN_FOUR_CHARACTER_CONSTANTS = YES;
|
||||
GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES;
|
||||
GCC_WARN_PEDANTIC = YES;
|
||||
GCC_WARN_SHADOW = YES;
|
||||
GCC_WARN_SIGN_COMPARE = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNKNOWN_PRAGMAS = YES;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_LABEL = YES;
|
||||
GCC_WARN_UNUSED_PARAMETER = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/include";
|
||||
INSTALL_PATH = "";
|
||||
LIBRARY_SEARCH_PATHS = "";
|
||||
@@ -472,6 +428,11 @@
|
||||
33335DE09CF844709E9E4AA9 /* RelWithDebInfo */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CLANG_WARN_ASSIGN_ENUM = YES;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_IMPLICIT_SIGN_CONVERSION = NO;
|
||||
CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
EXECUTABLE_PREFIX = "";
|
||||
EXECUTABLE_SUFFIX = "";
|
||||
@@ -480,6 +441,25 @@
|
||||
GCC_OPTIMIZATION_LEVEL = 2;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = "'CMAKE_INTDIR=\"$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)\"'";
|
||||
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
|
||||
GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES;
|
||||
GCC_TREAT_INCOMPATIBLE_POINTER_TYPE_WARNINGS_AS_ERRORS = YES;
|
||||
GCC_TREAT_WARNINGS_AS_ERRORS = YES;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES;
|
||||
GCC_WARN_ABOUT_MISSING_NEWLINE = YES;
|
||||
GCC_WARN_ABOUT_MISSING_PROTOTYPES = NO;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES;
|
||||
GCC_WARN_FOUR_CHARACTER_CONSTANTS = YES;
|
||||
GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES;
|
||||
GCC_WARN_PEDANTIC = YES;
|
||||
GCC_WARN_SHADOW = YES;
|
||||
GCC_WARN_SIGN_COMPARE = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNKNOWN_PRAGMAS = YES;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_LABEL = YES;
|
||||
GCC_WARN_UNUSED_PARAMETER = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/include";
|
||||
INSTALL_PATH = "";
|
||||
LIBRARY_SEARCH_PATHS = "";
|
||||
@@ -511,6 +491,11 @@
|
||||
33B3983234F648E28F058235 /* MinSizeRel */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CLANG_WARN_ASSIGN_ENUM = YES;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_IMPLICIT_SIGN_CONVERSION = NO;
|
||||
CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
EXECUTABLE_PREFIX = "";
|
||||
EXECUTABLE_SUFFIX = "";
|
||||
@@ -519,6 +504,25 @@
|
||||
GCC_OPTIMIZATION_LEVEL = s;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = "'CMAKE_INTDIR=\"$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)\"'";
|
||||
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
|
||||
GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES;
|
||||
GCC_TREAT_INCOMPATIBLE_POINTER_TYPE_WARNINGS_AS_ERRORS = YES;
|
||||
GCC_TREAT_WARNINGS_AS_ERRORS = YES;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES;
|
||||
GCC_WARN_ABOUT_MISSING_NEWLINE = YES;
|
||||
GCC_WARN_ABOUT_MISSING_PROTOTYPES = NO;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES;
|
||||
GCC_WARN_FOUR_CHARACTER_CONSTANTS = YES;
|
||||
GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES;
|
||||
GCC_WARN_PEDANTIC = YES;
|
||||
GCC_WARN_SHADOW = YES;
|
||||
GCC_WARN_SIGN_COMPARE = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNKNOWN_PRAGMAS = YES;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_LABEL = YES;
|
||||
GCC_WARN_UNUSED_PARAMETER = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/include";
|
||||
INSTALL_PATH = "";
|
||||
LIBRARY_SEARCH_PATHS = "";
|
||||
@@ -589,6 +593,11 @@
|
||||
37C0FFB777CF4C19BD7AA662 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CLANG_WARN_ASSIGN_ENUM = YES;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_IMPLICIT_SIGN_CONVERSION = NO;
|
||||
CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
EXECUTABLE_PREFIX = "";
|
||||
EXECUTABLE_SUFFIX = "";
|
||||
@@ -597,6 +606,25 @@
|
||||
GCC_OPTIMIZATION_LEVEL = 3;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = "'CMAKE_INTDIR=\"$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)\"'";
|
||||
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
|
||||
GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES;
|
||||
GCC_TREAT_INCOMPATIBLE_POINTER_TYPE_WARNINGS_AS_ERRORS = YES;
|
||||
GCC_TREAT_WARNINGS_AS_ERRORS = YES;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES;
|
||||
GCC_WARN_ABOUT_MISSING_NEWLINE = YES;
|
||||
GCC_WARN_ABOUT_MISSING_PROTOTYPES = NO;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES;
|
||||
GCC_WARN_FOUR_CHARACTER_CONSTANTS = YES;
|
||||
GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES;
|
||||
GCC_WARN_PEDANTIC = YES;
|
||||
GCC_WARN_SHADOW = YES;
|
||||
GCC_WARN_SIGN_COMPARE = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNKNOWN_PRAGMAS = YES;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_LABEL = YES;
|
||||
GCC_WARN_UNUSED_PARAMETER = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/include";
|
||||
INSTALL_PATH = "";
|
||||
LIBRARY_SEARCH_PATHS = "";
|
||||
@@ -779,8 +807,9 @@
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CONFIGURATION_BUILD_DIR = .;
|
||||
ENABLE_TESTABILITY = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
SDKROOT = /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk;
|
||||
SDKROOT = macosx;
|
||||
SYMROOT = build;
|
||||
};
|
||||
name = Debug;
|
||||
@@ -790,7 +819,7 @@
|
||||
buildSettings = {
|
||||
CONFIGURATION_BUILD_DIR = .;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
SDKROOT = /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk;
|
||||
SDKROOT = macosx;
|
||||
SYMROOT = build;
|
||||
};
|
||||
name = Release;
|
||||
@@ -950,7 +979,7 @@
|
||||
buildSettings = {
|
||||
CONFIGURATION_BUILD_DIR = .;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
SDKROOT = /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk;
|
||||
SDKROOT = macosx;
|
||||
SYMROOT = build;
|
||||
};
|
||||
name = MinSizeRel;
|
||||
|
||||
62
docs/header.html
Normal file
62
docs/header.html
Normal file
@@ -0,0 +1,62 @@
|
||||
<!-- HTML header for doxygen 1.8.6-->
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=9"/>
|
||||
<meta name="generator" content="Doxygen $doxygenversion"/>
|
||||
<!--BEGIN PROJECT_NAME--><title>$projectname: $title</title><!--END PROJECT_NAME-->
|
||||
<!--BEGIN !PROJECT_NAME--><title>$title</title><!--END !PROJECT_NAME-->
|
||||
<link href="$relpath^tabs.css" rel="stylesheet" type="text/css"/>
|
||||
<script type="text/javascript" src="$relpath^jquery.js"></script>
|
||||
<script type="text/javascript" src="$relpath^dynsections.js"></script>
|
||||
$treeview
|
||||
$search
|
||||
$mathjax
|
||||
<link href="$relpath^$stylesheet" rel="stylesheet" type="text/css" />
|
||||
<link href="https://fonts.googleapis.com/css?family=Roboto:300,400,400italic,500,500italic,700,700italic|Roboto+Mono:400,700" rel="stylesheet">
|
||||
$extrastylesheet
|
||||
</head>
|
||||
<body>
|
||||
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
|
||||
|
||||
<!--BEGIN TITLEAREA-->
|
||||
<div id="titlearea" style="height: 110px;">
|
||||
<table cellspacing="0" cellpadding="0">
|
||||
<tbody>
|
||||
<tr style="height: 56px;">
|
||||
<!--BEGIN PROJECT_LOGO-->
|
||||
<td id="projectlogo"><img alt="Logo" src="$relpath^$projectlogo"/></td>
|
||||
<!--END PROJECT_LOGO-->
|
||||
<td id="commonprojectlogo">
|
||||
<img alt="Logo" src="$relpath^fpl_logo_small.png"/>
|
||||
</td>
|
||||
<!--BEGIN PROJECT_NAME-->
|
||||
<td style="padding-left: 0.5em;">
|
||||
<div id="projectname">$projectname
|
||||
<!--BEGIN PROJECT_NUMBER--> <span id="projectnumber">$projectnumber</span><!--END PROJECT_NUMBER-->
|
||||
</div>
|
||||
<div style="font-size:12px;">
|
||||
An open source project by <a href="https://developers.google.com/games/#Tools">FPL</a>.
|
||||
</div>
|
||||
<!--BEGIN PROJECT_BRIEF--><div id="projectbrief">$projectbrief</div><!--END PROJECT_BRIEF-->
|
||||
</td>
|
||||
<!--END PROJECT_NAME-->
|
||||
<!--BEGIN !PROJECT_NAME-->
|
||||
<!--BEGIN PROJECT_BRIEF-->
|
||||
<td style="padding-left: 0.5em;">
|
||||
<div id="projectbrief">$projectbrief</div>
|
||||
</td>
|
||||
<!--END PROJECT_BRIEF-->
|
||||
<!--END !PROJECT_NAME-->
|
||||
<!--BEGIN DISABLE_INDEX-->
|
||||
<!--BEGIN SEARCHENGINE-->
|
||||
<td>$searchbox</td>
|
||||
<!--END SEARCHENGINE-->
|
||||
<!--END DISABLE_INDEX-->
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<!--END TITLEAREA-->
|
||||
<!-- end header part -->
|
||||
BIN
docs/html/fpl_logo_small.png
Normal file
BIN
docs/html/fpl_logo_small.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 5.0 KiB |
@@ -1,3 +1,4 @@
|
||||
<!-- HTML header for doxygen 1.8.6-->
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
@@ -15,17 +16,24 @@
|
||||
$(document).ready(initResizable);
|
||||
$(window).load(resizeHeight);
|
||||
</script>
|
||||
<link href="doxygen.css" rel="stylesheet" type="text/css" />
|
||||
<link href="style.css" rel="stylesheet" type="text/css" />
|
||||
<link href="https://fonts.googleapis.com/css?family=Roboto:300,400,400italic,500,500italic,700,700italic|Roboto+Mono:400,700" rel="stylesheet">
|
||||
</head>
|
||||
<body>
|
||||
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
|
||||
<div id="titlearea">
|
||||
<div id="titlearea" style="height: 110px;">
|
||||
<table cellspacing="0" cellpadding="0">
|
||||
<tbody>
|
||||
<tr style="height: 56px;">
|
||||
<td id="commonprojectlogo">
|
||||
<img alt="Logo" src="fpl_logo_small.png"/>
|
||||
</td>
|
||||
<td style="padding-left: 0.5em;">
|
||||
<div id="projectname">FlatBuffers
|
||||
</div>
|
||||
<div style="font-size:12px;">
|
||||
An open source project by <a href="https://developers.google.com/games/#Tools">FPL</a>.
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
@@ -54,7 +62,7 @@ $(document).ready(function(){initNavTree('index.html','');});
|
||||
</div><!--header-->
|
||||
<div class="contents">
|
||||
<div class="textblock"><p>FlatBuffers is an efficient cross platform serialization library for C++, with support for Java, C# and Go. It was created at Google specifically for game development and other performance-critical applications.</p>
|
||||
<p>It is available as open source under the Apache license, v2 (see LICENSE.txt).</p>
|
||||
<p>It is available as Open Source on <a href="http://github.com/google/flatbuffers">GitHub</a> under the Apache license, v2 (see LICENSE.txt).</p>
|
||||
<h2>Why use FlatBuffers?</h2>
|
||||
<ul>
|
||||
<li><b>Access to serialized data without parsing/unpacking</b> - What sets FlatBuffers apart is that it represents hierarchical data in a flat binary buffer in such a way that it can still be accessed directly without parsing/unpacking, while also still supporting data structure evolution (forwards/backwards compatibility).</li>
|
||||
@@ -72,11 +80,17 @@ $(document).ready(function(){initNavTree('index.html','');});
|
||||
<h3>But all the cool kids use JSON!</h3>
|
||||
<p>JSON is very readable (which is why we use it as our optional text format) and very convenient when used together with dynamically typed languages (such as JavaScript). When serializing data from statically typed languages, however, JSON not only has the obvious drawback of runtime inefficiency, but also forces you to write <em>more</em> code to access data (counterintuitively) due to its dynamic-typing serialization system. In this context, it is only a better choice for systems that have very little to no information ahead of time about what data needs to be stored.</p>
|
||||
<p>Read more about the "why" of FlatBuffers in the <a href="md__white_paper.html">white paper</a>.</p>
|
||||
<h3>Who uses FlatBuffers?</h3>
|
||||
<ul>
|
||||
<li><a href="http://www.cocos2d-x.org/">Cocos2d-x</a>, the #1 open source mobile game engine, uses it to serialize all their <a href="http://www.cocos2d-x.org/reference/native-cpp/V3.5/d7/d2d/namespaceflatbuffers.html">game data</a>.</li>
|
||||
<li><a href="http://facebook.com/">Facebook</a> uses it for client-server communication in their Android app. They have a nice <a href="https://code.facebook.com/posts/872547912839369/improving-facebook-s-performance-on-android-with-flatbuffers/">article</a> explaining how it speeds up loading their posts.</li>
|
||||
<li><a href="https://developers.google.com/games/#Tools">Fun Propulsion Labs</a> at Google uses it extensively in all their libraries and games.</li>
|
||||
</ul>
|
||||
<h2>Usage in brief</h2>
|
||||
<p>This section is a quick rundown of how to use this system. Subsequent sections provide a more in-depth usage guide.</p>
|
||||
<ul>
|
||||
<li>Write a schema file that allows you to define the data structures you may want to serialize. Fields can have a scalar type (ints/floats of all sizes), or they can be a: string; array of any type; reference to yet another object; or, a set of possible objects (unions). Fields are optional and have defaults, so they don't need to be present for every object instance.</li>
|
||||
<li>Use <code>flatc</code> (the FlatBuffer compiler) to generate a C++ header (or Java/C#/Go classes) with helper classes to access and construct serialized data. This header (say <code>mydata_generated.h</code>) only depends on <code>flatbuffers.h</code>, which defines the core functionality.</li>
|
||||
<li>Use <code>flatc</code> (the FlatBuffer compiler) to generate a C++ header (or Java/C#/Go/Python.. classes) with helper classes to access and construct serialized data. This header (say <code>mydata_generated.h</code>) only depends on <code>flatbuffers.h</code>, which defines the core functionality.</li>
|
||||
<li>Use the <code>FlatBufferBuilder</code> class to construct a flat binary buffer. The generated functions allow you to add objects to this buffer recursively, often as simply as making a single function call.</li>
|
||||
<li>Store or send your buffer somewhere!</li>
|
||||
<li>When reading it back, you can obtain the pointer to the root object from the binary buffer, and from there traverse it conveniently in-place with <code>object->field()</code>.</li>
|
||||
@@ -89,6 +103,7 @@ $(document).ready(function(){initNavTree('index.html','');});
|
||||
<li>How to <a href="md__cpp_usage.html">use the generated C++ code</a> in your own programs.</li>
|
||||
<li>How to <a href="md__java_usage.html">use the generated Java/C# code</a> in your own programs.</li>
|
||||
<li>How to <a href="md__go_usage.html">use the generated Go code</a> in your own programs.</li>
|
||||
<li><a href="md__support.html">Support matrix</a> for platforms/languages/features.</li>
|
||||
<li>Some <a href="md__benchmarks.html">benchmarks</a> showing the advantage of using FlatBuffers.</li>
|
||||
<li>A <a href="md__white_paper.html">white paper</a> explaining the "why" of FlatBuffers.</li>
|
||||
<li>A description of the <a href="md__internals.html">internals</a> of FlatBuffers.</li>
|
||||
@@ -96,10 +111,21 @@ $(document).ready(function(){initNavTree('index.html','');});
|
||||
</ul>
|
||||
<h2>Online resources</h2>
|
||||
<ul>
|
||||
<li><a href="http://github.com/google/flatbuffers">github repository</a></li>
|
||||
<li><a href="http://google.github.io/flatbuffers">landing page</a></li>
|
||||
<li><a href="http://github.com/google/flatbuffers">GitHub repository</a></li>
|
||||
<li><a href="http://google.github.io/flatbuffers">Landing page</a></li>
|
||||
<li><a href="http://group.google.com/group/flatbuffers">FlatBuffers Google Group</a></li>
|
||||
<li><a href="http://github.com/google/flatbuffers/issues">FlatBuffers Issues Tracker</a> </li>
|
||||
<li><a href="http://github.com/google/flatbuffers/issues">FlatBuffers Issues Tracker</a></li>
|
||||
<li>Videos:<ul>
|
||||
<li>Colt's <a href="https://www.youtube.com/watch?v=iQTxMkSJ1dQ">DevByte</a>.</li>
|
||||
<li>GDC 2015 <a href="https://www.youtube.com/watch?v=olmL1fUnQAQ">Lightning Talk</a>.</li>
|
||||
<li>FlatBuffers for <a href="https://www.youtube.com/watch?v=-BPVId_lA5w">Go</a>.</li>
|
||||
<li>Evolution of FlatBuffers <a href="https://www.youtube.com/watch?v=a0QE0xS8rKM">visualization</a>.</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>Useful documentation created by others:<ul>
|
||||
<li><a href="http://exiin.com/blog/flatbuffers-for-unity-sample-code/">Using FlatBuffers in Unity</a> </li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</div></div><!-- contents -->
|
||||
</div><!-- doc-content -->
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
<!-- HTML header for doxygen 1.8.6-->
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
@@ -15,17 +16,24 @@
|
||||
$(document).ready(initResizable);
|
||||
$(window).load(resizeHeight);
|
||||
</script>
|
||||
<link href="doxygen.css" rel="stylesheet" type="text/css" />
|
||||
<link href="style.css" rel="stylesheet" type="text/css" />
|
||||
<link href="https://fonts.googleapis.com/css?family=Roboto:300,400,400italic,500,500italic,700,700italic|Roboto+Mono:400,700" rel="stylesheet">
|
||||
</head>
|
||||
<body>
|
||||
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
|
||||
<div id="titlearea">
|
||||
<div id="titlearea" style="height: 110px;">
|
||||
<table cellspacing="0" cellpadding="0">
|
||||
<tbody>
|
||||
<tr style="height: 56px;">
|
||||
<td id="commonprojectlogo">
|
||||
<img alt="Logo" src="fpl_logo_small.png"/>
|
||||
</td>
|
||||
<td style="padding-left: 0.5em;">
|
||||
<div id="projectname">FlatBuffers
|
||||
</div>
|
||||
<div style="font-size:12px;">
|
||||
An open source project by <a href="https://developers.google.com/games/#Tools">FPL</a>.
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
@@ -82,7 +90,7 @@ $(document).ready(function(){initNavTree('md__benchmarks.html','');});
|
||||
<h3>Some other serialization systems we compared against but did not benchmark (yet), in rough order of applicability:</h3>
|
||||
<ul>
|
||||
<li>Cap'n'Proto promises to reduce Protocol Buffers much like FlatBuffers does, though with a more complicated binary encoding and less flexibility (no optional fields to allow deprecating fields or serializing with missing fields for which defaults exist). It currently also isn't fully cross-platform portable (lack of VS support).</li>
|
||||
<li>msgpack: has very minimal forwards/backwards compatability support when used with the typed C++ interface. Also lacks VS2010 support.</li>
|
||||
<li>msgpack: has very minimal forwards/backwards compatibility support when used with the typed C++ interface. Also lacks VS2010 support.</li>
|
||||
<li>Thrift: very similar to Protocol Buffers, but appears to be less efficient, and have more dependencies.</li>
|
||||
<li>YAML: a superset of JSON and otherwise very similar. Used by e.g. Unity.</li>
|
||||
<li>C# comes with built-in serialization functionality, as used by Unity also. Being tied to the language, and having no automatic versioning support limits its applicability.</li>
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
<!-- HTML header for doxygen 1.8.6-->
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
@@ -15,17 +16,24 @@
|
||||
$(document).ready(initResizable);
|
||||
$(window).load(resizeHeight);
|
||||
</script>
|
||||
<link href="doxygen.css" rel="stylesheet" type="text/css" />
|
||||
<link href="style.css" rel="stylesheet" type="text/css" />
|
||||
<link href="https://fonts.googleapis.com/css?family=Roboto:300,400,400italic,500,500italic,700,700italic|Roboto+Mono:400,700" rel="stylesheet">
|
||||
</head>
|
||||
<body>
|
||||
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
|
||||
<div id="titlearea">
|
||||
<div id="titlearea" style="height: 110px;">
|
||||
<table cellspacing="0" cellpadding="0">
|
||||
<tbody>
|
||||
<tr style="height: 56px;">
|
||||
<td id="commonprojectlogo">
|
||||
<img alt="Logo" src="fpl_logo_small.png"/>
|
||||
</td>
|
||||
<td style="padding-left: 0.5em;">
|
||||
<div id="projectname">FlatBuffers
|
||||
</div>
|
||||
<div style="font-size:12px;">
|
||||
An open source project by <a href="https://developers.google.com/games/#Tools">FPL</a>.
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
<!-- HTML header for doxygen 1.8.6-->
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
@@ -15,17 +16,24 @@
|
||||
$(document).ready(initResizable);
|
||||
$(window).load(resizeHeight);
|
||||
</script>
|
||||
<link href="doxygen.css" rel="stylesheet" type="text/css" />
|
||||
<link href="style.css" rel="stylesheet" type="text/css" />
|
||||
<link href="https://fonts.googleapis.com/css?family=Roboto:300,400,400italic,500,500italic,700,700italic|Roboto+Mono:400,700" rel="stylesheet">
|
||||
</head>
|
||||
<body>
|
||||
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
|
||||
<div id="titlearea">
|
||||
<div id="titlearea" style="height: 110px;">
|
||||
<table cellspacing="0" cellpadding="0">
|
||||
<tbody>
|
||||
<tr style="height: 56px;">
|
||||
<td id="commonprojectlogo">
|
||||
<img alt="Logo" src="fpl_logo_small.png"/>
|
||||
</td>
|
||||
<td style="padding-left: 0.5em;">
|
||||
<div id="projectname">FlatBuffers
|
||||
</div>
|
||||
<div style="font-size:12px;">
|
||||
An open source project by <a href="https://developers.google.com/games/#Tools">FPL</a>.
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
@@ -67,10 +75,18 @@ $(document).ready(function(){initNavTree('md__compiler.html','');});
|
||||
<li><code>-t</code> : If data is contained in this file, generate a <code>filename.json</code> representing the data in the flatbuffer.</li>
|
||||
<li><code>-o PATH</code> : Output all generated files to PATH (either absolute, or relative to the current directory). If omitted, PATH will be the current directory. PATH should end in your systems path separator, e.g. <code>/</code> or <code>\</code>.</li>
|
||||
<li><code>-I PATH</code> : when encountering <code>include</code> statements, attempt to load the files from this path. Paths will be tried in the order given, and if all fail (or none are specified) it will try to load relative to the path of the schema file being parsed.</li>
|
||||
<li><code>-M</code> : Print make rules for generated files.</li>
|
||||
<li><code>--strict-json</code> : Require & generate strict JSON (field names are enclosed in quotes, no trailing commas in tables/vectors). By default, no quotes are required/generated, and trailing commas are allowed.</li>
|
||||
<li><code>--defaults-json</code> : Output fields whose value is equal to the default value when writing JSON text.</li>
|
||||
<li><code>--no-prefix</code> : Don't prefix enum values in generated C++ by their enum type.</li>
|
||||
<li><code>--gen-includes</code> : Generate include statements for included schemas the generated file depends on (C++).</li>
|
||||
<li><code>--proto</code>: Expect input files to be .proto files (protocol buffers). Output the corresponding .fbs file. Currently supports: <code>package</code>, <code>message</code>, <code>enum</code>. Does not support, but will skip without error: <code>import</code>, <code>option</code>. Does not support, will generate error: <code>service</code>, <code>extend</code>, <code>extensions</code>, <code>oneof</code>, <code>group</code>, custom options, nested declarations. </li>
|
||||
<li><code>--scoped-enums</code> : Use C++11 style scoped and strongly typed enums in generated C++. This also implies <code>--no-prefix</code>.</li>
|
||||
<li><code>--gen-includes</code> : (deprecated), this is the default behavior. If the original behavior is required (no include statements) use <code>--no-includes.</code></li>
|
||||
<li><code>--no-includes</code> : Don't generate include statements for included schemas the generated file depends on (C++).</li>
|
||||
<li><code>--gen-mutable</code> : Generate additional non-const accessors for mutating FlatBuffers in-place.</li>
|
||||
<li><code>--gen-onefile</code> : Generate single output file (useful for C#)</li>
|
||||
<li><code>--raw-binary</code> : Allow binaries without a file_indentifier to be read. This may crash flatc given a mismatched schema.</li>
|
||||
<li><code>--proto</code>: Expect input files to be .proto files (protocol buffers). Output the corresponding .fbs file. Currently supports: <code>package</code>, <code>message</code>, <code>enum</code>, nested declarations, <code>import</code> (use <code>-I</code> for paths), <code>extend</code>, <code>oneof</code>, <code>group</code>. Does not support, but will skip without error: <code>option</code>, <code>service</code>, <code>extensions</code>, and most everything else.</li>
|
||||
<li><code>--schema</code>: Serialize schemas instead of JSON (use with -b). This will output a binary version of the specified schema that itself corresponds to the reflection/reflection.fbs schema. Loading this binary file is the basis for reflection functionality. </li>
|
||||
</ul>
|
||||
</div></div><!-- contents -->
|
||||
</div><!-- doc-content -->
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
<!-- HTML header for doxygen 1.8.6-->
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
@@ -15,17 +16,24 @@
|
||||
$(document).ready(initResizable);
|
||||
$(window).load(resizeHeight);
|
||||
</script>
|
||||
<link href="doxygen.css" rel="stylesheet" type="text/css" />
|
||||
<link href="style.css" rel="stylesheet" type="text/css" />
|
||||
<link href="https://fonts.googleapis.com/css?family=Roboto:300,400,400italic,500,500italic,700,700italic|Roboto+Mono:400,700" rel="stylesheet">
|
||||
</head>
|
||||
<body>
|
||||
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
|
||||
<div id="titlearea">
|
||||
<div id="titlearea" style="height: 110px;">
|
||||
<table cellspacing="0" cellpadding="0">
|
||||
<tbody>
|
||||
<tr style="height: 56px;">
|
||||
<td id="commonprojectlogo">
|
||||
<img alt="Logo" src="fpl_logo_small.png"/>
|
||||
</td>
|
||||
<td style="padding-left: 0.5em;">
|
||||
<div id="projectname">FlatBuffers
|
||||
</div>
|
||||
<div style="font-size:12px;">
|
||||
An open source project by <a href="https://developers.google.com/games/#Tools">FPL</a>.
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
@@ -71,7 +79,7 @@ $(document).ready(function(){initNavTree('md__cpp_usage.html','');});
|
||||
<p>We have now serialized the non-scalar components of of the monster example, so we could create the monster something like this:</p>
|
||||
<div class="fragment"><div class="line"><span class="keyword">auto</span> mloc = CreateMonster(fbb, &vec, 150, 80, name, inventory, Color_Red, 0, Any_NONE);</div>
|
||||
</div><!-- fragment --><p>Note that we're passing <code>150</code> for the <code>mana</code> field, which happens to be the default value: this means the field will not actually be written to the buffer, since we'll get that value anyway when we query it. This is a nice space savings, since it is very common for fields to be at their default. It means we also don't need to be scared to add fields only used in a minority of cases, since they won't bloat up the buffer sizes if they're not actually used.</p>
|
||||
<p>We do something similarly for the union field <code>test</code> by specifying a <code>0</code> offset and the <code>NONE</code> enum value (part of every union) to indicate we don't actually want to write this field. You can use <code>0</code> also as a default for other non-scalar types, such as strings, vectors and tables.</p>
|
||||
<p>We do something similarly for the union field <code>test</code> by specifying a <code>0</code> offset and the <code>NONE</code> enum value (part of every union) to indicate we don't actually want to write this field. You can use <code>0</code> also as a default for other non-scalar types, such as strings, vectors and tables. To pass an actual table, pass a preconstructed table as <code>mytable.Union()</code> that corresponds to union enum you're passing.</p>
|
||||
<p>Tables (like <code>Monster</code>) give you full flexibility on what fields you write (unlike <code>Vec3</code>, which always has all fields set because it is a <code>struct</code>). If you want even more control over this (i.e. skip fields even when they are not default), instead of the convenient <code>CreateMonster</code> call we can also build the object field-by-field manually:</p>
|
||||
<div class="fragment"><div class="line">MonsterBuilder mb(fbb);</div>
|
||||
<div class="line">mb.add_pos(&vec);</div>
|
||||
@@ -102,7 +110,27 @@ $(document).ready(function(){initNavTree('md__cpp_usage.html','');});
|
||||
<div class="fragment"><div class="line"><span class="keyword">auto</span> inv = monster->inventory();</div>
|
||||
<div class="line">assert(inv);</div>
|
||||
<div class="line">assert(inv->Get(9) == 9);</div>
|
||||
</div><!-- fragment --><h3>Storing maps / dictionaries in a FlatBuffer</h3>
|
||||
</div><!-- fragment --><h3>Mutating FlatBuffers</h3>
|
||||
<p>As you saw above, typically once you have created a FlatBuffer, it is read-only from that moment on. There are however cases where you have just received a FlatBuffer, and you'd like to modify something about it before sending it on to another recipient. With the above functionality, you'd have to generate an entirely new FlatBuffer, while tracking what you modify in your own data structures. This is inconvenient.</p>
|
||||
<p>For this reason FlatBuffers can also be mutated in-place. While this is great for making small fixes to an existing buffer, you generally want to create buffers from scratch whenever possible, since it is much more efficient and the API is much more general purpose.</p>
|
||||
<p>To get non-const accessors, invoke <code>flatc</code> with <code>--gen-mutable</code>.</p>
|
||||
<p>Similar to the reading API above, you now can:</p>
|
||||
<div class="fragment"><div class="line"><span class="keyword">auto</span> monster = GetMutableMonster(buffer_pointer); <span class="comment">// non-const</span></div>
|
||||
<div class="line">monster->mutate_hp(10); <span class="comment">// Set table field.</span></div>
|
||||
<div class="line">monster->mutable_pos()->mutate_z(4); <span class="comment">// Set struct field.</span></div>
|
||||
<div class="line">monster->mutable_inventory()->Mutate(0, 1); <span class="comment">// Set vector element.</span></div>
|
||||
</div><!-- fragment --><p>We use the somewhat verbose term <code>mutate</code> instead of <code>set</code> to indicate that this is a special use case, not to be confused with the default way of constructing FlatBuffer data.</p>
|
||||
<p>After the above mutations, you can send on the FlatBuffer to a new recipient without any further work!</p>
|
||||
<p>Note that any <code>mutate_</code> functions on tables return a bool, which is false if the field we're trying to set isn't present in the buffer. Fields are not present if they weren't set, or even if they happen to be equal to the default value. For example, in the creation code above we set the <code>mana</code> field to <code>150</code>, which is the default value, so it was never stored in the buffer. Trying to call mutate_mana() on such data will return false, and the value won't actually be modified!</p>
|
||||
<p>One way to solve this is to call <code>ForceDefaults()</code> on a <code>FlatBufferBuilder</code> to force all fields you set to actually be written. This of course increases the size of the buffer somewhat, but this may be acceptable for a mutable buffer.</p>
|
||||
<p>Alternatively, you can use the more powerful reflection functionality:</p>
|
||||
<h3>Reflection (& Resizing)</h3>
|
||||
<p>If the above ways of accessing a buffer are still too static for you, there is experimental support for reflection in FlatBuffers, allowing you to read and write data even if you don't know the exact format of a buffer, and even allows you to change sizes of strings and vectors in-place.</p>
|
||||
<p>The way this works is very elegant, there is actually a FlatBuffer schema that describes schemas (!) which you can find in <code>reflection/reflection.fbs</code>. The compiler <code>flatc</code> can write out any schemas it has just parsed as a binary FlatBuffer, corresponding to this meta-schema.</p>
|
||||
<p>Loading in one of these binary schemas at runtime allows you traverse any FlatBuffer data that corresponds to it without knowing the exact format. You can query what fields are present, and then read/write them after.</p>
|
||||
<p>For convenient field manipulation, you can include the header <code>flatbuffers/reflection.h</code> which includes both the generated code from the meta schema, as well as a lot of helper functions.</p>
|
||||
<p>And example of usage for the moment you can find in <code>test.cpp/ReflectionTest()</code>.</p>
|
||||
<h3>Storing maps / dictionaries in a FlatBuffer</h3>
|
||||
<p>FlatBuffers doesn't support maps natively, but there is support to emulate their behavior with vectors and binary search, which means you can have fast lookups directly from a FlatBuffer without having to unpack your data into a <code>std::map</code> or similar.</p>
|
||||
<p>To use it:</p><ul>
|
||||
<li>Designate one of the fields in a table as they "key" field. You do this by setting the <code>key</code> attribute on this field, e.g. <code>name:string (key)</code>. You may only have one key field, and it must be of string or scalar type.</li>
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
<!-- HTML header for doxygen 1.8.6-->
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
@@ -15,17 +16,24 @@
|
||||
$(document).ready(initResizable);
|
||||
$(window).load(resizeHeight);
|
||||
</script>
|
||||
<link href="doxygen.css" rel="stylesheet" type="text/css" />
|
||||
<link href="style.css" rel="stylesheet" type="text/css" />
|
||||
<link href="https://fonts.googleapis.com/css?family=Roboto:300,400,400italic,500,500italic,700,700italic|Roboto+Mono:400,700" rel="stylesheet">
|
||||
</head>
|
||||
<body>
|
||||
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
|
||||
<div id="titlearea">
|
||||
<div id="titlearea" style="height: 110px;">
|
||||
<table cellspacing="0" cellpadding="0">
|
||||
<tbody>
|
||||
<tr style="height: 56px;">
|
||||
<td id="commonprojectlogo">
|
||||
<img alt="Logo" src="fpl_logo_small.png"/>
|
||||
</td>
|
||||
<td style="padding-left: 0.5em;">
|
||||
<div id="projectname">FlatBuffers
|
||||
</div>
|
||||
<div style="font-size:12px;">
|
||||
An open source project by <a href="https://developers.google.com/games/#Tools">FPL</a>.
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
<!-- HTML header for doxygen 1.8.6-->
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=9"/>
|
||||
<meta name="generator" content="Doxygen 1.8.7"/>
|
||||
<title>FlatBuffers: Formal Grammar of the schema language</title>
|
||||
<title>FlatBuffers: Grammar of the schema language</title>
|
||||
<link href="tabs.css" rel="stylesheet" type="text/css"/>
|
||||
<script type="text/javascript" src="jquery.js"></script>
|
||||
<script type="text/javascript" src="dynsections.js"></script>
|
||||
@@ -15,17 +16,24 @@
|
||||
$(document).ready(initResizable);
|
||||
$(window).load(resizeHeight);
|
||||
</script>
|
||||
<link href="doxygen.css" rel="stylesheet" type="text/css" />
|
||||
<link href="style.css" rel="stylesheet" type="text/css" />
|
||||
<link href="https://fonts.googleapis.com/css?family=Roboto:300,400,400italic,500,500italic,700,700italic|Roboto+Mono:400,700" rel="stylesheet">
|
||||
</head>
|
||||
<body>
|
||||
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
|
||||
<div id="titlearea">
|
||||
<div id="titlearea" style="height: 110px;">
|
||||
<table cellspacing="0" cellpadding="0">
|
||||
<tbody>
|
||||
<tr style="height: 56px;">
|
||||
<td id="commonprojectlogo">
|
||||
<img alt="Logo" src="fpl_logo_small.png"/>
|
||||
</td>
|
||||
<td style="padding-left: 0.5em;">
|
||||
<div id="projectname">FlatBuffers
|
||||
</div>
|
||||
<div style="font-size:12px;">
|
||||
An open source project by <a href="https://developers.google.com/games/#Tools">FPL</a>.
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
@@ -50,24 +58,29 @@ $(document).ready(function(){initNavTree('md__grammar.html','');});
|
||||
<div id="doc-content">
|
||||
<div class="header">
|
||||
<div class="headertitle">
|
||||
<div class="title">Formal Grammar of the schema language </div> </div>
|
||||
<div class="title">Grammar of the schema language </div> </div>
|
||||
</div><!--header-->
|
||||
<div class="contents">
|
||||
<div class="textblock"><p>schema = include* ( namespace_decl | type_decl | enum_decl | root_decl | attribute_decl | object )*</p>
|
||||
<div class="textblock"><p>schema = include* ( namespace_decl | type_decl | enum_decl | root_decl | file_extension_decl | file_identifier_decl | attribute_decl | object )*</p>
|
||||
<p>include = <code>include</code> string_constant <code>;</code></p>
|
||||
<p>namespace_decl = <code>namespace</code> ident ( <code>.</code> ident )* <code>;</code></p>
|
||||
<p>attribute_decl = <code>attribute</code> string_constant <code>;</code></p>
|
||||
<p>type_decl = ( <code>table</code> | <code>struct</code> ) ident metadata <code>{</code> field_decl+ <code>}</code></p>
|
||||
<p>enum_decl = ( <code>enum</code> | <code>union</code> ) ident [ <code>:</code> type ] metadata <code>{</code> commasep( enumval_decl ) <code>}</code></p>
|
||||
<p>root_decl = <code>root_type</code> ident <code>;</code></p>
|
||||
<p>field_decl = type <code>:</code> ident [ <code>=</code> scalar ] metadata <code>;</code></p>
|
||||
<p>field_decl = ident <code>:</code> type [ <code>=</code> scalar ] metadata <code>;</code></p>
|
||||
<p>type = <code>bool</code> | <code>byte</code> | <code>ubyte</code> | <code>short</code> | <code>ushort</code> | <code>int</code> | <code>uint</code> | <code>float</code> | <code>long</code> | <code>ulong</code> | <code>double</code> | <code>string</code> | <code>[</code> type <code>]</code> | ident</p>
|
||||
<p>enumval_decl = ident [ <code>=</code> integer_constant ]</p>
|
||||
<p>metadata = [ <code>(</code> commasep( ident [ <code>:</code> scalar ] ) <code>)</code> ]</p>
|
||||
<p>scalar = integer_constant | float_constant | <code>true</code> | <code>false</code></p>
|
||||
<p>metadata = [ <code>(</code> commasep( ident [ <code>:</code> single_value ] ) <code>)</code> ]</p>
|
||||
<p>scalar = integer_constant | float_constant</p>
|
||||
<p>object = { commasep( ident <code>:</code> value ) }</p>
|
||||
<p>value = scalar | object | string_constant | <code>[</code> commasep( value ) <code>]</code></p>
|
||||
<p>commasep(x) = [ x ( <code>,</code> x )* ] </p>
|
||||
<p>single_value = scalar | string_constant</p>
|
||||
<p>value = single_value | object | <code>[</code> commasep( value ) <code>]</code></p>
|
||||
<p>commasep(x) = [ x ( <code>,</code> x )* ]</p>
|
||||
<p>file_extension_decl = <code>file_extension</code> string_constant <code>;</code></p>
|
||||
<p>file_identifier_decl = <code>file_identifier</code> string_constant <code>;</code></p>
|
||||
<p>integer_constant = -?[0-9]+ | <code>true</code> | <code>false</code></p>
|
||||
<p>float_constant = -?[0-9]+.[0-9]+((e|E)(+|-)?[0-9]+)? </p>
|
||||
</div></div><!-- contents -->
|
||||
</div><!-- doc-content -->
|
||||
<!-- Google Analytics -->
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
<!-- HTML header for doxygen 1.8.6-->
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
@@ -15,17 +16,24 @@
|
||||
$(document).ready(initResizable);
|
||||
$(window).load(resizeHeight);
|
||||
</script>
|
||||
<link href="doxygen.css" rel="stylesheet" type="text/css" />
|
||||
<link href="style.css" rel="stylesheet" type="text/css" />
|
||||
<link href="https://fonts.googleapis.com/css?family=Roboto:300,400,400italic,500,500italic,700,700italic|Roboto+Mono:400,700" rel="stylesheet">
|
||||
</head>
|
||||
<body>
|
||||
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
|
||||
<div id="titlearea">
|
||||
<div id="titlearea" style="height: 110px;">
|
||||
<table cellspacing="0" cellpadding="0">
|
||||
<tbody>
|
||||
<tr style="height: 56px;">
|
||||
<td id="commonprojectlogo">
|
||||
<img alt="Logo" src="fpl_logo_small.png"/>
|
||||
</td>
|
||||
<td style="padding-left: 0.5em;">
|
||||
<div id="projectname">FlatBuffers
|
||||
</div>
|
||||
<div style="font-size:12px;">
|
||||
An open source project by <a href="https://developers.google.com/games/#Tools">FPL</a>.
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
<!-- HTML header for doxygen 1.8.6-->
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
@@ -15,17 +16,24 @@
|
||||
$(document).ready(initResizable);
|
||||
$(window).load(resizeHeight);
|
||||
</script>
|
||||
<link href="doxygen.css" rel="stylesheet" type="text/css" />
|
||||
<link href="style.css" rel="stylesheet" type="text/css" />
|
||||
<link href="https://fonts.googleapis.com/css?family=Roboto:300,400,400italic,500,500italic,700,700italic|Roboto+Mono:400,700" rel="stylesheet">
|
||||
</head>
|
||||
<body>
|
||||
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
|
||||
<div id="titlearea">
|
||||
<div id="titlearea" style="height: 110px;">
|
||||
<table cellspacing="0" cellpadding="0">
|
||||
<tbody>
|
||||
<tr style="height: 56px;">
|
||||
<td id="commonprojectlogo">
|
||||
<img alt="Logo" src="fpl_logo_small.png"/>
|
||||
</td>
|
||||
<td style="padding-left: 0.5em;">
|
||||
<div id="projectname">FlatBuffers
|
||||
</div>
|
||||
<div style="font-size:12px;">
|
||||
An open source project by <a href="https://developers.google.com/games/#Tools">FPL</a>.
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
@@ -54,7 +62,7 @@ $(document).ready(function(){initNavTree('md__java_usage.html','');});
|
||||
</div><!--header-->
|
||||
<div class="contents">
|
||||
<div class="textblock"><p>FlatBuffers supports reading and writing binary FlatBuffers in Java and C#. Generate code for Java with the <code>-j</code> option to <code>flatc</code>, or for C# with <code>-n</code> (think .Net).</p>
|
||||
<p>Note that this document is from the perspective of Java. Code for both languages is generated in the same way, with only very subtle differences, for example any <code>camelCase</code> Java call will be <code>CamelCase</code> in C#.</p>
|
||||
<p>Note that this document is from the perspective of Java. Code for both languages is generated in the same way, with only minor differences. These differences are <a href="#differences-in-c-sharp">explained in a section below</a>.</p>
|
||||
<p>See <code>javaTest.java</code> for an example. Essentially, you read a FlatBuffer binary file into a <code>byte[]</code>, which you then turn into a <code>ByteBuffer</code>, which you pass to the <code>getRootAsMyRootType</code> function:</p>
|
||||
<div class="fragment"><div class="line">ByteBuffer bb = ByteBuffer.wrap(data);</div>
|
||||
<div class="line">Monster monster = Monster.getRootAsMonster(bb);</div>
|
||||
@@ -88,7 +96,7 @@ $(document).ready(function(){initNavTree('md__java_usage.html','');});
|
||||
</div><!-- fragment --><p>For some simpler types, you can use a convenient <code>create</code> function call that allows you to construct tables in one function call. This example definition however contains an inline struct field, so we have to create the table manually. This is to create the buffer without using temporary object allocation.</p>
|
||||
<p>It's important to understand that fields that are structs are inline (like <code>Vec3</code> above), and MUST thus be created between the start and end calls of a table. Everything else (other tables, strings, vectors) MUST be created before the start of the table they are referenced in.</p>
|
||||
<p>Structs do have convenient methods that even have arguments for nested structs.</p>
|
||||
<p>As you can see, references to other objects (e.g. the string above) are simple ints, and thus do not have the type-safety of the Offset type in C++. Extra case must thus be taken that you set the right offset on the right field.</p>
|
||||
<p>As you can see, references to other objects (e.g. the string above) are simple ints, and thus do not have the type-safety of the Offset type in C++. Extra care must thus be taken that you set the right offset on the right field.</p>
|
||||
<p>Vectors can be created from the corresponding Java array like so:</p>
|
||||
<div class="fragment"><div class="line"><span class="keywordtype">int</span> inv = Monster.createInventoryVector(fbb, <span class="keyword">new</span> byte[] { 0, 1, 2, 3, 4 });</div>
|
||||
</div><!-- fragment --><p>This works for arrays of scalars and (int) offsets to strings/tables, but not structs. If you want to write structs, or what you want to write does not sit in an array, you can also use the start/end pattern:</p>
|
||||
@@ -100,8 +108,29 @@ $(document).ready(function(){initNavTree('md__java_usage.html','');});
|
||||
<p>To finish the buffer, call:</p>
|
||||
<div class="fragment"><div class="line">Monster.finishMonsterBuffer(fbb, mon);</div>
|
||||
</div><!-- fragment --><p>The buffer is now ready to be transmitted. It is contained in the <code>ByteBuffer</code> which you can obtain from <code>fbb.dataBuffer()</code>. Importantly, the valid data does not start from offset 0 in this buffer, but from <code>fbb.dataBuffer().position()</code> (this is because the data was built backwards in memory). It ends at <code>fbb.capacity()</code>.</p>
|
||||
<h2>Text Parsing</h2>
|
||||
<p>There currently is no support for parsing text (Schema's and JSON) directly from Java, though you could use the C++ parser through JNI. Please see the C++ documentation for more on text parsing. </p>
|
||||
<h2>Differences in C-sharp</h2>
|
||||
<p>C# code works almost identically to Java, with only a few minor differences. You can see an example of C# code in <code>tests/FlatBuffers.Test/FlatBuffersExampleTests.cs</code>.</p>
|
||||
<p>First of all, naming follows standard C# style with <code>PascalCasing</code> identifiers, e.g. <code>GetRootAsMyRootType</code>. Also, values (except vectors and unions) are available as properties instead of parameterless accessor methods as in Java. The performance-enhancing methods to which you can pass an already created object are prefixed with <code>Get</code>, e.g.:</p>
|
||||
<div class="fragment"><div class="line"><span class="comment">// property</span></div>
|
||||
<div class="line">var pos = monster.Pos;</div>
|
||||
<div class="line"><span class="comment">// method filling a preconstructed object</span></div>
|
||||
<div class="line">var preconstructedPos = <span class="keyword">new</span> Vec3();</div>
|
||||
<div class="line">monster.GetPos(preconstructedPos);</div>
|
||||
</div><!-- fragment --><h2>Text parsing</h2>
|
||||
<p>There currently is no support for parsing text (Schema's and JSON) directly from Java or C#, though you could use the C++ parser through native call interfaces available to each language. Please see the C++ documentation for more on text parsing.</p>
|
||||
<h3>Mutating FlatBuffers</h3>
|
||||
<p>As you saw above, typically once you have created a FlatBuffer, it is read-only from that moment on. There are however cases where you have just received a FlatBuffer, and you'd like to modify something about it before sending it on to another recipient. With the above functionality, you'd have to generate an entirely new FlatBuffer, while tracking what you modify in your own data structures. This is inconvenient.</p>
|
||||
<p>For this reason FlatBuffers can also be mutated in-place. While this is great for making small fixes to an existing buffer, you generally want to create buffers from scratch whenever possible, since it is much more efficient and the API is much more general purpose.</p>
|
||||
<p>To get non-const accessors, invoke <code>flatc</code> with <code>--gen-mutable</code>.</p>
|
||||
<p>You now can:</p>
|
||||
<div class="fragment"><div class="line">Monster monster = Monster.getRootAsMonster(bb);</div>
|
||||
<div class="line">monster.mutateHp(10); <span class="comment">// Set table field.</span></div>
|
||||
<div class="line">monster.pos().mutateZ(4); <span class="comment">// Set struct field.</span></div>
|
||||
<div class="line">monster.mutateInventory(0, 1); <span class="comment">// Set vector element.</span></div>
|
||||
</div><!-- fragment --><p>We use the somewhat verbose term <code>mutate</code> instead of <code>set</code> to indicate that this is a special use case, not to be confused with the default way of constructing FlatBuffer data.</p>
|
||||
<p>After the above mutations, you can send on the FlatBuffer to a new recipient without any further work!</p>
|
||||
<p>Note that any <code>mutate</code> functions on tables return a boolean, which is false if the field we're trying to set isn't present in the buffer. Fields are not present if they weren't set, or even if they happen to be equal to the default value. For example, in the creation code above we set the <code>mana</code> field to <code>150</code>, which is the default value, so it was never stored in the buffer. Trying to call mutateMana() on such data will return false, and the value won't actually be modified!</p>
|
||||
<p>One way to solve this is to call <code>forceDefaults()</code> on a <code>FlatBufferBuilder</code> to force all fields you set to actually be written. This of course increases the size of the buffer somewhat, but this may be acceptable for a mutable buffer. </p>
|
||||
</div></div><!-- contents -->
|
||||
</div><!-- doc-content -->
|
||||
<!-- Google Analytics -->
|
||||
|
||||
120
docs/html/md__python_usage.html
Normal file
120
docs/html/md__python_usage.html
Normal file
@@ -0,0 +1,120 @@
|
||||
<!-- HTML header for doxygen 1.8.6-->
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=9"/>
|
||||
<meta name="generator" content="Doxygen 1.8.7"/>
|
||||
<title>FlatBuffers: Use in Python</title>
|
||||
<link href="tabs.css" rel="stylesheet" type="text/css"/>
|
||||
<script type="text/javascript" src="jquery.js"></script>
|
||||
<script type="text/javascript" src="dynsections.js"></script>
|
||||
<link href="navtree.css" rel="stylesheet" type="text/css"/>
|
||||
<script type="text/javascript" src="resize.js"></script>
|
||||
<script type="text/javascript" src="navtree.js"></script>
|
||||
<script type="text/javascript">
|
||||
$(document).ready(initResizable);
|
||||
$(window).load(resizeHeight);
|
||||
</script>
|
||||
<link href="style.css" rel="stylesheet" type="text/css" />
|
||||
<link href="https://fonts.googleapis.com/css?family=Roboto:300,400,400italic,500,500italic,700,700italic|Roboto+Mono:400,700" rel="stylesheet">
|
||||
</head>
|
||||
<body>
|
||||
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
|
||||
<div id="titlearea" style="height: 110px;">
|
||||
<table cellspacing="0" cellpadding="0">
|
||||
<tbody>
|
||||
<tr style="height: 56px;">
|
||||
<td id="commonprojectlogo">
|
||||
<img alt="Logo" src="fpl_logo_small.png"/>
|
||||
</td>
|
||||
<td style="padding-left: 0.5em;">
|
||||
<div id="projectname">FlatBuffers
|
||||
</div>
|
||||
<div style="font-size:12px;">
|
||||
An open source project by <a href="https://developers.google.com/games/#Tools">FPL</a>.
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<!-- end header part -->
|
||||
<!-- Generated by Doxygen 1.8.7 -->
|
||||
</div><!-- top -->
|
||||
<div id="side-nav" class="ui-resizable side-nav-resizable">
|
||||
<div id="nav-tree">
|
||||
<div id="nav-tree-contents">
|
||||
<div id="nav-sync" class="sync"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="splitbar" style="-moz-user-select:none;"
|
||||
class="ui-resizable-handle">
|
||||
</div>
|
||||
</div>
|
||||
<script type="text/javascript">
|
||||
$(document).ready(function(){initNavTree('md__python_usage.html','');});
|
||||
</script>
|
||||
<div id="doc-content">
|
||||
<div class="header">
|
||||
<div class="headertitle">
|
||||
<div class="title">Use in Python </div> </div>
|
||||
</div><!--header-->
|
||||
<div class="contents">
|
||||
<div class="textblock"><p>There's experimental support for reading FlatBuffers in Python. Generate code for Python with the <code>-p</code> option to <code>flatc</code>.</p>
|
||||
<p>See <code>py_test.py</code> for an example. You import the generated code, read a FlatBuffer binary file into a <code>bytearray</code>, which you pass to the <code>GetRootAsMonster</code> function:</p>
|
||||
<div class="fragment"><div class="line"><a name="l00001"></a><span class="lineno"> 1</span> import MyGame.Example <span class="keyword">as</span> example</div>
|
||||
<div class="line"><a name="l00002"></a><span class="lineno"> 2</span> <span class="keyword">import</span> flatbuffers</div>
|
||||
<div class="line"><a name="l00003"></a><span class="lineno"> 3</span> </div>
|
||||
<div class="line"><a name="l00004"></a><span class="lineno"> 4</span> buf = open(<span class="stringliteral">'monster.dat'</span>, <span class="stringliteral">'rb'</span>).read()</div>
|
||||
<div class="line"><a name="l00005"></a><span class="lineno"> 5</span> buf = bytearray(buf)</div>
|
||||
<div class="line"><a name="l00006"></a><span class="lineno"> 6</span> monster = example.GetRootAsMonster(buf, 0)</div>
|
||||
</div><!-- fragment --><p>Now you can access values like this:</p>
|
||||
<div class="fragment"><div class="line"><a name="l00001"></a><span class="lineno"> 1</span> hp = monster.Hp()</div>
|
||||
<div class="line"><a name="l00002"></a><span class="lineno"> 2</span> pos = monster.Pos()</div>
|
||||
</div><!-- fragment --><p>To access vectors you pass an extra index to the vector field accessor. Then a second method with the same name suffixed by <code>Length</code> let's you know the number of elements you can access:</p>
|
||||
<div class="fragment"><div class="line"><a name="l00001"></a><span class="lineno"> 1</span> <span class="keywordflow">for</span> i <span class="keywordflow">in</span> xrange(monster.InventoryLength()):</div>
|
||||
<div class="line"><a name="l00002"></a><span class="lineno"> 2</span>  monster.Inventory(i) <span class="comment"># do something here</span></div>
|
||||
</div><!-- fragment --><p>You can also construct these buffers in Python using the functions found in the generated code, and the FlatBufferBuilder class:</p>
|
||||
<div class="fragment"><div class="line"><a name="l00001"></a><span class="lineno"> 1</span> builder = flatbuffers.Builder(0)</div>
|
||||
</div><!-- fragment --><p>Create strings:</p>
|
||||
<div class="fragment"><div class="line"><a name="l00001"></a><span class="lineno"> 1</span> s = builder.CreateString(<span class="stringliteral">"MyMonster"</span>)</div>
|
||||
</div><!-- fragment --><p>Create a table with a struct contained therein:</p>
|
||||
<div class="fragment"><div class="line"><a name="l00001"></a><span class="lineno"> 1</span> example.MonsterStart(builder)</div>
|
||||
<div class="line"><a name="l00002"></a><span class="lineno"> 2</span> example.MonsterAddPos(builder, example.CreateVec3(builder, 1.0, 2.0, 3.0, 3.0, 4, 5, 6))</div>
|
||||
<div class="line"><a name="l00003"></a><span class="lineno"> 3</span> example.MonsterAddHp(builder, 80)</div>
|
||||
<div class="line"><a name="l00004"></a><span class="lineno"> 4</span> example.MonsterAddName(builder, str)</div>
|
||||
<div class="line"><a name="l00005"></a><span class="lineno"> 5</span> example.MonsterAddInventory(builder, inv)</div>
|
||||
<div class="line"><a name="l00006"></a><span class="lineno"> 6</span> example.MonsterAddTest_Type(builder, 1)</div>
|
||||
<div class="line"><a name="l00007"></a><span class="lineno"> 7</span> example.MonsterAddTest(builder, mon2)</div>
|
||||
<div class="line"><a name="l00008"></a><span class="lineno"> 8</span> example.MonsterAddTest4(builder, test4s)</div>
|
||||
<div class="line"><a name="l00009"></a><span class="lineno"> 9</span> mon = example.MonsterEnd(builder)</div>
|
||||
<div class="line"><a name="l00010"></a><span class="lineno"> 10</span> </div>
|
||||
<div class="line"><a name="l00011"></a><span class="lineno"> 11</span> final_flatbuffer = builder.Output()</div>
|
||||
</div><!-- fragment --><p>Unlike C++, Python does not support table creation functions like 'createMonster()'. This is to create the buffer without using temporary object allocation (since the <code>Vec3</code> is an inline component of <code>Monster</code>, it has to be created right where it is added, whereas the name and the inventory are not inline, and <b>must</b> be created outside of the table creation sequence). Structs do have convenient methods that allow you to construct them in one call. These also have arguments for nested structs, e.g. if a struct has a field <code>a</code> and a nested struct field <code>b</code> (which has fields <code>c</code> and <code>d</code>), then the arguments will be <code>a</code>, <code>c</code> and <code>d</code>.</p>
|
||||
<p>Vectors also use this start/end pattern to allow vectors of both scalar types and structs:</p>
|
||||
<div class="fragment"><div class="line"><a name="l00001"></a><span class="lineno"> 1</span> example.MonsterStartInventoryVector(builder, 5)</div>
|
||||
<div class="line"><a name="l00002"></a><span class="lineno"> 2</span> i = 4</div>
|
||||
<div class="line"><a name="l00003"></a><span class="lineno"> 3</span> <span class="keywordflow">while</span> i >= 0:</div>
|
||||
<div class="line"><a name="l00004"></a><span class="lineno"> 4</span>  builder.PrependByte(byte(i))</div>
|
||||
<div class="line"><a name="l00005"></a><span class="lineno"> 5</span>  i -= 1</div>
|
||||
<div class="line"><a name="l00006"></a><span class="lineno"> 6</span> </div>
|
||||
<div class="line"><a name="l00007"></a><span class="lineno"> 7</span> inv = builder.EndVector(5)</div>
|
||||
</div><!-- fragment --><p>The generated method 'StartInventoryVector' is provided as a convenience function which calls 'StartVector' with the correct element size of the vector type which in this case is 'ubyte' or 1 byte per vector element. You pass the number of elements you want to write. You write the elements backwards since the buffer is being constructed back to front. Use the correct <code>Prepend</code> call for the type, or <code>PrependUOffsetT</code> for offsets. You then pass <code>inv</code> to the corresponding <code>Add</code> call when you construct the table containing it afterwards.</p>
|
||||
<p>There are <code>Prepend</code> functions for all the scalar types. You use <code>PrependUOffset</code> for any previously constructed objects (such as other tables, strings, vectors). For structs, you use the appropriate <code>create</code> function in-line, as shown above in the <code>Monster</code> example.</p>
|
||||
<p>Once you're done constructing a buffer, you call <code>Finish</code> with the root object offset (<code>mon</code> in the example above). Your data now resides in Builder.Bytes. Important to note is that the real data starts at the index indicated by Head(), for Offset() bytes (this is because the buffer is constructed backwards). If you wanted to read the buffer right after creating it (using <code>GetRootAsMonster</code> above), the second argument, instead of <code>0</code> would thus also be <code>Head()</code>.</p>
|
||||
<h2>Text Parsing</h2>
|
||||
<p>There currently is no support for parsing text (Schema's and JSON) directly from Python, though you could use the C++ parser through SWIG or ctypes. Please see the C++ documentation for more on text parsing. </p>
|
||||
</div></div><!-- contents -->
|
||||
</div><!-- doc-content -->
|
||||
<!-- Google Analytics -->
|
||||
<script>
|
||||
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
|
||||
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
|
||||
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
|
||||
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
|
||||
ga('create', 'UA-49880327-7', 'auto');
|
||||
ga('send', 'pageview');
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,3 +1,4 @@
|
||||
<!-- HTML header for doxygen 1.8.6-->
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
@@ -15,17 +16,24 @@
|
||||
$(document).ready(initResizable);
|
||||
$(window).load(resizeHeight);
|
||||
</script>
|
||||
<link href="doxygen.css" rel="stylesheet" type="text/css" />
|
||||
<link href="style.css" rel="stylesheet" type="text/css" />
|
||||
<link href="https://fonts.googleapis.com/css?family=Roboto:300,400,400italic,500,500italic,700,700italic|Roboto+Mono:400,700" rel="stylesheet">
|
||||
</head>
|
||||
<body>
|
||||
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
|
||||
<div id="titlearea">
|
||||
<div id="titlearea" style="height: 110px;">
|
||||
<table cellspacing="0" cellpadding="0">
|
||||
<tbody>
|
||||
<tr style="height: 56px;">
|
||||
<td id="commonprojectlogo">
|
||||
<img alt="Logo" src="fpl_logo_small.png"/>
|
||||
</td>
|
||||
<td style="padding-left: 0.5em;">
|
||||
<div id="projectname">FlatBuffers
|
||||
</div>
|
||||
<div style="font-size:12px;">
|
||||
An open source project by <a href="https://developers.google.com/games/#Tools">FPL</a>.
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
@@ -108,7 +116,8 @@ root_type Monster;
|
||||
</ul>
|
||||
<p>You can't change types of fields once they're used, with the exception of same-size data where a <code>reinterpret_cast</code> would give you a desirable result, e.g. you could change a <code>uint</code> to an <code>int</code> if no values in current data use the high bit yet.</p>
|
||||
<h3>(Default) Values</h3>
|
||||
<p>Values are a sequence of digits, optionally followed by a <code>.</code> and more digits for float constants, and optionally prefixed by a <code>-</code>. Non-scalar defaults are currently not supported (always NULL).</p>
|
||||
<p>Values are a sequence of digits, optionally followed by a <code>.</code> and more digits for float constants, and optionally prefixed by a <code>-</code>. Floats may end with an <code>e</code> or <code>E</code>, followed by a <code>+</code> or <code>-</code> and more digits (scientific notation).</p>
|
||||
<p>Only scalar values can have defaults, non-scalar (string/vector/table) fields default to NULL when not present.</p>
|
||||
<p>You generally do not want to change default values after they're initially defined. Fields that have the default value are not actually stored in the serialized data but are generated in code, so when you change the default, you'd now get a different value than from code generated from an older version of the schema. There are situations however where this may be desirable, especially if you can ensure a simultaneous rebuild of all code.</p>
|
||||
<h3>Enums</h3>
|
||||
<p>Define a sequence of named constants, each with a given value, or increasing by one from the previous one. The default first value is <code>0</code>. As you can see in the enum declaration, you specify the underlying integral type of the enum with <code>:</code> (in this case <code>byte</code>), which then determines the type of any fields declared with this enum type.</p>
|
||||
|
||||
122
docs/html/md__support.html
Normal file
122
docs/html/md__support.html
Normal file
@@ -0,0 +1,122 @@
|
||||
<!-- HTML header for doxygen 1.8.6-->
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=9"/>
|
||||
<meta name="generator" content="Doxygen 1.8.7"/>
|
||||
<title>FlatBuffers: Platform / Language / Feature support</title>
|
||||
<link href="tabs.css" rel="stylesheet" type="text/css"/>
|
||||
<script type="text/javascript" src="jquery.js"></script>
|
||||
<script type="text/javascript" src="dynsections.js"></script>
|
||||
<link href="navtree.css" rel="stylesheet" type="text/css"/>
|
||||
<script type="text/javascript" src="resize.js"></script>
|
||||
<script type="text/javascript" src="navtree.js"></script>
|
||||
<script type="text/javascript">
|
||||
$(document).ready(initResizable);
|
||||
$(window).load(resizeHeight);
|
||||
</script>
|
||||
<link href="style.css" rel="stylesheet" type="text/css" />
|
||||
<link href="https://fonts.googleapis.com/css?family=Roboto:300,400,400italic,500,500italic,700,700italic|Roboto+Mono:400,700" rel="stylesheet">
|
||||
</head>
|
||||
<body>
|
||||
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
|
||||
<div id="titlearea" style="height: 110px;">
|
||||
<table cellspacing="0" cellpadding="0">
|
||||
<tbody>
|
||||
<tr style="height: 56px;">
|
||||
<td id="commonprojectlogo">
|
||||
<img alt="Logo" src="fpl_logo_small.png"/>
|
||||
</td>
|
||||
<td style="padding-left: 0.5em;">
|
||||
<div id="projectname">FlatBuffers
|
||||
</div>
|
||||
<div style="font-size:12px;">
|
||||
An open source project by <a href="https://developers.google.com/games/#Tools">FPL</a>.
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<!-- end header part -->
|
||||
<!-- Generated by Doxygen 1.8.7 -->
|
||||
</div><!-- top -->
|
||||
<div id="side-nav" class="ui-resizable side-nav-resizable">
|
||||
<div id="nav-tree">
|
||||
<div id="nav-tree-contents">
|
||||
<div id="nav-sync" class="sync"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="splitbar" style="-moz-user-select:none;"
|
||||
class="ui-resizable-handle">
|
||||
</div>
|
||||
</div>
|
||||
<script type="text/javascript">
|
||||
$(document).ready(function(){initNavTree('md__support.html','');});
|
||||
</script>
|
||||
<div id="doc-content">
|
||||
<div class="header">
|
||||
<div class="headertitle">
|
||||
<div class="title">Platform / Language / Feature support </div> </div>
|
||||
</div><!--header-->
|
||||
<div class="contents">
|
||||
<div class="textblock"><p>FlatBuffers is actively being worked on, which means that certain platform / language / feature combinations may not be available yet.</p>
|
||||
<p>This page tries to track those issues, to make informed decisions easier. In general:</p>
|
||||
<ul>
|
||||
<li>Languages: language support beyond the ones created by the original FlatBuffer authors typically depends on community contributions.</li>
|
||||
<li>Features: C++ was the first language supported, since our original target was high performance game development. It thus has the richest feature set, and is likely most robust. Other languages are catching up however.</li>
|
||||
<li>Platforms: All language implementations are typically portable to most platforms, unless where noted otherwise.</li>
|
||||
</ul>
|
||||
<p>NOTE: this table is a start, it needs to be extended.</p>
|
||||
<table class="doxtable">
|
||||
<tr>
|
||||
<th>Feature </th><th>C++ </th><th>Java </th><th>C# </th><th>Go </th><th>Python </th><th>JS </th></tr>
|
||||
<tr>
|
||||
<td>Codegen for all basic features </td><td>Yes </td><td>Yes </td><td>Yes </td><td>Yes </td><td>Yes </td><td>WIP </td></tr>
|
||||
<tr>
|
||||
<td>JSON parsing </td><td>Yes </td><td>No </td><td>No </td><td>No </td><td>No </td><td>No </td></tr>
|
||||
<tr>
|
||||
<td>Simple mutation </td><td>Yes </td><td>WIP </td><td>WIP </td><td>No </td><td>No </td><td>No </td></tr>
|
||||
<tr>
|
||||
<td>Reflection </td><td>Yes </td><td>No </td><td>No </td><td>No </td><td>No </td><td>No </td></tr>
|
||||
<tr>
|
||||
<td>Buffer verifier </td><td>Yes </td><td>No </td><td>No </td><td>No </td><td>No </td><td>No </td></tr>
|
||||
<tr>
|
||||
<td>Testing: basic </td><td>Yes </td><td>Yes </td><td>Yes </td><td>Yes </td><td>Yes </td><td>WIP </td></tr>
|
||||
<tr>
|
||||
<td>Testing: fuzz </td><td>Yes </td><td>No </td><td>No </td><td>Yes </td><td>Yes </td><td>No </td></tr>
|
||||
<tr>
|
||||
<td>Performance: </td><td>Superb </td><td>Great </td><td>Great </td><td>Great </td><td>Ok </td><td>? </td></tr>
|
||||
<tr>
|
||||
<td>Platform: Windows </td><td>VS2010 </td><td>Yes </td><td>Yes </td><td>? </td><td>? </td><td>? </td></tr>
|
||||
<tr>
|
||||
<td>Platform: Linux </td><td>GCC282 </td><td>Yes </td><td>? </td><td>Yes </td><td>Yes </td><td>? </td></tr>
|
||||
<tr>
|
||||
<td>Platform: OS X </td><td>Xcode4 </td><td>? </td><td>? </td><td>? </td><td>Yes </td><td>? </td></tr>
|
||||
<tr>
|
||||
<td>Platform: Android </td><td>NDK10d </td><td>Yes </td><td>? </td><td>? </td><td>? </td><td>? </td></tr>
|
||||
<tr>
|
||||
<td>Platform: iOS </td><td>? </td><td>? </td><td>? </td><td>? </td><td>? </td><td>? </td></tr>
|
||||
<tr>
|
||||
<td>Engine: Unity </td><td>? </td><td>? </td><td>Yes </td><td>? </td><td>? </td><td>? </td></tr>
|
||||
<tr>
|
||||
<td>Primary authors (github) </td><td>wvo </td><td>wvo </td><td>(ev/js)</td><td>rw </td><td>rw </td><td>(ev) </td></tr>
|
||||
</table>
|
||||
<ul>
|
||||
<li>ev = evolutional</li>
|
||||
<li>js = jonsimantov </li>
|
||||
</ul>
|
||||
</div></div><!-- contents -->
|
||||
</div><!-- doc-content -->
|
||||
<!-- Google Analytics -->
|
||||
<script>
|
||||
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
|
||||
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
|
||||
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
|
||||
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
|
||||
ga('create', 'UA-49880327-7', 'auto');
|
||||
ga('send', 'pageview');
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,3 +1,4 @@
|
||||
<!-- HTML header for doxygen 1.8.6-->
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
@@ -15,17 +16,24 @@
|
||||
$(document).ready(initResizable);
|
||||
$(window).load(resizeHeight);
|
||||
</script>
|
||||
<link href="doxygen.css" rel="stylesheet" type="text/css" />
|
||||
<link href="style.css" rel="stylesheet" type="text/css" />
|
||||
<link href="https://fonts.googleapis.com/css?family=Roboto:300,400,400italic,500,500italic,700,700italic|Roboto+Mono:400,700" rel="stylesheet">
|
||||
</head>
|
||||
<body>
|
||||
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
|
||||
<div id="titlearea">
|
||||
<div id="titlearea" style="height: 110px;">
|
||||
<table cellspacing="0" cellpadding="0">
|
||||
<tbody>
|
||||
<tr style="height: 56px;">
|
||||
<td id="commonprojectlogo">
|
||||
<img alt="Logo" src="fpl_logo_small.png"/>
|
||||
</td>
|
||||
<td style="padding-left: 0.5em;">
|
||||
<div id="projectname">FlatBuffers
|
||||
</div>
|
||||
<div style="font-size:12px;">
|
||||
An open source project by <a href="https://developers.google.com/games/#Tools">FPL</a>.
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
||||
@@ -7,10 +7,12 @@ var NAVTREE =
|
||||
[ "Use in C++", "md__cpp_usage.html", null ],
|
||||
[ "Use in Go", "md__go_usage.html", null ],
|
||||
[ "Use in Java/C-sharp", "md__java_usage.html", null ],
|
||||
[ "Use in Python", "md__python_usage.html", null ],
|
||||
[ "Platform / Language / Feature support", "md__support.html", null ],
|
||||
[ "Benchmarks", "md__benchmarks.html", null ],
|
||||
[ "FlatBuffers white paper", "md__white_paper.html", null ],
|
||||
[ "FlatBuffer Internals", "md__internals.html", null ],
|
||||
[ "Formal Grammar of the schema language", "md__grammar.html", null ]
|
||||
[ "Grammar of the schema language", "md__grammar.html", null ]
|
||||
] ]
|
||||
];
|
||||
|
||||
|
||||
@@ -1,15 +1,17 @@
|
||||
var NAVTREEINDEX0 =
|
||||
{
|
||||
"index.html":[],
|
||||
"md__benchmarks.html":[6],
|
||||
"md__benchmarks.html":[8],
|
||||
"md__building.html":[0],
|
||||
"md__compiler.html":[1],
|
||||
"md__cpp_usage.html":[3],
|
||||
"md__go_usage.html":[4],
|
||||
"md__grammar.html":[9],
|
||||
"md__internals.html":[8],
|
||||
"md__grammar.html":[11],
|
||||
"md__internals.html":[10],
|
||||
"md__java_usage.html":[5],
|
||||
"md__python_usage.html":[6],
|
||||
"md__schemas.html":[2],
|
||||
"md__white_paper.html":[7],
|
||||
"md__support.html":[7],
|
||||
"md__white_paper.html":[9],
|
||||
"pages.html":[]
|
||||
};
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
<!-- HTML header for doxygen 1.8.6-->
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
@@ -15,17 +16,24 @@
|
||||
$(document).ready(initResizable);
|
||||
$(window).load(resizeHeight);
|
||||
</script>
|
||||
<link href="doxygen.css" rel="stylesheet" type="text/css" />
|
||||
<link href="style.css" rel="stylesheet" type="text/css" />
|
||||
<link href="https://fonts.googleapis.com/css?family=Roboto:300,400,400italic,500,500italic,700,700italic|Roboto+Mono:400,700" rel="stylesheet">
|
||||
</head>
|
||||
<body>
|
||||
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
|
||||
<div id="titlearea">
|
||||
<div id="titlearea" style="height: 110px;">
|
||||
<table cellspacing="0" cellpadding="0">
|
||||
<tbody>
|
||||
<tr style="height: 56px;">
|
||||
<td id="commonprojectlogo">
|
||||
<img alt="Logo" src="fpl_logo_small.png"/>
|
||||
</td>
|
||||
<td style="padding-left: 0.5em;">
|
||||
<div id="projectname">FlatBuffers
|
||||
</div>
|
||||
<div style="font-size:12px;">
|
||||
An open source project by <a href="https://developers.google.com/games/#Tools">FPL</a>.
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
@@ -61,10 +69,12 @@ $(document).ready(function(){initNavTree('pages.html','');});
|
||||
<tr id="row_3_"><td class="entry"><span style="width:16px;display:inline-block;"> </span><a class="el" href="md__cpp_usage.html" target="_self">Use in C++</a></td><td class="desc"></td></tr>
|
||||
<tr id="row_4_" class="even"><td class="entry"><span style="width:16px;display:inline-block;"> </span><a class="el" href="md__go_usage.html" target="_self">Use in Go</a></td><td class="desc"></td></tr>
|
||||
<tr id="row_5_"><td class="entry"><span style="width:16px;display:inline-block;"> </span><a class="el" href="md__java_usage.html" target="_self">Use in Java/C-sharp</a></td><td class="desc"></td></tr>
|
||||
<tr id="row_6_" class="even"><td class="entry"><span style="width:16px;display:inline-block;"> </span><a class="el" href="md__benchmarks.html" target="_self">Benchmarks</a></td><td class="desc"></td></tr>
|
||||
<tr id="row_7_"><td class="entry"><span style="width:16px;display:inline-block;"> </span><a class="el" href="md__white_paper.html" target="_self">FlatBuffers white paper</a></td><td class="desc"></td></tr>
|
||||
<tr id="row_8_" class="even"><td class="entry"><span style="width:16px;display:inline-block;"> </span><a class="el" href="md__internals.html" target="_self">FlatBuffer Internals</a></td><td class="desc"></td></tr>
|
||||
<tr id="row_9_"><td class="entry"><span style="width:16px;display:inline-block;"> </span><a class="el" href="md__grammar.html" target="_self">Formal Grammar of the schema language</a></td><td class="desc"></td></tr>
|
||||
<tr id="row_6_" class="even"><td class="entry"><span style="width:16px;display:inline-block;"> </span><a class="el" href="md__python_usage.html" target="_self">Use in Python</a></td><td class="desc"></td></tr>
|
||||
<tr id="row_7_"><td class="entry"><span style="width:16px;display:inline-block;"> </span><a class="el" href="md__support.html" target="_self">Platform / Language / Feature support</a></td><td class="desc"></td></tr>
|
||||
<tr id="row_8_" class="even"><td class="entry"><span style="width:16px;display:inline-block;"> </span><a class="el" href="md__benchmarks.html" target="_self">Benchmarks</a></td><td class="desc"></td></tr>
|
||||
<tr id="row_9_"><td class="entry"><span style="width:16px;display:inline-block;"> </span><a class="el" href="md__white_paper.html" target="_self">FlatBuffers white paper</a></td><td class="desc"></td></tr>
|
||||
<tr id="row_10_" class="even"><td class="entry"><span style="width:16px;display:inline-block;"> </span><a class="el" href="md__internals.html" target="_self">FlatBuffer Internals</a></td><td class="desc"></td></tr>
|
||||
<tr id="row_11_"><td class="entry"><span style="width:16px;display:inline-block;"> </span><a class="el" href="md__grammar.html" target="_self">Grammar of the schema language</a></td><td class="desc"></td></tr>
|
||||
</table>
|
||||
</div><!-- directory -->
|
||||
</div><!-- contents -->
|
||||
|
||||
396
docs/html/style.css
Normal file
396
docs/html/style.css
Normal file
@@ -0,0 +1,396 @@
|
||||
body,
|
||||
#projectname,
|
||||
table,
|
||||
div,
|
||||
p,
|
||||
dl,
|
||||
.title,
|
||||
.tabs,
|
||||
.tabs2,
|
||||
.tabs3,
|
||||
#nav-tree .label {
|
||||
font-family: roboto, sans-serif;
|
||||
}
|
||||
|
||||
#commonprojectlogo {
|
||||
padding: 5px 0px 5px 15px;
|
||||
}
|
||||
|
||||
#projectname {
|
||||
color: #00bcd4;
|
||||
font-size: 280%;
|
||||
padding: 15px 0px;
|
||||
font-weight: 300;
|
||||
}
|
||||
|
||||
#titlearea {
|
||||
border-bottom: 2px solid #e5e5e5;
|
||||
}
|
||||
|
||||
.title {
|
||||
color: #212121;
|
||||
font: 300 34px/40px Roboto,sans-serif;
|
||||
}
|
||||
|
||||
#nav-tree {
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
#navrow1, #navrow2 {
|
||||
border-bottom: 2px solid #e7e7e7;
|
||||
}
|
||||
|
||||
.tabs, .tabs2, .tabs3 {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.tabs,
|
||||
.tabs2,
|
||||
.tabs3,
|
||||
.tablist li,
|
||||
.tablist li.current a {
|
||||
background-image: none;
|
||||
}
|
||||
|
||||
.tablist {
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.tablist li, .tablist li p {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.tablist li a,
|
||||
.tablist li.current a {
|
||||
color: #757575;
|
||||
text-shadow: none;
|
||||
}
|
||||
|
||||
.tablist li.current a {
|
||||
background: #00bcd4;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.tablist a {
|
||||
background-image: none;
|
||||
border-right: 2px solid #e5e5e5;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.tablist a:hover,
|
||||
.tablist li.current a:hover {
|
||||
background-image: none;
|
||||
text-decoration: underline;
|
||||
text-shadow: none;
|
||||
}
|
||||
|
||||
.tablist a:hover {
|
||||
color: #00bcd4;
|
||||
}
|
||||
|
||||
.tablist li.current a:hover {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
div.header {
|
||||
background-color: #f7f7f7;
|
||||
background-image: none;
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
#MSearchBox {
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 5px;
|
||||
display: inline-block;
|
||||
height: 20px;
|
||||
right: 10px;
|
||||
}
|
||||
|
||||
#MSearchBox .left,
|
||||
#MSearchBox .right,
|
||||
#MSearchField {
|
||||
background: none;
|
||||
}
|
||||
|
||||
a.SelectItem:hover {
|
||||
background-color: #00bcd4;
|
||||
}
|
||||
|
||||
#nav-tree {
|
||||
background-image: none;
|
||||
}
|
||||
|
||||
#nav-tree .selected {
|
||||
background-image: none;
|
||||
text-shadow: none;
|
||||
background-color: #f7f7f7;
|
||||
}
|
||||
|
||||
#nav-tree a {
|
||||
color: #212121;
|
||||
}
|
||||
|
||||
#nav-tree .selected a {
|
||||
color: #0288d1;
|
||||
}
|
||||
|
||||
#nav-tree .item:hover {
|
||||
background-color: #f7f7f7;
|
||||
}
|
||||
|
||||
#nav-tree .item:hover a {
|
||||
color: #0288d1;
|
||||
}
|
||||
|
||||
#nav-tree .label {
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
#nav-sync {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.ui-resizable-e {
|
||||
background: #ebebeb;
|
||||
border-left: 1px solid #ddd;
|
||||
border-right: 1px solid #ddd;
|
||||
}
|
||||
|
||||
.contents tr td .image {
|
||||
margin-top: 24px;
|
||||
}
|
||||
|
||||
.image {
|
||||
text-align: left;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
a:link,
|
||||
a:visited,
|
||||
.contents a:link,
|
||||
.contents a:visited,
|
||||
a.el {
|
||||
color: #0288d1;
|
||||
font-weight: normal;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
div.contents {
|
||||
margin-right: 12px;
|
||||
}
|
||||
|
||||
.directory tr, .directory tr.even {
|
||||
background: #7cb342;
|
||||
border-top: 1px solid #7cb342;
|
||||
}
|
||||
|
||||
.directory td,
|
||||
.directory td.entry,
|
||||
.directory td.desc {
|
||||
background: rgba(255,255,255,.95);
|
||||
border-left: none;
|
||||
color: #212121;
|
||||
padding-top: 10px;
|
||||
padding-bottom: 10px;
|
||||
padding-left: 8px;
|
||||
padding-right: 8px;
|
||||
}
|
||||
|
||||
.directory tr#row_0_ {
|
||||
border-top-color: #7cb342;
|
||||
}
|
||||
|
||||
.directory tr#row_0_ td {
|
||||
background: #7cb342;
|
||||
color: #fff;
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.memSeparator {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.memitem {
|
||||
background: #7cb342;
|
||||
}
|
||||
|
||||
.memproto, dl.reflist dt {
|
||||
background: #7cb342;
|
||||
background-image: none;
|
||||
border: none;
|
||||
box-shadow: none;
|
||||
-webkit-box-shadow: none;
|
||||
color: #fff;
|
||||
text-shadow: none;
|
||||
}
|
||||
|
||||
.memproto .memtemplate,
|
||||
.memproto a.el,
|
||||
.memproto .paramname {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.memdoc, dl.reflist dd {
|
||||
border: none;
|
||||
background-color: rgba(255,255,255,.95);
|
||||
background-image: none;
|
||||
box-shadow: none;
|
||||
-webkit-box-shadow: none;
|
||||
-webkit-border-bottom-left-radius: 0;
|
||||
-webkit-border-bottom-right-radius: 0;
|
||||
}
|
||||
|
||||
.memitem, table.doxtable, table.memberdecls {
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
table.doxtable th {
|
||||
background: #7cb342;
|
||||
}
|
||||
|
||||
table.doxtable tr {
|
||||
background: #7cb342;
|
||||
border-top: 1px solid #7cb342;
|
||||
}
|
||||
|
||||
table.doxtable td, table.doxtable th {
|
||||
border: none;
|
||||
padding: 10px 8px;
|
||||
}
|
||||
|
||||
table.doxtable td {
|
||||
background-color: rgba(255,255,255,.95);
|
||||
}
|
||||
|
||||
.memberdecls {
|
||||
background: #7cb342;
|
||||
border-top: 1px solid #7cb342;
|
||||
}
|
||||
|
||||
.memberdecls .heading h2 {
|
||||
border-bottom: none;
|
||||
color: #fff;
|
||||
font-size: 110%;
|
||||
font-weight: bold;
|
||||
margin: 0 0 0 6px;
|
||||
}
|
||||
|
||||
.memberdecls tr:not(.heading) td {
|
||||
background-color: rgba(255,255,255,.95);
|
||||
}
|
||||
|
||||
h1, h2, h2.groupheader, h3, h4, h5, h6 {
|
||||
color: #212121;
|
||||
}
|
||||
|
||||
h1 {
|
||||
border-bottom: 1px solid #ebebeb;
|
||||
font: 400 28px/32px Roboto,sans-serif;
|
||||
letter-spacing: -.01em;
|
||||
margin: 40px 0 20px;
|
||||
padding-bottom: 3px;
|
||||
}
|
||||
|
||||
h2, h2.groupheader {
|
||||
border-bottom: 1px solid #ebebeb;
|
||||
font: 400 23px/32px Roboto,sans-serif;
|
||||
letter-spacing: -.01em;
|
||||
margin: 40px 0 20px;
|
||||
padding-bottom: 3px;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font: 500 20px/32px Roboto,sans-serif;
|
||||
margin: 32px 0 16px;
|
||||
}
|
||||
|
||||
h4 {
|
||||
font: 500 18px/32px Roboto,sans-serif;
|
||||
margin: 32px 0 16px;
|
||||
}
|
||||
|
||||
ol,
|
||||
ul {
|
||||
margin: 0;
|
||||
padding-left: 40px;
|
||||
}
|
||||
|
||||
ol {
|
||||
list-style: decimal outside;
|
||||
}
|
||||
|
||||
ol ol {
|
||||
list-style-type: lower-alpha;
|
||||
}
|
||||
|
||||
ol ol ol {
|
||||
list-style-type: lower-roman;
|
||||
}
|
||||
|
||||
ul {
|
||||
list-style: disc outside;
|
||||
}
|
||||
|
||||
li,
|
||||
li p {
|
||||
margin: 8px 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
div.summary
|
||||
{
|
||||
float: none;
|
||||
font-size: 8pt;
|
||||
padding-left: 5px;
|
||||
width: calc(100% - 10px);
|
||||
text-align: left;
|
||||
display: block;
|
||||
}
|
||||
|
||||
div.ingroups {
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
div.fragment {
|
||||
border: 1px solid #ddd;
|
||||
color: #455a64;
|
||||
font: 14px/20px Roboto Mono, monospace;
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
div.line {
|
||||
line-height: 1.5;
|
||||
font-size: inherit;
|
||||
}
|
||||
|
||||
code, pre {
|
||||
color: #455a64;
|
||||
background: #f7f7f7;
|
||||
font: 400 100%/1 Roboto Mono,monospace;
|
||||
padding: 1px 4px;
|
||||
}
|
||||
|
||||
span.preprocessor, span.comment {
|
||||
color: #0b8043;
|
||||
}
|
||||
|
||||
span.keywordtype {
|
||||
color: #0097a7;
|
||||
}
|
||||
|
||||
.paramname {
|
||||
color: #ef6c00;
|
||||
}
|
||||
|
||||
.memTemplParams {
|
||||
color: #ef6c00;
|
||||
}
|
||||
|
||||
span.mlabel {
|
||||
background: rgba(255,255,255,.25);
|
||||
border: none;
|
||||
}
|
||||
|
||||
blockquote {
|
||||
border: 1px solid #ddd;
|
||||
}
|
||||
BIN
docs/images/fpl_logo_small.png
Normal file
BIN
docs/images/fpl_logo_small.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 5.0 KiB |
BIN
docs/images/ftv2mnode.png
Normal file
BIN
docs/images/ftv2mnode.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.0 KiB |
BIN
docs/images/ftv2pnode.png
Normal file
BIN
docs/images/ftv2pnode.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.0 KiB |
@@ -39,7 +39,7 @@ meant to be representative of game data, e.g. a scene format.
|
||||
optional fields to allow deprecating fields or serializing with missing
|
||||
fields for which defaults exist).
|
||||
It currently also isn't fully cross-platform portable (lack of VS support).
|
||||
- msgpack: has very minimal forwards/backwards compatability support when used
|
||||
- msgpack: has very minimal forwards/backwards compatibility support when used
|
||||
with the typed C++ interface. Also lacks VS2010 support.
|
||||
- Thrift: very similar to Protocol Buffers, but appears to be less efficient,
|
||||
and have more dependencies.
|
||||
|
||||
@@ -41,19 +41,44 @@ be generated for each file processed:
|
||||
fail (or none are specified) it will try to load relative to the path of
|
||||
the schema file being parsed.
|
||||
|
||||
- `-M` : Print make rules for generated files.
|
||||
|
||||
- `--strict-json` : Require & generate strict JSON (field names are enclosed
|
||||
in quotes, no trailing commas in tables/vectors). By default, no quotes are
|
||||
required/generated, and trailing commas are allowed.
|
||||
|
||||
- `--defaults-json` : Output fields whose value is equal to the default value
|
||||
when writing JSON text.
|
||||
|
||||
- `--no-prefix` : Don't prefix enum values in generated C++ by their enum
|
||||
type.
|
||||
|
||||
- `--gen-includes` : Generate include statements for included schemas the
|
||||
- `--scoped-enums` : Use C++11 style scoped and strongly typed enums in
|
||||
generated C++. This also implies `--no-prefix`.
|
||||
|
||||
- `--gen-includes` : (deprecated), this is the default behavior.
|
||||
If the original behavior is required (no include
|
||||
statements) use `--no-includes.`
|
||||
|
||||
- `--no-includes` : Don't generate include statements for included schemas the
|
||||
generated file depends on (C++).
|
||||
|
||||
- `--gen-mutable` : Generate additional non-const accessors for mutating
|
||||
FlatBuffers in-place.
|
||||
|
||||
- `--gen-onefile` : Generate single output file (useful for C#)
|
||||
|
||||
- `--raw-binary` : Allow binaries without a file_indentifier to be read.
|
||||
This may crash flatc given a mismatched schema.
|
||||
|
||||
- `--proto`: Expect input files to be .proto files (protocol buffers).
|
||||
Output the corresponding .fbs file.
|
||||
Currently supports: `package`, `message`, `enum`.
|
||||
Does not support, but will skip without error: `import`, `option`.
|
||||
Does not support, will generate error: `service`, `extend`, `extensions`,
|
||||
`oneof`, `group`, custom options, nested declarations.
|
||||
Currently supports: `package`, `message`, `enum`, nested declarations,
|
||||
`import` (use `-I` for paths), `extend`, `oneof`, `group`.
|
||||
Does not support, but will skip without error: `option`, `service`,
|
||||
`extensions`, and most everything else.
|
||||
|
||||
- `--schema`: Serialize schemas instead of JSON (use with -b). This will
|
||||
output a binary version of the specified schema that itself corresponds
|
||||
to the reflection/reflection.fbs schema. Loading this binary file is the
|
||||
basis for reflection functionality.
|
||||
|
||||
@@ -72,7 +72,9 @@ since they won't bloat up the buffer sizes if they're not actually used.
|
||||
We do something similarly for the union field `test` by specifying a `0` offset
|
||||
and the `NONE` enum value (part of every union) to indicate we don't actually
|
||||
want to write this field. You can use `0` also as a default for other
|
||||
non-scalar types, such as strings, vectors and tables.
|
||||
non-scalar types, such as strings, vectors and tables. To pass an actual
|
||||
table, pass a preconstructed table as `mytable.Union()` that corresponds to
|
||||
union enum you're passing.
|
||||
|
||||
Tables (like `Monster`) give you full flexibility on what fields you write
|
||||
(unlike `Vec3`, which always has all fields set because it is a `struct`).
|
||||
@@ -163,6 +165,75 @@ Similarly, we can access elements of the inventory array:
|
||||
assert(inv->Get(9) == 9);
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
### Mutating FlatBuffers
|
||||
|
||||
As you saw above, typically once you have created a FlatBuffer, it is
|
||||
read-only from that moment on. There are however cases where you have just
|
||||
received a FlatBuffer, and you'd like to modify something about it before
|
||||
sending it on to another recipient. With the above functionality, you'd have
|
||||
to generate an entirely new FlatBuffer, while tracking what you modify in your
|
||||
own data structures. This is inconvenient.
|
||||
|
||||
For this reason FlatBuffers can also be mutated in-place. While this is great
|
||||
for making small fixes to an existing buffer, you generally want to create
|
||||
buffers from scratch whenever possible, since it is much more efficient and
|
||||
the API is much more general purpose.
|
||||
|
||||
To get non-const accessors, invoke `flatc` with `--gen-mutable`.
|
||||
|
||||
Similar to the reading API above, you now can:
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
|
||||
auto monster = GetMutableMonster(buffer_pointer); // non-const
|
||||
monster->mutate_hp(10); // Set table field.
|
||||
monster->mutable_pos()->mutate_z(4); // Set struct field.
|
||||
monster->mutable_inventory()->Mutate(0, 1); // Set vector element.
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
We use the somewhat verbose term `mutate` instead of `set` to indicate that
|
||||
this is a special use case, not to be confused with the default way of
|
||||
constructing FlatBuffer data.
|
||||
|
||||
After the above mutations, you can send on the FlatBuffer to a new recipient
|
||||
without any further work!
|
||||
|
||||
Note that any `mutate_` functions on tables return a bool, which is false
|
||||
if the field we're trying to set isn't present in the buffer. Fields are not
|
||||
present if they weren't set, or even if they happen to be equal to the
|
||||
default value. For example, in the creation code above we set the `mana` field
|
||||
to `150`, which is the default value, so it was never stored in the buffer.
|
||||
Trying to call mutate_mana() on such data will return false, and the value won't
|
||||
actually be modified!
|
||||
|
||||
One way to solve this is to call `ForceDefaults()` on a
|
||||
`FlatBufferBuilder` to force all fields you set to actually be written. This
|
||||
of course increases the size of the buffer somewhat, but this may be
|
||||
acceptable for a mutable buffer.
|
||||
|
||||
Alternatively, you can use the more powerful reflection functionality:
|
||||
|
||||
### Reflection (& Resizing)
|
||||
|
||||
If the above ways of accessing a buffer are still too static for you, there is
|
||||
experimental support for reflection in FlatBuffers, allowing you to read and
|
||||
write data even if you don't know the exact format of a buffer, and even allows
|
||||
you to change sizes of strings and vectors in-place.
|
||||
|
||||
The way this works is very elegant, there is actually a FlatBuffer schema that
|
||||
describes schemas (!) which you can find in `reflection/reflection.fbs`.
|
||||
The compiler `flatc` can write out any schemas it has just parsed as a binary
|
||||
FlatBuffer, corresponding to this meta-schema.
|
||||
|
||||
Loading in one of these binary schemas at runtime allows you traverse any
|
||||
FlatBuffer data that corresponds to it without knowing the exact format. You
|
||||
can query what fields are present, and then read/write them after.
|
||||
|
||||
For convenient field manipulation, you can include the header
|
||||
`flatbuffers/reflection.h` which includes both the generated code from the meta
|
||||
schema, as well as a lot of helper functions.
|
||||
|
||||
And example of usage for the moment you can find in `test.cpp/ReflectionTest()`.
|
||||
|
||||
### Storing maps / dictionaries in a FlatBuffer
|
||||
|
||||
FlatBuffers doesn't support maps natively, but there is support to
|
||||
|
||||
@@ -4,7 +4,8 @@ FlatBuffers is an efficient cross platform serialization library for C++,
|
||||
with support for Java, C# and Go. It was created at Google specifically for game
|
||||
development and other performance-critical applications.
|
||||
|
||||
It is available as open source under the Apache license, v2 (see LICENSE.txt).
|
||||
It is available as Open Source on [GitHub](http://github.com/google/flatbuffers)
|
||||
under the Apache license, v2 (see LICENSE.txt).
|
||||
|
||||
## Why use FlatBuffers?
|
||||
|
||||
@@ -75,6 +76,17 @@ little to no information ahead of time about what data needs to be stored.
|
||||
Read more about the "why" of FlatBuffers in the
|
||||
[white paper](md__white_paper.html).
|
||||
|
||||
### Who uses FlatBuffers?
|
||||
- [Cocos2d-x](http://www.cocos2d-x.org/), the #1 open source mobile game
|
||||
engine, uses it to serialize all their
|
||||
[game data](http://www.cocos2d-x.org/reference/native-cpp/V3.5/d7/d2d/namespaceflatbuffers.html).
|
||||
- [Facebook](http://facebook.com/) uses it for client-server communication in
|
||||
their Android app. They have a nice
|
||||
[article](https://code.facebook.com/posts/872547912839369/improving-facebook-s-performance-on-android-with-flatbuffers/)
|
||||
explaining how it speeds up loading their posts.
|
||||
- [Fun Propulsion Labs](https://developers.google.com/games/#Tools)
|
||||
at Google uses it extensively in all their libraries and games.
|
||||
|
||||
## Usage in brief
|
||||
|
||||
This section is a quick rundown of how to use this system. Subsequent
|
||||
@@ -88,8 +100,8 @@ sections provide a more in-depth usage guide.
|
||||
present for every object instance.
|
||||
|
||||
- Use `flatc` (the FlatBuffer compiler) to generate a C++ header (or
|
||||
Java/C#/Go classes) with helper classes to access and construct serialized
|
||||
data. This header (say `mydata_generated.h`) only depends on
|
||||
Java/C#/Go/Python.. classes) with helper classes to access and construct
|
||||
serialized data. This header (say `mydata_generated.h`) only depends on
|
||||
`flatbuffers.h`, which defines the core functionality.
|
||||
|
||||
- Use the `FlatBufferBuilder` class to construct a flat binary buffer.
|
||||
@@ -114,6 +126,7 @@ sections provide a more in-depth usage guide.
|
||||
programs.
|
||||
- How to [use the generated Go code](md__go_usage.html) in your own
|
||||
programs.
|
||||
- [Support matrix](md__support.html) for platforms/languages/features.
|
||||
- Some [benchmarks](md__benchmarks.html) showing the advantage of using
|
||||
FlatBuffers.
|
||||
- A [white paper](md__white_paper.html) explaining the "why" of FlatBuffers.
|
||||
@@ -122,7 +135,15 @@ sections provide a more in-depth usage guide.
|
||||
|
||||
## Online resources
|
||||
|
||||
- [github repository](http://github.com/google/flatbuffers)
|
||||
- [landing page](http://google.github.io/flatbuffers)
|
||||
- [GitHub repository](http://github.com/google/flatbuffers)
|
||||
- [Landing page](http://google.github.io/flatbuffers)
|
||||
- [FlatBuffers Google Group](http://group.google.com/group/flatbuffers)
|
||||
- [FlatBuffers Issues Tracker](http://github.com/google/flatbuffers/issues)
|
||||
- Videos:
|
||||
- Colt's [DevByte](https://www.youtube.com/watch?v=iQTxMkSJ1dQ).
|
||||
- GDC 2015 [Lightning Talk](https://www.youtube.com/watch?v=olmL1fUnQAQ).
|
||||
- FlatBuffers for [Go](https://www.youtube.com/watch?v=-BPVId_lA5w).
|
||||
- Evolution of FlatBuffers
|
||||
[visualization](https://www.youtube.com/watch?v=a0QE0xS8rKM).
|
||||
- Useful documentation created by others:
|
||||
- [Using FlatBuffers in Unity](http://exiin.com/blog/flatbuffers-for-unity-sample-code/)
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
# Formal Grammar of the schema language
|
||||
# Grammar of the schema language
|
||||
|
||||
schema = include*
|
||||
( namespace\_decl | type\_decl | enum\_decl | root\_decl |
|
||||
file_extension_decl | file_identifier_decl |
|
||||
attribute\_decl | object )*
|
||||
|
||||
include = `include` string\_constant `;`
|
||||
@@ -17,7 +18,7 @@ enumval\_decl ) `}`
|
||||
|
||||
root\_decl = `root_type` ident `;`
|
||||
|
||||
field\_decl = type `:` ident [ `=` scalar ] metadata `;`
|
||||
field\_decl = ident `:` type [ `=` scalar ] metadata `;`
|
||||
|
||||
type = `bool` | `byte` | `ubyte` | `short` | `ushort` | `int` | `uint` |
|
||||
`float` | `long` | `ulong` | `double`
|
||||
@@ -25,12 +26,22 @@ type = `bool` | `byte` | `ubyte` | `short` | `ushort` | `int` | `uint` |
|
||||
|
||||
enumval\_decl = ident [ `=` integer\_constant ]
|
||||
|
||||
metadata = [ `(` commasep( ident [ `:` scalar ] ) `)` ]
|
||||
metadata = [ `(` commasep( ident [ `:` single\_value ] ) `)` ]
|
||||
|
||||
scalar = integer\_constant | float\_constant | `true` | `false`
|
||||
scalar = integer\_constant | float\_constant
|
||||
|
||||
object = { commasep( ident `:` value ) }
|
||||
|
||||
value = scalar | object | string\_constant | `[` commasep( value ) `]`
|
||||
single\_value = scalar | string\_constant
|
||||
|
||||
value = single\_value | object | `[` commasep( value ) `]`
|
||||
|
||||
commasep(x) = [ x ( `,` x )\* ]
|
||||
|
||||
file_extension_decl = `file_extension` string\_constant `;`
|
||||
|
||||
file_identifier_decl = `file_identifier` string\_constant `;`
|
||||
|
||||
integer\_constant = -?[0-9]+ | `true` | `false`
|
||||
|
||||
float\_constant = -?[0-9]+.[0-9]+((e|E)(+|-)?[0-9]+)?
|
||||
|
||||
@@ -5,8 +5,8 @@ Generate code for Java with the `-j` option to `flatc`, or for C# with `-n`
|
||||
(think .Net).
|
||||
|
||||
Note that this document is from the perspective of Java. Code for both languages
|
||||
is generated in the same way, with only very subtle differences, for example
|
||||
any `camelCase` Java call will be `CamelCase` in C#.
|
||||
is generated in the same way, with only minor differences. These differences
|
||||
are [explained in a section below](#differences-in-c-sharp).
|
||||
|
||||
See `javaTest.java` for an example. Essentially, you read a FlatBuffer binary
|
||||
file into a `byte[]`, which you then turn into a `ByteBuffer`, which you pass to
|
||||
@@ -109,7 +109,7 @@ Structs do have convenient methods that even have arguments for nested structs.
|
||||
|
||||
As you can see, references to other objects (e.g. the string above) are simple
|
||||
ints, and thus do not have the type-safety of the Offset type in C++. Extra
|
||||
case must thus be taken that you set the right offset on the right field.
|
||||
care must thus be taken that you set the right offset on the right field.
|
||||
|
||||
Vectors can be created from the corresponding Java array like so:
|
||||
|
||||
@@ -151,8 +151,74 @@ not start from offset 0 in this buffer, but from `fbb.dataBuffer().position()`
|
||||
It ends at `fbb.capacity()`.
|
||||
|
||||
|
||||
## Text Parsing
|
||||
## Differences in C-sharp
|
||||
|
||||
C# code works almost identically to Java, with only a few minor differences.
|
||||
You can see an example of C# code in `tests/FlatBuffers.Test/FlatBuffersExampleTests.cs`.
|
||||
|
||||
First of all, naming follows standard C# style with `PascalCasing` identifiers,
|
||||
e.g. `GetRootAsMyRootType`. Also, values (except vectors and unions) are available
|
||||
as properties instead of parameterless accessor methods as in Java. The
|
||||
performance-enhancing methods to which you can pass an already created object
|
||||
are prefixed with `Get`, e.g.:
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cs}
|
||||
// property
|
||||
var pos = monster.Pos;
|
||||
// method filling a preconstructed object
|
||||
var preconstructedPos = new Vec3();
|
||||
monster.GetPos(preconstructedPos);
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
||||
## Text parsing
|
||||
|
||||
There currently is no support for parsing text (Schema's and JSON) directly
|
||||
from Java, though you could use the C++ parser through JNI. Please see the
|
||||
from Java or C#, though you could use the C++ parser through native call
|
||||
interfaces available to each language. Please see the
|
||||
C++ documentation for more on text parsing.
|
||||
|
||||
### Mutating FlatBuffers
|
||||
|
||||
As you saw above, typically once you have created a FlatBuffer, it is
|
||||
read-only from that moment on. There are however cases where you have just
|
||||
received a FlatBuffer, and you'd like to modify something about it before
|
||||
sending it on to another recipient. With the above functionality, you'd have
|
||||
to generate an entirely new FlatBuffer, while tracking what you modify in your
|
||||
own data structures. This is inconvenient.
|
||||
|
||||
For this reason FlatBuffers can also be mutated in-place. While this is great
|
||||
for making small fixes to an existing buffer, you generally want to create
|
||||
buffers from scratch whenever possible, since it is much more efficient and
|
||||
the API is much more general purpose.
|
||||
|
||||
To get non-const accessors, invoke `flatc` with `--gen-mutable`.
|
||||
|
||||
You now can:
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.java}
|
||||
Monster monster = Monster.getRootAsMonster(bb);
|
||||
monster.mutateHp(10); // Set table field.
|
||||
monster.pos().mutateZ(4); // Set struct field.
|
||||
monster.mutateInventory(0, 1); // Set vector element.
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
We use the somewhat verbose term `mutate` instead of `set` to indicate that
|
||||
this is a special use case, not to be confused with the default way of
|
||||
constructing FlatBuffer data.
|
||||
|
||||
After the above mutations, you can send on the FlatBuffer to a new recipient
|
||||
without any further work!
|
||||
|
||||
Note that any `mutate` functions on tables return a boolean, which is false
|
||||
if the field we're trying to set isn't present in the buffer. Fields are not
|
||||
present if they weren't set, or even if they happen to be equal to the
|
||||
default value. For example, in the creation code above we set the `mana` field
|
||||
to `150`, which is the default value, so it was never stored in the buffer.
|
||||
Trying to call mutateMana() on such data will return false, and the value won't
|
||||
actually be modified!
|
||||
|
||||
One way to solve this is to call `forceDefaults()` on a
|
||||
`FlatBufferBuilder` to force all fields you set to actually be written. This
|
||||
of course increases the size of the buffer somewhat, but this may be
|
||||
acceptable for a mutable buffer.
|
||||
|
||||
115
docs/source/PythonUsage.md
Executable file
115
docs/source/PythonUsage.md
Executable file
@@ -0,0 +1,115 @@
|
||||
# Use in Python
|
||||
|
||||
There's experimental support for reading FlatBuffers in Python. Generate
|
||||
code for Python with the `-p` option to `flatc`.
|
||||
|
||||
See `py_test.py` for an example. You import the generated code, read a
|
||||
FlatBuffer binary file into a `bytearray`, which you pass to the
|
||||
`GetRootAsMonster` function:
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.py}
|
||||
import MyGame.Example as example
|
||||
import flatbuffers
|
||||
|
||||
buf = open('monster.dat', 'rb').read()
|
||||
buf = bytearray(buf)
|
||||
monster = example.GetRootAsMonster(buf, 0)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Now you can access values like this:
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.py}
|
||||
hp = monster.Hp()
|
||||
pos = monster.Pos()
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
To access vectors you pass an extra index to the
|
||||
vector field accessor. Then a second method with the same name suffixed
|
||||
by `Length` let's you know the number of elements you can access:
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.py}
|
||||
for i in xrange(monster.InventoryLength()):
|
||||
monster.Inventory(i) # do something here
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
You can also construct these buffers in Python using the functions found
|
||||
in the generated code, and the FlatBufferBuilder class:
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.py}
|
||||
builder = flatbuffers.Builder(0)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Create strings:
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.py}
|
||||
s = builder.CreateString("MyMonster")
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Create a table with a struct contained therein:
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.py}
|
||||
example.MonsterStart(builder)
|
||||
example.MonsterAddPos(builder, example.CreateVec3(builder, 1.0, 2.0, 3.0, 3.0, 4, 5, 6))
|
||||
example.MonsterAddHp(builder, 80)
|
||||
example.MonsterAddName(builder, str)
|
||||
example.MonsterAddInventory(builder, inv)
|
||||
example.MonsterAddTest_Type(builder, 1)
|
||||
example.MonsterAddTest(builder, mon2)
|
||||
example.MonsterAddTest4(builder, test4s)
|
||||
mon = example.MonsterEnd(builder)
|
||||
|
||||
final_flatbuffer = builder.Output()
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Unlike C++, Python does not support table creation functions like 'createMonster()'.
|
||||
This is to create the buffer without
|
||||
using temporary object allocation (since the `Vec3` is an inline component of
|
||||
`Monster`, it has to be created right where it is added, whereas the name and
|
||||
the inventory are not inline, and **must** be created outside of the table
|
||||
creation sequence).
|
||||
Structs do have convenient methods that allow you to construct them in one call.
|
||||
These also have arguments for nested structs, e.g. if a struct has a field `a`
|
||||
and a nested struct field `b` (which has fields `c` and `d`), then the arguments
|
||||
will be `a`, `c` and `d`.
|
||||
|
||||
Vectors also use this start/end pattern to allow vectors of both scalar types
|
||||
and structs:
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.py}
|
||||
example.MonsterStartInventoryVector(builder, 5)
|
||||
i = 4
|
||||
while i >= 0:
|
||||
builder.PrependByte(byte(i))
|
||||
i -= 1
|
||||
|
||||
inv = builder.EndVector(5)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The generated method 'StartInventoryVector' is provided as a convenience
|
||||
function which calls 'StartVector' with the correct element size of the vector
|
||||
type which in this case is 'ubyte' or 1 byte per vector element.
|
||||
You pass the number of elements you want to write.
|
||||
You write the elements backwards since the buffer
|
||||
is being constructed back to front. Use the correct `Prepend` call for the type,
|
||||
or `PrependUOffsetT` for offsets. You then pass `inv` to the corresponding
|
||||
`Add` call when you construct the table containing it afterwards.
|
||||
|
||||
There are `Prepend` functions for all the scalar types. You use
|
||||
`PrependUOffset` for any previously constructed objects (such as other tables,
|
||||
strings, vectors). For structs, you use the appropriate `create` function
|
||||
in-line, as shown above in the `Monster` example.
|
||||
|
||||
Once you're done constructing a buffer, you call `Finish` with the root object
|
||||
offset (`mon` in the example above). Your data now resides in Builder.Bytes.
|
||||
Important to note is that the real data starts at the index indicated by Head(),
|
||||
for Offset() bytes (this is because the buffer is constructed backwards).
|
||||
If you wanted to read the buffer right after creating it (using
|
||||
`GetRootAsMonster` above), the second argument, instead of `0` would thus
|
||||
also be `Head()`.
|
||||
|
||||
## Text Parsing
|
||||
|
||||
There currently is no support for parsing text (Schema's and JSON) directly
|
||||
from Python, though you could use the C++ parser through SWIG or ctypes. Please
|
||||
see the C++ documentation for more on text parsing.
|
||||
|
||||
@@ -111,8 +111,11 @@ high bit yet.
|
||||
### (Default) Values
|
||||
|
||||
Values are a sequence of digits, optionally followed by a `.` and more digits
|
||||
for float constants, and optionally prefixed by a `-`. Non-scalar defaults are
|
||||
currently not supported (always NULL).
|
||||
for float constants, and optionally prefixed by a `-`. Floats may end with an
|
||||
`e` or `E`, followed by a `+` or `-` and more digits (scientific notation).
|
||||
|
||||
Only scalar values can have defaults, non-scalar (string/vector/table) fields
|
||||
default to NULL when not present.
|
||||
|
||||
You generally do not want to change default values after they're initially
|
||||
defined. Fields that have the default value are not actually stored in the
|
||||
|
||||
39
docs/source/Support.md
Executable file
39
docs/source/Support.md
Executable file
@@ -0,0 +1,39 @@
|
||||
# Platform / Language / Feature support
|
||||
|
||||
FlatBuffers is actively being worked on, which means that certain platform /
|
||||
language / feature combinations may not be available yet.
|
||||
|
||||
This page tries to track those issues, to make informed decisions easier.
|
||||
In general:
|
||||
|
||||
* Languages: language support beyond the ones created by the original
|
||||
FlatBuffer authors typically depends on community contributions.
|
||||
* Features: C++ was the first language supported, since our original
|
||||
target was high performance game development. It thus has the richest
|
||||
feature set, and is likely most robust. Other languages are catching up
|
||||
however.
|
||||
* Platforms: All language implementations are typically portable to most
|
||||
platforms, unless where noted otherwise.
|
||||
|
||||
NOTE: this table is a start, it needs to be extended.
|
||||
|
||||
Feature | C++ | Java | C# | Go | Python | JS
|
||||
------------------------------ | ------ | ------ | ------ | ------ | ------ | ------
|
||||
Codegen for all basic features | Yes | Yes | Yes | Yes | Yes | WIP
|
||||
JSON parsing | Yes | No | No | No | No | No
|
||||
Simple mutation | Yes | WIP | WIP | No | No | No
|
||||
Reflection | Yes | No | No | No | No | No
|
||||
Buffer verifier | Yes | No | No | No | No | No
|
||||
Testing: basic | Yes | Yes | Yes | Yes | Yes | WIP
|
||||
Testing: fuzz | Yes | No | No | Yes | Yes | No
|
||||
Performance: | Superb | Great | Great | Great | Ok | ?
|
||||
Platform: Windows | VS2010 | Yes | Yes | ? | ? | ?
|
||||
Platform: Linux | GCC282 | Yes | ? | Yes | Yes | ?
|
||||
Platform: OS X | Xcode4 | ? | ? | ? | Yes | ?
|
||||
Platform: Android | NDK10d | Yes | ? | ? | ? | ?
|
||||
Platform: iOS | ? | ? | ? | ? | ? | ?
|
||||
Engine: Unity | ? | ? | Yes | ? | ? | ?
|
||||
Primary authors (github) | wvo | wvo | (ev/js)| rw | rw | (ev)
|
||||
|
||||
* ev = evolutional
|
||||
* js = jonsimantov
|
||||
@@ -750,6 +750,8 @@ INPUT = "FlatBuffers.md" \
|
||||
"CppUsage.md" \
|
||||
"GoUsage.md" \
|
||||
"JavaUsage.md" \
|
||||
"PythonUsage.md" \
|
||||
"Support.md" \
|
||||
"Benchmarks.md" \
|
||||
"WhitePaper.md" \
|
||||
"Internals.md" \
|
||||
@@ -1105,7 +1107,7 @@ HTML_FILE_EXTENSION = .html
|
||||
# of the possible markers and block names see the documentation.
|
||||
# This tag requires that the tag GENERATE_HTML is set to YES.
|
||||
|
||||
HTML_HEADER =
|
||||
HTML_HEADER = ../header.html
|
||||
|
||||
# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each
|
||||
# generated HTML page. If the tag is left blank doxygen will generate a standard
|
||||
@@ -1127,7 +1129,7 @@ HTML_FOOTER = ../footer.html
|
||||
# obsolete.
|
||||
# This tag requires that the tag GENERATE_HTML is set to YES.
|
||||
|
||||
HTML_STYLESHEET =
|
||||
HTML_STYLESHEET = style.css
|
||||
|
||||
# The HTML_EXTRA_STYLESHEET tag can be used to specify an additional user-
|
||||
# defined cascading style sheet that is included after the standard style sheets
|
||||
@@ -1148,7 +1150,7 @@ HTML_EXTRA_STYLESHEET =
|
||||
# files will be copied as-is; there are no commands or markers available.
|
||||
# This tag requires that the tag GENERATE_HTML is set to YES.
|
||||
|
||||
HTML_EXTRA_FILES =
|
||||
HTML_EXTRA_FILES = ../images/fpl_logo_small.png ../images/ftv2mnode.png ../images/ftv2pnode.png
|
||||
|
||||
# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
|
||||
# will adjust the colors in the stylesheet and background images according to
|
||||
|
||||
396
docs/source/style.css
Normal file
396
docs/source/style.css
Normal file
@@ -0,0 +1,396 @@
|
||||
body,
|
||||
#projectname,
|
||||
table,
|
||||
div,
|
||||
p,
|
||||
dl,
|
||||
.title,
|
||||
.tabs,
|
||||
.tabs2,
|
||||
.tabs3,
|
||||
#nav-tree .label {
|
||||
font-family: roboto, sans-serif;
|
||||
}
|
||||
|
||||
#commonprojectlogo {
|
||||
padding: 5px 0px 5px 15px;
|
||||
}
|
||||
|
||||
#projectname {
|
||||
color: #00bcd4;
|
||||
font-size: 280%;
|
||||
padding: 15px 0px;
|
||||
font-weight: 300;
|
||||
}
|
||||
|
||||
#titlearea {
|
||||
border-bottom: 2px solid #e5e5e5;
|
||||
}
|
||||
|
||||
.title {
|
||||
color: #212121;
|
||||
font: 300 34px/40px Roboto,sans-serif;
|
||||
}
|
||||
|
||||
#nav-tree {
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
#navrow1, #navrow2 {
|
||||
border-bottom: 2px solid #e7e7e7;
|
||||
}
|
||||
|
||||
.tabs, .tabs2, .tabs3 {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.tabs,
|
||||
.tabs2,
|
||||
.tabs3,
|
||||
.tablist li,
|
||||
.tablist li.current a {
|
||||
background-image: none;
|
||||
}
|
||||
|
||||
.tablist {
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.tablist li, .tablist li p {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.tablist li a,
|
||||
.tablist li.current a {
|
||||
color: #757575;
|
||||
text-shadow: none;
|
||||
}
|
||||
|
||||
.tablist li.current a {
|
||||
background: #00bcd4;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.tablist a {
|
||||
background-image: none;
|
||||
border-right: 2px solid #e5e5e5;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.tablist a:hover,
|
||||
.tablist li.current a:hover {
|
||||
background-image: none;
|
||||
text-decoration: underline;
|
||||
text-shadow: none;
|
||||
}
|
||||
|
||||
.tablist a:hover {
|
||||
color: #00bcd4;
|
||||
}
|
||||
|
||||
.tablist li.current a:hover {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
div.header {
|
||||
background-color: #f7f7f7;
|
||||
background-image: none;
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
#MSearchBox {
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 5px;
|
||||
display: inline-block;
|
||||
height: 20px;
|
||||
right: 10px;
|
||||
}
|
||||
|
||||
#MSearchBox .left,
|
||||
#MSearchBox .right,
|
||||
#MSearchField {
|
||||
background: none;
|
||||
}
|
||||
|
||||
a.SelectItem:hover {
|
||||
background-color: #00bcd4;
|
||||
}
|
||||
|
||||
#nav-tree {
|
||||
background-image: none;
|
||||
}
|
||||
|
||||
#nav-tree .selected {
|
||||
background-image: none;
|
||||
text-shadow: none;
|
||||
background-color: #f7f7f7;
|
||||
}
|
||||
|
||||
#nav-tree a {
|
||||
color: #212121;
|
||||
}
|
||||
|
||||
#nav-tree .selected a {
|
||||
color: #0288d1;
|
||||
}
|
||||
|
||||
#nav-tree .item:hover {
|
||||
background-color: #f7f7f7;
|
||||
}
|
||||
|
||||
#nav-tree .item:hover a {
|
||||
color: #0288d1;
|
||||
}
|
||||
|
||||
#nav-tree .label {
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
#nav-sync {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.ui-resizable-e {
|
||||
background: #ebebeb;
|
||||
border-left: 1px solid #ddd;
|
||||
border-right: 1px solid #ddd;
|
||||
}
|
||||
|
||||
.contents tr td .image {
|
||||
margin-top: 24px;
|
||||
}
|
||||
|
||||
.image {
|
||||
text-align: left;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
a:link,
|
||||
a:visited,
|
||||
.contents a:link,
|
||||
.contents a:visited,
|
||||
a.el {
|
||||
color: #0288d1;
|
||||
font-weight: normal;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
div.contents {
|
||||
margin-right: 12px;
|
||||
}
|
||||
|
||||
.directory tr, .directory tr.even {
|
||||
background: #7cb342;
|
||||
border-top: 1px solid #7cb342;
|
||||
}
|
||||
|
||||
.directory td,
|
||||
.directory td.entry,
|
||||
.directory td.desc {
|
||||
background: rgba(255,255,255,.95);
|
||||
border-left: none;
|
||||
color: #212121;
|
||||
padding-top: 10px;
|
||||
padding-bottom: 10px;
|
||||
padding-left: 8px;
|
||||
padding-right: 8px;
|
||||
}
|
||||
|
||||
.directory tr#row_0_ {
|
||||
border-top-color: #7cb342;
|
||||
}
|
||||
|
||||
.directory tr#row_0_ td {
|
||||
background: #7cb342;
|
||||
color: #fff;
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.memSeparator {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.memitem {
|
||||
background: #7cb342;
|
||||
}
|
||||
|
||||
.memproto, dl.reflist dt {
|
||||
background: #7cb342;
|
||||
background-image: none;
|
||||
border: none;
|
||||
box-shadow: none;
|
||||
-webkit-box-shadow: none;
|
||||
color: #fff;
|
||||
text-shadow: none;
|
||||
}
|
||||
|
||||
.memproto .memtemplate,
|
||||
.memproto a.el,
|
||||
.memproto .paramname {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.memdoc, dl.reflist dd {
|
||||
border: none;
|
||||
background-color: rgba(255,255,255,.95);
|
||||
background-image: none;
|
||||
box-shadow: none;
|
||||
-webkit-box-shadow: none;
|
||||
-webkit-border-bottom-left-radius: 0;
|
||||
-webkit-border-bottom-right-radius: 0;
|
||||
}
|
||||
|
||||
.memitem, table.doxtable, table.memberdecls {
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
table.doxtable th {
|
||||
background: #7cb342;
|
||||
}
|
||||
|
||||
table.doxtable tr {
|
||||
background: #7cb342;
|
||||
border-top: 1px solid #7cb342;
|
||||
}
|
||||
|
||||
table.doxtable td, table.doxtable th {
|
||||
border: none;
|
||||
padding: 10px 8px;
|
||||
}
|
||||
|
||||
table.doxtable td {
|
||||
background-color: rgba(255,255,255,.95);
|
||||
}
|
||||
|
||||
.memberdecls {
|
||||
background: #7cb342;
|
||||
border-top: 1px solid #7cb342;
|
||||
}
|
||||
|
||||
.memberdecls .heading h2 {
|
||||
border-bottom: none;
|
||||
color: #fff;
|
||||
font-size: 110%;
|
||||
font-weight: bold;
|
||||
margin: 0 0 0 6px;
|
||||
}
|
||||
|
||||
.memberdecls tr:not(.heading) td {
|
||||
background-color: rgba(255,255,255,.95);
|
||||
}
|
||||
|
||||
h1, h2, h2.groupheader, h3, h4, h5, h6 {
|
||||
color: #212121;
|
||||
}
|
||||
|
||||
h1 {
|
||||
border-bottom: 1px solid #ebebeb;
|
||||
font: 400 28px/32px Roboto,sans-serif;
|
||||
letter-spacing: -.01em;
|
||||
margin: 40px 0 20px;
|
||||
padding-bottom: 3px;
|
||||
}
|
||||
|
||||
h2, h2.groupheader {
|
||||
border-bottom: 1px solid #ebebeb;
|
||||
font: 400 23px/32px Roboto,sans-serif;
|
||||
letter-spacing: -.01em;
|
||||
margin: 40px 0 20px;
|
||||
padding-bottom: 3px;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font: 500 20px/32px Roboto,sans-serif;
|
||||
margin: 32px 0 16px;
|
||||
}
|
||||
|
||||
h4 {
|
||||
font: 500 18px/32px Roboto,sans-serif;
|
||||
margin: 32px 0 16px;
|
||||
}
|
||||
|
||||
ol,
|
||||
ul {
|
||||
margin: 0;
|
||||
padding-left: 40px;
|
||||
}
|
||||
|
||||
ol {
|
||||
list-style: decimal outside;
|
||||
}
|
||||
|
||||
ol ol {
|
||||
list-style-type: lower-alpha;
|
||||
}
|
||||
|
||||
ol ol ol {
|
||||
list-style-type: lower-roman;
|
||||
}
|
||||
|
||||
ul {
|
||||
list-style: disc outside;
|
||||
}
|
||||
|
||||
li,
|
||||
li p {
|
||||
margin: 8px 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
div.summary
|
||||
{
|
||||
float: none;
|
||||
font-size: 8pt;
|
||||
padding-left: 5px;
|
||||
width: calc(100% - 10px);
|
||||
text-align: left;
|
||||
display: block;
|
||||
}
|
||||
|
||||
div.ingroups {
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
div.fragment {
|
||||
border: 1px solid #ddd;
|
||||
color: #455a64;
|
||||
font: 14px/20px Roboto Mono, monospace;
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
div.line {
|
||||
line-height: 1.5;
|
||||
font-size: inherit;
|
||||
}
|
||||
|
||||
code, pre {
|
||||
color: #455a64;
|
||||
background: #f7f7f7;
|
||||
font: 400 100%/1 Roboto Mono,monospace;
|
||||
padding: 1px 4px;
|
||||
}
|
||||
|
||||
span.preprocessor, span.comment {
|
||||
color: #0b8043;
|
||||
}
|
||||
|
||||
span.keywordtype {
|
||||
color: #0097a7;
|
||||
}
|
||||
|
||||
.paramname {
|
||||
color: #ef6c00;
|
||||
}
|
||||
|
||||
.memTemplParams {
|
||||
color: #ef6c00;
|
||||
}
|
||||
|
||||
span.mlabel {
|
||||
background: rgba(255,255,255,.25);
|
||||
border: none;
|
||||
}
|
||||
|
||||
blockquote {
|
||||
border: 1px solid #ddd;
|
||||
}
|
||||
@@ -8,11 +8,12 @@ package flatbuffers
|
||||
type Builder struct {
|
||||
Bytes []byte
|
||||
|
||||
minalign int
|
||||
vtable []UOffsetT
|
||||
objectEnd UOffsetT
|
||||
vtables []UOffsetT
|
||||
head UOffsetT
|
||||
minalign int
|
||||
vtable []UOffsetT
|
||||
objectEnd UOffsetT
|
||||
insideObject bool
|
||||
vtables []UOffsetT
|
||||
head UOffsetT
|
||||
}
|
||||
|
||||
// NewBuilder initializes a Builder of size `initial_size`.
|
||||
@@ -31,11 +32,40 @@ func NewBuilder(initialSize int) *Builder {
|
||||
return b
|
||||
}
|
||||
|
||||
// Reset truncates the underlying Builder buffer, facilitating alloc-free
|
||||
// reuse of a Builder.
|
||||
func (b *Builder) Reset() {
|
||||
if b.Bytes != nil {
|
||||
b.Bytes = b.Bytes[:cap(b.Bytes)]
|
||||
}
|
||||
|
||||
if b.vtables != nil {
|
||||
b.vtables = b.vtables[:0]
|
||||
}
|
||||
|
||||
if b.vtable != nil {
|
||||
b.vtable = b.vtable[:0]
|
||||
}
|
||||
|
||||
b.head = UOffsetT(len(b.Bytes))
|
||||
b.minalign = 1
|
||||
}
|
||||
|
||||
// StartObject initializes bookkeeping for writing a new object.
|
||||
func (b *Builder) StartObject(numfields int) {
|
||||
b.notNested()
|
||||
b.insideObject = true
|
||||
|
||||
// use 32-bit offsets so that arithmetic doesn't overflow.
|
||||
b.vtable = make([]UOffsetT, numfields)
|
||||
if cap(b.vtable) < numfields || b.vtable == nil {
|
||||
b.vtable = make([]UOffsetT, numfields)
|
||||
} else {
|
||||
b.vtable = b.vtable[:numfields]
|
||||
for i := 0; i < len(b.vtable); i++ {
|
||||
b.vtable[i] = 0
|
||||
}
|
||||
}
|
||||
|
||||
b.objectEnd = b.Offset()
|
||||
b.minalign = 1
|
||||
}
|
||||
@@ -137,16 +167,18 @@ func (b *Builder) WriteVtable() (n UOffsetT) {
|
||||
SOffsetT(existingVtable)-SOffsetT(objectOffset))
|
||||
}
|
||||
|
||||
b.vtable = nil
|
||||
b.vtable = b.vtable[:0]
|
||||
return objectOffset
|
||||
}
|
||||
|
||||
// EndObject writes data necessary to finish object construction.
|
||||
func (b *Builder) EndObject() UOffsetT {
|
||||
if b.vtable == nil {
|
||||
if !b.insideObject {
|
||||
panic("not in object")
|
||||
}
|
||||
return b.WriteVtable()
|
||||
n := b.WriteVtable()
|
||||
b.insideObject = false
|
||||
return n
|
||||
}
|
||||
|
||||
// Doubles the size of the byteslice, and copies the old data towards the
|
||||
@@ -155,13 +187,20 @@ func (b *Builder) growByteBuffer() {
|
||||
if (int64(len(b.Bytes)) & int64(0xC0000000)) != 0 {
|
||||
panic("cannot grow buffer beyond 2 gigabytes")
|
||||
}
|
||||
newSize := len(b.Bytes) * 2
|
||||
if newSize == 0 {
|
||||
newSize = 1
|
||||
newLen := len(b.Bytes) * 2
|
||||
if newLen == 0 {
|
||||
newLen = 1
|
||||
}
|
||||
bytes2 := make([]byte, newSize)
|
||||
copy(bytes2[newSize-len(b.Bytes):], b.Bytes)
|
||||
b.Bytes = bytes2
|
||||
|
||||
if cap(b.Bytes) >= newLen {
|
||||
b.Bytes = b.Bytes[:newLen]
|
||||
} else {
|
||||
extension := make([]byte, newLen-len(b.Bytes))
|
||||
b.Bytes = append(b.Bytes, extension...)
|
||||
}
|
||||
|
||||
middle := newLen / 2
|
||||
copy(b.Bytes[middle:], b.Bytes[:middle])
|
||||
}
|
||||
|
||||
// Head gives the start of useful data in the underlying byte buffer.
|
||||
@@ -198,7 +237,7 @@ func (b *Builder) Prep(size, additionalBytes int) {
|
||||
alignSize &= (size - 1)
|
||||
|
||||
// Reallocate the buffer if needed:
|
||||
for int(b.head) < alignSize+size+additionalBytes {
|
||||
for int(b.head) <= alignSize+size+additionalBytes {
|
||||
oldBufSize := len(b.Bytes)
|
||||
b.growByteBuffer()
|
||||
b.head += UOffsetT(len(b.Bytes) - oldBufSize)
|
||||
@@ -247,16 +286,32 @@ func (b *Builder) EndVector(vectorNumElems int) UOffsetT {
|
||||
|
||||
// CreateString writes a null-terminated string as a vector.
|
||||
func (b *Builder) CreateString(s string) UOffsetT {
|
||||
b.notNested()
|
||||
|
||||
b.Prep(int(SizeUOffsetT), (len(s)+1)*SizeByte)
|
||||
b.PlaceByte(0)
|
||||
|
||||
x := []byte(s)
|
||||
l := UOffsetT(len(x))
|
||||
l := UOffsetT(len(s))
|
||||
|
||||
b.head -= l
|
||||
copy(b.Bytes[b.head:b.head+l], x)
|
||||
copy(b.Bytes[b.head:b.head+l], s)
|
||||
|
||||
return b.EndVector(len(x))
|
||||
return b.EndVector(len(s))
|
||||
}
|
||||
|
||||
// CreateByteString writes a byte slice as a string (null-terminated).
|
||||
func (b *Builder) CreateByteString(s []byte) UOffsetT {
|
||||
b.notNested()
|
||||
|
||||
b.Prep(int(SizeUOffsetT), (len(s)+1)*SizeByte)
|
||||
b.PlaceByte(0)
|
||||
|
||||
l := UOffsetT(len(s))
|
||||
|
||||
b.head -= l
|
||||
copy(b.Bytes[b.head:b.head+l], s)
|
||||
|
||||
return b.EndVector(len(s))
|
||||
}
|
||||
|
||||
// CreateByteVector writes a ubyte vector
|
||||
@@ -274,7 +329,7 @@ func (b *Builder) CreateByteVector(v []byte) UOffsetT {
|
||||
func (b *Builder) notNested() {
|
||||
// Check that no other objects are being built while making this
|
||||
// object. If not, panic:
|
||||
if b.vtable != nil {
|
||||
if b.insideObject {
|
||||
panic("non-inline data write inside of object")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,10 +26,15 @@ func (t *Table) Indirect(off UOffsetT) UOffsetT {
|
||||
|
||||
// String gets a string from data stored inside the flatbuffer.
|
||||
func (t *Table) String(off UOffsetT) string {
|
||||
return string(t.ByteVector(off))
|
||||
}
|
||||
|
||||
// ByteVector gets a byte slice from data stored inside the flatbuffer.
|
||||
func (t *Table) ByteVector(off UOffsetT) []byte {
|
||||
off += GetUOffsetT(t.Bytes[off:])
|
||||
start := off + UOffsetT(SizeUOffsetT)
|
||||
length := GetUOffsetT(t.Bytes[off:])
|
||||
return string(t.Bytes[start : start+length])
|
||||
return t.Bytes[start : start+length]
|
||||
}
|
||||
|
||||
// VectorLen retrieves the length of the vector whose offset is stored at
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstddef>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
@@ -272,6 +273,8 @@ public:
|
||||
return IndirectHelper<T>::Read(Data(), i);
|
||||
}
|
||||
|
||||
return_type operator[](uoffset_t i) const { return Get(i); }
|
||||
|
||||
// If this is a Vector of enums, T will be its storage type, not the enum
|
||||
// type. This function makes it convenient to retrieve value with enum
|
||||
// type E.
|
||||
@@ -286,37 +289,49 @@ public:
|
||||
iterator begin() { return iterator(Data(), 0); }
|
||||
const_iterator begin() const { return const_iterator(Data(), 0); }
|
||||
|
||||
iterator end() { return iterator(Data(), length_); }
|
||||
const_iterator end() const { return const_iterator(Data(), length_); }
|
||||
iterator end() { return iterator(Data(), size()); }
|
||||
const_iterator end() const { return const_iterator(Data(), size()); }
|
||||
|
||||
// Change elements if you have a non-const pointer to this object.
|
||||
// Scalars only. See reflection.h, and the documentation.
|
||||
void Mutate(uoffset_t i, T val) {
|
||||
assert(i < size());
|
||||
WriteScalar(data() + i, val);
|
||||
}
|
||||
|
||||
// Change an element of a vector of tables (or strings).
|
||||
// "val" points to the new table/string, as you can obtain from
|
||||
// e.g. reflection::AddFlatBuffer().
|
||||
void MutateOffset(uoffset_t i, const uint8_t *val) {
|
||||
assert(i < size());
|
||||
assert(sizeof(T) == sizeof(uoffset_t));
|
||||
WriteScalar(data() + i, val - (Data() + i * sizeof(uoffset_t)));
|
||||
}
|
||||
|
||||
// The raw data in little endian format. Use with care.
|
||||
const uint8_t *Data() const {
|
||||
return reinterpret_cast<const uint8_t *>(&length_ + 1);
|
||||
}
|
||||
|
||||
uint8_t *Data() {
|
||||
return reinterpret_cast<uint8_t *>(&length_ + 1);
|
||||
}
|
||||
|
||||
// Similarly, but typed, much like std::vector::data
|
||||
const T *data() const { return reinterpret_cast<const T *>(Data()); }
|
||||
T *data() { return reinterpret_cast<T *>(Data()); }
|
||||
|
||||
template<typename K> return_type LookupByKey(K key) const {
|
||||
auto span = size();
|
||||
uoffset_t start = 0;
|
||||
// Perform binary search for key.
|
||||
while (span) {
|
||||
// Compare against middle element of current span.
|
||||
auto middle = span / 2;
|
||||
auto table = Get(start + middle);
|
||||
auto comp = table->KeyCompareWithValue(key);
|
||||
if (comp > 0) {
|
||||
// Greater than. Adjust span and try again.
|
||||
span = middle;
|
||||
} else if (comp < 0) {
|
||||
// Less than. Adjust span and try again.
|
||||
middle++;
|
||||
start += middle;
|
||||
span -= middle;
|
||||
} else {
|
||||
// Found element.
|
||||
return table;
|
||||
}
|
||||
void *search_result = std::bsearch(&key, Data(), size(),
|
||||
IndirectHelper<T>::element_stride, KeyCompare<K>);
|
||||
|
||||
if (!search_result) {
|
||||
return nullptr; // Key not found.
|
||||
}
|
||||
return nullptr; // Key not found.
|
||||
|
||||
const uint8_t *data = reinterpret_cast<const uint8_t *>(search_result);
|
||||
|
||||
return IndirectHelper<T>::Read(data, 0);
|
||||
}
|
||||
|
||||
protected:
|
||||
@@ -324,6 +339,35 @@ protected:
|
||||
// try to construct these manually.
|
||||
Vector();
|
||||
|
||||
uoffset_t length_;
|
||||
|
||||
private:
|
||||
template<typename K> static int KeyCompare(const void *ap, const void *bp) {
|
||||
const K *key = reinterpret_cast<const K *>(ap);
|
||||
const uint8_t *data = reinterpret_cast<const uint8_t *>(bp);
|
||||
auto table = IndirectHelper<T>::Read(data, 0);
|
||||
|
||||
// std::bsearch compares with the operands transposed, so we negate the
|
||||
// result here.
|
||||
return -table->KeyCompareWithValue(*key);
|
||||
}
|
||||
};
|
||||
|
||||
// Represent a vector much like the template above, but in this case we
|
||||
// don't know what the element types are (used with reflection.h).
|
||||
class VectorOfAny {
|
||||
public:
|
||||
uoffset_t size() const { return EndianScalar(length_); }
|
||||
|
||||
const uint8_t *Data() const {
|
||||
return reinterpret_cast<const uint8_t *>(&length_ + 1);
|
||||
}
|
||||
uint8_t *Data() {
|
||||
return reinterpret_cast<uint8_t *>(&length_ + 1);
|
||||
}
|
||||
protected:
|
||||
VectorOfAny();
|
||||
|
||||
uoffset_t length_;
|
||||
};
|
||||
|
||||
@@ -335,6 +379,7 @@ template<typename T> static inline size_t VectorLength(const Vector<T> *v) {
|
||||
|
||||
struct String : public Vector<char> {
|
||||
const char *c_str() const { return reinterpret_cast<const char *>(Data()); }
|
||||
std::string str() const { return c_str(); }
|
||||
|
||||
bool operator <(const String &o) const {
|
||||
return strcmp(c_str(), o.c_str()) < 0;
|
||||
@@ -399,7 +444,10 @@ class vector_downward {
|
||||
uint8_t *make_space(size_t len) {
|
||||
if (len > static_cast<size_t>(cur_ - buf_)) {
|
||||
auto old_size = size();
|
||||
auto largest_align = AlignOf<largest_scalar_t>();
|
||||
reserved_ += std::max(len, growth_policy(reserved_));
|
||||
// Round up to avoid undefined behavior from unaligned loads and stores.
|
||||
reserved_ = (reserved_ + (largest_align - 1)) & ~(largest_align - 1);
|
||||
auto new_buf = allocator_.allocate(reserved_);
|
||||
auto new_cur = new_buf + reserved_ - old_size;
|
||||
memcpy(new_cur, cur_, old_size);
|
||||
@@ -476,7 +524,7 @@ class FlatBufferBuilder FLATBUFFERS_FINAL_CLASS {
|
||||
explicit FlatBufferBuilder(uoffset_t initial_size = 1024,
|
||||
const simple_allocator *allocator = nullptr)
|
||||
: buf_(initial_size, allocator ? *allocator : default_allocator),
|
||||
minalign_(1), force_defaults_(false) {
|
||||
nested(false), finished(false), minalign_(1), force_defaults_(false) {
|
||||
offsetbuf_.reserve(16); // Avoid first few reallocs.
|
||||
vtables_.reserve(16);
|
||||
EndianCheck();
|
||||
@@ -487,6 +535,8 @@ class FlatBufferBuilder FLATBUFFERS_FINAL_CLASS {
|
||||
void Clear() {
|
||||
buf_.clear();
|
||||
offsetbuf_.clear();
|
||||
nested = false;
|
||||
finished = false;
|
||||
vtables_.clear();
|
||||
minalign_ = 1;
|
||||
}
|
||||
@@ -495,11 +545,33 @@ class FlatBufferBuilder FLATBUFFERS_FINAL_CLASS {
|
||||
uoffset_t GetSize() const { return buf_.size(); }
|
||||
|
||||
// Get the serialized buffer (after you call Finish()).
|
||||
uint8_t *GetBufferPointer() const { return buf_.data(); }
|
||||
uint8_t *GetBufferPointer() const {
|
||||
Finished();
|
||||
return buf_.data();
|
||||
}
|
||||
|
||||
// Get a pointer to an unfinished buffer.
|
||||
uint8_t *GetCurrentBufferPointer() const { return buf_.data(); }
|
||||
|
||||
// Get the released pointer to the serialized buffer.
|
||||
// Don't attempt to use this FlatBufferBuilder afterwards!
|
||||
unique_ptr_t ReleaseBufferPointer() { return buf_.release(); }
|
||||
// The unique_ptr returned has a special allocator that knows how to
|
||||
// deallocate this pointer (since it points to the middle of an allocation).
|
||||
// Thus, do not mix this pointer with other unique_ptr's, or call release() /
|
||||
// reset() on it.
|
||||
unique_ptr_t ReleaseBufferPointer() {
|
||||
Finished();
|
||||
return buf_.release();
|
||||
}
|
||||
|
||||
void Finished() const {
|
||||
// If you get this assert, you're attempting to get access a buffer
|
||||
// which hasn't been finished yet. Be sure to call
|
||||
// FlatBufferBuilder::Finish with your root table.
|
||||
// If you really need to access an unfinished buffer, call
|
||||
// GetCurrentBufferPointer instead.
|
||||
assert(finished);
|
||||
}
|
||||
|
||||
void ForceDefaults(bool fd) { force_defaults_ = fd; }
|
||||
|
||||
@@ -573,21 +645,30 @@ class FlatBufferBuilder FLATBUFFERS_FINAL_CLASS {
|
||||
// This function converts them to be relative to the current location
|
||||
// in the buffer (when stored here), pointing upwards.
|
||||
uoffset_t ReferTo(uoffset_t off) {
|
||||
Align(sizeof(uoffset_t)); // To ensure GetSize() below is correct.
|
||||
assert(off <= GetSize()); // Must refer to something already in buffer.
|
||||
// Align to ensure GetSize() below is correct.
|
||||
Align(sizeof(uoffset_t));
|
||||
// Offset must refer to something already in buffer.
|
||||
assert(off && off <= GetSize());
|
||||
return GetSize() - off + sizeof(uoffset_t);
|
||||
}
|
||||
|
||||
void NotNested() {
|
||||
// If you hit this, you're trying to construct an object when another
|
||||
// hasn't finished yet.
|
||||
assert(!offsetbuf_.size());
|
||||
// If you hit this, you're trying to construct a Table/Vector/String
|
||||
// during the construction of its parent table (between the MyTableBuilder
|
||||
// and table.Finish().
|
||||
// Move the creation of these sub-objects to above the MyTableBuilder to
|
||||
// not get this assert.
|
||||
// Ignoring this assert may appear to work in simple cases, but the reason
|
||||
// it is here is that storing objects in-line may cause vtable offsets
|
||||
// to not fit anymore. It also leads to vtable duplication.
|
||||
assert(!nested);
|
||||
}
|
||||
|
||||
// From generated code (or from the parser), we call StartTable/EndTable
|
||||
// with a sequence of AddElement calls in between.
|
||||
uoffset_t StartTable() {
|
||||
NotNested();
|
||||
nested = true;
|
||||
return GetSize();
|
||||
}
|
||||
|
||||
@@ -595,6 +676,8 @@ class FlatBufferBuilder FLATBUFFERS_FINAL_CLASS {
|
||||
// table, comparing it against existing vtables, and writing the
|
||||
// resulting vtable offset.
|
||||
uoffset_t EndTable(uoffset_t start, voffset_t numfields) {
|
||||
// If you get this assert, a corresponding StartTable wasn't called.
|
||||
assert(nested);
|
||||
// Write the vtable offset, which is the start of any Table.
|
||||
// We fill it's value later.
|
||||
auto vtableoffsetloc = PushElement<soffset_t>(0);
|
||||
@@ -641,6 +724,8 @@ class FlatBufferBuilder FLATBUFFERS_FINAL_CLASS {
|
||||
WriteScalar(buf_.data_at(vtableoffsetloc),
|
||||
static_cast<soffset_t>(vt_use) -
|
||||
static_cast<soffset_t>(vtableoffsetloc));
|
||||
|
||||
nested = false;
|
||||
return vtableoffsetloc;
|
||||
}
|
||||
|
||||
@@ -692,11 +777,19 @@ class FlatBufferBuilder FLATBUFFERS_FINAL_CLASS {
|
||||
return CreateString(str.c_str(), str.length());
|
||||
}
|
||||
|
||||
Offset<String> CreateString(const String *str) {
|
||||
return CreateString(str->c_str(), str->Length());
|
||||
}
|
||||
|
||||
uoffset_t EndVector(size_t len) {
|
||||
assert(nested); // Hit if no corresponding StartVector.
|
||||
nested = false;
|
||||
return PushElement(static_cast<uoffset_t>(len));
|
||||
}
|
||||
|
||||
void StartVector(size_t len, size_t elemsize) {
|
||||
NotNested();
|
||||
nested = true;
|
||||
PreAlign<uoffset_t>(len * elemsize);
|
||||
PreAlign(len * elemsize, elemsize); // Just in case elemsize > uoffset_t.
|
||||
}
|
||||
@@ -706,7 +799,6 @@ class FlatBufferBuilder FLATBUFFERS_FINAL_CLASS {
|
||||
}
|
||||
|
||||
template<typename T> Offset<Vector<T>> CreateVector(const T *v, size_t len) {
|
||||
NotNested();
|
||||
StartVector(len, sizeof(T));
|
||||
for (auto i = len; i > 0; ) {
|
||||
PushElement(v[--i]);
|
||||
@@ -720,7 +812,6 @@ class FlatBufferBuilder FLATBUFFERS_FINAL_CLASS {
|
||||
|
||||
template<typename T> Offset<Vector<const T *>> CreateVectorOfStructs(
|
||||
const T *v, size_t len) {
|
||||
NotNested();
|
||||
StartVector(len * sizeof(T) / AlignOf<T>(), AlignOf<T>());
|
||||
PushBytes(reinterpret_cast<const uint8_t *>(v), sizeof(T) * len);
|
||||
return Offset<Vector<const T *>>(EndVector(len));
|
||||
@@ -744,7 +835,7 @@ class FlatBufferBuilder FLATBUFFERS_FINAL_CLASS {
|
||||
}
|
||||
|
||||
template<typename T> Offset<Vector<Offset<T>>> CreateVectorOfSortedTables(
|
||||
std::vector<T> *v) {
|
||||
std::vector<Offset<T>> *v) {
|
||||
return CreateVectorOfSortedTables(v->data(), v->size());
|
||||
}
|
||||
|
||||
@@ -771,6 +862,7 @@ class FlatBufferBuilder FLATBUFFERS_FINAL_CLASS {
|
||||
// FlatBuffers file header.
|
||||
template<typename T> void Finish(Offset<T> root,
|
||||
const char *file_identifier = nullptr) {
|
||||
NotNested();
|
||||
// This will cause the whole buffer to be aligned.
|
||||
PreAlign(sizeof(uoffset_t) + (file_identifier ? kFileIdentifierLength : 0),
|
||||
minalign_);
|
||||
@@ -780,6 +872,7 @@ class FlatBufferBuilder FLATBUFFERS_FINAL_CLASS {
|
||||
kFileIdentifierLength);
|
||||
}
|
||||
PushElement(ReferTo(root.o)); // Location of root.
|
||||
finished = true;
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -799,6 +892,12 @@ class FlatBufferBuilder FLATBUFFERS_FINAL_CLASS {
|
||||
// Accumulating offsets of table members while it is being built.
|
||||
std::vector<FieldLoc> offsetbuf_;
|
||||
|
||||
// Ensure objects are not nested.
|
||||
bool nested;
|
||||
|
||||
// Ensure the buffer is finished before it is being accessed.
|
||||
bool finished;
|
||||
|
||||
std::vector<uoffset_t> vtables_; // todo: Could make this into a map?
|
||||
|
||||
size_t minalign_;
|
||||
@@ -806,11 +905,15 @@ class FlatBufferBuilder FLATBUFFERS_FINAL_CLASS {
|
||||
bool force_defaults_; // Serialize values equal to their defaults anyway.
|
||||
};
|
||||
|
||||
// Helper to get a typed pointer to the root object contained in the buffer.
|
||||
template<typename T> const T *GetRoot(const void *buf) {
|
||||
// Helpers to get a typed pointer to the root object contained in the buffer.
|
||||
template<typename T> T *GetMutableRoot(void *buf) {
|
||||
EndianCheck();
|
||||
return reinterpret_cast<const T *>(reinterpret_cast<const uint8_t *>(buf) +
|
||||
EndianScalar(*reinterpret_cast<const uoffset_t *>(buf)));
|
||||
return reinterpret_cast<T *>(reinterpret_cast<uint8_t *>(buf) +
|
||||
EndianScalar(*reinterpret_cast<uoffset_t *>(buf)));
|
||||
}
|
||||
|
||||
template<typename T> const T *GetRoot(const void *buf) {
|
||||
return GetMutableRoot<T>(const_cast<void *>(buf));
|
||||
}
|
||||
|
||||
// Helper to see if the identifier in a buffer has the expected value.
|
||||
@@ -838,7 +941,7 @@ class Verifier FLATBUFFERS_FINAL_CLASS {
|
||||
|
||||
// Verify any range within the buffer.
|
||||
bool Verify(const void *elem, size_t elem_len) const {
|
||||
return Check(elem >= buf_ && elem <= end_ - elem_len);
|
||||
return Check(elem_len <= (size_t) (end_ - buf_) && elem >= buf_ && elem <= end_ - elem_len);
|
||||
}
|
||||
|
||||
// Verify a range indicated by sizeof(T).
|
||||
@@ -859,6 +962,11 @@ class Verifier FLATBUFFERS_FINAL_CLASS {
|
||||
&end);
|
||||
}
|
||||
|
||||
// Verify a pointer (may be NULL) of a vector to struct.
|
||||
template<typename T> bool Verify(const Vector<const T *> *vec) const {
|
||||
return Verify(reinterpret_cast<const Vector<T> *>(vec));
|
||||
}
|
||||
|
||||
// Verify a pointer (may be NULL) to string.
|
||||
bool Verify(const String *str) const {
|
||||
const uint8_t *end;
|
||||
@@ -953,6 +1061,9 @@ class Struct FLATBUFFERS_FINAL_CLASS {
|
||||
return reinterpret_cast<T>(&data_[o]);
|
||||
}
|
||||
|
||||
const uint8_t *GetAddressOf(uoffset_t o) const { return &data_[o]; }
|
||||
uint8_t *GetAddressOf(uoffset_t o) { return &data_[o]; }
|
||||
|
||||
private:
|
||||
uint8_t data_[1];
|
||||
};
|
||||
@@ -978,28 +1089,47 @@ class Table {
|
||||
return field_offset ? ReadScalar<T>(data_ + field_offset) : defaultval;
|
||||
}
|
||||
|
||||
template<typename P> P GetPointer(voffset_t field) const {
|
||||
template<typename P> P GetPointer(voffset_t field) {
|
||||
auto field_offset = GetOptionalFieldOffset(field);
|
||||
auto p = data_ + field_offset;
|
||||
return field_offset
|
||||
? reinterpret_cast<P>(p + ReadScalar<uoffset_t>(p))
|
||||
: nullptr;
|
||||
}
|
||||
template<typename P> P GetPointer(voffset_t field) const {
|
||||
return const_cast<Table *>(this)->GetPointer<P>(field);
|
||||
}
|
||||
|
||||
template<typename P> P GetStruct(voffset_t field) const {
|
||||
auto field_offset = GetOptionalFieldOffset(field);
|
||||
return field_offset ? reinterpret_cast<P>(data_ + field_offset) : nullptr;
|
||||
auto p = const_cast<uint8_t *>(data_ + field_offset);
|
||||
return field_offset ? reinterpret_cast<P>(p) : nullptr;
|
||||
}
|
||||
|
||||
template<typename T> void SetField(voffset_t field, T val) {
|
||||
template<typename T> bool SetField(voffset_t field, T val) {
|
||||
auto field_offset = GetOptionalFieldOffset(field);
|
||||
// If this asserts, you're trying to set a field that's not there
|
||||
// (or should we return a bool instead?).
|
||||
// check if it exists first using CheckField()
|
||||
assert(field_offset);
|
||||
if (!field_offset) return false;
|
||||
WriteScalar(data_ + field_offset, val);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SetPointer(voffset_t field, const uint8_t *val) {
|
||||
auto field_offset = GetOptionalFieldOffset(field);
|
||||
if (!field_offset) return false;
|
||||
WriteScalar(data_ + field_offset, val - (data_ + field_offset));
|
||||
return true;
|
||||
}
|
||||
|
||||
uint8_t *GetAddressOf(voffset_t field) {
|
||||
auto field_offset = GetOptionalFieldOffset(field);
|
||||
return field_offset ? data_ + field_offset : nullptr;
|
||||
}
|
||||
const uint8_t *GetAddressOf(voffset_t field) const {
|
||||
return const_cast<Table *>(this)->GetAddressOf(field);
|
||||
}
|
||||
|
||||
uint8_t *GetVTable() { return data_ - ReadScalar<soffset_t>(data_); }
|
||||
|
||||
bool CheckField(voffset_t field) const {
|
||||
return GetOptionalFieldOffset(field) != 0;
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
|
||||
#include "flatbuffers/flatbuffers.h"
|
||||
#include "flatbuffers/hash.h"
|
||||
#include "flatbuffers/reflection.h"
|
||||
|
||||
// This file defines the data types representing a parsed IDL (Interface
|
||||
// Definition Language) / schema file.
|
||||
@@ -35,24 +36,24 @@ namespace flatbuffers {
|
||||
// Additionally, Parser::ParseType assumes bool..string is a contiguous range
|
||||
// of type tokens.
|
||||
#define FLATBUFFERS_GEN_TYPES_SCALAR(TD) \
|
||||
TD(NONE, "", uint8_t, byte, byte, byte) \
|
||||
TD(UTYPE, "", uint8_t, byte, byte, byte) /* begin scalar/int */ \
|
||||
TD(BOOL, "bool", uint8_t, boolean,byte, bool) \
|
||||
TD(CHAR, "byte", int8_t, byte, int8, sbyte) \
|
||||
TD(UCHAR, "ubyte", uint8_t, byte, byte, byte) \
|
||||
TD(SHORT, "short", int16_t, short, int16, short) \
|
||||
TD(USHORT, "ushort", uint16_t, short, uint16, ushort) \
|
||||
TD(INT, "int", int32_t, int, int32, int) \
|
||||
TD(UINT, "uint", uint32_t, int, uint32, uint) \
|
||||
TD(LONG, "long", int64_t, long, int64, long) \
|
||||
TD(ULONG, "ulong", uint64_t, long, uint64, ulong) /* end int */ \
|
||||
TD(FLOAT, "float", float, float, float32, float) /* begin float */ \
|
||||
TD(DOUBLE, "double", double, double, float64, double) /* end float/scalar */
|
||||
TD(NONE, "", uint8_t, byte, byte, byte, uint8) \
|
||||
TD(UTYPE, "", uint8_t, byte, byte, byte, uint8) /* begin scalar/int */ \
|
||||
TD(BOOL, "bool", uint8_t, boolean,byte, bool, bool) \
|
||||
TD(CHAR, "byte", int8_t, byte, int8, sbyte, int8) \
|
||||
TD(UCHAR, "ubyte", uint8_t, byte, byte, byte, uint8) \
|
||||
TD(SHORT, "short", int16_t, short, int16, short, int16) \
|
||||
TD(USHORT, "ushort", uint16_t, short, uint16, ushort, uint16) \
|
||||
TD(INT, "int", int32_t, int, int32, int, int32) \
|
||||
TD(UINT, "uint", uint32_t, int, uint32, uint, uint32) \
|
||||
TD(LONG, "long", int64_t, long, int64, long, int64) \
|
||||
TD(ULONG, "ulong", uint64_t, long, uint64, ulong, uint64) /* end int */ \
|
||||
TD(FLOAT, "float", float, float, float32, float, float32) /* begin float */ \
|
||||
TD(DOUBLE, "double", double, double, float64, double, float64) /* end float/scalar */
|
||||
#define FLATBUFFERS_GEN_TYPES_POINTER(TD) \
|
||||
TD(STRING, "string", Offset<void>, int, int, int) \
|
||||
TD(VECTOR, "", Offset<void>, int, int, int) \
|
||||
TD(STRUCT, "", Offset<void>, int, int, int) \
|
||||
TD(UNION, "", Offset<void>, int, int, int)
|
||||
TD(STRING, "string", Offset<void>, int, int, StringOffset, int) \
|
||||
TD(VECTOR, "", Offset<void>, int, int, VectorOffset, int) \
|
||||
TD(STRUCT, "", Offset<void>, int, int, int, int) \
|
||||
TD(UNION, "", Offset<void>, int, int, int, int)
|
||||
|
||||
// The fields are:
|
||||
// - enum
|
||||
@@ -61,12 +62,13 @@ namespace flatbuffers {
|
||||
// - Java type.
|
||||
// - Go type.
|
||||
// - C# / .Net type.
|
||||
// - Python type.
|
||||
|
||||
// using these macros, we can now write code dealing with types just once, e.g.
|
||||
|
||||
/*
|
||||
switch (type) {
|
||||
#define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE) \
|
||||
#define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \
|
||||
case BASE_TYPE_ ## ENUM: \
|
||||
// do something specific to CTYPE here
|
||||
FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
|
||||
@@ -83,13 +85,13 @@ switch (type) {
|
||||
__extension__ // Stop GCC complaining about trailing comma with -Wpendantic.
|
||||
#endif
|
||||
enum BaseType {
|
||||
#define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE) \
|
||||
#define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \
|
||||
BASE_TYPE_ ## ENUM,
|
||||
FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
|
||||
#undef FLATBUFFERS_TD
|
||||
};
|
||||
|
||||
#define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE) \
|
||||
#define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \
|
||||
static_assert(sizeof(CTYPE) <= sizeof(largest_scalar_t), \
|
||||
"define largest_scalar_t as " #CTYPE);
|
||||
FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
|
||||
@@ -123,8 +125,15 @@ struct Type {
|
||||
enum_def(_ed)
|
||||
{}
|
||||
|
||||
bool operator==(const Type &o) {
|
||||
return base_type == o.base_type && element == o.element &&
|
||||
struct_def == o.struct_def && enum_def == o.enum_def;
|
||||
}
|
||||
|
||||
Type VectorType() const { return Type(element, struct_def, enum_def); }
|
||||
|
||||
Offset<reflection::Type> Serialize(FlatBufferBuilder *builder) const;
|
||||
|
||||
BaseType base_type;
|
||||
BaseType element; // only set if t == BASE_TYPE_VECTOR
|
||||
StructDef *struct_def; // only set if t or element == BASE_TYPE_STRUCT
|
||||
@@ -159,6 +168,17 @@ template<typename T> class SymbolTable {
|
||||
return false;
|
||||
}
|
||||
|
||||
void Move(const std::string &oldname, const std::string &newname) {
|
||||
auto it = dict.find(oldname);
|
||||
if (it != dict.end()) {
|
||||
auto obj = it->second;
|
||||
dict.erase(it);
|
||||
dict[newname] = obj;
|
||||
} else {
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
T *Lookup(const std::string &name) const {
|
||||
auto it = dict.find(name);
|
||||
return it == dict.end() ? nullptr : it->second;
|
||||
@@ -174,11 +194,19 @@ template<typename T> class SymbolTable {
|
||||
// A name space, as set in the schema.
|
||||
struct Namespace {
|
||||
std::vector<std::string> components;
|
||||
|
||||
// Given a (potentally unqualified) name, return the "fully qualified" name
|
||||
// which has a full namespaced descriptor.
|
||||
// With max_components you can request less than the number of components
|
||||
// the current namespace has.
|
||||
std::string GetFullyQualifiedName(const std::string &name,
|
||||
size_t max_components = 1000) const;
|
||||
};
|
||||
|
||||
// Base class for all definition types (fields, structs_, enums_).
|
||||
struct Definition {
|
||||
Definition() : generated(false), defined_namespace(nullptr) {}
|
||||
Definition() : generated(false), defined_namespace(nullptr),
|
||||
serialized_location(0), index(-1) {}
|
||||
|
||||
std::string name;
|
||||
std::string file;
|
||||
@@ -186,12 +214,19 @@ struct Definition {
|
||||
SymbolTable<Value> attributes;
|
||||
bool generated; // did we already output code for this definition?
|
||||
Namespace *defined_namespace; // Where it was defined.
|
||||
|
||||
// For use with Serialize()
|
||||
uoffset_t serialized_location;
|
||||
int index; // Inside the vector it is stored.
|
||||
};
|
||||
|
||||
struct FieldDef : public Definition {
|
||||
FieldDef() : deprecated(false), required(false), key(false), padding(0),
|
||||
used(false) {}
|
||||
|
||||
Offset<reflection::Field> Serialize(FlatBufferBuilder *builder, uint16_t id)
|
||||
const;
|
||||
|
||||
Value value;
|
||||
bool deprecated; // Field is allowed to be present in old data, but can't be
|
||||
// written in new data nor accessed in new code.
|
||||
@@ -211,12 +246,14 @@ struct StructDef : public Definition {
|
||||
bytesize(0)
|
||||
{}
|
||||
|
||||
void PadLastField(size_t minalign) {
|
||||
auto padding = PaddingBytes(bytesize, minalign);
|
||||
void PadLastField(size_t min_align) {
|
||||
auto padding = PaddingBytes(bytesize, min_align);
|
||||
bytesize += padding;
|
||||
if (fields.vec.size()) fields.vec.back()->padding = padding;
|
||||
}
|
||||
|
||||
Offset<reflection::Object> Serialize(FlatBufferBuilder *builder) const;
|
||||
|
||||
SymbolTable<FieldDef> fields;
|
||||
bool fixed; // If it's struct, not a table.
|
||||
bool predecl; // If it's used before it was defined.
|
||||
@@ -242,6 +279,8 @@ struct EnumVal {
|
||||
EnumVal(const std::string &_name, int64_t _val)
|
||||
: name(_name), value(_val), struct_def(nullptr) {}
|
||||
|
||||
Offset<reflection::EnumVal> Serialize(FlatBufferBuilder *builder) const;
|
||||
|
||||
std::string name;
|
||||
std::vector<std::string> doc_comment;
|
||||
int64_t value;
|
||||
@@ -262,6 +301,8 @@ struct EnumDef : public Definition {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Offset<reflection::Enum> Serialize(FlatBufferBuilder *builder) const;
|
||||
|
||||
SymbolTable<EnumVal> vals;
|
||||
bool is_union;
|
||||
Type underlying_type;
|
||||
@@ -270,12 +311,13 @@ struct EnumDef : public Definition {
|
||||
class Parser {
|
||||
public:
|
||||
Parser(bool strict_json = false, bool proto_mode = false)
|
||||
: root_struct_def(nullptr),
|
||||
: root_struct_def_(nullptr),
|
||||
source_(nullptr),
|
||||
cursor_(nullptr),
|
||||
line_(1),
|
||||
proto_mode_(proto_mode),
|
||||
strict_json_(strict_json) {
|
||||
strict_json_(strict_json),
|
||||
anonymous_counter(0) {
|
||||
// Just in case none are declared:
|
||||
namespaces_.push_back(new Namespace());
|
||||
known_attributes_.insert("deprecated");
|
||||
@@ -318,11 +360,18 @@ class Parser {
|
||||
std::set<std::string> GetIncludedFilesRecursive(
|
||||
const std::string &file_name) const;
|
||||
|
||||
// Fills builder_ with a binary version of the schema parsed.
|
||||
// See reflection/reflection.fbs
|
||||
void Serialize();
|
||||
|
||||
private:
|
||||
int64_t ParseHexNum(int nibbles);
|
||||
void Next();
|
||||
bool IsNext(int t);
|
||||
void Expect(int t);
|
||||
std::string TokenToStringId(int t);
|
||||
EnumDef *LookupEnum(const std::string &id);
|
||||
void ParseNamespacing(std::string *id, std::string *last);
|
||||
void ParseTypeIdent(Type &type);
|
||||
void ParseType(Type &type);
|
||||
FieldDef &AddField(StructDef &struct_def,
|
||||
@@ -339,12 +388,19 @@ class Parser {
|
||||
void ParseHash(Value &e, FieldDef* field);
|
||||
void ParseSingleValue(Value &e);
|
||||
int64_t ParseIntegerFromString(Type &type);
|
||||
StructDef *LookupCreateStruct(const std::string &name);
|
||||
void ParseEnum(bool is_union);
|
||||
StructDef *LookupCreateStruct(const std::string &name,
|
||||
bool create_if_new = true,
|
||||
bool definition = false);
|
||||
EnumDef &ParseEnum(bool is_union);
|
||||
void ParseNamespace();
|
||||
StructDef &StartStruct();
|
||||
StructDef &StartStruct(const std::string &name);
|
||||
void ParseDecl();
|
||||
void ParseProtoFields(StructDef *struct_def, bool isextend,
|
||||
bool inside_oneof);
|
||||
void ParseProtoOption();
|
||||
void ParseProtoKey();
|
||||
void ParseProtoDecl();
|
||||
void ParseProtoCurliesOrIdent();
|
||||
Type ParseTypeFromProtoType();
|
||||
|
||||
public:
|
||||
@@ -354,7 +410,7 @@ class Parser {
|
||||
std::string error_; // User readable error_ if Parse() == false
|
||||
|
||||
FlatBufferBuilder builder_; // any data contained in the file
|
||||
StructDef *root_struct_def;
|
||||
StructDef *root_struct_def_;
|
||||
std::string file_identifier_;
|
||||
std::string file_extension_;
|
||||
|
||||
@@ -375,31 +431,47 @@ class Parser {
|
||||
std::vector<uint8_t> struct_stack_;
|
||||
|
||||
std::set<std::string> known_attributes_;
|
||||
|
||||
int anonymous_counter;
|
||||
};
|
||||
|
||||
// Utility functions for multiple generators:
|
||||
|
||||
extern std::string MakeCamel(const std::string &in, bool first = true);
|
||||
|
||||
struct CommentConfig;
|
||||
|
||||
extern void GenComment(const std::vector<std::string> &dc,
|
||||
std::string *code_ptr,
|
||||
const CommentConfig *config,
|
||||
const char *prefix = "");
|
||||
|
||||
// Container of options that may apply to any of the source/text generators.
|
||||
struct GeneratorOptions {
|
||||
bool strict_json;
|
||||
bool skip_js_exports;
|
||||
bool output_default_scalars_in_json;
|
||||
int indent_step;
|
||||
bool output_enum_identifiers;
|
||||
bool prefixed_enums;
|
||||
bool scoped_enums;
|
||||
bool include_dependence_headers;
|
||||
bool mutable_buffer;
|
||||
bool one_file;
|
||||
|
||||
// Possible options for the more general generator below.
|
||||
enum Language { kJava, kCSharp, kGo, kMAX };
|
||||
|
||||
Language lang;
|
||||
|
||||
GeneratorOptions() : strict_json(false), indent_step(2),
|
||||
output_enum_identifiers(true), prefixed_enums(true),
|
||||
include_dependence_headers(false),
|
||||
GeneratorOptions() : strict_json(false),
|
||||
skip_js_exports(false),
|
||||
output_default_scalars_in_json(false),
|
||||
indent_step(2),
|
||||
output_enum_identifiers(true), prefixed_enums(true), scoped_enums(false),
|
||||
include_dependence_headers(true),
|
||||
mutable_buffer(false),
|
||||
one_file(false),
|
||||
lang(GeneratorOptions::kJava) {}
|
||||
};
|
||||
|
||||
@@ -436,6 +508,15 @@ extern bool GenerateCPP(const Parser &parser,
|
||||
const std::string &file_name,
|
||||
const GeneratorOptions &opts);
|
||||
|
||||
// Generate JavaScript code from the definitions in the Parser object.
|
||||
// See idl_gen_js.
|
||||
extern std::string GenerateJS(const Parser &parser,
|
||||
const GeneratorOptions &opts);
|
||||
extern bool GenerateJS(const Parser &parser,
|
||||
const std::string &path,
|
||||
const std::string &file_name,
|
||||
const GeneratorOptions &opts);
|
||||
|
||||
// Generate Go files from the definitions in the Parser object.
|
||||
// See idl_gen_go.cpp.
|
||||
extern bool GenerateGo(const Parser &parser,
|
||||
@@ -450,6 +531,13 @@ extern bool GenerateJava(const Parser &parser,
|
||||
const std::string &file_name,
|
||||
const GeneratorOptions &opts);
|
||||
|
||||
// Generate Python files from the definitions in the Parser object.
|
||||
// See idl_gen_python.cpp.
|
||||
extern bool GeneratePython(const Parser &parser,
|
||||
const std::string &path,
|
||||
const std::string &file_name,
|
||||
const GeneratorOptions &opts);
|
||||
|
||||
// Generate C# files from the definitions in the Parser object.
|
||||
// See idl_gen_csharp.cpp.
|
||||
extern bool GenerateCSharp(const Parser &parser,
|
||||
@@ -474,6 +562,13 @@ extern bool GenerateFBS(const Parser &parser,
|
||||
const std::string &file_name,
|
||||
const GeneratorOptions &opts);
|
||||
|
||||
// Generate a make rule for the generated JavaScript code.
|
||||
// See idl_gen_js.cpp.
|
||||
extern std::string JSMakeRule(const Parser &parser,
|
||||
const std::string &path,
|
||||
const std::string &file_name,
|
||||
const GeneratorOptions &opts);
|
||||
|
||||
// Generate a make rule for the generated C++ header.
|
||||
// See idl_gen_cpp.cpp.
|
||||
extern std::string CPPMakeRule(const Parser &parser,
|
||||
|
||||
427
include/flatbuffers/reflection.h
Normal file
427
include/flatbuffers/reflection.h
Normal file
@@ -0,0 +1,427 @@
|
||||
/*
|
||||
* Copyright 2015 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_REFLECTION_H_
|
||||
#define FLATBUFFERS_REFLECTION_H_
|
||||
|
||||
// This is somewhat of a circular dependency because flatc (and thus this
|
||||
// file) is needed to generate this header in the first place.
|
||||
// Should normally not be a problem since it can be generated by the
|
||||
// previous version of flatc whenever this code needs to change.
|
||||
// See reflection/generate_code.sh
|
||||
#include "flatbuffers/reflection_generated.h"
|
||||
|
||||
// Helper functionality for reflection.
|
||||
|
||||
namespace flatbuffers {
|
||||
|
||||
// ------------------------- GETTERS -------------------------
|
||||
|
||||
// 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.
|
||||
static size_t sizes[] = { 0, 1, 1, 1, 1, 2, 2, 4, 4, 8, 8, 4, 8, 4, 4, 4, 4 };
|
||||
return sizes[base_type];
|
||||
}
|
||||
|
||||
// Same as above, but now correctly returns the size of a struct if
|
||||
// the field (or vector element) is a struct.
|
||||
inline size_t GetTypeSizeInline(reflection::BaseType base_type,
|
||||
int type_index,
|
||||
const reflection::Schema &schema) {
|
||||
if (base_type == reflection::Obj &&
|
||||
schema.objects()->Get(type_index)->is_struct()) {
|
||||
return schema.objects()->Get(type_index)->bytesize();
|
||||
} else {
|
||||
return GetTypeSize(base_type);
|
||||
}
|
||||
}
|
||||
|
||||
// Get the root, regardless of what type it is.
|
||||
inline Table *GetAnyRoot(uint8_t *flatbuf) {
|
||||
return GetMutableRoot<Table>(flatbuf);
|
||||
}
|
||||
inline const Table *GetAnyRoot(const uint8_t *flatbuf) {
|
||||
return GetRoot<Table>(flatbuf);
|
||||
}
|
||||
|
||||
// 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) {
|
||||
assert(sizeof(T) == GetTypeSize(field.type()->base_type()));
|
||||
return table.GetField<T>(field.offset(),
|
||||
static_cast<T>(field.default_integer()));
|
||||
}
|
||||
|
||||
// Get a field, if you know it's floating point and its exact type.
|
||||
template<typename T> T GetFieldF(const Table &table,
|
||||
const reflection::Field &field) {
|
||||
assert(sizeof(T) == GetTypeSize(field.type()->base_type()));
|
||||
return table.GetField<T>(field.offset(),
|
||||
static_cast<T>(field.default_real()));
|
||||
}
|
||||
|
||||
// Get a field, if you know it's a string.
|
||||
inline const String *GetFieldS(const Table &table,
|
||||
const reflection::Field &field) {
|
||||
assert(field.type()->base_type() == reflection::String);
|
||||
return table.GetPointer<const String *>(field.offset());
|
||||
}
|
||||
|
||||
// Get a field, if you know it's a vector.
|
||||
template<typename T> Vector<T> *GetFieldV(const Table &table,
|
||||
const reflection::Field &field) {
|
||||
assert(field.type()->base_type() == reflection::Vector &&
|
||||
sizeof(T) == GetTypeSize(field.type()->element()));
|
||||
return table.GetPointer<Vector<T> *>(field.offset());
|
||||
}
|
||||
|
||||
// Get a field, if you know it's a vector, generically.
|
||||
// To actually access elements, use the return value together with
|
||||
// field.type()->element() in any of GetAnyVectorElemI below etc.
|
||||
inline VectorOfAny *GetFieldAnyV(const Table &table,
|
||||
const reflection::Field &field) {
|
||||
return table.GetPointer<VectorOfAny *>(field.offset());
|
||||
}
|
||||
|
||||
// Get a field, if you know it's a table.
|
||||
inline Table *GetFieldT(const Table &table,
|
||||
const reflection::Field &field) {
|
||||
assert(field.type()->base_type() == reflection::Obj ||
|
||||
field.type()->base_type() == reflection::Union);
|
||||
return table.GetPointer<Table *>(field.offset());
|
||||
}
|
||||
|
||||
// Raw helper functions used below: get any value in memory as a 64bit int, a
|
||||
// double or a string.
|
||||
// All scalars get static_cast to an int64_t, strings use strtoull, every other
|
||||
// data type returns 0.
|
||||
int64_t GetAnyValueI(reflection::BaseType type, const uint8_t *data);
|
||||
// All scalars static cast to double, strings use strtod, every other data
|
||||
// type is 0.0.
|
||||
double GetAnyValueF(reflection::BaseType type, const uint8_t *data);
|
||||
// All scalars converted using stringstream, strings as-is, and all other
|
||||
// data types provide some level of debug-pretty-printing.
|
||||
std::string GetAnyValueS(reflection::BaseType type, const uint8_t *data,
|
||||
const reflection::Schema *schema,
|
||||
int type_index);
|
||||
|
||||
// Get any table field as a 64bit int, regardless of what type it is.
|
||||
inline int64_t GetAnyFieldI(const Table &table,
|
||||
const reflection::Field &field) {
|
||||
auto field_ptr = table.GetAddressOf(field.offset());
|
||||
return field_ptr ? GetAnyValueI(field.type()->base_type(), field_ptr)
|
||||
: field.default_integer();
|
||||
}
|
||||
|
||||
// Get any table field as a double, regardless of what type it is.
|
||||
inline double GetAnyFieldF(const Table &table,
|
||||
const reflection::Field &field) {
|
||||
auto field_ptr = table.GetAddressOf(field.offset());
|
||||
return field_ptr ? GetAnyValueF(field.type()->base_type(), field_ptr)
|
||||
: field.default_real();
|
||||
}
|
||||
|
||||
|
||||
// Get any table field as a string, regardless of what type it is.
|
||||
// You may pass nullptr for the schema if you don't care to have fields that
|
||||
// are of table type pretty-printed.
|
||||
inline std::string GetAnyFieldS(const Table &table,
|
||||
const reflection::Field &field,
|
||||
const reflection::Schema *schema) {
|
||||
auto field_ptr = table.GetAddressOf(field.offset());
|
||||
return field_ptr ? GetAnyValueS(field.type()->base_type(), field_ptr, schema,
|
||||
field.type()->index())
|
||||
: "";
|
||||
}
|
||||
|
||||
// Get any struct field as a 64bit int, regardless of what type it is.
|
||||
inline int64_t GetAnyFieldI(const Struct &st,
|
||||
const reflection::Field &field) {
|
||||
return GetAnyValueI(field.type()->base_type(),
|
||||
st.GetAddressOf(field.offset()));
|
||||
}
|
||||
|
||||
// Get any struct field as a double, regardless of what type it is.
|
||||
inline double GetAnyFieldF(const Struct &st,
|
||||
const reflection::Field &field) {
|
||||
return GetAnyValueF(field.type()->base_type(),
|
||||
st.GetAddressOf(field.offset()));
|
||||
}
|
||||
|
||||
// Get any struct field as a string, regardless of what type it is.
|
||||
inline std::string GetAnyFieldS(const Struct &st,
|
||||
const reflection::Field &field) {
|
||||
return GetAnyValueS(field.type()->base_type(),
|
||||
st.GetAddressOf(field.offset()), nullptr, -1);
|
||||
}
|
||||
|
||||
// Get any vector element as a 64bit int, regardless of what type it is.
|
||||
inline int64_t GetAnyVectorElemI(const VectorOfAny *vec,
|
||||
reflection::BaseType elem_type, size_t i) {
|
||||
return GetAnyValueI(elem_type, vec->Data() + GetTypeSize(elem_type) * i);
|
||||
}
|
||||
|
||||
// Get any vector element as a double, regardless of what type it is.
|
||||
inline double GetAnyVectorElemF(const VectorOfAny *vec,
|
||||
reflection::BaseType elem_type, size_t i) {
|
||||
return GetAnyValueF(elem_type, vec->Data() + GetTypeSize(elem_type) * i);
|
||||
}
|
||||
|
||||
// Get any vector element as a string, regardless of what type it is.
|
||||
inline std::string GetAnyVectorElemS(const VectorOfAny *vec,
|
||||
reflection::BaseType elem_type, size_t i) {
|
||||
return GetAnyValueS(elem_type, vec->Data() + GetTypeSize(elem_type) * i,
|
||||
nullptr, -1);
|
||||
}
|
||||
|
||||
// Get a vector element that's a table/string/vector from a generic vector.
|
||||
// Pass Table/String/VectorOfAny as template parameter.
|
||||
// Warning: does no typechecking.
|
||||
template<typename T> T *GetAnyVectorElemPointer(const VectorOfAny *vec,
|
||||
size_t i) {
|
||||
auto elem_ptr = vec->Data() + sizeof(uoffset_t) * i;
|
||||
return (T *)(elem_ptr + ReadScalar<uoffset_t>(elem_ptr));
|
||||
}
|
||||
|
||||
// Get the inline-address of a vector element. Useful for Structs (pass Struct
|
||||
// as template arg), or being able to address a range of scalars in-line.
|
||||
// Get elem_size from GetTypeSizeInline().
|
||||
// Note: little-endian data on all platforms, use EndianScalar() instead of
|
||||
// raw pointer access with scalars).
|
||||
template<typename T> T *GetAnyVectorElemAddressOf(const VectorOfAny *vec,
|
||||
size_t i,
|
||||
size_t elem_size) {
|
||||
// C-cast to allow const conversion.
|
||||
return (T *)(vec->Data() + elem_size * i);
|
||||
}
|
||||
|
||||
// Similarly, for elements of tables.
|
||||
template<typename T> T *GetAnyFieldAddressOf(const Table &table,
|
||||
const reflection::Field &field) {
|
||||
return (T *)table.GetAddressOf(field.offset());
|
||||
}
|
||||
|
||||
// Similarly, for elements of structs.
|
||||
template<typename T> T *GetAnyFieldAddressOf(const Struct &st,
|
||||
const reflection::Field &field) {
|
||||
return (T *)st.GetAddressOf(field.offset());
|
||||
}
|
||||
|
||||
// ------------------------- SETTERS -------------------------
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
// Raw helper functions used below: set any value in memory as a 64bit int, a
|
||||
// double or a string.
|
||||
// These work for all scalar values, but do nothing for other data types.
|
||||
// To set a string, see SetString below.
|
||||
void SetAnyValueI(reflection::BaseType type, uint8_t *data, int64_t val);
|
||||
void SetAnyValueF(reflection::BaseType type, uint8_t *data, double val);
|
||||
void SetAnyValueS(reflection::BaseType type, uint8_t *data, const char *val);
|
||||
|
||||
// Set any table field as a 64bit int, regardless of type what it is.
|
||||
inline bool SetAnyFieldI(Table *table, const reflection::Field &field,
|
||||
int64_t val) {
|
||||
auto field_ptr = table->GetAddressOf(field.offset());
|
||||
if (!field_ptr) return false;
|
||||
SetAnyValueI(field.type()->base_type(), field_ptr, val);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Set any table field as a double, regardless of what type it is.
|
||||
inline bool SetAnyFieldF(Table *table, const reflection::Field &field,
|
||||
double val) {
|
||||
auto field_ptr = table->GetAddressOf(field.offset());
|
||||
if (!field_ptr) return false;
|
||||
SetAnyValueF(field.type()->base_type(), field_ptr, val);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Set any table field as a string, regardless of what type it is.
|
||||
inline bool SetAnyFieldS(Table *table, const reflection::Field &field,
|
||||
const char *val) {
|
||||
auto field_ptr = table->GetAddressOf(field.offset());
|
||||
if (!field_ptr) return false;
|
||||
SetAnyValueS(field.type()->base_type(), field_ptr, val);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Set any struct field as a 64bit int, regardless of type what it is.
|
||||
inline void SetAnyFieldI(Struct *st, const reflection::Field &field,
|
||||
int64_t val) {
|
||||
SetAnyValueI(field.type()->base_type(), st->GetAddressOf(field.offset()),
|
||||
val);
|
||||
}
|
||||
|
||||
// Set any struct field as a double, regardless of type what it is.
|
||||
inline void SetAnyFieldF(Struct *st, const reflection::Field &field,
|
||||
double val) {
|
||||
SetAnyValueF(field.type()->base_type(), st->GetAddressOf(field.offset()),
|
||||
val);
|
||||
}
|
||||
|
||||
// Set any struct field as a string, regardless of type what it is.
|
||||
inline void SetAnyFieldS(Struct *st, const reflection::Field &field,
|
||||
const char *val) {
|
||||
SetAnyValueS(field.type()->base_type(), st->GetAddressOf(field.offset()),
|
||||
val);
|
||||
}
|
||||
|
||||
// Set any vector element as a 64bit int, regardless of type what it is.
|
||||
inline void SetAnyVectorElemI(VectorOfAny *vec, reflection::BaseType elem_type,
|
||||
size_t i, int64_t val) {
|
||||
SetAnyValueI(elem_type, vec->Data() + GetTypeSize(elem_type) * i, val);
|
||||
}
|
||||
|
||||
// Set any vector element as a double, regardless of type what it is.
|
||||
inline void SetAnyVectorElemF(VectorOfAny *vec, reflection::BaseType elem_type,
|
||||
size_t i, double val) {
|
||||
SetAnyValueF(elem_type, vec->Data() + GetTypeSize(elem_type) * i, val);
|
||||
}
|
||||
|
||||
// Set any vector element as a string, regardless of type what it is.
|
||||
inline void SetAnyVectorElemS(VectorOfAny *vec, reflection::BaseType elem_type,
|
||||
size_t i, const char *val) {
|
||||
SetAnyValueS(elem_type, vec->Data() + GetTypeSize(elem_type) * i, val);
|
||||
}
|
||||
|
||||
|
||||
// ------------------------- RESIZING SETTERS -------------------------
|
||||
|
||||
// "smart" pointer for use with resizing vectors: turns a pointer inside
|
||||
// a vector into a relative offset, such that it is not affected by resizes.
|
||||
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())),
|
||||
vec_(vec) {}
|
||||
|
||||
T *operator*() const {
|
||||
return reinterpret_cast<T *>(
|
||||
reinterpret_cast<uint8_t *>(vec_.data()) + offset_);
|
||||
}
|
||||
T *operator->() const {
|
||||
return operator*();
|
||||
}
|
||||
void operator=(const pointer_inside_vector &piv);
|
||||
private:
|
||||
size_t offset_;
|
||||
std::vector<U> &vec_;
|
||||
};
|
||||
|
||||
// Helper to create the above easily without specifying template args.
|
||||
template<typename T, typename U> pointer_inside_vector<T, U> piv(T *ptr,
|
||||
std::vector<U> &vec) {
|
||||
return pointer_inside_vector<T, U>(ptr, vec);
|
||||
}
|
||||
|
||||
// Helper to figure out the actual table type a union refers to.
|
||||
inline const reflection::Object &GetUnionType(
|
||||
const reflection::Schema &schema, const reflection::Object &parent,
|
||||
const reflection::Field &unionfield, const Table &table) {
|
||||
auto enumdef = schema.enums()->Get(unionfield.type()->index());
|
||||
// TODO: this is clumsy and slow, but no other way to find it?
|
||||
auto type_field = parent.fields()->LookupByKey(
|
||||
(unionfield.name()->str() + "_type").c_str());
|
||||
assert(type_field);
|
||||
auto union_type = GetFieldI<uint8_t>(table, *type_field);
|
||||
auto enumval = enumdef->values()->LookupByKey(union_type);
|
||||
return *enumval->object();
|
||||
}
|
||||
|
||||
// Changes the contents of a string inside a FlatBuffer. FlatBuffer must
|
||||
// live inside a std::vector so we can resize the buffer if needed.
|
||||
// "str" must live inside "flatbuf" and may be invalidated after this call.
|
||||
// If your FlatBuffer's root table is not the schema's root table, you should
|
||||
// pass in your root_table type as well.
|
||||
void SetString(const reflection::Schema &schema, const std::string &val,
|
||||
const String *str, std::vector<uint8_t> *flatbuf,
|
||||
const reflection::Object *root_table = nullptr);
|
||||
|
||||
// Resizes a flatbuffers::Vector inside a FlatBuffer. FlatBuffer must
|
||||
// live inside a std::vector so we can resize the buffer if needed.
|
||||
// "vec" must live inside "flatbuf" and may be invalidated after this call.
|
||||
// If your FlatBuffer's root table is not the schema's root table, you should
|
||||
// pass in your root_table type as well.
|
||||
uint8_t *ResizeAnyVector(const reflection::Schema &schema, uoffset_t newsize,
|
||||
const VectorOfAny *vec, uoffset_t num_elems,
|
||||
uoffset_t elem_size, std::vector<uint8_t> *flatbuf,
|
||||
const reflection::Object *root_table = nullptr);
|
||||
|
||||
template <typename T>
|
||||
void ResizeVector(const reflection::Schema &schema, uoffset_t newsize, T val,
|
||||
const Vector<T> *vec, std::vector<uint8_t> *flatbuf,
|
||||
const reflection::Object *root_table = nullptr) {
|
||||
auto delta_elem = static_cast<int>(newsize) - static_cast<int>(vec->size());
|
||||
auto newelems = ResizeAnyVector(schema, newsize,
|
||||
reinterpret_cast<const VectorOfAny *>(vec),
|
||||
vec->size(),
|
||||
static_cast<uoffset_t>(sizeof(T)), flatbuf,
|
||||
root_table);
|
||||
// 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;
|
||||
if (is_scalar) {
|
||||
WriteScalar(loc, val);
|
||||
} else { // struct
|
||||
*reinterpret_cast<T *>(loc) = val;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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
|
||||
// sufficient, in particular for adding new tables and new fields.
|
||||
// This is potentially slightly less efficient than a FlatBuffer constructed
|
||||
// in one piece, since the new FlatBuffer doesn't share any vtables with the
|
||||
// existing one.
|
||||
// The return value can now be set using Vector::MutateOffset or SetFieldT
|
||||
// below.
|
||||
const uint8_t *AddFlatBuffer(std::vector<uint8_t> &flatbuf,
|
||||
const uint8_t *newbuf, size_t newlen);
|
||||
|
||||
inline bool SetFieldT(Table *table, const reflection::Field &field,
|
||||
const uint8_t *val) {
|
||||
assert(sizeof(uoffset_t) == GetTypeSize(field.type()->base_type()));
|
||||
return table->SetPointer(field.offset(), val);
|
||||
}
|
||||
|
||||
// ------------------------- COPYING -------------------------
|
||||
|
||||
// Generic copying of tables from a FlatBuffer into a FlatBuffer builder.
|
||||
// Can be used to do any kind of merging/selecting you may want to do out
|
||||
// of existing buffers. Also useful to reconstruct a whole buffer if the
|
||||
// above resizing functionality has introduced garbage in a buffer you want
|
||||
// to remove.
|
||||
// Note: this does not deal with DAGs correctly. If the table passed forms a
|
||||
// DAG, the copy will be a tree instead (with duplicates).
|
||||
|
||||
Offset<const Table *> CopyTable(FlatBufferBuilder &fbb,
|
||||
const reflection::Schema &schema,
|
||||
const reflection::Object &objectdef,
|
||||
const Table &table);
|
||||
|
||||
} // namespace flatbuffers
|
||||
|
||||
#endif // FLATBUFFERS_REFLECTION_H_
|
||||
378
include/flatbuffers/reflection_generated.h
Normal file
378
include/flatbuffers/reflection_generated.h
Normal file
@@ -0,0 +1,378 @@
|
||||
// automatically generated by the FlatBuffers compiler, do not modify
|
||||
|
||||
#ifndef FLATBUFFERS_GENERATED_REFLECTION_REFLECTION_H_
|
||||
#define FLATBUFFERS_GENERATED_REFLECTION_REFLECTION_H_
|
||||
|
||||
#include "flatbuffers/flatbuffers.h"
|
||||
|
||||
|
||||
namespace reflection {
|
||||
|
||||
struct Type;
|
||||
struct EnumVal;
|
||||
struct Enum;
|
||||
struct Field;
|
||||
struct Object;
|
||||
struct Schema;
|
||||
|
||||
enum BaseType {
|
||||
None = 0,
|
||||
UType = 1,
|
||||
Bool = 2,
|
||||
Byte = 3,
|
||||
UByte = 4,
|
||||
Short = 5,
|
||||
UShort = 6,
|
||||
Int = 7,
|
||||
UInt = 8,
|
||||
Long = 9,
|
||||
ULong = 10,
|
||||
Float = 11,
|
||||
Double = 12,
|
||||
String = 13,
|
||||
Vector = 14,
|
||||
Obj = 15,
|
||||
Union = 16
|
||||
};
|
||||
|
||||
inline const char **EnumNamesBaseType() {
|
||||
static const char *names[] = { "None", "UType", "Bool", "Byte", "UByte", "Short", "UShort", "Int", "UInt", "Long", "ULong", "Float", "Double", "String", "Vector", "Obj", "Union", nullptr };
|
||||
return names;
|
||||
}
|
||||
|
||||
inline const char *EnumNameBaseType(BaseType e) { return EnumNamesBaseType()[e]; }
|
||||
|
||||
struct Type FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
|
||||
BaseType base_type() const { return static_cast<BaseType>(GetField<int8_t>(4, 0)); }
|
||||
BaseType element() const { return static_cast<BaseType>(GetField<int8_t>(6, 0)); }
|
||||
int32_t index() const { return GetField<int32_t>(8, -1); }
|
||||
bool Verify(flatbuffers::Verifier &verifier) const {
|
||||
return VerifyTableStart(verifier) &&
|
||||
VerifyField<int8_t>(verifier, 4 /* base_type */) &&
|
||||
VerifyField<int8_t>(verifier, 6 /* element */) &&
|
||||
VerifyField<int32_t>(verifier, 8 /* index */) &&
|
||||
verifier.EndTable();
|
||||
}
|
||||
};
|
||||
|
||||
struct TypeBuilder {
|
||||
flatbuffers::FlatBufferBuilder &fbb_;
|
||||
flatbuffers::uoffset_t start_;
|
||||
void add_base_type(BaseType base_type) { fbb_.AddElement<int8_t>(4, static_cast<int8_t>(base_type), 0); }
|
||||
void add_element(BaseType element) { fbb_.AddElement<int8_t>(6, static_cast<int8_t>(element), 0); }
|
||||
void add_index(int32_t index) { fbb_.AddElement<int32_t>(8, index, -1); }
|
||||
TypeBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) { start_ = fbb_.StartTable(); }
|
||||
TypeBuilder &operator=(const TypeBuilder &);
|
||||
flatbuffers::Offset<Type> Finish() {
|
||||
auto o = flatbuffers::Offset<Type>(fbb_.EndTable(start_, 3));
|
||||
return o;
|
||||
}
|
||||
};
|
||||
|
||||
inline flatbuffers::Offset<Type> CreateType(flatbuffers::FlatBufferBuilder &_fbb,
|
||||
BaseType base_type = None,
|
||||
BaseType element = None,
|
||||
int32_t index = -1) {
|
||||
TypeBuilder builder_(_fbb);
|
||||
builder_.add_index(index);
|
||||
builder_.add_element(element);
|
||||
builder_.add_base_type(base_type);
|
||||
return builder_.Finish();
|
||||
}
|
||||
|
||||
struct EnumVal FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
|
||||
const flatbuffers::String *name() const { return GetPointer<const flatbuffers::String *>(4); }
|
||||
int64_t value() const { return GetField<int64_t>(6, 0); }
|
||||
bool KeyCompareLessThan(const EnumVal *o) const { return value() < o->value(); }
|
||||
int KeyCompareWithValue(int64_t val) const { return value() < val ? -1 : value() > val; }
|
||||
const Object *object() const { return GetPointer<const Object *>(8); }
|
||||
bool Verify(flatbuffers::Verifier &verifier) const {
|
||||
return VerifyTableStart(verifier) &&
|
||||
VerifyFieldRequired<flatbuffers::uoffset_t>(verifier, 4 /* name */) &&
|
||||
verifier.Verify(name()) &&
|
||||
VerifyField<int64_t>(verifier, 6 /* value */) &&
|
||||
VerifyField<flatbuffers::uoffset_t>(verifier, 8 /* object */) &&
|
||||
verifier.VerifyTable(object()) &&
|
||||
verifier.EndTable();
|
||||
}
|
||||
};
|
||||
|
||||
struct EnumValBuilder {
|
||||
flatbuffers::FlatBufferBuilder &fbb_;
|
||||
flatbuffers::uoffset_t start_;
|
||||
void add_name(flatbuffers::Offset<flatbuffers::String> name) { fbb_.AddOffset(4, name); }
|
||||
void add_value(int64_t value) { fbb_.AddElement<int64_t>(6, value, 0); }
|
||||
void add_object(flatbuffers::Offset<Object> object) { fbb_.AddOffset(8, object); }
|
||||
EnumValBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) { start_ = fbb_.StartTable(); }
|
||||
EnumValBuilder &operator=(const EnumValBuilder &);
|
||||
flatbuffers::Offset<EnumVal> Finish() {
|
||||
auto o = flatbuffers::Offset<EnumVal>(fbb_.EndTable(start_, 3));
|
||||
fbb_.Required(o, 4); // name
|
||||
return o;
|
||||
}
|
||||
};
|
||||
|
||||
inline flatbuffers::Offset<EnumVal> CreateEnumVal(flatbuffers::FlatBufferBuilder &_fbb,
|
||||
flatbuffers::Offset<flatbuffers::String> name = 0,
|
||||
int64_t value = 0,
|
||||
flatbuffers::Offset<Object> object = 0) {
|
||||
EnumValBuilder builder_(_fbb);
|
||||
builder_.add_value(value);
|
||||
builder_.add_object(object);
|
||||
builder_.add_name(name);
|
||||
return builder_.Finish();
|
||||
}
|
||||
|
||||
struct Enum FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
|
||||
const flatbuffers::String *name() const { return GetPointer<const flatbuffers::String *>(4); }
|
||||
bool KeyCompareLessThan(const Enum *o) const { return *name() < *o->name(); }
|
||||
int KeyCompareWithValue(const char *val) const { return strcmp(name()->c_str(), val); }
|
||||
const flatbuffers::Vector<flatbuffers::Offset<EnumVal>> *values() const { return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<EnumVal>> *>(6); }
|
||||
uint8_t is_union() const { return GetField<uint8_t>(8, 0); }
|
||||
const Type *underlying_type() const { return GetPointer<const Type *>(10); }
|
||||
bool Verify(flatbuffers::Verifier &verifier) const {
|
||||
return VerifyTableStart(verifier) &&
|
||||
VerifyFieldRequired<flatbuffers::uoffset_t>(verifier, 4 /* name */) &&
|
||||
verifier.Verify(name()) &&
|
||||
VerifyFieldRequired<flatbuffers::uoffset_t>(verifier, 6 /* values */) &&
|
||||
verifier.Verify(values()) &&
|
||||
verifier.VerifyVectorOfTables(values()) &&
|
||||
VerifyField<uint8_t>(verifier, 8 /* is_union */) &&
|
||||
VerifyFieldRequired<flatbuffers::uoffset_t>(verifier, 10 /* underlying_type */) &&
|
||||
verifier.VerifyTable(underlying_type()) &&
|
||||
verifier.EndTable();
|
||||
}
|
||||
};
|
||||
|
||||
struct EnumBuilder {
|
||||
flatbuffers::FlatBufferBuilder &fbb_;
|
||||
flatbuffers::uoffset_t start_;
|
||||
void add_name(flatbuffers::Offset<flatbuffers::String> name) { fbb_.AddOffset(4, name); }
|
||||
void add_values(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<EnumVal>>> values) { fbb_.AddOffset(6, values); }
|
||||
void add_is_union(uint8_t is_union) { fbb_.AddElement<uint8_t>(8, is_union, 0); }
|
||||
void add_underlying_type(flatbuffers::Offset<Type> underlying_type) { fbb_.AddOffset(10, underlying_type); }
|
||||
EnumBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) { start_ = fbb_.StartTable(); }
|
||||
EnumBuilder &operator=(const EnumBuilder &);
|
||||
flatbuffers::Offset<Enum> Finish() {
|
||||
auto o = flatbuffers::Offset<Enum>(fbb_.EndTable(start_, 4));
|
||||
fbb_.Required(o, 4); // name
|
||||
fbb_.Required(o, 6); // values
|
||||
fbb_.Required(o, 10); // underlying_type
|
||||
return o;
|
||||
}
|
||||
};
|
||||
|
||||
inline flatbuffers::Offset<Enum> CreateEnum(flatbuffers::FlatBufferBuilder &_fbb,
|
||||
flatbuffers::Offset<flatbuffers::String> name = 0,
|
||||
flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<EnumVal>>> values = 0,
|
||||
uint8_t is_union = 0,
|
||||
flatbuffers::Offset<Type> underlying_type = 0) {
|
||||
EnumBuilder builder_(_fbb);
|
||||
builder_.add_underlying_type(underlying_type);
|
||||
builder_.add_values(values);
|
||||
builder_.add_name(name);
|
||||
builder_.add_is_union(is_union);
|
||||
return builder_.Finish();
|
||||
}
|
||||
|
||||
struct Field FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
|
||||
const flatbuffers::String *name() const { return GetPointer<const flatbuffers::String *>(4); }
|
||||
bool KeyCompareLessThan(const Field *o) const { return *name() < *o->name(); }
|
||||
int KeyCompareWithValue(const char *val) const { return strcmp(name()->c_str(), val); }
|
||||
const Type *type() const { return GetPointer<const Type *>(6); }
|
||||
uint16_t id() const { return GetField<uint16_t>(8, 0); }
|
||||
uint16_t offset() const { return GetField<uint16_t>(10, 0); }
|
||||
int64_t default_integer() const { return GetField<int64_t>(12, 0); }
|
||||
double default_real() const { return GetField<double>(14, 0.0); }
|
||||
uint8_t deprecated() const { return GetField<uint8_t>(16, 0); }
|
||||
uint8_t required() const { return GetField<uint8_t>(18, 0); }
|
||||
uint8_t key() const { return GetField<uint8_t>(20, 0); }
|
||||
bool Verify(flatbuffers::Verifier &verifier) const {
|
||||
return VerifyTableStart(verifier) &&
|
||||
VerifyFieldRequired<flatbuffers::uoffset_t>(verifier, 4 /* name */) &&
|
||||
verifier.Verify(name()) &&
|
||||
VerifyFieldRequired<flatbuffers::uoffset_t>(verifier, 6 /* type */) &&
|
||||
verifier.VerifyTable(type()) &&
|
||||
VerifyField<uint16_t>(verifier, 8 /* id */) &&
|
||||
VerifyField<uint16_t>(verifier, 10 /* offset */) &&
|
||||
VerifyField<int64_t>(verifier, 12 /* default_integer */) &&
|
||||
VerifyField<double>(verifier, 14 /* default_real */) &&
|
||||
VerifyField<uint8_t>(verifier, 16 /* deprecated */) &&
|
||||
VerifyField<uint8_t>(verifier, 18 /* required */) &&
|
||||
VerifyField<uint8_t>(verifier, 20 /* key */) &&
|
||||
verifier.EndTable();
|
||||
}
|
||||
};
|
||||
|
||||
struct FieldBuilder {
|
||||
flatbuffers::FlatBufferBuilder &fbb_;
|
||||
flatbuffers::uoffset_t start_;
|
||||
void add_name(flatbuffers::Offset<flatbuffers::String> name) { fbb_.AddOffset(4, name); }
|
||||
void add_type(flatbuffers::Offset<Type> type) { fbb_.AddOffset(6, type); }
|
||||
void add_id(uint16_t id) { fbb_.AddElement<uint16_t>(8, id, 0); }
|
||||
void add_offset(uint16_t offset) { fbb_.AddElement<uint16_t>(10, offset, 0); }
|
||||
void add_default_integer(int64_t default_integer) { fbb_.AddElement<int64_t>(12, default_integer, 0); }
|
||||
void add_default_real(double default_real) { fbb_.AddElement<double>(14, default_real, 0.0); }
|
||||
void add_deprecated(uint8_t deprecated) { fbb_.AddElement<uint8_t>(16, deprecated, 0); }
|
||||
void add_required(uint8_t required) { fbb_.AddElement<uint8_t>(18, required, 0); }
|
||||
void add_key(uint8_t key) { fbb_.AddElement<uint8_t>(20, key, 0); }
|
||||
FieldBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) { start_ = fbb_.StartTable(); }
|
||||
FieldBuilder &operator=(const FieldBuilder &);
|
||||
flatbuffers::Offset<Field> Finish() {
|
||||
auto o = flatbuffers::Offset<Field>(fbb_.EndTable(start_, 9));
|
||||
fbb_.Required(o, 4); // name
|
||||
fbb_.Required(o, 6); // type
|
||||
return o;
|
||||
}
|
||||
};
|
||||
|
||||
inline flatbuffers::Offset<Field> CreateField(flatbuffers::FlatBufferBuilder &_fbb,
|
||||
flatbuffers::Offset<flatbuffers::String> name = 0,
|
||||
flatbuffers::Offset<Type> type = 0,
|
||||
uint16_t id = 0,
|
||||
uint16_t offset = 0,
|
||||
int64_t default_integer = 0,
|
||||
double default_real = 0.0,
|
||||
uint8_t deprecated = 0,
|
||||
uint8_t required = 0,
|
||||
uint8_t key = 0) {
|
||||
FieldBuilder builder_(_fbb);
|
||||
builder_.add_default_real(default_real);
|
||||
builder_.add_default_integer(default_integer);
|
||||
builder_.add_type(type);
|
||||
builder_.add_name(name);
|
||||
builder_.add_offset(offset);
|
||||
builder_.add_id(id);
|
||||
builder_.add_key(key);
|
||||
builder_.add_required(required);
|
||||
builder_.add_deprecated(deprecated);
|
||||
return builder_.Finish();
|
||||
}
|
||||
|
||||
struct Object FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
|
||||
const flatbuffers::String *name() const { return GetPointer<const flatbuffers::String *>(4); }
|
||||
bool KeyCompareLessThan(const Object *o) const { return *name() < *o->name(); }
|
||||
int KeyCompareWithValue(const char *val) const { return strcmp(name()->c_str(), val); }
|
||||
const flatbuffers::Vector<flatbuffers::Offset<Field>> *fields() const { return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<Field>> *>(6); }
|
||||
uint8_t is_struct() const { return GetField<uint8_t>(8, 0); }
|
||||
int32_t minalign() const { return GetField<int32_t>(10, 0); }
|
||||
int32_t bytesize() const { return GetField<int32_t>(12, 0); }
|
||||
bool Verify(flatbuffers::Verifier &verifier) const {
|
||||
return VerifyTableStart(verifier) &&
|
||||
VerifyFieldRequired<flatbuffers::uoffset_t>(verifier, 4 /* name */) &&
|
||||
verifier.Verify(name()) &&
|
||||
VerifyFieldRequired<flatbuffers::uoffset_t>(verifier, 6 /* fields */) &&
|
||||
verifier.Verify(fields()) &&
|
||||
verifier.VerifyVectorOfTables(fields()) &&
|
||||
VerifyField<uint8_t>(verifier, 8 /* is_struct */) &&
|
||||
VerifyField<int32_t>(verifier, 10 /* minalign */) &&
|
||||
VerifyField<int32_t>(verifier, 12 /* bytesize */) &&
|
||||
verifier.EndTable();
|
||||
}
|
||||
};
|
||||
|
||||
struct ObjectBuilder {
|
||||
flatbuffers::FlatBufferBuilder &fbb_;
|
||||
flatbuffers::uoffset_t start_;
|
||||
void add_name(flatbuffers::Offset<flatbuffers::String> name) { fbb_.AddOffset(4, name); }
|
||||
void add_fields(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<Field>>> fields) { fbb_.AddOffset(6, fields); }
|
||||
void add_is_struct(uint8_t is_struct) { fbb_.AddElement<uint8_t>(8, is_struct, 0); }
|
||||
void add_minalign(int32_t minalign) { fbb_.AddElement<int32_t>(10, minalign, 0); }
|
||||
void add_bytesize(int32_t bytesize) { fbb_.AddElement<int32_t>(12, bytesize, 0); }
|
||||
ObjectBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) { start_ = fbb_.StartTable(); }
|
||||
ObjectBuilder &operator=(const ObjectBuilder &);
|
||||
flatbuffers::Offset<Object> Finish() {
|
||||
auto o = flatbuffers::Offset<Object>(fbb_.EndTable(start_, 5));
|
||||
fbb_.Required(o, 4); // name
|
||||
fbb_.Required(o, 6); // fields
|
||||
return o;
|
||||
}
|
||||
};
|
||||
|
||||
inline flatbuffers::Offset<Object> CreateObject(flatbuffers::FlatBufferBuilder &_fbb,
|
||||
flatbuffers::Offset<flatbuffers::String> name = 0,
|
||||
flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<Field>>> fields = 0,
|
||||
uint8_t is_struct = 0,
|
||||
int32_t minalign = 0,
|
||||
int32_t bytesize = 0) {
|
||||
ObjectBuilder builder_(_fbb);
|
||||
builder_.add_bytesize(bytesize);
|
||||
builder_.add_minalign(minalign);
|
||||
builder_.add_fields(fields);
|
||||
builder_.add_name(name);
|
||||
builder_.add_is_struct(is_struct);
|
||||
return builder_.Finish();
|
||||
}
|
||||
|
||||
struct Schema FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
|
||||
const flatbuffers::Vector<flatbuffers::Offset<Object>> *objects() const { return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<Object>> *>(4); }
|
||||
const flatbuffers::Vector<flatbuffers::Offset<Enum>> *enums() const { return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<Enum>> *>(6); }
|
||||
const flatbuffers::String *file_ident() const { return GetPointer<const flatbuffers::String *>(8); }
|
||||
const flatbuffers::String *file_ext() const { return GetPointer<const flatbuffers::String *>(10); }
|
||||
const Object *root_table() const { return GetPointer<const Object *>(12); }
|
||||
bool Verify(flatbuffers::Verifier &verifier) const {
|
||||
return VerifyTableStart(verifier) &&
|
||||
VerifyFieldRequired<flatbuffers::uoffset_t>(verifier, 4 /* objects */) &&
|
||||
verifier.Verify(objects()) &&
|
||||
verifier.VerifyVectorOfTables(objects()) &&
|
||||
VerifyFieldRequired<flatbuffers::uoffset_t>(verifier, 6 /* enums */) &&
|
||||
verifier.Verify(enums()) &&
|
||||
verifier.VerifyVectorOfTables(enums()) &&
|
||||
VerifyField<flatbuffers::uoffset_t>(verifier, 8 /* file_ident */) &&
|
||||
verifier.Verify(file_ident()) &&
|
||||
VerifyField<flatbuffers::uoffset_t>(verifier, 10 /* file_ext */) &&
|
||||
verifier.Verify(file_ext()) &&
|
||||
VerifyField<flatbuffers::uoffset_t>(verifier, 12 /* root_table */) &&
|
||||
verifier.VerifyTable(root_table()) &&
|
||||
verifier.EndTable();
|
||||
}
|
||||
};
|
||||
|
||||
struct SchemaBuilder {
|
||||
flatbuffers::FlatBufferBuilder &fbb_;
|
||||
flatbuffers::uoffset_t start_;
|
||||
void add_objects(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<Object>>> objects) { fbb_.AddOffset(4, objects); }
|
||||
void add_enums(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<Enum>>> enums) { fbb_.AddOffset(6, enums); }
|
||||
void add_file_ident(flatbuffers::Offset<flatbuffers::String> file_ident) { fbb_.AddOffset(8, file_ident); }
|
||||
void add_file_ext(flatbuffers::Offset<flatbuffers::String> file_ext) { fbb_.AddOffset(10, file_ext); }
|
||||
void add_root_table(flatbuffers::Offset<Object> root_table) { fbb_.AddOffset(12, root_table); }
|
||||
SchemaBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) { start_ = fbb_.StartTable(); }
|
||||
SchemaBuilder &operator=(const SchemaBuilder &);
|
||||
flatbuffers::Offset<Schema> Finish() {
|
||||
auto o = flatbuffers::Offset<Schema>(fbb_.EndTable(start_, 5));
|
||||
fbb_.Required(o, 4); // objects
|
||||
fbb_.Required(o, 6); // enums
|
||||
return o;
|
||||
}
|
||||
};
|
||||
|
||||
inline flatbuffers::Offset<Schema> CreateSchema(flatbuffers::FlatBufferBuilder &_fbb,
|
||||
flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<Object>>> objects = 0,
|
||||
flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<Enum>>> enums = 0,
|
||||
flatbuffers::Offset<flatbuffers::String> file_ident = 0,
|
||||
flatbuffers::Offset<flatbuffers::String> file_ext = 0,
|
||||
flatbuffers::Offset<Object> root_table = 0) {
|
||||
SchemaBuilder builder_(_fbb);
|
||||
builder_.add_root_table(root_table);
|
||||
builder_.add_file_ext(file_ext);
|
||||
builder_.add_file_ident(file_ident);
|
||||
builder_.add_enums(enums);
|
||||
builder_.add_objects(objects);
|
||||
return builder_.Finish();
|
||||
}
|
||||
|
||||
inline const reflection::Schema *GetSchema(const void *buf) { return flatbuffers::GetRoot<reflection::Schema>(buf); }
|
||||
|
||||
inline bool VerifySchemaBuffer(flatbuffers::Verifier &verifier) { return verifier.VerifyBuffer<reflection::Schema>(); }
|
||||
|
||||
inline const char *SchemaIdentifier() { return "BFBS"; }
|
||||
|
||||
inline bool SchemaBufferHasIdentifier(const void *buf) { return flatbuffers::BufferHasIdentifier(buf, SchemaIdentifier()); }
|
||||
|
||||
inline const char *SchemaExtension() { return "bfbs"; }
|
||||
|
||||
inline void FinishSchemaBuffer(flatbuffers::FlatBufferBuilder &fbb, flatbuffers::Offset<reflection::Schema> root) { fbb.Finish(root, SchemaIdentifier()); }
|
||||
|
||||
} // namespace reflection
|
||||
|
||||
#endif // FLATBUFFERS_GENERATED_REFLECTION_REFLECTION_H_
|
||||
@@ -42,10 +42,8 @@ namespace flatbuffers {
|
||||
|
||||
// Convert an integer or floating point value to a string.
|
||||
// In contrast to std::stringstream, "char" values are
|
||||
// converted to a string of digits.
|
||||
// converted to a string of digits, and we don't use scientific notation.
|
||||
template<typename T> std::string NumToString(T t) {
|
||||
// to_string() prints different numbers of digits for floats depending on
|
||||
// platform and isn't available on Android, so we use stringstream
|
||||
std::stringstream ss;
|
||||
ss << t;
|
||||
return ss.str();
|
||||
@@ -58,6 +56,27 @@ template<> inline std::string NumToString<unsigned char>(unsigned char t) {
|
||||
return NumToString(static_cast<int>(t));
|
||||
}
|
||||
|
||||
// Special versions for floats/doubles.
|
||||
template<> inline std::string NumToString<double>(double t) {
|
||||
// to_string() prints different numbers of digits for floats depending on
|
||||
// platform and isn't available on Android, so we use stringstream
|
||||
std::stringstream ss;
|
||||
// Use std::fixed to surpress scientific notation.
|
||||
ss << std::fixed << t;
|
||||
auto s = ss.str();
|
||||
// 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.back() == '.')
|
||||
s.erase(s.size() - 1, 1); // Strip '.' if a whole number.
|
||||
}
|
||||
return s;
|
||||
}
|
||||
template<> inline std::string NumToString<float>(float t) {
|
||||
return NumToString(static_cast<double>(t));
|
||||
}
|
||||
|
||||
// Convert an integer value to a hexadecimal string.
|
||||
// The returned string length is always xdigits long, prefixed by 0 digits.
|
||||
// For example, IntToStringHex(0x23, 8) returns the string "00000023".
|
||||
@@ -71,8 +90,17 @@ inline std::string IntToStringHex(int i, int xdigits) {
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
// Portable implementation of strtoull().
|
||||
// Portable implementation of strtoll().
|
||||
inline int64_t StringToInt(const char *str, int base = 10) {
|
||||
#ifdef _MSC_VER
|
||||
return _strtoi64(str, nullptr, base);
|
||||
#else
|
||||
return strtoll(str, nullptr, base);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Portable implementation of strtoull().
|
||||
inline int64_t StringToUInt(const char *str, int base = 10) {
|
||||
#ifdef _MSC_VER
|
||||
return _strtoui64(str, nullptr, base);
|
||||
#else
|
||||
@@ -93,8 +121,18 @@ inline bool FileExists(const char *name) {
|
||||
inline bool LoadFile(const char *name, bool binary, std::string *buf) {
|
||||
std::ifstream ifs(name, binary ? std::ifstream::binary : std::ifstream::in);
|
||||
if (!ifs.is_open()) return false;
|
||||
*buf = std::string(std::istreambuf_iterator<char>(ifs),
|
||||
std::istreambuf_iterator<char>());
|
||||
if (binary) {
|
||||
// The fastest way to read a file into a string.
|
||||
ifs.seekg(0, std::ios::end);
|
||||
(*buf).resize(static_cast<size_t>(ifs.tellg()));
|
||||
ifs.seekg(0, std::ios::beg);
|
||||
ifs.read(&(*buf)[0], (*buf).size());
|
||||
} else {
|
||||
// This is slower, but works correctly on all platforms for text files.
|
||||
std::ostringstream oss;
|
||||
oss << ifs.rdbuf();
|
||||
*buf = oss.str();
|
||||
}
|
||||
return !ifs.bad();
|
||||
}
|
||||
|
||||
|
||||
@@ -52,6 +52,13 @@ public class FlatBufferBuilder {
|
||||
bb = newByteBuffer(initial_size);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
@@ -262,6 +269,21 @@ public class FlatBufferBuilder {
|
||||
return endVector();
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode the string {@code s} in the buffer using UTF-8.
|
||||
*
|
||||
* @param s An already encoded UTF-8 string
|
||||
* @return The offset in the buffer where the encoded string starts
|
||||
*/
|
||||
public int createString(ByteBuffer s) {
|
||||
int length = s.remaining();
|
||||
addByte((byte)0);
|
||||
startVector(1, length, 1);
|
||||
bb.position(space -= length);
|
||||
bb.put(s);
|
||||
return endVector();
|
||||
}
|
||||
|
||||
/**
|
||||
* Should not be creating any other object, string or vector
|
||||
* while an object is being constructed
|
||||
|
||||
@@ -25,6 +25,8 @@ public class Table {
|
||||
protected int bb_pos;
|
||||
protected ByteBuffer bb;
|
||||
|
||||
public ByteBuffer getByteBuffer() { return bb; }
|
||||
|
||||
// Look up a field in the vtable, return an offset into the object, or 0 if the field is not
|
||||
// present.
|
||||
protected int __offset(int vtable_offset) {
|
||||
@@ -45,7 +47,7 @@ public class Table {
|
||||
protected String __string(int offset) {
|
||||
offset += bb.getInt(offset);
|
||||
if (bb.hasArray()) {
|
||||
return new String(bb.array(), offset + SIZEOF_INT, bb.getInt(offset), FlatBufferBuilder.utf8charset);
|
||||
return new String(bb.array(), bb.arrayOffset() + offset + SIZEOF_INT, bb.getInt(offset), FlatBufferBuilder.utf8charset);
|
||||
} else {
|
||||
// We can't access .array(), since the ByteBuffer is read-only,
|
||||
// off-heap or a memory map
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>com.google.flatbuffers</groupId>
|
||||
<artifactId>flatbuffers-java</artifactId>
|
||||
<version>0.0.0-SNAPSHOT</version>
|
||||
<version>1.2.0-SNAPSHOT</version>
|
||||
<packaging>jar</packaging>
|
||||
<name>FlatBuffers Java API</name>
|
||||
<description>
|
||||
|
||||
1072
js/flatbuffers.js
Normal file
1072
js/flatbuffers.js
Normal file
File diff suppressed because it is too large
Load Diff
@@ -17,7 +17,6 @@
|
||||
//#define UNSAFE_BYTEBUFFER // uncomment this line to use faster ByteBuffer
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
|
||||
namespace FlatBuffers
|
||||
{
|
||||
@@ -36,13 +35,23 @@ namespace FlatBuffers
|
||||
|
||||
public byte[] Data { get { return _buffer; } }
|
||||
|
||||
public ByteBuffer(byte[] buffer)
|
||||
public ByteBuffer(byte[] buffer) : this(buffer, 0) { }
|
||||
|
||||
public ByteBuffer(byte[] buffer, int pos)
|
||||
{
|
||||
_buffer = buffer;
|
||||
_pos = 0;
|
||||
_pos = pos;
|
||||
}
|
||||
|
||||
public int position() { return _pos; }
|
||||
public int Position {
|
||||
get { return _pos; }
|
||||
set { _pos = value; }
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
_pos = 0;
|
||||
}
|
||||
|
||||
// Pre-allocated helper arrays for convertion.
|
||||
private float[] floathelper = new[] { 0.0f };
|
||||
@@ -93,7 +102,6 @@ namespace FlatBuffers
|
||||
_buffer[offset + count - 1 - i] = (byte)(data >> i * 8);
|
||||
}
|
||||
}
|
||||
_pos = offset;
|
||||
}
|
||||
|
||||
protected ulong ReadLittleEndian(int offset, int count)
|
||||
@@ -130,14 +138,18 @@ namespace FlatBuffers
|
||||
{
|
||||
AssertOffsetAndLength(offset, sizeof(sbyte));
|
||||
_buffer[offset] = (byte)value;
|
||||
_pos = offset;
|
||||
}
|
||||
|
||||
public void PutByte(int offset, byte value)
|
||||
{
|
||||
AssertOffsetAndLength(offset, sizeof(byte));
|
||||
_buffer[offset] = value;
|
||||
_pos = offset;
|
||||
}
|
||||
|
||||
// this method exists in order to conform with Java ByteBuffer standards
|
||||
public void Put(int offset, byte value)
|
||||
{
|
||||
PutByte(offset, value);
|
||||
}
|
||||
|
||||
#if UNSAFE_BYTEBUFFER
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/*
|
||||
/*
|
||||
* Copyright 2014 Google Inc. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@@ -49,8 +49,19 @@ namespace FlatBuffers
|
||||
_bb = new ByteBuffer(new byte[initialSize]);
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
_space = _bb.Length;
|
||||
_bb.Reset();
|
||||
_minAlign = 1;
|
||||
_vtable = null;
|
||||
_objectStart = 0;
|
||||
_vtables = new int[16];
|
||||
_numVtables = 0;
|
||||
_vectorNumElems = 0;
|
||||
}
|
||||
|
||||
public int Offset() { return _bb.Length - _space; }
|
||||
public int Offset { get { return _bb.Length - _space; } }
|
||||
|
||||
public void Pad(int size)
|
||||
{
|
||||
@@ -75,8 +86,7 @@ namespace FlatBuffers
|
||||
|
||||
Buffer.BlockCopy(oldBuf, 0, newBuf, newBufSize - oldBufSize,
|
||||
oldBufSize);
|
||||
|
||||
_bb = new ByteBuffer(newBuf);
|
||||
_bb = new ByteBuffer(newBuf, newBufSize);
|
||||
}
|
||||
|
||||
// Prepare to write an element of `size` after `additional_bytes`
|
||||
@@ -181,10 +191,10 @@ namespace FlatBuffers
|
||||
public void AddOffset(int off)
|
||||
{
|
||||
Prep(sizeof(int), 0); // Ensure alignment is already done.
|
||||
if (off > Offset())
|
||||
if (off > Offset)
|
||||
throw new ArgumentException();
|
||||
|
||||
off = Offset() - off + sizeof(int);
|
||||
off = Offset - off + sizeof(int);
|
||||
PutInt(off);
|
||||
}
|
||||
|
||||
@@ -196,10 +206,10 @@ namespace FlatBuffers
|
||||
Prep(alignment, elemSize * count); // Just in case alignment > int.
|
||||
}
|
||||
|
||||
public int EndVector()
|
||||
public VectorOffset EndVector()
|
||||
{
|
||||
PutInt(_vectorNumElems);
|
||||
return Offset();
|
||||
return new VectorOffset(Offset);
|
||||
}
|
||||
|
||||
public void Nested(int obj)
|
||||
@@ -207,7 +217,7 @@ namespace FlatBuffers
|
||||
// Structs are always stored inline, so need to be created right
|
||||
// where they are used. You'll get this assert if you created it
|
||||
// elsewhere.
|
||||
if (obj != Offset())
|
||||
if (obj != Offset)
|
||||
throw new Exception(
|
||||
"FlatBuffers: struct must be serialized inline.");
|
||||
}
|
||||
@@ -225,7 +235,7 @@ namespace FlatBuffers
|
||||
{
|
||||
NotNested();
|
||||
_vtable = new int[numfields];
|
||||
_objectStart = Offset();
|
||||
_objectStart = Offset;
|
||||
}
|
||||
|
||||
|
||||
@@ -233,7 +243,7 @@ namespace FlatBuffers
|
||||
// buffer.
|
||||
public void Slot(int voffset)
|
||||
{
|
||||
_vtable[voffset] = Offset();
|
||||
_vtable[voffset] = Offset;
|
||||
}
|
||||
|
||||
// Add a scalar to a table at `o` into its vtable, with value `x` and default `d`
|
||||
@@ -250,7 +260,7 @@ namespace FlatBuffers
|
||||
public void AddDouble(int o, double x, double d) { if (x != d) { AddDouble(x); Slot(o); } }
|
||||
public void AddOffset(int o, int x, int d) { if (x != d) { AddOffset(x); Slot(o); } }
|
||||
|
||||
public int CreateString(string s)
|
||||
public StringOffset CreateString(string s)
|
||||
{
|
||||
NotNested();
|
||||
byte[] utf8 = Encoding.UTF8.GetBytes(s);
|
||||
@@ -258,7 +268,7 @@ namespace FlatBuffers
|
||||
StartVector(1, utf8.Length, 1);
|
||||
Buffer.BlockCopy(utf8, 0, _bb.Data, _space -= utf8.Length,
|
||||
utf8.Length);
|
||||
return EndVector();
|
||||
return new StringOffset(EndVector().Value);
|
||||
}
|
||||
|
||||
// Structs are stored inline, so nothing additional is being added.
|
||||
@@ -280,7 +290,7 @@ namespace FlatBuffers
|
||||
"Flatbuffers: calling endObject without a startObject");
|
||||
|
||||
AddInt((int)0);
|
||||
var vtableloc = Offset();
|
||||
var vtableloc = Offset;
|
||||
// Write out the current vtable.
|
||||
for (int i = _vtable.Length - 1; i >= 0 ; i--) {
|
||||
// Offset relative to the start of the table.
|
||||
@@ -333,9 +343,9 @@ namespace FlatBuffers
|
||||
|
||||
_vtables = newvtables;
|
||||
};
|
||||
_vtables[_numVtables++] = Offset();
|
||||
_vtables[_numVtables++] = Offset;
|
||||
// Point table to current vtable.
|
||||
_bb.PutInt(_bb.Length - vtableloc, Offset() - vtableloc);
|
||||
_bb.PutInt(_bb.Length - vtableloc, Offset - vtableloc);
|
||||
}
|
||||
|
||||
_vtable = null;
|
||||
@@ -359,16 +369,17 @@ namespace FlatBuffers
|
||||
{
|
||||
Prep(_minAlign, sizeof(int));
|
||||
AddOffset(rootTable);
|
||||
_bb.Position = _space;
|
||||
}
|
||||
|
||||
public ByteBuffer DataBuffer() { return _bb; }
|
||||
public ByteBuffer DataBuffer { get { return _bb; } }
|
||||
|
||||
// Utility function for copying a byte array that starts at 0.
|
||||
public byte[] SizedByteArray()
|
||||
{
|
||||
var newArray = new byte[_bb.Data.Length - _bb.position()];
|
||||
Buffer.BlockCopy(_bb.Data, _bb.position(), newArray, 0,
|
||||
_bb.Data.Length - _bb.position());
|
||||
var newArray = new byte[_bb.Data.Length - _bb.Position];
|
||||
Buffer.BlockCopy(_bb.Data, _bb.Position, newArray, 0,
|
||||
_bb.Data.Length - _bb.Position);
|
||||
return newArray;
|
||||
}
|
||||
|
||||
@@ -387,7 +398,7 @@ namespace FlatBuffers
|
||||
{
|
||||
AddByte((byte)fileIdentifier[i]);
|
||||
}
|
||||
AddOffset(rootTable);
|
||||
Finish(rootTable);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
<Compile Include="ByteBuffer.cs" />
|
||||
<Compile Include="FlatBufferBuilder.cs" />
|
||||
<Compile Include="FlatBufferConstants.cs" />
|
||||
<Compile Include="Offset.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Struct.cs" />
|
||||
<Compile Include="Table.cs" />
|
||||
|
||||
48
net/FlatBuffers/Offset.cs
Normal file
48
net/FlatBuffers/Offset.cs
Normal file
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright 2014 Google Inc. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
namespace FlatBuffers
|
||||
{
|
||||
/// <summary>
|
||||
/// Offset class for typesafe assignments.
|
||||
/// </summary>
|
||||
public struct Offset<T> where T : class
|
||||
{
|
||||
public int Value;
|
||||
public Offset(int value)
|
||||
{
|
||||
Value = value;
|
||||
}
|
||||
}
|
||||
|
||||
public struct StringOffset
|
||||
{
|
||||
public int Value;
|
||||
public StringOffset(int value)
|
||||
{
|
||||
Value = value;
|
||||
}
|
||||
}
|
||||
|
||||
public struct VectorOffset
|
||||
{
|
||||
public int Value;
|
||||
public VectorOffset(int value)
|
||||
{
|
||||
Value = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -66,7 +66,7 @@ namespace FlatBuffers
|
||||
}
|
||||
|
||||
// Initialize any Table-derived type to point to the union at the given offset.
|
||||
protected Table __union(Table t, int offset)
|
||||
protected TTable __union<TTable>(TTable t, int offset) where TTable : Table
|
||||
{
|
||||
offset += bb_pos;
|
||||
t.bb_pos = offset + bb.GetInt(offset);
|
||||
@@ -81,7 +81,7 @@ namespace FlatBuffers
|
||||
|
||||
for (var i = 0; i < FlatBufferConstants.FileIdentifierLength; i++)
|
||||
{
|
||||
if (ident[i] != (char)bb.Get(bb.position() + sizeof(int) + i)) return false;
|
||||
if (ident[i] != (char)bb.Get(bb.Position + sizeof(int) + i)) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
0
python/__init__.py
Normal file
0
python/__init__.py
Normal file
17
python/flatbuffers/__init__.py
Normal file
17
python/flatbuffers/__init__.py
Normal file
@@ -0,0 +1,17 @@
|
||||
# Copyright 2014 Google Inc. All rights reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from .builder import Builder
|
||||
from .table import Table
|
||||
from .compat import range_func as compat_range
|
||||
558
python/flatbuffers/builder.py
Normal file
558
python/flatbuffers/builder.py
Normal file
@@ -0,0 +1,558 @@
|
||||
# Copyright 2014 Google Inc. All rights reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from . import number_types as N
|
||||
from .number_types import (UOffsetTFlags, SOffsetTFlags, VOffsetTFlags)
|
||||
|
||||
from . import encode
|
||||
from . import packer
|
||||
|
||||
from . import compat
|
||||
from .compat import range_func
|
||||
from .compat import memoryview_type
|
||||
|
||||
|
||||
class OffsetArithmeticError(RuntimeError):
|
||||
"""
|
||||
Error caused by an Offset arithmetic error. Probably caused by bad
|
||||
writing of fields. This is considered an unreachable situation in
|
||||
normal circumstances.
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
class NotInObjectError(RuntimeError):
|
||||
"""
|
||||
Error caused by using a Builder to write Object data when not inside
|
||||
an Object.
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
class ObjectIsNestedError(RuntimeError):
|
||||
"""
|
||||
Error caused by using a Builder to begin an Object when an Object is
|
||||
already being built.
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
class StructIsNotInlineError(RuntimeError):
|
||||
"""
|
||||
Error caused by using a Builder to write a Struct at a location that
|
||||
is not the current Offset.
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
class BuilderSizeError(RuntimeError):
|
||||
"""
|
||||
Error caused by causing a Builder to exceed the hardcoded limit of 2
|
||||
gigabytes.
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
# VtableMetadataFields is the count of metadata fields in each vtable.
|
||||
VtableMetadataFields = 2
|
||||
|
||||
|
||||
class Builder(object):
|
||||
"""
|
||||
A Builder is used to construct one or more FlatBuffers. Typically, Builder
|
||||
objects will be used from code generated by the `flatc` compiler.
|
||||
|
||||
A Builder constructs byte buffers in a last-first manner for simplicity and
|
||||
performance during reading.
|
||||
|
||||
Internally, a Builder is a state machine for creating FlatBuffer objects.
|
||||
|
||||
It holds the following internal state:
|
||||
Bytes: an array of bytes.
|
||||
current_vtable: a list of integers.
|
||||
vtables: a list of vtable entries (i.e. a list of list of integers).
|
||||
"""
|
||||
|
||||
__slots__ = ("Bytes", "current_vtable", "head", "minalign", "objectEnd",
|
||||
"vtables")
|
||||
|
||||
"""
|
||||
Maximum buffer size constant, in bytes.
|
||||
Builder will never allow it's buffer grow over this size.
|
||||
Currently equals 2Gb.
|
||||
"""
|
||||
MAX_BUFFER_SIZE = 2**31
|
||||
|
||||
def __init__(self, initialSize):
|
||||
"""
|
||||
Initializes a Builder of size `initial_size`.
|
||||
The internal buffer is grown as needed.
|
||||
"""
|
||||
|
||||
if not (0 <= initialSize <= Builder.MAX_BUFFER_SIZE):
|
||||
msg = "flatbuffers: Cannot create Builder larger than 2 gigabytes."
|
||||
raise BuilderSizeError(msg)
|
||||
|
||||
self.Bytes = bytearray(initialSize)
|
||||
self.current_vtable = None
|
||||
self.head = UOffsetTFlags.py_type(initialSize)
|
||||
self.minalign = 1
|
||||
self.objectEnd = None
|
||||
self.vtables = []
|
||||
|
||||
def Output(self):
|
||||
"""
|
||||
Output returns the portion of the buffer that has been used for
|
||||
writing data.
|
||||
"""
|
||||
|
||||
return self.Bytes[self.Head():]
|
||||
|
||||
def StartObject(self, numfields):
|
||||
"""StartObject initializes bookkeeping for writing a new object."""
|
||||
|
||||
self.assertNotNested()
|
||||
|
||||
# use 32-bit offsets so that arithmetic doesn't overflow.
|
||||
self.current_vtable = [0 for _ in range_func(numfields)]
|
||||
self.objectEnd = self.Offset()
|
||||
self.minalign = 1
|
||||
|
||||
def WriteVtable(self):
|
||||
"""
|
||||
WriteVtable serializes the vtable for the current object, if needed.
|
||||
|
||||
Before writing out the vtable, this checks pre-existing vtables for
|
||||
equality to this one. If an equal vtable is found, point the object to
|
||||
the existing vtable and return.
|
||||
|
||||
Because vtable values are sensitive to alignment of object data, not
|
||||
all logically-equal vtables will be deduplicated.
|
||||
|
||||
A vtable has the following format:
|
||||
<VOffsetT: size of the vtable in bytes, including this value>
|
||||
<VOffsetT: size of the object in bytes, including the vtable offset>
|
||||
<VOffsetT: offset for a field> * N, where N is the number of fields
|
||||
in the schema for this type. Includes deprecated fields.
|
||||
Thus, a vtable is made of 2 + N elements, each VOffsetT bytes wide.
|
||||
|
||||
An object has the following format:
|
||||
<SOffsetT: offset to this object's vtable (may be negative)>
|
||||
<byte: data>+
|
||||
"""
|
||||
|
||||
# Prepend a zero scalar to the object. Later in this function we'll
|
||||
# write an offset here that points to the object's vtable:
|
||||
self.PrependSOffsetTRelative(0)
|
||||
|
||||
objectOffset = self.Offset()
|
||||
existingVtable = None
|
||||
|
||||
# Search backwards through existing vtables, because similar vtables
|
||||
# are likely to have been recently appended. See
|
||||
# BenchmarkVtableDeduplication for a case in which this heuristic
|
||||
# saves about 30% of the time used in writing objects with duplicate
|
||||
# tables.
|
||||
|
||||
i = len(self.vtables) - 1
|
||||
while i >= 0:
|
||||
# Find the other vtable, which is associated with `i`:
|
||||
vt2Offset = self.vtables[i]
|
||||
vt2Start = len(self.Bytes) - vt2Offset
|
||||
vt2Len = encode.Get(packer.voffset, self.Bytes, vt2Start)
|
||||
|
||||
metadata = VtableMetadataFields * N.VOffsetTFlags.bytewidth
|
||||
vt2End = vt2Start + vt2Len
|
||||
vt2 = self.Bytes[vt2Start+metadata:vt2End]
|
||||
|
||||
# Compare the other vtable to the one under consideration.
|
||||
# If they are equal, store the offset and break:
|
||||
if vtableEqual(self.current_vtable, objectOffset, vt2):
|
||||
existingVtable = vt2Offset
|
||||
break
|
||||
|
||||
i -= 1
|
||||
|
||||
if existingVtable is None:
|
||||
# Did not find a vtable, so write this one to the buffer.
|
||||
|
||||
# Write out the current vtable in reverse , because
|
||||
# serialization occurs in last-first order:
|
||||
i = len(self.current_vtable) - 1
|
||||
while i >= 0:
|
||||
off = 0
|
||||
if self.current_vtable[i] != 0:
|
||||
# Forward reference to field;
|
||||
# use 32bit number to ensure no overflow:
|
||||
off = objectOffset - self.current_vtable[i]
|
||||
|
||||
self.PrependVOffsetT(off)
|
||||
i -= 1
|
||||
|
||||
# The two metadata fields are written last.
|
||||
|
||||
# First, store the object bytesize:
|
||||
objectSize = UOffsetTFlags.py_type(objectOffset - self.objectEnd)
|
||||
self.PrependVOffsetT(VOffsetTFlags.py_type(objectSize))
|
||||
|
||||
# Second, store the vtable bytesize:
|
||||
vBytes = len(self.current_vtable) + VtableMetadataFields
|
||||
vBytes *= N.VOffsetTFlags.bytewidth
|
||||
self.PrependVOffsetT(VOffsetTFlags.py_type(vBytes))
|
||||
|
||||
# Next, write the offset to the new vtable in the
|
||||
# already-allocated SOffsetT at the beginning of this object:
|
||||
objectStart = SOffsetTFlags.py_type(len(self.Bytes) - objectOffset)
|
||||
encode.Write(packer.soffset, self.Bytes, objectStart,
|
||||
SOffsetTFlags.py_type(self.Offset() - objectOffset))
|
||||
|
||||
# Finally, store this vtable in memory for future
|
||||
# deduplication:
|
||||
self.vtables.append(self.Offset())
|
||||
else:
|
||||
# Found a duplicate vtable.
|
||||
|
||||
objectStart = SOffsetTFlags.py_type(len(self.Bytes) - objectOffset)
|
||||
self.head = UOffsetTFlags.py_type(objectStart)
|
||||
|
||||
# Write the offset to the found vtable in the
|
||||
# already-allocated SOffsetT at the beginning of this object:
|
||||
encode.Write(packer.soffset, self.Bytes, self.Head(),
|
||||
SOffsetTFlags.py_type(existingVtable - objectOffset))
|
||||
|
||||
self.current_vtable = None
|
||||
return objectOffset
|
||||
|
||||
def EndObject(self):
|
||||
"""EndObject writes data necessary to finish object construction."""
|
||||
if self.current_vtable is None:
|
||||
msg = ("flatbuffers: Tried to write the end of an Object when "
|
||||
"the Builder was not currently writing an Object.")
|
||||
raise NotInObjectError(msg)
|
||||
return self.WriteVtable()
|
||||
|
||||
def growByteBuffer(self):
|
||||
"""Doubles the size of the byteslice, and copies the old data towards
|
||||
the end of the new buffer (since we build the buffer backwards)."""
|
||||
if len(self.Bytes) == Builder.MAX_BUFFER_SIZE:
|
||||
msg = "flatbuffers: cannot grow buffer beyond 2 gigabytes"
|
||||
raise BuilderSizeError(msg)
|
||||
|
||||
newSize = min(len(self.Bytes) * 2, Builder.MAX_BUFFER_SIZE)
|
||||
if newSize == 0:
|
||||
newSize = 1
|
||||
bytes2 = bytearray(newSize)
|
||||
bytes2[newSize-len(self.Bytes):] = self.Bytes
|
||||
self.Bytes = bytes2
|
||||
|
||||
def Head(self):
|
||||
"""
|
||||
Head gives the start of useful data in the underlying byte buffer.
|
||||
Note: unlike other functions, this value is interpreted as from the left.
|
||||
"""
|
||||
return self.head
|
||||
|
||||
def Offset(self):
|
||||
"""Offset relative to the end of the buffer."""
|
||||
return UOffsetTFlags.py_type(len(self.Bytes) - self.Head())
|
||||
|
||||
def Pad(self, n):
|
||||
"""Pad places zeros at the current offset."""
|
||||
for i in range_func(n):
|
||||
self.Place(0, N.Uint8Flags)
|
||||
|
||||
def Prep(self, size, additionalBytes):
|
||||
"""
|
||||
Prep prepares to write an element of `size` after `additional_bytes`
|
||||
have been written, e.g. if you write a string, you need to align
|
||||
such the int length field is aligned to SizeInt32, and the string
|
||||
data follows it directly.
|
||||
If all you need to do is align, `additionalBytes` will be 0.
|
||||
"""
|
||||
|
||||
# Track the biggest thing we've ever aligned to.
|
||||
if size > self.minalign:
|
||||
self.minalign = size
|
||||
|
||||
# Find the amount of alignment needed such that `size` is properly
|
||||
# aligned after `additionalBytes`:
|
||||
alignSize = (~(len(self.Bytes) - self.Head() + additionalBytes)) + 1
|
||||
alignSize &= (size - 1)
|
||||
|
||||
# Reallocate the buffer if needed:
|
||||
while self.Head() < alignSize+size+additionalBytes:
|
||||
oldBufSize = len(self.Bytes)
|
||||
self.growByteBuffer()
|
||||
updated_head = self.head + len(self.Bytes) - oldBufSize
|
||||
self.head = UOffsetTFlags.py_type(updated_head)
|
||||
self.Pad(alignSize)
|
||||
|
||||
def PrependSOffsetTRelative(self, off):
|
||||
"""
|
||||
PrependSOffsetTRelative prepends an SOffsetT, relative to where it
|
||||
will be written.
|
||||
"""
|
||||
|
||||
# Ensure alignment is already done:
|
||||
self.Prep(N.SOffsetTFlags.bytewidth, 0)
|
||||
if not (off <= self.Offset()):
|
||||
msg = "flatbuffers: Offset arithmetic error."
|
||||
raise OffsetArithmeticError(msg)
|
||||
off2 = self.Offset() - off + N.SOffsetTFlags.bytewidth
|
||||
self.PlaceSOffsetT(off2)
|
||||
|
||||
def PrependUOffsetTRelative(self, off):
|
||||
"""
|
||||
PrependUOffsetTRelative prepends an UOffsetT, relative to where it
|
||||
will be written.
|
||||
"""
|
||||
|
||||
# Ensure alignment is already done:
|
||||
self.Prep(N.UOffsetTFlags.bytewidth, 0)
|
||||
if not (off <= self.Offset()):
|
||||
msg = "flatbuffers: Offset arithmetic error."
|
||||
raise OffsetArithmeticError(msg)
|
||||
off2 = self.Offset() - off + N.UOffsetTFlags.bytewidth
|
||||
self.PlaceUOffsetT(off2)
|
||||
|
||||
def StartVector(self, elemSize, numElems, alignment):
|
||||
"""
|
||||
StartVector initializes bookkeeping for writing a new vector.
|
||||
|
||||
A vector has the following format:
|
||||
<UOffsetT: number of elements in this vector>
|
||||
<T: data>+, where T is the type of elements of this vector.
|
||||
"""
|
||||
|
||||
self.assertNotNested()
|
||||
self.Prep(N.Uint32Flags.bytewidth, elemSize*numElems)
|
||||
self.Prep(alignment, elemSize*numElems) # In case alignment > int.
|
||||
return self.Offset()
|
||||
|
||||
def EndVector(self, vectorNumElems):
|
||||
"""EndVector writes data necessary to finish vector construction."""
|
||||
|
||||
# we already made space for this, so write without PrependUint32
|
||||
self.PlaceUOffsetT(vectorNumElems)
|
||||
return self.Offset()
|
||||
|
||||
def CreateString(self, s):
|
||||
"""CreateString writes a null-terminated byte string as a vector."""
|
||||
|
||||
self.assertNotNested()
|
||||
|
||||
if isinstance(s, compat.string_types):
|
||||
x = s.encode()
|
||||
elif isinstance(s, compat.binary_type):
|
||||
x = s
|
||||
else:
|
||||
raise TypeError("non-string passed to CreateString")
|
||||
|
||||
self.Prep(N.UOffsetTFlags.bytewidth, (len(x)+1)*N.Uint8Flags.bytewidth)
|
||||
self.Place(0, N.Uint8Flags)
|
||||
|
||||
l = UOffsetTFlags.py_type(len(s))
|
||||
|
||||
self.head = UOffsetTFlags.py_type(self.Head() - l)
|
||||
self.Bytes[self.Head():self.Head()+l] = x
|
||||
|
||||
return self.EndVector(len(x))
|
||||
|
||||
def assertNotNested(self):
|
||||
"""
|
||||
Check that no other objects are being built while making this
|
||||
object. If not, raise an exception.
|
||||
"""
|
||||
|
||||
if self.current_vtable is not None:
|
||||
msg = ("flatbuffers: Tried to write a new Object when the "
|
||||
"Builder was already writing an Object.")
|
||||
raise ObjectIsNestedError(msg)
|
||||
|
||||
def assertNested(self, obj):
|
||||
"""
|
||||
Structs are always stored inline, so need to be created right
|
||||
where they are used. You'll get this error if you created it
|
||||
elsewhere.
|
||||
"""
|
||||
|
||||
N.enforce_number(obj, N.UOffsetTFlags)
|
||||
if obj != self.Offset():
|
||||
msg = ("flatbuffers: Tried to write a Struct at an Offset that "
|
||||
"is different from the current Offset of the Builder.")
|
||||
raise StructIsNotInlineError(msg)
|
||||
|
||||
def Slot(self, slotnum):
|
||||
"""
|
||||
Slot sets the vtable key `voffset` to the current location in the
|
||||
buffer.
|
||||
|
||||
"""
|
||||
if self.current_vtable is None:
|
||||
msg = ("flatbuffers: Tried to write an Object field when "
|
||||
"the Builder was not currently writing an Object.")
|
||||
raise NotInObjectError(msg)
|
||||
|
||||
self.current_vtable[slotnum] = self.Offset()
|
||||
|
||||
def Finish(self, rootTable):
|
||||
"""Finish finalizes a buffer, pointing to the given `rootTable`."""
|
||||
N.enforce_number(rootTable, N.UOffsetTFlags)
|
||||
self.Prep(self.minalign, N.UOffsetTFlags.bytewidth)
|
||||
self.PrependUOffsetTRelative(rootTable)
|
||||
return self.Head()
|
||||
|
||||
def Prepend(self, flags, off):
|
||||
self.Prep(flags.bytewidth, 0)
|
||||
self.Place(off, flags)
|
||||
|
||||
def PrependSlot(self, flags, o, x, d):
|
||||
N.enforce_number(x, flags)
|
||||
N.enforce_number(d, flags)
|
||||
if x != d:
|
||||
self.Prepend(flags, x)
|
||||
self.Slot(o)
|
||||
|
||||
def PrependBoolSlot(self, *args): self.PrependSlot(N.BoolFlags, *args)
|
||||
|
||||
def PrependByteSlot(self, *args): self.PrependSlot(N.Uint8Flags, *args)
|
||||
|
||||
def PrependUint8Slot(self, *args): self.PrependSlot(N.Uint8Flags, *args)
|
||||
|
||||
def PrependUint16Slot(self, *args): self.PrependSlot(N.Uint16Flags, *args)
|
||||
|
||||
def PrependUint32Slot(self, *args): self.PrependSlot(N.Uint32Flags, *args)
|
||||
|
||||
def PrependUint64Slot(self, *args): self.PrependSlot(N.Uint64Flags, *args)
|
||||
|
||||
def PrependInt8Slot(self, *args): self.PrependSlot(N.Int8Flags, *args)
|
||||
|
||||
def PrependInt16Slot(self, *args): self.PrependSlot(N.Int16Flags, *args)
|
||||
|
||||
def PrependInt32Slot(self, *args): self.PrependSlot(N.Int32Flags, *args)
|
||||
|
||||
def PrependInt64Slot(self, *args): self.PrependSlot(N.Int64Flags, *args)
|
||||
|
||||
def PrependFloat32Slot(self, *args): self.PrependSlot(N.Float32Flags,
|
||||
*args)
|
||||
|
||||
def PrependFloat64Slot(self, *args): self.PrependSlot(N.Float64Flags,
|
||||
*args)
|
||||
|
||||
def PrependUOffsetTRelativeSlot(self, o, x, d):
|
||||
"""
|
||||
PrependUOffsetTRelativeSlot prepends an UOffsetT onto the object at
|
||||
vtable slot `o`. If value `x` equals default `d`, then the slot will
|
||||
be set to zero and no other data will be written.
|
||||
"""
|
||||
|
||||
if x != d:
|
||||
self.PrependUOffsetTRelative(x)
|
||||
self.Slot(o)
|
||||
|
||||
def PrependStructSlot(self, v, x, d):
|
||||
"""
|
||||
PrependStructSlot prepends a struct onto the object at vtable slot `o`.
|
||||
Structs are stored inline, so nothing additional is being added.
|
||||
In generated code, `d` is always 0.
|
||||
"""
|
||||
|
||||
N.enforce_number(d, N.UOffsetTFlags)
|
||||
if x != d:
|
||||
self.assertNested(x)
|
||||
self.Slot(v)
|
||||
|
||||
def PrependBool(self, x): self.Prepend(N.BoolFlags, x)
|
||||
|
||||
def PrependByte(self, x): self.Prepend(N.Uint8Flags, x)
|
||||
|
||||
def PrependUint8(self, x): self.Prepend(N.Uint8Flags, x)
|
||||
|
||||
def PrependUint16(self, x): self.Prepend(N.Uint16Flags, x)
|
||||
|
||||
def PrependUint32(self, x): self.Prepend(N.Uint32Flags, x)
|
||||
|
||||
def PrependUint64(self, x): self.Prepend(N.Uint64Flags, x)
|
||||
|
||||
def PrependInt8(self, x): self.Prepend(N.Int8Flags, x)
|
||||
|
||||
def PrependInt16(self, x): self.Prepend(N.Int16Flags, x)
|
||||
|
||||
def PrependInt32(self, x): self.Prepend(N.Int32Flags, x)
|
||||
|
||||
def PrependInt64(self, x): self.Prepend(N.Int64Flags, x)
|
||||
|
||||
def PrependFloat32(self, x): self.Prepend(N.Float32Flags, x)
|
||||
|
||||
def PrependFloat64(self, x): self.Prepend(N.Float64Flags, x)
|
||||
|
||||
def PrependVOffsetT(self, x): self.Prepend(N.VOffsetTFlags, x)
|
||||
|
||||
def Place(self, x, flags):
|
||||
"""
|
||||
Place prepends a value specified by `flags` to the Builder,
|
||||
without checking for available space.
|
||||
"""
|
||||
|
||||
N.enforce_number(x, flags)
|
||||
self.head = self.head - flags.bytewidth
|
||||
encode.Write(flags.packer_type, self.Bytes, self.Head(), x)
|
||||
|
||||
def PlaceVOffsetT(self, x):
|
||||
"""
|
||||
PlaceVOffsetT prepends a VOffsetT to the Builder, without checking for
|
||||
space.
|
||||
"""
|
||||
N.enforce_number(x, N.VOffsetTFlags)
|
||||
self.head = self.head - N.VOffsetTFlags.bytewidth
|
||||
encode.Write(packer.voffset, self.Bytes, self.Head(), x)
|
||||
|
||||
def PlaceSOffsetT(self, x):
|
||||
"""
|
||||
PlaceSOffsetT prepends a SOffsetT to the Builder, without checking for
|
||||
space.
|
||||
"""
|
||||
N.enforce_number(x, N.SOffsetTFlags)
|
||||
self.head = self.head - N.SOffsetTFlags.bytewidth
|
||||
encode.Write(packer.soffset, self.Bytes, self.Head(), x)
|
||||
|
||||
def PlaceUOffsetT(self, x):
|
||||
"""
|
||||
PlaceUOffsetT prepends a UOffsetT to the Builder, without checking for
|
||||
space.
|
||||
"""
|
||||
N.enforce_number(x, N.UOffsetTFlags)
|
||||
self.head = self.head - N.UOffsetTFlags.bytewidth
|
||||
encode.Write(packer.uoffset, self.Bytes, self.Head(), x)
|
||||
|
||||
|
||||
def vtableEqual(a, objectStart, b):
|
||||
"""vtableEqual compares an unwritten vtable to a written vtable."""
|
||||
|
||||
N.enforce_number(objectStart, N.UOffsetTFlags)
|
||||
|
||||
if len(a) * N.VOffsetTFlags.bytewidth != len(b):
|
||||
return False
|
||||
|
||||
for i, elem in enumerate(a):
|
||||
x = encode.Get(packer.voffset, b, i * N.VOffsetTFlags.bytewidth)
|
||||
|
||||
# Skip vtable entries that indicate a default value.
|
||||
if x == 0 and elem == 0:
|
||||
pass
|
||||
else:
|
||||
y = objectStart - elem
|
||||
if x != y:
|
||||
return False
|
||||
return True
|
||||
27
python/flatbuffers/compat.py
Normal file
27
python/flatbuffers/compat.py
Normal file
@@ -0,0 +1,27 @@
|
||||
""" A tiny version of `six` to help with backwards compability. """
|
||||
|
||||
import sys
|
||||
|
||||
PY2 = sys.version_info[0] == 2
|
||||
PY26 = sys.version_info[0:2] == (2, 6)
|
||||
PY3 = sys.version_info[0] == 3
|
||||
PY34 = sys.version_info[0:2] >= (3, 4)
|
||||
|
||||
if PY3:
|
||||
string_types = (str,)
|
||||
binary_type = bytes
|
||||
range_func = range
|
||||
memoryview_type = memoryview
|
||||
struct_bool_decl = "?"
|
||||
else:
|
||||
string_types = (basestring,)
|
||||
binary_type = str
|
||||
range_func = xrange
|
||||
if PY26:
|
||||
memoryview_type = buffer
|
||||
struct_bool_decl = "<b"
|
||||
else:
|
||||
memoryview_type = memoryview
|
||||
struct_bool_decl = "?"
|
||||
|
||||
# NOTE: Future Jython support may require code here (look at `six`).
|
||||
29
python/flatbuffers/encode.py
Normal file
29
python/flatbuffers/encode.py
Normal file
@@ -0,0 +1,29 @@
|
||||
# Copyright 2014 Google Inc. All rights reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import ctypes
|
||||
|
||||
from . import number_types as N
|
||||
from . import packer
|
||||
from .compat import memoryview_type
|
||||
|
||||
|
||||
def Get(packer_type, buf, head):
|
||||
""" Get decodes a value at buf[head:] using `packer_type`. """
|
||||
return packer_type.unpack_from(memoryview_type(buf), head)[0]
|
||||
|
||||
|
||||
def Write(packer_type, buf, head, n):
|
||||
""" Write encodes `n` at buf[head:] using `packer_type`. """
|
||||
packer_type.pack_into(buf, head, n)
|
||||
174
python/flatbuffers/number_types.py
Normal file
174
python/flatbuffers/number_types.py
Normal file
@@ -0,0 +1,174 @@
|
||||
# Copyright 2014 Google Inc. All rights reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import ctypes
|
||||
import collections
|
||||
import struct
|
||||
from ctypes import sizeof
|
||||
|
||||
from . import packer
|
||||
|
||||
|
||||
# For reference, see:
|
||||
# https://docs.python.org/2/library/ctypes.html#ctypes-fundamental-data-types-2
|
||||
|
||||
# These classes could be collections.namedtuple instances, but those are new
|
||||
# in 2.6 and we want to work towards 2.5 compatability.
|
||||
|
||||
class BoolFlags(object):
|
||||
bytewidth = 1
|
||||
min_val = False
|
||||
max_val = True
|
||||
py_type = bool
|
||||
name = "bool"
|
||||
packer_type = packer.boolean
|
||||
|
||||
|
||||
class Uint8Flags(object):
|
||||
bytewidth = 1
|
||||
min_val = 0
|
||||
max_val = (2**8) - 1
|
||||
py_type = int
|
||||
name = "uint8"
|
||||
packer_type = packer.uint8
|
||||
|
||||
|
||||
class Uint16Flags(object):
|
||||
bytewidth = 2
|
||||
min_val = 0
|
||||
max_val = (2**16) - 1
|
||||
py_type = int
|
||||
name = "uint16"
|
||||
packer_type = packer.uint16
|
||||
|
||||
|
||||
class Uint32Flags(object):
|
||||
bytewidth = 4
|
||||
min_val = 0
|
||||
max_val = (2**32) - 1
|
||||
py_type = int
|
||||
name = "uint32"
|
||||
packer_type = packer.uint32
|
||||
|
||||
|
||||
class Uint64Flags(object):
|
||||
bytewidth = 8
|
||||
min_val = 0
|
||||
max_val = (2**64) - 1
|
||||
py_type = int
|
||||
name = "uint64"
|
||||
packer_type = packer.uint64
|
||||
|
||||
|
||||
class Int8Flags(object):
|
||||
bytewidth = 1
|
||||
min_val = -(2**7)
|
||||
max_val = (2**7) - 1
|
||||
py_type = int
|
||||
name = "int8"
|
||||
packer_type = packer.int8
|
||||
|
||||
|
||||
class Int16Flags(object):
|
||||
bytewidth = 2
|
||||
min_val = -(2**15)
|
||||
max_val = (2**15) - 1
|
||||
py_type = int
|
||||
name = "int16"
|
||||
packer_type = packer.int16
|
||||
|
||||
|
||||
class Int32Flags(object):
|
||||
bytewidth = 4
|
||||
min_val = -(2**31)
|
||||
max_val = (2**31) - 1
|
||||
py_type = int
|
||||
name = "int32"
|
||||
packer_type = packer.int32
|
||||
|
||||
|
||||
class Int64Flags(object):
|
||||
bytewidth = 8
|
||||
min_val = -(2**63)
|
||||
max_val = (2**63) - 1
|
||||
py_type = int
|
||||
name = "int64"
|
||||
packer_type = packer.int64
|
||||
|
||||
|
||||
class Float32Flags(object):
|
||||
bytewidth = 4
|
||||
min_val = None
|
||||
max_val = None
|
||||
py_type = float
|
||||
name = "float32"
|
||||
packer_type = packer.float32
|
||||
|
||||
|
||||
class Float64Flags(object):
|
||||
bytewidth = 8
|
||||
min_val = None
|
||||
max_val = None
|
||||
py_type = float
|
||||
name = "float64"
|
||||
packer_type = packer.float64
|
||||
|
||||
|
||||
class SOffsetTFlags(Int32Flags):
|
||||
pass
|
||||
|
||||
|
||||
class UOffsetTFlags(Uint32Flags):
|
||||
pass
|
||||
|
||||
|
||||
class VOffsetTFlags(Uint16Flags):
|
||||
pass
|
||||
|
||||
|
||||
def valid_number(n, flags):
|
||||
if flags.min_val is None and flags.max_val is None:
|
||||
return True
|
||||
return flags.min_val <= n <= flags.max_val
|
||||
|
||||
|
||||
def enforce_number(n, flags):
|
||||
if flags.min_val is None and flags.max_val is None:
|
||||
return
|
||||
if not flags.min_val <= n <= flags.max_val:
|
||||
raise TypeError("bad number %s for type %s" % (str(n), flags.name))
|
||||
|
||||
|
||||
def float32_to_uint32(n):
|
||||
packed = struct.pack("<1f", n)
|
||||
(converted,) = struct.unpack("<1L", packed)
|
||||
return converted
|
||||
|
||||
|
||||
def uint32_to_float32(n):
|
||||
packed = struct.pack("<1L", n)
|
||||
(unpacked,) = struct.unpack("<1f", packed)
|
||||
return unpacked
|
||||
|
||||
|
||||
def float64_to_uint64(n):
|
||||
packed = struct.pack("<1d", n)
|
||||
(converted,) = struct.unpack("<1Q", packed)
|
||||
return converted
|
||||
|
||||
|
||||
def uint64_to_float64(n):
|
||||
packed = struct.pack("<1Q", n)
|
||||
(unpacked,) = struct.unpack("<1d", packed)
|
||||
return unpacked
|
||||
28
python/flatbuffers/packer.py
Normal file
28
python/flatbuffers/packer.py
Normal file
@@ -0,0 +1,28 @@
|
||||
"""
|
||||
Provide pre-compiled struct packers for encoding and decoding.
|
||||
|
||||
See: https://docs.python.org/2/library/struct.html#format-characters
|
||||
"""
|
||||
|
||||
import struct
|
||||
from . import compat
|
||||
|
||||
|
||||
boolean = struct.Struct(compat.struct_bool_decl)
|
||||
|
||||
uint8 = struct.Struct("<B")
|
||||
uint16 = struct.Struct("<H")
|
||||
uint32 = struct.Struct("<I")
|
||||
uint64 = struct.Struct("<Q")
|
||||
|
||||
int8 = struct.Struct("<b")
|
||||
int16 = struct.Struct("<h")
|
||||
int32 = struct.Struct("<i")
|
||||
int64 = struct.Struct("<q")
|
||||
|
||||
float32 = struct.Struct("<f")
|
||||
float64 = struct.Struct("<d")
|
||||
|
||||
uoffset = uint32
|
||||
soffset = int32
|
||||
voffset = uint16
|
||||
117
python/flatbuffers/table.py
Normal file
117
python/flatbuffers/table.py
Normal file
@@ -0,0 +1,117 @@
|
||||
# Copyright 2014 Google Inc. All rights reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from . import encode
|
||||
from . import number_types as N
|
||||
|
||||
|
||||
class Table(object):
|
||||
"""Table wraps a byte slice and provides read access to its data.
|
||||
|
||||
The variable `Pos` indicates the root of the FlatBuffers object therein."""
|
||||
|
||||
__slots__ = ("Bytes", "Pos")
|
||||
|
||||
def __init__(self, buf, pos):
|
||||
N.enforce_number(pos, N.UOffsetTFlags)
|
||||
|
||||
self.Bytes = buf
|
||||
self.Pos = pos
|
||||
|
||||
def Offset(self, vtableOffset):
|
||||
"""Offset provides access into the Table's vtable.
|
||||
|
||||
Deprecated fields are ignored by checking the vtable's length."""
|
||||
|
||||
vtable = self.Pos - self.Get(N.SOffsetTFlags, self.Pos)
|
||||
vtableEnd = self.Get(N.VOffsetTFlags, vtable)
|
||||
if vtableOffset < vtableEnd:
|
||||
return self.Get(N.VOffsetTFlags, vtable + vtableOffset)
|
||||
return 0
|
||||
|
||||
def Indirect(self, off):
|
||||
"""Indirect retrieves the relative offset stored at `offset`."""
|
||||
N.enforce_number(off, N.UOffsetTFlags)
|
||||
return off + encode.Get(N.UOffsetTFlags.packer_type, self.Bytes, off)
|
||||
|
||||
def String(self, off):
|
||||
"""String gets a string from data stored inside the flatbuffer."""
|
||||
N.enforce_number(off, N.UOffsetTFlags)
|
||||
off += encode.Get(N.UOffsetTFlags.packer_type, self.Bytes, off)
|
||||
start = off + N.UOffsetTFlags.bytewidth
|
||||
length = encode.Get(N.UOffsetTFlags.packer_type, self.Bytes, off)
|
||||
return bytes(self.Bytes[start:start+length])
|
||||
|
||||
def VectorLen(self, off):
|
||||
"""VectorLen retrieves the length of the vector whose offset is stored
|
||||
at "off" in this object."""
|
||||
N.enforce_number(off, N.UOffsetTFlags)
|
||||
|
||||
off += self.Pos
|
||||
off += encode.Get(N.UOffsetTFlags.packer_type, self.Bytes, off)
|
||||
ret = encode.Get(N.UOffsetTFlags.packer_type, self.Bytes, off)
|
||||
return ret
|
||||
|
||||
def Vector(self, off):
|
||||
"""Vector retrieves the start of data of the vector whose offset is
|
||||
stored at "off" in this object."""
|
||||
N.enforce_number(off, N.UOffsetTFlags)
|
||||
|
||||
off += self.Pos
|
||||
x = off + self.Get(N.UOffsetTFlags, off)
|
||||
# data starts after metadata containing the vector length
|
||||
x += N.UOffsetTFlags.bytewidth
|
||||
return x
|
||||
|
||||
def Union(self, t2, off):
|
||||
"""Union initializes any Table-derived type to point to the union at
|
||||
the given offset."""
|
||||
assert type(t2) is Table
|
||||
N.enforce_number(off, N.UOffsetTFlags)
|
||||
|
||||
off += self.Pos
|
||||
t2.Pos = off + self.Get(N.UOffsetTFlags, off)
|
||||
t2.Bytes = self.Bytes
|
||||
|
||||
def Get(self, flags, off):
|
||||
"""
|
||||
Get retrieves a value of the type specified by `flags` at the
|
||||
given offset.
|
||||
"""
|
||||
N.enforce_number(off, N.UOffsetTFlags)
|
||||
return flags.py_type(encode.Get(flags.packer_type, self.Bytes, off))
|
||||
|
||||
def GetSlot(self, slot, d, validator_flags):
|
||||
N.enforce_number(slot, N.VOffsetTFlags)
|
||||
if validator_flags is not None:
|
||||
N.enforce_number(d, validator_flags)
|
||||
off = self.Offset(slot)
|
||||
if off == 0:
|
||||
return d
|
||||
return self.Get(validator_flags, self.Pos + off)
|
||||
|
||||
def GetVOffsetTSlot(self, slot, d):
|
||||
"""
|
||||
GetVOffsetTSlot retrieves the VOffsetT that the given vtable location
|
||||
points to. If the vtable value is zero, the default value `d`
|
||||
will be returned.
|
||||
"""
|
||||
|
||||
N.enforce_number(slot, N.VOffsetTFlags)
|
||||
N.enforce_number(d, N.VOffsetTFlags)
|
||||
|
||||
off = self.Offset(slot)
|
||||
if off == 0:
|
||||
return d
|
||||
return off
|
||||
16
python/setup.py
Normal file
16
python/setup.py
Normal file
@@ -0,0 +1,16 @@
|
||||
from setuptools import setup
|
||||
|
||||
setup(
|
||||
name='flatbuffers',
|
||||
version='2015.05.14.0',
|
||||
license='Apache 2.0',
|
||||
author='FlatBuffers Contributors',
|
||||
author_email='me@rwinslow.com',
|
||||
url='https://github.com/google/flatbuffers',
|
||||
long_description=('Python runtime library for use with the Flatbuffers'
|
||||
'serialization format.'),
|
||||
packages=['flatbuffers'],
|
||||
include_package_data=True,
|
||||
requires=[],
|
||||
description='The FlatBuffers serialization format for Python',
|
||||
)
|
||||
@@ -1,7 +1,13 @@
|
||||
FlatBuffers Version 1.0
|
||||
FlatBuffers Version 1.1.0
|
||||
|
||||
# Welcome to FlatBuffers!
|
||||
|
||||
## Build Status
|
||||
|
||||
- Travis: [](https://travis-ci.org/google/flatbuffers)
|
||||
|
||||
----
|
||||
|
||||
FlatBuffers is a serialization library for games and other memory constrained
|
||||
apps. Go to our [landing page][] to browse our documentation.
|
||||
|
||||
|
||||
1
reflection/generate_code.sh
Normal file
1
reflection/generate_code.sh
Normal file
@@ -0,0 +1 @@
|
||||
../flatc -c --no-prefix -o ../include/flatbuffers reflection.fbs
|
||||
81
reflection/reflection.fbs
Normal file
81
reflection/reflection.fbs
Normal file
@@ -0,0 +1,81 @@
|
||||
// This schema defines objects that represent a parsed schema, like
|
||||
// the binary version of a .fbs file.
|
||||
// This could be used to operate on unknown FlatBuffers at runtime.
|
||||
// It can even ... represent itself (!)
|
||||
|
||||
namespace reflection;
|
||||
|
||||
// These must correspond to the enum in idl.h.
|
||||
enum BaseType : byte {
|
||||
None,
|
||||
UType,
|
||||
Bool,
|
||||
Byte,
|
||||
UByte,
|
||||
Short,
|
||||
UShort,
|
||||
Int,
|
||||
UInt,
|
||||
Long,
|
||||
ULong,
|
||||
Float,
|
||||
Double,
|
||||
String,
|
||||
Vector,
|
||||
Obj, // Used for tables & structs.
|
||||
Union
|
||||
}
|
||||
|
||||
table Type {
|
||||
base_type:BaseType;
|
||||
element:BaseType = None; // Only if base_type == Vector.
|
||||
index:int = -1; // If base_type == Object, index into "objects" below.
|
||||
// If base_type == Union, UnionType, or integral derived
|
||||
// from an enum, index into "enums" below.
|
||||
}
|
||||
|
||||
table EnumVal {
|
||||
name:string (required);
|
||||
value:long (key);
|
||||
object:Object; // Only if part of a union.
|
||||
}
|
||||
|
||||
table Enum {
|
||||
name:string (required, key);
|
||||
values:[EnumVal] (required); // In order of their values.
|
||||
is_union:bool = false;
|
||||
underlying_type:Type (required);
|
||||
}
|
||||
|
||||
table Field {
|
||||
name:string (required, key);
|
||||
type:Type (required);
|
||||
id:ushort;
|
||||
offset:ushort; // Offset into the vtable for tables, or into the struct.
|
||||
default_integer:long = 0;
|
||||
default_real:double = 0.0;
|
||||
deprecated:bool = false;
|
||||
required:bool = false;
|
||||
key:bool = false;
|
||||
}
|
||||
|
||||
table Object { // Used for both tables and structs.
|
||||
name:string (required, key);
|
||||
fields:[Field] (required); // Sorted.
|
||||
is_struct:bool = false;
|
||||
minalign:int;
|
||||
bytesize:int; // For structs.
|
||||
}
|
||||
|
||||
table Schema {
|
||||
objects:[Object] (required); // Sorted.
|
||||
enums:[Enum] (required); // Sorted.
|
||||
file_ident:string;
|
||||
file_ext:string;
|
||||
root_table:Object;
|
||||
}
|
||||
|
||||
root_type Schema;
|
||||
|
||||
file_identifier "BFBS";
|
||||
file_extension "bfbs";
|
||||
21
samples/monster_generated.h
Executable file → Normal file
21
samples/monster_generated.h
Executable file → Normal file
@@ -23,7 +23,7 @@ inline const char **EnumNamesColor() {
|
||||
return names;
|
||||
}
|
||||
|
||||
inline const char *EnumNameColor(Color e) { return EnumNamesColor()[e]; }
|
||||
inline const char *EnumNameColor(Color e) { return EnumNamesColor()[static_cast<int>(e)]; }
|
||||
|
||||
enum Any {
|
||||
Any_NONE = 0,
|
||||
@@ -35,7 +35,7 @@ inline const char **EnumNamesAny() {
|
||||
return names;
|
||||
}
|
||||
|
||||
inline const char *EnumNameAny(Any e) { return EnumNamesAny()[e]; }
|
||||
inline const char *EnumNameAny(Any e) { return EnumNamesAny()[static_cast<int>(e)]; }
|
||||
|
||||
inline bool VerifyAny(flatbuffers::Verifier &verifier, const void *union_obj, Any type);
|
||||
|
||||
@@ -50,18 +50,27 @@ MANUALLY_ALIGNED_STRUCT(4) Vec3 FLATBUFFERS_FINAL_CLASS {
|
||||
: x_(flatbuffers::EndianScalar(x)), y_(flatbuffers::EndianScalar(y)), z_(flatbuffers::EndianScalar(z)) { }
|
||||
|
||||
float x() const { return flatbuffers::EndianScalar(x_); }
|
||||
void mutate_x(float x) { flatbuffers::WriteScalar(&x_, x); }
|
||||
float y() const { return flatbuffers::EndianScalar(y_); }
|
||||
void mutate_y(float y) { flatbuffers::WriteScalar(&y_, y); }
|
||||
float z() const { return flatbuffers::EndianScalar(z_); }
|
||||
void mutate_z(float z) { flatbuffers::WriteScalar(&z_, z); }
|
||||
};
|
||||
STRUCT_END(Vec3, 12);
|
||||
|
||||
struct Monster FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
|
||||
const Vec3 *pos() const { return GetStruct<const Vec3 *>(4); }
|
||||
Vec3 *mutable_pos() { return GetStruct<Vec3 *>(4); }
|
||||
int16_t mana() const { return GetField<int16_t>(6, 150); }
|
||||
bool mutate_mana(int16_t mana) { return SetField(6, mana); }
|
||||
int16_t hp() const { return GetField<int16_t>(8, 100); }
|
||||
bool mutate_hp(int16_t hp) { return SetField(8, hp); }
|
||||
const flatbuffers::String *name() const { return GetPointer<const flatbuffers::String *>(10); }
|
||||
flatbuffers::String *mutable_name() { return GetPointer<flatbuffers::String *>(10); }
|
||||
const flatbuffers::Vector<uint8_t> *inventory() const { return GetPointer<const flatbuffers::Vector<uint8_t> *>(14); }
|
||||
flatbuffers::Vector<uint8_t> *mutable_inventory() { return GetPointer<flatbuffers::Vector<uint8_t> *>(14); }
|
||||
Color color() const { return static_cast<Color>(GetField<int8_t>(16, 2)); }
|
||||
bool mutate_color(Color color) { return SetField(16, static_cast<int8_t>(color)); }
|
||||
bool Verify(flatbuffers::Verifier &verifier) const {
|
||||
return VerifyTableStart(verifier) &&
|
||||
VerifyField<Vec3>(verifier, 4 /* pos */) &&
|
||||
@@ -118,11 +127,13 @@ inline bool VerifyAny(flatbuffers::Verifier &verifier, const void *union_obj, An
|
||||
}
|
||||
}
|
||||
|
||||
inline const Monster *GetMonster(const void *buf) { return flatbuffers::GetRoot<Monster>(buf); }
|
||||
inline const MyGame::Sample::Monster *GetMonster(const void *buf) { return flatbuffers::GetRoot<MyGame::Sample::Monster>(buf); }
|
||||
|
||||
inline bool VerifyMonsterBuffer(flatbuffers::Verifier &verifier) { return verifier.VerifyBuffer<Monster>(); }
|
||||
inline Monster *GetMutableMonster(void *buf) { return flatbuffers::GetMutableRoot<Monster>(buf); }
|
||||
|
||||
inline void FinishMonsterBuffer(flatbuffers::FlatBufferBuilder &fbb, flatbuffers::Offset<Monster> root) { fbb.Finish(root); }
|
||||
inline bool VerifyMonsterBuffer(flatbuffers::Verifier &verifier) { return verifier.VerifyBuffer<MyGame::Sample::Monster>(); }
|
||||
|
||||
inline void FinishMonsterBuffer(flatbuffers::FlatBufferBuilder &fbb, flatbuffers::Offset<MyGame::Sample::Monster> root) { fbb.Finish(root); }
|
||||
|
||||
} // namespace Sample
|
||||
} // namespace MyGame
|
||||
|
||||
2
samples/sample_binary.cpp
Executable file → Normal file
2
samples/sample_binary.cpp
Executable file → Normal file
@@ -49,7 +49,7 @@ int main(int /*argc*/, const char * /*argv*/[]) {
|
||||
|
||||
assert(monster->hp() == 80);
|
||||
assert(monster->mana() == 150); // default
|
||||
assert(!strcmp(monster->name()->c_str(), "MyMonster"));
|
||||
assert(monster->name()->str() == "MyMonster");
|
||||
|
||||
auto pos = monster->pos();
|
||||
assert(pos);
|
||||
|
||||
0
samples/sample_text.cpp
Executable file → Normal file
0
samples/sample_text.cpp
Executable file → Normal file
126
src/flatc.cpp
Executable file → Normal file
126
src/flatc.cpp
Executable file → Normal file
@@ -18,8 +18,8 @@
|
||||
#include "flatbuffers/idl.h"
|
||||
#include "flatbuffers/util.h"
|
||||
|
||||
static void Error(const char *err, const char *obj = nullptr,
|
||||
bool usage = false, bool show_exe_name = true);
|
||||
static void Error(const std::string &err, bool usage = false,
|
||||
bool show_exe_name = true);
|
||||
|
||||
// This struct allows us to create a table of all possible output generators
|
||||
// for the various programming languages and formats we support.
|
||||
@@ -60,20 +60,25 @@ const Generator generators[] = {
|
||||
flatbuffers::GeneratorOptions::kJava,
|
||||
"Generate Java classes for tables/structs",
|
||||
flatbuffers::GeneralMakeRule },
|
||||
{ flatbuffers::GenerateJS, "-s", "JavaScript",
|
||||
flatbuffers::GeneratorOptions::kMAX,
|
||||
"Generate JavaScript code for tables/structs",
|
||||
flatbuffers::JSMakeRule },
|
||||
{ flatbuffers::GenerateGeneral, "-n", "C#",
|
||||
flatbuffers::GeneratorOptions::kCSharp,
|
||||
"Generate C# classes for tables/structs",
|
||||
flatbuffers::GeneralMakeRule },
|
||||
{ flatbuffers::GeneratePython, "-p", "Python",
|
||||
flatbuffers::GeneratorOptions::kMAX,
|
||||
"Generate Python files for tables/structs",
|
||||
flatbuffers::GeneralMakeRule },
|
||||
};
|
||||
|
||||
const char *program_name = NULL;
|
||||
|
||||
static void Error(const char *err, const char *obj, bool usage,
|
||||
bool show_exe_name) {
|
||||
static void Error(const std::string &err, bool usage, bool show_exe_name) {
|
||||
if (show_exe_name) printf("%s: ", program_name);
|
||||
printf("%s", err);
|
||||
if (obj) printf(": %s", obj);
|
||||
printf("\n");
|
||||
printf("%s\n", err.c_str());
|
||||
if (usage) {
|
||||
printf("usage: %s [OPTION]... FILE... [-- FILE...]\n", program_name);
|
||||
for (size_t i = 0; i < sizeof(generators) / sizeof(generators[0]); ++i)
|
||||
@@ -86,10 +91,22 @@ static void Error(const char *err, const char *obj, bool usage,
|
||||
" -M Print make rules for generated files.\n"
|
||||
" --strict-json Strict JSON: field names must be / will be quoted,\n"
|
||||
" no trailing commas in tables/vectors.\n"
|
||||
" --defaults-json Output fields whose value is the default when\n"
|
||||
" writing JSON\n"
|
||||
" --no-prefix Don\'t prefix enum values with the enum type in C++.\n"
|
||||
" --gen-includes Generate include statements for included schemas the\n"
|
||||
" generated file depends on (C++).\n"
|
||||
" --scoped-enums Use C++11 style scoped and strongly typed enums.\n"
|
||||
" also implies --no-prefix.\n"
|
||||
" --gen-includes (deprecated), this is the default behavior.\n"
|
||||
" If the original behavior is required (no include\n"
|
||||
" statements) use --no-includes.\n"
|
||||
" --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"
|
||||
" --raw-binary Allow binaries without file_indentifier to be read.\n"
|
||||
" This may crash flatc given a mismatched schema.\n"
|
||||
" --proto Input is a .proto, translate to .fbs.\n"
|
||||
" --schema Serialize schemas instead of JSON (use with -b)\n"
|
||||
"FILEs may depend on declarations in earlier files.\n"
|
||||
"FILEs after the -- must be binary flatbuffer format files.\n"
|
||||
"Output files are named using the base file name of the input,\n"
|
||||
@@ -109,43 +126,62 @@ int main(int argc, const char *argv[]) {
|
||||
bool any_generator = false;
|
||||
bool print_make_rules = false;
|
||||
bool proto_mode = false;
|
||||
bool raw_binary = false;
|
||||
bool schema_binary = false;
|
||||
std::vector<std::string> filenames;
|
||||
std::vector<const char *> include_directories;
|
||||
size_t binary_files_from = std::numeric_limits<size_t>::max();
|
||||
for (int argi = 1; argi < argc; argi++) {
|
||||
const char *arg = argv[argi];
|
||||
std::string arg = argv[argi];
|
||||
if (arg[0] == '-') {
|
||||
if (filenames.size() && arg[1] != '-')
|
||||
Error("invalid option location", arg, true);
|
||||
std::string opt = arg;
|
||||
if (opt == "-o") {
|
||||
if (++argi >= argc) Error("missing path following", arg, true);
|
||||
Error("invalid option location: " + arg, true);
|
||||
if (arg == "-o") {
|
||||
if (++argi >= argc) Error("missing path following: " + arg, true);
|
||||
output_path = flatbuffers::ConCatPathFileName(argv[argi], "");
|
||||
} else if(opt == "-I") {
|
||||
if (++argi >= argc) Error("missing path following", arg, true);
|
||||
} else if(arg == "-I") {
|
||||
if (++argi >= argc) Error("missing path following" + arg, true);
|
||||
include_directories.push_back(argv[argi]);
|
||||
} else if(opt == "--strict-json") {
|
||||
} else if(arg == "--strict-json") {
|
||||
opts.strict_json = true;
|
||||
} else if(opt == "--no-prefix") {
|
||||
} else if(arg == "--no-js-exports") {
|
||||
opts.skip_js_exports = true;
|
||||
} else if(arg == "--defaults-json") {
|
||||
opts.output_default_scalars_in_json = true;
|
||||
} else if(arg == "--no-prefix") {
|
||||
opts.prefixed_enums = false;
|
||||
} else if(opt == "--gen-includes") {
|
||||
opts.include_dependence_headers = true;
|
||||
} else if(opt == "--") { // Separator between text and binary inputs.
|
||||
} else if(arg == "--scoped-enums") {
|
||||
opts.prefixed_enums = false;
|
||||
opts.scoped_enums = true;
|
||||
} else if(arg == "--gen-mutable") {
|
||||
opts.mutable_buffer = true;
|
||||
} else if(arg == "--gen-includes") {
|
||||
// Deprecated, remove this option some time in the future.
|
||||
printf("warning: --gen-includes is deprecated (it is now default)\n");
|
||||
} else if(arg == "--no-includes") {
|
||||
opts.include_dependence_headers = false;
|
||||
} else if (arg == "--gen-onefile") {
|
||||
opts.one_file = true;
|
||||
} else if (arg == "--raw-binary") {
|
||||
raw_binary = true;
|
||||
} else if(arg == "--") { // Separator between text and binary inputs.
|
||||
binary_files_from = filenames.size();
|
||||
} else if(opt == "--proto") {
|
||||
} else if(arg == "--proto") {
|
||||
proto_mode = true;
|
||||
any_generator = true;
|
||||
} else if(opt == "-M") {
|
||||
} else if(arg == "--schema") {
|
||||
schema_binary = true;
|
||||
} else if(arg == "-M") {
|
||||
print_make_rules = true;
|
||||
} else {
|
||||
for (size_t i = 0; i < num_generators; ++i) {
|
||||
if (opt == generators[i].generator_opt) {
|
||||
if (arg == generators[i].generator_opt) {
|
||||
generator_enabled[i] = true;
|
||||
any_generator = true;
|
||||
goto found;
|
||||
}
|
||||
}
|
||||
Error("unknown commandline argument", arg, true);
|
||||
Error("unknown commandline argument" + arg, true);
|
||||
found:;
|
||||
}
|
||||
} else {
|
||||
@@ -153,10 +189,10 @@ int main(int argc, const char *argv[]) {
|
||||
}
|
||||
}
|
||||
|
||||
if (!filenames.size()) Error("missing input files", nullptr, true);
|
||||
if (!filenames.size()) Error("missing input files", false, true);
|
||||
|
||||
if (!any_generator)
|
||||
Error("no options", "specify one of -c -g -j -t -b etc.", true);
|
||||
Error("no options: specify one of -c -g -j -t -b etc.", true);
|
||||
|
||||
// Now process the files:
|
||||
flatbuffers::Parser parser(opts.strict_json, proto_mode);
|
||||
@@ -165,7 +201,7 @@ int main(int argc, const char *argv[]) {
|
||||
++file_it) {
|
||||
std::string contents;
|
||||
if (!flatbuffers::LoadFile(file_it->c_str(), true, &contents))
|
||||
Error("unable to load file", file_it->c_str());
|
||||
Error("unable to load file" + *file_it);
|
||||
|
||||
bool is_binary = static_cast<size_t>(file_it - filenames.begin()) >=
|
||||
binary_files_from;
|
||||
@@ -174,13 +210,37 @@ int main(int argc, const char *argv[]) {
|
||||
parser.builder_.PushBytes(
|
||||
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 {
|
||||
auto local_include_directory = flatbuffers::StripFileName(*file_it);
|
||||
include_directories.push_back(local_include_directory.c_str());
|
||||
include_directories.push_back(nullptr);
|
||||
if (!parser.Parse(contents.c_str(), &include_directories[0],
|
||||
file_it->c_str()))
|
||||
Error(parser.error_.c_str(), nullptr, false, false);
|
||||
Error(parser.error_, false, false);
|
||||
if (schema_binary) {
|
||||
parser.Serialize();
|
||||
parser.file_extension_ = reflection::SchemaExtension();
|
||||
}
|
||||
include_directories.pop_back();
|
||||
include_directories.pop_back();
|
||||
}
|
||||
@@ -194,10 +254,10 @@ int main(int argc, const char *argv[]) {
|
||||
if (!print_make_rules) {
|
||||
flatbuffers::EnsureDirExists(output_path);
|
||||
if (!generators[i].generate(parser, output_path, filebase, opts)) {
|
||||
Error((std::string("Unable to generate ") +
|
||||
generators[i].lang_name +
|
||||
" for " +
|
||||
filebase).c_str());
|
||||
Error(std::string("Unable to generate ") +
|
||||
generators[i].lang_name +
|
||||
" for " +
|
||||
filebase);
|
||||
}
|
||||
} else {
|
||||
std::string make_rule = generators[i].make_rule(
|
||||
|
||||
@@ -18,11 +18,12 @@
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include "flatbuffers/hash.h"
|
||||
#include <stdio.h>
|
||||
|
||||
enum OutputFormat {
|
||||
kDecimal,
|
||||
kHexadecimal,
|
||||
kHexadecimal0x,
|
||||
kHexadecimal0x
|
||||
};
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
|
||||
@@ -44,12 +44,25 @@ static std::string WrapInNameSpace(const Parser &parser,
|
||||
return WrapInNameSpace(parser, def.defined_namespace, def.name);
|
||||
}
|
||||
|
||||
// Translates a qualified name in flatbuffer text format to the same name in
|
||||
// the equivalent C++ namepsace.
|
||||
static std::string TranslateNameSpace(const std::string &qualified_name) {
|
||||
std::string cpp_qualified_name = qualified_name;
|
||||
size_t start_pos = 0;
|
||||
while((start_pos = cpp_qualified_name.find(".", start_pos)) !=
|
||||
std::string::npos) {
|
||||
cpp_qualified_name.replace(start_pos, 1, "::");
|
||||
}
|
||||
return cpp_qualified_name;
|
||||
}
|
||||
|
||||
|
||||
// Return a C++ type from the table in idl.h
|
||||
static std::string GenTypeBasic(const Parser &parser, const Type &type,
|
||||
bool real_enum) {
|
||||
static const char *ctypename[] = {
|
||||
#define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE) #CTYPE,
|
||||
#define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \
|
||||
#CTYPE,
|
||||
FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
|
||||
#undef FLATBUFFERS_TD
|
||||
};
|
||||
@@ -111,12 +124,28 @@ static std::string GenTypeGet(const Parser &parser, const Type &type,
|
||||
: beforeptr + GenTypePointer(parser, type) + afterptr;
|
||||
}
|
||||
|
||||
static std::string GenEnumDecl(const EnumDef &enum_def,
|
||||
const GeneratorOptions &opts) {
|
||||
return (opts.scoped_enums ? "enum class " : "enum ") + enum_def.name;
|
||||
}
|
||||
|
||||
static std::string GenEnumVal(const EnumDef &enum_def, const EnumVal &enum_val,
|
||||
const GeneratorOptions &opts) {
|
||||
return opts.prefixed_enums ? enum_def.name + "_" + enum_val.name
|
||||
: enum_val.name;
|
||||
}
|
||||
|
||||
static std::string GetEnumVal(const EnumDef &enum_def, const EnumVal &enum_val,
|
||||
const GeneratorOptions &opts) {
|
||||
if (opts.scoped_enums) {
|
||||
return enum_def.name + "::" + enum_val.name;
|
||||
} else if (opts.prefixed_enums) {
|
||||
return enum_def.name + "_" + enum_val.name;
|
||||
} else {
|
||||
return enum_val.name;
|
||||
}
|
||||
}
|
||||
|
||||
// Generate an enum declaration and an enum string lookup table.
|
||||
static void GenEnum(const Parser &parser, EnumDef &enum_def,
|
||||
std::string *code_ptr, std::string *code_ptr_post,
|
||||
@@ -124,13 +153,13 @@ static void GenEnum(const Parser &parser, EnumDef &enum_def,
|
||||
if (enum_def.generated) return;
|
||||
std::string &code = *code_ptr;
|
||||
std::string &code_post = *code_ptr_post;
|
||||
GenComment(enum_def.doc_comment, code_ptr);
|
||||
code += "enum " + enum_def.name + " {\n";
|
||||
GenComment(enum_def.doc_comment, code_ptr, nullptr);
|
||||
code += GenEnumDecl(enum_def, opts) + " {\n";
|
||||
for (auto it = enum_def.vals.vec.begin();
|
||||
it != enum_def.vals.vec.end();
|
||||
++it) {
|
||||
auto &ev = **it;
|
||||
GenComment(ev.doc_comment, code_ptr, " ");
|
||||
GenComment(ev.doc_comment, code_ptr, nullptr, " ");
|
||||
code += " " + GenEnumVal(enum_def, ev, opts) + " = ";
|
||||
code += NumToString(ev.value);
|
||||
code += (it + 1) != enum_def.vals.vec.end() ? ",\n" : "\n";
|
||||
@@ -158,9 +187,9 @@ static void GenEnum(const Parser &parser, EnumDef &enum_def,
|
||||
}
|
||||
code += "nullptr };\n return names;\n}\n\n";
|
||||
code += "inline const char *EnumName" + enum_def.name;
|
||||
code += "(" + enum_def.name + " e) { return EnumNames" + enum_def.name + "()[e";
|
||||
code += "(" + enum_def.name + " e) { return EnumNames" + enum_def.name + "()[static_cast<int>(e)";
|
||||
if (enum_def.vals.vec.front()->value)
|
||||
code += " - " + GenEnumVal(enum_def, *enum_def.vals.vec.front(), opts);
|
||||
code += " - static_cast<int>(" + GetEnumVal(enum_def, *enum_def.vals.vec.front(), opts) +")";
|
||||
code += "]; }\n\n";
|
||||
}
|
||||
|
||||
@@ -179,7 +208,7 @@ static void GenEnum(const Parser &parser, EnumDef &enum_def,
|
||||
it != enum_def.vals.vec.end();
|
||||
++it) {
|
||||
auto &ev = **it;
|
||||
code_post += " case " + GenEnumVal(enum_def, ev, opts);
|
||||
code_post += " case " + GetEnumVal(enum_def, ev, opts);
|
||||
if (!ev.value) {
|
||||
code_post += ": return true;\n"; // "NONE" enum value.
|
||||
} else {
|
||||
@@ -212,7 +241,7 @@ static void GenTable(const Parser &parser, StructDef &struct_def,
|
||||
|
||||
// Generate an accessor struct, with methods of the form:
|
||||
// type name() const { return GetField<type>(offset, defaultval); }
|
||||
GenComment(struct_def.doc_comment, code_ptr);
|
||||
GenComment(struct_def.doc_comment, code_ptr, nullptr);
|
||||
code += "struct " + struct_def.name;
|
||||
code += " FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table";
|
||||
code += " {\n";
|
||||
@@ -221,29 +250,53 @@ static void GenTable(const Parser &parser, StructDef &struct_def,
|
||||
++it) {
|
||||
auto &field = **it;
|
||||
if (!field.deprecated) { // Deprecated fields won't be accessible.
|
||||
GenComment(field.doc_comment, code_ptr, " ");
|
||||
auto is_scalar = IsScalar(field.value.type.base_type);
|
||||
GenComment(field.doc_comment, code_ptr, nullptr, " ");
|
||||
code += " " + GenTypeGet(parser, field.value.type, " ", "const ", " *",
|
||||
true);
|
||||
code += field.name + "() const { return ";
|
||||
// Call a different accessor for pointers, that indirects.
|
||||
std::string call = IsScalar(field.value.type.base_type)
|
||||
auto accessor = is_scalar
|
||||
? "GetField<"
|
||||
: (IsStruct(field.value.type) ? "GetStruct<" : "GetPointer<");
|
||||
call += GenTypeGet(parser, field.value.type, "", "const ", " *", false);
|
||||
call += ">(" + NumToString(field.value.offset);
|
||||
auto offsetstr = NumToString(field.value.offset);
|
||||
auto call =
|
||||
accessor +
|
||||
GenTypeGet(parser, field.value.type, "", "const ", " *", false) +
|
||||
">(" + offsetstr;
|
||||
// Default value as second arg for non-pointer types.
|
||||
if (IsScalar(field.value.type.base_type))
|
||||
call += ", " + field.value.constant;
|
||||
call += ")";
|
||||
code += GenUnderlyingCast(parser, field, true, call);
|
||||
code += "; }\n";
|
||||
if (opts.mutable_buffer) {
|
||||
if (is_scalar) {
|
||||
code += " bool mutate_" + field.name + "(";
|
||||
code += GenTypeBasic(parser, field.value.type, true);
|
||||
code += " " + field.name + ") { return SetField(" + offsetstr + ", ";
|
||||
code += GenUnderlyingCast(parser, field, false, field.name);
|
||||
code += "); }\n";
|
||||
} else {
|
||||
auto type = GenTypeGet(parser, field.value.type, " ", "", " *", true);
|
||||
code += " " + type + "mutable_" + field.name + "() { return ";
|
||||
code += GenUnderlyingCast(parser, field, true,
|
||||
accessor + type + ">(" + offsetstr + ")");
|
||||
code += "; }\n";
|
||||
}
|
||||
}
|
||||
auto nested = field.attributes.Lookup("nested_flatbuffer");
|
||||
if (nested) {
|
||||
auto nested_root = parser.structs_.Lookup(nested->constant);
|
||||
std::string qualified_name =
|
||||
parser.namespaces_.back()->GetFullyQualifiedName(nested->constant);
|
||||
auto nested_root = parser.structs_.Lookup(qualified_name);
|
||||
assert(nested_root); // Guaranteed to exist by parser.
|
||||
code += " const " + nested_root->name + " *" + field.name;
|
||||
(void)nested_root;
|
||||
std::string cpp_qualified_name = TranslateNameSpace(qualified_name);
|
||||
|
||||
code += " const " + cpp_qualified_name + " *" + field.name;
|
||||
code += "_nested_root() const { return flatbuffers::GetRoot<";
|
||||
code += nested_root->name + ">(" + field.name + "()->Data()); }\n";
|
||||
code += cpp_qualified_name + ">(" + field.name + "()->Data()); }\n";
|
||||
}
|
||||
// Generate a comparison function for this field if it is a key.
|
||||
if (field.key) {
|
||||
@@ -388,7 +441,7 @@ static void GenTable(const Parser &parser, StructDef &struct_def,
|
||||
if (ev) {
|
||||
code += WrapInNameSpace(parser,
|
||||
field.value.type.enum_def->defined_namespace,
|
||||
GenEnumVal(*field.value.type.enum_def, *ev,
|
||||
GetEnumVal(*field.value.type.enum_def, *ev,
|
||||
opts));
|
||||
} else {
|
||||
code += GenUnderlyingCast(parser, field, true, field.value.constant);
|
||||
@@ -416,7 +469,8 @@ static void GenTable(const Parser &parser, StructDef &struct_def,
|
||||
code += " return builder_.Finish();\n}\n\n";
|
||||
}
|
||||
|
||||
static void GenPadding(const FieldDef &field, const std::function<void (int bits)> &f) {
|
||||
static void GenPadding(const FieldDef &field,
|
||||
const std::function<void (int bits)> &f) {
|
||||
if (field.padding) {
|
||||
for (int i = 0; i < 4; i++)
|
||||
if (static_cast<int>(field.padding) & (1 << i))
|
||||
@@ -427,7 +481,7 @@ static void GenPadding(const FieldDef &field, const std::function<void (int bits
|
||||
|
||||
// Generate an accessor struct with constructor for a flatbuffers struct.
|
||||
static void GenStruct(const Parser &parser, StructDef &struct_def,
|
||||
std::string *code_ptr) {
|
||||
const GeneratorOptions &opts, std::string *code_ptr) {
|
||||
if (struct_def.generated) return;
|
||||
std::string &code = *code_ptr;
|
||||
|
||||
@@ -436,7 +490,7 @@ static void GenStruct(const Parser &parser, StructDef &struct_def,
|
||||
// Generates manual padding and alignment.
|
||||
// Variables are private because they contain little endian data on all
|
||||
// platforms.
|
||||
GenComment(struct_def.doc_comment, code_ptr);
|
||||
GenComment(struct_def.doc_comment, code_ptr, nullptr);
|
||||
code += "MANUALLY_ALIGNED_STRUCT(" + NumToString(struct_def.minalign) + ") ";
|
||||
code += struct_def.name + " FLATBUFFERS_FINAL_CLASS {\n private:\n";
|
||||
int padding_id = 0;
|
||||
@@ -501,15 +555,31 @@ static void GenStruct(const Parser &parser, StructDef &struct_def,
|
||||
it != struct_def.fields.vec.end();
|
||||
++it) {
|
||||
auto &field = **it;
|
||||
GenComment(field.doc_comment, code_ptr, " ");
|
||||
GenComment(field.doc_comment, code_ptr, nullptr, " ");
|
||||
auto is_scalar = IsScalar(field.value.type.base_type);
|
||||
code += " " + GenTypeGet(parser, field.value.type, " ", "const ", " &",
|
||||
true);
|
||||
code += field.name + "() const { return ";
|
||||
code += GenUnderlyingCast(parser, field, true,
|
||||
IsScalar(field.value.type.base_type)
|
||||
is_scalar
|
||||
? "flatbuffers::EndianScalar(" + field.name + "_)"
|
||||
: field.name + "_");
|
||||
code += "; }\n";
|
||||
if (opts.mutable_buffer) {
|
||||
if (is_scalar) {
|
||||
code += " void mutate_" + field.name + "(";
|
||||
code += GenTypeBasic(parser, field.value.type, true);
|
||||
code += " " + field.name + ") { flatbuffers::WriteScalar(&";
|
||||
code += field.name + "_, ";
|
||||
code += GenUnderlyingCast(parser, field, false, field.name);
|
||||
code += "); }\n";
|
||||
} else {
|
||||
code += " ";
|
||||
code += GenTypeGet(parser, field.value.type, "", "", " &", true);
|
||||
code += "mutable_" + field.name + "() { return " + field.name;
|
||||
code += "_; }\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
code += "};\nSTRUCT_END(" + struct_def.name + ", ";
|
||||
code += NumToString(struct_def.bytesize) + ");\n\n";
|
||||
@@ -581,7 +651,7 @@ std::string GenerateCPP(const Parser &parser,
|
||||
std::string decl_code;
|
||||
for (auto it = parser.structs_.vec.begin();
|
||||
it != parser.structs_.vec.end(); ++it) {
|
||||
if ((**it).fixed) GenStruct(parser, **it, &decl_code);
|
||||
if ((**it).fixed) GenStruct(parser, **it, opts, &decl_code);
|
||||
}
|
||||
for (auto it = parser.structs_.vec.begin();
|
||||
it != parser.structs_.vec.end(); ++it) {
|
||||
@@ -647,20 +717,30 @@ std::string GenerateCPP(const Parser &parser,
|
||||
code += enum_code_post;
|
||||
|
||||
// Generate convenient global helper functions:
|
||||
if (parser.root_struct_def) {
|
||||
auto &name = parser.root_struct_def->name;
|
||||
if (parser.root_struct_def_) {
|
||||
auto &name = parser.root_struct_def_->name;
|
||||
std::string qualified_name =
|
||||
parser.namespaces_.back()->GetFullyQualifiedName(name);
|
||||
std::string cpp_qualified_name = TranslateNameSpace(qualified_name);
|
||||
|
||||
// The root datatype accessor:
|
||||
code += "inline const " + name + " *Get";
|
||||
code += "inline const " + cpp_qualified_name + " *Get";
|
||||
code += name;
|
||||
code += "(const void *buf) { return flatbuffers::GetRoot<";
|
||||
code += name + ">(buf); }\n\n";
|
||||
code += cpp_qualified_name + ">(buf); }\n\n";
|
||||
if (opts.mutable_buffer) {
|
||||
code += "inline " + name + " *GetMutable";
|
||||
code += name;
|
||||
code += "(void *buf) { return flatbuffers::GetMutableRoot<";
|
||||
code += name + ">(buf); }\n\n";
|
||||
}
|
||||
|
||||
// The root verifier:
|
||||
code += "inline bool Verify";
|
||||
code += name;
|
||||
code += "Buffer(flatbuffers::Verifier &verifier) { "
|
||||
"return verifier.VerifyBuffer<";
|
||||
code += name + ">(); }\n\n";
|
||||
code += cpp_qualified_name + ">(); }\n\n";
|
||||
|
||||
if (parser.file_identifier_.length()) {
|
||||
// Return the identifier
|
||||
@@ -675,10 +755,17 @@ std::string GenerateCPP(const Parser &parser,
|
||||
code += name + "Identifier()); }\n\n";
|
||||
}
|
||||
|
||||
if (parser.file_extension_.length()) {
|
||||
// Return the extension
|
||||
code += "inline const char *" + name;
|
||||
code += "Extension() { return \"" + parser.file_extension_;
|
||||
code += "\"; }\n\n";
|
||||
}
|
||||
|
||||
// Finish a buffer with a given root object:
|
||||
code += "inline void Finish" + name;
|
||||
code += "Buffer(flatbuffers::FlatBufferBuilder &fbb, flatbuffers::Offset<";
|
||||
code += name + "> root) { fbb.Finish(root";
|
||||
code += cpp_qualified_name + "> root) { fbb.Finish(root";
|
||||
if (parser.file_identifier_.length())
|
||||
code += ", " + name + "Identifier()";
|
||||
code += "); }\n\n";
|
||||
|
||||
@@ -24,19 +24,49 @@ namespace flatbuffers {
|
||||
|
||||
static std::string GenType(const Type &type) {
|
||||
switch (type.base_type) {
|
||||
case BASE_TYPE_STRUCT: return type.struct_def->name;
|
||||
case BASE_TYPE_UNION: return type.enum_def->name;
|
||||
case BASE_TYPE_VECTOR: return "[" + GenType(type.VectorType()) + "]";
|
||||
default: return kTypeNames[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];
|
||||
}
|
||||
}
|
||||
|
||||
static void GenNameSpace(const Namespace &name_space, std::string *_schema,
|
||||
const Namespace **last_namespace) {
|
||||
if (*last_namespace == &name_space) return;
|
||||
*last_namespace = &name_space;
|
||||
auto &schema = *_schema;
|
||||
schema += "namespace ";
|
||||
for (auto it = name_space.components.begin();
|
||||
it != name_space.components.end(); ++it) {
|
||||
if (it != name_space.components.begin()) schema += ".";
|
||||
schema += *it;
|
||||
}
|
||||
schema += ";\n\n";
|
||||
}
|
||||
|
||||
// Generate a flatbuffer schema from the Parser's internal representation.
|
||||
std::string GenerateFBS(const Parser &parser, const std::string &file_name,
|
||||
const GeneratorOptions &opts) {
|
||||
// Proto namespaces may clash with table names, so we have to prefix all:
|
||||
for (auto it = parser.namespaces_.begin(); it != parser.namespaces_.end();
|
||||
++it) {
|
||||
for (auto comp = (*it)->components.begin(); comp != (*it)->components.end();
|
||||
++comp) {
|
||||
(*comp) = "_" + (*comp);
|
||||
}
|
||||
}
|
||||
|
||||
std::string schema;
|
||||
schema += "// Generated from " + file_name + ".proto\n\n";
|
||||
if (opts.include_dependence_headers) {
|
||||
#ifdef FBS_GEN_INCLUDES // TODO: currently all in one file.
|
||||
int num_includes = 0;
|
||||
for (auto it = parser.included_files_.begin();
|
||||
it != parser.included_files_.end(); ++it) {
|
||||
@@ -48,24 +78,21 @@ std::string GenerateFBS(const Parser &parser, const std::string &file_name,
|
||||
}
|
||||
}
|
||||
if (num_includes) schema += "\n";
|
||||
#endif
|
||||
}
|
||||
schema += "namespace ";
|
||||
auto name_space = parser.namespaces_.back();
|
||||
for (auto it = name_space->components.begin();
|
||||
it != name_space->components.end(); ++it) {
|
||||
if (it != name_space->components.begin()) schema += ".";
|
||||
schema += *it;
|
||||
}
|
||||
schema += ";\n\n";
|
||||
// Generate code for all the enum declarations.
|
||||
const Namespace *last_namespace = nullptr;
|
||||
for (auto enum_def_it = parser.enums_.vec.begin();
|
||||
enum_def_it != parser.enums_.vec.end(); ++enum_def_it) {
|
||||
EnumDef &enum_def = **enum_def_it;
|
||||
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";
|
||||
for (auto it = enum_def.vals.vec.begin();
|
||||
it != enum_def.vals.vec.end(); ++it) {
|
||||
auto &ev = **it;
|
||||
GenComment(ev.doc_comment, &schema, nullptr, " ");
|
||||
schema += " " + ev.name + " = " + NumToString(ev.value) + ",\n";
|
||||
}
|
||||
schema += "}\n\n";
|
||||
@@ -74,10 +101,13 @@ std::string GenerateFBS(const Parser &parser, const std::string &file_name,
|
||||
for (auto it = parser.structs_.vec.begin();
|
||||
it != parser.structs_.vec.end(); ++it) {
|
||||
StructDef &struct_def = **it;
|
||||
GenNameSpace(*struct_def.defined_namespace, &schema, &last_namespace);
|
||||
GenComment(struct_def.doc_comment, &schema, nullptr);
|
||||
schema += "table " + struct_def.name + " {\n";
|
||||
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)";
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include "flatbuffers/flatbuffers.h"
|
||||
#include "flatbuffers/idl.h"
|
||||
#include "flatbuffers/util.h"
|
||||
#include <algorithm>
|
||||
|
||||
namespace flatbuffers {
|
||||
|
||||
@@ -37,14 +38,34 @@ std::string MakeCamel(const std::string &in, bool first) {
|
||||
return s;
|
||||
}
|
||||
|
||||
struct CommentConfig {
|
||||
const char *first_line;
|
||||
const char *content_line_prefix;
|
||||
const char *last_line;
|
||||
};
|
||||
|
||||
// Generate a documentation comment, if available.
|
||||
void GenComment(const std::vector<std::string> &dc, std::string *code_ptr,
|
||||
const char *prefix) {
|
||||
const CommentConfig *config, const char *prefix) {
|
||||
if (dc.begin() == dc.end()) {
|
||||
// Don't output empty comment blocks with 0 lines of comment content.
|
||||
return;
|
||||
}
|
||||
|
||||
std::string &code = *code_ptr;
|
||||
if (config != nullptr && config->first_line != nullptr) {
|
||||
code += std::string(prefix) + std::string(config->first_line) + "\n";
|
||||
}
|
||||
std::string line_prefix = std::string(prefix) +
|
||||
((config != nullptr && config->content_line_prefix != nullptr) ?
|
||||
config->content_line_prefix : "///");
|
||||
for (auto it = dc.begin();
|
||||
it != dc.end();
|
||||
++it) {
|
||||
code += std::string(prefix) + "///" + *it + "\n";
|
||||
code += line_prefix + *it + "\n";
|
||||
}
|
||||
if (config != nullptr && config->last_line != nullptr) {
|
||||
code += std::string(prefix) + std::string(config->last_line) + "\n";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,12 +80,20 @@ struct LanguageParameters {
|
||||
const char *bool_type;
|
||||
const char *open_curly;
|
||||
const char *const_decl;
|
||||
const char *unsubclassable_decl;
|
||||
const char *enum_decl;
|
||||
const char *enum_separator;
|
||||
const char *getter_prefix;
|
||||
const char *getter_suffix;
|
||||
const char *inheritance_marker;
|
||||
const char *namespace_ident;
|
||||
const char *namespace_begin;
|
||||
const char *namespace_end;
|
||||
const char *set_bb_byteorder;
|
||||
const char *get_bb_position;
|
||||
const char *get_fbb_offset;
|
||||
const char *includes;
|
||||
CommentConfig comment_config;
|
||||
};
|
||||
|
||||
LanguageParameters language_parameters[] = {
|
||||
@@ -76,13 +105,25 @@ LanguageParameters language_parameters[] = {
|
||||
"boolean ",
|
||||
" {\n",
|
||||
" final ",
|
||||
"final ",
|
||||
"final class ",
|
||||
";\n",
|
||||
"()",
|
||||
"",
|
||||
" extends ",
|
||||
"package ",
|
||||
";",
|
||||
"",
|
||||
"_bb.order(ByteOrder.LITTLE_ENDIAN); ",
|
||||
"position()",
|
||||
"offset()",
|
||||
"import java.nio.*;\nimport java.lang.*;\nimport java.util.*;\n"
|
||||
"import com.google.flatbuffers.*;\n\n",
|
||||
"import com.google.flatbuffers.*;\n\n@SuppressWarnings(\"unused\")\n",
|
||||
{
|
||||
"/**",
|
||||
" *",
|
||||
" */",
|
||||
},
|
||||
},
|
||||
{
|
||||
GeneratorOptions::kCSharp,
|
||||
@@ -92,12 +133,24 @@ LanguageParameters language_parameters[] = {
|
||||
"bool ",
|
||||
"\n{\n",
|
||||
" readonly ",
|
||||
"sealed ",
|
||||
"enum ",
|
||||
",\n",
|
||||
" { get",
|
||||
"} ",
|
||||
" : ",
|
||||
"namespace ",
|
||||
"\n{",
|
||||
"\n}\n",
|
||||
"",
|
||||
"Position",
|
||||
"Offset",
|
||||
"using FlatBuffers;\n\n",
|
||||
{
|
||||
nullptr,
|
||||
"///",
|
||||
nullptr,
|
||||
},
|
||||
},
|
||||
// TODO: add Go support to the general generator.
|
||||
// WARNING: this is currently only used for generating make rules for Go.
|
||||
@@ -109,12 +162,24 @@ LanguageParameters language_parameters[] = {
|
||||
"bool ",
|
||||
"\n{\n",
|
||||
"const ",
|
||||
" ",
|
||||
"class ",
|
||||
";\n",
|
||||
"()",
|
||||
"",
|
||||
"",
|
||||
"package ",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"position()",
|
||||
"offset()",
|
||||
"import (\n\tflatbuffers \"github.com/google/flatbuffers/go\"\n)",
|
||||
{
|
||||
nullptr,
|
||||
"///",
|
||||
nullptr,
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
@@ -132,15 +197,29 @@ static std::string FunctionStart(const LanguageParameters &lang, char upper) {
|
||||
static std::string GenTypeBasic(const LanguageParameters &lang,
|
||||
const Type &type) {
|
||||
static const char *gtypename[] = {
|
||||
#define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE) \
|
||||
#define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \
|
||||
#JTYPE, #NTYPE, #GTYPE,
|
||||
FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
|
||||
#undef FLATBUFFERS_TD
|
||||
};
|
||||
|
||||
if(lang.language == GeneratorOptions::kCSharp && type.base_type == BASE_TYPE_STRUCT) {
|
||||
return "Offset<" + type.struct_def->name + ">";
|
||||
}
|
||||
|
||||
return gtypename[type.base_type * GeneratorOptions::kMAX + lang.language];
|
||||
}
|
||||
|
||||
// Generate type to be used in user-facing API
|
||||
static std::string GenTypeForUser(const LanguageParameters &lang,
|
||||
const Type &type) {
|
||||
if (lang.language == GeneratorOptions::kCSharp) {
|
||||
if (type.enum_def != nullptr &&
|
||||
type.base_type != BASE_TYPE_UNION) return type.enum_def->name;
|
||||
}
|
||||
return GenTypeBasic(lang, type);
|
||||
}
|
||||
|
||||
static std::string GenTypeGet(const LanguageParameters &lang,
|
||||
const Type &type);
|
||||
|
||||
@@ -173,6 +252,8 @@ static Type DestinationType(const LanguageParameters &lang, const Type &type,
|
||||
bool vectorelem) {
|
||||
if (lang.language != GeneratorOptions::kJava) return type;
|
||||
switch (type.base_type) {
|
||||
// We use int for both uchar/ushort, since that generally means less casting
|
||||
// than using short for uchar.
|
||||
case BASE_TYPE_UCHAR: return Type(BASE_TYPE_INT);
|
||||
case BASE_TYPE_USHORT: return Type(BASE_TYPE_INT);
|
||||
case BASE_TYPE_UINT: return Type(BASE_TYPE_LONG);
|
||||
@@ -184,6 +265,49 @@ static Type DestinationType(const LanguageParameters &lang, const Type &type,
|
||||
}
|
||||
}
|
||||
|
||||
static std::string GenOffsetType(const LanguageParameters &lang, const StructDef &struct_def) {
|
||||
if(lang.language == GeneratorOptions::kCSharp) {
|
||||
return "Offset<" + struct_def.name + ">";
|
||||
} else {
|
||||
return "int";
|
||||
}
|
||||
}
|
||||
|
||||
static std::string GenOffsetConstruct(const LanguageParameters &lang,
|
||||
const StructDef &struct_def,
|
||||
const std::string &variable_name)
|
||||
{
|
||||
if(lang.language == GeneratorOptions::kCSharp) {
|
||||
return "new Offset<" + struct_def.name + ">(" + variable_name + ")";
|
||||
}
|
||||
return variable_name;
|
||||
}
|
||||
|
||||
static std::string GenVectorOffsetType(const LanguageParameters &lang) {
|
||||
if(lang.language == GeneratorOptions::kCSharp) {
|
||||
return "VectorOffset";
|
||||
} else {
|
||||
return "int";
|
||||
}
|
||||
}
|
||||
|
||||
// Generate destination type name
|
||||
static std::string GenTypeNameDest(const LanguageParameters &lang, const Type &type)
|
||||
{
|
||||
if (lang.language == GeneratorOptions::kCSharp) {
|
||||
// C# enums are represented by themselves
|
||||
if (type.enum_def != nullptr && type.base_type != BASE_TYPE_UNION)
|
||||
return type.enum_def->name;
|
||||
|
||||
// Unions in C# use a generic Table-derived type for better type safety
|
||||
if (type.base_type == BASE_TYPE_UNION)
|
||||
return "TTable";
|
||||
}
|
||||
|
||||
// default behavior
|
||||
return GenTypeGet(lang, DestinationType(lang, type, true));
|
||||
}
|
||||
|
||||
// Mask to turn serialized value into destination type value.
|
||||
static std::string DestinationMask(const LanguageParameters &lang,
|
||||
const Type &type, bool vectorelem) {
|
||||
@@ -200,19 +324,86 @@ static std::string DestinationMask(const LanguageParameters &lang,
|
||||
}
|
||||
}
|
||||
|
||||
// Cast necessary to correctly read serialized unsigned values.
|
||||
// Casts necessary to correctly read serialized data
|
||||
static std::string DestinationCast(const LanguageParameters &lang,
|
||||
const Type &type) {
|
||||
if (lang.language == GeneratorOptions::kJava &&
|
||||
(type.base_type == BASE_TYPE_UINT ||
|
||||
(type.base_type == BASE_TYPE_VECTOR &&
|
||||
type.element == BASE_TYPE_UINT))) return "(long)";
|
||||
switch (lang.language) {
|
||||
case GeneratorOptions::kJava:
|
||||
// Cast necessary to correctly read serialized unsigned values.
|
||||
if (type.base_type == BASE_TYPE_UINT ||
|
||||
(type.base_type == BASE_TYPE_VECTOR &&
|
||||
type.element == BASE_TYPE_UINT)) return "(long)";
|
||||
break;
|
||||
|
||||
case GeneratorOptions::kCSharp:
|
||||
// Cast from raw integral types to enum
|
||||
if (type.enum_def != nullptr &&
|
||||
type.base_type != BASE_TYPE_UNION) return "(" + type.enum_def->name + ")";
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
// Read value and possibly process it to get proper value
|
||||
static std::string DestinationValue(const LanguageParameters &lang,
|
||||
const std::string &name,
|
||||
const Type &type) {
|
||||
std::string type_mask = DestinationMask(lang, type, false);
|
||||
// is a typecast needed? (for C# enums and unsigned values in Java)
|
||||
if (type_mask.length() ||
|
||||
(lang.language == GeneratorOptions::kCSharp &&
|
||||
type.enum_def != nullptr &&
|
||||
type.base_type != BASE_TYPE_UNION)) {
|
||||
return "(" + GenTypeBasic(lang, type) + ")(" + name + type_mask + ")";
|
||||
} else {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
||||
// Cast statements for mutator method parameters.
|
||||
// In Java, parameters representing unsigned numbers need to be cast down to their respective type.
|
||||
// For example, a long holding an unsigned int value would be cast down to int before being put onto the buffer.
|
||||
// In C#, one cast directly cast an Enum to its underlying type, which is essential before putting it onto the buffer.
|
||||
static std::string SourceCast(const LanguageParameters &lang,
|
||||
const Type &type) {
|
||||
if (type.base_type == BASE_TYPE_VECTOR) {
|
||||
return SourceCast(lang, type.VectorType());
|
||||
} else {
|
||||
switch (lang.language) {
|
||||
case GeneratorOptions::kJava:
|
||||
if (type.base_type == BASE_TYPE_UINT) return "(int)";
|
||||
else if (type.base_type == BASE_TYPE_USHORT) return "(short)";
|
||||
else if (type.base_type == BASE_TYPE_UCHAR) return "(byte)";
|
||||
break;
|
||||
case GeneratorOptions::kCSharp:
|
||||
if (type.enum_def != nullptr &&
|
||||
type.base_type != BASE_TYPE_UNION)
|
||||
return "(" + GenTypeGet(lang, type) + ")";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
static std::string GenDefaultValue(const LanguageParameters &lang, const Value &value, bool for_buffer) {
|
||||
if(lang.language == GeneratorOptions::kCSharp && !for_buffer) {
|
||||
switch(value.type.base_type) {
|
||||
case BASE_TYPE_STRING:
|
||||
return "default(StringOffset)";
|
||||
case BASE_TYPE_STRUCT:
|
||||
return "default(Offset<" + value.type.struct_def->name + ">)";
|
||||
case BASE_TYPE_VECTOR:
|
||||
return "default(VectorOffset)";
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static std::string GenDefaultValue(const Value &value) {
|
||||
return value.type.base_type == BASE_TYPE_BOOL
|
||||
? (value.constant == "0" ? "false" : "true")
|
||||
: value.constant;
|
||||
@@ -228,49 +419,62 @@ static void GenEnum(const LanguageParameters &lang, EnumDef &enum_def,
|
||||
// In Java, we use ints rather than the Enum feature, because we want them
|
||||
// to map directly to how they're used in C/C++ and file formats.
|
||||
// That, and Java Enums are expensive, and not universally liked.
|
||||
GenComment(enum_def.doc_comment, code_ptr);
|
||||
code += "public class " + enum_def.name + lang.open_curly;
|
||||
GenComment(enum_def.doc_comment, code_ptr, &lang.comment_config);
|
||||
code += std::string("public ") + lang.enum_decl + enum_def.name;
|
||||
if (lang.language == GeneratorOptions::kCSharp) {
|
||||
code += lang.inheritance_marker + GenTypeBasic(lang, enum_def.underlying_type);
|
||||
}
|
||||
code += lang.open_curly;
|
||||
if (lang.language == GeneratorOptions::kJava) {
|
||||
code += " private " + enum_def.name + "() { }\n";
|
||||
}
|
||||
for (auto it = enum_def.vals.vec.begin();
|
||||
it != enum_def.vals.vec.end();
|
||||
++it) {
|
||||
auto &ev = **it;
|
||||
GenComment(ev.doc_comment, code_ptr, " ");
|
||||
code += " public static";
|
||||
code += lang.const_decl;
|
||||
code += GenTypeBasic(lang, enum_def.underlying_type);
|
||||
GenComment(ev.doc_comment, code_ptr, &lang.comment_config, " ");
|
||||
if (lang.language != GeneratorOptions::kCSharp) {
|
||||
code += " public static";
|
||||
code += lang.const_decl;
|
||||
code += GenTypeBasic(lang, enum_def.underlying_type);
|
||||
}
|
||||
code += " " + ev.name + " = ";
|
||||
code += NumToString(ev.value) + ";\n";
|
||||
code += NumToString(ev.value);
|
||||
code += lang.enum_separator;
|
||||
}
|
||||
|
||||
// Generate a generate string table for enum values.
|
||||
// Problem is, if values are very sparse that could generate really big
|
||||
// tables. Ideally in that case we generate a map lookup instead, but for
|
||||
// the moment we simply don't output a table at all.
|
||||
auto range = enum_def.vals.vec.back()->value -
|
||||
enum_def.vals.vec.front()->value + 1;
|
||||
// Average distance between values above which we consider a table
|
||||
// "too sparse". Change at will.
|
||||
static const int kMaxSparseness = 5;
|
||||
if (range / static_cast<int64_t>(enum_def.vals.vec.size()) < kMaxSparseness) {
|
||||
code += "\n private static";
|
||||
code += lang.const_decl;
|
||||
code += lang.string_type;
|
||||
code += "[] names = { ";
|
||||
auto val = enum_def.vals.vec.front()->value;
|
||||
for (auto it = enum_def.vals.vec.begin();
|
||||
it != enum_def.vals.vec.end();
|
||||
++it) {
|
||||
while (val++ != (*it)->value) code += "\"\", ";
|
||||
code += "\"" + (*it)->name + "\", ";
|
||||
// We do not do that for C# where this functionality is native.
|
||||
if (lang.language != GeneratorOptions::kCSharp) {
|
||||
// Problem is, if values are very sparse that could generate really big
|
||||
// tables. Ideally in that case we generate a map lookup instead, but for
|
||||
// the moment we simply don't output a table at all.
|
||||
auto range = enum_def.vals.vec.back()->value -
|
||||
enum_def.vals.vec.front()->value + 1;
|
||||
// Average distance between values above which we consider a table
|
||||
// "too sparse". Change at will.
|
||||
static const int kMaxSparseness = 5;
|
||||
if (range / static_cast<int64_t>(enum_def.vals.vec.size()) < kMaxSparseness) {
|
||||
code += "\n private static";
|
||||
code += lang.const_decl;
|
||||
code += lang.string_type;
|
||||
code += "[] names = { ";
|
||||
auto val = enum_def.vals.vec.front()->value;
|
||||
for (auto it = enum_def.vals.vec.begin();
|
||||
it != enum_def.vals.vec.end();
|
||||
++it) {
|
||||
while (val++ != (*it)->value) code += "\"\", ";
|
||||
code += "\"" + (*it)->name + "\", ";
|
||||
}
|
||||
code += "};\n\n";
|
||||
code += " public static ";
|
||||
code += lang.string_type;
|
||||
code += " " + MakeCamel("name", lang.first_camel_upper);
|
||||
code += "(int e) { return names[e";
|
||||
if (enum_def.vals.vec.front()->value)
|
||||
code += " - " + enum_def.vals.vec.front()->name;
|
||||
code += "]; }\n";
|
||||
}
|
||||
code += "};\n\n";
|
||||
code += " public static ";
|
||||
code += lang.string_type;
|
||||
code += " " + MakeCamel("name", lang.first_camel_upper);
|
||||
code += "(int e) { return names[e";
|
||||
if (enum_def.vals.vec.front()->value)
|
||||
code += " - " + enum_def.vals.vec.front()->name;
|
||||
code += "]; }\n";
|
||||
}
|
||||
|
||||
// Close the class
|
||||
@@ -297,6 +501,22 @@ static std::string GenGetter(const LanguageParameters &lang,
|
||||
}
|
||||
}
|
||||
|
||||
// Direct mutation is only allowed for scalar fields.
|
||||
// Hence a setter method will only be generated for such fields.
|
||||
static std::string GenSetter(const LanguageParameters &lang,
|
||||
const Type &type) {
|
||||
if (IsScalar(type.base_type)) {
|
||||
std::string setter = "bb." + FunctionStart(lang, 'P') + "ut";
|
||||
if (GenTypeBasic(lang, type) != "byte" &&
|
||||
type.base_type != BASE_TYPE_BOOL) {
|
||||
setter += MakeCamel(GenTypeGet(lang, type));
|
||||
}
|
||||
return setter;
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
// Returns the method name for use with add/put calls.
|
||||
static std::string GenMethod(const LanguageParameters &lang, const Type &type) {
|
||||
return IsScalar(type.base_type)
|
||||
@@ -317,13 +537,13 @@ static void GenStructArgs(const LanguageParameters &lang,
|
||||
if (IsStruct(field.value.type)) {
|
||||
// Generate arguments for a struct inside a struct. To ensure names
|
||||
// don't clash, and to make it obvious these arguments are constructing
|
||||
// a nested struct, prefix the name with the struct name.
|
||||
// a nested struct, prefix the name with the field name.
|
||||
GenStructArgs(lang, *field.value.type.struct_def, code_ptr,
|
||||
(field.value.type.struct_def->name + "_").c_str());
|
||||
(nameprefix + (field.name + "_")).c_str());
|
||||
} else {
|
||||
code += ", ";
|
||||
code += GenTypeBasic(lang,
|
||||
DestinationType(lang, field.value.type, false));
|
||||
code += GenTypeForUser(lang,
|
||||
DestinationType(lang, field.value.type, false));
|
||||
code += " ";
|
||||
code += nameprefix;
|
||||
code += MakeCamel(field.name, lang.first_camel_upper);
|
||||
@@ -350,25 +570,20 @@ static void GenStructBody(const LanguageParameters &lang,
|
||||
}
|
||||
if (IsStruct(field.value.type)) {
|
||||
GenStructBody(lang, *field.value.type.struct_def, code_ptr,
|
||||
(field.value.type.struct_def->name + "_").c_str());
|
||||
(nameprefix + (field.name + "_")).c_str());
|
||||
} else {
|
||||
code += " builder." + FunctionStart(lang, 'P') + "ut";
|
||||
code += GenMethod(lang, field.value.type) + "(";
|
||||
auto argname = nameprefix + MakeCamel(field.name, lang.first_camel_upper);
|
||||
std::string type_mask = DestinationMask(lang, field.value.type, false);
|
||||
if (type_mask.length()) {
|
||||
code += "(" + GenTypeBasic(lang, field.value.type) + ")";
|
||||
code += "(" + argname + type_mask + ")";
|
||||
} else {
|
||||
code += argname;
|
||||
}
|
||||
code += DestinationValue(lang, argname, field.value.type);
|
||||
code += ");\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void GenStruct(const LanguageParameters &lang, const Parser &parser,
|
||||
StructDef &struct_def, std::string *code_ptr) {
|
||||
StructDef &struct_def, const GeneratorOptions &opts,
|
||||
std::string *code_ptr) {
|
||||
if (struct_def.generated) return;
|
||||
std::string &code = *code_ptr;
|
||||
|
||||
@@ -378,8 +593,9 @@ static void GenStruct(const LanguageParameters &lang, const Parser &parser,
|
||||
// public type name() {
|
||||
// int o = __offset(offset); return o != 0 ? bb.getType(o + i) : default;
|
||||
// }
|
||||
GenComment(struct_def.doc_comment, code_ptr);
|
||||
code += "public class " + struct_def.name + lang.inheritance_marker;
|
||||
GenComment(struct_def.doc_comment, code_ptr, &lang.comment_config);
|
||||
code += std::string("public ") + lang.unsubclassable_decl;
|
||||
code += "class " + struct_def.name + lang.inheritance_marker;
|
||||
code += struct_def.fixed ? "Struct" : "Table";
|
||||
code += " {\n";
|
||||
if (!struct_def.fixed) {
|
||||
@@ -396,8 +612,12 @@ static void GenStruct(const LanguageParameters &lang, const Parser &parser,
|
||||
code += method_signature + "(ByteBuffer _bb, " + struct_def.name + " obj) { ";
|
||||
code += lang.set_bb_byteorder;
|
||||
code += "return (obj.__init(_bb." + FunctionStart(lang, 'G');
|
||||
code += "etInt(_bb.position()) + _bb.position(), _bb)); }\n";
|
||||
if (parser.root_struct_def == &struct_def) {
|
||||
code += "etInt(_bb.";
|
||||
code += lang.get_bb_position;
|
||||
code += ") + _bb.";
|
||||
code += lang.get_bb_position;
|
||||
code += ", _bb)); }\n";
|
||||
if (parser.root_struct_def_ == &struct_def) {
|
||||
if (parser.file_identifier_.length()) {
|
||||
// Check if a buffer has the identifier.
|
||||
code += " public static ";
|
||||
@@ -418,58 +638,88 @@ static void GenStruct(const LanguageParameters &lang, const Parser &parser,
|
||||
++it) {
|
||||
auto &field = **it;
|
||||
if (field.deprecated) continue;
|
||||
GenComment(field.doc_comment, code_ptr, " ");
|
||||
GenComment(field.doc_comment, code_ptr, &lang.comment_config, " ");
|
||||
std::string type_name = GenTypeGet(lang, field.value.type);
|
||||
std::string type_name_dest =
|
||||
GenTypeGet(lang, DestinationType(lang, field.value.type, true));
|
||||
std::string type_name_dest = GenTypeNameDest(lang, field.value.type);
|
||||
std::string dest_mask = DestinationMask(lang, field.value.type, true);
|
||||
std::string dest_cast = DestinationCast(lang, field.value.type);
|
||||
std::string src_cast = SourceCast(lang, field.value.type);
|
||||
std::string method_start = " public " + type_name_dest + " " +
|
||||
MakeCamel(field.name, lang.first_camel_upper);
|
||||
|
||||
// Most field accessors need to retrieve and test the field offset first,
|
||||
// this is the prefix code for that:
|
||||
auto offset_prefix = " { int o = __offset(" +
|
||||
NumToString(field.value.offset) +
|
||||
"); return o != 0 ? ";
|
||||
// Generate the accessors that don't do object reuse.
|
||||
if (field.value.type.base_type == BASE_TYPE_STRUCT) {
|
||||
// Calls the accessor that takes an accessor object with a new object.
|
||||
code += method_start + "() { return ";
|
||||
code += MakeCamel(field.name, lang.first_camel_upper);
|
||||
code += "(new ";
|
||||
code += type_name + "()); }\n";
|
||||
if (lang.language == GeneratorOptions::kCSharp) {
|
||||
code += method_start + " { get { return Get";
|
||||
code += MakeCamel(field.name, lang.first_camel_upper);
|
||||
code += "(new ";
|
||||
code += type_name + "()); } }\n";
|
||||
method_start = " public " + type_name_dest + " Get" + MakeCamel(field.name, lang.first_camel_upper);
|
||||
}
|
||||
else {
|
||||
code += method_start + "() { return ";
|
||||
code += MakeCamel(field.name, lang.first_camel_upper);
|
||||
code += "(new ";
|
||||
code += type_name + "()); }\n";
|
||||
}
|
||||
} else if (field.value.type.base_type == BASE_TYPE_VECTOR &&
|
||||
field.value.type.element == BASE_TYPE_STRUCT) {
|
||||
// Accessors for vectors of structs also take accessor objects, this
|
||||
// generates a variant without that argument.
|
||||
code += method_start + "(int j) { return ";
|
||||
if (lang.language == GeneratorOptions::kCSharp) {
|
||||
method_start = " public " + type_name_dest + " Get" + MakeCamel(field.name, lang.first_camel_upper);
|
||||
code += method_start + "(int j) { return Get";
|
||||
} else {
|
||||
code += method_start + "(int j) { return ";
|
||||
}
|
||||
code += MakeCamel(field.name, lang.first_camel_upper);
|
||||
code += "(new ";
|
||||
code += type_name + "(), j); }\n";
|
||||
} else if (field.value.type.base_type == BASE_TYPE_VECTOR) {
|
||||
if (lang.language == GeneratorOptions::kCSharp) {
|
||||
method_start = " public " + type_name_dest + " Get" + MakeCamel(field.name, lang.first_camel_upper);
|
||||
}
|
||||
} else if (field.value.type.base_type == BASE_TYPE_UNION) {
|
||||
if (lang.language == GeneratorOptions::kCSharp) {
|
||||
// union types in C# use generic Table-derived type for better type safety
|
||||
method_start = " public " + type_name_dest + " Get" + MakeCamel(field.name, lang.first_camel_upper) + "<TTable>";
|
||||
offset_prefix = " where TTable : Table" + offset_prefix;
|
||||
type_name = type_name_dest;
|
||||
}
|
||||
}
|
||||
std::string getter = dest_cast + GenGetter(lang, field.value.type);
|
||||
code += method_start + "(";
|
||||
// Most field accessors need to retrieve and test the field offset first,
|
||||
// this is the prefix code for that:
|
||||
auto offset_prefix = ") { int o = __offset(" +
|
||||
NumToString(field.value.offset) +
|
||||
"); return o != 0 ? ";
|
||||
code += method_start;
|
||||
std::string default_cast = "";
|
||||
if (lang.language == GeneratorOptions::kCSharp)
|
||||
default_cast = "(" + type_name_dest + ")";
|
||||
std::string member_suffix = "";
|
||||
if (IsScalar(field.value.type.base_type)) {
|
||||
code += lang.getter_prefix;
|
||||
member_suffix = lang.getter_suffix;
|
||||
if (struct_def.fixed) {
|
||||
code += ") { return " + getter;
|
||||
code += " { return " + getter;
|
||||
code += "(bb_pos + " + NumToString(field.value.offset) + ")";
|
||||
code += dest_mask;
|
||||
} else {
|
||||
code += offset_prefix + getter;
|
||||
code += "(o + bb_pos)" + dest_mask + " : " + default_cast;
|
||||
code += GenDefaultValue(field.value);
|
||||
code += GenDefaultValue(lang, field.value, false);
|
||||
}
|
||||
} else {
|
||||
switch (field.value.type.base_type) {
|
||||
case BASE_TYPE_STRUCT:
|
||||
code += type_name + " obj";
|
||||
code += "(" + type_name + " obj";
|
||||
if (struct_def.fixed) {
|
||||
code += ") { return obj.__init(bb_pos + ";
|
||||
code += NumToString(field.value.offset) + ", bb)";
|
||||
} else {
|
||||
code += ")";
|
||||
code += offset_prefix;
|
||||
code += "obj.__init(";
|
||||
code += field.value.type.struct_def->fixed
|
||||
@@ -479,15 +729,18 @@ static void GenStruct(const LanguageParameters &lang, const Parser &parser,
|
||||
}
|
||||
break;
|
||||
case BASE_TYPE_STRING:
|
||||
code += offset_prefix + getter +"(o + bb_pos) : null";
|
||||
code += lang.getter_prefix;
|
||||
member_suffix = lang.getter_suffix;
|
||||
code += offset_prefix + getter + "(o + bb_pos) : null";
|
||||
break;
|
||||
case BASE_TYPE_VECTOR: {
|
||||
auto vectortype = field.value.type.VectorType();
|
||||
code += "(";
|
||||
if (vectortype.base_type == BASE_TYPE_STRUCT) {
|
||||
code += type_name + " obj, ";
|
||||
getter = "obj.__init";
|
||||
}
|
||||
code += "int j" + offset_prefix + getter +"(";
|
||||
code += "int j)" + offset_prefix + getter +"(";
|
||||
auto index = "__vector(o) + j * " +
|
||||
NumToString(InlineSize(vectortype));
|
||||
if (vectortype.base_type == BASE_TYPE_STRUCT) {
|
||||
@@ -499,24 +752,30 @@ static void GenStruct(const LanguageParameters &lang, const Parser &parser,
|
||||
code += index;
|
||||
}
|
||||
code += ")" + dest_mask + " : ";
|
||||
code += IsScalar(field.value.type.element)
|
||||
? default_cast + "0"
|
||||
: "null";
|
||||
|
||||
code += field.value.type.element == BASE_TYPE_BOOL ? "false" :
|
||||
(IsScalar(field.value.type.element) ? default_cast + "0" : "null");
|
||||
break;
|
||||
}
|
||||
case BASE_TYPE_UNION:
|
||||
code += type_name + " obj" + offset_prefix + getter;
|
||||
code += "(" + type_name + " obj)" + offset_prefix + getter;
|
||||
code += "(obj, o) : null";
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
code += "; }\n";
|
||||
code += "; ";
|
||||
code += member_suffix;
|
||||
code += "}\n";
|
||||
if (field.value.type.base_type == BASE_TYPE_VECTOR) {
|
||||
code += " public int " + MakeCamel(field.name, lang.first_camel_upper);
|
||||
code += "Length(" + offset_prefix;
|
||||
code += "__vector_len(o) : 0; }\n";
|
||||
code += "Length";
|
||||
code += lang.getter_prefix;
|
||||
code += offset_prefix;
|
||||
code += "__vector_len(o) : 0; ";
|
||||
code += lang.getter_suffix;
|
||||
code += "}\n";
|
||||
}
|
||||
// Generate a ByteBuffer accessor for strings & vectors of scalars.
|
||||
if (((field.value.type.base_type == BASE_TYPE_VECTOR &&
|
||||
@@ -531,17 +790,54 @@ static void GenStruct(const LanguageParameters &lang, const Parser &parser,
|
||||
InlineSize(field.value.type.VectorType()));
|
||||
code += "); }\n";
|
||||
}
|
||||
|
||||
// generate mutators for scalar fields or vectors of scalars
|
||||
if (opts.mutable_buffer) {
|
||||
auto underlying_type = field.value.type.base_type == BASE_TYPE_VECTOR
|
||||
? field.value.type.VectorType()
|
||||
: field.value.type;
|
||||
// boolean parameters have to be explicitly converted to byte representation
|
||||
auto setter_parameter = underlying_type.base_type == BASE_TYPE_BOOL ? "(byte)(" + field.name + " ? 1 : 0)" : field.name;
|
||||
auto mutator_prefix = MakeCamel("mutate", lang.first_camel_upper);
|
||||
//a vector mutator also needs the index of the vector element it should mutate
|
||||
auto mutator_params = (field.value.type.base_type == BASE_TYPE_VECTOR ? "(int j, " : "(") +
|
||||
GenTypeNameDest(lang, underlying_type) + " " +
|
||||
field.name + ") { ";
|
||||
auto setter_index = field.value.type.base_type == BASE_TYPE_VECTOR
|
||||
? "__vector(o) + j * " + NumToString(InlineSize(underlying_type))
|
||||
: (struct_def.fixed ? "bb_pos + " + NumToString(field.value.offset) : "o + bb_pos");
|
||||
|
||||
|
||||
if (IsScalar(field.value.type.base_type) ||
|
||||
(field.value.type.base_type == BASE_TYPE_VECTOR &&
|
||||
IsScalar(field.value.type.VectorType().base_type))) {
|
||||
code += " public ";
|
||||
code += struct_def.fixed ? "void " : lang.bool_type;
|
||||
code += mutator_prefix + MakeCamel(field.name, true);
|
||||
code += mutator_params;
|
||||
if (struct_def.fixed) {
|
||||
code += GenSetter(lang, underlying_type) + "(" + setter_index + ", ";
|
||||
code += src_cast + setter_parameter + "); }\n";
|
||||
} else {
|
||||
code += "int o = __offset(" + NumToString(field.value.offset) + ");";
|
||||
code += " if (o != 0) { " + GenSetter(lang, underlying_type);
|
||||
code += "(" + setter_index + ", " + src_cast + setter_parameter + "); return true; } else { return false; } }\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
code += "\n";
|
||||
if (struct_def.fixed) {
|
||||
// create a struct constructor function
|
||||
code += " public static int " + FunctionStart(lang, 'C') + "reate";
|
||||
code += " public static " + GenOffsetType(lang, struct_def) + " ";
|
||||
code += FunctionStart(lang, 'C') + "reate";
|
||||
code += struct_def.name + "(FlatBufferBuilder builder";
|
||||
GenStructArgs(lang, struct_def, code_ptr, "");
|
||||
code += ") {\n";
|
||||
GenStructBody(lang, struct_def, code_ptr, "");
|
||||
code += " return builder.";
|
||||
code += FunctionStart(lang, 'O') + "ffset();\n }\n";
|
||||
code += " return ";
|
||||
code += GenOffsetConstruct(lang, struct_def, "builder." + std::string(lang.get_fbb_offset));
|
||||
code += ";\n }\n";
|
||||
} else {
|
||||
// Generate a method that creates a table in one go. This is only possible
|
||||
// when the table has no struct fields, since those have to be created
|
||||
@@ -560,23 +856,31 @@ static void GenStruct(const LanguageParameters &lang, const Parser &parser,
|
||||
}
|
||||
if (has_no_struct_fields && num_fields) {
|
||||
// Generate a table constructor of the form:
|
||||
// public static void createName(FlatBufferBuilder builder, args...)
|
||||
code += " public static int " + FunctionStart(lang, 'C') + "reate";
|
||||
code += struct_def.name;
|
||||
// public static int createName(FlatBufferBuilder builder, args...)
|
||||
code += " public static " + GenOffsetType(lang, struct_def) + " ";
|
||||
code += FunctionStart(lang, 'C') + "reate" + struct_def.name;
|
||||
code += "(FlatBufferBuilder builder";
|
||||
for (auto it = struct_def.fields.vec.begin();
|
||||
it != struct_def.fields.vec.end(); ++it) {
|
||||
auto &field = **it;
|
||||
if (field.deprecated) continue;
|
||||
code += ",\n ";
|
||||
code += GenTypeBasic(lang,
|
||||
DestinationType(lang, field.value.type, false));
|
||||
code += GenTypeForUser(lang,
|
||||
DestinationType(lang, field.value.type, false));
|
||||
code += " ";
|
||||
code += field.name;
|
||||
// Java doesn't have defaults, which means this method must always
|
||||
// supply all arguments, and thus won't compile when fields are added.
|
||||
if (lang.language != GeneratorOptions::kJava) {
|
||||
code += " = " + GenDefaultValue(field.value);
|
||||
code += " = ";
|
||||
// in C#, enum values have their own type, so we need to cast the
|
||||
// numeric value to the proper type
|
||||
if (lang.language == GeneratorOptions::kCSharp &&
|
||||
field.value.type.enum_def != nullptr &&
|
||||
field.value.type.base_type != BASE_TYPE_UNION) {
|
||||
code += "(" + field.value.type.enum_def->name + ")";
|
||||
}
|
||||
code += GenDefaultValue(lang, field.value, false);
|
||||
}
|
||||
}
|
||||
code += ") {\n builder.";
|
||||
@@ -618,21 +922,18 @@ static void GenStruct(const LanguageParameters &lang, const Parser &parser,
|
||||
code += " public static void " + FunctionStart(lang, 'A') + "dd";
|
||||
code += MakeCamel(field.name);
|
||||
code += "(FlatBufferBuilder builder, ";
|
||||
code += GenTypeBasic(lang,
|
||||
DestinationType(lang, field.value.type, false));
|
||||
code += GenTypeForUser(lang,
|
||||
DestinationType(lang, field.value.type, false));
|
||||
auto argname = MakeCamel(field.name, false);
|
||||
if (!IsScalar(field.value.type.base_type)) argname += "Offset";
|
||||
code += " " + argname + ") { builder." + FunctionStart(lang, 'A') + "dd";
|
||||
code += GenMethod(lang, field.value.type) + "(";
|
||||
code += NumToString(it - struct_def.fields.vec.begin()) + ", ";
|
||||
std::string type_mask = DestinationMask(lang, field.value.type, false);
|
||||
if (type_mask.length()) {
|
||||
code += "(" + GenTypeBasic(lang, field.value.type) + ")";
|
||||
code += "(" + argname + type_mask + ")";
|
||||
} else {
|
||||
code += argname;
|
||||
code += DestinationValue(lang, argname, field.value.type);
|
||||
if(!IsScalar(field.value.type.base_type) && field.value.type.base_type != BASE_TYPE_UNION && lang.language == GeneratorOptions::kCSharp) {
|
||||
code += ".Value";
|
||||
}
|
||||
code += ", " + GenDefaultValue(field.value);
|
||||
code += ", " + GenDefaultValue(lang, field.value, true);
|
||||
code += "); }\n";
|
||||
if (field.value.type.base_type == BASE_TYPE_VECTOR) {
|
||||
auto vector_type = field.value.type.VectorType();
|
||||
@@ -640,7 +941,7 @@ static void GenStruct(const LanguageParameters &lang, const Parser &parser,
|
||||
auto elem_size = InlineSize(vector_type);
|
||||
if (!IsStruct(vector_type)) {
|
||||
// Generate a method to create a vector from a Java array.
|
||||
code += " public static int " + FunctionStart(lang, 'C') + "reate";
|
||||
code += " public static " + GenVectorOffsetType(lang) + " " + FunctionStart(lang, 'C') + "reate";
|
||||
code += MakeCamel(field.name);
|
||||
code += "Vector(FlatBufferBuilder builder, ";
|
||||
code += GenTypeBasic(lang, vector_type) + "[] data) ";
|
||||
@@ -652,8 +953,12 @@ static void GenStruct(const LanguageParameters &lang, const Parser &parser,
|
||||
code += FunctionStart(lang, 'L') + "ength - 1; i >= 0; i--) builder.";
|
||||
code += FunctionStart(lang, 'A') + "dd";
|
||||
code += GenMethod(lang, vector_type);
|
||||
code += "(data[i]); return builder.";
|
||||
code += FunctionStart(lang, 'E') + "ndVector(); }\n";
|
||||
code += "(data[i]";
|
||||
if(lang.language == GeneratorOptions::kCSharp &&
|
||||
(vector_type.base_type == BASE_TYPE_STRUCT || vector_type.base_type == BASE_TYPE_STRING))
|
||||
code += ".Value";
|
||||
code += "); return ";
|
||||
code += "builder." + FunctionStart(lang, 'E') + "ndVector(); }\n";
|
||||
}
|
||||
// Generate a method to start a vector, data to be added manually after.
|
||||
code += " public static void " + FunctionStart(lang, 'S') + "tart";
|
||||
@@ -665,7 +970,7 @@ static void GenStruct(const LanguageParameters &lang, const Parser &parser,
|
||||
code += "); }\n";
|
||||
}
|
||||
}
|
||||
code += " public static int ";
|
||||
code += " public static " + GenOffsetType(lang, struct_def) + " ";
|
||||
code += FunctionStart(lang, 'E') + "nd" + struct_def.name;
|
||||
code += "(FlatBufferBuilder builder) {\n int o = builder.";
|
||||
code += FunctionStart(lang, 'E') + "ndObject();\n";
|
||||
@@ -679,12 +984,16 @@ static void GenStruct(const LanguageParameters &lang, const Parser &parser,
|
||||
code += "); // " + field.name + "\n";
|
||||
}
|
||||
}
|
||||
code += " return o;\n }\n";
|
||||
if (parser.root_struct_def == &struct_def) {
|
||||
code += " return " + GenOffsetConstruct(lang, struct_def, "o") + ";\n }\n";
|
||||
if (parser.root_struct_def_ == &struct_def) {
|
||||
code += " public static void ";
|
||||
code += FunctionStart(lang, 'F') + "inish" + struct_def.name;
|
||||
code += "Buffer(FlatBufferBuilder builder, int offset) { ";
|
||||
code += "builder." + FunctionStart(lang, 'F') + "inish(offset";
|
||||
code += "Buffer(FlatBufferBuilder builder, " + GenOffsetType(lang, struct_def) + " offset) {";
|
||||
code += " builder." + FunctionStart(lang, 'F') + "inish(offset";
|
||||
if (lang.language == GeneratorOptions::kCSharp) {
|
||||
code += ".Value";
|
||||
}
|
||||
|
||||
if (parser.file_identifier_.length())
|
||||
code += ", \"" + parser.file_identifier_ + "\"";
|
||||
code += "); }\n";
|
||||
@@ -696,8 +1005,8 @@ static void GenStruct(const LanguageParameters &lang, const Parser &parser,
|
||||
// Save out the generated code for a single class while adding
|
||||
// declaration boilerplate.
|
||||
static bool SaveClass(const LanguageParameters &lang, const Parser &parser,
|
||||
const Definition &def, const std::string &classcode,
|
||||
const std::string &path, bool needs_includes) {
|
||||
const std::string &defname, const std::string &classcode,
|
||||
const std::string &path, bool needs_includes, bool onefile) {
|
||||
if (!classcode.length()) return true;
|
||||
|
||||
std::string namespace_general;
|
||||
@@ -708,44 +1017,63 @@ static bool SaveClass(const LanguageParameters &lang, const Parser &parser,
|
||||
namespace_general += ".";
|
||||
}
|
||||
namespace_general += *it;
|
||||
namespace_dir += *it + kPathSeparator;
|
||||
if (!onefile) {
|
||||
namespace_dir += *it + kPathSeparator;
|
||||
}
|
||||
|
||||
}
|
||||
EnsureDirExists(namespace_dir);
|
||||
|
||||
std::string code = "// automatically generated, do not modify\n\n";
|
||||
code += lang.namespace_ident + namespace_general + lang.namespace_begin;
|
||||
code += "\n\n";
|
||||
if (!namespace_general.empty()) {
|
||||
code += lang.namespace_ident + namespace_general + lang.namespace_begin;
|
||||
code += "\n\n";
|
||||
}
|
||||
if (needs_includes) code += lang.includes;
|
||||
code += classcode;
|
||||
code += lang.namespace_end;
|
||||
auto filename = namespace_dir + def.name + lang.file_extension;
|
||||
if (!namespace_general.empty()) code += lang.namespace_end;
|
||||
auto filename = namespace_dir + defname + lang.file_extension;
|
||||
return SaveFile(filename.c_str(), code, false);
|
||||
}
|
||||
|
||||
bool GenerateGeneral(const Parser &parser,
|
||||
const std::string &path,
|
||||
const std::string & /*file_name*/,
|
||||
const std::string & file_name,
|
||||
const GeneratorOptions &opts) {
|
||||
|
||||
assert(opts.lang <= GeneratorOptions::kMAX);
|
||||
auto lang = language_parameters[opts.lang];
|
||||
std::string one_file_code;
|
||||
|
||||
for (auto it = parser.enums_.vec.begin();
|
||||
it != parser.enums_.vec.end(); ++it) {
|
||||
std::string enumcode;
|
||||
GenEnum(lang, **it, &enumcode);
|
||||
if (!SaveClass(lang, parser, **it, enumcode, path, false))
|
||||
return false;
|
||||
if (opts.one_file) {
|
||||
one_file_code += enumcode;
|
||||
}
|
||||
else {
|
||||
if (!SaveClass(lang, parser, (**it).name, enumcode, path, false, false))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
for (auto it = parser.structs_.vec.begin();
|
||||
it != parser.structs_.vec.end(); ++it) {
|
||||
std::string declcode;
|
||||
GenStruct(lang, parser, **it, &declcode);
|
||||
if (!SaveClass(lang, parser, **it, declcode, path, true))
|
||||
return false;
|
||||
GenStruct(lang, parser, **it, opts, &declcode);
|
||||
if (opts.one_file) {
|
||||
one_file_code += declcode;
|
||||
}
|
||||
else {
|
||||
if (!SaveClass(lang, parser, (**it).name, declcode, path, true, false))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (opts.one_file) {
|
||||
return SaveClass(lang, parser, file_name, one_file_code,path, true, true);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -828,7 +1156,7 @@ std::string BinaryMakeRule(const Parser &parser,
|
||||
std::string make_rule = BinaryFileName(parser, path, filebase) + ": " +
|
||||
file_name;
|
||||
auto included_files = parser.GetIncludedFilesRecursive(
|
||||
parser.root_struct_def->file);
|
||||
parser.root_struct_def_->file);
|
||||
for (auto it = included_files.begin();
|
||||
it != included_files.end(); ++it) {
|
||||
make_rule += " " + *it;
|
||||
|
||||
@@ -144,6 +144,19 @@ static void GetVectorLen(const StructDef &struct_def,
|
||||
code += "\treturn 0\n}\n\n";
|
||||
}
|
||||
|
||||
// Get a [ubyte] vector as a byte slice.
|
||||
static void GetUByteSlice(const StructDef &struct_def,
|
||||
const FieldDef &field,
|
||||
std::string *code_ptr) {
|
||||
std::string &code = *code_ptr;
|
||||
|
||||
GenReceiver(struct_def, code_ptr);
|
||||
code += " " + MakeCamel(field.name) + "Bytes(";
|
||||
code += ") []byte " + OffsetPrefix(field);
|
||||
code += "\t\treturn rcv._tab.ByteVector(o + rcv._tab.Pos)\n\t}\n";
|
||||
code += "\treturn nil\n}\n\n";
|
||||
}
|
||||
|
||||
// Get the value of a struct's scalar.
|
||||
static void GetScalarFieldOfStruct(const StructDef &struct_def,
|
||||
const FieldDef &field,
|
||||
@@ -225,7 +238,7 @@ static void GetStringField(const StructDef &struct_def,
|
||||
code += " " + MakeCamel(field.name);
|
||||
code += "() " + TypeName(field) + " ";
|
||||
code += OffsetPrefix(field) + "\t\treturn " + GenGetter(field.value.type);
|
||||
code += "(o + rcv._tab.Pos)\n\t}\n\treturn \"\"\n";
|
||||
code += "(o + rcv._tab.Pos)\n\t}\n\treturn nil\n";
|
||||
code += "}\n\n";
|
||||
}
|
||||
|
||||
@@ -288,7 +301,7 @@ static void GetMemberOfVectorOfNonStruct(const StructDef &struct_def,
|
||||
code += NumToString(InlineSize(vectortype)) + "))\n";
|
||||
code += "\t}\n";
|
||||
if (vectortype.base_type == BASE_TYPE_STRING) {
|
||||
code += "\treturn \"\"\n";
|
||||
code += "\treturn nil\n";
|
||||
} else {
|
||||
code += "\treturn 0\n";
|
||||
}
|
||||
@@ -317,9 +330,9 @@ static void StructBuilderArgs(const StructDef &struct_def,
|
||||
if (IsStruct(field.value.type)) {
|
||||
// Generate arguments for a struct inside a struct. To ensure names
|
||||
// don't clash, and to make it obvious these arguments are constructing
|
||||
// a nested struct, prefix the name with the struct name.
|
||||
// a nested struct, prefix the name with the field name.
|
||||
StructBuilderArgs(*field.value.type.struct_def,
|
||||
(field.value.type.struct_def->name + "_").c_str(),
|
||||
(nameprefix + (field.name + "_")).c_str(),
|
||||
code_ptr);
|
||||
} else {
|
||||
std::string &code = *code_ptr;
|
||||
@@ -352,7 +365,7 @@ static void StructBuilderBody(const StructDef &struct_def,
|
||||
code += " builder.Pad(" + NumToString(field.padding) + ")\n";
|
||||
if (IsStruct(field.value.type)) {
|
||||
StructBuilderBody(*field.value.type.struct_def,
|
||||
(field.value.type.struct_def->name + "_").c_str(),
|
||||
(nameprefix + (field.name + "_")).c_str(),
|
||||
code_ptr);
|
||||
} else {
|
||||
code += " builder.Prepend" + GenMethod(field) + "(";
|
||||
@@ -443,7 +456,7 @@ static void GenReceiver(const StructDef &struct_def, std::string *code_ptr) {
|
||||
static void GenStructAccessor(const StructDef &struct_def,
|
||||
const FieldDef &field,
|
||||
std::string *code_ptr) {
|
||||
GenComment(field.doc_comment, code_ptr, "");
|
||||
GenComment(field.doc_comment, code_ptr, nullptr, "");
|
||||
if (IsScalar(field.value.type.base_type)) {
|
||||
if (struct_def.fixed) {
|
||||
GetScalarFieldOfStruct(struct_def, field, code_ptr);
|
||||
@@ -480,6 +493,9 @@ static void GenStructAccessor(const StructDef &struct_def,
|
||||
}
|
||||
if (field.value.type.base_type == BASE_TYPE_VECTOR) {
|
||||
GetVectorLen(struct_def, field, code_ptr);
|
||||
if (field.value.type.element == BASE_TYPE_UCHAR) {
|
||||
GetUByteSlice(struct_def, field, code_ptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -510,7 +526,7 @@ static void GenStruct(const StructDef &struct_def,
|
||||
StructDef *root_struct_def) {
|
||||
if (struct_def.generated) return;
|
||||
|
||||
GenComment(struct_def.doc_comment, code_ptr);
|
||||
GenComment(struct_def.doc_comment, code_ptr, nullptr);
|
||||
BeginClass(struct_def, code_ptr);
|
||||
if (&struct_def == root_struct_def) {
|
||||
// Generate a special accessor for the table that has been declared as
|
||||
@@ -542,13 +558,13 @@ static void GenStruct(const StructDef &struct_def,
|
||||
static void GenEnum(const EnumDef &enum_def, std::string *code_ptr) {
|
||||
if (enum_def.generated) return;
|
||||
|
||||
GenComment(enum_def.doc_comment, code_ptr);
|
||||
GenComment(enum_def.doc_comment, code_ptr, nullptr);
|
||||
BeginEnum(code_ptr);
|
||||
for (auto it = enum_def.vals.vec.begin();
|
||||
it != enum_def.vals.vec.end();
|
||||
++it) {
|
||||
auto &ev = **it;
|
||||
GenComment(ev.doc_comment, code_ptr, "\t");
|
||||
GenComment(ev.doc_comment, code_ptr, nullptr, "\t");
|
||||
EnumMember(enum_def, ev, code_ptr);
|
||||
}
|
||||
EndEnum(code_ptr);
|
||||
@@ -557,7 +573,7 @@ static void GenEnum(const EnumDef &enum_def, std::string *code_ptr) {
|
||||
// Returns the function name that is able to read a value of the given type.
|
||||
static std::string GenGetter(const Type &type) {
|
||||
switch (type.base_type) {
|
||||
case BASE_TYPE_STRING: return "rcv._tab.String";
|
||||
case BASE_TYPE_STRING: return "rcv._tab.ByteVector";
|
||||
case BASE_TYPE_UNION: return "rcv._tab.Union";
|
||||
case BASE_TYPE_VECTOR: return GenGetter(type.VectorType());
|
||||
default:
|
||||
@@ -600,7 +616,8 @@ static bool SaveType(const Parser &parser, const Definition &def,
|
||||
|
||||
static std::string GenTypeBasic(const Type &type) {
|
||||
static const char *ctypename[] = {
|
||||
#define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE) #GTYPE,
|
||||
#define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \
|
||||
#GTYPE,
|
||||
FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
|
||||
#undef FLATBUFFERS_TD
|
||||
};
|
||||
@@ -610,7 +627,7 @@ static std::string GenTypeBasic(const Type &type) {
|
||||
static std::string GenTypePointer(const Type &type) {
|
||||
switch (type.base_type) {
|
||||
case BASE_TYPE_STRING:
|
||||
return "string";
|
||||
return "[]byte";
|
||||
case BASE_TYPE_VECTOR:
|
||||
return GenTypeGet(type.VectorType());
|
||||
case BASE_TYPE_STRUCT:
|
||||
@@ -660,7 +677,7 @@ bool GenerateGo(const Parser &parser,
|
||||
for (auto it = parser.structs_.vec.begin();
|
||||
it != parser.structs_.vec.end(); ++it) {
|
||||
std::string declcode;
|
||||
go::GenStruct(**it, &declcode, parser.root_struct_def);
|
||||
go::GenStruct(**it, &declcode, parser.root_struct_def_);
|
||||
if (!go::SaveType(parser, **it, declcode, path, true))
|
||||
return false;
|
||||
}
|
||||
|
||||
727
src/idl_gen_js.cpp
Normal file
727
src/idl_gen_js.cpp
Normal file
@@ -0,0 +1,727 @@
|
||||
/*
|
||||
* Copyright 2014 Google Inc. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
// independent from idl_parser, since this code is not needed for most clients
|
||||
|
||||
#include "flatbuffers/flatbuffers.h"
|
||||
#include "flatbuffers/idl.h"
|
||||
#include "flatbuffers/util.h"
|
||||
|
||||
namespace flatbuffers {
|
||||
namespace js {
|
||||
|
||||
static void GenNamespaces(const Parser &parser, std::string *code_ptr,
|
||||
std::string *exports_ptr) {
|
||||
std::set<std::string> namespaces;
|
||||
|
||||
for (auto it = parser.namespaces_.begin();
|
||||
it != parser.namespaces_.end(); ++it) {
|
||||
std::string namespace_so_far;
|
||||
|
||||
// Gather all parent namespaces for this namespace
|
||||
for (auto component = (*it)->components.begin();
|
||||
component != (*it)->components.end(); ++component) {
|
||||
if (!namespace_so_far.empty()) {
|
||||
namespace_so_far += '.';
|
||||
}
|
||||
namespace_so_far += *component;
|
||||
namespaces.insert(namespace_so_far);
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure parent namespaces come before child namespaces
|
||||
std::vector<std::string> sorted_namespaces(
|
||||
namespaces.begin(), namespaces.end());
|
||||
std::sort(sorted_namespaces.begin(), sorted_namespaces.end());
|
||||
|
||||
// Emit namespaces in a form that Closure Compiler can optimize
|
||||
std::string &code = *code_ptr;
|
||||
std::string &exports = *exports_ptr;
|
||||
for (auto it = sorted_namespaces.begin();
|
||||
it != sorted_namespaces.end(); it++) {
|
||||
code += "/**\n * @const\n*/\n";
|
||||
if (it->find('.') == std::string::npos) {
|
||||
code += "var ";
|
||||
exports += "this." + *it + " = " + *it + ";\n";
|
||||
}
|
||||
code += *it + " = " + *it + " || {};\n\n";
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure that a type is prefixed with its namespace whenever it is used
|
||||
// outside of its namespace.
|
||||
static std::string WrapInNameSpace(const Namespace *ns,
|
||||
const std::string &name) {
|
||||
std::string qualified_name;
|
||||
for (auto it = ns->components.begin();
|
||||
it != ns->components.end(); ++it) {
|
||||
qualified_name += *it + ".";
|
||||
}
|
||||
return qualified_name + name;
|
||||
}
|
||||
|
||||
static std::string WrapInNameSpace(const Definition &def) {
|
||||
return WrapInNameSpace(def.defined_namespace, def.name);
|
||||
}
|
||||
|
||||
// Generate a documentation comment, if available.
|
||||
static void GenDocComment(const std::vector<std::string> &dc,
|
||||
std::string *code_ptr,
|
||||
const std::string &extra_lines,
|
||||
const char *indent = nullptr) {
|
||||
if (dc.empty() && extra_lines.empty()) {
|
||||
// Don't output empty comment blocks with 0 lines of comment content.
|
||||
return;
|
||||
}
|
||||
|
||||
std::string &code = *code_ptr;
|
||||
if (indent) code += indent;
|
||||
code += "/**\n";
|
||||
for (auto it = dc.begin(); it != dc.end(); ++it) {
|
||||
if (indent) code += indent;
|
||||
code += " *" + *it + "\n";
|
||||
}
|
||||
if (!extra_lines.empty()) {
|
||||
if (!dc.empty()) {
|
||||
if (indent) code += indent;
|
||||
code += " *\n";
|
||||
}
|
||||
if (indent) code += indent;
|
||||
std::string::size_type start = 0;
|
||||
for (;;) {
|
||||
auto end = extra_lines.find('\n', start);
|
||||
if (end != std::string::npos) {
|
||||
code += " * " + extra_lines.substr(start, end - start) + "\n";
|
||||
start = end + 1;
|
||||
} else {
|
||||
code += " * " + extra_lines.substr(start) + "\n";
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (indent) code += indent;
|
||||
code += " */\n";
|
||||
}
|
||||
|
||||
static void GenDocComment(std::string *code_ptr,
|
||||
const std::string &extra_lines) {
|
||||
GenDocComment(std::vector<std::string>(), code_ptr, extra_lines);
|
||||
}
|
||||
|
||||
// Generate an enum declaration and an enum string lookup table.
|
||||
static void GenEnum(EnumDef &enum_def, std::string *code_ptr,
|
||||
std::string *exports_ptr) {
|
||||
if (enum_def.generated) return;
|
||||
std::string &code = *code_ptr;
|
||||
std::string &exports = *exports_ptr;
|
||||
GenDocComment(enum_def.doc_comment, code_ptr, "@enum");
|
||||
if (enum_def.defined_namespace->components.empty()) {
|
||||
code += "var ";
|
||||
exports += "this." + enum_def.name + " = " + enum_def.name + ";\n";
|
||||
}
|
||||
code += WrapInNameSpace(enum_def) + " = {\n";
|
||||
for (auto it = enum_def.vals.vec.begin();
|
||||
it != enum_def.vals.vec.end(); ++it) {
|
||||
auto &ev = **it;
|
||||
if (!ev.doc_comment.empty()) {
|
||||
if (it != enum_def.vals.vec.begin()) {
|
||||
code += '\n';
|
||||
}
|
||||
GenDocComment(ev.doc_comment, code_ptr, "", " ");
|
||||
}
|
||||
code += " " + ev.name + ": " + NumToString(ev.value);
|
||||
code += (it + 1) != enum_def.vals.vec.end() ? ",\n" : "\n";
|
||||
}
|
||||
code += "};\n\n";
|
||||
}
|
||||
|
||||
static std::string GenType(const Type &type) {
|
||||
switch (type.base_type) {
|
||||
case BASE_TYPE_BOOL:
|
||||
case BASE_TYPE_CHAR: return "Int8";
|
||||
case BASE_TYPE_UTYPE:
|
||||
case BASE_TYPE_UCHAR: return "Uint8";
|
||||
case BASE_TYPE_SHORT: return "Int16";
|
||||
case BASE_TYPE_USHORT: return "Uint16";
|
||||
case BASE_TYPE_INT: return "Int32";
|
||||
case BASE_TYPE_UINT: return "Uint32";
|
||||
case BASE_TYPE_LONG: return "Int64";
|
||||
case BASE_TYPE_ULONG: return "Uint64";
|
||||
case BASE_TYPE_FLOAT: return "Float32";
|
||||
case BASE_TYPE_DOUBLE: return "Float64";
|
||||
case BASE_TYPE_STRING: return "String";
|
||||
case BASE_TYPE_VECTOR: return GenType(type.VectorType());
|
||||
case BASE_TYPE_STRUCT: return type.struct_def->name;
|
||||
default: return "Table";
|
||||
}
|
||||
}
|
||||
|
||||
static std::string GenGetter(const Type &type, const std::string &arguments) {
|
||||
switch (type.base_type) {
|
||||
case BASE_TYPE_STRING: return "this.bb.__string" + arguments;
|
||||
case BASE_TYPE_STRUCT: return "this.bb.__struct" + arguments;
|
||||
case BASE_TYPE_UNION: return "this.bb.__union" + arguments;
|
||||
case BASE_TYPE_VECTOR: return GenGetter(type.VectorType(), arguments);
|
||||
default: {
|
||||
auto getter = "this.bb.read" + MakeCamel(GenType(type)) + arguments;
|
||||
if (type.base_type == BASE_TYPE_BOOL) {
|
||||
getter = "!!" + getter;
|
||||
}
|
||||
if (type.enum_def) {
|
||||
getter = "/** @type {" + WrapInNameSpace(*type.enum_def) + "} */ (" +
|
||||
getter + ")";
|
||||
}
|
||||
return getter;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static std::string GenDefaultValue(const Value &value) {
|
||||
if (value.type.enum_def) {
|
||||
if (auto val = value.type.enum_def->ReverseLookup(
|
||||
atoi(value.constant.c_str()), false)) {
|
||||
return WrapInNameSpace(*value.type.enum_def) + "." + val->name;
|
||||
}
|
||||
}
|
||||
|
||||
switch (value.type.base_type) {
|
||||
case BASE_TYPE_BOOL:
|
||||
return value.constant == "0" ? "false" : "true";
|
||||
|
||||
case BASE_TYPE_STRING:
|
||||
return "null";
|
||||
|
||||
case BASE_TYPE_LONG:
|
||||
case BASE_TYPE_ULONG:
|
||||
if (value.constant != "0") {
|
||||
int64_t constant = StringToInt(value.constant.c_str());
|
||||
return "new flatbuffers.Long(" + NumToString((int32_t)constant) +
|
||||
", " + NumToString((int32_t)(constant >> 32)) + ")";
|
||||
}
|
||||
return "flatbuffers.Long.ZERO";
|
||||
|
||||
default:
|
||||
return value.constant;
|
||||
}
|
||||
}
|
||||
|
||||
static std::string GenTypeName(const Type &type, bool input) {
|
||||
if (!input) {
|
||||
if (type.base_type == BASE_TYPE_STRING) {
|
||||
return "string|Uint8Array";
|
||||
}
|
||||
if (type.base_type == BASE_TYPE_STRUCT) {
|
||||
return WrapInNameSpace(*type.struct_def);
|
||||
}
|
||||
}
|
||||
|
||||
switch (type.base_type) {
|
||||
case BASE_TYPE_BOOL: return "boolean";
|
||||
case BASE_TYPE_LONG:
|
||||
case BASE_TYPE_ULONG: return "flatbuffers.Long";
|
||||
default:
|
||||
if (IsScalar(type.base_type)) {
|
||||
if (type.enum_def) {
|
||||
return WrapInNameSpace(*type.enum_def);
|
||||
}
|
||||
return "number";
|
||||
}
|
||||
return "flatbuffers.Offset";
|
||||
}
|
||||
}
|
||||
|
||||
// Returns the method name for use with add/put calls.
|
||||
static std::string GenWriteMethod(const Type &type) {
|
||||
// Forward to signed versions since unsigned versions don't exist
|
||||
switch (type.base_type) {
|
||||
case BASE_TYPE_UTYPE:
|
||||
case BASE_TYPE_UCHAR: return GenWriteMethod(Type(BASE_TYPE_CHAR));
|
||||
case BASE_TYPE_USHORT: return GenWriteMethod(Type(BASE_TYPE_SHORT));
|
||||
case BASE_TYPE_UINT: return GenWriteMethod(Type(BASE_TYPE_INT));
|
||||
case BASE_TYPE_ULONG: return GenWriteMethod(Type(BASE_TYPE_LONG));
|
||||
default: break;
|
||||
}
|
||||
|
||||
return IsScalar(type.base_type)
|
||||
? MakeCamel(GenType(type))
|
||||
: (IsStruct(type) ? "Struct" : "Offset");
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static std::string MaybeAdd(T value) {
|
||||
return value != 0 ? " + " + NumToString(value) : "";
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static std::string MaybeScale(T value) {
|
||||
return value != 1 ? " * " + NumToString(value) : "";
|
||||
}
|
||||
|
||||
static void GenStructArgs(const StructDef &struct_def,
|
||||
std::string *annotations,
|
||||
std::string *arguments,
|
||||
const std::string &nameprefix) {
|
||||
for (auto it = struct_def.fields.vec.begin();
|
||||
it != struct_def.fields.vec.end(); ++it) {
|
||||
auto &field = **it;
|
||||
if (IsStruct(field.value.type)) {
|
||||
// Generate arguments for a struct inside a struct. To ensure names
|
||||
// don't clash, and to make it obvious these arguments are constructing
|
||||
// a nested struct, prefix the name with the field name.
|
||||
GenStructArgs(*field.value.type.struct_def, annotations, arguments,
|
||||
nameprefix + field.name + "_");
|
||||
} else {
|
||||
*annotations += "@param {" + GenTypeName(field.value.type, true);
|
||||
*annotations += "} " + nameprefix + field.name + "\n";
|
||||
*arguments += ", " + nameprefix + field.name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void GenStructBody(const StructDef &struct_def,
|
||||
std::string *body,
|
||||
const std::string &nameprefix) {
|
||||
*body += " builder.prep(";
|
||||
*body += NumToString(struct_def.minalign) + ", ";
|
||||
*body += NumToString(struct_def.bytesize) + ");\n";
|
||||
|
||||
for (auto it = struct_def.fields.vec.rbegin();
|
||||
it != struct_def.fields.vec.rend(); ++it) {
|
||||
auto &field = **it;
|
||||
if (field.padding) {
|
||||
*body += " builder.pad(" + NumToString(field.padding) + ");\n";
|
||||
}
|
||||
if (IsStruct(field.value.type)) {
|
||||
// Generate arguments for a struct inside a struct. To ensure names
|
||||
// don't clash, and to make it obvious these arguments are constructing
|
||||
// a nested struct, prefix the name with the field name.
|
||||
GenStructBody(*field.value.type.struct_def, body,
|
||||
nameprefix + field.name + "_");
|
||||
} else {
|
||||
*body += " builder.write" + GenWriteMethod(field.value.type) + "(";
|
||||
if (field.value.type.base_type == BASE_TYPE_BOOL) {
|
||||
*body += "+";
|
||||
}
|
||||
*body += nameprefix + field.name + ");\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Generate an accessor struct with constructor for a flatbuffers struct.
|
||||
static void GenStruct(const Parser &parser, StructDef &struct_def,
|
||||
std::string *code_ptr, std::string *exports_ptr) {
|
||||
if (struct_def.generated) return;
|
||||
std::string &code = *code_ptr;
|
||||
std::string &exports = *exports_ptr;
|
||||
|
||||
// Emit constructor
|
||||
bool isStatement = struct_def.defined_namespace->components.empty();
|
||||
std::string object_name = WrapInNameSpace(struct_def);
|
||||
GenDocComment(struct_def.doc_comment, code_ptr, "@constructor");
|
||||
if (isStatement) {
|
||||
exports += "this." + struct_def.name + " = " + struct_def.name + ";\n";
|
||||
code += "function " + object_name;
|
||||
} else {
|
||||
code += object_name + " = function";
|
||||
}
|
||||
code += "() {\n";
|
||||
code += " /**\n";
|
||||
code += " * @type {flatbuffers.ByteBuffer}\n";
|
||||
code += " */\n";
|
||||
code += " this.bb = null;\n";
|
||||
code += "\n";
|
||||
code += " /**\n";
|
||||
code += " * @type {number}\n";
|
||||
code += " */\n";
|
||||
code += " this.bb_pos = 0;\n";
|
||||
code += isStatement ? "}\n\n" : "};\n\n";
|
||||
|
||||
// Generate the __init method that sets the field in a pre-existing
|
||||
// accessor object. This is to allow object reuse.
|
||||
code += "/**\n";
|
||||
code += " * @param {number} i\n";
|
||||
code += " * @param {flatbuffers.ByteBuffer} bb\n";
|
||||
code += " * @returns {" + object_name + "}\n";
|
||||
code += " */\n";
|
||||
code += object_name + ".prototype.__init = function(i, bb) {\n";
|
||||
code += " this.bb_pos = i;\n";
|
||||
code += " this.bb = bb;\n";
|
||||
code += " return this;\n";
|
||||
code += "};\n\n";
|
||||
|
||||
// Generate a special accessor for the table that when used as the root of a
|
||||
// FlatBuffer
|
||||
if (!struct_def.fixed) {
|
||||
GenDocComment(code_ptr,
|
||||
"@param {flatbuffers.ByteBuffer} bb\n"
|
||||
"@param {" + object_name + "=} obj\n"
|
||||
"@returns {" + object_name + "}");
|
||||
code += object_name + ".getRootAs" + struct_def.name;
|
||||
code += " = function(bb, obj) {\n";
|
||||
code += " return (obj || new " + object_name;
|
||||
code += ").__init(bb.readInt32(bb.position()) + bb.position(), bb);\n";
|
||||
code += "};\n\n";
|
||||
|
||||
// Generate the identifier check method
|
||||
if (parser.root_struct_def_ == &struct_def &&
|
||||
!parser.file_identifier_.empty()) {
|
||||
GenDocComment(code_ptr,
|
||||
"@param {flatbuffers.ByteBuffer} bb\n"
|
||||
"@returns {boolean}");
|
||||
code += object_name + ".bufferHasIdentifier = function(bb) {\n";
|
||||
code += " return bb.__has_identifier('" + parser.file_identifier_;
|
||||
code += "');\n};\n\n";
|
||||
}
|
||||
}
|
||||
|
||||
// Emit field accessors
|
||||
for (auto it = struct_def.fields.vec.begin();
|
||||
it != struct_def.fields.vec.end(); ++it) {
|
||||
auto &field = **it;
|
||||
if (field.deprecated) continue;
|
||||
auto offset_prefix = " var offset = this.bb.__offset(this.bb_pos, " +
|
||||
NumToString(field.value.offset) + ");\n return offset ? ";
|
||||
|
||||
// Emit a scalar field
|
||||
if (IsScalar(field.value.type.base_type) ||
|
||||
field.value.type.base_type == BASE_TYPE_STRING) {
|
||||
GenDocComment(field.doc_comment, code_ptr,
|
||||
std::string(field.value.type.base_type == BASE_TYPE_STRING ?
|
||||
"@param {flatbuffers.Encoding=} optionalEncoding\n" : "") +
|
||||
"@returns {" + GenTypeName(field.value.type, false) + "}");
|
||||
code += object_name + ".prototype." + MakeCamel(field.name, false);
|
||||
code += " = function(";
|
||||
if (field.value.type.base_type == BASE_TYPE_STRING) {
|
||||
code += "optionalEncoding";
|
||||
}
|
||||
code += ") {\n";
|
||||
if (struct_def.fixed) {
|
||||
code += " return " + GenGetter(field.value.type, "(this.bb_pos" +
|
||||
MaybeAdd(field.value.offset) + ")") + ";\n";
|
||||
} else {
|
||||
std::string index = "this.bb_pos + offset";
|
||||
if (field.value.type.base_type == BASE_TYPE_STRING) {
|
||||
index += ", optionalEncoding";
|
||||
}
|
||||
code += offset_prefix + GenGetter(field.value.type,
|
||||
"(" + index + ")") + " : " + GenDefaultValue(field.value);
|
||||
code += ";\n";
|
||||
}
|
||||
}
|
||||
|
||||
// Emit an object field
|
||||
else {
|
||||
switch (field.value.type.base_type) {
|
||||
case BASE_TYPE_STRUCT: {
|
||||
auto type = WrapInNameSpace(*field.value.type.struct_def);
|
||||
GenDocComment(field.doc_comment, code_ptr,
|
||||
"@param {" + type + "=} obj\n@returns {" + type + "}");
|
||||
code += object_name + ".prototype." + MakeCamel(field.name, false);
|
||||
code += " = function(obj) {\n";
|
||||
if (struct_def.fixed) {
|
||||
code += " return (obj || new " + type;
|
||||
code += ").__init(this.bb_pos";
|
||||
code += MaybeAdd(field.value.offset) + ", this.bb);\n";
|
||||
} else {
|
||||
code += offset_prefix + "(obj || new " + type + ").__init(";
|
||||
code += field.value.type.struct_def->fixed
|
||||
? "this.bb_pos + offset"
|
||||
: "this.bb.__indirect(this.bb_pos + offset)";
|
||||
code += ", this.bb) : null;\n";
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case BASE_TYPE_VECTOR: {
|
||||
auto vectortype = field.value.type.VectorType();
|
||||
auto vectortypename = GenTypeName(vectortype, false);
|
||||
auto inline_size = InlineSize(vectortype);
|
||||
auto index = "this.bb.__vector(this.bb_pos + offset) + index" +
|
||||
MaybeScale(inline_size);
|
||||
std::string args = "@param {number} index\n";
|
||||
if (vectortype.base_type == BASE_TYPE_STRUCT) {
|
||||
args += "@param {" + vectortypename + "=} obj\n";
|
||||
} else if (vectortype.base_type == BASE_TYPE_STRING) {
|
||||
args += "@param {flatbuffers.Encoding=} optionalEncoding\n";
|
||||
}
|
||||
GenDocComment(field.doc_comment, code_ptr, args +
|
||||
"@returns {" + vectortypename + "}");
|
||||
code += object_name + ".prototype." + MakeCamel(field.name, false);
|
||||
code += " = function(index";
|
||||
if (vectortype.base_type == BASE_TYPE_STRUCT) {
|
||||
code += ", obj";
|
||||
} else if (vectortype.base_type == BASE_TYPE_STRING) {
|
||||
code += ", optionalEncoding";
|
||||
}
|
||||
code += ") {\n";
|
||||
if (vectortype.base_type == BASE_TYPE_STRUCT) {
|
||||
code += offset_prefix + "(obj || new " + vectortypename;
|
||||
code += ").__init(";
|
||||
code += vectortype.struct_def->fixed
|
||||
? index
|
||||
: "this.bb.__indirect(" + index + ")";
|
||||
code += ", this.bb)";
|
||||
} else {
|
||||
if (vectortype.base_type == BASE_TYPE_STRING) {
|
||||
index += ", optionalEncoding";
|
||||
}
|
||||
code += offset_prefix + GenGetter(vectortype, "(" + index + ")");
|
||||
}
|
||||
code += " : ";
|
||||
if (field.value.type.element == BASE_TYPE_BOOL) {
|
||||
code += "false";
|
||||
} else if (field.value.type.element == BASE_TYPE_LONG ||
|
||||
field.value.type.element == BASE_TYPE_ULONG) {
|
||||
code += "flatbuffers.Long.ZERO";
|
||||
} else if (IsScalar(field.value.type.element)) {
|
||||
code += "0";
|
||||
} else {
|
||||
code += "null";
|
||||
}
|
||||
code += ";\n";
|
||||
break;
|
||||
}
|
||||
|
||||
case BASE_TYPE_UNION:
|
||||
GenDocComment(field.doc_comment, code_ptr,
|
||||
"@param {flatbuffers.Table} obj\n"
|
||||
"@returns {?flatbuffers.Table}");
|
||||
code += object_name + ".prototype." + MakeCamel(field.name, false);
|
||||
code += " = function(obj) {\n";
|
||||
code += offset_prefix + GenGetter(field.value.type,
|
||||
"(obj, this.bb_pos + offset)") + " : null;\n";
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
code += "};\n\n";
|
||||
|
||||
// Emit a length helper
|
||||
if (field.value.type.base_type == BASE_TYPE_VECTOR) {
|
||||
GenDocComment(code_ptr, "@returns {number}");
|
||||
code += object_name + ".prototype." + MakeCamel(field.name, false);
|
||||
code += "Length = function() {\n" + offset_prefix;
|
||||
code += "this.bb.__vector_len(this.bb_pos + offset) : 0;\n};\n\n";
|
||||
}
|
||||
}
|
||||
|
||||
// Emit a factory constructor
|
||||
if (struct_def.fixed) {
|
||||
std::string annotations = "@param {flatbuffers.Builder} builder\n";
|
||||
std::string arguments;
|
||||
GenStructArgs(struct_def, &annotations, &arguments, "");
|
||||
GenDocComment(code_ptr, annotations +
|
||||
"@returns {flatbuffers.Offset}");
|
||||
code += object_name + ".create" + struct_def.name + " = function(builder";
|
||||
code += arguments + ") {\n";
|
||||
GenStructBody(struct_def, &code, "");
|
||||
code += " return builder.offset();\n};\n\n";
|
||||
} else {
|
||||
// Generate a method to start building a new object
|
||||
GenDocComment(code_ptr,
|
||||
"@param {flatbuffers.Builder} builder");
|
||||
code += object_name + ".start" + struct_def.name;
|
||||
code += " = function(builder) {\n";
|
||||
code += " builder.startObject(" + NumToString(
|
||||
struct_def.fields.vec.size()) + ");\n";
|
||||
code += "};\n\n";
|
||||
|
||||
// Generate a set of static methods that allow table construction
|
||||
for (auto it = struct_def.fields.vec.begin();
|
||||
it != struct_def.fields.vec.end(); ++it) {
|
||||
auto &field = **it;
|
||||
if (field.deprecated) continue;
|
||||
auto argname = MakeCamel(field.name, false);
|
||||
if (!IsScalar(field.value.type.base_type)) {
|
||||
argname += "Offset";
|
||||
}
|
||||
|
||||
// Generate the field insertion method
|
||||
GenDocComment(code_ptr,
|
||||
"@param {flatbuffers.Builder} builder\n"
|
||||
"@param {" + GenTypeName(field.value.type, true) + "} " +
|
||||
argname);
|
||||
code += object_name + ".add" + MakeCamel(field.name);
|
||||
code += " = function(builder, " + argname + ") {\n";
|
||||
code += " builder.addField" + GenWriteMethod(field.value.type) + "(";
|
||||
code += NumToString(it - struct_def.fields.vec.begin()) + ", ";
|
||||
if (field.value.type.base_type == BASE_TYPE_BOOL) {
|
||||
code += "+";
|
||||
}
|
||||
code += argname + ", ";
|
||||
if (!IsScalar(field.value.type.base_type)) {
|
||||
code += "0";
|
||||
} else {
|
||||
if (field.value.type.base_type == BASE_TYPE_BOOL) {
|
||||
code += "+";
|
||||
}
|
||||
code += GenDefaultValue(field.value);
|
||||
}
|
||||
code += ");\n};\n\n";
|
||||
|
||||
if (field.value.type.base_type == BASE_TYPE_VECTOR) {
|
||||
auto vector_type = field.value.type.VectorType();
|
||||
auto alignment = InlineAlignment(vector_type);
|
||||
auto elem_size = InlineSize(vector_type);
|
||||
|
||||
// Generate a method to create a vector from a JavaScript array
|
||||
if (!IsStruct(vector_type)) {
|
||||
GenDocComment(code_ptr,
|
||||
"@param {flatbuffers.Builder} builder\n"
|
||||
"@param {Array.<" + GenTypeName(vector_type, true) +
|
||||
">} data\n"
|
||||
"@returns {flatbuffers.Offset}");
|
||||
code += object_name + ".create" + MakeCamel(field.name);
|
||||
code += "Vector = function(builder, data) {\n";
|
||||
code += " builder.startVector(" + NumToString(elem_size);
|
||||
code += ", data.length, " + NumToString(alignment) + ");\n";
|
||||
code += " for (var i = data.length - 1; i >= 0; i--) {\n";
|
||||
code += " builder.add" + GenWriteMethod(vector_type) + "(";
|
||||
if (vector_type.base_type == BASE_TYPE_BOOL) {
|
||||
code += "+";
|
||||
}
|
||||
code += "data[i]);\n";
|
||||
code += " }\n";
|
||||
code += " return builder.endVector();\n";
|
||||
code += "};\n\n";
|
||||
}
|
||||
|
||||
// Generate a method to start a vector, data to be added manually after
|
||||
GenDocComment(code_ptr,
|
||||
"@param {flatbuffers.Builder} builder\n"
|
||||
"@param {number} numElems");
|
||||
code += object_name + ".start" + MakeCamel(field.name);
|
||||
code += "Vector = function(builder, numElems) {\n";
|
||||
code += " builder.startVector(" + NumToString(elem_size);
|
||||
code += ", numElems, " + NumToString(alignment) + ");\n";
|
||||
code += "};\n\n";
|
||||
}
|
||||
}
|
||||
|
||||
// Generate a method to stop building a new object
|
||||
GenDocComment(code_ptr,
|
||||
"@param {flatbuffers.Builder} builder\n"
|
||||
"@returns {flatbuffers.Offset}");
|
||||
code += object_name + ".end" + struct_def.name;
|
||||
code += " = function(builder) {\n";
|
||||
code += " var offset = builder.endObject();\n";
|
||||
for (auto it = struct_def.fields.vec.begin();
|
||||
it != struct_def.fields.vec.end(); ++it) {
|
||||
auto &field = **it;
|
||||
if (!field.deprecated && field.required) {
|
||||
code += " builder.requiredField(offset, ";
|
||||
code += NumToString(field.value.offset);
|
||||
code += "); // " + field.name + "\n";
|
||||
}
|
||||
}
|
||||
code += " return offset;\n";
|
||||
code += "};\n\n";
|
||||
|
||||
// Generate the method to complete buffer construction
|
||||
if (parser.root_struct_def_ == &struct_def) {
|
||||
GenDocComment(code_ptr,
|
||||
"@param {flatbuffers.Builder} builder\n"
|
||||
"@param {flatbuffers.Offset} offset");
|
||||
code += object_name + ".finish" + struct_def.name + "Buffer";
|
||||
code += " = function(builder, offset) {\n";
|
||||
code += " builder.finish(offset";
|
||||
if (!parser.file_identifier_.empty()) {
|
||||
code += ", '" + parser.file_identifier_ + "'";
|
||||
}
|
||||
code += ");\n";
|
||||
code += "};\n\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace js
|
||||
|
||||
// Iterate through all definitions we haven't generate code for (enums, structs,
|
||||
// and tables) and output them to a single file.
|
||||
std::string GenerateJS(const Parser &parser,
|
||||
const GeneratorOptions &opts) {
|
||||
using namespace js;
|
||||
|
||||
// Generate code for all the enum declarations.
|
||||
std::string enum_code, exports_code;
|
||||
for (auto it = parser.enums_.vec.begin();
|
||||
it != parser.enums_.vec.end(); ++it) {
|
||||
GenEnum(**it, &enum_code, &exports_code);
|
||||
}
|
||||
|
||||
// Generate code for all structs, then all tables.
|
||||
std::string decl_code;
|
||||
for (auto it = parser.structs_.vec.begin();
|
||||
it != parser.structs_.vec.end(); ++it) {
|
||||
GenStruct(parser, **it, &decl_code, &exports_code);
|
||||
}
|
||||
|
||||
// Only output file-level code if there were any declarations.
|
||||
if (enum_code.length() || decl_code.length()) {
|
||||
std::string code;
|
||||
code = "// automatically generated by the FlatBuffers compiler,"
|
||||
" do not modify\n\n";
|
||||
|
||||
// Generate code for all the namespace declarations.
|
||||
GenNamespaces(parser, &code, &exports_code);
|
||||
|
||||
// Output the main declaration code from above.
|
||||
code += enum_code;
|
||||
code += decl_code;
|
||||
|
||||
if (!exports_code.empty() && !opts.skip_js_exports) {
|
||||
code += "// Exports for Node.js and RequireJS\n";
|
||||
code += exports_code;
|
||||
}
|
||||
|
||||
return code;
|
||||
}
|
||||
|
||||
return std::string();
|
||||
}
|
||||
|
||||
static std::string GeneratedFileName(const std::string &path,
|
||||
const std::string &file_name) {
|
||||
return path + file_name + "_generated.js";
|
||||
}
|
||||
|
||||
bool GenerateJS(const Parser &parser,
|
||||
const std::string &path,
|
||||
const std::string &file_name,
|
||||
const GeneratorOptions &opts) {
|
||||
auto code = GenerateJS(parser, opts);
|
||||
return !code.length() ||
|
||||
SaveFile(GeneratedFileName(path, file_name).c_str(), code, false);
|
||||
}
|
||||
|
||||
std::string JSMakeRule(const Parser &parser,
|
||||
const std::string &path,
|
||||
const std::string &file_name,
|
||||
const GeneratorOptions & /*opts*/) {
|
||||
std::string filebase = flatbuffers::StripPath(
|
||||
flatbuffers::StripExtension(file_name));
|
||||
std::string make_rule = GeneratedFileName(path, filebase) + ": ";
|
||||
auto included_files = parser.GetIncludedFilesRecursive(file_name);
|
||||
for (auto it = included_files.begin();
|
||||
it != included_files.end(); ++it) {
|
||||
make_rule += " " + *it;
|
||||
}
|
||||
return make_rule;
|
||||
}
|
||||
|
||||
} // namespace flatbuffers
|
||||
662
src/idl_gen_python.cpp
Normal file
662
src/idl_gen_python.cpp
Normal file
@@ -0,0 +1,662 @@
|
||||
/*
|
||||
* Copyright 2014 Google Inc. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
// independent from idl_parser, since this code is not needed for most clients
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "flatbuffers/flatbuffers.h"
|
||||
#include "flatbuffers/idl.h"
|
||||
#include "flatbuffers/util.h"
|
||||
|
||||
namespace flatbuffers {
|
||||
namespace python {
|
||||
|
||||
static std::string GenGetter(const Type &type);
|
||||
static std::string GenMethod(const FieldDef &field);
|
||||
static void GenStructBuilder(const StructDef &struct_def,
|
||||
std::string *code_ptr);
|
||||
static void GenReceiver(const StructDef &struct_def, std::string *code_ptr);
|
||||
static std::string GenTypeBasic(const Type &type);
|
||||
static std::string GenTypeGet(const Type &type);
|
||||
static std::string TypeName(const FieldDef &field);
|
||||
|
||||
|
||||
// Hardcode spaces per indentation.
|
||||
const std::string Indent = " ";
|
||||
|
||||
// Most field accessors need to retrieve and test the field offset first,
|
||||
// this is the prefix code for that.
|
||||
std::string OffsetPrefix(const FieldDef &field) {
|
||||
return "\n" + Indent + Indent +
|
||||
"o = flatbuffers.number_types.UOffsetTFlags.py_type" +
|
||||
"(self._tab.Offset(" +
|
||||
NumToString(field.value.offset) +
|
||||
"))\n" + Indent + Indent + "if o != 0:\n";
|
||||
}
|
||||
|
||||
// Begin by declaring namespace and imports.
|
||||
static void BeginFile(const std::string name_space_name,
|
||||
const bool needs_imports,
|
||||
std::string *code_ptr) {
|
||||
std::string &code = *code_ptr;
|
||||
code += "# automatically generated, do not modify\n\n";
|
||||
code += "# namespace: " + name_space_name + "\n\n";
|
||||
if (needs_imports) {
|
||||
code += "import flatbuffers\n\n";
|
||||
}
|
||||
}
|
||||
|
||||
// Begin a class declaration.
|
||||
static void BeginClass(const StructDef &struct_def, std::string *code_ptr) {
|
||||
std::string &code = *code_ptr;
|
||||
code += "class " + struct_def.name + "(object):\n";
|
||||
code += Indent + "__slots__ = ['_tab']";
|
||||
code += "\n\n";
|
||||
}
|
||||
|
||||
// Begin enum code with a class declaration.
|
||||
static void BeginEnum(const std::string class_name, std::string *code_ptr) {
|
||||
std::string &code = *code_ptr;
|
||||
code += "class " + class_name + "(object):\n";
|
||||
}
|
||||
|
||||
// A single enum member.
|
||||
static void EnumMember(const EnumVal ev, std::string *code_ptr) {
|
||||
std::string &code = *code_ptr;
|
||||
code += Indent;
|
||||
code += ev.name;
|
||||
code += " = ";
|
||||
code += NumToString(ev.value) + "\n";
|
||||
}
|
||||
|
||||
// End enum code.
|
||||
static void EndEnum(std::string *code_ptr) {
|
||||
std::string &code = *code_ptr;
|
||||
code += "\n";
|
||||
}
|
||||
|
||||
// Initialize a new struct or table from existing data.
|
||||
static void NewRootTypeFromBuffer(const StructDef &struct_def,
|
||||
std::string *code_ptr) {
|
||||
std::string &code = *code_ptr;
|
||||
|
||||
code += Indent + "@classmethod\n";
|
||||
code += Indent + "def GetRootAs";
|
||||
code += struct_def.name;
|
||||
code += "(cls, buf, offset):";
|
||||
code += "\n";
|
||||
code += Indent + Indent;
|
||||
code += "n = flatbuffers.encode.Get";
|
||||
code += "(flatbuffers.packer.uoffset, buf, offset)\n";
|
||||
code += Indent + Indent + "x = " + struct_def.name + "()\n";
|
||||
code += Indent + Indent + "x.Init(buf, n + offset)\n";
|
||||
code += Indent + Indent + "return x\n";
|
||||
code += "\n\n";
|
||||
}
|
||||
|
||||
// Initialize an existing object with other data, to avoid an allocation.
|
||||
static void InitializeExisting(const StructDef &struct_def,
|
||||
std::string *code_ptr) {
|
||||
std::string &code = *code_ptr;
|
||||
|
||||
GenReceiver(struct_def, code_ptr);
|
||||
code += "Init(self, buf, pos):\n";
|
||||
code += Indent + Indent + "self._tab = flatbuffers.table.Table(buf, pos)\n";
|
||||
code += "\n";
|
||||
}
|
||||
|
||||
// Get the length of a vector.
|
||||
static void GetVectorLen(const StructDef &struct_def,
|
||||
const FieldDef &field,
|
||||
std::string *code_ptr) {
|
||||
std::string &code = *code_ptr;
|
||||
|
||||
GenReceiver(struct_def, code_ptr);
|
||||
code += MakeCamel(field.name) + "Length(self";
|
||||
code += "):" + OffsetPrefix(field);
|
||||
code += Indent + Indent + Indent + "return self._tab.VectorLen(o)\n";
|
||||
code += Indent + Indent + "return 0\n\n";
|
||||
}
|
||||
|
||||
// Get the value of a struct's scalar.
|
||||
static void GetScalarFieldOfStruct(const StructDef &struct_def,
|
||||
const FieldDef &field,
|
||||
std::string *code_ptr) {
|
||||
std::string &code = *code_ptr;
|
||||
std::string getter = GenGetter(field.value.type);
|
||||
GenReceiver(struct_def, code_ptr);
|
||||
code += MakeCamel(field.name);
|
||||
code += "(self): return " + getter;
|
||||
code += "self._tab.Pos + flatbuffers.number_types.UOffsetTFlags.py_type(";
|
||||
code += NumToString(field.value.offset) + "))\n";
|
||||
}
|
||||
|
||||
// Get the value of a table's scalar.
|
||||
static void GetScalarFieldOfTable(const StructDef &struct_def,
|
||||
const FieldDef &field,
|
||||
std::string *code_ptr) {
|
||||
std::string &code = *code_ptr;
|
||||
std::string getter = GenGetter(field.value.type);
|
||||
GenReceiver(struct_def, code_ptr);
|
||||
code += MakeCamel(field.name);
|
||||
code += "(self):";
|
||||
code += OffsetPrefix(field);
|
||||
code += Indent + Indent + Indent + "return " + getter;
|
||||
code += "o + self._tab.Pos)\n";
|
||||
code += Indent + Indent + "return " + field.value.constant + "\n\n";
|
||||
}
|
||||
|
||||
// Get a struct by initializing an existing struct.
|
||||
// Specific to Struct.
|
||||
static void GetStructFieldOfStruct(const StructDef &struct_def,
|
||||
const FieldDef &field,
|
||||
std::string *code_ptr) {
|
||||
std::string &code = *code_ptr;
|
||||
GenReceiver(struct_def, code_ptr);
|
||||
code += MakeCamel(field.name);
|
||||
code += "(self, obj):\n";
|
||||
code += Indent + Indent + "obj.Init(self._tab.Bytes, self._tab.Pos + ";
|
||||
code += NumToString(field.value.offset) + ")";
|
||||
code += "\n" + Indent + Indent + "return obj\n\n";
|
||||
}
|
||||
|
||||
// Get a struct by initializing an existing struct.
|
||||
// Specific to Table.
|
||||
static void GetStructFieldOfTable(const StructDef &struct_def,
|
||||
const FieldDef &field,
|
||||
std::string *code_ptr) {
|
||||
std::string &code = *code_ptr;
|
||||
GenReceiver(struct_def, code_ptr);
|
||||
code += MakeCamel(field.name);
|
||||
code += "(self):";
|
||||
code += OffsetPrefix(field);
|
||||
if (field.value.type.struct_def->fixed) {
|
||||
code += Indent + Indent + Indent + "x = o + self._tab.Pos\n";
|
||||
} else {
|
||||
code += Indent + Indent + Indent;
|
||||
code += "x = self._tab.Indirect(o + self._tab.Pos)\n";
|
||||
}
|
||||
code += Indent + Indent + Indent;
|
||||
code += "from ." + TypeName(field) + " import " + TypeName(field) + "\n";
|
||||
code += Indent + Indent + Indent + "obj = " + TypeName(field) + "()\n";
|
||||
code += Indent + Indent + Indent + "obj.Init(self._tab.Bytes, x)\n";
|
||||
code += Indent + Indent + Indent + "return obj\n";
|
||||
code += Indent + Indent + "return None\n\n";
|
||||
}
|
||||
|
||||
// Get the value of a string.
|
||||
static void GetStringField(const StructDef &struct_def,
|
||||
const FieldDef &field,
|
||||
std::string *code_ptr) {
|
||||
std::string &code = *code_ptr;
|
||||
GenReceiver(struct_def, code_ptr);
|
||||
code += MakeCamel(field.name);
|
||||
code += "(self):";
|
||||
code += OffsetPrefix(field);
|
||||
code += Indent + Indent + Indent + "return " + GenGetter(field.value.type);
|
||||
code += "o + self._tab.Pos)\n";
|
||||
code += Indent + Indent + "return \"\"\n\n";
|
||||
}
|
||||
|
||||
// Get the value of a union from an object.
|
||||
static void GetUnionField(const StructDef &struct_def,
|
||||
const FieldDef &field,
|
||||
std::string *code_ptr) {
|
||||
std::string &code = *code_ptr;
|
||||
GenReceiver(struct_def, code_ptr);
|
||||
code += MakeCamel(field.name) + "(self):";
|
||||
code += OffsetPrefix(field);
|
||||
|
||||
// TODO(rw): this works and is not the good way to it:
|
||||
bool is_native_table = TypeName(field) == "*flatbuffers.Table";
|
||||
if (is_native_table) {
|
||||
code += Indent + Indent + Indent + "from flatbuffers.table import Table\n";
|
||||
} else {
|
||||
code += Indent + Indent + Indent;
|
||||
code += "from ." + TypeName(field) + " import " + TypeName(field) + "\n";
|
||||
}
|
||||
code += Indent + Indent + Indent + "obj = Table(bytearray(), 0)\n";
|
||||
code += Indent + Indent + Indent + GenGetter(field.value.type);
|
||||
code += "obj, o)\n" + Indent + Indent + Indent + "return obj\n";
|
||||
code += Indent + Indent + "return None\n\n";
|
||||
}
|
||||
|
||||
// Get the value of a vector's struct member.
|
||||
static void GetMemberOfVectorOfStruct(const StructDef &struct_def,
|
||||
const FieldDef &field,
|
||||
std::string *code_ptr) {
|
||||
std::string &code = *code_ptr;
|
||||
auto vectortype = field.value.type.VectorType();
|
||||
|
||||
GenReceiver(struct_def, code_ptr);
|
||||
code += MakeCamel(field.name);
|
||||
code += "(self, j):" + OffsetPrefix(field);
|
||||
code += Indent + Indent + Indent + "x = self._tab.Vector(o)\n";
|
||||
code += Indent + Indent + Indent;
|
||||
code += "x += flatbuffers.number_types.UOffsetTFlags.py_type(j) * ";
|
||||
code += NumToString(InlineSize(vectortype)) + "\n";
|
||||
if (!(vectortype.struct_def->fixed)) {
|
||||
code += Indent + Indent + Indent + "x = self._tab.Indirect(x)\n";
|
||||
}
|
||||
code += Indent + Indent + Indent;
|
||||
code += "from ." + TypeName(field) + " import " + TypeName(field) + "\n";
|
||||
code += Indent + Indent + Indent + "obj = " + TypeName(field) + "()\n";
|
||||
code += Indent + Indent + Indent + "obj.Init(self._tab.Bytes, x)\n";
|
||||
code += Indent + Indent + Indent + "return obj\n";
|
||||
code += Indent + Indent + "return None\n\n";
|
||||
}
|
||||
|
||||
// Get the value of a vector's non-struct member. Uses a named return
|
||||
// argument to conveniently set the zero value for the result.
|
||||
static void GetMemberOfVectorOfNonStruct(const StructDef &struct_def,
|
||||
const FieldDef &field,
|
||||
std::string *code_ptr) {
|
||||
std::string &code = *code_ptr;
|
||||
auto vectortype = field.value.type.VectorType();
|
||||
|
||||
GenReceiver(struct_def, code_ptr);
|
||||
code += MakeCamel(field.name);
|
||||
code += "(self, j):";
|
||||
code += OffsetPrefix(field);
|
||||
code += Indent + Indent + Indent + "a = self._tab.Vector(o)\n";
|
||||
code += Indent + Indent + Indent;
|
||||
code += "return " + GenGetter(field.value.type);
|
||||
code += "a + flatbuffers.number_types.UOffsetTFlags.py_type(j * ";
|
||||
code += NumToString(InlineSize(vectortype)) + "))\n";
|
||||
if (vectortype.base_type == BASE_TYPE_STRING) {
|
||||
code += Indent + Indent + "return \"\"\n";
|
||||
} else {
|
||||
code += Indent + Indent + "return 0\n";
|
||||
}
|
||||
code += "\n";
|
||||
}
|
||||
|
||||
// Begin the creator function signature.
|
||||
static void BeginBuilderArgs(const StructDef &struct_def,
|
||||
std::string *code_ptr) {
|
||||
std::string &code = *code_ptr;
|
||||
|
||||
code += "\n";
|
||||
code += "def Create" + struct_def.name;
|
||||
code += "(builder";
|
||||
}
|
||||
|
||||
// Recursively generate arguments for a constructor, to deal with nested
|
||||
// structs.
|
||||
static void StructBuilderArgs(const StructDef &struct_def,
|
||||
const char *nameprefix,
|
||||
std::string *code_ptr) {
|
||||
for (auto it = struct_def.fields.vec.begin();
|
||||
it != struct_def.fields.vec.end();
|
||||
++it) {
|
||||
auto &field = **it;
|
||||
if (IsStruct(field.value.type)) {
|
||||
// Generate arguments for a struct inside a struct. To ensure names
|
||||
// don't clash, and to make it obvious these arguments are constructing
|
||||
// a nested struct, prefix the name with the field name.
|
||||
StructBuilderArgs(*field.value.type.struct_def,
|
||||
(nameprefix + (field.name + "_")).c_str(),
|
||||
code_ptr);
|
||||
} else {
|
||||
std::string &code = *code_ptr;
|
||||
code += (std::string)", " + nameprefix;
|
||||
code += MakeCamel(field.name, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// End the creator function signature.
|
||||
static void EndBuilderArgs(std::string *code_ptr) {
|
||||
std::string &code = *code_ptr;
|
||||
code += "):\n";
|
||||
}
|
||||
|
||||
// Recursively generate struct construction statements and instert manual
|
||||
// padding.
|
||||
static void StructBuilderBody(const StructDef &struct_def,
|
||||
const char *nameprefix,
|
||||
std::string *code_ptr) {
|
||||
std::string &code = *code_ptr;
|
||||
code += " builder.Prep(" + NumToString(struct_def.minalign) + ", ";
|
||||
code += NumToString(struct_def.bytesize) + ")\n";
|
||||
for (auto it = struct_def.fields.vec.rbegin();
|
||||
it != struct_def.fields.vec.rend();
|
||||
++it) {
|
||||
auto &field = **it;
|
||||
if (field.padding)
|
||||
code += " builder.Pad(" + NumToString(field.padding) + ")\n";
|
||||
if (IsStruct(field.value.type)) {
|
||||
StructBuilderBody(*field.value.type.struct_def,
|
||||
(nameprefix + (field.name + "_")).c_str(),
|
||||
code_ptr);
|
||||
} else {
|
||||
code += " builder.Prepend" + GenMethod(field) + "(";
|
||||
code += nameprefix + MakeCamel(field.name, false) + ")\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void EndBuilderBody(std::string *code_ptr) {
|
||||
std::string &code = *code_ptr;
|
||||
code += " return builder.Offset()\n";
|
||||
}
|
||||
|
||||
// Get the value of a table's starting offset.
|
||||
static void GetStartOfTable(const StructDef &struct_def,
|
||||
std::string *code_ptr) {
|
||||
std::string &code = *code_ptr;
|
||||
code += "def " + struct_def.name + "Start";
|
||||
code += "(builder): ";
|
||||
code += "builder.StartObject(";
|
||||
code += NumToString(struct_def.fields.vec.size());
|
||||
code += ")\n";
|
||||
}
|
||||
|
||||
// Set the value of a table's field.
|
||||
static void BuildFieldOfTable(const StructDef &struct_def,
|
||||
const FieldDef &field,
|
||||
const size_t offset,
|
||||
std::string *code_ptr) {
|
||||
std::string &code = *code_ptr;
|
||||
code += "def " + struct_def.name + "Add" + MakeCamel(field.name);
|
||||
code += "(builder, ";
|
||||
code += MakeCamel(field.name, false);
|
||||
code += "): ";
|
||||
code += "builder.Prepend";
|
||||
code += GenMethod(field) + "Slot(";
|
||||
code += NumToString(offset) + ", ";
|
||||
if (!IsScalar(field.value.type.base_type) && (!struct_def.fixed)) {
|
||||
code += "flatbuffers.number_types.UOffsetTFlags.py_type";
|
||||
code += "(";
|
||||
code += MakeCamel(field.name, false) + ")";
|
||||
} else {
|
||||
code += MakeCamel(field.name, false);
|
||||
}
|
||||
code += ", " + field.value.constant;
|
||||
code += ")\n";
|
||||
}
|
||||
|
||||
// Set the value of one of the members of a table's vector.
|
||||
static void BuildVectorOfTable(const StructDef &struct_def,
|
||||
const FieldDef &field,
|
||||
std::string *code_ptr) {
|
||||
std::string &code = *code_ptr;
|
||||
code += "def " + struct_def.name + "Start";
|
||||
code += MakeCamel(field.name);
|
||||
code += "Vector(builder, numElems): return builder.StartVector(";
|
||||
auto vector_type = field.value.type.VectorType();
|
||||
auto alignment = InlineAlignment(vector_type);
|
||||
auto elem_size = InlineSize(vector_type);
|
||||
code += NumToString(elem_size);
|
||||
code += ", numElems, " + NumToString(alignment);
|
||||
code += ")\n";
|
||||
}
|
||||
|
||||
// Get the offset of the end of a table.
|
||||
static void GetEndOffsetOnTable(const StructDef &struct_def,
|
||||
std::string *code_ptr) {
|
||||
std::string &code = *code_ptr;
|
||||
code += "def " + struct_def.name + "End";
|
||||
code += "(builder): ";
|
||||
code += "return builder.EndObject()\n";
|
||||
}
|
||||
|
||||
// Generate the receiver for function signatures.
|
||||
static void GenReceiver(const StructDef &struct_def, std::string *code_ptr) {
|
||||
std::string &code = *code_ptr;
|
||||
code += Indent + "# " + struct_def.name + "\n";
|
||||
code += Indent + "def ";
|
||||
}
|
||||
|
||||
// Generate a struct field, conditioned on its child type(s).
|
||||
static void GenStructAccessor(const StructDef &struct_def,
|
||||
const FieldDef &field,
|
||||
std::string *code_ptr) {
|
||||
GenComment(field.doc_comment, code_ptr, nullptr, "# ");
|
||||
if (IsScalar(field.value.type.base_type)) {
|
||||
if (struct_def.fixed) {
|
||||
GetScalarFieldOfStruct(struct_def, field, code_ptr);
|
||||
} else {
|
||||
GetScalarFieldOfTable(struct_def, field, code_ptr);
|
||||
}
|
||||
} else {
|
||||
switch (field.value.type.base_type) {
|
||||
case BASE_TYPE_STRUCT:
|
||||
if (struct_def.fixed) {
|
||||
GetStructFieldOfStruct(struct_def, field, code_ptr);
|
||||
} else {
|
||||
GetStructFieldOfTable(struct_def, field, code_ptr);
|
||||
}
|
||||
break;
|
||||
case BASE_TYPE_STRING:
|
||||
GetStringField(struct_def, field, code_ptr);
|
||||
break;
|
||||
case BASE_TYPE_VECTOR: {
|
||||
auto vectortype = field.value.type.VectorType();
|
||||
if (vectortype.base_type == BASE_TYPE_STRUCT) {
|
||||
GetMemberOfVectorOfStruct(struct_def, field, code_ptr);
|
||||
} else {
|
||||
GetMemberOfVectorOfNonStruct(struct_def, field, code_ptr);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case BASE_TYPE_UNION:
|
||||
GetUnionField(struct_def, field, code_ptr);
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
if (field.value.type.base_type == BASE_TYPE_VECTOR) {
|
||||
GetVectorLen(struct_def, field, code_ptr);
|
||||
}
|
||||
}
|
||||
|
||||
// Generate table constructors, conditioned on its members' types.
|
||||
static void GenTableBuilders(const StructDef &struct_def,
|
||||
std::string *code_ptr) {
|
||||
GetStartOfTable(struct_def, code_ptr);
|
||||
|
||||
for (auto it = struct_def.fields.vec.begin();
|
||||
it != struct_def.fields.vec.end();
|
||||
++it) {
|
||||
auto &field = **it;
|
||||
if (field.deprecated) continue;
|
||||
|
||||
auto offset = it - struct_def.fields.vec.begin();
|
||||
BuildFieldOfTable(struct_def, field, offset, code_ptr);
|
||||
if (field.value.type.base_type == BASE_TYPE_VECTOR) {
|
||||
BuildVectorOfTable(struct_def, field, code_ptr);
|
||||
}
|
||||
}
|
||||
|
||||
GetEndOffsetOnTable(struct_def, code_ptr);
|
||||
}
|
||||
|
||||
// Generate struct or table methods.
|
||||
static void GenStruct(const StructDef &struct_def,
|
||||
std::string *code_ptr,
|
||||
StructDef *root_struct_def) {
|
||||
if (struct_def.generated) return;
|
||||
|
||||
GenComment(struct_def.doc_comment, code_ptr, nullptr, "# ");
|
||||
BeginClass(struct_def, code_ptr);
|
||||
if (&struct_def == root_struct_def) {
|
||||
// Generate a special accessor for the table that has been declared as
|
||||
// the root type.
|
||||
NewRootTypeFromBuffer(struct_def, code_ptr);
|
||||
}
|
||||
// Generate the Init method that sets the field in a pre-existing
|
||||
// accessor object. This is to allow object reuse.
|
||||
InitializeExisting(struct_def, code_ptr);
|
||||
for (auto it = struct_def.fields.vec.begin();
|
||||
it != struct_def.fields.vec.end();
|
||||
++it) {
|
||||
auto &field = **it;
|
||||
if (field.deprecated) continue;
|
||||
|
||||
GenStructAccessor(struct_def, field, code_ptr);
|
||||
}
|
||||
|
||||
if (struct_def.fixed) {
|
||||
// create a struct constructor function
|
||||
GenStructBuilder(struct_def, code_ptr);
|
||||
} else {
|
||||
// Create a set of functions that allow table construction.
|
||||
GenTableBuilders(struct_def, code_ptr);
|
||||
}
|
||||
}
|
||||
|
||||
// Generate enum declarations.
|
||||
static void GenEnum(const EnumDef &enum_def, std::string *code_ptr) {
|
||||
if (enum_def.generated) return;
|
||||
|
||||
GenComment(enum_def.doc_comment, code_ptr, nullptr, "# ");
|
||||
BeginEnum(enum_def.name, code_ptr);
|
||||
for (auto it = enum_def.vals.vec.begin();
|
||||
it != enum_def.vals.vec.end();
|
||||
++it) {
|
||||
auto &ev = **it;
|
||||
GenComment(ev.doc_comment, code_ptr, nullptr, "# ");
|
||||
EnumMember(ev, code_ptr);
|
||||
}
|
||||
EndEnum(code_ptr);
|
||||
}
|
||||
|
||||
// Returns the function name that is able to read a value of the given type.
|
||||
static std::string GenGetter(const Type &type) {
|
||||
switch (type.base_type) {
|
||||
case BASE_TYPE_STRING: return "self._tab.String(";
|
||||
case BASE_TYPE_UNION: return "self._tab.Union(";
|
||||
case BASE_TYPE_VECTOR: return GenGetter(type.VectorType());
|
||||
default:
|
||||
return "self._tab.Get(flatbuffers.number_types." + \
|
||||
MakeCamel(GenTypeGet(type)) + \
|
||||
"Flags, ";
|
||||
}
|
||||
}
|
||||
|
||||
// Returns the method name for use with add/put calls.
|
||||
static std::string GenMethod(const FieldDef &field) {
|
||||
return IsScalar(field.value.type.base_type)
|
||||
? MakeCamel(GenTypeBasic(field.value.type))
|
||||
: (IsStruct(field.value.type) ? "Struct" : "UOffsetTRelative");
|
||||
}
|
||||
|
||||
|
||||
// Save out the generated code for a Python Table type.
|
||||
static bool SaveType(const Parser &parser, const Definition &def,
|
||||
const std::string &classcode, const std::string &path,
|
||||
bool needs_imports) {
|
||||
if (!classcode.length()) return true;
|
||||
|
||||
std::string namespace_name;
|
||||
std::string namespace_dir = path;
|
||||
auto &namespaces = parser.namespaces_.back()->components;
|
||||
for (auto it = namespaces.begin(); it != namespaces.end(); ++it) {
|
||||
if (namespace_name.length()) {
|
||||
namespace_name += ".";
|
||||
namespace_dir += kPathSeparator;
|
||||
}
|
||||
namespace_name = *it;
|
||||
namespace_dir += *it;
|
||||
EnsureDirExists(namespace_dir.c_str());
|
||||
|
||||
std::string init_py_filename = namespace_dir + "/__init__.py";
|
||||
SaveFile(init_py_filename.c_str(), "", false);
|
||||
}
|
||||
|
||||
|
||||
std::string code = "";
|
||||
BeginFile(namespace_name, needs_imports, &code);
|
||||
code += classcode;
|
||||
std::string filename = namespace_dir + kPathSeparator + def.name + ".py";
|
||||
return SaveFile(filename.c_str(), code, false);
|
||||
}
|
||||
|
||||
static std::string GenTypeBasic(const Type &type) {
|
||||
static const char *ctypename[] = {
|
||||
#define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \
|
||||
#PTYPE,
|
||||
FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
|
||||
#undef FLATBUFFERS_TD
|
||||
};
|
||||
return ctypename[type.base_type];
|
||||
}
|
||||
|
||||
static std::string GenTypePointer(const Type &type) {
|
||||
switch (type.base_type) {
|
||||
case BASE_TYPE_STRING:
|
||||
return "string";
|
||||
case BASE_TYPE_VECTOR:
|
||||
return GenTypeGet(type.VectorType());
|
||||
case BASE_TYPE_STRUCT:
|
||||
return type.struct_def->name;
|
||||
case BASE_TYPE_UNION:
|
||||
// fall through
|
||||
default:
|
||||
return "*flatbuffers.Table";
|
||||
}
|
||||
}
|
||||
|
||||
static std::string GenTypeGet(const Type &type) {
|
||||
return IsScalar(type.base_type)
|
||||
? GenTypeBasic(type)
|
||||
: GenTypePointer(type);
|
||||
}
|
||||
|
||||
static std::string TypeName(const FieldDef &field) {
|
||||
return GenTypeGet(field.value.type);
|
||||
}
|
||||
|
||||
// Create a struct with a builder and the struct's arguments.
|
||||
static void GenStructBuilder(const StructDef &struct_def,
|
||||
std::string *code_ptr) {
|
||||
BeginBuilderArgs(struct_def, code_ptr);
|
||||
StructBuilderArgs(struct_def, "", code_ptr);
|
||||
EndBuilderArgs(code_ptr);
|
||||
|
||||
StructBuilderBody(struct_def, "", code_ptr);
|
||||
EndBuilderBody(code_ptr);
|
||||
}
|
||||
|
||||
} // namespace python
|
||||
|
||||
bool GeneratePython(const Parser &parser,
|
||||
const std::string &path,
|
||||
const std::string & /*file_name*/,
|
||||
const GeneratorOptions & /*opts*/) {
|
||||
for (auto it = parser.enums_.vec.begin();
|
||||
it != parser.enums_.vec.end(); ++it) {
|
||||
std::string enumcode;
|
||||
python::GenEnum(**it, &enumcode);
|
||||
if (!python::SaveType(parser, **it, enumcode, path, false))
|
||||
return false;
|
||||
}
|
||||
|
||||
for (auto it = parser.structs_.vec.begin();
|
||||
it != parser.structs_.vec.end(); ++it) {
|
||||
std::string declcode;
|
||||
python::GenStruct(**it, &declcode, parser.root_struct_def_);
|
||||
if (!python::SaveType(parser, **it, declcode, path, true))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace flatbuffers
|
||||
@@ -60,7 +60,12 @@ template<typename T> void Print(T val, Type type, int /*indent*/,
|
||||
return;
|
||||
}
|
||||
}
|
||||
text += NumToString(val);
|
||||
|
||||
if (type.base_type == BASE_TYPE_BOOL) {
|
||||
text += val != 0 ? "true" : "false";
|
||||
} else {
|
||||
text += NumToString(val);
|
||||
}
|
||||
}
|
||||
|
||||
// Print a vector a sequence of JSON values, comma separated, wrapped in "[]".
|
||||
@@ -80,7 +85,7 @@ template<typename T> void PrintVector(const Vector<T> &v, Type type,
|
||||
Print(v.GetStructFromOffset(i * type.struct_def->bytesize), type,
|
||||
indent + Indent(opts), nullptr, opts, _text);
|
||||
else
|
||||
Print(v.Get(i), type, indent + Indent(opts), nullptr,
|
||||
Print(v[i], type, indent + Indent(opts), nullptr,
|
||||
opts, _text);
|
||||
}
|
||||
text += NewLine(opts);
|
||||
@@ -92,7 +97,7 @@ static void EscapeString(const String &s, std::string *_text) {
|
||||
std::string &text = *_text;
|
||||
text += "\"";
|
||||
for (uoffset_t i = 0; i < s.size(); i++) {
|
||||
char c = s.Get(i);
|
||||
char c = s[i];
|
||||
switch (c) {
|
||||
case '\n': text += "\\n"; break;
|
||||
case '\t': text += "\\t"; break;
|
||||
@@ -159,7 +164,8 @@ template<> void Print<const void *>(const void *val,
|
||||
type = type.VectorType();
|
||||
// Call PrintVector above specifically for each element type:
|
||||
switch (type.base_type) {
|
||||
#define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE) \
|
||||
#define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, \
|
||||
PTYPE) \
|
||||
case BASE_TYPE_ ## ENUM: \
|
||||
PrintVector<CTYPE>( \
|
||||
*reinterpret_cast<const Vector<CTYPE> *>(val), \
|
||||
@@ -215,8 +221,11 @@ static void GenStruct(const StructDef &struct_def, const Table *table,
|
||||
it != struct_def.fields.vec.end();
|
||||
++it) {
|
||||
FieldDef &fd = **it;
|
||||
if (struct_def.fixed || table->CheckField(fd.value.offset)) {
|
||||
// The field is present.
|
||||
auto is_present = struct_def.fixed || table->CheckField(fd.value.offset);
|
||||
auto output_anyway = opts.output_default_scalars_in_json &&
|
||||
IsScalar(fd.value.type.base_type) &&
|
||||
!fd.deprecated;
|
||||
if (is_present || output_anyway) {
|
||||
if (fieldout++) {
|
||||
text += ",";
|
||||
}
|
||||
@@ -224,28 +233,36 @@ static void GenStruct(const StructDef &struct_def, const Table *table,
|
||||
text.append(indent + Indent(opts), ' ');
|
||||
OutputIdentifier(fd.name, opts, _text);
|
||||
text += ": ";
|
||||
switch (fd.value.type.base_type) {
|
||||
#define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE) \
|
||||
case BASE_TYPE_ ## ENUM: \
|
||||
GenField<CTYPE>(fd, table, struct_def.fixed, \
|
||||
opts, indent + Indent(opts), _text); \
|
||||
if (is_present) {
|
||||
switch (fd.value.type.base_type) {
|
||||
#define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, \
|
||||
PTYPE) \
|
||||
case BASE_TYPE_ ## ENUM: \
|
||||
GenField<CTYPE>(fd, table, struct_def.fixed, \
|
||||
opts, indent + Indent(opts), _text); \
|
||||
break;
|
||||
FLATBUFFERS_GEN_TYPES_SCALAR(FLATBUFFERS_TD)
|
||||
#undef FLATBUFFERS_TD
|
||||
// Generate drop-thru case statements for all pointer types:
|
||||
#define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, \
|
||||
PTYPE) \
|
||||
case BASE_TYPE_ ## ENUM:
|
||||
FLATBUFFERS_GEN_TYPES_POINTER(FLATBUFFERS_TD)
|
||||
#undef FLATBUFFERS_TD
|
||||
GenFieldOffset(fd, table, struct_def.fixed, indent + Indent(opts),
|
||||
union_sd, opts, _text);
|
||||
break;
|
||||
FLATBUFFERS_GEN_TYPES_SCALAR(FLATBUFFERS_TD)
|
||||
#undef FLATBUFFERS_TD
|
||||
// Generate drop-thru case statements for all pointer types:
|
||||
#define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE) \
|
||||
case BASE_TYPE_ ## ENUM:
|
||||
FLATBUFFERS_GEN_TYPES_POINTER(FLATBUFFERS_TD)
|
||||
#undef FLATBUFFERS_TD
|
||||
GenFieldOffset(fd, table, struct_def.fixed, indent + Indent(opts),
|
||||
union_sd, opts, _text);
|
||||
break;
|
||||
}
|
||||
if (fd.value.type.base_type == BASE_TYPE_UTYPE) {
|
||||
auto enum_val = fd.value.type.enum_def->ReverseLookup(
|
||||
table->GetField<uint8_t>(fd.value.offset, 0));
|
||||
assert(enum_val);
|
||||
union_sd = enum_val->struct_def;
|
||||
}
|
||||
}
|
||||
if (fd.value.type.base_type == BASE_TYPE_UTYPE) {
|
||||
auto enum_val = fd.value.type.enum_def->ReverseLookup(
|
||||
table->GetField<uint8_t>(fd.value.offset, 0));
|
||||
assert(enum_val);
|
||||
union_sd = enum_val->struct_def;
|
||||
else
|
||||
{
|
||||
text += fd.value.constant;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -258,9 +275,9 @@ static void GenStruct(const StructDef &struct_def, const Table *table,
|
||||
void GenerateText(const Parser &parser, const void *flatbuffer,
|
||||
const GeneratorOptions &opts, std::string *_text) {
|
||||
std::string &text = *_text;
|
||||
assert(parser.root_struct_def); // call SetRootType()
|
||||
assert(parser.root_struct_def_); // call SetRootType()
|
||||
text.reserve(1024); // Reduce amount of inevitable reallocs.
|
||||
GenStruct(*parser.root_struct_def,
|
||||
GenStruct(*parser.root_struct_def_,
|
||||
GetRoot<Table>(flatbuffer),
|
||||
0,
|
||||
opts,
|
||||
@@ -277,7 +294,7 @@ bool GenerateTextFile(const Parser &parser,
|
||||
const std::string &path,
|
||||
const std::string &file_name,
|
||||
const GeneratorOptions &opts) {
|
||||
if (!parser.builder_.GetSize() || !parser.root_struct_def) return true;
|
||||
if (!parser.builder_.GetSize() || !parser.root_struct_def_) return true;
|
||||
std::string text;
|
||||
GenerateText(parser, parser.builder_.GetBufferPointer(), opts,
|
||||
&text);
|
||||
@@ -290,12 +307,12 @@ std::string TextMakeRule(const Parser &parser,
|
||||
const std::string &path,
|
||||
const std::string &file_name,
|
||||
const GeneratorOptions & /*opts*/) {
|
||||
if (!parser.builder_.GetSize() || !parser.root_struct_def) return "";
|
||||
if (!parser.builder_.GetSize() || !parser.root_struct_def_) return "";
|
||||
std::string filebase = flatbuffers::StripPath(
|
||||
flatbuffers::StripExtension(file_name));
|
||||
std::string make_rule = TextFileName(path, filebase) + ": " + file_name;
|
||||
auto included_files = parser.GetIncludedFilesRecursive(
|
||||
parser.root_struct_def->file);
|
||||
parser.root_struct_def_->file);
|
||||
for (auto it = included_files.begin();
|
||||
it != included_files.end(); ++it) {
|
||||
make_rule += " " + *it;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
471
src/reflection.cpp
Normal file
471
src/reflection.cpp
Normal file
@@ -0,0 +1,471 @@
|
||||
/*
|
||||
* Copyright 2015 Google Inc. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "flatbuffers/reflection.h"
|
||||
#include "flatbuffers/util.h"
|
||||
|
||||
// Helper functionality for reflection.
|
||||
|
||||
namespace flatbuffers {
|
||||
|
||||
int64_t GetAnyValueI(reflection::BaseType type, const uint8_t *data) {
|
||||
# define FLATBUFFERS_GET(T) static_cast<int64_t>(ReadScalar<T>(data))
|
||||
switch (type) {
|
||||
case reflection::UType:
|
||||
case reflection::Bool:
|
||||
case reflection::UByte: return FLATBUFFERS_GET(uint8_t);
|
||||
case reflection::Byte: return FLATBUFFERS_GET(int8_t);
|
||||
case reflection::Short: return FLATBUFFERS_GET(int16_t);
|
||||
case reflection::UShort: return FLATBUFFERS_GET(uint16_t);
|
||||
case reflection::Int: return FLATBUFFERS_GET(int32_t);
|
||||
case reflection::UInt: return FLATBUFFERS_GET(uint32_t);
|
||||
case reflection::Long: return FLATBUFFERS_GET(int64_t);
|
||||
case reflection::ULong: return FLATBUFFERS_GET(uint64_t);
|
||||
case reflection::Float: return FLATBUFFERS_GET(float);
|
||||
case reflection::Double: return FLATBUFFERS_GET(double);
|
||||
case reflection::String: {
|
||||
auto s = reinterpret_cast<const String *>(ReadScalar<uoffset_t>(data) +
|
||||
data);
|
||||
return s ? StringToInt(s->c_str()) : 0;
|
||||
}
|
||||
default: return 0; // Tables & vectors do not make sense.
|
||||
}
|
||||
# undef FLATBUFFERS_GET
|
||||
}
|
||||
|
||||
double GetAnyValueF(reflection::BaseType type, const uint8_t *data) {
|
||||
switch (type) {
|
||||
case reflection::Float: return static_cast<double>(ReadScalar<float>(data));
|
||||
case reflection::Double: return ReadScalar<double>(data);
|
||||
case reflection::String: {
|
||||
auto s = reinterpret_cast<const String *>(ReadScalar<uoffset_t>(data) +
|
||||
data);
|
||||
return s ? strtod(s->c_str(), nullptr) : 0.0;
|
||||
}
|
||||
default: return static_cast<double>(GetAnyValueI(type, data));
|
||||
}
|
||||
}
|
||||
|
||||
std::string GetAnyValueS(reflection::BaseType type, const uint8_t *data,
|
||||
const reflection::Schema *schema, int type_index) {
|
||||
switch (type) {
|
||||
case reflection::Float:
|
||||
case reflection::Double: return NumToString(GetAnyValueF(type, data));
|
||||
case reflection::String: {
|
||||
auto s = reinterpret_cast<const String *>(ReadScalar<uoffset_t>(data) +
|
||||
data);
|
||||
return s ? s->c_str() : "";
|
||||
}
|
||||
case reflection::Obj:
|
||||
if (schema) {
|
||||
// Convert the table to a string. This is mostly for debugging purposes,
|
||||
// and does NOT promise to be JSON compliant.
|
||||
// Also prefixes the type.
|
||||
auto &objectdef = *schema->objects()->Get(type_index);
|
||||
auto s = objectdef.name()->str();
|
||||
if (objectdef.is_struct()) {
|
||||
s += "(struct)"; // TODO: implement this as well.
|
||||
} else {
|
||||
auto table_field = reinterpret_cast<const Table *>(
|
||||
ReadScalar<uoffset_t>(data) + data);
|
||||
s += " { ";
|
||||
auto fielddefs = objectdef.fields();
|
||||
for (auto it = fielddefs->begin(); it != fielddefs->end(); ++it) {
|
||||
auto &fielddef = **it;
|
||||
if (!table_field->CheckField(fielddef.offset())) continue;
|
||||
auto val = GetAnyFieldS(*table_field, fielddef, schema);
|
||||
if (fielddef.type()->base_type() == reflection::String)
|
||||
val = "\"" + val + "\""; // Doesn't deal with escape codes etc.
|
||||
s += fielddef.name()->str();
|
||||
s += ": ";
|
||||
s += val;
|
||||
s += ", ";
|
||||
}
|
||||
s += "}";
|
||||
}
|
||||
return s;
|
||||
} else {
|
||||
return "(table)";
|
||||
}
|
||||
case reflection::Vector:
|
||||
return "[(elements)]"; // TODO: implement this as well.
|
||||
case reflection::Union:
|
||||
return "(union)"; // TODO: implement this as well.
|
||||
default: return NumToString(GetAnyValueI(type, data));
|
||||
}
|
||||
}
|
||||
|
||||
void SetAnyValueI(reflection::BaseType type, uint8_t *data, int64_t val) {
|
||||
# define FLATBUFFERS_SET(T) WriteScalar(data, static_cast<T>(val))
|
||||
switch (type) {
|
||||
case reflection::UType:
|
||||
case reflection::Bool:
|
||||
case reflection::UByte: FLATBUFFERS_SET(uint8_t ); break;
|
||||
case reflection::Byte: FLATBUFFERS_SET(int8_t ); break;
|
||||
case reflection::Short: FLATBUFFERS_SET(int16_t ); break;
|
||||
case reflection::UShort: FLATBUFFERS_SET(uint16_t); break;
|
||||
case reflection::Int: FLATBUFFERS_SET(int32_t ); break;
|
||||
case reflection::UInt: FLATBUFFERS_SET(uint32_t); break;
|
||||
case reflection::Long: FLATBUFFERS_SET(int64_t ); break;
|
||||
case reflection::ULong: FLATBUFFERS_SET(uint64_t); break;
|
||||
case reflection::Float: FLATBUFFERS_SET(float ); break;
|
||||
case reflection::Double: FLATBUFFERS_SET(double ); break;
|
||||
// TODO: support strings
|
||||
default: break;
|
||||
}
|
||||
# undef FLATBUFFERS_SET
|
||||
}
|
||||
|
||||
void SetAnyValueF(reflection::BaseType type, uint8_t *data, double val) {
|
||||
switch (type) {
|
||||
case reflection::Float: WriteScalar(data, static_cast<float>(val)); break;
|
||||
case reflection::Double: WriteScalar(data, val); break;
|
||||
// TODO: support strings.
|
||||
default: SetAnyValueI(type, data, static_cast<int64_t>(val)); break;
|
||||
}
|
||||
}
|
||||
|
||||
void SetAnyValueS(reflection::BaseType type, uint8_t *data, const char *val) {
|
||||
switch (type) {
|
||||
case reflection::Float:
|
||||
case reflection::Double:
|
||||
SetAnyValueF(type, data, strtod(val, nullptr));
|
||||
break;
|
||||
// TODO: support strings.
|
||||
default: SetAnyValueI(type, data, StringToInt(val)); break;
|
||||
}
|
||||
}
|
||||
|
||||
// Resize a FlatBuffer in-place by iterating through all offsets in the buffer
|
||||
// and adjusting them by "delta" if they straddle the start offset.
|
||||
// Once that is done, bytes can now be inserted/deleted safely.
|
||||
// "delta" may be negative (shrinking).
|
||||
// Unless "delta" is a multiple of the largest alignment, you'll create a small
|
||||
// amount of garbage space in the buffer (usually 0..7 bytes).
|
||||
// If your FlatBuffer's root table is not the schema's root table, you should
|
||||
// pass in your root_table type as well.
|
||||
class ResizeContext {
|
||||
public:
|
||||
ResizeContext(const reflection::Schema &schema, uoffset_t start, int delta,
|
||||
std::vector<uint8_t> *flatbuf,
|
||||
const reflection::Object *root_table = nullptr)
|
||||
: schema_(schema), startptr_(flatbuf->data() + start),
|
||||
delta_(delta), buf_(*flatbuf),
|
||||
dag_check_(flatbuf->size() / sizeof(uoffset_t), false) {
|
||||
auto mask = static_cast<int>(sizeof(largest_scalar_t) - 1);
|
||||
delta_ = (delta_ + mask) & ~mask;
|
||||
if (!delta_) return; // We can't shrink by less than largest_scalar_t.
|
||||
// Now change all the offsets by delta_.
|
||||
auto root = GetAnyRoot(buf_.data());
|
||||
Straddle<uoffset_t, 1>(buf_.data(), root, buf_.data());
|
||||
ResizeTable(root_table ? *root_table : *schema.root_table(), root);
|
||||
// We can now add or remove bytes at start.
|
||||
if (delta_ > 0) buf_.insert(buf_.begin() + start, delta_, 0);
|
||||
else buf_.erase(buf_.begin() + start, buf_.begin() + start - delta_);
|
||||
}
|
||||
|
||||
// Check if the range between first (lower address) and second straddles
|
||||
// the insertion point. If it does, change the offset at offsetloc (of
|
||||
// type T, with direction D).
|
||||
template<typename T, int D> void Straddle(void *first, void *second,
|
||||
void *offsetloc) {
|
||||
if (first <= startptr_ && second >= startptr_) {
|
||||
WriteScalar<T>(offsetloc, ReadScalar<T>(offsetloc) + delta_ * D);
|
||||
DagCheck(offsetloc) = true;
|
||||
}
|
||||
}
|
||||
|
||||
// This returns a boolean that records if the corresponding offset location
|
||||
// has been modified already. If so, we can't even read the corresponding
|
||||
// offset, since it is pointing to a location that is illegal until the
|
||||
// resize actually happens.
|
||||
// This must be checked for every offset, since we can't know which offsets
|
||||
// will straddle and which won't.
|
||||
uint8_t &DagCheck(void *offsetloc) {
|
||||
auto dag_idx = reinterpret_cast<uoffset_t *>(offsetloc) -
|
||||
reinterpret_cast<uoffset_t *>(buf_.data());
|
||||
return dag_check_[dag_idx];
|
||||
}
|
||||
|
||||
void ResizeTable(const reflection::Object &objectdef, Table *table) {
|
||||
if (DagCheck(table))
|
||||
return; // Table already visited.
|
||||
auto vtable = table->GetVTable();
|
||||
// Check if the vtable offset points beyond the insertion point.
|
||||
Straddle<soffset_t, -1>(table, vtable, table);
|
||||
// This direction shouldn't happen because vtables that sit before tables
|
||||
// are always directly adjacent, but check just in case we ever change the
|
||||
// way flatbuffers are built.
|
||||
Straddle<soffset_t, -1>(vtable, table, table);
|
||||
// Early out: since all fields inside the table must point forwards in
|
||||
// memory, if the insertion point is before the table we can stop here.
|
||||
auto tableloc = reinterpret_cast<uint8_t *>(table);
|
||||
if (startptr_ <= tableloc) return;
|
||||
// Check each field.
|
||||
auto fielddefs = objectdef.fields();
|
||||
for (auto it = fielddefs->begin(); it != fielddefs->end(); ++it) {
|
||||
auto &fielddef = **it;
|
||||
auto base_type = fielddef.type()->base_type();
|
||||
// Ignore scalars.
|
||||
if (base_type <= reflection::Double) continue;
|
||||
// Ignore fields that are not stored.
|
||||
auto offset = table->GetOptionalFieldOffset(fielddef.offset());
|
||||
if (!offset) continue;
|
||||
// Ignore structs.
|
||||
auto subobjectdef = base_type == reflection::Obj ?
|
||||
schema_.objects()->Get(fielddef.type()->index()) : nullptr;
|
||||
if (subobjectdef && subobjectdef->is_struct()) continue;
|
||||
// Get this fields' offset, and read it if safe.
|
||||
auto offsetloc = tableloc + offset;
|
||||
if (DagCheck(offsetloc))
|
||||
continue; // This offset already visited.
|
||||
auto ref = offsetloc + ReadScalar<uoffset_t>(offsetloc);
|
||||
Straddle<uoffset_t, 1>(offsetloc, ref, offsetloc);
|
||||
// Recurse.
|
||||
switch (base_type) {
|
||||
case reflection::Obj: {
|
||||
ResizeTable(*subobjectdef, reinterpret_cast<Table *>(ref));
|
||||
break;
|
||||
}
|
||||
case reflection::Vector: {
|
||||
auto elem_type = fielddef.type()->element();
|
||||
if (elem_type != reflection::Obj && elem_type != reflection::String)
|
||||
break;
|
||||
auto vec = reinterpret_cast<Vector<uoffset_t> *>(ref);
|
||||
auto elemobjectdef = elem_type == reflection::Obj
|
||||
? schema_.objects()->Get(fielddef.type()->index())
|
||||
: nullptr;
|
||||
if (elemobjectdef && elemobjectdef->is_struct()) break;
|
||||
for (uoffset_t i = 0; i < vec->size(); i++) {
|
||||
auto loc = vec->Data() + i * sizeof(uoffset_t);
|
||||
if (DagCheck(loc))
|
||||
continue; // This offset already visited.
|
||||
auto dest = loc + vec->Get(i);
|
||||
Straddle<uoffset_t, 1>(loc, dest ,loc);
|
||||
if (elemobjectdef)
|
||||
ResizeTable(*elemobjectdef, reinterpret_cast<Table *>(dest));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case reflection::Union: {
|
||||
ResizeTable(GetUnionType(schema_, objectdef, fielddef, *table),
|
||||
reinterpret_cast<Table *>(ref));
|
||||
break;
|
||||
}
|
||||
case reflection::String:
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void operator=(const ResizeContext &rc);
|
||||
|
||||
private:
|
||||
const reflection::Schema &schema_;
|
||||
uint8_t *startptr_;
|
||||
int delta_;
|
||||
std::vector<uint8_t> &buf_;
|
||||
std::vector<uint8_t> dag_check_;
|
||||
};
|
||||
|
||||
void SetString(const reflection::Schema &schema, const std::string &val,
|
||||
const String *str, std::vector<uint8_t> *flatbuf,
|
||||
const reflection::Object *root_table) {
|
||||
auto delta = static_cast<int>(val.size()) - static_cast<int>(str->Length());
|
||||
auto start = static_cast<uoffset_t>(reinterpret_cast<const uint8_t *>(str) -
|
||||
flatbuf->data() +
|
||||
sizeof(uoffset_t));
|
||||
if (delta) {
|
||||
// Clear the old string, since we don't want parts of it remaining.
|
||||
memset(flatbuf->data() + start, 0, str->Length());
|
||||
// Different size, we must expand (or contract).
|
||||
ResizeContext(schema, start, delta, flatbuf, root_table);
|
||||
}
|
||||
// Copy new data. Safe because we created the right amount of space.
|
||||
memcpy(flatbuf->data() + start, val.c_str(), val.size() + 1);
|
||||
}
|
||||
|
||||
uint8_t *ResizeAnyVector(const reflection::Schema &schema, uoffset_t newsize,
|
||||
const VectorOfAny *vec, uoffset_t num_elems,
|
||||
uoffset_t elem_size, std::vector<uint8_t> *flatbuf,
|
||||
const reflection::Object *root_table) {
|
||||
auto delta_elem = static_cast<int>(newsize) - static_cast<int>(num_elems);
|
||||
auto delta_bytes = delta_elem * static_cast<int>(elem_size);
|
||||
auto vec_start = reinterpret_cast<const uint8_t *>(vec) - flatbuf->data();
|
||||
auto start = static_cast<uoffset_t>(vec_start + sizeof(uoffset_t) +
|
||||
elem_size * num_elems);
|
||||
if (delta_bytes) {
|
||||
if (delta_elem < 0) {
|
||||
// Clear elements we're throwing away, since some might remain in the
|
||||
// buffer.
|
||||
auto size_clear = -delta_elem * elem_size;
|
||||
memset(flatbuf->data() + start - size_clear, 0, size_clear);
|
||||
}
|
||||
ResizeContext(schema, start, delta_bytes, flatbuf, root_table);
|
||||
WriteScalar(flatbuf->data() + vec_start, newsize); // Length field.
|
||||
// Set new elements to 0.. this can be overwritten by the caller.
|
||||
if (delta_elem > 0) {
|
||||
memset(flatbuf->data() + start, 0, delta_elem * elem_size);
|
||||
}
|
||||
}
|
||||
return flatbuf->data() + start;
|
||||
}
|
||||
|
||||
const uint8_t *AddFlatBuffer(std::vector<uint8_t> &flatbuf,
|
||||
const uint8_t *newbuf, size_t newlen) {
|
||||
// Align to sizeof(uoffset_t) past sizeof(largest_scalar_t) since we're
|
||||
// going to chop off the root offset.
|
||||
while ((flatbuf.size() & (sizeof(uoffset_t) - 1)) ||
|
||||
!(flatbuf.size() & (sizeof(largest_scalar_t) - 1))) {
|
||||
flatbuf.push_back(0);
|
||||
}
|
||||
auto insertion_point = static_cast<uoffset_t>(flatbuf.size());
|
||||
// Insert the entire FlatBuffer minus the root pointer.
|
||||
flatbuf.insert(flatbuf.end(), newbuf + sizeof(uoffset_t), newbuf + newlen);
|
||||
auto root_offset = ReadScalar<uoffset_t>(newbuf) - sizeof(uoffset_t);
|
||||
return flatbuf.data() + insertion_point + root_offset;
|
||||
}
|
||||
|
||||
void CopyInline(FlatBufferBuilder &fbb, const reflection::Field &fielddef,
|
||||
const Table &table, size_t align, size_t size) {
|
||||
fbb.Align(align);
|
||||
fbb.PushBytes(table.GetStruct<const uint8_t *>(fielddef.offset()), size);
|
||||
fbb.TrackField(fielddef.offset(), fbb.GetSize());
|
||||
}
|
||||
|
||||
Offset<const Table *> CopyTable(FlatBufferBuilder &fbb,
|
||||
const reflection::Schema &schema,
|
||||
const reflection::Object &objectdef,
|
||||
const Table &table) {
|
||||
// Before we can construct the table, we have to first generate any
|
||||
// subobjects, and collect their offsets.
|
||||
std::vector<uoffset_t> offsets;
|
||||
auto fielddefs = objectdef.fields();
|
||||
for (auto it = fielddefs->begin(); it != fielddefs->end(); ++it) {
|
||||
auto &fielddef = **it;
|
||||
// Skip if field is not present in the source.
|
||||
if (!table.CheckField(fielddef.offset())) continue;
|
||||
uoffset_t offset = 0;
|
||||
switch (fielddef.type()->base_type()) {
|
||||
case reflection::String: {
|
||||
offset = fbb.CreateString(GetFieldS(table, fielddef)).o;
|
||||
break;
|
||||
}
|
||||
case reflection::Obj: {
|
||||
auto &subobjectdef = *schema.objects()->Get(fielddef.type()->index());
|
||||
if (!subobjectdef.is_struct()) {
|
||||
offset = CopyTable(fbb, schema, subobjectdef,
|
||||
*GetFieldT(table, fielddef)).o;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case reflection::Union: {
|
||||
auto &subobjectdef = GetUnionType(schema, objectdef, fielddef, table);
|
||||
offset = CopyTable(fbb, schema, subobjectdef,
|
||||
*GetFieldT(table, fielddef)).o;
|
||||
break;
|
||||
}
|
||||
case reflection::Vector: {
|
||||
auto vec = table.GetPointer<const Vector<Offset<Table>> *>(
|
||||
fielddef.offset());
|
||||
auto element_base_type = fielddef.type()->element();
|
||||
auto elemobjectdef = element_base_type == reflection::Obj
|
||||
? schema.objects()->Get(fielddef.type()->index())
|
||||
: nullptr;
|
||||
switch (element_base_type) {
|
||||
case reflection::String: {
|
||||
std::vector<Offset<const String *>> elements(vec->size());
|
||||
auto vec_s = reinterpret_cast<const Vector<Offset<String>> *>(vec);
|
||||
for (uoffset_t i = 0; i < vec_s->size(); i++) {
|
||||
elements[i] = fbb.CreateString(vec_s->Get(i)).o;
|
||||
}
|
||||
offset = fbb.CreateVector(elements).o;
|
||||
break;
|
||||
}
|
||||
case reflection::Obj: {
|
||||
if (!elemobjectdef->is_struct()) {
|
||||
std::vector<Offset<const Table *>> elements(vec->size());
|
||||
for (uoffset_t i = 0; i < vec->size(); i++) {
|
||||
elements[i] =
|
||||
CopyTable(fbb, schema, *elemobjectdef, *vec->Get(i));
|
||||
}
|
||||
offset = fbb.CreateVector(elements).o;
|
||||
break;
|
||||
}
|
||||
// FALL-THRU:
|
||||
}
|
||||
default: { // Scalars and structs.
|
||||
auto element_size = GetTypeSize(element_base_type);
|
||||
if (elemobjectdef && elemobjectdef->is_struct())
|
||||
element_size = elemobjectdef->bytesize();
|
||||
fbb.StartVector(element_size, vec->size());
|
||||
fbb.PushBytes(vec->Data(), element_size * vec->size());
|
||||
offset = fbb.EndVector(vec->size());
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: // Scalars.
|
||||
break;
|
||||
}
|
||||
if (offset) {
|
||||
offsets.push_back(offset);
|
||||
}
|
||||
}
|
||||
// Now we can build the actual table from either offsets or scalar data.
|
||||
auto start = objectdef.is_struct()
|
||||
? fbb.StartStruct(objectdef.minalign())
|
||||
: fbb.StartTable();
|
||||
size_t offset_idx = 0;
|
||||
for (auto it = fielddefs->begin(); it != fielddefs->end(); ++it) {
|
||||
auto &fielddef = **it;
|
||||
if (!table.CheckField(fielddef.offset())) continue;
|
||||
auto base_type = fielddef.type()->base_type();
|
||||
switch (base_type) {
|
||||
case reflection::Obj: {
|
||||
auto &subobjectdef = *schema.objects()->Get(fielddef.type()->index());
|
||||
if (subobjectdef.is_struct()) {
|
||||
CopyInline(fbb, fielddef, table, subobjectdef.minalign(),
|
||||
subobjectdef.bytesize());
|
||||
break;
|
||||
}
|
||||
// else: FALL-THRU:
|
||||
}
|
||||
case reflection::Union:
|
||||
case reflection::String:
|
||||
case reflection::Vector:
|
||||
fbb.AddOffset(fielddef.offset(), Offset<void>(offsets[offset_idx++]));
|
||||
break;
|
||||
default: { // Scalars.
|
||||
auto size = GetTypeSize(base_type);
|
||||
CopyInline(fbb, fielddef, table, size, size);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
assert(offset_idx == offsets.size());
|
||||
if (objectdef.is_struct()) {
|
||||
fbb.ClearOffsets();
|
||||
return fbb.EndStruct();
|
||||
} else {
|
||||
return fbb.EndTable(start, static_cast<voffset_t>(fielddefs->size()));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace flatbuffers
|
||||
@@ -39,6 +39,25 @@ namespace FlatBuffers.Test
|
||||
}
|
||||
}
|
||||
|
||||
public class AssertArrayFailedException : Exception
|
||||
{
|
||||
private readonly int _index;
|
||||
private readonly object _expected;
|
||||
private readonly object _actual;
|
||||
|
||||
public AssertArrayFailedException(int index, object expected, object actual)
|
||||
{
|
||||
_index = index;
|
||||
_expected = expected;
|
||||
_actual = actual;
|
||||
}
|
||||
|
||||
public override string Message
|
||||
{
|
||||
get { return string.Format("Expected {0} at index {1} but saw {2}", _expected, _index, _actual); }
|
||||
}
|
||||
}
|
||||
|
||||
public class AssertUnexpectedThrowException : Exception
|
||||
{
|
||||
private readonly object _expected;
|
||||
@@ -64,6 +83,22 @@ namespace FlatBuffers.Test
|
||||
}
|
||||
}
|
||||
|
||||
public static void ArrayEqual<T>(T[] expected, T[] actual)
|
||||
{
|
||||
if (expected.Length != actual.Length)
|
||||
{
|
||||
throw new AssertFailedException(expected, actual);
|
||||
}
|
||||
|
||||
for(var i = 0; i < expected.Length; ++i)
|
||||
{
|
||||
if (!expected[i].Equals(actual[i]))
|
||||
{
|
||||
throw new AssertArrayFailedException(i, expected, actual);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void IsTrue(bool value)
|
||||
{
|
||||
if (!value)
|
||||
|
||||
@@ -18,9 +18,11 @@ using System;
|
||||
|
||||
namespace FlatBuffers.Test
|
||||
{
|
||||
[FlatBuffersTestClass]
|
||||
public class ByteBufferTests
|
||||
{
|
||||
|
||||
[FlatBuffersTestMethod]
|
||||
public void ByteBuffer_Length_MatchesBufferLength()
|
||||
{
|
||||
var buffer = new byte[1000];
|
||||
@@ -28,6 +30,7 @@ namespace FlatBuffers.Test
|
||||
Assert.AreEqual(buffer.Length, uut.Length);
|
||||
}
|
||||
|
||||
[FlatBuffersTestMethod]
|
||||
public void ByteBuffer_PutBytePopulatesBufferAtZeroOffset()
|
||||
{
|
||||
var buffer = new byte[1];
|
||||
@@ -37,6 +40,7 @@ namespace FlatBuffers.Test
|
||||
Assert.AreEqual((byte)99, buffer[0]);
|
||||
}
|
||||
|
||||
[FlatBuffersTestMethod]
|
||||
public void ByteBuffer_PutByteCannotPutAtOffsetPastLength()
|
||||
{
|
||||
var buffer = new byte[1];
|
||||
@@ -44,6 +48,7 @@ namespace FlatBuffers.Test
|
||||
Assert.Throws<ArgumentOutOfRangeException>(() => uut.PutByte(1, 99));
|
||||
}
|
||||
|
||||
[FlatBuffersTestMethod]
|
||||
public void ByteBuffer_PutShortPopulatesBufferCorrectly()
|
||||
{
|
||||
var buffer = new byte[2];
|
||||
@@ -55,6 +60,7 @@ namespace FlatBuffers.Test
|
||||
Assert.AreEqual((byte)0, buffer[1]);
|
||||
}
|
||||
|
||||
[FlatBuffersTestMethod]
|
||||
public void ByteBuffer_PutShortCannotPutAtOffsetPastLength()
|
||||
{
|
||||
var buffer = new byte[2];
|
||||
@@ -62,6 +68,7 @@ namespace FlatBuffers.Test
|
||||
Assert.Throws<ArgumentOutOfRangeException>(() => uut.PutShort(2, 99));
|
||||
}
|
||||
|
||||
[FlatBuffersTestMethod]
|
||||
public void ByteBuffer_PutShortChecksLength()
|
||||
{
|
||||
var buffer = new byte[1];
|
||||
@@ -69,6 +76,7 @@ namespace FlatBuffers.Test
|
||||
Assert.Throws<ArgumentOutOfRangeException>(() => uut.PutShort(0, 99));
|
||||
}
|
||||
|
||||
[FlatBuffersTestMethod]
|
||||
public void ByteBuffer_PutShortChecksLengthAndOffset()
|
||||
{
|
||||
var buffer = new byte[2];
|
||||
@@ -76,6 +84,7 @@ namespace FlatBuffers.Test
|
||||
Assert.Throws<ArgumentOutOfRangeException>(() => uut.PutShort(1, 99));
|
||||
}
|
||||
|
||||
[FlatBuffersTestMethod]
|
||||
public void ByteBuffer_PutIntPopulatesBufferCorrectly()
|
||||
{
|
||||
var buffer = new byte[4];
|
||||
@@ -89,6 +98,7 @@ namespace FlatBuffers.Test
|
||||
Assert.AreEqual(0x0A, buffer[3]);
|
||||
}
|
||||
|
||||
[FlatBuffersTestMethod]
|
||||
public void ByteBuffer_PutIntCannotPutAtOffsetPastLength()
|
||||
{
|
||||
var buffer = new byte[4];
|
||||
@@ -96,6 +106,7 @@ namespace FlatBuffers.Test
|
||||
Assert.Throws<ArgumentOutOfRangeException>(() => uut.PutInt(2, 0x0A0B0C0D));
|
||||
}
|
||||
|
||||
[FlatBuffersTestMethod]
|
||||
public void ByteBuffer_PutIntChecksLength()
|
||||
{
|
||||
var buffer = new byte[1];
|
||||
@@ -103,6 +114,7 @@ namespace FlatBuffers.Test
|
||||
Assert.Throws<ArgumentOutOfRangeException>(() => uut.PutInt(0, 0x0A0B0C0D));
|
||||
}
|
||||
|
||||
[FlatBuffersTestMethod]
|
||||
public void ByteBuffer_PutIntChecksLengthAndOffset()
|
||||
{
|
||||
var buffer = new byte[4];
|
||||
@@ -110,6 +122,7 @@ namespace FlatBuffers.Test
|
||||
Assert.Throws<ArgumentOutOfRangeException>(() => uut.PutInt(2, 0x0A0B0C0D));
|
||||
}
|
||||
|
||||
[FlatBuffersTestMethod]
|
||||
public void ByteBuffer_PutLongPopulatesBufferCorrectly()
|
||||
{
|
||||
var buffer = new byte[8];
|
||||
@@ -127,6 +140,7 @@ namespace FlatBuffers.Test
|
||||
Assert.AreEqual(0x01, buffer[7]);
|
||||
}
|
||||
|
||||
[FlatBuffersTestMethod]
|
||||
public void ByteBuffer_PutLongCannotPutAtOffsetPastLength()
|
||||
{
|
||||
var buffer = new byte[8];
|
||||
@@ -134,6 +148,7 @@ namespace FlatBuffers.Test
|
||||
Assert.Throws<ArgumentOutOfRangeException>(() => uut.PutLong(2, 0x010203040A0B0C0D));
|
||||
}
|
||||
|
||||
[FlatBuffersTestMethod]
|
||||
public void ByteBuffer_PutLongChecksLength()
|
||||
{
|
||||
var buffer = new byte[1];
|
||||
@@ -141,6 +156,7 @@ namespace FlatBuffers.Test
|
||||
Assert.Throws<ArgumentOutOfRangeException>(() => uut.PutLong(0, 0x010203040A0B0C0D));
|
||||
}
|
||||
|
||||
[FlatBuffersTestMethod]
|
||||
public void ByteBuffer_PutLongChecksLengthAndOffset()
|
||||
{
|
||||
var buffer = new byte[8];
|
||||
@@ -148,6 +164,7 @@ namespace FlatBuffers.Test
|
||||
Assert.Throws<ArgumentOutOfRangeException>(() => uut.PutLong(2, 0x010203040A0B0C0D));
|
||||
}
|
||||
|
||||
[FlatBuffersTestMethod]
|
||||
public void ByteBuffer_GetByteReturnsCorrectData()
|
||||
{
|
||||
var buffer = new byte[1];
|
||||
@@ -156,6 +173,7 @@ namespace FlatBuffers.Test
|
||||
Assert.AreEqual((byte)99, uut.Get(0));
|
||||
}
|
||||
|
||||
[FlatBuffersTestMethod]
|
||||
public void ByteBuffer_GetByteChecksOffset()
|
||||
{
|
||||
var buffer = new byte[1];
|
||||
@@ -163,6 +181,7 @@ namespace FlatBuffers.Test
|
||||
Assert.Throws<ArgumentOutOfRangeException>(()=>uut.Get(1));
|
||||
}
|
||||
|
||||
[FlatBuffersTestMethod]
|
||||
public void ByteBuffer_GetShortReturnsCorrectData()
|
||||
{
|
||||
var buffer = new byte[2];
|
||||
@@ -172,6 +191,7 @@ namespace FlatBuffers.Test
|
||||
Assert.AreEqual(1, uut.GetShort(0));
|
||||
}
|
||||
|
||||
[FlatBuffersTestMethod]
|
||||
public void ByteBuffer_GetShortChecksOffset()
|
||||
{
|
||||
var buffer = new byte[2];
|
||||
@@ -179,6 +199,7 @@ namespace FlatBuffers.Test
|
||||
Assert.Throws<ArgumentOutOfRangeException>(() => uut.GetShort(2));
|
||||
}
|
||||
|
||||
[FlatBuffersTestMethod]
|
||||
public void ByteBuffer_GetShortChecksLength()
|
||||
{
|
||||
var buffer = new byte[2];
|
||||
@@ -186,6 +207,7 @@ namespace FlatBuffers.Test
|
||||
Assert.Throws<ArgumentOutOfRangeException>(() => uut.GetShort(1));
|
||||
}
|
||||
|
||||
[FlatBuffersTestMethod]
|
||||
public void ByteBuffer_GetIntReturnsCorrectData()
|
||||
{
|
||||
var buffer = new byte[4];
|
||||
@@ -197,6 +219,7 @@ namespace FlatBuffers.Test
|
||||
Assert.AreEqual(0x0A0B0C0D, uut.GetInt(0));
|
||||
}
|
||||
|
||||
[FlatBuffersTestMethod]
|
||||
public void ByteBuffer_GetIntChecksOffset()
|
||||
{
|
||||
var buffer = new byte[4];
|
||||
@@ -204,6 +227,7 @@ namespace FlatBuffers.Test
|
||||
Assert.Throws<ArgumentOutOfRangeException>(() => uut.GetInt(4));
|
||||
}
|
||||
|
||||
[FlatBuffersTestMethod]
|
||||
public void ByteBuffer_GetIntChecksLength()
|
||||
{
|
||||
var buffer = new byte[2];
|
||||
@@ -211,6 +235,7 @@ namespace FlatBuffers.Test
|
||||
Assert.Throws<ArgumentOutOfRangeException>(() => uut.GetInt(0));
|
||||
}
|
||||
|
||||
[FlatBuffersTestMethod]
|
||||
public void ByteBuffer_GetLongReturnsCorrectData()
|
||||
{
|
||||
var buffer = new byte[8];
|
||||
@@ -226,6 +251,7 @@ namespace FlatBuffers.Test
|
||||
Assert.AreEqual(0x010203040A0B0C0D, uut.GetLong(0));
|
||||
}
|
||||
|
||||
[FlatBuffersTestMethod]
|
||||
public void ByteBuffer_GetLongChecksOffset()
|
||||
{
|
||||
var buffer = new byte[8];
|
||||
@@ -233,39 +259,44 @@ namespace FlatBuffers.Test
|
||||
Assert.Throws<ArgumentOutOfRangeException>(() => uut.GetLong(8));
|
||||
}
|
||||
|
||||
[FlatBuffersTestMethod]
|
||||
public void ByteBuffer_GetLongChecksLength()
|
||||
{
|
||||
var buffer = new byte[7];
|
||||
var uut = new ByteBuffer(buffer);
|
||||
Assert.Throws<ArgumentOutOfRangeException>(() => uut.GetLong(0));
|
||||
}
|
||||
|
||||
[FlatBuffersTestMethod]
|
||||
public void ByteBuffer_ReverseBytesUshort()
|
||||
{
|
||||
ushort original = (ushort)0x1234U;
|
||||
ushort reverse = ByteBuffer.ReverseBytes(original);
|
||||
const ushort original = (ushort)0x1234U;
|
||||
var reverse = ByteBuffer.ReverseBytes(original);
|
||||
Assert.AreEqual(0x3412U, reverse);
|
||||
|
||||
ushort rereverse = ByteBuffer.ReverseBytes(reverse);
|
||||
var rereverse = ByteBuffer.ReverseBytes(reverse);
|
||||
Assert.AreEqual(original, rereverse);
|
||||
}
|
||||
|
||||
[FlatBuffersTestMethod]
|
||||
public void ByteBuffer_ReverseBytesUint()
|
||||
{
|
||||
uint original = 0x12345678;
|
||||
uint reverse = ByteBuffer.ReverseBytes(original);
|
||||
const uint original = 0x12345678;
|
||||
var reverse = ByteBuffer.ReverseBytes(original);
|
||||
Assert.AreEqual(0x78563412U, reverse);
|
||||
|
||||
uint rereverse = ByteBuffer.ReverseBytes(reverse);
|
||||
var rereverse = ByteBuffer.ReverseBytes(reverse);
|
||||
Assert.AreEqual(original, rereverse);
|
||||
}
|
||||
|
||||
[FlatBuffersTestMethod]
|
||||
public void ByteBuffer_ReverseBytesUlong()
|
||||
{
|
||||
ulong original = 0x1234567890ABCDEFUL;
|
||||
ulong reverse = ByteBuffer.ReverseBytes(original);
|
||||
const ulong original = 0x1234567890ABCDEFUL;
|
||||
var reverse = ByteBuffer.ReverseBytes(original);
|
||||
Assert.AreEqual(0xEFCDAB9078563412UL, reverse);
|
||||
|
||||
ulong rereverse = ByteBuffer.ReverseBytes(reverse);
|
||||
var rereverse = ByteBuffer.ReverseBytes(reverse);
|
||||
Assert.AreEqual(original, rereverse);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,6 +41,9 @@
|
||||
<Compile Include="..\..\net\FlatBuffers\ByteBuffer.cs">
|
||||
<Link>FlatBuffers\ByteBuffer.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\..\net\FlatBuffers\Offset.cs">
|
||||
<Link>FlatBuffers\Offset.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\..\net\FlatBuffers\FlatBufferBuilder.cs">
|
||||
<Link>FlatBuffers\FlatBufferBuilder.cs</Link>
|
||||
</Compile>
|
||||
@@ -68,14 +71,23 @@
|
||||
<Compile Include="..\MyGame\Example\Test.cs">
|
||||
<Link>MyGame\Example\Test.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\MyGame\Example\TestSimpleTableWithEnum.cs">
|
||||
<Link>MyGame\Example\TestSimpleTableWithEnum.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\MyGame\Example\Vec3.cs">
|
||||
<Link>MyGame\Example\Vec3.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="Assert.cs" />
|
||||
<Compile Include="ByteBufferTests.cs" />
|
||||
<Compile Include="FlatBuffersFuzzTests.cs" />
|
||||
<Compile Include="FlatBuffersTestClassAttribute.cs" />
|
||||
<Compile Include="FlatBuffersTestMethodAttribute.cs" />
|
||||
<Compile Include="FuzzTestData.cs" />
|
||||
<Compile Include="Lcg.cs" />
|
||||
<Compile Include="Program.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="FlatBuffersExampleTests.cs" />
|
||||
<Compile Include="TestTable.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="..\monsterdata_test.mon">
|
||||
|
||||
@@ -19,6 +19,7 @@ using MyGame.Example;
|
||||
|
||||
namespace FlatBuffers.Test
|
||||
{
|
||||
[FlatBuffersTestClass]
|
||||
public class FlatBuffersExampleTests
|
||||
{
|
||||
public void RunTests()
|
||||
@@ -28,6 +29,7 @@ namespace FlatBuffers.Test
|
||||
TestEnums();
|
||||
}
|
||||
|
||||
[FlatBuffersTestMethod]
|
||||
public void CanCreateNewFlatBufferFromScratch()
|
||||
{
|
||||
// Second, let's create a FlatBuffer from scratch in C#, and test it also.
|
||||
@@ -61,84 +63,130 @@ namespace FlatBuffers.Test
|
||||
var test4 = fbb.EndVector();
|
||||
|
||||
Monster.StartTestarrayofstringVector(fbb, 2);
|
||||
fbb.AddOffset(test2);
|
||||
fbb.AddOffset(test1);
|
||||
fbb.AddOffset(test2.Value);
|
||||
fbb.AddOffset(test1.Value);
|
||||
var testArrayOfString = fbb.EndVector();
|
||||
|
||||
|
||||
Monster.StartMonster(fbb);
|
||||
Monster.AddPos(fbb, Vec3.CreateVec3(fbb, 1.0f, 2.0f, 3.0f, 3.0,
|
||||
Color.Green, (short)5, (sbyte)6));
|
||||
Monster.AddHp(fbb, (short)80);
|
||||
Monster.AddName(fbb, str);
|
||||
Monster.AddInventory(fbb, inv);
|
||||
Monster.AddTestType(fbb, (byte)1);
|
||||
Monster.AddTest(fbb, mon2);
|
||||
Monster.AddTestType(fbb, Any.Monster);
|
||||
Monster.AddTest(fbb, mon2.Value);
|
||||
Monster.AddTest4(fbb, test4);
|
||||
Monster.AddTestarrayofstring(fbb, testArrayOfString);
|
||||
Monster.AddTestbool(fbb, false);
|
||||
var mon = Monster.EndMonster(fbb);
|
||||
|
||||
fbb.Finish(mon);
|
||||
Monster.FinishMonsterBuffer(fbb, mon);
|
||||
|
||||
|
||||
// Dump to output directory so we can inspect later, if needed
|
||||
using (var ms = new MemoryStream(fbb.DataBuffer().Data, fbb.DataBuffer().position(), fbb.Offset()))
|
||||
using (var ms = new MemoryStream(fbb.DataBuffer.Data, fbb.DataBuffer.Position, fbb.Offset))
|
||||
{
|
||||
var data = ms.ToArray();
|
||||
File.WriteAllBytes(@"Resources/monsterdata_cstest.mon",data);
|
||||
}
|
||||
|
||||
// Now assert the buffer
|
||||
TestBuffer(fbb.DataBuffer());
|
||||
TestBuffer(fbb.DataBuffer);
|
||||
|
||||
//Attempt to mutate Monster fields and check whether the buffer has been mutated properly
|
||||
// revert to original values after testing
|
||||
Monster monster = Monster.GetRootAsMonster(fbb.DataBuffer);
|
||||
|
||||
// mana is optional and does not exist in the buffer so the mutation should fail
|
||||
// the mana field should retain its default value
|
||||
Assert.AreEqual(monster.MutateMana((short)10), false);
|
||||
Assert.AreEqual(monster.Mana, (short)150);
|
||||
|
||||
// testType is an existing field and mutating it should succeed
|
||||
Assert.AreEqual(monster.TestType, Any.Monster);
|
||||
Assert.AreEqual(monster.MutateTestType(Any.NONE), true);
|
||||
Assert.AreEqual(monster.TestType, Any.NONE);
|
||||
Assert.AreEqual(monster.MutateTestType(Any.Monster), true);
|
||||
Assert.AreEqual(monster.TestType, Any.Monster);
|
||||
|
||||
//mutate the inventory vector
|
||||
Assert.AreEqual(monster.MutateInventory(0, 1), true);
|
||||
Assert.AreEqual(monster.MutateInventory(1, 2), true);
|
||||
Assert.AreEqual(monster.MutateInventory(2, 3), true);
|
||||
Assert.AreEqual(monster.MutateInventory(3, 4), true);
|
||||
Assert.AreEqual(monster.MutateInventory(4, 5), true);
|
||||
|
||||
for (int i = 0; i < monster.InventoryLength; i++)
|
||||
{
|
||||
Assert.AreEqual(monster.GetInventory(i), i + 1);
|
||||
}
|
||||
|
||||
//reverse mutation
|
||||
Assert.AreEqual(monster.MutateInventory(0, 0), true);
|
||||
Assert.AreEqual(monster.MutateInventory(1, 1), true);
|
||||
Assert.AreEqual(monster.MutateInventory(2, 2), true);
|
||||
Assert.AreEqual(monster.MutateInventory(3, 3), true);
|
||||
Assert.AreEqual(monster.MutateInventory(4, 4), true);
|
||||
|
||||
// get a struct field and edit one of its fields
|
||||
Vec3 pos = monster.Pos;
|
||||
Assert.AreEqual(pos.X, 1.0f);
|
||||
pos.MutateX(55.0f);
|
||||
Assert.AreEqual(pos.X, 55.0f);
|
||||
pos.MutateX(1.0f);
|
||||
Assert.AreEqual(pos.X, 1.0f);
|
||||
|
||||
TestBuffer(fbb.DataBuffer);
|
||||
}
|
||||
|
||||
private void TestBuffer(ByteBuffer bb)
|
||||
{
|
||||
var monster = Monster.GetRootAsMonster(bb);
|
||||
|
||||
Assert.AreEqual(80, monster.Hp());
|
||||
Assert.AreEqual(150, monster.Mana());
|
||||
Assert.AreEqual("MyMonster", monster.Name());
|
||||
Assert.AreEqual(80, monster.Hp);
|
||||
Assert.AreEqual(150, monster.Mana);
|
||||
Assert.AreEqual("MyMonster", monster.Name);
|
||||
|
||||
var pos = monster.Pos();
|
||||
Assert.AreEqual(1.0f, pos.X());
|
||||
Assert.AreEqual(2.0f, pos.Y());
|
||||
Assert.AreEqual(3.0f, pos.Z());
|
||||
var pos = monster.Pos;
|
||||
Assert.AreEqual(1.0f, pos.X);
|
||||
Assert.AreEqual(2.0f, pos.Y);
|
||||
Assert.AreEqual(3.0f, pos.Z);
|
||||
|
||||
Assert.AreEqual(3.0f, pos.Test1());
|
||||
Assert.AreEqual(Color.Green, pos.Test2());
|
||||
var t = pos.Test3();
|
||||
Assert.AreEqual((short)5, t.A());
|
||||
Assert.AreEqual((sbyte)6, t.B());
|
||||
Assert.AreEqual(3.0f, pos.Test1);
|
||||
Assert.AreEqual(Color.Green, pos.Test2);
|
||||
var t = pos.Test3;
|
||||
Assert.AreEqual((short)5, t.A);
|
||||
Assert.AreEqual((sbyte)6, t.B);
|
||||
|
||||
Assert.AreEqual((byte)Any.Monster, monster.TestType());
|
||||
Assert.AreEqual(Any.Monster, monster.TestType);
|
||||
|
||||
var monster2 = new Monster();
|
||||
Assert.IsTrue(monster.Test(monster2) != null);
|
||||
Assert.AreEqual("Fred", monster2.Name());
|
||||
Assert.IsTrue(monster.GetTest(monster2) != null);
|
||||
Assert.AreEqual("Fred", monster2.Name);
|
||||
|
||||
|
||||
Assert.AreEqual(5, monster.InventoryLength());
|
||||
Assert.AreEqual(5, monster.InventoryLength);
|
||||
var invsum = 0;
|
||||
for (var i = 0; i < monster.InventoryLength(); i++)
|
||||
for (var i = 0; i < monster.InventoryLength; i++)
|
||||
{
|
||||
invsum += monster.Inventory(i);
|
||||
invsum += monster.GetInventory(i);
|
||||
}
|
||||
Assert.AreEqual(10, invsum);
|
||||
|
||||
var test0 = monster.Test4(0);
|
||||
var test1 = monster.Test4(1);
|
||||
Assert.AreEqual(2, monster.Test4Length());
|
||||
var test0 = monster.GetTest4(0);
|
||||
var test1 = monster.GetTest4(1);
|
||||
Assert.AreEqual(2, monster.Test4Length);
|
||||
|
||||
Assert.AreEqual(100, test0.A() + test0.B() + test1.A() + test1.B());
|
||||
Assert.AreEqual(100, test0.A + test0.B + test1.A + test1.B);
|
||||
|
||||
Assert.AreEqual(2, monster.TestarrayofstringLength());
|
||||
Assert.AreEqual("test1", monster.Testarrayofstring(0));
|
||||
Assert.AreEqual("test2", monster.Testarrayofstring(1));
|
||||
Assert.AreEqual(2, monster.TestarrayofstringLength);
|
||||
Assert.AreEqual("test1", monster.GetTestarrayofstring(0));
|
||||
Assert.AreEqual("test2", monster.GetTestarrayofstring(1));
|
||||
|
||||
Assert.AreEqual(false, monster.Testbool());
|
||||
Assert.AreEqual(false, monster.Testbool);
|
||||
}
|
||||
|
||||
[FlatBuffersTestMethod]
|
||||
public void CanReadCppGeneratedWireFile()
|
||||
{
|
||||
var data = File.ReadAllBytes(@"Resources/monsterdata_test.mon");
|
||||
@@ -146,12 +194,13 @@ namespace FlatBuffers.Test
|
||||
TestBuffer(bb);
|
||||
}
|
||||
|
||||
[FlatBuffersTestMethod]
|
||||
public void TestEnums()
|
||||
{
|
||||
Assert.AreEqual(Color.Name(Color.Red), "Red");
|
||||
Assert.AreEqual(Color.Name(Color.Blue), "Blue");
|
||||
Assert.AreEqual(Any.Name(Any.NONE), "NONE");
|
||||
Assert.AreEqual(Any.Name(Any.Monster), "Monster");
|
||||
Assert.AreEqual("Red", Color.Red.ToString());
|
||||
Assert.AreEqual("Blue", Color.Blue.ToString());
|
||||
Assert.AreEqual("NONE", Any.NONE.ToString());
|
||||
Assert.AreEqual("Monster", Any.Monster.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
742
tests/FlatBuffers.Test/FlatBuffersFuzzTests.cs
Normal file
742
tests/FlatBuffers.Test/FlatBuffersFuzzTests.cs
Normal file
@@ -0,0 +1,742 @@
|
||||
/*
|
||||
* Copyright 2015 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.
|
||||
*/
|
||||
|
||||
using System;
|
||||
|
||||
namespace FlatBuffers.Test
|
||||
{
|
||||
[FlatBuffersTestClass]
|
||||
public class FlatBuffersFuzzTests
|
||||
{
|
||||
private readonly Lcg _lcg = new Lcg();
|
||||
|
||||
[FlatBuffersTestMethod]
|
||||
public void TestObjects()
|
||||
{
|
||||
CheckObjects(11, 100);
|
||||
}
|
||||
|
||||
[FlatBuffersTestMethod]
|
||||
public void TestNumbers()
|
||||
{
|
||||
var builder = new FlatBufferBuilder(1);
|
||||
Assert.ArrayEqual(new byte[] { 0 }, builder.DataBuffer.Data);
|
||||
builder.AddBool(true);
|
||||
Assert.ArrayEqual(new byte[] { 1 }, builder.DataBuffer.Data);
|
||||
builder.AddSbyte(-127);
|
||||
Assert.ArrayEqual(new byte[] { 129, 1 }, builder.DataBuffer.Data);
|
||||
builder.AddByte(255);
|
||||
Assert.ArrayEqual(new byte[] { 0, 255, 129, 1 }, builder.DataBuffer.Data); // First pad
|
||||
builder.AddShort(-32222);
|
||||
Assert.ArrayEqual(new byte[] { 0, 0, 0x22, 0x82, 0, 255, 129, 1 }, builder.DataBuffer.Data); // Second pad
|
||||
builder.AddUshort(0xFEEE);
|
||||
Assert.ArrayEqual(new byte[] { 0xEE, 0xFE, 0x22, 0x82, 0, 255, 129, 1 }, builder.DataBuffer.Data); // no pad
|
||||
builder.AddInt(-53687092);
|
||||
Assert.ArrayEqual(new byte[] { 0, 0, 0, 0, 204, 204, 204, 252, 0xEE, 0xFE, 0x22, 0x82, 0, 255, 129, 1 }, builder.DataBuffer.Data); // third pad
|
||||
builder.AddUint(0x98765432);
|
||||
Assert.ArrayEqual(new byte[] { 0x32, 0x54, 0x76, 0x98, 204, 204, 204, 252, 0xEE, 0xFE, 0x22, 0x82, 0, 255, 129, 1 }, builder.DataBuffer.Data); // no pad
|
||||
}
|
||||
|
||||
[FlatBuffersTestMethod]
|
||||
public void TestNumbers64()
|
||||
{
|
||||
var builder = new FlatBufferBuilder(1);
|
||||
builder.AddUlong(0x1122334455667788);
|
||||
Assert.ArrayEqual(new byte[] { 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11 }, builder.DataBuffer.Data);
|
||||
|
||||
builder = new FlatBufferBuilder(1);
|
||||
builder.AddLong(0x1122334455667788);
|
||||
Assert.ArrayEqual(new byte[] { 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11 }, builder.DataBuffer.Data);
|
||||
}
|
||||
|
||||
[FlatBuffersTestMethod]
|
||||
public void TestVector_1xUInt8()
|
||||
{
|
||||
var builder = new FlatBufferBuilder(1);
|
||||
builder.StartVector(sizeof(byte), 1, 1);
|
||||
Assert.ArrayEqual(new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 }, builder.DataBuffer.Data);
|
||||
builder.AddByte(1);
|
||||
Assert.ArrayEqual(new byte[] { 0, 0, 0, 0, 1, 0, 0, 0 }, builder.DataBuffer.Data);
|
||||
builder.EndVector();
|
||||
Assert.ArrayEqual(new byte[] { 1, 0, 0, 0, 1, 0, 0, 0 }, builder.DataBuffer.Data);
|
||||
}
|
||||
|
||||
[FlatBuffersTestMethod]
|
||||
public void TestVector_2xUint8()
|
||||
{
|
||||
var builder = new FlatBufferBuilder(1);
|
||||
builder.StartVector(sizeof(byte), 2, 1);
|
||||
Assert.ArrayEqual(new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 }, builder.DataBuffer.Data);
|
||||
builder.AddByte(1);
|
||||
Assert.ArrayEqual(new byte[] { 0, 0, 0, 0, 0, 1, 0, 0 }, builder.DataBuffer.Data);
|
||||
builder.AddByte(2);
|
||||
Assert.ArrayEqual(new byte[] { 0, 0, 0, 0, 2, 1, 0, 0 }, builder.DataBuffer.Data);
|
||||
builder.EndVector();
|
||||
Assert.ArrayEqual(new byte[] { 2, 0, 0, 0, 2, 1, 0, 0 }, builder.DataBuffer.Data);
|
||||
}
|
||||
|
||||
[FlatBuffersTestMethod]
|
||||
public void TestVector_1xUInt16()
|
||||
{
|
||||
var builder = new FlatBufferBuilder(1);
|
||||
builder.StartVector(sizeof(ushort), 1, 1);
|
||||
Assert.ArrayEqual(new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 }, builder.DataBuffer.Data);
|
||||
builder.AddUshort(1);
|
||||
Assert.ArrayEqual(new byte[] { 0, 0, 0, 0, 1, 0, 0, 0 }, builder.DataBuffer.Data);
|
||||
builder.EndVector();
|
||||
Assert.ArrayEqual(new byte[] { 1, 0, 0, 0, 1, 0, 0, 0 }, builder.DataBuffer.Data);
|
||||
}
|
||||
|
||||
[FlatBuffersTestMethod]
|
||||
public void TestVector_2xUInt16()
|
||||
{
|
||||
var builder = new FlatBufferBuilder(1);
|
||||
builder.StartVector(sizeof(ushort), 2, 1);
|
||||
Assert.ArrayEqual(new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 }, builder.DataBuffer.Data);
|
||||
builder.AddUshort(0xABCD);
|
||||
Assert.ArrayEqual(new byte[] { 0, 0, 0, 0, 0, 0, 0xCD, 0xAB }, builder.DataBuffer.Data);
|
||||
builder.AddUshort(0xDCBA);
|
||||
Assert.ArrayEqual(new byte[] { 0, 0, 0, 0, 0xBA, 0xDC, 0xCD, 0xAB }, builder.DataBuffer.Data);
|
||||
builder.EndVector();
|
||||
Assert.ArrayEqual(new byte[] { 2, 0, 0, 0, 0xBA, 0xDC, 0xCD, 0xAB }, builder.DataBuffer.Data);
|
||||
}
|
||||
|
||||
[FlatBuffersTestMethod]
|
||||
public void TestCreateAsciiString()
|
||||
{
|
||||
var builder = new FlatBufferBuilder(1);
|
||||
builder.CreateString("foo");
|
||||
Assert.ArrayEqual(new byte[] { 3, 0, 0, 0, (byte)'f', (byte)'o', (byte)'o', 0 }, builder.DataBuffer.Data);
|
||||
|
||||
builder.CreateString("moop");
|
||||
Assert.ArrayEqual(new byte[]
|
||||
{
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0, // Padding to 32 bytes
|
||||
4, 0, 0, 0,
|
||||
(byte)'m', (byte)'o', (byte)'o', (byte)'p',
|
||||
0, 0, 0, 0, // zero terminator with 3 byte pad
|
||||
3, 0, 0, 0,
|
||||
(byte)'f', (byte)'o', (byte)'o', 0
|
||||
}, builder.DataBuffer.Data);
|
||||
}
|
||||
|
||||
[FlatBuffersTestMethod]
|
||||
public void TestCreateArbitarytring()
|
||||
{
|
||||
var builder = new FlatBufferBuilder(1);
|
||||
builder.CreateString("\x01\x02\x03");
|
||||
Assert.ArrayEqual(new byte[]
|
||||
{
|
||||
3, 0, 0, 0,
|
||||
0x01, 0x02, 0x03, 0
|
||||
}, builder.DataBuffer.Data); // No padding
|
||||
builder.CreateString("\x04\x05\x06\x07");
|
||||
Assert.ArrayEqual(new byte[]
|
||||
{
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0, // Padding to 32 bytes
|
||||
4, 0, 0, 0,
|
||||
0x04, 0x05, 0x06, 0x07,
|
||||
0, 0, 0, 0, // zero terminator with 3 byte pad
|
||||
3, 0, 0, 0,
|
||||
0x01, 0x02, 0x03, 0
|
||||
}, builder.DataBuffer.Data); // No padding
|
||||
}
|
||||
|
||||
[FlatBuffersTestMethod]
|
||||
public void TestEmptyVTable()
|
||||
{
|
||||
var builder = new FlatBufferBuilder(1);
|
||||
builder.StartObject(0);
|
||||
Assert.ArrayEqual(new byte[] { 0 }, builder.DataBuffer.Data);
|
||||
builder.EndObject();
|
||||
Assert.ArrayEqual(new byte[]
|
||||
{
|
||||
4, 0, 4, 0,
|
||||
4, 0, 0, 0
|
||||
},
|
||||
builder.DataBuffer.Data);
|
||||
}
|
||||
|
||||
[FlatBuffersTestMethod]
|
||||
public void TestVTableWithOneBool()
|
||||
{
|
||||
var builder = new FlatBufferBuilder(1);
|
||||
builder.StartObject(1);
|
||||
Assert.ArrayEqual(new byte[] { 0 }, builder.DataBuffer.Data);
|
||||
builder.AddBool(0, true, false);
|
||||
builder.EndObject();
|
||||
Assert.ArrayEqual(new byte[]
|
||||
{
|
||||
0, 0, // padding to 16 bytes
|
||||
6, 0, // vtable bytes
|
||||
8, 0, // object length inc vtable offset
|
||||
7, 0, // start of bool value
|
||||
6, 0, 0, 0, // int32 offset for start of vtable
|
||||
0, 0, 0, // padding
|
||||
1, // value 0
|
||||
},
|
||||
builder.DataBuffer.Data);
|
||||
}
|
||||
|
||||
[FlatBuffersTestMethod]
|
||||
public void TestVTableWithOneBool_DefaultValue()
|
||||
{
|
||||
var builder = new FlatBufferBuilder(1);
|
||||
builder.StartObject(1);
|
||||
Assert.ArrayEqual(new byte[] { 0 }, builder.DataBuffer.Data);
|
||||
builder.AddBool(0, false, false);
|
||||
builder.EndObject();
|
||||
Assert.ArrayEqual(new byte[]
|
||||
{
|
||||
0, 0, 0, 0, 0, 0, // padding to 16 bytes
|
||||
6, 0, // vtable bytes
|
||||
4, 0, // end of object from here
|
||||
0, 0, // entry 0 is empty (default value)
|
||||
6, 0, 0, 0, // int32 offset for start of vtable
|
||||
},
|
||||
builder.DataBuffer.Data);
|
||||
}
|
||||
|
||||
[FlatBuffersTestMethod]
|
||||
public void TestVTableWithOneInt16()
|
||||
{
|
||||
var builder = new FlatBufferBuilder(1);
|
||||
builder.StartObject(1);
|
||||
Assert.ArrayEqual(new byte[] { 0 }, builder.DataBuffer.Data);
|
||||
builder.AddShort(0, 0x789A, 0);
|
||||
builder.EndObject();
|
||||
Assert.ArrayEqual(new byte[]
|
||||
{
|
||||
0, 0, // padding to 16 bytes
|
||||
6, 0, // vtable bytes
|
||||
8, 0, // object length inc vtable offset
|
||||
6, 0, // start of int16 value
|
||||
6, 0, 0, 0, // int32 offset for start of vtable
|
||||
0, 0, // padding
|
||||
0x9A, 0x78, //value 0
|
||||
},
|
||||
builder.DataBuffer.Data);
|
||||
}
|
||||
|
||||
[FlatBuffersTestMethod]
|
||||
public void TestVTableWithTwoInt16()
|
||||
{
|
||||
var builder = new FlatBufferBuilder(1);
|
||||
builder.StartObject(2);
|
||||
Assert.ArrayEqual(new byte[] { 0 }, builder.DataBuffer.Data);
|
||||
builder.AddShort(0, 0x3456, 0);
|
||||
builder.AddShort(1, 0x789A, 0);
|
||||
builder.EndObject();
|
||||
Assert.ArrayEqual(new byte[]
|
||||
{
|
||||
8, 0, // vtable bytes
|
||||
8, 0, // object length inc vtable offset
|
||||
6, 0, // start of int16 value 0
|
||||
4, 0, // start of int16 value 1
|
||||
8, 0, 0, 0, // int32 offset for start of vtable
|
||||
0x9A, 0x78, // value 1
|
||||
0x56, 0x34, // value 0
|
||||
},
|
||||
builder.DataBuffer.Data);
|
||||
}
|
||||
|
||||
[FlatBuffersTestMethod]
|
||||
public void TestVTableWithInt16AndBool()
|
||||
{
|
||||
var builder = new FlatBufferBuilder(1);
|
||||
builder.StartObject(2);
|
||||
Assert.ArrayEqual(new byte[] { 0 }, builder.DataBuffer.Data);
|
||||
builder.AddShort(0, 0x3456, 0);
|
||||
builder.AddBool(1, true, false);
|
||||
builder.EndObject();
|
||||
Assert.ArrayEqual(new byte[]
|
||||
{
|
||||
8, 0, // vtable bytes
|
||||
8, 0, // object length inc vtable offset
|
||||
6, 0, // start of int16 value 0
|
||||
5, 0, // start of bool value 1
|
||||
8, 0, 0, 0, // int32 offset for start of vtable
|
||||
0, 1, // padding + value 1
|
||||
0x56, 0x34, // value 0
|
||||
},
|
||||
builder.DataBuffer.Data);
|
||||
}
|
||||
|
||||
[FlatBuffersTestMethod]
|
||||
public void TestVTableWithEmptyVector()
|
||||
{
|
||||
var builder = new FlatBufferBuilder(1);
|
||||
builder.StartVector(sizeof(byte), 0, 1);
|
||||
var vecEnd = builder.EndVector();
|
||||
|
||||
builder.StartObject(1);
|
||||
|
||||
builder.AddOffset(0, vecEnd.Value, 0);
|
||||
builder.EndObject();
|
||||
Assert.ArrayEqual(new byte[]
|
||||
{
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
0, 0, // Padding to 32 bytes
|
||||
6, 0, // vtable bytes
|
||||
8, 0, // object length inc vtable offset
|
||||
4, 0, // start of vector offset value 0
|
||||
6, 0, 0, 0, // int32 offset for start of vtable
|
||||
4, 0, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
},
|
||||
builder.DataBuffer.Data);
|
||||
}
|
||||
|
||||
[FlatBuffersTestMethod]
|
||||
public void TestVTableWithEmptyVectorAndScalars()
|
||||
{
|
||||
var builder = new FlatBufferBuilder(1);
|
||||
builder.StartVector(sizeof(byte), 0, 1);
|
||||
var vecEnd = builder.EndVector();
|
||||
|
||||
builder.StartObject(2);
|
||||
builder.AddShort(0, 55, 0);
|
||||
builder.AddOffset(1, vecEnd.Value, 0);
|
||||
builder.EndObject();
|
||||
Assert.ArrayEqual(new byte[]
|
||||
{
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0, // Padding to 32 bytes
|
||||
8, 0, // vtable bytes
|
||||
12, 0, // object length inc vtable offset
|
||||
10, 0, // offset to int16 value 0
|
||||
4, 0, // start of vector offset value 1
|
||||
8, 0, 0, 0, // int32 offset for start of vtable
|
||||
8, 0, 0, 0, // value 1
|
||||
0, 0, 55, 0, // value 0
|
||||
0, 0, 0, 0, // length of vector (not in sctruc)
|
||||
},
|
||||
builder.DataBuffer.Data);
|
||||
}
|
||||
|
||||
|
||||
[FlatBuffersTestMethod]
|
||||
public void TestVTableWith_1xInt16_and_Vector_or_2xInt16()
|
||||
{
|
||||
var builder = new FlatBufferBuilder(1);
|
||||
builder.StartVector(sizeof(short), 2, 1);
|
||||
builder.AddShort(0x1234);
|
||||
builder.AddShort(0x5678);
|
||||
var vecEnd = builder.EndVector();
|
||||
|
||||
builder.StartObject(2);
|
||||
builder.AddOffset(1, vecEnd.Value, 0);
|
||||
builder.AddShort(0, 55, 0);
|
||||
builder.EndObject();
|
||||
Assert.ArrayEqual(new byte[]
|
||||
{
|
||||
0, 0, 0, 0, // Padding to 32 bytes
|
||||
8, 0, // vtable bytes
|
||||
12, 0, // object length
|
||||
6, 0, // start of value 0 from end of vtable
|
||||
8, 0, // start of value 1 from end of buffer
|
||||
8, 0, 0, 0, // int32 offset for start of vtable
|
||||
0, 0, 55, 0, // padding + value 0
|
||||
4, 0, 0, 0, // position of vector from here
|
||||
2, 0, 0, 0, // length of vector
|
||||
0x78, 0x56, // vector value 0
|
||||
0x34, 0x12, // vector value 1
|
||||
},
|
||||
builder.DataBuffer.Data);
|
||||
}
|
||||
|
||||
[FlatBuffersTestMethod]
|
||||
public void TestVTableWithAStruct_of_int8_int16_int32()
|
||||
{
|
||||
var builder = new FlatBufferBuilder(1);
|
||||
builder.StartObject(1);
|
||||
builder.Prep(4+4+4, 0);
|
||||
builder.AddSbyte(55);
|
||||
builder.Pad(3);
|
||||
builder.AddShort(0x1234);
|
||||
builder.Pad(2);
|
||||
builder.AddInt(0x12345678);
|
||||
var structStart = builder.Offset;
|
||||
builder.AddStruct(0, structStart, 0);
|
||||
builder.EndObject();
|
||||
Assert.ArrayEqual(new byte[]
|
||||
{
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
0, 0, // Padding to 32 bytes
|
||||
6, 0, // vtable bytes
|
||||
16, 0, // object length
|
||||
4, 0, // start of struct from here
|
||||
6, 0, 0, 0, // int32 offset for start of vtable
|
||||
0x78, 0x56, 0x34, 0x12, // struct value 2
|
||||
0x00, 0x00, 0x34, 0x12, // struct value 1
|
||||
0x00, 0x00, 0x00, 55, // struct value 0
|
||||
},
|
||||
builder.DataBuffer.Data);
|
||||
}
|
||||
|
||||
[FlatBuffersTestMethod]
|
||||
public void TestVTableWithAVectorOf_2xStructOf_2xInt8()
|
||||
{
|
||||
var builder = new FlatBufferBuilder(1);
|
||||
builder.StartVector(sizeof(byte)*2, 2, 1);
|
||||
builder.AddByte(33);
|
||||
builder.AddByte(44);
|
||||
builder.AddByte(55);
|
||||
builder.AddByte(66);
|
||||
var vecEnd = builder.EndVector();
|
||||
|
||||
builder.StartObject(1);
|
||||
builder.AddOffset(0, vecEnd.Value, 0);
|
||||
builder.EndObject();
|
||||
|
||||
Assert.ArrayEqual(new byte[]
|
||||
{
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
0, 0, // Padding to 32 bytes
|
||||
6, 0, // vtable bytes
|
||||
8, 0, // object length
|
||||
4, 0, // offset of vector offset
|
||||
6, 0, 0, 0, // int32 offset for start of vtable
|
||||
4, 0, 0, 0, // Vector start offset
|
||||
2, 0, 0, 0, // Vector len
|
||||
66, // vector 1, 1
|
||||
55, // vector 1, 0
|
||||
44, // vector 0, 1
|
||||
33, // vector 0, 0
|
||||
},
|
||||
builder.DataBuffer.Data);
|
||||
}
|
||||
|
||||
[FlatBuffersTestMethod]
|
||||
public void TestVTableWithSomeElements()
|
||||
{
|
||||
var builder = new FlatBufferBuilder(1);
|
||||
builder.StartObject(2);
|
||||
builder.AddByte(0, 33, 0);
|
||||
builder.AddShort(1, 66, 0);
|
||||
var off = builder.EndObject();
|
||||
builder.Finish(off);
|
||||
|
||||
Assert.ArrayEqual(new byte[]
|
||||
{
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0, //Padding to 32 bytes
|
||||
12, 0, 0, 0, // root of table, pointing to vtable offset
|
||||
8, 0, // vtable bytes
|
||||
8, 0, // object length
|
||||
7, 0, // start of value 0
|
||||
4, 0, // start of value 1
|
||||
8, 0, 0, 0, // int32 offset for start of vtable
|
||||
66, 0, // value 1
|
||||
0, 33, // value 0
|
||||
|
||||
},
|
||||
builder.DataBuffer.Data);
|
||||
}
|
||||
|
||||
[FlatBuffersTestMethod]
|
||||
public void TestTwoFinishTable()
|
||||
{
|
||||
var builder = new FlatBufferBuilder(1);
|
||||
builder.StartObject(2);
|
||||
builder.AddByte(0, 33, 0);
|
||||
builder.AddByte(1, 44, 0);
|
||||
var off0 = builder.EndObject();
|
||||
builder.Finish(off0);
|
||||
|
||||
builder.StartObject(3);
|
||||
builder.AddByte(0, 55, 0);
|
||||
builder.AddByte(1, 66, 0);
|
||||
builder.AddByte(2, 77, 0);
|
||||
var off1 = builder.EndObject();
|
||||
builder.Finish(off1);
|
||||
|
||||
Assert.ArrayEqual(new byte[]
|
||||
{
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0, // padding to 64 bytes
|
||||
16, 0, 0, 0, // root of table, pointing to vtable offset (obj1)
|
||||
0, 0, // padding
|
||||
|
||||
10, 0, // vtable bytes
|
||||
8, 0, // object length
|
||||
7, 0, // start of value 0
|
||||
6, 0, // start of value 1
|
||||
5, 0, // start of value 2
|
||||
10, 0, 0, 0, // int32 offset for start of vtable
|
||||
0, // pad
|
||||
77, // values 2, 1, 0
|
||||
66,
|
||||
55,
|
||||
|
||||
12, 0, 0, 0, // root of table, pointing to vtable offset (obj0)
|
||||
8, 0, // vtable bytes
|
||||
8, 0, // object length
|
||||
7, 0, // start of value 0
|
||||
6, 0, // start of value 1
|
||||
8, 0, 0, 0, // int32 offset for start of vtable
|
||||
0, 0, // pad
|
||||
44, // value 1, 0
|
||||
33,
|
||||
},
|
||||
builder.DataBuffer.Data);
|
||||
}
|
||||
|
||||
[FlatBuffersTestMethod]
|
||||
public void TestBunchOfBools()
|
||||
{
|
||||
var builder = new FlatBufferBuilder(1);
|
||||
builder.StartObject(8);
|
||||
for (var i = 0; i < 8; i++)
|
||||
{
|
||||
builder.AddBool(i, true, false);
|
||||
}
|
||||
var off = builder.EndObject();
|
||||
builder.Finish(off);
|
||||
|
||||
Assert.ArrayEqual(new byte[]
|
||||
{
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0, // padding to 64 bytes
|
||||
|
||||
24, 0, 0, 0, // root of table, pointing to vtable offset (obj0)
|
||||
20, 0, // vtable bytes
|
||||
12, 0, // object length
|
||||
11, 0, // start of value 0
|
||||
10, 0, // start of value 1
|
||||
9, 0, // start of value 2
|
||||
8, 0, // start of value 3
|
||||
7, 0, // start of value 4
|
||||
6, 0, // start of value 5
|
||||
5, 0, // start of value 6
|
||||
4, 0, // start of value 7
|
||||
|
||||
20, 0, 0, 0, // int32 offset for start of vtable
|
||||
|
||||
1, 1, 1, 1, // values
|
||||
1, 1, 1, 1,
|
||||
|
||||
},
|
||||
builder.DataBuffer.Data);
|
||||
}
|
||||
|
||||
[FlatBuffersTestMethod]
|
||||
public void TestWithFloat()
|
||||
{
|
||||
var builder = new FlatBufferBuilder(1);
|
||||
builder.StartObject(1);
|
||||
builder.AddFloat(0, 1, 0);
|
||||
builder.EndObject();
|
||||
|
||||
|
||||
Assert.ArrayEqual(new byte[]
|
||||
{
|
||||
0, 0,
|
||||
6, 0, // vtable bytes
|
||||
8, 0, // object length
|
||||
4, 0, // start of value 0
|
||||
6, 0, 0, 0, // int32 offset for start of vtable
|
||||
0, 0, 128, 63, // value
|
||||
|
||||
},
|
||||
builder.DataBuffer.Data);
|
||||
}
|
||||
|
||||
private void CheckObjects(int fieldCount, int objectCount)
|
||||
{
|
||||
_lcg.Reset();
|
||||
|
||||
const int testValuesMax = 11;
|
||||
|
||||
var builder = new FlatBufferBuilder(1);
|
||||
|
||||
var objects = new int[objectCount];
|
||||
|
||||
for (var i = 0; i < objectCount; ++i)
|
||||
{
|
||||
builder.StartObject(fieldCount);
|
||||
|
||||
for (var j = 0; j < fieldCount; ++j)
|
||||
{
|
||||
var fieldType = _lcg.Next()%testValuesMax;
|
||||
|
||||
switch (fieldType)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
builder.AddBool(j, FuzzTestData.BoolValue, false);
|
||||
break;
|
||||
}
|
||||
case 1:
|
||||
{
|
||||
builder.AddSbyte(j, FuzzTestData.Int8Value, 0);
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
builder.AddByte(j, FuzzTestData.UInt8Value, 0);
|
||||
break;
|
||||
}
|
||||
case 3:
|
||||
{
|
||||
builder.AddShort(j, FuzzTestData.Int16Value, 0);
|
||||
break;
|
||||
}
|
||||
case 4:
|
||||
{
|
||||
builder.AddUshort(j, FuzzTestData.UInt16Value, 0);
|
||||
break;
|
||||
}
|
||||
case 5:
|
||||
{
|
||||
builder.AddInt(j, FuzzTestData.Int32Value, 0);
|
||||
break;
|
||||
}
|
||||
case 6:
|
||||
{
|
||||
builder.AddUint(j, FuzzTestData.UInt32Value, 0);
|
||||
break;
|
||||
}
|
||||
case 7:
|
||||
{
|
||||
builder.AddLong(j, FuzzTestData.Int64Value, 0);
|
||||
break;
|
||||
}
|
||||
case 8:
|
||||
{
|
||||
builder.AddUlong(j, FuzzTestData.UInt64Value, 0);
|
||||
break;
|
||||
}
|
||||
case 9:
|
||||
{
|
||||
builder.AddFloat(j, FuzzTestData.Float32Value, 0);
|
||||
break;
|
||||
}
|
||||
case 10:
|
||||
{
|
||||
builder.AddDouble(j, FuzzTestData.Float64Value, 0);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw new Exception("Unreachable");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
var offset = builder.EndObject();
|
||||
|
||||
// Store the object offset
|
||||
objects[i] = offset;
|
||||
}
|
||||
|
||||
_lcg.Reset();
|
||||
|
||||
// Test all objects are readable and return expected values...
|
||||
for (var i = 0; i < objectCount; ++i)
|
||||
{
|
||||
var table = new TestTable(builder.DataBuffer, builder.DataBuffer.Length - objects[i]);
|
||||
|
||||
for (var j = 0; j < fieldCount; ++j)
|
||||
{
|
||||
var fieldType = _lcg.Next() % testValuesMax;
|
||||
var fc = 2 + j; // 2 == VtableMetadataFields
|
||||
var f = fc * 2;
|
||||
|
||||
switch (fieldType)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
Assert.AreEqual(FuzzTestData.BoolValue, table.GetSlot(f, false));
|
||||
break;
|
||||
}
|
||||
case 1:
|
||||
{
|
||||
Assert.AreEqual(FuzzTestData.Int8Value, table.GetSlot(f, (sbyte)0));
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
Assert.AreEqual(FuzzTestData.UInt8Value, table.GetSlot(f, (byte)0));
|
||||
break;
|
||||
}
|
||||
case 3:
|
||||
{
|
||||
Assert.AreEqual(FuzzTestData.Int16Value, table.GetSlot(f, (short)0));
|
||||
break;
|
||||
}
|
||||
case 4:
|
||||
{
|
||||
Assert.AreEqual(FuzzTestData.UInt16Value, table.GetSlot(f, (ushort)0));
|
||||
break;
|
||||
}
|
||||
case 5:
|
||||
{
|
||||
Assert.AreEqual(FuzzTestData.Int32Value, table.GetSlot(f, (int)0));
|
||||
break;
|
||||
}
|
||||
case 6:
|
||||
{
|
||||
Assert.AreEqual(FuzzTestData.UInt32Value, table.GetSlot(f, (uint)0));
|
||||
break;
|
||||
}
|
||||
case 7:
|
||||
{
|
||||
Assert.AreEqual(FuzzTestData.Int64Value, table.GetSlot(f, (long)0));
|
||||
break;
|
||||
}
|
||||
case 8:
|
||||
{
|
||||
Assert.AreEqual(FuzzTestData.UInt64Value, table.GetSlot(f, (ulong)0));
|
||||
break;
|
||||
}
|
||||
case 9:
|
||||
{
|
||||
Assert.AreEqual(FuzzTestData.Float32Value, table.GetSlot(f, (float)0));
|
||||
break;
|
||||
}
|
||||
case 10:
|
||||
{
|
||||
Assert.AreEqual(FuzzTestData.Float64Value, table.GetSlot(f, (double)0));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw new Exception("Unreachable");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
12
tests/FlatBuffers.Test/FlatBuffersTestClassAttribute.cs
Normal file
12
tests/FlatBuffers.Test/FlatBuffersTestClassAttribute.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace FlatBuffers.Test
|
||||
{
|
||||
[AttributeUsage(AttributeTargets.Class)]
|
||||
public class FlatBuffersTestClassAttribute : Attribute
|
||||
{
|
||||
}
|
||||
}
|
||||
9
tests/FlatBuffers.Test/FlatBuffersTestMethodAttribute.cs
Normal file
9
tests/FlatBuffers.Test/FlatBuffersTestMethodAttribute.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
using System;
|
||||
|
||||
namespace FlatBuffers.Test
|
||||
{
|
||||
[AttributeUsage(AttributeTargets.Method)]
|
||||
public class FlatBuffersTestMethodAttribute : Attribute
|
||||
{
|
||||
}
|
||||
}
|
||||
22
tests/FlatBuffers.Test/FuzzTestData.cs
Normal file
22
tests/FlatBuffers.Test/FuzzTestData.cs
Normal file
@@ -0,0 +1,22 @@
|
||||
using System;
|
||||
|
||||
namespace FlatBuffers.Test
|
||||
{
|
||||
internal static class FuzzTestData
|
||||
{
|
||||
private static readonly byte[] _overflowInt32 = new byte[] {0x83, 0x33, 0x33, 0x33};
|
||||
private static readonly byte[] _overflowInt64 = new byte[] { 0x84, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44 };
|
||||
|
||||
public static readonly bool BoolValue = true;
|
||||
public static readonly sbyte Int8Value = -127; // 0x81
|
||||
public static readonly byte UInt8Value = 255; // 0xFF
|
||||
public static readonly short Int16Value = -32222; // 0x8222;
|
||||
public static readonly ushort UInt16Value = 65262; // 0xFEEE
|
||||
public static readonly int Int32Value = BitConverter.ToInt32(_overflowInt32, 0);
|
||||
public static readonly uint UInt32Value = 0xFDDDDDDD;
|
||||
public static readonly long Int64Value = BitConverter.ToInt64(_overflowInt64, 0);
|
||||
public static readonly ulong UInt64Value = 0xFCCCCCCCCCCCCCCC;
|
||||
public static readonly float Float32Value = 3.14159f;
|
||||
public static readonly double Float64Value = 3.14159265359;
|
||||
}
|
||||
}
|
||||
26
tests/FlatBuffers.Test/Lcg.cs
Normal file
26
tests/FlatBuffers.Test/Lcg.cs
Normal file
@@ -0,0 +1,26 @@
|
||||
namespace FlatBuffers.Test
|
||||
{
|
||||
/// <summary>
|
||||
/// Lcg Pseudo RNG
|
||||
/// </summary>
|
||||
internal sealed class Lcg
|
||||
{
|
||||
private const uint InitialValue = 10000;
|
||||
private uint _state;
|
||||
|
||||
public Lcg()
|
||||
{
|
||||
_state = InitialValue;
|
||||
}
|
||||
|
||||
public uint Next()
|
||||
{
|
||||
return (_state = 69069 * _state + 362437);
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
_state = InitialValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
|
||||
@@ -24,38 +25,43 @@ namespace FlatBuffers.Test
|
||||
{
|
||||
public static int Main(string[] args)
|
||||
{
|
||||
var tests = new FlatBuffersExampleTests();
|
||||
try
|
||||
var testResults = new List<bool>();
|
||||
|
||||
var testClasses = Assembly.GetExecutingAssembly().GetExportedTypes()
|
||||
.Where(t => t.IsClass && t.GetCustomAttributes(typeof (FlatBuffersTestClassAttribute), false).Length > 0);
|
||||
|
||||
foreach (var testClass in testClasses)
|
||||
{
|
||||
tests.RunTests();
|
||||
var methods = testClass.GetMethods(BindingFlags.Public |
|
||||
BindingFlags.Instance)
|
||||
.Where(m => m.GetCustomAttributes(typeof(FlatBuffersTestMethodAttribute), false).Length > 0);
|
||||
|
||||
var inst = Activator.CreateInstance(testClass);
|
||||
|
||||
foreach (var method in methods)
|
||||
{
|
||||
try
|
||||
{
|
||||
method.Invoke(inst, new object[] { });
|
||||
testResults.Add(true);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine("{0}: FAILED when invoking {1} with error {2}",
|
||||
testClass.Name ,method.Name, ex.GetBaseException());
|
||||
testResults.Add(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
||||
var failedCount = testResults.Count(i => i == false);
|
||||
|
||||
Console.WriteLine("{0} tests run, {1} failed", testResults.Count, failedCount);
|
||||
|
||||
if (failedCount > 0)
|
||||
{
|
||||
Console.WriteLine("FlatBuffersExampleTests FAILED - {0}", ex.GetBaseException());
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Run ByteBuffers Tests
|
||||
var testClass = new ByteBufferTests();
|
||||
|
||||
var methods = testClass.GetType().GetMethods(BindingFlags.Public |
|
||||
BindingFlags.Instance)
|
||||
.Where(m => m.Name.StartsWith("ByteBuffer_"));
|
||||
foreach (var method in methods)
|
||||
{
|
||||
try
|
||||
{
|
||||
method.Invoke(testClass, new object[] { });
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine("ByteBufferTests FAILED when invoking {0} with error {1}",
|
||||
method.Name, ex.GetBaseException());
|
||||
return -1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user