forked from BigfootDev/flatbuffers
Compare commits
170 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bf9eb67ab9 | ||
|
|
9e7e8cbe9f | ||
|
|
b72a75f87d | ||
|
|
6cfcd8628a | ||
|
|
ddb12c0192 | ||
|
|
2032b94f61 | ||
|
|
860dc803fe | ||
|
|
5b43e4bbb8 | ||
|
|
ecd76e898d | ||
|
|
f55d4388e0 | ||
|
|
e7340c390f | ||
|
|
90441c2078 | ||
|
|
cef8f928bb | ||
|
|
98b9b5a933 | ||
|
|
d07a3d2f4c | ||
|
|
640df2c1f5 | ||
|
|
60340ac529 | ||
|
|
2bd4a27550 | ||
|
|
23bb57401c | ||
|
|
dd6daa709b | ||
|
|
dd85c3b721 | ||
|
|
94cb1ff9ea | ||
|
|
3ff6cdf491 | ||
|
|
c329d6fa90 | ||
|
|
249f3b3714 | ||
|
|
2d67de3151 | ||
|
|
5cdbd02404 | ||
|
|
b2ce86ef8a | ||
|
|
8e7acae013 | ||
|
|
343bbe808e | ||
|
|
cb9ab2fe58 | ||
|
|
4cbff97c43 | ||
|
|
88abae649c | ||
|
|
a7461433c6 | ||
|
|
440a70f4a3 | ||
|
|
02e73e1ae9 | ||
|
|
f93d0f6ac1 | ||
|
|
fd51fadaac | ||
|
|
11198f10f5 | ||
|
|
3b23ff18ea | ||
|
|
4f066c39ce | ||
|
|
ca68d8b043 | ||
|
|
407fb5d537 | ||
|
|
73a648b685 | ||
|
|
eb2a81f73d | ||
|
|
3968d00568 | ||
|
|
4f10da8d99 | ||
|
|
9e82ee2527 | ||
|
|
e237f53bfc | ||
|
|
98be491e72 | ||
|
|
71628dad0d | ||
|
|
cb7b2bf87e | ||
|
|
bfa430309a | ||
|
|
1c7d91cc55 | ||
|
|
2e865f4d4e | ||
|
|
13c9c674fd | ||
|
|
034275c6e2 | ||
|
|
4e5152d886 | ||
|
|
dc61512f20 | ||
|
|
1d60824d56 | ||
|
|
f89badd30f | ||
|
|
1b9d1b0110 | ||
|
|
6e2d530d61 | ||
|
|
9bf9b18f0a | ||
|
|
537c6ec1e6 | ||
|
|
a1f14005ab | ||
|
|
0cdacdfb35 | ||
|
|
bb58442054 | ||
|
|
4567b13115 | ||
|
|
8f8fb2b367 | ||
|
|
69d761d15e | ||
|
|
4f32cbf268 | ||
|
|
0eaaf18192 | ||
|
|
957d167199 | ||
|
|
e9d9d64527 | ||
|
|
78c50e340b | ||
|
|
9d483a3f0b | ||
|
|
b650dfba49 | ||
|
|
6980818337 | ||
|
|
224f7527e3 | ||
|
|
a66a88034a | ||
|
|
e1defaae5e | ||
|
|
78fdce28c7 | ||
|
|
60e94cf083 | ||
|
|
cf47f27164 | ||
|
|
cc7f9b89f3 | ||
|
|
600f3fbcd4 | ||
|
|
76a024137f | ||
|
|
31e34faa15 | ||
|
|
4d98faa515 | ||
|
|
d8210d5a83 | ||
|
|
7d3930a2fd | ||
|
|
347dba8501 | ||
|
|
fcacb46d01 | ||
|
|
3f388ec747 | ||
|
|
38bf4cfc03 | ||
|
|
c2f40c37b2 | ||
|
|
63d51afd11 | ||
|
|
d44931656a | ||
|
|
bbfd12eb11 | ||
|
|
7c94ff6c30 | ||
|
|
4fa4d36706 | ||
|
|
46208b1e91 | ||
|
|
b99332efd7 | ||
|
|
dd288f71f3 | ||
|
|
155c55900f | ||
|
|
0eb7b3beb0 | ||
|
|
a821b15634 | ||
|
|
87704e987e | ||
|
|
cb99116aca | ||
|
|
9ad73bf5a7 | ||
|
|
dba962ebb8 | ||
|
|
60a0f35fbc | ||
|
|
58e8552da0 | ||
|
|
d56a4055da | ||
|
|
30c4948541 | ||
|
|
80d148b175 | ||
|
|
2aa0d9a54d | ||
|
|
79cd55bd3a | ||
|
|
b378b8eb69 | ||
|
|
9635d494b3 | ||
|
|
0143f4e364 | ||
|
|
e161ade68c | ||
|
|
f575b02fda | ||
|
|
5f32f94810 | ||
|
|
d6b1ce09cf | ||
|
|
f23009f04f | ||
|
|
30bae01ea3 | ||
|
|
9068b0ee63 | ||
|
|
f8a0d3889b | ||
|
|
688fc77460 | ||
|
|
dd8922878d | ||
|
|
ab54e61805 | ||
|
|
f445c1eb4a | ||
|
|
980a6d66d3 | ||
|
|
21591916af | ||
|
|
b6c3d7b899 | ||
|
|
db0fcdd906 | ||
|
|
91fe9ba93f | ||
|
|
4c3b6c247d | ||
|
|
160e8f2fdc | ||
|
|
705577de51 | ||
|
|
0fb1d44bc4 | ||
|
|
bd20a60d6a | ||
|
|
b78c4332be | ||
|
|
636b516492 | ||
|
|
560718e976 | ||
|
|
ff687ae9c1 | ||
|
|
ca417426c7 | ||
|
|
55b30827f2 | ||
|
|
efbb11e093 | ||
|
|
5c0f914f38 | ||
|
|
802639e40d | ||
|
|
ad8b1e5dbd | ||
|
|
76d31e1b5e | ||
|
|
20396a1760 | ||
|
|
a3d8391f7b | ||
|
|
241e87d143 | ||
|
|
35f0b41fed | ||
|
|
cb5422c398 | ||
|
|
4ed6fafdfa | ||
|
|
53ce80ce91 | ||
|
|
233976c821 | ||
|
|
99fe1dc80f | ||
|
|
a4f9d1bfcc | ||
|
|
a4c362a1ba | ||
|
|
7c3c027295 | ||
|
|
569492e890 | ||
|
|
d840856093 | ||
|
|
925c1d77fc |
40
.appveyor/check-generate-code.bat
Normal file
40
.appveyor/check-generate-code.bat
Normal file
@@ -0,0 +1,40 @@
|
||||
:: 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.
|
||||
set buildtype=Release
|
||||
if "%1"=="-b" set buildtype=%2
|
||||
|
||||
cd tests
|
||||
call generate_code.bat -b %buildtype% || goto FAIL
|
||||
|
||||
:: TODO: Release and Debug builds produce differences here for some reason.
|
||||
git checkout HEAD -- monster_test.bfbs
|
||||
|
||||
git -c core.autocrlf=true diff --exit-code --quiet || goto :DIFFFOUND
|
||||
goto SUCCESS
|
||||
|
||||
:DIFFFOUND
|
||||
@echo "" >&2
|
||||
@echo "ERROR: ********************************************************" >&2
|
||||
@echo "ERROR: The following differences were found after running the" >&2
|
||||
@echo "ERROR: tests/generate_code.sh script. Maybe you forgot to run" >&2
|
||||
@echo "ERROR: it after making changes in a generator or schema?" >&2
|
||||
@echo "ERROR: ********************************************************" >&2
|
||||
@echo "" >&2
|
||||
@git -c core.autocrlf=true --no-pager diff --binary
|
||||
|
||||
:FAIL
|
||||
set EXITCODE=1
|
||||
:SUCCESS
|
||||
cd ..
|
||||
EXIT /B %EXITCODE%
|
||||
18
.bazelci/presubmit.yml
Normal file
18
.bazelci/presubmit.yml
Normal file
@@ -0,0 +1,18 @@
|
||||
---
|
||||
buildifier: latest
|
||||
platforms:
|
||||
ubuntu1604:
|
||||
build_targets:
|
||||
- "..."
|
||||
test_targets:
|
||||
- "..."
|
||||
ubuntu1804:
|
||||
build_targets:
|
||||
- "..."
|
||||
test_targets:
|
||||
- "..."
|
||||
macos:
|
||||
build_targets:
|
||||
- "..."
|
||||
test_targets:
|
||||
- "..."
|
||||
@@ -1,7 +1,7 @@
|
||||
root = true
|
||||
[*.{cpp,cc,h}]
|
||||
end_of_line = LF
|
||||
# Don't set line endings to avoid conflict with core.autocrlf flag.
|
||||
# Line endings on checkout/checkin are controlled by .gitattributes file.
|
||||
[*]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
insert_final_newline = true
|
||||
|
||||
|
||||
1
.gitattributes
vendored
1
.gitattributes
vendored
@@ -1 +1,2 @@
|
||||
# Set the default behavior, in case people don't have core.autocrlf set.
|
||||
* text=auto
|
||||
|
||||
7
.gitignore
vendored
7
.gitignore
vendored
@@ -26,6 +26,9 @@
|
||||
**/install_manifest.txt
|
||||
**/CMakeCache.txt
|
||||
**/CMakeTestfile.cmake
|
||||
**/CPackConfig.cmake
|
||||
**/CPackSourceConfig.cmake
|
||||
**/compile_commands.json
|
||||
**/Debug/**
|
||||
**/Release/**
|
||||
**/RelWithDebInfo/**
|
||||
@@ -46,6 +49,8 @@ flatsamplebinary
|
||||
flatsamplebinary.exe
|
||||
flatsampletext
|
||||
flatsampletext.exe
|
||||
flatsamplebfbs
|
||||
flatsamplebfbs.exe
|
||||
grpctest
|
||||
grpctest.exe
|
||||
snapshot.sh
|
||||
@@ -109,3 +114,5 @@ dart/.dart_tool/
|
||||
dart/build/
|
||||
dart/doc/api/
|
||||
Cargo.lock
|
||||
.corpus**
|
||||
.seed**
|
||||
|
||||
124
.travis.yml
124
.travis.yml
@@ -2,12 +2,18 @@ env:
|
||||
global:
|
||||
# Set at the root level as this is ignored when set under matrix.env.
|
||||
- GCC_VERSION="4.9"
|
||||
# Fail on first error if UBSAN or ASAN enabled for a target
|
||||
- UBSAN_OPTIONS=halt_on_error=1
|
||||
- ASAN_OPTIONS=halt_on_error=1
|
||||
# Travis machines have 2 cores
|
||||
- JOBS=2
|
||||
- MAKEFLAGS="-j 2"
|
||||
|
||||
conan-linux: &conan-linux
|
||||
os: linux
|
||||
sudo: required
|
||||
dist: xenial
|
||||
language: python
|
||||
python: "3.6"
|
||||
python: "3.7"
|
||||
services:
|
||||
- docker
|
||||
install:
|
||||
@@ -53,7 +59,18 @@ matrix:
|
||||
# branch: master
|
||||
- language: cpp
|
||||
os:
|
||||
- linux
|
||||
- linux
|
||||
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- docker-ce
|
||||
script:
|
||||
- bash .travis/build-and-run-docker-test-containers.sh
|
||||
|
||||
- language: cpp
|
||||
os:
|
||||
- linux
|
||||
|
||||
compiler:
|
||||
- gcc
|
||||
@@ -72,10 +89,18 @@ matrix:
|
||||
- if [ "$TRAVIS_OS_NAME" == "linux" ]; then sudo ln -s -v -f $(which gcc-$GCC_VERSION) /usr/bin/gcc; fi
|
||||
|
||||
script:
|
||||
- bash .travis/check-sources.sh
|
||||
- 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
|
||||
- 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
|
||||
-DFLATBUFFERS_CODE_SANITIZE=ON
|
||||
- cmake --build . -- -j${JOBS}
|
||||
- LD_LIBRARY_PATH=$TRAVIS_BUILD_DIR/google/grpc/install/lib ctest --extra-verbose --output-on-failure
|
||||
- bash .travis/check-generate-code.sh
|
||||
- if [ "$CONAN" == "true" ] && [ "$TRAVIS_OS_NAME" == "linux" ]; then sudo pip install conan && conan create . flatbuffers/${TRAVIS_BRANCH}@google/testing -s build_type=$BUILD_TYPE -tf conan/test_package; fi
|
||||
|
||||
- language: cpp
|
||||
os: osx
|
||||
@@ -84,30 +109,37 @@ matrix:
|
||||
matrix:
|
||||
- BUILD_TYPE=Debug
|
||||
- BUILD_TYPE=Release
|
||||
|
||||
script:
|
||||
- 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
|
||||
- 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
|
||||
-DFLATBUFFERS_CODE_SANITIZE=ON
|
||||
- cmake --build . -- -j${JOBS}
|
||||
- DYLD_LIBRARY_PATH=$TRAVIS_BUILD_DIR/google/grpc/install/lib ctest --extra-verbose --output-on-failure
|
||||
- bash .travis/check-generate-code.sh
|
||||
|
||||
- <<: *conan-linux
|
||||
env: CONAN_GCC_VERSIONS=4.9 CONAN_DOCKER_IMAGE=lasote/conangcc49
|
||||
env: CONAN_GCC_VERSIONS=4.9 CONAN_DOCKER_IMAGE=conanio/gcc49
|
||||
- <<: *conan-linux
|
||||
env: CONAN_GCC_VERSIONS=5 CONAN_DOCKER_IMAGE=lasote/conangcc5
|
||||
env: CONAN_GCC_VERSIONS=5 CONAN_DOCKER_IMAGE=conanio/gcc5
|
||||
- <<: *conan-linux
|
||||
env: CONAN_GCC_VERSIONS=6 CONAN_DOCKER_IMAGE=lasote/conangcc6
|
||||
env: CONAN_GCC_VERSIONS=6 CONAN_DOCKER_IMAGE=conanio/gcc6
|
||||
- <<: *conan-linux
|
||||
env: CONAN_GCC_VERSIONS=7 CONAN_DOCKER_IMAGE=lasote/conangcc7
|
||||
env: CONAN_GCC_VERSIONS=7 CONAN_DOCKER_IMAGE=conanio/gcc7
|
||||
- <<: *conan-linux
|
||||
env: CONAN_GCC_VERSIONS=8 CONAN_DOCKER_IMAGE=lasote/conangcc8
|
||||
env: CONAN_GCC_VERSIONS=8 CONAN_DOCKER_IMAGE=conanio/gcc8
|
||||
- <<: *conan-linux
|
||||
env: CONAN_CLANG_VERSIONS=3.9 CONAN_DOCKER_IMAGE=lasote/conanclang39
|
||||
env: CONAN_CLANG_VERSIONS=3.9 CONAN_DOCKER_IMAGE=conanio/clang39
|
||||
- <<: *conan-linux
|
||||
env: CONAN_CLANG_VERSIONS=4.0 CONAN_DOCKER_IMAGE=lasote/conanclang40
|
||||
env: CONAN_CLANG_VERSIONS=4.0 CONAN_DOCKER_IMAGE=conanio/clang40
|
||||
- <<: *conan-linux
|
||||
env: CONAN_CLANG_VERSIONS=5.0 CONAN_DOCKER_IMAGE=lasote/conanclang50
|
||||
env: CONAN_CLANG_VERSIONS=5.0 CONAN_DOCKER_IMAGE=conanio/clang50
|
||||
- <<: *conan-linux
|
||||
env: CONAN_CLANG_VERSIONS=6.0 CONAN_DOCKER_IMAGE=lasote/conanclang60
|
||||
env: CONAN_CLANG_VERSIONS=6.0 CONAN_DOCKER_IMAGE=conanio/clang60
|
||||
- <<: *conan-osx
|
||||
osx_image: xcode7.3
|
||||
env: CONAN_APPLE_CLANG_VERSIONS=7.3
|
||||
@@ -118,29 +150,37 @@ matrix:
|
||||
osx_image: xcode9
|
||||
env: CONAN_APPLE_CLANG_VERSIONS=9.0
|
||||
- <<: *conan-osx
|
||||
osx_image: xcode9.3
|
||||
osx_image: xcode9.4
|
||||
env: CONAN_APPLE_CLANG_VERSIONS=9.1
|
||||
- <<: *conan-osx
|
||||
osx_image: xcode10
|
||||
env: CONAN_APPLE_CLANG_VERSIONS=10.0
|
||||
|
||||
#- 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))
|
||||
- language: android
|
||||
sudo: true
|
||||
android:
|
||||
components:
|
||||
- tools
|
||||
- platform-tools
|
||||
- build-tools-25.0.2
|
||||
- android-25
|
||||
- extra-android-m2repository
|
||||
compiler:
|
||||
- gcc
|
||||
|
||||
before_install:
|
||||
# Output something every 10 minutes or Travis kills the job
|
||||
- while sleep 540; do echo "=====[ $SECONDS seconds still running ]====="; done &
|
||||
- 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))
|
||||
# Kill the sleep loop
|
||||
- kill %1
|
||||
|
||||
40
.travis/build-and-run-docker-test-containers.sh
Executable file
40
.travis/build-and-run-docker-test-containers.sh
Executable file
@@ -0,0 +1,40 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# 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.
|
||||
set -e
|
||||
|
||||
# build flatc on debian once to speed up the test loop below
|
||||
docker build -t build_flatc_debian_stretch -f tests/docker/Dockerfile.testing.build_flatc_debian_stretch .
|
||||
BUILD_CONTAINER_ID=$(docker create --read-only build_flatc_debian_stretch)
|
||||
docker cp ${BUILD_CONTAINER_ID}:/code/flatc flatc_debian_stretch
|
||||
|
||||
for f in $(ls tests/docker/languages | sort)
|
||||
do
|
||||
# docker pull sometimes fails for unknown reasons, probably travisci-related. this retries the pull we need a few times.
|
||||
REQUIRED_BASE_IMAGE=$(cat tests/docker/languages/${f} | head -n 1 | awk ' { print $2 } ')
|
||||
|
||||
set +e
|
||||
n=0
|
||||
until [ $n -ge 5 ]
|
||||
do
|
||||
docker pull $REQUIRED_BASE_IMAGE && break
|
||||
n=$[$n+1]
|
||||
sleep 1
|
||||
done
|
||||
set -e
|
||||
|
||||
docker build -t $(echo ${f} | cut -f 3- -d .) -f tests/docker/languages/${f} .
|
||||
echo "TEST OK: ${f}"
|
||||
done
|
||||
34
.travis/check-generate-code.sh
Executable file
34
.travis/check-generate-code.sh
Executable file
@@ -0,0 +1,34 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# 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.
|
||||
set -e
|
||||
|
||||
cd tests
|
||||
./generate_code.sh
|
||||
cd ..
|
||||
|
||||
# TODO: Linux and macos builds produce differences here for some reason.
|
||||
git checkout HEAD -- tests/monster_test.bfbs
|
||||
|
||||
if ! git diff --quiet; then
|
||||
echo >&2
|
||||
echo "ERROR: ********************************************************" >&2
|
||||
echo "ERROR: The following differences were found after running the" >&2
|
||||
echo "ERROR: tests/generate_code.sh script. Maybe you forgot to run" >&2
|
||||
echo "ERROR: it after making changes in a generator or schema?" >&2
|
||||
echo "ERROR: ********************************************************" >&2
|
||||
echo >&2
|
||||
git diff --binary --exit-code
|
||||
fi
|
||||
33
.travis/check-sources.sh
Normal file
33
.travis/check-sources.sh
Normal file
@@ -0,0 +1,33 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# 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.
|
||||
set -e
|
||||
|
||||
if [ -n "$1" ]; then
|
||||
scan_dir="$1"
|
||||
else
|
||||
scan_dir="$( pwd )"
|
||||
fi
|
||||
|
||||
py_checker="$0.py"
|
||||
|
||||
echo "scan root directory = '$scan_dir'"
|
||||
python3 --version
|
||||
# Scan recursively and search all *.cpp and *.h files using regex patterns.
|
||||
# Assume that script running from a root of Flatbuffers working dir.
|
||||
python3 $py_checker "ascii" "$scan_dir/include" "\.h$"
|
||||
python3 $py_checker "ascii" "$scan_dir/src" "\.cpp$"
|
||||
python3 $py_checker "ascii" "$scan_dir/tests" "\.h$"
|
||||
python3 $py_checker "utf-8" "$scan_dir/tests" "\.cpp$"
|
||||
35
.travis/check-sources.sh.py
Normal file
35
.travis/check-sources.sh.py
Normal file
@@ -0,0 +1,35 @@
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
|
||||
def check_encoding(encoding, scan_dir, regex_pattern):
|
||||
fname = None
|
||||
try:
|
||||
assert encoding in ['ascii', 'utf-8'], "unexpected encoding"
|
||||
cmp = re.compile(regex_pattern)
|
||||
for root, dirs, files in os.walk(scan_dir):
|
||||
fname = root
|
||||
cmp_list = [f for f in files if cmp.search(f) is not None]
|
||||
for f in cmp_list:
|
||||
fname = os.path.join(root, f)
|
||||
with open(fname, mode='rb') as test_file:
|
||||
btext = test_file.read()
|
||||
# check encoding
|
||||
btext.decode(encoding=encoding, errors="strict")
|
||||
if encoding == "utf-8" and btext.startswith(b'\xEF\xBB\xBF'):
|
||||
raise ValueError("unexpected BOM in file")
|
||||
# check LF line endings
|
||||
LF = btext.count(b'\n')
|
||||
CR = btext.count(b'\r')
|
||||
if CR!=0:
|
||||
raise ValueError("invalid line endings: LF({})/CR({})".format(LF, CR))
|
||||
except Exception as err:
|
||||
print("ERROR with [{}]: {}".format(fname, err))
|
||||
return -1
|
||||
else:
|
||||
return 0
|
||||
|
||||
if __name__ == "__main__":
|
||||
# python check-sources.sh.py 'ascii' '.' '.*\.(cpp|h)$'
|
||||
res = check_encoding(sys.argv[1], sys.argv[2], sys.argv[3])
|
||||
sys.exit(0 if res == 0 else -1)
|
||||
48
BUILD
48
BUILD
@@ -12,6 +12,8 @@ exports_files([
|
||||
"LICENSE",
|
||||
])
|
||||
|
||||
load(":build_defs.bzl", "flatbuffer_cc_library")
|
||||
|
||||
# Public flatc library to compile flatbuffer files at runtime.
|
||||
cc_library(
|
||||
name = "flatbuffers",
|
||||
@@ -86,10 +88,10 @@ cc_binary(
|
||||
"src/idl_gen_general.cpp",
|
||||
"src/idl_gen_go.cpp",
|
||||
"src/idl_gen_grpc.cpp",
|
||||
"src/idl_gen_js.cpp",
|
||||
"src/idl_gen_js_ts.cpp",
|
||||
"src/idl_gen_json_schema.cpp",
|
||||
"src/idl_gen_lua.cpp",
|
||||
"src/idl_gen_lobster.cpp",
|
||||
"src/idl_gen_lua.cpp",
|
||||
"src/idl_gen_php.cpp",
|
||||
"src/idl_gen_python.cpp",
|
||||
"src/idl_gen_rust.cpp",
|
||||
@@ -104,6 +106,19 @@ cc_binary(
|
||||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "runtime_cc",
|
||||
hdrs = [
|
||||
"include/flatbuffers/base.h",
|
||||
"include/flatbuffers/flatbuffers.h",
|
||||
"include/flatbuffers/flexbuffers.h",
|
||||
"include/flatbuffers/stl_emulation.h",
|
||||
"include/flatbuffers/util.h",
|
||||
],
|
||||
includes = ["include/"],
|
||||
linkstatic = 1,
|
||||
)
|
||||
|
||||
# Test binary.
|
||||
cc_test(
|
||||
name = "flatbuffers_test",
|
||||
@@ -118,19 +133,19 @@ cc_test(
|
||||
"src/idl_parser.cpp",
|
||||
"src/reflection.cpp",
|
||||
"src/util.cpp",
|
||||
"tests/monster_test_generated.h",
|
||||
"tests/namespace_test/namespace_test1_generated.h",
|
||||
"tests/namespace_test/namespace_test2_generated.h",
|
||||
"tests/test.cpp",
|
||||
"tests/test_builder.h",
|
||||
"tests/test_assert.cpp",
|
||||
"tests/test_assert.h",
|
||||
"tests/test_builder.cpp",
|
||||
"tests/test_assert.cpp",
|
||||
"tests/test_builder.h",
|
||||
"tests/union_vector/union_vector_generated.h",
|
||||
":public_headers",
|
||||
],
|
||||
copts = [
|
||||
"-DFLATBUFFERS_TRACK_VERIFIER_BUFFER_SIZE",
|
||||
"-DBAZEL_TEST_DATA_PATH",
|
||||
],
|
||||
data = [
|
||||
":tests/include_test/include_test1.fbs",
|
||||
@@ -142,7 +157,30 @@ cc_test(
|
||||
":tests/prototest/test.golden",
|
||||
":tests/prototest/test.proto",
|
||||
":tests/prototest/test_union.golden",
|
||||
":tests/unicode_test.json",
|
||||
":tests/union_vector/union_vector.fbs",
|
||||
":tests/union_vector/union_vector.json",
|
||||
],
|
||||
includes = ["include/"],
|
||||
deps = [
|
||||
":monster_extra_cc_fbs",
|
||||
":monster_test_cc_fbs",
|
||||
],
|
||||
)
|
||||
|
||||
# Test bzl rules
|
||||
|
||||
flatbuffer_cc_library(
|
||||
name = "monster_test_cc_fbs",
|
||||
srcs = ["tests/monster_test.fbs"],
|
||||
include_paths = ["tests/include_test"],
|
||||
includes = [
|
||||
"tests/include_test/include_test1.fbs",
|
||||
"tests/include_test/sub/include_test2.fbs",
|
||||
],
|
||||
)
|
||||
|
||||
flatbuffer_cc_library(
|
||||
name = "monster_extra_cc_fbs",
|
||||
srcs = ["tests/monster_extra.fbs"],
|
||||
)
|
||||
|
||||
4
CMake/DESCRIPTION.txt
Normal file
4
CMake/DESCRIPTION.txt
Normal file
@@ -0,0 +1,4 @@
|
||||
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.
|
||||
@@ -45,6 +45,7 @@ if(FLATBUFFERS_FOUND)
|
||||
add_custom_command(OUTPUT ${FLATC_OUTPUT}
|
||||
COMMAND ${FLATBUFFERS_FLATC_EXECUTABLE}
|
||||
ARGS -c -o "${CMAKE_CURRENT_BINARY_DIR}/" ${FILE}
|
||||
DEPENDS ${FILE}
|
||||
COMMENT "Building C++ header for ${FILE}"
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
endforeach()
|
||||
|
||||
@@ -37,5 +37,3 @@ if (UNIX)
|
||||
"${CPACK_DEBIAN_PACKAGE_NAME}_${CPACK_DEBIAN_PACKAGE_VERSION}_${CPACK_DEBIAN_PACKAGE_ARCHITECTURE}")
|
||||
|
||||
endif(UNIX)
|
||||
|
||||
INCLUDE(CPack)
|
||||
|
||||
34
CMake/PackageRedhat.cmake
Normal file
34
CMake/PackageRedhat.cmake
Normal file
@@ -0,0 +1,34 @@
|
||||
if (UNIX)
|
||||
set(CPACK_GENERATOR "RPM")
|
||||
set(CPACK_SOURCE_TGZ "ON")
|
||||
|
||||
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "FlatBuffers serialization library and schema compiler.")
|
||||
|
||||
set(CPACK_RPM_PACKAGE_HOMEPAGE "https://github.com/google/flatbuffers")
|
||||
set(CPACK_RPM_PACKAGE_MAINTAINER "Marc Butler <mockbutler@gmail.com>")
|
||||
|
||||
set(CPACK_PACKAGE_VERSION_MAJOR ${VERSION_MAJOR})
|
||||
set(CPACK_PACKAGE_VERSION_MINOR ${VERSION_MINOR})
|
||||
set(CPACK_PACKAGE_VERSION_PATCH ${VERSION_PATCH})
|
||||
set(CPACK_PACKAGE_VERSION "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}-${VERSION_COMMIT}")
|
||||
set(CPACK_RPM_PACKAGE_VERSION "${CPACK_PACKAGE_VERSION}")
|
||||
|
||||
set(CPACK_RPM_PACKAGE_NAME "flatbuffers")
|
||||
|
||||
# Assume this is not a cross complation build.
|
||||
if(NOT CPACK_RPM_PACKAGE_ARCHITECTURE)
|
||||
set(CPACK_RPM_PACKAGE_ARCHITECTURE "${CMAKE_SYSTEM_PROCESSOR}")
|
||||
endif(NOT CPACK_RPM_PACKAGE_ARCHITECTURE)
|
||||
|
||||
set(CPACK_RPM_PACKAGE_VENDOR "Google, Inc.")
|
||||
set(CPACK_RPM_PACKAGE_LICENSE "Apache 2.0")
|
||||
set(CPACK_RESOURCE_FILE_LICENSE ${CMAKE_SOURCE_DIR}/LICENSE.txt)
|
||||
set(CPACK_PACKAGE_DESCRIPTION_FILE ${CMAKE_SOURCE_DIR}/CMake/DESCRIPTION.txt)
|
||||
|
||||
# This may reduce rpm compatiblity with very old systems.
|
||||
set(CPACK_RPM_COMPRESSION_TYPE lzma)
|
||||
|
||||
set(CPACK_RPM_PACKAGE_NAME "flatbuffers")
|
||||
set(CPACK_PACKAGE_FILE_NAME
|
||||
"${CPACK_RPM_PACKAGE_NAME}_${CPACK_RPM_PACKAGE_VERSION}_${CPACK_RPM_PACKAGE_ARCHITECTURE}")
|
||||
endif(UNIX)
|
||||
@@ -1,4 +1,7 @@
|
||||
cmake_minimum_required(VERSION 2.8)
|
||||
# generate compile_commands.json
|
||||
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
||||
include(CheckCXXSymbolExists)
|
||||
|
||||
project(FlatBuffers)
|
||||
|
||||
@@ -16,6 +19,16 @@ option(FLATBUFFERS_BUILD_SHAREDLIB
|
||||
"Enable the build of the flatbuffers shared library"
|
||||
OFF)
|
||||
option(FLATBUFFERS_LIBCXX_WITH_CLANG "Force libc++ when using Clang" ON)
|
||||
# NOTE: Sanitizer check only works on Linux & OSX (gcc & llvm).
|
||||
option(FLATBUFFERS_CODE_SANITIZE
|
||||
"Add '-fsanitize' flags to 'flattests' and 'flatc' targets."
|
||||
OFF)
|
||||
option(FLATBUFFERS_PACKAGE_REDHAT
|
||||
"Build an rpm using the 'package' target."
|
||||
OFF)
|
||||
option(FLATBUFFERS_PACKAGE_DEBIAN
|
||||
"Build an deb using the 'package' target."
|
||||
OFF)
|
||||
|
||||
if(NOT FLATBUFFERS_BUILD_FLATC AND FLATBUFFERS_BUILD_TESTS)
|
||||
message(WARNING
|
||||
@@ -23,6 +36,22 @@ if(NOT FLATBUFFERS_BUILD_FLATC AND FLATBUFFERS_BUILD_TESTS)
|
||||
set(FLATBUFFERS_BUILD_TESTS OFF)
|
||||
endif()
|
||||
|
||||
if(DEFINED FLATBUFFERS_MAX_PARSING_DEPTH)
|
||||
# Override the default recursion depth limit.
|
||||
add_definitions(-DFLATBUFFERS_MAX_PARSING_DEPTH=${FLATBUFFERS_MAX_PARSING_DEPTH})
|
||||
message(STATUS "FLATBUFFERS_MAX_PARSING_DEPTH: ${FLATBUFFERS_MAX_PARSING_DEPTH}")
|
||||
endif()
|
||||
|
||||
# Auto-detect locale-narrow 'strtod_l' function.
|
||||
if(NOT DEFINED FLATBUFFERS_LOCALE_INDEPENDENT)
|
||||
if(MSVC)
|
||||
check_cxx_symbol_exists(_strtof_l stdlib.h FLATBUFFERS_LOCALE_INDEPENDENT)
|
||||
else()
|
||||
check_cxx_symbol_exists(strtof_l stdlib.h FLATBUFFERS_LOCALE_INDEPENDENT)
|
||||
endif()
|
||||
endif()
|
||||
add_definitions(-DFLATBUFFERS_LOCALE_INDEPENDENT=$<BOOL:${FLATBUFFERS_LOCALE_INDEPENDENT}>)
|
||||
|
||||
set(FlatBuffers_Library_SRCS
|
||||
include/flatbuffers/code_generators.h
|
||||
include/flatbuffers/base.h
|
||||
@@ -49,7 +78,7 @@ set(FlatBuffers_Compiler_SRCS
|
||||
src/idl_gen_dart.cpp
|
||||
src/idl_gen_general.cpp
|
||||
src/idl_gen_go.cpp
|
||||
src/idl_gen_js.cpp
|
||||
src/idl_gen_js_ts.cpp
|
||||
src/idl_gen_php.cpp
|
||||
src/idl_gen_python.cpp
|
||||
src/idl_gen_lobster.cpp
|
||||
@@ -100,6 +129,14 @@ set(FlatBuffers_Sample_Text_SRCS
|
||||
${CMAKE_CURRENT_BINARY_DIR}/samples/monster_generated.h
|
||||
)
|
||||
|
||||
set(FlatBuffers_Sample_BFBS_SRCS
|
||||
${FlatBuffers_Library_SRCS}
|
||||
src/idl_gen_general.cpp
|
||||
samples/sample_bfbs.cpp
|
||||
# file generated by running compiler on samples/monster.fbs
|
||||
${CMAKE_CURRENT_BINARY_DIR}/samples/monster_generated.h
|
||||
)
|
||||
|
||||
set(FlatBuffers_GRPCTest_SRCS
|
||||
include/flatbuffers/flatbuffers.h
|
||||
include/flatbuffers/grpc.h
|
||||
@@ -121,9 +158,11 @@ set(FlatBuffers_GRPCTest_SRCS
|
||||
if(EXISTS "${CMAKE_TOOLCHAIN_FILE}")
|
||||
# do not apply any global settings if the toolchain
|
||||
# is being configured externally
|
||||
message(STATUS "Using toolchain file: ${CMAKE_TOOLCHAIN_FILE}.")
|
||||
elseif(APPLE)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -stdlib=libc++")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -pedantic -Werror -Wextra -Wno-unused-parameter")
|
||||
set(FLATBUFFERS_PRIVATE_CXX_FLAGS "-Wold-style-cast")
|
||||
elseif(CMAKE_COMPILER_IS_GNUCXX)
|
||||
if(CYGWIN)
|
||||
set(CMAKE_CXX_FLAGS
|
||||
@@ -134,10 +173,11 @@ elseif(CMAKE_COMPILER_IS_GNUCXX)
|
||||
endif(CYGWIN)
|
||||
set(CMAKE_CXX_FLAGS
|
||||
"${CMAKE_CXX_FLAGS} -Wall -pedantic -Werror -Wextra -Werror=shadow")
|
||||
set(FLATBUFFERS_PRIVATE_CXX_FLAGS "-Wold-style-cast")
|
||||
if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 4.4)
|
||||
if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 7.0)
|
||||
set(CMAKE_CXX_FLAGS
|
||||
"${CMAKE_CXX_FLAGS} -faligned-new")
|
||||
"${CMAKE_CXX_FLAGS} -faligned-new -Werror=implicit-fallthrough=2")
|
||||
endif()
|
||||
set(CMAKE_CXX_FLAGS
|
||||
"${CMAKE_CXX_FLAGS} -Wunused-result -Werror=unused-result -Wunused-parameter -Werror=unused-parameter")
|
||||
@@ -151,6 +191,10 @@ 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")
|
||||
set(FLATBUFFERS_PRIVATE_CXX_FLAGS "-Wold-style-cast")
|
||||
if(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 3.8)
|
||||
list(APPEND FLATBUFFERS_PRIVATE_CXX_FLAGS "-Wimplicit-fallthrough" "-Wextra-semi" "-Werror=unused-private-field") # enable warning
|
||||
endif()
|
||||
if(FLATBUFFERS_LIBCXX_WITH_CLANG)
|
||||
if(NOT "${CMAKE_SYSTEM_NAME}" MATCHES "Linux")
|
||||
set(CMAKE_CXX_FLAGS
|
||||
@@ -181,6 +225,27 @@ if(FLATBUFFERS_CODE_COVERAGE)
|
||||
"${CMAKE_EXE_LINKER_FLAGS} -fprofile-arcs -ftest-coverage")
|
||||
endif()
|
||||
|
||||
function(add_fsanitize_to_target _target _sanitizer)
|
||||
# FLATBUFFERS_CODE_SANITIZE: boolean {ON,OFF,YES,NO} or string with list of sanitizer.
|
||||
# List of sanitizer is string starts with '=': "=address,undefined,thread,memory".
|
||||
if((${CMAKE_CXX_COMPILER_ID} MATCHES "Clang") OR
|
||||
((${CMAKE_CXX_COMPILER_ID} MATCHES "GNU") AND NOT (CMAKE_CXX_COMPILER_VERSION VERSION_LESS "4.9"))
|
||||
)
|
||||
set(_sanitizer_flags "=address,undefined")
|
||||
if(_sanitizer MATCHES "=.*")
|
||||
# override default by user-defined sanitizer list
|
||||
set(_sanitizer_flags ${_sanitizer})
|
||||
endif()
|
||||
target_compile_options(${_target} PRIVATE
|
||||
-g -fsigned-char -fno-omit-frame-pointer
|
||||
"-fsanitize${_sanitizer_flags}")
|
||||
target_link_libraries(${_target} PRIVATE
|
||||
"-fsanitize${_sanitizer_flags}")
|
||||
set_property(TARGET ${_target} PROPERTY POSITION_INDEPENDENT_CODE ON)
|
||||
message(STATUS "Sanitizer ${_sanitizer_flags} added to ${_target}")
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
if(BIICODE)
|
||||
include(biicode/cmake/biicode.cmake)
|
||||
return()
|
||||
@@ -194,10 +259,15 @@ if(FLATBUFFERS_BUILD_FLATLIB)
|
||||
# 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>)
|
||||
target_compile_options(flatbuffers PRIVATE "${FLATBUFFERS_PRIVATE_CXX_FLAGS}")
|
||||
endif()
|
||||
|
||||
if(FLATBUFFERS_BUILD_FLATC)
|
||||
add_executable(flatc ${FlatBuffers_Compiler_SRCS})
|
||||
target_compile_options(flatc PRIVATE "${FLATBUFFERS_PRIVATE_CXX_FLAGS}")
|
||||
if(FLATBUFFERS_CODE_SANITIZE AND NOT WIN32)
|
||||
add_fsanitize_to_target(flatc ${FLATBUFFERS_CODE_SANITIZE})
|
||||
endif()
|
||||
if(NOT FLATBUFFERS_FLATC_EXECUTABLE)
|
||||
set(FLATBUFFERS_FLATC_EXECUTABLE $<TARGET_FILE:flatc>)
|
||||
endif()
|
||||
@@ -219,7 +289,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}.10.0")
|
||||
set(FlatBuffers_Library_SONAME_FULL "${FlatBuffers_Library_SONAME_MAJOR}.11.0")
|
||||
set_target_properties(flatbuffers_shared PROPERTIES OUTPUT_NAME flatbuffers
|
||||
SOVERSION "${FlatBuffers_Library_SONAME_MAJOR}"
|
||||
VERSION "${FlatBuffers_Library_SONAME_FULL}")
|
||||
@@ -256,11 +326,20 @@ if(FLATBUFFERS_BUILD_TESTS)
|
||||
set_property(TARGET flattests
|
||||
PROPERTY COMPILE_DEFINITIONS FLATBUFFERS_TRACK_VERIFIER_BUFFER_SIZE
|
||||
FLATBUFFERS_DEBUG_VERIFICATION_FAILURE=1)
|
||||
if(FLATBUFFERS_CODE_SANITIZE)
|
||||
if(WIN32)
|
||||
target_compile_definitions(flattests PRIVATE FLATBUFFERS_MEMORY_LEAK_TRACKING)
|
||||
message(STATUS "Sanitizer MSVC::_CrtDumpMemoryLeaks added to flattests")
|
||||
else()
|
||||
add_fsanitize_to_target(flattests ${FLATBUFFERS_CODE_SANITIZE})
|
||||
endif()
|
||||
endif()
|
||||
|
||||
compile_flatbuffers_schema_to_cpp(samples/monster.fbs)
|
||||
include_directories(${CMAKE_CURRENT_BINARY_DIR}/samples)
|
||||
add_executable(flatsamplebinary ${FlatBuffers_Sample_Binary_SRCS})
|
||||
add_executable(flatsampletext ${FlatBuffers_Sample_Text_SRCS})
|
||||
add_executable(flatsamplebfbs ${FlatBuffers_Sample_BFBS_SRCS})
|
||||
endif()
|
||||
|
||||
if(FLATBUFFERS_BUILD_GRPCTEST)
|
||||
@@ -320,7 +399,6 @@ if(FLATBUFFERS_INSTALL)
|
||||
install(
|
||||
TARGETS flatc EXPORT FlatcTargets
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||
CONFIGURATIONS Release
|
||||
)
|
||||
|
||||
install(
|
||||
@@ -328,7 +406,6 @@ if(FLATBUFFERS_INSTALL)
|
||||
FILE FlatcTargets.cmake
|
||||
NAMESPACE flatbuffers::
|
||||
DESTINATION ${FB_CMAKE_DIR}
|
||||
CONFIGURATIONS Release
|
||||
)
|
||||
endif()
|
||||
|
||||
@@ -372,6 +449,13 @@ endif()
|
||||
|
||||
include(CMake/BuildFlatBuffers.cmake)
|
||||
|
||||
if(FLATBUFFERS_PACKAGE_DEBIAN)
|
||||
include(CMake/PackageDebian.cmake)
|
||||
if(UNIX)
|
||||
# Use of CPack only supported on Linux systems.
|
||||
if(FLATBUFFERS_PACKAGE_DEBIAN)
|
||||
include(CMake/PackageDebian.cmake)
|
||||
endif()
|
||||
if (FLATBUFFERS_PACKAGE_REDHAT)
|
||||
include(CMake/PackageRedhat.cmake)
|
||||
endif()
|
||||
include(CPack)
|
||||
endif()
|
||||
|
||||
13
WORKSPACE
13
WORKSPACE
@@ -1,2 +1,15 @@
|
||||
workspace(name = "com_github_google_flatbuffers")
|
||||
|
||||
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
|
||||
|
||||
http_archive(
|
||||
name = "io_bazel_rules_go",
|
||||
sha256 = "492c3ac68ed9dcf527a07e6a1b2dcbf199c6bf8b35517951467ac32e421c06c1",
|
||||
urls = ["https://github.com/bazelbuild/rules_go/releases/download/0.17.0/rules_go-0.17.0.tar.gz"],
|
||||
)
|
||||
|
||||
load("@io_bazel_rules_go//go:deps.bzl", "go_register_toolchains", "go_rules_dependencies")
|
||||
|
||||
go_rules_dependencies()
|
||||
|
||||
go_register_toolchains()
|
||||
|
||||
@@ -66,7 +66,7 @@ android {
|
||||
ndkBuild {
|
||||
targets "FlatBufferTest"
|
||||
arguments "-j" + Runtime.getRuntime().availableProcessors()
|
||||
abiFilters "armeabi", "armeabi-v7a", "arm64-v8a", "x86", "x86_64"
|
||||
abiFilters "armeabi-v7a", "arm64-v8a", "x86", "x86_64"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
12
appveyor.yml
12
appveyor.yml
@@ -13,8 +13,13 @@ environment:
|
||||
|
||||
matrix:
|
||||
- CMAKE_VS_VERSION: "10 2010"
|
||||
MONSTER_EXTRA: "skip"
|
||||
|
||||
- CMAKE_VS_VERSION: "12 2013"
|
||||
MONSTER_EXTRA: "skip"
|
||||
|
||||
- CMAKE_VS_VERSION: "14 2015"
|
||||
MONSTER_EXTRA: ""
|
||||
|
||||
platform:
|
||||
- x86
|
||||
@@ -25,7 +30,8 @@ configuration:
|
||||
- Release
|
||||
|
||||
before_build:
|
||||
- cmake -G"Visual Studio %CMAKE_VS_VERSION%"
|
||||
- set MONSTER_EXTRA=%MONSTER_EXTRA%
|
||||
- cmake -G"Visual Studio %CMAKE_VS_VERSION%" -DFLATBUFFERS_CODE_SANITIZE=1 .
|
||||
# This cuts down on a lot of noise generated by xamarin warnings.
|
||||
- del "C:\Program Files (x86)\MSBuild\14.0\Microsoft.Common.targets\ImportAfter\Xamarin.Common.targets"
|
||||
|
||||
@@ -46,6 +52,7 @@ install:
|
||||
- cargo -V
|
||||
|
||||
test_script:
|
||||
- call .appveyor\check-generate-code.bat -b %CONFIGURATION%
|
||||
- "cd tests"
|
||||
- rem "Building all code"
|
||||
- generate_code.bat -b %CONFIGURATION%
|
||||
@@ -85,6 +92,9 @@ test_script:
|
||||
- "cd FlatBuffers.Test"
|
||||
- "msbuild.exe /property:Configuration=Release;OutputPath=tempcs /verbosity:minimal FlatBuffers.Test.csproj"
|
||||
- "tempcs\\FlatBuffers.Test.exe"
|
||||
# Run tests with UNSAFE_BYTEBUFFER
|
||||
- "msbuild.exe /property:Configuration=Release;UnsafeByteBuffer=true;OutputPath=tempcsUnsafe /verbosity:minimal FlatBuffers.Test.csproj"
|
||||
- "tempcsUnsafe\\FlatBuffers.Test.exe"
|
||||
# TODO: add more languages.
|
||||
- "cd ..\\.."
|
||||
|
||||
|
||||
237
build_defs.bzl
Normal file
237
build_defs.bzl
Normal file
@@ -0,0 +1,237 @@
|
||||
# Description:
|
||||
# BUILD rules for generating flatbuffer files in various languages.
|
||||
|
||||
"""
|
||||
Rules for building C++ flatbuffers with Bazel.
|
||||
"""
|
||||
|
||||
flatc_path = "@com_github_google_flatbuffers//:flatc"
|
||||
|
||||
DEFAULT_INCLUDE_PATHS = [
|
||||
"./",
|
||||
"$(GENDIR)",
|
||||
"$(BINDIR)",
|
||||
]
|
||||
|
||||
DEFAULT_FLATC_ARGS = [
|
||||
"--gen-object-api",
|
||||
"--gen-compare",
|
||||
"--no-includes",
|
||||
"--gen-mutable",
|
||||
"--reflect-names",
|
||||
"--cpp-ptr-type flatbuffers::unique_ptr",
|
||||
]
|
||||
|
||||
def flatbuffer_library_public(
|
||||
name,
|
||||
srcs,
|
||||
outs,
|
||||
language_flag,
|
||||
out_prefix = "",
|
||||
includes = [],
|
||||
include_paths = DEFAULT_INCLUDE_PATHS,
|
||||
flatc_args = DEFAULT_FLATC_ARGS,
|
||||
reflection_name = "",
|
||||
reflection_visiblity = None,
|
||||
output_to_bindir = False):
|
||||
"""Generates code files for reading/writing the given flatbuffers in the requested language using the public compiler.
|
||||
|
||||
Args:
|
||||
name: Rule name.
|
||||
srcs: Source .fbs files. Sent in order to the compiler.
|
||||
outs: Output files from flatc.
|
||||
language_flag: Target language flag. One of [-c, -j, -js].
|
||||
out_prefix: Prepend this path to the front of all generated files except on
|
||||
single source targets. Usually is a directory name.
|
||||
includes: Optional, list of filegroups of schemas that the srcs depend on.
|
||||
include_paths: Optional, list of paths the includes files can be found in.
|
||||
flatc_args: Optional, list of additional arguments to pass to flatc.
|
||||
reflection_name: Optional, if set this will generate the flatbuffer
|
||||
reflection binaries for the schemas.
|
||||
reflection_visiblity: The visibility of the generated reflection Fileset.
|
||||
output_to_bindir: Passed to genrule for output to bin directory.
|
||||
|
||||
|
||||
This rule creates a filegroup(name) with all generated source files, and
|
||||
optionally a Fileset([reflection_name]) with all generated reflection
|
||||
binaries.
|
||||
"""
|
||||
include_paths_cmd = ["-I %s" % (s) for s in include_paths]
|
||||
|
||||
# '$(@D)' when given a single source target will give the appropriate
|
||||
# directory. Appending 'out_prefix' is only necessary when given a build
|
||||
# target with multiple sources.
|
||||
output_directory = (
|
||||
("-o $(@D)/%s" % (out_prefix)) if len(srcs) > 1 else ("-o $(@D)")
|
||||
)
|
||||
genrule_cmd = " ".join([
|
||||
"SRCS=($(SRCS));",
|
||||
"for f in $${SRCS[@]:0:%s}; do" % len(srcs),
|
||||
"$(location %s)" % (flatc_path),
|
||||
" ".join(include_paths_cmd),
|
||||
" ".join(flatc_args),
|
||||
language_flag,
|
||||
output_directory,
|
||||
"$$f;",
|
||||
"done",
|
||||
])
|
||||
native.genrule(
|
||||
name = name,
|
||||
srcs = srcs + includes,
|
||||
outs = outs,
|
||||
output_to_bindir = output_to_bindir,
|
||||
tools = [flatc_path],
|
||||
cmd = genrule_cmd,
|
||||
message = "Generating flatbuffer files for %s:" % (name),
|
||||
)
|
||||
if reflection_name:
|
||||
reflection_genrule_cmd = " ".join([
|
||||
"SRCS=($(SRCS));",
|
||||
"for f in $${SRCS[@]:0:%s}; do" % len(srcs),
|
||||
"$(location %s)" % (flatc_path),
|
||||
"-b --schema",
|
||||
" ".join(flatc_args),
|
||||
" ".join(include_paths_cmd),
|
||||
language_flag,
|
||||
output_directory,
|
||||
"$$f;",
|
||||
"done",
|
||||
])
|
||||
reflection_outs = [
|
||||
(out_prefix + "%s.bfbs") % (s.replace(".fbs", "").split("/")[-1])
|
||||
for s in srcs
|
||||
]
|
||||
native.genrule(
|
||||
name = "%s_srcs" % reflection_name,
|
||||
srcs = srcs + includes,
|
||||
outs = reflection_outs,
|
||||
output_to_bindir = output_to_bindir,
|
||||
tools = [flatc_path],
|
||||
cmd = reflection_genrule_cmd,
|
||||
message = "Generating flatbuffer reflection binary for %s:" % (name),
|
||||
)
|
||||
native.Fileset(
|
||||
name = reflection_name,
|
||||
out = "%s_out" % reflection_name,
|
||||
entries = [
|
||||
native.FilesetEntry(files = reflection_outs),
|
||||
],
|
||||
visibility = reflection_visiblity,
|
||||
)
|
||||
|
||||
def flatbuffer_cc_library(
|
||||
name,
|
||||
srcs,
|
||||
srcs_filegroup_name = "",
|
||||
out_prefix = "",
|
||||
includes = [],
|
||||
include_paths = DEFAULT_INCLUDE_PATHS,
|
||||
flatc_args = DEFAULT_FLATC_ARGS,
|
||||
visibility = None,
|
||||
srcs_filegroup_visibility = None,
|
||||
gen_reflections = False):
|
||||
'''A cc_library with the generated reader/writers for the given flatbuffer definitions.
|
||||
|
||||
Args:
|
||||
name: Rule name.
|
||||
srcs: Source .fbs files. Sent in order to the compiler.
|
||||
srcs_filegroup_name: Name of the output filegroup that holds srcs. Pass this
|
||||
filegroup into the `includes` parameter of any other
|
||||
flatbuffer_cc_library that depends on this one's schemas.
|
||||
out_prefix: Prepend this path to the front of all generated files. Usually
|
||||
is a directory name.
|
||||
includes: Optional, list of filegroups of schemas that the srcs depend on.
|
||||
** SEE REMARKS BELOW **
|
||||
include_paths: Optional, list of paths the includes files can be found in.
|
||||
flatc_args: Optional list of additional arguments to pass to flatc
|
||||
(e.g. --gen-mutable).
|
||||
visibility: The visibility of the generated cc_library. By default, use the
|
||||
default visibility of the project.
|
||||
srcs_filegroup_visibility: The visibility of the generated srcs filegroup.
|
||||
By default, use the value of the visibility parameter above.
|
||||
gen_reflections: Optional, if true this will generate the flatbuffer
|
||||
reflection binaries for the schemas.
|
||||
|
||||
This produces:
|
||||
filegroup([name]_srcs): all generated .h files.
|
||||
filegroup(srcs_filegroup_name if specified, or [name]_includes if not):
|
||||
Other flatbuffer_cc_library's can pass this in for their `includes`
|
||||
parameter, if they depend on the schemas in this library.
|
||||
Fileset([name]_reflection): (Optional) all generated reflection binaries.
|
||||
cc_library([name]): library with sources and flatbuffers deps.
|
||||
|
||||
Remarks:
|
||||
** Because the genrule used to call flatc does not have any trivial way of
|
||||
computing the output list of files transitively generated by includes and
|
||||
--gen-includes (the default) being defined for flatc, the --gen-includes
|
||||
flag will not work as expected. The way around this is to add a dependency
|
||||
to the flatbuffer_cc_library defined alongside the flatc included Fileset.
|
||||
For example you might define:
|
||||
|
||||
flatbuffer_cc_library(
|
||||
name = "my_fbs",
|
||||
srcs = [ "schemas/foo.fbs" ],
|
||||
includes = [ "//third_party/bazz:bazz_fbs_includes" ],
|
||||
)
|
||||
|
||||
In which foo.fbs includes a few files from the Fileset defined at
|
||||
//third_party/bazz:bazz_fbs_includes. When compiling the library that
|
||||
includes foo_generated.h, and therefore has my_fbs as a dependency, it
|
||||
will fail to find any of the bazz *_generated.h files unless you also
|
||||
add bazz's flatbuffer_cc_library to your own dependency list, e.g.:
|
||||
|
||||
cc_library(
|
||||
name = "my_lib",
|
||||
deps = [
|
||||
":my_fbs",
|
||||
"//third_party/bazz:bazz_fbs"
|
||||
],
|
||||
)
|
||||
|
||||
Happy dependent Flatbuffering!
|
||||
'''
|
||||
output_headers = [
|
||||
(out_prefix + "%s_generated.h") % (s.replace(".fbs", "").split("/")[-1])
|
||||
for s in srcs
|
||||
]
|
||||
reflection_name = "%s_reflection" % name if gen_reflections else ""
|
||||
|
||||
srcs_lib = "%s_srcs" % (name)
|
||||
flatbuffer_library_public(
|
||||
name = srcs_lib,
|
||||
srcs = srcs,
|
||||
outs = output_headers,
|
||||
language_flag = "-c",
|
||||
out_prefix = out_prefix,
|
||||
includes = includes,
|
||||
include_paths = include_paths,
|
||||
flatc_args = flatc_args,
|
||||
reflection_name = reflection_name,
|
||||
reflection_visiblity = visibility,
|
||||
)
|
||||
native.cc_library(
|
||||
name = name,
|
||||
hdrs = [
|
||||
":" + srcs_lib,
|
||||
],
|
||||
srcs = [
|
||||
":" + srcs_lib,
|
||||
],
|
||||
features = [
|
||||
"-parse_headers",
|
||||
],
|
||||
deps = [
|
||||
"@com_github_google_flatbuffers//:runtime_cc",
|
||||
],
|
||||
includes = [],
|
||||
linkstatic = 1,
|
||||
visibility = visibility,
|
||||
)
|
||||
|
||||
# A filegroup for the `srcs`. That is, all the schema files for this
|
||||
# Flatbuffer set.
|
||||
native.filegroup(
|
||||
name = srcs_filegroup_name if srcs_filegroup_name else "%s_includes" % (name),
|
||||
srcs = srcs,
|
||||
visibility = srcs_filegroup_visibility if srcs_filegroup_visibility != None else visibility,
|
||||
)
|
||||
@@ -1,7 +1,10 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
from cpt.packager import ConanMultiPackager
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
from cpt.packager import ConanMultiPackager
|
||||
|
||||
|
||||
def set_appveyor_environment():
|
||||
if os.getenv("APPVEYOR") is not None:
|
||||
@@ -13,6 +16,39 @@ def set_appveyor_environment():
|
||||
os.environ["CONAN_ARCHS"] = ci_platform
|
||||
os.environ["CONAN_BUILD_TYPES"] = os.getenv("Configuration").replace('"', '')
|
||||
|
||||
|
||||
def get_branch():
|
||||
try:
|
||||
for line in subprocess.check_output("git branch", shell=True).decode().splitlines():
|
||||
line = line.strip()
|
||||
if line.startswith("*") and " (HEAD detached" not in line:
|
||||
return line.replace("*", "", 1).strip()
|
||||
return ""
|
||||
except Exception:
|
||||
pass
|
||||
return ""
|
||||
|
||||
|
||||
def get_version():
|
||||
version = get_branch()
|
||||
if os.getenv("TRAVIS", False):
|
||||
version = os.getenv("TRAVIS_BRANCH")
|
||||
|
||||
if os.getenv("APPVEYOR", False):
|
||||
version = os.getenv("APPVEYOR_REPO_BRANCH")
|
||||
if os.getenv("APPVEYOR_REPO_TAG") == "true":
|
||||
version = os.getenv("APPVEYOR_REPO_TAG_NAME")
|
||||
|
||||
match = re.search(r"v(\d+\.\d+\.\d+.*)", version)
|
||||
if match:
|
||||
return match.group(1)
|
||||
return version
|
||||
|
||||
|
||||
def get_reference(username):
|
||||
return "flatbuffers/{}@google/stable".format(get_version())
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
login_username = os.getenv("CONAN_LOGIN_USERNAME", "aardappel")
|
||||
username = os.getenv("CONAN_USERNAME", "google")
|
||||
@@ -22,7 +58,8 @@ if __name__ == "__main__":
|
||||
upload_only_when_stable = os.getenv("CONAN_UPLOAD_ONLY_WHEN_STABLE", True)
|
||||
set_appveyor_environment()
|
||||
|
||||
builder = ConanMultiPackager(username=username,
|
||||
builder = ConanMultiPackager(reference=get_reference(username),
|
||||
username=username,
|
||||
login_username=login_username,
|
||||
upload=upload,
|
||||
stable_branch_pattern=stable_branch_pattern,
|
||||
|
||||
@@ -10,15 +10,15 @@ from conans import ConanFile, CMake, tools
|
||||
|
||||
class FlatbuffersConan(ConanFile):
|
||||
name = "flatbuffers"
|
||||
version = "1.10.0"
|
||||
license = "Apache-2.0"
|
||||
url = "https://github.com/google/flatbuffers"
|
||||
homepage = "http://google.github.io/flatbuffers/"
|
||||
author = "Wouter van Oortmerssen"
|
||||
topics = ("conan", "flatbuffers", "serialization", "rpc", "json-parser")
|
||||
description = "Memory Efficient Serialization Library"
|
||||
settings = "os", "compiler", "build_type", "arch"
|
||||
options = {"shared": [True, False], "fPIC": [True, False]}
|
||||
default_options = "shared=False", "fPIC=True"
|
||||
default_options = {"shared": False, "fPIC": True}
|
||||
generators = "cmake"
|
||||
exports = "LICENSE.txt"
|
||||
exports_sources = ["CMake/*", "include/*", "src/*", "grpc/*", "CMakeLists.txt", "conan/CMakeLists.txt"]
|
||||
@@ -57,6 +57,7 @@ class FlatbuffersConan(ConanFile):
|
||||
cmake = self.configure_cmake()
|
||||
cmake.install()
|
||||
self.copy(pattern="LICENSE.txt", dst="licenses")
|
||||
self.copy(pattern="FindFlatBuffers.cmake", dst=os.path.join("lib", "cmake", "flatbuffers"), src="CMake")
|
||||
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:
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: flat_buffers
|
||||
version: 1.10.0
|
||||
version: 1.11.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
|
||||
|
||||
@@ -8,8 +8,8 @@ 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;
|
||||
import './monster_test_my_game.example_generated.dart' as my_game_example;
|
||||
|
||||
class Monster {
|
||||
Monster._(this._bc, this._bcOffset);
|
||||
|
||||
@@ -8,8 +8,8 @@ import 'package:flat_buffers/flat_buffers.dart' as fb;
|
||||
|
||||
import 'include_test1_my_game.example_generated.dart';
|
||||
import 'include_test2_my_game.example_generated.dart';
|
||||
import './monster_test_my_game.example2_generated.dart' as my_game_example2;
|
||||
import './monster_test_my_game_generated.dart' as my_game;
|
||||
import './monster_test_my_game.example2_generated.dart' as my_game_example2;
|
||||
|
||||
class Color {
|
||||
final int value;
|
||||
@@ -90,6 +90,88 @@ class _AnyTypeIdReader extends fb.Reader<AnyTypeId> {
|
||||
new AnyTypeId.fromValue(const fb.Uint8Reader().read(bc, offset));
|
||||
}
|
||||
|
||||
class AnyUniqueAliasesTypeId {
|
||||
final int value;
|
||||
const AnyUniqueAliasesTypeId._(this.value);
|
||||
|
||||
factory AnyUniqueAliasesTypeId.fromValue(int value) {
|
||||
if (value == null) value = 0;
|
||||
if (!values.containsKey(value)) {
|
||||
throw new StateError('Invalid value $value for bit flag enum AnyUniqueAliasesTypeId');
|
||||
}
|
||||
return values[value];
|
||||
}
|
||||
|
||||
static const int minValue = 0;
|
||||
static const int maxValue = 3;
|
||||
static bool containsValue(int value) => values.containsKey(value);
|
||||
|
||||
static const AnyUniqueAliasesTypeId NONE = const AnyUniqueAliasesTypeId._(0);
|
||||
static const AnyUniqueAliasesTypeId M = const AnyUniqueAliasesTypeId._(1);
|
||||
static const AnyUniqueAliasesTypeId T = const AnyUniqueAliasesTypeId._(2);
|
||||
static const AnyUniqueAliasesTypeId M2 = const AnyUniqueAliasesTypeId._(3);
|
||||
static get values => {0: NONE,1: M,2: T,3: M2,};
|
||||
|
||||
static const fb.Reader<AnyUniqueAliasesTypeId> reader = const _AnyUniqueAliasesTypeIdReader();
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'AnyUniqueAliasesTypeId{value: $value}';
|
||||
}
|
||||
}
|
||||
|
||||
class _AnyUniqueAliasesTypeIdReader extends fb.Reader<AnyUniqueAliasesTypeId> {
|
||||
const _AnyUniqueAliasesTypeIdReader();
|
||||
|
||||
@override
|
||||
int get size => 1;
|
||||
|
||||
@override
|
||||
AnyUniqueAliasesTypeId read(fb.BufferContext bc, int offset) =>
|
||||
new AnyUniqueAliasesTypeId.fromValue(const fb.Uint8Reader().read(bc, offset));
|
||||
}
|
||||
|
||||
class AnyAmbiguousAliasesTypeId {
|
||||
final int value;
|
||||
const AnyAmbiguousAliasesTypeId._(this.value);
|
||||
|
||||
factory AnyAmbiguousAliasesTypeId.fromValue(int value) {
|
||||
if (value == null) value = 0;
|
||||
if (!values.containsKey(value)) {
|
||||
throw new StateError('Invalid value $value for bit flag enum AnyAmbiguousAliasesTypeId');
|
||||
}
|
||||
return values[value];
|
||||
}
|
||||
|
||||
static const int minValue = 0;
|
||||
static const int maxValue = 3;
|
||||
static bool containsValue(int value) => values.containsKey(value);
|
||||
|
||||
static const AnyAmbiguousAliasesTypeId NONE = const AnyAmbiguousAliasesTypeId._(0);
|
||||
static const AnyAmbiguousAliasesTypeId M1 = const AnyAmbiguousAliasesTypeId._(1);
|
||||
static const AnyAmbiguousAliasesTypeId M2 = const AnyAmbiguousAliasesTypeId._(2);
|
||||
static const AnyAmbiguousAliasesTypeId M3 = const AnyAmbiguousAliasesTypeId._(3);
|
||||
static get values => {0: NONE,1: M1,2: M2,3: M3,};
|
||||
|
||||
static const fb.Reader<AnyAmbiguousAliasesTypeId> reader = const _AnyAmbiguousAliasesTypeIdReader();
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'AnyAmbiguousAliasesTypeId{value: $value}';
|
||||
}
|
||||
}
|
||||
|
||||
class _AnyAmbiguousAliasesTypeIdReader extends fb.Reader<AnyAmbiguousAliasesTypeId> {
|
||||
const _AnyAmbiguousAliasesTypeIdReader();
|
||||
|
||||
@override
|
||||
int get size => 1;
|
||||
|
||||
@override
|
||||
AnyAmbiguousAliasesTypeId read(fb.BufferContext bc, int offset) =>
|
||||
new AnyAmbiguousAliasesTypeId.fromValue(const fb.Uint8Reader().read(bc, offset));
|
||||
}
|
||||
|
||||
class Test {
|
||||
Test._(this._bc, this._bcOffset);
|
||||
|
||||
@@ -654,10 +736,29 @@ class Monster {
|
||||
List<int> get vectorOfCoOwningReferences => const fb.ListReader<int>(const fb.Uint64Reader()).vTableGet(_bc, _bcOffset, 84, null);
|
||||
int get nonOwningReference => const fb.Uint64Reader().vTableGet(_bc, _bcOffset, 86, 0);
|
||||
List<int> get vectorOfNonOwningReferences => const fb.ListReader<int>(const fb.Uint64Reader()).vTableGet(_bc, _bcOffset, 88, null);
|
||||
AnyUniqueAliasesTypeId get anyUniqueType => new AnyUniqueAliasesTypeId.fromValue(const fb.Uint8Reader().vTableGet(_bc, _bcOffset, 90, 0));
|
||||
dynamic get anyUnique {
|
||||
switch (anyUniqueType?.value) {
|
||||
case 1: return M.reader.vTableGet(_bc, _bcOffset, 92, null);
|
||||
case 2: return T.reader.vTableGet(_bc, _bcOffset, 92, null);
|
||||
case 3: return M2.reader.vTableGet(_bc, _bcOffset, 92, null);
|
||||
default: return null;
|
||||
}
|
||||
}
|
||||
AnyAmbiguousAliasesTypeId get anyAmbiguousType => new AnyAmbiguousAliasesTypeId.fromValue(const fb.Uint8Reader().vTableGet(_bc, _bcOffset, 94, 0));
|
||||
dynamic get anyAmbiguous {
|
||||
switch (anyAmbiguousType?.value) {
|
||||
case 1: return M1.reader.vTableGet(_bc, _bcOffset, 96, null);
|
||||
case 2: return M2.reader.vTableGet(_bc, _bcOffset, 96, null);
|
||||
case 3: return M3.reader.vTableGet(_bc, _bcOffset, 96, null);
|
||||
default: return null;
|
||||
}
|
||||
}
|
||||
List<Color> get vectorOfEnums => const fb.ListReader<Color>(Color.reader).vTableGet(_bc, _bcOffset, 98, null);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'Monster{pos: $pos, mana: $mana, hp: $hp, name: $name, inventory: $inventory, color: $color, testType: $testType, test: $test, test4: $test4, testarrayofstring: $testarrayofstring, testarrayoftables: $testarrayoftables, enemy: $enemy, testnestedflatbuffer: $testnestedflatbuffer, testempty: $testempty, testbool: $testbool, testhashs32Fnv1: $testhashs32Fnv1, testhashu32Fnv1: $testhashu32Fnv1, testhashs64Fnv1: $testhashs64Fnv1, testhashu64Fnv1: $testhashu64Fnv1, testhashs32Fnv1a: $testhashs32Fnv1a, testhashu32Fnv1a: $testhashu32Fnv1a, testhashs64Fnv1a: $testhashs64Fnv1a, testhashu64Fnv1a: $testhashu64Fnv1a, testarrayofbools: $testarrayofbools, testf: $testf, testf2: $testf2, testf3: $testf3, testarrayofstring2: $testarrayofstring2, testarrayofsortedstruct: $testarrayofsortedstruct, flex: $flex, test5: $test5, vectorOfLongs: $vectorOfLongs, vectorOfDoubles: $vectorOfDoubles, parentNamespaceTest: $parentNamespaceTest, vectorOfReferrables: $vectorOfReferrables, singleWeakReference: $singleWeakReference, vectorOfWeakReferences: $vectorOfWeakReferences, vectorOfStrongReferrables: $vectorOfStrongReferrables, coOwningReference: $coOwningReference, vectorOfCoOwningReferences: $vectorOfCoOwningReferences, nonOwningReference: $nonOwningReference, vectorOfNonOwningReferences: $vectorOfNonOwningReferences}';
|
||||
return 'Monster{pos: $pos, mana: $mana, hp: $hp, name: $name, inventory: $inventory, color: $color, testType: $testType, test: $test, test4: $test4, testarrayofstring: $testarrayofstring, testarrayoftables: $testarrayoftables, enemy: $enemy, testnestedflatbuffer: $testnestedflatbuffer, testempty: $testempty, testbool: $testbool, testhashs32Fnv1: $testhashs32Fnv1, testhashu32Fnv1: $testhashu32Fnv1, testhashs64Fnv1: $testhashs64Fnv1, testhashu64Fnv1: $testhashu64Fnv1, testhashs32Fnv1a: $testhashs32Fnv1a, testhashu32Fnv1a: $testhashu32Fnv1a, testhashs64Fnv1a: $testhashs64Fnv1a, testhashu64Fnv1a: $testhashu64Fnv1a, testarrayofbools: $testarrayofbools, testf: $testf, testf2: $testf2, testf3: $testf3, testarrayofstring2: $testarrayofstring2, testarrayofsortedstruct: $testarrayofsortedstruct, flex: $flex, test5: $test5, vectorOfLongs: $vectorOfLongs, vectorOfDoubles: $vectorOfDoubles, parentNamespaceTest: $parentNamespaceTest, vectorOfReferrables: $vectorOfReferrables, singleWeakReference: $singleWeakReference, vectorOfWeakReferences: $vectorOfWeakReferences, vectorOfStrongReferrables: $vectorOfStrongReferrables, coOwningReference: $coOwningReference, vectorOfCoOwningReferences: $vectorOfCoOwningReferences, nonOwningReference: $nonOwningReference, vectorOfNonOwningReferences: $vectorOfNonOwningReferences, anyUniqueType: $anyUniqueType, anyUnique: $anyUnique, anyAmbiguousType: $anyAmbiguousType, anyAmbiguous: $anyAmbiguous, vectorOfEnums: $vectorOfEnums}';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -848,6 +949,26 @@ class MonsterBuilder {
|
||||
fbBuilder.addOffset(42, offset);
|
||||
return fbBuilder.offset;
|
||||
}
|
||||
int addAnyUniqueType(AnyUniqueAliasesTypeId anyUniqueType) {
|
||||
fbBuilder.addUint8(43, anyUniqueType?.value);
|
||||
return fbBuilder.offset;
|
||||
}
|
||||
int addAnyUniqueOffset(int offset) {
|
||||
fbBuilder.addOffset(44, offset);
|
||||
return fbBuilder.offset;
|
||||
}
|
||||
int addAnyAmbiguousType(AnyAmbiguousAliasesTypeId anyAmbiguousType) {
|
||||
fbBuilder.addUint8(45, anyAmbiguousType?.value);
|
||||
return fbBuilder.offset;
|
||||
}
|
||||
int addAnyAmbiguousOffset(int offset) {
|
||||
fbBuilder.addOffset(46, offset);
|
||||
return fbBuilder.offset;
|
||||
}
|
||||
int addVectorOfEnumsOffset(int offset) {
|
||||
fbBuilder.addOffset(47, offset);
|
||||
return fbBuilder.offset;
|
||||
}
|
||||
|
||||
int finish() {
|
||||
return fbBuilder.endTable();
|
||||
@@ -897,6 +1018,11 @@ class MonsterObjectBuilder extends fb.ObjectBuilder {
|
||||
final List<int> _vectorOfCoOwningReferences;
|
||||
final int _nonOwningReference;
|
||||
final List<int> _vectorOfNonOwningReferences;
|
||||
final AnyUniqueAliasesTypeId _anyUniqueType;
|
||||
final dynamic _anyUnique;
|
||||
final AnyAmbiguousAliasesTypeId _anyAmbiguousType;
|
||||
final dynamic _anyAmbiguous;
|
||||
final List<Color> _vectorOfEnums;
|
||||
|
||||
MonsterObjectBuilder({
|
||||
Vec3ObjectBuilder pos,
|
||||
@@ -941,6 +1067,11 @@ class MonsterObjectBuilder extends fb.ObjectBuilder {
|
||||
List<int> vectorOfCoOwningReferences,
|
||||
int nonOwningReference,
|
||||
List<int> vectorOfNonOwningReferences,
|
||||
AnyUniqueAliasesTypeId anyUniqueType,
|
||||
dynamic anyUnique,
|
||||
AnyAmbiguousAliasesTypeId anyAmbiguousType,
|
||||
dynamic anyAmbiguous,
|
||||
List<Color> vectorOfEnums,
|
||||
})
|
||||
: _pos = pos,
|
||||
_mana = mana,
|
||||
@@ -983,7 +1114,12 @@ class MonsterObjectBuilder extends fb.ObjectBuilder {
|
||||
_coOwningReference = coOwningReference,
|
||||
_vectorOfCoOwningReferences = vectorOfCoOwningReferences,
|
||||
_nonOwningReference = nonOwningReference,
|
||||
_vectorOfNonOwningReferences = vectorOfNonOwningReferences;
|
||||
_vectorOfNonOwningReferences = vectorOfNonOwningReferences,
|
||||
_anyUniqueType = anyUniqueType,
|
||||
_anyUnique = anyUnique,
|
||||
_anyAmbiguousType = anyAmbiguousType,
|
||||
_anyAmbiguous = anyAmbiguous,
|
||||
_vectorOfEnums = vectorOfEnums;
|
||||
|
||||
/// Finish building, and store into the [fbBuilder].
|
||||
@override
|
||||
@@ -1046,6 +1182,11 @@ class MonsterObjectBuilder extends fb.ObjectBuilder {
|
||||
final int vectorOfNonOwningReferencesOffset = _vectorOfNonOwningReferences?.isNotEmpty == true
|
||||
? fbBuilder.writeListUint64(_vectorOfNonOwningReferences)
|
||||
: null;
|
||||
final int anyUniqueOffset = _anyUnique?.getOrCreateOffset(fbBuilder);
|
||||
final int anyAmbiguousOffset = _anyAmbiguous?.getOrCreateOffset(fbBuilder);
|
||||
final int vectorOfEnumsOffset = _vectorOfEnums?.isNotEmpty == true
|
||||
? fbBuilder.writeListInt8(_vectorOfEnums.map((f) => f.value))
|
||||
: null;
|
||||
|
||||
fbBuilder.startTable();
|
||||
if (_pos != null) {
|
||||
@@ -1136,6 +1277,17 @@ class MonsterObjectBuilder extends fb.ObjectBuilder {
|
||||
if (vectorOfNonOwningReferencesOffset != null) {
|
||||
fbBuilder.addOffset(42, vectorOfNonOwningReferencesOffset);
|
||||
}
|
||||
fbBuilder.addUint8(43, _anyUniqueType?.value);
|
||||
if (anyUniqueOffset != null) {
|
||||
fbBuilder.addOffset(44, anyUniqueOffset);
|
||||
}
|
||||
fbBuilder.addUint8(45, _anyAmbiguousType?.value);
|
||||
if (anyAmbiguousOffset != null) {
|
||||
fbBuilder.addOffset(46, anyAmbiguousOffset);
|
||||
}
|
||||
if (vectorOfEnumsOffset != null) {
|
||||
fbBuilder.addOffset(47, vectorOfEnumsOffset);
|
||||
}
|
||||
return fbBuilder.endTable();
|
||||
}
|
||||
|
||||
|
||||
@@ -80,6 +80,14 @@ 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.
|
||||
|
||||
#### Override default depth limit of nested objects
|
||||
To override [the depth limit of recursion](@ref flatbuffers_guide_use_cpp),
|
||||
add this directive:
|
||||
```cmake
|
||||
set(FLATBUFFERS_MAX_PARSING_DEPTH 16)
|
||||
```
|
||||
to `CMakeLists.txt` file before `add_subdirectory(${FLATBUFFERS_SRC_DIR})` line.
|
||||
|
||||
#### For Google Play apps
|
||||
|
||||
For applications on Google Play that integrate this library, usage is tracked.
|
||||
|
||||
@@ -72,6 +72,12 @@ Additional options:
|
||||
in quotes, no trailing commas in tables/vectors). By default, no quotes are
|
||||
required/generated, and trailing commas are allowed.
|
||||
|
||||
- `--allow-non-utf8` : Pass non-UTF-8 input through parser and emit nonstandard
|
||||
\x escapes in JSON. (Default is to raise parse error on non-UTF-8 input.)
|
||||
|
||||
- `--natural-utf8` : Output strings with UTF-8 as human-readable strings.
|
||||
By default, UTF-8 characters are printed as \uXXXX escapes."
|
||||
|
||||
- `--defaults-json` : Output fields whose value is equal to the default value
|
||||
when writing JSON text.
|
||||
|
||||
@@ -91,21 +97,42 @@ Additional options:
|
||||
- `--gen-mutable` : Generate additional non-const accessors for mutating
|
||||
FlatBuffers in-place.
|
||||
|
||||
`--gen-object-api` : Generate an additional object-based API. This API is
|
||||
- `--gen-onefile` : Generate single output file for C# and Go.
|
||||
|
||||
- `--gen-name-strings` : Generate type name functions for C++.
|
||||
|
||||
- `--gen-object-api` : Generate an additional object-based API. This API is
|
||||
more convenient for object construction and mutation than the base API,
|
||||
at the cost of efficiency (object allocation). Recommended only to be used
|
||||
if other options are insufficient.
|
||||
|
||||
- `--gen-compare` : Generate operator== for object-based API types.
|
||||
- `--gen-compare` : Generate operator== for object-based API types.
|
||||
|
||||
- `--gen-onefile` : Generate single output file (useful for C#)
|
||||
- `--gen-nullable` : Add Clang _Nullable for C++ pointer. or @Nullable for Java.
|
||||
|
||||
- `--gen-all`: Generate not just code for the current schema files, but
|
||||
- `--gen-generated` : Add @Generated annotation for Java.
|
||||
|
||||
- `--gen-all` : Generate not just code for the current schema files, but
|
||||
for all files it includes as well. If the language uses a single file for
|
||||
output (by default the case for C++ and JS), all code will end up in
|
||||
this one file.
|
||||
|
||||
- `--no-js-exports` : Removes Node.js style export lines (useful for JS)
|
||||
- `--cpp-ptr-type T` : Set object API pointer type (default std::unique_ptr)
|
||||
|
||||
- `--cpp-str-type T` : Set object API string type (default std::string)
|
||||
T::c_str(), T::length() and T::empty() must be supported.
|
||||
The custom type also needs to be constructible from std::string (see the
|
||||
--cpp-str-flex-ctor option to change this behavior).
|
||||
|
||||
- `--cpp-str-flex-ctor` : Don't construct custom string types by passing
|
||||
std::string from Flatbuffers, but (char* + length). This allows efficient
|
||||
construction of custom string types, including zero-copy construction.
|
||||
|
||||
- `--object-prefix` : Customise class prefix for C++ object-based API.
|
||||
|
||||
- `--object-suffix` : Customise class suffix for C++ object-based API.
|
||||
|
||||
- `--no-js-exports` : Removes Node.js style export lines (useful for JS)
|
||||
|
||||
- `--goog-js-export` : Uses goog.exportsSymbol and goog.exportsProperty
|
||||
instead of Node.js style exporting. Needed for compatibility with the
|
||||
@@ -115,9 +142,16 @@ Additional options:
|
||||
instead of Node.js style exporting. Useful when integrating flatbuffers
|
||||
with modern Javascript projects.
|
||||
|
||||
- `--go-namespace` : Generate the overrided namespace in Golang.
|
||||
|
||||
- `--go-import` : Generate the overrided import for flatbuffers in Golang.
|
||||
(default is "github.com/google/flatbuffers/go").
|
||||
|
||||
- `--raw-binary` : Allow binaries without a file_indentifier to be read.
|
||||
This may crash flatc given a mismatched schema.
|
||||
|
||||
- `--size-prefixed` : Input binaries are size prefixed buffers.
|
||||
|
||||
- `--proto`: Expect input files to be .proto files (protocol buffers).
|
||||
Output the corresponding .fbs file.
|
||||
Currently supports: `package`, `message`, `enum`, nested declarations,
|
||||
@@ -125,6 +159,10 @@ Additional options:
|
||||
Does not support, but will skip without error: `option`, `service`,
|
||||
`extensions`, and most everything else.
|
||||
|
||||
- `--oneof-union` : Translate .proto oneofs to flatbuffer unions.
|
||||
|
||||
- `--grpc` : Generate GRPC interfaces for the specified languages.
|
||||
|
||||
- `--schema`: Serialize schemas instead of JSON (use with -b). This will
|
||||
output a binary version of the specified schema that itself corresponds
|
||||
to the reflection/reflection.fbs schema. Loading this binary file is the
|
||||
@@ -136,12 +174,22 @@ Additional options:
|
||||
an evolution of. Gives errors if not. Useful to check if schema
|
||||
modifications don't break schema evolution rules.
|
||||
|
||||
- `--conform-includes PATH` : Include path for the schema given with
|
||||
`--conform PATH`.
|
||||
|
||||
- `--include-prefix PATH` : Prefix this path to any generated include
|
||||
statements.
|
||||
|
||||
- `--keep-prefix` : Keep original prefix of schema include statement.
|
||||
|
||||
- `--no-fb-impor` : Don't include flatbuffers import statement for TypeScript.
|
||||
|
||||
- `--no-ts-reexpor` : Don't re-export imported dependencies for TypeScript.
|
||||
|
||||
- `--short-name` : Use short function names for JS and TypeScript.
|
||||
|
||||
- `--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.
|
||||
|
||||
@@ -88,6 +88,14 @@ convenient accessors for all fields, e.g. `hp()`, `mana()`, etc:
|
||||
|
||||
*Note: That we never stored a `mana` value, so it will return the default.*
|
||||
|
||||
The following attributes are supported:
|
||||
|
||||
- `shared` (on a field): For string fields, this enables the usage of string
|
||||
pooling (i.e. `CreateSharedString`) as default serialization behavior.
|
||||
|
||||
Specifically, `CreateXxxDirect` functions and `Pack` functions for object
|
||||
based API (see below) will use `CreateSharedString` to create strings.
|
||||
|
||||
## Object based API. {#flatbuffers_cpp_object_based_api}
|
||||
|
||||
FlatBuffers is all about memory efficiency, which is why its base API is written
|
||||
@@ -130,10 +138,10 @@ The following attributes are specific to the object-based API code generation:
|
||||
verbatim in the class constructor initializer list for this member.
|
||||
|
||||
- `native_custom_alloc`:"custom_allocator" (on a table or struct): When using the
|
||||
object-based API all generated NativeTables that are allocated when unpacking
|
||||
your flatbuffer will use "custom allocator". The allocator is also used by
|
||||
any std::vector that appears in a table defined with `native_custom_alloc`.
|
||||
This can be used to provide allocation from a pool for example, for faster
|
||||
object-based API all generated NativeTables that are allocated when unpacking
|
||||
your flatbuffer will use "custom allocator". The allocator is also used by
|
||||
any std::vector that appears in a table defined with `native_custom_alloc`.
|
||||
This can be used to provide allocation from a pool for example, for faster
|
||||
unpacking when using the object-based API.
|
||||
|
||||
Minimal Example:
|
||||
@@ -151,8 +159,8 @@ The following attributes are specific to the object-based API code generation:
|
||||
typedef T *pointer;
|
||||
|
||||
template <class U>
|
||||
struct rebind {
|
||||
typedef custom_allocator<U> other;
|
||||
struct rebind {
|
||||
typedef custom_allocator<U> other;
|
||||
};
|
||||
|
||||
pointer allocate(const std::size_t n) {
|
||||
@@ -164,7 +172,7 @@ The following attributes are specific to the object-based API code generation:
|
||||
}
|
||||
|
||||
custom_allocator() throw() {}
|
||||
template <class U>
|
||||
template <class U>
|
||||
custom_allocator(const custom_allocator<U>&) throw() {}
|
||||
};
|
||||
|
||||
@@ -208,12 +216,15 @@ The following attributes are specific to the object-based API code generation:
|
||||
|
||||
Finally, the following top-level attribute
|
||||
|
||||
- native_include: "path" (at file level): Because the `native_type` attribute
|
||||
- `native_include`: "path" (at file level): Because the `native_type` attribute
|
||||
can be used to introduce types that are unknown to flatbuffers, it may be
|
||||
necessary to include "external" header files in the generated code. This
|
||||
attribute can be used to directly add an #include directive to the top of
|
||||
the generated code that includes the specified path directly.
|
||||
|
||||
- `force_align`: this attribute may not be respected in the object API,
|
||||
depending on the aligned of the allocator used with `new`.
|
||||
|
||||
# External references.
|
||||
|
||||
An additional feature of the object API is the ability to allow you to load
|
||||
@@ -240,8 +251,9 @@ influence this either globally (using the `--cpp-ptr-type` argument to
|
||||
`flatc`) or per field (using the `cpp_ptr_type` attribute) to by any smart
|
||||
pointer type (`my_ptr<T>`), or by specifying `naked` as the type to get `T *`
|
||||
pointers. Unlike the smart pointers, naked pointers do not manage memory for
|
||||
you, so you'll have to manage their lifecycles manually.
|
||||
|
||||
you, so you'll have to manage their lifecycles manually. To reference the
|
||||
pointer type specified by the `--cpp-ptr-type` argument to `flatc` from a
|
||||
flatbuffer field set the `cpp_ptr_type` attribute to `default_ptr_type`.
|
||||
|
||||
# Using different string type.
|
||||
|
||||
@@ -249,7 +261,18 @@ By default the object tree is built out of `std::string`, but you can
|
||||
influence this either globally (using the `--cpp-str-type` argument to
|
||||
`flatc`) or per field using the `cpp_str_type` attribute.
|
||||
|
||||
The type must support T::c_str() and T::length() as member functions.
|
||||
The type must support T::c_str(), T::length() and T::empty() as member functions.
|
||||
|
||||
Further, the type must be constructible from std::string, as by default a
|
||||
std::string instance is constructed and then used to initialize the custom
|
||||
string type. This behavior impedes efficient and zero-copy construction of
|
||||
custom string types; the `--cpp-str-flex-ctor` argument to `flatc` or the
|
||||
per field attribute `cpp_str_flex_ctor` can be used to change this behavior,
|
||||
so that the custom string type is constructed by passing the pointer and
|
||||
length of the FlatBuffers String. The custom string class will require a
|
||||
constructor in the following format: custom_str_class(const char *, size_t).
|
||||
Please note that the character array is not guaranteed to be NULL terminated,
|
||||
you should always use the provided size to determine end of string.
|
||||
|
||||
## Reflection (& Resizing)
|
||||
|
||||
@@ -495,4 +518,49 @@ needed to use unions.
|
||||
|
||||
To use scalars, simply wrap them in a struct.
|
||||
|
||||
## Depth limit of nested objects and stack-overflow control
|
||||
The parser of Flatbuffers schema or json-files is kind of recursive parser.
|
||||
To avoid stack-overflow problem the parser has a built-in limiter of
|
||||
recursion depth. Number of nested declarations in a schema or number of
|
||||
nested json-objects is limited. By default, this depth limit set to `64`.
|
||||
It is possible to override this limit with `FLATBUFFERS_MAX_PARSING_DEPTH`
|
||||
definition. This definition can be helpful for testing purposes or embedded
|
||||
applications. For details see [build](@ref flatbuffers_guide_building) of
|
||||
CMake-based projects.
|
||||
|
||||
## Dependence from C-locale {#flatbuffers_locale_cpp}
|
||||
The Flatbuffers [grammar](@ref flatbuffers grammar) uses ASCII
|
||||
character set for identifiers, alphanumeric literals, reserved words.
|
||||
|
||||
Internal implementation of the Flatbuffers depends from functions which
|
||||
depend from C-locale: `strtod()` or `strtof()`, for example.
|
||||
The library expects the dot `.` symbol as the separator of an integer
|
||||
part from the fractional part of a float number.
|
||||
Another separator symbols (`,` for example) will break the compatibility
|
||||
and may lead to an error while parsing a Flatbuffers schema or a json file.
|
||||
|
||||
The Standard C locale is a global resource, there is only one locale for
|
||||
the entire application. Some modern compilers and platforms have
|
||||
locale-independent or locale-narrow functions `strtof_l`, `strtod_l`,
|
||||
`strtoll_l`, `strtoull_l` to resolve this dependency.
|
||||
These functions use specified locale rather than the global or per-thread
|
||||
locale instead. They are part of POSIX-2008 but not part of the C/C++
|
||||
standard library, therefore, may be missing on some platforms.
|
||||
|
||||
The Flatbuffers library try to detect these functions at configuration and
|
||||
compile time:
|
||||
- `_MSC_VER >= 1900`: check MSVC2012 or higher for MSVC buid
|
||||
- `_XOPEN_SOURCE>=700`: check POSIX-2008 for GCC/Clang build
|
||||
- `check_cxx_symbol_exists(strtof_l stdlib.h)`: CMake check of `strtod_f`
|
||||
|
||||
After detection, the definition `FLATBUFFERS_LOCALE_INDEPENDENT` will be
|
||||
set to `0` or `1`.
|
||||
|
||||
It is possible to test the compatibility of the Flatbuffers library with
|
||||
a specific locale using the environment variable `FLATBUFFERS_TEST_LOCALE`:
|
||||
```sh
|
||||
>FLATBUFFERS_TEST_LOCALE="" ./flattests
|
||||
>FLATBUFFERS_TEST_LOCALE="ru_RU.CP1251" ./flattests
|
||||
```
|
||||
|
||||
<br>
|
||||
|
||||
@@ -16,7 +16,7 @@ documentation to build `flatc` and should be familiar with
|
||||
|
||||
## FlatBuffers Dart library code location
|
||||
|
||||
The code for the FlatBuffers Go library can be found at
|
||||
The code for the FlatBuffers Dart 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).
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ attribute\_decl = `attribute` ident | `"`ident`"` `;`
|
||||
|
||||
type\_decl = ( `table` | `struct` ) ident metadata `{` field\_decl+ `}`
|
||||
|
||||
enum\_decl = ( `enum` ident [ `:` type ] | `union` ident ) metadata `{`
|
||||
enum\_decl = ( `enum` ident `:` type | `union` ident ) metadata `{`
|
||||
commasep( enumval\_decl ) `}`
|
||||
|
||||
root\_decl = `root_type` ident `;`
|
||||
@@ -49,11 +49,26 @@ file_extension_decl = `file_extension` string\_constant `;`
|
||||
|
||||
file_identifier_decl = `file_identifier` string\_constant `;`
|
||||
|
||||
integer\_constant = `-?[0-9]+` | `true` | `false`
|
||||
|
||||
float\_constant = `-?[0-9]+.[0-9]+((e|E)(+|-)?[0-9]+)?`
|
||||
|
||||
string\_constant = `\".*?\"`
|
||||
|
||||
ident = `[a-zA-Z_][a-zA-Z0-9_]*`
|
||||
|
||||
`[:digit:]` = `[0-9]`
|
||||
|
||||
`[:xdigit:]` = `[0-9a-fA-F]`
|
||||
|
||||
dec\_integer\_constant = `[-+]?[:digit:]+`
|
||||
|
||||
hex\_integer\_constant = `[-+]?0[xX][:xdigit:]+`
|
||||
|
||||
integer\_constant = dec\_integer\_constant | hex\_integer\_constant
|
||||
|
||||
dec\_float\_constant = `[-+]?(([.][:digit:]+)|([:digit:]+[.][:digit:]*)|([:digit:]+))([eE][-+]?[:digit:]+)?`
|
||||
|
||||
hex\_float\_constant = `[-+]?0[xX](([.][:xdigit:]+)|([:xdigit:]+[.][:xdigit:]*)|([:xdigit:]+))([pP][-+]?[:digit:]+)`
|
||||
|
||||
special\_float\_constant = `[-+]?(nan|inf|infinity)`
|
||||
|
||||
float\_constant = decimal\_float\_constant | hexadecimal\_float\_constant | special\_float\_constant
|
||||
|
||||
boolean\_constant = `(true|false)` | (integer\_constant ? `true` : `false`)
|
||||
|
||||
@@ -18,7 +18,8 @@ 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
|
||||
compiler (e.g. `flatc --rust mygame.fbs` or via helpers listed in "Useful
|
||||
tools created by others" section bellow), 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`.
|
||||
|
||||
@@ -67,6 +68,7 @@ It can be run by `cd`ing to the `rust_usage_test` directory and executing: `carg
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.rs}
|
||||
extern crate flatbuffers;
|
||||
|
||||
#[allow(dead_code, unused_imports)]
|
||||
#[path = "../../monster_test_generated.rs"]
|
||||
mod monster_test_generated;
|
||||
pub use monster_test_generated::my_game;
|
||||
@@ -163,4 +165,10 @@ 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.
|
||||
|
||||
## Useful tools created by others
|
||||
|
||||
* [flatc-rust](https://github.com/frol/flatc-rust) - FlatBuffers compiler
|
||||
(flatc) as API for transparent `.fbs` to `.rs` code-generation via Cargo
|
||||
build scripts integration.
|
||||
|
||||
<br>
|
||||
|
||||
@@ -84,7 +84,7 @@ parent object, and use no virtual table).
|
||||
|
||||
### Types
|
||||
|
||||
Built-in scalar types are
|
||||
Built-in scalar types are
|
||||
|
||||
- 8 bit: `byte` (`int8`), `ubyte` (`uint8`), `bool`
|
||||
|
||||
@@ -141,6 +141,9 @@ is `0`. As you can see in the enum declaration, you specify the underlying
|
||||
integral type of the enum with `:` (in this case `byte`), which then determines
|
||||
the type of any fields declared with this enum type.
|
||||
|
||||
Only integer types are allowed, i.e. `byte`, `ubyte`, `short` `ushort`, `int`,
|
||||
`uint`, `long` and `ulong`.
|
||||
|
||||
Typically, enum values should only ever be added, never removed (there is no
|
||||
deprecation for enums). This requires code to handle forwards compatibility
|
||||
itself, by handling unknown enum values.
|
||||
@@ -150,9 +153,23 @@ itself, by handling unknown enum values.
|
||||
Unions share a lot of properties with enums, but instead of new names
|
||||
for constants, you use names of tables. You can then declare
|
||||
a union field, which can hold a reference to any of those types, and
|
||||
additionally a hidden field with the suffix `_type` is generated that
|
||||
holds the corresponding enum value, allowing you to know which type to
|
||||
cast to at runtime.
|
||||
additionally a field with the suffix `_type` is generated that holds
|
||||
the corresponding enum value, allowing you to know which type to cast
|
||||
to at runtime.
|
||||
|
||||
It's possible to give an alias name to a type union. This way a type can even be
|
||||
used to mean different things depending on the name used:
|
||||
|
||||
table PointPosition { x:uint; y:uint; }
|
||||
table MarkerPosition {}
|
||||
union Position {
|
||||
Start:MarkerPosition,
|
||||
Point:PointPosition,
|
||||
Finish:MarkerPosition
|
||||
}
|
||||
|
||||
Unions contain a special `NONE` marker to denote that no value is stored so that
|
||||
name cannot be used as an alias.
|
||||
|
||||
Unions are a good way to be able to send multiple message types as a FlatBuffer.
|
||||
Note that because a union field is really two fields, it must always be
|
||||
@@ -304,8 +321,11 @@ Current understood attributes:
|
||||
these structs to be aligned to that amount inside a buffer, IF that
|
||||
buffer is allocated with that alignment (which is not necessarily
|
||||
the case for buffers accessed directly inside a `FlatBufferBuilder`).
|
||||
- `bit_flags` (on an enum): the values of this field indicate bits,
|
||||
meaning that any value N specified in the schema will end up
|
||||
Note: currently not guaranteed to have an effect when used with
|
||||
`--object-api`, since that may allocate objects at alignments less than
|
||||
what you specify with `force_align`.
|
||||
- `bit_flags` (on an unsigned enum): the values of this field indicate bits,
|
||||
meaning that any unsigned value N specified in the schema will end up
|
||||
representing 1<<N, or if you don't specify values at all, you'll get
|
||||
the sequence 1, 2, 4, 8, ...
|
||||
- `nested_flatbuffer: "table_name"` (on a field): this indicates that the field
|
||||
@@ -385,6 +405,31 @@ When parsing JSON, it recognizes the following escape codes in strings:
|
||||
It also generates these escape codes back again when generating JSON from a
|
||||
binary representation.
|
||||
|
||||
When parsing numbers, the parser is more flexible than JSON.
|
||||
A format of numeric literals is more close to the C/C++.
|
||||
According to the [grammar](@ref flatbuffers_grammar), it accepts the following
|
||||
numerical literals:
|
||||
|
||||
- An integer literal can have any number of leading zero `0` digits.
|
||||
Unlike C/C++, the parser ignores a leading zero, not interpreting it as the
|
||||
beginning of the octal number.
|
||||
The numbers `[081, -00094]` are equal to `[81, -94]` decimal integers.
|
||||
- The parser accepts unsigned and signed hexadecimal integer numbers.
|
||||
For example: `[0x123, +0x45, -0x67]` are equal to `[291, 69, -103]` decimals.
|
||||
- The format of float-point numbers is fully compatible with C/C++ format.
|
||||
If a modern C++ compiler is used the parser accepts hexadecimal and special
|
||||
float-point literals as well:
|
||||
`[-1.0, 2., .3e0, 3.e4, 0x21.34p-5, -inf, nan]`.
|
||||
The exponent suffix of hexadecimal float-point number is mandatory.
|
||||
|
||||
Extended float-point support was tested with:
|
||||
- x64 Windows: `MSVC2015` and higher.
|
||||
- x64 Linux: `LLVM 6.0`, `GCC 4.9` and higher.
|
||||
|
||||
- For compatibility with a JSON lint tool all numeric literals of scalar
|
||||
fields can be wrapped to quoted string:
|
||||
`"1", "2.0", "0x48A", "0x0C.0Ep-1", "-inf", "true"`.
|
||||
|
||||
## Guidelines
|
||||
|
||||
### Efficiency
|
||||
|
||||
@@ -274,43 +274,43 @@ Please be aware of the difference between `flatc` and `flatcc` tools.
|
||||
|
||||
<div class="language-cpp">
|
||||
~~~{.sh}
|
||||
cd flatbuffers/sample
|
||||
cd flatbuffers/samples
|
||||
./../flatc --cpp monster.fbs
|
||||
~~~
|
||||
</div>
|
||||
<div class="language-java">
|
||||
~~~{.sh}
|
||||
cd flatbuffers/sample
|
||||
cd flatbuffers/samples
|
||||
./../flatc --java monster.fbs
|
||||
~~~
|
||||
</div>
|
||||
<div class="language-csharp">
|
||||
~~~{.sh}
|
||||
cd flatbuffers/sample
|
||||
cd flatbuffers/samples
|
||||
./../flatc --csharp monster.fbs
|
||||
~~~
|
||||
</div>
|
||||
<div class="language-go">
|
||||
~~~{.sh}
|
||||
cd flatbuffers/sample
|
||||
cd flatbuffers/samples
|
||||
./../flatc --go monster.fbs
|
||||
~~~
|
||||
</div>
|
||||
<div class="language-python">
|
||||
~~~{.sh}
|
||||
cd flatbuffers/sample
|
||||
cd flatbuffers/samples
|
||||
./../flatc --python monster.fbs
|
||||
~~~
|
||||
</div>
|
||||
<div class="language-javascript">
|
||||
~~~{.sh}
|
||||
cd flatbuffers/sample
|
||||
cd flatbuffers/samples
|
||||
./../flatc --js monster.fbs
|
||||
~~~
|
||||
</div>
|
||||
<div class="language-typescript">
|
||||
~~~{.sh}
|
||||
cd flatbuffers/sample
|
||||
cd flatbuffers/samples
|
||||
./../flatc --ts monster.fbs
|
||||
~~~
|
||||
</div>
|
||||
@@ -331,25 +331,25 @@ Please be aware of the difference between `flatc` and `flatcc` tools.
|
||||
</div>
|
||||
<div class="language-dart">
|
||||
~~~{.sh}
|
||||
cd flatbuffers/sample
|
||||
cd flatbuffers/samples
|
||||
./../flatc --dart monster.fbs
|
||||
~~~
|
||||
</div>
|
||||
<div class="language-lua">
|
||||
~~~{.sh}
|
||||
cd flatbuffers/sample
|
||||
cd flatbuffers/samples
|
||||
./../flatc --lua monster.fbs
|
||||
~~~
|
||||
</div>
|
||||
<div class="language-lobster">
|
||||
~~~{.sh}
|
||||
cd flatbuffers/sample
|
||||
cd flatbuffers/samples
|
||||
./../flatc --lobster monster.fbs
|
||||
~~~
|
||||
</div>
|
||||
<div class="language-rust">
|
||||
~~~{.sh}
|
||||
cd flatbuffers/sample
|
||||
cd flatbuffers/samples
|
||||
./../flatc --rust monster.fbs
|
||||
~~~
|
||||
</div>
|
||||
@@ -370,7 +370,7 @@ The first step is to import/include the library, generated files, etc.
|
||||
|
||||
<div class="language-cpp">
|
||||
~~~{.cpp}
|
||||
#include "monster_generate.h" // This was generated by `flatc`.
|
||||
#include "monster_generated.h" // This was generated by `flatc`.
|
||||
|
||||
using namespace MyGame::Sample; // Specified in the schema.
|
||||
~~~
|
||||
@@ -495,6 +495,7 @@ The first step is to import/include the library, generated files, etc.
|
||||
extern crate flatbuffers;
|
||||
|
||||
// import the generated code
|
||||
#[allow(dead_code, unused_imports)]
|
||||
#[path = "./monster_generated.rs"]
|
||||
mod monster_generated;
|
||||
pub use monster_generated::my_game::sample::{get_root_as_monster,
|
||||
@@ -652,14 +653,14 @@ our `orc` Monster, lets create some `Weapon`s: a `Sword` and an `Axe`.
|
||||
|
||||
// Create the first `Weapon` ("Sword").
|
||||
sample.WeaponStart(builder)
|
||||
sample.Weapon.AddName(builder, weaponOne)
|
||||
sample.Weapon.AddDamage(builder, 3)
|
||||
sample.WeaponAddName(builder, weaponOne)
|
||||
sample.WeaponAddDamage(builder, 3)
|
||||
sword := sample.WeaponEnd(builder)
|
||||
|
||||
// Create the second `Weapon` ("Axe").
|
||||
sample.WeaponStart(builder)
|
||||
sample.Weapon.AddName(builder, weaponTwo)
|
||||
sample.Weapon.AddDamage(builder, 5)
|
||||
sample.WeaponAddName(builder, weaponTwo)
|
||||
sample.WeaponAddDamage(builder, 5)
|
||||
axe := sample.WeaponEnd(builder)
|
||||
~~~
|
||||
</div>
|
||||
@@ -734,10 +735,10 @@ our `orc` Monster, lets create some `Weapon`s: a `Sword` and an `Axe`.
|
||||
</div>
|
||||
<div class="language-c">
|
||||
~~~{.c}
|
||||
ns(Weapon_ref_t) weapon_one_name = flatbuffers_string_create_str(B, "Sword");
|
||||
flatbuffers_string_ref_t weapon_one_name = flatbuffers_string_create_str(B, "Sword");
|
||||
uint16_t weapon_one_damage = 3;
|
||||
|
||||
ns(Weapon_ref_t) weapon_two_name = flatbuffers_string_create_str(B, "Axe");
|
||||
flatbuffers_string_ref_t weapon_two_name = flatbuffers_string_create_str(B, "Axe");
|
||||
uint16_t weapon_two_damage = 5;
|
||||
|
||||
ns(Weapon_ref_t) sword = ns(Weapon_create(B, weapon_one_name, weapon_one_damage));
|
||||
@@ -767,7 +768,7 @@ our `orc` Monster, lets create some `Weapon`s: a `Sword` and an `Axe`.
|
||||
|
||||
|
||||
|
||||
// The genearted ObjectBuilder classes offer an easier to use alternative
|
||||
// The generated ObjectBuilder classes offer an easier to use alternative
|
||||
// at the cost of requiring some additional reference allocations. If memory
|
||||
// usage is critical, or if you'll be working with especially large messages
|
||||
// or tables, you should prefer using the generated Builder classes.
|
||||
@@ -1238,7 +1239,7 @@ for the `path` field above:
|
||||
final vec3Builder = new myGame.Vec3Builder(builder);
|
||||
vec3Builder.finish(4.0, 5.0, 6.0);
|
||||
vec3Builder.finish(1.0, 2.0, 3.0);
|
||||
final int path = builder.endStructVector(2); // the lenght of the vector
|
||||
final int path = builder.endStructVector(2); // the length of the vector
|
||||
|
||||
// Otherwise, using the ObjectBuilder classes:
|
||||
// The dart implementation provides a simple interface for writing vectors
|
||||
@@ -1520,7 +1521,7 @@ can serialize the monster itself:
|
||||
// Create the monster using the `Monster::create` helper function. This
|
||||
// function accepts a `MonsterArgs` struct, which supplies all of the data
|
||||
// needed to build a `Monster`. To supply empty/default fields, just use the
|
||||
// Rust built-in `Default::default()` function, as demononstrated below.
|
||||
// Rust built-in `Default::default()` function, as demonstrated below.
|
||||
let orc = Monster::create(&mut builder, &MonsterArgs{
|
||||
pos: Some(&Vec3::new(1.0f32, 2.0f32, 3.0f32)),
|
||||
mana: 150,
|
||||
@@ -1663,7 +1664,7 @@ Here is a repetition these lines, to help highlight them more clearly:
|
||||
</div>
|
||||
<div class="language-c">
|
||||
~~~{.c}
|
||||
// Add union type and data simultanously.
|
||||
// Add union type and data simultaneously.
|
||||
ns(Monster_equipped_Weapon_add(B, axe));
|
||||
~~~
|
||||
</div>
|
||||
@@ -1906,7 +1907,7 @@ like so:
|
||||
|
||||
|
||||
Now you can write the bytes to a file, send them over the network..
|
||||
**Make sure your file mode (or tranfer protocol) is set to BINARY, not text.**
|
||||
**Make sure your file mode (or transfer protocol) is set to BINARY, not text.**
|
||||
If you transfer a FlatBuffer in text mode, the buffer will be corrupted,
|
||||
which will lead to hard to find problems when you read the buffer.
|
||||
|
||||
@@ -1921,7 +1922,7 @@ before:
|
||||
|
||||
<div class="language-cpp">
|
||||
~~~{.cpp}
|
||||
#include "monster_generate.h" // This was generated by `flatc`.
|
||||
#include "monster_generated.h" // This was generated by `flatc`.
|
||||
|
||||
using namespace MyGame::Sample; // Specified in the schema.
|
||||
~~~
|
||||
@@ -2042,6 +2043,7 @@ import './monster_my_game.sample_generated.dart' as myGame;
|
||||
extern crate flatbuffers;
|
||||
|
||||
// import the generated code
|
||||
#[allow(dead_code, unused_imports)]
|
||||
#[path = "./monster_generated.rs"]
|
||||
mod monster_generated;
|
||||
pub use monster_generated::my_game::sample::{get_root_as_monster,
|
||||
@@ -2207,7 +2209,7 @@ accessors for all non-`deprecated` fields. For example:
|
||||
<div class="language-csharp">
|
||||
~~~{.cs}
|
||||
// For C#, unlike most other languages support by FlatBuffers, most values (except for
|
||||
// vectors and unions) are available as propreties instead of asccessor methods.
|
||||
// vectors and unions) are available as properties instead of accessor methods.
|
||||
var hp = monster.Hp
|
||||
var mana = monster.Mana
|
||||
var name = monster.Name
|
||||
@@ -2258,7 +2260,7 @@ accessors for all non-`deprecated` fields. For example:
|
||||
<div class="language-dart">
|
||||
~~~{.dart}
|
||||
// For Dart, unlike other languages support by FlatBuffers, most values
|
||||
// are available as propreties instead of asccessor methods.
|
||||
// are available as properties instead of accessor methods.
|
||||
var hp = monster.hp;
|
||||
var mana = monster.mana;
|
||||
var name = monster.name;
|
||||
|
||||
@@ -17,7 +17,7 @@ documentation to build `flatc` and should be familiar with
|
||||
## FlatBuffers TypeScript library code location
|
||||
|
||||
The code for the FlatBuffers TypeScript library can be found at
|
||||
`flatbuffers/js` with typings available at @types/flatubffers.
|
||||
`flatbuffers/js` with typings available at `@types/flatbuffers`.
|
||||
|
||||
## Testing the FlatBuffers TypeScript library
|
||||
|
||||
|
||||
@@ -45,6 +45,8 @@
|
||||
title="Use in Lua"/>
|
||||
<tab type="user" url="@ref flatbuffers_guide_use_lobster"
|
||||
title="Use in Lobster"/>
|
||||
<tab type="user" url="@ref flatbuffers_guide_use_rust"
|
||||
title="Use in Rust"/>
|
||||
<tab type="user" url="@ref flexbuffers"
|
||||
title="Schema-less version"/>
|
||||
<tab type="usergroup" url="" title="gRPC">
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<groupId>com.google.flatbuffers</groupId>
|
||||
<artifactId>flatbuffers-parent</artifactId>
|
||||
<version>1.10.0</version>
|
||||
<version>1.11.0</version>
|
||||
</parent>
|
||||
<artifactId>flatbuffers-java-grpc</artifactId>
|
||||
<name>${project.artifactId}</name>
|
||||
@@ -24,7 +24,7 @@
|
||||
</developer>
|
||||
</developers>
|
||||
<properties>
|
||||
<gRPC.version>1.9.0</gRPC.version>
|
||||
<gRPC.version>1.11.0</gRPC.version>
|
||||
</properties>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<groupId>com.google.flatbuffers</groupId>
|
||||
<artifactId>flatbuffers-parent</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
<version>1.10.0</version>
|
||||
<version>1.11.0</version>
|
||||
<name>flatbuffers-parent</name>
|
||||
<description>parent pom for flatbuffers java artifacts</description>
|
||||
<properties>
|
||||
|
||||
@@ -84,7 +84,7 @@ void GenerateImports(grpc_generator::File *file, grpc_generator::Printer *printe
|
||||
}
|
||||
printer->Print("import (\n");
|
||||
printer->Indent();
|
||||
printer->Print(vars, "$context$ \"golang.org/x/net/context\"\n");
|
||||
printer->Print(vars, "$context$ \"context\"\n");
|
||||
printer->Print(vars, "$grpc$ \"google.golang.org/grpc\"\n");
|
||||
printer->Outdent();
|
||||
printer->Print(")\n\n");
|
||||
|
||||
@@ -37,9 +37,6 @@
|
||||
#define XSTR(s) STR(s)
|
||||
#endif
|
||||
|
||||
#ifndef FALLTHROUGH_INTENDED
|
||||
#define FALLTHROUGH_INTENDED
|
||||
#endif
|
||||
|
||||
typedef grpc_generator::Printer Printer;
|
||||
typedef std::map<grpc::string, grpc::string> VARS;
|
||||
@@ -72,13 +69,14 @@ void GenerateImports(grpc_generator::File* file,
|
||||
// - remove embedded underscores & capitalize the following letter
|
||||
static string MixedLower(const string& word) {
|
||||
string w;
|
||||
w += (string::value_type)tolower(word[0]);
|
||||
w += static_cast<string::value_type>(tolower(word[0]));
|
||||
bool after_underscore = false;
|
||||
for (size_t i = 1; i < word.length(); ++i) {
|
||||
if (word[i] == '_') {
|
||||
after_underscore = true;
|
||||
} else {
|
||||
w += after_underscore ? (string::value_type)toupper(word[i]) : word[i];
|
||||
w += after_underscore ? static_cast<string::value_type>(toupper(word[i]))
|
||||
: word[i];
|
||||
after_underscore = false;
|
||||
}
|
||||
}
|
||||
@@ -92,7 +90,7 @@ static string MixedLower(const string& word) {
|
||||
static string ToAllUpperCase(const string& word) {
|
||||
string w;
|
||||
for (size_t i = 0; i < word.length(); ++i) {
|
||||
w += (string::value_type)toupper(word[i]);
|
||||
w += static_cast<string::value_type>(toupper(word[i]));
|
||||
if ((i < word.length() - 1) && islower(word[i]) && isupper(word[i + 1])) {
|
||||
w += '_';
|
||||
}
|
||||
@@ -345,8 +343,8 @@ static void PrintMethodFields(Printer* p, VARS& vars,
|
||||
|
||||
for (int i = 0; i < service->method_count(); ++i) {
|
||||
auto method = service->method(i);
|
||||
vars["arg_in_id"] = to_string((long)2 * i); //trying to make msvc 10 happy
|
||||
vars["arg_out_id"] = to_string((long)2 * i + 1);
|
||||
vars["arg_in_id"] = to_string(2L * i); //trying to make msvc 10 happy
|
||||
vars["arg_out_id"] = to_string(2L * i + 1);
|
||||
vars["method_name"] = method->name();
|
||||
vars["input_type_name"] = method->get_input_type_name();
|
||||
vars["output_type_name"] = method->get_output_type_name();
|
||||
@@ -355,8 +353,8 @@ static void PrintMethodFields(Printer* p, VARS& vars,
|
||||
vars["method_field_name"] = MethodPropertiesFieldName(method.get());
|
||||
vars["method_new_field_name"] = MethodPropertiesGetterName(method.get());
|
||||
vars["method_method_name"] = MethodPropertiesGetterName(method.get());
|
||||
bool client_streaming = method->ClientStreaming();
|
||||
bool server_streaming = method->ServerStreaming();
|
||||
bool client_streaming = method->ClientStreaming() || method->BidiStreaming();
|
||||
bool server_streaming = method->ServerStreaming() || method->BidiStreaming();
|
||||
if (client_streaming) {
|
||||
if (server_streaming) {
|
||||
vars["method_type"] = "BIDI_STREAMING";
|
||||
@@ -478,7 +476,7 @@ static void PrintStub(Printer* p, VARS& vars, const ServiceDescriptor* service,
|
||||
break;
|
||||
case BLOCKING_CLIENT_INTERFACE:
|
||||
interface = true;
|
||||
FALLTHROUGH_INTENDED; // fallthrough
|
||||
FLATBUFFERS_FALLTHROUGH(); // fall thru
|
||||
case BLOCKING_CLIENT_IMPL:
|
||||
call_type = BLOCKING_CALL;
|
||||
stub_name += "BlockingStub";
|
||||
@@ -486,7 +484,7 @@ static void PrintStub(Printer* p, VARS& vars, const ServiceDescriptor* service,
|
||||
break;
|
||||
case FUTURE_CLIENT_INTERFACE:
|
||||
interface = true;
|
||||
FALLTHROUGH_INTENDED; // fallthrough
|
||||
FLATBUFFERS_FALLTHROUGH(); // fall thru
|
||||
case FUTURE_CLIENT_IMPL:
|
||||
call_type = FUTURE_CALL;
|
||||
stub_name += "FutureStub";
|
||||
@@ -548,8 +546,8 @@ static void PrintStub(Printer* p, VARS& vars, const ServiceDescriptor* service,
|
||||
vars["output_type"] = JavaClassName(vars, method->get_output_type_name());
|
||||
vars["lower_method_name"] = LowerMethodName(&*method);
|
||||
vars["method_method_name"] = MethodPropertiesGetterName(&*method);
|
||||
bool client_streaming = method->ClientStreaming();
|
||||
bool server_streaming = method->ServerStreaming();
|
||||
bool client_streaming = method->ClientStreaming() || method->BidiStreaming();
|
||||
bool server_streaming = method->ServerStreaming() || method->BidiStreaming();
|
||||
|
||||
if (call_type == BLOCKING_CALL && client_streaming) {
|
||||
// Blocking client interface with client streaming is not available
|
||||
@@ -759,7 +757,7 @@ static void PrintMethodHandlerClass(Printer* p, VARS& vars,
|
||||
|
||||
for (int i = 0; i < service->method_count(); ++i) {
|
||||
auto method = service->method(i);
|
||||
if (method->ClientStreaming()) {
|
||||
if (method->ClientStreaming() || method->BidiStreaming()) {
|
||||
continue;
|
||||
}
|
||||
vars["method_id_name"] = MethodIdFieldName(&*method);
|
||||
@@ -793,7 +791,7 @@ static void PrintMethodHandlerClass(Printer* p, VARS& vars,
|
||||
|
||||
for (int i = 0; i < service->method_count(); ++i) {
|
||||
auto method = service->method(i);
|
||||
if (!method->ClientStreaming()) {
|
||||
if (!(method->ClientStreaming() || method->BidiStreaming())) {
|
||||
continue;
|
||||
}
|
||||
vars["method_id_name"] = MethodIdFieldName(&*method);
|
||||
@@ -929,8 +927,8 @@ static void PrintBindServiceMethodBody(Printer* p, VARS& vars,
|
||||
vars["input_type"] = JavaClassName(vars, method->get_input_type_name());
|
||||
vars["output_type"] = JavaClassName(vars, method->get_output_type_name());
|
||||
vars["method_id_name"] = MethodIdFieldName(&*method);
|
||||
bool client_streaming = method->ClientStreaming();
|
||||
bool server_streaming = method->ServerStreaming();
|
||||
bool client_streaming = method->ClientStreaming() || method->BidiStreaming();
|
||||
bool server_streaming = method->ServerStreaming() || method->BidiStreaming();
|
||||
if (client_streaming) {
|
||||
if (server_streaming) {
|
||||
vars["calls_method"] = "asyncBidiStreamingCall";
|
||||
|
||||
42
grpc/tests/GameFactory.java
Normal file
42
grpc/tests/GameFactory.java
Normal file
@@ -0,0 +1,42 @@
|
||||
import java.nio.ByteBuffer;
|
||||
import MyGame.Example.Monster;
|
||||
import MyGame.Example.Stat;
|
||||
import com.google.flatbuffers.FlatBufferBuilder;
|
||||
|
||||
class GameFactory {
|
||||
public static Monster createMonster(String monsterName, short nestedMonsterHp, short nestedMonsterMana) {
|
||||
FlatBufferBuilder builder = new FlatBufferBuilder();
|
||||
|
||||
int name_offset = builder.createString(monsterName);
|
||||
Monster.startMonster(builder);
|
||||
Monster.addName(builder, name_offset);
|
||||
Monster.addHp(builder, nestedMonsterHp);
|
||||
Monster.addMana(builder, nestedMonsterMana);
|
||||
int monster_offset = Monster.endMonster(builder);
|
||||
Monster.finishMonsterBuffer(builder, monster_offset);
|
||||
|
||||
ByteBuffer buffer = builder.dataBuffer();
|
||||
Monster monster = Monster.getRootAsMonster(buffer);
|
||||
return monster;
|
||||
}
|
||||
|
||||
public static Monster createMonsterFromStat(Stat stat, int seqNo) {
|
||||
FlatBufferBuilder builder = new FlatBufferBuilder();
|
||||
int name_offset = builder.createString(stat.id() + " No." + seqNo);
|
||||
Monster.startMonster(builder);
|
||||
Monster.addName(builder, name_offset);
|
||||
int monster_offset = Monster.endMonster(builder);
|
||||
Monster.finishMonsterBuffer(builder, monster_offset);
|
||||
Monster monster = Monster.getRootAsMonster(builder.dataBuffer());
|
||||
return monster;
|
||||
}
|
||||
|
||||
public static Stat createStat(String greeting, long val, int count) {
|
||||
FlatBufferBuilder builder = new FlatBufferBuilder();
|
||||
int statOffset = Stat.createStat(builder, builder.createString(greeting), val, count);
|
||||
builder.finish(statOffset);
|
||||
Stat stat = Stat.getRootAsStat(builder.dataBuffer());
|
||||
return stat;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -22,21 +22,32 @@ import io.grpc.ManagedChannel;
|
||||
import io.grpc.ManagedChannelBuilder;
|
||||
import io.grpc.Server;
|
||||
import io.grpc.ServerBuilder;
|
||||
import io.grpc.stub.StreamObserver;
|
||||
import org.junit.Assert;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.InterruptedException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Iterator;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
|
||||
|
||||
/**
|
||||
* Demonstrates basic client-server interaction using grpc-java over netty.
|
||||
*/
|
||||
public class JavaGrpcTest {
|
||||
static final String BIG_MONSTER_NAME = "big-monster";
|
||||
static final String BIG_MONSTER_NAME = "Cyberdemon";
|
||||
static final short nestedMonsterHp = 600;
|
||||
static final short nestedMonsterMana = 1024;
|
||||
static final int numStreamedMsgs = 10;
|
||||
static final int timeoutMs = 3000;
|
||||
static Server server;
|
||||
static ManagedChannel channel;
|
||||
static MonsterStorageGrpc.MonsterStorageBlockingStub blockingStub;
|
||||
static MonsterStorageGrpc.MonsterStorageStub asyncStub;
|
||||
|
||||
static class MyService extends MonsterStorageGrpc.MonsterStorageImplBase {
|
||||
@Override
|
||||
@@ -46,10 +57,7 @@ public class JavaGrpcTest {
|
||||
Assert.assertEquals(request.mana(), nestedMonsterMana);
|
||||
System.out.println("Received store request from " + request.name());
|
||||
// Create a response from the incoming request name.
|
||||
FlatBufferBuilder builder = new FlatBufferBuilder();
|
||||
int statOffset = Stat.createStat(builder, builder.createString("Hello " + request.name()), 100, 10);
|
||||
builder.finish(statOffset);
|
||||
Stat stat = Stat.getRootAsStat(builder.dataBuffer());
|
||||
Stat stat = GameFactory.createStat("Hello " + request.name(), 100, 10);
|
||||
responseObserver.onNext(stat);
|
||||
responseObserver.onCompleted();
|
||||
}
|
||||
@@ -58,55 +66,101 @@ public class JavaGrpcTest {
|
||||
public void retrieve(Stat request, io.grpc.stub.StreamObserver<Monster> responseObserver) {
|
||||
// Create 10 monsters for streaming response.
|
||||
for (int i=0; i<numStreamedMsgs; i++) {
|
||||
FlatBufferBuilder builder = new FlatBufferBuilder();
|
||||
int i1 = builder.createString(request.id() + " No." + i);
|
||||
Monster.startMonster(builder);
|
||||
Monster.addName(builder, i1);
|
||||
int i2 = Monster.endMonster(builder);
|
||||
Monster.finishMonsterBuffer(builder, i2);
|
||||
Monster monster = Monster.getRootAsMonster(builder.dataBuffer());
|
||||
Monster monster = GameFactory.createMonsterFromStat(request, i);
|
||||
responseObserver.onNext(monster);
|
||||
}
|
||||
responseObserver.onCompleted();
|
||||
}
|
||||
|
||||
@Override
|
||||
public StreamObserver<Monster> getMaxHitPoint(final StreamObserver<Stat> responseObserver) {
|
||||
return computeMinMax(responseObserver, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public StreamObserver<Monster> getMinMaxHitPoints(final StreamObserver<Stat> responseObserver) {
|
||||
return computeMinMax(responseObserver, true);
|
||||
}
|
||||
|
||||
private StreamObserver<Monster> computeMinMax(final StreamObserver<Stat> responseObserver, final boolean includeMin) {
|
||||
final AtomicInteger maxHp = new AtomicInteger(Integer.MIN_VALUE);
|
||||
final AtomicReference<String> maxHpMonsterName = new AtomicReference<String>();
|
||||
final AtomicInteger maxHpCount = new AtomicInteger();
|
||||
|
||||
final AtomicInteger minHp = new AtomicInteger(Integer.MAX_VALUE);
|
||||
final AtomicReference<String> minHpMonsterName = new AtomicReference<String>();
|
||||
final AtomicInteger minHpCount = new AtomicInteger();
|
||||
|
||||
return new StreamObserver<Monster>() {
|
||||
public void onNext(Monster monster) {
|
||||
if (monster.hp() > maxHp.get()) {
|
||||
// Found a monster of higher hit points.
|
||||
maxHp.set(monster.hp());
|
||||
maxHpMonsterName.set(monster.name());
|
||||
maxHpCount.set(1);
|
||||
}
|
||||
else if (monster.hp() == maxHp.get()) {
|
||||
// Count how many times we saw a monster of current max hit points.
|
||||
maxHpCount.getAndIncrement();
|
||||
}
|
||||
|
||||
if (monster.hp() < minHp.get()) {
|
||||
// Found a monster of a lower hit points.
|
||||
minHp.set(monster.hp());
|
||||
minHpMonsterName.set(monster.name());
|
||||
minHpCount.set(1);
|
||||
}
|
||||
else if (monster.hp() == minHp.get()) {
|
||||
// Count how many times we saw a monster of current min hit points.
|
||||
minHpCount.getAndIncrement();
|
||||
}
|
||||
}
|
||||
public void onCompleted() {
|
||||
Stat maxHpStat = GameFactory.createStat(maxHpMonsterName.get(), maxHp.get(), maxHpCount.get());
|
||||
// Send max hit points first.
|
||||
responseObserver.onNext(maxHpStat);
|
||||
if (includeMin) {
|
||||
// Send min hit points.
|
||||
Stat minHpStat = GameFactory.createStat(minHpMonsterName.get(), minHp.get(), minHpCount.get());
|
||||
responseObserver.onNext(minHpStat);
|
||||
}
|
||||
responseObserver.onCompleted();
|
||||
}
|
||||
public void onError(Throwable t) {
|
||||
// Not expected
|
||||
Assert.fail();
|
||||
};
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static int startServer() throws IOException {
|
||||
Server server = ServerBuilder.forPort(0).addService(new MyService()).build().start();
|
||||
return server.getPort();
|
||||
}
|
||||
|
||||
@org.junit.Test
|
||||
public void testMonster() throws IOException {
|
||||
int port = startServer();
|
||||
ManagedChannel channel = ManagedChannelBuilder.forAddress("localhost", port)
|
||||
@org.junit.BeforeClass
|
||||
public static void startServer() throws IOException {
|
||||
server = ServerBuilder.forPort(0).addService(new MyService()).build().start();
|
||||
int port = server.getPort();
|
||||
channel = ManagedChannelBuilder.forAddress("localhost", port)
|
||||
// Channels are secure by default (via SSL/TLS). For the example we disable TLS to avoid
|
||||
// needing certificates.
|
||||
.usePlaintext(true)
|
||||
.directExecutor()
|
||||
.build();
|
||||
blockingStub = MonsterStorageGrpc.newBlockingStub(channel);
|
||||
asyncStub = MonsterStorageGrpc.newStub(channel);
|
||||
}
|
||||
|
||||
MonsterStorageGrpc.MonsterStorageBlockingStub stub = MonsterStorageGrpc.newBlockingStub(channel);
|
||||
|
||||
FlatBufferBuilder builder = new FlatBufferBuilder();
|
||||
|
||||
int o_string = builder.createString(BIG_MONSTER_NAME);
|
||||
Monster.startMonster(builder);
|
||||
Monster.addName(builder, o_string);
|
||||
Monster.addHp(builder, nestedMonsterHp);
|
||||
Monster.addMana(builder, nestedMonsterMana);
|
||||
int monster1 = Monster.endMonster(builder);
|
||||
Monster.finishMonsterBuffer(builder, monster1);
|
||||
|
||||
ByteBuffer buffer = builder.dataBuffer();
|
||||
Monster monsterRequest = Monster.getRootAsMonster(buffer);
|
||||
Stat stat = stub.store(monsterRequest);
|
||||
@org.junit.Test
|
||||
public void testUnary() throws IOException {
|
||||
Monster monsterRequest = GameFactory.createMonster(BIG_MONSTER_NAME, nestedMonsterHp, nestedMonsterMana);
|
||||
Stat stat = blockingStub.store(monsterRequest);
|
||||
Assert.assertEquals(stat.id(), "Hello " + BIG_MONSTER_NAME);
|
||||
System.out.println("Received stat response from service: " + stat.id());
|
||||
}
|
||||
|
||||
|
||||
Iterator<Monster> iterator = stub.retrieve(stat);
|
||||
@org.junit.Test
|
||||
public void testServerStreaming() throws IOException {
|
||||
Monster monsterRequest = GameFactory.createMonster(BIG_MONSTER_NAME, nestedMonsterHp, nestedMonsterMana);
|
||||
Stat stat = blockingStub.store(monsterRequest);
|
||||
Iterator<Monster> iterator = blockingStub.retrieve(stat);
|
||||
int counter = 0;
|
||||
while(iterator.hasNext()) {
|
||||
Monster m = iterator.next();
|
||||
@@ -116,4 +170,73 @@ public class JavaGrpcTest {
|
||||
Assert.assertEquals(counter, numStreamedMsgs);
|
||||
System.out.println("FlatBuffers GRPC client/server test: completed successfully");
|
||||
}
|
||||
|
||||
@org.junit.Test
|
||||
public void testClientStreaming() throws IOException, InterruptedException {
|
||||
final AtomicReference<Stat> maxHitStat = new AtomicReference<Stat>();
|
||||
final CountDownLatch streamAlive = new CountDownLatch(1);
|
||||
|
||||
StreamObserver<Stat> statObserver = new StreamObserver<Stat>() {
|
||||
public void onCompleted() {
|
||||
streamAlive.countDown();
|
||||
}
|
||||
public void onError(Throwable ex) { }
|
||||
public void onNext(Stat stat) {
|
||||
maxHitStat.set(stat);
|
||||
}
|
||||
};
|
||||
StreamObserver<Monster> monsterStream = asyncStub.getMaxHitPoint(statObserver);
|
||||
short count = 10;
|
||||
for (short i = 0;i < count; ++i) {
|
||||
Monster monster = GameFactory.createMonster(BIG_MONSTER_NAME + i, (short) (nestedMonsterHp * i), nestedMonsterMana);
|
||||
monsterStream.onNext(monster);
|
||||
}
|
||||
monsterStream.onCompleted();
|
||||
// Wait a little bit for the server to send the stats of the monster with the max hit-points.
|
||||
streamAlive.await(timeoutMs, TimeUnit.MILLISECONDS);
|
||||
Assert.assertEquals(maxHitStat.get().id(), BIG_MONSTER_NAME + (count - 1));
|
||||
Assert.assertEquals(maxHitStat.get().val(), nestedMonsterHp * (count - 1));
|
||||
Assert.assertEquals(maxHitStat.get().count(), 1);
|
||||
}
|
||||
|
||||
@org.junit.Test
|
||||
public void testBiDiStreaming() throws IOException, InterruptedException {
|
||||
final AtomicReference<Stat> maxHitStat = new AtomicReference<Stat>();
|
||||
final AtomicReference<Stat> minHitStat = new AtomicReference<Stat>();
|
||||
final CountDownLatch streamAlive = new CountDownLatch(1);
|
||||
|
||||
StreamObserver<Stat> statObserver = new StreamObserver<Stat>() {
|
||||
public void onCompleted() {
|
||||
streamAlive.countDown();
|
||||
}
|
||||
public void onError(Throwable ex) { }
|
||||
public void onNext(Stat stat) {
|
||||
// We expect the server to send the max stat first and then the min stat.
|
||||
if (maxHitStat.get() == null) {
|
||||
maxHitStat.set(stat);
|
||||
}
|
||||
else {
|
||||
minHitStat.set(stat);
|
||||
}
|
||||
}
|
||||
};
|
||||
StreamObserver<Monster> monsterStream = asyncStub.getMinMaxHitPoints(statObserver);
|
||||
short count = 10;
|
||||
for (short i = 0;i < count; ++i) {
|
||||
Monster monster = GameFactory.createMonster(BIG_MONSTER_NAME + i, (short) (nestedMonsterHp * i), nestedMonsterMana);
|
||||
monsterStream.onNext(monster);
|
||||
}
|
||||
monsterStream.onCompleted();
|
||||
|
||||
// Wait a little bit for the server to send the stats of the monster with the max and min hit-points.
|
||||
streamAlive.await(timeoutMs, TimeUnit.MILLISECONDS);
|
||||
|
||||
Assert.assertEquals(maxHitStat.get().id(), BIG_MONSTER_NAME + (count - 1));
|
||||
Assert.assertEquals(maxHitStat.get().val(), nestedMonsterHp * (count - 1));
|
||||
Assert.assertEquals(maxHitStat.get().count(), 1);
|
||||
|
||||
Assert.assertEquals(minHitStat.get().id(), BIG_MONSTER_NAME + 0);
|
||||
Assert.assertEquals(minHitStat.get().val(), nestedMonsterHp * 0);
|
||||
Assert.assertEquals(minHitStat.get().count(), 1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,10 +3,10 @@ package testing
|
||||
import (
|
||||
"../../tests/MyGame/Example"
|
||||
|
||||
"context"
|
||||
"net"
|
||||
"testing"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
"google.golang.org/grpc"
|
||||
)
|
||||
|
||||
|
||||
@@ -23,6 +23,9 @@
|
||||
#include "test_assert.h"
|
||||
|
||||
using namespace MyGame::Example;
|
||||
using flatbuffers::grpc::MessageBuilder;
|
||||
using flatbuffers::FlatBufferBuilder;
|
||||
|
||||
void message_builder_tests();
|
||||
|
||||
// The callback implementation of our server, that derives from the generated
|
||||
@@ -46,9 +49,9 @@ class ServiceImpl final : public MyGame::Example::MonsterStorage::Service {
|
||||
const flatbuffers::grpc::Message<Stat> *request,
|
||||
::grpc::ServerWriter<flatbuffers::grpc::Message<Monster>> *writer)
|
||||
override {
|
||||
for (int i = 0; i < 10; i++) {
|
||||
for (int i = 0; i < 5; i++) {
|
||||
fbb_.Clear();
|
||||
// Create 10 monsters for resposne.
|
||||
// Create 5 monsters for resposne.
|
||||
auto monster_offset =
|
||||
CreateMonster(fbb_, 0, 0, 0,
|
||||
fbb_.CreateString(request->GetRoot()->id()->str() +
|
||||
@@ -94,6 +97,45 @@ void RunServer() {
|
||||
server_instance->Wait();
|
||||
}
|
||||
|
||||
template <class Builder>
|
||||
void StoreRPC(MonsterStorage::Stub *stub) {
|
||||
Builder fbb;
|
||||
grpc::ClientContext context;
|
||||
// Build a request with the name set.
|
||||
auto monster_offset = CreateMonster(fbb, 0, 0, 0, fbb.CreateString("Fred"));
|
||||
MessageBuilder mb(std::move(fbb));
|
||||
mb.Finish(monster_offset);
|
||||
auto request = mb.ReleaseMessage<Monster>();
|
||||
flatbuffers::grpc::Message<Stat> response;
|
||||
|
||||
// The actual RPC.
|
||||
auto status = stub->Store(&context, request, &response);
|
||||
|
||||
if (status.ok()) {
|
||||
auto resp = response.GetRoot()->id();
|
||||
std::cout << "RPC response: " << resp->str() << std::endl;
|
||||
} else {
|
||||
std::cout << "RPC failed" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
template <class Builder>
|
||||
void RetrieveRPC(MonsterStorage::Stub *stub) {
|
||||
Builder fbb;
|
||||
grpc::ClientContext context;
|
||||
fbb.Clear();
|
||||
auto stat_offset = CreateStat(fbb, fbb.CreateString("Fred"));
|
||||
fbb.Finish(stat_offset);
|
||||
auto request = MessageBuilder(std::move(fbb)).ReleaseMessage<Stat>();
|
||||
|
||||
flatbuffers::grpc::Message<Monster> response;
|
||||
auto stream = stub->Retrieve(&context, request);
|
||||
while (stream->Read(&response)) {
|
||||
auto resp = response.GetRoot()->name();
|
||||
std::cout << "RPC Streaming response: " << resp->str() << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
int grpc_server_test() {
|
||||
// Launch server.
|
||||
std::thread server_thread(RunServer);
|
||||
@@ -107,39 +149,12 @@ int grpc_server_test() {
|
||||
grpc::InsecureChannelCredentials());
|
||||
auto stub = MyGame::Example::MonsterStorage::NewStub(channel);
|
||||
|
||||
flatbuffers::grpc::MessageBuilder fbb;
|
||||
{
|
||||
grpc::ClientContext context;
|
||||
// Build a request with the name set.
|
||||
auto monster_offset = CreateMonster(fbb, 0, 0, 0, fbb.CreateString("Fred"));
|
||||
fbb.Finish(monster_offset);
|
||||
auto request = fbb.ReleaseMessage<Monster>();
|
||||
flatbuffers::grpc::Message<Stat> response;
|
||||
StoreRPC<MessageBuilder>(stub.get());
|
||||
StoreRPC<FlatBufferBuilder>(stub.get());
|
||||
|
||||
// The actual RPC.
|
||||
auto status = stub->Store(&context, request, &response);
|
||||
RetrieveRPC<MessageBuilder>(stub.get());
|
||||
RetrieveRPC<FlatBufferBuilder>(stub.get());
|
||||
|
||||
if (status.ok()) {
|
||||
auto resp = response.GetRoot()->id();
|
||||
std::cout << "RPC response: " << resp->str() << std::endl;
|
||||
} else {
|
||||
std::cout << "RPC failed" << std::endl;
|
||||
}
|
||||
}
|
||||
{
|
||||
grpc::ClientContext context;
|
||||
fbb.Clear();
|
||||
auto stat_offset = CreateStat(fbb, fbb.CreateString("Fred"));
|
||||
fbb.Finish(stat_offset);
|
||||
auto request = fbb.ReleaseMessage<Stat>();
|
||||
|
||||
flatbuffers::grpc::Message<Monster> response;
|
||||
auto stream = stub->Retrieve(&context, request);
|
||||
while (stream->Read(&response)) {
|
||||
auto resp = response.GetRoot()->name();
|
||||
std::cout << "RPC Streaming response: " << resp->str() << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
#if !FLATBUFFERS_GRPC_DISABLE_AUTO_VERIFICATION
|
||||
{
|
||||
|
||||
@@ -3,6 +3,10 @@
|
||||
#include "test_assert.h"
|
||||
#include "test_builder.h"
|
||||
|
||||
using MyGame::Example::Vec3;
|
||||
using MyGame::Example::CreateStat;
|
||||
using MyGame::Example::Any_NONE;
|
||||
|
||||
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);
|
||||
@@ -14,19 +18,37 @@ bool release_n_verify(flatbuffers::grpc::MessageBuilder &mbb, const std::string
|
||||
return (monster->name()->str() == expected_name) && (monster->color() == color);
|
||||
}
|
||||
|
||||
template <>
|
||||
struct BuilderReuseTests<flatbuffers::grpc::MessageBuilder> {
|
||||
void builder_move_assign_after_releaseraw_test(flatbuffers::grpc::MessageBuilder dst) {
|
||||
auto root_offset1 = populate1(dst);
|
||||
dst.Finish(root_offset1);
|
||||
size_t size, offset;
|
||||
grpc_slice slice;
|
||||
dst.ReleaseRaw(size, offset, slice);
|
||||
flatbuffers::FlatBufferBuilder src;
|
||||
auto root_offset2 = populate2(src);
|
||||
src.Finish(root_offset2);
|
||||
auto src_size = src.GetSize();
|
||||
// Move into a released builder.
|
||||
dst = std::move(src);
|
||||
TEST_EQ(dst.GetSize(), src_size);
|
||||
TEST_ASSERT(release_n_verify(dst, m2_name, m2_color));
|
||||
TEST_EQ(src.GetSize(), 0);
|
||||
grpc_slice_unref(slice);
|
||||
}
|
||||
|
||||
template <class SrcBuilder>
|
||||
struct BuilderReuseTests<flatbuffers::grpc::MessageBuilder, SrcBuilder> {
|
||||
static void builder_reusable_after_release_message_test(TestSelector selector) {
|
||||
if (!selector.count(REUSABLE_AFTER_RELEASE_MESSAGE)) {
|
||||
return;
|
||||
}
|
||||
|
||||
flatbuffers::grpc::MessageBuilder b1;
|
||||
flatbuffers::grpc::MessageBuilder mb;
|
||||
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>());
|
||||
auto root_offset1 = populate1(mb);
|
||||
mb.Finish(root_offset1);
|
||||
buffers.push_back(mb.ReleaseMessage<Monster>());
|
||||
TEST_ASSERT_FUNC(verify(buffers[i], m1_name, m1_color));
|
||||
}
|
||||
}
|
||||
@@ -36,14 +58,15 @@ struct BuilderReuseTests<flatbuffers::grpc::MessageBuilder> {
|
||||
return;
|
||||
}
|
||||
|
||||
// FIXME: Populate-Release loop fails assert(GRPC_SLICE_IS_EMPTY(slice_)).
|
||||
// FIXME: Populate-Release loop fails assert(GRPC_SLICE_IS_EMPTY(slice_)) in SliceAllocator::allocate
|
||||
// in the second iteration.
|
||||
|
||||
flatbuffers::grpc::MessageBuilder b1;
|
||||
flatbuffers::grpc::MessageBuilder mb;
|
||||
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());
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
auto root_offset1 = populate1(mb);
|
||||
mb.Finish(root_offset1);
|
||||
buffers.push_back(mb.Release());
|
||||
TEST_ASSERT_FUNC(verify(buffers[i], m1_name, m1_color));
|
||||
}
|
||||
}
|
||||
@@ -53,13 +76,13 @@ struct BuilderReuseTests<flatbuffers::grpc::MessageBuilder> {
|
||||
return;
|
||||
}
|
||||
|
||||
flatbuffers::grpc::MessageBuilder b1;
|
||||
flatbuffers::grpc::MessageBuilder mb;
|
||||
for (int i = 0; i < 5; ++i) {
|
||||
auto root_offset1 = populate1(b1);
|
||||
b1.Finish(root_offset1);
|
||||
auto root_offset1 = populate1(mb);
|
||||
mb.Finish(root_offset1);
|
||||
size_t size, offset;
|
||||
grpc_slice slice;
|
||||
const uint8_t *buf = b1.ReleaseRaw(size, offset, slice);
|
||||
const uint8_t *buf = mb.ReleaseRaw(size, offset, slice);
|
||||
TEST_ASSERT_FUNC(verify(buf, offset, m1_name, m1_color));
|
||||
grpc_slice_unref(slice);
|
||||
}
|
||||
@@ -70,22 +93,23 @@ struct BuilderReuseTests<flatbuffers::grpc::MessageBuilder> {
|
||||
return;
|
||||
}
|
||||
|
||||
// FIXME: Release-move_assign loop fails assert(p == GRPC_SLICE_START_PTR(slice_)).
|
||||
// FIXME: Release-move_assign loop fails assert(p == GRPC_SLICE_START_PTR(slice_))
|
||||
// in DetachedBuffer destructor after all the iterations
|
||||
|
||||
flatbuffers::grpc::MessageBuilder b1;
|
||||
flatbuffers::grpc::MessageBuilder dst;
|
||||
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());
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
auto root_offset1 = populate1(dst);
|
||||
dst.Finish(root_offset1);
|
||||
buffers.push_back(dst.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);
|
||||
// bring dst back to life.
|
||||
SrcBuilder src;
|
||||
dst = std::move(src);
|
||||
TEST_EQ_FUNC(dst.GetSize(), 0);
|
||||
TEST_EQ_FUNC(src.GetSize(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -94,20 +118,20 @@ struct BuilderReuseTests<flatbuffers::grpc::MessageBuilder> {
|
||||
return;
|
||||
}
|
||||
|
||||
flatbuffers::grpc::MessageBuilder b1;
|
||||
flatbuffers::grpc::MessageBuilder dst;
|
||||
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>());
|
||||
auto root_offset1 = populate1(dst);
|
||||
dst.Finish(root_offset1);
|
||||
buffers.push_back(dst.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);
|
||||
// bring dst back to life.
|
||||
SrcBuilder src;
|
||||
dst = std::move(src);
|
||||
TEST_EQ_FUNC(dst.GetSize(), 0);
|
||||
TEST_EQ_FUNC(src.GetSize(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -116,20 +140,20 @@ struct BuilderReuseTests<flatbuffers::grpc::MessageBuilder> {
|
||||
return;
|
||||
}
|
||||
|
||||
flatbuffers::grpc::MessageBuilder b1;
|
||||
flatbuffers::grpc::MessageBuilder dst;
|
||||
for (int i = 0; i < 5; ++i) {
|
||||
auto root_offset1 = populate1(b1);
|
||||
b1.Finish(root_offset1);
|
||||
auto root_offset1 = populate1(dst);
|
||||
dst.Finish(root_offset1);
|
||||
size_t size, offset;
|
||||
grpc_slice slice = grpc_empty_slice();
|
||||
const uint8_t *buf = b1.ReleaseRaw(size, offset, slice);
|
||||
const uint8_t *buf = dst.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);
|
||||
SrcBuilder src;
|
||||
dst = std::move(src);
|
||||
TEST_EQ_FUNC(dst.GetSize(), 0);
|
||||
TEST_EQ_FUNC(src.GetSize(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -153,7 +177,7 @@ void slice_allocator_tests() {
|
||||
buf[0] = 100;
|
||||
buf[size-1] = 200;
|
||||
flatbuffers::grpc::SliceAllocator sa2(std::move(sa1));
|
||||
// buf should be deleted after move-construct
|
||||
// buf should not be deleted after move-construct
|
||||
TEST_EQ_FUNC(buf[0], 100);
|
||||
TEST_EQ_FUNC(buf[size-1], 200);
|
||||
// buf is freed here
|
||||
@@ -170,13 +194,140 @@ void slice_allocator_tests() {
|
||||
}
|
||||
}
|
||||
|
||||
/// This function does not populate exactly the first half of the table. But it could.
|
||||
void populate_first_half(MyGame::Example::MonsterBuilder &wrapper, flatbuffers::Offset<flatbuffers::String> name_offset) {
|
||||
wrapper.add_name(name_offset);
|
||||
wrapper.add_color(m1_color);
|
||||
}
|
||||
|
||||
/// This function does not populate exactly the second half of the table. But it could.
|
||||
void populate_second_half(MyGame::Example::MonsterBuilder &wrapper) {
|
||||
wrapper.add_hp(77);
|
||||
wrapper.add_mana(88);
|
||||
Vec3 vec3;
|
||||
wrapper.add_pos(&vec3);
|
||||
}
|
||||
|
||||
/// This function is a hack to update the FlatBufferBuilder reference (fbb_) in the MonsterBuilder object.
|
||||
/// This function will break if fbb_ is not the first member in MonsterBuilder. In that case, some offset must be added.
|
||||
/// This function is used exclusively for testing correctness of move operations between FlatBufferBuilders.
|
||||
/// If MonsterBuilder had a fbb_ pointer, this hack would be unnecessary. That involves a code-generator change though.
|
||||
void test_only_hack_update_fbb_reference(MyGame::Example::MonsterBuilder &monsterBuilder,
|
||||
flatbuffers::grpc::MessageBuilder &mb) {
|
||||
*reinterpret_cast<flatbuffers::FlatBufferBuilder **>(&monsterBuilder) = &mb;
|
||||
}
|
||||
|
||||
/// This test validates correctness of move conversion of FlatBufferBuilder to a MessageBuilder DURING
|
||||
/// a table construction. Half of the table is constructed using FlatBufferBuilder and the other half
|
||||
/// of the table is constructed using a MessageBuilder.
|
||||
void builder_move_ctor_conversion_before_finish_half_n_half_table_test() {
|
||||
for (size_t initial_size = 4 ; initial_size <= 2048; initial_size *= 2) {
|
||||
flatbuffers::FlatBufferBuilder fbb(initial_size);
|
||||
auto name_offset = fbb.CreateString(m1_name);
|
||||
MyGame::Example::MonsterBuilder monsterBuilder(fbb); // starts a table in FlatBufferBuilder
|
||||
populate_first_half(monsterBuilder, name_offset);
|
||||
flatbuffers::grpc::MessageBuilder mb(std::move(fbb));
|
||||
test_only_hack_update_fbb_reference(monsterBuilder, mb); // hack
|
||||
populate_second_half(monsterBuilder);
|
||||
mb.Finish(monsterBuilder.Finish()); // ends the table in MessageBuilder
|
||||
TEST_ASSERT_FUNC(release_n_verify(mb, m1_name, m1_color));
|
||||
TEST_EQ_FUNC(fbb.GetSize(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
/// This test populates a COMPLETE inner table before move conversion and later populates more members in the outer table.
|
||||
void builder_move_ctor_conversion_before_finish_test() {
|
||||
for (size_t initial_size = 4 ; initial_size <= 2048; initial_size *= 2) {
|
||||
flatbuffers::FlatBufferBuilder fbb(initial_size);
|
||||
auto stat_offset = CreateStat(fbb, fbb.CreateString("SomeId"), 0, 0);
|
||||
flatbuffers::grpc::MessageBuilder mb(std::move(fbb));
|
||||
auto monster_offset = CreateMonster(mb, 0, 150, 100, mb.CreateString(m1_name), 0, m1_color, Any_NONE, 0, 0, 0, 0, 0, 0, stat_offset);
|
||||
mb.Finish(monster_offset);
|
||||
TEST_ASSERT_FUNC(release_n_verify(mb, m1_name, m1_color));
|
||||
TEST_EQ_FUNC(fbb.GetSize(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
/// This test validates correctness of move conversion of FlatBufferBuilder to a MessageBuilder DURING
|
||||
/// a table construction. Half of the table is constructed using FlatBufferBuilder and the other half
|
||||
/// of the table is constructed using a MessageBuilder.
|
||||
void builder_move_assign_conversion_before_finish_half_n_half_table_test() {
|
||||
flatbuffers::FlatBufferBuilder fbb;
|
||||
flatbuffers::grpc::MessageBuilder mb;
|
||||
|
||||
for (int i = 0;i < 5; ++i) {
|
||||
flatbuffers::FlatBufferBuilder fbb;
|
||||
auto name_offset = fbb.CreateString(m1_name);
|
||||
MyGame::Example::MonsterBuilder monsterBuilder(fbb); // starts a table in FlatBufferBuilder
|
||||
populate_first_half(monsterBuilder, name_offset);
|
||||
mb = std::move(fbb);
|
||||
test_only_hack_update_fbb_reference(monsterBuilder, mb); // hack
|
||||
populate_second_half(monsterBuilder);
|
||||
mb.Finish(monsterBuilder.Finish()); // ends the table in MessageBuilder
|
||||
TEST_ASSERT_FUNC(release_n_verify(mb, m1_name, m1_color));
|
||||
TEST_EQ_FUNC(fbb.GetSize(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
/// This test populates a COMPLETE inner table before move conversion and later populates more members in the outer table.
|
||||
void builder_move_assign_conversion_before_finish_test() {
|
||||
flatbuffers::FlatBufferBuilder fbb;
|
||||
flatbuffers::grpc::MessageBuilder mb;
|
||||
|
||||
for (int i = 0;i < 5; ++i) {
|
||||
auto stat_offset = CreateStat(fbb, fbb.CreateString("SomeId"), 0, 0);
|
||||
mb = std::move(fbb);
|
||||
auto monster_offset = CreateMonster(mb, 0, 150, 100, mb.CreateString(m1_name), 0, m1_color, Any_NONE, 0, 0, 0, 0, 0, 0, stat_offset);
|
||||
mb.Finish(monster_offset);
|
||||
TEST_ASSERT_FUNC(release_n_verify(mb, m1_name, m1_color));
|
||||
TEST_EQ_FUNC(fbb.GetSize(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
/// This test populates data, finishes the buffer, and does move conversion after.
|
||||
void builder_move_ctor_conversion_after_finish_test() {
|
||||
flatbuffers::FlatBufferBuilder fbb;
|
||||
fbb.Finish(populate1(fbb));
|
||||
flatbuffers::grpc::MessageBuilder mb(std::move(fbb));
|
||||
TEST_ASSERT_FUNC(release_n_verify(mb, m1_name, m1_color));
|
||||
TEST_EQ_FUNC(fbb.GetSize(), 0);
|
||||
}
|
||||
|
||||
/// This test populates data, finishes the buffer, and does move conversion after.
|
||||
void builder_move_assign_conversion_after_finish_test() {
|
||||
flatbuffers::FlatBufferBuilder fbb;
|
||||
flatbuffers::grpc::MessageBuilder mb;
|
||||
|
||||
for (int i = 0;i < 5; ++i) {
|
||||
fbb.Finish(populate1(fbb));
|
||||
mb = std::move(fbb);
|
||||
TEST_ASSERT_FUNC(release_n_verify(mb, m1_name, m1_color));
|
||||
TEST_EQ_FUNC(fbb.GetSize(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
void message_builder_tests() {
|
||||
using flatbuffers::grpc::MessageBuilder;
|
||||
using flatbuffers::FlatBufferBuilder;
|
||||
|
||||
slice_allocator_tests();
|
||||
BuilderTests<flatbuffers::grpc::MessageBuilder>::all_tests();
|
||||
|
||||
#ifndef __APPLE__
|
||||
builder_move_ctor_conversion_before_finish_half_n_half_table_test();
|
||||
builder_move_assign_conversion_before_finish_half_n_half_table_test();
|
||||
#endif // __APPLE__
|
||||
builder_move_ctor_conversion_before_finish_test();
|
||||
builder_move_assign_conversion_before_finish_test();
|
||||
|
||||
builder_move_ctor_conversion_after_finish_test();
|
||||
builder_move_assign_conversion_after_finish_test();
|
||||
|
||||
BuilderTests<MessageBuilder, MessageBuilder>::all_tests();
|
||||
BuilderTests<MessageBuilder, FlatBufferBuilder>::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, // 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,
|
||||
@@ -184,5 +335,6 @@ void message_builder_tests() {
|
||||
REUSABLE_AFTER_RELEASE_RAW_AND_MOVE_ASSIGN
|
||||
};
|
||||
|
||||
BuilderReuseTests<flatbuffers::grpc::MessageBuilder>::run_tests(TestSelector(tests, tests+6));
|
||||
BuilderReuseTests<MessageBuilder, MessageBuilder>::run_tests(TestSelector(tests, tests+6));
|
||||
BuilderReuseTests<MessageBuilder, FlatBufferBuilder>::run_tests(TestSelector(tests, tests+6));
|
||||
}
|
||||
|
||||
@@ -4,13 +4,13 @@
|
||||
<parent>
|
||||
<groupId>com.google.flatbuffers</groupId>
|
||||
<artifactId>flatbuffers-parent</artifactId>
|
||||
<version>1.10.0</version>
|
||||
<version>1.11.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.9.0</gRPC.version>
|
||||
<gRPC.version>1.11.0</gRPC.version>
|
||||
</properties>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
|
||||
@@ -2,15 +2,26 @@
|
||||
#define FLATBUFFERS_BASE_H_
|
||||
|
||||
// clang-format off
|
||||
|
||||
// If activate should be declared and included first.
|
||||
#if defined(FLATBUFFERS_MEMORY_LEAK_TRACKING) && \
|
||||
defined(_MSC_VER) && defined(_DEBUG)
|
||||
// The _CRTDBG_MAP_ALLOC inside <crtdbg.h> will replace
|
||||
// calloc/free (etc) to its debug version using #define directives.
|
||||
#define _CRTDBG_MAP_ALLOC
|
||||
#include <stdlib.h>
|
||||
#include <crtdbg.h>
|
||||
// Replace operator new by trace-enabled version.
|
||||
#define DEBUG_NEW new(_NORMAL_BLOCK, __FILE__, __LINE__)
|
||||
#define new DEBUG_NEW
|
||||
#endif
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#if !defined(FLATBUFFERS_ASSERT)
|
||||
#include <assert.h>
|
||||
#define FLATBUFFERS_ASSERT assert
|
||||
#elif defined(FLATBUFFERS_ASSERT_INCLUDE)
|
||||
// Include file with forward declaration
|
||||
#include FLATBUFFERS_ASSERT_INCLUDE
|
||||
#endif
|
||||
|
||||
#ifndef ARDUINO
|
||||
@@ -21,13 +32,6 @@
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
|
||||
#if defined(FLATBUFFERS_MEMORY_LEAK_TRACKING) && \
|
||||
defined(_MSC_VER) && defined(_DEBUG)
|
||||
#include <crtdbg.h>
|
||||
#define DEBUG_NEW new(_NORMAL_BLOCK, __FILE__, __LINE__)
|
||||
#define new DEBUG_NEW
|
||||
#endif
|
||||
|
||||
#if defined(ARDUINO) && !defined(ARDUINOSTL_M_H)
|
||||
#include <utility.h>
|
||||
#else
|
||||
@@ -57,6 +61,27 @@
|
||||
// Clang 3.4 and later implement all of the ISO C++ 2014 standard.
|
||||
// http://clang.llvm.org/cxx_status.html
|
||||
|
||||
// Note the MSVC value '__cplusplus' may be incorrect:
|
||||
// The '__cplusplus' predefined macro in the MSVC stuck at the value 199711L,
|
||||
// indicating (erroneously!) that the compiler conformed to the C++98 Standard.
|
||||
// This value should be correct starting from MSVC2017-15.7-Preview-3.
|
||||
// The '__cplusplus' will be valid only if MSVC2017-15.7-P3 and the `/Zc:__cplusplus` switch is set.
|
||||
// Workaround (for details see MSDN):
|
||||
// Use the _MSC_VER and _MSVC_LANG definition instead of the __cplusplus for compatibility.
|
||||
// The _MSVC_LANG macro reports the Standard version regardless of the '/Zc:__cplusplus' switch.
|
||||
|
||||
#if defined(__GNUC__) && !defined(__clang__)
|
||||
#define FLATBUFFERS_GCC (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
|
||||
#else
|
||||
#define FLATBUFFERS_GCC 0
|
||||
#endif
|
||||
|
||||
#if defined(__clang__)
|
||||
#define FLATBUFFERS_CLANG (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__)
|
||||
#else
|
||||
#define FLATBUFFERS_CLANG 0
|
||||
#endif
|
||||
|
||||
/// @cond FLATBUFFERS_INTERNAL
|
||||
#if __cplusplus <= 199711L && \
|
||||
(!defined(_MSC_VER) || _MSC_VER < 1600) && \
|
||||
@@ -93,7 +118,8 @@
|
||||
#endif // __s390x__
|
||||
#if !defined(FLATBUFFERS_LITTLEENDIAN)
|
||||
#if defined(__GNUC__) || defined(__clang__)
|
||||
#ifdef __BIG_ENDIAN__
|
||||
#if (defined(__BIG_ENDIAN__) || \
|
||||
(defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__))
|
||||
#define FLATBUFFERS_LITTLEENDIAN 0
|
||||
#else
|
||||
#define FLATBUFFERS_LITTLEENDIAN 1
|
||||
@@ -110,7 +136,7 @@
|
||||
#endif // !defined(FLATBUFFERS_LITTLEENDIAN)
|
||||
|
||||
#define FLATBUFFERS_VERSION_MAJOR 1
|
||||
#define FLATBUFFERS_VERSION_MINOR 10
|
||||
#define FLATBUFFERS_VERSION_MINOR 11
|
||||
#define FLATBUFFERS_VERSION_REVISION 0
|
||||
#define FLATBUFFERS_STRING_EXPAND(X) #X
|
||||
#define FLATBUFFERS_STRING(X) FLATBUFFERS_STRING_EXPAND(X)
|
||||
@@ -120,9 +146,11 @@
|
||||
defined(__clang__)
|
||||
#define FLATBUFFERS_FINAL_CLASS final
|
||||
#define FLATBUFFERS_OVERRIDE override
|
||||
#define FLATBUFFERS_VTABLE_UNDERLYING_TYPE : flatbuffers::voffset_t
|
||||
#else
|
||||
#define FLATBUFFERS_FINAL_CLASS
|
||||
#define FLATBUFFERS_OVERRIDE
|
||||
#define FLATBUFFERS_VTABLE_UNDERLYING_TYPE
|
||||
#endif
|
||||
|
||||
#if (!defined(_MSC_VER) || _MSC_VER >= 1900) && \
|
||||
@@ -130,7 +158,7 @@
|
||||
(defined(__cpp_constexpr) && __cpp_constexpr >= 200704)
|
||||
#define FLATBUFFERS_CONSTEXPR constexpr
|
||||
#else
|
||||
#define FLATBUFFERS_CONSTEXPR
|
||||
#define FLATBUFFERS_CONSTEXPR const
|
||||
#endif
|
||||
|
||||
#if (defined(__cplusplus) && __cplusplus >= 201402L) || \
|
||||
@@ -180,6 +208,65 @@
|
||||
#endif // __has_include
|
||||
#endif // !FLATBUFFERS_HAS_STRING_VIEW
|
||||
|
||||
#ifndef FLATBUFFERS_HAS_NEW_STRTOD
|
||||
// Modern (C++11) strtod and strtof functions are available for use.
|
||||
// 1) nan/inf strings as argument of strtod;
|
||||
// 2) hex-float as argument of strtod/strtof.
|
||||
#if (defined(_MSC_VER) && _MSC_VER >= 1900) || \
|
||||
(defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__ >= 409)) || \
|
||||
(defined(__clang__))
|
||||
#define FLATBUFFERS_HAS_NEW_STRTOD 1
|
||||
#endif
|
||||
#endif // !FLATBUFFERS_HAS_NEW_STRTOD
|
||||
|
||||
#ifndef FLATBUFFERS_LOCALE_INDEPENDENT
|
||||
// Enable locale independent functions {strtof_l, strtod_l,strtoll_l, strtoull_l}.
|
||||
// They are part of the POSIX-2008 but not part of the C/C++ standard.
|
||||
// GCC/Clang have definition (_XOPEN_SOURCE>=700) if POSIX-2008.
|
||||
#if ((defined(_MSC_VER) && _MSC_VER >= 1800) || \
|
||||
(defined(_XOPEN_SOURCE) && (_XOPEN_SOURCE>=700)))
|
||||
#define FLATBUFFERS_LOCALE_INDEPENDENT 1
|
||||
#else
|
||||
#define FLATBUFFERS_LOCALE_INDEPENDENT 0
|
||||
#endif
|
||||
#endif // !FLATBUFFERS_LOCALE_INDEPENDENT
|
||||
|
||||
// Suppress Undefined Behavior Sanitizer (recoverable only). Usage:
|
||||
// - __supress_ubsan__("undefined")
|
||||
// - __supress_ubsan__("signed-integer-overflow")
|
||||
#if defined(__clang__)
|
||||
#define __supress_ubsan__(type) __attribute__((no_sanitize(type)))
|
||||
#elif defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__ >= 409)
|
||||
#define __supress_ubsan__(type) __attribute__((no_sanitize_undefined))
|
||||
#else
|
||||
#define __supress_ubsan__(type)
|
||||
#endif
|
||||
|
||||
// This is constexpr function used for checking compile-time constants.
|
||||
// Avoid `#pragma warning(disable: 4127) // C4127: expression is constant`.
|
||||
template<typename T> FLATBUFFERS_CONSTEXPR inline bool IsConstTrue(T t) {
|
||||
return !!t;
|
||||
}
|
||||
|
||||
// Enable C++ attribute [[]] if std:c++17 or higher.
|
||||
#if ((__cplusplus >= 201703L) \
|
||||
|| (defined(_MSVC_LANG) && (_MSVC_LANG >= 201703L)))
|
||||
// All attributes unknown to an implementation are ignored without causing an error.
|
||||
#define FLATBUFFERS_ATTRIBUTE(attr) [[attr]]
|
||||
|
||||
#define FLATBUFFERS_FALLTHROUGH() [[fallthrough]]
|
||||
#else
|
||||
#define FLATBUFFERS_ATTRIBUTE(attr)
|
||||
|
||||
#if FLATBUFFERS_CLANG >= 30800
|
||||
#define FLATBUFFERS_FALLTHROUGH() [[clang::fallthrough]]
|
||||
#elif FLATBUFFERS_GCC >= 70300
|
||||
#define FLATBUFFERS_FALLTHROUGH() [[gnu::fallthrough]]
|
||||
#else
|
||||
#define FLATBUFFERS_FALLTHROUGH()
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/// @endcond
|
||||
|
||||
/// @file
|
||||
@@ -262,14 +349,25 @@ template<typename T> T EndianScalar(T t) {
|
||||
#endif
|
||||
}
|
||||
|
||||
template<typename T> T ReadScalar(const void *p) {
|
||||
template<typename T>
|
||||
// UBSAN: C++ aliasing type rules, see std::bit_cast<> for details.
|
||||
__supress_ubsan__("alignment")
|
||||
T ReadScalar(const void *p) {
|
||||
return EndianScalar(*reinterpret_cast<const T *>(p));
|
||||
}
|
||||
|
||||
template<typename T> void WriteScalar(void *p, T t) {
|
||||
template<typename T>
|
||||
// UBSAN: C++ aliasing type rules, see std::bit_cast<> for details.
|
||||
__supress_ubsan__("alignment")
|
||||
void WriteScalar(void *p, T t) {
|
||||
*reinterpret_cast<T *>(p) = EndianScalar(t);
|
||||
}
|
||||
|
||||
template<typename T> struct Offset;
|
||||
template<typename T> __supress_ubsan__("alignment") void WriteScalar(void *p, Offset<T> t) {
|
||||
*reinterpret_cast<uoffset_t *>(p) = EndianScalar(t.o);
|
||||
}
|
||||
|
||||
// Computes how many bytes you'd have to pad to be able to write an
|
||||
// "scalar_size" scalar if the buffer had grown to "buf_size" (downwards in
|
||||
// memory).
|
||||
|
||||
@@ -130,6 +130,74 @@ extern void GenComment(const std::vector<std::string> &dc,
|
||||
std::string *code_ptr, const CommentConfig *config,
|
||||
const char *prefix = "");
|
||||
|
||||
class FloatConstantGenerator {
|
||||
public:
|
||||
virtual ~FloatConstantGenerator() {}
|
||||
std::string GenFloatConstant(const FieldDef &field) const;
|
||||
|
||||
private:
|
||||
virtual std::string Value(double v, const std::string &src) const = 0;
|
||||
virtual std::string Inf(double v) const = 0;
|
||||
virtual std::string NaN(double v) const = 0;
|
||||
|
||||
virtual std::string Value(float v, const std::string &src) const = 0;
|
||||
virtual std::string Inf(float v) const = 0;
|
||||
virtual std::string NaN(float v) const = 0;
|
||||
|
||||
template<typename T>
|
||||
std::string GenFloatConstantImpl(const FieldDef &field) const;
|
||||
};
|
||||
|
||||
class SimpleFloatConstantGenerator : public FloatConstantGenerator {
|
||||
public:
|
||||
SimpleFloatConstantGenerator(const char *nan_number,
|
||||
const char *pos_inf_number,
|
||||
const char *neg_inf_number);
|
||||
|
||||
private:
|
||||
std::string Value(double v,
|
||||
const std::string &src) const FLATBUFFERS_OVERRIDE;
|
||||
std::string Inf(double v) const FLATBUFFERS_OVERRIDE;
|
||||
std::string NaN(double v) const FLATBUFFERS_OVERRIDE;
|
||||
|
||||
std::string Value(float v, const std::string &src) const FLATBUFFERS_OVERRIDE;
|
||||
std::string Inf(float v) const FLATBUFFERS_OVERRIDE;
|
||||
std::string NaN(float v) const FLATBUFFERS_OVERRIDE;
|
||||
|
||||
const std::string nan_number_;
|
||||
const std::string pos_inf_number_;
|
||||
const std::string neg_inf_number_;
|
||||
};
|
||||
|
||||
// C++, C#, Java like generator.
|
||||
class TypedFloatConstantGenerator : public FloatConstantGenerator {
|
||||
public:
|
||||
TypedFloatConstantGenerator(const char *double_prefix,
|
||||
const char *single_prefix, const char *nan_number,
|
||||
const char *pos_inf_number,
|
||||
const char *neg_inf_number = "");
|
||||
|
||||
private:
|
||||
std::string Value(double v,
|
||||
const std::string &src) const FLATBUFFERS_OVERRIDE;
|
||||
std::string Inf(double v) const FLATBUFFERS_OVERRIDE;
|
||||
|
||||
std::string NaN(double v) const FLATBUFFERS_OVERRIDE;
|
||||
|
||||
std::string Value(float v, const std::string &src) const FLATBUFFERS_OVERRIDE;
|
||||
std::string Inf(float v) const FLATBUFFERS_OVERRIDE;
|
||||
std::string NaN(float v) const FLATBUFFERS_OVERRIDE;
|
||||
|
||||
std::string MakeNaN(const std::string &prefix) const;
|
||||
std::string MakeInf(bool neg, const std::string &prefix) const;
|
||||
|
||||
const std::string double_prefix_;
|
||||
const std::string single_prefix_;
|
||||
const std::string nan_number_;
|
||||
const std::string pos_inf_number_;
|
||||
const std::string neg_inf_number_;
|
||||
};
|
||||
|
||||
} // namespace flatbuffers
|
||||
|
||||
#endif // FLATBUFFERS_CODE_GENERATORS_H_
|
||||
|
||||
@@ -19,7 +19,25 @@
|
||||
|
||||
#include "flatbuffers/base.h"
|
||||
|
||||
#if defined(FLATBUFFERS_NAN_DEFAULTS)
|
||||
#include <cmath>
|
||||
#endif
|
||||
|
||||
namespace flatbuffers {
|
||||
// Generic 'operator==' with conditional specialisations.
|
||||
template<typename T> inline bool IsTheSameAs(T e, T def) { return e == def; }
|
||||
|
||||
#if defined(FLATBUFFERS_NAN_DEFAULTS) && \
|
||||
(!defined(_MSC_VER) || _MSC_VER >= 1800)
|
||||
// Like `operator==(e, def)` with weak NaN if T=(float|double).
|
||||
template<> inline bool IsTheSameAs<float>(float e, float def) {
|
||||
return (e == def) || (std::isnan(def) && std::isnan(e));
|
||||
}
|
||||
template<> inline bool IsTheSameAs<double>(double e, double def) {
|
||||
return (e == def) || (std::isnan(def) && std::isnan(e));
|
||||
}
|
||||
#endif
|
||||
|
||||
// Wrapper for uoffset_t to allow safe template specialization.
|
||||
// Value is allowed to be 0 to indicate a null object (see e.g. AddOffset).
|
||||
template<typename T> struct Offset {
|
||||
@@ -98,16 +116,21 @@ template<typename T, typename IT> struct VectorIterator {
|
||||
VectorIterator(const uint8_t *data, uoffset_t i)
|
||||
: data_(data + IndirectHelper<T>::element_stride * i) {}
|
||||
VectorIterator(const VectorIterator &other) : data_(other.data_) {}
|
||||
VectorIterator() : data_(nullptr) {}
|
||||
|
||||
VectorIterator &operator=(const VectorIterator &other) {
|
||||
data_ = other.data_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// clang-format off
|
||||
#if !defined(FLATBUFFERS_CPP98_STL)
|
||||
VectorIterator &operator=(VectorIterator &&other) {
|
||||
data_ = other.data_;
|
||||
return *this;
|
||||
}
|
||||
#endif // !defined(FLATBUFFERS_CPP98_STL)
|
||||
// clang-format on
|
||||
|
||||
bool operator==(const VectorIterator &other) const {
|
||||
return data_ == other.data_;
|
||||
@@ -161,7 +184,7 @@ template<typename T, typename IT> struct VectorIterator {
|
||||
return temp;
|
||||
}
|
||||
|
||||
VectorIterator operator-(const uoffset_t &offset) {
|
||||
VectorIterator operator-(const uoffset_t &offset) const {
|
||||
return VectorIterator(data_ - offset * IndirectHelper<T>::element_stride,
|
||||
0);
|
||||
}
|
||||
@@ -175,6 +198,19 @@ template<typename T, typename IT> struct VectorIterator {
|
||||
const uint8_t *data_;
|
||||
};
|
||||
|
||||
template<typename Iterator> struct VectorReverseIterator :
|
||||
public std::reverse_iterator<Iterator> {
|
||||
|
||||
explicit VectorReverseIterator(Iterator iter) : iter_(iter) {}
|
||||
|
||||
typename Iterator::value_type operator*() const { return *(iter_ - 1); }
|
||||
|
||||
typename Iterator::value_type operator->() const { return *(iter_ - 1); }
|
||||
|
||||
private:
|
||||
Iterator iter_;
|
||||
};
|
||||
|
||||
struct String;
|
||||
|
||||
// This is used as a helper type for accessing vectors.
|
||||
@@ -185,10 +221,13 @@ template<typename T> class Vector {
|
||||
iterator;
|
||||
typedef VectorIterator<T, typename IndirectHelper<T>::return_type>
|
||||
const_iterator;
|
||||
typedef VectorReverseIterator<iterator> reverse_iterator;
|
||||
typedef VectorReverseIterator<const_iterator> const_reverse_iterator;
|
||||
|
||||
uoffset_t size() const { return EndianScalar(length_); }
|
||||
|
||||
// Deprecated: use size(). Here for backwards compatibility.
|
||||
FLATBUFFERS_ATTRIBUTE(deprecated("use size() instead"))
|
||||
uoffset_t Length() const { return size(); }
|
||||
|
||||
typedef typename IndirectHelper<T>::return_type return_type;
|
||||
@@ -230,6 +269,20 @@ template<typename T> class Vector {
|
||||
iterator end() { return iterator(Data(), size()); }
|
||||
const_iterator end() const { return const_iterator(Data(), size()); }
|
||||
|
||||
reverse_iterator rbegin() { return reverse_iterator(end()); }
|
||||
const_reverse_iterator rbegin() const { return const_reverse_iterator(end()); }
|
||||
|
||||
reverse_iterator rend() { return reverse_iterator(end()); }
|
||||
const_reverse_iterator rend() const { return const_reverse_iterator(end()); }
|
||||
|
||||
const_iterator cbegin() const { return begin(); }
|
||||
|
||||
const_iterator cend() const { return end(); }
|
||||
|
||||
const_reverse_iterator crbegin() const { return rbegin(); }
|
||||
|
||||
const_reverse_iterator crend() const { return rend(); }
|
||||
|
||||
// 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) {
|
||||
@@ -337,23 +390,31 @@ const Vector<Offset<T>> *VectorCast(const Vector<Offset<U>> *ptr) {
|
||||
// Convenient helper function to get the length of any vector, regardless
|
||||
// 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;
|
||||
return v ? v->size() : 0;
|
||||
}
|
||||
|
||||
// Lexicographically compare two strings (possibly containing nulls), and
|
||||
// return true if the first is less than the second.
|
||||
static inline bool StringLessThan(const char *a_data, uoffset_t a_size,
|
||||
const char *b_data, uoffset_t b_size) {
|
||||
const auto cmp = memcmp(a_data, b_data, (std::min)(a_size, b_size));
|
||||
return cmp == 0 ? a_size < b_size : cmp < 0;
|
||||
}
|
||||
|
||||
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()); }
|
||||
std::string str() const { return std::string(c_str(), size()); }
|
||||
|
||||
// clang-format off
|
||||
#ifdef FLATBUFFERS_HAS_STRING_VIEW
|
||||
flatbuffers::string_view string_view() const {
|
||||
return flatbuffers::string_view(c_str(), Length());
|
||||
return flatbuffers::string_view(c_str(), size());
|
||||
}
|
||||
#endif // FLATBUFFERS_HAS_STRING_VIEW
|
||||
// clang-format on
|
||||
|
||||
bool operator<(const String &o) const {
|
||||
return strcmp(c_str(), o.c_str()) < 0;
|
||||
return StringLessThan(this->data(), this->size(), o.data(), o.size());
|
||||
}
|
||||
};
|
||||
|
||||
@@ -421,6 +482,10 @@ class DefaultAllocator : public Allocator {
|
||||
void deallocate(uint8_t *p, size_t) FLATBUFFERS_OVERRIDE {
|
||||
delete[] p;
|
||||
}
|
||||
|
||||
static void dealloc(void *p, size_t) {
|
||||
delete[] static_cast<uint8_t *>(p);
|
||||
}
|
||||
};
|
||||
|
||||
// These functions allow for a null allocator to mean use the default allocator,
|
||||
@@ -469,6 +534,9 @@ class DetachedBuffer {
|
||||
cur_(cur),
|
||||
size_(sz) {}
|
||||
|
||||
// clang-format off
|
||||
#if !defined(FLATBUFFERS_CPP98_STL)
|
||||
// clang-format on
|
||||
DetachedBuffer(DetachedBuffer &&other)
|
||||
: allocator_(other.allocator_),
|
||||
own_allocator_(other.own_allocator_),
|
||||
@@ -478,7 +546,13 @@ class DetachedBuffer {
|
||||
size_(other.size_) {
|
||||
other.reset();
|
||||
}
|
||||
// clang-format off
|
||||
#endif // !defined(FLATBUFFERS_CPP98_STL)
|
||||
// clang-format on
|
||||
|
||||
// clang-format off
|
||||
#if !defined(FLATBUFFERS_CPP98_STL)
|
||||
// clang-format on
|
||||
DetachedBuffer &operator=(DetachedBuffer &&other) {
|
||||
destroy();
|
||||
|
||||
@@ -493,6 +567,9 @@ class DetachedBuffer {
|
||||
|
||||
return *this;
|
||||
}
|
||||
// clang-format off
|
||||
#endif // !defined(FLATBUFFERS_CPP98_STL)
|
||||
// clang-format on
|
||||
|
||||
~DetachedBuffer() { destroy(); }
|
||||
|
||||
@@ -522,12 +599,18 @@ class DetachedBuffer {
|
||||
#endif
|
||||
// clang-format on
|
||||
|
||||
// clang-format off
|
||||
#if !defined(FLATBUFFERS_CPP98_STL)
|
||||
// clang-format on
|
||||
// These may change access mode, leave these at end of public section
|
||||
FLATBUFFERS_DELETE_FUNC(DetachedBuffer(const DetachedBuffer &other))
|
||||
FLATBUFFERS_DELETE_FUNC(
|
||||
DetachedBuffer &operator=(const DetachedBuffer &other))
|
||||
// clang-format off
|
||||
#endif // !defined(FLATBUFFERS_CPP98_STL)
|
||||
// clang-format on
|
||||
|
||||
protected:
|
||||
protected:
|
||||
Allocator *allocator_;
|
||||
bool own_allocator_;
|
||||
uint8_t *buf_;
|
||||
@@ -572,7 +655,13 @@ class vector_downward {
|
||||
cur_(nullptr),
|
||||
scratch_(nullptr) {}
|
||||
|
||||
// clang-format off
|
||||
#if !defined(FLATBUFFERS_CPP98_STL)
|
||||
vector_downward(vector_downward &&other)
|
||||
#else
|
||||
vector_downward(vector_downward &other)
|
||||
#endif // defined(FLATBUFFERS_CPP98_STL)
|
||||
// clang-format on
|
||||
: allocator_(other.allocator_),
|
||||
own_allocator_(other.own_allocator_),
|
||||
initial_size_(other.initial_size_),
|
||||
@@ -591,12 +680,18 @@ class vector_downward {
|
||||
other.scratch_ = nullptr;
|
||||
}
|
||||
|
||||
// clang-format off
|
||||
#if !defined(FLATBUFFERS_CPP98_STL)
|
||||
// clang-format on
|
||||
vector_downward &operator=(vector_downward &&other) {
|
||||
// Move construct a temporary and swap idiom
|
||||
vector_downward temp(std::move(other));
|
||||
swap(temp);
|
||||
return *this;
|
||||
}
|
||||
// clang-format off
|
||||
#endif // defined(FLATBUFFERS_CPP98_STL)
|
||||
// clang-format on
|
||||
|
||||
~vector_downward() {
|
||||
clear_buffer();
|
||||
@@ -842,8 +937,13 @@ class FlatBufferBuilder {
|
||||
EndianCheck();
|
||||
}
|
||||
|
||||
// clang-format off
|
||||
/// @brief Move constructor for FlatBufferBuilder.
|
||||
#if !defined(FLATBUFFERS_CPP98_STL)
|
||||
FlatBufferBuilder(FlatBufferBuilder &&other)
|
||||
#else
|
||||
FlatBufferBuilder(FlatBufferBuilder &other)
|
||||
#endif // #if !defined(FLATBUFFERS_CPP98_STL)
|
||||
: buf_(1024, nullptr, false, AlignOf<largest_scalar_t>()),
|
||||
num_field_loc(0),
|
||||
max_voffset_(0),
|
||||
@@ -858,7 +958,11 @@ class FlatBufferBuilder {
|
||||
// Lack of delegating constructors in vs2010 makes it more verbose than needed.
|
||||
Swap(other);
|
||||
}
|
||||
// clang-format on
|
||||
|
||||
// clang-format off
|
||||
#if !defined(FLATBUFFERS_CPP98_STL)
|
||||
// clang-format on
|
||||
/// @brief Move assignment operator for FlatBufferBuilder.
|
||||
FlatBufferBuilder &operator=(FlatBufferBuilder &&other) {
|
||||
// Move construct a temporary and swap idiom
|
||||
@@ -866,6 +970,9 @@ class FlatBufferBuilder {
|
||||
Swap(temp);
|
||||
return *this;
|
||||
}
|
||||
// clang-format off
|
||||
#endif // defined(FLATBUFFERS_CPP98_STL)
|
||||
// clang-format on
|
||||
|
||||
void Swap(FlatBufferBuilder &other) {
|
||||
using std::swap;
|
||||
@@ -920,8 +1027,8 @@ class FlatBufferBuilder {
|
||||
/// @warning Do NOT attempt to use this FlatBufferBuilder afterwards!
|
||||
/// @return A `FlatBuffer` that owns the buffer and its allocator and
|
||||
/// behaves similar to a `unique_ptr` with a deleter.
|
||||
/// Deprecated: use Release() instead
|
||||
DetachedBuffer ReleaseBufferPointer() {
|
||||
FLATBUFFERS_ATTRIBUTE(deprecated("use Release() instead")) DetachedBuffer
|
||||
ReleaseBufferPointer() {
|
||||
Finished();
|
||||
return buf_.release();
|
||||
}
|
||||
@@ -940,7 +1047,7 @@ class FlatBufferBuilder {
|
||||
/// `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.
|
||||
/// @remark If the allocator is owned, it gets deleted when the destructor is called..
|
||||
uint8_t *ReleaseRaw(size_t &size, size_t &offset) {
|
||||
Finished();
|
||||
return buf_.release_raw(size, offset);
|
||||
@@ -1029,7 +1136,7 @@ class FlatBufferBuilder {
|
||||
// Like PushElement, but additionally tracks the field this represents.
|
||||
template<typename T> void AddElement(voffset_t field, T e, T def) {
|
||||
// We don't serialize values equal to the default.
|
||||
if (e == def && !force_defaults_) return;
|
||||
if (IsTheSameAs(e, def) && !force_defaults_) return;
|
||||
auto off = PushElement(e);
|
||||
TrackField(field, off);
|
||||
}
|
||||
@@ -1129,7 +1236,7 @@ class FlatBufferBuilder {
|
||||
auto vt_offset_ptr = reinterpret_cast<uoffset_t *>(it);
|
||||
auto vt2 = reinterpret_cast<voffset_t *>(buf_.data_at(*vt_offset_ptr));
|
||||
auto vt2_size = *vt2;
|
||||
if (vt1_size != vt2_size || memcmp(vt2, vt1, vt1_size)) continue;
|
||||
if (vt1_size != vt2_size || 0 != memcmp(vt2, vt1, vt1_size)) continue;
|
||||
vt_use = *vt_offset_ptr;
|
||||
buf_.pop(GetSize() - vtableoffsetloc);
|
||||
break;
|
||||
@@ -1150,7 +1257,7 @@ class FlatBufferBuilder {
|
||||
return vtableoffsetloc;
|
||||
}
|
||||
|
||||
// DEPRECATED: call the version above instead.
|
||||
FLATBUFFERS_ATTRIBUTE(deprecated("call the version above instead"))
|
||||
uoffset_t EndTable(uoffset_t start, voffset_t /*numfields*/) {
|
||||
return EndTable(start);
|
||||
}
|
||||
@@ -1233,7 +1340,7 @@ class FlatBufferBuilder {
|
||||
/// @param[in] str A const pointer to a `String` struct to add to the buffer.
|
||||
/// @return Returns the offset in the buffer where the string starts
|
||||
Offset<String> CreateString(const String *str) {
|
||||
return str ? CreateString(str->c_str(), str->Length()) : 0;
|
||||
return str ? CreateString(str->c_str(), str->size()) : 0;
|
||||
}
|
||||
|
||||
/// @brief Store a string in the buffer, which can contain any binary data.
|
||||
@@ -1293,7 +1400,7 @@ class FlatBufferBuilder {
|
||||
/// @param[in] str A const pointer to a `String` struct to add to the buffer.
|
||||
/// @return Returns the offset in the buffer where the string starts
|
||||
Offset<String> CreateSharedString(const String *str) {
|
||||
return CreateSharedString(str->c_str(), str->Length());
|
||||
return CreateSharedString(str->c_str(), str->size());
|
||||
}
|
||||
|
||||
/// @cond FLATBUFFERS_INTERNAL
|
||||
@@ -1457,7 +1564,7 @@ class FlatBufferBuilder {
|
||||
extern T Pack(const S &);
|
||||
typedef T (*Pack_t)(const S &);
|
||||
std::vector<T> vv(len);
|
||||
std::transform(v, v + len, vv.begin(), *(Pack_t)&Pack);
|
||||
std::transform(v, v + len, vv.begin(), static_cast<Pack_t&>(Pack));
|
||||
return CreateVectorOfStructs<T>(vv.data(), vv.size());
|
||||
}
|
||||
|
||||
@@ -1595,7 +1702,7 @@ class FlatBufferBuilder {
|
||||
extern T Pack(const S &);
|
||||
typedef T (*Pack_t)(const S &);
|
||||
std::vector<T> vv(len);
|
||||
std::transform(v, v + len, vv.begin(), *(Pack_t)&Pack);
|
||||
std::transform(v, v + len, vv.begin(), static_cast<Pack_t&>(Pack));
|
||||
return CreateVectorOfSortedStructs<T>(vv, len);
|
||||
}
|
||||
|
||||
@@ -1681,6 +1788,19 @@ class FlatBufferBuilder {
|
||||
reinterpret_cast<uint8_t **>(buf));
|
||||
}
|
||||
|
||||
|
||||
// @brief Create a vector of scalar type T given as input a vector of scalar
|
||||
// type U, useful with e.g. pre "enum class" enums, or any existing scalar
|
||||
// data of the wrong type.
|
||||
template<typename T, typename U>
|
||||
Offset<Vector<T>> CreateVectorScalarCast(const U *v, size_t len) {
|
||||
AssertScalarT<T>();
|
||||
AssertScalarT<U>();
|
||||
StartVector(len, sizeof(T));
|
||||
for (auto i = len; i > 0;) { PushElement(static_cast<T>(v[--i])); }
|
||||
return Offset<Vector<T>>(EndVector(len));
|
||||
}
|
||||
|
||||
/// @brief Write a struct by itself, typically to be part of a union.
|
||||
template<typename T> Offset<const T *> CreateStruct(const T &structobj) {
|
||||
NotNested();
|
||||
@@ -1713,7 +1833,12 @@ class FlatBufferBuilder {
|
||||
Finish(root.o, file_identifier, true);
|
||||
}
|
||||
|
||||
protected:
|
||||
void SwapBufAllocator(FlatBufferBuilder &other) {
|
||||
buf_.swap_allocator(other.buf_);
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
// You shouldn't really be copying instances of this class.
|
||||
FlatBufferBuilder(const FlatBufferBuilder &);
|
||||
FlatBufferBuilder &operator=(const FlatBufferBuilder &);
|
||||
@@ -1766,8 +1891,8 @@ class FlatBufferBuilder {
|
||||
bool operator()(const Offset<String> &a, const Offset<String> &b) const {
|
||||
auto stra = reinterpret_cast<const String *>(buf_->data_at(a.o));
|
||||
auto strb = reinterpret_cast<const String *>(buf_->data_at(b.o));
|
||||
return strncmp(stra->c_str(), strb->c_str(),
|
||||
(std::min)(stra->size(), strb->size()) + 1) < 0;
|
||||
return StringLessThan(stra->data(), stra->size(),
|
||||
strb->data(), strb->size());
|
||||
}
|
||||
const vector_downward *buf_;
|
||||
};
|
||||
@@ -1846,20 +1971,17 @@ inline bool BufferHasIdentifier(const void *buf, const char *identifier, bool si
|
||||
class Verifier FLATBUFFERS_FINAL_CLASS {
|
||||
public:
|
||||
Verifier(const uint8_t *buf, size_t buf_len, uoffset_t _max_depth = 64,
|
||||
uoffset_t _max_tables = 1000000)
|
||||
uoffset_t _max_tables = 1000000, bool _check_alignment = true)
|
||||
: buf_(buf),
|
||||
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_(0)
|
||||
#endif
|
||||
// clang-format on
|
||||
max_tables_(_max_tables),
|
||||
upper_bound_(0),
|
||||
check_alignment_(_check_alignment)
|
||||
{
|
||||
assert(size_ < FLATBUFFERS_MAX_BUFFER_SIZE);
|
||||
FLATBUFFERS_ASSERT(size_ < FLATBUFFERS_MAX_BUFFER_SIZE);
|
||||
}
|
||||
|
||||
// Central location where any verification failures register.
|
||||
@@ -1889,7 +2011,7 @@ class Verifier FLATBUFFERS_FINAL_CLASS {
|
||||
}
|
||||
|
||||
template<typename T> bool VerifyAlignment(size_t elem) const {
|
||||
return (elem & (sizeof(T) - 1)) == 0;
|
||||
return (elem & (sizeof(T) - 1)) == 0 || !check_alignment_;
|
||||
}
|
||||
|
||||
// Verify a range indicated by sizeof(T).
|
||||
@@ -2019,7 +2141,7 @@ class Verifier FLATBUFFERS_FINAL_CLASS {
|
||||
if (!Verify<uoffset_t>(start)) return 0;
|
||||
auto o = ReadScalar<uoffset_t>(buf_ + start);
|
||||
// May not point to itself.
|
||||
Check(o != 0);
|
||||
if (!Check(o != 0)) return 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
|
||||
@@ -2048,17 +2170,22 @@ class Verifier FLATBUFFERS_FINAL_CLASS {
|
||||
return true;
|
||||
}
|
||||
|
||||
// clang-format off
|
||||
#ifdef FLATBUFFERS_TRACK_VERIFIER_BUFFER_SIZE
|
||||
// Returns the message size in bytes
|
||||
size_t GetComputedSize() const {
|
||||
uintptr_t size = upper_bound_;
|
||||
// Align the size to uoffset_t
|
||||
size = (size - 1 + sizeof(uoffset_t)) & ~(sizeof(uoffset_t) - 1);
|
||||
return (size > size_) ? 0 : size;
|
||||
// clang-format off
|
||||
#ifdef FLATBUFFERS_TRACK_VERIFIER_BUFFER_SIZE
|
||||
uintptr_t size = upper_bound_;
|
||||
// Align the size to uoffset_t
|
||||
size = (size - 1 + sizeof(uoffset_t)) & ~(sizeof(uoffset_t) - 1);
|
||||
return (size > size_) ? 0 : size;
|
||||
#else
|
||||
// Must turn on FLATBUFFERS_TRACK_VERIFIER_BUFFER_SIZE for this to work.
|
||||
(void)upper_bound_;
|
||||
FLATBUFFERS_ASSERT(false);
|
||||
return 0;
|
||||
#endif
|
||||
// clang-format on
|
||||
}
|
||||
#endif
|
||||
// clang-format on
|
||||
|
||||
private:
|
||||
const uint8_t *buf_;
|
||||
@@ -2067,11 +2194,8 @@ class Verifier FLATBUFFERS_FINAL_CLASS {
|
||||
uoffset_t max_depth_;
|
||||
uoffset_t num_tables_;
|
||||
uoffset_t max_tables_;
|
||||
// clang-format off
|
||||
#ifdef FLATBUFFERS_TRACK_VERIFIER_BUFFER_SIZE
|
||||
mutable size_t upper_bound_;
|
||||
#endif
|
||||
// clang-format on
|
||||
mutable size_t upper_bound_;
|
||||
bool check_alignment_;
|
||||
};
|
||||
|
||||
// Convenient way to bundle a buffer and its length, to pass it around
|
||||
@@ -2163,7 +2287,7 @@ class Table {
|
||||
|
||||
template<typename T> bool SetField(voffset_t field, T val, T def) {
|
||||
auto field_offset = GetOptionalFieldOffset(field);
|
||||
if (!field_offset) return val == def;
|
||||
if (!field_offset) return IsTheSameAs(val, def);
|
||||
WriteScalar(data_ + field_offset, val);
|
||||
return true;
|
||||
}
|
||||
@@ -2315,9 +2439,11 @@ typedef uint64_t hash_value_t;
|
||||
// Note: this function will return false for fields equal to the default
|
||||
// value, since they're not stored in the buffer (unless force_defaults was
|
||||
// used).
|
||||
template<typename T> bool IsFieldPresent(const T *table, voffset_t field) {
|
||||
template<typename T>
|
||||
bool IsFieldPresent(const T *table, typename T::FlatBuffersVTableOffset field) {
|
||||
// Cast, since Table is a private baseclass of any table types.
|
||||
return reinterpret_cast<const Table *>(table)->CheckField(field);
|
||||
return reinterpret_cast<const Table *>(table)->CheckField(
|
||||
static_cast<voffset_t>(field));
|
||||
}
|
||||
|
||||
// Utility function for reverse lookups on the EnumNames*() functions
|
||||
@@ -2342,10 +2468,10 @@ inline int LookupEnum(const char **names, const char *name) {
|
||||
// clang-format off
|
||||
#if defined(_MSC_VER)
|
||||
#define FLATBUFFERS_MANUALLY_ALIGNED_STRUCT(alignment) \
|
||||
__pragma(pack(1)); \
|
||||
__pragma(pack(1)) \
|
||||
struct __declspec(align(alignment))
|
||||
#define FLATBUFFERS_STRUCT_END(name, size) \
|
||||
__pragma(pack()); \
|
||||
__pragma(pack()) \
|
||||
static_assert(sizeof(name) == size, "compiler breaks packing rules")
|
||||
#elif defined(__GNUC__) || defined(__clang__)
|
||||
#define FLATBUFFERS_MANUALLY_ALIGNED_STRUCT(alignment) \
|
||||
@@ -2424,7 +2550,7 @@ struct TypeTable {
|
||||
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 int64_t *values; // Only set for non-consecutive enum/union or structs.
|
||||
const char * const *names; // Only set if compiled with --reflect-names.
|
||||
};
|
||||
|
||||
|
||||
@@ -80,6 +80,9 @@ class FlatCompiler {
|
||||
const std::string &contents,
|
||||
std::vector<const char *> &include_directories) const;
|
||||
|
||||
void LoadBinarySchema(Parser &parser, const std::string &filename,
|
||||
const std::string &contents);
|
||||
|
||||
void Warn(const std::string &warn, bool show_exe_name = true) const;
|
||||
|
||||
void Error(const std::string &err, bool usage = true,
|
||||
|
||||
@@ -153,7 +153,7 @@ inline uint64_t ReadUInt64(const uint8_t *data, uint8_t byte_width) {
|
||||
// constant, which here it isn't. Test if memcpy is still faster than
|
||||
// the conditionals in ReadSizedScalar. Can also use inline asm.
|
||||
// clang-format off
|
||||
#ifdef _MSC_VER
|
||||
#if defined(_MSC_VER) && (defined(_M_X64) || defined _M_IX86)
|
||||
uint64_t u = 0;
|
||||
__movsb(reinterpret_cast<uint8_t *>(&u),
|
||||
reinterpret_cast<const uint8_t *>(data), byte_width);
|
||||
@@ -337,6 +337,16 @@ class Map : public Vector {
|
||||
bool IsTheEmptyMap() const { return data_ == EmptyMap().data_; }
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
void AppendToString(std::string &s, T &&v, bool keys_quoted) {
|
||||
s += "[ ";
|
||||
for (size_t i = 0; i < v.size(); i++) {
|
||||
if (i) s += ", ";
|
||||
v[i].ToString(true, keys_quoted, s);
|
||||
}
|
||||
s += " ]";
|
||||
}
|
||||
|
||||
class Reference {
|
||||
public:
|
||||
Reference(const uint8_t *data, uint8_t parent_width, uint8_t byte_width,
|
||||
@@ -484,7 +494,7 @@ class Reference {
|
||||
}
|
||||
|
||||
// Unlike AsString(), this will convert any type to a std::string.
|
||||
std::string ToString() {
|
||||
std::string ToString() const {
|
||||
std::string s;
|
||||
ToString(false, false, s);
|
||||
return s;
|
||||
@@ -532,13 +542,14 @@ class Reference {
|
||||
}
|
||||
s += " }";
|
||||
} else if (IsVector()) {
|
||||
s += "[ ";
|
||||
auto v = AsVector();
|
||||
for (size_t i = 0; i < v.size(); i++) {
|
||||
v[i].ToString(true, keys_quoted, s);
|
||||
if (i < v.size() - 1) s += ", ";
|
||||
}
|
||||
s += " ]";
|
||||
AppendToString<Vector>(s, AsVector(), keys_quoted);
|
||||
} else if (IsTypedVector()) {
|
||||
AppendToString<TypedVector>(s, AsTypedVector(), keys_quoted);
|
||||
} else if (IsFixedTypedVector()) {
|
||||
AppendToString<FixedTypedVector>(s, AsFixedTypedVector(), keys_quoted);
|
||||
} else if (IsBlob()) {
|
||||
auto blob = AsBlob();
|
||||
flatbuffers::EscapeString(reinterpret_cast<const char*>(blob.data()), blob.size(), &s, true, false);
|
||||
} else {
|
||||
s += "(?)";
|
||||
}
|
||||
@@ -591,7 +602,7 @@ class Reference {
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T> T As();
|
||||
template<typename T> T As() const;
|
||||
|
||||
// Experimental: Mutation functions.
|
||||
// These allow scalars in an already created buffer to be updated in-place.
|
||||
@@ -704,35 +715,35 @@ class Reference {
|
||||
};
|
||||
|
||||
// Template specialization for As().
|
||||
template<> inline bool Reference::As<bool>() { return AsBool(); }
|
||||
template<> inline bool Reference::As<bool>() const { return AsBool(); }
|
||||
|
||||
template<> inline int8_t Reference::As<int8_t>() { return AsInt8(); }
|
||||
template<> inline int16_t Reference::As<int16_t>() { return AsInt16(); }
|
||||
template<> inline int32_t Reference::As<int32_t>() { return AsInt32(); }
|
||||
template<> inline int64_t Reference::As<int64_t>() { return AsInt64(); }
|
||||
template<> inline int8_t Reference::As<int8_t>() const { return AsInt8(); }
|
||||
template<> inline int16_t Reference::As<int16_t>() const { return AsInt16(); }
|
||||
template<> inline int32_t Reference::As<int32_t>() const { return AsInt32(); }
|
||||
template<> inline int64_t Reference::As<int64_t>() const { return AsInt64(); }
|
||||
|
||||
template<> inline uint8_t Reference::As<uint8_t>() { return AsUInt8(); }
|
||||
template<> inline uint16_t Reference::As<uint16_t>() { return AsUInt16(); }
|
||||
template<> inline uint32_t Reference::As<uint32_t>() { return AsUInt32(); }
|
||||
template<> inline uint64_t Reference::As<uint64_t>() { return AsUInt64(); }
|
||||
template<> inline uint8_t Reference::As<uint8_t>() const { return AsUInt8(); }
|
||||
template<> inline uint16_t Reference::As<uint16_t>() const { return AsUInt16(); }
|
||||
template<> inline uint32_t Reference::As<uint32_t>() const { return AsUInt32(); }
|
||||
template<> inline uint64_t Reference::As<uint64_t>() const { return AsUInt64(); }
|
||||
|
||||
template<> inline double Reference::As<double>() { return AsDouble(); }
|
||||
template<> inline float Reference::As<float>() { return AsFloat(); }
|
||||
template<> inline double Reference::As<double>() const { return AsDouble(); }
|
||||
template<> inline float Reference::As<float>() const { return AsFloat(); }
|
||||
|
||||
template<> inline String Reference::As<String>() { return AsString(); }
|
||||
template<> inline std::string Reference::As<std::string>() {
|
||||
template<> inline String Reference::As<String>() const { return AsString(); }
|
||||
template<> inline std::string Reference::As<std::string>() const {
|
||||
return AsString().str();
|
||||
}
|
||||
|
||||
template<> inline Blob Reference::As<Blob>() { return AsBlob(); }
|
||||
template<> inline Vector Reference::As<Vector>() { return AsVector(); }
|
||||
template<> inline TypedVector Reference::As<TypedVector>() {
|
||||
template<> inline Blob Reference::As<Blob>() const { return AsBlob(); }
|
||||
template<> inline Vector Reference::As<Vector>() const { return AsVector(); }
|
||||
template<> inline TypedVector Reference::As<TypedVector>() const {
|
||||
return AsTypedVector();
|
||||
}
|
||||
template<> inline FixedTypedVector Reference::As<FixedTypedVector>() {
|
||||
template<> inline FixedTypedVector Reference::As<FixedTypedVector>() const {
|
||||
return AsFixedTypedVector();
|
||||
}
|
||||
template<> inline Map Reference::As<Map>() { return AsMap(); }
|
||||
template<> inline Map Reference::As<Map>() const { return AsMap(); }
|
||||
|
||||
inline uint8_t PackedType(BitWidth bit_width, Type type) {
|
||||
return static_cast<uint8_t>(bit_width | (type << 2));
|
||||
|
||||
@@ -164,7 +164,7 @@ class MessageBuilder : private detail::SliceAllocatorMember,
|
||||
public FlatBufferBuilder {
|
||||
public:
|
||||
explicit MessageBuilder(uoffset_t initial_size = 1024)
|
||||
: FlatBufferBuilder(initial_size, &slice_allocator_, false) {}
|
||||
: FlatBufferBuilder(initial_size, &slice_allocator_, false) {}
|
||||
|
||||
MessageBuilder(const MessageBuilder &other) = delete;
|
||||
MessageBuilder &operator=(const MessageBuilder &other) = delete;
|
||||
@@ -175,6 +175,30 @@ class MessageBuilder : private detail::SliceAllocatorMember,
|
||||
Swap(other);
|
||||
}
|
||||
|
||||
/// Create a MessageBuilder from a FlatBufferBuilder.
|
||||
explicit MessageBuilder(FlatBufferBuilder &&src, void (*dealloc)(void*, size_t) = &DefaultAllocator::dealloc)
|
||||
: FlatBufferBuilder(1024, &slice_allocator_, false) {
|
||||
src.Swap(*this);
|
||||
src.SwapBufAllocator(*this);
|
||||
if (buf_.capacity()) {
|
||||
uint8_t *buf = buf_.scratch_data(); // pointer to memory
|
||||
size_t capacity = buf_.capacity(); // size of memory
|
||||
slice_allocator_.slice_ = grpc_slice_new_with_len(buf, capacity, dealloc);
|
||||
}
|
||||
else {
|
||||
slice_allocator_.slice_ = grpc_empty_slice();
|
||||
}
|
||||
}
|
||||
|
||||
/// Move-assign a FlatBufferBuilder to a MessageBuilder.
|
||||
/// Only FlatBufferBuilder with default allocator (basically, nullptr) is supported.
|
||||
MessageBuilder &operator=(FlatBufferBuilder &&src) {
|
||||
// Move construct a temporary and swap
|
||||
MessageBuilder temp(std::move(src));
|
||||
Swap(temp);
|
||||
return *this;
|
||||
}
|
||||
|
||||
MessageBuilder &operator=(MessageBuilder &&other) {
|
||||
// Move construct a temporary and swap
|
||||
MessageBuilder temp(std::move(other));
|
||||
|
||||
@@ -39,7 +39,7 @@ template<> struct FnvTraits<uint64_t> {
|
||||
static const uint64_t kOffsetBasis = 0xcbf29ce484222645ULL;
|
||||
};
|
||||
|
||||
template<typename T> FLATBUFFERS_CONSTEXPR_CPP14 T HashFnv1(const char *input) {
|
||||
template<typename T> T HashFnv1(const char *input) {
|
||||
T hash = FnvTraits<T>::kOffsetBasis;
|
||||
for (const char *c = input; *c; ++c) {
|
||||
hash *= FnvTraits<T>::kFnvPrime;
|
||||
@@ -48,7 +48,7 @@ template<typename T> FLATBUFFERS_CONSTEXPR_CPP14 T HashFnv1(const char *input) {
|
||||
return hash;
|
||||
}
|
||||
|
||||
template<typename T> FLATBUFFERS_CONSTEXPR_CPP14 T HashFnv1a(const char *input) {
|
||||
template<typename T> T HashFnv1a(const char *input) {
|
||||
T hash = FnvTraits<T>::kOffsetBasis;
|
||||
for (const char *c = input; *c; ++c) {
|
||||
hash ^= static_cast<unsigned char>(*c);
|
||||
@@ -57,12 +57,12 @@ template<typename T> FLATBUFFERS_CONSTEXPR_CPP14 T HashFnv1a(const char *input)
|
||||
return hash;
|
||||
}
|
||||
|
||||
template <> FLATBUFFERS_CONSTEXPR_CPP14 inline uint16_t HashFnv1<uint16_t>(const char *input) {
|
||||
template <> inline uint16_t HashFnv1<uint16_t>(const char *input) {
|
||||
uint32_t hash = HashFnv1<uint32_t>(input);
|
||||
return (hash >> 16) ^ (hash & 0xffff);
|
||||
}
|
||||
|
||||
template <> FLATBUFFERS_CONSTEXPR_CPP14 inline uint16_t HashFnv1a<uint16_t>(const char *input) {
|
||||
template <> inline uint16_t HashFnv1a<uint16_t>(const char *input) {
|
||||
uint32_t hash = HashFnv1a<uint32_t>(input);
|
||||
return (hash >> 16) ^ (hash & 0xffff);
|
||||
}
|
||||
|
||||
@@ -34,6 +34,12 @@
|
||||
// This file defines the data types representing a parsed IDL (Interface
|
||||
// Definition Language) / schema file.
|
||||
|
||||
// Limits maximum depth of nested objects.
|
||||
// Prevents stack overflow while parse flatbuffers or json.
|
||||
#if !defined(FLATBUFFERS_MAX_PARSING_DEPTH)
|
||||
# define FLATBUFFERS_MAX_PARSING_DEPTH 64
|
||||
#endif
|
||||
|
||||
namespace flatbuffers {
|
||||
|
||||
// The order of these matters for Is*() functions below.
|
||||
@@ -43,7 +49,7 @@ namespace flatbuffers {
|
||||
#define FLATBUFFERS_GEN_TYPES_SCALAR(TD) \
|
||||
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(BOOL, "bool", uint8_t, boolean,bool, 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) \
|
||||
@@ -147,6 +153,8 @@ struct Type {
|
||||
|
||||
Offset<reflection::Type> Serialize(FlatBufferBuilder *builder) const;
|
||||
|
||||
bool Deserialize(const Parser &parser, const reflection::Type *type);
|
||||
|
||||
BaseType base_type;
|
||||
BaseType element; // only set if t == BASE_TYPE_VECTOR
|
||||
StructDef *struct_def; // only set if t or element == BASE_TYPE_STRUCT
|
||||
@@ -229,6 +237,9 @@ struct Definition {
|
||||
flatbuffers::Vector<flatbuffers::Offset<reflection::KeyValue>>>
|
||||
SerializeAttributes(FlatBufferBuilder *builder, const Parser &parser) const;
|
||||
|
||||
bool DeserializeAttributes(Parser &parser,
|
||||
const Vector<Offset<reflection::KeyValue>> *attrs);
|
||||
|
||||
std::string name;
|
||||
std::string file;
|
||||
std::vector<std::string> doc_comment;
|
||||
@@ -247,6 +258,7 @@ struct FieldDef : public Definition {
|
||||
: deprecated(false),
|
||||
required(false),
|
||||
key(false),
|
||||
shared(false),
|
||||
native_inline(false),
|
||||
flexbuffer(false),
|
||||
nested_flatbuffer(NULL),
|
||||
@@ -255,11 +267,15 @@ struct FieldDef : public Definition {
|
||||
Offset<reflection::Field> Serialize(FlatBufferBuilder *builder, uint16_t id,
|
||||
const Parser &parser) const;
|
||||
|
||||
bool Deserialize(Parser &parser, const reflection::Field *field);
|
||||
|
||||
Value value;
|
||||
bool deprecated; // Field is allowed to be present in old data, but can't be.
|
||||
// written in new data nor accessed in new code.
|
||||
bool required; // Field must always be present.
|
||||
bool key; // Field functions as a key for creating sorted vectors.
|
||||
bool shared; // Field will be using string pooling (i.e. CreateSharedString)
|
||||
// as default serialization behavior if field is a string.
|
||||
bool native_inline; // Field will be defined inline (instead of as a pointer)
|
||||
// for native tables if field is a struct.
|
||||
bool flexbuffer; // This field contains FlexBuffer data.
|
||||
@@ -285,6 +301,8 @@ struct StructDef : public Definition {
|
||||
Offset<reflection::Object> Serialize(FlatBufferBuilder *builder,
|
||||
const Parser &parser) const;
|
||||
|
||||
bool Deserialize(Parser &parser, const reflection::Object *object);
|
||||
|
||||
SymbolTable<FieldDef> fields;
|
||||
|
||||
bool fixed; // If it's struct, not a table.
|
||||
@@ -311,9 +329,14 @@ inline size_t InlineAlignment(const Type &type) {
|
||||
|
||||
struct EnumVal {
|
||||
EnumVal(const std::string &_name, int64_t _val) : name(_name), value(_val) {}
|
||||
EnumVal() : value(0) {}
|
||||
|
||||
Offset<reflection::EnumVal> Serialize(FlatBufferBuilder *builder, const Parser &parser) const;
|
||||
|
||||
bool Deserialize(const Parser &parser, const reflection::EnumVal *val);
|
||||
bool IsZero() const { return 0 == value; }
|
||||
bool IsNonZero() const { return !IsZero(); }
|
||||
|
||||
std::string name;
|
||||
std::vector<std::string> doc_comment;
|
||||
int64_t value;
|
||||
@@ -321,12 +344,12 @@ struct EnumVal {
|
||||
};
|
||||
|
||||
struct EnumDef : public Definition {
|
||||
EnumDef() : is_union(false), uses_type_aliases(false) {}
|
||||
EnumDef() : is_union(false), uses_multiple_type_instances(false) {}
|
||||
|
||||
EnumVal *ReverseLookup(int64_t enum_idx, bool skip_union_default = true) {
|
||||
for (auto it = vals.vec.begin() +
|
||||
for (auto it = Vals().begin() +
|
||||
static_cast<int>(is_union && skip_union_default);
|
||||
it != vals.vec.end(); ++it) {
|
||||
it != Vals().end(); ++it) {
|
||||
if ((*it)->value == enum_idx) { return *it; }
|
||||
}
|
||||
return nullptr;
|
||||
@@ -334,9 +357,19 @@ struct EnumDef : public Definition {
|
||||
|
||||
Offset<reflection::Enum> Serialize(FlatBufferBuilder *builder, const Parser &parser) const;
|
||||
|
||||
bool Deserialize(Parser &parser, const reflection::Enum *values);
|
||||
|
||||
size_t size() const { return vals.vec.size(); }
|
||||
|
||||
const std::vector<EnumVal *> &Vals() const {
|
||||
return vals.vec;
|
||||
}
|
||||
|
||||
SymbolTable<EnumVal> vals;
|
||||
bool is_union;
|
||||
bool uses_type_aliases;
|
||||
// Type is a union which uses type aliases where at least one type is
|
||||
// available under two different names.
|
||||
bool uses_multiple_type_instances;
|
||||
Type underlying_type;
|
||||
};
|
||||
|
||||
@@ -350,11 +383,14 @@ inline bool EqualByName(const Type &a, const Type &b) {
|
||||
struct RPCCall : public Definition {
|
||||
Offset<reflection::RPCCall> Serialize(FlatBufferBuilder *builder, const Parser &parser) const;
|
||||
|
||||
bool Deserialize(Parser &parser, const reflection::RPCCall *call);
|
||||
|
||||
StructDef *request, *response;
|
||||
};
|
||||
|
||||
struct ServiceDef : public Definition {
|
||||
Offset<reflection::Service> Serialize(FlatBufferBuilder *builder, const Parser &parser) const;
|
||||
bool Deserialize(Parser &parser, const reflection::Service *service);
|
||||
|
||||
SymbolTable<RPCCall> calls;
|
||||
};
|
||||
@@ -382,7 +418,9 @@ struct IDLOptions {
|
||||
bool gen_compare;
|
||||
std::string cpp_object_api_pointer_type;
|
||||
std::string cpp_object_api_string_type;
|
||||
bool cpp_object_api_string_flexible_constructor;
|
||||
bool gen_nullable;
|
||||
bool gen_generated;
|
||||
std::string object_prefix;
|
||||
std::string object_suffix;
|
||||
bool union_value_namespacing;
|
||||
@@ -396,6 +434,7 @@ struct IDLOptions {
|
||||
std::string go_import;
|
||||
std::string go_namespace;
|
||||
bool reexport_ts_modules;
|
||||
bool js_ts_short_names;
|
||||
bool protobuf_ascii_alike;
|
||||
bool size_prefixed;
|
||||
std::string root_type;
|
||||
@@ -456,7 +495,9 @@ struct IDLOptions {
|
||||
generate_object_based_api(false),
|
||||
gen_compare(false),
|
||||
cpp_object_api_pointer_type("std::unique_ptr"),
|
||||
cpp_object_api_string_flexible_constructor(false),
|
||||
gen_nullable(false),
|
||||
gen_generated(false),
|
||||
object_suffix("T"),
|
||||
union_value_namespacing(true),
|
||||
allow_non_utf8(false),
|
||||
@@ -466,6 +507,7 @@ struct IDLOptions {
|
||||
binary_schema_builtins(false),
|
||||
skip_flatbuffers_import(false),
|
||||
reexport_ts_modules(true),
|
||||
js_ts_short_names(false),
|
||||
protobuf_ascii_alike(false),
|
||||
size_prefixed(false),
|
||||
force_defaults(false),
|
||||
@@ -478,7 +520,11 @@ struct IDLOptions {
|
||||
// This encapsulates where the parser is in the current source file.
|
||||
struct ParserState {
|
||||
ParserState()
|
||||
: cursor_(nullptr), line_start_(nullptr), line_(0), token_(-1) {}
|
||||
: cursor_(nullptr),
|
||||
line_start_(nullptr),
|
||||
line_(0),
|
||||
token_(-1),
|
||||
attr_is_trivial_ascii_string_(true) {}
|
||||
|
||||
protected:
|
||||
void ResetState(const char *source) {
|
||||
@@ -502,6 +548,10 @@ struct ParserState {
|
||||
int line_; // the current line being parsed
|
||||
int token_;
|
||||
|
||||
// Flag: text in attribute_ is true ASCII string without escape
|
||||
// sequences. Only printable ASCII (without [\t\r\n]).
|
||||
// Used for number-in-string (and base64 string in future).
|
||||
bool attr_is_trivial_ascii_string_;
|
||||
std::string attribute_;
|
||||
std::vector<std::string> doc_comment_;
|
||||
};
|
||||
@@ -573,6 +623,7 @@ class Parser : public ParserState {
|
||||
known_attributes_["deprecated"] = true;
|
||||
known_attributes_["required"] = true;
|
||||
known_attributes_["key"] = true;
|
||||
known_attributes_["shared"] = true;
|
||||
known_attributes_["hash"] = true;
|
||||
known_attributes_["id"] = true;
|
||||
known_attributes_["force_align"] = true;
|
||||
@@ -586,6 +637,7 @@ class Parser : public ParserState {
|
||||
known_attributes_["cpp_ptr_type"] = true;
|
||||
known_attributes_["cpp_ptr_type_get"] = true;
|
||||
known_attributes_["cpp_str_type"] = true;
|
||||
known_attributes_["cpp_str_flex_ctor"] = true;
|
||||
known_attributes_["native_inline"] = true;
|
||||
known_attributes_["native_custom_alloc"] = true;
|
||||
known_attributes_["native_type"] = true;
|
||||
@@ -629,6 +681,15 @@ class Parser : public ParserState {
|
||||
// See reflection/reflection.fbs
|
||||
void Serialize();
|
||||
|
||||
// Deserialize a schema buffer
|
||||
bool Deserialize(const uint8_t *buf, const size_t size);
|
||||
|
||||
// Fills internal structure as if the schema passed had been loaded by parsing
|
||||
// with Parse except that included filenames will not be populated.
|
||||
bool Deserialize(const reflection::Schema* schema);
|
||||
|
||||
Type* DeserializeType(const reflection::Type* type);
|
||||
|
||||
// Checks that the schema represented by this parser is a safe evolution
|
||||
// of the schema provided. Returns non-empty error on any problems.
|
||||
std::string ConformTo(const Parser &base);
|
||||
@@ -638,14 +699,15 @@ class Parser : public ParserState {
|
||||
bool ParseFlexBuffer(const char *source, const char *source_filename,
|
||||
flexbuffers::Builder *builder);
|
||||
|
||||
FLATBUFFERS_CHECKED_ERROR CheckInRange(int64_t val, int64_t min, int64_t max);
|
||||
|
||||
StructDef *LookupStruct(const std::string &id) const;
|
||||
|
||||
std::string UnqualifiedName(std::string fullQualifiedName);
|
||||
|
||||
FLATBUFFERS_CHECKED_ERROR Error(const std::string &msg);
|
||||
|
||||
private:
|
||||
void Message(const std::string &msg);
|
||||
void Warning(const std::string &msg);
|
||||
FLATBUFFERS_CHECKED_ERROR Error(const std::string &msg);
|
||||
FLATBUFFERS_CHECKED_ERROR ParseHexNum(int nibbles, uint64_t *val);
|
||||
FLATBUFFERS_CHECKED_ERROR Next();
|
||||
FLATBUFFERS_CHECKED_ERROR SkipByteOrderMark();
|
||||
@@ -666,37 +728,20 @@ class Parser : public ParserState {
|
||||
FLATBUFFERS_CHECKED_ERROR ParseComma();
|
||||
FLATBUFFERS_CHECKED_ERROR ParseAnyValue(Value &val, FieldDef *field,
|
||||
size_t parent_fieldn,
|
||||
const StructDef *parent_struct_def);
|
||||
// clang-format off
|
||||
#if defined(FLATBUFFERS_CPP98_STL)
|
||||
typedef CheckedError (*ParseTableDelimitersBody)(
|
||||
const std::string &name, size_t &fieldn, const StructDef *struct_def,
|
||||
void *state);
|
||||
#else
|
||||
typedef std::function<CheckedError(const std::string&, size_t&,
|
||||
const StructDef*, void*)>
|
||||
ParseTableDelimitersBody;
|
||||
#endif // defined(FLATBUFFERS_CPP98_STL)
|
||||
// clang-format on
|
||||
const StructDef *parent_struct_def,
|
||||
uoffset_t count,
|
||||
bool inside_vector = false);
|
||||
template<typename F>
|
||||
FLATBUFFERS_CHECKED_ERROR ParseTableDelimiters(size_t &fieldn,
|
||||
const StructDef *struct_def,
|
||||
ParseTableDelimitersBody body,
|
||||
void *state);
|
||||
F body);
|
||||
FLATBUFFERS_CHECKED_ERROR ParseTable(const StructDef &struct_def,
|
||||
std::string *value, uoffset_t *ovalue);
|
||||
void SerializeStruct(const StructDef &struct_def, const Value &val);
|
||||
// clang-format off
|
||||
#if defined(FLATBUFFERS_CPP98_STL)
|
||||
typedef CheckedError (*ParseVectorDelimitersBody)(size_t &count,
|
||||
void *state);
|
||||
#else
|
||||
typedef std::function<CheckedError(size_t&, void*)>
|
||||
ParseVectorDelimitersBody;
|
||||
#endif // defined(FLATBUFFERS_CPP98_STL)
|
||||
// clang-format on
|
||||
FLATBUFFERS_CHECKED_ERROR ParseVectorDelimiters(
|
||||
size_t &count, ParseVectorDelimitersBody body, void *state);
|
||||
FLATBUFFERS_CHECKED_ERROR ParseVector(const Type &type, uoffset_t *ovalue);
|
||||
template<typename F>
|
||||
FLATBUFFERS_CHECKED_ERROR ParseVectorDelimiters(uoffset_t &count, F body);
|
||||
FLATBUFFERS_CHECKED_ERROR ParseVector(const Type &type, uoffset_t *ovalue,
|
||||
FieldDef *field, size_t fieldn);
|
||||
FLATBUFFERS_CHECKED_ERROR ParseNestedFlatbuffer(Value &val, FieldDef *field,
|
||||
size_t fieldn,
|
||||
const StructDef *parent_struct_def);
|
||||
@@ -705,8 +750,8 @@ class Parser : public ParserState {
|
||||
BaseType req, bool *destmatch);
|
||||
FLATBUFFERS_CHECKED_ERROR ParseHash(Value &e, FieldDef* field);
|
||||
FLATBUFFERS_CHECKED_ERROR TokenError();
|
||||
FLATBUFFERS_CHECKED_ERROR ParseSingleValue(const std::string *name, Value &e);
|
||||
FLATBUFFERS_CHECKED_ERROR ParseEnumFromString(Type &type, int64_t *result);
|
||||
FLATBUFFERS_CHECKED_ERROR ParseSingleValue(const std::string *name, Value &e, bool check_now);
|
||||
FLATBUFFERS_CHECKED_ERROR ParseEnumFromString(const Type &type, std::string *result);
|
||||
StructDef *LookupCreateStruct(const std::string &name,
|
||||
bool create_if_new = true,
|
||||
bool definition = false);
|
||||
@@ -742,17 +787,11 @@ class Parser : public ParserState {
|
||||
const char *suffix,
|
||||
BaseType baseType);
|
||||
|
||||
bool SupportsVectorOfUnions() const;
|
||||
bool SupportsAdvancedUnionFeatures() 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;
|
||||
}
|
||||
template<typename F> CheckedError Recurse(F f);
|
||||
|
||||
public:
|
||||
SymbolTable<Type> types_;
|
||||
@@ -801,6 +840,10 @@ extern std::string MakeCamel(const std::string &in, bool first = true);
|
||||
// strict_json adds "quotes" around field names if true.
|
||||
// If the flatbuffer cannot be encoded in JSON (e.g., it contains non-UTF-8
|
||||
// byte arrays in String values), returns false.
|
||||
extern bool GenerateTextFromTable(const Parser &parser,
|
||||
const void *table,
|
||||
const std::string &tablename,
|
||||
std::string *text);
|
||||
extern bool GenerateText(const Parser &parser,
|
||||
const void *flatbuffer,
|
||||
std::string *text);
|
||||
@@ -827,7 +870,7 @@ extern bool GenerateDart(const Parser &parser,
|
||||
|
||||
// Generate JavaScript or TypeScript code from the definitions in the Parser object.
|
||||
// See idl_gen_js.
|
||||
extern bool GenerateJS(const Parser &parser,
|
||||
extern bool GenerateJSTS(const Parser &parser,
|
||||
const std::string &path,
|
||||
const std::string &file_name);
|
||||
|
||||
@@ -858,8 +901,8 @@ extern bool GenerateLobster(const Parser &parser,
|
||||
// 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);
|
||||
const std::string &path,
|
||||
const std::string &file_name);
|
||||
|
||||
// Generate Rust files from the definitions in the Parser object.
|
||||
// See idl_gen_rust.cpp.
|
||||
@@ -889,7 +932,7 @@ extern bool GenerateFBS(const Parser &parser,
|
||||
|
||||
// Generate a make rule for the generated JavaScript or TypeScript code.
|
||||
// See idl_gen_js.cpp.
|
||||
extern std::string JSMakeRule(const Parser &parser,
|
||||
extern std::string JSTSMakeRule(const Parser &parser,
|
||||
const std::string &path,
|
||||
const std::string &file_name);
|
||||
|
||||
|
||||
@@ -88,27 +88,27 @@ inline size_t InlineSize(ElementaryType type, const TypeTable *type_table) {
|
||||
switch (type_table->st) {
|
||||
case ST_TABLE:
|
||||
case ST_UNION: return 4;
|
||||
case ST_STRUCT: return type_table->values[type_table->num_elems];
|
||||
case ST_STRUCT: return static_cast<size_t>(type_table->values[type_table->num_elems]);
|
||||
default: FLATBUFFERS_ASSERT(false); return 1;
|
||||
}
|
||||
default: FLATBUFFERS_ASSERT(false); return 1;
|
||||
}
|
||||
}
|
||||
|
||||
inline int32_t LookupEnum(int32_t enum_val, const int32_t *values,
|
||||
inline int64_t LookupEnum(int64_t enum_val, const int64_t *values,
|
||||
size_t num_values) {
|
||||
if (!values) return enum_val;
|
||||
for (size_t i = 0; i < num_values; i++) {
|
||||
if (enum_val == values[i]) return static_cast<int32_t>(i);
|
||||
if (enum_val == values[i]) return static_cast<int64_t>(i);
|
||||
}
|
||||
return -1; // Unknown enum value.
|
||||
}
|
||||
|
||||
template<typename T> const char *EnumName(T tval, const TypeTable *type_table) {
|
||||
if (!type_table || !type_table->names) return nullptr;
|
||||
auto i = LookupEnum(static_cast<int32_t>(tval), type_table->values,
|
||||
auto i = LookupEnum(static_cast<int64_t>(tval), type_table->values,
|
||||
type_table->num_elems);
|
||||
if (i >= 0 && i < static_cast<int32_t>(type_table->num_elems)) {
|
||||
if (i >= 0 && i < static_cast<int64_t>(type_table->num_elems)) {
|
||||
return type_table->names[i];
|
||||
}
|
||||
return nullptr;
|
||||
@@ -122,58 +122,58 @@ inline void IterateValue(ElementaryType type, const uint8_t *val,
|
||||
soffset_t vector_index, IterationVisitor *visitor) {
|
||||
switch (type) {
|
||||
case ET_UTYPE: {
|
||||
auto tval = *reinterpret_cast<const uint8_t *>(val);
|
||||
auto tval = ReadScalar<uint8_t>(val);
|
||||
visitor->UType(tval, EnumName(tval, type_table));
|
||||
break;
|
||||
}
|
||||
case ET_BOOL: {
|
||||
visitor->Bool(*reinterpret_cast<const uint8_t *>(val) != 0);
|
||||
visitor->Bool(ReadScalar<uint8_t>(val) != 0);
|
||||
break;
|
||||
}
|
||||
case ET_CHAR: {
|
||||
auto tval = *reinterpret_cast<const int8_t *>(val);
|
||||
auto tval = ReadScalar<int8_t>(val);
|
||||
visitor->Char(tval, EnumName(tval, type_table));
|
||||
break;
|
||||
}
|
||||
case ET_UCHAR: {
|
||||
auto tval = *reinterpret_cast<const uint8_t *>(val);
|
||||
auto tval = ReadScalar<uint8_t>(val);
|
||||
visitor->UChar(tval, EnumName(tval, type_table));
|
||||
break;
|
||||
}
|
||||
case ET_SHORT: {
|
||||
auto tval = *reinterpret_cast<const int16_t *>(val);
|
||||
auto tval = ReadScalar<int16_t>(val);
|
||||
visitor->Short(tval, EnumName(tval, type_table));
|
||||
break;
|
||||
}
|
||||
case ET_USHORT: {
|
||||
auto tval = *reinterpret_cast<const uint16_t *>(val);
|
||||
auto tval = ReadScalar<uint16_t>(val);
|
||||
visitor->UShort(tval, EnumName(tval, type_table));
|
||||
break;
|
||||
}
|
||||
case ET_INT: {
|
||||
auto tval = *reinterpret_cast<const int32_t *>(val);
|
||||
auto tval = ReadScalar<int32_t>(val);
|
||||
visitor->Int(tval, EnumName(tval, type_table));
|
||||
break;
|
||||
}
|
||||
case ET_UINT: {
|
||||
auto tval = *reinterpret_cast<const uint32_t *>(val);
|
||||
auto tval = ReadScalar<uint32_t>(val);
|
||||
visitor->UInt(tval, EnumName(tval, type_table));
|
||||
break;
|
||||
}
|
||||
case ET_LONG: {
|
||||
visitor->Long(*reinterpret_cast<const int64_t *>(val));
|
||||
visitor->Long(ReadScalar<int64_t>(val));
|
||||
break;
|
||||
}
|
||||
case ET_ULONG: {
|
||||
visitor->ULong(*reinterpret_cast<const uint64_t *>(val));
|
||||
visitor->ULong(ReadScalar<uint64_t>(val));
|
||||
break;
|
||||
}
|
||||
case ET_FLOAT: {
|
||||
visitor->Float(*reinterpret_cast<const float *>(val));
|
||||
visitor->Float(ReadScalar<float>(val));
|
||||
break;
|
||||
}
|
||||
case ET_DOUBLE: {
|
||||
visitor->Double(*reinterpret_cast<const double *>(val));
|
||||
visitor->Double(ReadScalar<double>(val));
|
||||
break;
|
||||
}
|
||||
case ET_STRING: {
|
||||
@@ -287,10 +287,20 @@ struct ToStringVisitor : public IterationVisitor {
|
||||
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) {}
|
||||
bool vector_delimited;
|
||||
ToStringVisitor(std::string delimiter, bool quotes, std::string indent,
|
||||
bool vdelimited = true)
|
||||
: d(delimiter),
|
||||
q(quotes),
|
||||
in(indent),
|
||||
indent_level(0),
|
||||
vector_delimited(vdelimited) {}
|
||||
ToStringVisitor(std::string delimiter)
|
||||
: d(delimiter), q(false), in(""), indent_level(0) {}
|
||||
: d(delimiter),
|
||||
q(false),
|
||||
in(""),
|
||||
indent_level(0),
|
||||
vector_delimited(true) {}
|
||||
|
||||
void append_indent() {
|
||||
for (size_t i = 0; i < indent_level; i++) { s += in; }
|
||||
@@ -350,30 +360,44 @@ struct ToStringVisitor : public IterationVisitor {
|
||||
void Unknown(const uint8_t *) { s += "(?)"; }
|
||||
void StartVector() {
|
||||
s += "[";
|
||||
s += d;
|
||||
indent_level++;
|
||||
append_indent();
|
||||
if (vector_delimited) {
|
||||
s += d;
|
||||
indent_level++;
|
||||
append_indent();
|
||||
} else {
|
||||
s += " ";
|
||||
}
|
||||
}
|
||||
void EndVector() {
|
||||
s += d;
|
||||
indent_level--;
|
||||
append_indent();
|
||||
if (vector_delimited) {
|
||||
s += d;
|
||||
indent_level--;
|
||||
append_indent();
|
||||
} else {
|
||||
s += " ";
|
||||
}
|
||||
s += "]";
|
||||
}
|
||||
void Element(size_t i, ElementaryType /*type*/,
|
||||
const TypeTable * /*type_table*/, const uint8_t * /*val*/) {
|
||||
if (i) {
|
||||
s += ",";
|
||||
s += d;
|
||||
append_indent();
|
||||
if (vector_delimited) {
|
||||
s += d;
|
||||
append_indent();
|
||||
} else {
|
||||
s += " ";
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
inline std::string FlatBufferToString(const uint8_t *buffer,
|
||||
const TypeTable *type_table,
|
||||
bool multi_line = false) {
|
||||
ToStringVisitor tostring_visitor(multi_line ? "\n" : " ");
|
||||
bool multi_line = false,
|
||||
bool vector_delimited = true) {
|
||||
ToStringVisitor tostring_visitor(multi_line ? "\n" : " ", false, "",
|
||||
vector_delimited);
|
||||
IterateFlatBuffer(buffer, type_table, &tostring_visitor);
|
||||
return tostring_visitor.s;
|
||||
}
|
||||
|
||||
@@ -228,7 +228,7 @@ inline std::string GetAnyVectorElemS(const VectorOfAny *vec,
|
||||
template<typename T>
|
||||
T *GetAnyVectorElemPointer(const VectorOfAny *vec, size_t i) {
|
||||
auto elem_ptr = vec->Data() + sizeof(uoffset_t) * i;
|
||||
return (T *)(elem_ptr + ReadScalar<uoffset_t>(elem_ptr));
|
||||
return reinterpret_cast<T*>(elem_ptr + ReadScalar<uoffset_t>(elem_ptr));
|
||||
}
|
||||
|
||||
// Get the inline-address of a vector element. Useful for Structs (pass Struct
|
||||
@@ -239,20 +239,19 @@ T *GetAnyVectorElemPointer(const VectorOfAny *vec, size_t i) {
|
||||
template<typename T>
|
||||
T *GetAnyVectorElemAddressOf(const VectorOfAny *vec, size_t i,
|
||||
size_t elem_size) {
|
||||
// C-cast to allow const conversion.
|
||||
return (T *)(vec->Data() + elem_size * i);
|
||||
return reinterpret_cast<T *>(vec->Data() + elem_size * i);
|
||||
}
|
||||
|
||||
// Similarly, for elements of tables.
|
||||
template<typename T>
|
||||
T *GetAnyFieldAddressOf(const Table &table, const reflection::Field &field) {
|
||||
return (T *)table.GetAddressOf(field.offset());
|
||||
return reinterpret_cast<T *>(table.GetAddressOf(field.offset()));
|
||||
}
|
||||
|
||||
// Similarly, for elements of structs.
|
||||
template<typename T>
|
||||
T *GetAnyFieldAddressOf(const Struct &st, const reflection::Field &field) {
|
||||
return (T *)st.GetAddressOf(field.offset());
|
||||
return reinterpret_cast<T *>(st.GetAddressOf(field.offset()));
|
||||
}
|
||||
|
||||
// ------------------------- SETTERS -------------------------
|
||||
|
||||
@@ -94,12 +94,13 @@ inline const char * const *EnumNamesBaseType() {
|
||||
}
|
||||
|
||||
inline const char *EnumNameBaseType(BaseType e) {
|
||||
const size_t index = static_cast<int>(e);
|
||||
if (e < None || e > Union) return "";
|
||||
const size_t index = static_cast<size_t>(e);
|
||||
return EnumNamesBaseType()[index];
|
||||
}
|
||||
|
||||
struct Type FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
|
||||
enum {
|
||||
enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE {
|
||||
VT_BASE_TYPE = 4,
|
||||
VT_ELEMENT = 6,
|
||||
VT_INDEX = 8
|
||||
@@ -159,7 +160,7 @@ inline flatbuffers::Offset<Type> CreateType(
|
||||
}
|
||||
|
||||
struct KeyValue FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
|
||||
enum {
|
||||
enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE {
|
||||
VT_KEY = 4,
|
||||
VT_VALUE = 6
|
||||
};
|
||||
@@ -221,14 +222,16 @@ inline flatbuffers::Offset<KeyValue> CreateKeyValueDirect(
|
||||
flatbuffers::FlatBufferBuilder &_fbb,
|
||||
const char *key = nullptr,
|
||||
const char *value = nullptr) {
|
||||
auto key__ = key ? _fbb.CreateString(key) : 0;
|
||||
auto value__ = value ? _fbb.CreateString(value) : 0;
|
||||
return reflection::CreateKeyValue(
|
||||
_fbb,
|
||||
key ? _fbb.CreateString(key) : 0,
|
||||
value ? _fbb.CreateString(value) : 0);
|
||||
key__,
|
||||
value__);
|
||||
}
|
||||
|
||||
struct EnumVal FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
|
||||
enum {
|
||||
enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE {
|
||||
VT_NAME = 4,
|
||||
VT_VALUE = 6,
|
||||
VT_OBJECT = 8,
|
||||
@@ -326,17 +329,19 @@ inline flatbuffers::Offset<EnumVal> CreateEnumValDirect(
|
||||
flatbuffers::Offset<Object> object = 0,
|
||||
flatbuffers::Offset<Type> union_type = 0,
|
||||
const std::vector<flatbuffers::Offset<flatbuffers::String>> *documentation = nullptr) {
|
||||
auto name__ = name ? _fbb.CreateString(name) : 0;
|
||||
auto documentation__ = documentation ? _fbb.CreateVector<flatbuffers::Offset<flatbuffers::String>>(*documentation) : 0;
|
||||
return reflection::CreateEnumVal(
|
||||
_fbb,
|
||||
name ? _fbb.CreateString(name) : 0,
|
||||
name__,
|
||||
value,
|
||||
object,
|
||||
union_type,
|
||||
documentation ? _fbb.CreateVector<flatbuffers::Offset<flatbuffers::String>>(*documentation) : 0);
|
||||
documentation__);
|
||||
}
|
||||
|
||||
struct Enum FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
|
||||
enum {
|
||||
enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE {
|
||||
VT_NAME = 4,
|
||||
VT_VALUES = 6,
|
||||
VT_IS_UNION = 8,
|
||||
@@ -450,18 +455,22 @@ inline flatbuffers::Offset<Enum> CreateEnumDirect(
|
||||
flatbuffers::Offset<Type> underlying_type = 0,
|
||||
const std::vector<flatbuffers::Offset<KeyValue>> *attributes = nullptr,
|
||||
const std::vector<flatbuffers::Offset<flatbuffers::String>> *documentation = nullptr) {
|
||||
auto name__ = name ? _fbb.CreateString(name) : 0;
|
||||
auto values__ = values ? _fbb.CreateVector<flatbuffers::Offset<EnumVal>>(*values) : 0;
|
||||
auto attributes__ = attributes ? _fbb.CreateVector<flatbuffers::Offset<KeyValue>>(*attributes) : 0;
|
||||
auto documentation__ = documentation ? _fbb.CreateVector<flatbuffers::Offset<flatbuffers::String>>(*documentation) : 0;
|
||||
return reflection::CreateEnum(
|
||||
_fbb,
|
||||
name ? _fbb.CreateString(name) : 0,
|
||||
values ? _fbb.CreateVector<flatbuffers::Offset<EnumVal>>(*values) : 0,
|
||||
name__,
|
||||
values__,
|
||||
is_union,
|
||||
underlying_type,
|
||||
attributes ? _fbb.CreateVector<flatbuffers::Offset<KeyValue>>(*attributes) : 0,
|
||||
documentation ? _fbb.CreateVector<flatbuffers::Offset<flatbuffers::String>>(*documentation) : 0);
|
||||
attributes__,
|
||||
documentation__);
|
||||
}
|
||||
|
||||
struct Field FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
|
||||
enum {
|
||||
enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE {
|
||||
VT_NAME = 4,
|
||||
VT_TYPE = 6,
|
||||
VT_ID = 8,
|
||||
@@ -627,9 +636,12 @@ inline flatbuffers::Offset<Field> CreateFieldDirect(
|
||||
bool key = false,
|
||||
const std::vector<flatbuffers::Offset<KeyValue>> *attributes = nullptr,
|
||||
const std::vector<flatbuffers::Offset<flatbuffers::String>> *documentation = nullptr) {
|
||||
auto name__ = name ? _fbb.CreateString(name) : 0;
|
||||
auto attributes__ = attributes ? _fbb.CreateVector<flatbuffers::Offset<KeyValue>>(*attributes) : 0;
|
||||
auto documentation__ = documentation ? _fbb.CreateVector<flatbuffers::Offset<flatbuffers::String>>(*documentation) : 0;
|
||||
return reflection::CreateField(
|
||||
_fbb,
|
||||
name ? _fbb.CreateString(name) : 0,
|
||||
name__,
|
||||
type,
|
||||
id,
|
||||
offset,
|
||||
@@ -638,12 +650,12 @@ inline flatbuffers::Offset<Field> CreateFieldDirect(
|
||||
deprecated,
|
||||
required,
|
||||
key,
|
||||
attributes ? _fbb.CreateVector<flatbuffers::Offset<KeyValue>>(*attributes) : 0,
|
||||
documentation ? _fbb.CreateVector<flatbuffers::Offset<flatbuffers::String>>(*documentation) : 0);
|
||||
attributes__,
|
||||
documentation__);
|
||||
}
|
||||
|
||||
struct Object FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
|
||||
enum {
|
||||
enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE {
|
||||
VT_NAME = 4,
|
||||
VT_FIELDS = 6,
|
||||
VT_IS_STRUCT = 8,
|
||||
@@ -766,19 +778,23 @@ inline flatbuffers::Offset<Object> CreateObjectDirect(
|
||||
int32_t bytesize = 0,
|
||||
const std::vector<flatbuffers::Offset<KeyValue>> *attributes = nullptr,
|
||||
const std::vector<flatbuffers::Offset<flatbuffers::String>> *documentation = nullptr) {
|
||||
auto name__ = name ? _fbb.CreateString(name) : 0;
|
||||
auto fields__ = fields ? _fbb.CreateVector<flatbuffers::Offset<Field>>(*fields) : 0;
|
||||
auto attributes__ = attributes ? _fbb.CreateVector<flatbuffers::Offset<KeyValue>>(*attributes) : 0;
|
||||
auto documentation__ = documentation ? _fbb.CreateVector<flatbuffers::Offset<flatbuffers::String>>(*documentation) : 0;
|
||||
return reflection::CreateObject(
|
||||
_fbb,
|
||||
name ? _fbb.CreateString(name) : 0,
|
||||
fields ? _fbb.CreateVector<flatbuffers::Offset<Field>>(*fields) : 0,
|
||||
name__,
|
||||
fields__,
|
||||
is_struct,
|
||||
minalign,
|
||||
bytesize,
|
||||
attributes ? _fbb.CreateVector<flatbuffers::Offset<KeyValue>>(*attributes) : 0,
|
||||
documentation ? _fbb.CreateVector<flatbuffers::Offset<flatbuffers::String>>(*documentation) : 0);
|
||||
attributes__,
|
||||
documentation__);
|
||||
}
|
||||
|
||||
struct RPCCall FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
|
||||
enum {
|
||||
enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE {
|
||||
VT_NAME = 4,
|
||||
VT_REQUEST = 6,
|
||||
VT_RESPONSE = 8,
|
||||
@@ -880,17 +896,20 @@ inline flatbuffers::Offset<RPCCall> CreateRPCCallDirect(
|
||||
flatbuffers::Offset<Object> response = 0,
|
||||
const std::vector<flatbuffers::Offset<KeyValue>> *attributes = nullptr,
|
||||
const std::vector<flatbuffers::Offset<flatbuffers::String>> *documentation = nullptr) {
|
||||
auto name__ = name ? _fbb.CreateString(name) : 0;
|
||||
auto attributes__ = attributes ? _fbb.CreateVector<flatbuffers::Offset<KeyValue>>(*attributes) : 0;
|
||||
auto documentation__ = documentation ? _fbb.CreateVector<flatbuffers::Offset<flatbuffers::String>>(*documentation) : 0;
|
||||
return reflection::CreateRPCCall(
|
||||
_fbb,
|
||||
name ? _fbb.CreateString(name) : 0,
|
||||
name__,
|
||||
request,
|
||||
response,
|
||||
attributes ? _fbb.CreateVector<flatbuffers::Offset<KeyValue>>(*attributes) : 0,
|
||||
documentation ? _fbb.CreateVector<flatbuffers::Offset<flatbuffers::String>>(*documentation) : 0);
|
||||
attributes__,
|
||||
documentation__);
|
||||
}
|
||||
|
||||
struct Service FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
|
||||
enum {
|
||||
enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE {
|
||||
VT_NAME = 4,
|
||||
VT_CALLS = 6,
|
||||
VT_ATTRIBUTES = 8,
|
||||
@@ -979,16 +998,20 @@ inline flatbuffers::Offset<Service> CreateServiceDirect(
|
||||
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) {
|
||||
auto name__ = name ? _fbb.CreateString(name) : 0;
|
||||
auto calls__ = calls ? _fbb.CreateVector<flatbuffers::Offset<RPCCall>>(*calls) : 0;
|
||||
auto attributes__ = attributes ? _fbb.CreateVector<flatbuffers::Offset<KeyValue>>(*attributes) : 0;
|
||||
auto documentation__ = documentation ? _fbb.CreateVector<flatbuffers::Offset<flatbuffers::String>>(*documentation) : 0;
|
||||
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);
|
||||
name__,
|
||||
calls__,
|
||||
attributes__,
|
||||
documentation__);
|
||||
}
|
||||
|
||||
struct Schema FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
|
||||
enum {
|
||||
enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE {
|
||||
VT_OBJECTS = 4,
|
||||
VT_ENUMS = 6,
|
||||
VT_FILE_IDENT = 8,
|
||||
@@ -1096,14 +1119,19 @@ inline flatbuffers::Offset<Schema> CreateSchemaDirect(
|
||||
const char *file_ext = nullptr,
|
||||
flatbuffers::Offset<Object> root_table = 0,
|
||||
const std::vector<flatbuffers::Offset<Service>> *services = nullptr) {
|
||||
auto objects__ = objects ? _fbb.CreateVector<flatbuffers::Offset<Object>>(*objects) : 0;
|
||||
auto enums__ = enums ? _fbb.CreateVector<flatbuffers::Offset<Enum>>(*enums) : 0;
|
||||
auto file_ident__ = file_ident ? _fbb.CreateString(file_ident) : 0;
|
||||
auto file_ext__ = file_ext ? _fbb.CreateString(file_ext) : 0;
|
||||
auto services__ = services ? _fbb.CreateVector<flatbuffers::Offset<Service>>(*services) : 0;
|
||||
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,
|
||||
objects__,
|
||||
enums__,
|
||||
file_ident__,
|
||||
file_ext__,
|
||||
root_table,
|
||||
services ? _fbb.CreateVector<flatbuffers::Offset<Service>>(*services) : 0);
|
||||
services__);
|
||||
}
|
||||
|
||||
inline const reflection::Schema *GetSchema(const void *buf) {
|
||||
|
||||
@@ -72,7 +72,7 @@ class Registry {
|
||||
return DetachedBuffer();
|
||||
}
|
||||
// We have a valid FlatBuffer. Detach it from the builder and return.
|
||||
return parser.builder_.ReleaseBufferPointer();
|
||||
return parser.builder_.Release();
|
||||
}
|
||||
|
||||
// Modify any parsing / output options used by the other functions.
|
||||
|
||||
@@ -37,9 +37,9 @@
|
||||
// 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))
|
||||
#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
|
||||
|
||||
@@ -88,12 +88,33 @@ inline void vector_emplace_back(std::vector<T> *vector, V &&data) {
|
||||
#endif // defined(FLATBUFFERS_TEMPLATES_ALIASES)
|
||||
#else
|
||||
template <typename T> class numeric_limits :
|
||||
public std::numeric_limits<T> {};
|
||||
public std::numeric_limits<T> {
|
||||
public:
|
||||
// Android NDK fix.
|
||||
static T lowest() {
|
||||
return std::numeric_limits<T>::min();
|
||||
}
|
||||
};
|
||||
|
||||
template <> class numeric_limits<float> :
|
||||
public std::numeric_limits<float> {
|
||||
public:
|
||||
static float lowest() { return -FLT_MAX; }
|
||||
};
|
||||
|
||||
template <> class numeric_limits<double> :
|
||||
public std::numeric_limits<double> {
|
||||
public:
|
||||
static double lowest() { return -DBL_MAX; }
|
||||
};
|
||||
|
||||
template <> class numeric_limits<unsigned long long> {
|
||||
public:
|
||||
static unsigned long long min() { return 0ULL; }
|
||||
static unsigned long long max() { return ~0ULL; }
|
||||
static unsigned long long lowest() {
|
||||
return numeric_limits<unsigned long long>::min();
|
||||
}
|
||||
};
|
||||
|
||||
template <> class numeric_limits<long long> {
|
||||
@@ -105,6 +126,9 @@ inline void vector_emplace_back(std::vector<T> *vector, V &&data) {
|
||||
return static_cast<long long>(
|
||||
(1ULL << ((sizeof(long long) << 3) - 1)) - 1);
|
||||
}
|
||||
static long long lowest() {
|
||||
return numeric_limits<long long>::min();
|
||||
}
|
||||
};
|
||||
#endif // FLATBUFFERS_CPP98_STL
|
||||
|
||||
@@ -114,6 +138,7 @@ inline void vector_emplace_back(std::vector<T> *vector, V &&data) {
|
||||
template <typename T, typename U> using is_same = std::is_same<T,U>;
|
||||
template <typename T> using is_floating_point = std::is_floating_point<T>;
|
||||
template <typename T> using is_unsigned = std::is_unsigned<T>;
|
||||
template <typename T> using make_unsigned = std::make_unsigned<T>;
|
||||
#else
|
||||
// Map C++ TR1 templates defined by stlport.
|
||||
template <typename T> using is_scalar = std::tr1::is_scalar<T>;
|
||||
@@ -121,6 +146,17 @@ inline void vector_emplace_back(std::vector<T> *vector, V &&data) {
|
||||
template <typename T> using is_floating_point =
|
||||
std::tr1::is_floating_point<T>;
|
||||
template <typename T> using is_unsigned = std::tr1::is_unsigned<T>;
|
||||
// Android NDK doesn't have std::make_unsigned or std::tr1::make_unsigned.
|
||||
template<typename T> struct make_unsigned {
|
||||
static_assert(is_unsigned<T>::value, "Specialization not implemented!");
|
||||
using type = T;
|
||||
};
|
||||
template<> struct make_unsigned<char> { using type = unsigned char; };
|
||||
template<> struct make_unsigned<short> { using type = unsigned short; };
|
||||
template<> struct make_unsigned<int> { using type = unsigned int; };
|
||||
template<> struct make_unsigned<long> { using type = unsigned long; };
|
||||
template<>
|
||||
struct make_unsigned<long long> { using type = unsigned long long; };
|
||||
#endif // !FLATBUFFERS_CPP98_STL
|
||||
#else
|
||||
// MSVC 2010 doesn't support C++11 aliases.
|
||||
@@ -129,6 +165,7 @@ 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> {};
|
||||
template <typename T> struct make_unsigned : public std::make_unsigned<T> {};
|
||||
#endif // defined(FLATBUFFERS_TEMPLATES_ALIASES)
|
||||
|
||||
#ifndef FLATBUFFERS_CPP98_STL
|
||||
|
||||
@@ -17,39 +17,63 @@
|
||||
#ifndef FLATBUFFERS_UTIL_H_
|
||||
#define FLATBUFFERS_UTIL_H_
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <fstream>
|
||||
#include <iomanip>
|
||||
#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
|
||||
# define WIN32_LEAN_AND_MEAN
|
||||
# endif
|
||||
# ifndef NOMINMAX
|
||||
# define NOMINMAX
|
||||
# endif
|
||||
# include <windows.h> // Must be included before <direct.h>
|
||||
# include <direct.h>
|
||||
# include <winbase.h>
|
||||
# undef interface // This is also important because of reasons
|
||||
#else
|
||||
# include <limits.h>
|
||||
#endif
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "flatbuffers/base.h"
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#ifndef FLATBUFFERS_PREFER_PRINTF
|
||||
# include <sstream>
|
||||
#else // FLATBUFFERS_PREFER_PRINTF
|
||||
# include <float.h>
|
||||
# include <stdio.h>
|
||||
#endif // FLATBUFFERS_PREFER_PRINTF
|
||||
|
||||
#include <iomanip>
|
||||
#include <string>
|
||||
|
||||
namespace flatbuffers {
|
||||
|
||||
// @locale-independent functions for ASCII characters set.
|
||||
|
||||
// Fast checking that character lies in closed range: [a <= x <= b]
|
||||
// using one compare (conditional branch) operator.
|
||||
inline bool check_ascii_range(char x, char a, char b) {
|
||||
FLATBUFFERS_ASSERT(a <= b);
|
||||
// (Hacker's Delight): `a <= x <= b` <=> `(x-a) <={u} (b-a)`.
|
||||
// The x, a, b will be promoted to int and subtracted without overflow.
|
||||
return static_cast<unsigned int>(x - a) <= static_cast<unsigned int>(b - a);
|
||||
}
|
||||
|
||||
// Case-insensitive isalpha
|
||||
inline bool is_alpha(char c) {
|
||||
// ASCII only: alpha to upper case => reset bit 0x20 (~0x20 = 0xDF).
|
||||
return check_ascii_range(c & 0xDF, 'a' & 0xDF, 'z' & 0xDF);
|
||||
}
|
||||
|
||||
// Check (case-insensitive) that `c` is equal to alpha.
|
||||
inline bool is_alpha_char(char c, char alpha) {
|
||||
FLATBUFFERS_ASSERT(is_alpha(alpha));
|
||||
// ASCII only: alpha to upper case => reset bit 0x20 (~0x20 = 0xDF).
|
||||
return ((c & 0xDF) == (alpha & 0xDF));
|
||||
}
|
||||
|
||||
// https://en.cppreference.com/w/cpp/string/byte/isxdigit
|
||||
// isdigit and isxdigit are the only standard narrow character classification
|
||||
// functions that are not affected by the currently installed C locale. although
|
||||
// some implementations (e.g. Microsoft in 1252 codepage) may classify
|
||||
// additional single-byte characters as digits.
|
||||
inline bool is_digit(char c) { return check_ascii_range(c, '0', '9'); }
|
||||
|
||||
inline bool is_xdigit(char c) {
|
||||
// Replace by look-up table.
|
||||
return is_digit(c) || check_ascii_range(c & 0xDF, 'a' & 0xDF, 'f' & 0xDF);
|
||||
}
|
||||
|
||||
// Case-insensitive isalnum
|
||||
inline bool is_alnum(char c) { return is_alpha(c) || is_digit(c); }
|
||||
|
||||
// @end-locale-independent functions for ASCII character set
|
||||
|
||||
#ifdef FLATBUFFERS_PREFER_PRINTF
|
||||
template<typename T> size_t IntToDigitCount(T t) {
|
||||
size_t digit_count = 0;
|
||||
@@ -73,21 +97,22 @@ template<typename T> size_t NumToStringWidth(T t, int precision = 0) {
|
||||
return string_width;
|
||||
}
|
||||
|
||||
template<typename T> std::string NumToStringImplWrapper(T t, const char* fmt,
|
||||
int precision = 0) {
|
||||
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);
|
||||
snprintf(const_cast<char *>(s.data()), (s.size() + 1), fmt, precision, t);
|
||||
return s;
|
||||
}
|
||||
#endif // FLATBUFFERS_PREFER_PRINTF
|
||||
#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) {
|
||||
// clang-format off
|
||||
|
||||
#ifndef FLATBUFFERS_PREFER_PRINTF
|
||||
std::stringstream ss;
|
||||
ss << t;
|
||||
@@ -105,6 +130,9 @@ template<> inline std::string NumToString<signed char>(signed char t) {
|
||||
template<> inline std::string NumToString<unsigned char>(unsigned char t) {
|
||||
return NumToString(static_cast<int>(t));
|
||||
}
|
||||
template<> inline std::string NumToString<char>(char t) {
|
||||
return NumToString(static_cast<int>(t));
|
||||
}
|
||||
#if defined(FLATBUFFERS_CPP98_STL)
|
||||
template<> inline std::string NumToString<long long>(long long t) {
|
||||
char buf[21]; // (log((1 << 63) - 1) / log(10)) + 2
|
||||
@@ -123,6 +151,7 @@ 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) {
|
||||
// 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
|
||||
@@ -158,7 +187,9 @@ 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) {
|
||||
FLATBUFFERS_ASSERT(i >= 0);
|
||||
// clang-format off
|
||||
|
||||
#ifndef FLATBUFFERS_PREFER_PRINTF
|
||||
std::stringstream ss;
|
||||
ss << std::setw(xdigits) << std::setfill('0') << std::hex << std::uppercase
|
||||
@@ -170,28 +201,193 @@ inline std::string IntToStringHex(int i, int xdigits) {
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
// Portable implementation of strtoll().
|
||||
inline int64_t StringToInt(const char *str, char **endptr = nullptr,
|
||||
int base = 10) {
|
||||
// clang-format off
|
||||
// clang-format off
|
||||
// Use locale independent functions {strtod_l, strtof_l, strtoll_l, strtoull_l}.
|
||||
#if defined(FLATBUFFERS_LOCALE_INDEPENDENT) && (FLATBUFFERS_LOCALE_INDEPENDENT > 0)
|
||||
class ClassicLocale {
|
||||
#ifdef _MSC_VER
|
||||
typedef _locale_t locale_type;
|
||||
#else
|
||||
typedef locale_t locale_type; // POSIX.1-2008 locale_t type
|
||||
#endif
|
||||
ClassicLocale();
|
||||
~ClassicLocale();
|
||||
locale_type locale_;
|
||||
static ClassicLocale instance_;
|
||||
public:
|
||||
static locale_type Get() { return instance_.locale_; }
|
||||
};
|
||||
|
||||
#ifdef _MSC_VER
|
||||
return _strtoi64(str, endptr, base);
|
||||
#define __strtoull_impl(s, pe, b) _strtoui64_l(s, pe, b, ClassicLocale::Get())
|
||||
#define __strtoll_impl(s, pe, b) _strtoi64_l(s, pe, b, ClassicLocale::Get())
|
||||
#define __strtod_impl(s, pe) _strtod_l(s, pe, ClassicLocale::Get())
|
||||
#define __strtof_impl(s, pe) _strtof_l(s, pe, ClassicLocale::Get())
|
||||
#else
|
||||
return strtoll(str, endptr, base);
|
||||
#define __strtoull_impl(s, pe, b) strtoull_l(s, pe, b, ClassicLocale::Get())
|
||||
#define __strtoll_impl(s, pe, b) strtoll_l(s, pe, b, ClassicLocale::Get())
|
||||
#define __strtod_impl(s, pe) strtod_l(s, pe, ClassicLocale::Get())
|
||||
#define __strtof_impl(s, pe) strtof_l(s, pe, ClassicLocale::Get())
|
||||
#endif
|
||||
// clang-format on
|
||||
#else
|
||||
#define __strtod_impl(s, pe) strtod(s, pe)
|
||||
#define __strtof_impl(s, pe) static_cast<float>(strtod(s, pe))
|
||||
#ifdef _MSC_VER
|
||||
#define __strtoull_impl(s, pe, b) _strtoui64(s, pe, b)
|
||||
#define __strtoll_impl(s, pe, b) _strtoi64(s, pe, b)
|
||||
#else
|
||||
#define __strtoull_impl(s, pe, b) strtoull(s, pe, b)
|
||||
#define __strtoll_impl(s, pe, b) strtoll(s, pe, b)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
inline void strtoval_impl(int64_t *val, const char *str, char **endptr,
|
||||
int base) {
|
||||
*val = __strtoll_impl(str, endptr, base);
|
||||
}
|
||||
|
||||
// Portable implementation of strtoull().
|
||||
inline uint64_t StringToUInt(const char *str, char **endptr = nullptr,
|
||||
int base = 10) {
|
||||
// clang-format off
|
||||
#ifdef _MSC_VER
|
||||
return _strtoui64(str, endptr, base);
|
||||
#else
|
||||
return strtoull(str, endptr, base);
|
||||
#endif
|
||||
// clang-format on
|
||||
inline void strtoval_impl(uint64_t *val, const char *str, char **endptr,
|
||||
int base) {
|
||||
*val = __strtoull_impl(str, endptr, base);
|
||||
}
|
||||
|
||||
inline void strtoval_impl(double *val, const char *str, char **endptr) {
|
||||
*val = __strtod_impl(str, endptr);
|
||||
}
|
||||
|
||||
// UBSAN: double to float is safe if numeric_limits<float>::is_iec559 is true.
|
||||
__supress_ubsan__("float-cast-overflow")
|
||||
inline void strtoval_impl(float *val, const char *str, char **endptr) {
|
||||
*val = __strtof_impl(str, endptr);
|
||||
}
|
||||
#undef __strtoull_impl
|
||||
#undef __strtoll_impl
|
||||
#undef __strtod_impl
|
||||
#undef __strtof_impl
|
||||
// clang-format on
|
||||
|
||||
// Adaptor for strtoull()/strtoll().
|
||||
// Flatbuffers accepts numbers with any count of leading zeros (-009 is -9),
|
||||
// while strtoll with base=0 interprets first leading zero as octal prefix.
|
||||
// In future, it is possible to add prefixed 0b0101.
|
||||
// 1) Checks errno code for overflow condition (out of range).
|
||||
// 2) If base <= 0, function try to detect base of number by prefix.
|
||||
//
|
||||
// Return value (like strtoull and strtoll, but reject partial result):
|
||||
// - If successful, an integer value corresponding to the str is returned.
|
||||
// - If full string conversion can't be performed, 0 is returned.
|
||||
// - If the converted value falls out of range of corresponding return type, a
|
||||
// range error occurs. In this case value MAX(T)/MIN(T) is returned.
|
||||
template<typename T>
|
||||
inline bool StringToIntegerImpl(T *val, const char *const str,
|
||||
const int base = 0,
|
||||
const bool check_errno = true) {
|
||||
// T is int64_t or uint64_T
|
||||
FLATBUFFERS_ASSERT(str);
|
||||
if (base <= 0) {
|
||||
auto s = str;
|
||||
while (*s && !is_digit(*s)) s++;
|
||||
if (s[0] == '0' && is_alpha_char(s[1], 'X'))
|
||||
return StringToIntegerImpl(val, str, 16, check_errno);
|
||||
// if a prefix not match, try base=10
|
||||
return StringToIntegerImpl(val, str, 10, check_errno);
|
||||
} else {
|
||||
if (check_errno) errno = 0; // clear thread-local errno
|
||||
auto endptr = str;
|
||||
strtoval_impl(val, str, const_cast<char **>(&endptr), base);
|
||||
if ((*endptr != '\0') || (endptr == str)) {
|
||||
*val = 0; // erase partial result
|
||||
return false; // invalid string
|
||||
}
|
||||
// errno is out-of-range, return MAX/MIN
|
||||
if (check_errno && errno) return false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline bool StringToFloatImpl(T *val, const char *const str) {
|
||||
// Type T must be either float or double.
|
||||
FLATBUFFERS_ASSERT(str && val);
|
||||
auto end = str;
|
||||
strtoval_impl(val, str, const_cast<char **>(&end));
|
||||
auto done = (end != str) && (*end == '\0');
|
||||
if (!done) *val = 0; // erase partial result
|
||||
return done;
|
||||
}
|
||||
|
||||
// Convert a string to an instance of T.
|
||||
// Return value (matched with StringToInteger64Impl and strtod):
|
||||
// - If successful, a numeric value corresponding to the str is returned.
|
||||
// - If full string conversion can't be performed, 0 is returned.
|
||||
// - If the converted value falls out of range of corresponding return type, a
|
||||
// range error occurs. In this case value MAX(T)/MIN(T) is returned.
|
||||
template<typename T> inline bool StringToNumber(const char *s, T *val) {
|
||||
FLATBUFFERS_ASSERT(s && val);
|
||||
int64_t i64;
|
||||
// The errno check isn't needed, will return MAX/MIN on overflow.
|
||||
if (StringToIntegerImpl(&i64, s, 0, false)) {
|
||||
const int64_t max = flatbuffers::numeric_limits<T>::max();
|
||||
const int64_t min = flatbuffers::numeric_limits<T>::lowest();
|
||||
if (i64 > max) {
|
||||
*val = static_cast<T>(max);
|
||||
return false;
|
||||
}
|
||||
if (i64 < min) {
|
||||
// For unsigned types return max to distinguish from
|
||||
// "no conversion can be performed" when 0 is returned.
|
||||
*val = static_cast<T>(flatbuffers::is_unsigned<T>::value ? max : min);
|
||||
return false;
|
||||
}
|
||||
*val = static_cast<T>(i64);
|
||||
return true;
|
||||
}
|
||||
*val = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
template<> inline bool StringToNumber<int64_t>(const char *str, int64_t *val) {
|
||||
return StringToIntegerImpl(val, str);
|
||||
}
|
||||
|
||||
template<>
|
||||
inline bool StringToNumber<uint64_t>(const char *str, uint64_t *val) {
|
||||
if (!StringToIntegerImpl(val, str)) return false;
|
||||
// The strtoull accepts negative numbers:
|
||||
// If the minus sign was part of the input sequence, the numeric value
|
||||
// calculated from the sequence of digits is negated as if by unary minus
|
||||
// in the result type, which applies unsigned integer wraparound rules.
|
||||
// Fix this behaviour (except -0).
|
||||
if (*val) {
|
||||
auto s = str;
|
||||
while (*s && !is_digit(*s)) s++;
|
||||
s = (s > str) ? (s - 1) : s; // step back to one symbol
|
||||
if (*s == '-') {
|
||||
// For unsigned types return the max to distinguish from
|
||||
// "no conversion can be performed".
|
||||
*val = flatbuffers::numeric_limits<uint64_t>::max();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template<> inline bool StringToNumber(const char *s, float *val) {
|
||||
return StringToFloatImpl(val, s);
|
||||
}
|
||||
|
||||
template<> inline bool StringToNumber(const char *s, double *val) {
|
||||
return StringToFloatImpl(val, s);
|
||||
}
|
||||
|
||||
inline int64_t StringToInt(const char *s, int base = 10) {
|
||||
int64_t val;
|
||||
return StringToIntegerImpl(&val, s, base) ? val : 0;
|
||||
}
|
||||
|
||||
inline uint64_t StringToUInt(const char *s, int base = 10) {
|
||||
uint64_t val;
|
||||
return StringToIntegerImpl(&val, s, base) ? val : 0;
|
||||
}
|
||||
|
||||
typedef bool (*LoadFileFunction)(const char *filename, bool binary,
|
||||
@@ -220,13 +416,7 @@ bool LoadFile(const char *name, bool binary, std::string *buf);
|
||||
// If "binary" is false data is written using ifstream's
|
||||
// text mode, otherwise data is written with no
|
||||
// transcoding.
|
||||
inline bool SaveFile(const char *name, const char *buf, size_t len,
|
||||
bool binary) {
|
||||
std::ofstream ofs(name, binary ? std::ofstream::binary : std::ofstream::out);
|
||||
if (!ofs.is_open()) return false;
|
||||
ofs.write(buf, len);
|
||||
return !ofs.bad();
|
||||
}
|
||||
bool SaveFile(const char *name, const char *buf, size_t len, bool binary);
|
||||
|
||||
// Save data "buf" into file "name" returning true if
|
||||
// successful, false otherwise. If "binary" is false
|
||||
@@ -242,100 +432,35 @@ inline bool SaveFile(const char *name, const std::string &buf, bool binary) {
|
||||
// Windows ('/' or '\\') separators are used.
|
||||
|
||||
// Any new separators inserted are always posix.
|
||||
|
||||
// We internally store paths in posix format ('/'). Paths supplied
|
||||
// by the user should go through PosixPath to ensure correct behavior
|
||||
// on Windows when paths are string-compared.
|
||||
|
||||
static const char kPathSeparator = '/';
|
||||
static const char kPathSeparatorWindows = '\\';
|
||||
static const char *PathSeparatorSet = "\\/"; // Intentionally no ':'
|
||||
FLATBUFFERS_CONSTEXPR char kPathSeparator = '/';
|
||||
|
||||
// Returns the path with the extension, if any, removed.
|
||||
inline std::string StripExtension(const std::string &filepath) {
|
||||
size_t i = filepath.find_last_of(".");
|
||||
return i != std::string::npos ? filepath.substr(0, i) : filepath;
|
||||
}
|
||||
std::string StripExtension(const std::string &filepath);
|
||||
|
||||
// Returns the extension, if any.
|
||||
inline std::string GetExtension(const std::string &filepath) {
|
||||
size_t i = filepath.find_last_of(".");
|
||||
return i != std::string::npos ? filepath.substr(i + 1) : "";
|
||||
}
|
||||
std::string GetExtension(const std::string &filepath);
|
||||
|
||||
// Return the last component of the path, after the last separator.
|
||||
inline std::string StripPath(const std::string &filepath) {
|
||||
size_t i = filepath.find_last_of(PathSeparatorSet);
|
||||
return i != std::string::npos ? filepath.substr(i + 1) : filepath;
|
||||
}
|
||||
std::string StripPath(const std::string &filepath);
|
||||
|
||||
// Strip the last component of the path + separator.
|
||||
inline std::string StripFileName(const std::string &filepath) {
|
||||
size_t i = filepath.find_last_of(PathSeparatorSet);
|
||||
return i != std::string::npos ? filepath.substr(0, i) : "";
|
||||
}
|
||||
std::string StripFileName(const std::string &filepath);
|
||||
|
||||
// Concatenates a path with a filename, regardless of wether the path
|
||||
// ends in a separator or not.
|
||||
inline std::string ConCatPathFileName(const std::string &path,
|
||||
const std::string &filename) {
|
||||
std::string filepath = path;
|
||||
if (filepath.length()) {
|
||||
char &filepath_last_character = string_back(filepath);
|
||||
if (filepath_last_character == kPathSeparatorWindows) {
|
||||
filepath_last_character = kPathSeparator;
|
||||
} else if (filepath_last_character != kPathSeparator) {
|
||||
filepath += kPathSeparator;
|
||||
}
|
||||
}
|
||||
filepath += filename;
|
||||
// Ignore './' at the start of filepath.
|
||||
if (filepath[0] == '.' && filepath[1] == kPathSeparator) {
|
||||
filepath.erase(0, 2);
|
||||
}
|
||||
return filepath;
|
||||
}
|
||||
std::string ConCatPathFileName(const std::string &path,
|
||||
const std::string &filename);
|
||||
|
||||
// Replaces any '\\' separators with '/'
|
||||
inline std::string PosixPath(const char *path) {
|
||||
std::string p = path;
|
||||
std::replace(p.begin(), p.end(), '\\', '/');
|
||||
return p;
|
||||
}
|
||||
std::string PosixPath(const char *path);
|
||||
|
||||
// This function ensure a directory exists, by recursively
|
||||
// creating dirs for any parts of the path that don't exist yet.
|
||||
inline void EnsureDirExists(const std::string &filepath) {
|
||||
auto parent = StripFileName(filepath);
|
||||
if (parent.length()) EnsureDirExists(parent);
|
||||
// clang-format off
|
||||
#ifdef _WIN32
|
||||
(void)_mkdir(filepath.c_str());
|
||||
#else
|
||||
mkdir(filepath.c_str(), S_IRWXU|S_IRGRP|S_IXGRP);
|
||||
#endif
|
||||
// clang-format on
|
||||
}
|
||||
void EnsureDirExists(const std::string &filepath);
|
||||
|
||||
// Obtains the absolute path from any other path.
|
||||
// Returns the input path if the absolute path couldn't be resolved.
|
||||
inline std::string AbsolutePath(const std::string &filepath) {
|
||||
// clang-format off
|
||||
#ifdef FLATBUFFERS_NO_ABSOLUTE_PATH_RESOLUTION
|
||||
return filepath;
|
||||
#else
|
||||
#ifdef _WIN32
|
||||
char abs_path[MAX_PATH];
|
||||
return GetFullPathNameA(filepath.c_str(), MAX_PATH, abs_path, nullptr)
|
||||
#else
|
||||
char abs_path[PATH_MAX];
|
||||
return realpath(filepath.c_str(), abs_path)
|
||||
#endif
|
||||
? abs_path
|
||||
: filepath;
|
||||
#endif // FLATBUFFERS_NO_ABSOLUTE_PATH_RESOLUTION
|
||||
// clang-format on
|
||||
}
|
||||
std::string AbsolutePath(const std::string &filepath);
|
||||
|
||||
// To and from UTF-8 unicode conversion functions
|
||||
|
||||
@@ -379,7 +504,8 @@ inline int FromUTF8(const char **in) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ((static_cast<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; }
|
||||
@@ -438,7 +564,7 @@ inline std::string WordWrap(const std::string in, size_t max_length,
|
||||
|
||||
return wrapped;
|
||||
}
|
||||
#endif // !FLATBUFFERS_PREFER_PRINTF
|
||||
#endif // !FLATBUFFERS_PREFER_PRINTF
|
||||
|
||||
inline bool EscapeString(const char *s, size_t length, std::string *_text,
|
||||
bool allow_non_utf8, bool natural_utf8) {
|
||||
@@ -510,6 +636,19 @@ inline bool EscapeString(const char *s, size_t length, std::string *_text,
|
||||
return true;
|
||||
}
|
||||
|
||||
// Remove paired quotes in a string: "text"|'text' -> text.
|
||||
std::string RemoveStringQuotes(const std::string &s);
|
||||
|
||||
// Change th global C-locale to locale with name <locale_name>.
|
||||
// Returns an actual locale name in <_value>, useful if locale_name is "" or
|
||||
// null.
|
||||
bool SetGlobalTestLocale(const char *locale_name,
|
||||
std::string *_value = nullptr);
|
||||
|
||||
// Read (or test) a value of environment variable.
|
||||
bool ReadEnvironmentVariable(const char *var_name,
|
||||
std::string *_value = nullptr);
|
||||
|
||||
} // namespace flatbuffers
|
||||
|
||||
#endif // FLATBUFFERS_UTIL_H_
|
||||
|
||||
@@ -21,11 +21,7 @@ import static com.google.flatbuffers.Constants.*;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.*;
|
||||
import java.nio.charset.CharacterCodingException;
|
||||
import java.nio.charset.CharsetEncoder;
|
||||
import java.nio.charset.CoderResult;
|
||||
import java.util.Arrays;
|
||||
import java.nio.charset.Charset;
|
||||
|
||||
/// @file
|
||||
/// @addtogroup flatbuffers_java_api
|
||||
@@ -39,7 +35,6 @@ public class FlatBufferBuilder {
|
||||
/// @cond FLATBUFFERS_INTERNAL
|
||||
ByteBuffer bb; // Where we construct the FlatBuffer.
|
||||
int space; // Remaining space in the ByteBuffer.
|
||||
static final Charset utf8charset = Charset.forName("UTF-8"); // The UTF-8 character set used by FlatBuffers.
|
||||
int minalign = 1; // Minimum alignment encountered so far.
|
||||
int[] vtable = null; // The vtable for the current table.
|
||||
int vtable_in_use = 0; // The amount of fields we're actually using.
|
||||
@@ -50,9 +45,8 @@ public class FlatBufferBuilder {
|
||||
int num_vtables = 0; // Number of entries in `vtables` in use.
|
||||
int vector_num_elems = 0; // For the current vector being built.
|
||||
boolean force_defaults = false; // False omits default values from the serialized data.
|
||||
CharsetEncoder encoder = utf8charset.newEncoder();
|
||||
ByteBuffer dst;
|
||||
ByteBufferFactory bb_factory; // Factory for allocating the internal buffer
|
||||
final Utf8 utf8; // UTF-8 encoder to use
|
||||
/// @endcond
|
||||
|
||||
/**
|
||||
@@ -62,10 +56,32 @@ public class FlatBufferBuilder {
|
||||
* @param bb_factory The factory to be used for allocating the internal buffer
|
||||
*/
|
||||
public FlatBufferBuilder(int initial_size, ByteBufferFactory bb_factory) {
|
||||
if (initial_size <= 0) initial_size = 1;
|
||||
this(initial_size, bb_factory, null, Utf8.getDefault());
|
||||
}
|
||||
|
||||
/**
|
||||
* Start with a buffer of size `initial_size`, then grow as required.
|
||||
*
|
||||
* @param initial_size The initial size of the internal buffer to use.
|
||||
* @param bb_factory The factory to be used for allocating the internal buffer
|
||||
* @param existing_bb The byte buffer to reuse.
|
||||
* @param utf8 The Utf8 codec
|
||||
*/
|
||||
public FlatBufferBuilder(int initial_size, ByteBufferFactory bb_factory,
|
||||
ByteBuffer existing_bb, Utf8 utf8) {
|
||||
if (initial_size <= 0) {
|
||||
initial_size = 1;
|
||||
}
|
||||
space = initial_size;
|
||||
this.bb_factory = bb_factory;
|
||||
bb = bb_factory.newByteBuffer(initial_size);
|
||||
if (existing_bb != null) {
|
||||
bb = existing_bb;
|
||||
bb.clear();
|
||||
bb.order(ByteOrder.LITTLE_ENDIAN);
|
||||
} else {
|
||||
bb = bb_factory.newByteBuffer(initial_size);
|
||||
}
|
||||
this.utf8 = utf8;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -74,7 +90,7 @@ public class FlatBufferBuilder {
|
||||
* @param initial_size The initial size of the internal buffer to use.
|
||||
*/
|
||||
public FlatBufferBuilder(int initial_size) {
|
||||
this(initial_size, new HeapByteBufferFactory());
|
||||
this(initial_size, HeapByteBufferFactory.INSTANCE, null, Utf8.getDefault());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -94,7 +110,7 @@ public class FlatBufferBuilder {
|
||||
* the existing buffer needs to grow
|
||||
*/
|
||||
public FlatBufferBuilder(ByteBuffer existing_bb, ByteBufferFactory bb_factory) {
|
||||
init(existing_bb, bb_factory);
|
||||
this(existing_bb.capacity(), bb_factory, existing_bb, Utf8.getDefault());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -105,7 +121,7 @@ public class FlatBufferBuilder {
|
||||
* @param existing_bb The byte buffer to reuse.
|
||||
*/
|
||||
public FlatBufferBuilder(ByteBuffer existing_bb) {
|
||||
init(existing_bb, new HeapByteBufferFactory());
|
||||
this(existing_bb, new HeapByteBufferFactory());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -144,14 +160,15 @@ public class FlatBufferBuilder {
|
||||
* preserve the default behavior in the event that the user does not provide
|
||||
* their own implementation of this interface.
|
||||
*/
|
||||
public interface ByteBufferFactory {
|
||||
public static abstract class ByteBufferFactory {
|
||||
/**
|
||||
* Create a `ByteBuffer` with a given capacity.
|
||||
* The returned ByteBuf must have a ByteOrder.LITTLE_ENDIAN ByteOrder.
|
||||
*
|
||||
* @param capacity The size of the `ByteBuffer` to allocate.
|
||||
* @return Returns the new `ByteBuffer` that was allocated.
|
||||
*/
|
||||
ByteBuffer newByteBuffer(int capacity);
|
||||
public abstract ByteBuffer newByteBuffer(int capacity);
|
||||
|
||||
/**
|
||||
* Release a ByteBuffer. Current {@link FlatBufferBuilder}
|
||||
@@ -162,7 +179,7 @@ public class FlatBufferBuilder {
|
||||
*
|
||||
* @param bb the buffer to release
|
||||
*/
|
||||
default void releaseByteBuffer(ByteBuffer bb) {
|
||||
public void releaseByteBuffer(ByteBuffer bb) {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -172,7 +189,10 @@ public class FlatBufferBuilder {
|
||||
*
|
||||
* Allocate memory for a new byte-array backed `ByteBuffer` array inside the JVM.
|
||||
*/
|
||||
public static final class HeapByteBufferFactory implements ByteBufferFactory {
|
||||
public static final class HeapByteBufferFactory extends ByteBufferFactory {
|
||||
|
||||
public static final HeapByteBufferFactory INSTANCE = new HeapByteBufferFactory();
|
||||
|
||||
@Override
|
||||
public ByteBuffer newByteBuffer(int capacity) {
|
||||
return ByteBuffer.allocate(capacity).order(ByteOrder.LITTLE_ENDIAN);
|
||||
@@ -503,27 +523,12 @@ public class FlatBufferBuilder {
|
||||
* @return The offset in the buffer where the encoded string starts.
|
||||
*/
|
||||
public int createString(CharSequence s) {
|
||||
int length = s.length();
|
||||
int estimatedDstCapacity = (int) (length * encoder.maxBytesPerChar());
|
||||
if (dst == null || dst.capacity() < estimatedDstCapacity) {
|
||||
dst = ByteBuffer.allocate(Math.max(128, estimatedDstCapacity));
|
||||
}
|
||||
|
||||
dst.clear();
|
||||
|
||||
CharBuffer src = s instanceof CharBuffer ? (CharBuffer) s :
|
||||
CharBuffer.wrap(s);
|
||||
CoderResult result = encoder.encode(src, dst, true);
|
||||
if (result.isError()) {
|
||||
try {
|
||||
result.throwException();
|
||||
} catch (CharacterCodingException x) {
|
||||
throw new Error(x);
|
||||
}
|
||||
}
|
||||
|
||||
dst.flip();
|
||||
return createString(dst);
|
||||
int length = utf8.encodedLength(s);
|
||||
addByte((byte)0);
|
||||
startVector(1, length, 1);
|
||||
bb.position(space -= length);
|
||||
utf8.encodeUtf8(s, bb);
|
||||
return endVector();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -19,11 +19,7 @@ package com.google.flatbuffers;
|
||||
import static com.google.flatbuffers.Constants.*;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.CharBuffer;
|
||||
import java.nio.charset.CharacterCodingException;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.CharsetDecoder;
|
||||
import java.nio.charset.CoderResult;
|
||||
|
||||
/// @cond FLATBUFFERS_INTERNAL
|
||||
|
||||
@@ -31,23 +27,21 @@ import java.nio.charset.CoderResult;
|
||||
* All tables in the generated code derive from this class, and add their own accessors.
|
||||
*/
|
||||
public class Table {
|
||||
private final static ThreadLocal<CharsetDecoder> UTF8_DECODER = new ThreadLocal<CharsetDecoder>() {
|
||||
@Override
|
||||
protected CharsetDecoder initialValue() {
|
||||
return Charset.forName("UTF-8").newDecoder();
|
||||
}
|
||||
};
|
||||
public final static ThreadLocal<Charset> UTF8_CHARSET = new ThreadLocal<Charset>() {
|
||||
@Override
|
||||
protected Charset initialValue() {
|
||||
return Charset.forName("UTF-8");
|
||||
}
|
||||
};
|
||||
private final static ThreadLocal<CharBuffer> CHAR_BUFFER = new ThreadLocal<CharBuffer>();
|
||||
/** Used to hold the position of the `bb` buffer. */
|
||||
protected int bb_pos;
|
||||
/** The underlying ByteBuffer to hold the data of the Table. */
|
||||
protected ByteBuffer bb;
|
||||
/** Used to hold the vtable position. */
|
||||
protected int vtable_start;
|
||||
/** Used to hold the vtable size. */
|
||||
protected int vtable_size;
|
||||
Utf8 utf8 = Utf8.getDefault();
|
||||
|
||||
/**
|
||||
* Get the underlying ByteBuffer.
|
||||
@@ -63,8 +57,7 @@ public class Table {
|
||||
* @return Returns an offset into the object, or `0` if the field is not present.
|
||||
*/
|
||||
protected int __offset(int vtable_offset) {
|
||||
int vtable = bb_pos - bb.getInt(bb_pos);
|
||||
return vtable_offset < bb.getShort(vtable) ? bb.getShort(vtable + vtable_offset) : 0;
|
||||
return vtable_offset < vtable_size ? bb.getShort(vtable_start + vtable_offset) : 0;
|
||||
}
|
||||
|
||||
protected static int __offset(int vtable_offset, int offset, ByteBuffer bb) {
|
||||
@@ -98,34 +91,9 @@ public class Table {
|
||||
* @return Returns a `String` from the data stored inside the FlatBuffer at `offset`.
|
||||
*/
|
||||
protected String __string(int offset) {
|
||||
CharsetDecoder decoder = UTF8_DECODER.get();
|
||||
decoder.reset();
|
||||
|
||||
offset += bb.getInt(offset);
|
||||
ByteBuffer src = bb.duplicate().order(ByteOrder.LITTLE_ENDIAN);
|
||||
int length = src.getInt(offset);
|
||||
src.position(offset + SIZEOF_INT);
|
||||
src.limit(offset + SIZEOF_INT + length);
|
||||
|
||||
int required = (int)((float)length * decoder.maxCharsPerByte());
|
||||
CharBuffer dst = CHAR_BUFFER.get();
|
||||
if (dst == null || dst.capacity() < required) {
|
||||
dst = CharBuffer.allocate(required);
|
||||
CHAR_BUFFER.set(dst);
|
||||
}
|
||||
|
||||
dst.clear();
|
||||
|
||||
try {
|
||||
CoderResult cr = decoder.decode(src, dst, true);
|
||||
if (!cr.isUnderflow()) {
|
||||
cr.throwException();
|
||||
}
|
||||
} catch (CharacterCodingException x) {
|
||||
throw new RuntimeException(x);
|
||||
}
|
||||
|
||||
return dst.flip().toString();
|
||||
int length = bb.getInt(offset);
|
||||
return utf8.decodeUtf8(bb, offset + SIZEOF_INT, length);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -204,6 +172,8 @@ public class Table {
|
||||
offset += bb_pos;
|
||||
t.bb_pos = offset + bb.getInt(offset);
|
||||
t.bb = bb;
|
||||
t.vtable_start = t.bb_pos - bb.getInt(t.bb_pos);
|
||||
t.vtable_size = bb.getShort(t.vtable_start);
|
||||
return t;
|
||||
}
|
||||
|
||||
@@ -303,6 +273,8 @@ public class Table {
|
||||
public void __reset() {
|
||||
bb = null;
|
||||
bb_pos = 0;
|
||||
vtable_start = 0;
|
||||
vtable_size = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
191
java/com/google/flatbuffers/Utf8.java
Normal file
191
java/com/google/flatbuffers/Utf8.java
Normal file
@@ -0,0 +1,191 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.google.flatbuffers;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import static java.lang.Character.MIN_HIGH_SURROGATE;
|
||||
import static java.lang.Character.MIN_LOW_SURROGATE;
|
||||
import static java.lang.Character.MIN_SUPPLEMENTARY_CODE_POINT;
|
||||
|
||||
public abstract class Utf8 {
|
||||
|
||||
/**
|
||||
* Returns the number of bytes in the UTF-8-encoded form of {@code sequence}. For a string,
|
||||
* this method is equivalent to {@code string.getBytes(UTF_8).length}, but is more efficient in
|
||||
* both time and space.
|
||||
*
|
||||
* @throws IllegalArgumentException if {@code sequence} contains ill-formed UTF-16 (unpaired
|
||||
* surrogates)
|
||||
*/
|
||||
public abstract int encodedLength(CharSequence sequence);
|
||||
|
||||
/**
|
||||
* Encodes the given characters to the target {@link ByteBuffer} using UTF-8 encoding.
|
||||
*
|
||||
* <p>Selects an optimal algorithm based on the type of {@link ByteBuffer} (i.e. heap or direct)
|
||||
* and the capabilities of the platform.
|
||||
*
|
||||
* @param in the source string to be encoded
|
||||
* @param out the target buffer to receive the encoded string.
|
||||
*/
|
||||
public abstract void encodeUtf8(CharSequence in, ByteBuffer out);
|
||||
|
||||
/**
|
||||
* Decodes the given UTF-8 portion of the {@link ByteBuffer} into a {@link String}.
|
||||
*
|
||||
* @throws IllegalArgumentException if the input is not valid UTF-8.
|
||||
*/
|
||||
public abstract String decodeUtf8(ByteBuffer buffer, int offset, int length);
|
||||
|
||||
private static Utf8 DEFAULT;
|
||||
|
||||
/**
|
||||
* Get the default UTF-8 processor.
|
||||
* @return the default processor
|
||||
*/
|
||||
public static Utf8 getDefault() {
|
||||
if (DEFAULT == null) {
|
||||
DEFAULT = new Utf8Safe();
|
||||
}
|
||||
return DEFAULT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the default instance of the UTF-8 processor.
|
||||
* @param instance the new instance to use
|
||||
*/
|
||||
public static void setDefault(Utf8 instance) {
|
||||
DEFAULT = instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility methods for decoding bytes into {@link String}. Callers are responsible for extracting
|
||||
* bytes (possibly using Unsafe methods), and checking remaining bytes. All other UTF-8 validity
|
||||
* checks and codepoint conversion happen in this class.
|
||||
*/
|
||||
static class DecodeUtil {
|
||||
|
||||
/**
|
||||
* Returns whether this is a single-byte codepoint (i.e., ASCII) with the form '0XXXXXXX'.
|
||||
*/
|
||||
static boolean isOneByte(byte b) {
|
||||
return b >= 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this is a two-byte codepoint with the form '10XXXXXX'.
|
||||
*/
|
||||
static boolean isTwoBytes(byte b) {
|
||||
return b < (byte) 0xE0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this is a three-byte codepoint with the form '110XXXXX'.
|
||||
*/
|
||||
static boolean isThreeBytes(byte b) {
|
||||
return b < (byte) 0xF0;
|
||||
}
|
||||
|
||||
static void handleOneByte(byte byte1, char[] resultArr, int resultPos) {
|
||||
resultArr[resultPos] = (char) byte1;
|
||||
}
|
||||
|
||||
static void handleTwoBytes(
|
||||
byte byte1, byte byte2, char[] resultArr, int resultPos)
|
||||
throws IllegalArgumentException {
|
||||
// Simultaneously checks for illegal trailing-byte in leading position (<= '11000000') and
|
||||
// overlong 2-byte, '11000001'.
|
||||
if (byte1 < (byte) 0xC2
|
||||
|| isNotTrailingByte(byte2)) {
|
||||
throw new IllegalArgumentException("Invalid UTF-8");
|
||||
}
|
||||
resultArr[resultPos] = (char) (((byte1 & 0x1F) << 6) | trailingByteValue(byte2));
|
||||
}
|
||||
|
||||
static void handleThreeBytes(
|
||||
byte byte1, byte byte2, byte byte3, char[] resultArr, int resultPos)
|
||||
throws IllegalArgumentException {
|
||||
if (isNotTrailingByte(byte2)
|
||||
// overlong? 5 most significant bits must not all be zero
|
||||
|| (byte1 == (byte) 0xE0 && byte2 < (byte) 0xA0)
|
||||
// check for illegal surrogate codepoints
|
||||
|| (byte1 == (byte) 0xED && byte2 >= (byte) 0xA0)
|
||||
|| isNotTrailingByte(byte3)) {
|
||||
throw new IllegalArgumentException("Invalid UTF-8");
|
||||
}
|
||||
resultArr[resultPos] = (char)
|
||||
(((byte1 & 0x0F) << 12) | (trailingByteValue(byte2) << 6) | trailingByteValue(byte3));
|
||||
}
|
||||
|
||||
static void handleFourBytes(
|
||||
byte byte1, byte byte2, byte byte3, byte byte4, char[] resultArr, int resultPos)
|
||||
throws IllegalArgumentException{
|
||||
if (isNotTrailingByte(byte2)
|
||||
// Check that 1 <= plane <= 16. Tricky optimized form of:
|
||||
// valid 4-byte leading byte?
|
||||
// if (byte1 > (byte) 0xF4 ||
|
||||
// overlong? 4 most significant bits must not all be zero
|
||||
// byte1 == (byte) 0xF0 && byte2 < (byte) 0x90 ||
|
||||
// codepoint larger than the highest code point (U+10FFFF)?
|
||||
// byte1 == (byte) 0xF4 && byte2 > (byte) 0x8F)
|
||||
|| (((byte1 << 28) + (byte2 - (byte) 0x90)) >> 30) != 0
|
||||
|| isNotTrailingByte(byte3)
|
||||
|| isNotTrailingByte(byte4)) {
|
||||
throw new IllegalArgumentException("Invalid UTF-8");
|
||||
}
|
||||
int codepoint = ((byte1 & 0x07) << 18)
|
||||
| (trailingByteValue(byte2) << 12)
|
||||
| (trailingByteValue(byte3) << 6)
|
||||
| trailingByteValue(byte4);
|
||||
resultArr[resultPos] = DecodeUtil.highSurrogate(codepoint);
|
||||
resultArr[resultPos + 1] = DecodeUtil.lowSurrogate(codepoint);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the byte is not a valid continuation of the form '10XXXXXX'.
|
||||
*/
|
||||
private static boolean isNotTrailingByte(byte b) {
|
||||
return b > (byte) 0xBF;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the actual value of the trailing byte (removes the prefix '10') for composition.
|
||||
*/
|
||||
private static int trailingByteValue(byte b) {
|
||||
return b & 0x3F;
|
||||
}
|
||||
|
||||
private static char highSurrogate(int codePoint) {
|
||||
return (char) ((MIN_HIGH_SURROGATE - (MIN_SUPPLEMENTARY_CODE_POINT >>> 10))
|
||||
+ (codePoint >>> 10));
|
||||
}
|
||||
|
||||
private static char lowSurrogate(int codePoint) {
|
||||
return (char) (MIN_LOW_SURROGATE + (codePoint & 0x3ff));
|
||||
}
|
||||
}
|
||||
|
||||
// These UTF-8 handling methods are copied from Guava's Utf8Unsafe class with a modification to throw
|
||||
// a protocol buffer local exception. This exception is then caught in CodedOutputStream so it can
|
||||
// fallback to more lenient behavior.
|
||||
static class UnpairedSurrogateException extends IllegalArgumentException {
|
||||
UnpairedSurrogateException(int index, int length) {
|
||||
super("Unpaired surrogate at index " + index + " of " + length);
|
||||
}
|
||||
}
|
||||
}
|
||||
99
java/com/google/flatbuffers/Utf8Old.java
Normal file
99
java/com/google/flatbuffers/Utf8Old.java
Normal file
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.google.flatbuffers;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.CharBuffer;
|
||||
import java.nio.charset.CharacterCodingException;
|
||||
import java.nio.charset.CharsetDecoder;
|
||||
import java.nio.charset.CharsetEncoder;
|
||||
import java.nio.charset.CoderResult;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
/**
|
||||
* This class implements the Utf8 API using the Java Utf8 encoder. Use
|
||||
* Utf8.setDefault(new Utf8Old()); to use it.
|
||||
*/
|
||||
public class Utf8Old extends Utf8 {
|
||||
|
||||
private static class Cache {
|
||||
final CharsetEncoder encoder;
|
||||
final CharsetDecoder decoder;
|
||||
CharSequence lastInput = null;
|
||||
ByteBuffer lastOutput = null;
|
||||
|
||||
Cache() {
|
||||
encoder = StandardCharsets.UTF_8.newEncoder();
|
||||
decoder = StandardCharsets.UTF_8.newDecoder();
|
||||
}
|
||||
}
|
||||
|
||||
private static final ThreadLocal<Cache> CACHE =
|
||||
ThreadLocal.withInitial(() -> new Cache());
|
||||
|
||||
// Play some games so that the old encoder doesn't pay twice for computing
|
||||
// the length of the encoded string.
|
||||
|
||||
@Override
|
||||
public int encodedLength(CharSequence in) {
|
||||
final Cache cache = CACHE.get();
|
||||
int estimated = (int) (in.length() * cache.encoder.maxBytesPerChar());
|
||||
if (cache.lastOutput == null || cache.lastOutput.capacity() < estimated) {
|
||||
cache.lastOutput = ByteBuffer.allocate(Math.max(128, estimated));
|
||||
}
|
||||
cache.lastOutput.clear();
|
||||
cache.lastInput = in;
|
||||
CharBuffer wrap = (in instanceof CharBuffer) ?
|
||||
(CharBuffer) in : CharBuffer.wrap(in);
|
||||
CoderResult result = cache.encoder.encode(wrap, cache.lastOutput, true);
|
||||
if (result.isError()) {
|
||||
try {
|
||||
result.throwException();
|
||||
} catch (CharacterCodingException e) {
|
||||
throw new IllegalArgumentException("bad character encoding", e);
|
||||
}
|
||||
}
|
||||
return cache.lastOutput.remaining();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encodeUtf8(CharSequence in, ByteBuffer out) {
|
||||
final Cache cache = CACHE.get();
|
||||
if (cache.lastInput != in) {
|
||||
// Update the lastOutput to match our input, although flatbuffer should
|
||||
// never take this branch.
|
||||
encodedLength(in);
|
||||
}
|
||||
out.put(cache.lastOutput);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String decodeUtf8(ByteBuffer buffer, int offset, int length) {
|
||||
CharsetDecoder decoder = CACHE.get().decoder;
|
||||
decoder.reset();
|
||||
buffer = buffer.duplicate();
|
||||
buffer.position(offset);
|
||||
buffer.limit(offset + length);
|
||||
try {
|
||||
CharBuffer result = decoder.decode(buffer);
|
||||
result.flip();
|
||||
return result.toString();
|
||||
} catch (CharacterCodingException e) {
|
||||
throw new IllegalArgumentException("Bad encoding", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
451
java/com/google/flatbuffers/Utf8Safe.java
Normal file
451
java/com/google/flatbuffers/Utf8Safe.java
Normal file
@@ -0,0 +1,451 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// 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.
|
||||
|
||||
package com.google.flatbuffers;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import static java.lang.Character.MAX_SURROGATE;
|
||||
import static java.lang.Character.MIN_SUPPLEMENTARY_CODE_POINT;
|
||||
import static java.lang.Character.MIN_SURROGATE;
|
||||
import static java.lang.Character.isSurrogatePair;
|
||||
import static java.lang.Character.toCodePoint;
|
||||
|
||||
/**
|
||||
* A set of low-level, high-performance static utility methods related
|
||||
* to the UTF-8 character encoding. This class has no dependencies
|
||||
* outside of the core JDK libraries.
|
||||
*
|
||||
* <p>There are several variants of UTF-8. The one implemented by
|
||||
* this class is the restricted definition of UTF-8 introduced in
|
||||
* Unicode 3.1, which mandates the rejection of "overlong" byte
|
||||
* sequences as well as rejection of 3-byte surrogate codepoint byte
|
||||
* sequences. Note that the UTF-8 decoder included in Oracle's JDK
|
||||
* has been modified to also reject "overlong" byte sequences, but (as
|
||||
* of 2011) still accepts 3-byte surrogate codepoint byte sequences.
|
||||
*
|
||||
* <p>The byte sequences considered valid by this class are exactly
|
||||
* those that can be roundtrip converted to Strings and back to bytes
|
||||
* using the UTF-8 charset, without loss: <pre> {@code
|
||||
* Arrays.equals(bytes, new String(bytes, Internal.UTF_8).getBytes(Internal.UTF_8))
|
||||
* }</pre>
|
||||
*
|
||||
* <p>See the Unicode Standard,</br>
|
||||
* Table 3-6. <em>UTF-8 Bit Distribution</em>,</br>
|
||||
* Table 3-7. <em>Well Formed UTF-8 Byte Sequences</em>.
|
||||
*/
|
||||
final public class Utf8Safe extends Utf8 {
|
||||
|
||||
/**
|
||||
* Returns the number of bytes in the UTF-8-encoded form of {@code sequence}. For a string,
|
||||
* this method is equivalent to {@code string.getBytes(UTF_8).length}, but is more efficient in
|
||||
* both time and space.
|
||||
*
|
||||
* @throws IllegalArgumentException if {@code sequence} contains ill-formed UTF-16 (unpaired
|
||||
* surrogates)
|
||||
*/
|
||||
private static int computeEncodedLength(CharSequence sequence) {
|
||||
// Warning to maintainers: this implementation is highly optimized.
|
||||
int utf16Length = sequence.length();
|
||||
int utf8Length = utf16Length;
|
||||
int i = 0;
|
||||
|
||||
// This loop optimizes for pure ASCII.
|
||||
while (i < utf16Length && sequence.charAt(i) < 0x80) {
|
||||
i++;
|
||||
}
|
||||
|
||||
// This loop optimizes for chars less than 0x800.
|
||||
for (; i < utf16Length; i++) {
|
||||
char c = sequence.charAt(i);
|
||||
if (c < 0x800) {
|
||||
utf8Length += ((0x7f - c) >>> 31); // branch free!
|
||||
} else {
|
||||
utf8Length += encodedLengthGeneral(sequence, i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (utf8Length < utf16Length) {
|
||||
// Necessary and sufficient condition for overflow because of maximum 3x expansion
|
||||
throw new IllegalArgumentException("UTF-8 length does not fit in int: "
|
||||
+ (utf8Length + (1L << 32)));
|
||||
}
|
||||
return utf8Length;
|
||||
}
|
||||
|
||||
private static int encodedLengthGeneral(CharSequence sequence, int start) {
|
||||
int utf16Length = sequence.length();
|
||||
int utf8Length = 0;
|
||||
for (int i = start; i < utf16Length; i++) {
|
||||
char c = sequence.charAt(i);
|
||||
if (c < 0x800) {
|
||||
utf8Length += (0x7f - c) >>> 31; // branch free!
|
||||
} else {
|
||||
utf8Length += 2;
|
||||
// jdk7+: if (Character.isSurrogate(c)) {
|
||||
if (Character.MIN_SURROGATE <= c && c <= Character.MAX_SURROGATE) {
|
||||
// Check that we have a well-formed surrogate pair.
|
||||
int cp = Character.codePointAt(sequence, i);
|
||||
if (cp < MIN_SUPPLEMENTARY_CODE_POINT) {
|
||||
throw new Utf8Safe.UnpairedSurrogateException(i, utf16Length);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
return utf8Length;
|
||||
}
|
||||
|
||||
private static String decodeUtf8Array(byte[] bytes, int index, int size) {
|
||||
// Bitwise OR combines the sign bits so any negative value fails the check.
|
||||
if ((index | size | bytes.length - index - size) < 0) {
|
||||
throw new ArrayIndexOutOfBoundsException(
|
||||
String.format("buffer length=%d, index=%d, size=%d", bytes.length, index, size));
|
||||
}
|
||||
|
||||
int offset = index;
|
||||
final int limit = offset + size;
|
||||
|
||||
// The longest possible resulting String is the same as the number of input bytes, when it is
|
||||
// all ASCII. For other cases, this over-allocates and we will truncate in the end.
|
||||
char[] resultArr = new char[size];
|
||||
int resultPos = 0;
|
||||
|
||||
// Optimize for 100% ASCII (Hotspot loves small simple top-level loops like this).
|
||||
// This simple loop stops when we encounter a byte >= 0x80 (i.e. non-ASCII).
|
||||
while (offset < limit) {
|
||||
byte b = bytes[offset];
|
||||
if (!DecodeUtil.isOneByte(b)) {
|
||||
break;
|
||||
}
|
||||
offset++;
|
||||
DecodeUtil.handleOneByte(b, resultArr, resultPos++);
|
||||
}
|
||||
|
||||
while (offset < limit) {
|
||||
byte byte1 = bytes[offset++];
|
||||
if (DecodeUtil.isOneByte(byte1)) {
|
||||
DecodeUtil.handleOneByte(byte1, resultArr, resultPos++);
|
||||
// It's common for there to be multiple ASCII characters in a run mixed in, so add an
|
||||
// extra optimized loop to take care of these runs.
|
||||
while (offset < limit) {
|
||||
byte b = bytes[offset];
|
||||
if (!DecodeUtil.isOneByte(b)) {
|
||||
break;
|
||||
}
|
||||
offset++;
|
||||
DecodeUtil.handleOneByte(b, resultArr, resultPos++);
|
||||
}
|
||||
} else if (DecodeUtil.isTwoBytes(byte1)) {
|
||||
if (offset >= limit) {
|
||||
throw new IllegalArgumentException("Invalid UTF-8");
|
||||
}
|
||||
DecodeUtil.handleTwoBytes(byte1, /* byte2 */ bytes[offset++], resultArr, resultPos++);
|
||||
} else if (DecodeUtil.isThreeBytes(byte1)) {
|
||||
if (offset >= limit - 1) {
|
||||
throw new IllegalArgumentException("Invalid UTF-8");
|
||||
}
|
||||
DecodeUtil.handleThreeBytes(
|
||||
byte1,
|
||||
/* byte2 */ bytes[offset++],
|
||||
/* byte3 */ bytes[offset++],
|
||||
resultArr,
|
||||
resultPos++);
|
||||
} else {
|
||||
if (offset >= limit - 2) {
|
||||
throw new IllegalArgumentException("Invalid UTF-8");
|
||||
}
|
||||
DecodeUtil.handleFourBytes(
|
||||
byte1,
|
||||
/* byte2 */ bytes[offset++],
|
||||
/* byte3 */ bytes[offset++],
|
||||
/* byte4 */ bytes[offset++],
|
||||
resultArr,
|
||||
resultPos++);
|
||||
// 4-byte case requires two chars.
|
||||
resultPos++;
|
||||
}
|
||||
}
|
||||
|
||||
return new String(resultArr, 0, resultPos);
|
||||
}
|
||||
|
||||
private static String decodeUtf8Buffer(ByteBuffer buffer, int offset,
|
||||
int length) {
|
||||
// Bitwise OR combines the sign bits so any negative value fails the check.
|
||||
if ((offset | length | buffer.limit() - offset - length) < 0) {
|
||||
throw new ArrayIndexOutOfBoundsException(
|
||||
String.format("buffer limit=%d, index=%d, limit=%d", buffer.limit(),
|
||||
offset, length));
|
||||
}
|
||||
|
||||
final int limit = offset + length;
|
||||
|
||||
// The longest possible resulting String is the same as the number of input bytes, when it is
|
||||
// all ASCII. For other cases, this over-allocates and we will truncate in the end.
|
||||
char[] resultArr = new char[length];
|
||||
int resultPos = 0;
|
||||
|
||||
// Optimize for 100% ASCII (Hotspot loves small simple top-level loops like this).
|
||||
// This simple loop stops when we encounter a byte >= 0x80 (i.e. non-ASCII).
|
||||
while (offset < limit) {
|
||||
byte b = buffer.get(offset);
|
||||
if (!DecodeUtil.isOneByte(b)) {
|
||||
break;
|
||||
}
|
||||
offset++;
|
||||
DecodeUtil.handleOneByte(b, resultArr, resultPos++);
|
||||
}
|
||||
|
||||
while (offset < limit) {
|
||||
byte byte1 = buffer.get(offset++);
|
||||
if (DecodeUtil.isOneByte(byte1)) {
|
||||
DecodeUtil.handleOneByte(byte1, resultArr, resultPos++);
|
||||
// It's common for there to be multiple ASCII characters in a run mixed in, so add an
|
||||
// extra optimized loop to take care of these runs.
|
||||
while (offset < limit) {
|
||||
byte b = buffer.get(offset);
|
||||
if (!DecodeUtil.isOneByte(b)) {
|
||||
break;
|
||||
}
|
||||
offset++;
|
||||
DecodeUtil.handleOneByte(b, resultArr, resultPos++);
|
||||
}
|
||||
} else if (DecodeUtil.isTwoBytes(byte1)) {
|
||||
if (offset >= limit) {
|
||||
throw new IllegalArgumentException("Invalid UTF-8");
|
||||
}
|
||||
DecodeUtil.handleTwoBytes(
|
||||
byte1, /* byte2 */ buffer.get(offset++), resultArr, resultPos++);
|
||||
} else if (DecodeUtil.isThreeBytes(byte1)) {
|
||||
if (offset >= limit - 1) {
|
||||
throw new IllegalArgumentException("Invalid UTF-8");
|
||||
}
|
||||
DecodeUtil.handleThreeBytes(
|
||||
byte1,
|
||||
/* byte2 */ buffer.get(offset++),
|
||||
/* byte3 */ buffer.get(offset++),
|
||||
resultArr,
|
||||
resultPos++);
|
||||
} else {
|
||||
if (offset >= limit - 2) {
|
||||
throw new IllegalArgumentException("Invalid UTF-8");
|
||||
}
|
||||
DecodeUtil.handleFourBytes(
|
||||
byte1,
|
||||
/* byte2 */ buffer.get(offset++),
|
||||
/* byte3 */ buffer.get(offset++),
|
||||
/* byte4 */ buffer.get(offset++),
|
||||
resultArr,
|
||||
resultPos++);
|
||||
// 4-byte case requires two chars.
|
||||
resultPos++;
|
||||
}
|
||||
}
|
||||
|
||||
return new String(resultArr, 0, resultPos);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int encodedLength(CharSequence in) {
|
||||
return computeEncodedLength(in);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes the given UTF-8 portion of the {@link ByteBuffer} into a {@link String}.
|
||||
*
|
||||
* @throws IllegalArgumentException if the input is not valid UTF-8.
|
||||
*/
|
||||
@Override
|
||||
public String decodeUtf8(ByteBuffer buffer, int offset, int length)
|
||||
throws IllegalArgumentException {
|
||||
if (buffer.hasArray()) {
|
||||
return decodeUtf8Array(buffer.array(), buffer.arrayOffset() + offset, length);
|
||||
} else {
|
||||
return decodeUtf8Buffer(buffer, offset, length);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static void encodeUtf8Buffer(CharSequence in, ByteBuffer out) {
|
||||
final int inLength = in.length();
|
||||
int outIx = out.position();
|
||||
int inIx = 0;
|
||||
|
||||
// Since ByteBuffer.putXXX() already checks boundaries for us, no need to explicitly check
|
||||
// access. Assume the buffer is big enough and let it handle the out of bounds exception
|
||||
// if it occurs.
|
||||
try {
|
||||
// Designed to take advantage of
|
||||
// https://wikis.oracle.com/display/HotSpotInternals/RangeCheckElimination
|
||||
for (char c; inIx < inLength && (c = in.charAt(inIx)) < 0x80; ++inIx) {
|
||||
out.put(outIx + inIx, (byte) c);
|
||||
}
|
||||
if (inIx == inLength) {
|
||||
// Successfully encoded the entire string.
|
||||
out.position(outIx + inIx);
|
||||
return;
|
||||
}
|
||||
|
||||
outIx += inIx;
|
||||
for (char c; inIx < inLength; ++inIx, ++outIx) {
|
||||
c = in.charAt(inIx);
|
||||
if (c < 0x80) {
|
||||
// One byte (0xxx xxxx)
|
||||
out.put(outIx, (byte) c);
|
||||
} else if (c < 0x800) {
|
||||
// Two bytes (110x xxxx 10xx xxxx)
|
||||
|
||||
// Benchmarks show put performs better than putShort here (for HotSpot).
|
||||
out.put(outIx++, (byte) (0xC0 | (c >>> 6)));
|
||||
out.put(outIx, (byte) (0x80 | (0x3F & c)));
|
||||
} else if (c < MIN_SURROGATE || MAX_SURROGATE < c) {
|
||||
// Three bytes (1110 xxxx 10xx xxxx 10xx xxxx)
|
||||
// Maximum single-char code point is 0xFFFF, 16 bits.
|
||||
|
||||
// Benchmarks show put performs better than putShort here (for HotSpot).
|
||||
out.put(outIx++, (byte) (0xE0 | (c >>> 12)));
|
||||
out.put(outIx++, (byte) (0x80 | (0x3F & (c >>> 6))));
|
||||
out.put(outIx, (byte) (0x80 | (0x3F & c)));
|
||||
} else {
|
||||
// Four bytes (1111 xxxx 10xx xxxx 10xx xxxx 10xx xxxx)
|
||||
|
||||
// Minimum code point represented by a surrogate pair is 0x10000, 17 bits, four UTF-8
|
||||
// bytes
|
||||
final char low;
|
||||
if (inIx + 1 == inLength || !isSurrogatePair(c, (low = in.charAt(++inIx)))) {
|
||||
throw new UnpairedSurrogateException(inIx, inLength);
|
||||
}
|
||||
// TODO(nathanmittler): Consider using putInt() to improve performance.
|
||||
int codePoint = toCodePoint(c, low);
|
||||
out.put(outIx++, (byte) ((0xF << 4) | (codePoint >>> 18)));
|
||||
out.put(outIx++, (byte) (0x80 | (0x3F & (codePoint >>> 12))));
|
||||
out.put(outIx++, (byte) (0x80 | (0x3F & (codePoint >>> 6))));
|
||||
out.put(outIx, (byte) (0x80 | (0x3F & codePoint)));
|
||||
}
|
||||
}
|
||||
|
||||
// Successfully encoded the entire string.
|
||||
out.position(outIx);
|
||||
} catch (IndexOutOfBoundsException e) {
|
||||
// TODO(nathanmittler): Consider making the API throw IndexOutOfBoundsException instead.
|
||||
|
||||
// If we failed in the outer ASCII loop, outIx will not have been updated. In this case,
|
||||
// use inIx to determine the bad write index.
|
||||
int badWriteIndex = out.position() + Math.max(inIx, outIx - out.position() + 1);
|
||||
throw new ArrayIndexOutOfBoundsException(
|
||||
"Failed writing " + in.charAt(inIx) + " at index " + badWriteIndex);
|
||||
}
|
||||
}
|
||||
|
||||
private static int encodeUtf8Array(CharSequence in, byte[] out,
|
||||
int offset, int length) {
|
||||
int utf16Length = in.length();
|
||||
int j = offset;
|
||||
int i = 0;
|
||||
int limit = offset + length;
|
||||
// Designed to take advantage of
|
||||
// https://wikis.oracle.com/display/HotSpotInternals/RangeCheckElimination
|
||||
for (char c; i < utf16Length && i + j < limit && (c = in.charAt(i)) < 0x80; i++) {
|
||||
out[j + i] = (byte) c;
|
||||
}
|
||||
if (i == utf16Length) {
|
||||
return j + utf16Length;
|
||||
}
|
||||
j += i;
|
||||
for (char c; i < utf16Length; i++) {
|
||||
c = in.charAt(i);
|
||||
if (c < 0x80 && j < limit) {
|
||||
out[j++] = (byte) c;
|
||||
} else if (c < 0x800 && j <= limit - 2) { // 11 bits, two UTF-8 bytes
|
||||
out[j++] = (byte) ((0xF << 6) | (c >>> 6));
|
||||
out[j++] = (byte) (0x80 | (0x3F & c));
|
||||
} else if ((c < Character.MIN_SURROGATE || Character.MAX_SURROGATE < c) && j <= limit - 3) {
|
||||
// Maximum single-char code point is 0xFFFF, 16 bits, three UTF-8 bytes
|
||||
out[j++] = (byte) ((0xF << 5) | (c >>> 12));
|
||||
out[j++] = (byte) (0x80 | (0x3F & (c >>> 6)));
|
||||
out[j++] = (byte) (0x80 | (0x3F & c));
|
||||
} else if (j <= limit - 4) {
|
||||
// Minimum code point represented by a surrogate pair is 0x10000, 17 bits,
|
||||
// four UTF-8 bytes
|
||||
final char low;
|
||||
if (i + 1 == in.length()
|
||||
|| !Character.isSurrogatePair(c, (low = in.charAt(++i)))) {
|
||||
throw new UnpairedSurrogateException((i - 1), utf16Length);
|
||||
}
|
||||
int codePoint = Character.toCodePoint(c, low);
|
||||
out[j++] = (byte) ((0xF << 4) | (codePoint >>> 18));
|
||||
out[j++] = (byte) (0x80 | (0x3F & (codePoint >>> 12)));
|
||||
out[j++] = (byte) (0x80 | (0x3F & (codePoint >>> 6)));
|
||||
out[j++] = (byte) (0x80 | (0x3F & codePoint));
|
||||
} else {
|
||||
// If we are surrogates and we're not a surrogate pair, always throw an
|
||||
// UnpairedSurrogateException instead of an ArrayOutOfBoundsException.
|
||||
if ((Character.MIN_SURROGATE <= c && c <= Character.MAX_SURROGATE)
|
||||
&& (i + 1 == in.length()
|
||||
|| !Character.isSurrogatePair(c, in.charAt(i + 1)))) {
|
||||
throw new UnpairedSurrogateException(i, utf16Length);
|
||||
}
|
||||
throw new ArrayIndexOutOfBoundsException("Failed writing " + c + " at index " + j);
|
||||
}
|
||||
}
|
||||
return j;
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes the given characters to the target {@link ByteBuffer} using UTF-8 encoding.
|
||||
*
|
||||
* <p>Selects an optimal algorithm based on the type of {@link ByteBuffer} (i.e. heap or direct)
|
||||
* and the capabilities of the platform.
|
||||
*
|
||||
* @param in the source string to be encoded
|
||||
* @param out the target buffer to receive the encoded string.
|
||||
*/
|
||||
@Override
|
||||
public void encodeUtf8(CharSequence in, ByteBuffer out) {
|
||||
if (out.hasArray()) {
|
||||
int start = out.arrayOffset();
|
||||
int end = encodeUtf8Array(in, out.array(), start + out.position(),
|
||||
out.remaining());
|
||||
out.position(end - start);
|
||||
} else {
|
||||
encodeUtf8Buffer(in, out);
|
||||
}
|
||||
}
|
||||
|
||||
// These UTF-8 handling methods are copied from Guava's Utf8Unsafe class with
|
||||
// a modification to throw a local exception. This exception can be caught
|
||||
// to fallback to more lenient behavior.
|
||||
static class UnpairedSurrogateException extends IllegalArgumentException {
|
||||
UnpairedSurrogateException(int index, int length) {
|
||||
super("Unpaired surrogate at index " + index + " of " + length);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -226,6 +226,19 @@ flatbuffers.Builder = function(opt_initial_size) {
|
||||
this.force_defaults = false;
|
||||
};
|
||||
|
||||
flatbuffers.Builder.prototype.clear = function() {
|
||||
this.bb.clear();
|
||||
this.space = this.bb.capacity();
|
||||
this.minalign = 1;
|
||||
this.vtable = null;
|
||||
this.vtable_in_use = 0;
|
||||
this.isNested = false;
|
||||
this.object_start = 0;
|
||||
this.vtables = [];
|
||||
this.vector_num_elems = 0;
|
||||
this.force_defaults = false;
|
||||
};
|
||||
|
||||
/**
|
||||
* In order to save space, fields that are set to their default value
|
||||
* don't get serialized into the buffer. Forcing defaults provides a
|
||||
@@ -828,6 +841,10 @@ flatbuffers.ByteBuffer.allocate = function(byte_size) {
|
||||
return new flatbuffers.ByteBuffer(new Uint8Array(byte_size));
|
||||
};
|
||||
|
||||
flatbuffers.ByteBuffer.prototype.clear = function() {
|
||||
this.position_ = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the underlying `Uint8Array`.
|
||||
*
|
||||
|
||||
@@ -34,7 +34,7 @@ local function vtableEqual(a, objectStart, b)
|
||||
end
|
||||
|
||||
for i, elem in ipairs(a) do
|
||||
local x = VOffsetT:Unpack(b, i * VOffsetT.bytewidth)
|
||||
local x = string.unpack(VOffsetT.packFmt, b, 1 + (i - 1) * VOffsetT.bytewidth)
|
||||
if x ~= 0 or elem ~= 0 then
|
||||
local y = objectStart - elem
|
||||
if x ~= y then
|
||||
@@ -96,11 +96,13 @@ function mt:WriteVtable()
|
||||
i = i - 1
|
||||
end
|
||||
|
||||
i = #self.vtables
|
||||
while i >= 1 do
|
||||
|
||||
local vt2Offset = self.vtables[i]
|
||||
local vt2Start = #self.bytes - vt2Offset
|
||||
local vt2len = VOffsetT:Unpack(self.bytes, vt2Start)
|
||||
local vt2lenstr = self.bytes:Slice(vt2Start, vt2Start+1)
|
||||
local vt2Len = string.unpack(VOffsetT.packFmt, vt2lenstr, 1)
|
||||
|
||||
local metadata = VtableMetadataFields * VOffsetT.bytewidth
|
||||
local vt2End = vt2Start + vt2Len
|
||||
@@ -364,4 +366,4 @@ function mt:Place(x, flags)
|
||||
self.bytes:Set(d, h)
|
||||
end
|
||||
|
||||
return m
|
||||
return m
|
||||
|
||||
@@ -119,8 +119,8 @@ local int16_mt =
|
||||
local int32_mt =
|
||||
{
|
||||
bytewidth = 4,
|
||||
min_value = -2^15,
|
||||
max_value = 2^15-1,
|
||||
min_value = -2^31,
|
||||
max_value = 2^31-1,
|
||||
lua_type = type(1),
|
||||
name = "int32",
|
||||
packFmt = "<i4"
|
||||
@@ -195,4 +195,4 @@ end
|
||||
|
||||
GenerateTypes(m)
|
||||
|
||||
return m
|
||||
return m
|
||||
|
||||
@@ -42,20 +42,24 @@ using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
#if ENABLE_SPAN_T
|
||||
using System.Buffers.Binary;
|
||||
#endif
|
||||
|
||||
#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
|
||||
public abstract class ByteBufferAllocator
|
||||
{
|
||||
#if UNSAFE_BYTEBUFFER
|
||||
public unsafe byte* Buffer
|
||||
{
|
||||
get;
|
||||
protected set;
|
||||
}
|
||||
#if ENABLE_SPAN_T
|
||||
public abstract Span<byte> Span { get; }
|
||||
public abstract ReadOnlySpan<byte> ReadOnlySpan { get; }
|
||||
public abstract Memory<byte> Memory { get; }
|
||||
public abstract ReadOnlyMemory<byte> ReadOnlyMemory { get; }
|
||||
|
||||
#else
|
||||
public byte[] Buffer
|
||||
{
|
||||
@@ -70,23 +74,17 @@ namespace FlatBuffers
|
||||
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
|
||||
public sealed class ByteArrayAllocator : ByteBufferAllocator
|
||||
{
|
||||
private byte[] _buffer;
|
||||
|
||||
public ByteArrayAllocator(byte[] buffer)
|
||||
{
|
||||
_buffer = buffer;
|
||||
InitPointer();
|
||||
InitBuffer();
|
||||
}
|
||||
|
||||
public override void GrowFront(int newSize)
|
||||
@@ -101,63 +99,29 @@ namespace FlatBuffers
|
||||
byte[] newBuffer = new byte[newSize];
|
||||
System.Buffer.BlockCopy(_buffer, 0, newBuffer, newSize - Length, Length);
|
||||
_buffer = newBuffer;
|
||||
InitPointer();
|
||||
InitBuffer();
|
||||
}
|
||||
|
||||
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; }
|
||||
}
|
||||
#if ENABLE_SPAN_T
|
||||
public override Span<byte> Span => _buffer;
|
||||
public override ReadOnlySpan<byte> ReadOnlySpan => _buffer;
|
||||
public override Memory<byte> Memory => _buffer;
|
||||
public override ReadOnlyMemory<byte> ReadOnlyMemory => _buffer;
|
||||
#endif
|
||||
|
||||
#if UNSAFE_BYTEBUFFER
|
||||
private GCHandle _handle;
|
||||
|
||||
~ByteArrayAllocator()
|
||||
{
|
||||
if (_handle.IsAllocated)
|
||||
{
|
||||
_handle.Free();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
private void InitPointer()
|
||||
private void InitBuffer()
|
||||
{
|
||||
Length = _buffer.Length;
|
||||
#if UNSAFE_BYTEBUFFER
|
||||
if (_handle.IsAllocated)
|
||||
{
|
||||
_handle.Free();
|
||||
}
|
||||
_handle = GCHandle.Alloc(_buffer, GCHandleType.Pinned);
|
||||
unsafe
|
||||
{
|
||||
Buffer = (byte*)_handle.AddrOfPinnedObject().ToPointer();
|
||||
}
|
||||
#else
|
||||
#if !ENABLE_SPAN_T
|
||||
Buffer = _buffer;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Class to mimic Java's ByteBuffer which is used heavily in Flatbuffers.
|
||||
/// </summary>
|
||||
public class ByteBuffer : IDisposable
|
||||
public class ByteBuffer
|
||||
{
|
||||
private ByteBufferAllocator _buffer;
|
||||
private int _pos; // Must track start of the buffer.
|
||||
@@ -178,15 +142,8 @@ namespace FlatBuffers
|
||||
_pos = pos;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
public int Position
|
||||
{
|
||||
if (_buffer != null)
|
||||
{
|
||||
_buffer.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
public int Position {
|
||||
get { return _pos; }
|
||||
set { _pos = value; }
|
||||
}
|
||||
@@ -278,16 +235,10 @@ namespace FlatBuffers
|
||||
// the buffer position and length.
|
||||
#if ENABLE_SPAN_T
|
||||
public T[] ToArray<T>(int pos, int len)
|
||||
where T: struct
|
||||
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;
|
||||
}
|
||||
AssertOffsetAndLength(pos, len);
|
||||
return MemoryMarshal.Cast<byte, T>(_buffer.ReadOnlySpan.Slice(pos)).Slice(0, len).ToArray();
|
||||
}
|
||||
#else
|
||||
public T[] ToArray<T>(int pos, int len)
|
||||
@@ -295,7 +246,7 @@ namespace FlatBuffers
|
||||
{
|
||||
AssertOffsetAndLength(pos, len);
|
||||
T[] arr = new T[len];
|
||||
Buffer.BlockCopy(_buffer.ByteArray, pos, arr, 0, ArraySize(arr));
|
||||
Buffer.BlockCopy(_buffer.Buffer, pos, arr, 0, ArraySize(arr));
|
||||
return arr;
|
||||
}
|
||||
#endif
|
||||
@@ -310,23 +261,30 @@ namespace FlatBuffers
|
||||
return ToArray<byte>(0, Length);
|
||||
}
|
||||
|
||||
|
||||
#if ENABLE_SPAN_T
|
||||
public unsafe Span<byte> ToSpan(int pos, int len)
|
||||
public ReadOnlyMemory<byte> ToReadOnlyMemory(int pos, int len)
|
||||
{
|
||||
return new Span<byte>(_buffer.Buffer, _buffer.Length).Slice(pos, len);
|
||||
return _buffer.ReadOnlyMemory.Slice(pos, len);
|
||||
}
|
||||
|
||||
public Memory<byte> ToMemory(int pos, int len)
|
||||
{
|
||||
return _buffer.Memory.Slice(pos, len);
|
||||
}
|
||||
|
||||
public Span<byte> ToSpan(int pos, int len)
|
||||
{
|
||||
return _buffer.Span.Slice(pos, len);
|
||||
}
|
||||
#else
|
||||
public ArraySegment<byte> ToArraySegment(int pos, int len)
|
||||
{
|
||||
return new ArraySegment<byte>(_buffer.ByteArray, pos, len);
|
||||
return new ArraySegment<byte>(_buffer.Buffer, pos, len);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !ENABLE_SPAN_T
|
||||
public MemoryStream ToMemoryStream(int pos, int len)
|
||||
{
|
||||
return new MemoryStream(_buffer.ByteArray, pos, len);
|
||||
return new MemoryStream(_buffer.Buffer, pos, len);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -391,15 +349,15 @@ namespace FlatBuffers
|
||||
{
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
r |= (ulong)_buffer.Buffer[offset + i] << i * 8;
|
||||
r |= (ulong)_buffer.Buffer[offset + i] << i * 8;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
r |= (ulong)_buffer.Buffer[offset + count - 1 - i] << i * 8;
|
||||
}
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
r |= (ulong)_buffer.Buffer[offset + count - 1 - i] << i * 8;
|
||||
}
|
||||
}
|
||||
return r;
|
||||
}
|
||||
@@ -414,31 +372,26 @@ namespace FlatBuffers
|
||||
#endif
|
||||
}
|
||||
|
||||
#if UNSAFE_BYTEBUFFER
|
||||
#if ENABLE_SPAN_T
|
||||
|
||||
public unsafe void PutSbyte(int offset, sbyte value)
|
||||
public void PutSbyte(int offset, sbyte value)
|
||||
{
|
||||
AssertOffsetAndLength(offset, sizeof(sbyte));
|
||||
_buffer.Buffer[offset] = (byte)value;
|
||||
_buffer.Span[offset] = (byte)value;
|
||||
}
|
||||
|
||||
public unsafe void PutByte(int offset, byte value)
|
||||
public void PutByte(int offset, byte value)
|
||||
{
|
||||
AssertOffsetAndLength(offset, sizeof(byte));
|
||||
_buffer.Buffer[offset] = value;
|
||||
_buffer.Span[offset] = value;
|
||||
}
|
||||
|
||||
public unsafe void PutByte(int offset, byte value, int count)
|
||||
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);
|
||||
Span<byte> span = _buffer.Span.Slice(offset, count);
|
||||
for (var i = 0; i < span.Length; ++i)
|
||||
span[i] = value;
|
||||
}
|
||||
#else
|
||||
public void PutSbyte(int offset, sbyte value)
|
||||
@@ -459,13 +412,13 @@ namespace FlatBuffers
|
||||
for (var i = 0; i < count; ++i)
|
||||
_buffer.Buffer[offset + i] = value;
|
||||
}
|
||||
#endif
|
||||
|
||||
// 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)
|
||||
@@ -473,7 +426,10 @@ namespace FlatBuffers
|
||||
AssertOffsetAndLength(offset, value.Length);
|
||||
fixed (char* s = value)
|
||||
{
|
||||
Encoding.UTF8.GetBytes(s, value.Length, _buffer.Buffer + offset, Length - offset);
|
||||
fixed (byte* buffer = &MemoryMarshal.GetReference(_buffer.Span))
|
||||
{
|
||||
Encoding.UTF8.GetBytes(s, value.Length, buffer + offset, Length - offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
@@ -481,7 +437,7 @@ namespace FlatBuffers
|
||||
{
|
||||
AssertOffsetAndLength(offset, value.Length);
|
||||
Encoding.UTF8.GetBytes(value, 0, value.Length,
|
||||
_buffer.ByteArray, offset);
|
||||
_buffer.Buffer, offset);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -495,10 +451,17 @@ namespace FlatBuffers
|
||||
public unsafe void PutUshort(int offset, ushort value)
|
||||
{
|
||||
AssertOffsetAndLength(offset, sizeof(ushort));
|
||||
byte* ptr = _buffer.Buffer;
|
||||
*(ushort*)(ptr + offset) = BitConverter.IsLittleEndian
|
||||
? value
|
||||
: ReverseBytes(value);
|
||||
#if ENABLE_SPAN_T
|
||||
Span<byte> span = _buffer.Span.Slice(offset);
|
||||
BinaryPrimitives.WriteUInt16LittleEndian(span, value);
|
||||
#else
|
||||
fixed (byte* ptr = _buffer.Buffer)
|
||||
{
|
||||
*(ushort*)(ptr + offset) = BitConverter.IsLittleEndian
|
||||
? value
|
||||
: ReverseBytes(value);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
public void PutInt(int offset, int value)
|
||||
@@ -509,10 +472,17 @@ namespace FlatBuffers
|
||||
public unsafe void PutUint(int offset, uint value)
|
||||
{
|
||||
AssertOffsetAndLength(offset, sizeof(uint));
|
||||
byte* ptr = _buffer.Buffer;
|
||||
*(uint*)(ptr + offset) = BitConverter.IsLittleEndian
|
||||
? value
|
||||
: ReverseBytes(value);
|
||||
#if ENABLE_SPAN_T
|
||||
Span<byte> span = _buffer.Span.Slice(offset);
|
||||
BinaryPrimitives.WriteUInt32LittleEndian(span, value);
|
||||
#else
|
||||
fixed (byte* ptr = _buffer.Buffer)
|
||||
{
|
||||
*(uint*)(ptr + offset) = BitConverter.IsLittleEndian
|
||||
? value
|
||||
: ReverseBytes(value);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
public unsafe void PutLong(int offset, long value)
|
||||
@@ -523,38 +493,56 @@ namespace FlatBuffers
|
||||
public unsafe void PutUlong(int offset, ulong value)
|
||||
{
|
||||
AssertOffsetAndLength(offset, sizeof(ulong));
|
||||
byte* ptr = _buffer.Buffer;
|
||||
*(ulong*)(ptr + offset) = BitConverter.IsLittleEndian
|
||||
? value
|
||||
: ReverseBytes(value);
|
||||
#if ENABLE_SPAN_T
|
||||
Span<byte> span = _buffer.Span.Slice(offset);
|
||||
BinaryPrimitives.WriteUInt64LittleEndian(span, value);
|
||||
#else
|
||||
fixed (byte* ptr = _buffer.Buffer)
|
||||
{
|
||||
*(ulong*)(ptr + offset) = BitConverter.IsLittleEndian
|
||||
? value
|
||||
: ReverseBytes(value);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
public unsafe void PutFloat(int offset, float value)
|
||||
{
|
||||
AssertOffsetAndLength(offset, sizeof(float));
|
||||
byte* ptr = _buffer.Buffer;
|
||||
if (BitConverter.IsLittleEndian)
|
||||
#if ENABLE_SPAN_T
|
||||
fixed (byte* ptr = &MemoryMarshal.GetReference(_buffer.Span))
|
||||
#else
|
||||
fixed (byte* ptr = _buffer.Buffer)
|
||||
#endif
|
||||
{
|
||||
*(float*)(ptr + offset) = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
*(uint*)(ptr + offset) = ReverseBytes(*(uint*)(&value));
|
||||
if (BitConverter.IsLittleEndian)
|
||||
{
|
||||
*(float*)(ptr + offset) = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
*(uint*)(ptr + offset) = ReverseBytes(*(uint*)(&value));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public unsafe void PutDouble(int offset, double value)
|
||||
{
|
||||
AssertOffsetAndLength(offset, sizeof(double));
|
||||
byte* ptr = _buffer.Buffer;
|
||||
if (BitConverter.IsLittleEndian)
|
||||
#if ENABLE_SPAN_T
|
||||
fixed (byte* ptr = &MemoryMarshal.GetReference(_buffer.Span))
|
||||
#else
|
||||
fixed (byte* ptr = _buffer.Buffer)
|
||||
#endif
|
||||
{
|
||||
*(double*)(ptr + offset) = value;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
*(ulong*)(ptr + offset) = ReverseBytes(*(ulong*)(ptr + offset));
|
||||
if (BitConverter.IsLittleEndian)
|
||||
{
|
||||
*(double*)(ptr + offset) = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
*(ulong*)(ptr + offset) = ReverseBytes(*(ulong*)(&value));
|
||||
}
|
||||
}
|
||||
}
|
||||
#else // !UNSAFE_BYTEBUFFER
|
||||
@@ -613,17 +601,17 @@ namespace FlatBuffers
|
||||
|
||||
#endif // UNSAFE_BYTEBUFFER
|
||||
|
||||
#if UNSAFE_BYTEBUFFER
|
||||
public unsafe sbyte GetSbyte(int index)
|
||||
#if ENABLE_SPAN_T
|
||||
public sbyte GetSbyte(int index)
|
||||
{
|
||||
AssertOffsetAndLength(index, sizeof(sbyte));
|
||||
return (sbyte)_buffer.Buffer[index];
|
||||
return (sbyte)_buffer.ReadOnlySpan[index];
|
||||
}
|
||||
|
||||
public unsafe byte Get(int index)
|
||||
public byte Get(int index)
|
||||
{
|
||||
AssertOffsetAndLength(index, sizeof(byte));
|
||||
return _buffer.Buffer[index];
|
||||
return _buffer.ReadOnlySpan[index];
|
||||
}
|
||||
#else
|
||||
public sbyte GetSbyte(int index)
|
||||
@@ -642,12 +630,15 @@ namespace FlatBuffers
|
||||
#if ENABLE_SPAN_T
|
||||
public unsafe string GetStringUTF8(int startPos, int len)
|
||||
{
|
||||
return Encoding.UTF8.GetString(_buffer.Buffer + startPos, len);
|
||||
fixed (byte* buffer = &MemoryMarshal.GetReference(_buffer.ReadOnlySpan.Slice(startPos)))
|
||||
{
|
||||
return Encoding.UTF8.GetString(buffer, len);
|
||||
}
|
||||
}
|
||||
#else
|
||||
public string GetStringUTF8(int startPos, int len)
|
||||
{
|
||||
return Encoding.UTF8.GetString(_buffer.ByteArray, startPos, len);
|
||||
return Encoding.UTF8.GetString(_buffer.Buffer, startPos, len);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -661,12 +652,17 @@ namespace FlatBuffers
|
||||
public unsafe ushort GetUshort(int offset)
|
||||
{
|
||||
AssertOffsetAndLength(offset, sizeof(ushort));
|
||||
byte* ptr = _buffer.Buffer;
|
||||
#if ENABLE_SPAN_T
|
||||
ReadOnlySpan<byte> span = _buffer.ReadOnlySpan.Slice(offset);
|
||||
return BinaryPrimitives.ReadUInt16LittleEndian(span);
|
||||
#else
|
||||
fixed (byte* ptr = _buffer.Buffer)
|
||||
{
|
||||
return BitConverter.IsLittleEndian
|
||||
? *(ushort*)(ptr + offset)
|
||||
: ReverseBytes(*(ushort*)(ptr + offset));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
public int GetInt(int offset)
|
||||
@@ -677,12 +673,17 @@ namespace FlatBuffers
|
||||
public unsafe uint GetUint(int offset)
|
||||
{
|
||||
AssertOffsetAndLength(offset, sizeof(uint));
|
||||
byte* ptr = _buffer.Buffer;
|
||||
#if ENABLE_SPAN_T
|
||||
ReadOnlySpan<byte> span = _buffer.ReadOnlySpan.Slice(offset);
|
||||
return BinaryPrimitives.ReadUInt32LittleEndian(span);
|
||||
#else
|
||||
fixed (byte* ptr = _buffer.Buffer)
|
||||
{
|
||||
return BitConverter.IsLittleEndian
|
||||
? *(uint*)(ptr + offset)
|
||||
: ReverseBytes(*(uint*)(ptr + offset));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
public long GetLong(int offset)
|
||||
@@ -693,18 +694,27 @@ namespace FlatBuffers
|
||||
public unsafe ulong GetUlong(int offset)
|
||||
{
|
||||
AssertOffsetAndLength(offset, sizeof(ulong));
|
||||
byte* ptr = _buffer.Buffer;
|
||||
#if ENABLE_SPAN_T
|
||||
ReadOnlySpan<byte> span = _buffer.ReadOnlySpan.Slice(offset);
|
||||
return BinaryPrimitives.ReadUInt64LittleEndian(span);
|
||||
#else
|
||||
fixed (byte* ptr = _buffer.Buffer)
|
||||
{
|
||||
return BitConverter.IsLittleEndian
|
||||
? *(ulong*)(ptr + offset)
|
||||
: ReverseBytes(*(ulong*)(ptr + offset));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
public unsafe float GetFloat(int offset)
|
||||
{
|
||||
AssertOffsetAndLength(offset, sizeof(float));
|
||||
byte* ptr = _buffer.Buffer;
|
||||
#if ENABLE_SPAN_T
|
||||
fixed (byte* ptr = &MemoryMarshal.GetReference(_buffer.ReadOnlySpan))
|
||||
#else
|
||||
fixed (byte* ptr = _buffer.Buffer)
|
||||
#endif
|
||||
{
|
||||
if (BitConverter.IsLittleEndian)
|
||||
{
|
||||
@@ -721,7 +731,11 @@ namespace FlatBuffers
|
||||
public unsafe double GetDouble(int offset)
|
||||
{
|
||||
AssertOffsetAndLength(offset, sizeof(double));
|
||||
byte* ptr = _buffer.Buffer;
|
||||
#if ENABLE_SPAN_T
|
||||
fixed (byte* ptr = &MemoryMarshal.GetReference(_buffer.ReadOnlySpan))
|
||||
#else
|
||||
fixed (byte* ptr = _buffer.Buffer)
|
||||
#endif
|
||||
{
|
||||
if (BitConverter.IsLittleEndian)
|
||||
{
|
||||
@@ -758,7 +772,7 @@ namespace FlatBuffers
|
||||
|
||||
public long GetLong(int index)
|
||||
{
|
||||
return (long)ReadLittleEndian(index, sizeof(long));
|
||||
return (long)ReadLittleEndian(index, sizeof(long));
|
||||
}
|
||||
|
||||
public ulong GetUlong(int index)
|
||||
@@ -819,12 +833,9 @@ namespace FlatBuffers
|
||||
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));
|
||||
}
|
||||
MemoryMarshal.Cast<T, byte>(x).CopyTo(_buffer.Span.Slice(offset, numBytes));
|
||||
#else
|
||||
Buffer.BlockCopy(x, 0, _buffer.ByteArray, offset, numBytes);
|
||||
Buffer.BlockCopy(x, 0, _buffer.Buffer, offset, numBytes);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
@@ -841,7 +852,7 @@ namespace FlatBuffers
|
||||
}
|
||||
|
||||
#if ENABLE_SPAN_T
|
||||
public unsafe int Put<T>(int offset, Span<T> x)
|
||||
public int Put<T>(int offset, Span<T> x)
|
||||
where T : struct
|
||||
{
|
||||
if (x.Length == 0)
|
||||
@@ -861,7 +872,7 @@ namespace FlatBuffers
|
||||
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));
|
||||
MemoryMarshal.Cast<T, byte>(x).CopyTo(_buffer.Span.Slice(offset, numBytes));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
19
net/FlatBuffers/FlatBuffers.Core.csproj
Normal file
19
net/FlatBuffers/FlatBuffers.Core.csproj
Normal file
@@ -0,0 +1,19 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Remove="Properties\**" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Remove="Properties\**" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Remove="Properties\**" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -1,16 +1,54 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<?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')" />
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>netstandard1.1;netstandard1.4;netstandard2.0</TargetFrameworks>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{28C00774-1E73-4A75-AD8F-844CD21A064D}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>FlatBuffers</RootNamespace>
|
||||
<AssemblyName>FlatBuffers</AssemblyName>
|
||||
<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>
|
||||
<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>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="System.Memory" Version="4.5.1" />
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
</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>
|
||||
52
net/FlatBuffers/Properties/AssemblyInfo.cs
Normal file
52
net/FlatBuffers/Properties/AssemblyInfo.cs
Normal file
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* 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")]
|
||||
12
package.json
12
package.json
@@ -1,8 +1,11 @@
|
||||
{
|
||||
"name": "flatbuffers",
|
||||
"version": "1.10.0",
|
||||
"version": "1.11.0",
|
||||
"description": "Memory Efficient Serialization Library",
|
||||
"files": ["js/flatbuffers.js", "js/flatbuffers.mjs"],
|
||||
"files": [
|
||||
"js/flatbuffers.js",
|
||||
"js/flatbuffers.mjs"
|
||||
],
|
||||
"main": "js/flatbuffers",
|
||||
"module": "js/flatbuffers.mjs",
|
||||
"directories": {
|
||||
@@ -11,7 +14,7 @@
|
||||
},
|
||||
"scripts": {
|
||||
"test": "tests/JavaScriptTest.sh",
|
||||
"append-esm-export": "sed \"s/this.flatbuffers = flatbuffers;/export { flatbuffers };/\" js/flatbuffers.js >> js/flatbuffers.mjs",
|
||||
"append-esm-export": "sed \"s/this.flatbuffers = flatbuffers;/export { flatbuffers };/\" js/flatbuffers.js > js/flatbuffers.mjs",
|
||||
"prepublishOnly": "npm run append-esm-export"
|
||||
},
|
||||
"repository": {
|
||||
@@ -26,5 +29,6 @@
|
||||
"bugs": {
|
||||
"url": "https://github.com/google/flatbuffers/issues"
|
||||
},
|
||||
"homepage": "https://google.github.io/flatbuffers/"
|
||||
"homepage": "https://google.github.io/flatbuffers/",
|
||||
"dependencies": {}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
|
||||
namespace Google\FlatBuffers;
|
||||
|
||||
class FlatbufferBuilder
|
||||
final class FlatbufferBuilder
|
||||
{
|
||||
/**
|
||||
* Internal ByteBuffer for the FlatBuffer data.
|
||||
@@ -278,6 +278,15 @@ class FlatbufferBuilder
|
||||
{
|
||||
$this->bb->putDouble($this->space -= 8, $x);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $off
|
||||
*/
|
||||
public function putOffset($off)
|
||||
{
|
||||
$new_off = $this->offset() - $off + Constants::SIZEOF_INT;
|
||||
$this->putInt($new_off);
|
||||
}
|
||||
/// @endcond
|
||||
|
||||
/**
|
||||
@@ -562,9 +571,7 @@ class FlatbufferBuilder
|
||||
if ($off > $this->offset()) {
|
||||
throw new \Exception("");
|
||||
}
|
||||
|
||||
$off = $this->offset() - $off + Constants::SIZEOF_INT;
|
||||
$this->putInt($off);
|
||||
$this->putOffset($off);
|
||||
}
|
||||
|
||||
/// @cond FLATBUFFERS_INTERNAL
|
||||
|
||||
11
pom.xml
11
pom.xml
@@ -1,11 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>com.google.flatbuffers</groupId>
|
||||
<artifactId>flatbuffers-java</artifactId>
|
||||
<version>1.10.0</version>
|
||||
<version>1.11.0</version>
|
||||
<packaging>bundle</packaging>
|
||||
<name>FlatBuffers Java API</name>
|
||||
<description>
|
||||
@@ -32,6 +30,7 @@
|
||||
<connection>
|
||||
scm:git:https://github.com/google/flatbuffers.git
|
||||
</connection>
|
||||
<tag>1.11.0</tag>
|
||||
</scm>
|
||||
<dependencies>
|
||||
</dependencies>
|
||||
@@ -78,6 +77,10 @@
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
<version>2.9.1</version>
|
||||
<configuration>
|
||||
<additionalparam>-Xdoclint:none</additionalparam>
|
||||
<additionalOptions>-Xdoclint:none</additionalOptions>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>attach-javadocs</id>
|
||||
|
||||
@@ -21,8 +21,9 @@ from . import packer
|
||||
from . import compat
|
||||
from .compat import range_func
|
||||
from .compat import memoryview_type
|
||||
from .compat import import_numpy, NumpyRequiredForThisFeature
|
||||
|
||||
|
||||
np = import_numpy()
|
||||
## @file
|
||||
## @addtogroup flatbuffers_python_api
|
||||
## @{
|
||||
@@ -441,6 +442,41 @@ class Builder(object):
|
||||
|
||||
return self.EndVector(len(x))
|
||||
|
||||
def CreateNumpyVector(self, x):
|
||||
"""CreateNumpyVector writes a numpy array into the buffer."""
|
||||
|
||||
if np is None:
|
||||
# Numpy is required for this feature
|
||||
raise NumpyRequiredForThisFeature("Numpy was not found.")
|
||||
|
||||
if not isinstance(x, np.ndarray):
|
||||
raise TypeError("non-numpy-ndarray passed to CreateNumpyVector")
|
||||
|
||||
if x.dtype.kind not in ['b', 'i', 'u', 'f']:
|
||||
raise TypeError("numpy-ndarray holds elements of unsupported datatype")
|
||||
|
||||
if x.ndim > 1:
|
||||
raise TypeError("multidimensional-ndarray passed to CreateNumpyVector")
|
||||
|
||||
self.StartVector(x.itemsize, x.size, x.dtype.alignment)
|
||||
|
||||
# Ensure little endian byte ordering
|
||||
if x.dtype.str[0] == "<":
|
||||
x_lend = x
|
||||
else:
|
||||
x_lend = x.byteswap(inplace=False)
|
||||
|
||||
# Calculate total length
|
||||
l = UOffsetTFlags.py_type(x_lend.itemsize * x_lend.size)
|
||||
## @cond FLATBUFFERS_INTERNAL
|
||||
self.head = UOffsetTFlags.py_type(self.Head() - l)
|
||||
## @endcond
|
||||
|
||||
# tobytes ensures c_contiguous ordering
|
||||
self.Bytes[self.Head():self.Head()+l] = x_lend.tobytes(order='C')
|
||||
|
||||
return self.EndVector(x.size)
|
||||
|
||||
## @cond FLATBUFFERS_INTERNAL
|
||||
def assertNested(self):
|
||||
"""
|
||||
|
||||
@@ -15,4 +15,4 @@
|
||||
set buildtype=Release
|
||||
if "%1"=="-b" set buildtype=%2
|
||||
|
||||
..\%buildtype%\flatc.exe --cpp --no-prefix -o ../include/flatbuffers reflection.fbs
|
||||
..\%buildtype%\flatc.exe --cpp --no-prefix -o ../include/flatbuffers reflection.fbs || exit /b 1
|
||||
|
||||
@@ -13,5 +13,6 @@
|
||||
# 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.
|
||||
set -e
|
||||
|
||||
../flatc -c --no-prefix -o ../include/flatbuffers reflection.fbs
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "flatbuffers"
|
||||
version = "0.5.0"
|
||||
version = "0.6.0"
|
||||
authors = ["Robert Winslow <hello@rwinslow.com>", "FlatBuffers Maintainers"]
|
||||
license = "Apache-2.0"
|
||||
description = "Official FlatBuffers Rust runtime library."
|
||||
|
||||
@@ -29,6 +29,8 @@ use vtable::{VTable, field_index_to_field_offset};
|
||||
use vtable_writer::VTableWriter;
|
||||
use vector::{SafeSliceAccess, Vector};
|
||||
|
||||
pub const N_SMALLVEC_STRING_VECTOR_CAPACITY: usize = 16;
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
struct FieldLoc {
|
||||
off: UOffsetT,
|
||||
@@ -268,10 +270,12 @@ impl<'fbb> FlatBufferBuilder<'fbb> {
|
||||
#[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());
|
||||
// internally, smallvec can be a stack-allocated or heap-allocated vector:
|
||||
// if xs.len() > N_SMALLVEC_STRING_VECTOR_CAPACITY then it will overflow to the heap.
|
||||
let mut offsets: smallvec::SmallVec<[WIPOffset<&str>; N_SMALLVEC_STRING_VECTOR_CAPACITY]> = smallvec::SmallVec::with_capacity(xs.len());
|
||||
unsafe { offsets.set_len(xs.len()); }
|
||||
|
||||
// note that this happens in reverse, because the buffer is built back-to-front:
|
||||
for (i, &s) in xs.iter().enumerate().rev() {
|
||||
let o = self.create_string(s);
|
||||
offsets[i] = o;
|
||||
|
||||
@@ -88,7 +88,7 @@ impl EndianScalar for f32 {
|
||||
}
|
||||
#[cfg(not(target_endian = "little"))]
|
||||
{
|
||||
byte_swap_f32(&self)
|
||||
byte_swap_f32(self)
|
||||
}
|
||||
}
|
||||
/// Convert f32 from little-endian to host endian-ness.
|
||||
@@ -100,7 +100,7 @@ impl EndianScalar for f32 {
|
||||
}
|
||||
#[cfg(not(target_endian = "little"))]
|
||||
{
|
||||
byte_swap_f32(&self)
|
||||
byte_swap_f32(self)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -115,7 +115,7 @@ impl EndianScalar for f64 {
|
||||
}
|
||||
#[cfg(not(target_endian = "little"))]
|
||||
{
|
||||
byte_swap_f64(&self)
|
||||
byte_swap_f64(self)
|
||||
}
|
||||
}
|
||||
/// Convert f64 from little-endian to host endian-ness.
|
||||
@@ -127,7 +127,7 @@ impl EndianScalar for f64 {
|
||||
}
|
||||
#[cfg(not(target_endian = "little"))]
|
||||
{
|
||||
byte_swap_f64(&self)
|
||||
byte_swap_f64(self)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,9 @@ use std::mem::size_of;
|
||||
use std::slice::from_raw_parts;
|
||||
use std::str::from_utf8_unchecked;
|
||||
|
||||
use endian_scalar::{EndianScalar, read_scalar};
|
||||
#[cfg(target_endian = "little")]
|
||||
use endian_scalar::EndianScalar;
|
||||
use endian_scalar::read_scalar;
|
||||
use follow::Follow;
|
||||
use primitives::*;
|
||||
|
||||
@@ -85,6 +87,7 @@ mod le_safe_slice_impls {
|
||||
impl super::SafeSliceAccess for f64 {}
|
||||
}
|
||||
|
||||
#[cfg(target_endian = "little")]
|
||||
pub use self::le_safe_slice_impls::*;
|
||||
|
||||
pub fn follow_cast_ref<'a, T: Sized + 'a>(buf: &'a [u8], loc: usize) -> &'a T {
|
||||
@@ -104,6 +107,7 @@ impl<'a> Follow<'a> for &'a str {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_endian = "little")]
|
||||
fn follow_slice_helper<T>(buf: &[u8], loc: usize) -> &[T] {
|
||||
let sz = size_of::<T>();
|
||||
debug_assert!(sz > 0);
|
||||
|
||||
@@ -66,7 +66,7 @@ android {
|
||||
ndkBuild {
|
||||
targets "FlatBufferSample"
|
||||
arguments "-j" + Runtime.getRuntime().availableProcessors()
|
||||
abiFilters "armeabi", "armeabi-v7a", "arm64-v8a", "x86", "x86_64"
|
||||
abiFilters "armeabi-v7a", "arm64-v8a", "x86", "x86_64"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ fi
|
||||
echo Compiling and running the C# sample.
|
||||
|
||||
# Compile and execute the sample.
|
||||
csc SampleBinary.cs MyGame/Sample/*.cs ../net/FlatBuffers/*.cs
|
||||
mcs SampleBinary.cs MyGame/Sample/*.cs ../net/FlatBuffers/*.cs
|
||||
mono SampleBinary.exe
|
||||
|
||||
# Cleanup temporary files.
|
||||
|
||||
BIN
samples/monster.bfbs
Normal file
BIN
samples/monster.bfbs
Normal file
Binary file not shown.
@@ -22,6 +22,7 @@ table Monster {
|
||||
color:Color = Blue;
|
||||
weapons:[Weapon];
|
||||
equipped:Equipment;
|
||||
path:[Vec3];
|
||||
}
|
||||
|
||||
table Weapon {
|
||||
|
||||
@@ -18,8 +18,11 @@ struct Weapon;
|
||||
struct WeaponT;
|
||||
|
||||
bool operator==(const Vec3 &lhs, const Vec3 &rhs);
|
||||
bool operator!=(const Vec3 &lhs, const Vec3 &rhs);
|
||||
bool operator==(const MonsterT &lhs, const MonsterT &rhs);
|
||||
bool operator!=(const MonsterT &lhs, const MonsterT &rhs);
|
||||
bool operator==(const WeaponT &lhs, const WeaponT &rhs);
|
||||
bool operator!=(const WeaponT &lhs, const WeaponT &rhs);
|
||||
|
||||
inline const flatbuffers::TypeTable *Vec3TypeTable();
|
||||
|
||||
@@ -55,7 +58,8 @@ inline const char * const *EnumNamesColor() {
|
||||
}
|
||||
|
||||
inline const char *EnumNameColor(Color e) {
|
||||
const size_t index = static_cast<int>(e);
|
||||
if (e < Color_Red || e > Color_Blue) return "";
|
||||
const size_t index = static_cast<size_t>(e);
|
||||
return EnumNamesColor()[index];
|
||||
}
|
||||
|
||||
@@ -84,7 +88,8 @@ inline const char * const *EnumNamesEquipment() {
|
||||
}
|
||||
|
||||
inline const char *EnumNameEquipment(Equipment e) {
|
||||
const size_t index = static_cast<int>(e);
|
||||
if (e < Equipment_NONE || e > Equipment_Weapon) return "";
|
||||
const size_t index = static_cast<size_t>(e);
|
||||
return EnumNamesEquipment()[index];
|
||||
}
|
||||
|
||||
@@ -116,10 +121,11 @@ struct EquipmentUnion {
|
||||
#ifndef FLATBUFFERS_CPP98_STL
|
||||
template <typename T>
|
||||
void Set(T&& val) {
|
||||
using RT = typename std::remove_reference<T>::type;
|
||||
Reset();
|
||||
type = EquipmentTraits<typename T::TableType>::enum_value;
|
||||
type = EquipmentTraits<typename RT::TableType>::enum_value;
|
||||
if (type != Equipment_NONE) {
|
||||
value = new T(std::forward<T>(val));
|
||||
value = new RT(std::forward<T>(val));
|
||||
}
|
||||
}
|
||||
#endif // FLATBUFFERS_CPP98_STL
|
||||
@@ -153,6 +159,11 @@ inline bool operator==(const EquipmentUnion &lhs, const EquipmentUnion &rhs) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline bool operator!=(const EquipmentUnion &lhs, const EquipmentUnion &rhs) {
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
bool VerifyEquipment(flatbuffers::Verifier &verifier, const void *obj, Equipment type);
|
||||
bool VerifyEquipmentVector(flatbuffers::Verifier &verifier, const flatbuffers::Vector<flatbuffers::Offset<void>> *values, const flatbuffers::Vector<uint8_t> *types);
|
||||
|
||||
@@ -163,8 +174,11 @@ FLATBUFFERS_MANUALLY_ALIGNED_STRUCT(4) Vec3 FLATBUFFERS_FINAL_CLASS {
|
||||
float z_;
|
||||
|
||||
public:
|
||||
static const flatbuffers::TypeTable *MiniReflectTypeTable() {
|
||||
return Vec3TypeTable();
|
||||
}
|
||||
Vec3() {
|
||||
memset(this, 0, sizeof(Vec3));
|
||||
memset(static_cast<void *>(this), 0, sizeof(Vec3));
|
||||
}
|
||||
Vec3(float _x, float _y, float _z)
|
||||
: x_(flatbuffers::EndianScalar(_x)),
|
||||
@@ -199,6 +213,11 @@ inline bool operator==(const Vec3 &lhs, const Vec3 &rhs) {
|
||||
(lhs.z() == rhs.z());
|
||||
}
|
||||
|
||||
inline bool operator!=(const Vec3 &lhs, const Vec3 &rhs) {
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
|
||||
struct MonsterT : public flatbuffers::NativeTable {
|
||||
typedef Monster TableType;
|
||||
flatbuffers::unique_ptr<Vec3> pos;
|
||||
@@ -209,6 +228,7 @@ struct MonsterT : public flatbuffers::NativeTable {
|
||||
Color color;
|
||||
std::vector<flatbuffers::unique_ptr<WeaponT>> weapons;
|
||||
EquipmentUnion equipped;
|
||||
std::vector<Vec3> path;
|
||||
MonsterT()
|
||||
: mana(150),
|
||||
hp(100),
|
||||
@@ -225,15 +245,21 @@ inline bool operator==(const MonsterT &lhs, const MonsterT &rhs) {
|
||||
(lhs.inventory == rhs.inventory) &&
|
||||
(lhs.color == rhs.color) &&
|
||||
(lhs.weapons == rhs.weapons) &&
|
||||
(lhs.equipped == rhs.equipped);
|
||||
(lhs.equipped == rhs.equipped) &&
|
||||
(lhs.path == rhs.path);
|
||||
}
|
||||
|
||||
inline bool operator!=(const MonsterT &lhs, const MonsterT &rhs) {
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
|
||||
struct Monster FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
|
||||
typedef MonsterT NativeTableType;
|
||||
static const flatbuffers::TypeTable *MiniReflectTypeTable() {
|
||||
return MonsterTypeTable();
|
||||
}
|
||||
enum {
|
||||
enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE {
|
||||
VT_POS = 4,
|
||||
VT_MANA = 6,
|
||||
VT_HP = 8,
|
||||
@@ -242,7 +268,8 @@ struct Monster FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
|
||||
VT_COLOR = 16,
|
||||
VT_WEAPONS = 18,
|
||||
VT_EQUIPPED_TYPE = 20,
|
||||
VT_EQUIPPED = 22
|
||||
VT_EQUIPPED = 22,
|
||||
VT_PATH = 24
|
||||
};
|
||||
const Vec3 *pos() const {
|
||||
return GetStruct<const Vec3 *>(VT_POS);
|
||||
@@ -302,6 +329,12 @@ struct Monster FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
|
||||
void *mutable_equipped() {
|
||||
return GetPointer<void *>(VT_EQUIPPED);
|
||||
}
|
||||
const flatbuffers::Vector<const Vec3 *> *path() const {
|
||||
return GetPointer<const flatbuffers::Vector<const Vec3 *> *>(VT_PATH);
|
||||
}
|
||||
flatbuffers::Vector<const Vec3 *> *mutable_path() {
|
||||
return GetPointer<flatbuffers::Vector<const Vec3 *> *>(VT_PATH);
|
||||
}
|
||||
bool Verify(flatbuffers::Verifier &verifier) const {
|
||||
return VerifyTableStart(verifier) &&
|
||||
VerifyField<Vec3>(verifier, VT_POS) &&
|
||||
@@ -318,6 +351,8 @@ struct Monster FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
|
||||
VerifyField<uint8_t>(verifier, VT_EQUIPPED_TYPE) &&
|
||||
VerifyOffset(verifier, VT_EQUIPPED) &&
|
||||
VerifyEquipment(verifier, equipped(), equipped_type()) &&
|
||||
VerifyOffset(verifier, VT_PATH) &&
|
||||
verifier.VerifyVector(path()) &&
|
||||
verifier.EndTable();
|
||||
}
|
||||
MonsterT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const;
|
||||
@@ -359,6 +394,9 @@ struct MonsterBuilder {
|
||||
void add_equipped(flatbuffers::Offset<void> equipped) {
|
||||
fbb_.AddOffset(Monster::VT_EQUIPPED, equipped);
|
||||
}
|
||||
void add_path(flatbuffers::Offset<flatbuffers::Vector<const Vec3 *>> path) {
|
||||
fbb_.AddOffset(Monster::VT_PATH, path);
|
||||
}
|
||||
explicit MonsterBuilder(flatbuffers::FlatBufferBuilder &_fbb)
|
||||
: fbb_(_fbb) {
|
||||
start_ = fbb_.StartTable();
|
||||
@@ -381,8 +419,10 @@ inline flatbuffers::Offset<Monster> CreateMonster(
|
||||
Color color = Color_Blue,
|
||||
flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<Weapon>>> weapons = 0,
|
||||
Equipment equipped_type = Equipment_NONE,
|
||||
flatbuffers::Offset<void> equipped = 0) {
|
||||
flatbuffers::Offset<void> equipped = 0,
|
||||
flatbuffers::Offset<flatbuffers::Vector<const Vec3 *>> path = 0) {
|
||||
MonsterBuilder builder_(_fbb);
|
||||
builder_.add_path(path);
|
||||
builder_.add_equipped(equipped);
|
||||
builder_.add_weapons(weapons);
|
||||
builder_.add_inventory(inventory);
|
||||
@@ -405,18 +445,24 @@ inline flatbuffers::Offset<Monster> CreateMonsterDirect(
|
||||
Color color = Color_Blue,
|
||||
const std::vector<flatbuffers::Offset<Weapon>> *weapons = nullptr,
|
||||
Equipment equipped_type = Equipment_NONE,
|
||||
flatbuffers::Offset<void> equipped = 0) {
|
||||
flatbuffers::Offset<void> equipped = 0,
|
||||
const std::vector<Vec3> *path = nullptr) {
|
||||
auto name__ = name ? _fbb.CreateString(name) : 0;
|
||||
auto inventory__ = inventory ? _fbb.CreateVector<uint8_t>(*inventory) : 0;
|
||||
auto weapons__ = weapons ? _fbb.CreateVector<flatbuffers::Offset<Weapon>>(*weapons) : 0;
|
||||
auto path__ = path ? _fbb.CreateVectorOfStructs<Vec3>(*path) : 0;
|
||||
return MyGame::Sample::CreateMonster(
|
||||
_fbb,
|
||||
pos,
|
||||
mana,
|
||||
hp,
|
||||
name ? _fbb.CreateString(name) : 0,
|
||||
inventory ? _fbb.CreateVector<uint8_t>(*inventory) : 0,
|
||||
name__,
|
||||
inventory__,
|
||||
color,
|
||||
weapons ? _fbb.CreateVector<flatbuffers::Offset<Weapon>>(*weapons) : 0,
|
||||
weapons__,
|
||||
equipped_type,
|
||||
equipped);
|
||||
equipped,
|
||||
path__);
|
||||
}
|
||||
|
||||
flatbuffers::Offset<Monster> CreateMonster(flatbuffers::FlatBufferBuilder &_fbb, const MonsterT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr);
|
||||
@@ -436,12 +482,17 @@ inline bool operator==(const WeaponT &lhs, const WeaponT &rhs) {
|
||||
(lhs.damage == rhs.damage);
|
||||
}
|
||||
|
||||
inline bool operator!=(const WeaponT &lhs, const WeaponT &rhs) {
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
|
||||
struct Weapon FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
|
||||
typedef WeaponT NativeTableType;
|
||||
static const flatbuffers::TypeTable *MiniReflectTypeTable() {
|
||||
return WeaponTypeTable();
|
||||
}
|
||||
enum {
|
||||
enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE {
|
||||
VT_NAME = 4,
|
||||
VT_DAMAGE = 6
|
||||
};
|
||||
@@ -504,9 +555,10 @@ inline flatbuffers::Offset<Weapon> CreateWeaponDirect(
|
||||
flatbuffers::FlatBufferBuilder &_fbb,
|
||||
const char *name = nullptr,
|
||||
int16_t damage = 0) {
|
||||
auto name__ = name ? _fbb.CreateString(name) : 0;
|
||||
return MyGame::Sample::CreateWeapon(
|
||||
_fbb,
|
||||
name ? _fbb.CreateString(name) : 0,
|
||||
name__,
|
||||
damage);
|
||||
}
|
||||
|
||||
@@ -530,6 +582,7 @@ inline void Monster::UnPackTo(MonsterT *_o, const flatbuffers::resolver_function
|
||||
{ auto _e = weapons(); if (_e) { _o->weapons.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->weapons[_i] = flatbuffers::unique_ptr<WeaponT>(_e->Get(_i)->UnPack(_resolver)); } } };
|
||||
{ auto _e = equipped_type(); _o->equipped.type = _e; };
|
||||
{ auto _e = equipped(); if (_e) _o->equipped.value = EquipmentUnion::UnPack(_e, equipped_type(), _resolver); };
|
||||
{ auto _e = path(); if (_e) { _o->path.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->path[_i] = *_e->Get(_i); } } };
|
||||
}
|
||||
|
||||
inline flatbuffers::Offset<Monster> Monster::Pack(flatbuffers::FlatBufferBuilder &_fbb, const MonsterT* _o, const flatbuffers::rehasher_function_t *_rehasher) {
|
||||
@@ -549,6 +602,7 @@ inline flatbuffers::Offset<Monster> CreateMonster(flatbuffers::FlatBufferBuilder
|
||||
auto _weapons = _o->weapons.size() ? _fbb.CreateVector<flatbuffers::Offset<Weapon>> (_o->weapons.size(), [](size_t i, _VectorArgs *__va) { return CreateWeapon(*__va->__fbb, __va->__o->weapons[i].get(), __va->__rehasher); }, &_va ) : 0;
|
||||
auto _equipped_type = _o->equipped.type;
|
||||
auto _equipped = _o->equipped.Pack(_fbb);
|
||||
auto _path = _o->path.size() ? _fbb.CreateVectorOfStructs(_o->path) : 0;
|
||||
return MyGame::Sample::CreateMonster(
|
||||
_fbb,
|
||||
_pos,
|
||||
@@ -559,7 +613,8 @@ inline flatbuffers::Offset<Monster> CreateMonster(flatbuffers::FlatBufferBuilder
|
||||
_color,
|
||||
_weapons,
|
||||
_equipped_type,
|
||||
_equipped);
|
||||
_equipped,
|
||||
_path);
|
||||
}
|
||||
|
||||
inline WeaponT *Weapon::UnPack(const flatbuffers::resolver_function_t *_resolver) const {
|
||||
@@ -704,7 +759,7 @@ inline const flatbuffers::TypeTable *Vec3TypeTable() {
|
||||
{ flatbuffers::ET_FLOAT, 0, -1 },
|
||||
{ flatbuffers::ET_FLOAT, 0, -1 }
|
||||
};
|
||||
static const int32_t values[] = { 0, 4, 8, 12 };
|
||||
static const int64_t values[] = { 0, 4, 8, 12 };
|
||||
static const char * const names[] = {
|
||||
"x",
|
||||
"y",
|
||||
@@ -727,7 +782,8 @@ inline const flatbuffers::TypeTable *MonsterTypeTable() {
|
||||
{ flatbuffers::ET_CHAR, 0, 1 },
|
||||
{ flatbuffers::ET_SEQUENCE, 1, 2 },
|
||||
{ flatbuffers::ET_UTYPE, 0, 3 },
|
||||
{ flatbuffers::ET_SEQUENCE, 0, 3 }
|
||||
{ flatbuffers::ET_SEQUENCE, 0, 3 },
|
||||
{ flatbuffers::ET_SEQUENCE, 1, 0 }
|
||||
};
|
||||
static const flatbuffers::TypeFunction type_refs[] = {
|
||||
Vec3TypeTable,
|
||||
@@ -745,10 +801,11 @@ inline const flatbuffers::TypeTable *MonsterTypeTable() {
|
||||
"color",
|
||||
"weapons",
|
||||
"equipped_type",
|
||||
"equipped"
|
||||
"equipped",
|
||||
"path"
|
||||
};
|
||||
static const flatbuffers::TypeTable tt = {
|
||||
flatbuffers::ST_TABLE, 10, type_codes, type_refs, nullptr, names
|
||||
flatbuffers::ST_TABLE, 11, type_codes, type_refs, nullptr, names
|
||||
};
|
||||
return &tt;
|
||||
}
|
||||
|
||||
@@ -58,11 +58,15 @@ struct Monster : flatbuffers_handle
|
||||
buf_.flatbuffers_field_int8(pos_, 20, 0)
|
||||
def equipped_as_Weapon():
|
||||
MyGame_Sample_Weapon { buf_, buf_.flatbuffers_field_table(pos_, 22) }
|
||||
def path(i:int):
|
||||
MyGame_Sample_Vec3 { buf_, buf_.flatbuffers_field_vector(pos_, 24) + i * 12 }
|
||||
def path_length():
|
||||
buf_.flatbuffers_field_vector_len(pos_, 24)
|
||||
|
||||
def GetRootAsMonster(buf:string): Monster { buf, buf.flatbuffers_indirect(0) }
|
||||
|
||||
def MonsterStart(b_:flatbuffers_builder):
|
||||
b_.StartObject(10)
|
||||
b_.StartObject(11)
|
||||
def MonsterAddPos(b_:flatbuffers_builder, pos:int):
|
||||
b_.PrependStructSlot(0, pos, 0)
|
||||
def MonsterAddMana(b_:flatbuffers_builder, mana:int):
|
||||
@@ -93,6 +97,10 @@ def MonsterAddEquippedType(b_:flatbuffers_builder, equipped_type:int):
|
||||
b_.PrependUint8Slot(8, equipped_type, 0)
|
||||
def MonsterAddEquipped(b_:flatbuffers_builder, equipped:int):
|
||||
b_.PrependUOffsetTRelativeSlot(9, equipped, 0)
|
||||
def MonsterAddPath(b_:flatbuffers_builder, path:int):
|
||||
b_.PrependUOffsetTRelativeSlot(10, path, 0)
|
||||
def MonsterStartPathVector(b_:flatbuffers_builder, n_:int):
|
||||
b_.StartVector(12, n_, 4)
|
||||
def MonsterEnd(b_:flatbuffers_builder):
|
||||
b_.EndObject()
|
||||
|
||||
|
||||
78
samples/sample_bfbs.cpp
Normal file
78
samples/sample_bfbs.cpp
Normal file
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright 2014 Google Inc. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "flatbuffers/idl.h"
|
||||
#include "flatbuffers/util.h"
|
||||
|
||||
#include "monster_test_generated.h"
|
||||
#include "monster_generated.h" // Already includes "flatbuffers/flatbuffers.h".
|
||||
|
||||
using namespace MyGame::Sample;
|
||||
|
||||
// This is an example of parsing text straight into a buffer and then
|
||||
// generating flatbuffer (JSON) text from the buffer.
|
||||
int main(int /*argc*/, const char * /*argv*/[]) {
|
||||
// load FlatBuffer schema (.fbs) and JSON from disk
|
||||
std::string schema_file;
|
||||
std::string json_file;
|
||||
std::string bfbs_file;
|
||||
bool ok =
|
||||
flatbuffers::LoadFile("tests/monster_test.fbs", false, &schema_file) &&
|
||||
flatbuffers::LoadFile("tests/monsterdata_test.golden", false, &json_file) &&
|
||||
flatbuffers::LoadFile("tests/monster_test.bfbs", true, &bfbs_file);
|
||||
if (!ok) {
|
||||
printf("couldn't load files!\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
const char *include_directories[] = { "samples", "tests",
|
||||
"tests/include_test", nullptr };
|
||||
// parse fbs schema
|
||||
flatbuffers::Parser parser1;
|
||||
ok = parser1.Parse(schema_file.c_str(), include_directories);
|
||||
assert(ok);
|
||||
|
||||
// inizialize parser by deserializing bfbs schema
|
||||
flatbuffers::Parser parser2;
|
||||
ok = parser2.Deserialize((uint8_t *)bfbs_file.c_str(), bfbs_file.length());
|
||||
assert(ok);
|
||||
|
||||
// parse json in parser from fbs and bfbs
|
||||
ok = parser1.Parse(json_file.c_str(), include_directories);
|
||||
assert(ok);
|
||||
ok = parser2.Parse(json_file.c_str(), include_directories);
|
||||
assert(ok);
|
||||
|
||||
// to ensure it is correct, we now generate text back from the binary,
|
||||
// and compare the two:
|
||||
std::string jsongen1;
|
||||
if (!GenerateText(parser1, parser1.builder_.GetBufferPointer(), &jsongen1)) {
|
||||
printf("Couldn't serialize parsed data to JSON!\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::string jsongen2;
|
||||
if (!GenerateText(parser2, parser2.builder_.GetBufferPointer(), &jsongen2)) {
|
||||
printf("Couldn't serialize parsed data to JSON!\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (jsongen1 != jsongen2) {
|
||||
printf("%s----------------\n%s", jsongen1.c_str(), jsongen2.c_str());
|
||||
}
|
||||
|
||||
printf("The FlatBuffer has been parsed from JSON successfully.\n");
|
||||
}
|
||||
37
snap/snapcraft.yaml
Normal file
37
snap/snapcraft.yaml
Normal file
@@ -0,0 +1,37 @@
|
||||
name: flatbuffers
|
||||
base: core18
|
||||
version: latest
|
||||
version-script: git describe --always | sed -e 's/-/+git/;y/-/./' | tail -c +2
|
||||
summary: FlatBuffers compiler
|
||||
description: |
|
||||
FlatBuffers compiler
|
||||
|
||||
NOTE: This snap also ships the necessary header files required to compile
|
||||
projects using flatbuffers, however, for the compilation to work, you have
|
||||
to manually add the following path in your project's configuration:
|
||||
|
||||
/snap/flatbuffers/current/include
|
||||
|
||||
If you need to use flatbuffers headers from a location other than the above
|
||||
path, it is recommended to not use this snap as that could cause a mismatch.
|
||||
|
||||
grade: stable
|
||||
confinement: strict
|
||||
|
||||
parts:
|
||||
flatc:
|
||||
plugin: cmake
|
||||
source: .
|
||||
configflags:
|
||||
- -GUnix Makefiles
|
||||
- -DCMAKE_BUILD_TYPE=Release
|
||||
build-packages:
|
||||
- g++
|
||||
# used to set version number
|
||||
- git
|
||||
|
||||
apps:
|
||||
flatc:
|
||||
command: flatc
|
||||
plugs:
|
||||
- home
|
||||
@@ -19,6 +19,8 @@
|
||||
#include "flatbuffers/base.h"
|
||||
#include "flatbuffers/util.h"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
# pragma warning(push)
|
||||
# pragma warning(disable : 4127) // C4127: conditional expression is constant
|
||||
@@ -157,6 +159,123 @@ void GenComment(const std::vector<std::string> &dc, std::string *code_ptr,
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
std::string FloatConstantGenerator::GenFloatConstantImpl(
|
||||
const FieldDef &field) const {
|
||||
const auto &constant = field.value.constant;
|
||||
T v;
|
||||
auto done = StringToNumber(constant.c_str(), &v);
|
||||
FLATBUFFERS_ASSERT(done);
|
||||
if (done) {
|
||||
#if (!defined(_MSC_VER) || (_MSC_VER >= 1800))
|
||||
if (std::isnan(v)) return NaN(v);
|
||||
if (std::isinf(v)) return Inf(v);
|
||||
#endif
|
||||
return Value(v, constant);
|
||||
}
|
||||
return "#"; // compile time error
|
||||
}
|
||||
|
||||
std::string FloatConstantGenerator::GenFloatConstant(
|
||||
const FieldDef &field) const {
|
||||
switch (field.value.type.base_type) {
|
||||
case BASE_TYPE_FLOAT: return GenFloatConstantImpl<float>(field);
|
||||
case BASE_TYPE_DOUBLE: return GenFloatConstantImpl<double>(field);
|
||||
default: {
|
||||
FLATBUFFERS_ASSERT(false);
|
||||
return "INVALID_BASE_TYPE";
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
TypedFloatConstantGenerator::TypedFloatConstantGenerator(
|
||||
const char *double_prefix, const char *single_prefix,
|
||||
const char *nan_number, const char *pos_inf_number,
|
||||
const char *neg_inf_number)
|
||||
: double_prefix_(double_prefix),
|
||||
single_prefix_(single_prefix),
|
||||
nan_number_(nan_number),
|
||||
pos_inf_number_(pos_inf_number),
|
||||
neg_inf_number_(neg_inf_number) {}
|
||||
|
||||
std::string TypedFloatConstantGenerator::MakeNaN(
|
||||
const std::string &prefix) const {
|
||||
return prefix + nan_number_;
|
||||
}
|
||||
std::string TypedFloatConstantGenerator::MakeInf(
|
||||
bool neg, const std::string &prefix) const {
|
||||
if (neg)
|
||||
return !neg_inf_number_.empty() ? (prefix + neg_inf_number_)
|
||||
: ("-" + prefix + pos_inf_number_);
|
||||
else
|
||||
return prefix + pos_inf_number_;
|
||||
}
|
||||
|
||||
std::string TypedFloatConstantGenerator::Value(double v,
|
||||
const std::string &src) const {
|
||||
(void)v;
|
||||
return src;
|
||||
}
|
||||
|
||||
std::string TypedFloatConstantGenerator::Inf(double v) const {
|
||||
return MakeInf(v < 0, double_prefix_);
|
||||
}
|
||||
|
||||
std::string TypedFloatConstantGenerator::NaN(double v) const {
|
||||
(void)v;
|
||||
return MakeNaN(double_prefix_);
|
||||
}
|
||||
|
||||
std::string TypedFloatConstantGenerator::Value(float v,
|
||||
const std::string &src) const {
|
||||
(void)v;
|
||||
return src + "f";
|
||||
}
|
||||
|
||||
std::string TypedFloatConstantGenerator::Inf(float v) const {
|
||||
return MakeInf(v < 0, single_prefix_);
|
||||
}
|
||||
|
||||
std::string TypedFloatConstantGenerator::NaN(float v) const {
|
||||
(void)v;
|
||||
return MakeNaN(single_prefix_);
|
||||
}
|
||||
|
||||
SimpleFloatConstantGenerator::SimpleFloatConstantGenerator(
|
||||
const char *nan_number, const char *pos_inf_number,
|
||||
const char *neg_inf_number)
|
||||
: nan_number_(nan_number),
|
||||
pos_inf_number_(pos_inf_number),
|
||||
neg_inf_number_(neg_inf_number) {}
|
||||
|
||||
std::string SimpleFloatConstantGenerator::Value(double v,
|
||||
const std::string &src) const {
|
||||
(void)v;
|
||||
return src;
|
||||
}
|
||||
|
||||
std::string SimpleFloatConstantGenerator::Inf(double v) const {
|
||||
return (v < 0) ? neg_inf_number_ : pos_inf_number_;
|
||||
}
|
||||
|
||||
std::string SimpleFloatConstantGenerator::NaN(double v) const {
|
||||
(void)v;
|
||||
return nan_number_;
|
||||
}
|
||||
|
||||
std::string SimpleFloatConstantGenerator::Value(float v,
|
||||
const std::string &src) const {
|
||||
return this->Value(static_cast<double>(v), src);
|
||||
}
|
||||
|
||||
std::string SimpleFloatConstantGenerator::Inf(float v) const {
|
||||
return this->Inf(static_cast<double>(v));
|
||||
}
|
||||
|
||||
std::string SimpleFloatConstantGenerator::NaN(float v) const {
|
||||
return this->NaN(static_cast<double>(v));
|
||||
}
|
||||
|
||||
} // namespace flatbuffers
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
|
||||
#include <list>
|
||||
|
||||
#define FLATC_VERSION "1.10.0 (" __DATE__ " " __TIME__ ")"
|
||||
#define FLATC_VERSION "1.11.0"
|
||||
|
||||
namespace flatbuffers {
|
||||
|
||||
@@ -30,12 +30,23 @@ void FlatCompiler::ParseFile(
|
||||
include_directories.push_back(local_include_directory.c_str());
|
||||
include_directories.push_back(nullptr);
|
||||
if (!parser.Parse(contents.c_str(), &include_directories[0],
|
||||
filename.c_str()))
|
||||
filename.c_str())) {
|
||||
Error(parser.error_, false, false);
|
||||
}
|
||||
if (!parser.error_.empty()) { Warn(parser.error_, false); }
|
||||
include_directories.pop_back();
|
||||
include_directories.pop_back();
|
||||
}
|
||||
|
||||
void FlatCompiler::LoadBinarySchema(flatbuffers::Parser &parser,
|
||||
const std::string &filename,
|
||||
const std::string &contents) {
|
||||
if (!parser.Deserialize(reinterpret_cast<const uint8_t *>(contents.c_str()),
|
||||
contents.size())) {
|
||||
Error("failed to load binary schema: " + filename, false, false);
|
||||
}
|
||||
}
|
||||
|
||||
void FlatCompiler::Warn(const std::string &warn, bool show_exe_name) const {
|
||||
params_.warn_fn(this, warn, show_exe_name);
|
||||
}
|
||||
@@ -89,45 +100,56 @@ std::string FlatCompiler::GetUsageString(const char *program_name) const {
|
||||
" --gen-name-strings Generate type name functions for C++.\n"
|
||||
" --gen-object-api Generate an additional object-based API.\n"
|
||||
" --gen-compare Generate operator== for object-based API types.\n"
|
||||
" --cpp-ptr-type T Set object API pointer type (default std::unique_ptr)\n"
|
||||
" --cpp-str-type T Set object API string type (default std::string)\n"
|
||||
" T::c_str() and T::length() must be supported\n"
|
||||
" --gen-nullable Add Clang _Nullable for C++ pointer. or @Nullable for Java\n"
|
||||
" --gen-generated Add @Generated annotation for Java\n"
|
||||
" --gen-all Generate not just code for the current schema files,\n"
|
||||
" but for all files it includes as well.\n"
|
||||
" If the language uses a single file for output (by default\n"
|
||||
" the case for C++ and JS), all code will end up in this one\n"
|
||||
" file.\n"
|
||||
" --cpp-ptr-type T Set object API pointer type (default std::unique_ptr).\n"
|
||||
" --cpp-str-type T Set object API string type (default std::string).\n"
|
||||
" T::c_str(), T::length() and T::empty() must be supported.\n"
|
||||
" The custom type also needs to be constructible from std::string\n"
|
||||
" (see the --cpp-str-flex-ctor option to change this behavior).\n"
|
||||
" --cpp-str-flex-ctor Don't construct custom string types by passing std::string\n"
|
||||
" from Flatbuffers, but (char* + length).\n"
|
||||
" --object-prefix Customise class prefix for C++ object-based API.\n"
|
||||
" --object-suffix Customise class suffix for C++ object-based API.\n"
|
||||
" Default value is \"T\"\n"
|
||||
" Default value is \"T\".\n"
|
||||
" --no-js-exports Removes Node.js style export lines in JS.\n"
|
||||
" --goog-js-export Uses goog.exports* for closure compiler exporting in JS.\n"
|
||||
" --es6-js-export Uses ECMAScript 6 export style lines in JS.\n"
|
||||
" --go-namespace Generate the overrided namespace in Golang.\n"
|
||||
" --go-import Generate the overrided import for flatbuffers in Golang.\n"
|
||||
" (default is \"github.com/google/flatbuffers/go\")\n"
|
||||
" --go-import Generate the overrided import for flatbuffers in Golang\n"
|
||||
" (default is \"github.com/google/flatbuffers/go\").\n"
|
||||
" --raw-binary Allow binaries without file_indentifier to be read.\n"
|
||||
" This may crash flatc given a mismatched schema.\n"
|
||||
" --size-prefixed Input binaries are size prefixed buffers.\n"
|
||||
" --proto Input is a .proto, translate to .fbs.\n"
|
||||
" --oneof-union Translate .proto oneofs to flatbuffer unions.\n"
|
||||
" --grpc Generate GRPC interfaces for the specified languages\n"
|
||||
" --schema Serialize schemas instead of JSON (use with -b)\n"
|
||||
" --grpc Generate GRPC interfaces for the specified languages.\n"
|
||||
" --schema Serialize schemas instead of JSON (use with -b).\n"
|
||||
" --bfbs-comments Add doc comments to the binary schema files.\n"
|
||||
" --bfbs-builtins Add builtin attributes to the binary schema files.\n"
|
||||
" --conform FILE Specify a schema the following schemas should be\n"
|
||||
" an evolution of. Gives errors if not.\n"
|
||||
" --conform-includes Include path for the schema given with --conform\n"
|
||||
" PATH \n"
|
||||
" --conform-includes Include path for the schema given with --conform PATH\n"
|
||||
" --include-prefix Prefix this path to any generated include statements.\n"
|
||||
" PATH\n"
|
||||
" --keep-prefix Keep original prefix of schema include statement.\n"
|
||||
" --no-fb-import Don't include flatbuffers import statement for TypeScript.\n"
|
||||
" --no-ts-reexport Don't re-export imported dependencies for TypeScript.\n"
|
||||
" --short-names Use short function names for JS and TypeScript.\n"
|
||||
" --reflect-types Add minimal type reflection to code generation.\n"
|
||||
" --reflect-names Add minimal type/name reflection.\n"
|
||||
" --root-type T Select or override the default root_type\n"
|
||||
" --force-defaults Emit default values in binary output from JSON\n"
|
||||
" --force-empty When serializing from object API representation, "
|
||||
" --force-empty When serializing from object API representation,\n"
|
||||
" force strings and vectors to empty rather than null.\n"
|
||||
"FILEs may be schemas (must end in .fbs), or JSON files (conforming to preceding\n"
|
||||
"schema). FILEs after the -- must be binary flatbuffer format files.\n"
|
||||
"FILEs may be schemas (must end in .fbs), binary schemas (must end in .bfbs),\n"
|
||||
"or JSON files (conforming to preceding schema). FILEs after the -- must be\n"
|
||||
"binary flatbuffer format files.\n"
|
||||
"Output files are named using the base file name of the input,\n"
|
||||
"and written to the current directory or the path given by -o.\n"
|
||||
"example: " << program_name << " -c -b schema1.fbs schema2.fbs data.json\n";
|
||||
@@ -231,8 +253,12 @@ int FlatCompiler::Compile(int argc, const char **argv) {
|
||||
} else if (arg == "--cpp-str-type") {
|
||||
if (++argi >= argc) Error("missing type following" + arg, true);
|
||||
opts.cpp_object_api_string_type = argv[argi];
|
||||
} else if (arg == "--cpp-str-flex-ctor") {
|
||||
opts.cpp_object_api_string_flexible_constructor = true;
|
||||
} else if (arg == "--gen-nullable") {
|
||||
opts.gen_nullable = true;
|
||||
} else if (arg == "--gen-generated") {
|
||||
opts.gen_generated = true;
|
||||
} else if (arg == "--object-prefix") {
|
||||
if (++argi >= argc) Error("missing prefix following" + arg, true);
|
||||
opts.object_prefix = argv[argi];
|
||||
@@ -276,6 +302,8 @@ int FlatCompiler::Compile(int argc, const char **argv) {
|
||||
opts.skip_flatbuffers_import = true;
|
||||
} else if (arg == "--no-ts-reexport") {
|
||||
opts.reexport_ts_modules = false;
|
||||
} else if (arg == "--short-names") {
|
||||
opts.js_ts_short_names = true;
|
||||
} else if (arg == "--reflect-types") {
|
||||
opts.mini_reflect = IDLOptions::kTypes;
|
||||
} else if (arg == "--reflect-names") {
|
||||
@@ -320,8 +348,14 @@ int FlatCompiler::Compile(int argc, const char **argv) {
|
||||
std::string contents;
|
||||
if (!flatbuffers::LoadFile(conform_to_schema.c_str(), true, &contents))
|
||||
Error("unable to load schema: " + conform_to_schema);
|
||||
ParseFile(conform_parser, conform_to_schema, contents,
|
||||
conform_include_directories);
|
||||
|
||||
if (flatbuffers::GetExtension(conform_to_schema) ==
|
||||
reflection::SchemaExtension()) {
|
||||
LoadBinarySchema(conform_parser, conform_to_schema, contents);
|
||||
} else {
|
||||
ParseFile(conform_parser, conform_to_schema, contents,
|
||||
conform_include_directories);
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<flatbuffers::Parser> parser(new flatbuffers::Parser(opts));
|
||||
@@ -337,6 +371,7 @@ int FlatCompiler::Compile(int argc, const char **argv) {
|
||||
static_cast<size_t>(file_it - filenames.begin()) >= binary_files_from;
|
||||
auto ext = flatbuffers::GetExtension(filename);
|
||||
auto is_schema = ext == "fbs" || ext == "proto";
|
||||
auto is_binary_schema = ext == reflection::SchemaExtension();
|
||||
if (is_binary) {
|
||||
parser->builder_.Clear();
|
||||
parser->builder_.PushFlatBuffer(
|
||||
@@ -363,7 +398,7 @@ int FlatCompiler::Compile(int argc, const char **argv) {
|
||||
}
|
||||
} else {
|
||||
// Check if file contains 0 bytes.
|
||||
if (contents.length() != strlen(contents.c_str())) {
|
||||
if (!is_binary_schema && contents.length() != strlen(contents.c_str())) {
|
||||
Error("input file appears to be binary: " + filename, true);
|
||||
}
|
||||
if (is_schema) {
|
||||
@@ -372,15 +407,19 @@ int FlatCompiler::Compile(int argc, const char **argv) {
|
||||
// so explicitly using an include.
|
||||
parser.reset(new flatbuffers::Parser(opts));
|
||||
}
|
||||
ParseFile(*parser.get(), filename, contents, include_directories);
|
||||
if (!is_schema && !parser->builder_.GetSize()) {
|
||||
// If a file doesn't end in .fbs, it must be json/binary. Ensure we
|
||||
// didn't just parse a schema with a different extension.
|
||||
Error(
|
||||
"input file is neither json nor a .fbs (schema) file: " + filename,
|
||||
true);
|
||||
if (is_binary_schema) {
|
||||
LoadBinarySchema(*parser.get(), filename, contents);
|
||||
} else {
|
||||
ParseFile(*parser.get(), filename, contents, include_directories);
|
||||
if (!is_schema && !parser->builder_.GetSize()) {
|
||||
// If a file doesn't end in .fbs, it must be json/binary. Ensure we
|
||||
// didn't just parse a schema with a different extension.
|
||||
Error("input file is neither json nor a .fbs (schema) file: " +
|
||||
filename,
|
||||
true);
|
||||
}
|
||||
}
|
||||
if (is_schema && !conform_to_schema.empty()) {
|
||||
if ((is_schema || is_binary_schema) && !conform_to_schema.empty()) {
|
||||
auto err = parser->ConformTo(conform_parser);
|
||||
if (!err.empty()) Error("schemas don\'t conform: " + err);
|
||||
}
|
||||
@@ -398,7 +437,8 @@ int FlatCompiler::Compile(int argc, const char **argv) {
|
||||
if (generator_enabled[i]) {
|
||||
if (!print_make_rules) {
|
||||
flatbuffers::EnsureDirExists(output_path);
|
||||
if ((!params_.generators[i].schema_only || is_schema) &&
|
||||
if ((!params_.generators[i].schema_only ||
|
||||
(is_schema || is_binary_schema)) &&
|
||||
!params_.generators[i].generate(*parser.get(), output_path,
|
||||
filebase)) {
|
||||
Error(std::string("Unable to generate ") +
|
||||
|
||||
@@ -55,15 +55,15 @@ int main(int argc, const char *argv[]) {
|
||||
flatbuffers::GenerateJavaGRPC, flatbuffers::IDLOptions::kJava,
|
||||
"Generate Java classes for tables/structs",
|
||||
flatbuffers::GeneralMakeRule },
|
||||
{ flatbuffers::GenerateJS, "-s", "--js", "JavaScript", true, nullptr,
|
||||
{ flatbuffers::GenerateJSTS, "-s", "--js", "JavaScript", true, nullptr,
|
||||
flatbuffers::IDLOptions::kJs,
|
||||
"Generate JavaScript code for tables/structs", flatbuffers::JSMakeRule },
|
||||
"Generate JavaScript code for tables/structs", flatbuffers::JSTSMakeRule },
|
||||
{ flatbuffers::GenerateDart, "-d", "--dart", "Dart", true, nullptr,
|
||||
flatbuffers::IDLOptions::kDart,
|
||||
"Generate Dart classes for tables/structs", flatbuffers::DartMakeRule },
|
||||
{ flatbuffers::GenerateJS, "-T", "--ts", "TypeScript", true, nullptr,
|
||||
{ flatbuffers::GenerateJSTS, "-T", "--ts", "TypeScript", true, nullptr,
|
||||
flatbuffers::IDLOptions::kTs,
|
||||
"Generate TypeScript code for tables/structs", flatbuffers::JSMakeRule },
|
||||
"Generate TypeScript code for tables/structs", flatbuffers::JSTSMakeRule },
|
||||
{ flatbuffers::GenerateGeneral, "-n", "--csharp", "C#", true, nullptr,
|
||||
flatbuffers::IDLOptions::kCSharp,
|
||||
"Generate C# classes for tables/structs", flatbuffers::GeneralMakeRule },
|
||||
|
||||
@@ -25,7 +25,7 @@ enum OutputFormat { kDecimal, kHexadecimal, kHexadecimal0x };
|
||||
int main(int argc, char *argv[]) {
|
||||
const char *name = argv[0];
|
||||
if (argc <= 1) {
|
||||
printf("%s HASH [OPTION]... STRING... [-- STRING...]\n", name);
|
||||
printf("%s HASH [OPTION]... [--] STRING...\n", name);
|
||||
printf("Available hashing algorithms:\n");
|
||||
printf(" 16 bit:\n");
|
||||
size_t size = sizeof(flatbuffers::kHashFunctions16) /
|
||||
@@ -50,7 +50,7 @@ int main(int argc, char *argv[]) {
|
||||
" -x Output hash in hexadecimal.\n"
|
||||
" -0x Output hash in hexadecimal and prefix with 0x.\n"
|
||||
" -c Append the string to the output in a c-style comment.\n");
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
const char *hash_algorithm = argv[1];
|
||||
@@ -64,7 +64,7 @@ int main(int argc, char *argv[]) {
|
||||
|
||||
if (!hash_function16 && !hash_function32 && !hash_function64) {
|
||||
printf("\"%s\" is not a known hash algorithm.\n", hash_algorithm);
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
OutputFormat output_format = kHexadecimal;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -16,7 +16,6 @@
|
||||
|
||||
// independent from idl_parser, since this code is not needed for most clients
|
||||
#include <cassert>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "flatbuffers/code_generators.h"
|
||||
#include "flatbuffers/flatbuffers.h"
|
||||
@@ -52,11 +51,11 @@ static const char *keywords[] = {
|
||||
// and tables) and output them to a single file.
|
||||
class DartGenerator : public BaseGenerator {
|
||||
public:
|
||||
typedef std::unordered_map<std::string, std::string> namespace_code_map;
|
||||
typedef std::map<std::string, std::string> namespace_code_map;
|
||||
|
||||
DartGenerator(const Parser &parser, const std::string &path,
|
||||
const std::string &file_name)
|
||||
: BaseGenerator(parser, path, file_name, "", "."){};
|
||||
: BaseGenerator(parser, path, file_name, "", ".") {}
|
||||
// Iterate through all definitions we haven't generate code for (enums,
|
||||
// structs, and tables) and output them to a single file.
|
||||
bool generate() {
|
||||
@@ -252,12 +251,11 @@ class DartGenerator : public BaseGenerator {
|
||||
" static bool containsValue(int value) =>"
|
||||
" values.containsKey(value);\n\n";
|
||||
|
||||
for (auto it = enum_def.vals.vec.begin(); it != enum_def.vals.vec.end();
|
||||
++it) {
|
||||
for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
|
||||
auto &ev = **it;
|
||||
|
||||
if (!ev.doc_comment.empty()) {
|
||||
if (it != enum_def.vals.vec.begin()) { code += '\n'; }
|
||||
if (it != enum_def.Vals().begin()) { code += '\n'; }
|
||||
GenDocComment(ev.doc_comment, &code, "", " ");
|
||||
}
|
||||
code += " static const " + name + " " + ev.name + " = ";
|
||||
@@ -265,8 +263,7 @@ class DartGenerator : public BaseGenerator {
|
||||
}
|
||||
|
||||
code += " static get values => {";
|
||||
for (auto it = enum_def.vals.vec.begin(); it != enum_def.vals.vec.end();
|
||||
++it) {
|
||||
for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
|
||||
auto &ev = **it;
|
||||
code += NumToString(ev.value) + ": " + ev.name + ",";
|
||||
}
|
||||
@@ -504,8 +501,9 @@ class DartGenerator : public BaseGenerator {
|
||||
if (field.value.type.base_type == BASE_TYPE_UNION) {
|
||||
code += " {\n";
|
||||
code += " switch (" + field_name + "Type?.value) {\n";
|
||||
for (auto en_it = field.value.type.enum_def->vals.vec.begin() + 1;
|
||||
en_it != field.value.type.enum_def->vals.vec.end(); ++en_it) {
|
||||
auto &enum_def = *field.value.type.enum_def;
|
||||
for (auto en_it = enum_def.Vals().begin() + 1;
|
||||
en_it != enum_def.Vals().end(); ++en_it) {
|
||||
auto &ev = **en_it;
|
||||
|
||||
auto enum_name = NamespaceAliasFromUnionType(ev.name);
|
||||
|
||||
@@ -96,8 +96,7 @@ std::string GenerateFBS(const Parser &parser, const std::string &file_name) {
|
||||
else
|
||||
schema += "enum " + enum_def.name + " : ";
|
||||
schema += GenType(enum_def.underlying_type, true) + " {\n";
|
||||
for (auto it = enum_def.vals.vec.begin(); it != enum_def.vals.vec.end();
|
||||
++it) {
|
||||
for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
|
||||
auto &ev = **it;
|
||||
GenComment(ev.doc_comment, &schema, nullptr, " ");
|
||||
if (enum_def.is_union)
|
||||
|
||||
@@ -56,10 +56,18 @@ struct LanguageParameters {
|
||||
std::string optional_suffix;
|
||||
std::string includes;
|
||||
std::string class_annotation;
|
||||
std::string generated_type_annotation;
|
||||
CommentConfig comment_config;
|
||||
const FloatConstantGenerator *float_gen;
|
||||
};
|
||||
|
||||
const LanguageParameters &GetLangParams(IDLOptions::Language lang) {
|
||||
static TypedFloatConstantGenerator CSharpFloatGen(
|
||||
"Double.", "Single.", "NaN", "PositiveInfinity", "NegativeInfinity");
|
||||
|
||||
static TypedFloatConstantGenerator JavaFloatGen(
|
||||
"Double.", "Float.", "NaN", "POSITIVE_INFINITY", "NEGATIVE_INFINITY");
|
||||
|
||||
static const LanguageParameters language_parameters[] = {
|
||||
{
|
||||
IDLOptions::kJava,
|
||||
@@ -88,11 +96,13 @@ const LanguageParameters &GetLangParams(IDLOptions::Language lang) {
|
||||
"import java.nio.*;\nimport java.lang.*;\nimport "
|
||||
"java.util.*;\nimport com.google.flatbuffers.*;\n",
|
||||
"\n@SuppressWarnings(\"unused\")\n",
|
||||
"\n@javax.annotation.Generated(value=\"flatc\")\n",
|
||||
{
|
||||
"/**",
|
||||
" *",
|
||||
" */",
|
||||
},
|
||||
&JavaFloatGen
|
||||
},
|
||||
{
|
||||
IDLOptions::kCSharp,
|
||||
@@ -120,11 +130,13 @@ const LanguageParameters &GetLangParams(IDLOptions::Language lang) {
|
||||
"?",
|
||||
"using global::System;\nusing global::FlatBuffers;\n\n",
|
||||
"",
|
||||
"",
|
||||
{
|
||||
nullptr,
|
||||
"///",
|
||||
nullptr,
|
||||
},
|
||||
&CSharpFloatGen
|
||||
},
|
||||
};
|
||||
|
||||
@@ -218,6 +230,9 @@ class GeneralGenerator : public BaseGenerator {
|
||||
}
|
||||
code += lang_.class_annotation;
|
||||
}
|
||||
if (parser_.opts.gen_generated) {
|
||||
code += lang_.generated_type_annotation;
|
||||
}
|
||||
code += classcode;
|
||||
if (!namespace_name.empty()) code += lang_.namespace_end;
|
||||
auto filename = NamespaceDir(ns) + defname + lang_.file_extension;
|
||||
@@ -291,7 +306,7 @@ class GeneralGenerator : public BaseGenerator {
|
||||
case BASE_TYPE_UNION:
|
||||
// Unions in C# use a generic Table-derived type for better type safety
|
||||
if (lang_.language == IDLOptions::kCSharp) return "TTable";
|
||||
// fall through
|
||||
FLATBUFFERS_FALLTHROUGH(); // else fall thru
|
||||
default: return "Table";
|
||||
}
|
||||
}
|
||||
@@ -312,7 +327,7 @@ class GeneralGenerator : public BaseGenerator {
|
||||
case BASE_TYPE_UINT: return Type(BASE_TYPE_LONG);
|
||||
case BASE_TYPE_VECTOR:
|
||||
if (vectorelem) return DestinationType(type.VectorType(), vectorelem);
|
||||
// else fall thru
|
||||
FLATBUFFERS_FALLTHROUGH(); // else fall thru
|
||||
default: return type;
|
||||
}
|
||||
}
|
||||
@@ -356,7 +371,7 @@ class GeneralGenerator : public BaseGenerator {
|
||||
case BASE_TYPE_UINT: return " & 0xFFFFFFFFL";
|
||||
case BASE_TYPE_VECTOR:
|
||||
if (vectorelem) return DestinationMask(type.VectorType(), vectorelem);
|
||||
// else fall thru
|
||||
FLATBUFFERS_FALLTHROUGH(); // else fall thru
|
||||
default: return "";
|
||||
}
|
||||
}
|
||||
@@ -423,7 +438,8 @@ class GeneralGenerator : public BaseGenerator {
|
||||
return SourceCastBasic(type, true);
|
||||
}
|
||||
|
||||
std::string GenEnumDefaultValue(const Value &value) const {
|
||||
std::string GenEnumDefaultValue(const FieldDef &field) const {
|
||||
auto& value = field.value;
|
||||
auto enum_def = value.type.enum_def;
|
||||
auto vec = enum_def->vals.vec;
|
||||
auto default_value = StringToInt(value.constant.c_str());
|
||||
@@ -440,19 +456,19 @@ class GeneralGenerator : public BaseGenerator {
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string GenDefaultValue(const Value &value, bool enableLangOverrides) const {
|
||||
std::string GenDefaultValue(const FieldDef &field, bool enableLangOverrides) const {
|
||||
auto& value = field.value;
|
||||
if (enableLangOverrides) {
|
||||
// handles both enum case and vector of enum case
|
||||
if (lang_.language == IDLOptions::kCSharp &&
|
||||
value.type.enum_def != nullptr &&
|
||||
value.type.base_type != BASE_TYPE_UNION) {
|
||||
return GenEnumDefaultValue(value);
|
||||
return GenEnumDefaultValue(field);
|
||||
}
|
||||
}
|
||||
|
||||
auto longSuffix = lang_.language == IDLOptions::kJava ? "L" : "";
|
||||
switch (value.type.base_type) {
|
||||
case BASE_TYPE_FLOAT: return value.constant + "f";
|
||||
case BASE_TYPE_BOOL: return value.constant == "0" ? "false" : "true";
|
||||
case BASE_TYPE_ULONG: {
|
||||
if (lang_.language != IDLOptions::kJava) return value.constant;
|
||||
@@ -462,16 +478,21 @@ class GeneralGenerator : public BaseGenerator {
|
||||
}
|
||||
case BASE_TYPE_UINT:
|
||||
case BASE_TYPE_LONG: return value.constant + longSuffix;
|
||||
default: return value.constant;
|
||||
default:
|
||||
if(IsFloat(value.type.base_type))
|
||||
return lang_.float_gen->GenFloatConstant(field);
|
||||
else
|
||||
return value.constant;
|
||||
}
|
||||
}
|
||||
|
||||
std::string GenDefaultValue(const Value &value) const {
|
||||
return GenDefaultValue(value, true);
|
||||
std::string GenDefaultValue(const FieldDef &field) const {
|
||||
return GenDefaultValue(field, true);
|
||||
}
|
||||
|
||||
std::string GenDefaultValueBasic(const Value &value,
|
||||
std::string GenDefaultValueBasic(const FieldDef &field,
|
||||
bool enableLangOverrides) const {
|
||||
auto& value = field.value;
|
||||
if (!IsScalar(value.type.base_type)) {
|
||||
if (enableLangOverrides) {
|
||||
if (lang_.language == IDLOptions::kCSharp) {
|
||||
@@ -487,11 +508,11 @@ class GeneralGenerator : public BaseGenerator {
|
||||
}
|
||||
return "0";
|
||||
}
|
||||
return GenDefaultValue(value, enableLangOverrides);
|
||||
return GenDefaultValue(field, enableLangOverrides);
|
||||
}
|
||||
|
||||
std::string GenDefaultValueBasic(const Value &value) const {
|
||||
return GenDefaultValueBasic(value, true);
|
||||
std::string GenDefaultValueBasic(const FieldDef &field) const {
|
||||
return GenDefaultValueBasic(field, true);
|
||||
}
|
||||
|
||||
void GenEnum(EnumDef &enum_def, std::string *code_ptr) const {
|
||||
@@ -522,8 +543,7 @@ class GeneralGenerator : public BaseGenerator {
|
||||
if (lang_.language == IDLOptions::kJava) {
|
||||
code += " private " + enum_def.name + "() { }\n";
|
||||
}
|
||||
for (auto it = enum_def.vals.vec.begin(); it != enum_def.vals.vec.end();
|
||||
++it) {
|
||||
for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
|
||||
auto &ev = **it;
|
||||
GenComment(ev.doc_comment, code_ptr, &lang_.comment_config, " ");
|
||||
if (lang_.language != IDLOptions::kCSharp) {
|
||||
@@ -553,8 +573,8 @@ class GeneralGenerator : public BaseGenerator {
|
||||
code += lang_.const_decl;
|
||||
code += lang_.string_type;
|
||||
code += "[] names = { ";
|
||||
auto val = enum_def.vals.vec.front()->value;
|
||||
for (auto it = enum_def.vals.vec.begin(); it != enum_def.vals.vec.end();
|
||||
auto val = enum_def.Vals().front()->value;
|
||||
for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end();
|
||||
++it) {
|
||||
while (val++ != (*it)->value) code += "\"\", ";
|
||||
code += "\"" + (*it)->name + "\", ";
|
||||
@@ -853,7 +873,15 @@ class GeneralGenerator : public BaseGenerator {
|
||||
// accessor object. This is to allow object reuse.
|
||||
code += " public void __init(int _i, ByteBuffer _bb) ";
|
||||
code += "{ " + lang_.accessor_prefix + "bb_pos = _i; ";
|
||||
code += lang_.accessor_prefix + "bb = _bb; }\n";
|
||||
code += lang_.accessor_prefix + "bb = _bb; ";
|
||||
if (!struct_def.fixed && lang_.language == IDLOptions::kJava) {
|
||||
code += lang_.accessor_prefix + "vtable_start = " + lang_.accessor_prefix + "bb_pos - ";
|
||||
code += lang_.accessor_prefix + "bb." + FunctionStart('G') + "etInt(";
|
||||
code += lang_.accessor_prefix + "bb_pos); " + lang_.accessor_prefix + "vtable_size = ";
|
||||
code += lang_.accessor_prefix + "bb." + FunctionStart('G') + "etShort(";
|
||||
code += lang_.accessor_prefix + "vtable_start); ";
|
||||
}
|
||||
code += "}\n";
|
||||
code +=
|
||||
" public " + struct_def.name + " __assign(int _i, ByteBuffer _bb) ";
|
||||
code += "{ __init(_i, _bb); return this; }\n\n";
|
||||
@@ -950,7 +978,7 @@ class GeneralGenerator : public BaseGenerator {
|
||||
code += offset_prefix + getter;
|
||||
code += "(o + " + lang_.accessor_prefix + "bb_pos)" + dest_mask;
|
||||
code += " : " + default_cast;
|
||||
code += GenDefaultValue(field.value);
|
||||
code += GenDefaultValue(field);
|
||||
}
|
||||
} else {
|
||||
switch (field.value.type.base_type) {
|
||||
@@ -1014,6 +1042,8 @@ class GeneralGenerator : public BaseGenerator {
|
||||
? index
|
||||
: lang_.accessor_prefix + "__indirect(" + index + ")";
|
||||
code += ", " + lang_.accessor_prefix + "bb";
|
||||
} else if (vectortype.base_type == BASE_TYPE_UNION) {
|
||||
code += index + " - " + lang_.accessor_prefix + "bb_pos";
|
||||
} else {
|
||||
code += index;
|
||||
}
|
||||
@@ -1272,7 +1302,7 @@ class GeneralGenerator : public BaseGenerator {
|
||||
// supply all arguments, and thus won't compile when fields are added.
|
||||
if (lang_.language != IDLOptions::kJava) {
|
||||
code += " = ";
|
||||
code += GenDefaultValueBasic(field.value);
|
||||
code += GenDefaultValueBasic(field);
|
||||
}
|
||||
}
|
||||
code += ") {\n builder.";
|
||||
@@ -1332,7 +1362,7 @@ class GeneralGenerator : public BaseGenerator {
|
||||
code += ", ";
|
||||
if (lang_.language == IDLOptions::kJava)
|
||||
code += SourceCastBasic(field.value.type);
|
||||
code += GenDefaultValue(field.value, false);
|
||||
code += GenDefaultValue(field, false);
|
||||
code += "); }\n";
|
||||
if (field.value.type.base_type == BASE_TYPE_VECTOR) {
|
||||
auto vector_type = field.value.type.VectorType();
|
||||
|
||||
1429
src/idl_gen_go.cpp
1429
src/idl_gen_go.cpp
File diff suppressed because it is too large
Load Diff
@@ -113,12 +113,12 @@ class FlatBufService : public grpc_generator::Service {
|
||||
|
||||
int method_count() const {
|
||||
return static_cast<int>(service_->calls.vec.size());
|
||||
};
|
||||
}
|
||||
|
||||
std::unique_ptr<const grpc_generator::Method> method(int i) const {
|
||||
return std::unique_ptr<const grpc_generator::Method>(
|
||||
new FlatBufMethod(service_->calls.vec[i]));
|
||||
};
|
||||
}
|
||||
|
||||
private:
|
||||
const ServiceDef *service_;
|
||||
@@ -235,7 +235,7 @@ class FlatBufFile : public grpc_generator::File {
|
||||
|
||||
int service_count() const {
|
||||
return static_cast<int>(parser_.services_.vec.size());
|
||||
};
|
||||
}
|
||||
|
||||
std::unique_ptr<const grpc_generator::Service> service(int i) const {
|
||||
return std::unique_ptr<const grpc_generator::Service>(
|
||||
|
||||
@@ -28,7 +28,7 @@ namespace flatbuffers {
|
||||
|
||||
const std::string kGeneratedFileNamePostfix = "_generated";
|
||||
|
||||
struct JsLanguageParameters {
|
||||
struct JsTsLanguageParameters {
|
||||
IDLOptions::Language language;
|
||||
std::string file_extension;
|
||||
};
|
||||
@@ -41,8 +41,8 @@ struct ReexportDescription {
|
||||
|
||||
enum AnnotationType { kParam = 0, kType = 1, kReturns = 2 };
|
||||
|
||||
const JsLanguageParameters &GetJsLangParams(IDLOptions::Language lang) {
|
||||
static JsLanguageParameters js_language_parameters[] = {
|
||||
const JsTsLanguageParameters &GetJsLangParams(IDLOptions::Language lang) {
|
||||
static JsTsLanguageParameters js_language_parameters[] = {
|
||||
{
|
||||
IDLOptions::kJs,
|
||||
".js",
|
||||
@@ -63,23 +63,23 @@ const JsLanguageParameters &GetJsLangParams(IDLOptions::Language lang) {
|
||||
|
||||
static std::string GeneratedFileName(const std::string &path,
|
||||
const std::string &file_name,
|
||||
const JsLanguageParameters &lang) {
|
||||
const JsTsLanguageParameters &lang) {
|
||||
return path + file_name + kGeneratedFileNamePostfix + lang.file_extension;
|
||||
}
|
||||
|
||||
namespace js {
|
||||
namespace jsts {
|
||||
// Iterate through all definitions we haven't generate code for (enums, structs,
|
||||
// and tables) and output them to a single file.
|
||||
class JsGenerator : public BaseGenerator {
|
||||
class JsTsGenerator : public BaseGenerator {
|
||||
public:
|
||||
typedef std::unordered_set<std::string> imported_fileset;
|
||||
typedef std::unordered_multimap<std::string, ReexportDescription>
|
||||
reexport_map;
|
||||
|
||||
JsGenerator(const Parser &parser, const std::string &path,
|
||||
const std::string &file_name)
|
||||
JsTsGenerator(const Parser &parser, const std::string &path,
|
||||
const std::string &file_name)
|
||||
: BaseGenerator(parser, path, file_name, "", "."),
|
||||
lang_(GetJsLangParams(parser_.opts.lang)){};
|
||||
lang_(GetJsLangParams(parser_.opts.lang)) {}
|
||||
// Iterate through all definitions we haven't generate code for (enums,
|
||||
// structs, and tables) and output them to a single file.
|
||||
bool generate() {
|
||||
@@ -105,10 +105,10 @@ class JsGenerator : public BaseGenerator {
|
||||
|
||||
if (lang_.language == IDLOptions::kJs && !exports_code.empty() &&
|
||||
!parser_.opts.skip_js_exports) {
|
||||
if( parser_.opts.use_ES6_js_export_format )
|
||||
code += "// Exports for ECMAScript6 Modules\n";
|
||||
else
|
||||
code += "// Exports for Node.js and RequireJS\n";
|
||||
if (parser_.opts.use_ES6_js_export_format)
|
||||
code += "// Exports for ECMAScript6 Modules\n";
|
||||
else
|
||||
code += "// Exports for Node.js and RequireJS\n";
|
||||
code += exports_code;
|
||||
}
|
||||
|
||||
@@ -117,7 +117,7 @@ class JsGenerator : public BaseGenerator {
|
||||
}
|
||||
|
||||
private:
|
||||
JsLanguageParameters lang_;
|
||||
JsTsLanguageParameters lang_;
|
||||
|
||||
// Generate code for imports
|
||||
void generateImportDependencies(std::string *code_ptr,
|
||||
@@ -128,8 +128,7 @@ class JsGenerator : public BaseGenerator {
|
||||
const auto basename =
|
||||
flatbuffers::StripPath(flatbuffers::StripExtension(file));
|
||||
if (basename != file_name_) {
|
||||
const auto file_name = basename + kGeneratedFileNamePostfix;
|
||||
code += GenPrefixedImport(file, file_name);
|
||||
code += GenPrefixedImport(file, basename);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -149,10 +148,8 @@ class JsGenerator : public BaseGenerator {
|
||||
const auto basename =
|
||||
flatbuffers::StripPath(flatbuffers::StripExtension(file.first));
|
||||
if (basename != file_name_) {
|
||||
const auto file_name = basename + kGeneratedFileNamePostfix;
|
||||
|
||||
if (imported_files.find(file.first) == imported_files.end()) {
|
||||
code += GenPrefixedImport(file.first, file_name);
|
||||
code += GenPrefixedImport(file.first, basename);
|
||||
imported_files.emplace(file.first);
|
||||
}
|
||||
|
||||
@@ -171,7 +168,8 @@ class JsGenerator : public BaseGenerator {
|
||||
for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
|
||||
++it) {
|
||||
auto &enum_def = **it;
|
||||
GenEnum(enum_def, enum_code_ptr, exports_code_ptr, reexports);
|
||||
GenEnum(enum_def, enum_code_ptr, exports_code_ptr, reexports, false);
|
||||
GenEnum(enum_def, enum_code_ptr, exports_code_ptr, reexports, true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -228,7 +226,7 @@ class JsGenerator : public BaseGenerator {
|
||||
code += "var ";
|
||||
if (parser_.opts.use_goog_js_export_format) {
|
||||
exports += "goog.exportSymbol('" + *it + "', " + *it + ");\n";
|
||||
} else if( parser_.opts.use_ES6_js_export_format){
|
||||
} else if (parser_.opts.use_ES6_js_export_format) {
|
||||
exports += "export {" + *it + "};\n";
|
||||
} else {
|
||||
exports += "this." + *it + " = " + *it + ";\n";
|
||||
@@ -325,12 +323,16 @@ class JsGenerator : public BaseGenerator {
|
||||
|
||||
// Generate an enum declaration and an enum string lookup table.
|
||||
void GenEnum(EnumDef &enum_def, std::string *code_ptr,
|
||||
std::string *exports_ptr, reexport_map &reexports) {
|
||||
std::string *exports_ptr, reexport_map &reexports,
|
||||
bool reverse) {
|
||||
if (enum_def.generated) return;
|
||||
if (reverse && lang_.language == IDLOptions::kTs) return; // FIXME.
|
||||
std::string &code = *code_ptr;
|
||||
std::string &exports = *exports_ptr;
|
||||
GenDocComment(enum_def.doc_comment, code_ptr, "@enum");
|
||||
GenDocComment(enum_def.doc_comment, code_ptr,
|
||||
reverse ? "@enum {string}" : "@enum {number}");
|
||||
std::string ns = GetNameSpace(enum_def);
|
||||
std::string enum_def_name = enum_def.name + (reverse ? "Name" : "");
|
||||
if (lang_.language == IDLOptions::kTs) {
|
||||
if (!ns.empty()) { code += "export namespace " + ns + "{\n"; }
|
||||
code += "export enum " + enum_def.name + "{\n";
|
||||
@@ -338,27 +340,35 @@ class JsGenerator : public BaseGenerator {
|
||||
if (enum_def.defined_namespace->components.empty()) {
|
||||
code += "var ";
|
||||
if (parser_.opts.use_goog_js_export_format) {
|
||||
exports += "goog.exportSymbol('" + enum_def.name + "', " +
|
||||
exports += "goog.exportSymbol('" + enum_def_name + "', " +
|
||||
enum_def.name + ");\n";
|
||||
} else if (parser_.opts.use_ES6_js_export_format) {
|
||||
exports += "export {" + enum_def.name + "};\n";
|
||||
exports += "export {" + enum_def_name + "};\n";
|
||||
} else {
|
||||
exports += "this." + enum_def.name + " = " + enum_def.name + ";\n";
|
||||
exports += "this." + enum_def_name + " = " + enum_def_name + ";\n";
|
||||
}
|
||||
}
|
||||
code += WrapInNameSpace(enum_def) + " = {\n";
|
||||
code += WrapInNameSpace(enum_def) + (reverse ? "Name" : "") + " = {\n";
|
||||
}
|
||||
for (auto it = enum_def.vals.vec.begin(); it != enum_def.vals.vec.end();
|
||||
++it) {
|
||||
for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
|
||||
auto &ev = **it;
|
||||
if (!ev.doc_comment.empty()) {
|
||||
if (it != enum_def.vals.vec.begin()) { code += '\n'; }
|
||||
if (it != enum_def.Vals().begin()) { code += '\n'; }
|
||||
GenDocComment(ev.doc_comment, code_ptr, "", " ");
|
||||
}
|
||||
code += " " + ev.name;
|
||||
code += lang_.language == IDLOptions::kTs ? "= " : ": ";
|
||||
code += NumToString(ev.value);
|
||||
code += (it + 1) != enum_def.vals.vec.end() ? ",\n" : "\n";
|
||||
|
||||
// Generate mapping between EnumName: EnumValue(int)
|
||||
if (reverse) {
|
||||
code += " " + NumToString(ev.value);
|
||||
code += lang_.language == IDLOptions::kTs ? "= " : ": ";
|
||||
code += "'" + ev.name + "'";
|
||||
} else {
|
||||
code += " " + ev.name;
|
||||
code += lang_.language == IDLOptions::kTs ? "= " : ": ";
|
||||
code += NumToString(ev.value);
|
||||
}
|
||||
|
||||
code += (it + 1) != enum_def.Vals().end() ? ",\n" : "\n";
|
||||
|
||||
if (ev.union_type.struct_def) {
|
||||
ReexportDescription desc = { ev.name,
|
||||
@@ -446,8 +456,9 @@ class JsGenerator : public BaseGenerator {
|
||||
case BASE_TYPE_LONG:
|
||||
case BASE_TYPE_ULONG: {
|
||||
int64_t constant = StringToInt(value.constant.c_str());
|
||||
return context + ".createLong(" + NumToString((int32_t)constant) +
|
||||
", " + NumToString((int32_t)(constant >> 32)) + ")";
|
||||
return context + ".createLong(" +
|
||||
NumToString(static_cast<int32_t>(constant)) + ", " +
|
||||
NumToString(static_cast<int32_t>(constant >> 32)) + ")";
|
||||
}
|
||||
|
||||
default: return value.constant;
|
||||
@@ -510,10 +521,26 @@ class JsGenerator : public BaseGenerator {
|
||||
return "NS" + std::to_string(HashFnv1a<uint64_t>(file.c_str()));
|
||||
}
|
||||
|
||||
static std::string GenPrefixedImport(const std::string &full_file_name,
|
||||
const std::string &base_file_name) {
|
||||
std::string GenPrefixedImport(const std::string &full_file_name,
|
||||
const std::string &base_name) {
|
||||
// Either keep the include path as it was
|
||||
// or use only the base_name + kGeneratedFileNamePostfix
|
||||
std::string path;
|
||||
if (parser_.opts.keep_include_path) {
|
||||
auto it = parser_.included_files_.find(full_file_name);
|
||||
FLATBUFFERS_ASSERT(it != parser_.included_files_.end());
|
||||
path =
|
||||
flatbuffers::StripExtension(it->second) + kGeneratedFileNamePostfix;
|
||||
} else {
|
||||
path = base_name + kGeneratedFileNamePostfix;
|
||||
}
|
||||
|
||||
// Add the include prefix and make the path always relative
|
||||
path = flatbuffers::ConCatPathFileName(parser_.opts.include_prefix, path);
|
||||
path = std::string(".") + kPathSeparator + path;
|
||||
|
||||
return "import * as " + GenFileNamespacePrefix(full_file_name) +
|
||||
" from \"./" + base_file_name + "\";\n";
|
||||
" from \"" + path + "\";\n";
|
||||
}
|
||||
|
||||
// Adds a source-dependent prefix, for of import * statements.
|
||||
@@ -521,7 +548,9 @@ class JsGenerator : public BaseGenerator {
|
||||
const std::string &file) {
|
||||
const auto basename =
|
||||
flatbuffers::StripPath(flatbuffers::StripExtension(file));
|
||||
if (basename == file_name_ || parser_.opts.generate_all) { return typeName; }
|
||||
if (basename == file_name_ || parser_.opts.generate_all) {
|
||||
return typeName;
|
||||
}
|
||||
return GenFileNamespacePrefix(file) + "." + typeName;
|
||||
}
|
||||
|
||||
@@ -668,11 +697,11 @@ class JsGenerator : public BaseGenerator {
|
||||
GenTypeAnnotation(kParam, object_name + "=", "obj") +
|
||||
GenTypeAnnotation(kReturns, object_name, "", false));
|
||||
if (lang_.language == IDLOptions::kTs) {
|
||||
code += "static getRootAs" + struct_def.name;
|
||||
code += "static getRoot" + Verbose(struct_def, "As");
|
||||
code += "(bb:flatbuffers.ByteBuffer, obj?:" + object_name +
|
||||
"):" + object_name + " {\n";
|
||||
} else {
|
||||
code += object_name + ".getRootAs" + struct_def.name;
|
||||
code += object_name + ".getRoot" + Verbose(struct_def, "As");
|
||||
code += " = function(bb, obj) {\n";
|
||||
}
|
||||
code += " return (obj || new " + object_name;
|
||||
@@ -736,6 +765,10 @@ class JsGenerator : public BaseGenerator {
|
||||
GenPrefixedTypeName(GenTypeName(field.value.type, false, true),
|
||||
field.value.type.enum_def->file) +
|
||||
" {\n";
|
||||
|
||||
if (!parser_.opts.generate_all) {
|
||||
imported_files.insert(field.value.type.enum_def->file);
|
||||
}
|
||||
} else {
|
||||
code += "):" + GenTypeName(field.value.type, false, true) + " {\n";
|
||||
}
|
||||
@@ -849,7 +882,7 @@ class JsGenerator : public BaseGenerator {
|
||||
code += prefix + ", obj?:" + vectortypename;
|
||||
|
||||
if (!parser_.opts.generate_all) {
|
||||
imported_files.insert(vectortype.struct_def->file);
|
||||
imported_files.insert(vectortype.struct_def->file);
|
||||
}
|
||||
} else if (vectortype.base_type == BASE_TYPE_STRING) {
|
||||
code += prefix + "):string\n";
|
||||
@@ -1056,12 +1089,12 @@ class JsGenerator : public BaseGenerator {
|
||||
"", false));
|
||||
|
||||
if (lang_.language == IDLOptions::kTs) {
|
||||
code +=
|
||||
"static create" + struct_def.name + "(builder:flatbuffers.Builder";
|
||||
code += "static create" + Verbose(struct_def) +
|
||||
"(builder:flatbuffers.Builder";
|
||||
code += arguments + "):flatbuffers.Offset {\n";
|
||||
} else {
|
||||
code +=
|
||||
object_name + ".create" + struct_def.name + " = function(builder";
|
||||
code += object_name + ".create" + Verbose(struct_def);
|
||||
code += " = function(builder";
|
||||
code += arguments + ") {\n";
|
||||
}
|
||||
|
||||
@@ -1073,10 +1106,10 @@ class JsGenerator : public BaseGenerator {
|
||||
"builder", false));
|
||||
|
||||
if (lang_.language == IDLOptions::kTs) {
|
||||
code += "static start" + struct_def.name;
|
||||
code += "(builder:flatbuffers.Builder) {\n";
|
||||
code += "static start" + Verbose(struct_def) +
|
||||
"(builder:flatbuffers.Builder) {\n";
|
||||
} else {
|
||||
code += object_name + ".start" + struct_def.name;
|
||||
code += object_name + ".start" + Verbose(struct_def);
|
||||
code += " = function(builder) {\n";
|
||||
}
|
||||
|
||||
@@ -1089,8 +1122,7 @@ class JsGenerator : public BaseGenerator {
|
||||
it != struct_def.fields.vec.end(); ++it) {
|
||||
auto &field = **it;
|
||||
if (field.deprecated) continue;
|
||||
auto argname = MakeCamel(field.name, false);
|
||||
if (!IsScalar(field.value.type.base_type)) { argname += "Offset"; }
|
||||
const auto argname = GetArgName(field);
|
||||
|
||||
// Generate the field insertion method
|
||||
GenDocComment(
|
||||
@@ -1100,17 +1132,9 @@ class JsGenerator : public BaseGenerator {
|
||||
argname, false));
|
||||
|
||||
if (lang_.language == IDLOptions::kTs) {
|
||||
std::string argType;
|
||||
if (field.value.type.enum_def) {
|
||||
argType = GenPrefixedTypeName(GenTypeName(field.value.type, true),
|
||||
field.value.type.enum_def->file);
|
||||
} else {
|
||||
argType = GenTypeName(field.value.type, true);
|
||||
}
|
||||
|
||||
code += "static add" + MakeCamel(field.name);
|
||||
code += "(builder:flatbuffers.Builder, " + argname + ":" + argType +
|
||||
") {\n";
|
||||
code += "(builder:flatbuffers.Builder, " + argname + ":" +
|
||||
GetArgType(field) + ") {\n";
|
||||
} else {
|
||||
code += object_name + ".add" + MakeCamel(field.name);
|
||||
code += " = function(builder, " + argname + ") {\n";
|
||||
@@ -1195,10 +1219,10 @@ class JsGenerator : public BaseGenerator {
|
||||
GenTypeAnnotation(kReturns, "flatbuffers.Offset", "", false));
|
||||
|
||||
if (lang_.language == IDLOptions::kTs) {
|
||||
code += "static end" + struct_def.name;
|
||||
code += "static end" + Verbose(struct_def);
|
||||
code += "(builder:flatbuffers.Builder):flatbuffers.Offset {\n";
|
||||
} else {
|
||||
code += object_name + ".end" + struct_def.name;
|
||||
code += object_name + ".end" + Verbose(struct_def);
|
||||
code += " = function(builder) {\n";
|
||||
}
|
||||
|
||||
@@ -1224,11 +1248,11 @@ class JsGenerator : public BaseGenerator {
|
||||
false));
|
||||
|
||||
if (lang_.language == IDLOptions::kTs) {
|
||||
code += "static finish" + struct_def.name + "Buffer";
|
||||
code += "static finish" + Verbose(struct_def) + "Buffer";
|
||||
code +=
|
||||
"(builder:flatbuffers.Builder, offset:flatbuffers.Offset) {\n";
|
||||
} else {
|
||||
code += object_name + ".finish" + struct_def.name + "Buffer";
|
||||
code += object_name + ".finish" + Verbose(struct_def) + "Buffer";
|
||||
code += " = function(builder, offset) {\n";
|
||||
}
|
||||
|
||||
@@ -1239,24 +1263,112 @@ class JsGenerator : public BaseGenerator {
|
||||
code += ");\n";
|
||||
code += "};\n\n";
|
||||
}
|
||||
|
||||
// Generate a convenient CreateX function
|
||||
if (lang_.language == IDLOptions::kJs) {
|
||||
std::string paramDoc =
|
||||
GenTypeAnnotation(kParam, "flatbuffers.Builder", "builder");
|
||||
for (auto it = struct_def.fields.vec.begin();
|
||||
it != struct_def.fields.vec.end(); ++it) {
|
||||
const auto &field = **it;
|
||||
if (field.deprecated)
|
||||
continue;
|
||||
paramDoc +=
|
||||
GenTypeAnnotation(kParam, GetArgType(field), GetArgName(field));
|
||||
}
|
||||
paramDoc +=
|
||||
GenTypeAnnotation(kReturns, "flatbuffers.Offset", "", false);
|
||||
|
||||
GenDocComment(code_ptr, paramDoc);
|
||||
}
|
||||
|
||||
if (lang_.language == IDLOptions::kTs) {
|
||||
code += "static create" + Verbose(struct_def);
|
||||
code += "(builder:flatbuffers.Builder";
|
||||
} else {
|
||||
code += object_name + ".create" + Verbose(struct_def);
|
||||
code += " = function(builder";
|
||||
}
|
||||
for (auto it = struct_def.fields.vec.begin();
|
||||
it != struct_def.fields.vec.end(); ++it) {
|
||||
const auto &field = **it;
|
||||
if (field.deprecated)
|
||||
continue;
|
||||
|
||||
if (lang_.language == IDLOptions::kTs) {
|
||||
code += ", " + GetArgName(field) + ":" + GetArgType(field);
|
||||
} else {
|
||||
code += ", " + GetArgName(field);
|
||||
}
|
||||
}
|
||||
|
||||
if (lang_.language == IDLOptions::kTs) {
|
||||
code += "):flatbuffers.Offset {\n";
|
||||
code += " " + struct_def.name + ".start" + Verbose(struct_def) +
|
||||
"(builder);\n";
|
||||
} else {
|
||||
code += ") {\n";
|
||||
code += " " + object_name + ".start" + Verbose(struct_def) +
|
||||
"(builder);\n";
|
||||
}
|
||||
|
||||
std::string methodPrefix =
|
||||
lang_.language == IDLOptions::kTs ? struct_def.name : object_name;
|
||||
for (auto it = struct_def.fields.vec.begin();
|
||||
it != struct_def.fields.vec.end(); ++it) {
|
||||
const auto &field = **it;
|
||||
if (field.deprecated)
|
||||
continue;
|
||||
|
||||
code += " " + methodPrefix + ".add" + MakeCamel(field.name) + "(";
|
||||
code += "builder, " + GetArgName(field) + ");\n";
|
||||
}
|
||||
|
||||
code += " return " + methodPrefix + ".end" + Verbose(struct_def) +
|
||||
"(builder);\n";
|
||||
code += "}\n";
|
||||
if (lang_.language == IDLOptions::kJs)
|
||||
code += "\n";
|
||||
}
|
||||
|
||||
if (lang_.language == IDLOptions::kTs) {
|
||||
if (!object_namespace.empty()) { code += "}\n"; }
|
||||
if (!object_namespace.empty()) {
|
||||
code += "}\n";
|
||||
}
|
||||
code += "}\n";
|
||||
}
|
||||
}
|
||||
};
|
||||
} // namespace js
|
||||
|
||||
bool GenerateJS(const Parser &parser, const std::string &path,
|
||||
const std::string &file_name) {
|
||||
js::JsGenerator generator(parser, path, file_name);
|
||||
std::string GetArgType(const FieldDef &field) {
|
||||
if (field.value.type.enum_def)
|
||||
return GenPrefixedTypeName(GenTypeName(field.value.type, true),
|
||||
field.value.type.enum_def->file);
|
||||
return GenTypeName(field.value.type, true);
|
||||
}
|
||||
|
||||
static std::string GetArgName(const FieldDef &field) {
|
||||
auto argname = MakeCamel(field.name, false);
|
||||
if (!IsScalar(field.value.type.base_type)) { argname += "Offset"; }
|
||||
|
||||
return argname;
|
||||
}
|
||||
|
||||
std::string Verbose(const StructDef &struct_def,
|
||||
const char* prefix = "")
|
||||
{
|
||||
return parser_.opts.js_ts_short_names ? "" : prefix + struct_def.name;
|
||||
}
|
||||
};
|
||||
} // namespace jsts
|
||||
|
||||
bool GenerateJSTS(const Parser &parser, const std::string &path,
|
||||
const std::string &file_name) {
|
||||
jsts::JsTsGenerator generator(parser, path, file_name);
|
||||
return generator.generate();
|
||||
}
|
||||
|
||||
std::string JSMakeRule(const Parser &parser, const std::string &path,
|
||||
const std::string &file_name) {
|
||||
std::string JSTSMakeRule(const Parser &parser, const std::string &path,
|
||||
const std::string &file_name) {
|
||||
FLATBUFFERS_ASSERT(parser.opts.lang <= IDLOptions::kMAX);
|
||||
const auto &lang = GetJsLangParams(parser.opts.lang);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user