mirror of
https://github.com/google/flatbuffers.git
synced 2026-06-02 20:15:34 +00:00
Compare commits
145 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c0698cc33f | ||
|
|
ea8a4296e7 | ||
|
|
f85af46262 | ||
|
|
7a43775661 | ||
|
|
062dcf7007 | ||
|
|
ebb410062b | ||
|
|
4b864fd172 | ||
|
|
7e711f80d7 | ||
|
|
bf871ffd7f | ||
|
|
a89be8739c | ||
|
|
0bffce5aef | ||
|
|
d48f08acfe | ||
|
|
43132560f9 | ||
|
|
c56fff88a2 | ||
|
|
49fed8c4f6 | ||
|
|
b1a925dfc2 | ||
|
|
33791dc7b0 | ||
|
|
873a60b0d8 | ||
|
|
4b10656f9b | ||
|
|
e317b148dc | ||
|
|
ed03faaf07 | ||
|
|
02a7807dd8 | ||
|
|
615885e889 | ||
|
|
528ccdd458 | ||
|
|
c23ba6756f | ||
|
|
10e1d1a69e | ||
|
|
660c491265 | ||
|
|
c504a45404 | ||
|
|
919c929d30 | ||
|
|
ba4a02b46a | ||
|
|
be3d0b9c64 | ||
|
|
872fad049e | ||
|
|
9e648c392b | ||
|
|
d4f65bb8a3 | ||
|
|
3c54fd964b | ||
|
|
e7578548a5 | ||
|
|
99acd0bcd7 | ||
|
|
d0321df8cf | ||
|
|
e1f48ad35a | ||
|
|
d8f49e18d7 | ||
|
|
1f5eae5d6a | ||
|
|
ea9d60bbdf | ||
|
|
c2c3a84aaf | ||
|
|
1f03becd24 | ||
|
|
c721009491 | ||
|
|
55289c55bf | ||
|
|
ed2415eb72 | ||
|
|
aaa89429d3 | ||
|
|
12e5cf0b29 | ||
|
|
75601b81cc | ||
|
|
e203882d54 | ||
|
|
b9f1103b8a | ||
|
|
fd40cc61a4 | ||
|
|
38a6623f34 | ||
|
|
27e4f43b77 | ||
|
|
42515cfd33 | ||
|
|
5d3648b88a | ||
|
|
fc3ce7d1ab | ||
|
|
4898809eca | ||
|
|
ca5aaf62d3 | ||
|
|
c80f8d18c1 | ||
|
|
0d1559bdd4 | ||
|
|
8b39a0ee53 | ||
|
|
f675f6433c | ||
|
|
118093b613 | ||
|
|
1bb2a3bd08 | ||
|
|
2361dfb66a | ||
|
|
7b50004ec9 | ||
|
|
6e185d06a7 | ||
|
|
c949229395 | ||
|
|
e1d5fda5d4 | ||
|
|
a2603ec27e | ||
|
|
5f1b1ad42c | ||
|
|
4235a25640 | ||
|
|
88cd182349 | ||
|
|
7c824ef690 | ||
|
|
6bfa107f4e | ||
|
|
0cd8daf14e | ||
|
|
79f2adc50a | ||
|
|
dcfe38c58f | ||
|
|
51d9641de6 | ||
|
|
af6c0e6839 | ||
|
|
7c3cb5caa1 | ||
|
|
8f1bebba05 | ||
|
|
cda1525f84 | ||
|
|
72b05bc865 | ||
|
|
b3e4d9169b | ||
|
|
e2eb6af3e3 | ||
|
|
b188fde27e | ||
|
|
ba5eb3b5cf | ||
|
|
8ea293b988 | ||
|
|
f19803d364 | ||
|
|
b2d69aacf4 | ||
|
|
3331805a1c | ||
|
|
ea06768ad1 | ||
|
|
741c63052d | ||
|
|
e9912e9298 | ||
|
|
7dbc8f564a | ||
|
|
a2fe49b498 | ||
|
|
7dd5cfb510 | ||
|
|
00b741e5fb | ||
|
|
bb321fbe19 | ||
|
|
7330436713 | ||
|
|
f9c64891dd | ||
|
|
b752e4a9bb | ||
|
|
3e3c770c4e | ||
|
|
5a3f18d17d | ||
|
|
10bdcefa4a | ||
|
|
9bab626cbf | ||
|
|
effb608027 | ||
|
|
a96f2bd6ca | ||
|
|
ab3b721a54 | ||
|
|
4cfe36ae8e | ||
|
|
c7a797b966 | ||
|
|
ecc07e7793 | ||
|
|
43944a0ab1 | ||
|
|
27ce09860a | ||
|
|
3a2f6d5300 | ||
|
|
06d3229dc3 | ||
|
|
348fcb5b88 | ||
|
|
b4ca4d3cde | ||
|
|
0848f58cdd | ||
|
|
8e42f44807 | ||
|
|
88912640d0 | ||
|
|
c43a0beff0 | ||
|
|
a9640bd9e1 | ||
|
|
f11ffedb2b | ||
|
|
5d42c8352e | ||
|
|
7c1203d44c | ||
|
|
a0a33d94a7 | ||
|
|
b10123ff63 | ||
|
|
3a2c535592 | ||
|
|
6621424308 | ||
|
|
d215852f52 | ||
|
|
12c4c2238c | ||
|
|
85faa46fb3 | ||
|
|
cc354ea368 | ||
|
|
bed19a5340 | ||
|
|
9bb88a026a | ||
|
|
34cb163e38 | ||
|
|
a66f9e769b | ||
|
|
86153fd740 | ||
|
|
7eb4c6098e | ||
|
|
af3c598189 | ||
|
|
eac0bc6490 |
16
.gitignore
vendored
16
.gitignore
vendored
@@ -12,8 +12,11 @@
|
||||
*.vcxproj.user
|
||||
*.sln
|
||||
*.suo
|
||||
*.opendb
|
||||
*.keystore
|
||||
**/.vs/**
|
||||
**/bin/**
|
||||
!tests/rust_usage_test/bin/**
|
||||
**/gen/**
|
||||
**/libs/**
|
||||
**/obj/**
|
||||
@@ -25,6 +28,8 @@
|
||||
**/CMakeTestfile.cmake
|
||||
**/Debug/**
|
||||
**/Release/**
|
||||
**/RelWithDebInfo/**
|
||||
**/x64/ #build artifacts from VS
|
||||
build.xml
|
||||
local.properties
|
||||
project.properties
|
||||
@@ -45,11 +50,14 @@ grpctest
|
||||
grpctest.exe
|
||||
snapshot.sh
|
||||
tags
|
||||
tests/dart_gen
|
||||
tests/go_gen
|
||||
tests/monsterdata_java_wire.mon
|
||||
tests/monsterdata_java_wire_sp.mon
|
||||
tests/monsterdata_go_wire.mon
|
||||
tests/monsterdata_javascript_wire.mon
|
||||
tests/monsterdata_lobster_wire.mon
|
||||
tests/monsterdata_rust_wire.mon
|
||||
tests/unicode_test.mon
|
||||
tests/ts/
|
||||
tests/php/
|
||||
@@ -93,3 +101,11 @@ js/flatbuffers.mjs
|
||||
.ninja_log
|
||||
build.ninja
|
||||
rules.ninja
|
||||
.vscode
|
||||
dart/.pub/
|
||||
dart/.packages
|
||||
dart/pubspec.lock
|
||||
dart/.dart_tool/
|
||||
dart/build/
|
||||
dart/doc/api/
|
||||
Cargo.lock
|
||||
|
||||
127
.travis.yml
127
.travis.yml
@@ -2,6 +2,29 @@ env:
|
||||
global:
|
||||
# Set at the root level as this is ignored when set under matrix.env.
|
||||
- GCC_VERSION="4.9"
|
||||
|
||||
conan-linux: &conan-linux
|
||||
os: linux
|
||||
sudo: required
|
||||
language: python
|
||||
python: "3.6"
|
||||
services:
|
||||
- docker
|
||||
install:
|
||||
- ./conan/travis/install.sh
|
||||
script:
|
||||
- ./conan/travis/build.sh
|
||||
if: tag IS present
|
||||
|
||||
conan-osx: &conan-osx
|
||||
os: osx
|
||||
language: generic
|
||||
install:
|
||||
- ./conan/travis/install.sh
|
||||
script:
|
||||
- ./conan/travis/build.sh
|
||||
if: tag IS present
|
||||
|
||||
matrix:
|
||||
include:
|
||||
#- language: python
|
||||
@@ -31,19 +54,14 @@ matrix:
|
||||
- language: cpp
|
||||
os:
|
||||
- linux
|
||||
- osx
|
||||
|
||||
compiler:
|
||||
- gcc
|
||||
#- clang
|
||||
|
||||
env:
|
||||
matrix:
|
||||
- BUILD_TYPE=Debug BIICODE=false
|
||||
- BUILD_TYPE=Release BIICODE=false CONAN=true
|
||||
# biicode .deb files no longer available.
|
||||
# - BUILD_TYPE=Release BIICODE=true
|
||||
# - BUILD_TYPE=Debug BIICODE=true
|
||||
- BUILD_TYPE=Debug
|
||||
- BUILD_TYPE=Release CONAN=true
|
||||
|
||||
before_install:
|
||||
- if [ "$TRAVIS_OS_NAME" == "linux" ]; then sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test; fi
|
||||
@@ -54,30 +72,75 @@ matrix:
|
||||
- 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
|
||||
- if [ "$CONAN" == "true" ] && [ "$TRAVIS_OS_NAME" == "linux" ]; then sudo pip install conan && conan create . flatbuffers/testing -s build_type=$BUILD_TYPE; fi
|
||||
- bash grpc/build_grpc.sh
|
||||
- cmake -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DFLATBUFFERS_BUILD_GRPCTEST=ON -DGRPC_INSTALL_PATH=$TRAVIS_BUILD_DIR/google/grpc/install -DPROTOBUF_DOWNLOAD_PATH=$TRAVIS_BUILD_DIR/google/grpc/third_party/protobuf . && make
|
||||
- LD_LIBRARY_PATH=$TRAVIS_BUILD_DIR/google/grpc/install/lib make test ARGS=-V
|
||||
- if [ "$CONAN" == "true" ] && [ "$TRAVIS_OS_NAME" == "linux" ]; then sudo pip install conan && conan create . google/testing -s build_type=$BUILD_TYPE -tf conan/test_package; fi
|
||||
|
||||
- language: android
|
||||
sudo: true
|
||||
android:
|
||||
components:
|
||||
- tools
|
||||
- platform-tools
|
||||
- build-tools-25.0.2
|
||||
- android-25
|
||||
- extra-android-m2repository
|
||||
compiler:
|
||||
- gcc
|
||||
before_install:
|
||||
- git clone https://github.com/urho3d/android-ndk.git $HOME/android-ndk-root
|
||||
- export ANDROID_NDK_HOME=$HOME/android-ndk-root
|
||||
# Setup environment for Linux build which is required to build the sample.
|
||||
- if [ "$TRAVIS_OS_NAME" == "linux" ]; then sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test; fi
|
||||
- if [ "$TRAVIS_OS_NAME" == "linux" ]; then sudo apt-get update -qq; fi
|
||||
- if [ "$TRAVIS_OS_NAME" == "linux" ]; then sudo apt-get install -qq g++-$GCC_VERSION; fi
|
||||
- if [ "$TRAVIS_OS_NAME" == "linux" ]; then sudo apt-get install -qq gcc-$GCC_VERSION; fi
|
||||
- if [ "$TRAVIS_OS_NAME" == "linux" ]; then sudo ln -s -v -f $(which g++-$GCC_VERSION) /usr/bin/g++; fi
|
||||
- if [ "$TRAVIS_OS_NAME" == "linux" ]; then sudo ln -s -v -f $(which gcc-$GCC_VERSION) /usr/bin/gcc; fi
|
||||
- language: cpp
|
||||
os: osx
|
||||
osx_image: xcode9.3
|
||||
env:
|
||||
matrix:
|
||||
- BUILD_TYPE=Debug
|
||||
- BUILD_TYPE=Release
|
||||
script:
|
||||
- failed=0; for build_gradle in $(git ls-files | grep build.gradle); do ( cd "$(dirname "${build_gradle}")" && ./gradlew build ) || failed=1; done; exit $((failed))
|
||||
- bash grpc/build_grpc.sh
|
||||
- cmake -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DFLATBUFFERS_BUILD_GRPCTEST=ON -DGRPC_INSTALL_PATH=$TRAVIS_BUILD_DIR/google/grpc/install -DPROTOBUF_DOWNLOAD_PATH=$TRAVIS_BUILD_DIR/google/grpc/third_party/protobuf . && make
|
||||
- ./flattests
|
||||
- DYLD_LIBRARY_PATH=$TRAVIS_BUILD_DIR/google/grpc/install/lib ./grpctest
|
||||
|
||||
- <<: *conan-linux
|
||||
env: CONAN_GCC_VERSIONS=4.9 CONAN_DOCKER_IMAGE=lasote/conangcc49
|
||||
- <<: *conan-linux
|
||||
env: CONAN_GCC_VERSIONS=5 CONAN_DOCKER_IMAGE=lasote/conangcc5
|
||||
- <<: *conan-linux
|
||||
env: CONAN_GCC_VERSIONS=6 CONAN_DOCKER_IMAGE=lasote/conangcc6
|
||||
- <<: *conan-linux
|
||||
env: CONAN_GCC_VERSIONS=7 CONAN_DOCKER_IMAGE=lasote/conangcc7
|
||||
- <<: *conan-linux
|
||||
env: CONAN_GCC_VERSIONS=8 CONAN_DOCKER_IMAGE=lasote/conangcc8
|
||||
- <<: *conan-linux
|
||||
env: CONAN_CLANG_VERSIONS=3.9 CONAN_DOCKER_IMAGE=lasote/conanclang39
|
||||
- <<: *conan-linux
|
||||
env: CONAN_CLANG_VERSIONS=4.0 CONAN_DOCKER_IMAGE=lasote/conanclang40
|
||||
- <<: *conan-linux
|
||||
env: CONAN_CLANG_VERSIONS=5.0 CONAN_DOCKER_IMAGE=lasote/conanclang50
|
||||
- <<: *conan-linux
|
||||
env: CONAN_CLANG_VERSIONS=6.0 CONAN_DOCKER_IMAGE=lasote/conanclang60
|
||||
- <<: *conan-osx
|
||||
osx_image: xcode7.3
|
||||
env: CONAN_APPLE_CLANG_VERSIONS=7.3
|
||||
- <<: *conan-osx
|
||||
osx_image: xcode8.3
|
||||
env: CONAN_APPLE_CLANG_VERSIONS=8.1
|
||||
- <<: *conan-osx
|
||||
osx_image: xcode9
|
||||
env: CONAN_APPLE_CLANG_VERSIONS=9.0
|
||||
- <<: *conan-osx
|
||||
osx_image: xcode9.3
|
||||
env: CONAN_APPLE_CLANG_VERSIONS=9.1
|
||||
|
||||
#- language: android
|
||||
# sudo: true
|
||||
# android:
|
||||
# components:
|
||||
# - tools
|
||||
# - platform-tools
|
||||
# - build-tools-25.0.2
|
||||
# - android-25
|
||||
# - extra-android-m2repository
|
||||
# compiler:
|
||||
# - gcc
|
||||
# before_install:
|
||||
# - git clone https://github.com/urho3d/android-ndk.git $HOME/android-ndk-root
|
||||
# - export ANDROID_NDK_HOME=$HOME/android-ndk-root
|
||||
# # Setup environment for Linux build which is required to build the sample.
|
||||
# - if [ "$TRAVIS_OS_NAME" == "linux" ]; then sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test; fi
|
||||
# - if [ "$TRAVIS_OS_NAME" == "linux" ]; then sudo apt-get update -qq; fi
|
||||
# - if [ "$TRAVIS_OS_NAME" == "linux" ]; then sudo apt-get install -qq g++-$GCC_VERSION; fi
|
||||
# - if [ "$TRAVIS_OS_NAME" == "linux" ]; then sudo apt-get install -qq gcc-$GCC_VERSION; fi
|
||||
# - if [ "$TRAVIS_OS_NAME" == "linux" ]; then sudo ln -s -v -f $(which g++-$GCC_VERSION) /usr/bin/g++; fi
|
||||
# - if [ "$TRAVIS_OS_NAME" == "linux" ]; then sudo ln -s -v -f $(which gcc-$GCC_VERSION) /usr/bin/gcc; fi
|
||||
# script:
|
||||
# - failed=0; for build_gradle in $(git ls-files | grep build.gradle); do ( cd "$(dirname "${build_gradle}")" && ./gradlew build ) || failed=1; done; exit $((failed))
|
||||
|
||||
21
BUILD
21
BUILD
@@ -1,3 +1,5 @@
|
||||
licenses(["notice"])
|
||||
|
||||
package(
|
||||
default_visibility = ["//visibility:public"],
|
||||
features = [
|
||||
@@ -10,11 +12,6 @@ exports_files([
|
||||
"LICENSE",
|
||||
])
|
||||
|
||||
FLATBUFFERS_COPTS = [
|
||||
"-Wno-implicit-fallthrough",
|
||||
"-linclude",
|
||||
]
|
||||
|
||||
# Public flatc library to compile flatbuffer files at runtime.
|
||||
cc_library(
|
||||
name = "flatbuffers",
|
||||
@@ -28,7 +25,6 @@ cc_library(
|
||||
"src/util.cpp",
|
||||
],
|
||||
hdrs = [":public_headers"],
|
||||
copts = FLATBUFFERS_COPTS,
|
||||
includes = ["include/"],
|
||||
linkstatic = 1,
|
||||
)
|
||||
@@ -43,6 +39,7 @@ filegroup(
|
||||
"include/flatbuffers/flexbuffers.h",
|
||||
"include/flatbuffers/hash.h",
|
||||
"include/flatbuffers/idl.h",
|
||||
"include/flatbuffers/minireflect.h",
|
||||
"include/flatbuffers/reflection.h",
|
||||
"include/flatbuffers/reflection_generated.h",
|
||||
"include/flatbuffers/stl_emulation.h",
|
||||
@@ -65,7 +62,6 @@ cc_library(
|
||||
"include/flatbuffers/flatc.h",
|
||||
":public_headers",
|
||||
],
|
||||
copts = FLATBUFFERS_COPTS,
|
||||
includes = [
|
||||
"grpc/",
|
||||
"include/",
|
||||
@@ -86,16 +82,19 @@ cc_binary(
|
||||
"grpc/src/compiler/schema_interface.h",
|
||||
"src/flatc_main.cpp",
|
||||
"src/idl_gen_cpp.cpp",
|
||||
"src/idl_gen_dart.cpp",
|
||||
"src/idl_gen_general.cpp",
|
||||
"src/idl_gen_go.cpp",
|
||||
"src/idl_gen_grpc.cpp",
|
||||
"src/idl_gen_js.cpp",
|
||||
"src/idl_gen_json_schema.cpp",
|
||||
"src/idl_gen_lua.cpp",
|
||||
"src/idl_gen_lobster.cpp",
|
||||
"src/idl_gen_php.cpp",
|
||||
"src/idl_gen_python.cpp",
|
||||
"src/idl_gen_rust.cpp",
|
||||
"src/idl_gen_text.cpp",
|
||||
],
|
||||
copts = FLATBUFFERS_COPTS,
|
||||
includes = [
|
||||
"grpc/",
|
||||
"include/",
|
||||
@@ -123,10 +122,14 @@ cc_test(
|
||||
"tests/namespace_test/namespace_test1_generated.h",
|
||||
"tests/namespace_test/namespace_test2_generated.h",
|
||||
"tests/test.cpp",
|
||||
"tests/test_builder.h",
|
||||
"tests/test_assert.h",
|
||||
"tests/test_builder.cpp",
|
||||
"tests/test_assert.cpp",
|
||||
"tests/union_vector/union_vector_generated.h",
|
||||
":public_headers",
|
||||
],
|
||||
copts = FLATBUFFERS_COPTS + [
|
||||
copts = [
|
||||
"-DFLATBUFFERS_TRACK_VERIFIER_BUFFER_SIZE",
|
||||
],
|
||||
data = [
|
||||
|
||||
@@ -71,6 +71,8 @@ function(build_flatbuffers flatbuffers_schemas
|
||||
)
|
||||
endif()
|
||||
|
||||
set(working_dir "${CMAKE_CURRENT_SOURCE_DIR}")
|
||||
|
||||
set(schema_glob "*.fbs")
|
||||
# Generate the include files parameters.
|
||||
set(include_params "")
|
||||
@@ -97,7 +99,8 @@ function(build_flatbuffers flatbuffers_schemas
|
||||
-o ${generated_includes_dir}
|
||||
${include_params}
|
||||
-c ${schema}
|
||||
DEPENDS ${FLATC_TARGET} ${schema} ${additional_dependencies})
|
||||
DEPENDS ${FLATC_TARGET} ${schema} ${additional_dependencies}
|
||||
WORKING_DIRECTORY "${working_dir}")
|
||||
list(APPEND all_generated_files ${generated_include})
|
||||
endif()
|
||||
|
||||
@@ -109,7 +112,8 @@ function(build_flatbuffers flatbuffers_schemas
|
||||
-o ${binary_schemas_dir}
|
||||
${include_params}
|
||||
${schema}
|
||||
DEPENDS ${FLATC_TARGET} ${schema} ${additional_dependencies})
|
||||
DEPENDS ${FLATC_TARGET} ${schema} ${additional_dependencies}
|
||||
WORKING_DIRECTORY "${working_dir}")
|
||||
list(APPEND all_generated_files ${binary_schema})
|
||||
endif()
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
find_program(GIT git)
|
||||
execute_process(
|
||||
COMMAND ${GIT} describe
|
||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
OUTPUT_VARIABLE GIT_DESCRIBE_DIRTY
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
|
||||
@@ -15,6 +15,7 @@ option(FLATBUFFERS_BUILD_GRPCTEST "Enable the build of grpctest" OFF)
|
||||
option(FLATBUFFERS_BUILD_SHAREDLIB
|
||||
"Enable the build of the flatbuffers shared library"
|
||||
OFF)
|
||||
option(FLATBUFFERS_LIBCXX_WITH_CLANG "Force libc++ when using Clang" ON)
|
||||
|
||||
if(NOT FLATBUFFERS_BUILD_FLATC AND FLATBUFFERS_BUILD_TESTS)
|
||||
message(WARNING
|
||||
@@ -45,11 +46,15 @@ set(FlatBuffers_Library_SRCS
|
||||
set(FlatBuffers_Compiler_SRCS
|
||||
${FlatBuffers_Library_SRCS}
|
||||
src/idl_gen_cpp.cpp
|
||||
src/idl_gen_dart.cpp
|
||||
src/idl_gen_general.cpp
|
||||
src/idl_gen_go.cpp
|
||||
src/idl_gen_js.cpp
|
||||
src/idl_gen_php.cpp
|
||||
src/idl_gen_python.cpp
|
||||
src/idl_gen_lobster.cpp
|
||||
src/idl_gen_lua.cpp
|
||||
src/idl_gen_rust.cpp
|
||||
src/idl_gen_fbs.cpp
|
||||
src/idl_gen_grpc.cpp
|
||||
src/idl_gen_json_schema.cpp
|
||||
@@ -73,6 +78,10 @@ set(FlatBuffers_Tests_SRCS
|
||||
${FlatBuffers_Library_SRCS}
|
||||
src/idl_gen_fbs.cpp
|
||||
tests/test.cpp
|
||||
tests/test_assert.h
|
||||
tests/test_assert.cpp
|
||||
tests/test_builder.h
|
||||
tests/test_builder.cpp
|
||||
# file generate by running compiler on tests/monster_test.fbs
|
||||
${CMAKE_CURRENT_BINARY_DIR}/tests/monster_test_generated.h
|
||||
)
|
||||
@@ -95,8 +104,13 @@ set(FlatBuffers_GRPCTest_SRCS
|
||||
include/flatbuffers/flatbuffers.h
|
||||
include/flatbuffers/grpc.h
|
||||
tests/monster_test.grpc.fb.h
|
||||
tests/test_assert.h
|
||||
tests/test_builder.h
|
||||
tests/monster_test.grpc.fb.cc
|
||||
tests/test_assert.cpp
|
||||
tests/test_builder.cpp
|
||||
grpc/tests/grpctest.cpp
|
||||
grpc/tests/message_builder_test.cpp
|
||||
# file generated by running compiler on samples/monster.fbs
|
||||
${CMAKE_CURRENT_BINARY_DIR}/samples/monster_generated.h
|
||||
)
|
||||
@@ -137,14 +151,16 @@ elseif(CMAKE_COMPILER_IS_GNUCXX)
|
||||
elseif(${CMAKE_CXX_COMPILER_ID} MATCHES "Clang")
|
||||
set(CMAKE_CXX_FLAGS
|
||||
"${CMAKE_CXX_FLAGS} -std=c++0x -Wall -pedantic -Werror -Wextra -Wno-unused-parameter")
|
||||
if(NOT "${CMAKE_SYSTEM_NAME}" MATCHES "Linux")
|
||||
set(CMAKE_CXX_FLAGS
|
||||
"${CMAKE_CXX_FLAGS} -stdlib=libc++")
|
||||
endif()
|
||||
if(NOT ("${CMAKE_SYSTEM_NAME}" MATCHES "FreeBSD" OR
|
||||
"${CMAKE_SYSTEM_NAME}" MATCHES "Linux"))
|
||||
set(CMAKE_EXE_LINKER_FLAGS
|
||||
"${CMAKE_EXE_LINKER_FLAGS} -lc++abi")
|
||||
if(FLATBUFFERS_LIBCXX_WITH_CLANG)
|
||||
if(NOT "${CMAKE_SYSTEM_NAME}" MATCHES "Linux")
|
||||
set(CMAKE_CXX_FLAGS
|
||||
"${CMAKE_CXX_FLAGS} -stdlib=libc++")
|
||||
endif()
|
||||
if(NOT ("${CMAKE_SYSTEM_NAME}" MATCHES "FreeBSD" OR
|
||||
"${CMAKE_SYSTEM_NAME}" MATCHES "Linux"))
|
||||
set(CMAKE_EXE_LINKER_FLAGS
|
||||
"${CMAKE_EXE_LINKER_FLAGS} -lc++abi")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Certain platforms such as ARM do not use signed chars by default
|
||||
@@ -174,7 +190,10 @@ include_directories(include)
|
||||
include_directories(grpc)
|
||||
|
||||
if(FLATBUFFERS_BUILD_FLATLIB)
|
||||
add_library(flatbuffers STATIC ${FlatBuffers_Library_SRCS})
|
||||
add_library(flatbuffers STATIC ${FlatBuffers_Library_SRCS})
|
||||
# CMake > 2.8.11: Attach header directory for when build via add_subdirectory().
|
||||
target_include_directories(flatbuffers INTERFACE
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>)
|
||||
endif()
|
||||
|
||||
if(FLATBUFFERS_BUILD_FLATC)
|
||||
@@ -200,7 +219,7 @@ if(FLATBUFFERS_BUILD_SHAREDLIB)
|
||||
# - minor updated when there are additions in API/ABI
|
||||
# - major (ABI number) updated when there are changes in ABI (or removals)
|
||||
set(FlatBuffers_Library_SONAME_MAJOR "1")
|
||||
set(FlatBuffers_Library_SONAME_FULL "${FlatBuffers_Library_SONAME_MAJOR}.9.0")
|
||||
set(FlatBuffers_Library_SONAME_FULL "${FlatBuffers_Library_SONAME_MAJOR}.10.0")
|
||||
set_target_properties(flatbuffers_shared PROPERTIES OUTPUT_NAME flatbuffers
|
||||
SOVERSION "${FlatBuffers_Library_SONAME_MAJOR}"
|
||||
VERSION "${FlatBuffers_Library_SONAME_FULL}")
|
||||
@@ -212,7 +231,7 @@ function(compile_flatbuffers_schema_to_cpp SRC_FBS)
|
||||
add_custom_command(
|
||||
OUTPUT ${GEN_HEADER}
|
||||
COMMAND "${FLATBUFFERS_FLATC_EXECUTABLE}" -c --no-includes --gen-mutable
|
||||
--gen-object-api -o "${SRC_FBS_DIR}"
|
||||
--gen-object-api --gen-compare -o "${SRC_FBS_DIR}"
|
||||
--cpp-ptr-type flatbuffers::unique_ptr # Used to test with C++98 STLs
|
||||
--reflect-names
|
||||
-I "${CMAKE_CURRENT_SOURCE_DIR}/tests/include_test"
|
||||
@@ -248,6 +267,15 @@ if(FLATBUFFERS_BUILD_GRPCTEST)
|
||||
if(CMAKE_COMPILER_IS_GNUCXX)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-unused-parameter -Wno-shadow")
|
||||
endif()
|
||||
if(NOT GRPC_INSTALL_PATH)
|
||||
message(SEND_ERROR "GRPC_INSTALL_PATH variable is not defined. See grpc/README.md")
|
||||
endif()
|
||||
if(NOT PROTOBUF_DOWNLOAD_PATH)
|
||||
message(SEND_ERROR "PROTOBUF_DOWNLOAD_PATH variable is not defined. See grpc/README.md")
|
||||
endif()
|
||||
INCLUDE_DIRECTORIES(${GRPC_INSTALL_PATH}/include)
|
||||
INCLUDE_DIRECTORIES(${PROTOBUF_DOWNLOAD_PATH}/src)
|
||||
LINK_DIRECTORIES(${GRPC_INSTALL_PATH}/lib)
|
||||
add_executable(grpctest ${FlatBuffers_GRPCTest_SRCS})
|
||||
target_link_libraries(grpctest grpc++_unsecure grpc_unsecure gpr pthread dl)
|
||||
endif()
|
||||
@@ -337,6 +365,9 @@ if(FLATBUFFERS_BUILD_TESTS)
|
||||
file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/tests" DESTINATION
|
||||
"${CMAKE_CURRENT_BINARY_DIR}")
|
||||
add_test(NAME flattests COMMAND flattests)
|
||||
if(FLATBUFFERS_BUILD_GRPCTEST)
|
||||
add_test(NAME grpctest COMMAND grpctest)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
include(CMake/BuildFlatBuffers.cmake)
|
||||
|
||||
@@ -47,6 +47,10 @@ include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := FlatBufferTest
|
||||
LOCAL_SRC_FILES := android/jni/main.cpp \
|
||||
tests/test.cpp \
|
||||
tests/test_assert.h \
|
||||
tests/test_builder.h \
|
||||
tests/test_assert.cpp \
|
||||
tests/test_builder.cpp \
|
||||
src/idl_gen_fbs.cpp \
|
||||
src/idl_gen_general.cpp
|
||||
LOCAL_LDLIBS := -llog -landroid -latomic
|
||||
|
||||
12
appveyor.yml
12
appveyor.yml
@@ -13,6 +13,7 @@ environment:
|
||||
|
||||
matrix:
|
||||
- CMAKE_VS_VERSION: "10 2010"
|
||||
- CMAKE_VS_VERSION: "12 2013"
|
||||
- CMAKE_VS_VERSION: "14 2015"
|
||||
|
||||
platform:
|
||||
@@ -32,8 +33,17 @@ build:
|
||||
project: ALL_BUILD.vcxproj
|
||||
verbosity: minimal
|
||||
|
||||
after_build:
|
||||
- python conan/appveyor/install.py
|
||||
- python conan/appveyor/build.py
|
||||
|
||||
install:
|
||||
- set PATH=%CONDA_INSTALL_LOCN%;%CONDA_INSTALL_LOCN%\scripts;%PATH%;
|
||||
- curl -sSf -o rustup-init.exe https://win.rustup.rs/
|
||||
- rustup-init.exe -y
|
||||
- set PATH=%PATH%;C:\Users\appveyor\.cargo\bin
|
||||
- rustc -V
|
||||
- cargo -V
|
||||
|
||||
test_script:
|
||||
- "cd tests"
|
||||
@@ -47,6 +57,8 @@ test_script:
|
||||
- rem "---------------- Java -----------------"
|
||||
- "java -version"
|
||||
- "JavaTest.bat"
|
||||
- rem "---------------- Rust ----------------"
|
||||
- "RustTest.bat"
|
||||
- rem "---------------- JS -----------------"
|
||||
- "node --version"
|
||||
- "..\\%CONFIGURATION%\\flatc -b -I include_test monster_test.fbs unicode_test.json"
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
# Biicode configuration file
|
||||
[paths]
|
||||
include
|
||||
[mains]
|
||||
!android/*
|
||||
[tests]
|
||||
tests/*
|
||||
@@ -1,21 +0,0 @@
|
||||
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,18 +0,0 @@
|
||||
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"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/samples/monsterdata.json"
|
||||
DESTINATION
|
||||
"${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/samples")
|
||||
endif()
|
||||
if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/tests")
|
||||
file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/tests"
|
||||
DESTINATION
|
||||
"${CMAKE_RUNTIME_OUTPUT_DIRECTORY}")
|
||||
endif()
|
||||
|
||||
ADD_BIICODE_TARGETS()
|
||||
|
||||
string(REPLACE " " ";" REPLACED_FLAGS ${CMAKE_CXX_FLAGS})
|
||||
target_compile_options(${BII_BLOCK_TARGET} INTERFACE ${REPLACED_FLAGS})
|
||||
@@ -1,30 +0,0 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# Copyright 2016 Google Inc. All rights reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
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
|
||||
12
conan/CMakeLists.txt
Normal file
12
conan/CMakeLists.txt
Normal file
@@ -0,0 +1,12 @@
|
||||
cmake_minimum_required(VERSION 2.8)
|
||||
|
||||
message(STATUS "Conan FlatBuffers Wrapper")
|
||||
|
||||
include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake)
|
||||
conan_basic_setup()
|
||||
|
||||
if (WIN32 AND MSVC AND FLATBUFFERS_BUILD_SHAREDLIB)
|
||||
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
|
||||
endif(WIN32 AND MSVC AND FLATBUFFERS_BUILD_SHAREDLIB)
|
||||
|
||||
include(${CMAKE_SOURCE_DIR}/CMakeListsOriginal.txt)
|
||||
8
conan/appveyor/build.py
Normal file
8
conan/appveyor/build.py
Normal file
@@ -0,0 +1,8 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
import os
|
||||
|
||||
if os.getenv("APPVEYOR_REPO_TAG") != "true":
|
||||
print("Skip build step. It's not TAG")
|
||||
else:
|
||||
os.system("python conan/build.py")
|
||||
8
conan/appveyor/install.py
Normal file
8
conan/appveyor/install.py
Normal file
@@ -0,0 +1,8 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
import os
|
||||
|
||||
if os.getenv("APPVEYOR_REPO_TAG") != "true":
|
||||
print("Skip step. It's not TAG")
|
||||
else:
|
||||
os.system("pip install conan conan-package-tools")
|
||||
32
conan/build.py
Normal file
32
conan/build.py
Normal file
@@ -0,0 +1,32 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
from cpt.packager import ConanMultiPackager
|
||||
import os
|
||||
|
||||
def set_appveyor_environment():
|
||||
if os.getenv("APPVEYOR") is not None:
|
||||
compiler_version = os.getenv("CMAKE_VS_VERSION").split(" ")[0].replace('"', '')
|
||||
os.environ["CONAN_VISUAL_VERSIONS"] = compiler_version
|
||||
os.environ["CONAN_STABLE_BRANCH_PATTERN"] = "master"
|
||||
ci_platform = os.getenv("Platform").replace('"', '')
|
||||
ci_platform = "x86" if ci_platform == "x86" else "x86_64"
|
||||
os.environ["CONAN_ARCHS"] = ci_platform
|
||||
os.environ["CONAN_BUILD_TYPES"] = os.getenv("Configuration").replace('"', '')
|
||||
|
||||
if __name__ == "__main__":
|
||||
login_username = os.getenv("CONAN_LOGIN_USERNAME", "aardappel")
|
||||
username = os.getenv("CONAN_USERNAME", "google")
|
||||
upload = os.getenv("CONAN_UPLOAD", "https://api.bintray.com/conan/aardappel/flatbuffers")
|
||||
stable_branch_pattern = os.getenv("CONAN_STABLE_BRANCH_PATTERN", r"v\d+\.\d+\.\d+.*")
|
||||
test_folder = os.getenv("CPT_TEST_FOLDER", os.path.join("conan", "test_package"))
|
||||
upload_only_when_stable = os.getenv("CONAN_UPLOAD_ONLY_WHEN_STABLE", True)
|
||||
set_appveyor_environment()
|
||||
|
||||
builder = ConanMultiPackager(username=username,
|
||||
login_username=login_username,
|
||||
upload=upload,
|
||||
stable_branch_pattern=stable_branch_pattern,
|
||||
upload_only_when_stable=upload_only_when_stable,
|
||||
test_folder=test_folder)
|
||||
builder.add_common_builds(pure_c=False)
|
||||
builder.run()
|
||||
9
conan/test_package/CMakeLists.txt
Normal file
9
conan/test_package/CMakeLists.txt
Normal file
@@ -0,0 +1,9 @@
|
||||
project(test_package CXX)
|
||||
cmake_minimum_required(VERSION 2.8.11)
|
||||
|
||||
include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake)
|
||||
conan_basic_setup()
|
||||
|
||||
add_executable(${PROJECT_NAME} test_package.cpp)
|
||||
target_link_libraries(${PROJECT_NAME} ${CONAN_LIBS})
|
||||
set_property(TARGET ${PROJECT_NAME} PROPERTY CXX_STANDARD 11)
|
||||
21
conan/test_package/conanfile.py
Normal file
21
conan/test_package/conanfile.py
Normal file
@@ -0,0 +1,21 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from conans import ConanFile, CMake
|
||||
import os
|
||||
|
||||
|
||||
class TestPackageConan(ConanFile):
|
||||
settings = "os", "compiler", "build_type", "arch"
|
||||
generators = "cmake"
|
||||
|
||||
def build(self):
|
||||
cmake = CMake(self)
|
||||
cmake.configure()
|
||||
cmake.build()
|
||||
|
||||
def test(self):
|
||||
bin_path = os.path.join("bin", "test_package")
|
||||
self.run(bin_path, run_environment=True)
|
||||
self.run("flatc --version", run_environment=True)
|
||||
self.run("flathash fnv1_16 conan", run_environment=True)
|
||||
35
conan/test_package/test_package.cpp
Normal file
35
conan/test_package/test_package.cpp
Normal file
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright 2018 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 <cstdlib>
|
||||
#include <iostream>
|
||||
#include "flatbuffers/util.h"
|
||||
|
||||
// Test to validate Conan package generated
|
||||
|
||||
int main(int /*argc*/, const char * /*argv*/ []) {
|
||||
|
||||
const std::string filename("conanbuildinfo.cmake");
|
||||
|
||||
if (flatbuffers::FileExists(filename.c_str())) {
|
||||
std::cout << "File " << filename << " exists.\n";
|
||||
} else {
|
||||
std::cout << "File " << filename << " does not exist.\n";
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
14
conan/travis/build.sh
Executable file
14
conan/travis/build.sh
Executable file
@@ -0,0 +1,14 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
set -x
|
||||
|
||||
if [[ "$(uname -s)" == 'Darwin' ]]; then
|
||||
if which pyenv > /dev/null; then
|
||||
eval "$(pyenv init -)"
|
||||
fi
|
||||
pyenv activate conan
|
||||
fi
|
||||
|
||||
conan user
|
||||
python conan/build.py
|
||||
22
conan/travis/install.sh
Executable file
22
conan/travis/install.sh
Executable file
@@ -0,0 +1,22 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
set -x
|
||||
|
||||
if [[ "$(uname -s)" == 'Darwin' ]]; then
|
||||
brew update || brew update
|
||||
brew outdated pyenv || brew upgrade pyenv
|
||||
brew install pyenv-virtualenv
|
||||
brew install cmake || true
|
||||
|
||||
if which pyenv > /dev/null; then
|
||||
eval "$(pyenv init -)"
|
||||
fi
|
||||
|
||||
pyenv install 2.7.10
|
||||
pyenv virtualenv 2.7.10 conan
|
||||
pyenv rehash
|
||||
pyenv activate conan
|
||||
fi
|
||||
|
||||
pip install -U conan_package_tools conan
|
||||
61
conanfile.py
61
conanfile.py
@@ -4,50 +4,71 @@
|
||||
"""Conan recipe package for Google FlatBuffers
|
||||
"""
|
||||
import os
|
||||
import shutil
|
||||
from conans import ConanFile, CMake, tools
|
||||
|
||||
|
||||
class FlatbuffersConan(ConanFile):
|
||||
name = "flatbuffers"
|
||||
version = "1.9.0"
|
||||
license = "https://github.com/google/flatbuffers/blob/master/LICENSE.txt"
|
||||
version = "1.10.0"
|
||||
license = "Apache-2.0"
|
||||
url = "https://github.com/google/flatbuffers"
|
||||
homepage = "http://google.github.io/flatbuffers/"
|
||||
author = "Wouter van Oortmerssen"
|
||||
description = "Memory Efficient Serialization Library"
|
||||
settings = "os", "compiler", "build_type", "arch", "os_build", "arch_build"
|
||||
options = {"shared": [True, False]}
|
||||
default_options = "shared=False"
|
||||
settings = "os", "compiler", "build_type", "arch"
|
||||
options = {"shared": [True, False], "fPIC": [True, False]}
|
||||
default_options = "shared=False", "fPIC=True"
|
||||
generators = "cmake"
|
||||
exports = "LICENSE.txt"
|
||||
exports_sources = ["CMake/*", "include/*", "src/*", "grpc/*", "CMakeLists.txt"]
|
||||
exports_sources = ["CMake/*", "include/*", "src/*", "grpc/*", "CMakeLists.txt", "conan/CMakeLists.txt"]
|
||||
|
||||
def _inject_magic_lines(self):
|
||||
"""Inject Conan setup in cmake file to solve exteral dependencies.
|
||||
def source(self):
|
||||
"""Wrap the original CMake file to call conan_basic_setup
|
||||
"""
|
||||
conan_magic_lines = '''project(FlatBuffers)
|
||||
include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake)
|
||||
conan_basic_setup()
|
||||
'''
|
||||
tools.replace_in_file("CMakeLists.txt", "project(FlatBuffers)", conan_magic_lines)
|
||||
shutil.move("CMakeLists.txt", "CMakeListsOriginal.txt")
|
||||
shutil.move(os.path.join("conan", "CMakeLists.txt"), "CMakeLists.txt")
|
||||
|
||||
def config_options(self):
|
||||
"""Remove fPIC option on Windows platform
|
||||
"""
|
||||
if self.settings.os == "Windows":
|
||||
self.options.remove("fPIC")
|
||||
|
||||
def configure_cmake(self):
|
||||
"""Create CMake instance and execute configure step
|
||||
"""
|
||||
cmake = CMake(self)
|
||||
cmake.definitions["FLATBUFFERS_BUILD_TESTS"] = False
|
||||
cmake.definitions["FLATBUFFERS_BUILD_SHAREDLIB"] = self.options.shared
|
||||
cmake.definitions["FLATBUFFERS_BUILD_FLATLIB"] = not self.options.shared
|
||||
cmake.configure()
|
||||
return cmake
|
||||
|
||||
def build(self):
|
||||
"""Configure, build and install FlatBuffers using CMake.
|
||||
"""
|
||||
self._inject_magic_lines()
|
||||
cmake = CMake(self)
|
||||
cmake.definitions["FLATBUFFERS_BUILD_TESTS"] = False
|
||||
cmake.definitions["FLATBUFFERS_BUILD_SHAREDLIB"] = self.options.shared
|
||||
cmake.configure()
|
||||
cmake = self.configure_cmake()
|
||||
cmake.build()
|
||||
cmake.install()
|
||||
|
||||
def package(self):
|
||||
"""Copy Flatbuffers' artifacts to package folder
|
||||
"""
|
||||
cmake = self.configure_cmake()
|
||||
cmake.install()
|
||||
self.copy(pattern="LICENSE.txt", dst="licenses")
|
||||
self.copy(pattern="flathash*", dst="bin", src="bin")
|
||||
self.copy(pattern="flatc*", dst="bin", src="bin")
|
||||
if self.settings.os == "Windows" and self.options.shared:
|
||||
if self.settings.compiler == "Visual Studio":
|
||||
shutil.move(os.path.join(self.package_folder, "lib", "%s.dll" % self.name),
|
||||
os.path.join(self.package_folder, "bin", "%s.dll" % self.name))
|
||||
elif self.settings.compiler == "gcc":
|
||||
shutil.move(os.path.join(self.package_folder, "lib", "lib%s.dll" % self.name),
|
||||
os.path.join(self.package_folder, "bin", "lib%s.dll" % self.name))
|
||||
|
||||
def package_info(self):
|
||||
"""Collect built libraries names and solve flatc path.
|
||||
"""
|
||||
self.cpp_info.libs = tools.collect_libs(self)
|
||||
self.env_info.PATH.append(os.path.join(self.package_folder, "bin"))
|
||||
self.user_info.flatc = os.path.join(self.package_folder, "bin", "flatc")
|
||||
|
||||
14
dart/CHANGELOG.md
Normal file
14
dart/CHANGELOG.md
Normal file
@@ -0,0 +1,14 @@
|
||||
# CHANGELOG
|
||||
|
||||
## 1.9.2
|
||||
|
||||
- Ensure `_writeString` adds enough padding to null terminate strings.
|
||||
|
||||
## 1.9.1
|
||||
|
||||
- Changed constant identifiers to be compatible with Dart 2.x
|
||||
- No longer supports Dart 1.x
|
||||
|
||||
## 1.9.0
|
||||
|
||||
- Initial release, supports Dart 1.x and many dev versions of Dart 2.x
|
||||
233
dart/LICENSE
Normal file
233
dart/LICENSE
Normal file
@@ -0,0 +1,233 @@
|
||||
The code in lib/flat_buffers.dart is based on code that was releases under the
|
||||
following license:
|
||||
|
||||
Copyright 2012, the Dart project authors. All rights reserved.
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following
|
||||
disclaimer in the documentation and/or other materials provided
|
||||
with the distribution.
|
||||
* Neither the name of Google Inc. nor the names of its
|
||||
contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
To the extent permissible, the changes to that code and the other assets in
|
||||
this package are licensed under the Apache2 license:
|
||||
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright 2014 Google Inc.
|
||||
|
||||
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.
|
||||
13
dart/README.md
Normal file
13
dart/README.md
Normal file
@@ -0,0 +1,13 @@
|
||||
# FlatBuffers for Dart
|
||||
|
||||
This package is used to read and write FlatBuffer files in Dart.
|
||||
|
||||
Most consumers will want to use the [`flatc`](https://github.com/google/flatbuffers)
|
||||
compiler to generate Dart code from a FlatBuffers IDL schema. For example, the
|
||||
`monster_my_game.sample_generated.dart` was generated with `flatc` from
|
||||
`monster.fbs` in the example folder. The generated classes can be used to read
|
||||
or write binary files that are interoperable with other languages and platforms
|
||||
supported by FlatBuffers, as illustrated in the `example.dart` in the
|
||||
examples folder.
|
||||
|
||||
Additional documentation and examples are available [at the FlatBuffers site](https://google.github.io/flatbuffers/index.html)
|
||||
155
dart/example/example.dart
Normal file
155
dart/example/example.dart
Normal file
@@ -0,0 +1,155 @@
|
||||
/*
|
||||
* Copyright 2018 Dan Field. 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 'package:flat_buffers/flat_buffers.dart' as fb;
|
||||
import './monster_my_game.sample_generated.dart' as myGame;
|
||||
|
||||
// Example how to use FlatBuffers to create and read binary buffers.
|
||||
|
||||
void main() {
|
||||
builderTest();
|
||||
objectBuilderTest();
|
||||
}
|
||||
|
||||
void builderTest() {
|
||||
final builder = new fb.Builder(initialSize: 1024);
|
||||
final int weaponOneName = builder.writeString("Sword");
|
||||
final int weaponOneDamage = 3;
|
||||
|
||||
final int weaponTwoName = builder.writeString("Axe");
|
||||
final int weaponTwoDamage = 5;
|
||||
|
||||
final swordBuilder = new myGame.WeaponBuilder(builder)
|
||||
..begin()
|
||||
..addNameOffset(weaponOneName)
|
||||
..addDamage(weaponOneDamage);
|
||||
final int sword = swordBuilder.finish();
|
||||
|
||||
final axeBuilder = new myGame.WeaponBuilder(builder)
|
||||
..begin()
|
||||
..addNameOffset(weaponTwoName)
|
||||
..addDamage(weaponTwoDamage);
|
||||
final int axe = axeBuilder.finish();
|
||||
|
||||
// Serialize a name for our monster, called "Orc".
|
||||
final int name = builder.writeString('Orc');
|
||||
|
||||
// Create a list representing the inventory of the Orc. Each number
|
||||
// could correspond to an item that can be claimed after he is slain.
|
||||
final List<int> treasure = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
|
||||
final inventory = builder.writeListUint8(treasure);
|
||||
final weapons = builder.writeList([sword, axe]);
|
||||
|
||||
// Struct builders are very easy to reuse.
|
||||
final vec3Builder = new myGame.Vec3Builder(builder);
|
||||
|
||||
vec3Builder.finish(4.0, 5.0, 6.0);
|
||||
vec3Builder.finish(1.0, 2.0, 3.0);
|
||||
// Set his hit points to 300 and his mana to 150.
|
||||
final int hp = 300;
|
||||
final int mana = 150;
|
||||
|
||||
final monster = new myGame.MonsterBuilder(builder)
|
||||
..begin()
|
||||
..addNameOffset(name)
|
||||
..addInventoryOffset(inventory)
|
||||
..addWeaponsOffset(weapons)
|
||||
..addEquippedType(myGame.EquipmentTypeId.Weapon)
|
||||
..addEquippedOffset(axe)
|
||||
..addHp(hp)
|
||||
..addMana(mana)
|
||||
..addPos(vec3Builder.finish(1.0, 2.0, 3.0))
|
||||
..addColor(myGame.Color.Red);
|
||||
|
||||
final int monsteroff = monster.finish();
|
||||
final buffer = builder.finish(monsteroff);
|
||||
if (verify(buffer)) {
|
||||
print(
|
||||
"The FlatBuffer was successfully created with a builder and verified!");
|
||||
}
|
||||
}
|
||||
|
||||
void objectBuilderTest() {
|
||||
// Create the builder here so we can use it for both weapons and equipped
|
||||
// the actual data will only be written to the buffer once.
|
||||
var axe = new myGame.WeaponObjectBuilder(name: 'Axe', damage: 5);
|
||||
|
||||
var monsterBuilder = new myGame.MonsterObjectBuilder(
|
||||
pos: new myGame.Vec3ObjectBuilder(x: 1.0, y: 2.0, z: 3.0),
|
||||
mana: 150,
|
||||
hp: 300,
|
||||
name: 'Orc',
|
||||
inventory: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
|
||||
color: myGame.Color.Red,
|
||||
weapons: [new myGame.WeaponObjectBuilder(name: 'Sword', damage: 3), axe],
|
||||
equippedType: myGame.EquipmentTypeId.Weapon,
|
||||
equipped: axe,
|
||||
);
|
||||
|
||||
var buffer = monsterBuilder.toBytes();
|
||||
|
||||
// We now have a FlatBuffer we can store on disk or send over a network.
|
||||
|
||||
// ** file/network code goes here :) **
|
||||
|
||||
// Instead, we're going to access it right away (as if we just received it).
|
||||
if (verify(buffer)) {
|
||||
print(
|
||||
"The FlatBuffer was successfully created with an object builder and verified!");
|
||||
}
|
||||
}
|
||||
|
||||
bool verify(List<int> buffer) {
|
||||
// Get access to the root:
|
||||
var monster = new myGame.Monster(buffer);
|
||||
|
||||
// Get and test some scalar types from the FlatBuffer.
|
||||
assert(monster.hp == 80);
|
||||
assert(monster.mana == 150); // default
|
||||
assert(monster.name == "MyMonster");
|
||||
|
||||
// Get and test a field of the FlatBuffer's `struct`.
|
||||
var pos = monster.pos;
|
||||
assert(pos != null);
|
||||
assert(pos.z == 3.0);
|
||||
|
||||
// Get a test an element from the `inventory` FlatBuffer's `vector`.
|
||||
var inv = monster.inventory;
|
||||
assert(inv != null);
|
||||
assert(inv.length == 10);
|
||||
assert(inv[9] == 9);
|
||||
|
||||
// Get and test the `weapons` FlatBuffers's `vector`.
|
||||
var expected_weapon_names = ["Sword", "Axe"];
|
||||
var expected_weapon_damages = [3, 5];
|
||||
var weps = monster.weapons;
|
||||
for (int i = 0; i < weps.length; i++) {
|
||||
assert(weps[i].name == expected_weapon_names[i]);
|
||||
assert(weps[i].damage == expected_weapon_damages[i]);
|
||||
}
|
||||
|
||||
// Get and test the `Equipment` union (`equipped` field).
|
||||
assert(monster.equippedType.value == myGame.EquipmentTypeId.Weapon.value);
|
||||
assert(monster.equippedType == myGame.EquipmentTypeId.Weapon);
|
||||
|
||||
assert(monster.equipped is myGame.Weapon);
|
||||
var equipped = monster.equipped as myGame.Weapon;
|
||||
assert(equipped.name == "Axe");
|
||||
assert(equipped.damage == 5);
|
||||
|
||||
print(monster);
|
||||
return true;
|
||||
}
|
||||
440
dart/example/monster_my_game.sample_generated.dart
Normal file
440
dart/example/monster_my_game.sample_generated.dart
Normal file
@@ -0,0 +1,440 @@
|
||||
// automatically generated by the FlatBuffers compiler, do not modify
|
||||
// ignore_for_file: unused_import, non_constant_identifier_names
|
||||
|
||||
library my_game.sample;
|
||||
|
||||
import 'dart:typed_data' show Uint8List;
|
||||
import 'package:flat_buffers/flat_buffers.dart' as fb;
|
||||
|
||||
|
||||
class Color {
|
||||
final int value;
|
||||
const Color._(this.value);
|
||||
|
||||
factory Color.fromValue(int value) {
|
||||
if (value == null) return null;
|
||||
if (!values.containsKey(value)) {
|
||||
throw new StateError('Invalid value $value for bit flag enum Color');
|
||||
}
|
||||
return values[value];
|
||||
}
|
||||
|
||||
static const int minValue = 0;
|
||||
static const int maxValue = 2;
|
||||
static bool containsValue(int value) => values.containsKey(value);
|
||||
|
||||
static const Color Red = const Color._(0);
|
||||
static const Color Green = const Color._(1);
|
||||
static const Color Blue = const Color._(2);
|
||||
static get values => {0: Red,1: Green,2: Blue,};
|
||||
|
||||
static const fb.Reader<Color> reader = const _ColorReader();
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'Color{value: $value}';
|
||||
}
|
||||
}
|
||||
|
||||
class _ColorReader extends fb.Reader<Color> {
|
||||
const _ColorReader();
|
||||
|
||||
@override
|
||||
int get size => 1;
|
||||
|
||||
@override
|
||||
Color read(fb.BufferContext bc, int offset) =>
|
||||
new Color.fromValue(const fb.Int8Reader().read(bc, offset));
|
||||
}
|
||||
|
||||
class EquipmentTypeId {
|
||||
final int value;
|
||||
const EquipmentTypeId._(this.value);
|
||||
|
||||
factory EquipmentTypeId.fromValue(int value) {
|
||||
if (value == null) return null;
|
||||
if (!values.containsKey(value)) {
|
||||
throw new StateError('Invalid value $value for bit flag enum EquipmentTypeId');
|
||||
}
|
||||
return values[value];
|
||||
}
|
||||
|
||||
static const int minValue = 0;
|
||||
static const int maxValue = 1;
|
||||
static bool containsValue(int value) => values.containsKey(value);
|
||||
|
||||
static const EquipmentTypeId NONE = const EquipmentTypeId._(0);
|
||||
static const EquipmentTypeId Weapon = const EquipmentTypeId._(1);
|
||||
static get values => {0: NONE,1: Weapon,};
|
||||
|
||||
static const fb.Reader<EquipmentTypeId> reader = const _EquipmentTypeIdReader();
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'EquipmentTypeId{value: $value}';
|
||||
}
|
||||
}
|
||||
|
||||
class _EquipmentTypeIdReader extends fb.Reader<EquipmentTypeId> {
|
||||
const _EquipmentTypeIdReader();
|
||||
|
||||
@override
|
||||
int get size => 1;
|
||||
|
||||
@override
|
||||
EquipmentTypeId read(fb.BufferContext bc, int offset) =>
|
||||
new EquipmentTypeId.fromValue(const fb.Uint8Reader().read(bc, offset));
|
||||
}
|
||||
|
||||
class Vec3 {
|
||||
Vec3._(this._bc, this._bcOffset);
|
||||
|
||||
static const fb.Reader<Vec3> reader = const _Vec3Reader();
|
||||
|
||||
final fb.BufferContext _bc;
|
||||
final int _bcOffset;
|
||||
|
||||
double get x => const fb.Float32Reader().read(_bc, _bcOffset + 0);
|
||||
double get y => const fb.Float32Reader().read(_bc, _bcOffset + 4);
|
||||
double get z => const fb.Float32Reader().read(_bc, _bcOffset + 8);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'Vec3{x: $x, y: $y, z: $z}';
|
||||
}
|
||||
}
|
||||
|
||||
class _Vec3Reader extends fb.StructReader<Vec3> {
|
||||
const _Vec3Reader();
|
||||
|
||||
@override
|
||||
int get size => 12;
|
||||
|
||||
@override
|
||||
Vec3 createObject(fb.BufferContext bc, int offset) =>
|
||||
new Vec3._(bc, offset);
|
||||
}
|
||||
|
||||
class Vec3Builder {
|
||||
Vec3Builder(this.fbBuilder) {
|
||||
assert(fbBuilder != null);
|
||||
}
|
||||
|
||||
final fb.Builder fbBuilder;
|
||||
|
||||
int finish(double x, double y, double z) {
|
||||
fbBuilder.putFloat32(z);
|
||||
fbBuilder.putFloat32(y);
|
||||
fbBuilder.putFloat32(x);
|
||||
return fbBuilder.offset;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class Vec3ObjectBuilder extends fb.ObjectBuilder {
|
||||
final double _x;
|
||||
final double _y;
|
||||
final double _z;
|
||||
|
||||
Vec3ObjectBuilder({
|
||||
double x,
|
||||
double y,
|
||||
double z,
|
||||
})
|
||||
: _x = x,
|
||||
_y = y,
|
||||
_z = z;
|
||||
|
||||
/// Finish building, and store into the [fbBuilder].
|
||||
@override
|
||||
int finish(
|
||||
fb.Builder fbBuilder) {
|
||||
assert(fbBuilder != null);
|
||||
|
||||
fbBuilder.putFloat32(_z);
|
||||
fbBuilder.putFloat32(_y);
|
||||
fbBuilder.putFloat32(_x);
|
||||
return fbBuilder.offset;
|
||||
}
|
||||
|
||||
/// Convenience method to serialize to byte list.
|
||||
@override
|
||||
Uint8List toBytes([String fileIdentifier]) {
|
||||
fb.Builder fbBuilder = new fb.Builder();
|
||||
int offset = finish(fbBuilder);
|
||||
return fbBuilder.finish(offset, fileIdentifier);
|
||||
}
|
||||
}
|
||||
class Monster {
|
||||
Monster._(this._bc, this._bcOffset);
|
||||
factory Monster(List<int> bytes) {
|
||||
fb.BufferContext rootRef = new fb.BufferContext.fromBytes(bytes);
|
||||
return reader.read(rootRef, 0);
|
||||
}
|
||||
|
||||
static const fb.Reader<Monster> reader = const _MonsterReader();
|
||||
|
||||
final fb.BufferContext _bc;
|
||||
final int _bcOffset;
|
||||
|
||||
Vec3 get pos => Vec3.reader.vTableGet(_bc, _bcOffset, 4, null);
|
||||
int get mana => const fb.Int16Reader().vTableGet(_bc, _bcOffset, 6, 150);
|
||||
int get hp => const fb.Int16Reader().vTableGet(_bc, _bcOffset, 8, 100);
|
||||
String get name => const fb.StringReader().vTableGet(_bc, _bcOffset, 10, null);
|
||||
List<int> get inventory => const fb.ListReader<int>(const fb.Uint8Reader()).vTableGet(_bc, _bcOffset, 14, null);
|
||||
Color get color => new Color.fromValue(const fb.Int8Reader().vTableGet(_bc, _bcOffset, 16, 2));
|
||||
List<Weapon> get weapons => const fb.ListReader<Weapon>(Weapon.reader).vTableGet(_bc, _bcOffset, 18, null);
|
||||
EquipmentTypeId get equippedType => new EquipmentTypeId.fromValue(const fb.Uint8Reader().vTableGet(_bc, _bcOffset, 20, null));
|
||||
dynamic get equipped {
|
||||
switch (equippedType?.value) {
|
||||
case 1: return Weapon.reader.vTableGet(_bc, _bcOffset, 22, null);
|
||||
default: return null;
|
||||
}
|
||||
}
|
||||
List<Vec3> get path => const fb.ListReader<Vec3>(Vec3.reader).vTableGet(_bc, _bcOffset, 24, null);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'Monster{pos: $pos, mana: $mana, hp: $hp, name: $name, inventory: $inventory, color: $color, weapons: $weapons, equippedType: $equippedType, equipped: $equipped, path: $path}';
|
||||
}
|
||||
}
|
||||
|
||||
class _MonsterReader extends fb.TableReader<Monster> {
|
||||
const _MonsterReader();
|
||||
|
||||
@override
|
||||
Monster createObject(fb.BufferContext bc, int offset) =>
|
||||
new Monster._(bc, offset);
|
||||
}
|
||||
|
||||
class MonsterBuilder {
|
||||
MonsterBuilder(this.fbBuilder) {
|
||||
assert(fbBuilder != null);
|
||||
}
|
||||
|
||||
final fb.Builder fbBuilder;
|
||||
|
||||
void begin() {
|
||||
fbBuilder.startTable();
|
||||
}
|
||||
|
||||
int addPos(int offset) {
|
||||
fbBuilder.addStruct(0, offset);
|
||||
return fbBuilder.offset;
|
||||
}
|
||||
int addMana(int mana) {
|
||||
fbBuilder.addInt16(1, mana);
|
||||
return fbBuilder.offset;
|
||||
}
|
||||
int addHp(int hp) {
|
||||
fbBuilder.addInt16(2, hp);
|
||||
return fbBuilder.offset;
|
||||
}
|
||||
int addNameOffset(int offset) {
|
||||
fbBuilder.addOffset(3, offset);
|
||||
return fbBuilder.offset;
|
||||
}
|
||||
int addInventoryOffset(int offset) {
|
||||
fbBuilder.addOffset(5, offset);
|
||||
return fbBuilder.offset;
|
||||
}
|
||||
int addColor(Color color) {
|
||||
fbBuilder.addInt8(6, color?.value);
|
||||
return fbBuilder.offset;
|
||||
}
|
||||
int addWeaponsOffset(int offset) {
|
||||
fbBuilder.addOffset(7, offset);
|
||||
return fbBuilder.offset;
|
||||
}
|
||||
int addEquippedType(EquipmentTypeId equippedType) {
|
||||
fbBuilder.addUint8(8, equippedType?.value);
|
||||
return fbBuilder.offset;
|
||||
}
|
||||
int addEquippedOffset(int offset) {
|
||||
fbBuilder.addOffset(9, offset);
|
||||
return fbBuilder.offset;
|
||||
}
|
||||
int addPathOffset(int offset) {
|
||||
fbBuilder.addOffset(10, offset);
|
||||
return fbBuilder.offset;
|
||||
}
|
||||
|
||||
int finish() {
|
||||
return fbBuilder.endTable();
|
||||
}
|
||||
}
|
||||
|
||||
class MonsterObjectBuilder extends fb.ObjectBuilder {
|
||||
final Vec3ObjectBuilder _pos;
|
||||
final int _mana;
|
||||
final int _hp;
|
||||
final String _name;
|
||||
final List<int> _inventory;
|
||||
final Color _color;
|
||||
final List<WeaponObjectBuilder> _weapons;
|
||||
final EquipmentTypeId _equippedType;
|
||||
final dynamic _equipped;
|
||||
final List<Vec3ObjectBuilder> _path;
|
||||
|
||||
MonsterObjectBuilder({
|
||||
Vec3ObjectBuilder pos,
|
||||
int mana,
|
||||
int hp,
|
||||
String name,
|
||||
List<int> inventory,
|
||||
Color color,
|
||||
List<WeaponObjectBuilder> weapons,
|
||||
EquipmentTypeId equippedType,
|
||||
dynamic equipped,
|
||||
List<Vec3ObjectBuilder> path,
|
||||
})
|
||||
: _pos = pos,
|
||||
_mana = mana,
|
||||
_hp = hp,
|
||||
_name = name,
|
||||
_inventory = inventory,
|
||||
_color = color,
|
||||
_weapons = weapons,
|
||||
_equippedType = equippedType,
|
||||
_equipped = equipped,
|
||||
_path = path;
|
||||
|
||||
/// Finish building, and store into the [fbBuilder].
|
||||
@override
|
||||
int finish(
|
||||
fb.Builder fbBuilder) {
|
||||
assert(fbBuilder != null);
|
||||
final int nameOffset = fbBuilder.writeString(_name);
|
||||
final int inventoryOffset = _inventory?.isNotEmpty == true
|
||||
? fbBuilder.writeListUint8(_inventory)
|
||||
: null;
|
||||
final int weaponsOffset = _weapons?.isNotEmpty == true
|
||||
? fbBuilder.writeList(_weapons.map((b) => b.getOrCreateOffset(fbBuilder)).toList())
|
||||
: null;
|
||||
final int equippedOffset = _equipped?.getOrCreateOffset(fbBuilder);
|
||||
final int pathOffset = _path?.isNotEmpty == true
|
||||
? fbBuilder.writeListOfStructs(_path)
|
||||
: null;
|
||||
|
||||
fbBuilder.startTable();
|
||||
if (_pos != null) {
|
||||
fbBuilder.addStruct(0, _pos.finish(fbBuilder));
|
||||
}
|
||||
fbBuilder.addInt16(1, _mana);
|
||||
fbBuilder.addInt16(2, _hp);
|
||||
if (nameOffset != null) {
|
||||
fbBuilder.addOffset(3, nameOffset);
|
||||
}
|
||||
if (inventoryOffset != null) {
|
||||
fbBuilder.addOffset(5, inventoryOffset);
|
||||
}
|
||||
fbBuilder.addInt8(6, _color?.value);
|
||||
if (weaponsOffset != null) {
|
||||
fbBuilder.addOffset(7, weaponsOffset);
|
||||
}
|
||||
fbBuilder.addUint8(8, _equippedType?.value);
|
||||
if (equippedOffset != null) {
|
||||
fbBuilder.addOffset(9, equippedOffset);
|
||||
}
|
||||
if (pathOffset != null) {
|
||||
fbBuilder.addOffset(10, pathOffset);
|
||||
}
|
||||
return fbBuilder.endTable();
|
||||
}
|
||||
|
||||
/// Convenience method to serialize to byte list.
|
||||
@override
|
||||
Uint8List toBytes([String fileIdentifier]) {
|
||||
fb.Builder fbBuilder = new fb.Builder();
|
||||
int offset = finish(fbBuilder);
|
||||
return fbBuilder.finish(offset, fileIdentifier);
|
||||
}
|
||||
}
|
||||
class Weapon {
|
||||
Weapon._(this._bc, this._bcOffset);
|
||||
factory Weapon(List<int> bytes) {
|
||||
fb.BufferContext rootRef = new fb.BufferContext.fromBytes(bytes);
|
||||
return reader.read(rootRef, 0);
|
||||
}
|
||||
|
||||
static const fb.Reader<Weapon> reader = const _WeaponReader();
|
||||
|
||||
final fb.BufferContext _bc;
|
||||
final int _bcOffset;
|
||||
|
||||
String get name => const fb.StringReader().vTableGet(_bc, _bcOffset, 4, null);
|
||||
int get damage => const fb.Int16Reader().vTableGet(_bc, _bcOffset, 6, null);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'Weapon{name: $name, damage: $damage}';
|
||||
}
|
||||
}
|
||||
|
||||
class _WeaponReader extends fb.TableReader<Weapon> {
|
||||
const _WeaponReader();
|
||||
|
||||
@override
|
||||
Weapon createObject(fb.BufferContext bc, int offset) =>
|
||||
new Weapon._(bc, offset);
|
||||
}
|
||||
|
||||
class WeaponBuilder {
|
||||
WeaponBuilder(this.fbBuilder) {
|
||||
assert(fbBuilder != null);
|
||||
}
|
||||
|
||||
final fb.Builder fbBuilder;
|
||||
|
||||
void begin() {
|
||||
fbBuilder.startTable();
|
||||
}
|
||||
|
||||
int addNameOffset(int offset) {
|
||||
fbBuilder.addOffset(0, offset);
|
||||
return fbBuilder.offset;
|
||||
}
|
||||
int addDamage(int damage) {
|
||||
fbBuilder.addInt16(1, damage);
|
||||
return fbBuilder.offset;
|
||||
}
|
||||
|
||||
int finish() {
|
||||
return fbBuilder.endTable();
|
||||
}
|
||||
}
|
||||
|
||||
class WeaponObjectBuilder extends fb.ObjectBuilder {
|
||||
final String _name;
|
||||
final int _damage;
|
||||
|
||||
WeaponObjectBuilder({
|
||||
String name,
|
||||
int damage,
|
||||
})
|
||||
: _name = name,
|
||||
_damage = damage;
|
||||
|
||||
/// Finish building, and store into the [fbBuilder].
|
||||
@override
|
||||
int finish(
|
||||
fb.Builder fbBuilder) {
|
||||
assert(fbBuilder != null);
|
||||
final int nameOffset = fbBuilder.writeString(_name);
|
||||
|
||||
fbBuilder.startTable();
|
||||
if (nameOffset != null) {
|
||||
fbBuilder.addOffset(0, nameOffset);
|
||||
}
|
||||
fbBuilder.addInt16(1, _damage);
|
||||
return fbBuilder.endTable();
|
||||
}
|
||||
|
||||
/// Convenience method to serialize to byte list.
|
||||
@override
|
||||
Uint8List toBytes([String fileIdentifier]) {
|
||||
fb.Builder fbBuilder = new fb.Builder();
|
||||
int offset = finish(fbBuilder);
|
||||
return fbBuilder.finish(offset, fileIdentifier);
|
||||
}
|
||||
}
|
||||
1241
dart/lib/flat_buffers.dart
Normal file
1241
dart/lib/flat_buffers.dart
Normal file
File diff suppressed because it is too large
Load Diff
28
dart/publish.sh
Executable file
28
dart/publish.sh
Executable file
@@ -0,0 +1,28 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Copyright 2018 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.
|
||||
#
|
||||
# Note to pub consumers: this file is used to assist with publishing the
|
||||
# pub package from the flatbuffers repository and is not meant for general use.
|
||||
# As pub does not currently provide a way to exclude files, it is included here.
|
||||
|
||||
command -v pub >/dev/null 2>&1 || { echo >&2 "Require `pub` but it's not installed. Aborting."; exit 1; }
|
||||
|
||||
cp ../samples/monster.fbs example/
|
||||
cp ../tests/monster_test.fbs test/
|
||||
pub publish
|
||||
|
||||
rm example/monster.fbs
|
||||
rm test/monster_test.fbs
|
||||
20
dart/pubspec.yaml
Normal file
20
dart/pubspec.yaml
Normal file
@@ -0,0 +1,20 @@
|
||||
name: flat_buffers
|
||||
version: 1.10.0
|
||||
description: >
|
||||
FlatBuffers reading and writing library for Dart. Use the flatc compiler to
|
||||
generate Dart classes for a FlatBuffers schema, and this library to assist with
|
||||
reading and writing the binary format.
|
||||
|
||||
Based on original work by Konstantin Scheglov and Paul Berry of the Dart SDK team.
|
||||
authors:
|
||||
- Dan Field <dfield@gmail.com>
|
||||
- Konstantin Scheglov
|
||||
- Paul Berry
|
||||
homepage: https://github.com/google/flatbuffers
|
||||
documentation: https://google.github.io/flatbuffers/index.html
|
||||
dev_dependencies:
|
||||
test: ^1.3.0
|
||||
test_reflective_loader: ^0.1.4
|
||||
path: ^1.5.1
|
||||
environment:
|
||||
sdk: '>=2.0.0-dev.28.0 <3.0.0'
|
||||
573
dart/test/flat_buffers_test.dart
Normal file
573
dart/test/flat_buffers_test.dart
Normal file
@@ -0,0 +1,573 @@
|
||||
// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
|
||||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
import 'dart:typed_data';
|
||||
import 'dart:io' as io;
|
||||
|
||||
import 'package:path/path.dart' as path;
|
||||
|
||||
import 'package:flat_buffers/flat_buffers.dart';
|
||||
import 'package:test/test.dart';
|
||||
import 'package:test_reflective_loader/test_reflective_loader.dart';
|
||||
|
||||
import './monster_test_my_game.example_generated.dart' as example;
|
||||
|
||||
main() {
|
||||
defineReflectiveSuite(() {
|
||||
defineReflectiveTests(BuilderTest);
|
||||
defineReflectiveTests(CheckOtherLangaugesData);
|
||||
});
|
||||
}
|
||||
|
||||
int indexToField(int index) {
|
||||
return (1 + 1 + index) * 2;
|
||||
}
|
||||
|
||||
@reflectiveTest
|
||||
class CheckOtherLangaugesData {
|
||||
test_cppData() async {
|
||||
List<int> data = await new io.File(path.join(
|
||||
path.dirname(io.Platform.script.path),
|
||||
'monsterdata_test.mon',
|
||||
))
|
||||
.readAsBytes();
|
||||
example.Monster mon = new example.Monster(data);
|
||||
expect(mon.hp, 80);
|
||||
expect(mon.mana, 150);
|
||||
expect(mon.name, 'MyMonster');
|
||||
expect(mon.pos.x, 1.0);
|
||||
expect(mon.pos.y, 2.0);
|
||||
expect(mon.pos.z, 3.0);
|
||||
expect(mon.pos.test1, 3.0);
|
||||
expect(mon.pos.test2.value, 2.0);
|
||||
expect(mon.pos.test3.a, 5);
|
||||
expect(mon.pos.test3.b, 6);
|
||||
expect(mon.testType.value, example.AnyTypeId.Monster.value);
|
||||
expect(mon.test is example.Monster, true);
|
||||
final monster2 = mon.test as example.Monster;
|
||||
expect(monster2.name, "Fred");
|
||||
|
||||
expect(mon.inventory.length, 5);
|
||||
expect(mon.inventory.reduce((cur, next) => cur + next), 10);
|
||||
expect(mon.test4.length, 2);
|
||||
expect(
|
||||
mon.test4[0].a + mon.test4[0].b + mon.test4[1].a + mon.test4[1].b, 100);
|
||||
expect(mon.testarrayofstring.length, 2);
|
||||
expect(mon.testarrayofstring[0], "test1");
|
||||
expect(mon.testarrayofstring[1], "test2");
|
||||
|
||||
// this will fail if accessing any field fails.
|
||||
expect(mon.toString(),
|
||||
'Monster{pos: Vec3{x: 1.0, y: 2.0, z: 3.0, test1: 3.0, test2: Color{value: 2}, test3: Test{a: 5, b: 6}}, mana: 150, hp: 80, name: MyMonster, inventory: [0, 1, 2, 3, 4], color: Color{value: 8}, testType: AnyTypeId{value: 1}, test: Monster{pos: null, mana: 150, hp: 100, name: Fred, inventory: null, color: Color{value: 8}, testType: AnyTypeId{value: 0}, test: null, test4: null, testarrayofstring: null, testarrayoftables: null, enemy: null, testnestedflatbuffer: null, testempty: null, testbool: false, testhashs32Fnv1: 0, testhashu32Fnv1: 0, testhashs64Fnv1: 0, testhashu64Fnv1: 0, testhashs32Fnv1a: 0, testhashu32Fnv1a: 0, testhashs64Fnv1a: 0, testhashu64Fnv1a: 0, testarrayofbools: null, testf: 3.14159, testf2: 3.0, testf3: 0.0, testarrayofstring2: null, testarrayofsortedstruct: null, flex: null, test5: null, vectorOfLongs: null, vectorOfDoubles: null, parentNamespaceTest: null, vectorOfReferrables: null, singleWeakReference: 0, vectorOfWeakReferences: null, vectorOfStrongReferrables: null, coOwningReference: 0, vectorOfCoOwningReferences: null, nonOwningReference: 0, vectorOfNonOwningReferences: null}, test4: [Test{a: 10, b: 20}, Test{a: 30, b: 40}], testarrayofstring: [test1, test2], testarrayoftables: null, enemy: Monster{pos: null, mana: 150, hp: 100, name: Fred, inventory: null, color: Color{value: 8}, testType: AnyTypeId{value: 0}, test: null, test4: null, testarrayofstring: null, testarrayoftables: null, enemy: null, testnestedflatbuffer: null, testempty: null, testbool: false, testhashs32Fnv1: 0, testhashu32Fnv1: 0, testhashs64Fnv1: 0, testhashu64Fnv1: 0, testhashs32Fnv1a: 0, testhashu32Fnv1a: 0, testhashs64Fnv1a: 0, testhashu64Fnv1a: 0, testarrayofbools: null, testf: 3.14159, testf2: 3.0, testf3: 0.0, testarrayofstring2: null, testarrayofsortedstruct: null, flex: null, test5: null, vectorOfLongs: null, vectorOfDoubles: null, parentNamespaceTest: null, vectorOfReferrables: null, singleWeakReference: 0, vectorOfWeakReferences: null, vectorOfStrongReferrables: null, coOwningReference: 0, vectorOfCoOwningReferences: null, nonOwningReference: 0, vectorOfNonOwningReferences: null}, testnestedflatbuffer: null, testempty: null, testbool: false, testhashs32Fnv1: -579221183, testhashu32Fnv1: 3715746113, testhashs64Fnv1: 7930699090847568257, testhashu64Fnv1: 7930699090847568257, testhashs32Fnv1a: -1904106383, testhashu32Fnv1a: 2390860913, testhashs64Fnv1a: 4898026182817603057, testhashu64Fnv1a: 4898026182817603057, testarrayofbools: [true, false, true], testf: 3.14159, testf2: 3.0, testf3: 0.0, testarrayofstring2: null, testarrayofsortedstruct: null, flex: null, test5: [Test{a: 10, b: 20}, Test{a: 30, b: 40}], vectorOfLongs: [1, 100, 10000, 1000000, 100000000], vectorOfDoubles: [-1.7976931348623157e+308, 0.0, 1.7976931348623157e+308], parentNamespaceTest: null, vectorOfReferrables: null, singleWeakReference: 0, vectorOfWeakReferences: null, vectorOfStrongReferrables: null, coOwningReference: 0, vectorOfCoOwningReferences: null, nonOwningReference: 0, vectorOfNonOwningReferences: null}');
|
||||
}
|
||||
}
|
||||
|
||||
@reflectiveTest
|
||||
class BuilderTest {
|
||||
void test_monsterBuilder() {
|
||||
final fbBuilder = new Builder();
|
||||
final str = fbBuilder.writeString('MyMonster');
|
||||
|
||||
fbBuilder.writeString('test1');
|
||||
fbBuilder.writeString('test2');
|
||||
final testArrayOfString = fbBuilder.endStructVector(2);
|
||||
|
||||
final fred = fbBuilder.writeString('Fred');
|
||||
|
||||
final List<int> treasure = [0, 1, 2, 3, 4];
|
||||
final inventory = fbBuilder.writeListUint8(treasure);
|
||||
|
||||
final monBuilder = new example.MonsterBuilder(fbBuilder)
|
||||
..begin()
|
||||
..addNameOffset(fred);
|
||||
final mon2 = monBuilder.finish();
|
||||
|
||||
final testBuilder = new example.TestBuilder(fbBuilder);
|
||||
testBuilder.finish(10, 20);
|
||||
testBuilder.finish(30, 40);
|
||||
final test4 = fbBuilder.endStructVector(2);
|
||||
|
||||
|
||||
monBuilder
|
||||
..begin()
|
||||
..addPos(
|
||||
new example.Vec3Builder(fbBuilder).finish(
|
||||
1.0,
|
||||
2.0,
|
||||
3.0,
|
||||
3.0,
|
||||
example.Color.Green,
|
||||
() => testBuilder.finish(5, 6),
|
||||
),
|
||||
)
|
||||
..addHp(80)
|
||||
..addNameOffset(str)
|
||||
..addInventoryOffset(inventory)
|
||||
..addTestType(example.AnyTypeId.Monster)
|
||||
..addTestOffset(mon2)
|
||||
..addTest4Offset(test4)
|
||||
..addTestarrayofstringOffset(testArrayOfString);
|
||||
final mon = monBuilder.finish();
|
||||
fbBuilder.finish(mon);
|
||||
}
|
||||
|
||||
void test_error_addInt32_withoutStartTable() {
|
||||
Builder builder = new Builder();
|
||||
expect(() {
|
||||
builder.addInt32(0, 0);
|
||||
}, throwsStateError);
|
||||
}
|
||||
|
||||
void test_error_addOffset_withoutStartTable() {
|
||||
Builder builder = new Builder();
|
||||
expect(() {
|
||||
builder.addOffset(0, 0);
|
||||
}, throwsStateError);
|
||||
}
|
||||
|
||||
void test_error_endTable_withoutStartTable() {
|
||||
Builder builder = new Builder();
|
||||
expect(() {
|
||||
builder.endTable();
|
||||
}, throwsStateError);
|
||||
}
|
||||
|
||||
void test_error_startTable_duringTable() {
|
||||
Builder builder = new Builder();
|
||||
builder.startTable();
|
||||
expect(() {
|
||||
builder.startTable();
|
||||
}, throwsStateError);
|
||||
}
|
||||
|
||||
void test_error_writeString_duringTable() {
|
||||
Builder builder = new Builder();
|
||||
builder.startTable();
|
||||
expect(() {
|
||||
builder.writeString('12345');
|
||||
}, throwsStateError);
|
||||
}
|
||||
|
||||
void test_file_identifier() {
|
||||
Uint8List byteList;
|
||||
{
|
||||
Builder builder = new Builder(initialSize: 0);
|
||||
builder.startTable();
|
||||
int offset = builder.endTable();
|
||||
byteList = builder.finish(offset, 'Az~ÿ');
|
||||
}
|
||||
// Convert byteList to a ByteData so that we can read data from it.
|
||||
ByteData byteData = byteList.buffer.asByteData(byteList.offsetInBytes);
|
||||
// First 4 bytes are an offset to the table data.
|
||||
int tableDataLoc = byteData.getUint32(0, Endian.little);
|
||||
// Next 4 bytes are the file identifier.
|
||||
expect(byteData.getUint8(4), 65); // 'a'
|
||||
expect(byteData.getUint8(5), 122); // 'z'
|
||||
expect(byteData.getUint8(6), 126); // '~'
|
||||
expect(byteData.getUint8(7), 255); // 'ÿ'
|
||||
// First 4 bytes of the table data are a backwards offset to the vtable.
|
||||
int vTableLoc = tableDataLoc -
|
||||
byteData.getInt32(tableDataLoc, Endian.little);
|
||||
// First 2 bytes of the vtable are the size of the vtable in bytes, which
|
||||
// should be 4.
|
||||
expect(byteData.getUint16(vTableLoc, Endian.little), 4);
|
||||
// Next 2 bytes are the size of the object in bytes (including the vtable
|
||||
// pointer), which should be 4.
|
||||
expect(byteData.getUint16(vTableLoc + 2, Endian.little), 4);
|
||||
}
|
||||
|
||||
void test_low() {
|
||||
Builder builder = new Builder(initialSize: 0);
|
||||
expect((builder..putUint8(1)).lowFinish(), [1]);
|
||||
expect((builder..putUint32(2)).lowFinish(), [2, 0, 0, 0, 0, 0, 0, 1]);
|
||||
expect((builder..putUint8(3)).lowFinish(),
|
||||
[0, 0, 0, 3, 2, 0, 0, 0, 0, 0, 0, 1]);
|
||||
expect((builder..putUint8(4)).lowFinish(),
|
||||
[0, 0, 4, 3, 2, 0, 0, 0, 0, 0, 0, 1]);
|
||||
expect((builder..putUint8(5)).lowFinish(),
|
||||
[0, 5, 4, 3, 2, 0, 0, 0, 0, 0, 0, 1]);
|
||||
expect((builder..putUint32(6)).lowFinish(),
|
||||
[6, 0, 0, 0, 0, 5, 4, 3, 2, 0, 0, 0, 0, 0, 0, 1]);
|
||||
}
|
||||
|
||||
void test_table_default() {
|
||||
List<int> byteList;
|
||||
{
|
||||
Builder builder = new Builder(initialSize: 0);
|
||||
builder.startTable();
|
||||
builder.addInt32(0, 10, 10);
|
||||
builder.addInt32(1, 20, 10);
|
||||
int offset = builder.endTable();
|
||||
byteList = builder.finish(offset);
|
||||
}
|
||||
// read and verify
|
||||
BufferContext buffer = new BufferContext.fromBytes(byteList);
|
||||
int objectOffset = buffer.derefObject(0);
|
||||
// was not written, so uses the new default value
|
||||
expect(
|
||||
const Int32Reader()
|
||||
.vTableGet(buffer, objectOffset, indexToField(0), 15),
|
||||
15);
|
||||
// has the written value
|
||||
expect(
|
||||
const Int32Reader()
|
||||
.vTableGet(buffer, objectOffset, indexToField(1), 15),
|
||||
20);
|
||||
}
|
||||
|
||||
void test_table_format() {
|
||||
Uint8List byteList;
|
||||
{
|
||||
Builder builder = new Builder(initialSize: 0);
|
||||
builder.startTable();
|
||||
builder.addInt32(0, 10);
|
||||
builder.addInt32(1, 20);
|
||||
builder.addInt32(2, 30);
|
||||
byteList = builder.finish(builder.endTable());
|
||||
}
|
||||
// Convert byteList to a ByteData so that we can read data from it.
|
||||
ByteData byteData = byteList.buffer.asByteData(byteList.offsetInBytes);
|
||||
// First 4 bytes are an offset to the table data.
|
||||
int tableDataLoc = byteData.getUint32(0, Endian.little);
|
||||
// First 4 bytes of the table data are a backwards offset to the vtable.
|
||||
int vTableLoc = tableDataLoc -
|
||||
byteData.getInt32(tableDataLoc, Endian.little);
|
||||
// First 2 bytes of the vtable are the size of the vtable in bytes, which
|
||||
// should be 10.
|
||||
expect(byteData.getUint16(vTableLoc, Endian.little), 10);
|
||||
// Next 2 bytes are the size of the object in bytes (including the vtable
|
||||
// pointer), which should be 16.
|
||||
expect(byteData.getUint16(vTableLoc + 2, Endian.little), 16);
|
||||
// Remaining 6 bytes are the offsets within the object where the ints are
|
||||
// located.
|
||||
for (int i = 0; i < 3; i++) {
|
||||
int offset =
|
||||
byteData.getUint16(vTableLoc + 4 + 2 * i, Endian.little);
|
||||
expect(byteData.getInt32(tableDataLoc + offset, Endian.little),
|
||||
10 + 10 * i);
|
||||
}
|
||||
}
|
||||
|
||||
void test_table_string() {
|
||||
String latinString = 'test';
|
||||
String unicodeString = 'Проба пера';
|
||||
List<int> byteList;
|
||||
{
|
||||
Builder builder = new Builder(initialSize: 0);
|
||||
int latinStringOffset = builder.writeString(latinString);
|
||||
int unicodeStringOffset = builder.writeString(unicodeString);
|
||||
builder.startTable();
|
||||
builder.addOffset(0, latinStringOffset);
|
||||
builder.addOffset(1, unicodeStringOffset);
|
||||
int offset = builder.endTable();
|
||||
byteList = builder.finish(offset);
|
||||
}
|
||||
// read and verify
|
||||
BufferContext buf = new BufferContext.fromBytes(byteList);
|
||||
int objectOffset = buf.derefObject(0);
|
||||
expect(const StringReader().vTableGet(buf, objectOffset, indexToField(0)),
|
||||
latinString);
|
||||
expect(const StringReader().vTableGet(buf, objectOffset, indexToField(1)),
|
||||
unicodeString);
|
||||
}
|
||||
|
||||
void test_table_types() {
|
||||
List<int> byteList;
|
||||
{
|
||||
Builder builder = new Builder(initialSize: 0);
|
||||
int stringOffset = builder.writeString('12345');
|
||||
builder.startTable();
|
||||
builder.addBool(0, true);
|
||||
builder.addInt8(1, 10);
|
||||
builder.addInt32(2, 20);
|
||||
builder.addOffset(3, stringOffset);
|
||||
builder.addInt32(4, 40);
|
||||
builder.addUint32(5, 0x9ABCDEF0);
|
||||
builder.addUint8(6, 0x9A);
|
||||
int offset = builder.endTable();
|
||||
byteList = builder.finish(offset);
|
||||
}
|
||||
// read and verify
|
||||
BufferContext buf = new BufferContext.fromBytes(byteList);
|
||||
int objectOffset = buf.derefObject(0);
|
||||
expect(
|
||||
const BoolReader().vTableGet(buf, objectOffset, indexToField(0)), true);
|
||||
expect(
|
||||
const Int8Reader().vTableGet(buf, objectOffset, indexToField(1)), 10);
|
||||
expect(
|
||||
const Int32Reader().vTableGet(buf, objectOffset, indexToField(2)), 20);
|
||||
expect(const StringReader().vTableGet(buf, objectOffset, indexToField(3)),
|
||||
'12345');
|
||||
expect(
|
||||
const Int32Reader().vTableGet(buf, objectOffset, indexToField(4)), 40);
|
||||
expect(const Uint32Reader().vTableGet(buf, objectOffset, indexToField(5)),
|
||||
0x9ABCDEF0);
|
||||
expect(const Uint8Reader().vTableGet(buf, objectOffset, indexToField(6)),
|
||||
0x9A);
|
||||
}
|
||||
|
||||
void test_writeList_of_Uint32() {
|
||||
List<int> values = <int>[10, 100, 12345, 0x9abcdef0];
|
||||
// write
|
||||
List<int> byteList;
|
||||
{
|
||||
Builder builder = new Builder(initialSize: 0);
|
||||
int offset = builder.writeListUint32(values);
|
||||
byteList = builder.finish(offset);
|
||||
}
|
||||
// read and verify
|
||||
BufferContext buf = new BufferContext.fromBytes(byteList);
|
||||
List<int> items = const Uint32ListReader().read(buf, 0);
|
||||
expect(items, hasLength(4));
|
||||
expect(items, orderedEquals(values));
|
||||
}
|
||||
|
||||
void test_writeList_ofBool() {
|
||||
void verifyListBooleans(int len, List<int> trueBits) {
|
||||
// write
|
||||
List<int> byteList;
|
||||
{
|
||||
Builder builder = new Builder(initialSize: 0);
|
||||
List<bool> values = new List<bool>.filled(len, false);
|
||||
for (int bit in trueBits) {
|
||||
values[bit] = true;
|
||||
}
|
||||
int offset = builder.writeListBool(values);
|
||||
byteList = builder.finish(offset);
|
||||
}
|
||||
// read and verify
|
||||
BufferContext buf = new BufferContext.fromBytes(byteList);
|
||||
List<bool> items = const BoolListReader().read(buf, 0);
|
||||
expect(items, hasLength(len));
|
||||
for (int i = 0; i < items.length; i++) {
|
||||
expect(items[i], trueBits.contains(i), reason: 'bit $i of $len');
|
||||
}
|
||||
}
|
||||
|
||||
verifyListBooleans(0, <int>[]);
|
||||
verifyListBooleans(1, <int>[]);
|
||||
verifyListBooleans(1, <int>[0]);
|
||||
verifyListBooleans(31, <int>[0, 1]);
|
||||
verifyListBooleans(31, <int>[1, 2, 24, 25, 30]);
|
||||
verifyListBooleans(31, <int>[0, 30]);
|
||||
verifyListBooleans(32, <int>[1, 2, 24, 25, 31]);
|
||||
verifyListBooleans(33, <int>[1, 2, 24, 25, 32]);
|
||||
verifyListBooleans(33, <int>[1, 2, 24, 25, 31, 32]);
|
||||
verifyListBooleans(63, <int>[]);
|
||||
verifyListBooleans(63, <int>[0, 1, 2, 61, 62]);
|
||||
verifyListBooleans(63, new List<int>.generate(63, (i) => i));
|
||||
verifyListBooleans(64, <int>[]);
|
||||
verifyListBooleans(64, <int>[0, 1, 2, 61, 62, 63]);
|
||||
verifyListBooleans(64, <int>[1, 2, 62]);
|
||||
verifyListBooleans(64, <int>[0, 1, 2, 63]);
|
||||
verifyListBooleans(64, new List<int>.generate(64, (i) => i));
|
||||
verifyListBooleans(100, <int>[0, 3, 30, 60, 90, 99]);
|
||||
}
|
||||
|
||||
void test_writeList_ofInt32() {
|
||||
List<int> byteList;
|
||||
{
|
||||
Builder builder = new Builder(initialSize: 0);
|
||||
int offset = builder.writeListInt32(<int>[1, 2, 3, 4, 5]);
|
||||
byteList = builder.finish(offset);
|
||||
}
|
||||
// read and verify
|
||||
BufferContext buf = new BufferContext.fromBytes(byteList);
|
||||
List<int> items = const ListReader<int>(const Int32Reader()).read(buf, 0);
|
||||
expect(items, hasLength(5));
|
||||
expect(items, orderedEquals(<int>[1, 2, 3, 4, 5]));
|
||||
}
|
||||
|
||||
void test_writeList_ofFloat64() {
|
||||
List<double> values = <double>[-1.234567, 3.4E+9, -5.6E-13, 7.8, 12.13];
|
||||
// write
|
||||
List<int> byteList;
|
||||
{
|
||||
Builder builder = new Builder(initialSize: 0);
|
||||
int offset = builder.writeListFloat64(values);
|
||||
byteList = builder.finish(offset);
|
||||
}
|
||||
|
||||
// read and verify
|
||||
BufferContext buf = new BufferContext.fromBytes(byteList);
|
||||
List<double> items = const Float64ListReader().read(buf, 0);
|
||||
|
||||
expect(items, hasLength(values.length));
|
||||
for (int i = 0; i < values.length; i++) {
|
||||
expect(values[i], closeTo(items[i], .001));
|
||||
}
|
||||
}
|
||||
|
||||
void test_writeList_ofFloat32() {
|
||||
List<double> values = [1.0, 2.23, -3.213, 7.8, 12.13];
|
||||
// write
|
||||
List<int> byteList;
|
||||
{
|
||||
Builder builder = new Builder(initialSize: 0);
|
||||
int offset = builder.writeListFloat32(values);
|
||||
byteList = builder.finish(offset);
|
||||
}
|
||||
// read and verify
|
||||
BufferContext buf = new BufferContext.fromBytes(byteList);
|
||||
List<double> items = const Float32ListReader().read(buf, 0);
|
||||
expect(items, hasLength(5));
|
||||
for (int i = 0; i < values.length; i++) {
|
||||
expect(values[i], closeTo(items[i], .001));
|
||||
}
|
||||
}
|
||||
|
||||
void test_writeList_ofObjects() {
|
||||
List<int> byteList;
|
||||
{
|
||||
Builder builder = new Builder(initialSize: 0);
|
||||
// write the object #1
|
||||
int object1;
|
||||
{
|
||||
builder.startTable();
|
||||
builder.addInt32(0, 10);
|
||||
builder.addInt32(1, 20);
|
||||
object1 = builder.endTable();
|
||||
}
|
||||
// write the object #1
|
||||
int object2;
|
||||
{
|
||||
builder.startTable();
|
||||
builder.addInt32(0, 100);
|
||||
builder.addInt32(1, 200);
|
||||
object2 = builder.endTable();
|
||||
}
|
||||
// write the list
|
||||
int offset = builder.writeList([object1, object2]);
|
||||
byteList = builder.finish(offset);
|
||||
}
|
||||
// read and verify
|
||||
BufferContext buf = new BufferContext.fromBytes(byteList);
|
||||
List<TestPointImpl> items =
|
||||
const ListReader<TestPointImpl>(const TestPointReader()).read(buf, 0);
|
||||
expect(items, hasLength(2));
|
||||
expect(items[0].x, 10);
|
||||
expect(items[0].y, 20);
|
||||
expect(items[1].x, 100);
|
||||
expect(items[1].y, 200);
|
||||
}
|
||||
|
||||
void test_writeList_ofStrings_asRoot() {
|
||||
List<int> byteList;
|
||||
{
|
||||
Builder builder = new Builder(initialSize: 0);
|
||||
int str1 = builder.writeString('12345');
|
||||
int str2 = builder.writeString('ABC');
|
||||
int offset = builder.writeList([str1, str2]);
|
||||
byteList = builder.finish(offset);
|
||||
}
|
||||
// read and verify
|
||||
BufferContext buf = new BufferContext.fromBytes(byteList);
|
||||
List<String> items =
|
||||
const ListReader<String>(const StringReader()).read(buf, 0);
|
||||
expect(items, hasLength(2));
|
||||
expect(items, contains('12345'));
|
||||
expect(items, contains('ABC'));
|
||||
}
|
||||
|
||||
void test_writeList_ofStrings_inObject() {
|
||||
List<int> byteList;
|
||||
{
|
||||
Builder builder = new Builder(initialSize: 0);
|
||||
int listOffset = builder.writeList(
|
||||
[builder.writeString('12345'), builder.writeString('ABC')]);
|
||||
builder.startTable();
|
||||
builder.addOffset(0, listOffset);
|
||||
int offset = builder.endTable();
|
||||
byteList = builder.finish(offset);
|
||||
}
|
||||
// read and verify
|
||||
BufferContext buf = new BufferContext.fromBytes(byteList);
|
||||
StringListWrapperImpl reader = new StringListWrapperReader().read(buf, 0);
|
||||
List<String> items = reader.items;
|
||||
expect(items, hasLength(2));
|
||||
expect(items, contains('12345'));
|
||||
expect(items, contains('ABC'));
|
||||
}
|
||||
|
||||
void test_writeList_ofUint32() {
|
||||
List<int> byteList;
|
||||
{
|
||||
Builder builder = new Builder(initialSize: 0);
|
||||
int offset = builder.writeListUint32(<int>[1, 2, 0x9ABCDEF0]);
|
||||
byteList = builder.finish(offset);
|
||||
}
|
||||
// read and verify
|
||||
BufferContext buf = new BufferContext.fromBytes(byteList);
|
||||
List<int> items = const Uint32ListReader().read(buf, 0);
|
||||
expect(items, hasLength(3));
|
||||
expect(items, orderedEquals(<int>[1, 2, 0x9ABCDEF0]));
|
||||
}
|
||||
|
||||
void test_writeList_ofUint16() {
|
||||
List<int> byteList;
|
||||
{
|
||||
Builder builder = new Builder(initialSize: 0);
|
||||
int offset = builder.writeListUint16(<int>[1, 2, 60000]);
|
||||
byteList = builder.finish(offset);
|
||||
}
|
||||
// read and verify
|
||||
BufferContext buf = new BufferContext.fromBytes(byteList);
|
||||
List<int> items = const Uint16ListReader().read(buf, 0);
|
||||
expect(items, hasLength(3));
|
||||
expect(items, orderedEquals(<int>[1, 2, 60000]));
|
||||
}
|
||||
|
||||
void test_writeList_ofUint8() {
|
||||
List<int> byteList;
|
||||
{
|
||||
Builder builder = new Builder(initialSize: 0);
|
||||
int offset = builder.writeListUint8(<int>[1, 2, 3, 4, 0x9A]);
|
||||
byteList = builder.finish(offset);
|
||||
}
|
||||
// read and verify
|
||||
BufferContext buf = new BufferContext.fromBytes(byteList);
|
||||
List<int> items = const Uint8ListReader().read(buf, 0);
|
||||
expect(items, hasLength(5));
|
||||
expect(items, orderedEquals(<int>[1, 2, 3, 4, 0x9A]));
|
||||
}
|
||||
}
|
||||
|
||||
class StringListWrapperImpl {
|
||||
final BufferContext bp;
|
||||
final int offset;
|
||||
|
||||
StringListWrapperImpl(this.bp, this.offset);
|
||||
|
||||
List<String> get items => const ListReader<String>(const StringReader())
|
||||
.vTableGet(bp, offset, indexToField(0));
|
||||
}
|
||||
|
||||
class StringListWrapperReader extends TableReader<StringListWrapperImpl> {
|
||||
const StringListWrapperReader();
|
||||
|
||||
@override
|
||||
StringListWrapperImpl createObject(BufferContext object, int offset) {
|
||||
return new StringListWrapperImpl(object, offset);
|
||||
}
|
||||
}
|
||||
|
||||
class TestPointImpl {
|
||||
final BufferContext bp;
|
||||
final int offset;
|
||||
|
||||
TestPointImpl(this.bp, this.offset);
|
||||
|
||||
int get x => const Int32Reader().vTableGet(bp, offset, indexToField(0), 0);
|
||||
|
||||
int get y => const Int32Reader().vTableGet(bp, offset, indexToField(1), 0);
|
||||
}
|
||||
|
||||
class TestPointReader extends TableReader<TestPointImpl> {
|
||||
const TestPointReader();
|
||||
|
||||
@override
|
||||
TestPointImpl createObject(BufferContext object, int offset) {
|
||||
return new TestPointImpl(object, offset);
|
||||
}
|
||||
}
|
||||
62
dart/test/monster_test_my_game.example2_generated.dart
Normal file
62
dart/test/monster_test_my_game.example2_generated.dart
Normal file
@@ -0,0 +1,62 @@
|
||||
// automatically generated by the FlatBuffers compiler, do not modify
|
||||
// ignore_for_file: unused_import, unused_field, unused_local_variable
|
||||
|
||||
library my_game.example2;
|
||||
|
||||
import 'dart:typed_data' show Uint8List;
|
||||
import 'package:flat_buffers/flat_buffers.dart' as fb;
|
||||
|
||||
import 'include_test1_my_game.example2_generated.dart';
|
||||
import 'include_test2_my_game.example2_generated.dart';
|
||||
import './monster_test_my_game.example_generated.dart' as my_game_example;
|
||||
import './monster_test_my_game_generated.dart' as my_game;
|
||||
|
||||
class Monster {
|
||||
Monster._(this._bc, this._bcOffset);
|
||||
factory Monster(List<int> bytes) {
|
||||
fb.BufferContext rootRef = new fb.BufferContext.fromBytes(bytes);
|
||||
return reader.read(rootRef, 0);
|
||||
}
|
||||
|
||||
static const fb.Reader<Monster> reader = const _MonsterReader();
|
||||
|
||||
final fb.BufferContext _bc;
|
||||
final int _bcOffset;
|
||||
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'Monster{}';
|
||||
}
|
||||
}
|
||||
|
||||
class _MonsterReader extends fb.TableReader<Monster> {
|
||||
const _MonsterReader();
|
||||
|
||||
@override
|
||||
Monster createObject(fb.BufferContext bc, int offset) =>
|
||||
new Monster._(bc, offset);
|
||||
}
|
||||
|
||||
class MonsterObjectBuilder extends fb.ObjectBuilder {
|
||||
|
||||
MonsterObjectBuilder();
|
||||
|
||||
/// Finish building, and store into the [fbBuilder].
|
||||
@override
|
||||
int finish(
|
||||
fb.Builder fbBuilder) {
|
||||
assert(fbBuilder != null);
|
||||
|
||||
fbBuilder.startTable();
|
||||
return fbBuilder.endTable();
|
||||
}
|
||||
|
||||
/// Convenience method to serialize to byte list.
|
||||
@override
|
||||
Uint8List toBytes([String fileIdentifier]) {
|
||||
fb.Builder fbBuilder = new fb.Builder();
|
||||
int offset = finish(fbBuilder);
|
||||
return fbBuilder.finish(offset, fileIdentifier);
|
||||
}
|
||||
}
|
||||
1334
dart/test/monster_test_my_game.example_generated.dart
Normal file
1334
dart/test/monster_test_my_game.example_generated.dart
Normal file
File diff suppressed because it is too large
Load Diff
62
dart/test/monster_test_my_game_generated.dart
Normal file
62
dart/test/monster_test_my_game_generated.dart
Normal file
@@ -0,0 +1,62 @@
|
||||
// automatically generated by the FlatBuffers compiler, do not modify
|
||||
// ignore_for_file: unused_import, unused_field, unused_local_variable
|
||||
|
||||
library my_game;
|
||||
|
||||
import 'dart:typed_data' show Uint8List;
|
||||
import 'package:flat_buffers/flat_buffers.dart' as fb;
|
||||
|
||||
import 'include_test1_my_game_generated.dart';
|
||||
import 'include_test2_my_game_generated.dart';
|
||||
import './monster_test_my_game.example_generated.dart' as my_game_example;
|
||||
import './monster_test_my_game.example2_generated.dart' as my_game_example2;
|
||||
|
||||
class InParentNamespace {
|
||||
InParentNamespace._(this._bc, this._bcOffset);
|
||||
factory InParentNamespace(List<int> bytes) {
|
||||
fb.BufferContext rootRef = new fb.BufferContext.fromBytes(bytes);
|
||||
return reader.read(rootRef, 0);
|
||||
}
|
||||
|
||||
static const fb.Reader<InParentNamespace> reader = const _InParentNamespaceReader();
|
||||
|
||||
final fb.BufferContext _bc;
|
||||
final int _bcOffset;
|
||||
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'InParentNamespace{}';
|
||||
}
|
||||
}
|
||||
|
||||
class _InParentNamespaceReader extends fb.TableReader<InParentNamespace> {
|
||||
const _InParentNamespaceReader();
|
||||
|
||||
@override
|
||||
InParentNamespace createObject(fb.BufferContext bc, int offset) =>
|
||||
new InParentNamespace._(bc, offset);
|
||||
}
|
||||
|
||||
class InParentNamespaceObjectBuilder extends fb.ObjectBuilder {
|
||||
|
||||
InParentNamespaceObjectBuilder();
|
||||
|
||||
/// Finish building, and store into the [fbBuilder].
|
||||
@override
|
||||
int finish(
|
||||
fb.Builder fbBuilder) {
|
||||
assert(fbBuilder != null);
|
||||
|
||||
fbBuilder.startTable();
|
||||
return fbBuilder.endTable();
|
||||
}
|
||||
|
||||
/// Convenience method to serialize to byte list.
|
||||
@override
|
||||
Uint8List toBytes([String fileIdentifier]) {
|
||||
fb.Builder fbBuilder = new fb.Builder();
|
||||
int offset = finish(fbBuilder);
|
||||
return fbBuilder.finish(offset, fileIdentifier);
|
||||
}
|
||||
}
|
||||
@@ -8,9 +8,9 @@ you to build project/make files for any platform. For details on `cmake`, see
|
||||
<https://www.cmake.org>. In brief, depending on your platform, use one of
|
||||
e.g.:
|
||||
|
||||
cmake -G "Unix Makefiles"
|
||||
cmake -G "Visual Studio 10"
|
||||
cmake -G "Xcode"
|
||||
cmake -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Release
|
||||
cmake -G "Visual Studio 10" -DCMAKE_BUILD_TYPE=Release
|
||||
cmake -G "Xcode" -DCMAKE_BUILD_TYPE=Release
|
||||
|
||||
Then, build as normal for your platform. This should result in a `flatc`
|
||||
executable, essential for the next steps.
|
||||
@@ -41,7 +41,7 @@ running the `android_sample.sh` script. Optionally, you may go to the
|
||||
`flatbuffers/samples/android` folder and build the sample with the
|
||||
`build_apk.sh` script or `ndk_build` / `adb` etc.
|
||||
|
||||
## Using FlatBuffers in your own projects.
|
||||
## Using FlatBuffers in your own projects
|
||||
|
||||
For C++, there is usually no runtime to compile, as the code consists of a
|
||||
single header, `include/flatbuffers/flatbuffers.h`. You should add the
|
||||
@@ -55,6 +55,31 @@ To see how to include FlatBuffers in any of our supported languages, please
|
||||
view the [Tutorial](@ref flatbuffers_guide_tutorial) and select your appropriate
|
||||
language using the radio buttons.
|
||||
|
||||
### Using in CMake-based projects
|
||||
If you want to use FlatBuffers in a project which already uses CMake, then a more
|
||||
robust and flexible approach is to build FlatBuffers as part of that project directly.
|
||||
This is done by making the FlatBuffers source code available to the main build
|
||||
and adding it using CMake's `add_subdirectory()` command. This has the
|
||||
significant advantage that the same compiler and linker settings are used
|
||||
between FlatBuffers and the rest of your project, so issues associated with using
|
||||
incompatible libraries (eg debug/release), etc. are avoided. This is
|
||||
particularly useful on Windows.
|
||||
|
||||
Suppose you put FlatBuffers source code in directory `${FLATBUFFERS_SRC_DIR}`.
|
||||
To build it as part of your project, add following code to your `CMakeLists.txt` file:
|
||||
```cmake
|
||||
# Add FlatBuffers directly to our build. This defines the `flatbuffers` target.
|
||||
add_subdirectory(${FLATBUFFERS_SRC_DIR}
|
||||
${CMAKE_CURRENT_BINARY_DIR}/flatbuffers-build
|
||||
EXCLUDE_FROM_ALL)
|
||||
|
||||
# Now simply link against flatbuffers as needed to your already declared target.
|
||||
# The flatbuffers target carry header search path automatically if CMake > 2.8.11.
|
||||
target_link_libraries(own_project_target PRIVATE flatbuffers)
|
||||
```
|
||||
When build your project the `flatbuffers` library will be compiled and linked
|
||||
to a target as part of your project.
|
||||
|
||||
#### For Google Play apps
|
||||
|
||||
For applications on Google Play that integrate this library, usage is tracked.
|
||||
|
||||
@@ -31,10 +31,20 @@ For any schema input files, one or more generators can be specified:
|
||||
|
||||
- `--js`, `-s`: Generate JavaScript code.
|
||||
|
||||
- `--ts`: Generate TypeScript code.
|
||||
|
||||
- `--php`: Generate PHP code.
|
||||
|
||||
- `--grpc`: Generate RPC stub code for GRPC.
|
||||
|
||||
- `--dart`: Generate Dart code.
|
||||
|
||||
- `--lua`: Generate Lua code.
|
||||
|
||||
- `--lobster`: Generate Lobster code.
|
||||
|
||||
- `--rust`, `-r` : Generate Rust code.
|
||||
|
||||
For any data input files:
|
||||
|
||||
- `--binary`, `-b` : If data is contained in this file, generate a
|
||||
@@ -86,6 +96,8 @@ Additional options:
|
||||
at the cost of efficiency (object allocation). Recommended only to be used
|
||||
if other options are insufficient.
|
||||
|
||||
- `--gen-compare` : Generate operator== for object-based API types.
|
||||
|
||||
- `--gen-onefile` : Generate single output file (useful for C#)
|
||||
|
||||
- `--gen-all`: Generate not just code for the current schema files, but
|
||||
@@ -99,6 +111,10 @@ Additional options:
|
||||
instead of Node.js style exporting. Needed for compatibility with the
|
||||
Google closure compiler (useful for JS).
|
||||
|
||||
- `--es6-js-export` : Generates ECMAScript v6 style export definitions
|
||||
instead of Node.js style exporting. Useful when integrating flatbuffers
|
||||
with modern Javascript projects.
|
||||
|
||||
- `--raw-binary` : Allow binaries without a file_indentifier to be read.
|
||||
This may crash flatc given a mismatched schema.
|
||||
|
||||
@@ -128,5 +144,12 @@ Additional options:
|
||||
- `--reflect-types` : Add minimal type reflection to code generation.
|
||||
- `--reflect-names` : Add minimal type/name reflection.
|
||||
|
||||
- `--root-type T` : Select or override the default root_type.
|
||||
|
||||
- `--force-defaults` : Emit default values in binary output from JSON.
|
||||
|
||||
- `--force-empty` : When serializing from object API representation, force
|
||||
strings and vectors to empty rather than null.
|
||||
|
||||
NOTE: short-form options for generators are deprecated, use the long form
|
||||
whenever possible.
|
||||
|
||||
@@ -59,15 +59,18 @@ a `char *` array, which you pass to `GetMonster()`.
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
|
||||
#include "flatbuffers/flatbuffers.h"
|
||||
#include "monster_test_generate.h"
|
||||
#include <cstdio> // For printing and file access.
|
||||
#include <iostream> // C++ header file for printing
|
||||
#include <fstream> // C++ header file for file access
|
||||
|
||||
FILE* file = fopen("monsterdata_test.mon", "rb");
|
||||
fseek(file, 0L, SEEK_END);
|
||||
int length = ftell(file);
|
||||
fseek(file, 0L, SEEK_SET);
|
||||
|
||||
std::ifstream infile;
|
||||
infile.open("monsterdata_test.mon", std::ios::binary | std::ios::in);
|
||||
infile.seekg(0,std::ios::end);
|
||||
int length = infile.tellg();
|
||||
infile.seekg(0,std::ios::beg);
|
||||
char *data = new char[length];
|
||||
fread(data, sizeof(char), length, file);
|
||||
fclose(file);
|
||||
infile.read(data, length);
|
||||
infile.close();
|
||||
|
||||
auto monster = GetMonster(data);
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
@@ -78,9 +81,9 @@ If you look in your generated header, you'll see it has
|
||||
convenient accessors for all fields, e.g. `hp()`, `mana()`, etc:
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
|
||||
printf("%d\n", monster->hp()); // `80`
|
||||
printf("%d\n", monster->mana()); // default value of `150`
|
||||
printf("%s\n", monster->name()->c_str()); // "MyMonster"
|
||||
std::cout << "hp : " << monster->hp() << std::endl; // `80`
|
||||
std::cout << "mana : " << monster->mana() << std::endl; // default value of `150`
|
||||
std::cout << "name : " << monster->name()->c_str() << std::endl; // "MyMonster"
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
*Note: That we never stored a `mana` value, so it will return the default.*
|
||||
|
||||
108
docs/source/DartUsage.md
Normal file
108
docs/source/DartUsage.md
Normal file
@@ -0,0 +1,108 @@
|
||||
Use in Dart {#flatbuffers_guide_use_dart}
|
||||
===========
|
||||
|
||||
## Before you get started
|
||||
|
||||
Before diving into the FlatBuffers usage in Dart, it should be noted that
|
||||
the [Tutorial](@ref flatbuffers_guide_tutorial) page has a complete guide
|
||||
to general FlatBuffers usage in all of the supported languages (including Dart).
|
||||
This page is designed to cover the nuances of FlatBuffers usage, specific to
|
||||
Dart.
|
||||
|
||||
You should also have read the [Building](@ref flatbuffers_guide_building)
|
||||
documentation to build `flatc` and should be familiar with
|
||||
[Using the schema compiler](@ref flatbuffers_guide_using_schema_compiler) and
|
||||
[Writing a schema](@ref flatbuffers_guide_writing_schema).
|
||||
|
||||
## FlatBuffers Dart library code location
|
||||
|
||||
The code for the FlatBuffers Go library can be found at
|
||||
`flatbuffers/dart`. You can browse the library code on the [FlatBuffers
|
||||
GitHub page](https://github.com/google/flatbuffers/tree/master/dart).
|
||||
|
||||
## Testing the FlatBuffers Dart library
|
||||
|
||||
The code to test the Dart library can be found at `flatbuffers/tests`.
|
||||
The test code itself is located in [dart_test.dart](https://github.com/google/
|
||||
flatbuffers/blob/master/tests/dart_test.dart).
|
||||
|
||||
To run the tests, use the [DartTest.sh](https://github.com/google/flatbuffers/
|
||||
blob/master/tests/DartTest.sh) shell script.
|
||||
|
||||
*Note: The shell script requires the [Dart SDK](https://www.dartlang.org/tools/sdk)
|
||||
to be installed.*
|
||||
|
||||
## Using the FlatBuffers Dart library
|
||||
|
||||
*Note: See [Tutorial](@ref flatbuffers_guide_tutorial) for a more in-depth
|
||||
example of how to use FlatBuffers in Dart.*
|
||||
|
||||
FlatBuffers supports reading and writing binary FlatBuffers in Dart.
|
||||
|
||||
To use FlatBuffers in your own code, first generate Dart classes from your
|
||||
schema with the `--dart` option to `flatc`. Then you can include both FlatBuffers
|
||||
and the generated code to read or write a FlatBuffer.
|
||||
|
||||
For example, here is how you would read a FlatBuffer binary file in Dart: First,
|
||||
include the library and generated code. Then read a FlatBuffer binary file into
|
||||
a `List<int>`, which you pass to the factory constructor for `Monster`:
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.dart}
|
||||
import 'dart:io' as io;
|
||||
|
||||
import 'package:flat_buffers/flat_buffers.dart' as fb;
|
||||
import './monster_my_game.sample_generated.dart' as myGame;
|
||||
|
||||
List<int> data = await new io.File('monster.dat').readAsBytes();
|
||||
var monster = new myGame.Monster(data);
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Now you can access values like this:
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.dart}
|
||||
var hp = monster.hp;
|
||||
var pos = monster.pos;
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
## Differences from the Dart SDK Front End flat_buffers
|
||||
|
||||
The work in this repository is signfiicantly based on the implementation used
|
||||
internally by the Dart SDK in the front end/analyzer package. Several
|
||||
significant changes have been made.
|
||||
|
||||
1. Support for packed boolean lists has been removed. This is not standard
|
||||
in other implementations and is not compatible with them. Do note that,
|
||||
like in the JavaScript implementation, __null values in boolean lists
|
||||
will be treated as false__. It is also still entirely possible to pack data
|
||||
in a single scalar field, but that would have to be done on the application
|
||||
side.
|
||||
2. The SDK implementation supports enums with regular Dart enums, which
|
||||
works if enums are always indexed at 1; however, FlatBuffers does not
|
||||
require that. This implementation uses specialized enum-like classes to
|
||||
ensure proper mapping from FlatBuffers to Dart and other platforms.
|
||||
3. The SDK implementation does not appear to support FlatBuffer structs or
|
||||
vectors of structs - it treated everything as a built-in scalar or a table.
|
||||
This implementation treats structs in a way that is compatible with other
|
||||
non-Dart implementations, and properly handles vectors of structs. Many of
|
||||
the methods prefixed with 'low' have been prepurposed to support this.
|
||||
4. The SDK implementation treats int64 and uint64 as float64s. This
|
||||
implementation does not. This may cause problems with JavaScript
|
||||
compatibility - however, it should be possible to use the JavaScript
|
||||
implementation, or to do a customized implementation that treats all 64 bit
|
||||
numbers as floats. Supporting the Dart VM and Flutter was a more important
|
||||
goal of this implementation. Support for 16 bit integers was also added.
|
||||
5. The code generation in this offers an "ObjectBuilder", which generates code
|
||||
very similar to the SDK classes that consume FlatBuffers, as well as Builder
|
||||
classes, which produces code which more closely resembles the builders in
|
||||
other languages. The ObjectBuilder classes are easier to use, at the cost of
|
||||
additional references allocated.
|
||||
|
||||
## Text Parsing
|
||||
|
||||
There currently is no support for parsing text (Schema's and JSON) directly
|
||||
from Dart, though you could use the C++ parser through Dart Native Extensions.
|
||||
Please see the C++ documentation for more on text parsing (note that this is
|
||||
not currently an option in Flutter - follow [this issue](https://github.com/flutter/flutter/issues/7053)
|
||||
for the latest).
|
||||
|
||||
<br>
|
||||
@@ -4,7 +4,7 @@ FlatBuffers {#flatbuffers_index}
|
||||
# Overview {#flatbuffers_overview}
|
||||
|
||||
[FlatBuffers](@ref flatbuffers_overview) is an efficient cross platform
|
||||
serialization library for C++, C#, C, Go, Java, JavaScript, TypeScript, PHP, and Python.
|
||||
serialization library for C++, C#, C, Go, Java, JavaScript, Lobster, Lua, TypeScript, PHP, Python, and Rust.
|
||||
It was originally created at Google for game development and other
|
||||
performance-critical applications.
|
||||
|
||||
@@ -134,12 +134,18 @@ sections provide a more in-depth usage guide.
|
||||
in your own programs.
|
||||
- How to [use the generated Go code](@ref flatbuffers_guide_use_go) in your
|
||||
own programs.
|
||||
- How to [use the generated Lua code](@ref flatbuffers_guide_use_lua) in your
|
||||
own programs.
|
||||
- How to [use the generated JavaScript code](@ref flatbuffers_guide_use_javascript) in your
|
||||
own programs.
|
||||
- How to [use the generated TypeScript code](@ref flatbuffers_guide_use_typescript) in your
|
||||
own programs.
|
||||
- How to [use FlatBuffers in C with `flatcc`](@ref flatbuffers_guide_use_c) in your
|
||||
own programs.
|
||||
- How to [use the generated Lobster code](@ref flatbuffers_guide_use_lobster) in your
|
||||
own programs.
|
||||
- How to [use the generated Rust code](@ref flatbuffers_guide_use_rust) in your
|
||||
own programs.
|
||||
- [Support matrix](@ref flatbuffers_support) for platforms/languages/features.
|
||||
- Some [benchmarks](@ref flatbuffers_benchmarks) showing the advantage of
|
||||
using FlatBuffers.
|
||||
|
||||
@@ -10,7 +10,7 @@ include = `include` string\_constant `;`
|
||||
|
||||
namespace\_decl = `namespace` ident ( `.` ident )* `;`
|
||||
|
||||
attribute\_decl = `attribute` string\_constant `;`
|
||||
attribute\_decl = `attribute` ident | `"`ident`"` `;`
|
||||
|
||||
type\_decl = ( `table` | `struct` ) ident metadata `{` field\_decl+ `}`
|
||||
|
||||
|
||||
@@ -169,7 +169,7 @@ Unions share a lot with enums.
|
||||
Predeclare all data types since circular references between types are allowed
|
||||
(circular references between object are not, though).
|
||||
|
||||
MANUALLY_ALIGNED_STRUCT(4) Vec3 {
|
||||
FLATBUFFERS_MANUALLY_ALIGNED_STRUCT(4) Vec3 {
|
||||
private:
|
||||
float x_;
|
||||
float y_;
|
||||
@@ -183,7 +183,7 @@ Predeclare all data types since circular references between types are allowed
|
||||
float y() const { return flatbuffers::EndianScalar(y_); }
|
||||
float z() const { return flatbuffers::EndianScalar(z_); }
|
||||
};
|
||||
STRUCT_END(Vec3, 12);
|
||||
FLATBUFFERS_STRUCT_END(Vec3, 12);
|
||||
|
||||
These ugly macros do a couple of things: they turn off any padding the compiler
|
||||
might normally do, since we add padding manually (though none in this example),
|
||||
|
||||
85
docs/source/LobsterUsage.md
Normal file
85
docs/source/LobsterUsage.md
Normal file
@@ -0,0 +1,85 @@
|
||||
Use in Lobster {#flatbuffers_guide_use_lobster}
|
||||
==============
|
||||
|
||||
## Before you get started
|
||||
|
||||
Before diving into the FlatBuffers usage in Lobster, it should be noted that the
|
||||
[Tutorial](@ref flatbuffers_guide_tutorial) page has a complete guide to general
|
||||
FlatBuffers usage in all of the supported languages (including Lobster). This
|
||||
page is designed to cover the nuances of FlatBuffers usage, specific to
|
||||
Lobster.
|
||||
|
||||
You should also have read the [Building](@ref flatbuffers_guide_building)
|
||||
documentation to build `flatc` and should be familiar with
|
||||
[Using the schema compiler](@ref flatbuffers_guide_using_schema_compiler) and
|
||||
[Writing a schema](@ref flatbuffers_guide_writing_schema).
|
||||
|
||||
## FlatBuffers Lobster library code location
|
||||
|
||||
The code for the FlatBuffers Lobster library can be found at
|
||||
`flatbuffers/lobster`. You can browse the library code on the
|
||||
[FlatBuffers GitHub page](https://github.com/google/flatbuffers/tree/master/
|
||||
lobster).
|
||||
|
||||
## Testing the FlatBuffers Lobster library
|
||||
|
||||
The code to test the Lobster library can be found at `flatbuffers/tests`.
|
||||
The test code itself is located in [lobstertest.lobster](https://github.com/google/
|
||||
flatbuffers/blob/master/tests/lobstertest.lobster).
|
||||
|
||||
To run the tests, run `lobster lobstertest.lobster`. To obtain Lobster itself,
|
||||
go to the [Lobster homepage](http://strlen.com/lobster) or
|
||||
[github](https://github.com/aardappel/lobster) to learn how to build it for your
|
||||
platform.
|
||||
|
||||
## Using the FlatBuffers Lobster library
|
||||
|
||||
*Note: See [Tutorial](@ref flatbuffers_guide_tutorial) for a more in-depth
|
||||
example of how to use FlatBuffers in Lobster.*
|
||||
|
||||
There is support for both reading and writing FlatBuffers in Lobster.
|
||||
|
||||
To use FlatBuffers in your own code, first generate Lobster classes from your
|
||||
schema with the `--lobster` option to `flatc`. Then you can include both
|
||||
FlatBuffers and the generated code to read or write a FlatBuffer.
|
||||
|
||||
For example, here is how you would read a FlatBuffer binary file in Lobster:
|
||||
First, import the library and the generated code. Then read a FlatBuffer binary
|
||||
file into a string, which you pass to the `GetRootAsMonster` function:
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.lobster}
|
||||
include "monster_generated.lobster"
|
||||
|
||||
let fb = read_file("monsterdata_test.mon")
|
||||
assert fb
|
||||
let monster = MyGame_Example_GetRootAsMonster(fb)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Now you can access values like this:
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.lobster}
|
||||
let hp = monster.hp
|
||||
let pos = monster.pos
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
As you can see, even though `hp` and `pos` are functions that access FlatBuffer
|
||||
data in-place in the string buffer, they appear as field accesses.
|
||||
|
||||
## Speed
|
||||
|
||||
Using FlatBuffers in Lobster should be relatively fast, as the implementation
|
||||
makes use of native support for writing binary values, and access of vtables.
|
||||
Both generated code and the runtime library are therefore small and fast.
|
||||
|
||||
Actual speed will depend on wether you use Lobster as bytecode VM or compiled to
|
||||
C++.
|
||||
|
||||
## Text Parsing
|
||||
|
||||
Lobster has full support for parsing JSON into FlatBuffers, or generating
|
||||
JSON from FlatBuffers. See `samples/sample_test.lobster` for an example.
|
||||
|
||||
This uses the C++ parser and generator underneath, so should be both fast and
|
||||
conformant.
|
||||
|
||||
<br>
|
||||
81
docs/source/LuaUsage.md
Normal file
81
docs/source/LuaUsage.md
Normal file
@@ -0,0 +1,81 @@
|
||||
Use in Lua {#flatbuffers_guide_use_lua}
|
||||
=============
|
||||
|
||||
## Before you get started
|
||||
|
||||
Before diving into the FlatBuffers usage in Lua, it should be noted that the
|
||||
[Tutorial](@ref flatbuffers_guide_tutorial) page has a complete guide to general
|
||||
FlatBuffers usage in all of the supported languages (including Lua). This
|
||||
page is designed to cover the nuances of FlatBuffers usage, specific to
|
||||
Lua.
|
||||
|
||||
You should also have read the [Building](@ref flatbuffers_guide_building)
|
||||
documentation to build `flatc` and should be familiar with
|
||||
[Using the schema compiler](@ref flatbuffers_guide_using_schema_compiler) and
|
||||
[Writing a schema](@ref flatbuffers_guide_writing_schema).
|
||||
|
||||
## FlatBuffers Lua library code location
|
||||
|
||||
The code for the FlatBuffers Lua library can be found at
|
||||
`flatbuffers/lua`. You can browse the library code on the
|
||||
[FlatBuffers GitHub page](https://github.com/google/flatbuffers/tree/master/lua).
|
||||
|
||||
## Testing the FlatBuffers Lua library
|
||||
|
||||
The code to test the Lua library can be found at `flatbuffers/tests`.
|
||||
The test code itself is located in [luatest.lua](https://github.com/google/
|
||||
flatbuffers/blob/master/tests/luatest.lua).
|
||||
|
||||
To run the tests, use the [LuaTest.sh](https://github.com/google/flatbuffers/
|
||||
blob/master/tests/LuaTest.sh) shell script.
|
||||
|
||||
*Note: This script requires [Lua 5.3](https://www.lua.org/) to be
|
||||
installed.*
|
||||
|
||||
## Using the FlatBuffers Lua library
|
||||
|
||||
*Note: See [Tutorial](@ref flatbuffers_guide_tutorial) for a more in-depth
|
||||
example of how to use FlatBuffers in Lua.*
|
||||
|
||||
There is support for both reading and writing FlatBuffers in Lua.
|
||||
|
||||
To use FlatBuffers in your own code, first generate Lua classes from your
|
||||
schema with the `--lua` option to `flatc`. Then you can include both
|
||||
FlatBuffers and the generated code to read or write a FlatBuffer.
|
||||
|
||||
For example, here is how you would read a FlatBuffer binary file in Lua:
|
||||
First, require the module and the generated code. Then read a FlatBuffer binary
|
||||
file into a `string`, which you pass to the `GetRootAsMonster` function:
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.lua}
|
||||
-- require the library
|
||||
local flatbuffers = require("flatbuffers")
|
||||
|
||||
-- require the generated code
|
||||
local monster = require("MyGame.Sample.Monster")
|
||||
|
||||
-- read the flatbuffer from a file into a string
|
||||
local f = io.open('monster.dat', 'rb')
|
||||
local buf = f:read('*a')
|
||||
f:close()
|
||||
|
||||
-- parse the flatbuffer to get an instance to the root monster
|
||||
local monster1 = monster.GetRootAsMonster(buf, 0)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Now you can access values like this:
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.lua}
|
||||
-- use the : notation to access member data
|
||||
local hp = monster1:Hp()
|
||||
local pos = monster1:Pos()
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
||||
## Text Parsing
|
||||
|
||||
There currently is no support for parsing text (Schema's and JSON) directly
|
||||
from Lua, though you could use the C++ parser through SWIG or ctypes. Please
|
||||
see the C++ documentation for more on text parsing.
|
||||
|
||||
<br>
|
||||
166
docs/source/RustUsage.md
Normal file
166
docs/source/RustUsage.md
Normal file
@@ -0,0 +1,166 @@
|
||||
Use in Rust {#flatbuffers_guide_use_rust}
|
||||
==========
|
||||
|
||||
## Before you get started
|
||||
|
||||
Before diving into the FlatBuffers usage in Rust, it should be noted that
|
||||
the [Tutorial](@ref flatbuffers_guide_tutorial) page has a complete guide
|
||||
to general FlatBuffers usage in all of the supported languages (including Rust).
|
||||
This page is designed to cover the nuances of FlatBuffers usage, specific to
|
||||
Rust.
|
||||
|
||||
#### Prerequisites
|
||||
|
||||
This page assumes you have written a FlatBuffers schema and compiled it
|
||||
with the Schema Compiler. If you have not, please see
|
||||
[Using the schema compiler](@ref flatbuffers_guide_using_schema_compiler)
|
||||
and [Writing a schema](@ref flatbuffers_guide_writing_schema).
|
||||
|
||||
Assuming you wrote a schema, say `mygame.fbs` (though the extension doesn't
|
||||
matter), you've generated a Rust file called `mygame_generated.rs` using the
|
||||
compiler (e.g. `flatc --rust mygame.fbs`), you can now start using this in
|
||||
your program by including the file. As noted, this header relies on the crate
|
||||
`flatbuffers`, which should be in your include `Cargo.toml`.
|
||||
|
||||
## FlatBuffers Rust library code location
|
||||
|
||||
The code for the FlatBuffers Rust library can be found at
|
||||
`flatbuffers/rust`. You can browse the library code on the
|
||||
[FlatBuffers GitHub page](https://github.com/google/flatbuffers/tree/master/rust).
|
||||
|
||||
## Testing the FlatBuffers Rust library
|
||||
|
||||
The code to test the Rust library can be found at `flatbuffers/tests/rust_usage_test`.
|
||||
The test code itself is located in
|
||||
[integration_test.rs](https://github.com/google/flatbuffers/blob/master/tests/rust_usage_test/tests/integration_test.rs)
|
||||
|
||||
This test file requires `flatc` to be present. To review how to build the project,
|
||||
please read the [Building](@ref flatbuffers_guide_building) documenation.
|
||||
|
||||
To run the tests, execute `RustTest.sh` from the `flatbuffers/tests` directory.
|
||||
For example, on [Linux](https://en.wikipedia.org/wiki/Linux), you would simply
|
||||
run: `cd tests && ./RustTest.sh`.
|
||||
|
||||
*Note: The shell script requires [Rust](https://www.rust-lang.org) to
|
||||
be installed.*
|
||||
|
||||
## Using the FlatBuffers Rust library
|
||||
|
||||
*Note: See [Tutorial](@ref flatbuffers_guide_tutorial) for a more in-depth
|
||||
example of how to use FlatBuffers in Rust.*
|
||||
|
||||
FlatBuffers supports both reading and writing FlatBuffers in Rust.
|
||||
|
||||
To use FlatBuffers in your code, first generate the Rust modules from your
|
||||
schema with the `--rust` option to `flatc`. Then you can import both FlatBuffers
|
||||
and the generated code to read or write FlatBuffers.
|
||||
|
||||
For example, here is how you would read a FlatBuffer binary file in Rust:
|
||||
First, include the library and generated code. Then read the file into
|
||||
a `u8` vector, which you pass, as a byte slice, to `get_root_as_monster()`.
|
||||
|
||||
This full example program is available in the Rust test suite:
|
||||
[monster_example.rs](https://github.com/google/flatbuffers/blob/master/tests/rust_usage_test/bin/monster_example.rs)
|
||||
|
||||
It can be run by `cd`ing to the `rust_usage_test` directory and executing: `cargo run monster_example`.
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.rs}
|
||||
extern crate flatbuffers;
|
||||
|
||||
#[path = "../../monster_test_generated.rs"]
|
||||
mod monster_test_generated;
|
||||
pub use monster_test_generated::my_game;
|
||||
|
||||
use std::io::Read;
|
||||
|
||||
fn main() {
|
||||
let mut f = std::fs::File::open("../monsterdata_test.mon").unwrap();
|
||||
let mut buf = Vec::new();
|
||||
f.read_to_end(&mut buf).expect("file reading failed");
|
||||
|
||||
let monster = my_game::example::get_root_as_monster(&buf[..]);
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
`monster` is of type `Monster`, and points to somewhere *inside* your
|
||||
buffer (root object pointers are not the same as `buffer_pointer` !).
|
||||
If you look in your generated header, you'll see it has
|
||||
convenient accessors for all fields, e.g. `hp()`, `mana()`, etc:
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.rs}
|
||||
println!("{}", monster.hp()); // `80`
|
||||
println!("{}", monster.mana()); // default value of `150`
|
||||
println!("{:?}", monster.name()); // Some("MyMonster")
|
||||
}
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
*Note: That we never stored a `mana` value, so it will return the default.*
|
||||
|
||||
## Direct memory access
|
||||
|
||||
As you can see from the above examples, all elements in a buffer are
|
||||
accessed through generated accessors. This is because everything is
|
||||
stored in little endian format on all platforms (the accessor
|
||||
performs a swap operation on big endian machines), and also because
|
||||
the layout of things is generally not known to the user.
|
||||
|
||||
For structs, layout is deterministic and guaranteed to be the same
|
||||
across platforms (scalars are aligned to their
|
||||
own size, and structs themselves to their largest member), and you
|
||||
are allowed to access this memory directly by using `safe_slice` and
|
||||
on the reference to a struct, or even an array of structs.
|
||||
|
||||
To compute offsets to sub-elements of a struct, make sure they
|
||||
are structs themselves, as then you can use the pointers to
|
||||
figure out the offset without having to hardcode it. This is
|
||||
handy for use of arrays of structs with calls like `glVertexAttribPointer`
|
||||
in OpenGL or similar APIs.
|
||||
|
||||
It is important to note is that structs are still little endian on all
|
||||
machines, so only use tricks like this if you can guarantee you're not
|
||||
shipping on a big endian machine (using an `#[cfg(target_endian = "little")]`
|
||||
attribute would be wise).
|
||||
|
||||
The special function `safe_slice` is implemented on Vector objects that are
|
||||
represented in memory the same way as they are represented on the wire. This
|
||||
function is always available on vectors of struct, bool, u8, and i8. It is
|
||||
conditionally-compiled on little-endian systems for all the remaining scalar
|
||||
types.
|
||||
|
||||
The FlatBufferBuilder function `create_vector_direct` is implemented for all
|
||||
types that are endian-safe to write with a `memcpy`. It is the write-equivalent
|
||||
of `safe_slice`.
|
||||
|
||||
## Access of untrusted buffers
|
||||
|
||||
The generated accessor functions access fields over offsets, which is
|
||||
very quick. These offsets are used to index into Rust slices, so they are
|
||||
bounds-checked by the Rust runtime. However, our Rust implementation may
|
||||
change: we may convert access functions to use direct pointer dereferencing, to
|
||||
improve lookup speed. As a result, users should not rely on the aforementioned
|
||||
bounds-checking behavior.
|
||||
|
||||
When you're processing large amounts of data from a source you know (e.g.
|
||||
your own generated data on disk), this is acceptable, but when reading
|
||||
data from the network that can potentially have been modified by an
|
||||
attacker, this is undesirable.
|
||||
|
||||
The C++ port provides a buffer verifier. At this time, Rust does not. Rust may
|
||||
provide a verifier in a future version. In the meantime, Rust users can access
|
||||
the buffer verifier generated by the C++ port through a foreign function
|
||||
interface (FFI).
|
||||
|
||||
## Threading
|
||||
|
||||
Reading a FlatBuffer does not touch any memory outside the original buffer,
|
||||
and is entirely read-only (all immutable), so is safe to access from multiple
|
||||
threads even without synchronisation primitives.
|
||||
|
||||
Creating a FlatBuffer is not thread safe. All state related to building
|
||||
a FlatBuffer is contained in a FlatBufferBuilder instance, and no memory
|
||||
outside of it is touched. To make this thread safe, either do not
|
||||
share instances of FlatBufferBuilder between threads (recommended), or
|
||||
manually wrap it in synchronisation primitives. There's no automatic way to
|
||||
accomplish this, by design, as we feel multithreaded construction
|
||||
of a single buffer will be rare, and synchronisation overhead would be costly.
|
||||
|
||||
<br>
|
||||
@@ -18,24 +18,25 @@ In general:
|
||||
|
||||
NOTE: this table is a start, it needs to be extended.
|
||||
|
||||
Feature | C++ | Java | C# | Go | Python | JS | TS | C | PHP | Ruby
|
||||
------------------------------ | ------ | ------ | ------ | ------ | ------ | --------- | --------- | ------ | --- | ----
|
||||
Codegen for all basic features | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | WiP | WiP
|
||||
JSON parsing | Yes | No | No | No | No | No | No | Yes | No | No
|
||||
Simple mutation | Yes | Yes | Yes | Yes | No | No | No | No | No | No
|
||||
Reflection | Yes | No | No | No | No | No | No | Basic | No | No
|
||||
Buffer verifier | Yes | No | No | No | No | No | No | Yes | No | No
|
||||
Testing: basic | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | ? | ?
|
||||
Testing: fuzz | Yes | No | No | Yes | Yes | No | No | No | ? | ?
|
||||
Performance: | Superb | Great | Great | Great | Ok | ? | ? | Superb | ? | ?
|
||||
Platform: Windows | VS2010 | Yes | Yes | ? | ? | ? | Yes | VS2010 | ? | ?
|
||||
Platform: Linux | GCC282 | Yes | ? | Yes | Yes | ? | Yes | Yes | ? | ?
|
||||
Platform: OS X | Xcode4 | ? | ? | ? | Yes | ? | Yes | Yes | ? | ?
|
||||
Platform: Android | NDK10d | Yes | ? | ? | ? | ? | ? | ? | ? | ?
|
||||
Platform: iOS | ? | ? | ? | ? | ? | ? | ? | ? | ? | ?
|
||||
Engine: Unity | ? | ? | Yes | ? | ? | ? | ? | ? | ? | ?
|
||||
Primary authors (github) | gwvo | gwvo | ev*/js*| rw | rw | evanw/ev* | kr | mik* | ch* | rw
|
||||
Feature | C++ | Java | C# | Go | Python | JS | TS | C | PHP | Dart | Lobster | Rust
|
||||
------------------------------ | ------ | ------ | ------ | ------ | ------ | --------- | --------- | ------ | --- | ------- | ------- | ----
|
||||
Codegen for all basic features | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | WiP | Yes | Yes | Yes
|
||||
JSON parsing | Yes | No | No | No | No | No | No | Yes | No | No | Yes | No
|
||||
Simple mutation | Yes | Yes | Yes | Yes | No | No | No | No | No | No | No | No
|
||||
Reflection | Yes | No | No | No | No | No | No | Basic | No | No | No | No
|
||||
Buffer verifier | Yes | No | No | No | No | No | No | Yes | No | No | No | No
|
||||
Testing: basic | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | ? | Yes | Yes | Yes
|
||||
Testing: fuzz | Yes | No | No | Yes | Yes | No | No | No | ? | No | No | Yes
|
||||
Performance: | Superb | Great | Great | Great | Ok | ? | ? | Superb | ? | ? | Great | Superb
|
||||
Platform: Windows | VS2010 | Yes | Yes | ? | ? | ? | Yes | VS2010 | ? | Yes | Yes | Yes
|
||||
Platform: Linux | GCC282 | Yes | ? | Yes | Yes | ? | Yes | Yes | ? | Yes | Yes | Yes
|
||||
Platform: OS X | Xcode4 | ? | ? | ? | Yes | ? | Yes | Yes | ? | Yes | Yes | Yes
|
||||
Platform: Android | NDK10d | Yes | ? | ? | ? | ? | ? | ? | ? | Flutter | Yes | ?
|
||||
Platform: iOS | ? | ? | ? | ? | ? | ? | ? | ? | ? | Flutter | Yes | ?
|
||||
Engine: Unity | ? | ? | Yes | ? | ? | ? | ? | ? | ? | ? | No | ?
|
||||
Primary authors (github) | aard* | aard* | ev*/js*| rw | rw | evanw/ev* | kr* | mik* | ch* | dnfield | aard* | rw
|
||||
|
||||
* aard = aardappel (previously: gwvo)
|
||||
* ev = evolutional
|
||||
* js = jonsimantov
|
||||
* mik = mikkelfj
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -751,11 +751,16 @@ INPUT = "FlatBuffers.md" \
|
||||
"Schemas.md" \
|
||||
"CppUsage.md" \
|
||||
"CUsage.md" \
|
||||
"DartUsage.md" \
|
||||
"GoUsage.md" \
|
||||
"JavaCsharpUsage.md" \
|
||||
"JavaScriptUsage.md" \
|
||||
"TypeScriptUsage.md" \
|
||||
"PHPUsage.md" \
|
||||
"PythonUsage.md" \
|
||||
"LuaUsage.md" \
|
||||
"LobsterUsage.md" \
|
||||
"RustUsage.md" \
|
||||
"Support.md" \
|
||||
"Benchmarks.md" \
|
||||
"WhitePaper.md" \
|
||||
@@ -774,6 +779,7 @@ INPUT = "FlatBuffers.md" \
|
||||
"../../net/FlatBuffers/FlatBufferBuilder.cs" \
|
||||
"../../include/flatbuffers/flatbuffers.h" \
|
||||
"../../go/builder.go"
|
||||
"../../rust/flatbuffers/src/builder.rs"
|
||||
|
||||
# This tag can be used to specify the character encoding of the source files
|
||||
# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
|
||||
|
||||
@@ -39,6 +39,12 @@
|
||||
title="Use in PHP"/>
|
||||
<tab type="user" url="@ref flatbuffers_guide_use_python"
|
||||
title="Use in Python"/>
|
||||
<tab type="user" url="@ref flatbuffers_guide_use_dart"
|
||||
title="Use in Dart"/>
|
||||
<tab type="user" url="@ref flatbuffers_guide_use_lua"
|
||||
title="Use in Lua"/>
|
||||
<tab type="user" url="@ref flatbuffers_guide_use_lobster"
|
||||
title="Use in Lobster"/>
|
||||
<tab type="user" url="@ref flexbuffers"
|
||||
title="Schema-less version"/>
|
||||
<tab type="usergroup" url="" title="gRPC">
|
||||
|
||||
@@ -19,6 +19,8 @@ type Builder struct {
|
||||
finished bool
|
||||
}
|
||||
|
||||
const fileIdentifierLength = 4
|
||||
|
||||
// NewBuilder initializes a Builder of size `initial_size`.
|
||||
// The internal buffer is grown as needed.
|
||||
func NewBuilder(initialSize int) *Builder {
|
||||
@@ -80,7 +82,6 @@ func (b *Builder) StartObject(numfields int) {
|
||||
}
|
||||
|
||||
b.objectEnd = b.Offset()
|
||||
b.minalign = 1
|
||||
}
|
||||
|
||||
// WriteVtable serializes the vtable for the current object, if applicable.
|
||||
@@ -111,9 +112,10 @@ func (b *Builder) WriteVtable() (n UOffsetT) {
|
||||
existingVtable := UOffsetT(0)
|
||||
|
||||
// Trim vtable of trailing zeroes.
|
||||
i := len(b.vtable) - 1;
|
||||
for ; i >= 0 && b.vtable[i] == 0; i-- {}
|
||||
b.vtable = b.vtable[:i + 1];
|
||||
i := len(b.vtable) - 1
|
||||
for ; i >= 0 && b.vtable[i] == 0; i-- {
|
||||
}
|
||||
b.vtable = b.vtable[:i+1]
|
||||
|
||||
// Search backwards through existing vtables, because similar vtables
|
||||
// are likely to have been recently appended. See
|
||||
@@ -540,6 +542,23 @@ func (b *Builder) Slot(slotnum int) {
|
||||
b.vtable[slotnum] = UOffsetT(b.Offset())
|
||||
}
|
||||
|
||||
// FinishWithFileIdentifier finalizes a buffer, pointing to the given `rootTable`.
|
||||
// as well as applys a file identifier
|
||||
func (b *Builder) FinishWithFileIdentifier(rootTable UOffsetT, fid []byte) {
|
||||
if fid == nil || len(fid) != fileIdentifierLength {
|
||||
panic("incorrect file identifier length")
|
||||
}
|
||||
// In order to add a file identifier to the flatbuffer message, we need
|
||||
// to prepare an alignment and file identifier length
|
||||
b.Prep(b.minalign, SizeInt32+fileIdentifierLength)
|
||||
for i := fileIdentifierLength - 1; i >= 0; i-- {
|
||||
// place the file identifier
|
||||
b.PlaceByte(fid[i])
|
||||
}
|
||||
// finish
|
||||
b.Finish(rootTable)
|
||||
}
|
||||
|
||||
// Finish finalizes a buffer, pointing to the given `rootTable`.
|
||||
func (b *Builder) Finish(rootTable UOffsetT) {
|
||||
b.assertNotNested()
|
||||
|
||||
34
go/encode.go
34
go/encode.go
@@ -36,6 +36,7 @@ func GetUint8(buf []byte) (n uint8) {
|
||||
|
||||
// GetUint16 decodes a little-endian uint16 from a byte slice.
|
||||
func GetUint16(buf []byte) (n uint16) {
|
||||
_ = buf[1] // Force one bounds check. See: golang.org/issue/14808
|
||||
n |= uint16(buf[0])
|
||||
n |= uint16(buf[1]) << 8
|
||||
return
|
||||
@@ -43,6 +44,7 @@ func GetUint16(buf []byte) (n uint16) {
|
||||
|
||||
// GetUint32 decodes a little-endian uint32 from a byte slice.
|
||||
func GetUint32(buf []byte) (n uint32) {
|
||||
_ = buf[3] // Force one bounds check. See: golang.org/issue/14808
|
||||
n |= uint32(buf[0])
|
||||
n |= uint32(buf[1]) << 8
|
||||
n |= uint32(buf[2]) << 16
|
||||
@@ -52,6 +54,7 @@ func GetUint32(buf []byte) (n uint32) {
|
||||
|
||||
// GetUint64 decodes a little-endian uint64 from a byte slice.
|
||||
func GetUint64(buf []byte) (n uint64) {
|
||||
_ = buf[7] // Force one bounds check. See: golang.org/issue/14808
|
||||
n |= uint64(buf[0])
|
||||
n |= uint64(buf[1]) << 8
|
||||
n |= uint64(buf[2]) << 16
|
||||
@@ -71,6 +74,7 @@ func GetInt8(buf []byte) (n int8) {
|
||||
|
||||
// GetInt16 decodes a little-endian int16 from a byte slice.
|
||||
func GetInt16(buf []byte) (n int16) {
|
||||
_ = buf[1] // Force one bounds check. See: golang.org/issue/14808
|
||||
n |= int16(buf[0])
|
||||
n |= int16(buf[1]) << 8
|
||||
return
|
||||
@@ -78,6 +82,7 @@ func GetInt16(buf []byte) (n int16) {
|
||||
|
||||
// GetInt32 decodes a little-endian int32 from a byte slice.
|
||||
func GetInt32(buf []byte) (n int32) {
|
||||
_ = buf[3] // Force one bounds check. See: golang.org/issue/14808
|
||||
n |= int32(buf[0])
|
||||
n |= int32(buf[1]) << 8
|
||||
n |= int32(buf[2]) << 16
|
||||
@@ -87,6 +92,7 @@ func GetInt32(buf []byte) (n int32) {
|
||||
|
||||
// GetInt64 decodes a little-endian int64 from a byte slice.
|
||||
func GetInt64(buf []byte) (n int64) {
|
||||
_ = buf[7] // Force one bounds check. See: golang.org/issue/14808
|
||||
n |= int64(buf[0])
|
||||
n |= int64(buf[1]) << 8
|
||||
n |= int64(buf[2]) << 16
|
||||
@@ -145,12 +151,14 @@ func WriteUint8(buf []byte, n uint8) {
|
||||
|
||||
// WriteUint16 encodes a little-endian uint16 into a byte slice.
|
||||
func WriteUint16(buf []byte, n uint16) {
|
||||
_ = buf[1] // Force one bounds check. See: golang.org/issue/14808
|
||||
buf[0] = byte(n)
|
||||
buf[1] = byte(n >> 8)
|
||||
}
|
||||
|
||||
// WriteUint32 encodes a little-endian uint32 into a byte slice.
|
||||
func WriteUint32(buf []byte, n uint32) {
|
||||
_ = buf[3] // Force one bounds check. See: golang.org/issue/14808
|
||||
buf[0] = byte(n)
|
||||
buf[1] = byte(n >> 8)
|
||||
buf[2] = byte(n >> 16)
|
||||
@@ -159,9 +167,15 @@ func WriteUint32(buf []byte, n uint32) {
|
||||
|
||||
// WriteUint64 encodes a little-endian uint64 into a byte slice.
|
||||
func WriteUint64(buf []byte, n uint64) {
|
||||
for i := uint(0); i < uint(SizeUint64); i++ {
|
||||
buf[i] = byte(n >> (i * 8))
|
||||
}
|
||||
_ = buf[7] // Force one bounds check. See: golang.org/issue/14808
|
||||
buf[0] = byte(n)
|
||||
buf[1] = byte(n >> 8)
|
||||
buf[2] = byte(n >> 16)
|
||||
buf[3] = byte(n >> 24)
|
||||
buf[4] = byte(n >> 32)
|
||||
buf[5] = byte(n >> 40)
|
||||
buf[6] = byte(n >> 48)
|
||||
buf[7] = byte(n >> 56)
|
||||
}
|
||||
|
||||
// WriteInt8 encodes a little-endian int8 into a byte slice.
|
||||
@@ -171,12 +185,14 @@ func WriteInt8(buf []byte, n int8) {
|
||||
|
||||
// WriteInt16 encodes a little-endian int16 into a byte slice.
|
||||
func WriteInt16(buf []byte, n int16) {
|
||||
_ = buf[1] // Force one bounds check. See: golang.org/issue/14808
|
||||
buf[0] = byte(n)
|
||||
buf[1] = byte(n >> 8)
|
||||
}
|
||||
|
||||
// WriteInt32 encodes a little-endian int32 into a byte slice.
|
||||
func WriteInt32(buf []byte, n int32) {
|
||||
_ = buf[3] // Force one bounds check. See: golang.org/issue/14808
|
||||
buf[0] = byte(n)
|
||||
buf[1] = byte(n >> 8)
|
||||
buf[2] = byte(n >> 16)
|
||||
@@ -185,9 +201,15 @@ func WriteInt32(buf []byte, n int32) {
|
||||
|
||||
// WriteInt64 encodes a little-endian int64 into a byte slice.
|
||||
func WriteInt64(buf []byte, n int64) {
|
||||
for i := uint(0); i < uint(SizeInt64); i++ {
|
||||
buf[i] = byte(n >> (i * 8))
|
||||
}
|
||||
_ = buf[7] // Force one bounds check. See: golang.org/issue/14808
|
||||
buf[0] = byte(n)
|
||||
buf[1] = byte(n >> 8)
|
||||
buf[2] = byte(n >> 16)
|
||||
buf[3] = byte(n >> 24)
|
||||
buf[4] = byte(n >> 32)
|
||||
buf[5] = byte(n >> 40)
|
||||
buf[6] = byte(n >> 48)
|
||||
buf[7] = byte(n >> 56)
|
||||
}
|
||||
|
||||
// WriteFloat32 encodes a little-endian float32 into a byte slice.
|
||||
|
||||
@@ -9,3 +9,23 @@ from GRPC, and work with both the Protobuf and FlatBuffers code generator.
|
||||
the GRPC libraries for this to compile. This test will build using the
|
||||
`FLATBUFFERS_BUILD_GRPCTEST` option to the main FlatBuffers CMake project.
|
||||
|
||||
## Building Flatbuffers with gRPC
|
||||
|
||||
### Linux
|
||||
|
||||
1. Download, build and install gRPC. See [instructions](https://github.com/grpc/grpc/tree/master/src/cpp).
|
||||
* Lets say your gRPC clone is at `/your/path/to/grpc_repo`.
|
||||
* Install gRPC in a custom directory by running `make install prefix=/your/path/to/grpc_repo/install`.
|
||||
2. `export GRPC_INSTALL_PATH=/your/path/to/grpc_repo/install`
|
||||
3. `export PROTOBUF_DOWNLOAD_PATH=/your/path/to/grpc_repo/third_party/protobuf`
|
||||
4. `mkdir build ; cd build`
|
||||
5. `cmake -DFLATBUFFERS_BUILD_GRPCTEST=ON -DGRPC_INSTALL_PATH=${GRPC_INSTALL_PATH} -DPROTOBUF_DOWNLOAD_PATH=${PROTOBUF_DOWNLOAD_PATH} ..`
|
||||
6. `make`
|
||||
|
||||
## Running FlatBuffer gRPC tests
|
||||
|
||||
### Linux
|
||||
|
||||
1. `ln -s ${GRPC_INSTALL_PATH}/lib/libgrpc++_unsecure.so.6 ${GRPC_INSTALL_PATH}/lib/libgrpc++_unsecure.so.1`
|
||||
2. `export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:${GRPC_INSTALL_PATH}/lib`
|
||||
3. `make test ARGS=-V`
|
||||
|
||||
21
grpc/build_grpc.sh
Executable file
21
grpc/build_grpc.sh
Executable file
@@ -0,0 +1,21 @@
|
||||
#!/bin/bash
|
||||
|
||||
grpc_1_15_1_githash=1a60e6971f428323245a930031ad267bb3142ba4
|
||||
|
||||
function build_grpc () {
|
||||
git clone https://github.com/grpc/grpc.git google/grpc
|
||||
cd google/grpc
|
||||
git checkout ${grpc_1_15_1_githash}
|
||||
git submodule update --init
|
||||
make
|
||||
make install prefix=`pwd`/install
|
||||
if [ ! -f ${GRPC_INSTALL_PATH}/lib/libgrpc++_unsecure.so.1 ]; then
|
||||
ln -s ${GRPC_INSTALL_PATH}/lib/libgrpc++_unsecure.so.6 ${GRPC_INSTALL_PATH}/lib/libgrpc++_unsecure.so.1
|
||||
fi
|
||||
cd ../..
|
||||
}
|
||||
|
||||
GRPC_INSTALL_PATH=`pwd`/google/grpc/install
|
||||
PROTOBUF_DOWNLOAD_PATH=`pwd`/google/grpc/third_party/protobuf
|
||||
|
||||
build_grpc
|
||||
@@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<groupId>com.google.flatbuffers</groupId>
|
||||
<artifactId>flatbuffers-parent</artifactId>
|
||||
<version>1.8.0</version>
|
||||
<version>1.10.0</version>
|
||||
</parent>
|
||||
<artifactId>flatbuffers-java-grpc</artifactId>
|
||||
<name>${project.artifactId}</name>
|
||||
@@ -24,7 +24,7 @@
|
||||
</developer>
|
||||
</developers>
|
||||
<properties>
|
||||
<gRPC.version>1.8.0</gRPC.version>
|
||||
<gRPC.version>1.9.0</gRPC.version>
|
||||
</properties>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<groupId>com.google.flatbuffers</groupId>
|
||||
<artifactId>flatbuffers-parent</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
<version>1.8.0</version>
|
||||
<version>1.10.0</version>
|
||||
<name>flatbuffers-parent</name>
|
||||
<description>parent pom for flatbuffers java artifacts</description>
|
||||
<properties>
|
||||
@@ -201,7 +201,7 @@
|
||||
</build>
|
||||
|
||||
<modules>
|
||||
<!-- consider the benefits of publishing all maven artifacts in this project
|
||||
<!-- consider the benefits of publishing all maven artifacts in this project
|
||||
|
||||
<module>flatbuffers-compiler</module>
|
||||
<module>flatbuffers-java</module>
|
||||
|
||||
@@ -110,7 +110,7 @@ void GenerateServerMethod(const grpc_generator::Method *method, grpc_generator::
|
||||
vars["Method"] = exportName(method->name());
|
||||
vars["Request"] = method->get_input_type_name();
|
||||
vars["Response"] = (vars["CustomMethodIO"] == "") ? method->get_output_type_name() : vars["CustomMethodIO"];
|
||||
vars["FullMethodName"] = "/" + vars["Package"] + "." + vars["Service"] + "/" + vars["Method"];
|
||||
vars["FullMethodName"] = "/" + vars["ServicePrefix"] + "." + vars["Service"] + "/" + vars["Method"];
|
||||
vars["Handler"] = "_" + vars["Service"] + "_" + vars["Method"] + "_Handler";
|
||||
if (method->NoStreaming()) {
|
||||
printer->Print(vars, "func $Handler$(srv interface{}, ctx $context$.Context,\n\tdec func(interface{}) error, interceptor $grpc$.UnaryServerInterceptor) (interface{}, error) {\n");
|
||||
@@ -223,7 +223,7 @@ void GenerateClientMethod(const grpc_generator::Method *method, grpc_generator::
|
||||
vars["Method"] = exportName(method->name());
|
||||
vars["Request"] = (vars["CustomMethodIO"] == "") ? method->get_input_type_name() : vars["CustomMethodIO"];
|
||||
vars["Response"] = method->get_output_type_name();
|
||||
vars["FullMethodName"] = "/" + vars["Package"] + "." + vars["Service"] + "/" + vars["Method"];
|
||||
vars["FullMethodName"] = "/" + vars["ServicePrefix"] + "." + vars["Service"] + "/" + vars["Method"];
|
||||
if (method->NoStreaming()) {
|
||||
printer->Print(vars, "out := new($Response$)\n");
|
||||
printer->Print(vars, "err := $grpc$.Invoke(ctx, \"$FullMethodName$\", in, out, c.cc, opts...)\n");
|
||||
@@ -374,7 +374,7 @@ void GenerateService(const grpc_generator::Service *service, grpc_generator::Pri
|
||||
//Service Descriptor
|
||||
printer->Print(vars, "var $ServiceDesc$ = $grpc$.ServiceDesc{\n");
|
||||
printer->Indent();
|
||||
printer->Print(vars, "ServiceName: \"$Package$.$Service$\",\n");
|
||||
printer->Print(vars, "ServiceName: \"$ServicePrefix$.$Service$\",\n");
|
||||
printer->Print(vars, "HandlerType: (*$Service$Server)(nil),\n");
|
||||
printer->Print(vars, "Methods: []$grpc$.MethodDesc{\n");
|
||||
printer->Indent();
|
||||
@@ -433,6 +433,7 @@ grpc::string GenerateServiceSource(grpc_generator::File *file,
|
||||
auto printer = p.get();
|
||||
std::map<grpc::string, grpc::string> vars;
|
||||
vars["Package"] = parameters->package_name;
|
||||
vars["ServicePrefix"] = parameters->service_prefix;
|
||||
vars["grpc"] = "grpc";
|
||||
vars["context"] = "context";
|
||||
GenerateImports(file, printer, vars);
|
||||
|
||||
@@ -49,6 +49,9 @@ struct Parameters {
|
||||
|
||||
//Package name for the service
|
||||
grpc::string package_name;
|
||||
|
||||
//Prefix for RPC Calls
|
||||
grpc::string service_prefix;
|
||||
};
|
||||
|
||||
// Return the source of the generated service file.
|
||||
|
||||
@@ -65,8 +65,6 @@ class LogHelper {
|
||||
// Abort the program after logging the mesage.
|
||||
#define GRPC_CODEGEN_FAIL GRPC_CODEGEN_CHECK(false)
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace grpc_java_generator {
|
||||
struct Parameters {
|
||||
// //Defines the custom parameter types for methods
|
||||
|
||||
@@ -20,8 +20,10 @@
|
||||
|
||||
#include "monster_test.grpc.fb.h"
|
||||
#include "monster_test_generated.h"
|
||||
#include "test_assert.h"
|
||||
|
||||
using namespace MyGame::Example;
|
||||
void message_builder_tests();
|
||||
|
||||
// The callback implementation of our server, that derives from the generated
|
||||
// code. It implements all rpcs specified in the FlatBuffers schema.
|
||||
@@ -92,7 +94,7 @@ void RunServer() {
|
||||
server_instance->Wait();
|
||||
}
|
||||
|
||||
int main(int /*argc*/, const char * /*argv*/ []) {
|
||||
int grpc_server_test() {
|
||||
// Launch server.
|
||||
std::thread server_thread(RunServer);
|
||||
|
||||
@@ -163,3 +165,17 @@ int main(int /*argc*/, const char * /*argv*/ []) {
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int /*argc*/, const char * /*argv*/ []) {
|
||||
message_builder_tests();
|
||||
grpc_server_test();
|
||||
|
||||
if (!testing_fails) {
|
||||
TEST_OUTPUT_LINE("ALL TESTS PASSED");
|
||||
return 0;
|
||||
} else {
|
||||
TEST_OUTPUT_LINE("%d FAILED TESTS", testing_fails);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
188
grpc/tests/message_builder_test.cpp
Normal file
188
grpc/tests/message_builder_test.cpp
Normal file
@@ -0,0 +1,188 @@
|
||||
#include "flatbuffers/grpc.h"
|
||||
#include "monster_test_generated.h"
|
||||
#include "test_assert.h"
|
||||
#include "test_builder.h"
|
||||
|
||||
bool verify(flatbuffers::grpc::Message<Monster> &msg, const std::string &expected_name, Color color) {
|
||||
const Monster *monster = msg.GetRoot();
|
||||
return (monster->name()->str() == expected_name) && (monster->color() == color);
|
||||
}
|
||||
|
||||
bool release_n_verify(flatbuffers::grpc::MessageBuilder &mbb, const std::string &expected_name, Color color) {
|
||||
flatbuffers::grpc::Message<Monster> msg = mbb.ReleaseMessage<Monster>();
|
||||
const Monster *monster = msg.GetRoot();
|
||||
return (monster->name()->str() == expected_name) && (monster->color() == color);
|
||||
}
|
||||
|
||||
template <>
|
||||
struct BuilderReuseTests<flatbuffers::grpc::MessageBuilder> {
|
||||
static void builder_reusable_after_release_message_test(TestSelector selector) {
|
||||
if (!selector.count(REUSABLE_AFTER_RELEASE_MESSAGE)) {
|
||||
return;
|
||||
}
|
||||
|
||||
flatbuffers::grpc::MessageBuilder b1;
|
||||
std::vector<flatbuffers::grpc::Message<Monster>> buffers;
|
||||
for (int i = 0; i < 5; ++i) {
|
||||
auto root_offset1 = populate1(b1);
|
||||
b1.Finish(root_offset1);
|
||||
buffers.push_back(b1.ReleaseMessage<Monster>());
|
||||
TEST_ASSERT_FUNC(verify(buffers[i], m1_name, m1_color));
|
||||
}
|
||||
}
|
||||
|
||||
static void builder_reusable_after_release_test(TestSelector selector) {
|
||||
if (!selector.count(REUSABLE_AFTER_RELEASE)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// FIXME: Populate-Release loop fails assert(GRPC_SLICE_IS_EMPTY(slice_)).
|
||||
|
||||
flatbuffers::grpc::MessageBuilder b1;
|
||||
std::vector<flatbuffers::DetachedBuffer> buffers;
|
||||
for (int i = 0; i < 5; ++i) {
|
||||
auto root_offset1 = populate1(b1);
|
||||
b1.Finish(root_offset1);
|
||||
buffers.push_back(b1.Release());
|
||||
TEST_ASSERT_FUNC(verify(buffers[i], m1_name, m1_color));
|
||||
}
|
||||
}
|
||||
|
||||
static void builder_reusable_after_releaseraw_test(TestSelector selector) {
|
||||
if (!selector.count(REUSABLE_AFTER_RELEASE_RAW)) {
|
||||
return;
|
||||
}
|
||||
|
||||
flatbuffers::grpc::MessageBuilder b1;
|
||||
for (int i = 0; i < 5; ++i) {
|
||||
auto root_offset1 = populate1(b1);
|
||||
b1.Finish(root_offset1);
|
||||
size_t size, offset;
|
||||
grpc_slice slice;
|
||||
const uint8_t *buf = b1.ReleaseRaw(size, offset, slice);
|
||||
TEST_ASSERT_FUNC(verify(buf, offset, m1_name, m1_color));
|
||||
grpc_slice_unref(slice);
|
||||
}
|
||||
}
|
||||
|
||||
static void builder_reusable_after_release_and_move_assign_test(TestSelector selector) {
|
||||
if (!selector.count(REUSABLE_AFTER_RELEASE_AND_MOVE_ASSIGN)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// FIXME: Release-move_assign loop fails assert(p == GRPC_SLICE_START_PTR(slice_)).
|
||||
|
||||
flatbuffers::grpc::MessageBuilder b1;
|
||||
std::vector<flatbuffers::DetachedBuffer> buffers;
|
||||
|
||||
for (int i = 0; i < 1; ++i) {
|
||||
auto root_offset1 = populate1(b1);
|
||||
b1.Finish(root_offset1);
|
||||
buffers.push_back(b1.Release());
|
||||
TEST_ASSERT_FUNC(verify(buffers[i], m1_name, m1_color));
|
||||
|
||||
// bring b1 back to life.
|
||||
flatbuffers::grpc::MessageBuilder b2;
|
||||
b1 = std::move(b2);
|
||||
TEST_EQ_FUNC(b1.GetSize(), 0);
|
||||
TEST_EQ_FUNC(b2.GetSize(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
static void builder_reusable_after_release_message_and_move_assign_test(TestSelector selector) {
|
||||
if (!selector.count(REUSABLE_AFTER_RELEASE_MESSAGE_AND_MOVE_ASSIGN)) {
|
||||
return;
|
||||
}
|
||||
|
||||
flatbuffers::grpc::MessageBuilder b1;
|
||||
std::vector<flatbuffers::grpc::Message<Monster>> buffers;
|
||||
|
||||
for (int i = 0; i < 5; ++i) {
|
||||
auto root_offset1 = populate1(b1);
|
||||
b1.Finish(root_offset1);
|
||||
buffers.push_back(b1.ReleaseMessage<Monster>());
|
||||
TEST_ASSERT_FUNC(verify(buffers[i], m1_name, m1_color));
|
||||
|
||||
// bring b1 back to life.
|
||||
flatbuffers::grpc::MessageBuilder b2;
|
||||
b1 = std::move(b2);
|
||||
TEST_EQ_FUNC(b1.GetSize(), 0);
|
||||
TEST_EQ_FUNC(b2.GetSize(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
static void builder_reusable_after_releaseraw_and_move_assign_test(TestSelector selector) {
|
||||
if (!selector.count(REUSABLE_AFTER_RELEASE_RAW_AND_MOVE_ASSIGN)) {
|
||||
return;
|
||||
}
|
||||
|
||||
flatbuffers::grpc::MessageBuilder b1;
|
||||
for (int i = 0; i < 5; ++i) {
|
||||
auto root_offset1 = populate1(b1);
|
||||
b1.Finish(root_offset1);
|
||||
size_t size, offset;
|
||||
grpc_slice slice = grpc_empty_slice();
|
||||
const uint8_t *buf = b1.ReleaseRaw(size, offset, slice);
|
||||
TEST_ASSERT_FUNC(verify(buf, offset, m1_name, m1_color));
|
||||
grpc_slice_unref(slice);
|
||||
|
||||
flatbuffers::grpc::MessageBuilder b2;
|
||||
b1 = std::move(b2);
|
||||
TEST_EQ_FUNC(b1.GetSize(), 0);
|
||||
TEST_EQ_FUNC(b2.GetSize(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
static void run_tests(TestSelector selector) {
|
||||
builder_reusable_after_release_test(selector);
|
||||
builder_reusable_after_release_message_test(selector);
|
||||
builder_reusable_after_releaseraw_test(selector);
|
||||
builder_reusable_after_release_and_move_assign_test(selector);
|
||||
builder_reusable_after_releaseraw_and_move_assign_test(selector);
|
||||
builder_reusable_after_release_message_and_move_assign_test(selector);
|
||||
}
|
||||
};
|
||||
|
||||
void slice_allocator_tests() {
|
||||
// move-construct no-delete test
|
||||
{
|
||||
size_t size = 2048;
|
||||
flatbuffers::grpc::SliceAllocator sa1;
|
||||
uint8_t *buf = sa1.allocate(size);
|
||||
TEST_ASSERT_FUNC(buf != 0);
|
||||
buf[0] = 100;
|
||||
buf[size-1] = 200;
|
||||
flatbuffers::grpc::SliceAllocator sa2(std::move(sa1));
|
||||
// buf should be deleted after move-construct
|
||||
TEST_EQ_FUNC(buf[0], 100);
|
||||
TEST_EQ_FUNC(buf[size-1], 200);
|
||||
// buf is freed here
|
||||
}
|
||||
|
||||
// move-assign test
|
||||
{
|
||||
flatbuffers::grpc::SliceAllocator sa1, sa2;
|
||||
uint8_t *buf = sa1.allocate(2048);
|
||||
sa1 = std::move(sa2);
|
||||
// sa1 deletes previously allocated memory in move-assign.
|
||||
// So buf is no longer usable here.
|
||||
TEST_ASSERT_FUNC(buf != 0);
|
||||
}
|
||||
}
|
||||
|
||||
void message_builder_tests() {
|
||||
slice_allocator_tests();
|
||||
BuilderTests<flatbuffers::grpc::MessageBuilder>::all_tests();
|
||||
|
||||
BuilderReuseTestSelector tests[6] = {
|
||||
// REUSABLE_AFTER_RELEASE, // Assertion failed: (GRPC_SLICE_IS_EMPTY(slice_))
|
||||
// REUSABLE_AFTER_RELEASE_AND_MOVE_ASSIGN, // Assertion failed: (p == GRPC_SLICE_START_PTR(slice_)
|
||||
|
||||
REUSABLE_AFTER_RELEASE_RAW,
|
||||
REUSABLE_AFTER_RELEASE_MESSAGE,
|
||||
REUSABLE_AFTER_RELEASE_MESSAGE_AND_MOVE_ASSIGN,
|
||||
REUSABLE_AFTER_RELEASE_RAW_AND_MOVE_ASSIGN
|
||||
};
|
||||
|
||||
BuilderReuseTests<flatbuffers::grpc::MessageBuilder>::run_tests(TestSelector(tests, tests+6));
|
||||
}
|
||||
@@ -4,13 +4,13 @@
|
||||
<parent>
|
||||
<groupId>com.google.flatbuffers</groupId>
|
||||
<artifactId>flatbuffers-parent</artifactId>
|
||||
<version>1.8.0</version>
|
||||
<version>1.10.0</version>
|
||||
</parent>
|
||||
<artifactId>grpc-test</artifactId>
|
||||
<description>Example/Test project demonstrating usage of flatbuffers with GRPC-Java instead of protobufs
|
||||
</description>
|
||||
<properties>
|
||||
<gRPC.version>1.8.0</gRPC.version>
|
||||
<gRPC.version>1.9.0</gRPC.version>
|
||||
</properties>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
|
||||
@@ -9,6 +9,10 @@
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#if !defined(FLATBUFFERS_ASSERT)
|
||||
#define FLATBUFFERS_ASSERT assert
|
||||
#endif
|
||||
|
||||
#ifndef ARDUINO
|
||||
#include <cstdint>
|
||||
#endif
|
||||
@@ -47,6 +51,12 @@
|
||||
|
||||
#include "flatbuffers/stl_emulation.h"
|
||||
|
||||
// Note the __clang__ check is needed, because clang presents itself
|
||||
// as an older GNUC compiler (4.2).
|
||||
// Clang 3.3 and later implement all of the ISO C++ 2011 standard.
|
||||
// Clang 3.4 and later implement all of the ISO C++ 2014 standard.
|
||||
// http://clang.llvm.org/cxx_status.html
|
||||
|
||||
/// @cond FLATBUFFERS_INTERNAL
|
||||
#if __cplusplus <= 199711L && \
|
||||
(!defined(_MSC_VER) || _MSC_VER < 1600) && \
|
||||
@@ -100,13 +110,14 @@
|
||||
#endif // !defined(FLATBUFFERS_LITTLEENDIAN)
|
||||
|
||||
#define FLATBUFFERS_VERSION_MAJOR 1
|
||||
#define FLATBUFFERS_VERSION_MINOR 9
|
||||
#define FLATBUFFERS_VERSION_MINOR 10
|
||||
#define FLATBUFFERS_VERSION_REVISION 0
|
||||
#define FLATBUFFERS_STRING_EXPAND(X) #X
|
||||
#define FLATBUFFERS_STRING(X) FLATBUFFERS_STRING_EXPAND(X)
|
||||
|
||||
#if (!defined(_MSC_VER) || _MSC_VER > 1600) && \
|
||||
(!defined(__GNUC__) || (__GNUC__ * 100 + __GNUC_MINOR__ >= 407))
|
||||
(!defined(__GNUC__) || (__GNUC__ * 100 + __GNUC_MINOR__ >= 407)) || \
|
||||
defined(__clang__)
|
||||
#define FLATBUFFERS_FINAL_CLASS final
|
||||
#define FLATBUFFERS_OVERRIDE override
|
||||
#else
|
||||
@@ -115,7 +126,8 @@
|
||||
#endif
|
||||
|
||||
#if (!defined(_MSC_VER) || _MSC_VER >= 1900) && \
|
||||
(!defined(__GNUC__) || (__GNUC__ * 100 + __GNUC_MINOR__ >= 406))
|
||||
(!defined(__GNUC__) || (__GNUC__ * 100 + __GNUC_MINOR__ >= 406)) || \
|
||||
(defined(__cpp_constexpr) && __cpp_constexpr >= 200704)
|
||||
#define FLATBUFFERS_CONSTEXPR constexpr
|
||||
#else
|
||||
#define FLATBUFFERS_CONSTEXPR
|
||||
@@ -128,8 +140,9 @@
|
||||
#define FLATBUFFERS_CONSTEXPR_CPP14
|
||||
#endif
|
||||
|
||||
#if defined(__GXX_EXPERIMENTAL_CXX0X__) && __GNUC__ * 10 + __GNUC_MINOR__ >= 46 || \
|
||||
defined(_MSC_FULL_VER) && _MSC_FULL_VER >= 190023026
|
||||
#if (defined(__GXX_EXPERIMENTAL_CXX0X__) && (__GNUC__ * 100 + __GNUC_MINOR__ >= 406)) || \
|
||||
(defined(_MSC_FULL_VER) && (_MSC_FULL_VER >= 190023026)) || \
|
||||
defined(__clang__)
|
||||
#define FLATBUFFERS_NOEXCEPT noexcept
|
||||
#else
|
||||
#define FLATBUFFERS_NOEXCEPT
|
||||
@@ -138,16 +151,34 @@
|
||||
// NOTE: the FLATBUFFERS_DELETE_FUNC macro may change the access mode to
|
||||
// private, so be sure to put it at the end or reset access mode explicitly.
|
||||
#if (!defined(_MSC_VER) || _MSC_FULL_VER >= 180020827) && \
|
||||
(!defined(__GNUC__) || (__GNUC__ * 100 + __GNUC_MINOR__ >= 404))
|
||||
(!defined(__GNUC__) || (__GNUC__ * 100 + __GNUC_MINOR__ >= 404)) || \
|
||||
defined(__clang__)
|
||||
#define FLATBUFFERS_DELETE_FUNC(func) func = delete;
|
||||
#else
|
||||
#define FLATBUFFERS_DELETE_FUNC(func) private: func;
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable: 4127) // C4127: conditional expression is constant
|
||||
#endif
|
||||
#ifndef FLATBUFFERS_HAS_STRING_VIEW
|
||||
// Only provide flatbuffers::string_view if __has_include can be used
|
||||
// to detect a header that provides an implementation
|
||||
#if defined(__has_include)
|
||||
// Check for std::string_view (in c++17)
|
||||
#if __has_include(<string_view>) && (__cplusplus >= 201606 || _HAS_CXX17)
|
||||
#include <string_view>
|
||||
namespace flatbuffers {
|
||||
typedef std::string_view string_view;
|
||||
}
|
||||
#define FLATBUFFERS_HAS_STRING_VIEW 1
|
||||
// Check for std::experimental::string_view (in c++14, compiler-dependent)
|
||||
#elif __has_include(<experimental/string_view>) && (__cplusplus >= 201411)
|
||||
#include <experimental/string_view>
|
||||
namespace flatbuffers {
|
||||
typedef std::experimental::string_view string_view;
|
||||
}
|
||||
#define FLATBUFFERS_HAS_STRING_VIEW 1
|
||||
#endif
|
||||
#endif // __has_include
|
||||
#endif // !FLATBUFFERS_HAS_STRING_VIEW
|
||||
|
||||
/// @endcond
|
||||
|
||||
@@ -175,6 +206,11 @@ typedef uintmax_t largest_scalar_t;
|
||||
// We support aligning the contents of buffers up to this size.
|
||||
#define FLATBUFFERS_MAX_ALIGNMENT 16
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable: 4127) // C4127: conditional expression is constant
|
||||
#endif
|
||||
|
||||
template<typename T> T EndianSwap(T t) {
|
||||
#if defined(_MSC_VER)
|
||||
#define FLATBUFFERS_BYTESWAP16 _byteswap_ushort
|
||||
@@ -209,10 +245,14 @@ template<typename T> T EndianSwap(T t) {
|
||||
u.i = FLATBUFFERS_BYTESWAP64(u.i);
|
||||
return u.t;
|
||||
} else {
|
||||
assert(0);
|
||||
FLATBUFFERS_ASSERT(0);
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
|
||||
template<typename T> T EndianScalar(T t) {
|
||||
#if FLATBUFFERS_LITTLEENDIAN
|
||||
|
||||
@@ -33,7 +33,8 @@ template<typename T> struct Offset {
|
||||
inline void EndianCheck() {
|
||||
int endiantest = 1;
|
||||
// If this fails, see FLATBUFFERS_LITTLEENDIAN above.
|
||||
assert(*reinterpret_cast<char *>(&endiantest) == FLATBUFFERS_LITTLEENDIAN);
|
||||
FLATBUFFERS_ASSERT(*reinterpret_cast<char *>(&endiantest) ==
|
||||
FLATBUFFERS_LITTLEENDIAN);
|
||||
(void)endiantest;
|
||||
}
|
||||
|
||||
@@ -90,7 +91,7 @@ template<typename T> struct IndirectHelper<const T *> {
|
||||
template<typename T, typename IT> struct VectorIterator {
|
||||
typedef std::random_access_iterator_tag iterator_category;
|
||||
typedef IT value_type;
|
||||
typedef uoffset_t difference_type;
|
||||
typedef ptrdiff_t difference_type;
|
||||
typedef IT *pointer;
|
||||
typedef IT &reference;
|
||||
|
||||
@@ -120,7 +121,7 @@ template<typename T, typename IT> struct VectorIterator {
|
||||
return data_ != other.data_;
|
||||
}
|
||||
|
||||
ptrdiff_t operator-(const VectorIterator &other) const {
|
||||
difference_type operator-(const VectorIterator &other) const {
|
||||
return (data_ - other.data_) / IndirectHelper<T>::element_stride;
|
||||
}
|
||||
|
||||
@@ -194,7 +195,7 @@ template<typename T> class Vector {
|
||||
typedef typename IndirectHelper<T>::mutable_return_type mutable_return_type;
|
||||
|
||||
return_type Get(uoffset_t i) const {
|
||||
assert(i < size());
|
||||
FLATBUFFERS_ASSERT(i < size());
|
||||
return IndirectHelper<T>::Read(Data(), i);
|
||||
}
|
||||
|
||||
@@ -232,7 +233,7 @@ template<typename T> class Vector {
|
||||
// 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, const T &val) {
|
||||
assert(i < size());
|
||||
FLATBUFFERS_ASSERT(i < size());
|
||||
WriteScalar(data() + i, val);
|
||||
}
|
||||
|
||||
@@ -240,15 +241,15 @@ template<typename T> class Vector {
|
||||
// "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));
|
||||
FLATBUFFERS_ASSERT(i < size());
|
||||
static_assert(sizeof(T) == sizeof(uoffset_t), "Unrelated types");
|
||||
WriteScalar(data() + i,
|
||||
static_cast<uoffset_t>(val - (Data() + i * sizeof(uoffset_t))));
|
||||
}
|
||||
|
||||
// Get a mutable pointer to tables/strings inside this vector.
|
||||
mutable_return_type GetMutableObject(uoffset_t i) const {
|
||||
assert(i < size());
|
||||
FLATBUFFERS_ASSERT(i < size());
|
||||
return const_cast<mutable_return_type>(IndirectHelper<T>::Read(Data(), i));
|
||||
}
|
||||
|
||||
@@ -334,7 +335,7 @@ const Vector<Offset<T>> *VectorCast(const Vector<Offset<U>> *ptr) {
|
||||
#endif
|
||||
|
||||
// Convenient helper function to get the length of any vector, regardless
|
||||
// of wether it is null or not (the field is not set).
|
||||
// of whether it is null or not (the field is not set).
|
||||
template<typename T> static inline size_t VectorLength(const Vector<T> *v) {
|
||||
return v ? v->Length() : 0;
|
||||
}
|
||||
@@ -343,11 +344,31 @@ struct String : public Vector<char> {
|
||||
const char *c_str() const { return reinterpret_cast<const char *>(Data()); }
|
||||
std::string str() const { return std::string(c_str(), Length()); }
|
||||
|
||||
// clang-format off
|
||||
#ifdef FLATBUFFERS_HAS_STRING_VIEW
|
||||
flatbuffers::string_view string_view() const {
|
||||
return flatbuffers::string_view(c_str(), Length());
|
||||
}
|
||||
#endif // FLATBUFFERS_HAS_STRING_VIEW
|
||||
// clang-format on
|
||||
|
||||
bool operator<(const String &o) const {
|
||||
return strcmp(c_str(), o.c_str()) < 0;
|
||||
}
|
||||
};
|
||||
|
||||
// Convenience function to get std::string from a String returning an empty
|
||||
// string on null pointer.
|
||||
static inline std::string GetString(const String * str) {
|
||||
return str ? str->str() : "";
|
||||
}
|
||||
|
||||
// Convenience function to get char* from a String returning an empty string on
|
||||
// null pointer.
|
||||
static inline const char * GetCstring(const String * str) {
|
||||
return str ? str->c_str() : "";
|
||||
}
|
||||
|
||||
// Allocator interface. This is flatbuffers-specific and meant only for
|
||||
// `vector_downward` usage.
|
||||
class Allocator {
|
||||
@@ -368,7 +389,7 @@ class Allocator {
|
||||
virtual uint8_t *reallocate_downward(uint8_t *old_p, size_t old_size,
|
||||
size_t new_size, size_t in_use_back,
|
||||
size_t in_use_front) {
|
||||
assert(new_size > old_size); // vector_downward only grows
|
||||
FLATBUFFERS_ASSERT(new_size > old_size); // vector_downward only grows
|
||||
uint8_t *new_p = allocate(new_size);
|
||||
memcpy_downward(old_p, old_size, new_p, new_size, in_use_back,
|
||||
in_use_front);
|
||||
@@ -393,20 +414,39 @@ class Allocator {
|
||||
// DefaultAllocator uses new/delete to allocate memory regions
|
||||
class DefaultAllocator : public Allocator {
|
||||
public:
|
||||
virtual uint8_t *allocate(size_t size) FLATBUFFERS_OVERRIDE {
|
||||
uint8_t *allocate(size_t size) FLATBUFFERS_OVERRIDE {
|
||||
return new uint8_t[size];
|
||||
}
|
||||
|
||||
virtual void deallocate(uint8_t *p, size_t) FLATBUFFERS_OVERRIDE {
|
||||
void deallocate(uint8_t *p, size_t) FLATBUFFERS_OVERRIDE {
|
||||
delete[] p;
|
||||
}
|
||||
|
||||
static DefaultAllocator &instance() {
|
||||
static DefaultAllocator inst;
|
||||
return inst;
|
||||
}
|
||||
};
|
||||
|
||||
// These functions allow for a null allocator to mean use the default allocator,
|
||||
// as used by DetachedBuffer and vector_downward below.
|
||||
// This is to avoid having a statically or dynamically allocated default
|
||||
// allocator, or having to move it between the classes that may own it.
|
||||
inline uint8_t *Allocate(Allocator *allocator, size_t size) {
|
||||
return allocator ? allocator->allocate(size)
|
||||
: DefaultAllocator().allocate(size);
|
||||
}
|
||||
|
||||
inline void Deallocate(Allocator *allocator, uint8_t *p, size_t size) {
|
||||
if (allocator) allocator->deallocate(p, size);
|
||||
else DefaultAllocator().deallocate(p, size);
|
||||
}
|
||||
|
||||
inline uint8_t *ReallocateDownward(Allocator *allocator, uint8_t *old_p,
|
||||
size_t old_size, size_t new_size,
|
||||
size_t in_use_back, size_t in_use_front) {
|
||||
return allocator
|
||||
? allocator->reallocate_downward(old_p, old_size, new_size,
|
||||
in_use_back, in_use_front)
|
||||
: DefaultAllocator().reallocate_downward(old_p, old_size, new_size,
|
||||
in_use_back, in_use_front);
|
||||
}
|
||||
|
||||
// DetachedBuffer is a finished flatbuffer memory region, detached from its
|
||||
// builder. The original memory region and allocator are also stored so that
|
||||
// the DetachedBuffer can manage the memory lifetime.
|
||||
@@ -427,9 +467,7 @@ class DetachedBuffer {
|
||||
buf_(buf),
|
||||
reserved_(reserved),
|
||||
cur_(cur),
|
||||
size_(sz) {
|
||||
assert(allocator_);
|
||||
}
|
||||
size_(sz) {}
|
||||
|
||||
DetachedBuffer(DetachedBuffer &&other)
|
||||
: allocator_(other.allocator_),
|
||||
@@ -498,12 +536,8 @@ class DetachedBuffer {
|
||||
size_t size_;
|
||||
|
||||
inline void destroy() {
|
||||
if (buf_) {
|
||||
assert(allocator_);
|
||||
allocator_->deallocate(buf_, reserved_);
|
||||
}
|
||||
if (buf_) Deallocate(allocator_, buf_, reserved_);
|
||||
if (own_allocator_ && allocator_) { delete allocator_; }
|
||||
|
||||
reset();
|
||||
}
|
||||
|
||||
@@ -529,31 +563,48 @@ class vector_downward {
|
||||
Allocator *allocator,
|
||||
bool own_allocator,
|
||||
size_t buffer_minalign)
|
||||
: allocator_(allocator ? allocator : &DefaultAllocator::instance()),
|
||||
: allocator_(allocator),
|
||||
own_allocator_(own_allocator),
|
||||
initial_size_(initial_size),
|
||||
buffer_minalign_(buffer_minalign),
|
||||
reserved_(0),
|
||||
buf_(nullptr),
|
||||
cur_(nullptr),
|
||||
scratch_(nullptr) {
|
||||
assert(allocator_);
|
||||
scratch_(nullptr) {}
|
||||
|
||||
vector_downward(vector_downward &&other)
|
||||
: allocator_(other.allocator_),
|
||||
own_allocator_(other.own_allocator_),
|
||||
initial_size_(other.initial_size_),
|
||||
buffer_minalign_(other.buffer_minalign_),
|
||||
reserved_(other.reserved_),
|
||||
buf_(other.buf_),
|
||||
cur_(other.cur_),
|
||||
scratch_(other.scratch_) {
|
||||
// No change in other.allocator_
|
||||
// No change in other.initial_size_
|
||||
// No change in other.buffer_minalign_
|
||||
other.own_allocator_ = false;
|
||||
other.reserved_ = 0;
|
||||
other.buf_ = nullptr;
|
||||
other.cur_ = nullptr;
|
||||
other.scratch_ = nullptr;
|
||||
}
|
||||
|
||||
vector_downward &operator=(vector_downward &&other) {
|
||||
// Move construct a temporary and swap idiom
|
||||
vector_downward temp(std::move(other));
|
||||
swap(temp);
|
||||
return *this;
|
||||
}
|
||||
|
||||
~vector_downward() {
|
||||
if (buf_) {
|
||||
assert(allocator_);
|
||||
allocator_->deallocate(buf_, reserved_);
|
||||
}
|
||||
if (own_allocator_ && allocator_) { delete allocator_; }
|
||||
clear_buffer();
|
||||
clear_allocator();
|
||||
}
|
||||
|
||||
void reset() {
|
||||
if (buf_) {
|
||||
assert(allocator_);
|
||||
allocator_->deallocate(buf_, reserved_);
|
||||
buf_ = nullptr;
|
||||
}
|
||||
clear_buffer();
|
||||
clear();
|
||||
}
|
||||
|
||||
@@ -571,32 +622,61 @@ class vector_downward {
|
||||
scratch_ = buf_;
|
||||
}
|
||||
|
||||
// Relinquish the pointer to the caller.
|
||||
DetachedBuffer release() {
|
||||
DetachedBuffer fb(allocator_, own_allocator_, buf_, reserved_, cur_,
|
||||
size());
|
||||
void clear_allocator() {
|
||||
if (own_allocator_ && allocator_) { delete allocator_; }
|
||||
allocator_ = nullptr;
|
||||
own_allocator_ = false;
|
||||
}
|
||||
|
||||
void clear_buffer() {
|
||||
if (buf_) Deallocate(allocator_, buf_, reserved_);
|
||||
buf_ = nullptr;
|
||||
}
|
||||
|
||||
// Relinquish the pointer to the caller.
|
||||
uint8_t *release_raw(size_t &allocated_bytes, size_t &offset) {
|
||||
auto *buf = buf_;
|
||||
allocated_bytes = reserved_;
|
||||
offset = static_cast<size_t>(cur_ - buf_);
|
||||
|
||||
// release_raw only relinquishes the buffer ownership.
|
||||
// Does not deallocate or reset the allocator. Destructor will do that.
|
||||
buf_ = nullptr;
|
||||
clear();
|
||||
return buf;
|
||||
}
|
||||
|
||||
// Relinquish the pointer to the caller.
|
||||
DetachedBuffer release() {
|
||||
// allocator ownership (if any) is transferred to DetachedBuffer.
|
||||
DetachedBuffer fb(allocator_, own_allocator_, buf_, reserved_, cur_,
|
||||
size());
|
||||
if (own_allocator_) {
|
||||
allocator_ = nullptr;
|
||||
own_allocator_ = false;
|
||||
}
|
||||
buf_ = nullptr;
|
||||
clear();
|
||||
return fb;
|
||||
}
|
||||
|
||||
size_t ensure_space(size_t len) {
|
||||
assert(cur_ >= scratch_ && scratch_ >= buf_);
|
||||
FLATBUFFERS_ASSERT(cur_ >= scratch_ && scratch_ >= buf_);
|
||||
if (len > static_cast<size_t>(cur_ - scratch_)) { reallocate(len); }
|
||||
// Beyond this, signed offsets may not have enough range:
|
||||
// (FlatBuffers > 2GB not supported).
|
||||
assert(size() < FLATBUFFERS_MAX_BUFFER_SIZE);
|
||||
FLATBUFFERS_ASSERT(size() < FLATBUFFERS_MAX_BUFFER_SIZE);
|
||||
return len;
|
||||
}
|
||||
|
||||
inline uint8_t *make_space(size_t len) {
|
||||
cur_ -= ensure_space(len);
|
||||
size_t space = ensure_space(len);
|
||||
cur_ -= space;
|
||||
return cur_;
|
||||
}
|
||||
|
||||
Allocator &get_allocator() { return *allocator_; }
|
||||
// Returns nullptr if using the DefaultAllocator.
|
||||
Allocator *get_custom_allocator() { return allocator_; }
|
||||
|
||||
uoffset_t size() const {
|
||||
return static_cast<uoffset_t>(reserved_ - (cur_ - buf_));
|
||||
@@ -609,17 +689,17 @@ class vector_downward {
|
||||
size_t capacity() const { return reserved_; }
|
||||
|
||||
uint8_t *data() const {
|
||||
assert(cur_);
|
||||
FLATBUFFERS_ASSERT(cur_);
|
||||
return cur_;
|
||||
}
|
||||
|
||||
uint8_t *scratch_data() const {
|
||||
assert(buf_);
|
||||
FLATBUFFERS_ASSERT(buf_);
|
||||
return buf_;
|
||||
}
|
||||
|
||||
uint8_t *scratch_end() const {
|
||||
assert(scratch_);
|
||||
FLATBUFFERS_ASSERT(scratch_);
|
||||
return scratch_;
|
||||
}
|
||||
|
||||
@@ -656,6 +736,24 @@ class vector_downward {
|
||||
void pop(size_t bytes_to_remove) { cur_ += bytes_to_remove; }
|
||||
void scratch_pop(size_t bytes_to_remove) { scratch_ -= bytes_to_remove; }
|
||||
|
||||
void swap(vector_downward &other) {
|
||||
using std::swap;
|
||||
swap(allocator_, other.allocator_);
|
||||
swap(own_allocator_, other.own_allocator_);
|
||||
swap(initial_size_, other.initial_size_);
|
||||
swap(buffer_minalign_, other.buffer_minalign_);
|
||||
swap(reserved_, other.reserved_);
|
||||
swap(buf_, other.buf_);
|
||||
swap(cur_, other.cur_);
|
||||
swap(scratch_, other.scratch_);
|
||||
}
|
||||
|
||||
void swap_allocator(vector_downward &other) {
|
||||
using std::swap;
|
||||
swap(allocator_, other.allocator_);
|
||||
swap(own_allocator_, other.own_allocator_);
|
||||
}
|
||||
|
||||
private:
|
||||
// You shouldn't really be copying instances of this class.
|
||||
FLATBUFFERS_DELETE_FUNC(vector_downward(const vector_downward &))
|
||||
@@ -671,7 +769,6 @@ class vector_downward {
|
||||
uint8_t *scratch_; // Points to the end of the scratchpad in use.
|
||||
|
||||
void reallocate(size_t len) {
|
||||
assert(allocator_);
|
||||
auto old_reserved = reserved_;
|
||||
auto old_size = size();
|
||||
auto old_scratch_size = scratch_size();
|
||||
@@ -679,10 +776,10 @@ class vector_downward {
|
||||
old_reserved ? old_reserved / 2 : initial_size_);
|
||||
reserved_ = (reserved_ + buffer_minalign_ - 1) & ~(buffer_minalign_ - 1);
|
||||
if (buf_) {
|
||||
buf_ = allocator_->reallocate_downward(buf_, old_reserved, reserved_,
|
||||
old_size, old_scratch_size);
|
||||
buf_ = ReallocateDownward(allocator_, buf_, old_reserved, reserved_,
|
||||
old_size, old_scratch_size);
|
||||
} else {
|
||||
buf_ = allocator_->allocate(reserved_);
|
||||
buf_ = Allocate(allocator_, reserved_);
|
||||
}
|
||||
cur_ = buf_ + reserved_ - old_size;
|
||||
scratch_ = buf_ + old_scratch_size;
|
||||
@@ -720,8 +817,8 @@ class FlatBufferBuilder {
|
||||
/// @brief Default constructor for FlatBufferBuilder.
|
||||
/// @param[in] initial_size The initial size of the buffer, in bytes. Defaults
|
||||
/// to `1024`.
|
||||
/// @param[in] allocator An `Allocator` to use. Defaults to a new instance of
|
||||
/// a `DefaultAllocator`.
|
||||
/// @param[in] allocator An `Allocator` to use. If null will use
|
||||
/// `DefaultAllocator`.
|
||||
/// @param[in] own_allocator Whether the builder/vector should own the
|
||||
/// allocator. Defaults to / `false`.
|
||||
/// @param[in] buffer_minalign Force the buffer to be aligned to the given
|
||||
@@ -745,6 +842,44 @@ class FlatBufferBuilder {
|
||||
EndianCheck();
|
||||
}
|
||||
|
||||
/// @brief Move constructor for FlatBufferBuilder.
|
||||
FlatBufferBuilder(FlatBufferBuilder &&other)
|
||||
: buf_(1024, nullptr, false, AlignOf<largest_scalar_t>()),
|
||||
num_field_loc(0),
|
||||
max_voffset_(0),
|
||||
nested(false),
|
||||
finished(false),
|
||||
minalign_(1),
|
||||
force_defaults_(false),
|
||||
dedup_vtables_(true),
|
||||
string_pool(nullptr) {
|
||||
EndianCheck();
|
||||
// Default construct and swap idiom.
|
||||
// Lack of delegating constructors in vs2010 makes it more verbose than needed.
|
||||
Swap(other);
|
||||
}
|
||||
|
||||
/// @brief Move assignment operator for FlatBufferBuilder.
|
||||
FlatBufferBuilder &operator=(FlatBufferBuilder &&other) {
|
||||
// Move construct a temporary and swap idiom
|
||||
FlatBufferBuilder temp(std::move(other));
|
||||
Swap(temp);
|
||||
return *this;
|
||||
}
|
||||
|
||||
void Swap(FlatBufferBuilder &other) {
|
||||
using std::swap;
|
||||
buf_.swap(other.buf_);
|
||||
swap(num_field_loc, other.num_field_loc);
|
||||
swap(max_voffset_, other.max_voffset_);
|
||||
swap(nested, other.nested);
|
||||
swap(finished, other.finished);
|
||||
swap(minalign_, other.minalign_);
|
||||
swap(force_defaults_, other.force_defaults_);
|
||||
swap(dedup_vtables_, other.dedup_vtables_);
|
||||
swap(string_pool, other.string_pool);
|
||||
}
|
||||
|
||||
~FlatBufferBuilder() {
|
||||
if (string_pool) delete string_pool;
|
||||
}
|
||||
@@ -798,6 +933,19 @@ class FlatBufferBuilder {
|
||||
return buf_.release();
|
||||
}
|
||||
|
||||
/// @brief Get the released pointer to the serialized buffer.
|
||||
/// @param The size of the memory block containing
|
||||
/// the serialized `FlatBuffer`.
|
||||
/// @param The offset from the released pointer where the finished
|
||||
/// `FlatBuffer` starts.
|
||||
/// @return A raw pointer to the start of the memory block containing
|
||||
/// the serialized `FlatBuffer`.
|
||||
/// @remark If the allocator is owned, it gets deleted during this call.
|
||||
uint8_t *ReleaseRaw(size_t &size, size_t &offset) {
|
||||
Finished();
|
||||
return buf_.release_raw(size, offset);
|
||||
}
|
||||
|
||||
/// @brief get the minimum alignment this buffer needs to be accessed
|
||||
/// properly. This is only known once all elements have been written (after
|
||||
/// you call Finish()). You can use this information if you need to embed
|
||||
@@ -815,13 +963,14 @@ class FlatBufferBuilder {
|
||||
// FlatBufferBuilder::Finish with your root table.
|
||||
// If you really need to access an unfinished buffer, call
|
||||
// GetCurrentBufferPointer instead.
|
||||
assert(finished);
|
||||
FLATBUFFERS_ASSERT(finished);
|
||||
}
|
||||
/// @endcond
|
||||
|
||||
/// @brief In order to save space, fields that are set to their default value
|
||||
/// don't get serialized into the buffer.
|
||||
/// @param[in] bool fd When set to `true`, always serializes default values.
|
||||
/// @param[in] bool fd When set to `true`, always serializes default values that are set.
|
||||
/// Optional fields which are not set explicitly, will still not be serialized.
|
||||
void ForceDefaults(bool fd) { force_defaults_ = fd; }
|
||||
|
||||
/// @brief By default vtables are deduped in order to save space.
|
||||
@@ -908,7 +1057,7 @@ class FlatBufferBuilder {
|
||||
// Align to ensure GetSize() below is correct.
|
||||
Align(sizeof(uoffset_t));
|
||||
// Offset must refer to something already in buffer.
|
||||
assert(off && off <= GetSize());
|
||||
FLATBUFFERS_ASSERT(off && off <= GetSize());
|
||||
return GetSize() - off + static_cast<uoffset_t>(sizeof(uoffset_t));
|
||||
}
|
||||
|
||||
@@ -921,9 +1070,9 @@ class FlatBufferBuilder {
|
||||
// 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);
|
||||
FLATBUFFERS_ASSERT(!nested);
|
||||
// If you hit this, fields were added outside the scope of a table.
|
||||
assert(!num_field_loc);
|
||||
FLATBUFFERS_ASSERT(!num_field_loc);
|
||||
}
|
||||
|
||||
// From generated code (or from the parser), we call StartTable/EndTable
|
||||
@@ -939,7 +1088,7 @@ class FlatBufferBuilder {
|
||||
// resulting vtable offset.
|
||||
uoffset_t EndTable(uoffset_t start) {
|
||||
// If you get this assert, a corresponding StartTable wasn't called.
|
||||
assert(nested);
|
||||
FLATBUFFERS_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);
|
||||
@@ -953,7 +1102,8 @@ class FlatBufferBuilder {
|
||||
FieldIndexToOffset(0));
|
||||
buf_.fill_big(max_voffset_);
|
||||
auto table_object_size = vtableoffsetloc - start;
|
||||
assert(table_object_size < 0x10000); // Vtable use 16bit offsets.
|
||||
// Vtable use 16bit offsets.
|
||||
FLATBUFFERS_ASSERT(table_object_size < 0x10000);
|
||||
WriteScalar<voffset_t>(buf_.data() + sizeof(voffset_t),
|
||||
static_cast<voffset_t>(table_object_size));
|
||||
WriteScalar<voffset_t>(buf_.data(), max_voffset_);
|
||||
@@ -963,7 +1113,8 @@ class FlatBufferBuilder {
|
||||
auto field_location = reinterpret_cast<FieldLoc *>(it);
|
||||
auto pos = static_cast<voffset_t>(vtableoffsetloc - field_location->off);
|
||||
// If this asserts, it means you've set a field twice.
|
||||
assert(!ReadScalar<voffset_t>(buf_.data() + field_location->id));
|
||||
FLATBUFFERS_ASSERT(
|
||||
!ReadScalar<voffset_t>(buf_.data() + field_location->id));
|
||||
WriteScalar<voffset_t>(buf_.data() + field_location->id, pos);
|
||||
}
|
||||
ClearOffsets();
|
||||
@@ -1006,14 +1157,7 @@ class FlatBufferBuilder {
|
||||
|
||||
// This checks a required field has been set in a given table that has
|
||||
// just been constructed.
|
||||
template<typename T> void Required(Offset<T> table, voffset_t field) {
|
||||
auto table_ptr = buf_.data_at(table.o);
|
||||
auto vtable_ptr = table_ptr - ReadScalar<soffset_t>(table_ptr);
|
||||
bool ok = ReadScalar<voffset_t>(vtable_ptr + field) != 0;
|
||||
// If this fails, the caller will show what field needs to be set.
|
||||
assert(ok);
|
||||
(void)ok;
|
||||
}
|
||||
template<typename T> void Required(Offset<T> table, voffset_t field);
|
||||
|
||||
uoffset_t StartStruct(size_t alignment) {
|
||||
Align(alignment);
|
||||
@@ -1074,6 +1218,17 @@ class FlatBufferBuilder {
|
||||
return CreateString(str.c_str(), str.length());
|
||||
}
|
||||
|
||||
// clang-format off
|
||||
#ifdef FLATBUFFERS_HAS_STRING_VIEW
|
||||
/// @brief Store a string in the buffer, which can contain any binary data.
|
||||
/// @param[in] str A const string_view to copy in to the buffer.
|
||||
/// @return Returns the offset in the buffer where the string starts.
|
||||
Offset<String> CreateString(flatbuffers::string_view str) {
|
||||
return CreateString(str.data(), str.size());
|
||||
}
|
||||
#endif // FLATBUFFERS_HAS_STRING_VIEW
|
||||
// clang-format on
|
||||
|
||||
/// @brief Store a string in the buffer, which can contain any binary data.
|
||||
/// @param[in] str A const pointer to a `String` struct to add to the buffer.
|
||||
/// @return Returns the offset in the buffer where the string starts
|
||||
@@ -1143,7 +1298,7 @@ class FlatBufferBuilder {
|
||||
|
||||
/// @cond FLATBUFFERS_INTERNAL
|
||||
uoffset_t EndVector(size_t len) {
|
||||
assert(nested); // Hit if no corresponding StartVector.
|
||||
FLATBUFFERS_ASSERT(nested); // Hit if no corresponding StartVector.
|
||||
nested = false;
|
||||
return PushElement(static_cast<uoffset_t>(len));
|
||||
}
|
||||
@@ -1164,6 +1319,11 @@ class FlatBufferBuilder {
|
||||
PreAlign(len * elemsize, alignment);
|
||||
}
|
||||
|
||||
// Similar to ForceVectorAlignment but for String fields.
|
||||
void ForceStringAlignment(size_t len, size_t alignment) {
|
||||
PreAlign((len + 1) * sizeof(char), alignment);
|
||||
}
|
||||
|
||||
/// @endcond
|
||||
|
||||
/// @brief Serialize an array into a FlatBuffer `vector`.
|
||||
@@ -1510,6 +1670,13 @@ class FlatBufferBuilder {
|
||||
/// in the buffer.
|
||||
template<typename T>
|
||||
Offset<Vector<T>> CreateUninitializedVector(size_t len, T **buf) {
|
||||
AssertScalarT<T>();
|
||||
return CreateUninitializedVector(len, sizeof(T),
|
||||
reinterpret_cast<uint8_t **>(buf));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
Offset<Vector<const T*>> CreateUninitializedVectorOfStructs(size_t len, T **buf) {
|
||||
return CreateUninitializedVector(len, sizeof(T),
|
||||
reinterpret_cast<uint8_t **>(buf));
|
||||
}
|
||||
@@ -1559,7 +1726,7 @@ class FlatBufferBuilder {
|
||||
(file_identifier ? kFileIdentifierLength : 0),
|
||||
minalign_);
|
||||
if (file_identifier) {
|
||||
assert(strlen(file_identifier) == kFileIdentifierLength);
|
||||
FLATBUFFERS_ASSERT(strlen(file_identifier) == kFileIdentifierLength);
|
||||
PushBytes(reinterpret_cast<const uint8_t *>(file_identifier),
|
||||
kFileIdentifierLength);
|
||||
}
|
||||
@@ -1681,49 +1848,63 @@ class Verifier FLATBUFFERS_FINAL_CLASS {
|
||||
Verifier(const uint8_t *buf, size_t buf_len, uoffset_t _max_depth = 64,
|
||||
uoffset_t _max_tables = 1000000)
|
||||
: buf_(buf),
|
||||
end_(buf + buf_len),
|
||||
size_(buf_len),
|
||||
depth_(0),
|
||||
max_depth_(_max_depth),
|
||||
num_tables_(0),
|
||||
max_tables_(_max_tables)
|
||||
// clang-format off
|
||||
#ifdef FLATBUFFERS_TRACK_VERIFIER_BUFFER_SIZE
|
||||
, upper_bound_(buf)
|
||||
, upper_bound_(0)
|
||||
#endif
|
||||
// clang-format on
|
||||
{
|
||||
assert(size_ < FLATBUFFERS_MAX_BUFFER_SIZE);
|
||||
}
|
||||
|
||||
// Central location where any verification failures register.
|
||||
bool Check(bool ok) const {
|
||||
// clang-format off
|
||||
#ifdef FLATBUFFERS_DEBUG_VERIFICATION_FAILURE
|
||||
assert(ok);
|
||||
FLATBUFFERS_ASSERT(ok);
|
||||
#endif
|
||||
#ifdef FLATBUFFERS_TRACK_VERIFIER_BUFFER_SIZE
|
||||
if (!ok)
|
||||
upper_bound_ = buf_;
|
||||
upper_bound_ = 0;
|
||||
#endif
|
||||
// clang-format on
|
||||
return ok;
|
||||
}
|
||||
|
||||
// Verify any range within the buffer.
|
||||
bool Verify(const void *elem, size_t elem_len) const {
|
||||
bool Verify(size_t elem, size_t elem_len) const {
|
||||
// clang-format off
|
||||
#ifdef FLATBUFFERS_TRACK_VERIFIER_BUFFER_SIZE
|
||||
auto upper_bound = reinterpret_cast<const uint8_t *>(elem) + elem_len;
|
||||
auto upper_bound = elem + elem_len;
|
||||
if (upper_bound_ < upper_bound)
|
||||
upper_bound_ = upper_bound;
|
||||
#endif
|
||||
// clang-format on
|
||||
return Check(elem_len <= (size_t)(end_ - buf_) && elem >= buf_ &&
|
||||
elem <= end_ - elem_len);
|
||||
return Check(elem_len < size_ && elem <= size_ - elem_len);
|
||||
}
|
||||
|
||||
template<typename T> bool VerifyAlignment(size_t elem) const {
|
||||
return (elem & (sizeof(T) - 1)) == 0;
|
||||
}
|
||||
|
||||
// Verify a range indicated by sizeof(T).
|
||||
template<typename T> bool Verify(const void *elem) const {
|
||||
return Verify(elem, sizeof(T));
|
||||
template<typename T> bool Verify(size_t elem) const {
|
||||
return VerifyAlignment<T>(elem) && Verify(elem, sizeof(T));
|
||||
}
|
||||
|
||||
// Verify relative to a known-good base pointer.
|
||||
bool Verify(const uint8_t *base, voffset_t elem_off, size_t elem_len) const {
|
||||
return Verify(static_cast<size_t>(base - buf_) + elem_off, elem_len);
|
||||
}
|
||||
|
||||
template<typename T> bool Verify(const uint8_t *base, voffset_t elem_off)
|
||||
const {
|
||||
return Verify(static_cast<size_t>(base - buf_) + elem_off, sizeof(T));
|
||||
}
|
||||
|
||||
// Verify a pointer (may be NULL) of a table type.
|
||||
@@ -1732,31 +1913,32 @@ class Verifier FLATBUFFERS_FINAL_CLASS {
|
||||
}
|
||||
|
||||
// Verify a pointer (may be NULL) of any vector type.
|
||||
template<typename T> bool Verify(const Vector<T> *vec) const {
|
||||
const uint8_t *end;
|
||||
return !vec || VerifyVector(reinterpret_cast<const uint8_t *>(vec),
|
||||
sizeof(T), &end);
|
||||
template<typename T> bool VerifyVector(const Vector<T> *vec) const {
|
||||
return !vec || VerifyVectorOrString(reinterpret_cast<const uint8_t *>(vec),
|
||||
sizeof(T));
|
||||
}
|
||||
|
||||
// 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));
|
||||
template<typename T> bool VerifyVector(const Vector<const T *> *vec) const {
|
||||
return VerifyVector(reinterpret_cast<const Vector<T> *>(vec));
|
||||
}
|
||||
|
||||
// Verify a pointer (may be NULL) to string.
|
||||
bool Verify(const String *str) const {
|
||||
const uint8_t *end;
|
||||
bool VerifyString(const String *str) const {
|
||||
size_t end;
|
||||
return !str ||
|
||||
(VerifyVector(reinterpret_cast<const uint8_t *>(str), 1, &end) &&
|
||||
(VerifyVectorOrString(reinterpret_cast<const uint8_t *>(str),
|
||||
1, &end) &&
|
||||
Verify(end, 1) && // Must have terminator
|
||||
Check(*end == '\0')); // Terminating byte must be 0.
|
||||
Check(buf_[end] == '\0')); // Terminating byte must be 0.
|
||||
}
|
||||
|
||||
// Common code between vectors and strings.
|
||||
bool VerifyVector(const uint8_t *vec, size_t elem_size,
|
||||
const uint8_t **end) const {
|
||||
bool VerifyVectorOrString(const uint8_t *vec, size_t elem_size,
|
||||
size_t *end = nullptr) const {
|
||||
auto veco = static_cast<size_t>(vec - buf_);
|
||||
// Check we can read the size field.
|
||||
if (!Verify<uoffset_t>(vec)) return false;
|
||||
if (!Verify<uoffset_t>(veco)) return false;
|
||||
// Check the whole array. If this is a string, the byte past the array
|
||||
// must be 0.
|
||||
auto size = ReadScalar<uoffset_t>(vec);
|
||||
@@ -1764,15 +1946,15 @@ class Verifier FLATBUFFERS_FINAL_CLASS {
|
||||
if (!Check(size < max_elems))
|
||||
return false; // Protect against byte_size overflowing.
|
||||
auto byte_size = sizeof(size) + elem_size * size;
|
||||
*end = vec + byte_size;
|
||||
return Verify(vec, byte_size);
|
||||
if (end) *end = veco + byte_size;
|
||||
return Verify(veco, byte_size);
|
||||
}
|
||||
|
||||
// Special case for string contents, after the above has been called.
|
||||
bool VerifyVectorOfStrings(const Vector<Offset<String>> *vec) const {
|
||||
if (vec) {
|
||||
for (uoffset_t i = 0; i < vec->size(); i++) {
|
||||
if (!Verify(vec->Get(i))) return false;
|
||||
if (!VerifyString(vec->Get(i))) return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
@@ -1788,43 +1970,68 @@ class Verifier FLATBUFFERS_FINAL_CLASS {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool VerifyTableStart(const uint8_t *table) {
|
||||
// Check the vtable offset.
|
||||
auto tableo = static_cast<size_t>(table - buf_);
|
||||
if (!Verify<soffset_t>(tableo)) return false;
|
||||
// This offset may be signed, but doing the substraction unsigned always
|
||||
// gives the result we want.
|
||||
auto vtableo = tableo - static_cast<size_t>(ReadScalar<soffset_t>(table));
|
||||
// Check the vtable size field, then check vtable fits in its entirety.
|
||||
return VerifyComplexity() && Verify<voffset_t>(vtableo) &&
|
||||
VerifyAlignment<voffset_t>(ReadScalar<voffset_t>(buf_ + vtableo)) &&
|
||||
Verify(vtableo, ReadScalar<voffset_t>(buf_ + vtableo));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
bool VerifyBufferFromStart(const char *identifier, const uint8_t *start) {
|
||||
bool VerifyBufferFromStart(const char *identifier, size_t start) {
|
||||
if (identifier &&
|
||||
(size_t(end_ - start) < 2 * sizeof(flatbuffers::uoffset_t) ||
|
||||
!BufferHasIdentifier(start, identifier))) {
|
||||
(size_ < 2 * sizeof(flatbuffers::uoffset_t) ||
|
||||
!BufferHasIdentifier(buf_ + start, identifier))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Call T::Verify, which must be in the generated code for this type.
|
||||
auto o = VerifyOffset(start);
|
||||
return o && reinterpret_cast<const T *>(start + o)->Verify(*this)
|
||||
#ifdef FLATBUFFERS_TRACK_VERIFIER_BUFFER_SIZE
|
||||
return o && reinterpret_cast<const T *>(buf_ + start + o)->Verify(*this)
|
||||
// clang-format off
|
||||
#ifdef FLATBUFFERS_TRACK_VERIFIER_BUFFER_SIZE
|
||||
&& GetComputedSize()
|
||||
#endif
|
||||
#endif
|
||||
;
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
// Verify this whole buffer, starting with root type T.
|
||||
template<typename T> bool VerifyBuffer() { return VerifyBuffer<T>(nullptr); }
|
||||
|
||||
template<typename T> bool VerifyBuffer(const char *identifier) {
|
||||
return VerifyBufferFromStart<T>(identifier, buf_);
|
||||
return VerifyBufferFromStart<T>(identifier, 0);
|
||||
}
|
||||
|
||||
template<typename T> bool VerifySizePrefixedBuffer(const char *identifier) {
|
||||
return Verify<uoffset_t>(buf_) &&
|
||||
ReadScalar<uoffset_t>(buf_) == end_ - buf_ - sizeof(uoffset_t) &&
|
||||
VerifyBufferFromStart<T>(identifier, buf_ + sizeof(uoffset_t));
|
||||
return Verify<uoffset_t>(0U) &&
|
||||
ReadScalar<uoffset_t>(buf_) == size_ - sizeof(uoffset_t) &&
|
||||
VerifyBufferFromStart<T>(identifier, sizeof(uoffset_t));
|
||||
}
|
||||
|
||||
uoffset_t VerifyOffset(const uint8_t *start) const {
|
||||
if (!Verify<uoffset_t>(start)) return false;
|
||||
auto o = ReadScalar<uoffset_t>(start);
|
||||
uoffset_t VerifyOffset(size_t start) const {
|
||||
if (!Verify<uoffset_t>(start)) return 0;
|
||||
auto o = ReadScalar<uoffset_t>(buf_ + start);
|
||||
// May not point to itself.
|
||||
Check(o != 0);
|
||||
// Can't wrap around / buffers are max 2GB.
|
||||
if (!Check(static_cast<soffset_t>(o) >= 0)) return 0;
|
||||
// Must be inside the buffer to create a pointer from it (pointer outside
|
||||
// buffer is UB).
|
||||
if (!Verify(start + o, 1)) return 0;
|
||||
return o;
|
||||
}
|
||||
|
||||
uoffset_t VerifyOffset(const uint8_t *base, voffset_t start) const {
|
||||
return VerifyOffset(static_cast<size_t>(base - buf_) + start);
|
||||
}
|
||||
|
||||
// Called at the start of a table to increase counters measuring data
|
||||
// structure depth and amount, and possibly bails out with false if
|
||||
// limits set by the constructor have been hit. Needs to be balanced
|
||||
@@ -1845,24 +2052,24 @@ class Verifier FLATBUFFERS_FINAL_CLASS {
|
||||
#ifdef FLATBUFFERS_TRACK_VERIFIER_BUFFER_SIZE
|
||||
// Returns the message size in bytes
|
||||
size_t GetComputedSize() const {
|
||||
uintptr_t size = upper_bound_ - buf_;
|
||||
uintptr_t size = upper_bound_;
|
||||
// Align the size to uoffset_t
|
||||
size = (size - 1 + sizeof(uoffset_t)) & ~(sizeof(uoffset_t) - 1);
|
||||
return (buf_ + size > end_) ? 0 : size;
|
||||
return (size > size_) ? 0 : size;
|
||||
}
|
||||
#endif
|
||||
// clang-format on
|
||||
|
||||
private:
|
||||
const uint8_t *buf_;
|
||||
const uint8_t *end_;
|
||||
size_t size_;
|
||||
uoffset_t depth_;
|
||||
uoffset_t max_depth_;
|
||||
uoffset_t num_tables_;
|
||||
uoffset_t max_tables_;
|
||||
// clang-format off
|
||||
#ifdef FLATBUFFERS_TRACK_VERIFIER_BUFFER_SIZE
|
||||
mutable const uint8_t *upper_bound_;
|
||||
mutable size_t upper_bound_;
|
||||
#endif
|
||||
// clang-format on
|
||||
};
|
||||
@@ -1984,13 +2191,7 @@ class Table {
|
||||
// Verify the vtable of this table.
|
||||
// Call this once per table, followed by VerifyField once per field.
|
||||
bool VerifyTableStart(Verifier &verifier) const {
|
||||
// Check the vtable offset.
|
||||
if (!verifier.Verify<soffset_t>(data_)) return false;
|
||||
auto vtable = GetVTable();
|
||||
// Check the vtable size field, then check vtable fits in its entirety.
|
||||
return verifier.VerifyComplexity() && verifier.Verify<voffset_t>(vtable) &&
|
||||
(ReadScalar<voffset_t>(vtable) & (sizeof(voffset_t) - 1)) == 0 &&
|
||||
verifier.Verify(vtable, ReadScalar<voffset_t>(vtable));
|
||||
return verifier.VerifyTableStart(data_);
|
||||
}
|
||||
|
||||
// Verify a particular field.
|
||||
@@ -2000,7 +2201,7 @@ class Table {
|
||||
// VerifyTable().
|
||||
auto field_offset = GetOptionalFieldOffset(field);
|
||||
// Check the actual field.
|
||||
return !field_offset || verifier.Verify<T>(data_ + field_offset);
|
||||
return !field_offset || verifier.Verify<T>(data_, field_offset);
|
||||
}
|
||||
|
||||
// VerifyField for required fields.
|
||||
@@ -2008,19 +2209,19 @@ class Table {
|
||||
bool VerifyFieldRequired(const Verifier &verifier, voffset_t field) const {
|
||||
auto field_offset = GetOptionalFieldOffset(field);
|
||||
return verifier.Check(field_offset != 0) &&
|
||||
verifier.Verify<T>(data_ + field_offset);
|
||||
verifier.Verify<T>(data_, field_offset);
|
||||
}
|
||||
|
||||
// Versions for offsets.
|
||||
bool VerifyOffset(const Verifier &verifier, voffset_t field) const {
|
||||
auto field_offset = GetOptionalFieldOffset(field);
|
||||
return !field_offset || verifier.VerifyOffset(data_ + field_offset);
|
||||
return !field_offset || verifier.VerifyOffset(data_, field_offset);
|
||||
}
|
||||
|
||||
bool VerifyOffsetRequired(const Verifier &verifier, voffset_t field) const {
|
||||
auto field_offset = GetOptionalFieldOffset(field);
|
||||
return verifier.Check(field_offset != 0) &&
|
||||
verifier.VerifyOffset(data_ + field_offset);
|
||||
verifier.VerifyOffset(data_, field_offset);
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -2032,6 +2233,15 @@ class Table {
|
||||
uint8_t data_[1];
|
||||
};
|
||||
|
||||
template<typename T> void FlatBufferBuilder::Required(Offset<T> table,
|
||||
voffset_t field) {
|
||||
auto table_ptr = reinterpret_cast<const Table *>(buf_.data_at(table.o));
|
||||
bool ok = table_ptr->GetOptionalFieldOffset(field) != 0;
|
||||
// If this fails, the caller will show what field needs to be set.
|
||||
FLATBUFFERS_ASSERT(ok);
|
||||
(void)ok;
|
||||
}
|
||||
|
||||
/// @brief This can compute the start of a FlatBuffer from a root pointer, i.e.
|
||||
/// it is the opposite transformation of GetRoot().
|
||||
/// This may be useful if you want to pass on a root and have the recipient
|
||||
@@ -2066,7 +2276,7 @@ inline const uint8_t *GetBufferStartFromRootPointer(const void *root) {
|
||||
// or the buffer is corrupt.
|
||||
// Assert, because calling this function with bad data may cause reads
|
||||
// outside of buffer boundaries.
|
||||
assert(false);
|
||||
FLATBUFFERS_ASSERT(false);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -2131,17 +2341,17 @@ inline int LookupEnum(const char **names, const char *name) {
|
||||
|
||||
// clang-format off
|
||||
#if defined(_MSC_VER)
|
||||
#define MANUALLY_ALIGNED_STRUCT(alignment) \
|
||||
#define FLATBUFFERS_MANUALLY_ALIGNED_STRUCT(alignment) \
|
||||
__pragma(pack(1)); \
|
||||
struct __declspec(align(alignment))
|
||||
#define STRUCT_END(name, size) \
|
||||
#define FLATBUFFERS_STRUCT_END(name, size) \
|
||||
__pragma(pack()); \
|
||||
static_assert(sizeof(name) == size, "compiler breaks packing rules")
|
||||
#elif defined(__GNUC__) || defined(__clang__)
|
||||
#define MANUALLY_ALIGNED_STRUCT(alignment) \
|
||||
#define FLATBUFFERS_MANUALLY_ALIGNED_STRUCT(alignment) \
|
||||
_Pragma("pack(1)") \
|
||||
struct __attribute__((aligned(alignment)))
|
||||
#define STRUCT_END(name, size) \
|
||||
#define FLATBUFFERS_STRUCT_END(name, size) \
|
||||
_Pragma("pack()") \
|
||||
static_assert(sizeof(name) == size, "compiler breaks packing rules")
|
||||
#else
|
||||
@@ -2211,9 +2421,9 @@ typedef const TypeTable *(*TypeFunction)();
|
||||
|
||||
struct TypeTable {
|
||||
SequenceType st;
|
||||
size_t num_elems; // of each of the arrays below.
|
||||
const TypeCode *type_codes;
|
||||
const TypeFunction *type_refs;
|
||||
size_t num_elems; // of type_codes, values, names (but not type_refs).
|
||||
const TypeCode *type_codes; // num_elems count
|
||||
const TypeFunction *type_refs; // less than num_elems entries (see TypeCode).
|
||||
const int32_t *values; // Only set for non-consecutive enum/union or structs.
|
||||
const char * const *names; // Only set if compiled with --reflect-names.
|
||||
};
|
||||
@@ -2240,7 +2450,7 @@ volatile __attribute__((weak)) const char *flatbuffer_version_string =
|
||||
|
||||
#endif // !defined(_WIN32) && !defined(__CYGWIN__)
|
||||
|
||||
#define DEFINE_BITMASK_OPERATORS(E, T)\
|
||||
#define FLATBUFFERS_DEFINE_BITMASK_OPERATORS(E, T)\
|
||||
inline E operator | (E lhs, E rhs){\
|
||||
return E(T(lhs) | T(rhs));\
|
||||
}\
|
||||
@@ -2272,9 +2482,6 @@ volatile __attribute__((weak)) const char *flatbuffer_version_string =
|
||||
/// @endcond
|
||||
} // namespace flatbuffers
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
// clang-format on
|
||||
|
||||
#endif // FLATBUFFERS_H_
|
||||
|
||||
@@ -49,75 +49,75 @@ enum BitWidth {
|
||||
// These are used as the upper 6 bits of a type field to indicate the actual
|
||||
// type.
|
||||
enum Type {
|
||||
TYPE_NULL = 0,
|
||||
TYPE_INT = 1,
|
||||
TYPE_UINT = 2,
|
||||
TYPE_FLOAT = 3,
|
||||
FBT_NULL = 0,
|
||||
FBT_INT = 1,
|
||||
FBT_UINT = 2,
|
||||
FBT_FLOAT = 3,
|
||||
// Types above stored inline, types below store an offset.
|
||||
TYPE_KEY = 4,
|
||||
TYPE_STRING = 5,
|
||||
TYPE_INDIRECT_INT = 6,
|
||||
TYPE_INDIRECT_UINT = 7,
|
||||
TYPE_INDIRECT_FLOAT = 8,
|
||||
TYPE_MAP = 9,
|
||||
TYPE_VECTOR = 10, // Untyped.
|
||||
TYPE_VECTOR_INT = 11, // Typed any size (stores no type table).
|
||||
TYPE_VECTOR_UINT = 12,
|
||||
TYPE_VECTOR_FLOAT = 13,
|
||||
TYPE_VECTOR_KEY = 14,
|
||||
TYPE_VECTOR_STRING = 15,
|
||||
TYPE_VECTOR_INT2 = 16, // Typed tuple (no type table, no size field).
|
||||
TYPE_VECTOR_UINT2 = 17,
|
||||
TYPE_VECTOR_FLOAT2 = 18,
|
||||
TYPE_VECTOR_INT3 = 19, // Typed triple (no type table, no size field).
|
||||
TYPE_VECTOR_UINT3 = 20,
|
||||
TYPE_VECTOR_FLOAT3 = 21,
|
||||
TYPE_VECTOR_INT4 = 22, // Typed quad (no type table, no size field).
|
||||
TYPE_VECTOR_UINT4 = 23,
|
||||
TYPE_VECTOR_FLOAT4 = 24,
|
||||
TYPE_BLOB = 25,
|
||||
TYPE_BOOL = 26,
|
||||
TYPE_VECTOR_BOOL =
|
||||
FBT_KEY = 4,
|
||||
FBT_STRING = 5,
|
||||
FBT_INDIRECT_INT = 6,
|
||||
FBT_INDIRECT_UINT = 7,
|
||||
FBT_INDIRECT_FLOAT = 8,
|
||||
FBT_MAP = 9,
|
||||
FBT_VECTOR = 10, // Untyped.
|
||||
FBT_VECTOR_INT = 11, // Typed any size (stores no type table).
|
||||
FBT_VECTOR_UINT = 12,
|
||||
FBT_VECTOR_FLOAT = 13,
|
||||
FBT_VECTOR_KEY = 14,
|
||||
FBT_VECTOR_STRING = 15,
|
||||
FBT_VECTOR_INT2 = 16, // Typed tuple (no type table, no size field).
|
||||
FBT_VECTOR_UINT2 = 17,
|
||||
FBT_VECTOR_FLOAT2 = 18,
|
||||
FBT_VECTOR_INT3 = 19, // Typed triple (no type table, no size field).
|
||||
FBT_VECTOR_UINT3 = 20,
|
||||
FBT_VECTOR_FLOAT3 = 21,
|
||||
FBT_VECTOR_INT4 = 22, // Typed quad (no type table, no size field).
|
||||
FBT_VECTOR_UINT4 = 23,
|
||||
FBT_VECTOR_FLOAT4 = 24,
|
||||
FBT_BLOB = 25,
|
||||
FBT_BOOL = 26,
|
||||
FBT_VECTOR_BOOL =
|
||||
36, // To Allow the same type of conversion of type to vector type
|
||||
};
|
||||
|
||||
inline bool IsInline(Type t) { return t <= TYPE_FLOAT || t == TYPE_BOOL; }
|
||||
inline bool IsInline(Type t) { return t <= FBT_FLOAT || t == FBT_BOOL; }
|
||||
|
||||
inline bool IsTypedVectorElementType(Type t) {
|
||||
return (t >= TYPE_INT && t <= TYPE_STRING) || t == TYPE_BOOL;
|
||||
return (t >= FBT_INT && t <= FBT_STRING) || t == FBT_BOOL;
|
||||
}
|
||||
|
||||
inline bool IsTypedVector(Type t) {
|
||||
return (t >= TYPE_VECTOR_INT && t <= TYPE_VECTOR_STRING) ||
|
||||
t == TYPE_VECTOR_BOOL;
|
||||
return (t >= FBT_VECTOR_INT && t <= FBT_VECTOR_STRING) ||
|
||||
t == FBT_VECTOR_BOOL;
|
||||
}
|
||||
|
||||
inline bool IsFixedTypedVector(Type t) {
|
||||
return t >= TYPE_VECTOR_INT2 && t <= TYPE_VECTOR_FLOAT4;
|
||||
return t >= FBT_VECTOR_INT2 && t <= FBT_VECTOR_FLOAT4;
|
||||
}
|
||||
|
||||
inline Type ToTypedVector(Type t, size_t fixed_len = 0) {
|
||||
assert(IsTypedVectorElementType(t));
|
||||
FLATBUFFERS_ASSERT(IsTypedVectorElementType(t));
|
||||
switch (fixed_len) {
|
||||
case 0: return static_cast<Type>(t - TYPE_INT + TYPE_VECTOR_INT);
|
||||
case 2: return static_cast<Type>(t - TYPE_INT + TYPE_VECTOR_INT2);
|
||||
case 3: return static_cast<Type>(t - TYPE_INT + TYPE_VECTOR_INT3);
|
||||
case 4: return static_cast<Type>(t - TYPE_INT + TYPE_VECTOR_INT4);
|
||||
default: assert(0); return TYPE_NULL;
|
||||
case 0: return static_cast<Type>(t - FBT_INT + FBT_VECTOR_INT);
|
||||
case 2: return static_cast<Type>(t - FBT_INT + FBT_VECTOR_INT2);
|
||||
case 3: return static_cast<Type>(t - FBT_INT + FBT_VECTOR_INT3);
|
||||
case 4: return static_cast<Type>(t - FBT_INT + FBT_VECTOR_INT4);
|
||||
default: FLATBUFFERS_ASSERT(0); return FBT_NULL;
|
||||
}
|
||||
}
|
||||
|
||||
inline Type ToTypedVectorElementType(Type t) {
|
||||
assert(IsTypedVector(t));
|
||||
return static_cast<Type>(t - TYPE_VECTOR_INT + TYPE_INT);
|
||||
FLATBUFFERS_ASSERT(IsTypedVector(t));
|
||||
return static_cast<Type>(t - FBT_VECTOR_INT + FBT_INT);
|
||||
}
|
||||
|
||||
inline Type ToFixedTypedVectorElementType(Type t, uint8_t *len) {
|
||||
assert(IsFixedTypedVector(t));
|
||||
auto fixed_type = t - TYPE_VECTOR_INT2;
|
||||
FLATBUFFERS_ASSERT(IsFixedTypedVector(t));
|
||||
auto fixed_type = t - FBT_VECTOR_INT2;
|
||||
*len = static_cast<uint8_t>(fixed_type / 3 +
|
||||
2); // 3 types each, starting from length 2.
|
||||
return static_cast<Type>(fixed_type % 3 + TYPE_INT);
|
||||
return static_cast<Type>(fixed_type % 3 + FBT_INT);
|
||||
}
|
||||
|
||||
// TODO: implement proper support for 8/16bit floats, or decide not to
|
||||
@@ -271,7 +271,7 @@ class TypedVector : public Sized {
|
||||
|
||||
static TypedVector EmptyTypedVector() {
|
||||
static const uint8_t empty_typed_vector[] = { 0 /*len*/ };
|
||||
return TypedVector(empty_typed_vector + 1, 1, TYPE_INT);
|
||||
return TypedVector(empty_typed_vector + 1, 1, FBT_INT);
|
||||
}
|
||||
bool IsTheEmptyVector() const {
|
||||
return data_ == TypedVector::EmptyTypedVector().data_;
|
||||
@@ -295,7 +295,7 @@ class FixedTypedVector : public Object {
|
||||
|
||||
static FixedTypedVector EmptyFixedTypedVector() {
|
||||
static const uint8_t fixed_empty_vector[] = { 0 /* unused */ };
|
||||
return FixedTypedVector(fixed_empty_vector, 1, TYPE_INT, 0);
|
||||
return FixedTypedVector(fixed_empty_vector, 1, FBT_INT, 0);
|
||||
}
|
||||
bool IsTheEmptyFixedTypedVector() const {
|
||||
return data_ == FixedTypedVector::EmptyFixedTypedVector().data_;
|
||||
@@ -324,7 +324,7 @@ class Map : public Vector {
|
||||
return TypedVector(Indirect(keys_offset, byte_width_),
|
||||
static_cast<uint8_t>(
|
||||
ReadUInt64(keys_offset + byte_width_, byte_width_)),
|
||||
TYPE_KEY);
|
||||
FBT_KEY);
|
||||
}
|
||||
|
||||
static Map EmptyMap() {
|
||||
@@ -354,25 +354,28 @@ class Reference {
|
||||
|
||||
Type GetType() const { return type_; }
|
||||
|
||||
bool IsNull() const { return type_ == TYPE_NULL; }
|
||||
bool IsBool() const { return type_ == TYPE_BOOL; }
|
||||
bool IsInt() const { return type_ == TYPE_INT || type_ == TYPE_INDIRECT_INT; }
|
||||
bool IsNull() const { return type_ == FBT_NULL; }
|
||||
bool IsBool() const { return type_ == FBT_BOOL; }
|
||||
bool IsInt() const { return type_ == FBT_INT || type_ == FBT_INDIRECT_INT; }
|
||||
bool IsUInt() const {
|
||||
return type_ == TYPE_UINT || type_ == TYPE_INDIRECT_UINT;
|
||||
return type_ == FBT_UINT || type_ == FBT_INDIRECT_UINT;
|
||||
}
|
||||
bool IsIntOrUint() const { return IsInt() || IsUInt(); }
|
||||
bool IsFloat() const {
|
||||
return type_ == TYPE_FLOAT || type_ == TYPE_INDIRECT_FLOAT;
|
||||
return type_ == FBT_FLOAT || type_ == FBT_INDIRECT_FLOAT;
|
||||
}
|
||||
bool IsNumeric() const { return IsIntOrUint() || IsFloat(); }
|
||||
bool IsString() const { return type_ == TYPE_STRING; }
|
||||
bool IsKey() const { return type_ == TYPE_KEY; }
|
||||
bool IsVector() const { return type_ == TYPE_VECTOR || type_ == TYPE_MAP; }
|
||||
bool IsMap() const { return type_ == TYPE_MAP; }
|
||||
bool IsBlob() const { return type_ == TYPE_BLOB; }
|
||||
bool IsString() const { return type_ == FBT_STRING; }
|
||||
bool IsKey() const { return type_ == FBT_KEY; }
|
||||
bool IsVector() const { return type_ == FBT_VECTOR || type_ == FBT_MAP; }
|
||||
bool IsTypedVector() const { return flexbuffers::IsTypedVector(type_); }
|
||||
bool IsFixedTypedVector() const { return flexbuffers::IsFixedTypedVector(type_); }
|
||||
bool IsAnyVector() const { return (IsTypedVector() || IsFixedTypedVector() || IsVector());}
|
||||
bool IsMap() const { return type_ == FBT_MAP; }
|
||||
bool IsBlob() const { return type_ == FBT_BLOB; }
|
||||
|
||||
bool AsBool() const {
|
||||
return (type_ == TYPE_BOOL ? ReadUInt64(data_, parent_width_)
|
||||
return (type_ == FBT_BOOL ? ReadUInt64(data_, parent_width_)
|
||||
: AsUInt64()) != 0;
|
||||
}
|
||||
|
||||
@@ -380,22 +383,22 @@ class Reference {
|
||||
// Truncates floats, strings are attempted to be parsed for a number,
|
||||
// vectors/maps return their size. Returns 0 if all else fails.
|
||||
int64_t AsInt64() const {
|
||||
if (type_ == TYPE_INT) {
|
||||
if (type_ == FBT_INT) {
|
||||
// A fast path for the common case.
|
||||
return ReadInt64(data_, parent_width_);
|
||||
} else
|
||||
switch (type_) {
|
||||
case TYPE_INDIRECT_INT: return ReadInt64(Indirect(), byte_width_);
|
||||
case TYPE_UINT: return ReadUInt64(data_, parent_width_);
|
||||
case TYPE_INDIRECT_UINT: return ReadUInt64(Indirect(), byte_width_);
|
||||
case TYPE_FLOAT:
|
||||
case FBT_INDIRECT_INT: return ReadInt64(Indirect(), byte_width_);
|
||||
case FBT_UINT: return ReadUInt64(data_, parent_width_);
|
||||
case FBT_INDIRECT_UINT: return ReadUInt64(Indirect(), byte_width_);
|
||||
case FBT_FLOAT:
|
||||
return static_cast<int64_t>(ReadDouble(data_, parent_width_));
|
||||
case TYPE_INDIRECT_FLOAT:
|
||||
case FBT_INDIRECT_FLOAT:
|
||||
return static_cast<int64_t>(ReadDouble(Indirect(), byte_width_));
|
||||
case TYPE_NULL: return 0;
|
||||
case TYPE_STRING: return flatbuffers::StringToInt(AsString().c_str());
|
||||
case TYPE_VECTOR: return static_cast<int64_t>(AsVector().size());
|
||||
case TYPE_BOOL: return ReadInt64(data_, parent_width_);
|
||||
case FBT_NULL: return 0;
|
||||
case FBT_STRING: return flatbuffers::StringToInt(AsString().c_str());
|
||||
case FBT_VECTOR: return static_cast<int64_t>(AsVector().size());
|
||||
case FBT_BOOL: return ReadInt64(data_, parent_width_);
|
||||
default:
|
||||
// Convert other things to int.
|
||||
return 0;
|
||||
@@ -409,22 +412,22 @@ class Reference {
|
||||
int8_t AsInt8() const { return static_cast<int8_t>(AsInt64()); }
|
||||
|
||||
uint64_t AsUInt64() const {
|
||||
if (type_ == TYPE_UINT) {
|
||||
if (type_ == FBT_UINT) {
|
||||
// A fast path for the common case.
|
||||
return ReadUInt64(data_, parent_width_);
|
||||
} else
|
||||
switch (type_) {
|
||||
case TYPE_INDIRECT_UINT: return ReadUInt64(Indirect(), byte_width_);
|
||||
case TYPE_INT: return ReadInt64(data_, parent_width_);
|
||||
case TYPE_INDIRECT_INT: return ReadInt64(Indirect(), byte_width_);
|
||||
case TYPE_FLOAT:
|
||||
case FBT_INDIRECT_UINT: return ReadUInt64(Indirect(), byte_width_);
|
||||
case FBT_INT: return ReadInt64(data_, parent_width_);
|
||||
case FBT_INDIRECT_INT: return ReadInt64(Indirect(), byte_width_);
|
||||
case FBT_FLOAT:
|
||||
return static_cast<uint64_t>(ReadDouble(data_, parent_width_));
|
||||
case TYPE_INDIRECT_FLOAT:
|
||||
case FBT_INDIRECT_FLOAT:
|
||||
return static_cast<uint64_t>(ReadDouble(Indirect(), byte_width_));
|
||||
case TYPE_NULL: return 0;
|
||||
case TYPE_STRING: return flatbuffers::StringToUInt(AsString().c_str());
|
||||
case TYPE_VECTOR: return static_cast<uint64_t>(AsVector().size());
|
||||
case TYPE_BOOL: return ReadUInt64(data_, parent_width_);
|
||||
case FBT_NULL: return 0;
|
||||
case FBT_STRING: return flatbuffers::StringToUInt(AsString().c_str());
|
||||
case FBT_VECTOR: return static_cast<uint64_t>(AsVector().size());
|
||||
case FBT_BOOL: return ReadUInt64(data_, parent_width_);
|
||||
default:
|
||||
// Convert other things to uint.
|
||||
return 0;
|
||||
@@ -436,24 +439,24 @@ class Reference {
|
||||
uint8_t AsUInt8() const { return static_cast<uint8_t>(AsUInt64()); }
|
||||
|
||||
double AsDouble() const {
|
||||
if (type_ == TYPE_FLOAT) {
|
||||
if (type_ == FBT_FLOAT) {
|
||||
// A fast path for the common case.
|
||||
return ReadDouble(data_, parent_width_);
|
||||
} else
|
||||
switch (type_) {
|
||||
case TYPE_INDIRECT_FLOAT: return ReadDouble(Indirect(), byte_width_);
|
||||
case TYPE_INT:
|
||||
case FBT_INDIRECT_FLOAT: return ReadDouble(Indirect(), byte_width_);
|
||||
case FBT_INT:
|
||||
return static_cast<double>(ReadInt64(data_, parent_width_));
|
||||
case TYPE_UINT:
|
||||
case FBT_UINT:
|
||||
return static_cast<double>(ReadUInt64(data_, parent_width_));
|
||||
case TYPE_INDIRECT_INT:
|
||||
case FBT_INDIRECT_INT:
|
||||
return static_cast<double>(ReadInt64(Indirect(), byte_width_));
|
||||
case TYPE_INDIRECT_UINT:
|
||||
case FBT_INDIRECT_UINT:
|
||||
return static_cast<double>(ReadUInt64(Indirect(), byte_width_));
|
||||
case TYPE_NULL: return 0.0;
|
||||
case TYPE_STRING: return strtod(AsString().c_str(), nullptr);
|
||||
case TYPE_VECTOR: return static_cast<double>(AsVector().size());
|
||||
case TYPE_BOOL:
|
||||
case FBT_NULL: return 0.0;
|
||||
case FBT_STRING: return strtod(AsString().c_str(), nullptr);
|
||||
case FBT_VECTOR: return static_cast<double>(AsVector().size());
|
||||
case FBT_BOOL:
|
||||
return static_cast<double>(ReadUInt64(data_, parent_width_));
|
||||
default:
|
||||
// Convert strings and other things to float.
|
||||
@@ -464,7 +467,7 @@ class Reference {
|
||||
float AsFloat() const { return static_cast<float>(AsDouble()); }
|
||||
|
||||
const char *AsKey() const {
|
||||
if (type_ == TYPE_KEY) {
|
||||
if (type_ == FBT_KEY) {
|
||||
return reinterpret_cast<const char *>(Indirect());
|
||||
} else {
|
||||
return "";
|
||||
@@ -473,7 +476,7 @@ class Reference {
|
||||
|
||||
// This function returns the empty string if you try to read a not-string.
|
||||
String AsString() const {
|
||||
if (type_ == TYPE_STRING) {
|
||||
if (type_ == FBT_STRING) {
|
||||
return String(Indirect(), byte_width_);
|
||||
} else {
|
||||
return String::EmptyString();
|
||||
@@ -492,17 +495,17 @@ class Reference {
|
||||
// they always do). keys_quoted determines if keys are quoted, at any level.
|
||||
// TODO(wvo): add further options to have indentation/newlines.
|
||||
void ToString(bool strings_quoted, bool keys_quoted, std::string &s) const {
|
||||
if (type_ == TYPE_STRING) {
|
||||
if (type_ == FBT_STRING) {
|
||||
String str(Indirect(), byte_width_);
|
||||
if (strings_quoted) {
|
||||
flatbuffers::EscapeString(str.c_str(), str.length(), &s, true);
|
||||
flatbuffers::EscapeString(str.c_str(), str.length(), &s, true, false);
|
||||
} else {
|
||||
s.append(str.c_str(), str.length());
|
||||
}
|
||||
} else if (IsKey()) {
|
||||
auto str = AsKey();
|
||||
if (keys_quoted) {
|
||||
flatbuffers::EscapeString(str, strlen(str), &s, true);
|
||||
flatbuffers::EscapeString(str, strlen(str), &s, true, false);
|
||||
} else {
|
||||
s += str;
|
||||
}
|
||||
@@ -544,7 +547,7 @@ class Reference {
|
||||
// This function returns the empty blob if you try to read a not-blob.
|
||||
// Strings can be viewed as blobs too.
|
||||
Blob AsBlob() const {
|
||||
if (type_ == TYPE_BLOB || type_ == TYPE_STRING) {
|
||||
if (type_ == FBT_BLOB || type_ == FBT_STRING) {
|
||||
return Blob(Indirect(), byte_width_);
|
||||
} else {
|
||||
return Blob::EmptyBlob();
|
||||
@@ -554,7 +557,7 @@ class Reference {
|
||||
// This function returns the empty vector if you try to read a not-vector.
|
||||
// Maps can be viewed as vectors too.
|
||||
Vector AsVector() const {
|
||||
if (type_ == TYPE_VECTOR || type_ == TYPE_MAP) {
|
||||
if (type_ == FBT_VECTOR || type_ == FBT_MAP) {
|
||||
return Vector(Indirect(), byte_width_);
|
||||
} else {
|
||||
return Vector::EmptyVector();
|
||||
@@ -562,7 +565,7 @@ class Reference {
|
||||
}
|
||||
|
||||
TypedVector AsTypedVector() const {
|
||||
if (IsTypedVector(type_)) {
|
||||
if (IsTypedVector()) {
|
||||
return TypedVector(Indirect(), byte_width_,
|
||||
ToTypedVectorElementType(type_));
|
||||
} else {
|
||||
@@ -571,7 +574,7 @@ class Reference {
|
||||
}
|
||||
|
||||
FixedTypedVector AsFixedTypedVector() const {
|
||||
if (IsFixedTypedVector(type_)) {
|
||||
if (IsFixedTypedVector()) {
|
||||
uint8_t len = 0;
|
||||
auto vtype = ToFixedTypedVectorElementType(type_, &len);
|
||||
return FixedTypedVector(Indirect(), byte_width_, vtype, len);
|
||||
@@ -581,7 +584,7 @@ class Reference {
|
||||
}
|
||||
|
||||
Map AsMap() const {
|
||||
if (type_ == TYPE_MAP) {
|
||||
if (type_ == FBT_MAP) {
|
||||
return Map(Indirect(), byte_width_);
|
||||
} else {
|
||||
return Map::EmptyMap();
|
||||
@@ -597,14 +600,14 @@ class Reference {
|
||||
// To avoid this, you can construct the values you intend to mutate using
|
||||
// Builder::ForceMinimumBitWidth.
|
||||
bool MutateInt(int64_t i) {
|
||||
if (type_ == TYPE_INT) {
|
||||
if (type_ == FBT_INT) {
|
||||
return Mutate(data_, i, parent_width_, WidthI(i));
|
||||
} else if (type_ == TYPE_INDIRECT_INT) {
|
||||
} else if (type_ == FBT_INDIRECT_INT) {
|
||||
return Mutate(Indirect(), i, byte_width_, WidthI(i));
|
||||
} else if (type_ == TYPE_UINT) {
|
||||
} else if (type_ == FBT_UINT) {
|
||||
auto u = static_cast<uint64_t>(i);
|
||||
return Mutate(data_, u, parent_width_, WidthU(u));
|
||||
} else if (type_ == TYPE_INDIRECT_UINT) {
|
||||
} else if (type_ == FBT_INDIRECT_UINT) {
|
||||
auto u = static_cast<uint64_t>(i);
|
||||
return Mutate(Indirect(), u, byte_width_, WidthU(u));
|
||||
} else {
|
||||
@@ -613,18 +616,18 @@ class Reference {
|
||||
}
|
||||
|
||||
bool MutateBool(bool b) {
|
||||
return type_ == TYPE_BOOL && Mutate(data_, b, parent_width_, BIT_WIDTH_8);
|
||||
return type_ == FBT_BOOL && Mutate(data_, b, parent_width_, BIT_WIDTH_8);
|
||||
}
|
||||
|
||||
bool MutateUInt(uint64_t u) {
|
||||
if (type_ == TYPE_UINT) {
|
||||
if (type_ == FBT_UINT) {
|
||||
return Mutate(data_, u, parent_width_, WidthU(u));
|
||||
} else if (type_ == TYPE_INDIRECT_UINT) {
|
||||
} else if (type_ == FBT_INDIRECT_UINT) {
|
||||
return Mutate(Indirect(), u, byte_width_, WidthU(u));
|
||||
} else if (type_ == TYPE_INT) {
|
||||
} else if (type_ == FBT_INT) {
|
||||
auto i = static_cast<int64_t>(u);
|
||||
return Mutate(data_, i, parent_width_, WidthI(i));
|
||||
} else if (type_ == TYPE_INDIRECT_INT) {
|
||||
} else if (type_ == FBT_INDIRECT_INT) {
|
||||
auto i = static_cast<int64_t>(u);
|
||||
return Mutate(Indirect(), i, byte_width_, WidthI(i));
|
||||
} else {
|
||||
@@ -633,9 +636,9 @@ class Reference {
|
||||
}
|
||||
|
||||
bool MutateFloat(float f) {
|
||||
if (type_ == TYPE_FLOAT) {
|
||||
if (type_ == FBT_FLOAT) {
|
||||
return MutateF(data_, f, parent_width_, BIT_WIDTH_32);
|
||||
} else if (type_ == TYPE_INDIRECT_FLOAT) {
|
||||
} else if (type_ == FBT_INDIRECT_FLOAT) {
|
||||
return MutateF(Indirect(), f, byte_width_, BIT_WIDTH_32);
|
||||
} else {
|
||||
return false;
|
||||
@@ -643,9 +646,9 @@ class Reference {
|
||||
}
|
||||
|
||||
bool MutateFloat(double d) {
|
||||
if (type_ == TYPE_FLOAT) {
|
||||
if (type_ == FBT_FLOAT) {
|
||||
return MutateF(data_, d, parent_width_, WidthF(d));
|
||||
} else if (type_ == TYPE_INDIRECT_FLOAT) {
|
||||
} else if (type_ == FBT_INDIRECT_FLOAT) {
|
||||
return MutateF(Indirect(), d, byte_width_, WidthF(d));
|
||||
} else {
|
||||
return false;
|
||||
@@ -690,7 +693,7 @@ class Reference {
|
||||
return Mutate(dest, static_cast<double>(t), byte_width, value_width);
|
||||
if (byte_width == sizeof(float))
|
||||
return Mutate(dest, static_cast<float>(t), byte_width, value_width);
|
||||
assert(false);
|
||||
FLATBUFFERS_ASSERT(false);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -735,7 +738,7 @@ inline uint8_t PackedType(BitWidth bit_width, Type type) {
|
||||
return static_cast<uint8_t>(bit_width | (type << 2));
|
||||
}
|
||||
|
||||
inline uint8_t NullPackedType() { return PackedType(BIT_WIDTH_8, TYPE_NULL); }
|
||||
inline uint8_t NullPackedType() { return PackedType(BIT_WIDTH_8, FBT_NULL); }
|
||||
|
||||
// Vector accessors.
|
||||
// Note: if you try to access outside of bounds, you get a Null value back
|
||||
@@ -870,16 +873,16 @@ class Builder FLATBUFFERS_FINAL_CLASS {
|
||||
Null();
|
||||
}
|
||||
|
||||
void Int(int64_t i) { stack_.push_back(Value(i, TYPE_INT, WidthI(i))); }
|
||||
void Int(int64_t i) { stack_.push_back(Value(i, FBT_INT, WidthI(i))); }
|
||||
void Int(const char *key, int64_t i) {
|
||||
Key(key);
|
||||
Int(i);
|
||||
}
|
||||
|
||||
void UInt(uint64_t u) { stack_.push_back(Value(u, TYPE_UINT, WidthU(u))); }
|
||||
void UInt(uint64_t u) { stack_.push_back(Value(u, FBT_UINT, WidthU(u))); }
|
||||
void UInt(const char *key, uint64_t u) {
|
||||
Key(key);
|
||||
Int(u);
|
||||
UInt(u);
|
||||
}
|
||||
|
||||
void Float(float f) { stack_.push_back(Value(f)); }
|
||||
@@ -900,14 +903,14 @@ class Builder FLATBUFFERS_FINAL_CLASS {
|
||||
Bool(b);
|
||||
}
|
||||
|
||||
void IndirectInt(int64_t i) { PushIndirect(i, TYPE_INDIRECT_INT, WidthI(i)); }
|
||||
void IndirectInt(int64_t i) { PushIndirect(i, FBT_INDIRECT_INT, WidthI(i)); }
|
||||
void IndirectInt(const char *key, int64_t i) {
|
||||
Key(key);
|
||||
IndirectInt(i);
|
||||
}
|
||||
|
||||
void IndirectUInt(uint64_t u) {
|
||||
PushIndirect(u, TYPE_INDIRECT_UINT, WidthU(u));
|
||||
PushIndirect(u, FBT_INDIRECT_UINT, WidthU(u));
|
||||
}
|
||||
void IndirectUInt(const char *key, uint64_t u) {
|
||||
Key(key);
|
||||
@@ -915,7 +918,7 @@ class Builder FLATBUFFERS_FINAL_CLASS {
|
||||
}
|
||||
|
||||
void IndirectFloat(float f) {
|
||||
PushIndirect(f, TYPE_INDIRECT_FLOAT, BIT_WIDTH_32);
|
||||
PushIndirect(f, FBT_INDIRECT_FLOAT, BIT_WIDTH_32);
|
||||
}
|
||||
void IndirectFloat(const char *key, float f) {
|
||||
Key(key);
|
||||
@@ -923,7 +926,7 @@ class Builder FLATBUFFERS_FINAL_CLASS {
|
||||
}
|
||||
|
||||
void IndirectDouble(double f) {
|
||||
PushIndirect(f, TYPE_INDIRECT_FLOAT, WidthF(f));
|
||||
PushIndirect(f, FBT_INDIRECT_FLOAT, WidthF(f));
|
||||
}
|
||||
void IndirectDouble(const char *key, double d) {
|
||||
Key(key);
|
||||
@@ -944,7 +947,7 @@ class Builder FLATBUFFERS_FINAL_CLASS {
|
||||
key_pool.insert(sloc);
|
||||
}
|
||||
}
|
||||
stack_.push_back(Value(static_cast<uint64_t>(sloc), TYPE_KEY, BIT_WIDTH_8));
|
||||
stack_.push_back(Value(static_cast<uint64_t>(sloc), FBT_KEY, BIT_WIDTH_8));
|
||||
return sloc;
|
||||
}
|
||||
|
||||
@@ -953,7 +956,7 @@ class Builder FLATBUFFERS_FINAL_CLASS {
|
||||
|
||||
size_t String(const char *str, size_t len) {
|
||||
auto reset_to = buf_.size();
|
||||
auto sloc = CreateBlob(str, len, 1, TYPE_STRING);
|
||||
auto sloc = CreateBlob(str, len, 1, FBT_STRING);
|
||||
if (flags_ & BUILDER_FLAG_SHARE_STRINGS) {
|
||||
StringOffset so(sloc, len);
|
||||
auto it = string_pool.find(so);
|
||||
@@ -991,10 +994,10 @@ class Builder FLATBUFFERS_FINAL_CLASS {
|
||||
}
|
||||
|
||||
size_t Blob(const void *data, size_t len) {
|
||||
return CreateBlob(data, len, 0, TYPE_BLOB);
|
||||
return CreateBlob(data, len, 0, FBT_BLOB);
|
||||
}
|
||||
size_t Blob(const std::vector<uint8_t> &v) {
|
||||
return CreateBlob(flatbuffers::vector_data(v), v.size(), 0, TYPE_BLOB);
|
||||
return CreateBlob(flatbuffers::vector_data(v), v.size(), 0, FBT_BLOB);
|
||||
}
|
||||
|
||||
// TODO(wvo): support all the FlexBuffer types (like flexbuffers::String),
|
||||
@@ -1026,11 +1029,11 @@ class Builder FLATBUFFERS_FINAL_CLASS {
|
||||
// We should have interleaved keys and values on the stack.
|
||||
// Make sure it is an even number:
|
||||
auto len = stack_.size() - start;
|
||||
assert(!(len & 1));
|
||||
FLATBUFFERS_ASSERT(!(len & 1));
|
||||
len /= 2;
|
||||
// Make sure keys are all strings:
|
||||
for (auto key = start; key < stack_.size(); key += 2) {
|
||||
assert(stack_[key].type_ == TYPE_KEY);
|
||||
FLATBUFFERS_ASSERT(stack_[key].type_ == FBT_KEY);
|
||||
}
|
||||
// Now sort values, so later we can do a binary seach lookup.
|
||||
// We want to sort 2 array elements at a time.
|
||||
@@ -1061,7 +1064,7 @@ class Builder FLATBUFFERS_FINAL_CLASS {
|
||||
// TODO: Have to check for pointer equality, as some sort
|
||||
// implementation apparently call this function with the same
|
||||
// element?? Why?
|
||||
assert(comp || &a == &b);
|
||||
FLATBUFFERS_ASSERT(comp || &a == &b);
|
||||
return comp < 0;
|
||||
});
|
||||
// First create a vector out of all keys.
|
||||
@@ -1141,9 +1144,9 @@ class Builder FLATBUFFERS_FINAL_CLASS {
|
||||
template<typename T> size_t FixedTypedVector(const T *elems, size_t len) {
|
||||
// We only support a few fixed vector lengths. Anything bigger use a
|
||||
// regular typed vector.
|
||||
assert(len >= 2 && len <= 4);
|
||||
FLATBUFFERS_ASSERT(len >= 2 && len <= 4);
|
||||
// And only scalar values.
|
||||
assert(flatbuffers::is_scalar<T>::value);
|
||||
static_assert(flatbuffers::is_scalar<T>::value, "Unrelated types");
|
||||
return ScalarVector(elems, len, true);
|
||||
}
|
||||
|
||||
@@ -1222,7 +1225,7 @@ class Builder FLATBUFFERS_FINAL_CLASS {
|
||||
// in a parent. You need to have exactly one root to finish a buffer.
|
||||
// Check your Start/End calls are matched, and all objects are inside
|
||||
// some other object.
|
||||
assert(stack_.size() == 1);
|
||||
FLATBUFFERS_ASSERT(stack_.size() == 1);
|
||||
|
||||
// Write root value.
|
||||
auto byte_width = Align(stack_[0].ElemWidth(buf_.size(), 0));
|
||||
@@ -1240,7 +1243,7 @@ class Builder FLATBUFFERS_FINAL_CLASS {
|
||||
// If you get this assert, you're attempting to get access a buffer
|
||||
// which hasn't been finished yet. Be sure to call
|
||||
// Builder::Finish with your root object.
|
||||
assert(finished_);
|
||||
FLATBUFFERS_ASSERT(finished_);
|
||||
}
|
||||
|
||||
// Align to prepare for writing a scalar with a certain size.
|
||||
@@ -1257,7 +1260,7 @@ class Builder FLATBUFFERS_FINAL_CLASS {
|
||||
}
|
||||
|
||||
template<typename T> void Write(T val, size_t byte_width) {
|
||||
assert(sizeof(T) >= byte_width);
|
||||
FLATBUFFERS_ASSERT(sizeof(T) >= byte_width);
|
||||
val = flatbuffers::EndianScalar(val);
|
||||
WriteBytes(&val, byte_width);
|
||||
}
|
||||
@@ -1268,13 +1271,13 @@ class Builder FLATBUFFERS_FINAL_CLASS {
|
||||
case 4: Write(static_cast<float>(f), byte_width); break;
|
||||
// case 2: Write(static_cast<half>(f), byte_width); break;
|
||||
// case 1: Write(static_cast<quarter>(f), byte_width); break;
|
||||
default: assert(0);
|
||||
default: FLATBUFFERS_ASSERT(0);
|
||||
}
|
||||
}
|
||||
|
||||
void WriteOffset(uint64_t o, uint8_t byte_width) {
|
||||
auto reloff = buf_.size() - o;
|
||||
assert(byte_width == 8 || reloff < 1ULL << (byte_width * 8));
|
||||
FLATBUFFERS_ASSERT(byte_width == 8 || reloff < 1ULL << (byte_width * 8));
|
||||
Write(reloff, byte_width);
|
||||
}
|
||||
|
||||
@@ -1291,18 +1294,18 @@ class Builder FLATBUFFERS_FINAL_CLASS {
|
||||
case 2: return BIT_WIDTH_16;
|
||||
case 4: return BIT_WIDTH_32;
|
||||
case 8: return BIT_WIDTH_64;
|
||||
default: assert(false); return BIT_WIDTH_64;
|
||||
default: FLATBUFFERS_ASSERT(false); return BIT_WIDTH_64;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T> static Type GetScalarType() {
|
||||
assert(flatbuffers::is_scalar<T>::value);
|
||||
static_assert(flatbuffers::is_scalar<T>::value, "Unrelated types");
|
||||
return flatbuffers::is_floating_point<T>::value
|
||||
? TYPE_FLOAT
|
||||
? FBT_FLOAT
|
||||
: flatbuffers::is_same<T, bool>::value
|
||||
? TYPE_BOOL
|
||||
: (flatbuffers::is_unsigned<T>::value ? TYPE_UINT
|
||||
: TYPE_INT);
|
||||
? FBT_BOOL
|
||||
: (flatbuffers::is_unsigned<T>::value ? FBT_UINT
|
||||
: FBT_INT);
|
||||
}
|
||||
|
||||
struct Value {
|
||||
@@ -1317,11 +1320,11 @@ class Builder FLATBUFFERS_FINAL_CLASS {
|
||||
// For scalars: of itself, for vector: of its elements, for string: length.
|
||||
BitWidth min_bit_width_;
|
||||
|
||||
Value() : i_(0), type_(TYPE_NULL), min_bit_width_(BIT_WIDTH_8) {}
|
||||
Value() : i_(0), type_(FBT_NULL), min_bit_width_(BIT_WIDTH_8) {}
|
||||
|
||||
Value(bool b)
|
||||
: u_(static_cast<uint64_t>(b)),
|
||||
type_(TYPE_BOOL),
|
||||
type_(FBT_BOOL),
|
||||
min_bit_width_(BIT_WIDTH_8) {}
|
||||
|
||||
Value(int64_t i, Type t, BitWidth bw)
|
||||
@@ -1329,8 +1332,8 @@ class Builder FLATBUFFERS_FINAL_CLASS {
|
||||
Value(uint64_t u, Type t, BitWidth bw)
|
||||
: u_(u), type_(t), min_bit_width_(bw) {}
|
||||
|
||||
Value(float f) : f_(f), type_(TYPE_FLOAT), min_bit_width_(BIT_WIDTH_32) {}
|
||||
Value(double f) : f_(f), type_(TYPE_FLOAT), min_bit_width_(WidthF(f)) {}
|
||||
Value(float f) : f_(f), type_(FBT_FLOAT), min_bit_width_(BIT_WIDTH_32) {}
|
||||
Value(double f) : f_(f), type_(FBT_FLOAT), min_bit_width_(WidthF(f)) {}
|
||||
|
||||
uint8_t StoredPackedType(BitWidth parent_bit_width_ = BIT_WIDTH_8) const {
|
||||
return PackedType(StoredWidth(parent_bit_width_), type_);
|
||||
@@ -1360,7 +1363,7 @@ class Builder FLATBUFFERS_FINAL_CLASS {
|
||||
byte_width)
|
||||
return bit_width;
|
||||
}
|
||||
assert(false); // Must match one of the sizes above.
|
||||
FLATBUFFERS_ASSERT(false); // Must match one of the sizes above.
|
||||
return BIT_WIDTH_64;
|
||||
}
|
||||
}
|
||||
@@ -1376,11 +1379,11 @@ class Builder FLATBUFFERS_FINAL_CLASS {
|
||||
|
||||
void WriteAny(const Value &val, uint8_t byte_width) {
|
||||
switch (val.type_) {
|
||||
case TYPE_NULL:
|
||||
case TYPE_INT: Write(val.i_, byte_width); break;
|
||||
case TYPE_BOOL:
|
||||
case TYPE_UINT: Write(val.u_, byte_width); break;
|
||||
case TYPE_FLOAT: WriteDouble(val.f_, byte_width); break;
|
||||
case FBT_NULL:
|
||||
case FBT_INT: Write(val.i_, byte_width); break;
|
||||
case FBT_BOOL:
|
||||
case FBT_UINT: Write(val.u_, byte_width); break;
|
||||
case FBT_FLOAT: WriteDouble(val.f_, byte_width); break;
|
||||
default: WriteOffset(val.u_, byte_width); break;
|
||||
}
|
||||
}
|
||||
@@ -1405,7 +1408,7 @@ class Builder FLATBUFFERS_FINAL_CLASS {
|
||||
// byte vector > 255 elements). For such types, write a "blob" instead.
|
||||
// TODO: instead of asserting, could write vector with larger elements
|
||||
// instead, though that would be wasteful.
|
||||
assert(WidthU(len) <= bit_width);
|
||||
FLATBUFFERS_ASSERT(WidthU(len) <= bit_width);
|
||||
if (!fixed) Write<uint64_t>(len, byte_width);
|
||||
auto vloc = buf_.size();
|
||||
for (size_t i = 0; i < len; i++) Write(elems[i], byte_width);
|
||||
@@ -1417,6 +1420,7 @@ class Builder FLATBUFFERS_FINAL_CLASS {
|
||||
|
||||
Value CreateVector(size_t start, size_t vec_len, size_t step, bool typed,
|
||||
bool fixed, const Value *keys = nullptr) {
|
||||
FLATBUFFERS_ASSERT(!fixed || typed); // typed=false, fixed=true combination is not supported.
|
||||
// Figure out smallest bit width we can store this vector with.
|
||||
auto bit_width = (std::max)(force_min_bit_width_, WidthU(vec_len));
|
||||
auto prefix_elems = 1;
|
||||
@@ -1426,7 +1430,7 @@ class Builder FLATBUFFERS_FINAL_CLASS {
|
||||
bit_width = (std::max)(bit_width, keys->ElemWidth(buf_.size(), 0));
|
||||
prefix_elems += 2;
|
||||
}
|
||||
Type vector_type = TYPE_KEY;
|
||||
Type vector_type = FBT_KEY;
|
||||
// Check bit widths and types for all elements.
|
||||
for (size_t i = start; i < stack_.size(); i += step) {
|
||||
auto elem_width = stack_[i].ElemWidth(buf_.size(), i + prefix_elems);
|
||||
@@ -1437,13 +1441,13 @@ class Builder FLATBUFFERS_FINAL_CLASS {
|
||||
} else {
|
||||
// If you get this assert, you are writing a typed vector with
|
||||
// elements that are not all the same type.
|
||||
assert(vector_type == stack_[i].type_);
|
||||
FLATBUFFERS_ASSERT(vector_type == stack_[i].type_);
|
||||
}
|
||||
}
|
||||
}
|
||||
// If you get this assert, your fixed types are not one of:
|
||||
// Int / UInt / Float / Key.
|
||||
assert(IsTypedVectorElementType(vector_type));
|
||||
FLATBUFFERS_ASSERT(!fixed || IsTypedVectorElementType(vector_type));
|
||||
auto byte_width = Align(bit_width);
|
||||
// Write vector. First the keys width/offset if available, and size.
|
||||
if (keys) {
|
||||
@@ -1463,9 +1467,9 @@ class Builder FLATBUFFERS_FINAL_CLASS {
|
||||
}
|
||||
}
|
||||
return Value(static_cast<uint64_t>(vloc),
|
||||
keys ? TYPE_MAP
|
||||
keys ? FBT_MAP
|
||||
: (typed ? ToTypedVector(vector_type, fixed ? vec_len : 0)
|
||||
: TYPE_VECTOR),
|
||||
: FBT_VECTOR),
|
||||
bit_width);
|
||||
}
|
||||
|
||||
@@ -1483,7 +1487,7 @@ class Builder FLATBUFFERS_FINAL_CLASS {
|
||||
BitWidth force_min_bit_width_;
|
||||
|
||||
struct KeyOffsetCompare {
|
||||
KeyOffsetCompare(const std::vector<uint8_t> &buf) : buf_(&buf) {}
|
||||
explicit KeyOffsetCompare(const std::vector<uint8_t> &buf) : buf_(&buf) {}
|
||||
bool operator()(size_t a, size_t b) const {
|
||||
auto stra =
|
||||
reinterpret_cast<const char *>(flatbuffers::vector_data(*buf_) + a);
|
||||
@@ -1496,7 +1500,7 @@ class Builder FLATBUFFERS_FINAL_CLASS {
|
||||
|
||||
typedef std::pair<size_t, size_t> StringOffset;
|
||||
struct StringOffsetCompare {
|
||||
StringOffsetCompare(const std::vector<uint8_t> &buf) : buf_(&buf) {}
|
||||
explicit StringOffsetCompare(const std::vector<uint8_t> &buf) : buf_(&buf) {}
|
||||
bool operator()(const StringOffset &a, const StringOffset &b) const {
|
||||
auto stra = reinterpret_cast<const char *>(
|
||||
flatbuffers::vector_data(*buf_) + a.first);
|
||||
|
||||
@@ -88,17 +88,35 @@ class SliceAllocator : public Allocator {
|
||||
SliceAllocator(const SliceAllocator &other) = delete;
|
||||
SliceAllocator &operator=(const SliceAllocator &other) = delete;
|
||||
|
||||
SliceAllocator(SliceAllocator &&other)
|
||||
: slice_(grpc_empty_slice()) {
|
||||
// default-construct and swap idiom
|
||||
swap(other);
|
||||
}
|
||||
|
||||
SliceAllocator &operator=(SliceAllocator &&other) {
|
||||
// move-construct and swap idiom
|
||||
SliceAllocator temp(std::move(other));
|
||||
swap(temp);
|
||||
return *this;
|
||||
}
|
||||
|
||||
void swap(SliceAllocator &other) {
|
||||
using std::swap;
|
||||
swap(slice_, other.slice_);
|
||||
}
|
||||
|
||||
virtual ~SliceAllocator() { grpc_slice_unref(slice_); }
|
||||
|
||||
virtual uint8_t *allocate(size_t size) override {
|
||||
assert(GRPC_SLICE_IS_EMPTY(slice_));
|
||||
FLATBUFFERS_ASSERT(GRPC_SLICE_IS_EMPTY(slice_));
|
||||
slice_ = grpc_slice_malloc(size);
|
||||
return GRPC_SLICE_START_PTR(slice_);
|
||||
}
|
||||
|
||||
virtual void deallocate(uint8_t *p, size_t size) override {
|
||||
assert(p == GRPC_SLICE_START_PTR(slice_));
|
||||
assert(size == GRPC_SLICE_LENGTH(slice_));
|
||||
FLATBUFFERS_ASSERT(p == GRPC_SLICE_START_PTR(slice_));
|
||||
FLATBUFFERS_ASSERT(size == GRPC_SLICE_LENGTH(slice_));
|
||||
grpc_slice_unref(slice_);
|
||||
slice_ = grpc_empty_slice();
|
||||
}
|
||||
@@ -106,9 +124,9 @@ class SliceAllocator : public Allocator {
|
||||
virtual uint8_t *reallocate_downward(uint8_t *old_p, size_t old_size,
|
||||
size_t new_size, size_t in_use_back,
|
||||
size_t in_use_front) override {
|
||||
assert(old_p == GRPC_SLICE_START_PTR(slice_));
|
||||
assert(old_size == GRPC_SLICE_LENGTH(slice_));
|
||||
assert(new_size > old_size);
|
||||
FLATBUFFERS_ASSERT(old_p == GRPC_SLICE_START_PTR(slice_));
|
||||
FLATBUFFERS_ASSERT(old_size == GRPC_SLICE_LENGTH(slice_));
|
||||
FLATBUFFERS_ASSERT(new_size > old_size);
|
||||
grpc_slice old_slice = slice_;
|
||||
grpc_slice new_slice = grpc_slice_malloc(new_size);
|
||||
uint8_t *new_p = GRPC_SLICE_START_PTR(new_slice);
|
||||
@@ -121,8 +139,8 @@ class SliceAllocator : public Allocator {
|
||||
|
||||
private:
|
||||
grpc_slice &get_slice(uint8_t *p, size_t size) {
|
||||
assert(p == GRPC_SLICE_START_PTR(slice_));
|
||||
assert(size == GRPC_SLICE_LENGTH(slice_));
|
||||
FLATBUFFERS_ASSERT(p == GRPC_SLICE_START_PTR(slice_));
|
||||
FLATBUFFERS_ASSERT(size == GRPC_SLICE_LENGTH(slice_));
|
||||
return slice_;
|
||||
}
|
||||
|
||||
@@ -151,6 +169,39 @@ class MessageBuilder : private detail::SliceAllocatorMember,
|
||||
MessageBuilder(const MessageBuilder &other) = delete;
|
||||
MessageBuilder &operator=(const MessageBuilder &other) = delete;
|
||||
|
||||
MessageBuilder(MessageBuilder &&other)
|
||||
: FlatBufferBuilder(1024, &slice_allocator_, false) {
|
||||
// Default construct and swap idiom.
|
||||
Swap(other);
|
||||
}
|
||||
|
||||
MessageBuilder &operator=(MessageBuilder &&other) {
|
||||
// Move construct a temporary and swap
|
||||
MessageBuilder temp(std::move(other));
|
||||
Swap(temp);
|
||||
return *this;
|
||||
}
|
||||
|
||||
void Swap(MessageBuilder &other) {
|
||||
slice_allocator_.swap(other.slice_allocator_);
|
||||
FlatBufferBuilder::Swap(other);
|
||||
// After swapping the FlatBufferBuilder, we swap back the allocator, which restores
|
||||
// the original allocator back in place. This is necessary because MessageBuilder's
|
||||
// allocator is its own member (SliceAllocatorMember). The allocator passed to
|
||||
// FlatBufferBuilder::vector_downward must point to this member.
|
||||
buf_.swap_allocator(other.buf_);
|
||||
}
|
||||
|
||||
// Releases the ownership of the buffer pointer.
|
||||
// Returns the size, offset, and the original grpc_slice that
|
||||
// allocated the buffer. Also see grpc_slice_unref().
|
||||
uint8_t *ReleaseRaw(size_t &size, size_t &offset, grpc_slice &slice) {
|
||||
uint8_t *buf = FlatBufferBuilder::ReleaseRaw(size, offset);
|
||||
slice = slice_allocator_.slice_;
|
||||
slice_allocator_.slice_ = grpc_empty_slice();
|
||||
return buf;
|
||||
}
|
||||
|
||||
~MessageBuilder() {}
|
||||
|
||||
// GetMessage extracts the subslice of the buffer corresponding to the
|
||||
@@ -162,10 +213,10 @@ class MessageBuilder : private detail::SliceAllocatorMember,
|
||||
auto msg_data = buf_.data(); // pointer to msg
|
||||
auto msg_size = buf_.size(); // size of msg
|
||||
// Do some sanity checks on data/size
|
||||
assert(msg_data);
|
||||
assert(msg_size);
|
||||
assert(msg_data >= buf_data);
|
||||
assert(msg_data + msg_size <= buf_data + buf_size);
|
||||
FLATBUFFERS_ASSERT(msg_data);
|
||||
FLATBUFFERS_ASSERT(msg_size);
|
||||
FLATBUFFERS_ASSERT(msg_data >= buf_data);
|
||||
FLATBUFFERS_ASSERT(msg_data + msg_size <= buf_data + buf_size);
|
||||
// Calculate offsets from the buffer start
|
||||
auto begin = msg_data - buf_data;
|
||||
auto end = begin + msg_size;
|
||||
|
||||
@@ -41,24 +41,24 @@ namespace flatbuffers {
|
||||
// of type tokens.
|
||||
// clang-format off
|
||||
#define FLATBUFFERS_GEN_TYPES_SCALAR(TD) \
|
||||
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 */
|
||||
TD(NONE, "", uint8_t, byte, byte, byte, uint8, u8) \
|
||||
TD(UTYPE, "", uint8_t, byte, byte, byte, uint8, u8) /* begin scalar/int */ \
|
||||
TD(BOOL, "bool", uint8_t, boolean,byte, bool, bool, bool) \
|
||||
TD(CHAR, "byte", int8_t, byte, int8, sbyte, int8, i8) \
|
||||
TD(UCHAR, "ubyte", uint8_t, byte, byte, byte, uint8, u8) \
|
||||
TD(SHORT, "short", int16_t, short, int16, short, int16, i16) \
|
||||
TD(USHORT, "ushort", uint16_t, short, uint16, ushort, uint16, u16) \
|
||||
TD(INT, "int", int32_t, int, int32, int, int32, i32) \
|
||||
TD(UINT, "uint", uint32_t, int, uint32, uint, uint32, u32) \
|
||||
TD(LONG, "long", int64_t, long, int64, long, int64, i64) \
|
||||
TD(ULONG, "ulong", uint64_t, long, uint64, ulong, uint64, u64) /* end int */ \
|
||||
TD(FLOAT, "float", float, float, float32, float, float32, f32) /* begin float */ \
|
||||
TD(DOUBLE, "double", double, double, float64, double, float64, f64) /* end float/scalar */
|
||||
#define FLATBUFFERS_GEN_TYPES_POINTER(TD) \
|
||||
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)
|
||||
TD(STRING, "string", Offset<void>, int, int, StringOffset, int, unused) \
|
||||
TD(VECTOR, "", Offset<void>, int, int, VectorOffset, int, unused) \
|
||||
TD(STRUCT, "", Offset<void>, int, int, int, int, unused) \
|
||||
TD(UNION, "", Offset<void>, int, int, int, int, unused)
|
||||
|
||||
// The fields are:
|
||||
// - enum
|
||||
@@ -68,12 +68,14 @@ namespace flatbuffers {
|
||||
// - Go type.
|
||||
// - C# / .Net type.
|
||||
// - Python type.
|
||||
// - Rust 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, PTYPE) \
|
||||
#define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, \
|
||||
RTYPE) \
|
||||
case BASE_TYPE_ ## ENUM: \
|
||||
// do something specific to CTYPE here
|
||||
FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
|
||||
@@ -90,13 +92,15 @@ switch (type) {
|
||||
__extension__ // Stop GCC complaining about trailing comma with -Wpendantic.
|
||||
#endif
|
||||
enum BaseType {
|
||||
#define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \
|
||||
#define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, \
|
||||
RTYPE) \
|
||||
BASE_TYPE_ ## ENUM,
|
||||
FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
|
||||
#undef FLATBUFFERS_TD
|
||||
};
|
||||
|
||||
#define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \
|
||||
#define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, \
|
||||
RTYPE) \
|
||||
static_assert(sizeof(CTYPE) <= sizeof(largest_scalar_t), \
|
||||
"define largest_scalar_t as " #CTYPE);
|
||||
FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
|
||||
@@ -111,6 +115,8 @@ inline bool IsFloat (BaseType t) { return t == BASE_TYPE_FLOAT ||
|
||||
inline bool IsLong (BaseType t) { return t == BASE_TYPE_LONG ||
|
||||
t == BASE_TYPE_ULONG; }
|
||||
inline bool IsBool (BaseType t) { return t == BASE_TYPE_BOOL; }
|
||||
inline bool IsOneByte(BaseType t) { return t >= BASE_TYPE_UTYPE &&
|
||||
t <= BASE_TYPE_UCHAR; }
|
||||
// clang-format on
|
||||
|
||||
extern const char *const kTypeNames[];
|
||||
@@ -181,7 +187,7 @@ template<typename T> class SymbolTable {
|
||||
dict.erase(it);
|
||||
dict[newname] = obj;
|
||||
} else {
|
||||
assert(false);
|
||||
FLATBUFFERS_ASSERT(false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -306,7 +312,7 @@ inline size_t InlineAlignment(const Type &type) {
|
||||
struct EnumVal {
|
||||
EnumVal(const std::string &_name, int64_t _val) : name(_name), value(_val) {}
|
||||
|
||||
Offset<reflection::EnumVal> Serialize(FlatBufferBuilder *builder) const;
|
||||
Offset<reflection::EnumVal> Serialize(FlatBufferBuilder *builder, const Parser &parser) const;
|
||||
|
||||
std::string name;
|
||||
std::vector<std::string> doc_comment;
|
||||
@@ -326,8 +332,7 @@ struct EnumDef : public Definition {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Offset<reflection::Enum> Serialize(FlatBufferBuilder *builder,
|
||||
const Parser &parser) const;
|
||||
Offset<reflection::Enum> Serialize(FlatBufferBuilder *builder, const Parser &parser) const;
|
||||
|
||||
SymbolTable<EnumVal> vals;
|
||||
bool is_union;
|
||||
@@ -342,14 +347,15 @@ inline bool EqualByName(const Type &a, const Type &b) {
|
||||
(a.enum_def == b.enum_def || a.enum_def->name == b.enum_def->name);
|
||||
}
|
||||
|
||||
struct RPCCall {
|
||||
std::string name;
|
||||
SymbolTable<Value> attributes;
|
||||
struct RPCCall : public Definition {
|
||||
Offset<reflection::RPCCall> Serialize(FlatBufferBuilder *builder, const Parser &parser) const;
|
||||
|
||||
StructDef *request, *response;
|
||||
std::vector<std::string> rpc_comment;
|
||||
};
|
||||
|
||||
struct ServiceDef : public Definition {
|
||||
Offset<reflection::Service> Serialize(FlatBufferBuilder *builder, const Parser &parser) const;
|
||||
|
||||
SymbolTable<RPCCall> calls;
|
||||
};
|
||||
|
||||
@@ -358,6 +364,7 @@ struct IDLOptions {
|
||||
bool strict_json;
|
||||
bool skip_js_exports;
|
||||
bool use_goog_js_export_format;
|
||||
bool use_ES6_js_export_format;
|
||||
bool output_default_scalars_in_json;
|
||||
int indent_step;
|
||||
bool output_enum_identifiers;
|
||||
@@ -372,6 +379,7 @@ struct IDLOptions {
|
||||
bool skip_unexpected_fields_in_json;
|
||||
bool generate_name_strings;
|
||||
bool generate_object_based_api;
|
||||
bool gen_compare;
|
||||
std::string cpp_object_api_pointer_type;
|
||||
std::string cpp_object_api_string_type;
|
||||
bool gen_nullable;
|
||||
@@ -379,15 +387,19 @@ struct IDLOptions {
|
||||
std::string object_suffix;
|
||||
bool union_value_namespacing;
|
||||
bool allow_non_utf8;
|
||||
bool natural_utf8;
|
||||
std::string include_prefix;
|
||||
bool keep_include_path;
|
||||
bool binary_schema_comments;
|
||||
bool binary_schema_builtins;
|
||||
bool skip_flatbuffers_import;
|
||||
std::string go_import;
|
||||
std::string go_namespace;
|
||||
bool reexport_ts_modules;
|
||||
bool protobuf_ascii_alike;
|
||||
bool size_prefixed;
|
||||
std::string root_type;
|
||||
bool force_defaults;
|
||||
|
||||
// Possible options for the more general generator below.
|
||||
enum Language {
|
||||
@@ -402,6 +414,10 @@ struct IDLOptions {
|
||||
kBinary = 1 << 8,
|
||||
kTs = 1 << 9,
|
||||
kJsonSchema = 1 << 10,
|
||||
kDart = 1 << 11,
|
||||
kLua = 1 << 12,
|
||||
kLobster = 1 << 13,
|
||||
kRust = 1 << 14,
|
||||
kMAX
|
||||
};
|
||||
|
||||
@@ -415,10 +431,15 @@ struct IDLOptions {
|
||||
// for code generation.
|
||||
unsigned long lang_to_generate;
|
||||
|
||||
// If set (default behavior), empty string and vector fields will be set to
|
||||
// nullptr to make the flatbuffer more compact.
|
||||
bool set_empty_to_null;
|
||||
|
||||
IDLOptions()
|
||||
: strict_json(false),
|
||||
skip_js_exports(false),
|
||||
use_goog_js_export_format(false),
|
||||
use_ES6_js_export_format(false),
|
||||
output_default_scalars_in_json(false),
|
||||
indent_step(2),
|
||||
output_enum_identifiers(true),
|
||||
@@ -433,28 +454,51 @@ struct IDLOptions {
|
||||
skip_unexpected_fields_in_json(false),
|
||||
generate_name_strings(false),
|
||||
generate_object_based_api(false),
|
||||
gen_compare(false),
|
||||
cpp_object_api_pointer_type("std::unique_ptr"),
|
||||
gen_nullable(false),
|
||||
object_suffix("T"),
|
||||
union_value_namespacing(true),
|
||||
allow_non_utf8(false),
|
||||
natural_utf8(false),
|
||||
keep_include_path(false),
|
||||
binary_schema_comments(false),
|
||||
binary_schema_builtins(false),
|
||||
skip_flatbuffers_import(false),
|
||||
reexport_ts_modules(true),
|
||||
protobuf_ascii_alike(false),
|
||||
size_prefixed(false),
|
||||
force_defaults(false),
|
||||
lang(IDLOptions::kJava),
|
||||
mini_reflect(IDLOptions::kNone),
|
||||
lang_to_generate(0) {}
|
||||
lang_to_generate(0),
|
||||
set_empty_to_null(true) {}
|
||||
};
|
||||
|
||||
// This encapsulates where the parser is in the current source file.
|
||||
struct ParserState {
|
||||
ParserState() : cursor_(nullptr), line_(1), token_(-1) {}
|
||||
ParserState()
|
||||
: cursor_(nullptr), line_start_(nullptr), line_(0), token_(-1) {}
|
||||
|
||||
protected:
|
||||
void ResetState(const char *source) {
|
||||
cursor_ = source;
|
||||
line_ = 0;
|
||||
MarkNewLine();
|
||||
}
|
||||
|
||||
void MarkNewLine() {
|
||||
line_start_ = cursor_;
|
||||
line_ += 1;
|
||||
}
|
||||
|
||||
int64_t CursorPosition() const {
|
||||
FLATBUFFERS_ASSERT(cursor_ && line_start_ && cursor_ >= line_start_);
|
||||
return static_cast<int64_t>(cursor_ - line_start_);
|
||||
}
|
||||
|
||||
const char *cursor_;
|
||||
const char *line_start_;
|
||||
int line_; // the current line being parsed
|
||||
int token_;
|
||||
|
||||
@@ -485,7 +529,7 @@ class CheckedError {
|
||||
*this = other; // Use assignment operator.
|
||||
}
|
||||
|
||||
~CheckedError() { assert(has_been_checked_); }
|
||||
~CheckedError() { FLATBUFFERS_ASSERT(has_been_checked_); }
|
||||
|
||||
bool Check() {
|
||||
has_been_checked_ = true;
|
||||
@@ -517,7 +561,11 @@ class Parser : public ParserState {
|
||||
opts(options),
|
||||
uses_flexbuffers_(false),
|
||||
source_(nullptr),
|
||||
anonymous_counter(0) {
|
||||
anonymous_counter(0),
|
||||
recurse_protection_counter(0) {
|
||||
if (opts.force_defaults) {
|
||||
builder_.ForceDefaults(true);
|
||||
}
|
||||
// Start out with the empty namespace being current.
|
||||
empty_namespace_ = new Namespace();
|
||||
namespaces_.push_back(empty_namespace_);
|
||||
@@ -543,6 +591,7 @@ class Parser : public ParserState {
|
||||
known_attributes_["native_type"] = true;
|
||||
known_attributes_["native_default"] = true;
|
||||
known_attributes_["flexbuffer"] = true;
|
||||
known_attributes_["private"] = true;
|
||||
}
|
||||
|
||||
~Parser() {
|
||||
@@ -696,6 +745,15 @@ class Parser : public ParserState {
|
||||
bool SupportsVectorOfUnions() const;
|
||||
Namespace *UniqueNamespace(Namespace *ns);
|
||||
|
||||
enum { kMaxParsingDepth = 64 };
|
||||
FLATBUFFERS_CHECKED_ERROR RecurseError();
|
||||
template<typename F> CheckedError Recurse(F f) {
|
||||
if (++recurse_protection_counter >= kMaxParsingDepth) return RecurseError();
|
||||
auto ce = f();
|
||||
recurse_protection_counter--;
|
||||
return ce;
|
||||
}
|
||||
|
||||
public:
|
||||
SymbolTable<Type> types_;
|
||||
SymbolTable<StructDef> structs_;
|
||||
@@ -728,6 +786,7 @@ class Parser : public ParserState {
|
||||
std::vector<std::pair<Value, FieldDef *>> field_stack_;
|
||||
|
||||
int anonymous_counter;
|
||||
int recurse_protection_counter;
|
||||
};
|
||||
|
||||
// Utility functions for multiple generators:
|
||||
@@ -762,6 +821,10 @@ extern bool GenerateCPP(const Parser &parser,
|
||||
const std::string &path,
|
||||
const std::string &file_name);
|
||||
|
||||
extern bool GenerateDart(const Parser &parser,
|
||||
const std::string &path,
|
||||
const std::string &file_name);
|
||||
|
||||
// Generate JavaScript or TypeScript code from the definitions in the Parser object.
|
||||
// See idl_gen_js.
|
||||
extern bool GenerateJS(const Parser &parser,
|
||||
@@ -786,6 +849,24 @@ extern bool GeneratePython(const Parser &parser,
|
||||
const std::string &path,
|
||||
const std::string &file_name);
|
||||
|
||||
// Generate Lobster files from the definitions in the Parser object.
|
||||
// See idl_gen_lobster.cpp.
|
||||
extern bool GenerateLobster(const Parser &parser,
|
||||
const std::string &path,
|
||||
const std::string &file_name);
|
||||
|
||||
// Generate Lua files from the definitions in the Parser object.
|
||||
// See idl_gen_lua.cpp.
|
||||
extern bool GenerateLua(const Parser &parser,
|
||||
const std::string &path,
|
||||
const std::string &file_name);
|
||||
|
||||
// Generate Rust files from the definitions in the Parser object.
|
||||
// See idl_gen_rust.cpp.
|
||||
extern bool GenerateRust(const Parser &parser,
|
||||
const std::string &path,
|
||||
const std::string &file_name);
|
||||
|
||||
// Generate Json schema file
|
||||
// See idl_gen_json_schema.cpp.
|
||||
extern bool GenerateJsonSchema(const Parser &parser,
|
||||
@@ -818,6 +899,18 @@ extern std::string CPPMakeRule(const Parser &parser,
|
||||
const std::string &path,
|
||||
const std::string &file_name);
|
||||
|
||||
// Generate a make rule for the generated Dart code
|
||||
// see idl_gen_dart.cpp
|
||||
extern std::string DartMakeRule(const Parser &parser,
|
||||
const std::string &path,
|
||||
const std::string &file_name);
|
||||
|
||||
// Generate a make rule for the generated Rust code.
|
||||
// See idl_gen_rust.cpp.
|
||||
extern std::string RustMakeRule(const Parser &parser,
|
||||
const std::string &path,
|
||||
const std::string &file_name);
|
||||
|
||||
// Generate a make rule for the generated Java/C#/... files.
|
||||
// See idl_gen_general.cpp.
|
||||
extern std::string GeneralMakeRule(const Parser &parser,
|
||||
|
||||
@@ -89,9 +89,9 @@ inline size_t InlineSize(ElementaryType type, const TypeTable *type_table) {
|
||||
case ST_TABLE:
|
||||
case ST_UNION: return 4;
|
||||
case ST_STRUCT: return type_table->values[type_table->num_elems];
|
||||
default: assert(false); return 1;
|
||||
default: FLATBUFFERS_ASSERT(false); return 1;
|
||||
}
|
||||
default: assert(false); return 1;
|
||||
default: FLATBUFFERS_ASSERT(false); return 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -190,7 +190,7 @@ inline void IterateValue(ElementaryType type, const uint8_t *val,
|
||||
case ST_STRUCT: IterateObject(val, type_table, visitor); break;
|
||||
case ST_UNION: {
|
||||
val += ReadScalar<uoffset_t>(val);
|
||||
assert(prev_val);
|
||||
FLATBUFFERS_ASSERT(prev_val);
|
||||
auto union_type = *prev_val; // Always a uint8_t.
|
||||
if (vector_index >= 0) {
|
||||
auto type_vec = reinterpret_cast<const Vector<uint8_t> *>(prev_val);
|
||||
@@ -217,7 +217,7 @@ inline void IterateValue(ElementaryType type, const uint8_t *val,
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ST_ENUM: assert(false); break;
|
||||
case ST_ENUM: FLATBUFFERS_ASSERT(false); break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -283,23 +283,54 @@ inline void IterateFlatBuffer(const uint8_t *buffer,
|
||||
|
||||
struct ToStringVisitor : public IterationVisitor {
|
||||
std::string s;
|
||||
void StartSequence() { s += "{ "; }
|
||||
void EndSequence() { s += " }"; }
|
||||
std::string d;
|
||||
bool q;
|
||||
std::string in;
|
||||
size_t indent_level;
|
||||
ToStringVisitor(std::string delimiter, bool quotes, std::string indent)
|
||||
: d(delimiter), q(quotes), in(indent), indent_level(0) {}
|
||||
ToStringVisitor(std::string delimiter)
|
||||
: d(delimiter), q(false), in(""), indent_level(0) {}
|
||||
|
||||
void append_indent() {
|
||||
for (size_t i = 0; i < indent_level; i++) { s += in; }
|
||||
}
|
||||
|
||||
void StartSequence() {
|
||||
s += "{";
|
||||
s += d;
|
||||
indent_level++;
|
||||
}
|
||||
void EndSequence() {
|
||||
s += d;
|
||||
indent_level--;
|
||||
append_indent();
|
||||
s += "}";
|
||||
}
|
||||
void Field(size_t /*field_idx*/, size_t set_idx, ElementaryType /*type*/,
|
||||
bool /*is_vector*/, const TypeTable * /*type_table*/,
|
||||
const char *name, const uint8_t *val) {
|
||||
if (!val) return;
|
||||
if (set_idx) s += ", ";
|
||||
if (set_idx) {
|
||||
s += ",";
|
||||
s += d;
|
||||
}
|
||||
append_indent();
|
||||
if (name) {
|
||||
if (q) s += "\"";
|
||||
s += name;
|
||||
if (q) s += "\"";
|
||||
s += ": ";
|
||||
}
|
||||
}
|
||||
template<typename T> void Named(T x, const char *name) {
|
||||
if (name)
|
||||
if (name) {
|
||||
if (q) s += "\"";
|
||||
s += name;
|
||||
else
|
||||
if (q) s += "\"";
|
||||
} else {
|
||||
s += NumToString(x);
|
||||
}
|
||||
}
|
||||
void UType(uint8_t x, const char *name) { Named(x, name); }
|
||||
void Bool(bool x) { s += x ? "true" : "false"; }
|
||||
@@ -314,20 +345,35 @@ struct ToStringVisitor : public IterationVisitor {
|
||||
void Float(float x) { s += NumToString(x); }
|
||||
void Double(double x) { s += NumToString(x); }
|
||||
void String(const struct String *str) {
|
||||
EscapeString(str->c_str(), str->size(), &s, true);
|
||||
EscapeString(str->c_str(), str->size(), &s, true, false);
|
||||
}
|
||||
void Unknown(const uint8_t *) { s += "(?)"; }
|
||||
void StartVector() { s += "[ "; }
|
||||
void EndVector() { s += " ]"; }
|
||||
void StartVector() {
|
||||
s += "[";
|
||||
s += d;
|
||||
indent_level++;
|
||||
append_indent();
|
||||
}
|
||||
void EndVector() {
|
||||
s += d;
|
||||
indent_level--;
|
||||
append_indent();
|
||||
s += "]";
|
||||
}
|
||||
void Element(size_t i, ElementaryType /*type*/,
|
||||
const TypeTable * /*type_table*/, const uint8_t * /*val*/) {
|
||||
if (i) s += ", ";
|
||||
if (i) {
|
||||
s += ",";
|
||||
s += d;
|
||||
append_indent();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
inline std::string FlatBufferToString(const uint8_t *buffer,
|
||||
const TypeTable *type_table) {
|
||||
ToStringVisitor tostring_visitor;
|
||||
const TypeTable *type_table,
|
||||
bool multi_line = false) {
|
||||
ToStringVisitor tostring_visitor(multi_line ? "\n" : " ");
|
||||
IterateFlatBuffer(buffer, type_table, &tostring_visitor);
|
||||
return tostring_visitor.s;
|
||||
}
|
||||
|
||||
@@ -72,20 +72,20 @@ inline const Table *GetAnyRoot(const uint8_t *flatbuf) {
|
||||
|
||||
// Get a field's default, if you know it's an integer, and its exact type.
|
||||
template<typename T> T GetFieldDefaultI(const reflection::Field &field) {
|
||||
assert(sizeof(T) == GetTypeSize(field.type()->base_type()));
|
||||
FLATBUFFERS_ASSERT(sizeof(T) == GetTypeSize(field.type()->base_type()));
|
||||
return static_cast<T>(field.default_integer());
|
||||
}
|
||||
|
||||
// Get a field's default, if you know it's floating point and its exact type.
|
||||
template<typename T> T GetFieldDefaultF(const reflection::Field &field) {
|
||||
assert(sizeof(T) == GetTypeSize(field.type()->base_type()));
|
||||
FLATBUFFERS_ASSERT(sizeof(T) == GetTypeSize(field.type()->base_type()));
|
||||
return static_cast<T>(field.default_real());
|
||||
}
|
||||
|
||||
// Get a field, if you know it's an integer, and its exact type.
|
||||
template<typename T>
|
||||
T GetFieldI(const Table &table, const reflection::Field &field) {
|
||||
assert(sizeof(T) == GetTypeSize(field.type()->base_type()));
|
||||
FLATBUFFERS_ASSERT(sizeof(T) == GetTypeSize(field.type()->base_type()));
|
||||
return table.GetField<T>(field.offset(),
|
||||
static_cast<T>(field.default_integer()));
|
||||
}
|
||||
@@ -93,7 +93,7 @@ T GetFieldI(const Table &table, const reflection::Field &field) {
|
||||
// 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()));
|
||||
FLATBUFFERS_ASSERT(sizeof(T) == GetTypeSize(field.type()->base_type()));
|
||||
return table.GetField<T>(field.offset(),
|
||||
static_cast<T>(field.default_real()));
|
||||
}
|
||||
@@ -101,15 +101,15 @@ T GetFieldF(const Table &table, const reflection::Field &field) {
|
||||
// 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);
|
||||
FLATBUFFERS_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()));
|
||||
FLATBUFFERS_ASSERT(field.type()->base_type() == reflection::Vector &&
|
||||
sizeof(T) == GetTypeSize(field.type()->element()));
|
||||
return table.GetPointer<Vector<T> *>(field.offset());
|
||||
}
|
||||
|
||||
@@ -123,8 +123,8 @@ inline VectorOfAny *GetFieldAnyV(const Table &table,
|
||||
|
||||
// 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);
|
||||
FLATBUFFERS_ASSERT(field.type()->base_type() == reflection::Obj ||
|
||||
field.type()->base_type() == reflection::Union);
|
||||
return table.GetPointer<Table *>(field.offset());
|
||||
}
|
||||
|
||||
@@ -133,14 +133,14 @@ inline const Struct *GetFieldStruct(const Table &table,
|
||||
const reflection::Field &field) {
|
||||
// TODO: This does NOT check if the field is a table or struct, but we'd need
|
||||
// access to the schema to check the is_struct flag.
|
||||
assert(field.type()->base_type() == reflection::Obj);
|
||||
FLATBUFFERS_ASSERT(field.type()->base_type() == reflection::Obj);
|
||||
return table.GetStruct<const Struct *>(field.offset());
|
||||
}
|
||||
|
||||
// Get a structure's field, if you know it's a struct.
|
||||
inline const Struct *GetFieldStruct(const Struct &structure,
|
||||
const reflection::Field &field) {
|
||||
assert(field.type()->base_type() == reflection::Obj);
|
||||
FLATBUFFERS_ASSERT(field.type()->base_type() == reflection::Obj);
|
||||
return structure.GetStruct<const Struct *>(field.offset());
|
||||
}
|
||||
|
||||
@@ -262,12 +262,12 @@ template<typename T>
|
||||
bool SetField(Table *table, const reflection::Field &field, T val) {
|
||||
reflection::BaseType type = field.type()->base_type();
|
||||
if (!IsScalar(type)) { return false; }
|
||||
assert(sizeof(T) == GetTypeSize(type));
|
||||
FLATBUFFERS_ASSERT(sizeof(T) == GetTypeSize(type));
|
||||
T def;
|
||||
if (IsInteger(type)) {
|
||||
def = GetFieldDefaultI<T>(field);
|
||||
} else {
|
||||
assert(IsFloat(type));
|
||||
FLATBUFFERS_ASSERT(IsFloat(type));
|
||||
def = GetFieldDefaultF<T>(field);
|
||||
}
|
||||
return table->SetField(field.offset(), val, def);
|
||||
@@ -386,7 +386,7 @@ inline const reflection::Object &GetUnionType(
|
||||
// TODO: this is clumsy and slow, but no other way to find it?
|
||||
auto type_field = parent.fields()->LookupByKey(
|
||||
(unionfield.name()->str() + UnionTypeFieldSuffix()).c_str());
|
||||
assert(type_field);
|
||||
FLATBUFFERS_ASSERT(type_field);
|
||||
auto union_type = GetFieldI<uint8_t>(table, *type_field);
|
||||
auto enumval = enumdef->values()->LookupByKey(union_type);
|
||||
return *enumval->object();
|
||||
@@ -444,7 +444,8 @@ const uint8_t *AddFlatBuffer(std::vector<uint8_t> &flatbuf,
|
||||
|
||||
inline bool SetFieldT(Table *table, const reflection::Field &field,
|
||||
const uint8_t *val) {
|
||||
assert(sizeof(uoffset_t) == GetTypeSize(field.type()->base_type()));
|
||||
FLATBUFFERS_ASSERT(sizeof(uoffset_t) ==
|
||||
GetTypeSize(field.type()->base_type()));
|
||||
return table->SetPointer(field.offset(), val);
|
||||
}
|
||||
|
||||
|
||||
@@ -20,6 +20,10 @@ struct Field;
|
||||
|
||||
struct Object;
|
||||
|
||||
struct RPCCall;
|
||||
|
||||
struct Service;
|
||||
|
||||
struct Schema;
|
||||
|
||||
enum BaseType {
|
||||
@@ -174,9 +178,9 @@ struct KeyValue FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
|
||||
bool Verify(flatbuffers::Verifier &verifier) const {
|
||||
return VerifyTableStart(verifier) &&
|
||||
VerifyOffsetRequired(verifier, VT_KEY) &&
|
||||
verifier.Verify(key()) &&
|
||||
verifier.VerifyString(key()) &&
|
||||
VerifyOffset(verifier, VT_VALUE) &&
|
||||
verifier.Verify(value()) &&
|
||||
verifier.VerifyString(value()) &&
|
||||
verifier.EndTable();
|
||||
}
|
||||
};
|
||||
@@ -228,7 +232,8 @@ struct EnumVal FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
|
||||
VT_NAME = 4,
|
||||
VT_VALUE = 6,
|
||||
VT_OBJECT = 8,
|
||||
VT_UNION_TYPE = 10
|
||||
VT_UNION_TYPE = 10,
|
||||
VT_DOCUMENTATION = 12
|
||||
};
|
||||
const flatbuffers::String *name() const {
|
||||
return GetPointer<const flatbuffers::String *>(VT_NAME);
|
||||
@@ -240,14 +245,7 @@ struct EnumVal FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
|
||||
return value() < o->value();
|
||||
}
|
||||
int KeyCompareWithValue(int64_t val) const {
|
||||
const auto key = value();
|
||||
if (key < val) {
|
||||
return -1;
|
||||
} else if (key > val) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
return static_cast<int>(value() > val) - static_cast<int>(value() < val);
|
||||
}
|
||||
const Object *object() const {
|
||||
return GetPointer<const Object *>(VT_OBJECT);
|
||||
@@ -255,15 +253,21 @@ struct EnumVal FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
|
||||
const Type *union_type() const {
|
||||
return GetPointer<const Type *>(VT_UNION_TYPE);
|
||||
}
|
||||
const flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>> *documentation() const {
|
||||
return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>> *>(VT_DOCUMENTATION);
|
||||
}
|
||||
bool Verify(flatbuffers::Verifier &verifier) const {
|
||||
return VerifyTableStart(verifier) &&
|
||||
VerifyOffsetRequired(verifier, VT_NAME) &&
|
||||
verifier.Verify(name()) &&
|
||||
verifier.VerifyString(name()) &&
|
||||
VerifyField<int64_t>(verifier, VT_VALUE) &&
|
||||
VerifyOffset(verifier, VT_OBJECT) &&
|
||||
verifier.VerifyTable(object()) &&
|
||||
VerifyOffset(verifier, VT_UNION_TYPE) &&
|
||||
verifier.VerifyTable(union_type()) &&
|
||||
VerifyOffset(verifier, VT_DOCUMENTATION) &&
|
||||
verifier.VerifyVector(documentation()) &&
|
||||
verifier.VerifyVectorOfStrings(documentation()) &&
|
||||
verifier.EndTable();
|
||||
}
|
||||
};
|
||||
@@ -283,6 +287,9 @@ struct EnumValBuilder {
|
||||
void add_union_type(flatbuffers::Offset<Type> union_type) {
|
||||
fbb_.AddOffset(EnumVal::VT_UNION_TYPE, union_type);
|
||||
}
|
||||
void add_documentation(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>>> documentation) {
|
||||
fbb_.AddOffset(EnumVal::VT_DOCUMENTATION, documentation);
|
||||
}
|
||||
explicit EnumValBuilder(flatbuffers::FlatBufferBuilder &_fbb)
|
||||
: fbb_(_fbb) {
|
||||
start_ = fbb_.StartTable();
|
||||
@@ -301,9 +308,11 @@ inline flatbuffers::Offset<EnumVal> CreateEnumVal(
|
||||
flatbuffers::Offset<flatbuffers::String> name = 0,
|
||||
int64_t value = 0,
|
||||
flatbuffers::Offset<Object> object = 0,
|
||||
flatbuffers::Offset<Type> union_type = 0) {
|
||||
flatbuffers::Offset<Type> union_type = 0,
|
||||
flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>>> documentation = 0) {
|
||||
EnumValBuilder builder_(_fbb);
|
||||
builder_.add_value(value);
|
||||
builder_.add_documentation(documentation);
|
||||
builder_.add_union_type(union_type);
|
||||
builder_.add_object(object);
|
||||
builder_.add_name(name);
|
||||
@@ -315,13 +324,15 @@ inline flatbuffers::Offset<EnumVal> CreateEnumValDirect(
|
||||
const char *name = nullptr,
|
||||
int64_t value = 0,
|
||||
flatbuffers::Offset<Object> object = 0,
|
||||
flatbuffers::Offset<Type> union_type = 0) {
|
||||
flatbuffers::Offset<Type> union_type = 0,
|
||||
const std::vector<flatbuffers::Offset<flatbuffers::String>> *documentation = nullptr) {
|
||||
return reflection::CreateEnumVal(
|
||||
_fbb,
|
||||
name ? _fbb.CreateString(name) : 0,
|
||||
value,
|
||||
object,
|
||||
union_type);
|
||||
union_type,
|
||||
documentation ? _fbb.CreateVector<flatbuffers::Offset<flatbuffers::String>>(*documentation) : 0);
|
||||
}
|
||||
|
||||
struct Enum FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
|
||||
@@ -360,18 +371,18 @@ struct Enum FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
|
||||
bool Verify(flatbuffers::Verifier &verifier) const {
|
||||
return VerifyTableStart(verifier) &&
|
||||
VerifyOffsetRequired(verifier, VT_NAME) &&
|
||||
verifier.Verify(name()) &&
|
||||
verifier.VerifyString(name()) &&
|
||||
VerifyOffsetRequired(verifier, VT_VALUES) &&
|
||||
verifier.Verify(values()) &&
|
||||
verifier.VerifyVector(values()) &&
|
||||
verifier.VerifyVectorOfTables(values()) &&
|
||||
VerifyField<uint8_t>(verifier, VT_IS_UNION) &&
|
||||
VerifyOffsetRequired(verifier, VT_UNDERLYING_TYPE) &&
|
||||
verifier.VerifyTable(underlying_type()) &&
|
||||
VerifyOffset(verifier, VT_ATTRIBUTES) &&
|
||||
verifier.Verify(attributes()) &&
|
||||
verifier.VerifyVector(attributes()) &&
|
||||
verifier.VerifyVectorOfTables(attributes()) &&
|
||||
VerifyOffset(verifier, VT_DOCUMENTATION) &&
|
||||
verifier.Verify(documentation()) &&
|
||||
verifier.VerifyVector(documentation()) &&
|
||||
verifier.VerifyVectorOfStrings(documentation()) &&
|
||||
verifier.EndTable();
|
||||
}
|
||||
@@ -505,7 +516,7 @@ struct Field FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
|
||||
bool Verify(flatbuffers::Verifier &verifier) const {
|
||||
return VerifyTableStart(verifier) &&
|
||||
VerifyOffsetRequired(verifier, VT_NAME) &&
|
||||
verifier.Verify(name()) &&
|
||||
verifier.VerifyString(name()) &&
|
||||
VerifyOffsetRequired(verifier, VT_TYPE) &&
|
||||
verifier.VerifyTable(type()) &&
|
||||
VerifyField<uint16_t>(verifier, VT_ID) &&
|
||||
@@ -516,10 +527,10 @@ struct Field FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
|
||||
VerifyField<uint8_t>(verifier, VT_REQUIRED) &&
|
||||
VerifyField<uint8_t>(verifier, VT_KEY) &&
|
||||
VerifyOffset(verifier, VT_ATTRIBUTES) &&
|
||||
verifier.Verify(attributes()) &&
|
||||
verifier.VerifyVector(attributes()) &&
|
||||
verifier.VerifyVectorOfTables(attributes()) &&
|
||||
VerifyOffset(verifier, VT_DOCUMENTATION) &&
|
||||
verifier.Verify(documentation()) &&
|
||||
verifier.VerifyVector(documentation()) &&
|
||||
verifier.VerifyVectorOfStrings(documentation()) &&
|
||||
verifier.EndTable();
|
||||
}
|
||||
@@ -671,18 +682,18 @@ struct Object FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
|
||||
bool Verify(flatbuffers::Verifier &verifier) const {
|
||||
return VerifyTableStart(verifier) &&
|
||||
VerifyOffsetRequired(verifier, VT_NAME) &&
|
||||
verifier.Verify(name()) &&
|
||||
verifier.VerifyString(name()) &&
|
||||
VerifyOffsetRequired(verifier, VT_FIELDS) &&
|
||||
verifier.Verify(fields()) &&
|
||||
verifier.VerifyVector(fields()) &&
|
||||
verifier.VerifyVectorOfTables(fields()) &&
|
||||
VerifyField<uint8_t>(verifier, VT_IS_STRUCT) &&
|
||||
VerifyField<int32_t>(verifier, VT_MINALIGN) &&
|
||||
VerifyField<int32_t>(verifier, VT_BYTESIZE) &&
|
||||
VerifyOffset(verifier, VT_ATTRIBUTES) &&
|
||||
verifier.Verify(attributes()) &&
|
||||
verifier.VerifyVector(attributes()) &&
|
||||
verifier.VerifyVectorOfTables(attributes()) &&
|
||||
VerifyOffset(verifier, VT_DOCUMENTATION) &&
|
||||
verifier.Verify(documentation()) &&
|
||||
verifier.VerifyVector(documentation()) &&
|
||||
verifier.VerifyVectorOfStrings(documentation()) &&
|
||||
verifier.EndTable();
|
||||
}
|
||||
@@ -766,13 +777,224 @@ inline flatbuffers::Offset<Object> CreateObjectDirect(
|
||||
documentation ? _fbb.CreateVector<flatbuffers::Offset<flatbuffers::String>>(*documentation) : 0);
|
||||
}
|
||||
|
||||
struct RPCCall FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
|
||||
enum {
|
||||
VT_NAME = 4,
|
||||
VT_REQUEST = 6,
|
||||
VT_RESPONSE = 8,
|
||||
VT_ATTRIBUTES = 10,
|
||||
VT_DOCUMENTATION = 12
|
||||
};
|
||||
const flatbuffers::String *name() const {
|
||||
return GetPointer<const flatbuffers::String *>(VT_NAME);
|
||||
}
|
||||
bool KeyCompareLessThan(const RPCCall *o) const {
|
||||
return *name() < *o->name();
|
||||
}
|
||||
int KeyCompareWithValue(const char *val) const {
|
||||
return strcmp(name()->c_str(), val);
|
||||
}
|
||||
const Object *request() const {
|
||||
return GetPointer<const Object *>(VT_REQUEST);
|
||||
}
|
||||
const Object *response() const {
|
||||
return GetPointer<const Object *>(VT_RESPONSE);
|
||||
}
|
||||
const flatbuffers::Vector<flatbuffers::Offset<KeyValue>> *attributes() const {
|
||||
return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<KeyValue>> *>(VT_ATTRIBUTES);
|
||||
}
|
||||
const flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>> *documentation() const {
|
||||
return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>> *>(VT_DOCUMENTATION);
|
||||
}
|
||||
bool Verify(flatbuffers::Verifier &verifier) const {
|
||||
return VerifyTableStart(verifier) &&
|
||||
VerifyOffsetRequired(verifier, VT_NAME) &&
|
||||
verifier.VerifyString(name()) &&
|
||||
VerifyOffsetRequired(verifier, VT_REQUEST) &&
|
||||
verifier.VerifyTable(request()) &&
|
||||
VerifyOffsetRequired(verifier, VT_RESPONSE) &&
|
||||
verifier.VerifyTable(response()) &&
|
||||
VerifyOffset(verifier, VT_ATTRIBUTES) &&
|
||||
verifier.VerifyVector(attributes()) &&
|
||||
verifier.VerifyVectorOfTables(attributes()) &&
|
||||
VerifyOffset(verifier, VT_DOCUMENTATION) &&
|
||||
verifier.VerifyVector(documentation()) &&
|
||||
verifier.VerifyVectorOfStrings(documentation()) &&
|
||||
verifier.EndTable();
|
||||
}
|
||||
};
|
||||
|
||||
struct RPCCallBuilder {
|
||||
flatbuffers::FlatBufferBuilder &fbb_;
|
||||
flatbuffers::uoffset_t start_;
|
||||
void add_name(flatbuffers::Offset<flatbuffers::String> name) {
|
||||
fbb_.AddOffset(RPCCall::VT_NAME, name);
|
||||
}
|
||||
void add_request(flatbuffers::Offset<Object> request) {
|
||||
fbb_.AddOffset(RPCCall::VT_REQUEST, request);
|
||||
}
|
||||
void add_response(flatbuffers::Offset<Object> response) {
|
||||
fbb_.AddOffset(RPCCall::VT_RESPONSE, response);
|
||||
}
|
||||
void add_attributes(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<KeyValue>>> attributes) {
|
||||
fbb_.AddOffset(RPCCall::VT_ATTRIBUTES, attributes);
|
||||
}
|
||||
void add_documentation(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>>> documentation) {
|
||||
fbb_.AddOffset(RPCCall::VT_DOCUMENTATION, documentation);
|
||||
}
|
||||
explicit RPCCallBuilder(flatbuffers::FlatBufferBuilder &_fbb)
|
||||
: fbb_(_fbb) {
|
||||
start_ = fbb_.StartTable();
|
||||
}
|
||||
RPCCallBuilder &operator=(const RPCCallBuilder &);
|
||||
flatbuffers::Offset<RPCCall> Finish() {
|
||||
const auto end = fbb_.EndTable(start_);
|
||||
auto o = flatbuffers::Offset<RPCCall>(end);
|
||||
fbb_.Required(o, RPCCall::VT_NAME);
|
||||
fbb_.Required(o, RPCCall::VT_REQUEST);
|
||||
fbb_.Required(o, RPCCall::VT_RESPONSE);
|
||||
return o;
|
||||
}
|
||||
};
|
||||
|
||||
inline flatbuffers::Offset<RPCCall> CreateRPCCall(
|
||||
flatbuffers::FlatBufferBuilder &_fbb,
|
||||
flatbuffers::Offset<flatbuffers::String> name = 0,
|
||||
flatbuffers::Offset<Object> request = 0,
|
||||
flatbuffers::Offset<Object> response = 0,
|
||||
flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<KeyValue>>> attributes = 0,
|
||||
flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>>> documentation = 0) {
|
||||
RPCCallBuilder builder_(_fbb);
|
||||
builder_.add_documentation(documentation);
|
||||
builder_.add_attributes(attributes);
|
||||
builder_.add_response(response);
|
||||
builder_.add_request(request);
|
||||
builder_.add_name(name);
|
||||
return builder_.Finish();
|
||||
}
|
||||
|
||||
inline flatbuffers::Offset<RPCCall> CreateRPCCallDirect(
|
||||
flatbuffers::FlatBufferBuilder &_fbb,
|
||||
const char *name = nullptr,
|
||||
flatbuffers::Offset<Object> request = 0,
|
||||
flatbuffers::Offset<Object> response = 0,
|
||||
const std::vector<flatbuffers::Offset<KeyValue>> *attributes = nullptr,
|
||||
const std::vector<flatbuffers::Offset<flatbuffers::String>> *documentation = nullptr) {
|
||||
return reflection::CreateRPCCall(
|
||||
_fbb,
|
||||
name ? _fbb.CreateString(name) : 0,
|
||||
request,
|
||||
response,
|
||||
attributes ? _fbb.CreateVector<flatbuffers::Offset<KeyValue>>(*attributes) : 0,
|
||||
documentation ? _fbb.CreateVector<flatbuffers::Offset<flatbuffers::String>>(*documentation) : 0);
|
||||
}
|
||||
|
||||
struct Service FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
|
||||
enum {
|
||||
VT_NAME = 4,
|
||||
VT_CALLS = 6,
|
||||
VT_ATTRIBUTES = 8,
|
||||
VT_DOCUMENTATION = 10
|
||||
};
|
||||
const flatbuffers::String *name() const {
|
||||
return GetPointer<const flatbuffers::String *>(VT_NAME);
|
||||
}
|
||||
bool KeyCompareLessThan(const Service *o) const {
|
||||
return *name() < *o->name();
|
||||
}
|
||||
int KeyCompareWithValue(const char *val) const {
|
||||
return strcmp(name()->c_str(), val);
|
||||
}
|
||||
const flatbuffers::Vector<flatbuffers::Offset<RPCCall>> *calls() const {
|
||||
return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<RPCCall>> *>(VT_CALLS);
|
||||
}
|
||||
const flatbuffers::Vector<flatbuffers::Offset<KeyValue>> *attributes() const {
|
||||
return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<KeyValue>> *>(VT_ATTRIBUTES);
|
||||
}
|
||||
const flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>> *documentation() const {
|
||||
return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>> *>(VT_DOCUMENTATION);
|
||||
}
|
||||
bool Verify(flatbuffers::Verifier &verifier) const {
|
||||
return VerifyTableStart(verifier) &&
|
||||
VerifyOffsetRequired(verifier, VT_NAME) &&
|
||||
verifier.VerifyString(name()) &&
|
||||
VerifyOffset(verifier, VT_CALLS) &&
|
||||
verifier.VerifyVector(calls()) &&
|
||||
verifier.VerifyVectorOfTables(calls()) &&
|
||||
VerifyOffset(verifier, VT_ATTRIBUTES) &&
|
||||
verifier.VerifyVector(attributes()) &&
|
||||
verifier.VerifyVectorOfTables(attributes()) &&
|
||||
VerifyOffset(verifier, VT_DOCUMENTATION) &&
|
||||
verifier.VerifyVector(documentation()) &&
|
||||
verifier.VerifyVectorOfStrings(documentation()) &&
|
||||
verifier.EndTable();
|
||||
}
|
||||
};
|
||||
|
||||
struct ServiceBuilder {
|
||||
flatbuffers::FlatBufferBuilder &fbb_;
|
||||
flatbuffers::uoffset_t start_;
|
||||
void add_name(flatbuffers::Offset<flatbuffers::String> name) {
|
||||
fbb_.AddOffset(Service::VT_NAME, name);
|
||||
}
|
||||
void add_calls(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<RPCCall>>> calls) {
|
||||
fbb_.AddOffset(Service::VT_CALLS, calls);
|
||||
}
|
||||
void add_attributes(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<KeyValue>>> attributes) {
|
||||
fbb_.AddOffset(Service::VT_ATTRIBUTES, attributes);
|
||||
}
|
||||
void add_documentation(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>>> documentation) {
|
||||
fbb_.AddOffset(Service::VT_DOCUMENTATION, documentation);
|
||||
}
|
||||
explicit ServiceBuilder(flatbuffers::FlatBufferBuilder &_fbb)
|
||||
: fbb_(_fbb) {
|
||||
start_ = fbb_.StartTable();
|
||||
}
|
||||
ServiceBuilder &operator=(const ServiceBuilder &);
|
||||
flatbuffers::Offset<Service> Finish() {
|
||||
const auto end = fbb_.EndTable(start_);
|
||||
auto o = flatbuffers::Offset<Service>(end);
|
||||
fbb_.Required(o, Service::VT_NAME);
|
||||
return o;
|
||||
}
|
||||
};
|
||||
|
||||
inline flatbuffers::Offset<Service> CreateService(
|
||||
flatbuffers::FlatBufferBuilder &_fbb,
|
||||
flatbuffers::Offset<flatbuffers::String> name = 0,
|
||||
flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<RPCCall>>> calls = 0,
|
||||
flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<KeyValue>>> attributes = 0,
|
||||
flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>>> documentation = 0) {
|
||||
ServiceBuilder builder_(_fbb);
|
||||
builder_.add_documentation(documentation);
|
||||
builder_.add_attributes(attributes);
|
||||
builder_.add_calls(calls);
|
||||
builder_.add_name(name);
|
||||
return builder_.Finish();
|
||||
}
|
||||
|
||||
inline flatbuffers::Offset<Service> CreateServiceDirect(
|
||||
flatbuffers::FlatBufferBuilder &_fbb,
|
||||
const char *name = nullptr,
|
||||
const std::vector<flatbuffers::Offset<RPCCall>> *calls = nullptr,
|
||||
const std::vector<flatbuffers::Offset<KeyValue>> *attributes = nullptr,
|
||||
const std::vector<flatbuffers::Offset<flatbuffers::String>> *documentation = nullptr) {
|
||||
return reflection::CreateService(
|
||||
_fbb,
|
||||
name ? _fbb.CreateString(name) : 0,
|
||||
calls ? _fbb.CreateVector<flatbuffers::Offset<RPCCall>>(*calls) : 0,
|
||||
attributes ? _fbb.CreateVector<flatbuffers::Offset<KeyValue>>(*attributes) : 0,
|
||||
documentation ? _fbb.CreateVector<flatbuffers::Offset<flatbuffers::String>>(*documentation) : 0);
|
||||
}
|
||||
|
||||
struct Schema FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
|
||||
enum {
|
||||
VT_OBJECTS = 4,
|
||||
VT_ENUMS = 6,
|
||||
VT_FILE_IDENT = 8,
|
||||
VT_FILE_EXT = 10,
|
||||
VT_ROOT_TABLE = 12
|
||||
VT_ROOT_TABLE = 12,
|
||||
VT_SERVICES = 14
|
||||
};
|
||||
const flatbuffers::Vector<flatbuffers::Offset<Object>> *objects() const {
|
||||
return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<Object>> *>(VT_OBJECTS);
|
||||
@@ -789,20 +1011,26 @@ struct Schema FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
|
||||
const Object *root_table() const {
|
||||
return GetPointer<const Object *>(VT_ROOT_TABLE);
|
||||
}
|
||||
const flatbuffers::Vector<flatbuffers::Offset<Service>> *services() const {
|
||||
return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<Service>> *>(VT_SERVICES);
|
||||
}
|
||||
bool Verify(flatbuffers::Verifier &verifier) const {
|
||||
return VerifyTableStart(verifier) &&
|
||||
VerifyOffsetRequired(verifier, VT_OBJECTS) &&
|
||||
verifier.Verify(objects()) &&
|
||||
verifier.VerifyVector(objects()) &&
|
||||
verifier.VerifyVectorOfTables(objects()) &&
|
||||
VerifyOffsetRequired(verifier, VT_ENUMS) &&
|
||||
verifier.Verify(enums()) &&
|
||||
verifier.VerifyVector(enums()) &&
|
||||
verifier.VerifyVectorOfTables(enums()) &&
|
||||
VerifyOffset(verifier, VT_FILE_IDENT) &&
|
||||
verifier.Verify(file_ident()) &&
|
||||
verifier.VerifyString(file_ident()) &&
|
||||
VerifyOffset(verifier, VT_FILE_EXT) &&
|
||||
verifier.Verify(file_ext()) &&
|
||||
verifier.VerifyString(file_ext()) &&
|
||||
VerifyOffset(verifier, VT_ROOT_TABLE) &&
|
||||
verifier.VerifyTable(root_table()) &&
|
||||
VerifyOffset(verifier, VT_SERVICES) &&
|
||||
verifier.VerifyVector(services()) &&
|
||||
verifier.VerifyVectorOfTables(services()) &&
|
||||
verifier.EndTable();
|
||||
}
|
||||
};
|
||||
@@ -825,6 +1053,9 @@ struct SchemaBuilder {
|
||||
void add_root_table(flatbuffers::Offset<Object> root_table) {
|
||||
fbb_.AddOffset(Schema::VT_ROOT_TABLE, root_table);
|
||||
}
|
||||
void add_services(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<Service>>> services) {
|
||||
fbb_.AddOffset(Schema::VT_SERVICES, services);
|
||||
}
|
||||
explicit SchemaBuilder(flatbuffers::FlatBufferBuilder &_fbb)
|
||||
: fbb_(_fbb) {
|
||||
start_ = fbb_.StartTable();
|
||||
@@ -845,8 +1076,10 @@ inline flatbuffers::Offset<Schema> CreateSchema(
|
||||
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) {
|
||||
flatbuffers::Offset<Object> root_table = 0,
|
||||
flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<Service>>> services = 0) {
|
||||
SchemaBuilder builder_(_fbb);
|
||||
builder_.add_services(services);
|
||||
builder_.add_root_table(root_table);
|
||||
builder_.add_file_ext(file_ext);
|
||||
builder_.add_file_ident(file_ident);
|
||||
@@ -861,14 +1094,16 @@ inline flatbuffers::Offset<Schema> CreateSchemaDirect(
|
||||
const std::vector<flatbuffers::Offset<Enum>> *enums = nullptr,
|
||||
const char *file_ident = nullptr,
|
||||
const char *file_ext = nullptr,
|
||||
flatbuffers::Offset<Object> root_table = 0) {
|
||||
flatbuffers::Offset<Object> root_table = 0,
|
||||
const std::vector<flatbuffers::Offset<Service>> *services = nullptr) {
|
||||
return reflection::CreateSchema(
|
||||
_fbb,
|
||||
objects ? _fbb.CreateVector<flatbuffers::Offset<Object>>(*objects) : 0,
|
||||
enums ? _fbb.CreateVector<flatbuffers::Offset<Enum>>(*enums) : 0,
|
||||
file_ident ? _fbb.CreateString(file_ident) : 0,
|
||||
file_ext ? _fbb.CreateString(file_ext) : 0,
|
||||
root_table);
|
||||
root_table,
|
||||
services ? _fbb.CreateVector<flatbuffers::Offset<Service>>(*services) : 0);
|
||||
}
|
||||
|
||||
inline const reflection::Schema *GetSchema(const void *buf) {
|
||||
|
||||
@@ -33,6 +33,16 @@
|
||||
#include <cctype>
|
||||
#endif // defined(FLATBUFFERS_CPP98_STL)
|
||||
|
||||
// Check if we can use template aliases
|
||||
// Not possible if Microsoft Compiler before 2012
|
||||
// Possible is the language feature __cpp_alias_templates is defined well
|
||||
// Or possible if the C++ std is C+11 or newer
|
||||
#if !(defined(_MSC_VER) && _MSC_VER <= 1700 /* MSVC2012 */) \
|
||||
&& ((defined(__cpp_alias_templates) && __cpp_alias_templates >= 200704) \
|
||||
|| (defined(__cplusplus) && __cplusplus >= 201103L))
|
||||
#define FLATBUFFERS_TEMPLATES_ALIASES
|
||||
#endif
|
||||
|
||||
// This header provides backwards compatibility for C++98 STLs like stlport.
|
||||
namespace flatbuffers {
|
||||
|
||||
@@ -69,13 +79,13 @@ inline void vector_emplace_back(std::vector<T> *vector, V &&data) {
|
||||
}
|
||||
|
||||
#ifndef FLATBUFFERS_CPP98_STL
|
||||
#if !(defined(_MSC_VER) && _MSC_VER <= 1700 /* MSVC2012 */)
|
||||
#if defined(FLATBUFFERS_TEMPLATES_ALIASES)
|
||||
template <typename T>
|
||||
using numeric_limits = std::numeric_limits<T>;
|
||||
#else
|
||||
template <typename T> class numeric_limits :
|
||||
public std::numeric_limits<T> {};
|
||||
#endif // !(defined(_MSC_VER) && _MSC_VER <= 1700 /* MSVC2012 */)
|
||||
#endif // defined(FLATBUFFERS_TEMPLATES_ALIASES)
|
||||
#else
|
||||
template <typename T> class numeric_limits :
|
||||
public std::numeric_limits<T> {};
|
||||
@@ -98,7 +108,7 @@ inline void vector_emplace_back(std::vector<T> *vector, V &&data) {
|
||||
};
|
||||
#endif // FLATBUFFERS_CPP98_STL
|
||||
|
||||
#if !(defined(_MSC_VER) && _MSC_VER <= 1700 /* MSVC2012 */)
|
||||
#if defined(FLATBUFFERS_TEMPLATES_ALIASES)
|
||||
#ifndef FLATBUFFERS_CPP98_STL
|
||||
template <typename T> using is_scalar = std::is_scalar<T>;
|
||||
template <typename T, typename U> using is_same = std::is_same<T,U>;
|
||||
@@ -119,10 +129,10 @@ inline void vector_emplace_back(std::vector<T> *vector, V &&data) {
|
||||
template <typename T> struct is_floating_point :
|
||||
public std::is_floating_point<T> {};
|
||||
template <typename T> struct is_unsigned : public std::is_unsigned<T> {};
|
||||
#endif // !(defined(_MSC_VER) && _MSC_VER <= 1700 /* MSVC2012 */)
|
||||
#endif // defined(FLATBUFFERS_TEMPLATES_ALIASES)
|
||||
|
||||
#ifndef FLATBUFFERS_CPP98_STL
|
||||
#if !(defined(_MSC_VER) && _MSC_VER <= 1700 /* MSVC2012 */)
|
||||
#if defined(FLATBUFFERS_TEMPLATES_ALIASES)
|
||||
template <class T> using unique_ptr = std::unique_ptr<T>;
|
||||
#else
|
||||
// MSVC 2010 doesn't support C++11 aliases.
|
||||
@@ -148,7 +158,7 @@ inline void vector_emplace_back(std::vector<T> *vector, V &&data) {
|
||||
return std::unique_ptr<T>::operator=(p);
|
||||
}
|
||||
};
|
||||
#endif // !(defined(_MSC_VER) && _MSC_VER <= 1700 /* MSVC2012 */)
|
||||
#endif // defined(FLATBUFFERS_TEMPLATES_ALIASES)
|
||||
#else
|
||||
// Very limited implementation of unique_ptr.
|
||||
// This is provided simply to allow the C++ code generated from the default
|
||||
|
||||
@@ -22,7 +22,12 @@
|
||||
#include <stdlib.h>
|
||||
#include <fstream>
|
||||
#include <iomanip>
|
||||
#include <sstream>
|
||||
#ifndef FLATBUFFERS_PREFER_PRINTF
|
||||
# include <sstream>
|
||||
#else // FLATBUFFERS_PREFER_PRINTF
|
||||
# include <float.h>
|
||||
# include <stdio.h>
|
||||
#endif // FLATBUFFERS_PREFER_PRINTF
|
||||
#include <string>
|
||||
#ifdef _WIN32
|
||||
# ifndef WIN32_LEAN_AND_MEAN
|
||||
@@ -45,13 +50,53 @@
|
||||
|
||||
namespace flatbuffers {
|
||||
|
||||
#ifdef FLATBUFFERS_PREFER_PRINTF
|
||||
template<typename T> size_t IntToDigitCount(T t) {
|
||||
size_t digit_count = 0;
|
||||
// Count the sign for negative numbers
|
||||
if (t < 0) digit_count++;
|
||||
// Count a single 0 left of the dot for fractional numbers
|
||||
if (-1 < t && t < 1) digit_count++;
|
||||
// Count digits until fractional part
|
||||
T eps = std::numeric_limits<float>::epsilon();
|
||||
while (t <= (-1 + eps) || (1 - eps) <= t) {
|
||||
t /= 10;
|
||||
digit_count++;
|
||||
}
|
||||
return digit_count;
|
||||
}
|
||||
|
||||
template<typename T> size_t NumToStringWidth(T t, int precision = 0) {
|
||||
size_t string_width = IntToDigitCount(t);
|
||||
// Count the dot for floating point numbers
|
||||
if (precision) string_width += (precision + 1);
|
||||
return string_width;
|
||||
}
|
||||
|
||||
template<typename T> std::string NumToStringImplWrapper(T t, const char* fmt,
|
||||
int precision = 0) {
|
||||
size_t string_width = NumToStringWidth(t, precision);
|
||||
std::string s(string_width, 0x00);
|
||||
// Allow snprintf to use std::string trailing null to detect buffer overflow
|
||||
snprintf(const_cast<char*>(s.data()), (s.size()+1), fmt, precision, t);
|
||||
return s;
|
||||
}
|
||||
#endif // FLATBUFFERS_PREFER_PRINTF
|
||||
|
||||
// Convert an integer or floating point value to a string.
|
||||
// In contrast to std::stringstream, "char" values are
|
||||
// converted to a string of digits, and we don't use scientific notation.
|
||||
template<typename T> std::string NumToString(T t) {
|
||||
std::stringstream ss;
|
||||
ss << t;
|
||||
return ss.str();
|
||||
// clang-format off
|
||||
#ifndef FLATBUFFERS_PREFER_PRINTF
|
||||
std::stringstream ss;
|
||||
ss << t;
|
||||
return ss.str();
|
||||
#else // FLATBUFFERS_PREFER_PRINTF
|
||||
auto v = static_cast<long long>(t);
|
||||
return NumToStringImplWrapper(v, "%.*lld");
|
||||
#endif // FLATBUFFERS_PREFER_PRINTF
|
||||
// clang-format on
|
||||
}
|
||||
// Avoid char types used as character data.
|
||||
template<> inline std::string NumToString<signed char>(signed char t) {
|
||||
@@ -77,15 +122,22 @@ inline std::string NumToString<unsigned long long>(unsigned long long t) {
|
||||
|
||||
// Special versions for floats/doubles.
|
||||
template<typename T> std::string FloatToString(T t, int precision) {
|
||||
// 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;
|
||||
// Default precision is 6, we want that to be higher for doubles.
|
||||
ss << std::setprecision(precision);
|
||||
ss << t;
|
||||
auto s = ss.str();
|
||||
// clang-format off
|
||||
#ifndef FLATBUFFERS_PREFER_PRINTF
|
||||
// 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 suppress scientific notation.
|
||||
ss << std::fixed;
|
||||
// Default precision is 6, we want that to be higher for doubles.
|
||||
ss << std::setprecision(precision);
|
||||
ss << t;
|
||||
auto s = ss.str();
|
||||
#else // FLATBUFFERS_PREFER_PRINTF
|
||||
auto v = static_cast<double>(t);
|
||||
auto s = NumToStringImplWrapper(v, "%0.*f", precision);
|
||||
#endif // FLATBUFFERS_PREFER_PRINTF
|
||||
// clang-format on
|
||||
// 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) {
|
||||
@@ -106,10 +158,16 @@ template<> inline std::string NumToString<float>(float t) {
|
||||
// The returned string length is always xdigits long, prefixed by 0 digits.
|
||||
// For example, IntToStringHex(0x23, 8) returns the string "00000023".
|
||||
inline std::string IntToStringHex(int i, int xdigits) {
|
||||
std::stringstream ss;
|
||||
ss << std::setw(xdigits) << std::setfill('0') << std::hex << std::uppercase
|
||||
<< i;
|
||||
return ss.str();
|
||||
// clang-format off
|
||||
#ifndef FLATBUFFERS_PREFER_PRINTF
|
||||
std::stringstream ss;
|
||||
ss << std::setw(xdigits) << std::setfill('0') << std::hex << std::uppercase
|
||||
<< i;
|
||||
return ss.str();
|
||||
#else // FLATBUFFERS_PREFER_PRINTF
|
||||
return NumToStringImplWrapper(i, "%.*X", xdigits);
|
||||
#endif // FLATBUFFERS_PREFER_PRINTF
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
// Portable implementation of strtoll().
|
||||
@@ -284,7 +342,7 @@ inline std::string AbsolutePath(const std::string &filepath) {
|
||||
// Convert a unicode code point into a UTF-8 representation by appending it
|
||||
// to a string. Returns the number of bytes generated.
|
||||
inline int ToUTF8(uint32_t ucc, std::string *out) {
|
||||
assert(!(ucc & 0x80000000)); // Top bit can't be set.
|
||||
FLATBUFFERS_ASSERT(!(ucc & 0x80000000)); // Top bit can't be set.
|
||||
// 6 possible encodings: http://en.wikipedia.org/wiki/UTF-8
|
||||
for (int i = 0; i < 6; i++) {
|
||||
// Max bits this encoding can represent.
|
||||
@@ -302,7 +360,7 @@ inline int ToUTF8(uint32_t ucc, std::string *out) {
|
||||
return i + 1; // Return the number of bytes added.
|
||||
}
|
||||
}
|
||||
assert(0); // Impossible to arrive here.
|
||||
FLATBUFFERS_ASSERT(0); // Impossible to arrive here.
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -321,7 +379,7 @@ inline int FromUTF8(const char **in) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ((static_cast<const unsigned char>(**in) << len) & 0x80) return -1; // Bit after leading 1's must be 0.
|
||||
if ((static_cast<unsigned char>(**in) << len) & 0x80) return -1; // Bit after leading 1's must be 0.
|
||||
if (!len) return *(*in)++;
|
||||
// UTF-8 encoded values with a length are between 2 and 4 bytes.
|
||||
if (len < 2 || len > 4) { return -1; }
|
||||
@@ -353,6 +411,7 @@ inline int FromUTF8(const char **in) {
|
||||
return ucc;
|
||||
}
|
||||
|
||||
#ifndef FLATBUFFERS_PREFER_PRINTF
|
||||
// Wraps a string to a maximum length, inserting new lines where necessary. Any
|
||||
// existing whitespace will be collapsed down to a single space. A prefix or
|
||||
// suffix can be provided, which will be inserted before or after a wrapped
|
||||
@@ -379,9 +438,10 @@ inline std::string WordWrap(const std::string in, size_t max_length,
|
||||
|
||||
return wrapped;
|
||||
}
|
||||
#endif // !FLATBUFFERS_PREFER_PRINTF
|
||||
|
||||
inline bool EscapeString(const char *s, size_t length, std::string *_text,
|
||||
bool allow_non_utf8) {
|
||||
bool allow_non_utf8, bool natural_utf8) {
|
||||
std::string &text = *_text;
|
||||
text += "\"";
|
||||
for (uoffset_t i = 0; i < length; i++) {
|
||||
@@ -421,7 +481,10 @@ inline bool EscapeString(const char *s, size_t length, std::string *_text,
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (ucc <= 0xFFFF) {
|
||||
if (natural_utf8) {
|
||||
// utf8 points to past all utf-8 bytes parsed
|
||||
text.append(s + i, static_cast<size_t>(utf8 - s - i));
|
||||
} else if (ucc <= 0xFFFF) {
|
||||
// Parses as Unicode within JSON's \uXXXX range, so use that.
|
||||
text += "\\u";
|
||||
text += IntToStringHex(ucc, 4);
|
||||
|
||||
@@ -152,6 +152,18 @@ public class FlatBufferBuilder {
|
||||
* @return Returns the new `ByteBuffer` that was allocated.
|
||||
*/
|
||||
ByteBuffer newByteBuffer(int capacity);
|
||||
|
||||
/**
|
||||
* Release a ByteBuffer. Current {@link FlatBufferBuilder}
|
||||
* released any reference to it, so it is safe to dispose the buffer
|
||||
* or return it to a pool.
|
||||
* It is not guaranteed that the buffer has been created
|
||||
* with {@link #newByteBuffer(int) }.
|
||||
*
|
||||
* @param bb the buffer to release
|
||||
*/
|
||||
default void releaseByteBuffer(ByteBuffer bb) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -241,7 +253,11 @@ public class FlatBufferBuilder {
|
||||
// Reallocate the buffer if needed.
|
||||
while (space < align_size + size + additional_bytes) {
|
||||
int old_buf_size = bb.capacity();
|
||||
bb = growByteBuffer(bb, bb_factory);
|
||||
ByteBuffer old = bb;
|
||||
bb = growByteBuffer(old, bb_factory);
|
||||
if (old != bb) {
|
||||
bb_factory.releaseByteBuffer(old);
|
||||
}
|
||||
space += bb.capacity() - old_buf_size;
|
||||
}
|
||||
pad(align_size);
|
||||
|
||||
@@ -28,6 +28,20 @@ public class Struct {
|
||||
protected int bb_pos;
|
||||
/** The underlying ByteBuffer to hold the data of the Struct. */
|
||||
protected ByteBuffer bb;
|
||||
|
||||
/**
|
||||
* Resets internal state with a null {@code ByteBuffer} and a zero position.
|
||||
*
|
||||
* This method exists primarily to allow recycling Struct instances without risking memory leaks
|
||||
* due to {@code ByteBuffer} references. The instance will be unusable until it is assigned
|
||||
* again to a {@code ByteBuffer}.
|
||||
*
|
||||
* @param struct the instance to reset to initial state
|
||||
*/
|
||||
public void __reset() {
|
||||
bb = null;
|
||||
bb_pos = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/// @endcond
|
||||
|
||||
@@ -292,6 +292,18 @@ public class Table {
|
||||
}
|
||||
return len_1 - len_2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the internal state with a null {@code ByteBuffer} and a zero position.
|
||||
*
|
||||
* This method exists primarily to allow recycling Table instances without risking memory leaks
|
||||
* due to {@code ByteBuffer} references. The instance will be unusable until it is assigned
|
||||
* again to a {@code ByteBuffer}.
|
||||
*/
|
||||
public void __reset() {
|
||||
bb = null;
|
||||
bb_pos = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/// @endcond
|
||||
|
||||
@@ -1040,6 +1040,26 @@ flatbuffers.ByteBuffer.prototype.writeFloat64 = function(offset, value) {
|
||||
this.writeInt32(offset + 4, flatbuffers.int32[flatbuffers.isLittleEndian ? 1 : 0]);
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the file identifier. Behavior is undefined for FlatBuffers whose
|
||||
* schema does not include a file_identifier (likely points at padding or the
|
||||
* start of a the root vtable).
|
||||
* @returns {string}
|
||||
*/
|
||||
flatbuffers.ByteBuffer.prototype.getBufferIdentifier = function() {
|
||||
if (this.bytes_.length < this.position_ + flatbuffers.SIZEOF_INT +
|
||||
flatbuffers.FILE_IDENTIFIER_LENGTH) {
|
||||
throw new Error(
|
||||
'FlatBuffers: ByteBuffer is too short to contain an identifier.');
|
||||
}
|
||||
var result = "";
|
||||
for (var i = 0; i < flatbuffers.FILE_IDENTIFIER_LENGTH; i++) {
|
||||
result += String.fromCharCode(
|
||||
this.readInt8(this.position_ + flatbuffers.SIZEOF_INT + i));
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
/**
|
||||
* Look up a field in the vtable, return an offset into the object, or 0 if the
|
||||
* field is not present.
|
||||
|
||||
278
lobster/flatbuffers.lobster
Normal file
278
lobster/flatbuffers.lobster
Normal file
@@ -0,0 +1,278 @@
|
||||
// Copyright 2018 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 "std.lobster"
|
||||
|
||||
namespace flatbuffers
|
||||
|
||||
struct handle:
|
||||
buf_:string
|
||||
pos_:int
|
||||
|
||||
enum + sz_8 = 1,
|
||||
sz_16 = 2,
|
||||
sz_32 = 4,
|
||||
sz_64 = 8,
|
||||
sz_voffset = 2,
|
||||
sz_uoffset = 4,
|
||||
sz_soffset = 4,
|
||||
sz_metadata_fields = 2
|
||||
|
||||
struct builder:
|
||||
buf:string = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
|
||||
current_vtable:[int] = []
|
||||
head:int = 0
|
||||
minalign:int = 1
|
||||
object_end:int = 0
|
||||
vtables:[int] = []
|
||||
nested:int = false
|
||||
finished:int = false
|
||||
|
||||
// Optionally call this right after creating the builder for a larger initial buffer.
|
||||
def Initial(initial_size:int):
|
||||
buf = "\x00".repeat_string(initial_size)
|
||||
|
||||
def Start():
|
||||
// Get the start of useful data in the underlying byte buffer.
|
||||
return buf.length - head
|
||||
|
||||
def Offset():
|
||||
// Offset relative to the end of the buffer.
|
||||
return head
|
||||
|
||||
// Returns a copy of the part of the buffer containing only the finished FlatBuffer
|
||||
def SizedCopy():
|
||||
assert finished
|
||||
return buf.substring(Start(), -1)
|
||||
|
||||
def StartNesting():
|
||||
assert not nested
|
||||
nested = true
|
||||
|
||||
def EndNesting():
|
||||
assert nested
|
||||
nested = false
|
||||
|
||||
def StartObject(numfields):
|
||||
StartNesting()
|
||||
current_vtable = map(numfields): 0
|
||||
object_end = head
|
||||
minalign = 1
|
||||
|
||||
def EndObject():
|
||||
EndNesting()
|
||||
// Prepend a zero scalar to the object. Later in this function we'll
|
||||
// write an offset here that points to the object's vtable:
|
||||
PrependInt32(0)
|
||||
object_offset := head
|
||||
// Write out new vtable speculatively.
|
||||
vtable_size := (current_vtable.length + sz_metadata_fields) * sz_voffset
|
||||
while current_vtable.length:
|
||||
o := current_vtable.pop()
|
||||
PrependVOffsetT(if o: object_offset - o else: 0)
|
||||
// The two metadata fields are written last.
|
||||
// First, store the object bytesize:
|
||||
PrependVOffsetT(object_offset - object_end)
|
||||
// Second, store the vtable bytesize:
|
||||
PrependVOffsetT(vtable_size)
|
||||
// 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.
|
||||
existing_vtable := do():
|
||||
reverse(vtables) vt2_offset:
|
||||
// Find the other vtable:
|
||||
vt2_start := buf.length - vt2_offset
|
||||
vt2_len := buf.read_int16_le(vt2_start)
|
||||
// Compare the other vtable to the one under consideration.
|
||||
// If they are equal, return the offset:
|
||||
if vtable_size == vt2_len and
|
||||
not compare_substring(buf, Start(), buf, vt2_start, vtable_size):
|
||||
return vt2_offset from do
|
||||
0
|
||||
if existing_vtable:
|
||||
// Found a duplicate vtable, remove the one we wrote.
|
||||
head = object_offset
|
||||
// Write the offset to the found vtable in the
|
||||
// already-allocated offset at the beginning of this object:
|
||||
buf.write_int32_le(Start(), existing_vtable - object_offset)
|
||||
else:
|
||||
// Did not find a vtable, so keep the one we wrote.
|
||||
// Next, write the offset to the new vtable in the
|
||||
// already-allocated offset at the beginning of this object:
|
||||
buf.write_int32_le(buf.length - object_offset, head - object_offset)
|
||||
// Finally, store this vtable in memory for future
|
||||
// deduplication:
|
||||
vtables.push(head)
|
||||
return object_offset
|
||||
|
||||
def Pad(n):
|
||||
for(n): buf, head = buf.write_int8_le_back(head, 0)
|
||||
|
||||
def Prep(size, additional_bytes):
|
||||
// Track the biggest thing we've ever aligned to.
|
||||
if size > minalign:
|
||||
minalign = size
|
||||
// Find the amount of alignment needed such that `size` is properly
|
||||
// aligned after `additionalBytes`:
|
||||
align_size := ((~(head + additional_bytes)) + 1) & (size - 1)
|
||||
Pad(align_size)
|
||||
|
||||
def PrependUOffsetTRelative(off):
|
||||
// Prepends an unsigned offset into vector data, relative to where it will be written.
|
||||
Prep(sz_uoffset, 0)
|
||||
assert off <= head
|
||||
PlaceUOffsetT(head - off + sz_uoffset)
|
||||
|
||||
def StartVector(elem_size, num_elems, alignment):
|
||||
// Initializes bookkeeping for writing a new vector.
|
||||
StartNesting()
|
||||
Prep(sz_32, elem_size * num_elems)
|
||||
Prep(alignment, elem_size * num_elems) // In case alignment > int.
|
||||
return head
|
||||
|
||||
def EndVector(vector_num_elems):
|
||||
EndNesting()
|
||||
// we already made space for this, so write without PrependUint32
|
||||
PlaceUOffsetT(vector_num_elems)
|
||||
return head
|
||||
|
||||
def CreateString(s:string):
|
||||
// writes a null-terminated byte string.
|
||||
StartNesting()
|
||||
Prep(sz_32, s.length + 1)
|
||||
buf, head = buf.write_substring_back(head, s, true)
|
||||
return EndVector(s.length)
|
||||
|
||||
def CreateByteVector(s:string):
|
||||
// writes a non-null-terminated byte string.
|
||||
StartNesting()
|
||||
Prep(sz_32, s.length)
|
||||
buf, head = buf.write_substring_back(head, s, false)
|
||||
return EndVector(s.length)
|
||||
|
||||
def Slot(slotnum):
|
||||
assert nested
|
||||
while current_vtable.length <= slotnum: current_vtable.push(0)
|
||||
current_vtable[slotnum] = head
|
||||
|
||||
def __Finish(root_table:int, size_prefix:int):
|
||||
// Finish finalizes a buffer, pointing to the given root_table
|
||||
assert not finished
|
||||
assert not nested
|
||||
prep_size := sz_32
|
||||
if size_prefix:
|
||||
prep_size += sz_32
|
||||
Prep(minalign, prep_size)
|
||||
PrependUOffsetTRelative(root_table)
|
||||
if size_prefix:
|
||||
PrependInt32(head)
|
||||
finished = true
|
||||
return Start()
|
||||
|
||||
def Finish(root_table:int):
|
||||
return __Finish(root_table, false)
|
||||
|
||||
def FinishSizePrefixed(root_table:int):
|
||||
return __Finish(root_table, true)
|
||||
|
||||
def PrependBool(x):
|
||||
buf, head = buf.write_int8_le_back(head, x)
|
||||
|
||||
def PrependByte(x):
|
||||
buf, head = buf.write_int8_le_back(head, x)
|
||||
|
||||
def PrependUint8(x):
|
||||
buf, head = buf.write_int8_le_back(head, x)
|
||||
|
||||
def PrependUint16(x):
|
||||
Prep(sz_16, 0)
|
||||
buf, head = buf.write_int16_le_back(head, x)
|
||||
|
||||
def PrependUint32(x):
|
||||
Prep(sz_32, 0)
|
||||
buf, head = buf.write_int32_le_back(head, x)
|
||||
|
||||
def PrependUint64(x):
|
||||
Prep(sz_64, 0)
|
||||
buf, head = buf.write_int64_le_back(head, x)
|
||||
|
||||
def PrependInt8(x):
|
||||
buf, head = buf.write_int8_le_back(head, x)
|
||||
|
||||
def PrependInt16(x):
|
||||
Prep(sz_16, 0)
|
||||
buf, head = buf.write_int16_le_back(head, x)
|
||||
|
||||
def PrependInt32(x):
|
||||
Prep(sz_32, 0)
|
||||
buf, head = buf.write_int32_le_back(head, x)
|
||||
|
||||
def PrependInt64(x):
|
||||
Prep(sz_64, 0)
|
||||
buf, head = buf.write_int64_le_back(head, x)
|
||||
|
||||
def PrependFloat32(x):
|
||||
Prep(sz_32, 0)
|
||||
buf, head = buf.write_float32_le_back(head, x)
|
||||
|
||||
def PrependFloat64(x):
|
||||
Prep(sz_64, 0)
|
||||
buf, head = buf.write_float64_le_back(head, x)
|
||||
|
||||
def PrependVOffsetT(x):
|
||||
Prep(sz_voffset, 0)
|
||||
buf, head = buf.write_int16_le_back(head, x)
|
||||
|
||||
def PlaceVOffsetT(x):
|
||||
buf, head = buf.write_int16_le_back(head, x)
|
||||
|
||||
def PlaceSOffsetT(x):
|
||||
buf, head = buf.write_int32_le_back(head, x)
|
||||
|
||||
def PlaceUOffsetT(x):
|
||||
buf, head = buf.write_int32_le_back(head, x)
|
||||
|
||||
def PrependSlot(o:int, x, d, f):
|
||||
if x != d:
|
||||
f(x)
|
||||
Slot(o)
|
||||
|
||||
def PrependBoolSlot(o, x, d): PrependSlot(o, x, d): PrependBool(_)
|
||||
def PrependByteSlot(o, x, d): PrependSlot(o, x, d): PrependByte(_)
|
||||
def PrependUint8Slot(o, x, d): PrependSlot(o, x, d): PrependUint8(_)
|
||||
def PrependUint16Slot(o, x, d): PrependSlot(o, x, d): PrependUint16(_)
|
||||
def PrependUint32Slot(o, x, d): PrependSlot(o, x, d): PrependUint32(_)
|
||||
def PrependUint64Slot(o, x, d): PrependSlot(o, x, d): PrependUint64(_)
|
||||
def PrependInt8Slot(o, x, d): PrependSlot(o, x, d): PrependInt8(_)
|
||||
def PrependInt16Slot(o, x, d): PrependSlot(o, x, d): PrependInt16(_)
|
||||
def PrependInt32Slot(o, x, d): PrependSlot(o, x, d): PrependInt32(_)
|
||||
def PrependInt64Slot(o, x, d): PrependSlot(o, x, d): PrependInt64(_)
|
||||
def PrependFloat32Slot(o, x, d): PrependSlot(o, x, d): PrependFloat32(_)
|
||||
def PrependFloat64Slot(o, x, d): PrependSlot(o, x, d): PrependFloat64(_)
|
||||
|
||||
def PrependUOffsetTRelativeSlot(o, x, d):
|
||||
if x != d:
|
||||
PrependUOffsetTRelative(x)
|
||||
Slot(o)
|
||||
|
||||
def PrependStructSlot(v, x, d):
|
||||
if x != d:
|
||||
// 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.
|
||||
assert x == head
|
||||
Slot(v)
|
||||
|
||||
8
lua/flatbuffers.lua
Normal file
8
lua/flatbuffers.lua
Normal file
@@ -0,0 +1,8 @@
|
||||
local m = {}
|
||||
|
||||
m.Builder = require("flatbuffers.builder").New
|
||||
m.N = require("flatbuffers.numTypes")
|
||||
m.view = require("flatbuffers.view")
|
||||
m.binaryArray = require("flatbuffers.binaryarray")
|
||||
|
||||
return m
|
||||
123
lua/flatbuffers/binaryarray.lua
Normal file
123
lua/flatbuffers/binaryarray.lua
Normal file
@@ -0,0 +1,123 @@
|
||||
local m = {} -- the module table
|
||||
|
||||
local mt = {} -- the module metatable
|
||||
|
||||
-- given a binary array, set a metamethod to return its length
|
||||
-- (e.g., #binaryArray, calls this)
|
||||
function mt:__len()
|
||||
return self.size
|
||||
end
|
||||
|
||||
-- Create a new binary array of an initial size
|
||||
function m.New(sizeOrString)
|
||||
-- the array storage itself
|
||||
local o = {}
|
||||
|
||||
if type(sizeOrString) == "string" then
|
||||
o.str = sizeOrString
|
||||
o.size = #sizeOrString
|
||||
elseif type(sizeOrString) == "number" then
|
||||
o.data = {}
|
||||
o.size = sizeOrString
|
||||
else
|
||||
error("Expect a integer size value or string to construct a binary array")
|
||||
end
|
||||
-- set the inheritance
|
||||
setmetatable(o, {__index = mt, __len = mt.__len})
|
||||
return o
|
||||
end
|
||||
|
||||
-- Get a slice of the binary array from start to end position
|
||||
function mt:Slice(startPos, endPos)
|
||||
startPos = startPos or 0
|
||||
endPos = endPos or self.size
|
||||
local d = self.data
|
||||
if d then
|
||||
-- if the self.data is defined, we are building the buffer
|
||||
-- in a Lua table
|
||||
|
||||
-- new table to store the slice components
|
||||
local b = {}
|
||||
|
||||
-- starting with the startPos, put all
|
||||
-- values into the new table to be concat later
|
||||
-- updated the startPos based on the size of the
|
||||
-- value
|
||||
while startPos < endPos do
|
||||
local v = d[startPos] or '/0'
|
||||
table.insert(b, v)
|
||||
startPos = startPos + #v
|
||||
end
|
||||
|
||||
-- combine the table of strings into one string
|
||||
-- this is faster than doing a bunch of concats by themselves
|
||||
return table.concat(b)
|
||||
else
|
||||
-- n.b start/endPos are 0-based incoming, so need to convert
|
||||
-- correctly. in python a slice includes start -> end - 1
|
||||
return self.str:sub(startPos+1, endPos)
|
||||
end
|
||||
end
|
||||
|
||||
-- Grow the binary array to a new size, placing the exisiting data
|
||||
-- at then end of the new array
|
||||
function mt:Grow(newsize)
|
||||
-- the new table to store the data
|
||||
local newT = {}
|
||||
|
||||
-- the offset to be applied to existing entries
|
||||
local offset = newsize - self.size
|
||||
|
||||
-- loop over all the current entries and
|
||||
-- add them to the new table at the correct
|
||||
-- offset location
|
||||
local d = self.data
|
||||
for i,data in pairs(d) do
|
||||
newT[i + offset] = data
|
||||
end
|
||||
|
||||
-- update this storage with the new table and size
|
||||
self.data = newT
|
||||
self.size = newsize
|
||||
end
|
||||
|
||||
-- memorization for padding strings
|
||||
local pads = {}
|
||||
|
||||
-- pad the binary with n \0 bytes at the starting position
|
||||
function mt:Pad(n, startPos)
|
||||
-- use memorization to avoid creating a bunch of strings
|
||||
-- all the time
|
||||
local s = pads[n]
|
||||
if not s then
|
||||
s = string.rep('\0', n)
|
||||
pads[n] = s
|
||||
end
|
||||
|
||||
-- store the padding string at the start position in the
|
||||
-- Lua table
|
||||
self.data[startPos] = s
|
||||
end
|
||||
|
||||
-- Sets the binary array value at the specified position
|
||||
function mt:Set(value, position)
|
||||
self.data[position] = value
|
||||
end
|
||||
|
||||
-- locals for slightly faster access
|
||||
local sunpack = string.unpack
|
||||
local spack = string.pack
|
||||
|
||||
-- Pack the data into a binary representation
|
||||
function m.Pack(fmt, ...)
|
||||
return spack(fmt, ...)
|
||||
end
|
||||
|
||||
-- Unpack the data from a binary representation in
|
||||
-- a Lua value
|
||||
function m.Unpack(fmt, s, pos)
|
||||
return sunpack(fmt, s.str, pos + 1)
|
||||
end
|
||||
|
||||
-- Return the binary array module
|
||||
return m
|
||||
367
lua/flatbuffers/builder.lua
Normal file
367
lua/flatbuffers/builder.lua
Normal file
@@ -0,0 +1,367 @@
|
||||
local N = require("flatbuffers.numTypes")
|
||||
local ba = require("flatbuffers.binaryarray")
|
||||
local compat = require("flatbuffers.compat")
|
||||
|
||||
local m = {}
|
||||
|
||||
local mt = {}
|
||||
|
||||
-- get locals for faster access
|
||||
local VOffsetT = N.VOffsetT
|
||||
local UOffsetT = N.UOffsetT
|
||||
local SOffsetT = N.SOffsetT
|
||||
local Bool = N.Bool
|
||||
local Uint8 = N.Uint8
|
||||
local Uint16 = N.Uint16
|
||||
local Uint32 = N.Uint32
|
||||
local Uint64 = N.Uint64
|
||||
local Int8 = N.Int8
|
||||
local Int16 = N.Int16
|
||||
local Int32 = N.Int32
|
||||
local Int64 = N.Int64
|
||||
local Float32 = N.Float32
|
||||
local Float64 = N.Float64
|
||||
|
||||
local MAX_BUFFER_SIZE = 0x80000000 -- 2 GB
|
||||
local VtableMetadataFields = 2
|
||||
|
||||
local getAlignSize = compat.GetAlignSize
|
||||
|
||||
local function vtableEqual(a, objectStart, b)
|
||||
UOffsetT:EnforceNumber(objectStart)
|
||||
if (#a * VOffsetT.bytewidth) ~= #b then
|
||||
return false
|
||||
end
|
||||
|
||||
for i, elem in ipairs(a) do
|
||||
local x = VOffsetT:Unpack(b, i * VOffsetT.bytewidth)
|
||||
if x ~= 0 or elem ~= 0 then
|
||||
local y = objectStart - elem
|
||||
if x ~= y then
|
||||
return false
|
||||
end
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
function m.New(initialSize)
|
||||
assert(0 <= initialSize and initialSize < MAX_BUFFER_SIZE)
|
||||
local o =
|
||||
{
|
||||
finished = false,
|
||||
bytes = ba.New(initialSize),
|
||||
nested = false,
|
||||
head = initialSize,
|
||||
minalign = 1,
|
||||
vtables = {}
|
||||
}
|
||||
setmetatable(o, {__index = mt})
|
||||
return o
|
||||
end
|
||||
|
||||
function mt:Output(full)
|
||||
assert(self.finished, "Builder Not Finished")
|
||||
if full then
|
||||
return self.bytes:Slice()
|
||||
else
|
||||
return self.bytes:Slice(self.head)
|
||||
end
|
||||
end
|
||||
|
||||
function mt:StartObject(numFields)
|
||||
assert(not self.nested)
|
||||
|
||||
local vtable = {}
|
||||
|
||||
for _=1,numFields do
|
||||
table.insert(vtable, 0)
|
||||
end
|
||||
|
||||
self.currentVTable = vtable
|
||||
self.objectEnd = self:Offset()
|
||||
self.nested = true
|
||||
end
|
||||
|
||||
function mt:WriteVtable()
|
||||
self:PrependSOffsetTRelative(0)
|
||||
local objectOffset = self:Offset()
|
||||
|
||||
local exisitingVTable
|
||||
local i = #self.vtables
|
||||
while i >= 1 do
|
||||
if self.vtables[i] == 0 then
|
||||
table.remove(self.vtables,i)
|
||||
end
|
||||
i = i - 1
|
||||
end
|
||||
|
||||
while i >= 1 do
|
||||
|
||||
local vt2Offset = self.vtables[i]
|
||||
local vt2Start = #self.bytes - vt2Offset
|
||||
local vt2len = VOffsetT:Unpack(self.bytes, vt2Start)
|
||||
|
||||
local metadata = VtableMetadataFields * VOffsetT.bytewidth
|
||||
local vt2End = vt2Start + vt2Len
|
||||
local vt2 = self.bytes:Slice(vt2Start+metadata,vt2End)
|
||||
|
||||
if vtableEqual(self.currentVTable, objectOffset, vt2) then
|
||||
exisitingVTable = vt2Offset
|
||||
break
|
||||
end
|
||||
|
||||
i = i - 1
|
||||
end
|
||||
|
||||
if not exisitingVTable then
|
||||
i = #self.currentVTable
|
||||
while i >= 1 do
|
||||
local off = 0
|
||||
local a = self.currentVTable[i]
|
||||
if a and a ~= 0 then
|
||||
off = objectOffset - a
|
||||
end
|
||||
self:PrependVOffsetT(off)
|
||||
|
||||
i = i - 1
|
||||
end
|
||||
|
||||
local objectSize = objectOffset - self.objectEnd
|
||||
self:PrependVOffsetT(objectSize)
|
||||
|
||||
local vBytes = #self.currentVTable + VtableMetadataFields
|
||||
vBytes = vBytes * VOffsetT.bytewidth
|
||||
self:PrependVOffsetT(vBytes)
|
||||
|
||||
local objectStart = #self.bytes - objectOffset
|
||||
self.bytes:Set(SOffsetT:Pack(self:Offset() - objectOffset),objectStart)
|
||||
|
||||
table.insert(self.vtables, self:Offset())
|
||||
else
|
||||
local objectStart = #self.bytes - objectOffset
|
||||
self.head = objectStart
|
||||
self.bytes:Set(SOffsetT:Pack(exisitingVTable - objectOffset),self.head)
|
||||
end
|
||||
|
||||
self.currentVTable = nil
|
||||
return objectOffset
|
||||
end
|
||||
|
||||
function mt:EndObject()
|
||||
assert(self.nested)
|
||||
self.nested = false
|
||||
return self:WriteVtable()
|
||||
end
|
||||
|
||||
local function growByteBuffer(self, desiredSize)
|
||||
local s = #self.bytes
|
||||
assert(s < MAX_BUFFER_SIZE, "Flat Buffers cannot grow buffer beyond 2 gigabytes")
|
||||
local newsize = s
|
||||
repeat
|
||||
newsize = math.min(newsize * 2, MAX_BUFFER_SIZE)
|
||||
if newsize == 0 then newsize = 1 end
|
||||
until newsize > desiredSize
|
||||
|
||||
self.bytes:Grow(newsize)
|
||||
end
|
||||
|
||||
function mt:Head()
|
||||
return self.head
|
||||
end
|
||||
|
||||
function mt:Offset()
|
||||
return #self.bytes - self.head
|
||||
end
|
||||
|
||||
function mt:Pad(n)
|
||||
if n > 0 then
|
||||
-- pads are 8-bit, so skip the bytewidth lookup
|
||||
local h = self.head - n -- UInt8
|
||||
self.head = h
|
||||
self.bytes:Pad(n, h)
|
||||
end
|
||||
end
|
||||
|
||||
function mt:Prep(size, additionalBytes)
|
||||
if size > self.minalign then
|
||||
self.minalign = size
|
||||
end
|
||||
|
||||
local h = self.head
|
||||
|
||||
local k = #self.bytes - h + additionalBytes
|
||||
local alignsize = ((~k) + 1) & (size - 1) -- getAlignSize(k, size)
|
||||
|
||||
local desiredSize = alignsize + size + additionalBytes
|
||||
|
||||
while self.head < desiredSize do
|
||||
local oldBufSize = #self.bytes
|
||||
growByteBuffer(self, desiredSize)
|
||||
local updatedHead = self.head + #self.bytes - oldBufSize
|
||||
self.head = updatedHead
|
||||
end
|
||||
|
||||
self:Pad(alignsize)
|
||||
end
|
||||
|
||||
function mt:PrependSOffsetTRelative(off)
|
||||
self:Prep(SOffsetT.bytewidth, 0)
|
||||
assert(off <= self:Offset(), "Offset arithmetic error")
|
||||
local off2 = self:Offset() - off + SOffsetT.bytewidth
|
||||
self:Place(off2, SOffsetT)
|
||||
end
|
||||
|
||||
function mt:PrependUOffsetTRelative(off)
|
||||
self:Prep(UOffsetT.bytewidth, 0)
|
||||
local soffset = self:Offset()
|
||||
if off <= soffset then
|
||||
local off2 = soffset - off + UOffsetT.bytewidth
|
||||
self:Place(off2, UOffsetT)
|
||||
else
|
||||
error("Offset arithmetic error")
|
||||
end
|
||||
end
|
||||
|
||||
function mt:StartVector(elemSize, numElements, alignment)
|
||||
assert(not self.nested)
|
||||
self.nested = true
|
||||
self:Prep(Uint32.bytewidth, elemSize * numElements)
|
||||
self:Prep(alignment, elemSize * numElements)
|
||||
return self:Offset()
|
||||
end
|
||||
|
||||
function mt:EndVector(vectorNumElements)
|
||||
assert(self.nested)
|
||||
self.nested = false
|
||||
self:Place(vectorNumElements, UOffsetT)
|
||||
return self:Offset()
|
||||
end
|
||||
|
||||
function mt:CreateString(s)
|
||||
assert(not self.nested)
|
||||
self.nested = true
|
||||
|
||||
assert(type(s) == "string")
|
||||
|
||||
self:Prep(UOffsetT.bytewidth, (#s + 1)*Uint8.bytewidth)
|
||||
self:Place(0, Uint8)
|
||||
|
||||
local l = #s
|
||||
self.head = self.head - l
|
||||
|
||||
self.bytes:Set(s, self.head, self.head + l)
|
||||
|
||||
return self:EndVector(#s)
|
||||
end
|
||||
|
||||
function mt:CreateByteVector(x)
|
||||
assert(not self.nested)
|
||||
self.nested = true
|
||||
self:Prep(UOffsetT.bytewidth, #x*Uint8.bytewidth)
|
||||
|
||||
local l = #x
|
||||
self.head = self.head - l
|
||||
|
||||
self.bytes:Set(x, self.head, self.head + l)
|
||||
|
||||
return self:EndVector(#x)
|
||||
end
|
||||
|
||||
function mt:Slot(slotnum)
|
||||
assert(self.nested)
|
||||
-- n.b. slot number is 0-based
|
||||
self.currentVTable[slotnum + 1] = self:Offset()
|
||||
end
|
||||
|
||||
local function finish(self, rootTable, sizePrefix)
|
||||
UOffsetT:EnforceNumber(rootTable)
|
||||
local prepSize = UOffsetT.bytewidth
|
||||
if sizePrefix then
|
||||
prepSize = prepSize + Int32.bytewidth
|
||||
end
|
||||
|
||||
self:Prep(self.minalign, prepSize)
|
||||
self:PrependUOffsetTRelative(rootTable)
|
||||
if sizePrefix then
|
||||
local size = #self.bytes - self.head
|
||||
Int32:EnforceNumber(size)
|
||||
self:PrependInt32(size)
|
||||
end
|
||||
self.finished = true
|
||||
return self.head
|
||||
end
|
||||
|
||||
function mt:Finish(rootTable)
|
||||
return finish(self, rootTable, false)
|
||||
end
|
||||
|
||||
function mt:FinishSizePrefixed(rootTable)
|
||||
return finish(self, rootTable, true)
|
||||
end
|
||||
|
||||
function mt:Prepend(flags, off)
|
||||
self:Prep(flags.bytewidth, 0)
|
||||
self:Place(off, flags)
|
||||
end
|
||||
|
||||
function mt:PrependSlot(flags, o, x, d)
|
||||
flags:EnforceNumber(x)
|
||||
flags:EnforceNumber(d)
|
||||
if x ~= d then
|
||||
self:Prepend(flags, x)
|
||||
self:Slot(o)
|
||||
end
|
||||
end
|
||||
|
||||
function mt:PrependBoolSlot(...) self:PrependSlot(Bool, ...) end
|
||||
function mt:PrependByteSlot(...) self:PrependSlot(Uint8, ...) end
|
||||
function mt:PrependUint8Slot(...) self:PrependSlot(Uint8, ...) end
|
||||
function mt:PrependUint16Slot(...) self:PrependSlot(Uint16, ...) end
|
||||
function mt:PrependUint32Slot(...) self:PrependSlot(Uint32, ...) end
|
||||
function mt:PrependUint64Slot(...) self:PrependSlot(Uint64, ...) end
|
||||
function mt:PrependInt8Slot(...) self:PrependSlot(Int8, ...) end
|
||||
function mt:PrependInt16Slot(...) self:PrependSlot(Int16, ...) end
|
||||
function mt:PrependInt32Slot(...) self:PrependSlot(Int32, ...) end
|
||||
function mt:PrependInt64Slot(...) self:PrependSlot(Int64, ...) end
|
||||
function mt:PrependFloat32Slot(...) self:PrependSlot(Float32, ...) end
|
||||
function mt:PrependFloat64Slot(...) self:PrependSlot(Float64, ...) end
|
||||
|
||||
function mt:PrependUOffsetTRelativeSlot(o,x,d)
|
||||
if x~=d then
|
||||
self:PrependUOffsetTRelative(x)
|
||||
self:Slot(o)
|
||||
end
|
||||
end
|
||||
|
||||
function mt:PrependStructSlot(v,x,d)
|
||||
UOffsetT:EnforceNumber(d)
|
||||
if x~=d then
|
||||
UOffsetT:EnforceNumber(x)
|
||||
assert(x == self:Offset(), "Tried to write a Struct at an Offset that is different from the current Offset of the Builder.")
|
||||
self:Slot(v)
|
||||
end
|
||||
end
|
||||
|
||||
function mt:PrependBool(x) self:Prepend(Bool, x) end
|
||||
function mt:PrependByte(x) self:Prepend(Uint8, x) end
|
||||
function mt:PrependUint8(x) self:Prepend(Uint8, x) end
|
||||
function mt:PrependUint16(x) self:Prepend(Uint16, x) end
|
||||
function mt:PrependUint32(x) self:Prepend(Uint32, x) end
|
||||
function mt:PrependUint64(x) self:Prepend(Uint64, x) end
|
||||
function mt:PrependInt8(x) self:Prepend(Int8, x) end
|
||||
function mt:PrependInt16(x) self:Prepend(Int16, x) end
|
||||
function mt:PrependInt32(x) self:Prepend(Int32, x) end
|
||||
function mt:PrependInt64(x) self:Prepend(Int64, x) end
|
||||
function mt:PrependFloat32(x) self:Prepend(Float32, x) end
|
||||
function mt:PrependFloat64(x) self:Prepend(Float64, x) end
|
||||
function mt:PrependVOffsetT(x) self:Prepend(VOffsetT, x) end
|
||||
|
||||
function mt:Place(x, flags)
|
||||
local d = flags:EnforceNumberAndPack(x)
|
||||
local h = self.head - flags.bytewidth
|
||||
self.head = h
|
||||
self.bytes:Set(d, h)
|
||||
end
|
||||
|
||||
return m
|
||||
17
lua/flatbuffers/compat.lua
Normal file
17
lua/flatbuffers/compat.lua
Normal file
@@ -0,0 +1,17 @@
|
||||
local m = {}
|
||||
|
||||
local getAlignSize
|
||||
if _VERSION == "Lua 5.3" then
|
||||
getAlignSize = function(k, size)
|
||||
return ((~k) + 1) & (size - 1)
|
||||
end
|
||||
else
|
||||
getAlignSize = function(self, size, additionalBytes)
|
||||
local alignsize = bit32.bnot(#self.bytes-self:Head() + additionalBytes) + 1
|
||||
return bit32.band(alignsize,(size - 1))
|
||||
end
|
||||
end
|
||||
|
||||
m.GetAlignSize = getAlignSize
|
||||
|
||||
return m
|
||||
198
lua/flatbuffers/numTypes.lua
Normal file
198
lua/flatbuffers/numTypes.lua
Normal file
@@ -0,0 +1,198 @@
|
||||
local m = {}
|
||||
|
||||
local ba = require("flatbuffers.binaryarray")
|
||||
|
||||
local bpack = ba.Pack
|
||||
local bunpack = ba.Unpack
|
||||
|
||||
local type_mt = {}
|
||||
|
||||
function type_mt:Pack(value)
|
||||
return bpack(self.packFmt, value)
|
||||
end
|
||||
|
||||
function type_mt:Unpack(buf, pos)
|
||||
return bunpack(self.packFmt, buf, pos)
|
||||
end
|
||||
|
||||
function type_mt:ValidNumber(n)
|
||||
if not self.min_value and not self.max_value then return true end
|
||||
return self.min_value <= n and n <= self.max_value
|
||||
end
|
||||
|
||||
function type_mt:EnforceNumber(n)
|
||||
-- duplicate code since the overhead of function calls
|
||||
-- for such a popular method is time consuming
|
||||
if not self.min_value and not self.max_value then
|
||||
return
|
||||
end
|
||||
|
||||
if self.min_value <= n and n <= self.max_value then
|
||||
return
|
||||
end
|
||||
|
||||
error("Number is not in the valid range")
|
||||
end
|
||||
|
||||
function type_mt:EnforceNumberAndPack(n)
|
||||
return bpack(self.packFmt, n)
|
||||
end
|
||||
|
||||
function type_mt:ConvertType(n, otherType)
|
||||
assert(self.bytewidth == otherType.bytewidth, "Cannot convert between types of different widths")
|
||||
if self == otherType then
|
||||
return n
|
||||
end
|
||||
return otherType:Unpack(self:Pack(n))
|
||||
end
|
||||
|
||||
local bool_mt =
|
||||
{
|
||||
bytewidth = 1,
|
||||
min_value = false,
|
||||
max_value = true,
|
||||
lua_type = type(true),
|
||||
name = "bool",
|
||||
packFmt = "<b"
|
||||
}
|
||||
|
||||
local uint8_mt =
|
||||
{
|
||||
bytewidth = 1,
|
||||
min_value = 0,
|
||||
max_value = 2^8-1,
|
||||
lua_type = type(1),
|
||||
name = "uint8",
|
||||
packFmt = "<I1"
|
||||
}
|
||||
|
||||
local uint16_mt =
|
||||
{
|
||||
bytewidth = 2,
|
||||
min_value = 0,
|
||||
max_value = 2^16-1,
|
||||
lua_type = type(1),
|
||||
name = "uint16",
|
||||
packFmt = "<I2"
|
||||
}
|
||||
|
||||
local uint32_mt =
|
||||
{
|
||||
bytewidth = 4,
|
||||
min_value = 0,
|
||||
max_value = 2^32-1,
|
||||
lua_type = type(1),
|
||||
name = "uint32",
|
||||
packFmt = "<I4"
|
||||
}
|
||||
|
||||
local uint64_mt =
|
||||
{
|
||||
bytewidth = 8,
|
||||
min_value = 0,
|
||||
max_value = 2^64-1,
|
||||
lua_type = type(1),
|
||||
name = "uint64",
|
||||
packFmt = "<I8"
|
||||
}
|
||||
|
||||
local int8_mt =
|
||||
{
|
||||
bytewidth = 1,
|
||||
min_value = -2^7,
|
||||
max_value = 2^7-1,
|
||||
lua_type = type(1),
|
||||
name = "int8",
|
||||
packFmt = "<i1"
|
||||
}
|
||||
|
||||
local int16_mt =
|
||||
{
|
||||
bytewidth = 2,
|
||||
min_value = -2^15,
|
||||
max_value = 2^15-1,
|
||||
lua_type = type(1),
|
||||
name = "int16",
|
||||
packFmt = "<i2"
|
||||
}
|
||||
|
||||
local int32_mt =
|
||||
{
|
||||
bytewidth = 4,
|
||||
min_value = -2^15,
|
||||
max_value = 2^15-1,
|
||||
lua_type = type(1),
|
||||
name = "int32",
|
||||
packFmt = "<i4"
|
||||
}
|
||||
|
||||
local int64_mt =
|
||||
{
|
||||
bytewidth = 8,
|
||||
min_value = -2^63,
|
||||
max_value = 2^63-1,
|
||||
lua_type = type(1),
|
||||
name = "int64",
|
||||
packFmt = "<i8"
|
||||
}
|
||||
|
||||
local float32_mt =
|
||||
{
|
||||
bytewidth = 4,
|
||||
min_value = nil,
|
||||
max_value = nil,
|
||||
lua_type = type(1.0),
|
||||
name = "float32",
|
||||
packFmt = "<f"
|
||||
}
|
||||
|
||||
local float64_mt =
|
||||
{
|
||||
bytewidth = 8,
|
||||
min_value = nil,
|
||||
max_value = nil,
|
||||
lua_type = type(1.0),
|
||||
name = "float64",
|
||||
packFmt = "<d"
|
||||
}
|
||||
|
||||
-- register the base class
|
||||
setmetatable(bool_mt, {__index = type_mt})
|
||||
setmetatable(uint8_mt, {__index = type_mt})
|
||||
setmetatable(uint16_mt, {__index = type_mt})
|
||||
setmetatable(uint32_mt, {__index = type_mt})
|
||||
setmetatable(uint64_mt, {__index = type_mt})
|
||||
setmetatable(int8_mt, {__index = type_mt})
|
||||
setmetatable(int16_mt, {__index = type_mt})
|
||||
setmetatable(int32_mt, {__index = type_mt})
|
||||
setmetatable(int64_mt, {__index = type_mt})
|
||||
setmetatable(float32_mt, {__index = type_mt})
|
||||
setmetatable(float64_mt, {__index = type_mt})
|
||||
|
||||
|
||||
m.Bool = bool_mt
|
||||
m.Uint8 = uint8_mt
|
||||
m.Uint16 = uint16_mt
|
||||
m.Uint32 = uint32_mt
|
||||
m.Uint64 = uint64_mt
|
||||
m.Int8 = int8_mt
|
||||
m.Int16 = int16_mt
|
||||
m.Int32 = int32_mt
|
||||
m.Int64 = int64_mt
|
||||
m.Float32 = float32_mt
|
||||
m.Float64 = float64_mt
|
||||
|
||||
m.UOffsetT = uint32_mt
|
||||
m.VOffsetT = uint16_mt
|
||||
m.SOffsetT = int32_mt
|
||||
|
||||
function GenerateTypes(listOfTypes)
|
||||
for _,t in pairs(listOfTypes) do
|
||||
t.Pack = function(self, value) return bpack(self.packFmt, value) end
|
||||
t.Unpack = function(self, buf, pos) return bunpack(self.packFmt, buf, pos) end
|
||||
end
|
||||
end
|
||||
|
||||
GenerateTypes(m)
|
||||
|
||||
return m
|
||||
97
lua/flatbuffers/view.lua
Normal file
97
lua/flatbuffers/view.lua
Normal file
@@ -0,0 +1,97 @@
|
||||
local m = {}
|
||||
local mt = {}
|
||||
|
||||
local mt_name = "flatbuffers.view.mt"
|
||||
|
||||
local N = require("flatbuffers.numTypes")
|
||||
local binaryarray = require("flatbuffers.binaryarray")
|
||||
|
||||
function m.New(buf, pos)
|
||||
N.UOffsetT:EnforceNumber(pos)
|
||||
|
||||
-- need to convert from a string buffer into
|
||||
-- a binary array
|
||||
|
||||
local o = {
|
||||
bytes = type(buf) == "string" and binaryarray.New(buf) or buf,
|
||||
pos = pos
|
||||
}
|
||||
setmetatable(o, {__index = mt, __metatable = mt_name})
|
||||
return o
|
||||
end
|
||||
|
||||
function mt:Offset(vtableOffset)
|
||||
local vtable = self.pos - self:Get(N.SOffsetT, self.pos)
|
||||
local vtableEnd = self:Get(N.VOffsetT, vtable)
|
||||
if vtableOffset < vtableEnd then
|
||||
return self:Get(N.VOffsetT, vtable + vtableOffset)
|
||||
end
|
||||
return 0
|
||||
end
|
||||
|
||||
function mt:Indirect(off)
|
||||
N.UOffsetT:EnforceNumber(off)
|
||||
return off + N.UOffsetT:Unpack(self.bytes, off)
|
||||
end
|
||||
|
||||
function mt:String(off)
|
||||
N.UOffsetT:EnforceNumber(off)
|
||||
off = off + N.UOffsetT:Unpack(self.bytes, off)
|
||||
local start = off + N.UOffsetT.bytewidth
|
||||
local length = N.UOffsetT:Unpack(self.bytes, off)
|
||||
return self.bytes:Slice(start, start+length)
|
||||
end
|
||||
|
||||
function mt:VectorLen(off)
|
||||
N.UOffsetT:EnforceNumber(off)
|
||||
off = off + self.pos
|
||||
off = off + N.UOffsetT:Unpack(self.bytes, off)
|
||||
return N.UOffsetT:Unpack(self.bytes, off)
|
||||
end
|
||||
|
||||
function mt:Vector(off)
|
||||
N.UOffsetT:EnforceNumber(off)
|
||||
|
||||
off = off + self.pos
|
||||
local x = off + self:Get(N.UOffsetT, off)
|
||||
x = x + N.UOffsetT.bytewidth
|
||||
return x
|
||||
end
|
||||
|
||||
function mt:Union(t2, off)
|
||||
assert(getmetatable(t2) == mt_name)
|
||||
N.UOffsetT:EnforceNumber(off)
|
||||
|
||||
off = off + self.pos
|
||||
t2.pos = off + self:Get(N.UOffsetT, off)
|
||||
t2.bytes = self.bytes
|
||||
end
|
||||
|
||||
function mt:Get(flags, off)
|
||||
N.UOffsetT:EnforceNumber(off)
|
||||
return flags:Unpack(self.bytes, off)
|
||||
end
|
||||
|
||||
function mt:GetSlot(slot, d, validatorFlags)
|
||||
N.VOffsetT:EnforceNumber(slot)
|
||||
if validatorFlags then
|
||||
validatorFlags:EnforceNumber(d)
|
||||
end
|
||||
local off = self:Offset(slot)
|
||||
if off == 0 then
|
||||
return d
|
||||
end
|
||||
return self:Get(validatorFlags, self.pos + off)
|
||||
end
|
||||
|
||||
function mt:GetVOffsetTSlot(slot, d)
|
||||
N.VOffsetT:EnforceNumber(slot)
|
||||
N.VOffsetT:EnforceNumber(d)
|
||||
local off = self:Offset(slot)
|
||||
if off == 0 then
|
||||
return d
|
||||
end
|
||||
return off
|
||||
end
|
||||
|
||||
return m
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
// There are 2 #defines that have an impact on performance of this ByteBuffer implementation
|
||||
// There are 3 #defines that have an impact on performance / features of this ByteBuffer implementation
|
||||
//
|
||||
// UNSAFE_BYTEBUFFER
|
||||
// This will use unsafe code to manipulate the underlying byte array. This
|
||||
@@ -24,26 +24,149 @@
|
||||
// This will disable the bounds check asserts to the byte array. This can
|
||||
// yield a small performance gain in normal code..
|
||||
//
|
||||
// ENABLE_SPAN_T
|
||||
// This will enable reading and writing blocks of memory with a Span<T> instead if just
|
||||
// T[]. You can also enable writing directly to shared memory or other types of memory
|
||||
// by providing a custom implementation of ByteBufferAllocator.
|
||||
// ENABLE_SPAN_T also requires UNSAFE_BYTEBUFFER to be defined
|
||||
//
|
||||
// Using UNSAFE_BYTEBUFFER and BYTEBUFFER_NO_BOUNDS_CHECK together can yield a
|
||||
// performance gain of ~15% for some operations, however doing so is potentially
|
||||
// dangerous. Do so at your own risk!
|
||||
//
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
#if ENABLE_SPAN_T && !UNSAFE_BYTEBUFFER
|
||||
#error ENABLE_SPAN_T requires UNSAFE_BYTEBUFFER to also be defined
|
||||
#endif
|
||||
|
||||
namespace FlatBuffers
|
||||
{
|
||||
public abstract class ByteBufferAllocator : IDisposable
|
||||
{
|
||||
#if UNSAFE_BYTEBUFFER
|
||||
public unsafe byte* Buffer
|
||||
{
|
||||
get;
|
||||
protected set;
|
||||
}
|
||||
#else
|
||||
public byte[] Buffer
|
||||
{
|
||||
get;
|
||||
protected set;
|
||||
}
|
||||
#endif
|
||||
|
||||
public int Length
|
||||
{
|
||||
get;
|
||||
protected set;
|
||||
}
|
||||
|
||||
public abstract void Dispose();
|
||||
|
||||
public abstract void GrowFront(int newSize);
|
||||
|
||||
#if !ENABLE_SPAN_T
|
||||
public abstract byte[] ByteArray { get; }
|
||||
#endif
|
||||
}
|
||||
|
||||
public class ByteArrayAllocator : ByteBufferAllocator
|
||||
{
|
||||
private byte[] _buffer;
|
||||
|
||||
public ByteArrayAllocator(byte[] buffer)
|
||||
{
|
||||
_buffer = buffer;
|
||||
InitPointer();
|
||||
}
|
||||
|
||||
public override void GrowFront(int newSize)
|
||||
{
|
||||
if ((Length & 0xC0000000) != 0)
|
||||
throw new Exception(
|
||||
"ByteBuffer: cannot grow buffer beyond 2 gigabytes.");
|
||||
|
||||
if (newSize < Length)
|
||||
throw new Exception("ByteBuffer: cannot truncate buffer.");
|
||||
|
||||
byte[] newBuffer = new byte[newSize];
|
||||
System.Buffer.BlockCopy(_buffer, 0, newBuffer, newSize - Length, Length);
|
||||
_buffer = newBuffer;
|
||||
InitPointer();
|
||||
}
|
||||
|
||||
public override void Dispose()
|
||||
{
|
||||
GC.SuppressFinalize(this);
|
||||
#if UNSAFE_BYTEBUFFER
|
||||
if (_handle.IsAllocated)
|
||||
{
|
||||
_handle.Free();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#if !ENABLE_SPAN_T
|
||||
public override byte[] ByteArray
|
||||
{
|
||||
get { return _buffer; }
|
||||
}
|
||||
#endif
|
||||
|
||||
#if UNSAFE_BYTEBUFFER
|
||||
private GCHandle _handle;
|
||||
|
||||
~ByteArrayAllocator()
|
||||
{
|
||||
if (_handle.IsAllocated)
|
||||
{
|
||||
_handle.Free();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
private void InitPointer()
|
||||
{
|
||||
Length = _buffer.Length;
|
||||
#if UNSAFE_BYTEBUFFER
|
||||
if (_handle.IsAllocated)
|
||||
{
|
||||
_handle.Free();
|
||||
}
|
||||
_handle = GCHandle.Alloc(_buffer, GCHandleType.Pinned);
|
||||
unsafe
|
||||
{
|
||||
Buffer = (byte*)_handle.AddrOfPinnedObject().ToPointer();
|
||||
}
|
||||
#else
|
||||
Buffer = _buffer;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Class to mimic Java's ByteBuffer which is used heavily in Flatbuffers.
|
||||
/// </summary>
|
||||
public class ByteBuffer
|
||||
public class ByteBuffer : IDisposable
|
||||
{
|
||||
protected byte[] _buffer;
|
||||
private ByteBufferAllocator _buffer;
|
||||
private int _pos; // Must track start of the buffer.
|
||||
|
||||
public int Length { get { return _buffer.Length; } }
|
||||
public ByteBuffer(ByteBufferAllocator allocator, int position)
|
||||
{
|
||||
_buffer = allocator;
|
||||
_pos = position;
|
||||
}
|
||||
|
||||
public ByteBuffer(int size) : this(new byte[size]) { }
|
||||
|
||||
@@ -51,15 +174,25 @@ namespace FlatBuffers
|
||||
|
||||
public ByteBuffer(byte[] buffer, int pos)
|
||||
{
|
||||
_buffer = buffer;
|
||||
_buffer = new ByteArrayAllocator(buffer);
|
||||
_pos = pos;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (_buffer != null)
|
||||
{
|
||||
_buffer.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
public int Position {
|
||||
get { return _pos; }
|
||||
set { _pos = value; }
|
||||
}
|
||||
|
||||
public int Length { get { return _buffer.Length; } }
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
_pos = 0;
|
||||
@@ -76,45 +209,126 @@ namespace FlatBuffers
|
||||
// the end of the new buffer.
|
||||
public void GrowFront(int newSize)
|
||||
{
|
||||
if ((Length & 0xC0000000) != 0)
|
||||
throw new Exception(
|
||||
"ByteBuffer: cannot grow buffer beyond 2 gigabytes.");
|
||||
|
||||
if (newSize < Length)
|
||||
throw new Exception("ByteBuffer: cannot truncate buffer.");
|
||||
|
||||
byte[] newBuffer = new byte[newSize];
|
||||
Buffer.BlockCopy(_buffer, 0, newBuffer, newSize - Length,
|
||||
Length);
|
||||
_buffer = newBuffer;
|
||||
_buffer.GrowFront(newSize);
|
||||
}
|
||||
|
||||
public byte[] ToArray(int pos, int len)
|
||||
{
|
||||
byte[] arr = new byte[len];
|
||||
Buffer.BlockCopy(_buffer, pos, arr, 0, len);
|
||||
return ToArray<byte>(pos, len);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A lookup of type sizes. Used instead of Marshal.SizeOf() which has additional
|
||||
/// overhead, but also is compatible with generic functions for simplified code.
|
||||
/// </summary>
|
||||
private static Dictionary<Type, int> genericSizes = new Dictionary<Type, int>()
|
||||
{
|
||||
{ typeof(bool), sizeof(bool) },
|
||||
{ typeof(float), sizeof(float) },
|
||||
{ typeof(double), sizeof(double) },
|
||||
{ typeof(sbyte), sizeof(sbyte) },
|
||||
{ typeof(byte), sizeof(byte) },
|
||||
{ typeof(short), sizeof(short) },
|
||||
{ typeof(ushort), sizeof(ushort) },
|
||||
{ typeof(int), sizeof(int) },
|
||||
{ typeof(uint), sizeof(uint) },
|
||||
{ typeof(ulong), sizeof(ulong) },
|
||||
{ typeof(long), sizeof(long) },
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Get the wire-size (in bytes) of a type supported by flatbuffers.
|
||||
/// </summary>
|
||||
/// <param name="t">The type to get the wire size of</param>
|
||||
/// <returns></returns>
|
||||
public static int SizeOf<T>()
|
||||
{
|
||||
return genericSizes[typeof(T)];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the Type provided is supported as scalar value
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The Type to check</typeparam>
|
||||
/// <returns>True if the type is a scalar type that is supported, falsed otherwise</returns>
|
||||
public static bool IsSupportedType<T>()
|
||||
{
|
||||
return genericSizes.ContainsKey(typeof(T));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the wire-size (in bytes) of an typed array
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the array</typeparam>
|
||||
/// <param name="x">The array to get the size of</param>
|
||||
/// <returns>The number of bytes the array takes on wire</returns>
|
||||
public static int ArraySize<T>(T[] x)
|
||||
{
|
||||
return SizeOf<T>() * x.Length;
|
||||
}
|
||||
|
||||
#if ENABLE_SPAN_T
|
||||
public static int ArraySize<T>(Span<T> x)
|
||||
{
|
||||
return SizeOf<T>() * x.Length;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Get a portion of the buffer casted into an array of type T, given
|
||||
// the buffer position and length.
|
||||
#if ENABLE_SPAN_T
|
||||
public T[] ToArray<T>(int pos, int len)
|
||||
where T: struct
|
||||
{
|
||||
unsafe
|
||||
{
|
||||
AssertOffsetAndLength(pos, len);
|
||||
T[] arr = new T[len];
|
||||
var typed = MemoryMarshal.Cast<byte, T>(new Span<byte>(_buffer.Buffer + pos, _buffer.Length));
|
||||
typed.Slice(0, arr.Length).CopyTo(arr);
|
||||
return arr;
|
||||
}
|
||||
}
|
||||
#else
|
||||
public T[] ToArray<T>(int pos, int len)
|
||||
where T : struct
|
||||
{
|
||||
AssertOffsetAndLength(pos, len);
|
||||
T[] arr = new T[len];
|
||||
Buffer.BlockCopy(_buffer.ByteArray, pos, arr, 0, ArraySize(arr));
|
||||
return arr;
|
||||
}
|
||||
#endif
|
||||
|
||||
public byte[] ToSizedArray()
|
||||
{
|
||||
return ToArray(Position, Length - Position);
|
||||
return ToArray<byte>(Position, Length - Position);
|
||||
}
|
||||
|
||||
public byte[] ToFullArray()
|
||||
{
|
||||
return ToArray(0, Length);
|
||||
return ToArray<byte>(0, Length);
|
||||
}
|
||||
|
||||
|
||||
#if ENABLE_SPAN_T
|
||||
public unsafe Span<byte> ToSpan(int pos, int len)
|
||||
{
|
||||
return new Span<byte>(_buffer.Buffer, _buffer.Length).Slice(pos, len);
|
||||
}
|
||||
#else
|
||||
public ArraySegment<byte> ToArraySegment(int pos, int len)
|
||||
{
|
||||
return new ArraySegment<byte>(_buffer, pos, len);
|
||||
return new ArraySegment<byte>(_buffer.ByteArray, pos, len);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !ENABLE_SPAN_T
|
||||
public MemoryStream ToMemoryStream(int pos, int len)
|
||||
{
|
||||
return new MemoryStream(_buffer, pos, len);
|
||||
return new MemoryStream(_buffer.ByteArray, pos, len);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !UNSAFE_BYTEBUFFER
|
||||
// Pre-allocated helper arrays for convertion.
|
||||
@@ -157,14 +371,14 @@ namespace FlatBuffers
|
||||
{
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
_buffer[offset + i] = (byte)(data >> i * 8);
|
||||
_buffer.Buffer[offset + i] = (byte)(data >> i * 8);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
_buffer[offset + count - 1 - i] = (byte)(data >> i * 8);
|
||||
_buffer.Buffer[offset + count - 1 - i] = (byte)(data >> i * 8);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -177,14 +391,14 @@ namespace FlatBuffers
|
||||
{
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
r |= (ulong)_buffer[offset + i] << i * 8;
|
||||
r |= (ulong)_buffer.Buffer[offset + i] << i * 8;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
r |= (ulong)_buffer[offset + count - 1 - i] << i * 8;
|
||||
r |= (ulong)_buffer.Buffer[offset + count - 1 - i] << i * 8;
|
||||
}
|
||||
}
|
||||
return r;
|
||||
@@ -193,30 +407,32 @@ namespace FlatBuffers
|
||||
|
||||
private void AssertOffsetAndLength(int offset, int length)
|
||||
{
|
||||
#if !BYTEBUFFER_NO_BOUNDS_CHECK
|
||||
#if !BYTEBUFFER_NO_BOUNDS_CHECK
|
||||
if (offset < 0 ||
|
||||
offset > _buffer.Length - length)
|
||||
throw new ArgumentOutOfRangeException();
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
public void PutSbyte(int offset, sbyte value)
|
||||
#if UNSAFE_BYTEBUFFER
|
||||
|
||||
public unsafe void PutSbyte(int offset, sbyte value)
|
||||
{
|
||||
AssertOffsetAndLength(offset, sizeof(sbyte));
|
||||
_buffer[offset] = (byte)value;
|
||||
_buffer.Buffer[offset] = (byte)value;
|
||||
}
|
||||
|
||||
public void PutByte(int offset, byte value)
|
||||
public unsafe void PutByte(int offset, byte value)
|
||||
{
|
||||
AssertOffsetAndLength(offset, sizeof(byte));
|
||||
_buffer[offset] = value;
|
||||
_buffer.Buffer[offset] = value;
|
||||
}
|
||||
|
||||
public void PutByte(int offset, byte value, int count)
|
||||
public unsafe void PutByte(int offset, byte value, int count)
|
||||
{
|
||||
AssertOffsetAndLength(offset, sizeof(byte) * count);
|
||||
for (var i = 0; i < count; ++i)
|
||||
_buffer[offset + i] = value;
|
||||
_buffer.Buffer[offset + i] = value;
|
||||
}
|
||||
|
||||
// this method exists in order to conform with Java ByteBuffer standards
|
||||
@@ -224,13 +440,50 @@ namespace FlatBuffers
|
||||
{
|
||||
PutByte(offset, value);
|
||||
}
|
||||
#else
|
||||
public void PutSbyte(int offset, sbyte value)
|
||||
{
|
||||
AssertOffsetAndLength(offset, sizeof(sbyte));
|
||||
_buffer.Buffer[offset] = (byte)value;
|
||||
}
|
||||
|
||||
public void PutByte(int offset, byte value)
|
||||
{
|
||||
AssertOffsetAndLength(offset, sizeof(byte));
|
||||
_buffer.Buffer[offset] = value;
|
||||
}
|
||||
|
||||
public void PutByte(int offset, byte value, int count)
|
||||
{
|
||||
AssertOffsetAndLength(offset, sizeof(byte) * count);
|
||||
for (var i = 0; i < count; ++i)
|
||||
_buffer.Buffer[offset + i] = value;
|
||||
}
|
||||
|
||||
// this method exists in order to conform with Java ByteBuffer standards
|
||||
public void Put(int offset, byte value)
|
||||
{
|
||||
PutByte(offset, value);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if ENABLE_SPAN_T
|
||||
public unsafe void PutStringUTF8(int offset, string value)
|
||||
{
|
||||
AssertOffsetAndLength(offset, value.Length);
|
||||
fixed (char* s = value)
|
||||
{
|
||||
Encoding.UTF8.GetBytes(s, value.Length, _buffer.Buffer + offset, Length - offset);
|
||||
}
|
||||
}
|
||||
#else
|
||||
public void PutStringUTF8(int offset, string value)
|
||||
{
|
||||
AssertOffsetAndLength(offset, value.Length);
|
||||
Encoding.UTF8.GetBytes(value, 0, value.Length,
|
||||
_buffer, offset);
|
||||
_buffer.ByteArray, offset);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if UNSAFE_BYTEBUFFER
|
||||
// Unsafe but more efficient versions of Put*.
|
||||
@@ -242,12 +495,10 @@ namespace FlatBuffers
|
||||
public unsafe void PutUshort(int offset, ushort value)
|
||||
{
|
||||
AssertOffsetAndLength(offset, sizeof(ushort));
|
||||
fixed (byte* ptr = _buffer)
|
||||
{
|
||||
*(ushort*)(ptr + offset) = BitConverter.IsLittleEndian
|
||||
? value
|
||||
: ReverseBytes(value);
|
||||
}
|
||||
byte* ptr = _buffer.Buffer;
|
||||
*(ushort*)(ptr + offset) = BitConverter.IsLittleEndian
|
||||
? value
|
||||
: ReverseBytes(value);
|
||||
}
|
||||
|
||||
public void PutInt(int offset, int value)
|
||||
@@ -258,12 +509,10 @@ namespace FlatBuffers
|
||||
public unsafe void PutUint(int offset, uint value)
|
||||
{
|
||||
AssertOffsetAndLength(offset, sizeof(uint));
|
||||
fixed (byte* ptr = _buffer)
|
||||
{
|
||||
*(uint*)(ptr + offset) = BitConverter.IsLittleEndian
|
||||
? value
|
||||
: ReverseBytes(value);
|
||||
}
|
||||
byte* ptr = _buffer.Buffer;
|
||||
*(uint*)(ptr + offset) = BitConverter.IsLittleEndian
|
||||
? value
|
||||
: ReverseBytes(value);
|
||||
}
|
||||
|
||||
public unsafe void PutLong(int offset, long value)
|
||||
@@ -274,44 +523,38 @@ namespace FlatBuffers
|
||||
public unsafe void PutUlong(int offset, ulong value)
|
||||
{
|
||||
AssertOffsetAndLength(offset, sizeof(ulong));
|
||||
fixed (byte* ptr = _buffer)
|
||||
{
|
||||
*(ulong*)(ptr + offset) = BitConverter.IsLittleEndian
|
||||
? value
|
||||
: ReverseBytes(value);
|
||||
}
|
||||
byte* ptr = _buffer.Buffer;
|
||||
*(ulong*)(ptr + offset) = BitConverter.IsLittleEndian
|
||||
? value
|
||||
: ReverseBytes(value);
|
||||
}
|
||||
|
||||
public unsafe void PutFloat(int offset, float value)
|
||||
{
|
||||
AssertOffsetAndLength(offset, sizeof(float));
|
||||
fixed (byte* ptr = _buffer)
|
||||
byte* ptr = _buffer.Buffer;
|
||||
if (BitConverter.IsLittleEndian)
|
||||
{
|
||||
if (BitConverter.IsLittleEndian)
|
||||
{
|
||||
*(float*)(ptr + offset) = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
*(uint*)(ptr + offset) = ReverseBytes(*(uint*)(&value));
|
||||
}
|
||||
*(float*)(ptr + offset) = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
*(uint*)(ptr + offset) = ReverseBytes(*(uint*)(&value));
|
||||
}
|
||||
}
|
||||
|
||||
public unsafe void PutDouble(int offset, double value)
|
||||
{
|
||||
AssertOffsetAndLength(offset, sizeof(double));
|
||||
fixed (byte* ptr = _buffer)
|
||||
byte* ptr = _buffer.Buffer;
|
||||
if (BitConverter.IsLittleEndian)
|
||||
{
|
||||
if (BitConverter.IsLittleEndian)
|
||||
{
|
||||
*(double*)(ptr + offset) = value;
|
||||
*(double*)(ptr + offset) = value;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
*(ulong*)(ptr + offset) = ReverseBytes(*(ulong*)(ptr + offset));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
*(ulong*)(ptr + offset) = ReverseBytes(*(ulong*)(ptr + offset));
|
||||
}
|
||||
}
|
||||
#else // !UNSAFE_BYTEBUFFER
|
||||
@@ -370,22 +613,43 @@ namespace FlatBuffers
|
||||
|
||||
#endif // UNSAFE_BYTEBUFFER
|
||||
|
||||
#if UNSAFE_BYTEBUFFER
|
||||
public unsafe sbyte GetSbyte(int index)
|
||||
{
|
||||
AssertOffsetAndLength(index, sizeof(sbyte));
|
||||
return (sbyte)_buffer.Buffer[index];
|
||||
}
|
||||
|
||||
public unsafe byte Get(int index)
|
||||
{
|
||||
AssertOffsetAndLength(index, sizeof(byte));
|
||||
return _buffer.Buffer[index];
|
||||
}
|
||||
#else
|
||||
public sbyte GetSbyte(int index)
|
||||
{
|
||||
AssertOffsetAndLength(index, sizeof(sbyte));
|
||||
return (sbyte)_buffer[index];
|
||||
return (sbyte)_buffer.Buffer[index];
|
||||
}
|
||||
|
||||
public byte Get(int index)
|
||||
{
|
||||
AssertOffsetAndLength(index, sizeof(byte));
|
||||
return _buffer[index];
|
||||
return _buffer.Buffer[index];
|
||||
}
|
||||
#endif
|
||||
|
||||
#if ENABLE_SPAN_T
|
||||
public unsafe string GetStringUTF8(int startPos, int len)
|
||||
{
|
||||
return Encoding.UTF8.GetString(_buffer.Buffer + startPos, len);
|
||||
}
|
||||
#else
|
||||
public string GetStringUTF8(int startPos, int len)
|
||||
{
|
||||
return Encoding.UTF8.GetString(_buffer, startPos, len);
|
||||
return Encoding.UTF8.GetString(_buffer.ByteArray, startPos, len);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if UNSAFE_BYTEBUFFER
|
||||
// Unsafe but more efficient versions of Get*.
|
||||
@@ -397,7 +661,7 @@ namespace FlatBuffers
|
||||
public unsafe ushort GetUshort(int offset)
|
||||
{
|
||||
AssertOffsetAndLength(offset, sizeof(ushort));
|
||||
fixed (byte* ptr = _buffer)
|
||||
byte* ptr = _buffer.Buffer;
|
||||
{
|
||||
return BitConverter.IsLittleEndian
|
||||
? *(ushort*)(ptr + offset)
|
||||
@@ -413,7 +677,7 @@ namespace FlatBuffers
|
||||
public unsafe uint GetUint(int offset)
|
||||
{
|
||||
AssertOffsetAndLength(offset, sizeof(uint));
|
||||
fixed (byte* ptr = _buffer)
|
||||
byte* ptr = _buffer.Buffer;
|
||||
{
|
||||
return BitConverter.IsLittleEndian
|
||||
? *(uint*)(ptr + offset)
|
||||
@@ -429,7 +693,7 @@ namespace FlatBuffers
|
||||
public unsafe ulong GetUlong(int offset)
|
||||
{
|
||||
AssertOffsetAndLength(offset, sizeof(ulong));
|
||||
fixed (byte* ptr = _buffer)
|
||||
byte* ptr = _buffer.Buffer;
|
||||
{
|
||||
return BitConverter.IsLittleEndian
|
||||
? *(ulong*)(ptr + offset)
|
||||
@@ -440,7 +704,7 @@ namespace FlatBuffers
|
||||
public unsafe float GetFloat(int offset)
|
||||
{
|
||||
AssertOffsetAndLength(offset, sizeof(float));
|
||||
fixed (byte* ptr = _buffer)
|
||||
byte* ptr = _buffer.Buffer;
|
||||
{
|
||||
if (BitConverter.IsLittleEndian)
|
||||
{
|
||||
@@ -457,7 +721,7 @@ namespace FlatBuffers
|
||||
public unsafe double GetDouble(int offset)
|
||||
{
|
||||
AssertOffsetAndLength(offset, sizeof(double));
|
||||
fixed (byte* ptr = _buffer)
|
||||
byte* ptr = _buffer.Buffer;
|
||||
{
|
||||
if (BitConverter.IsLittleEndian)
|
||||
{
|
||||
@@ -519,5 +783,98 @@ namespace FlatBuffers
|
||||
return doublehelper[0];
|
||||
}
|
||||
#endif // UNSAFE_BYTEBUFFER
|
||||
|
||||
/// <summary>
|
||||
/// Copies an array of type T into this buffer, ending at the given
|
||||
/// offset into this buffer. The starting offset is calculated based on the length
|
||||
/// of the array and is the value returned.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the input data (must be a struct)</typeparam>
|
||||
/// <param name="offset">The offset into this buffer where the copy will end</param>
|
||||
/// <param name="x">The array to copy data from</param>
|
||||
/// <returns>The 'start' location of this buffer now, after the copy completed</returns>
|
||||
public int Put<T>(int offset, T[] x)
|
||||
where T : struct
|
||||
{
|
||||
if (x == null)
|
||||
{
|
||||
throw new ArgumentNullException("Cannot put a null array");
|
||||
}
|
||||
|
||||
if (x.Length == 0)
|
||||
{
|
||||
throw new ArgumentException("Cannot put an empty array");
|
||||
}
|
||||
|
||||
if (!IsSupportedType<T>())
|
||||
{
|
||||
throw new ArgumentException("Cannot put an array of type "
|
||||
+ typeof(T) + " into this buffer");
|
||||
}
|
||||
|
||||
if (BitConverter.IsLittleEndian)
|
||||
{
|
||||
int numBytes = ByteBuffer.ArraySize(x);
|
||||
offset -= numBytes;
|
||||
AssertOffsetAndLength(offset, numBytes);
|
||||
// if we are LE, just do a block copy
|
||||
#if ENABLE_SPAN_T
|
||||
unsafe
|
||||
{
|
||||
MemoryMarshal.Cast<T, byte>(x).CopyTo(new Span<byte>(_buffer.Buffer, _buffer.Length).Slice(offset, numBytes));
|
||||
}
|
||||
#else
|
||||
Buffer.BlockCopy(x, 0, _buffer.ByteArray, offset, numBytes);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new NotImplementedException("Big Endian Support not implemented yet " +
|
||||
"for putting typed arrays");
|
||||
// if we are BE, we have to swap each element by itself
|
||||
//for(int i = x.Length - 1; i >= 0; i--)
|
||||
//{
|
||||
// todo: low priority, but need to genericize the Put<T>() functions
|
||||
//}
|
||||
}
|
||||
return offset;
|
||||
}
|
||||
|
||||
#if ENABLE_SPAN_T
|
||||
public unsafe int Put<T>(int offset, Span<T> x)
|
||||
where T : struct
|
||||
{
|
||||
if (x.Length == 0)
|
||||
{
|
||||
throw new ArgumentException("Cannot put an empty array");
|
||||
}
|
||||
|
||||
if (!IsSupportedType<T>())
|
||||
{
|
||||
throw new ArgumentException("Cannot put an array of type "
|
||||
+ typeof(T) + " into this buffer");
|
||||
}
|
||||
|
||||
if (BitConverter.IsLittleEndian)
|
||||
{
|
||||
int numBytes = ByteBuffer.ArraySize(x);
|
||||
offset -= numBytes;
|
||||
AssertOffsetAndLength(offset, numBytes);
|
||||
// if we are LE, just do a block copy
|
||||
MemoryMarshal.Cast<T, byte>(x).CopyTo(new Span<byte>(_buffer.Buffer, _buffer.Length).Slice(offset, numBytes));
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new NotImplementedException("Big Endian Support not implemented yet " +
|
||||
"for putting typed arrays");
|
||||
// if we are BE, we have to swap each element by itself
|
||||
//for(int i = x.Length - 1; i >= 0; i--)
|
||||
//{
|
||||
// todo: low priority, but need to genericize the Put<T>() functions
|
||||
//}
|
||||
}
|
||||
return offset;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
Binary file not shown.
@@ -62,6 +62,17 @@ namespace FlatBuffers
|
||||
_bb = new ByteBuffer(initialSize);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a FlatBufferBuilder backed by the pased in ByteBuffer
|
||||
/// </summary>
|
||||
/// <param name="buffer">The ByteBuffer to write to</param>
|
||||
public FlatBufferBuilder(ByteBuffer buffer)
|
||||
{
|
||||
_bb = buffer;
|
||||
_space = buffer.Length;
|
||||
buffer.Reset();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reset the FlatBufferBuilder by purging all data that it holds.
|
||||
/// </summary>
|
||||
@@ -179,6 +190,32 @@ namespace FlatBuffers
|
||||
_bb.PutFloat(_space -= sizeof(float), x);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Puts an array of type T into this builder at the
|
||||
/// current offset
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the input data </typeparam>
|
||||
/// <param name="x">The array to copy data from</param>
|
||||
public void Put<T>(T[] x)
|
||||
where T : struct
|
||||
{
|
||||
_space = _bb.Put(_space, x);
|
||||
}
|
||||
|
||||
#if ENABLE_SPAN_T
|
||||
/// <summary>
|
||||
/// Puts a span of type T into this builder at the
|
||||
/// current offset
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the input data </typeparam>
|
||||
/// <param name="x">The span to copy data from</param>
|
||||
public void Put<T>(Span<T> x)
|
||||
where T : struct
|
||||
{
|
||||
_space = _bb.Put(_space, x);
|
||||
}
|
||||
#endif
|
||||
|
||||
public void PutDouble(double x)
|
||||
{
|
||||
_bb.PutDouble(_space -= sizeof(double), x);
|
||||
@@ -245,6 +282,59 @@ namespace FlatBuffers
|
||||
/// <param name="x">The `float` to add to the buffer.</param>
|
||||
public void AddFloat(float x) { Prep(sizeof(float), 0); PutFloat(x); }
|
||||
|
||||
/// <summary>
|
||||
/// Add an array of type T to the buffer (aligns the data and grows if necessary).
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the input data</typeparam>
|
||||
/// <param name="x">The array to copy data from</param>
|
||||
public void Add<T>(T[] x)
|
||||
where T : struct
|
||||
{
|
||||
if (x == null)
|
||||
{
|
||||
throw new ArgumentNullException("Cannot add a null array");
|
||||
}
|
||||
|
||||
if( x.Length == 0)
|
||||
{
|
||||
// don't do anything if the array is empty
|
||||
return;
|
||||
}
|
||||
|
||||
if(!ByteBuffer.IsSupportedType<T>())
|
||||
{
|
||||
throw new ArgumentException("Cannot add this Type array to the builder");
|
||||
}
|
||||
|
||||
int size = ByteBuffer.SizeOf<T>();
|
||||
// Need to prep on size (for data alignment) and then we pass the
|
||||
// rest of the length (minus 1) as additional bytes
|
||||
Prep(size, size * (x.Length - 1));
|
||||
Put(x);
|
||||
}
|
||||
|
||||
#if ENABLE_SPAN_T
|
||||
/// <summary>
|
||||
/// Add a span of type T to the buffer (aligns the data and grows if necessary).
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the input data</typeparam>
|
||||
/// <param name="x">The span to copy data from</param>
|
||||
public void Add<T>(Span<T> x)
|
||||
where T : struct
|
||||
{
|
||||
if (!ByteBuffer.IsSupportedType<T>())
|
||||
{
|
||||
throw new ArgumentException("Cannot add this Type array to the builder");
|
||||
}
|
||||
|
||||
int size = ByteBuffer.SizeOf<T>();
|
||||
// Need to prep on size (for data alignment) and then we pass the
|
||||
// rest of the length (minus 1) as additional bytes
|
||||
Prep(size, size * (x.Length - 1));
|
||||
Put(x);
|
||||
}
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Add a `double` to the buffer (aligns the data and grows if necessary).
|
||||
/// </summary>
|
||||
@@ -468,6 +558,27 @@ namespace FlatBuffers
|
||||
return new StringOffset(EndVector().Value);
|
||||
}
|
||||
|
||||
|
||||
#if ENABLE_SPAN_T
|
||||
/// <summary>
|
||||
/// Creates a string in the buffer from a Span containing
|
||||
/// a UTF8 string.
|
||||
/// </summary>
|
||||
/// <param name="chars">the UTF8 string to add to the buffer</param>
|
||||
/// <returns>
|
||||
/// The offset in the buffer where the encoded string starts.
|
||||
/// </returns>
|
||||
public StringOffset CreateUTF8String(Span<byte> chars)
|
||||
{
|
||||
NotNested();
|
||||
AddByte(0);
|
||||
var utf8StringLen = chars.Length;
|
||||
StartVector(1, utf8StringLen, 1);
|
||||
_space = _bb.Put(_space, chars);
|
||||
return new StringOffset(EndVector().Value);
|
||||
}
|
||||
#endif
|
||||
|
||||
/// @cond FLATBUFFERS_INTERNAL
|
||||
// Structs are stored inline, so nothing additional is being added.
|
||||
// `d` is always 0.
|
||||
@@ -525,7 +636,7 @@ namespace FlatBuffers
|
||||
break;
|
||||
}
|
||||
|
||||
endLoop: { }
|
||||
endLoop: { }
|
||||
}
|
||||
|
||||
if (existingVtable != 0) {
|
||||
|
||||
@@ -1,54 +1,16 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{28C00774-1E73-4A75-AD8F-844CD21A064D}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<TargetFrameworks>netstandard1.1;netstandard1.4;netstandard2.0</TargetFrameworks>
|
||||
<RootNamespace>FlatBuffers</RootNamespace>
|
||||
<AssemblyName>FlatBuffers</AssemblyName>
|
||||
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<AssemblyVersion>1.0.0.0</AssemblyVersion>
|
||||
<Copyright>Copyright (c) 2015 Google Inc</Copyright>
|
||||
<RepositoryUrl>https://github.com/google/flatbuffers</RepositoryUrl>
|
||||
<PackageLicenseUrl>https://github.com/google/flatbuffers/blob/master/LICENSE.txt</PackageLicenseUrl>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<PackageReference Include="System.Memory" Version="4.5.1" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="ByteBuffer.cs" />
|
||||
<Compile Include="FlatBufferBuilder.cs" />
|
||||
<Compile Include="FlatBufferConstants.cs" />
|
||||
<Compile Include="IFlatbufferObject.cs" />
|
||||
<Compile Include="Offset.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Struct.cs" />
|
||||
<Compile Include="Table.cs" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
||||
</Target>
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
||||
@@ -1,52 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("FlatBuffers")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("FlatBuffers")]
|
||||
[assembly: AssemblyCopyright("Copyright (c) 2015 Google Inc")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("91c32e64-ef20-47df-9c9f-cec9207bc6df")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||
@@ -78,6 +78,23 @@ namespace FlatBuffers
|
||||
return offset + bb.GetInt(offset) + sizeof(int); // data starts after the length
|
||||
}
|
||||
|
||||
#if ENABLE_SPAN_T
|
||||
// Get the data of a vector whoses offset is stored at "offset" in this object as an
|
||||
// Spant<byte>. If the vector is not present in the ByteBuffer,
|
||||
// then an empty span will be returned.
|
||||
public Span<byte> __vector_as_span(int offset)
|
||||
{
|
||||
var o = this.__offset(offset);
|
||||
if (0 == o)
|
||||
{
|
||||
return new Span<byte>();
|
||||
}
|
||||
|
||||
var pos = this.__vector(o);
|
||||
var len = this.__vector_len(o);
|
||||
return bb.ToSpan(pos, len);
|
||||
}
|
||||
#else
|
||||
// Get the data of a vector whoses offset is stored at "offset" in this object as an
|
||||
// ArraySegment<byte>. If the vector is not present in the ByteBuffer,
|
||||
// then a null value will be returned.
|
||||
@@ -93,6 +110,30 @@ namespace FlatBuffers
|
||||
var len = this.__vector_len(o);
|
||||
return bb.ToArraySegment(pos, len);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Get the data of a vector whoses offset is stored at "offset" in this object as an
|
||||
// T[]. If the vector is not present in the ByteBuffer, then a null value will be
|
||||
// returned.
|
||||
public T[] __vector_as_array<T>(int offset)
|
||||
where T : struct
|
||||
{
|
||||
if(!BitConverter.IsLittleEndian)
|
||||
{
|
||||
throw new NotSupportedException("Getting typed arrays on a Big Endian " +
|
||||
"system is not support");
|
||||
}
|
||||
|
||||
var o = this.__offset(offset);
|
||||
if (0 == o)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var pos = this.__vector(o);
|
||||
var len = this.__vector_len(o);
|
||||
return bb.ToArray<T>(pos, len);
|
||||
}
|
||||
|
||||
// Initialize any Table-derived type to point to the union at the given offset.
|
||||
public T __union<T>(int offset) where T : struct, IFlatbufferObject
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "flatbuffers",
|
||||
"version": "1.9.0",
|
||||
"version": "1.10.0",
|
||||
"description": "Memory Efficient Serialization Library",
|
||||
"files": ["js/flatbuffers.js", "js/flatbuffers.mjs"],
|
||||
"main": "js/flatbuffers",
|
||||
|
||||
6
pom.xml
6
pom.xml
@@ -5,7 +5,7 @@
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>com.google.flatbuffers</groupId>
|
||||
<artifactId>flatbuffers-java</artifactId>
|
||||
<version>1.9.0</version>
|
||||
<version>1.10.0</version>
|
||||
<packaging>bundle</packaging>
|
||||
<name>FlatBuffers Java API</name>
|
||||
<description>
|
||||
@@ -47,8 +47,8 @@
|
||||
<plugin>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<source>1.6</source>
|
||||
<target>1.6</target>
|
||||
<source>1.8</source>
|
||||
<target>1.8</target>
|
||||
</configuration>
|
||||
<version>3.2</version>
|
||||
</plugin>
|
||||
|
||||
@@ -160,7 +160,6 @@ class Builder(object):
|
||||
# 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
|
||||
self.nested = True
|
||||
|
||||
def WriteVtable(self):
|
||||
|
||||
2
python/setup.cfg
Normal file
2
python/setup.cfg
Normal file
@@ -0,0 +1,2 @@
|
||||
[bdist_wheel]
|
||||
universal=1
|
||||
27
readme.md
27
readme.md
@@ -4,29 +4,34 @@
|
||||
[](https://gitter.im/google/flatbuffers?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||
[](https://travis-ci.org/google/flatbuffers) [](https://ci.appveyor.com/project/gwvo/flatbuffers)
|
||||
|
||||
**FlatBuffers** is an efficient cross platform serialization library for games and
|
||||
other memory constrained apps. It allows you to directly access serialized data without
|
||||
unpacking/parsing it first, while still having great forwards/backwards compatibility.
|
||||
**FlatBuffers** is a cross platform serialization library architected for
|
||||
maximum memory efficiency. It allows you to directly access serialized data without parsing/unpacking it first, while still having great forwards/backwards compatibility.
|
||||
|
||||
**Go to our [landing page][] to browse our documentation.**
|
||||
|
||||
## Supported operating systems
|
||||
* Android
|
||||
* Windows
|
||||
* MacOS X
|
||||
* Linux
|
||||
* Android
|
||||
* And any others with a recent C++ compiler.
|
||||
|
||||
## Supported programming languages
|
||||
* C++
|
||||
* C#
|
||||
* C
|
||||
* Dart
|
||||
* Go
|
||||
* Java
|
||||
* JavaScript
|
||||
* Lobster
|
||||
* Lua
|
||||
* PHP
|
||||
* Python
|
||||
* Rust
|
||||
* TypeScript
|
||||
|
||||
*and many more in progress...*
|
||||
*and more in progress...*
|
||||
|
||||
## Contribution
|
||||
* [FlatBuffers Google Group][] to discuss FlatBuffers with other developers and users.
|
||||
@@ -35,16 +40,6 @@ unpacking/parsing it first, while still having great forwards/backwards compatib
|
||||
|
||||
*To contribute to this project,* see [CONTRIBUTING][].
|
||||
|
||||
## Integration
|
||||
For applications on Google Play that integrate this tool, usage is tracked.
|
||||
This tracking is done automatically using the embedded version string
|
||||
(**`flatbuffer_version_string`**), and helps us continue to optimize it. Aside from
|
||||
consuming a few extra bytes in your application binary, it shouldn't affect
|
||||
your application at all. We use this information to let us know if FlatBuffers
|
||||
is useful and if we should continue to invest in it. Since this is open
|
||||
source, you are free to remove the version string but we would appreciate if
|
||||
you would leave it in.
|
||||
|
||||
## Licensing
|
||||
*Flatbuffers* is licensed under the Apache License, Version 2.0. See [LICENSE][] for the full license text.
|
||||
|
||||
@@ -55,5 +50,5 @@ you would leave it in.
|
||||
[FlatBuffers Google Group]: https://groups.google.com/forum/#!forum/flatbuffers
|
||||
[FlatBuffers Issues Tracker]: http://github.com/google/flatbuffers/issues
|
||||
[stackoverflow.com]: http://stackoverflow.com/search?q=flatbuffers
|
||||
[landing page]: http://google.github.io/flatbuffers
|
||||
[landing page]: https://google.github.io/flatbuffers
|
||||
[LICENSE]: https://github.com/google/flatbuffers/blob/master/LICENSE.txt
|
||||
|
||||
0
reflection/generate_code.sh
Normal file → Executable file
0
reflection/generate_code.sh
Normal file → Executable file
@@ -44,6 +44,7 @@ table EnumVal {
|
||||
value:long (key);
|
||||
object:Object; // Will be deprecated in favor of union_type in the future.
|
||||
union_type:Type;
|
||||
documentation:[string];
|
||||
}
|
||||
|
||||
table Enum {
|
||||
@@ -79,12 +80,28 @@ table Object { // Used for both tables and structs.
|
||||
documentation:[string];
|
||||
}
|
||||
|
||||
table RPCCall {
|
||||
name:string (required, key);
|
||||
request:Object (required); // must be a table (not a struct)
|
||||
response:Object (required); // must be a table (not a struct)
|
||||
attributes:[KeyValue];
|
||||
documentation:[string];
|
||||
}
|
||||
|
||||
table Service {
|
||||
name:string (required, key);
|
||||
calls:[RPCCall];
|
||||
attributes:[KeyValue];
|
||||
documentation:[string];
|
||||
}
|
||||
|
||||
table Schema {
|
||||
objects:[Object] (required); // Sorted.
|
||||
enums:[Enum] (required); // Sorted.
|
||||
objects:[Object] (required); // Sorted.
|
||||
enums:[Enum] (required); // Sorted.
|
||||
file_ident:string;
|
||||
file_ext:string;
|
||||
root_table:Object;
|
||||
services:[Service]; // Sorted.
|
||||
}
|
||||
|
||||
root_type Schema;
|
||||
|
||||
13
rust/flatbuffers/Cargo.toml
Normal file
13
rust/flatbuffers/Cargo.toml
Normal file
@@ -0,0 +1,13 @@
|
||||
[package]
|
||||
name = "flatbuffers"
|
||||
version = "0.5.0"
|
||||
authors = ["Robert Winslow <hello@rwinslow.com>", "FlatBuffers Maintainers"]
|
||||
license = "Apache-2.0"
|
||||
description = "Official FlatBuffers Rust runtime library."
|
||||
homepage = "https://google.github.io/flatbuffers/"
|
||||
repository = "https://github.com/google/flatbuffers"
|
||||
keywords = ["flatbuffers", "serialization", "zero-copy"]
|
||||
categories = ["encoding", "data-structures", "memory-management"]
|
||||
|
||||
[dependencies]
|
||||
smallvec = "0.6"
|
||||
636
rust/flatbuffers/src/builder.rs
Normal file
636
rust/flatbuffers/src/builder.rs
Normal file
@@ -0,0 +1,636 @@
|
||||
/*
|
||||
* Copyright 2018 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.
|
||||
*/
|
||||
|
||||
extern crate smallvec;
|
||||
|
||||
use std::cmp::max;
|
||||
use std::marker::PhantomData;
|
||||
use std::ptr::write_bytes;
|
||||
use std::slice::from_raw_parts;
|
||||
|
||||
use endian_scalar::{read_scalar, emplace_scalar};
|
||||
use primitives::*;
|
||||
use push::{Push, PushAlignment};
|
||||
use table::Table;
|
||||
use vtable::{VTable, field_index_to_field_offset};
|
||||
use vtable_writer::VTableWriter;
|
||||
use vector::{SafeSliceAccess, Vector};
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
struct FieldLoc {
|
||||
off: UOffsetT,
|
||||
id: VOffsetT,
|
||||
}
|
||||
|
||||
/// FlatBufferBuilder builds a FlatBuffer through manipulating its internal
|
||||
/// state. It has an owned `Vec<u8>` that grows as needed (up to the hardcoded
|
||||
/// limit of 2GiB, which is set by the FlatBuffers format).
|
||||
pub struct FlatBufferBuilder<'fbb> {
|
||||
owned_buf: Vec<u8>,
|
||||
head: usize,
|
||||
|
||||
field_locs: Vec<FieldLoc>,
|
||||
written_vtable_revpos: Vec<UOffsetT>,
|
||||
|
||||
nested: bool,
|
||||
finished: bool,
|
||||
|
||||
min_align: usize,
|
||||
|
||||
_phantom: PhantomData<&'fbb ()>,
|
||||
}
|
||||
|
||||
impl<'fbb> FlatBufferBuilder<'fbb> {
|
||||
/// Create a FlatBufferBuilder that is ready for writing.
|
||||
pub fn new() -> Self {
|
||||
Self::new_with_capacity(0)
|
||||
}
|
||||
|
||||
/// Create a FlatBufferBuilder that is ready for writing, with a
|
||||
/// ready-to-use capacity of the provided size.
|
||||
///
|
||||
/// The maximum valid value is `FLATBUFFERS_MAX_BUFFER_SIZE`.
|
||||
pub fn new_with_capacity(size: usize) -> Self {
|
||||
// we need to check the size here because we create the backing buffer
|
||||
// directly, bypassing the typical way of using grow_owned_buf:
|
||||
assert!(size <= FLATBUFFERS_MAX_BUFFER_SIZE,
|
||||
"cannot initialize buffer bigger than 2 gigabytes");
|
||||
|
||||
FlatBufferBuilder {
|
||||
owned_buf: vec![0u8; size],
|
||||
head: size,
|
||||
|
||||
field_locs: Vec::new(),
|
||||
written_vtable_revpos: Vec::new(),
|
||||
|
||||
nested: false,
|
||||
finished: false,
|
||||
|
||||
min_align: 0,
|
||||
|
||||
_phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
/// Reset the FlatBufferBuilder internal state. Use this method after a
|
||||
/// call to a `finish` function in order to re-use a FlatBufferBuilder.
|
||||
///
|
||||
/// This function is the only way to reset the `finished` state and start
|
||||
/// again.
|
||||
///
|
||||
/// If you are using a FlatBufferBuilder repeatedly, make sure to use this
|
||||
/// function, because it re-uses the FlatBufferBuilder's existing
|
||||
/// heap-allocated `Vec<u8>` internal buffer. This offers significant speed
|
||||
/// improvements as compared to creating a new FlatBufferBuilder for every
|
||||
/// new object.
|
||||
pub fn reset(&mut self) {
|
||||
// memset only the part of the buffer that could be dirty:
|
||||
{
|
||||
let to_clear = self.owned_buf.len() - self.head;
|
||||
let ptr = (&mut self.owned_buf[self.head..]).as_mut_ptr();
|
||||
unsafe { write_bytes(ptr, 0, to_clear); }
|
||||
}
|
||||
|
||||
self.head = self.owned_buf.len();
|
||||
self.written_vtable_revpos.clear();
|
||||
|
||||
self.nested = false;
|
||||
self.finished = false;
|
||||
|
||||
self.min_align = 0;
|
||||
}
|
||||
|
||||
/// Destroy the FlatBufferBuilder, returning its internal byte vector
|
||||
/// and the index into it that represents the start of valid data.
|
||||
pub fn collapse(self) -> (Vec<u8>, usize) {
|
||||
(self.owned_buf, self.head)
|
||||
}
|
||||
|
||||
/// Push a Push'able value onto the front of the in-progress data.
|
||||
///
|
||||
/// This function uses traits to provide a unified API for writing
|
||||
/// scalars, tables, vectors, and WIPOffsets.
|
||||
#[inline]
|
||||
pub fn push<P: Push>(&mut self, x: P) -> WIPOffset<P::Output> {
|
||||
let sz = P::size();
|
||||
self.align(sz, P::alignment());
|
||||
self.make_space(sz);
|
||||
{
|
||||
let (dst, rest) = (&mut self.owned_buf[self.head..]).split_at_mut(sz);
|
||||
x.push(dst, rest);
|
||||
}
|
||||
WIPOffset::new(self.used_space() as UOffsetT)
|
||||
}
|
||||
|
||||
/// Push a Push'able value onto the front of the in-progress data, and
|
||||
/// store a reference to it in the in-progress vtable. If the value matches
|
||||
/// the default, then this is a no-op.
|
||||
#[inline]
|
||||
pub fn push_slot<X: Push + PartialEq>(&mut self, slotoff: VOffsetT, x: X, default: X) {
|
||||
self.assert_nested("push_slot");
|
||||
if x == default {
|
||||
return;
|
||||
}
|
||||
self.push_slot_always(slotoff, x);
|
||||
}
|
||||
|
||||
/// Push a Push'able value onto the front of the in-progress data, and
|
||||
/// store a reference to it in the in-progress vtable.
|
||||
#[inline]
|
||||
pub fn push_slot_always<X: Push>(&mut self, slotoff: VOffsetT, x: X) {
|
||||
self.assert_nested("push_slot_always");
|
||||
let off = self.push(x);
|
||||
self.track_field(slotoff, off.value());
|
||||
}
|
||||
|
||||
/// Retrieve the number of vtables that have been serialized into the
|
||||
/// FlatBuffer. This is primarily used to check vtable deduplication.
|
||||
#[inline]
|
||||
pub fn num_written_vtables(&self) -> usize {
|
||||
self.written_vtable_revpos.len()
|
||||
}
|
||||
|
||||
/// Start a Table write.
|
||||
///
|
||||
/// Asserts that the builder is not in a nested state.
|
||||
///
|
||||
/// Users probably want to use `push_slot` to add values after calling this.
|
||||
#[inline]
|
||||
pub fn start_table(&mut self) -> WIPOffset<TableUnfinishedWIPOffset> {
|
||||
self.assert_not_nested("start_table can not be called when a table or vector is under construction");
|
||||
self.nested = true;
|
||||
|
||||
WIPOffset::new(self.used_space() as UOffsetT)
|
||||
}
|
||||
|
||||
/// End a Table write.
|
||||
///
|
||||
/// Asserts that the builder is in a nested state.
|
||||
#[inline]
|
||||
pub fn end_table(&mut self, off: WIPOffset<TableUnfinishedWIPOffset>) -> WIPOffset<TableFinishedWIPOffset> {
|
||||
self.assert_nested("end_table");
|
||||
|
||||
let o = self.write_vtable(off);
|
||||
|
||||
self.nested = false;
|
||||
self.field_locs.clear();
|
||||
|
||||
WIPOffset::new(o.value())
|
||||
}
|
||||
|
||||
/// Start a Vector write.
|
||||
///
|
||||
/// Asserts that the builder is not in a nested state.
|
||||
///
|
||||
/// Most users will prefer to call `create_vector`.
|
||||
/// Speed optimizing users who choose to create vectors manually using this
|
||||
/// function will want to use `push` to add values.
|
||||
#[inline]
|
||||
pub fn start_vector<T: Push>(&mut self, num_items: usize) {
|
||||
self.assert_not_nested("start_vector can not be called when a table or vector is under construction");
|
||||
self.nested = true;
|
||||
self.align(num_items * T::size(), T::alignment().max_of(SIZE_UOFFSET));
|
||||
}
|
||||
|
||||
/// End a Vector write.
|
||||
///
|
||||
/// Note that the `num_elems` parameter is the number of written items, not
|
||||
/// the byte count.
|
||||
///
|
||||
/// Asserts that the builder is in a nested state.
|
||||
#[inline]
|
||||
pub fn end_vector<T: Push>(&mut self, num_elems: usize) -> WIPOffset<Vector<'fbb, T>> {
|
||||
self.assert_nested("end_vector");
|
||||
self.nested = false;
|
||||
let o = self.push::<UOffsetT>(num_elems as UOffsetT);
|
||||
WIPOffset::new(o.value())
|
||||
}
|
||||
|
||||
/// Create a utf8 string.
|
||||
///
|
||||
/// The wire format represents this as a zero-terminated byte vector.
|
||||
#[inline]
|
||||
pub fn create_string<'a: 'b, 'b>(&'a mut self, s: &'b str) -> WIPOffset<&'fbb str> {
|
||||
self.assert_not_nested("create_string can not be called when a table or vector is under construction");
|
||||
WIPOffset::new(self.create_byte_string(s.as_bytes()).value())
|
||||
}
|
||||
|
||||
/// Create a zero-terminated byte vector.
|
||||
#[inline]
|
||||
pub fn create_byte_string(&mut self, data: &[u8]) -> WIPOffset<&'fbb [u8]> {
|
||||
self.assert_not_nested("create_byte_string can not be called when a table or vector is under construction");
|
||||
self.align(data.len() + 1, PushAlignment::new(SIZE_UOFFSET));
|
||||
self.push(0u8);
|
||||
self.push_bytes_unprefixed(data);
|
||||
self.push(data.len() as UOffsetT);
|
||||
WIPOffset::new(self.used_space() as UOffsetT)
|
||||
}
|
||||
|
||||
/// Create a vector by memcpy'ing. This is much faster than calling
|
||||
/// `create_vector`, but the underlying type must be represented as
|
||||
/// little-endian on the host machine. This property is encoded in the
|
||||
/// type system through the SafeSliceAccess trait. The following types are
|
||||
/// always safe, on any platform: bool, u8, i8, and any
|
||||
/// FlatBuffers-generated struct.
|
||||
#[inline]
|
||||
pub fn create_vector_direct<'a: 'b, 'b, T: SafeSliceAccess + Push + Sized + 'b>(&'a mut self, items: &'b [T]) -> WIPOffset<Vector<'fbb, T>> {
|
||||
self.assert_not_nested("create_vector_direct can not be called when a table or vector is under construction");
|
||||
let elem_size = T::size();
|
||||
self.align(items.len() * elem_size, T::alignment().max_of(SIZE_UOFFSET));
|
||||
|
||||
let bytes = {
|
||||
let ptr = items.as_ptr() as *const T as *const u8;
|
||||
unsafe { from_raw_parts(ptr, items.len() * elem_size) }
|
||||
};
|
||||
self.push_bytes_unprefixed(bytes);
|
||||
self.push(items.len() as UOffsetT);
|
||||
|
||||
WIPOffset::new(self.used_space() as UOffsetT)
|
||||
}
|
||||
|
||||
/// Create a vector of strings.
|
||||
///
|
||||
/// Speed-sensitive users may wish to reduce memory usage by creating the
|
||||
/// vector manually: use `start_vector`, `push`, and `end_vector`.
|
||||
#[inline]
|
||||
pub fn create_vector_of_strings<'a, 'b>(&'a mut self, xs: &'b [&'b str]) -> WIPOffset<Vector<'fbb, ForwardsUOffset<&'fbb str>>> {
|
||||
self.assert_not_nested("create_vector_of_strings can not be called when a table or vector is under construction");
|
||||
// internally, smallvec can be a stack-allocated or heap-allocated vector.
|
||||
// we expect it to usually be stack-allocated.
|
||||
let mut offsets: smallvec::SmallVec<[WIPOffset<&str>; 0]> = smallvec::SmallVec::with_capacity(xs.len());
|
||||
unsafe { offsets.set_len(xs.len()); }
|
||||
for (i, &s) in xs.iter().enumerate().rev() {
|
||||
let o = self.create_string(s);
|
||||
offsets[i] = o;
|
||||
}
|
||||
self.create_vector(&offsets[..])
|
||||
}
|
||||
|
||||
/// Create a vector of Push-able objects.
|
||||
///
|
||||
/// Speed-sensitive users may wish to reduce memory usage by creating the
|
||||
/// vector manually: use `start_vector`, `push`, and `end_vector`.
|
||||
#[inline]
|
||||
pub fn create_vector<'a: 'b, 'b, T: Push + Copy + 'b>(&'a mut self, items: &'b [T]) -> WIPOffset<Vector<'fbb, T::Output>> {
|
||||
let elem_size = T::size();
|
||||
self.align(items.len() * elem_size, T::alignment().max_of(SIZE_UOFFSET));
|
||||
for i in (0..items.len()).rev() {
|
||||
self.push(items[i]);
|
||||
}
|
||||
WIPOffset::new(self.push::<UOffsetT>(items.len() as UOffsetT).value())
|
||||
}
|
||||
|
||||
/// Get the byte slice for the data that has been written, regardless of
|
||||
/// whether it has been finished.
|
||||
#[inline]
|
||||
pub fn unfinished_data(&self) -> &[u8] {
|
||||
&self.owned_buf[self.head..]
|
||||
}
|
||||
/// Get the byte slice for the data that has been written after a call to
|
||||
/// one of the `finish` functions.
|
||||
#[inline]
|
||||
pub fn finished_data(&self) -> &[u8] {
|
||||
self.assert_finished("finished_bytes cannot be called when the buffer is not yet finished");
|
||||
&self.owned_buf[self.head..]
|
||||
}
|
||||
/// Assert that a field is present in the just-finished Table.
|
||||
///
|
||||
/// This is somewhat low-level and is mostly used by the generated code.
|
||||
#[inline]
|
||||
pub fn required(&self,
|
||||
tab_revloc: WIPOffset<TableFinishedWIPOffset>,
|
||||
slot_byte_loc: VOffsetT,
|
||||
assert_msg_name: &'static str) {
|
||||
let idx = self.used_space() - tab_revloc.value() as usize;
|
||||
let tab = Table::new(&self.owned_buf[self.head..], idx);
|
||||
let o = tab.vtable().get(slot_byte_loc) as usize;
|
||||
assert!(o != 0, "missing required field {}", assert_msg_name);
|
||||
}
|
||||
|
||||
/// Finalize the FlatBuffer by: aligning it, pushing an optional file
|
||||
/// identifier on to it, pushing a size prefix on to it, and marking the
|
||||
/// internal state of the FlatBufferBuilder as `finished`. Afterwards,
|
||||
/// users can call `finished_data` to get the resulting data.
|
||||
#[inline]
|
||||
pub fn finish_size_prefixed<T>(&mut self, root: WIPOffset<T>, file_identifier: Option<&str>) {
|
||||
self.finish_with_opts(root, file_identifier, true);
|
||||
}
|
||||
|
||||
/// Finalize the FlatBuffer by: aligning it, pushing an optional file
|
||||
/// identifier on to it, and marking the internal state of the
|
||||
/// FlatBufferBuilder as `finished`. Afterwards, users can call
|
||||
/// `finished_data` to get the resulting data.
|
||||
#[inline]
|
||||
pub fn finish<T>(&mut self, root: WIPOffset<T>, file_identifier: Option<&str>) {
|
||||
self.finish_with_opts(root, file_identifier, false);
|
||||
}
|
||||
|
||||
/// Finalize the FlatBuffer by: aligning it and marking the internal state
|
||||
/// of the FlatBufferBuilder as `finished`. Afterwards, users can call
|
||||
/// `finished_data` to get the resulting data.
|
||||
#[inline]
|
||||
pub fn finish_minimal<T>(&mut self, root: WIPOffset<T>) {
|
||||
self.finish_with_opts(root, None, false);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn used_space(&self) -> usize {
|
||||
self.owned_buf.len() - self.head as usize
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn track_field(&mut self, slot_off: VOffsetT, off: UOffsetT) {
|
||||
let fl = FieldLoc {
|
||||
id: slot_off,
|
||||
off: off,
|
||||
};
|
||||
self.field_locs.push(fl);
|
||||
}
|
||||
|
||||
/// Write the VTable, if it is new.
|
||||
fn write_vtable(&mut self, table_tail_revloc: WIPOffset<TableUnfinishedWIPOffset>) -> WIPOffset<VTableWIPOffset> {
|
||||
self.assert_nested("write_vtable");
|
||||
|
||||
// Write the vtable offset, which is the start of any Table.
|
||||
// We fill its value later.
|
||||
let object_revloc_to_vtable: WIPOffset<VTableWIPOffset> =
|
||||
WIPOffset::new(self.push::<UOffsetT>(0xF0F0F0F0 as UOffsetT).value());
|
||||
|
||||
// Layout of the data this function will create when a new vtable is
|
||||
// needed.
|
||||
// --------------------------------------------------------------------
|
||||
// vtable starts here
|
||||
// | x, x -- vtable len (bytes) [u16]
|
||||
// | x, x -- object inline len (bytes) [u16]
|
||||
// | x, x -- zero, or num bytes from start of object to field #0 [u16]
|
||||
// | ...
|
||||
// | x, x -- zero, or num bytes from start of object to field #n-1 [u16]
|
||||
// vtable ends here
|
||||
// table starts here
|
||||
// | x, x, x, x -- offset (negative direction) to the vtable [i32]
|
||||
// | aka "vtableoffset"
|
||||
// | -- table inline data begins here, we don't touch it --
|
||||
// table ends here -- aka "table_start"
|
||||
// --------------------------------------------------------------------
|
||||
//
|
||||
// Layout of the data this function will create when we re-use an
|
||||
// existing vtable.
|
||||
//
|
||||
// We always serialize this particular vtable, then compare it to the
|
||||
// other vtables we know about to see if there is a duplicate. If there
|
||||
// is, then we erase the serialized vtable we just made.
|
||||
// We serialize it first so that we are able to do byte-by-byte
|
||||
// comparisons with already-serialized vtables. This 1) saves
|
||||
// bookkeeping space (we only keep revlocs to existing vtables), 2)
|
||||
// allows us to convert to little-endian once, then do
|
||||
// fast memcmp comparisons, and 3) by ensuring we are comparing real
|
||||
// serialized vtables, we can be more assured that we are doing the
|
||||
// comparisons correctly.
|
||||
//
|
||||
// --------------------------------------------------------------------
|
||||
// table starts here
|
||||
// | x, x, x, x -- offset (negative direction) to an existing vtable [i32]
|
||||
// | aka "vtableoffset"
|
||||
// | -- table inline data begins here, we don't touch it --
|
||||
// table starts here: aka "table_start"
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
// fill the WIP vtable with zeros:
|
||||
let vtable_byte_len = get_vtable_byte_len(&self.field_locs);
|
||||
self.make_space(vtable_byte_len);
|
||||
|
||||
// compute the length of the table (not vtable!) in bytes:
|
||||
let table_object_size = object_revloc_to_vtable.value() - table_tail_revloc.value();
|
||||
debug_assert!(table_object_size < 0x10000); // vTable use 16bit offsets.
|
||||
|
||||
// Write the VTable (we may delete it afterwards, if it is a duplicate):
|
||||
let vt_start_pos = self.head;
|
||||
let vt_end_pos = self.head + vtable_byte_len;
|
||||
{
|
||||
// write the vtable header:
|
||||
let vtfw = &mut VTableWriter::init(&mut self.owned_buf[vt_start_pos..vt_end_pos]);
|
||||
vtfw.write_vtable_byte_length(vtable_byte_len as VOffsetT);
|
||||
vtfw.write_object_inline_size(table_object_size as VOffsetT);
|
||||
|
||||
// serialize every FieldLoc to the vtable:
|
||||
for &fl in self.field_locs.iter() {
|
||||
let pos: VOffsetT = (object_revloc_to_vtable.value() - fl.off) as VOffsetT;
|
||||
debug_assert_eq!(vtfw.get_field_offset(fl.id),
|
||||
0,
|
||||
"tried to write a vtable field multiple times");
|
||||
vtfw.write_field_offset(fl.id, pos);
|
||||
}
|
||||
}
|
||||
let dup_vt_use = {
|
||||
let this_vt = VTable::init(&self.owned_buf[..], self.head);
|
||||
self.find_duplicate_stored_vtable_revloc(this_vt)
|
||||
};
|
||||
|
||||
let vt_use = match dup_vt_use {
|
||||
Some(n) => {
|
||||
VTableWriter::init(&mut self.owned_buf[vt_start_pos..vt_end_pos]).clear();
|
||||
self.head += vtable_byte_len;
|
||||
n
|
||||
}
|
||||
None => {
|
||||
let new_vt_use = self.used_space() as UOffsetT;
|
||||
self.written_vtable_revpos.push(new_vt_use);
|
||||
new_vt_use
|
||||
}
|
||||
};
|
||||
|
||||
{
|
||||
let n = self.head + self.used_space() - object_revloc_to_vtable.value() as usize;
|
||||
let saw = read_scalar::<UOffsetT>(&self.owned_buf[n..n + SIZE_SOFFSET]);
|
||||
debug_assert_eq!(saw, 0xF0F0F0F0);
|
||||
emplace_scalar::<SOffsetT>(&mut self.owned_buf[n..n + SIZE_SOFFSET],
|
||||
vt_use as SOffsetT - object_revloc_to_vtable.value() as SOffsetT);
|
||||
}
|
||||
|
||||
self.field_locs.clear();
|
||||
|
||||
object_revloc_to_vtable
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn find_duplicate_stored_vtable_revloc(&self, needle: VTable) -> Option<UOffsetT> {
|
||||
for &revloc in self.written_vtable_revpos.iter().rev() {
|
||||
let o = VTable::init(&self.owned_buf[..], self.head + self.used_space() - revloc as usize);
|
||||
if needle == o {
|
||||
return Some(revloc);
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
// Only call this when you know it is safe to double the size of the buffer.
|
||||
#[inline]
|
||||
fn grow_owned_buf(&mut self) {
|
||||
let old_len = self.owned_buf.len();
|
||||
let new_len = max(1, old_len * 2);
|
||||
|
||||
let starting_active_size = self.used_space();
|
||||
|
||||
let diff = new_len - old_len;
|
||||
self.owned_buf.resize(new_len, 0);
|
||||
self.head += diff;
|
||||
|
||||
let ending_active_size = self.used_space();
|
||||
debug_assert_eq!(starting_active_size, ending_active_size);
|
||||
|
||||
if new_len == 1 {
|
||||
return;
|
||||
}
|
||||
|
||||
// calculate the midpoint, and safely copy the old end data to the new
|
||||
// end position:
|
||||
let middle = new_len / 2;
|
||||
{
|
||||
let (left, right) = &mut self.owned_buf[..].split_at_mut(middle);
|
||||
right.copy_from_slice(left);
|
||||
}
|
||||
// finally, zero out the old end data.
|
||||
{
|
||||
let ptr = (&mut self.owned_buf[..middle]).as_mut_ptr();
|
||||
unsafe { write_bytes(ptr, 0, middle); }
|
||||
}
|
||||
}
|
||||
|
||||
// with or without a size prefix changes how we load the data, so finish*
|
||||
// functions are split along those lines.
|
||||
fn finish_with_opts<T>(&mut self,
|
||||
root: WIPOffset<T>,
|
||||
file_identifier: Option<&str>,
|
||||
size_prefixed: bool) {
|
||||
self.assert_not_finished("buffer cannot be finished when it is already finished");
|
||||
self.assert_not_nested("buffer cannot be finished when a table or vector is under construction");
|
||||
self.written_vtable_revpos.clear();
|
||||
|
||||
let to_align = {
|
||||
// for the root offset:
|
||||
let a = SIZE_UOFFSET;
|
||||
// for the size prefix:
|
||||
let b = if size_prefixed { SIZE_UOFFSET } else { 0 };
|
||||
// for the file identifier (a string that is not zero-terminated):
|
||||
let c = if file_identifier.is_some() {
|
||||
FILE_IDENTIFIER_LENGTH
|
||||
} else {
|
||||
0
|
||||
};
|
||||
a + b + c
|
||||
};
|
||||
|
||||
{
|
||||
let ma = PushAlignment::new(self.min_align);
|
||||
self.align(to_align, ma);
|
||||
}
|
||||
|
||||
if let Some(ident) = file_identifier {
|
||||
debug_assert_eq!(ident.len(), FILE_IDENTIFIER_LENGTH);
|
||||
self.push_bytes_unprefixed(ident.as_bytes());
|
||||
}
|
||||
|
||||
self.push(root);
|
||||
|
||||
if size_prefixed {
|
||||
let sz = self.used_space() as UOffsetT;
|
||||
self.push::<UOffsetT>(sz);
|
||||
}
|
||||
self.finished = true;
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn align(&mut self, len: usize, alignment: PushAlignment) {
|
||||
self.track_min_align(alignment.value());
|
||||
let s = self.used_space() as usize;
|
||||
self.make_space(padding_bytes(s + len, alignment.value()));
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn track_min_align(&mut self, alignment: usize) {
|
||||
self.min_align = max(self.min_align, alignment);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn push_bytes_unprefixed(&mut self, x: &[u8]) -> UOffsetT {
|
||||
let n = self.make_space(x.len());
|
||||
&mut self.owned_buf[n..n + x.len()].copy_from_slice(x);
|
||||
|
||||
n as UOffsetT
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn make_space(&mut self, want: usize) -> usize {
|
||||
self.ensure_capacity(want);
|
||||
self.head -= want;
|
||||
self.head
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn ensure_capacity(&mut self, want: usize) -> usize {
|
||||
if self.unused_ready_space() >= want {
|
||||
return want;
|
||||
}
|
||||
assert!(want <= FLATBUFFERS_MAX_BUFFER_SIZE,
|
||||
"cannot grow buffer beyond 2 gigabytes");
|
||||
|
||||
while self.unused_ready_space() < want {
|
||||
self.grow_owned_buf();
|
||||
}
|
||||
want
|
||||
}
|
||||
#[inline]
|
||||
fn unused_ready_space(&self) -> usize {
|
||||
self.head
|
||||
}
|
||||
#[inline]
|
||||
fn assert_nested(&self, fn_name: &'static str) {
|
||||
// we don't assert that self.field_locs.len() >0 because the vtable
|
||||
// could be empty (e.g. for empty tables, or for all-default values).
|
||||
debug_assert!(self.nested, format!("incorrect FlatBufferBuilder usage: {} must be called while in a nested state", fn_name));
|
||||
}
|
||||
#[inline]
|
||||
fn assert_not_nested(&self, msg: &'static str) {
|
||||
debug_assert!(!self.nested, msg);
|
||||
}
|
||||
#[inline]
|
||||
fn assert_finished(&self, msg: &'static str) {
|
||||
debug_assert!(self.finished, msg);
|
||||
}
|
||||
#[inline]
|
||||
fn assert_not_finished(&self, msg: &'static str) {
|
||||
debug_assert!(!self.finished, msg);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// Compute the length of the vtable needed to represent the provided FieldLocs.
|
||||
/// If there are no FieldLocs, then provide the minimum number of bytes
|
||||
/// required: enough to write the VTable header.
|
||||
#[inline]
|
||||
fn get_vtable_byte_len(field_locs: &[FieldLoc]) -> usize {
|
||||
let max_voffset = field_locs.iter().map(|fl| fl.id).max();
|
||||
match max_voffset {
|
||||
None => { field_index_to_field_offset(0) as usize }
|
||||
Some(mv) => { mv as usize + SIZE_VOFFSET }
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn padding_bytes(buf_size: usize, scalar_size: usize) -> usize {
|
||||
// ((!buf_size) + 1) & (scalar_size - 1)
|
||||
(!buf_size).wrapping_add(1) & (scalar_size.wrapping_sub(1))
|
||||
}
|
||||
180
rust/flatbuffers/src/endian_scalar.rs
Normal file
180
rust/flatbuffers/src/endian_scalar.rs
Normal file
@@ -0,0 +1,180 @@
|
||||
/*
|
||||
* Copyright 2018 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.
|
||||
*/
|
||||
|
||||
use std::mem::size_of;
|
||||
|
||||
/// Trait for values that must be stored in little-endian byte order, but
|
||||
/// might be represented in memory as big-endian. Every type that implements
|
||||
/// EndianScalar is a valid FlatBuffers scalar value.
|
||||
///
|
||||
/// The Rust stdlib does not provide a trait to represent scalars, so this trait
|
||||
/// serves that purpose, too.
|
||||
///
|
||||
/// Note that we do not use the num-traits crate for this, because it provides
|
||||
/// "too much". For example, num-traits provides i128 support, but that is an
|
||||
/// invalid FlatBuffers type.
|
||||
pub trait EndianScalar: Sized + PartialEq + Copy + Clone {
|
||||
fn to_little_endian(self) -> Self;
|
||||
fn from_little_endian(self) -> Self;
|
||||
}
|
||||
|
||||
/// Macro for implementing a no-op endian conversion. This is used for types
|
||||
/// that are one byte wide.
|
||||
macro_rules! impl_endian_scalar_noop {
|
||||
($ty:ident) => (
|
||||
impl EndianScalar for $ty {
|
||||
#[inline]
|
||||
fn to_little_endian(self) -> Self {
|
||||
self
|
||||
}
|
||||
#[inline]
|
||||
fn from_little_endian(self) -> Self {
|
||||
self
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
/// Macro for implementing an endian conversion using the stdlib `to_le` and
|
||||
/// `from_le` functions. This is used for integer types. It is not used for
|
||||
/// floats, because the `to_le` and `from_le` are not implemented for them in
|
||||
/// the stdlib.
|
||||
macro_rules! impl_endian_scalar_stdlib_le_conversion {
|
||||
($ty:ident) => (
|
||||
impl EndianScalar for $ty {
|
||||
#[inline]
|
||||
fn to_little_endian(self) -> Self {
|
||||
Self::to_le(self)
|
||||
}
|
||||
#[inline]
|
||||
fn from_little_endian(self) -> Self {
|
||||
Self::from_le(self)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
impl_endian_scalar_noop!(bool);
|
||||
impl_endian_scalar_noop!(u8);
|
||||
impl_endian_scalar_noop!(i8);
|
||||
|
||||
impl_endian_scalar_stdlib_le_conversion!(u16);
|
||||
impl_endian_scalar_stdlib_le_conversion!(u32);
|
||||
impl_endian_scalar_stdlib_le_conversion!(u64);
|
||||
impl_endian_scalar_stdlib_le_conversion!(i16);
|
||||
impl_endian_scalar_stdlib_le_conversion!(i32);
|
||||
impl_endian_scalar_stdlib_le_conversion!(i64);
|
||||
|
||||
impl EndianScalar for f32 {
|
||||
/// Convert f32 from host endian-ness to little-endian.
|
||||
#[inline]
|
||||
fn to_little_endian(self) -> Self {
|
||||
#[cfg(target_endian = "little")]
|
||||
{
|
||||
self
|
||||
}
|
||||
#[cfg(not(target_endian = "little"))]
|
||||
{
|
||||
byte_swap_f32(&self)
|
||||
}
|
||||
}
|
||||
/// Convert f32 from little-endian to host endian-ness.
|
||||
#[inline]
|
||||
fn from_little_endian(self) -> Self {
|
||||
#[cfg(target_endian = "little")]
|
||||
{
|
||||
self
|
||||
}
|
||||
#[cfg(not(target_endian = "little"))]
|
||||
{
|
||||
byte_swap_f32(&self)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl EndianScalar for f64 {
|
||||
/// Convert f64 from host endian-ness to little-endian.
|
||||
#[inline]
|
||||
fn to_little_endian(self) -> Self {
|
||||
#[cfg(target_endian = "little")]
|
||||
{
|
||||
self
|
||||
}
|
||||
#[cfg(not(target_endian = "little"))]
|
||||
{
|
||||
byte_swap_f64(&self)
|
||||
}
|
||||
}
|
||||
/// Convert f64 from little-endian to host endian-ness.
|
||||
#[inline]
|
||||
fn from_little_endian(self) -> Self {
|
||||
#[cfg(target_endian = "little")]
|
||||
{
|
||||
self
|
||||
}
|
||||
#[cfg(not(target_endian = "little"))]
|
||||
{
|
||||
byte_swap_f64(&self)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Swaps the bytes of an f32.
|
||||
#[allow(dead_code)]
|
||||
#[inline]
|
||||
pub fn byte_swap_f32(x: f32) -> f32 {
|
||||
f32::from_bits(x.to_bits().swap_bytes())
|
||||
}
|
||||
|
||||
/// Swaps the bytes of an f64.
|
||||
#[allow(dead_code)]
|
||||
#[inline]
|
||||
pub fn byte_swap_f64(x: f64) -> f64 {
|
||||
f64::from_bits(x.to_bits().swap_bytes())
|
||||
}
|
||||
|
||||
/// Place an EndianScalar into the provided mutable byte slice. Performs
|
||||
/// endian conversion, if necessary.
|
||||
#[inline]
|
||||
pub fn emplace_scalar<T: EndianScalar>(s: &mut [u8], x: T) {
|
||||
let sz = size_of::<T>();
|
||||
let mut_ptr = (&mut s[..sz]).as_mut_ptr() as *mut T;
|
||||
let val = x.to_little_endian();
|
||||
unsafe {
|
||||
*mut_ptr = val;
|
||||
}
|
||||
}
|
||||
|
||||
/// Read an EndianScalar from the provided byte slice at the specified location.
|
||||
/// Performs endian conversion, if necessary.
|
||||
#[inline]
|
||||
pub fn read_scalar_at<T: EndianScalar>(s: &[u8], loc: usize) -> T {
|
||||
let buf = &s[loc..loc + size_of::<T>()];
|
||||
read_scalar(buf)
|
||||
}
|
||||
|
||||
/// Read an EndianScalar from the provided byte slice. Performs endian
|
||||
/// conversion, if necessary.
|
||||
#[inline]
|
||||
pub fn read_scalar<T: EndianScalar>(s: &[u8]) -> T {
|
||||
let sz = size_of::<T>();
|
||||
|
||||
let p = (&s[..sz]).as_ptr() as *const T;
|
||||
let x = unsafe { *p };
|
||||
|
||||
x.from_little_endian()
|
||||
}
|
||||
|
||||
62
rust/flatbuffers/src/follow.rs
Normal file
62
rust/flatbuffers/src/follow.rs
Normal file
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright 2018 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.
|
||||
*/
|
||||
|
||||
use std::marker::PhantomData;
|
||||
|
||||
/// Follow is a trait that allows us to access FlatBuffers in a declarative,
|
||||
/// type safe, and fast way. They compile down to almost no code (after
|
||||
/// optimizations). Conceptually, Follow lifts the offset-based access
|
||||
/// patterns of FlatBuffers data into the type system. This trait is used
|
||||
/// pervasively at read time, to access tables, vtables, vectors, strings, and
|
||||
/// all other data. At this time, Follow is not utilized much on the write
|
||||
/// path.
|
||||
///
|
||||
/// Writing a new Follow implementation primarily involves deciding whether
|
||||
/// you want to return data (of the type Self::Inner) or do you want to
|
||||
/// continue traversing the FlatBuffer.
|
||||
pub trait Follow<'a> {
|
||||
type Inner;
|
||||
fn follow(buf: &'a [u8], loc: usize) -> Self::Inner;
|
||||
}
|
||||
|
||||
/// Execute a follow as a top-level function.
|
||||
#[allow(dead_code)]
|
||||
#[inline]
|
||||
pub fn lifted_follow<'a, T: Follow<'a>>(buf: &'a [u8], loc: usize) -> T::Inner {
|
||||
T::follow(buf, loc)
|
||||
}
|
||||
|
||||
/// FollowStart wraps a Follow impl in a struct type. This can make certain
|
||||
/// programming patterns more ergonomic.
|
||||
#[derive(Debug)]
|
||||
pub struct FollowStart<T>(PhantomData<T>);
|
||||
impl<'a, T: Follow<'a> + 'a> FollowStart<T> {
|
||||
#[inline]
|
||||
pub fn new() -> Self {
|
||||
Self { 0: PhantomData }
|
||||
}
|
||||
#[inline]
|
||||
pub fn self_follow(&'a self, buf: &'a [u8], loc: usize) -> T::Inner {
|
||||
T::follow(buf, loc)
|
||||
}
|
||||
}
|
||||
impl<'a, T: Follow<'a>> Follow<'a> for FollowStart<T> {
|
||||
type Inner = T::Inner;
|
||||
#[inline]
|
||||
fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
|
||||
T::follow(buf, loc)
|
||||
}
|
||||
}
|
||||
52
rust/flatbuffers/src/lib.rs
Normal file
52
rust/flatbuffers/src/lib.rs
Normal file
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright 2018 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.
|
||||
*/
|
||||
|
||||
//! # FlatBuffers
|
||||
//!
|
||||
//! A library for memory-efficient serialization of data.
|
||||
//!
|
||||
//! This crate provides runtime support for the FlatBuffers format in the Rust programming language.
|
||||
//! To use this crate, first generate code with the `flatc` compiler, as described here: https://google.github.io/flatbuffers/
|
||||
//! Then, include that code into your project.
|
||||
//! Finally, add this crate to your `Cargo.toml`.
|
||||
//!
|
||||
//! At this time, Rust support is experimental, and APIs may change between minor versions.
|
||||
//!
|
||||
//! At this time, to generate Rust code, you will need the latest `master` version of `flatc`, available from here: https://github.com/google/flatbuffers
|
||||
//! (On OSX, you can install FlatBuffers from `HEAD` with the Homebrew package manager.)
|
||||
|
||||
mod builder;
|
||||
mod endian_scalar;
|
||||
mod follow;
|
||||
mod primitives;
|
||||
mod push;
|
||||
mod table;
|
||||
mod vector;
|
||||
mod vtable;
|
||||
mod vtable_writer;
|
||||
|
||||
pub use builder::FlatBufferBuilder;
|
||||
pub use endian_scalar::{EndianScalar, emplace_scalar, read_scalar, read_scalar_at, byte_swap_f32, byte_swap_f64};
|
||||
pub use follow::{Follow, FollowStart};
|
||||
pub use primitives::*;
|
||||
pub use push::Push;
|
||||
pub use table::{Table, buffer_has_identifier, get_root, get_size_prefixed_root};
|
||||
pub use vector::{SafeSliceAccess, Vector, follow_cast_ref};
|
||||
pub use vtable::field_index_to_field_offset;
|
||||
|
||||
// TODO(rw): Unify `create_vector` and `create_vector_direct` by using
|
||||
// `Into<Vector<...>>`.
|
||||
// TODO(rw): Split fill ops in builder into fill_small, fill_big like in C++.
|
||||
298
rust/flatbuffers/src/primitives.rs
Normal file
298
rust/flatbuffers/src/primitives.rs
Normal file
@@ -0,0 +1,298 @@
|
||||
/*
|
||||
* Copyright 2018 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.
|
||||
*/
|
||||
|
||||
use std::marker::PhantomData;
|
||||
use std::mem::size_of;
|
||||
use std::ops::Deref;
|
||||
|
||||
use endian_scalar::{emplace_scalar, read_scalar, read_scalar_at};
|
||||
use follow::Follow;
|
||||
use push::Push;
|
||||
|
||||
pub const FLATBUFFERS_MAX_BUFFER_SIZE: usize = (1u64 << 31) as usize;
|
||||
|
||||
pub const FILE_IDENTIFIER_LENGTH: usize = 4;
|
||||
|
||||
pub const VTABLE_METADATA_FIELDS: usize = 2;
|
||||
|
||||
pub const SIZE_U8: usize = size_of::<u8>();
|
||||
pub const SIZE_I8: usize = size_of::<i8>();
|
||||
|
||||
pub const SIZE_U16: usize = size_of::<u16>();
|
||||
pub const SIZE_I16: usize = size_of::<i16>();
|
||||
|
||||
pub const SIZE_U32: usize = size_of::<u32>();
|
||||
pub const SIZE_I32: usize = size_of::<i32>();
|
||||
|
||||
pub const SIZE_U64: usize = size_of::<u64>();
|
||||
pub const SIZE_I64: usize = size_of::<i64>();
|
||||
|
||||
pub const SIZE_F32: usize = size_of::<f32>();
|
||||
pub const SIZE_F64: usize = size_of::<f64>();
|
||||
|
||||
pub const SIZE_SOFFSET: usize = SIZE_I32;
|
||||
pub const SIZE_UOFFSET: usize = SIZE_U32;
|
||||
pub const SIZE_VOFFSET: usize = SIZE_I16;
|
||||
|
||||
pub const SIZE_SIZEPREFIX: usize = SIZE_UOFFSET;
|
||||
|
||||
/// SOffsetT is an i32 that is used by tables to reference their vtables.
|
||||
pub type SOffsetT = i32;
|
||||
|
||||
/// UOffsetT is a u32 that is used by pervasively to represent both pointers
|
||||
/// and lengths of vectors.
|
||||
pub type UOffsetT = u32;
|
||||
|
||||
/// VOffsetT is a i32 that is used by vtables to store field data.
|
||||
pub type VOffsetT = i16;
|
||||
|
||||
/// TableFinishedWIPOffset marks a WIPOffset as being for a finished table.
|
||||
pub struct TableFinishedWIPOffset {}
|
||||
|
||||
/// TableUnfinishedWIPOffset marks a WIPOffset as being for an unfinished table.
|
||||
pub struct TableUnfinishedWIPOffset {}
|
||||
|
||||
/// UnionWIPOffset marks a WIPOffset as being for a union value.
|
||||
pub struct UnionWIPOffset {}
|
||||
|
||||
/// VTableWIPOffset marks a WIPOffset as being for a vtable.
|
||||
pub struct VTableWIPOffset {}
|
||||
|
||||
/// WIPOffset contains an UOffsetT with a special meaning: it is the location of
|
||||
/// data relative to the *end* of an in-progress FlatBuffer. The
|
||||
/// FlatBufferBuilder uses this to track the location of objects in an absolute
|
||||
/// way. The impl of Push converts a WIPOffset into a ForwardsUOffset.
|
||||
#[derive(Debug)]
|
||||
pub struct WIPOffset<T>(UOffsetT, PhantomData<T>);
|
||||
|
||||
// TODO(rw): why do we need to reimplement (with a default impl) Copy to
|
||||
// avoid ownership errors?
|
||||
impl<T> Copy for WIPOffset<T> {}
|
||||
impl<T> Clone for WIPOffset<T> {
|
||||
#[inline]
|
||||
fn clone(&self) -> WIPOffset<T> {
|
||||
WIPOffset::new(self.0.clone())
|
||||
}
|
||||
}
|
||||
impl<T> PartialEq for WIPOffset<T> {
|
||||
fn eq(&self, o: &WIPOffset<T>) -> bool {
|
||||
self.value() == o.value()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Deref for WIPOffset<T> {
|
||||
type Target = UOffsetT;
|
||||
#[inline]
|
||||
fn deref(&self) -> &UOffsetT {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
impl<'a, T: 'a> WIPOffset<T> {
|
||||
/// Create a new WIPOffset.
|
||||
#[inline]
|
||||
pub fn new(o: UOffsetT) -> WIPOffset<T> {
|
||||
WIPOffset {
|
||||
0: o,
|
||||
1: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
/// Return a wrapped value that brings its meaning as a union WIPOffset
|
||||
/// into the type system.
|
||||
#[inline(always)]
|
||||
pub fn as_union_value(&self) -> WIPOffset<UnionWIPOffset> {
|
||||
WIPOffset::new(self.0)
|
||||
}
|
||||
/// Get the underlying value.
|
||||
#[inline(always)]
|
||||
pub fn value(&self) -> UOffsetT {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Push for WIPOffset<T> {
|
||||
type Output = ForwardsUOffset<T>;
|
||||
|
||||
#[inline(always)]
|
||||
fn push(&self, dst: &mut [u8], rest: &[u8]) {
|
||||
let n = (SIZE_UOFFSET + rest.len() - self.value() as usize) as UOffsetT;
|
||||
emplace_scalar::<UOffsetT>(dst, n);
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Push for ForwardsUOffset<T> {
|
||||
type Output = Self;
|
||||
|
||||
#[inline(always)]
|
||||
fn push(&self, dst: &mut [u8], rest: &[u8]) {
|
||||
self.value().push(dst, rest);
|
||||
}
|
||||
}
|
||||
|
||||
/// ForwardsUOffset is used by Follow to traverse a FlatBuffer: the pointer
|
||||
/// is incremented by the value contained in this type.
|
||||
#[derive(Debug)]
|
||||
pub struct ForwardsUOffset<T>(UOffsetT, PhantomData<T>);
|
||||
impl<T> ForwardsUOffset<T> {
|
||||
#[inline(always)]
|
||||
pub fn value(&self) -> UOffsetT {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: Follow<'a>> Follow<'a> for ForwardsUOffset<T> {
|
||||
type Inner = T::Inner;
|
||||
#[inline(always)]
|
||||
fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
|
||||
let slice = &buf[loc..loc + SIZE_UOFFSET];
|
||||
let off = read_scalar::<u32>(slice) as usize;
|
||||
T::follow(buf, loc + off)
|
||||
}
|
||||
}
|
||||
|
||||
/// ForwardsVOffset is used by Follow to traverse a FlatBuffer: the pointer
|
||||
/// is incremented by the value contained in this type.
|
||||
#[derive(Debug)]
|
||||
pub struct ForwardsVOffset<T>(VOffsetT, PhantomData<T>);
|
||||
impl<T> ForwardsVOffset<T> {
|
||||
#[inline(always)]
|
||||
pub fn value(&self) -> VOffsetT {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: Follow<'a>> Follow<'a> for ForwardsVOffset<T> {
|
||||
type Inner = T::Inner;
|
||||
#[inline(always)]
|
||||
fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
|
||||
let slice = &buf[loc..loc + SIZE_VOFFSET];
|
||||
let off = read_scalar::<VOffsetT>(slice) as usize;
|
||||
T::follow(buf, loc + off)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Push for ForwardsVOffset<T> {
|
||||
type Output = Self;
|
||||
|
||||
#[inline]
|
||||
fn push(&self, dst: &mut [u8], rest: &[u8]) {
|
||||
self.value().push(dst, rest);
|
||||
}
|
||||
}
|
||||
|
||||
/// ForwardsSOffset is used by Follow to traverse a FlatBuffer: the pointer
|
||||
/// is incremented by the *negative* of the value contained in this type.
|
||||
#[derive(Debug)]
|
||||
pub struct BackwardsSOffset<T>(SOffsetT, PhantomData<T>);
|
||||
impl<T> BackwardsSOffset<T> {
|
||||
#[inline(always)]
|
||||
pub fn value(&self) -> SOffsetT {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: Follow<'a>> Follow<'a> for BackwardsSOffset<T> {
|
||||
type Inner = T::Inner;
|
||||
#[inline(always)]
|
||||
fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
|
||||
let slice = &buf[loc..loc + SIZE_SOFFSET];
|
||||
let off = read_scalar::<SOffsetT>(slice);
|
||||
T::follow(buf, (loc as SOffsetT - off) as usize)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Push for BackwardsSOffset<T> {
|
||||
type Output = Self;
|
||||
|
||||
#[inline]
|
||||
fn push(&self, dst: &mut [u8], rest: &[u8]) {
|
||||
self.value().push(dst, rest);
|
||||
}
|
||||
}
|
||||
|
||||
/// SkipSizePrefix is used by Follow to traverse a FlatBuffer: the pointer is
|
||||
/// incremented by a fixed constant in order to skip over the size prefix value.
|
||||
pub struct SkipSizePrefix<T>(PhantomData<T>);
|
||||
impl<'a, T: Follow<'a> + 'a> Follow<'a> for SkipSizePrefix<T> {
|
||||
type Inner = T::Inner;
|
||||
#[inline(always)]
|
||||
fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
|
||||
T::follow(buf, loc + SIZE_SIZEPREFIX)
|
||||
}
|
||||
}
|
||||
|
||||
/// SkipRootOffset is used by Follow to traverse a FlatBuffer: the pointer is
|
||||
/// incremented by a fixed constant in order to skip over the root offset value.
|
||||
pub struct SkipRootOffset<T>(PhantomData<T>);
|
||||
impl<'a, T: Follow<'a> + 'a> Follow<'a> for SkipRootOffset<T> {
|
||||
type Inner = T::Inner;
|
||||
#[inline(always)]
|
||||
fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
|
||||
T::follow(buf, loc + SIZE_UOFFSET)
|
||||
}
|
||||
}
|
||||
|
||||
/// FileIdentifier is used by Follow to traverse a FlatBuffer: the pointer is
|
||||
/// dereferenced into a byte slice, whose bytes are the file identifer value.
|
||||
pub struct FileIdentifier;
|
||||
impl<'a> Follow<'a> for FileIdentifier {
|
||||
type Inner = &'a [u8];
|
||||
#[inline(always)]
|
||||
fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
|
||||
&buf[loc..loc + FILE_IDENTIFIER_LENGTH]
|
||||
}
|
||||
}
|
||||
|
||||
/// SkipFileIdentifier is used by Follow to traverse a FlatBuffer: the pointer
|
||||
/// is incremented by a fixed constant in order to skip over the file
|
||||
/// identifier value.
|
||||
pub struct SkipFileIdentifier<T>(PhantomData<T>);
|
||||
impl<'a, T: Follow<'a> + 'a> Follow<'a> for SkipFileIdentifier<T> {
|
||||
type Inner = T::Inner;
|
||||
#[inline(always)]
|
||||
fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
|
||||
T::follow(buf, loc + FILE_IDENTIFIER_LENGTH)
|
||||
}
|
||||
}
|
||||
|
||||
/// Follow trait impls for primitive types.
|
||||
///
|
||||
/// Ideally, these would be implemented as a single impl using trait bounds on
|
||||
/// EndianScalar, but implementing Follow that way causes a conflict with
|
||||
/// other impls.
|
||||
macro_rules! impl_follow_for_endian_scalar {
|
||||
($ty:ident) => (
|
||||
impl<'a> Follow<'a> for $ty {
|
||||
type Inner = $ty;
|
||||
#[inline(always)]
|
||||
fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
|
||||
read_scalar_at::<$ty>(buf, loc)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
impl_follow_for_endian_scalar!(bool);
|
||||
impl_follow_for_endian_scalar!(u8);
|
||||
impl_follow_for_endian_scalar!(u16);
|
||||
impl_follow_for_endian_scalar!(u32);
|
||||
impl_follow_for_endian_scalar!(u64);
|
||||
impl_follow_for_endian_scalar!(i8);
|
||||
impl_follow_for_endian_scalar!(i16);
|
||||
impl_follow_for_endian_scalar!(i32);
|
||||
impl_follow_for_endian_scalar!(i64);
|
||||
impl_follow_for_endian_scalar!(f32);
|
||||
impl_follow_for_endian_scalar!(f64);
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user