diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2019-05-16 09:59:13 +0200 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2019-05-20 10:28:53 +0000 |
commit | 6c11fb357ec39bf087b8b632e2b1e375aef1b38b (patch) | |
tree | c8315530db18a8ee566521c39ab8a6af4f72bc03 /chromium/third_party/flatbuffers | |
parent | 3ffaed019d0772e59d6cdb2d0d32fe4834c31f72 (diff) | |
download | qtwebengine-chromium-6c11fb357ec39bf087b8b632e2b1e375aef1b38b.tar.gz |
BASELINE: Update Chromium to 74.0.3729.159
Change-Id: I8d2497da544c275415aedd94dd25328d555de811
Reviewed-by: Michael BrĂ¼ning <michael.bruning@qt.io>
Diffstat (limited to 'chromium/third_party/flatbuffers')
120 files changed, 10983 insertions, 1889 deletions
diff --git a/chromium/third_party/flatbuffers/BUILD.gn b/chromium/third_party/flatbuffers/BUILD.gn index 87c4ca20ee4..1c389cc19f0 100644 --- a/chromium/third_party/flatbuffers/BUILD.gn +++ b/chromium/third_party/flatbuffers/BUILD.gn @@ -7,10 +7,6 @@ import("//third_party/flatbuffers/flatbuffer.gni") config("flatbuffers_config") { include_dirs = [ "src/include" ] - - if (is_clang) { - cflags = [ "-Wno-exit-time-destructors" ] - } } # The part of FlatBuffers that Chrome is interested in. @@ -21,6 +17,10 @@ source_set("flatbuffers") { "src/include/flatbuffers/stl_emulation.h", ] + if (is_win) { + data_deps = [ "//build/win:runtime_libs" ] + } + configs -= [ "//build/config/compiler:chromium_code" ] configs += [ "//build/config/compiler:no_chromium_code" ] @@ -60,12 +60,13 @@ source_set("compiler_files") { "src/src/idl_gen_general.cpp", "src/src/idl_gen_go.cpp", "src/src/idl_gen_grpc.cpp", - "src/src/idl_gen_js.cpp", + "src/src/idl_gen_js_ts.cpp", "src/src/idl_gen_json_schema.cpp", "src/src/idl_gen_lobster.cpp", "src/src/idl_gen_lua.cpp", "src/src/idl_gen_php.cpp", "src/src/idl_gen_python.cpp", + "src/src/idl_gen_rust.cpp", "src/src/idl_gen_text.cpp", "src/src/idl_parser.cpp", "src/src/reflection.cpp", @@ -103,9 +104,11 @@ flatbuffer("flatbuffers_samplebuffer") { flatc_include_dirs = [ "src/tests/include_test" ] } -test("flatbuffers_unittest") { +test("flatbuffers_unittests") { sources = [ "src/tests/test.cpp", + "src/tests/test_assert.cpp", + "src/tests/test_builder.cpp", ] deps = [ ":compiler_files", @@ -114,11 +117,18 @@ test("flatbuffers_unittest") { ] data = [ "src/tests/", + + "//testing/scripts/common.py", + "//testing/scripts/run_flatbuffers_unittests.py", + "//testing/xvfb.py", ] - if (is_win) { - # Suppress "object allocated on the heap may not be aligned 16". - cflags = [ "/wd4316" ] - } - defines = [ "FLATBUFFERS_TRACK_VERIFIER_BUFFER_SIZE" ] + defines = [ + "FLATBUFFERS_TRACK_VERIFIER_BUFFER_SIZE", + + # Careful, this test suite needs to be run in the actual out/<build_dir> + # directory. + "FLATBUFFERS_TEST_PATH_PREFIX=" + + rebase_path("//third_party/flatbuffers/src/", root_build_dir), + ] } diff --git a/chromium/third_party/flatbuffers/README.chromium b/chromium/third_party/flatbuffers/README.chromium index 1e7f330948a..ffff6181da4 100644 --- a/chromium/third_party/flatbuffers/README.chromium +++ b/chromium/third_party/flatbuffers/README.chromium @@ -1,8 +1,8 @@ Name: FlatBuffers Short Name: flatbuffers URL: https://github.com/google/flatbuffers -Version: 5d3648b88a91e8a5d67db83df2d08bb9e8702ae8 -Date: 2018-07-24 +Version: 9bf9b18f0a705dfd6d50b98056463a55de6a1bf9 +Date: 2019-02-25 License: Apache 2.0 License File: LICENSE Security Critical: yes diff --git a/chromium/third_party/flatbuffers/flatbuffer.gni b/chromium/third_party/flatbuffers/flatbuffer.gni index 11aae5ed74d..38ee2609765 100644 --- a/chromium/third_party/flatbuffers/flatbuffer.gni +++ b/chromium/third_party/flatbuffers/flatbuffer.gni @@ -128,10 +128,8 @@ template("flatbuffer") { public_deps = [ # The generated headers reference headers within FlatBuffers, so # dependencies must be able to find those headers too. - "//third_party/flatbuffers", - ] - deps = [ ":$action_name", + "//third_party/flatbuffers", ] # This will link any libraries in the deps (the use of invoker.deps in the diff --git a/chromium/third_party/flatbuffers/src/.appveyor/check-generate-code.bat b/chromium/third_party/flatbuffers/src/.appveyor/check-generate-code.bat new file mode 100644 index 00000000000..053c8b125cd --- /dev/null +++ b/chromium/third_party/flatbuffers/src/.appveyor/check-generate-code.bat @@ -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%
\ No newline at end of file diff --git a/chromium/third_party/flatbuffers/src/.bazelci/presubmit.yml b/chromium/third_party/flatbuffers/src/.bazelci/presubmit.yml new file mode 100644 index 00000000000..cea328d01a3 --- /dev/null +++ b/chromium/third_party/flatbuffers/src/.bazelci/presubmit.yml @@ -0,0 +1,23 @@ +--- +buildifier: true +platforms: + ubuntu1404: + build_targets: + - "..." + test_targets: + - "..." + ubuntu1604: + build_targets: + - "..." + test_targets: + - "..." + macos: + build_targets: + - "..." + test_targets: + - "..." + windows: + build_targets: + - "..." + test_targets: + - "..." diff --git a/chromium/third_party/flatbuffers/src/.editorconfig b/chromium/third_party/flatbuffers/src/.editorconfig index c5a1b6c86d4..be31d8c0520 100644 --- a/chromium/third_party/flatbuffers/src/.editorconfig +++ b/chromium/third_party/flatbuffers/src/.editorconfig @@ -1,5 +1,5 @@ root = true -[*.{cpp,cc,h}] +[*.{cpp,cc,h,sh}] end_of_line = LF indent_style = space indent_size = 2 diff --git a/chromium/third_party/flatbuffers/src/.travis.yml b/chromium/third_party/flatbuffers/src/.travis.yml index 3fb0abd66de..23c4c23ba8e 100644 --- a/chromium/third_party/flatbuffers/src/.travis.yml +++ b/chromium/third_party/flatbuffers/src/.travis.yml @@ -2,6 +2,35 @@ 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 + dist: xenial + language: python + python: "3.7" + services: + - docker + install: + - ./conan/travis/install.sh + script: + - ./conan/travis/build.sh + if: tag IS present + +conan-osx: &conan-osx + os: osx + language: generic + install: + - ./conan/travis/install.sh + script: + - ./conan/travis/build.sh + if: tag IS present + matrix: include: #- language: python @@ -30,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 @@ -49,8 +89,18 @@ matrix: - if [ "$TRAVIS_OS_NAME" == "linux" ]; then sudo ln -s -v -f $(which gcc-$GCC_VERSION) /usr/bin/gcc; fi script: - - cmake -DCMAKE_BUILD_TYPE=$BUILD_TYPE . && make && make test - - if [ "$CONAN" == "true" ] && [ "$TRAVIS_OS_NAME" == "linux" ]; then sudo pip install conan && conan create . flatbuffers/testing -s build_type=$BUILD_TYPE; fi + - 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 + -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 @@ -59,29 +109,74 @@ matrix: matrix: - BUILD_TYPE=Debug - BUILD_TYPE=Release + script: - - cmake -DCMAKE_BUILD_TYPE=$BUILD_TYPE . && make && make test + - 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 + -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 - #- 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)) + - <<: *conan-linux + env: CONAN_GCC_VERSIONS=4.9 CONAN_DOCKER_IMAGE=conanio/gcc49 + - <<: *conan-linux + env: CONAN_GCC_VERSIONS=5 CONAN_DOCKER_IMAGE=conanio/gcc5 + - <<: *conan-linux + env: CONAN_GCC_VERSIONS=6 CONAN_DOCKER_IMAGE=conanio/gcc6 + - <<: *conan-linux + env: CONAN_GCC_VERSIONS=7 CONAN_DOCKER_IMAGE=conanio/gcc7 + - <<: *conan-linux + env: CONAN_GCC_VERSIONS=8 CONAN_DOCKER_IMAGE=conanio/gcc8 + - <<: *conan-linux + env: CONAN_CLANG_VERSIONS=3.9 CONAN_DOCKER_IMAGE=conanio/clang39 + - <<: *conan-linux + env: CONAN_CLANG_VERSIONS=4.0 CONAN_DOCKER_IMAGE=conanio/clang40 + - <<: *conan-linux + env: CONAN_CLANG_VERSIONS=5.0 CONAN_DOCKER_IMAGE=conanio/clang50 + - <<: *conan-linux + env: CONAN_CLANG_VERSIONS=6.0 CONAN_DOCKER_IMAGE=conanio/clang60 + - <<: *conan-osx + osx_image: xcode7.3 + env: CONAN_APPLE_CLANG_VERSIONS=7.3 + - <<: *conan-osx + osx_image: xcode8.3 + env: CONAN_APPLE_CLANG_VERSIONS=8.1 + - <<: *conan-osx + osx_image: xcode9 + env: CONAN_APPLE_CLANG_VERSIONS=9.0 + - <<: *conan-osx + osx_image: xcode9.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)) diff --git a/chromium/third_party/flatbuffers/src/.travis/build-and-run-docker-test-containers.sh b/chromium/third_party/flatbuffers/src/.travis/build-and-run-docker-test-containers.sh new file mode 100755 index 00000000000..e6039bf623f --- /dev/null +++ b/chromium/third_party/flatbuffers/src/.travis/build-and-run-docker-test-containers.sh @@ -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 diff --git a/chromium/third_party/flatbuffers/src/.travis/check-generate-code.sh b/chromium/third_party/flatbuffers/src/.travis/check-generate-code.sh new file mode 100755 index 00000000000..880249140a3 --- /dev/null +++ b/chromium/third_party/flatbuffers/src/.travis/check-generate-code.sh @@ -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 diff --git a/chromium/third_party/flatbuffers/src/.travis/check-sources.sh b/chromium/third_party/flatbuffers/src/.travis/check-sources.sh new file mode 100644 index 00000000000..3e6dbf16bea --- /dev/null +++ b/chromium/third_party/flatbuffers/src/.travis/check-sources.sh @@ -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$" diff --git a/chromium/third_party/flatbuffers/src/.travis/check-sources.sh.py b/chromium/third_party/flatbuffers/src/.travis/check-sources.sh.py new file mode 100644 index 00000000000..5ad060cd2f0 --- /dev/null +++ b/chromium/third_party/flatbuffers/src/.travis/check-sources.sh.py @@ -0,0 +1,36 @@ +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 strict CRLF line-ending + LF = btext.count(b'\r') + CRLF = btext.count(b'\r\n') + assert LF >= CRLF, "CRLF logic error" + if CRLF != LF: + raise ValueError("CRLF violation: found {} LF characters".format(LF - CRLF)) + 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) diff --git a/chromium/third_party/flatbuffers/src/BUILD b/chromium/third_party/flatbuffers/src/BUILD index ba3ca2eb243..be302272d13 100644 --- a/chromium/third_party/flatbuffers/src/BUILD +++ b/chromium/third_party/flatbuffers/src/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,12 +88,13 @@ 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", "src/idl_gen_text.cpp", ], includes = [ @@ -103,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", @@ -117,15 +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_assert.cpp", + "tests/test_assert.h", + "tests/test_builder.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", @@ -137,7 +157,29 @@ 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", ], 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"], ) diff --git a/chromium/third_party/flatbuffers/src/CMake/DESCRIPTION.txt b/chromium/third_party/flatbuffers/src/CMake/DESCRIPTION.txt new file mode 100644 index 00000000000..3698b034a2e --- /dev/null +++ b/chromium/third_party/flatbuffers/src/CMake/DESCRIPTION.txt @@ -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. diff --git a/chromium/third_party/flatbuffers/src/CMake/FindFlatBuffers.cmake b/chromium/third_party/flatbuffers/src/CMake/FindFlatBuffers.cmake index 675ea88715c..aad9a6bfb09 100644 --- a/chromium/third_party/flatbuffers/src/CMake/FindFlatBuffers.cmake +++ b/chromium/third_party/flatbuffers/src/CMake/FindFlatBuffers.cmake @@ -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() diff --git a/chromium/third_party/flatbuffers/src/CMake/PackageDebian.cmake b/chromium/third_party/flatbuffers/src/CMake/PackageDebian.cmake index 6653181c169..f587ff7ffe2 100644 --- a/chromium/third_party/flatbuffers/src/CMake/PackageDebian.cmake +++ b/chromium/third_party/flatbuffers/src/CMake/PackageDebian.cmake @@ -37,5 +37,3 @@ if (UNIX) "${CPACK_DEBIAN_PACKAGE_NAME}_${CPACK_DEBIAN_PACKAGE_VERSION}_${CPACK_DEBIAN_PACKAGE_ARCHITECTURE}") endif(UNIX) - -INCLUDE(CPack) diff --git a/chromium/third_party/flatbuffers/src/CMake/PackageRedhat.cmake b/chromium/third_party/flatbuffers/src/CMake/PackageRedhat.cmake new file mode 100644 index 00000000000..4545e729083 --- /dev/null +++ b/chromium/third_party/flatbuffers/src/CMake/PackageRedhat.cmake @@ -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) diff --git a/chromium/third_party/flatbuffers/src/CMakeLists.txt b/chromium/third_party/flatbuffers/src/CMakeLists.txt index af1048dbecd..9f640ac351f 100644 --- a/chromium/third_party/flatbuffers/src/CMakeLists.txt +++ b/chromium/third_party/flatbuffers/src/CMakeLists.txt @@ -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,11 +78,12 @@ 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 src/idl_gen_lua.cpp + src/idl_gen_rust.cpp src/idl_gen_fbs.cpp src/idl_gen_grpc.cpp src/idl_gen_json_schema.cpp @@ -77,6 +107,10 @@ set(FlatBuffers_Tests_SRCS ${FlatBuffers_Library_SRCS} src/idl_gen_fbs.cpp tests/test.cpp + tests/test_assert.h + tests/test_assert.cpp + tests/test_builder.h + tests/test_builder.cpp # file generate by running compiler on tests/monster_test.fbs ${CMAKE_CURRENT_BINARY_DIR}/tests/monster_test_generated.h ) @@ -95,12 +129,25 @@ 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 tests/monster_test.grpc.fb.h + tests/test_assert.h + tests/test_builder.h tests/monster_test.grpc.fb.cc + tests/test_assert.cpp + tests/test_builder.cpp grpc/tests/grpctest.cpp + grpc/tests/message_builder_test.cpp # file generated by running compiler on samples/monster.fbs ${CMAKE_CURRENT_BINARY_DIR}/samples/monster_generated.h ) @@ -111,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 @@ -124,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") @@ -141,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" "-Wc++98-compat-extra-semi" "-Werror=unused-private-field") # enable warning + endif() if(FLATBUFFERS_LIBCXX_WITH_CLANG) if(NOT "${CMAKE_SYSTEM_NAME}" MATCHES "Linux") set(CMAKE_CXX_FLAGS @@ -171,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() @@ -184,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() @@ -209,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}.9.0") + set(FlatBuffers_Library_SONAME_FULL "${FlatBuffers_Library_SONAME_MAJOR}.10.0") set_target_properties(flatbuffers_shared PROPERTIES OUTPUT_NAME flatbuffers SOVERSION "${FlatBuffers_Library_SONAME_MAJOR}" VERSION "${FlatBuffers_Library_SONAME_FULL}") @@ -221,7 +301,7 @@ function(compile_flatbuffers_schema_to_cpp SRC_FBS) add_custom_command( OUTPUT ${GEN_HEADER} COMMAND "${FLATBUFFERS_FLATC_EXECUTABLE}" -c --no-includes --gen-mutable - --gen-object-api -o "${SRC_FBS_DIR}" + --gen-object-api --gen-compare -o "${SRC_FBS_DIR}" --cpp-ptr-type flatbuffers::unique_ptr # Used to test with C++98 STLs --reflect-names -I "${CMAKE_CURRENT_SOURCE_DIR}/tests/include_test" @@ -246,17 +326,35 @@ 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) if(CMAKE_COMPILER_IS_GNUCXX) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-unused-parameter -Wno-shadow") endif() + if(NOT GRPC_INSTALL_PATH) + message(SEND_ERROR "GRPC_INSTALL_PATH variable is not defined. See grpc/README.md") + endif() + if(NOT PROTOBUF_DOWNLOAD_PATH) + message(SEND_ERROR "PROTOBUF_DOWNLOAD_PATH variable is not defined. See grpc/README.md") + endif() + INCLUDE_DIRECTORIES(${GRPC_INSTALL_PATH}/include) + INCLUDE_DIRECTORIES(${PROTOBUF_DOWNLOAD_PATH}/src) + LINK_DIRECTORIES(${GRPC_INSTALL_PATH}/lib) add_executable(grpctest ${FlatBuffers_GRPCTest_SRCS}) target_link_libraries(grpctest grpc++_unsecure grpc_unsecure gpr pthread dl) endif() @@ -301,7 +399,6 @@ if(FLATBUFFERS_INSTALL) install( TARGETS flatc EXPORT FlatcTargets RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} - CONFIGURATIONS Release ) install( @@ -309,7 +406,6 @@ if(FLATBUFFERS_INSTALL) FILE FlatcTargets.cmake NAMESPACE flatbuffers:: DESTINATION ${FB_CMAKE_DIR} - CONFIGURATIONS Release ) endif() @@ -346,10 +442,20 @@ if(FLATBUFFERS_BUILD_TESTS) file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/tests" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}") add_test(NAME flattests COMMAND flattests) + if(FLATBUFFERS_BUILD_GRPCTEST) + add_test(NAME grpctest COMMAND grpctest) + endif() endif() include(CMake/BuildFlatBuffers.cmake) -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() diff --git a/chromium/third_party/flatbuffers/src/WORKSPACE b/chromium/third_party/flatbuffers/src/WORKSPACE index 6ffd07f53bb..be4a402e2da 100644 --- a/chromium/third_party/flatbuffers/src/WORKSPACE +++ b/chromium/third_party/flatbuffers/src/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() diff --git a/chromium/third_party/flatbuffers/src/android/build.gradle b/chromium/third_party/flatbuffers/src/android/build.gradle index 73e4188c8e2..5e9809be769 100644 --- a/chromium/third_party/flatbuffers/src/android/build.gradle +++ b/chromium/third_party/flatbuffers/src/android/build.gradle @@ -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" } } } diff --git a/chromium/third_party/flatbuffers/src/android/jni/Android.mk b/chromium/third_party/flatbuffers/src/android/jni/Android.mk index aec561a9526..b22033269f3 100644 --- a/chromium/third_party/flatbuffers/src/android/jni/Android.mk +++ b/chromium/third_party/flatbuffers/src/android/jni/Android.mk @@ -47,6 +47,10 @@ include $(CLEAR_VARS) LOCAL_MODULE := FlatBufferTest LOCAL_SRC_FILES := android/jni/main.cpp \ tests/test.cpp \ + tests/test_assert.h \ + tests/test_builder.h \ + tests/test_assert.cpp \ + tests/test_builder.cpp \ src/idl_gen_fbs.cpp \ src/idl_gen_general.cpp LOCAL_LDLIBS := -llog -landroid -latomic diff --git a/chromium/third_party/flatbuffers/src/appveyor.yml b/chromium/third_party/flatbuffers/src/appveyor.yml index d9dd5f1c551..75a63c87211 100644 --- a/chromium/third_party/flatbuffers/src/appveyor.yml +++ b/chromium/third_party/flatbuffers/src/appveyor.yml @@ -13,7 +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 @@ -24,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" @@ -32,10 +39,20 @@ build: project: ALL_BUILD.vcxproj verbosity: minimal +after_build: + - python conan/appveyor/install.py + - python conan/appveyor/build.py + install: - set PATH=%CONDA_INSTALL_LOCN%;%CONDA_INSTALL_LOCN%\scripts;%PATH%; + - curl -sSf -o rustup-init.exe https://win.rustup.rs/ + - rustup-init.exe -y + - set PATH=%PATH%;C:\Users\appveyor\.cargo\bin + - rustc -V + - cargo -V test_script: + - call .appveyor\check-generate-code.bat -b %CONFIGURATION% - "cd tests" - rem "Building all code" - generate_code.bat -b %CONFIGURATION% @@ -47,6 +64,8 @@ test_script: - rem "---------------- Java -----------------" - "java -version" - "JavaTest.bat" + - rem "---------------- Rust ----------------" + - "RustTest.bat" - rem "---------------- JS -----------------" - "node --version" - "..\\%CONFIGURATION%\\flatc -b -I include_test monster_test.fbs unicode_test.json" @@ -73,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 ..\\.." diff --git a/chromium/third_party/flatbuffers/src/build_defs.bzl b/chromium/third_party/flatbuffers/src/build_defs.bzl new file mode 100644 index 00000000000..c55ab5180dd --- /dev/null +++ b/chromium/third_party/flatbuffers/src/build_defs.bzl @@ -0,0 +1,230 @@ +# Description: +# BUILD rules for generating flatbuffer files in various languages. + +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. + Outs: + filegroup(name): all generated source files. + Fileset([reflection_name]): (Optional) 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. + Outs: + 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, + ) diff --git a/chromium/third_party/flatbuffers/src/conan/CMakeLists.txt b/chromium/third_party/flatbuffers/src/conan/CMakeLists.txt new file mode 100644 index 00000000000..d32a013271f --- /dev/null +++ b/chromium/third_party/flatbuffers/src/conan/CMakeLists.txt @@ -0,0 +1,12 @@ +cmake_minimum_required(VERSION 2.8) + +message(STATUS "Conan FlatBuffers Wrapper") + +include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake) +conan_basic_setup() + +if (WIN32 AND MSVC AND FLATBUFFERS_BUILD_SHAREDLIB) + set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON) +endif(WIN32 AND MSVC AND FLATBUFFERS_BUILD_SHAREDLIB) + +include(${CMAKE_SOURCE_DIR}/CMakeListsOriginal.txt) diff --git a/chromium/third_party/flatbuffers/src/conan/appveyor/build.py b/chromium/third_party/flatbuffers/src/conan/appveyor/build.py new file mode 100644 index 00000000000..9bac46dbe7b --- /dev/null +++ b/chromium/third_party/flatbuffers/src/conan/appveyor/build.py @@ -0,0 +1,8 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +import os + +if os.getenv("APPVEYOR_REPO_TAG") != "true": + print("Skip build step. It's not TAG") +else: + os.system("python conan/build.py") diff --git a/chromium/third_party/flatbuffers/src/conan/appveyor/install.py b/chromium/third_party/flatbuffers/src/conan/appveyor/install.py new file mode 100644 index 00000000000..962c7da6b7d --- /dev/null +++ b/chromium/third_party/flatbuffers/src/conan/appveyor/install.py @@ -0,0 +1,8 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +import os + +if os.getenv("APPVEYOR_REPO_TAG") != "true": + print("Skip step. It's not TAG") +else: + os.system("pip install conan conan-package-tools") diff --git a/chromium/third_party/flatbuffers/src/conan/build.py b/chromium/third_party/flatbuffers/src/conan/build.py new file mode 100644 index 00000000000..55456311bad --- /dev/null +++ b/chromium/third_party/flatbuffers/src/conan/build.py @@ -0,0 +1,69 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +import os +import re +import subprocess +from cpt.packager import ConanMultiPackager + + +def set_appveyor_environment(): + if os.getenv("APPVEYOR") is not None: + compiler_version = os.getenv("CMAKE_VS_VERSION").split(" ")[0].replace('"', '') + os.environ["CONAN_VISUAL_VERSIONS"] = compiler_version + os.environ["CONAN_STABLE_BRANCH_PATTERN"] = "master" + ci_platform = os.getenv("Platform").replace('"', '') + ci_platform = "x86" if ci_platform == "x86" else "x86_64" + os.environ["CONAN_ARCHS"] = ci_platform + os.environ["CONAN_BUILD_TYPES"] = os.getenv("Configuration").replace('"', '') + + +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") + upload = os.getenv("CONAN_UPLOAD", "https://api.bintray.com/conan/aardappel/flatbuffers") + stable_branch_pattern = os.getenv("CONAN_STABLE_BRANCH_PATTERN", r"v\d+\.\d+\.\d+.*") + test_folder = os.getenv("CPT_TEST_FOLDER", os.path.join("conan", "test_package")) + upload_only_when_stable = os.getenv("CONAN_UPLOAD_ONLY_WHEN_STABLE", True) + set_appveyor_environment() + + builder = ConanMultiPackager(reference=get_reference(username), + username=username, + login_username=login_username, + upload=upload, + stable_branch_pattern=stable_branch_pattern, + upload_only_when_stable=upload_only_when_stable, + test_folder=test_folder) + builder.add_common_builds(pure_c=False) + builder.run() diff --git a/chromium/third_party/flatbuffers/src/conan/test_package/CMakeLists.txt b/chromium/third_party/flatbuffers/src/conan/test_package/CMakeLists.txt new file mode 100644 index 00000000000..9c1c78c582d --- /dev/null +++ b/chromium/third_party/flatbuffers/src/conan/test_package/CMakeLists.txt @@ -0,0 +1,9 @@ +project(test_package CXX) +cmake_minimum_required(VERSION 2.8.11) + +include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake) +conan_basic_setup() + +add_executable(${PROJECT_NAME} test_package.cpp) +target_link_libraries(${PROJECT_NAME} ${CONAN_LIBS}) +set_property(TARGET ${PROJECT_NAME} PROPERTY CXX_STANDARD 11) diff --git a/chromium/third_party/flatbuffers/src/conan/test_package/conanfile.py b/chromium/third_party/flatbuffers/src/conan/test_package/conanfile.py new file mode 100644 index 00000000000..735e31d27bf --- /dev/null +++ b/chromium/third_party/flatbuffers/src/conan/test_package/conanfile.py @@ -0,0 +1,21 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +from conans import ConanFile, CMake +import os + + +class TestPackageConan(ConanFile): + settings = "os", "compiler", "build_type", "arch" + generators = "cmake" + + def build(self): + cmake = CMake(self) + cmake.configure() + cmake.build() + + def test(self): + bin_path = os.path.join("bin", "test_package") + self.run(bin_path, run_environment=True) + self.run("flatc --version", run_environment=True) + self.run("flathash fnv1_16 conan", run_environment=True) diff --git a/chromium/third_party/flatbuffers/src/conan/test_package/test_package.cpp b/chromium/third_party/flatbuffers/src/conan/test_package/test_package.cpp new file mode 100644 index 00000000000..df7d577ae64 --- /dev/null +++ b/chromium/third_party/flatbuffers/src/conan/test_package/test_package.cpp @@ -0,0 +1,35 @@ +/* + * Copyright 2018 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <cstdlib> +#include <iostream> +#include "flatbuffers/util.h" + +// Test to validate Conan package generated + +int main(int /*argc*/, const char * /*argv*/ []) { + + const std::string filename("conanbuildinfo.cmake"); + + if (flatbuffers::FileExists(filename.c_str())) { + std::cout << "File " << filename << " exists.\n"; + } else { + std::cout << "File " << filename << " does not exist.\n"; + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} diff --git a/chromium/third_party/flatbuffers/src/conan/travis/build.sh b/chromium/third_party/flatbuffers/src/conan/travis/build.sh new file mode 100755 index 00000000000..069ced202f8 --- /dev/null +++ b/chromium/third_party/flatbuffers/src/conan/travis/build.sh @@ -0,0 +1,14 @@ +#!/bin/bash + +set -e +set -x + +if [[ "$(uname -s)" == 'Darwin' ]]; then + if which pyenv > /dev/null; then + eval "$(pyenv init -)" + fi + pyenv activate conan +fi + +conan user +python conan/build.py diff --git a/chromium/third_party/flatbuffers/src/conan/travis/install.sh b/chromium/third_party/flatbuffers/src/conan/travis/install.sh new file mode 100755 index 00000000000..f4208d82643 --- /dev/null +++ b/chromium/third_party/flatbuffers/src/conan/travis/install.sh @@ -0,0 +1,22 @@ +#!/bin/bash + +set -e +set -x + +if [[ "$(uname -s)" == 'Darwin' ]]; then + brew update || brew update + brew outdated pyenv || brew upgrade pyenv + brew install pyenv-virtualenv + brew install cmake || true + + if which pyenv > /dev/null; then + eval "$(pyenv init -)" + fi + + pyenv install 2.7.10 + pyenv virtualenv 2.7.10 conan + pyenv rehash + pyenv activate conan +fi + +pip install -U conan_package_tools conan diff --git a/chromium/third_party/flatbuffers/src/conanfile.py b/chromium/third_party/flatbuffers/src/conanfile.py index ee54bd1d263..bdd832c36b8 100644 --- a/chromium/third_party/flatbuffers/src/conanfile.py +++ b/chromium/third_party/flatbuffers/src/conanfile.py @@ -4,52 +4,72 @@ """Conan recipe package for Google FlatBuffers """ import os +import shutil from conans import ConanFile, CMake, tools class FlatbuffersConan(ConanFile): name = "flatbuffers" - version = "1.9.0" - license = "https://github.com/google/flatbuffers/blob/master/LICENSE.txt" + 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", "os_build", "arch_build" - options = {"shared": [True, False]} - default_options = "shared=False" + settings = "os", "compiler", "build_type", "arch" + options = {"shared": [True, False], "fPIC": [True, False]} + default_options = {"shared": False, "fPIC": True} generators = "cmake" exports = "LICENSE.txt" - exports_sources = ["CMake/*", "include/*", "src/*", "grpc/*", "CMakeLists.txt"] + exports_sources = ["CMake/*", "include/*", "src/*", "grpc/*", "CMakeLists.txt", "conan/CMakeLists.txt"] - def _inject_magic_lines(self): - """Inject Conan setup in cmake file to solve exteral dependencies. + def source(self): + """Wrap the original CMake file to call conan_basic_setup """ - conan_magic_lines = '''project(FlatBuffers) - include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake) - conan_basic_setup() - ''' - tools.replace_in_file("CMakeLists.txt", "project(FlatBuffers)", conan_magic_lines) + shutil.move("CMakeLists.txt", "CMakeListsOriginal.txt") + shutil.move(os.path.join("conan", "CMakeLists.txt"), "CMakeLists.txt") - def build(self): - """Configure, build and install FlatBuffers using CMake. + def config_options(self): + """Remove fPIC option on Windows platform + """ + if self.settings.os == "Windows": + self.options.remove("fPIC") + + def configure_cmake(self): + """Create CMake instance and execute configure step """ - self._inject_magic_lines() cmake = CMake(self) cmake.definitions["FLATBUFFERS_BUILD_TESTS"] = False cmake.definitions["FLATBUFFERS_BUILD_SHAREDLIB"] = self.options.shared + cmake.definitions["FLATBUFFERS_BUILD_FLATLIB"] = not self.options.shared cmake.configure() + return cmake + + def build(self): + """Configure, build and install FlatBuffers using CMake. + """ + cmake = self.configure_cmake() cmake.build() - cmake.install() def package(self): """Copy Flatbuffers' artifacts to package folder """ + cmake = self.configure_cmake() + cmake.install() self.copy(pattern="LICENSE.txt", dst="licenses") + self.copy(pattern="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: + if self.settings.compiler == "Visual Studio": + shutil.move(os.path.join(self.package_folder, "lib", "%s.dll" % self.name), + os.path.join(self.package_folder, "bin", "%s.dll" % self.name)) + elif self.settings.compiler == "gcc": + shutil.move(os.path.join(self.package_folder, "lib", "lib%s.dll" % self.name), + os.path.join(self.package_folder, "bin", "lib%s.dll" % self.name)) def package_info(self): """Collect built libraries names and solve flatc path. """ self.cpp_info.libs = tools.collect_libs(self) - self.env_info.PATH.append(os.path.join(self.package_folder, "bin")) self.user_info.flatc = os.path.join(self.package_folder, "bin", "flatc") diff --git a/chromium/third_party/flatbuffers/src/dart/pubspec.yaml b/chromium/third_party/flatbuffers/src/dart/pubspec.yaml index 2fda1d4d044..6adf8aabb0c 100644 --- a/chromium/third_party/flatbuffers/src/dart/pubspec.yaml +++ b/chromium/third_party/flatbuffers/src/dart/pubspec.yaml @@ -1,5 +1,5 @@ name: flat_buffers -version: 1.9.2 +version: 1.10.0 description: > FlatBuffers reading and writing library for Dart. Use the flatc compiler to generate Dart classes for a FlatBuffers schema, and this library to assist with diff --git a/chromium/third_party/flatbuffers/src/docs/source/Building.md b/chromium/third_party/flatbuffers/src/docs/source/Building.md index c2faddad271..a89671109c3 100644 --- a/chromium/third_party/flatbuffers/src/docs/source/Building.md +++ b/chromium/third_party/flatbuffers/src/docs/source/Building.md @@ -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. diff --git a/chromium/third_party/flatbuffers/src/docs/source/Compiler.md b/chromium/third_party/flatbuffers/src/docs/source/Compiler.md index 60494049cae..d7b44c874b7 100644 --- a/chromium/third_party/flatbuffers/src/docs/source/Compiler.md +++ b/chromium/third_party/flatbuffers/src/docs/source/Compiler.md @@ -43,6 +43,8 @@ For any schema input files, one or more generators can be specified: - `--lobster`: Generate Lobster code. +- `--rust`, `-r` : Generate Rust code. + For any data input files: - `--binary`, `-b` : If data is contained in this file, generate a @@ -70,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. @@ -89,19 +97,36 @@ 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-onefile` : Generate single output file (useful for C#) +- `--gen-compare` : Generate operator== for object-based API types. + +- `--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() and T::length() must be supported. + +- `--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 @@ -111,9 +136,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, @@ -121,6 +153,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 @@ -132,12 +168,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. diff --git a/chromium/third_party/flatbuffers/src/docs/source/CppUsage.md b/chromium/third_party/flatbuffers/src/docs/source/CppUsage.md index 983dc5ae622..2808c49c601 100644 --- a/chromium/third_party/flatbuffers/src/docs/source/CppUsage.md +++ b/chromium/third_party/flatbuffers/src/docs/source/CppUsage.md @@ -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,7 +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. @@ -495,4 +508,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> diff --git a/chromium/third_party/flatbuffers/src/docs/source/FlatBuffers.md b/chromium/third_party/flatbuffers/src/docs/source/FlatBuffers.md index 98042214db1..7cc93b92c44 100644 --- a/chromium/third_party/flatbuffers/src/docs/source/FlatBuffers.md +++ b/chromium/third_party/flatbuffers/src/docs/source/FlatBuffers.md @@ -4,7 +4,7 @@ FlatBuffers {#flatbuffers_index} # Overview {#flatbuffers_overview} [FlatBuffers](@ref flatbuffers_overview) is an efficient cross platform -serialization library for C++, C#, C, Go, Java, JavaScript, Lobster, Lua, TypeScript, PHP, and Python. +serialization library for C++, C#, C, Go, Java, JavaScript, Lobster, Lua, TypeScript, PHP, Python, and Rust. It was originally created at Google for game development and other performance-critical applications. @@ -144,6 +144,8 @@ sections provide a more in-depth usage guide. own programs. - How to [use the generated Lobster code](@ref flatbuffers_guide_use_lobster) in your own programs. +- How to [use the generated Rust code](@ref flatbuffers_guide_use_rust) in your + own programs. - [Support matrix](@ref flatbuffers_support) for platforms/languages/features. - Some [benchmarks](@ref flatbuffers_benchmarks) showing the advantage of using FlatBuffers. diff --git a/chromium/third_party/flatbuffers/src/docs/source/Grammar.md b/chromium/third_party/flatbuffers/src/docs/source/Grammar.md index bf79596fa1e..724137e4117 100644 --- a/chromium/third_party/flatbuffers/src/docs/source/Grammar.md +++ b/chromium/third_party/flatbuffers/src/docs/source/Grammar.md @@ -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`) diff --git a/chromium/third_party/flatbuffers/src/docs/source/RustUsage.md b/chromium/third_party/flatbuffers/src/docs/source/RustUsage.md new file mode 100644 index 00000000000..80434a47011 --- /dev/null +++ b/chromium/third_party/flatbuffers/src/docs/source/RustUsage.md @@ -0,0 +1,173 @@ +Use in Rust {#flatbuffers_guide_use_rust} +========== + +## Before you get started + +Before diving into the FlatBuffers usage in Rust, it should be noted that +the [Tutorial](@ref flatbuffers_guide_tutorial) page has a complete guide +to general FlatBuffers usage in all of the supported languages (including Rust). +This page is designed to cover the nuances of FlatBuffers usage, specific to +Rust. + +#### Prerequisites + +This page assumes you have written a FlatBuffers schema and compiled it +with the Schema Compiler. If you have not, please see +[Using the schema compiler](@ref flatbuffers_guide_using_schema_compiler) +and [Writing a schema](@ref flatbuffers_guide_writing_schema). + +Assuming you wrote a schema, say `mygame.fbs` (though the extension doesn't +matter), you've generated a Rust file called `mygame_generated.rs` using the +compiler (e.g. `flatc --rust mygame.fbs` 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`. + +## FlatBuffers Rust library code location + +The code for the FlatBuffers Rust library can be found at +`flatbuffers/rust`. You can browse the library code on the +[FlatBuffers GitHub page](https://github.com/google/flatbuffers/tree/master/rust). + +## Testing the FlatBuffers Rust library + +The code to test the Rust library can be found at `flatbuffers/tests/rust_usage_test`. +The test code itself is located in +[integration_test.rs](https://github.com/google/flatbuffers/blob/master/tests/rust_usage_test/tests/integration_test.rs) + +This test file requires `flatc` to be present. To review how to build the project, +please read the [Building](@ref flatbuffers_guide_building) documenation. + +To run the tests, execute `RustTest.sh` from the `flatbuffers/tests` directory. +For example, on [Linux](https://en.wikipedia.org/wiki/Linux), you would simply +run: `cd tests && ./RustTest.sh`. + +*Note: The shell script requires [Rust](https://www.rust-lang.org) to +be installed.* + +## Using the FlatBuffers Rust library + +*Note: See [Tutorial](@ref flatbuffers_guide_tutorial) for a more in-depth +example of how to use FlatBuffers in Rust.* + +FlatBuffers supports both reading and writing FlatBuffers in Rust. + +To use FlatBuffers in your code, first generate the Rust modules from your +schema with the `--rust` option to `flatc`. Then you can import both FlatBuffers +and the generated code to read or write FlatBuffers. + +For example, here is how you would read a FlatBuffer binary file in Rust: +First, include the library and generated code. Then read the file into +a `u8` vector, which you pass, as a byte slice, to `get_root_as_monster()`. + +This full example program is available in the Rust test suite: +[monster_example.rs](https://github.com/google/flatbuffers/blob/master/tests/rust_usage_test/bin/monster_example.rs) + +It can be run by `cd`ing to the `rust_usage_test` directory and executing: `cargo run monster_example`. + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.rs} + extern crate flatbuffers; + + #[path = "../../monster_test_generated.rs"] + mod monster_test_generated; + pub use monster_test_generated::my_game; + + use std::io::Read; + + fn main() { + let mut f = std::fs::File::open("../monsterdata_test.mon").unwrap(); + let mut buf = Vec::new(); + f.read_to_end(&mut buf).expect("file reading failed"); + + let monster = my_game::example::get_root_as_monster(&buf[..]); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +`monster` is of type `Monster`, and points to somewhere *inside* your +buffer (root object pointers are not the same as `buffer_pointer` !). +If you look in your generated header, you'll see it has +convenient accessors for all fields, e.g. `hp()`, `mana()`, etc: + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.rs} + println!("{}", monster.hp()); // `80` + println!("{}", monster.mana()); // default value of `150` + println!("{:?}", monster.name()); // Some("MyMonster") + } +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +*Note: That we never stored a `mana` value, so it will return the default.* + +## Direct memory access + +As you can see from the above examples, all elements in a buffer are +accessed through generated accessors. This is because everything is +stored in little endian format on all platforms (the accessor +performs a swap operation on big endian machines), and also because +the layout of things is generally not known to the user. + +For structs, layout is deterministic and guaranteed to be the same +across platforms (scalars are aligned to their +own size, and structs themselves to their largest member), and you +are allowed to access this memory directly by using `safe_slice` and +on the reference to a struct, or even an array of structs. + +To compute offsets to sub-elements of a struct, make sure they +are structs themselves, as then you can use the pointers to +figure out the offset without having to hardcode it. This is +handy for use of arrays of structs with calls like `glVertexAttribPointer` +in OpenGL or similar APIs. + +It is important to note is that structs are still little endian on all +machines, so only use tricks like this if you can guarantee you're not +shipping on a big endian machine (using an `#[cfg(target_endian = "little")]` +attribute would be wise). + +The special function `safe_slice` is implemented on Vector objects that are +represented in memory the same way as they are represented on the wire. This +function is always available on vectors of struct, bool, u8, and i8. It is +conditionally-compiled on little-endian systems for all the remaining scalar +types. + +The FlatBufferBuilder function `create_vector_direct` is implemented for all +types that are endian-safe to write with a `memcpy`. It is the write-equivalent +of `safe_slice`. + +## Access of untrusted buffers + +The generated accessor functions access fields over offsets, which is +very quick. These offsets are used to index into Rust slices, so they are +bounds-checked by the Rust runtime. However, our Rust implementation may +change: we may convert access functions to use direct pointer dereferencing, to +improve lookup speed. As a result, users should not rely on the aforementioned +bounds-checking behavior. + +When you're processing large amounts of data from a source you know (e.g. +your own generated data on disk), this is acceptable, but when reading +data from the network that can potentially have been modified by an +attacker, this is undesirable. + +The C++ port provides a buffer verifier. At this time, Rust does not. Rust may +provide a verifier in a future version. In the meantime, Rust users can access +the buffer verifier generated by the C++ port through a foreign function +interface (FFI). + +## Threading + +Reading a FlatBuffer does not touch any memory outside the original buffer, +and is entirely read-only (all immutable), so is safe to access from multiple +threads even without synchronisation primitives. + +Creating a FlatBuffer is not thread safe. All state related to building +a FlatBuffer is contained in a FlatBufferBuilder instance, and no memory +outside of it is touched. To make this thread safe, either do not +share instances of FlatBufferBuilder between threads (recommended), or +manually wrap it in synchronisation primitives. There's no automatic way to +accomplish this, by design, as we feel multithreaded construction +of a single buffer will be rare, and synchronisation overhead would be costly. + +## 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> diff --git a/chromium/third_party/flatbuffers/src/docs/source/Schemas.md b/chromium/third_party/flatbuffers/src/docs/source/Schemas.md index a05b00273eb..66c800da5df 100644 --- a/chromium/third_party/flatbuffers/src/docs/source/Schemas.md +++ b/chromium/third_party/flatbuffers/src/docs/source/Schemas.md @@ -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,6 +321,9 @@ 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`). + 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 enum): the values of this field indicate bits, meaning that any value N specified in the schema will end up representing 1<<N, or if you don't specify values at all, you'll get @@ -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 diff --git a/chromium/third_party/flatbuffers/src/docs/source/Support.md b/chromium/third_party/flatbuffers/src/docs/source/Support.md index e4c66cd6044..c8ac7f7e89d 100644 --- a/chromium/third_party/flatbuffers/src/docs/source/Support.md +++ b/chromium/third_party/flatbuffers/src/docs/source/Support.md @@ -18,23 +18,23 @@ In general: NOTE: this table is a start, it needs to be extended. -Feature | C++ | Java | C# | Go | Python | JS | TS | C | PHP | Dart | Lobster ------------------------------- | ------ | ------ | ------ | ------ | ------ | --------- | --------- | ------ | --- | ------- | ------- -Codegen for all basic features | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | WiP | Yes | Yes -JSON parsing | Yes | No | No | No | No | No | No | Yes | No | No | Yes -Simple mutation | Yes | Yes | Yes | Yes | No | No | No | No | No | No | No -Reflection | Yes | No | No | No | No | No | No | Basic | No | No | No -Buffer verifier | Yes | No | No | No | No | No | No | Yes | No | No | No -Testing: basic | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | ? | Yes | Yes -Testing: fuzz | Yes | No | No | Yes | Yes | No | No | No | ? | No | No -Performance: | Superb | Great | Great | Great | Ok | ? | ? | Superb | ? | ? | Great -Platform: Windows | VS2010 | Yes | Yes | ? | ? | ? | Yes | VS2010 | ? | Yes | Yes -Platform: Linux | GCC282 | Yes | ? | Yes | Yes | ? | Yes | Yes | ? | Yes | Yes -Platform: OS X | Xcode4 | ? | ? | ? | Yes | ? | Yes | Yes | ? | Yes | Yes -Platform: Android | NDK10d | Yes | ? | ? | ? | ? | ? | ? | ? | Flutter | Yes -Platform: iOS | ? | ? | ? | ? | ? | ? | ? | ? | ? | Flutter | Yes -Engine: Unity | ? | ? | Yes | ? | ? | ? | ? | ? | ? | ? | No -Primary authors (github) | aard* | aard* | ev*/js*| rw | rw | evanw/ev* | kr* | mik* | ch* | dnfield | aard* +Feature | C++ | Java | C# | Go | Python | JS | TS | C | PHP | Dart | Lobster | Rust +------------------------------ | ------ | ------ | ------ | ------ | ------ | --------- | --------- | ------ | --- | ------- | ------- | ---- +Codegen for all basic features | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | WiP | Yes | Yes | Yes +JSON parsing | Yes | No | No | No | No | No | No | Yes | No | No | Yes | No +Simple mutation | Yes | Yes | Yes | Yes | No | No | No | No | No | No | No | No +Reflection | Yes | No | No | No | No | No | No | Basic | No | No | No | No +Buffer verifier | Yes | No | No | No | No | No | No | Yes | No | No | No | No +Testing: basic | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | ? | Yes | Yes | Yes +Testing: fuzz | Yes | No | No | Yes | Yes | No | No | No | ? | No | No | Yes +Performance: | Superb | Great | Great | Great | Ok | ? | ? | Superb | ? | ? | Great | Superb +Platform: Windows | VS2010 | Yes | Yes | ? | ? | ? | Yes | VS2010 | ? | Yes | Yes | Yes +Platform: Linux | GCC282 | Yes | ? | Yes | Yes | ? | Yes | Yes | ? | Yes | Yes | Yes +Platform: OS X | Xcode4 | ? | ? | ? | Yes | ? | Yes | Yes | ? | Yes | Yes | Yes +Platform: Android | NDK10d | Yes | ? | ? | ? | ? | ? | ? | ? | Flutter | Yes | ? +Platform: iOS | ? | ? | ? | ? | ? | ? | ? | ? | ? | Flutter | Yes | ? +Engine: Unity | ? | ? | Yes | ? | ? | ? | ? | ? | ? | ? | No | ? +Primary authors (github) | aard* | aard* | ev*/js*| rw | rw | evanw/ev* | kr* | mik* | ch* | dnfield | aard* | rw * aard = aardappel (previously: gwvo) * ev = evolutional diff --git a/chromium/third_party/flatbuffers/src/docs/source/Tutorial.md b/chromium/third_party/flatbuffers/src/docs/source/Tutorial.md index 8cb1ab17382..34cfe5b8642 100644 --- a/chromium/third_party/flatbuffers/src/docs/source/Tutorial.md +++ b/chromium/third_party/flatbuffers/src/docs/source/Tutorial.md @@ -33,6 +33,7 @@ Please select your desired language for our quest: <input type="radio" name="language" value="dart">Dart</input> <input type="radio" name="language" value="lua">Lua</input> <input type="radio" name="language" value="lobster">Lobster</input> + <input type="radio" name="language" value="rust">Rust</input> </form> \endhtmlonly @@ -144,6 +145,9 @@ For your chosen language, please cross-reference with: <div class="language-lobster"> [sample_binary.lobster](https://github.com/google/flatbuffers/blob/master/samples/sample_binary.lobster) </div> +<div class="language-rust"> +[sample_binary.rs](https://github.com/google/flatbuffers/blob/master/samples/sample_binary.rs) +</div> ## Writing the Monsters' FlatBuffer Schema @@ -343,6 +347,12 @@ Please be aware of the difference between `flatc` and `flatcc` tools. ./../flatc --lobster monster.fbs ~~~ </div> +<div class="language-rust"> +~~~{.sh} + cd flatbuffers/sample + ./../flatc --rust monster.fbs +~~~ +</div> For a more complete guide to using the `flatc` compiler, please read the [Using the schema compiler](@ref flatbuffers_guide_using_schema_compiler) @@ -360,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. ~~~ @@ -479,6 +489,21 @@ The first step is to import/include the library, generated files, etc. include "monster_generated.lobster" ~~~ </div> +<div class="language-rust"> +~~~{.rs} + // import the flatbuffers runtime library + extern crate flatbuffers; + + // import the generated code + #[path = "./monster_generated.rs"] + mod monster_generated; + pub use monster_generated::my_game::sample::{get_root_as_monster, + Color, Equipment, + Monster, MonsterArgs, + Vec3, + Weapon, WeaponArgs}; +~~~ +</div> Now we are ready to start building some buffers. In order to start, we need to create an instance of the `FlatBufferBuilder`, which will contain the buffer @@ -570,6 +595,13 @@ which will grow automatically if needed: let builder = flatbuffers_builder {} ~~~ </div> +<div class="language-rust"> +~~~{.rs} + // Build up a serialized buffer algorithmically. + // Initialize it with a capacity of 1024 bytes. + let mut builder = flatbuffers::FlatBufferBuilder::new_with_capacity(1024); +~~~ +</div> After creating the `builder`, we can start serializing our data. Before we make our `orc` Monster, lets create some `Weapon`s: a `Sword` and an `Axe`. @@ -788,6 +820,24 @@ our `orc` Monster, lets create some `Weapon`s: a `Sword` and an `Axe`. builder.MyGame_Sample_WeaponEnd() ~~~ </div> +<div class="language-rust"> +~~~{.rs} + // Serialize some weapons for the Monster: A 'sword' and an 'axe'. + let weapon_one_name = builder.create_string("Sword"); + let weapon_two_name = builder.create_string("Axe"); + + // Use the `Weapon::create` shortcut to create Weapons with named field + // arguments. + let sword = Weapon::create(&mut builder, &WeaponArgs{ + name: Some(weapon_one_name), + damage: 3, + }); + let axe = Weapon::create(&mut builder, &WeaponArgs{ + name: Some(weapon_two_name), + damage: 5, + }); +~~~ +</div> Now let's create our monster, the `orc`. For this `orc`, lets make him `red` with rage, positioned at `(1.0, 2.0, 3.0)`, and give him @@ -959,6 +1009,15 @@ traversal. This is generally easy to do on any tree structures. let inv = builder.MyGame_Sample_MonsterCreateInventoryVector(map(10): _) ~~~ </div> +<div class="language-rust"> +~~~{.rs} + // Name of the Monster. + let name = builder.create_string("Orc"); + + // Inventory. + let inventory = builder.create_vector(&[0u8, 1, 2, 3, 4, 5, 6, 7, 8, 9]); +~~~ +</div> We serialized two built-in data types (`string` and `vector`) and captured their return values. These values are offsets into the serialized data, @@ -1086,8 +1145,14 @@ offsets. let weapons = builder.MyGame_Sample_MonsterCreateWeaponsVector(weapon_offsets) ~~~ </div> +<div class="language-rust"> +~~~{.rs} + // Create a FlatBuffer `vector` that contains offsets to the sword and axe + // we created above. + let weapons = builder.create_vector(&[sword, axe]); +~~~ +</div> -<div class="language-cpp"> <br> Note there's additional convenience overloads of `CreateVector`, allowing you to work with data that's not in a `std::vector`, or allowing you to generate @@ -1203,6 +1268,18 @@ for the `path` field above: let path = builder.EndVector(2) ~~~ </div> +<div class="language-rust"> +~~~{.rs} + // Create the path vector of Vec3 objects. + let x = Vec3::new(1.0, 2.0, 3.0); + let y = Vec3::new(4.0, 5.0, 6.0); + let path = builder.create_vector(&[x, y]); + + // Note that, for convenience, it is also valid to create a vector of + // references to structs, like this: + // let path = builder.create_vector(&[&x, &y]); +~~~ +</div> We have now serialized the non-scalar components of the orc, so we can serialize the monster itself: @@ -1438,6 +1515,27 @@ can serialize the monster itself: let orc = builder.MyGame_Sample_MonsterEnd() ~~~ </div> +<div class="language-rust"> +~~~{.rs} + // 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. + let orc = Monster::create(&mut builder, &MonsterArgs{ + pos: Some(&Vec3::new(1.0f32, 2.0f32, 3.0f32)), + mana: 150, + hp: 80, + name: Some(name), + inventory: Some(inventory), + color: Color::Red, + weapons: Some(weapons), + equipped_type: Equipment::Weapon, + equipped: Some(axe.as_union_value()), + path: Some(path), + ..Default::default() + }); +~~~ +</div> Note how we create `Vec3` struct in-line in the table. Unlike tables, structs are simple combinations of scalars that are always stored inline, just like @@ -1592,6 +1690,14 @@ Here is a repetition these lines, to help highlight them more clearly: builder.MyGame_Sample_MonsterAddEquipped(axe) ~~~ </div> +<div class="language-rust"> + ~~~{.rs} + // You need to call `as_union_value` to turn an object into a type that + // can be used as a union value. + monster_builder.add_equipped_type(Equipment::Weapon); // Union type + monster_builder.add_equipped(axe.as_union_value()); // Union data + ~~~ +</div> After you have created your buffer, you will have the offset to the root of the data in the `orc` variable, so you can finish the buffer by calling the @@ -1675,6 +1781,12 @@ appropriate `finish` method. builder.Finish(orc) ~~~ </div> +<div class="language-rust"> +~~~{.rs} + // Call `finish()` to instruct the builder that this monster is complete. + builder.finish(orc, None); +~~~ +</div> The buffer is now ready to be stored somewhere, sent over the network, be compressed, or whatever you'd like to do with it. You can access the buffer @@ -1784,6 +1896,13 @@ like so: let buf = builder.SizedCopy() // Of type `string`. ~~~ </div> +<div class="language-rust"> +~~~{.rs} + // This must be called after `finish()`. + // `finished_data` returns a byte slice. + let buf = builder.finished_data(); // Of type `&[u8]` +~~~ +</div> Now you can write the bytes to a file, send them over the network.. @@ -1917,6 +2036,21 @@ import './monster_my_game.sample_generated.dart' as myGame; include "monster_generated.lobster" ~~~ </div> +<div class="language-rust"> +~~~{.rs} + // import the flatbuffers runtime library + extern crate flatbuffers; + + // import the generated code + #[path = "./monster_generated.rs"] + mod monster_generated; + pub use monster_generated::my_game::sample::{get_root_as_monster, + Color, Equipment, + Monster, MonsterArgs, + Vec3, + Weapon, WeaponArgs}; +~~~ +</div> Then, assuming you have a buffer of bytes received from disk, network, etc., you can create start accessing the buffer like so: @@ -2044,6 +2178,14 @@ myGame.Monster monster = new myGame.Monster(data); let monster = MyGame_Sample_GetRootAsMonster(buf) ~~~ </div> +<div class="language-rust"> +~~~{.rs} + let buf = /* the data you just read, in a &[u8] */ + + // Get an accessor to the root object inside the buffer. + let monster = get_root_as_monster(buf); +~~~ +</div> If you look in the generated files from the schema compiler, you will see it generated accessors for all non-`deprecated` fields. For example: @@ -2136,6 +2278,14 @@ accessors for all non-`deprecated` fields. For example: let name = monster.name ~~~ </div> +<div class="language-rust"> +~~~{.rs} + // Get and test some scalar types from the FlatBuffer. + let hp = monster.hp(); + let mana = monster.mana(); + let name = monster.name(); +~~~ +</div> These should hold `300`, `150`, and `"Orc"` respectively. @@ -2245,6 +2395,14 @@ To access sub-objects, in the case of our `pos`, which is a `Vec3`: let z = pos.z ~~~ </div> +<div class="language-rust"> +~~~{.rs} + let pos = monster.pos().unwrap(); + let x = pos.x(); + let y = pos.y(); + let z = pos.z(); +~~~ +</div> `x`, `y`, and `z` will contain `1.0`, `2.0`, and `3.0`, respectively. @@ -2329,6 +2487,16 @@ FlatBuffers `vector`. let third_item = monster.inventory(2) ~~~ </div> +<div class="language-rust"> +~~~{.rs} + // Get a test an element from the `inventory` FlatBuffer's `vector`. + let inv = monster.inventory().unwrap(); + + // Note that this vector is returned as a slice, because direct access for + // this type, a `u8` vector, is safe on all platforms: + let third_item = inv[2]; +~~~ +</div> For `vector`s of `table`s, you can access the elements like any other vector, except your need to handle the result as a FlatBuffer `table`: @@ -2424,6 +2592,17 @@ except your need to handle the result as a FlatBuffer `table`: let second_weapon_damage = monster.weapons(1).damage ~~~ </div> +<div class="language-rust"> +~~~{.rs} + // Get and test the `weapons` FlatBuffers's `vector`. + let weps = monster.weapons().unwrap(); + let weps_len = weps.len(); + + let wep2 = weps.get(1); + let second_weapon_name = wep2.name(); + let second_weapon_damage = wep2.damage(); +~~~ +</div> Last, we can access our `Equipped` FlatBuffer `union`. Just like when we created the `union`, we need to get both parts of the `union`: the type and the data. @@ -2585,6 +2764,18 @@ We can access the type to dynamically cast the data as needed (since the let weapon_damage = union_weapon.damage // 5 ~~~ </div> +<div class="language-rust"> +~~~{.rs} + // Get and test the `Equipment` union (`equipped` field). + // `equipped_as_weapon` returns a FlatBuffer handle much like normal table + // fields, but this will return `None` is the union is not actually of that + // type. + if monster.equipped_type() == Equipment::Weapon { + let equipped = monster.equipped_as_weapon().unwrap(); + let weapon_name = equipped.name(); + let weapon_damage = equipped.damage(); +~~~ +</div> ## Mutating FlatBuffers @@ -2675,6 +2866,11 @@ mutators like so: <API for mutating FlatBuffers is not yet available in Lobster.> ~~~ </div> +<div class="language-rust"> +~~~{.rs} + <API for mutating FlatBuffers is not yet available in Rust.> +~~~ +</div> We use the somewhat verbose term `mutate` instead of `set` to indicate that this is a special use case, not to be confused with the default way of constructing @@ -2798,5 +2994,8 @@ For your chosen language, see: <div class="language-lobster"> [Use in Lobster](@ref flatbuffers_guide_use_lobster) </div> +<div class="language-rust"> +[Use in Rust](@ref flatbuffers_guide_use_rust) +</div> <br> diff --git a/chromium/third_party/flatbuffers/src/docs/source/doxyfile b/chromium/third_party/flatbuffers/src/docs/source/doxyfile index 19a2ec943d3..6ba3c108cc9 100644 --- a/chromium/third_party/flatbuffers/src/docs/source/doxyfile +++ b/chromium/third_party/flatbuffers/src/docs/source/doxyfile @@ -760,6 +760,7 @@ INPUT = "FlatBuffers.md" \ "PythonUsage.md" \ "LuaUsage.md" \ "LobsterUsage.md" \ + "RustUsage.md" \ "Support.md" \ "Benchmarks.md" \ "WhitePaper.md" \ @@ -778,6 +779,7 @@ INPUT = "FlatBuffers.md" \ "../../net/FlatBuffers/FlatBufferBuilder.cs" \ "../../include/flatbuffers/flatbuffers.h" \ "../../go/builder.go" + "../../rust/flatbuffers/src/builder.rs" # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses diff --git a/chromium/third_party/flatbuffers/src/docs/source/doxygen_layout.xml b/chromium/third_party/flatbuffers/src/docs/source/doxygen_layout.xml index 3800932f106..a2325075f2d 100644 --- a/chromium/third_party/flatbuffers/src/docs/source/doxygen_layout.xml +++ b/chromium/third_party/flatbuffers/src/docs/source/doxygen_layout.xml @@ -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"> diff --git a/chromium/third_party/flatbuffers/src/grpc/README.md b/chromium/third_party/flatbuffers/src/grpc/README.md index 13485198cf8..544651d6024 100644 --- a/chromium/third_party/flatbuffers/src/grpc/README.md +++ b/chromium/third_party/flatbuffers/src/grpc/README.md @@ -9,3 +9,23 @@ from GRPC, and work with both the Protobuf and FlatBuffers code generator. the GRPC libraries for this to compile. This test will build using the `FLATBUFFERS_BUILD_GRPCTEST` option to the main FlatBuffers CMake project. +## Building Flatbuffers with gRPC + +### Linux + +1. Download, build and install gRPC. See [instructions](https://github.com/grpc/grpc/tree/master/src/cpp). + * Lets say your gRPC clone is at `/your/path/to/grpc_repo`. + * Install gRPC in a custom directory by running `make install prefix=/your/path/to/grpc_repo/install`. +2. `export GRPC_INSTALL_PATH=/your/path/to/grpc_repo/install` +3. `export PROTOBUF_DOWNLOAD_PATH=/your/path/to/grpc_repo/third_party/protobuf` +4. `mkdir build ; cd build` +5. `cmake -DFLATBUFFERS_BUILD_GRPCTEST=ON -DGRPC_INSTALL_PATH=${GRPC_INSTALL_PATH} -DPROTOBUF_DOWNLOAD_PATH=${PROTOBUF_DOWNLOAD_PATH} ..` +6. `make` + +## Running FlatBuffer gRPC tests + +### Linux + +1. `ln -s ${GRPC_INSTALL_PATH}/lib/libgrpc++_unsecure.so.6 ${GRPC_INSTALL_PATH}/lib/libgrpc++_unsecure.so.1` +2. `export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:${GRPC_INSTALL_PATH}/lib` +3. `make test ARGS=-V` diff --git a/chromium/third_party/flatbuffers/src/grpc/build_grpc.sh b/chromium/third_party/flatbuffers/src/grpc/build_grpc.sh new file mode 100755 index 00000000000..8fb9e1c4c39 --- /dev/null +++ b/chromium/third_party/flatbuffers/src/grpc/build_grpc.sh @@ -0,0 +1,21 @@ +#!/bin/bash + +grpc_1_15_1_githash=1a60e6971f428323245a930031ad267bb3142ba4 + +function build_grpc () { + git clone https://github.com/grpc/grpc.git google/grpc + cd google/grpc + git checkout ${grpc_1_15_1_githash} + git submodule update --init + make + make install prefix=`pwd`/install + if [ ! -f ${GRPC_INSTALL_PATH}/lib/libgrpc++_unsecure.so.1 ]; then + ln -s ${GRPC_INSTALL_PATH}/lib/libgrpc++_unsecure.so.6 ${GRPC_INSTALL_PATH}/lib/libgrpc++_unsecure.so.1 + fi + cd ../.. +} + +GRPC_INSTALL_PATH=`pwd`/google/grpc/install +PROTOBUF_DOWNLOAD_PATH=`pwd`/google/grpc/third_party/protobuf + +build_grpc diff --git a/chromium/third_party/flatbuffers/src/grpc/flatbuffers-java-grpc/pom.xml b/chromium/third_party/flatbuffers/src/grpc/flatbuffers-java-grpc/pom.xml index a9d182d374d..479905b6978 100644 --- a/chromium/third_party/flatbuffers/src/grpc/flatbuffers-java-grpc/pom.xml +++ b/chromium/third_party/flatbuffers/src/grpc/flatbuffers-java-grpc/pom.xml @@ -6,7 +6,7 @@ <parent> <groupId>com.google.flatbuffers</groupId> <artifactId>flatbuffers-parent</artifactId> - <version>1.9.0</version> + <version>1.10.0</version> </parent> <artifactId>flatbuffers-java-grpc</artifactId> <name>${project.artifactId}</name> @@ -24,7 +24,7 @@ </developer> </developers> <properties> - <gRPC.version>1.9.0</gRPC.version> + <gRPC.version>1.10.0</gRPC.version> </properties> <dependencies> <dependency> diff --git a/chromium/third_party/flatbuffers/src/grpc/pom.xml b/chromium/third_party/flatbuffers/src/grpc/pom.xml index fa911761d15..1f7b2367e54 100644 --- a/chromium/third_party/flatbuffers/src/grpc/pom.xml +++ b/chromium/third_party/flatbuffers/src/grpc/pom.xml @@ -4,7 +4,7 @@ <groupId>com.google.flatbuffers</groupId> <artifactId>flatbuffers-parent</artifactId> <packaging>pom</packaging> - <version>1.9.0</version> + <version>1.10.0</version> <name>flatbuffers-parent</name> <description>parent pom for flatbuffers java artifacts</description> <properties> diff --git a/chromium/third_party/flatbuffers/src/grpc/src/compiler/go_generator.cc b/chromium/third_party/flatbuffers/src/grpc/src/compiler/go_generator.cc index d620089afa9..604828d6038 100644 --- a/chromium/third_party/flatbuffers/src/grpc/src/compiler/go_generator.cc +++ b/chromium/third_party/flatbuffers/src/grpc/src/compiler/go_generator.cc @@ -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"); diff --git a/chromium/third_party/flatbuffers/src/grpc/src/compiler/java_generator.cc b/chromium/third_party/flatbuffers/src/grpc/src/compiler/java_generator.cc index 93d3108f539..661c9ee686f 100644 --- a/chromium/third_party/flatbuffers/src/grpc/src/compiler/java_generator.cc +++ b/chromium/third_party/flatbuffers/src/grpc/src/compiler/java_generator.cc @@ -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"; diff --git a/chromium/third_party/flatbuffers/src/include/flatbuffers/base.h b/chromium/third_party/flatbuffers/src/include/flatbuffers/base.h index 61ca651b1fa..a64a587f24e 100644 --- a/chromium/third_party/flatbuffers/src/include/flatbuffers/base.h +++ b/chromium/third_party/flatbuffers/src/include/flatbuffers/base.h @@ -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 @@ -51,6 +55,33 @@ #include "flatbuffers/stl_emulation.h" +// Note the __clang__ check is needed, because clang presents itself +// as an older GNUC compiler (4.2). +// Clang 3.3 and later implement all of the ISO C++ 2011 standard. +// Clang 3.4 and later implement all of the ISO C++ 2014 standard. +// http://clang.llvm.org/cxx_status.html + +// 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) && \ @@ -87,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 @@ -104,25 +136,29 @@ #endif // !defined(FLATBUFFERS_LITTLEENDIAN) #define FLATBUFFERS_VERSION_MAJOR 1 -#define FLATBUFFERS_VERSION_MINOR 9 +#define FLATBUFFERS_VERSION_MINOR 10 #define FLATBUFFERS_VERSION_REVISION 0 #define FLATBUFFERS_STRING_EXPAND(X) #X #define FLATBUFFERS_STRING(X) FLATBUFFERS_STRING_EXPAND(X) #if (!defined(_MSC_VER) || _MSC_VER > 1600) && \ - (!defined(__GNUC__) || (__GNUC__ * 100 + __GNUC_MINOR__ >= 407)) + (!defined(__GNUC__) || (__GNUC__ * 100 + __GNUC_MINOR__ >= 407)) || \ + defined(__clang__) #define FLATBUFFERS_FINAL_CLASS final #define FLATBUFFERS_OVERRIDE override + #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) && \ - (!defined(__GNUC__) || (__GNUC__ * 100 + __GNUC_MINOR__ >= 406)) + (!defined(__GNUC__) || (__GNUC__ * 100 + __GNUC_MINOR__ >= 406)) || \ + (defined(__cpp_constexpr) && __cpp_constexpr >= 200704) #define FLATBUFFERS_CONSTEXPR constexpr #else - #define FLATBUFFERS_CONSTEXPR + #define FLATBUFFERS_CONSTEXPR const #endif #if (defined(__cplusplus) && __cplusplus >= 201402L) || \ @@ -132,8 +168,9 @@ #define FLATBUFFERS_CONSTEXPR_CPP14 #endif -#if defined(__GXX_EXPERIMENTAL_CXX0X__) && __GNUC__ * 10 + __GNUC_MINOR__ >= 46 || \ - defined(_MSC_FULL_VER) && _MSC_FULL_VER >= 190023026 +#if (defined(__GXX_EXPERIMENTAL_CXX0X__) && (__GNUC__ * 100 + __GNUC_MINOR__ >= 406)) || \ + (defined(_MSC_FULL_VER) && (_MSC_FULL_VER >= 190023026)) || \ + defined(__clang__) #define FLATBUFFERS_NOEXCEPT noexcept #else #define FLATBUFFERS_NOEXCEPT @@ -142,17 +179,13 @@ // NOTE: the FLATBUFFERS_DELETE_FUNC macro may change the access mode to // private, so be sure to put it at the end or reset access mode explicitly. #if (!defined(_MSC_VER) || _MSC_FULL_VER >= 180020827) && \ - (!defined(__GNUC__) || (__GNUC__ * 100 + __GNUC_MINOR__ >= 404)) + (!defined(__GNUC__) || (__GNUC__ * 100 + __GNUC_MINOR__ >= 404)) || \ + defined(__clang__) #define FLATBUFFERS_DELETE_FUNC(func) func = delete; #else #define FLATBUFFERS_DELETE_FUNC(func) private: func; #endif -#if defined(_MSC_VER) - #pragma warning(push) - #pragma warning(disable: 4127) // C4127: conditional expression is constant -#endif - #ifndef FLATBUFFERS_HAS_STRING_VIEW // Only provide flatbuffers::string_view if __has_include can be used // to detect a header that provides an implementation @@ -175,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 @@ -201,6 +293,11 @@ typedef uintmax_t largest_scalar_t; // We support aligning the contents of buffers up to this size. #define FLATBUFFERS_MAX_ALIGNMENT 16 +#if defined(_MSC_VER) + #pragma warning(push) + #pragma warning(disable: 4127) // C4127: conditional expression is constant +#endif + template<typename T> T EndianSwap(T t) { #if defined(_MSC_VER) #define FLATBUFFERS_BYTESWAP16 _byteswap_ushort @@ -239,6 +336,10 @@ template<typename T> T EndianSwap(T t) { } } +#if defined(_MSC_VER) + #pragma warning(pop) +#endif + template<typename T> T EndianScalar(T t) { #if FLATBUFFERS_LITTLEENDIAN @@ -248,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). diff --git a/chromium/third_party/flatbuffers/src/include/flatbuffers/code_generators.h b/chromium/third_party/flatbuffers/src/include/flatbuffers/code_generators.h index d19002e69d6..c2ed707aeeb 100644 --- a/chromium/third_party/flatbuffers/src/include/flatbuffers/code_generators.h +++ b/chromium/third_party/flatbuffers/src/include/flatbuffers/code_generators.h @@ -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_ diff --git a/chromium/third_party/flatbuffers/src/include/flatbuffers/flatbuffers.h b/chromium/third_party/flatbuffers/src/include/flatbuffers/flatbuffers.h index 6453c3084a7..a1a95f00efb 100644 --- a/chromium/third_party/flatbuffers/src/include/flatbuffers/flatbuffers.h +++ b/chromium/third_party/flatbuffers/src/include/flatbuffers/flatbuffers.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,16 +655,51 @@ 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_), + buffer_minalign_(other.buffer_minalign_), + reserved_(other.reserved_), + buf_(other.buf_), + cur_(other.cur_), + scratch_(other.scratch_) { + // No change in other.allocator_ + // No change in other.initial_size_ + // No change in other.buffer_minalign_ + other.own_allocator_ = false; + other.reserved_ = 0; + other.buf_ = nullptr; + other.cur_ = nullptr; + other.scratch_ = nullptr; + } + + // 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() { - if (buf_) Deallocate(allocator_, buf_, reserved_); - if (own_allocator_ && allocator_) { delete allocator_; } + clear_buffer(); + clear_allocator(); } void reset() { - if (buf_) { - Deallocate(allocator_, buf_, reserved_); - buf_ = nullptr; - } + clear_buffer(); clear(); } @@ -599,12 +717,39 @@ class vector_downward { scratch_ = buf_; } + void clear_allocator() { + if (own_allocator_ && allocator_) { delete allocator_; } + allocator_ = nullptr; + own_allocator_ = false; + } + + void clear_buffer() { + if (buf_) Deallocate(allocator_, buf_, reserved_); + buf_ = nullptr; + } + + // Relinquish the pointer to the caller. + uint8_t *release_raw(size_t &allocated_bytes, size_t &offset) { + auto *buf = buf_; + allocated_bytes = reserved_; + offset = static_cast<size_t>(cur_ - buf_); + + // release_raw only relinquishes the buffer ownership. + // Does not deallocate or reset the allocator. Destructor will do that. + buf_ = nullptr; + clear(); + return buf; + } + // Relinquish the pointer to the caller. DetachedBuffer release() { + // allocator ownership (if any) is transferred to DetachedBuffer. DetachedBuffer fb(allocator_, own_allocator_, buf_, reserved_, cur_, size()); - allocator_ = nullptr; - own_allocator_ = false; + if (own_allocator_) { + allocator_ = nullptr; + own_allocator_ = false; + } buf_ = nullptr; clear(); return fb; @@ -686,6 +831,24 @@ class vector_downward { void pop(size_t bytes_to_remove) { cur_ += bytes_to_remove; } void scratch_pop(size_t bytes_to_remove) { scratch_ -= bytes_to_remove; } + void swap(vector_downward &other) { + using std::swap; + swap(allocator_, other.allocator_); + swap(own_allocator_, other.own_allocator_); + swap(initial_size_, other.initial_size_); + swap(buffer_minalign_, other.buffer_minalign_); + swap(reserved_, other.reserved_); + swap(buf_, other.buf_); + swap(cur_, other.cur_); + swap(scratch_, other.scratch_); + } + + void swap_allocator(vector_downward &other) { + using std::swap; + swap(allocator_, other.allocator_); + swap(own_allocator_, other.own_allocator_); + } + private: // You shouldn't really be copying instances of this class. FLATBUFFERS_DELETE_FUNC(vector_downward(const vector_downward &)) @@ -774,6 +937,56 @@ 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), + nested(false), + finished(false), + minalign_(1), + force_defaults_(false), + dedup_vtables_(true), + string_pool(nullptr) { + EndianCheck(); + // Default construct and swap idiom. + // Lack of delegating constructors in vs2010 makes it more verbose than needed. + Swap(other); + } + // 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 + FlatBufferBuilder temp(std::move(other)); + Swap(temp); + return *this; + } + // clang-format off + #endif // defined(FLATBUFFERS_CPP98_STL) + // clang-format on + + void Swap(FlatBufferBuilder &other) { + using std::swap; + buf_.swap(other.buf_); + swap(num_field_loc, other.num_field_loc); + swap(max_voffset_, other.max_voffset_); + swap(nested, other.nested); + swap(finished, other.finished); + swap(minalign_, other.minalign_); + swap(force_defaults_, other.force_defaults_); + swap(dedup_vtables_, other.dedup_vtables_); + swap(string_pool, other.string_pool); + } + ~FlatBufferBuilder() { if (string_pool) delete string_pool; } @@ -814,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(); } @@ -827,6 +1040,19 @@ class FlatBufferBuilder { return buf_.release(); } + /// @brief Get the released pointer to the serialized buffer. + /// @param The size of the memory block containing + /// the serialized `FlatBuffer`. + /// @param The offset from the released pointer where the finished + /// `FlatBuffer` starts. + /// @return A raw pointer to the start of the memory block containing + /// the serialized `FlatBuffer`. + /// @remark If the allocator is owned, it gets deleted when the destructor is called.. + uint8_t *ReleaseRaw(size_t &size, size_t &offset) { + Finished(); + return buf_.release_raw(size, offset); + } + /// @brief get the minimum alignment this buffer needs to be accessed /// properly. This is only known once all elements have been written (after /// you call Finish()). You can use this information if you need to embed @@ -910,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); } @@ -1010,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; @@ -1031,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); } @@ -1114,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. @@ -1174,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 @@ -1338,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()); } @@ -1476,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); } @@ -1562,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(); @@ -1594,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 &); @@ -1647,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_; }; @@ -1727,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. @@ -1770,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). @@ -1900,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 @@ -1929,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_; @@ -1948,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 @@ -2044,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; } @@ -2196,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 @@ -2223,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) \ @@ -2305,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. }; @@ -2363,9 +2608,6 @@ volatile __attribute__((weak)) const char *flatbuffer_version_string = /// @endcond } // namespace flatbuffers -#if defined(_MSC_VER) - #pragma warning(pop) -#endif // clang-format on #endif // FLATBUFFERS_H_ diff --git a/chromium/third_party/flatbuffers/src/include/flatbuffers/flatc.h b/chromium/third_party/flatbuffers/src/include/flatbuffers/flatc.h index c7b60febc2f..f2765d239ae 100644 --- a/chromium/third_party/flatbuffers/src/include/flatbuffers/flatc.h +++ b/chromium/third_party/flatbuffers/src/include/flatbuffers/flatc.h @@ -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, diff --git a/chromium/third_party/flatbuffers/src/include/flatbuffers/flexbuffers.h b/chromium/third_party/flatbuffers/src/include/flatbuffers/flexbuffers.h index 99345d97230..7cba5b75b71 100644 --- a/chromium/third_party/flatbuffers/src/include/flatbuffers/flexbuffers.h +++ b/chromium/third_party/flatbuffers/src/include/flatbuffers/flexbuffers.h @@ -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, @@ -368,6 +378,9 @@ class Reference { bool IsString() const { return type_ == FBT_STRING; } bool IsKey() const { return type_ == FBT_KEY; } bool IsVector() const { return type_ == FBT_VECTOR || type_ == FBT_MAP; } + bool IsTypedVector() const { return flexbuffers::IsTypedVector(type_); } + bool IsFixedTypedVector() const { return flexbuffers::IsFixedTypedVector(type_); } + bool IsAnyVector() const { return (IsTypedVector() || IsFixedTypedVector() || IsVector());} bool IsMap() const { return type_ == FBT_MAP; } bool IsBlob() const { return type_ == FBT_BLOB; } @@ -481,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; @@ -529,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 += "(?)"; } @@ -562,7 +576,7 @@ class Reference { } TypedVector AsTypedVector() const { - if (IsTypedVector(type_)) { + if (IsTypedVector()) { return TypedVector(Indirect(), byte_width_, ToTypedVectorElementType(type_)); } else { @@ -571,7 +585,7 @@ class Reference { } FixedTypedVector AsFixedTypedVector() const { - if (IsFixedTypedVector(type_)) { + if (IsFixedTypedVector()) { uint8_t len = 0; auto vtype = ToFixedTypedVectorElementType(type_, &len); return FixedTypedVector(Indirect(), byte_width_, vtype, len); @@ -588,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. @@ -701,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)); diff --git a/chromium/third_party/flatbuffers/src/include/flatbuffers/grpc.h b/chromium/third_party/flatbuffers/src/include/flatbuffers/grpc.h index 2c71c7da1cf..a75b67c771a 100644 --- a/chromium/third_party/flatbuffers/src/include/flatbuffers/grpc.h +++ b/chromium/third_party/flatbuffers/src/include/flatbuffers/grpc.h @@ -88,6 +88,24 @@ class SliceAllocator : public Allocator { SliceAllocator(const SliceAllocator &other) = delete; SliceAllocator &operator=(const SliceAllocator &other) = delete; + SliceAllocator(SliceAllocator &&other) + : slice_(grpc_empty_slice()) { + // default-construct and swap idiom + swap(other); + } + + SliceAllocator &operator=(SliceAllocator &&other) { + // move-construct and swap idiom + SliceAllocator temp(std::move(other)); + swap(temp); + return *this; + } + + void swap(SliceAllocator &other) { + using std::swap; + swap(slice_, other.slice_); + } + virtual ~SliceAllocator() { grpc_slice_unref(slice_); } virtual uint8_t *allocate(size_t size) override { @@ -146,11 +164,68 @@ 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; + MessageBuilder(MessageBuilder &&other) + : FlatBufferBuilder(1024, &slice_allocator_, false) { + // Default construct and swap idiom. + 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)); + Swap(temp); + return *this; + } + + void Swap(MessageBuilder &other) { + slice_allocator_.swap(other.slice_allocator_); + FlatBufferBuilder::Swap(other); + // After swapping the FlatBufferBuilder, we swap back the allocator, which restores + // the original allocator back in place. This is necessary because MessageBuilder's + // allocator is its own member (SliceAllocatorMember). The allocator passed to + // FlatBufferBuilder::vector_downward must point to this member. + buf_.swap_allocator(other.buf_); + } + + // Releases the ownership of the buffer pointer. + // Returns the size, offset, and the original grpc_slice that + // allocated the buffer. Also see grpc_slice_unref(). + uint8_t *ReleaseRaw(size_t &size, size_t &offset, grpc_slice &slice) { + uint8_t *buf = FlatBufferBuilder::ReleaseRaw(size, offset); + slice = slice_allocator_.slice_; + slice_allocator_.slice_ = grpc_empty_slice(); + return buf; + } + ~MessageBuilder() {} // GetMessage extracts the subslice of the buffer corresponding to the diff --git a/chromium/third_party/flatbuffers/src/include/flatbuffers/idl.h b/chromium/third_party/flatbuffers/src/include/flatbuffers/idl.h index e544b0df8b9..6b70f3ae7fa 100644 --- a/chromium/third_party/flatbuffers/src/include/flatbuffers/idl.h +++ b/chromium/third_party/flatbuffers/src/include/flatbuffers/idl.h @@ -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. @@ -41,24 +47,24 @@ namespace flatbuffers { // of type tokens. // clang-format off #define FLATBUFFERS_GEN_TYPES_SCALAR(TD) \ - TD(NONE, "", uint8_t, byte, byte, byte, uint8) \ - TD(UTYPE, "", uint8_t, byte, byte, byte, uint8) /* begin scalar/int */ \ - TD(BOOL, "bool", uint8_t, boolean,byte, bool, bool) \ - TD(CHAR, "byte", int8_t, byte, int8, sbyte, int8) \ - TD(UCHAR, "ubyte", uint8_t, byte, byte, byte, uint8) \ - TD(SHORT, "short", int16_t, short, int16, short, int16) \ - TD(USHORT, "ushort", uint16_t, short, uint16, ushort, uint16) \ - TD(INT, "int", int32_t, int, int32, int, int32) \ - TD(UINT, "uint", uint32_t, int, uint32, uint, uint32) \ - TD(LONG, "long", int64_t, long, int64, long, int64) \ - TD(ULONG, "ulong", uint64_t, long, uint64, ulong, uint64) /* end int */ \ - TD(FLOAT, "float", float, float, float32, float, float32) /* begin float */ \ - TD(DOUBLE, "double", double, double, float64, double, float64) /* end float/scalar */ + TD(NONE, "", uint8_t, byte, byte, byte, uint8, u8) \ + TD(UTYPE, "", uint8_t, byte, byte, byte, uint8, u8) /* begin scalar/int */ \ + TD(BOOL, "bool", uint8_t, boolean,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) \ + TD(USHORT, "ushort", uint16_t, short, uint16, ushort, uint16, u16) \ + TD(INT, "int", int32_t, int, int32, int, int32, i32) \ + TD(UINT, "uint", uint32_t, int, uint32, uint, uint32, u32) \ + TD(LONG, "long", int64_t, long, int64, long, int64, i64) \ + TD(ULONG, "ulong", uint64_t, long, uint64, ulong, uint64, u64) /* end int */ \ + TD(FLOAT, "float", float, float, float32, float, float32, f32) /* begin float */ \ + TD(DOUBLE, "double", double, double, float64, double, float64, f64) /* end float/scalar */ #define FLATBUFFERS_GEN_TYPES_POINTER(TD) \ - TD(STRING, "string", Offset<void>, int, int, StringOffset, int) \ - TD(VECTOR, "", Offset<void>, int, int, VectorOffset, int) \ - TD(STRUCT, "", Offset<void>, int, int, int, int) \ - TD(UNION, "", Offset<void>, int, int, int, int) + TD(STRING, "string", Offset<void>, int, int, StringOffset, int, unused) \ + TD(VECTOR, "", Offset<void>, int, int, VectorOffset, int, unused) \ + TD(STRUCT, "", Offset<void>, int, int, int, int, unused) \ + TD(UNION, "", Offset<void>, int, int, int, int, unused) // The fields are: // - enum @@ -68,12 +74,14 @@ namespace flatbuffers { // - Go type. // - C# / .Net type. // - Python type. +// - Rust type. // using these macros, we can now write code dealing with types just once, e.g. /* switch (type) { - #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \ + #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, \ + RTYPE) \ case BASE_TYPE_ ## ENUM: \ // do something specific to CTYPE here FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD) @@ -90,13 +98,15 @@ switch (type) { __extension__ // Stop GCC complaining about trailing comma with -Wpendantic. #endif enum BaseType { - #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \ + #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, \ + RTYPE) \ BASE_TYPE_ ## ENUM, FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD) #undef FLATBUFFERS_TD }; -#define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \ +#define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, \ + RTYPE) \ static_assert(sizeof(CTYPE) <= sizeof(largest_scalar_t), \ "define largest_scalar_t as " #CTYPE); FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD) @@ -111,6 +121,8 @@ inline bool IsFloat (BaseType t) { return t == BASE_TYPE_FLOAT || inline bool IsLong (BaseType t) { return t == BASE_TYPE_LONG || t == BASE_TYPE_ULONG; } inline bool IsBool (BaseType t) { return t == BASE_TYPE_BOOL; } +inline bool IsOneByte(BaseType t) { return t >= BASE_TYPE_UTYPE && + t <= BASE_TYPE_UCHAR; } // clang-format on extern const char *const kTypeNames[]; @@ -141,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 @@ -223,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; @@ -241,6 +258,7 @@ struct FieldDef : public Definition { : deprecated(false), required(false), key(false), + shared(false), native_inline(false), flexbuffer(false), nested_flatbuffer(NULL), @@ -249,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. @@ -279,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. @@ -305,9 +329,12 @@ 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); + std::string name; std::vector<std::string> doc_comment; int64_t value; @@ -315,7 +342,7 @@ 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() + @@ -328,9 +355,13 @@ struct EnumDef : public Definition { Offset<reflection::Enum> Serialize(FlatBufferBuilder *builder, const Parser &parser) const; + bool Deserialize(Parser &parser, const reflection::Enum *values); + 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; }; @@ -344,11 +375,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; }; @@ -373,9 +407,11 @@ struct IDLOptions { bool skip_unexpected_fields_in_json; bool generate_name_strings; bool generate_object_based_api; + bool gen_compare; std::string cpp_object_api_pointer_type; std::string cpp_object_api_string_type; bool gen_nullable; + bool gen_generated; std::string object_prefix; std::string object_suffix; bool union_value_namespacing; @@ -389,6 +425,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; @@ -410,6 +447,7 @@ struct IDLOptions { kDart = 1 << 11, kLua = 1 << 12, kLobster = 1 << 13, + kRust = 1 << 14, kMAX }; @@ -446,8 +484,10 @@ struct IDLOptions { skip_unexpected_fields_in_json(false), generate_name_strings(false), generate_object_based_api(false), + gen_compare(false), cpp_object_api_pointer_type("std::unique_ptr"), gen_nullable(false), + gen_generated(false), object_suffix("T"), union_value_namespacing(true), allow_non_utf8(false), @@ -457,6 +497,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), @@ -468,13 +509,39 @@ struct IDLOptions { // This encapsulates where the parser is in the current source file. struct ParserState { - ParserState() : cursor_(nullptr), line_(1), token_(-1) {} + ParserState() + : cursor_(nullptr), + line_start_(nullptr), + line_(0), + token_(-1), + attr_is_trivial_ascii_string_(true) {} protected: + void ResetState(const char *source) { + cursor_ = source; + line_ = 0; + MarkNewLine(); + } + + void MarkNewLine() { + line_start_ = cursor_; + line_ += 1; + } + + int64_t CursorPosition() const { + FLATBUFFERS_ASSERT(cursor_ && line_start_ && cursor_ >= line_start_); + return static_cast<int64_t>(cursor_ - line_start_); + } + const char *cursor_; + const char *line_start_; int line_; // the current line being parsed int token_; + // 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_; }; @@ -546,6 +613,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; @@ -564,6 +632,7 @@ class Parser : public ParserState { known_attributes_["native_type"] = true; known_attributes_["native_default"] = true; known_attributes_["flexbuffer"] = true; + known_attributes_["private"] = true; } ~Parser() { @@ -601,6 +670,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); @@ -610,10 +688,13 @@ 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); + FLATBUFFERS_CHECKED_ERROR InvalidNumber(const char *number, + const std::string &msg); StructDef *LookupStruct(const std::string &id) const; + std::string UnqualifiedName(std::string fullQualifiedName); + private: void Message(const std::string &msg); void Warning(const std::string &msg); @@ -639,35 +720,15 @@ class Parser : public ParserState { 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 + 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); + template<typename F> + FLATBUFFERS_CHECKED_ERROR ParseVectorDelimiters(size_t &count, F body); FLATBUFFERS_CHECKED_ERROR ParseVector(const Type &type, uoffset_t *ovalue); FLATBUFFERS_CHECKED_ERROR ParseNestedFlatbuffer(Value &val, FieldDef *field, size_t fieldn, @@ -677,7 +738,7 @@ 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 ParseSingleValue(const std::string *name, Value &e, bool check_now); FLATBUFFERS_CHECKED_ERROR ParseEnumFromString(Type &type, int64_t *result); StructDef *LookupCreateStruct(const std::string &name, bool create_if_new = true, @@ -717,14 +778,8 @@ class Parser : public ParserState { bool SupportsVectorOfUnions() const; Namespace *UniqueNamespace(Namespace *ns); - enum { kMaxParsingDepth = 64 }; FLATBUFFERS_CHECKED_ERROR RecurseError(); - template<typename F> CheckedError Recurse(F f) { - if (++recurse_protection_counter >= kMaxParsingDepth) return RecurseError(); - auto ce = f(); - recurse_protection_counter--; - return ce; - } + template<typename F> CheckedError Recurse(F f); public: SymbolTable<Type> types_; @@ -799,7 +854,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); @@ -830,8 +885,14 @@ 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. +extern bool GenerateRust(const Parser &parser, + const std::string &path, + const std::string &file_name); // Generate Json schema file // See idl_gen_json_schema.cpp. @@ -855,7 +916,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); @@ -871,6 +932,12 @@ extern std::string DartMakeRule(const Parser &parser, const std::string &path, const std::string &file_name); +// Generate a make rule for the generated Rust code. +// See idl_gen_rust.cpp. +extern std::string RustMakeRule(const Parser &parser, + const std::string &path, + const std::string &file_name); + // Generate a make rule for the generated Java/C#/... files. // See idl_gen_general.cpp. extern std::string GeneralMakeRule(const Parser &parser, diff --git a/chromium/third_party/flatbuffers/src/include/flatbuffers/minireflect.h b/chromium/third_party/flatbuffers/src/include/flatbuffers/minireflect.h index ff3e681b8d0..e3def08df33 100644 --- a/chromium/third_party/flatbuffers/src/include/flatbuffers/minireflect.h +++ b/chromium/third_party/flatbuffers/src/include/flatbuffers/minireflect.h @@ -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; @@ -284,14 +284,27 @@ inline void IterateFlatBuffer(const uint8_t *buffer, struct ToStringVisitor : public IterationVisitor { std::string s; std::string d; - ToStringVisitor(std::string delimiter): d(delimiter) {} + bool q; + std::string in; + size_t indent_level; + ToStringVisitor(std::string delimiter, bool quotes, std::string indent) + : d(delimiter), q(quotes), in(indent), indent_level(0) {} + ToStringVisitor(std::string delimiter) + : d(delimiter), q(false), in(""), indent_level(0) {} + + void append_indent() { + for (size_t i = 0; i < indent_level; i++) { s += in; } + } void StartSequence() { s += "{"; s += d; + indent_level++; } void EndSequence() { s += d; + indent_level--; + append_indent(); s += "}"; } void Field(size_t /*field_idx*/, size_t set_idx, ElementaryType /*type*/, @@ -302,16 +315,22 @@ struct ToStringVisitor : public IterationVisitor { s += ","; s += d; } + append_indent(); if (name) { + if (q) s += "\""; s += name; + if (q) s += "\""; s += ": "; } } template<typename T> void Named(T x, const char *name) { - if (name) + if (name) { + if (q) s += "\""; s += name; - else + if (q) s += "\""; + } else { s += NumToString(x); + } } void UType(uint8_t x, const char *name) { Named(x, name); } void Bool(bool x) { s += x ? "true" : "false"; } @@ -329,11 +348,25 @@ struct ToStringVisitor : public IterationVisitor { EscapeString(str->c_str(), str->size(), &s, true, false); } void Unknown(const uint8_t *) { s += "(?)"; } - void StartVector() { s += "[ "; } - void EndVector() { s += " ]"; } + void StartVector() { + s += "["; + s += d; + indent_level++; + append_indent(); + } + void EndVector() { + s += d; + indent_level--; + append_indent(); + s += "]"; + } void Element(size_t i, ElementaryType /*type*/, const TypeTable * /*type_table*/, const uint8_t * /*val*/) { - if (i) s += ", "; + if (i) { + s += ","; + s += d; + append_indent(); + } } }; diff --git a/chromium/third_party/flatbuffers/src/include/flatbuffers/reflection.h b/chromium/third_party/flatbuffers/src/include/flatbuffers/reflection.h index 5010e000219..580ae624ba5 100644 --- a/chromium/third_party/flatbuffers/src/include/flatbuffers/reflection.h +++ b/chromium/third_party/flatbuffers/src/include/flatbuffers/reflection.h @@ -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 ------------------------- diff --git a/chromium/third_party/flatbuffers/src/include/flatbuffers/reflection_generated.h b/chromium/third_party/flatbuffers/src/include/flatbuffers/reflection_generated.h index 26cdaafafd9..fc720599c26 100644 --- a/chromium/third_party/flatbuffers/src/include/flatbuffers/reflection_generated.h +++ b/chromium/third_party/flatbuffers/src/include/flatbuffers/reflection_generated.h @@ -94,12 +94,13 @@ inline const char * const *EnumNamesBaseType() { } inline const char *EnumNameBaseType(BaseType e) { + if (e < None || e > Union) return ""; const size_t index = static_cast<int>(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) { diff --git a/chromium/third_party/flatbuffers/src/include/flatbuffers/registry.h b/chromium/third_party/flatbuffers/src/include/flatbuffers/registry.h index f90fc8d2918..9ea425b3978 100644 --- a/chromium/third_party/flatbuffers/src/include/flatbuffers/registry.h +++ b/chromium/third_party/flatbuffers/src/include/flatbuffers/registry.h @@ -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. diff --git a/chromium/third_party/flatbuffers/src/include/flatbuffers/stl_emulation.h b/chromium/third_party/flatbuffers/src/include/flatbuffers/stl_emulation.h index 7e7e978a450..6f6e766424e 100644 --- a/chromium/third_party/flatbuffers/src/include/flatbuffers/stl_emulation.h +++ b/chromium/third_party/flatbuffers/src/include/flatbuffers/stl_emulation.h @@ -33,6 +33,16 @@ #include <cctype> #endif // defined(FLATBUFFERS_CPP98_STL) +// Check if we can use template aliases +// Not possible if Microsoft Compiler before 2012 +// Possible is the language feature __cpp_alias_templates is defined well +// Or possible if the C++ std is C+11 or newer +#if (defined(_MSC_VER) && _MSC_VER > 1700 /* MSVC2012 */) \ + || (defined(__cpp_alias_templates) && __cpp_alias_templates >= 200704) \ + || (defined(__cplusplus) && __cplusplus >= 201103L) + #define FLATBUFFERS_TEMPLATES_ALIASES +#endif + // This header provides backwards compatibility for C++98 STLs like stlport. namespace flatbuffers { @@ -69,21 +79,42 @@ inline void vector_emplace_back(std::vector<T> *vector, V &&data) { } #ifndef FLATBUFFERS_CPP98_STL - #if !(defined(_MSC_VER) && _MSC_VER <= 1700 /* MSVC2012 */) + #if defined(FLATBUFFERS_TEMPLATES_ALIASES) template <typename T> using numeric_limits = std::numeric_limits<T>; #else template <typename T> class numeric_limits : public std::numeric_limits<T> {}; - #endif // !(defined(_MSC_VER) && _MSC_VER <= 1700 /* MSVC2012 */) + #endif // defined(FLATBUFFERS_TEMPLATES_ALIASES) #else template <typename T> class numeric_limits : - public std::numeric_limits<T> {}; + 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> { @@ -95,15 +126,19 @@ 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 -#if !(defined(_MSC_VER) && _MSC_VER <= 1700 /* MSVC2012 */) +#if defined(FLATBUFFERS_TEMPLATES_ALIASES) #ifndef FLATBUFFERS_CPP98_STL template <typename T> using is_scalar = std::is_scalar<T>; template <typename T, typename U> using is_same = std::is_same<T,U>; 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>; @@ -111,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. @@ -119,10 +165,11 @@ inline void vector_emplace_back(std::vector<T> *vector, V &&data) { template <typename T> struct is_floating_point : public std::is_floating_point<T> {}; template <typename T> struct is_unsigned : public std::is_unsigned<T> {}; -#endif // !(defined(_MSC_VER) && _MSC_VER <= 1700 /* MSVC2012 */) + template <typename T> struct make_unsigned : public std::make_unsigned<T> {}; +#endif // defined(FLATBUFFERS_TEMPLATES_ALIASES) #ifndef FLATBUFFERS_CPP98_STL - #if !(defined(_MSC_VER) && _MSC_VER <= 1700 /* MSVC2012 */) + #if defined(FLATBUFFERS_TEMPLATES_ALIASES) template <class T> using unique_ptr = std::unique_ptr<T>; #else // MSVC 2010 doesn't support C++11 aliases. @@ -148,7 +195,7 @@ inline void vector_emplace_back(std::vector<T> *vector, V &&data) { return std::unique_ptr<T>::operator=(p); } }; - #endif // !(defined(_MSC_VER) && _MSC_VER <= 1700 /* MSVC2012 */) + #endif // defined(FLATBUFFERS_TEMPLATES_ALIASES) #else // Very limited implementation of unique_ptr. // This is provided simply to allow the C++ code generated from the default diff --git a/chromium/third_party/flatbuffers/src/include/flatbuffers/util.h b/chromium/third_party/flatbuffers/src/include/flatbuffers/util.h index cf2949a2074..71e1973f1f5 100644 --- a/chromium/third_party/flatbuffers/src/include/flatbuffers/util.h +++ b/chromium/third_party/flatbuffers/src/include/flatbuffers/util.h @@ -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> +#include "flatbuffers/base.h" + +#include <errno.h> + #ifndef FLATBUFFERS_PREFER_PRINTF # include <sstream> -#else // FLATBUFFERS_PREFER_PRINTF +#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> +#endif // FLATBUFFERS_PREFER_PRINTF -#include "flatbuffers/base.h" +#include <iomanip> +#include <string> namespace flatbuffers { +// @locale-independent functions for ASCII characters set. + +// Check that integer scalar is in closed range: (a <= x <= b) +// using one compare (conditional branch) operator. +template<typename T> inline bool check_in_range(T x, T a, T b) { + // (Hacker's Delight): `a <= x <= b` <=> `(x-a) <={u} (b-a)`. + FLATBUFFERS_ASSERT(a <= b); // static_assert only if 'a' & 'b' templated + typedef typename flatbuffers::make_unsigned<T>::type U; + return (static_cast<U>(x - a) <= static_cast<U>(b - a)); +} + +// Case-insensitive isalpha +inline bool is_alpha(char c) { + // ASCII only: alpha to upper case => reset bit 0x20 (~0x20 = 0xDF). + return check_in_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_in_range(c, '0', '9'); } + +inline bool is_xdigit(char c) { + // Replace by look-up table. + return is_digit(c) || check_in_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; @@ -123,6 +148,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 +184,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 +198,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 -} - -// Portable implementation of strtoull(). -inline uint64_t StringToUInt(const char *str, char **endptr = nullptr, - int base = 10) { - // clang-format off +#else + #define __strtod_impl(s, pe) strtod(s, pe) + #define __strtof_impl(s, pe) static_cast<float>(strtod(s, pe)) #ifdef _MSC_VER - return _strtoui64(str, endptr, base); + #define __strtoull_impl(s, pe, b) _strtoui64(s, pe, b) + #define __strtoll_impl(s, pe, b) _strtoi64(s, pe, b) #else - return strtoull(str, endptr, base); + #define __strtoull_impl(s, pe, b) strtoull(s, pe, b) + #define __strtoll_impl(s, pe, b) strtoll(s, pe, b) #endif - // clang-format on +#endif + +inline void strtoval_impl(int64_t *val, const char *str, char **endptr, + int base) { + *val = __strtoll_impl(str, endptr, base); +} + +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 +413,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 +429,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 +501,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 +561,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 +633,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_ diff --git a/chromium/third_party/flatbuffers/src/java/com/google/flatbuffers/FlatBufferBuilder.java b/chromium/third_party/flatbuffers/src/java/com/google/flatbuffers/FlatBufferBuilder.java index 44f107aead8..9f3ae20ec76 100644 --- a/chromium/third_party/flatbuffers/src/java/com/google/flatbuffers/FlatBufferBuilder.java +++ b/chromium/third_party/flatbuffers/src/java/com/google/flatbuffers/FlatBufferBuilder.java @@ -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,27 @@ 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} + * released any reference to it, so it is safe to dispose the buffer + * or return it to a pool. + * It is not guaranteed that the buffer has been created + * with {@link #newByteBuffer(int) }. + * + * @param bb the buffer to release + */ + public void releaseByteBuffer(ByteBuffer bb) { + } } /** @@ -160,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); @@ -241,7 +273,11 @@ public class FlatBufferBuilder { // Reallocate the buffer if needed. while (space < align_size + size + additional_bytes) { int old_buf_size = bb.capacity(); - bb = growByteBuffer(bb, bb_factory); + ByteBuffer old = bb; + bb = growByteBuffer(old, bb_factory); + if (old != bb) { + bb_factory.releaseByteBuffer(old); + } space += bb.capacity() - old_buf_size; } pad(align_size); @@ -487,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(); } /** diff --git a/chromium/third_party/flatbuffers/src/java/com/google/flatbuffers/Struct.java b/chromium/third_party/flatbuffers/src/java/com/google/flatbuffers/Struct.java index ae315531448..39a8215ad03 100644 --- a/chromium/third_party/flatbuffers/src/java/com/google/flatbuffers/Struct.java +++ b/chromium/third_party/flatbuffers/src/java/com/google/flatbuffers/Struct.java @@ -28,6 +28,20 @@ public class Struct { protected int bb_pos; /** The underlying ByteBuffer to hold the data of the Struct. */ protected ByteBuffer bb; + + /** + * Resets internal state with a null {@code ByteBuffer} and a zero position. + * + * This method exists primarily to allow recycling Struct instances without risking memory leaks + * due to {@code ByteBuffer} references. The instance will be unusable until it is assigned + * again to a {@code ByteBuffer}. + * + * @param struct the instance to reset to initial state + */ + public void __reset() { + bb = null; + bb_pos = 0; + } } /// @endcond diff --git a/chromium/third_party/flatbuffers/src/java/com/google/flatbuffers/Table.java b/chromium/third_party/flatbuffers/src/java/com/google/flatbuffers/Table.java index cbbeda11405..703ce28a6b4 100644 --- a/chromium/third_party/flatbuffers/src/java/com/google/flatbuffers/Table.java +++ b/chromium/third_party/flatbuffers/src/java/com/google/flatbuffers/Table.java @@ -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,17 @@ 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; + Utf8 utf8 = Utf8.getDefault(); /** * Get the underlying ByteBuffer. @@ -98,34 +88,10 @@ 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(); + return utf8.decodeUtf8(bb, offset + SIZEOF_INT, length); } /** @@ -292,6 +258,18 @@ public class Table { } return len_1 - len_2; } + + /** + * Resets the internal state with a null {@code ByteBuffer} and a zero position. + * + * This method exists primarily to allow recycling Table instances without risking memory leaks + * due to {@code ByteBuffer} references. The instance will be unusable until it is assigned + * again to a {@code ByteBuffer}. + */ + public void __reset() { + bb = null; + bb_pos = 0; + } } /// @endcond diff --git a/chromium/third_party/flatbuffers/src/java/com/google/flatbuffers/Utf8.java b/chromium/third_party/flatbuffers/src/java/com/google/flatbuffers/Utf8.java new file mode 100644 index 00000000000..a2640637e83 --- /dev/null +++ b/chromium/third_party/flatbuffers/src/java/com/google/flatbuffers/Utf8.java @@ -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); + } + } +} diff --git a/chromium/third_party/flatbuffers/src/java/com/google/flatbuffers/Utf8Old.java b/chromium/third_party/flatbuffers/src/java/com/google/flatbuffers/Utf8Old.java new file mode 100644 index 00000000000..9793333226b --- /dev/null +++ b/chromium/third_party/flatbuffers/src/java/com/google/flatbuffers/Utf8Old.java @@ -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); + } + } +} diff --git a/chromium/third_party/flatbuffers/src/java/com/google/flatbuffers/Utf8Safe.java b/chromium/third_party/flatbuffers/src/java/com/google/flatbuffers/Utf8Safe.java new file mode 100644 index 00000000000..06ea420bb57 --- /dev/null +++ b/chromium/third_party/flatbuffers/src/java/com/google/flatbuffers/Utf8Safe.java @@ -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); + } + } +} diff --git a/chromium/third_party/flatbuffers/src/js/flatbuffers.js b/chromium/third_party/flatbuffers/src/js/flatbuffers.js index 580020a49e6..0c970bd8b4d 100644 --- a/chromium/third_party/flatbuffers/src/js/flatbuffers.js +++ b/chromium/third_party/flatbuffers/src/js/flatbuffers.js @@ -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 @@ -816,6 +829,7 @@ flatbuffers.ByteBuffer = function(bytes) { * @private */ this.position_ = 0; + }; /** @@ -828,6 +842,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`. * diff --git a/chromium/third_party/flatbuffers/src/lua/flatbuffers/numTypes.lua b/chromium/third_party/flatbuffers/src/lua/flatbuffers/numTypes.lua index e8d87e12403..84d0261c5ce 100644 --- a/chromium/third_party/flatbuffers/src/lua/flatbuffers/numTypes.lua +++ b/chromium/third_party/flatbuffers/src/lua/flatbuffers/numTypes.lua @@ -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
\ No newline at end of file +return m diff --git a/chromium/third_party/flatbuffers/src/net/FlatBuffers/ByteBuffer.cs b/chromium/third_party/flatbuffers/src/net/FlatBuffers/ByteBuffer.cs index 307a98fadca..5e212ddd052 100644 --- a/chromium/third_party/flatbuffers/src/net/FlatBuffers/ByteBuffer.cs +++ b/chromium/third_party/flatbuffers/src/net/FlatBuffers/ByteBuffer.cs @@ -14,7 +14,7 @@ * limitations under the License. */ -// There are 2 #defines that have an impact on performance of this ByteBuffer implementation +// There are 3 #defines that have an impact on performance / features of this ByteBuffer implementation // // UNSAFE_BYTEBUFFER // This will use unsafe code to manipulate the underlying byte array. This @@ -24,6 +24,12 @@ // This will disable the bounds check asserts to the byte array. This can // yield a small performance gain in normal code.. // +// ENABLE_SPAN_T +// This will enable reading and writing blocks of memory with a Span<T> instead if just +// T[]. You can also enable writing directly to shared memory or other types of memory +// by providing a custom implementation of ByteBufferAllocator. +// ENABLE_SPAN_T also requires UNSAFE_BYTEBUFFER to be defined +// // Using UNSAFE_BYTEBUFFER and BYTEBUFFER_NO_BOUNDS_CHECK together can yield a // performance gain of ~15% for some operations, however doing so is potentially // dangerous. Do so at your own risk! @@ -32,19 +38,99 @@ using System; using System.Collections.Generic; using System.IO; +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 + { +#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 + { + get; + protected set; + } +#endif + + public int Length + { + get; + protected set; + } + + public abstract void GrowFront(int newSize); + } + + public sealed class ByteArrayAllocator : ByteBufferAllocator + { + private byte[] _buffer; + + public ByteArrayAllocator(byte[] buffer) + { + _buffer = buffer; + InitBuffer(); + } + + public override void GrowFront(int newSize) + { + if ((Length & 0xC0000000) != 0) + throw new Exception( + "ByteBuffer: cannot grow buffer beyond 2 gigabytes."); + + if (newSize < Length) + throw new Exception("ByteBuffer: cannot truncate buffer."); + + byte[] newBuffer = new byte[newSize]; + System.Buffer.BlockCopy(_buffer, 0, newBuffer, newSize - Length, Length); + _buffer = newBuffer; + InitBuffer(); + } + +#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 + + private void InitBuffer() + { + Length = _buffer.Length; +#if !ENABLE_SPAN_T + Buffer = _buffer; +#endif + } + } + /// <summary> /// Class to mimic Java's ByteBuffer which is used heavily in Flatbuffers. /// </summary> public class ByteBuffer { - protected byte[] _buffer; + private ByteBufferAllocator _buffer; private int _pos; // Must track start of the buffer. - public int Length { get { return _buffer.Length; } } + public ByteBuffer(ByteBufferAllocator allocator, int position) + { + _buffer = allocator; + _pos = position; + } public ByteBuffer(int size) : this(new byte[size]) { } @@ -52,15 +138,18 @@ namespace FlatBuffers public ByteBuffer(byte[] buffer, int pos) { - _buffer = buffer; + _buffer = new ByteArrayAllocator(buffer); _pos = pos; } - public int Position { + public int Position + { get { return _pos; } set { _pos = value; } } + public int Length { get { return _buffer.Length; } } + public void Reset() { _pos = 0; @@ -77,17 +166,7 @@ namespace FlatBuffers // the end of the new buffer. public void GrowFront(int newSize) { - if ((Length & 0xC0000000) != 0) - throw new Exception( - "ByteBuffer: cannot grow buffer beyond 2 gigabytes."); - - if (newSize < Length) - throw new Exception("ByteBuffer: cannot truncate buffer."); - - byte[] newBuffer = new byte[newSize]; - Buffer.BlockCopy(_buffer, 0, newBuffer, newSize - Length, - Length); - _buffer = newBuffer; + _buffer.GrowFront(newSize); } public byte[] ToArray(int pos, int len) @@ -145,16 +224,32 @@ namespace FlatBuffers return SizeOf<T>() * x.Length; } +#if ENABLE_SPAN_T + public static int ArraySize<T>(Span<T> x) + { + return SizeOf<T>() * x.Length; + } +#endif + // Get a portion of the buffer casted into an array of type T, given // the buffer position and length. +#if ENABLE_SPAN_T public T[] ToArray<T>(int pos, int len) - where T: struct + where T : struct + { + 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) + where T : struct { AssertOffsetAndLength(pos, len); T[] arr = new T[len]; - Buffer.BlockCopy(_buffer, pos, arr, 0, ArraySize(arr)); + Buffer.BlockCopy(_buffer.Buffer, pos, arr, 0, ArraySize(arr)); return arr; } +#endif public byte[] ToSizedArray() { @@ -166,15 +261,32 @@ namespace FlatBuffers return ToArray<byte>(0, Length); } +#if ENABLE_SPAN_T + public ReadOnlyMemory<byte> ToReadOnlyMemory(int pos, int 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, pos, len); + return new ArraySegment<byte>(_buffer.Buffer, pos, len); } public MemoryStream ToMemoryStream(int pos, int len) { - return new MemoryStream(_buffer, pos, len); + return new MemoryStream(_buffer.Buffer, pos, len); } +#endif #if !UNSAFE_BYTEBUFFER // Pre-allocated helper arrays for convertion. @@ -217,14 +329,14 @@ namespace FlatBuffers { for (int i = 0; i < count; i++) { - _buffer[offset + i] = (byte)(data >> i * 8); + _buffer.Buffer[offset + i] = (byte)(data >> i * 8); } } else { for (int i = 0; i < count; i++) { - _buffer[offset + count - 1 - i] = (byte)(data >> i * 8); + _buffer.Buffer[offset + count - 1 - i] = (byte)(data >> i * 8); } } } @@ -237,15 +349,15 @@ namespace FlatBuffers { for (int i = 0; i < count; i++) { - r |= (ulong)_buffer[offset + i] << i * 8; + r |= (ulong)_buffer.Buffer[offset + i] << i * 8; } } else { - for (int i = 0; i < count; i++) - { - r |= (ulong)_buffer[offset + count - 1 - i] << i * 8; - } + for (int i = 0; i < count; i++) + { + r |= (ulong)_buffer.Buffer[offset + count - 1 - i] << i * 8; + } } return r; } @@ -253,31 +365,54 @@ namespace FlatBuffers private void AssertOffsetAndLength(int offset, int length) { - #if !BYTEBUFFER_NO_BOUNDS_CHECK +#if !BYTEBUFFER_NO_BOUNDS_CHECK if (offset < 0 || offset > _buffer.Length - length) throw new ArgumentOutOfRangeException(); - #endif +#endif } +#if ENABLE_SPAN_T + public void PutSbyte(int offset, sbyte value) { AssertOffsetAndLength(offset, sizeof(sbyte)); - _buffer[offset] = (byte)value; + _buffer.Span[offset] = (byte)value; } public void PutByte(int offset, byte value) { AssertOffsetAndLength(offset, sizeof(byte)); - _buffer[offset] = value; + _buffer.Span[offset] = value; + } + + public void PutByte(int offset, byte value, int count) + { + AssertOffsetAndLength(offset, sizeof(byte) * count); + 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) + { + AssertOffsetAndLength(offset, sizeof(sbyte)); + _buffer.Buffer[offset] = (byte)value; + } + + public void PutByte(int offset, byte value) + { + AssertOffsetAndLength(offset, sizeof(byte)); + _buffer.Buffer[offset] = value; } public void PutByte(int offset, byte value, int count) { AssertOffsetAndLength(offset, sizeof(byte) * count); for (var i = 0; i < count; ++i) - _buffer[offset + i] = value; + _buffer.Buffer[offset + i] = value; } +#endif // this method exists in order to conform with Java ByteBuffer standards public void Put(int offset, byte value) @@ -285,12 +420,26 @@ namespace FlatBuffers PutByte(offset, value); } +#if ENABLE_SPAN_T + public unsafe void PutStringUTF8(int offset, string value) + { + AssertOffsetAndLength(offset, value.Length); + fixed (char* s = value) + { + fixed (byte* buffer = &MemoryMarshal.GetReference(_buffer.Span)) + { + Encoding.UTF8.GetBytes(s, value.Length, buffer + offset, Length - offset); + } + } + } +#else public void PutStringUTF8(int offset, string value) { AssertOffsetAndLength(offset, value.Length); Encoding.UTF8.GetBytes(value, 0, value.Length, - _buffer, offset); + _buffer.Buffer, offset); } +#endif #if UNSAFE_BYTEBUFFER // Unsafe but more efficient versions of Put*. @@ -302,12 +451,17 @@ namespace FlatBuffers public unsafe void PutUshort(int offset, ushort value) { AssertOffsetAndLength(offset, sizeof(ushort)); - fixed (byte* ptr = _buffer) +#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) @@ -318,12 +472,17 @@ namespace FlatBuffers public unsafe void PutUint(int offset, uint value) { AssertOffsetAndLength(offset, sizeof(uint)); - fixed (byte* ptr = _buffer) +#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) @@ -334,18 +493,27 @@ namespace FlatBuffers public unsafe void PutUlong(int offset, ulong value) { AssertOffsetAndLength(offset, sizeof(ulong)); - fixed (byte* ptr = _buffer) +#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)); - fixed (byte* ptr = _buffer) +#if ENABLE_SPAN_T + fixed (byte* ptr = &MemoryMarshal.GetReference(_buffer.Span)) +#else + fixed (byte* ptr = _buffer.Buffer) +#endif { if (BitConverter.IsLittleEndian) { @@ -361,16 +529,19 @@ namespace FlatBuffers public unsafe void PutDouble(int offset, double value) { AssertOffsetAndLength(offset, sizeof(double)); - fixed (byte* ptr = _buffer) +#if ENABLE_SPAN_T + fixed (byte* ptr = &MemoryMarshal.GetReference(_buffer.Span)) +#else + fixed (byte* ptr = _buffer.Buffer) +#endif { if (BitConverter.IsLittleEndian) { *(double*)(ptr + offset) = value; - } else { - *(ulong*)(ptr + offset) = ReverseBytes(*(ulong*)(ptr + offset)); + *(ulong*)(ptr + offset) = ReverseBytes(*(ulong*)(&value)); } } } @@ -428,74 +599,48 @@ namespace FlatBuffers WriteLittleEndian(offset, sizeof(double), ulonghelper[0]); } - /// <summary> - /// Copies an array of type T into this buffer, ending at the given - /// offset into this buffer. The starting offset is calculated based on the length - /// of the array and is the value returned. - /// </summary> - /// <typeparam name="T">The type of the input data (must be a struct)</typeparam> - /// <param name="offset">The offset into this buffer where the copy will end</param> - /// <param name="x">The array to copy data from</param> - /// <returns>The 'start' location of this buffer now, after the copy completed</returns> - public int Put<T>(int offset, T[] x) - where T : struct - { - if(x == null) - { - throw new ArgumentNullException("Cannot put a null array"); - } - - if(x.Length == 0) - { - throw new ArgumentException("Cannot put an empty array"); - } - - if(!IsSupportedType<T>()) - { - throw new ArgumentException("Cannot put an array of type " - + typeof(T) + " into this buffer"); - } +#endif // UNSAFE_BYTEBUFFER - if (BitConverter.IsLittleEndian) - { - int numBytes = ByteBuffer.ArraySize(x); - offset -= numBytes; - AssertOffsetAndLength(offset, numBytes); - // if we are LE, just do a block copy - Buffer.BlockCopy(x, 0, _buffer, offset, numBytes); - } - else - { - throw new NotImplementedException("Big Endian Support not implemented yet " + - "for putting typed arrays"); - // if we are BE, we have to swap each element by itself - //for(int i = x.Length - 1; i >= 0; i--) - //{ - // todo: low priority, but need to genericize the Put<T>() functions - //} - } - return offset; +#if ENABLE_SPAN_T + public sbyte GetSbyte(int index) + { + AssertOffsetAndLength(index, sizeof(sbyte)); + return (sbyte)_buffer.ReadOnlySpan[index]; } - -#endif // UNSAFE_BYTEBUFFER - + public byte Get(int index) + { + AssertOffsetAndLength(index, sizeof(byte)); + return _buffer.ReadOnlySpan[index]; + } +#else public sbyte GetSbyte(int index) { AssertOffsetAndLength(index, sizeof(sbyte)); - return (sbyte)_buffer[index]; + return (sbyte)_buffer.Buffer[index]; } public byte Get(int index) { AssertOffsetAndLength(index, sizeof(byte)); - return _buffer[index]; + return _buffer.Buffer[index]; } +#endif +#if ENABLE_SPAN_T + public unsafe string GetStringUTF8(int startPos, int len) + { + 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, startPos, len); + return Encoding.UTF8.GetString(_buffer.Buffer, startPos, len); } +#endif #if UNSAFE_BYTEBUFFER // Unsafe but more efficient versions of Get*. @@ -507,12 +652,17 @@ namespace FlatBuffers public unsafe ushort GetUshort(int offset) { AssertOffsetAndLength(offset, sizeof(ushort)); - fixed (byte* ptr = _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) @@ -523,12 +673,17 @@ namespace FlatBuffers public unsafe uint GetUint(int offset) { AssertOffsetAndLength(offset, sizeof(uint)); - fixed (byte* ptr = _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) @@ -539,18 +694,27 @@ namespace FlatBuffers public unsafe ulong GetUlong(int offset) { AssertOffsetAndLength(offset, sizeof(ulong)); - fixed (byte* ptr = _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)); - fixed (byte* ptr = _buffer) +#if ENABLE_SPAN_T + fixed (byte* ptr = &MemoryMarshal.GetReference(_buffer.ReadOnlySpan)) +#else + fixed (byte* ptr = _buffer.Buffer) +#endif { if (BitConverter.IsLittleEndian) { @@ -567,7 +731,11 @@ namespace FlatBuffers public unsafe double GetDouble(int offset) { AssertOffsetAndLength(offset, sizeof(double)); - fixed (byte* ptr = _buffer) +#if ENABLE_SPAN_T + fixed (byte* ptr = &MemoryMarshal.GetReference(_buffer.ReadOnlySpan)) +#else + fixed (byte* ptr = _buffer.Buffer) +#endif { if (BitConverter.IsLittleEndian) { @@ -604,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) @@ -629,5 +797,95 @@ namespace FlatBuffers return doublehelper[0]; } #endif // UNSAFE_BYTEBUFFER + + /// <summary> + /// Copies an array of type T into this buffer, ending at the given + /// offset into this buffer. The starting offset is calculated based on the length + /// of the array and is the value returned. + /// </summary> + /// <typeparam name="T">The type of the input data (must be a struct)</typeparam> + /// <param name="offset">The offset into this buffer where the copy will end</param> + /// <param name="x">The array to copy data from</param> + /// <returns>The 'start' location of this buffer now, after the copy completed</returns> + public int Put<T>(int offset, T[] x) + where T : struct + { + if (x == null) + { + throw new ArgumentNullException("Cannot put a null array"); + } + + if (x.Length == 0) + { + throw new ArgumentException("Cannot put an empty array"); + } + + if (!IsSupportedType<T>()) + { + throw new ArgumentException("Cannot put an array of type " + + typeof(T) + " into this buffer"); + } + + if (BitConverter.IsLittleEndian) + { + int numBytes = ByteBuffer.ArraySize(x); + offset -= numBytes; + AssertOffsetAndLength(offset, numBytes); + // if we are LE, just do a block copy +#if ENABLE_SPAN_T + MemoryMarshal.Cast<T, byte>(x).CopyTo(_buffer.Span.Slice(offset, numBytes)); +#else + Buffer.BlockCopy(x, 0, _buffer.Buffer, offset, numBytes); +#endif + } + else + { + throw new NotImplementedException("Big Endian Support not implemented yet " + + "for putting typed arrays"); + // if we are BE, we have to swap each element by itself + //for(int i = x.Length - 1; i >= 0; i--) + //{ + // todo: low priority, but need to genericize the Put<T>() functions + //} + } + return offset; + } + +#if ENABLE_SPAN_T + public int Put<T>(int offset, Span<T> x) + where T : struct + { + if (x.Length == 0) + { + throw new ArgumentException("Cannot put an empty array"); + } + + if (!IsSupportedType<T>()) + { + throw new ArgumentException("Cannot put an array of type " + + typeof(T) + " into this buffer"); + } + + if (BitConverter.IsLittleEndian) + { + int numBytes = ByteBuffer.ArraySize(x); + offset -= numBytes; + AssertOffsetAndLength(offset, numBytes); + // if we are LE, just do a block copy + MemoryMarshal.Cast<T, byte>(x).CopyTo(_buffer.Span.Slice(offset, numBytes)); + } + else + { + throw new NotImplementedException("Big Endian Support not implemented yet " + + "for putting typed arrays"); + // if we are BE, we have to swap each element by itself + //for(int i = x.Length - 1; i >= 0; i--) + //{ + // todo: low priority, but need to genericize the Put<T>() functions + //} + } + return offset; + } +#endif } } diff --git a/chromium/third_party/flatbuffers/src/net/FlatBuffers/FlatBufferBuilder.cs b/chromium/third_party/flatbuffers/src/net/FlatBuffers/FlatBufferBuilder.cs index 33bba969dda..93f72be342b 100644 --- a/chromium/third_party/flatbuffers/src/net/FlatBuffers/FlatBufferBuilder.cs +++ b/chromium/third_party/flatbuffers/src/net/FlatBuffers/FlatBufferBuilder.cs @@ -63,6 +63,17 @@ namespace FlatBuffers } /// <summary> + /// Create a FlatBufferBuilder backed by the pased in ByteBuffer + /// </summary> + /// <param name="buffer">The ByteBuffer to write to</param> + public FlatBufferBuilder(ByteBuffer buffer) + { + _bb = buffer; + _space = buffer.Length; + buffer.Reset(); + } + + /// <summary> /// Reset the FlatBufferBuilder by purging all data that it holds. /// </summary> public void Clear() @@ -191,6 +202,20 @@ namespace FlatBuffers _space = _bb.Put(_space, x); } +#if ENABLE_SPAN_T + /// <summary> + /// Puts a span of type T into this builder at the + /// current offset + /// </summary> + /// <typeparam name="T">The type of the input data </typeparam> + /// <param name="x">The span to copy data from</param> + public void Put<T>(Span<T> x) + where T : struct + { + _space = _bb.Put(_space, x); + } +#endif + public void PutDouble(double x) { _bb.PutDouble(_space -= sizeof(double), x); @@ -288,6 +313,28 @@ namespace FlatBuffers Put(x); } +#if ENABLE_SPAN_T + /// <summary> + /// Add a span of type T to the buffer (aligns the data and grows if necessary). + /// </summary> + /// <typeparam name="T">The type of the input data</typeparam> + /// <param name="x">The span to copy data from</param> + public void Add<T>(Span<T> x) + where T : struct + { + if (!ByteBuffer.IsSupportedType<T>()) + { + throw new ArgumentException("Cannot add this Type array to the builder"); + } + + int size = ByteBuffer.SizeOf<T>(); + // Need to prep on size (for data alignment) and then we pass the + // rest of the length (minus 1) as additional bytes + Prep(size, size * (x.Length - 1)); + Put(x); + } +#endif + /// <summary> /// Add a `double` to the buffer (aligns the data and grows if necessary). /// </summary> @@ -511,6 +558,27 @@ namespace FlatBuffers return new StringOffset(EndVector().Value); } + +#if ENABLE_SPAN_T + /// <summary> + /// Creates a string in the buffer from a Span containing + /// a UTF8 string. + /// </summary> + /// <param name="chars">the UTF8 string to add to the buffer</param> + /// <returns> + /// The offset in the buffer where the encoded string starts. + /// </returns> + public StringOffset CreateUTF8String(Span<byte> chars) + { + NotNested(); + AddByte(0); + var utf8StringLen = chars.Length; + StartVector(1, utf8StringLen, 1); + _space = _bb.Put(_space, chars); + return new StringOffset(EndVector().Value); + } +#endif + /// @cond FLATBUFFERS_INTERNAL // Structs are stored inline, so nothing additional is being added. // `d` is always 0. @@ -568,7 +636,7 @@ namespace FlatBuffers break; } - endLoop: { } + endLoop: { } } if (existingVtable != 0) { diff --git a/chromium/third_party/flatbuffers/src/net/FlatBuffers/FlatBuffers.Core.csproj b/chromium/third_party/flatbuffers/src/net/FlatBuffers/FlatBuffers.Core.csproj new file mode 100644 index 00000000000..4285dd7fad4 --- /dev/null +++ b/chromium/third_party/flatbuffers/src/net/FlatBuffers/FlatBuffers.Core.csproj @@ -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> diff --git a/chromium/third_party/flatbuffers/src/net/FlatBuffers/FlatBuffers.csproj b/chromium/third_party/flatbuffers/src/net/FlatBuffers/FlatBuffers.csproj index e8189aa9ff9..a0290947f92 100644 --- a/chromium/third_party/flatbuffers/src/net/FlatBuffers/FlatBuffers.csproj +++ b/chromium/third_party/flatbuffers/src/net/FlatBuffers/FlatBuffers.csproj @@ -1,13 +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> + <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>
\ No newline at end of file diff --git a/chromium/third_party/flatbuffers/src/net/FlatBuffers/Properties/AssemblyInfo.cs b/chromium/third_party/flatbuffers/src/net/FlatBuffers/Properties/AssemblyInfo.cs new file mode 100644 index 00000000000..1edfac47aae --- /dev/null +++ b/chromium/third_party/flatbuffers/src/net/FlatBuffers/Properties/AssemblyInfo.cs @@ -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")] diff --git a/chromium/third_party/flatbuffers/src/net/FlatBuffers/Table.cs b/chromium/third_party/flatbuffers/src/net/FlatBuffers/Table.cs index 07db5f42315..cc7f3c1c81c 100644 --- a/chromium/third_party/flatbuffers/src/net/FlatBuffers/Table.cs +++ b/chromium/third_party/flatbuffers/src/net/FlatBuffers/Table.cs @@ -78,6 +78,23 @@ namespace FlatBuffers return offset + bb.GetInt(offset) + sizeof(int); // data starts after the length } +#if ENABLE_SPAN_T + // Get the data of a vector whoses offset is stored at "offset" in this object as an + // Spant<byte>. If the vector is not present in the ByteBuffer, + // then an empty span will be returned. + public Span<byte> __vector_as_span(int offset) + { + var o = this.__offset(offset); + if (0 == o) + { + return new Span<byte>(); + } + + var pos = this.__vector(o); + var len = this.__vector_len(o); + return bb.ToSpan(pos, len); + } +#else // Get the data of a vector whoses offset is stored at "offset" in this object as an // ArraySegment<byte>. If the vector is not present in the ByteBuffer, // then a null value will be returned. @@ -93,6 +110,7 @@ namespace FlatBuffers var len = this.__vector_len(o); return bb.ToArraySegment(pos, len); } +#endif // Get the data of a vector whoses offset is stored at "offset" in this object as an // T[]. If the vector is not present in the ByteBuffer, then a null value will be diff --git a/chromium/third_party/flatbuffers/src/package.json b/chromium/third_party/flatbuffers/src/package.json index ae65135606f..daf76b07536 100644 --- a/chromium/third_party/flatbuffers/src/package.json +++ b/chromium/third_party/flatbuffers/src/package.json @@ -1,8 +1,11 @@ { "name": "flatbuffers", - "version": "1.9.0", + "version": "1.10.2", "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": {} } diff --git a/chromium/third_party/flatbuffers/src/php/FlatbufferBuilder.php b/chromium/third_party/flatbuffers/src/php/FlatbufferBuilder.php index 925b4387d16..4fbc2bc5064 100644 --- a/chromium/third_party/flatbuffers/src/php/FlatbufferBuilder.php +++ b/chromium/third_party/flatbuffers/src/php/FlatbufferBuilder.php @@ -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 diff --git a/chromium/third_party/flatbuffers/src/pom.xml b/chromium/third_party/flatbuffers/src/pom.xml index b7f1a796f5a..3e9191151a9 100644 --- a/chromium/third_party/flatbuffers/src/pom.xml +++ b/chromium/third_party/flatbuffers/src/pom.xml @@ -5,7 +5,7 @@ <modelVersion>4.0.0</modelVersion> <groupId>com.google.flatbuffers</groupId> <artifactId>flatbuffers-java</artifactId> - <version>1.9.0</version> + <version>1.10.1-SNAPSHOT</version> <packaging>bundle</packaging> <name>FlatBuffers Java API</name> <description> @@ -78,6 +78,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> diff --git a/chromium/third_party/flatbuffers/src/python/flatbuffers/builder.py b/chromium/third_party/flatbuffers/src/python/flatbuffers/builder.py index 09044575a4e..1e96d6fe72e 100644 --- a/chromium/third_party/flatbuffers/src/python/flatbuffers/builder.py +++ b/chromium/third_party/flatbuffers/src/python/flatbuffers/builder.py @@ -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): """ diff --git a/chromium/third_party/flatbuffers/src/readme.md b/chromium/third_party/flatbuffers/src/readme.md index 215c9abd037..3d5467eb380 100644 --- a/chromium/third_party/flatbuffers/src/readme.md +++ b/chromium/third_party/flatbuffers/src/readme.md @@ -4,29 +4,34 @@ [![Join the chat at https://gitter.im/google/flatbuffers](https://badges.gitter.im/google/flatbuffers.svg)](https://gitter.im/google/flatbuffers?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![Build Status](https://travis-ci.org/google/flatbuffers.svg?branch=master)](https://travis-ci.org/google/flatbuffers) [![Build status](https://ci.appveyor.com/api/projects/status/yg5idd2fnusv1n10?svg=true)](https://ci.appveyor.com/project/gwvo/flatbuffers) -**FlatBuffers** is an efficient cross platform serialization library for games and -other memory constrained apps. It allows you to directly access serialized data without -unpacking/parsing it first, while still having great forwards/backwards compatibility. +**FlatBuffers** is a cross platform serialization library architected for +maximum memory efficiency. It allows you to directly access serialized data without parsing/unpacking it first, while still having great forwards/backwards compatibility. **Go to our [landing page][] to browse our documentation.** ## Supported operating systems -* Android * Windows * MacOS X * Linux +* Android +* And any others with a recent C++ compiler. ## Supported programming languages * C++ * C# * C +* Dart * Go * Java * JavaScript +* Lobster +* Lua * PHP * Python +* Rust +* TypeScript -*and many more in progress...* +*and more in progress...* ## Contribution * [FlatBuffers Google Group][] to discuss FlatBuffers with other developers and users. @@ -35,16 +40,6 @@ unpacking/parsing it first, while still having great forwards/backwards compatib *To contribute to this project,* see [CONTRIBUTING][]. -## Integration -For applications on Google Play that integrate this tool, usage is tracked. -This tracking is done automatically using the embedded version string -(**`flatbuffer_version_string`**), and helps us continue to optimize it. Aside from -consuming a few extra bytes in your application binary, it shouldn't affect -your application at all. We use this information to let us know if FlatBuffers -is useful and if we should continue to invest in it. Since this is open -source, you are free to remove the version string but we would appreciate if -you would leave it in. - ## Licensing *Flatbuffers* is licensed under the Apache License, Version 2.0. See [LICENSE][] for the full license text. diff --git a/chromium/third_party/flatbuffers/src/reflection/generate_code.bat b/chromium/third_party/flatbuffers/src/reflection/generate_code.bat index 8f58c0c7037..e2993253b0d 100644 --- a/chromium/third_party/flatbuffers/src/reflection/generate_code.bat +++ b/chromium/third_party/flatbuffers/src/reflection/generate_code.bat @@ -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 diff --git a/chromium/third_party/flatbuffers/src/reflection/generate_code.sh b/chromium/third_party/flatbuffers/src/reflection/generate_code.sh index da8a18130cc..f186b732772 100755 --- a/chromium/third_party/flatbuffers/src/reflection/generate_code.sh +++ b/chromium/third_party/flatbuffers/src/reflection/generate_code.sh @@ -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 diff --git a/chromium/third_party/flatbuffers/src/rust/flatbuffers/Cargo.toml b/chromium/third_party/flatbuffers/src/rust/flatbuffers/Cargo.toml new file mode 100644 index 00000000000..67bbd8d06c6 --- /dev/null +++ b/chromium/third_party/flatbuffers/src/rust/flatbuffers/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "flatbuffers" +version = "0.5.0" +authors = ["Robert Winslow <hello@rwinslow.com>", "FlatBuffers Maintainers"] +license = "Apache-2.0" +description = "Official FlatBuffers Rust runtime library." +homepage = "https://google.github.io/flatbuffers/" +repository = "https://github.com/google/flatbuffers" +keywords = ["flatbuffers", "serialization", "zero-copy"] +categories = ["encoding", "data-structures", "memory-management"] + +[dependencies] +smallvec = "0.6" diff --git a/chromium/third_party/flatbuffers/src/rust/flatbuffers/src/builder.rs b/chromium/third_party/flatbuffers/src/rust/flatbuffers/src/builder.rs new file mode 100644 index 00000000000..f755a498734 --- /dev/null +++ b/chromium/third_party/flatbuffers/src/rust/flatbuffers/src/builder.rs @@ -0,0 +1,640 @@ +/* + * Copyright 2018 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +extern crate smallvec; + +use std::cmp::max; +use std::marker::PhantomData; +use std::ptr::write_bytes; +use std::slice::from_raw_parts; + +use endian_scalar::{read_scalar, emplace_scalar}; +use primitives::*; +use push::{Push, PushAlignment}; +use table::Table; +use vtable::{VTable, field_index_to_field_offset}; +use vtable_writer::VTableWriter; +use vector::{SafeSliceAccess, Vector}; + +pub const N_SMALLVEC_STRING_VECTOR_CAPACITY: usize = 16; + +#[derive(Clone, Copy, Debug)] +struct FieldLoc { + off: UOffsetT, + id: VOffsetT, +} + +/// FlatBufferBuilder builds a FlatBuffer through manipulating its internal +/// state. It has an owned `Vec<u8>` that grows as needed (up to the hardcoded +/// limit of 2GiB, which is set by the FlatBuffers format). +pub struct FlatBufferBuilder<'fbb> { + owned_buf: Vec<u8>, + head: usize, + + field_locs: Vec<FieldLoc>, + written_vtable_revpos: Vec<UOffsetT>, + + nested: bool, + finished: bool, + + min_align: usize, + + _phantom: PhantomData<&'fbb ()>, +} + +impl<'fbb> FlatBufferBuilder<'fbb> { + /// Create a FlatBufferBuilder that is ready for writing. + pub fn new() -> Self { + Self::new_with_capacity(0) + } + + /// Create a FlatBufferBuilder that is ready for writing, with a + /// ready-to-use capacity of the provided size. + /// + /// The maximum valid value is `FLATBUFFERS_MAX_BUFFER_SIZE`. + pub fn new_with_capacity(size: usize) -> Self { + // we need to check the size here because we create the backing buffer + // directly, bypassing the typical way of using grow_owned_buf: + assert!(size <= FLATBUFFERS_MAX_BUFFER_SIZE, + "cannot initialize buffer bigger than 2 gigabytes"); + + FlatBufferBuilder { + owned_buf: vec![0u8; size], + head: size, + + field_locs: Vec::new(), + written_vtable_revpos: Vec::new(), + + nested: false, + finished: false, + + min_align: 0, + + _phantom: PhantomData, + } + } + + /// Reset the FlatBufferBuilder internal state. Use this method after a + /// call to a `finish` function in order to re-use a FlatBufferBuilder. + /// + /// This function is the only way to reset the `finished` state and start + /// again. + /// + /// If you are using a FlatBufferBuilder repeatedly, make sure to use this + /// function, because it re-uses the FlatBufferBuilder's existing + /// heap-allocated `Vec<u8>` internal buffer. This offers significant speed + /// improvements as compared to creating a new FlatBufferBuilder for every + /// new object. + pub fn reset(&mut self) { + // memset only the part of the buffer that could be dirty: + { + let to_clear = self.owned_buf.len() - self.head; + let ptr = (&mut self.owned_buf[self.head..]).as_mut_ptr(); + unsafe { write_bytes(ptr, 0, to_clear); } + } + + self.head = self.owned_buf.len(); + self.written_vtable_revpos.clear(); + + self.nested = false; + self.finished = false; + + self.min_align = 0; + } + + /// Destroy the FlatBufferBuilder, returning its internal byte vector + /// and the index into it that represents the start of valid data. + pub fn collapse(self) -> (Vec<u8>, usize) { + (self.owned_buf, self.head) + } + + /// Push a Push'able value onto the front of the in-progress data. + /// + /// This function uses traits to provide a unified API for writing + /// scalars, tables, vectors, and WIPOffsets. + #[inline] + pub fn push<P: Push>(&mut self, x: P) -> WIPOffset<P::Output> { + let sz = P::size(); + self.align(sz, P::alignment()); + self.make_space(sz); + { + let (dst, rest) = (&mut self.owned_buf[self.head..]).split_at_mut(sz); + x.push(dst, rest); + } + WIPOffset::new(self.used_space() as UOffsetT) + } + + /// Push a Push'able value onto the front of the in-progress data, and + /// store a reference to it in the in-progress vtable. If the value matches + /// the default, then this is a no-op. + #[inline] + pub fn push_slot<X: Push + PartialEq>(&mut self, slotoff: VOffsetT, x: X, default: X) { + self.assert_nested("push_slot"); + if x == default { + return; + } + self.push_slot_always(slotoff, x); + } + + /// Push a Push'able value onto the front of the in-progress data, and + /// store a reference to it in the in-progress vtable. + #[inline] + pub fn push_slot_always<X: Push>(&mut self, slotoff: VOffsetT, x: X) { + self.assert_nested("push_slot_always"); + let off = self.push(x); + self.track_field(slotoff, off.value()); + } + + /// Retrieve the number of vtables that have been serialized into the + /// FlatBuffer. This is primarily used to check vtable deduplication. + #[inline] + pub fn num_written_vtables(&self) -> usize { + self.written_vtable_revpos.len() + } + + /// Start a Table write. + /// + /// Asserts that the builder is not in a nested state. + /// + /// Users probably want to use `push_slot` to add values after calling this. + #[inline] + pub fn start_table(&mut self) -> WIPOffset<TableUnfinishedWIPOffset> { + self.assert_not_nested("start_table can not be called when a table or vector is under construction"); + self.nested = true; + + WIPOffset::new(self.used_space() as UOffsetT) + } + + /// End a Table write. + /// + /// Asserts that the builder is in a nested state. + #[inline] + pub fn end_table(&mut self, off: WIPOffset<TableUnfinishedWIPOffset>) -> WIPOffset<TableFinishedWIPOffset> { + self.assert_nested("end_table"); + + let o = self.write_vtable(off); + + self.nested = false; + self.field_locs.clear(); + + WIPOffset::new(o.value()) + } + + /// Start a Vector write. + /// + /// Asserts that the builder is not in a nested state. + /// + /// Most users will prefer to call `create_vector`. + /// Speed optimizing users who choose to create vectors manually using this + /// function will want to use `push` to add values. + #[inline] + pub fn start_vector<T: Push>(&mut self, num_items: usize) { + self.assert_not_nested("start_vector can not be called when a table or vector is under construction"); + self.nested = true; + self.align(num_items * T::size(), T::alignment().max_of(SIZE_UOFFSET)); + } + + /// End a Vector write. + /// + /// Note that the `num_elems` parameter is the number of written items, not + /// the byte count. + /// + /// Asserts that the builder is in a nested state. + #[inline] + pub fn end_vector<T: Push>(&mut self, num_elems: usize) -> WIPOffset<Vector<'fbb, T>> { + self.assert_nested("end_vector"); + self.nested = false; + let o = self.push::<UOffsetT>(num_elems as UOffsetT); + WIPOffset::new(o.value()) + } + + /// Create a utf8 string. + /// + /// The wire format represents this as a zero-terminated byte vector. + #[inline] + pub fn create_string<'a: 'b, 'b>(&'a mut self, s: &'b str) -> WIPOffset<&'fbb str> { + self.assert_not_nested("create_string can not be called when a table or vector is under construction"); + WIPOffset::new(self.create_byte_string(s.as_bytes()).value()) + } + + /// Create a zero-terminated byte vector. + #[inline] + pub fn create_byte_string(&mut self, data: &[u8]) -> WIPOffset<&'fbb [u8]> { + self.assert_not_nested("create_byte_string can not be called when a table or vector is under construction"); + self.align(data.len() + 1, PushAlignment::new(SIZE_UOFFSET)); + self.push(0u8); + self.push_bytes_unprefixed(data); + self.push(data.len() as UOffsetT); + WIPOffset::new(self.used_space() as UOffsetT) + } + + /// Create a vector by memcpy'ing. This is much faster than calling + /// `create_vector`, but the underlying type must be represented as + /// little-endian on the host machine. This property is encoded in the + /// type system through the SafeSliceAccess trait. The following types are + /// always safe, on any platform: bool, u8, i8, and any + /// FlatBuffers-generated struct. + #[inline] + pub fn create_vector_direct<'a: 'b, 'b, T: SafeSliceAccess + Push + Sized + 'b>(&'a mut self, items: &'b [T]) -> WIPOffset<Vector<'fbb, T>> { + self.assert_not_nested("create_vector_direct can not be called when a table or vector is under construction"); + let elem_size = T::size(); + self.align(items.len() * elem_size, T::alignment().max_of(SIZE_UOFFSET)); + + let bytes = { + let ptr = items.as_ptr() as *const T as *const u8; + unsafe { from_raw_parts(ptr, items.len() * elem_size) } + }; + self.push_bytes_unprefixed(bytes); + self.push(items.len() as UOffsetT); + + WIPOffset::new(self.used_space() as UOffsetT) + } + + /// Create a vector of strings. + /// + /// Speed-sensitive users may wish to reduce memory usage by creating the + /// vector manually: use `start_vector`, `push`, and `end_vector`. + #[inline] + pub fn create_vector_of_strings<'a, 'b>(&'a mut self, xs: &'b [&'b str]) -> WIPOffset<Vector<'fbb, ForwardsUOffset<&'fbb str>>> { + self.assert_not_nested("create_vector_of_strings can not be called when a table or vector is under construction"); + // internally, smallvec can be a stack-allocated or heap-allocated vector: + // 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; + } + self.create_vector(&offsets[..]) + } + + /// Create a vector of Push-able objects. + /// + /// Speed-sensitive users may wish to reduce memory usage by creating the + /// vector manually: use `start_vector`, `push`, and `end_vector`. + #[inline] + pub fn create_vector<'a: 'b, 'b, T: Push + Copy + 'b>(&'a mut self, items: &'b [T]) -> WIPOffset<Vector<'fbb, T::Output>> { + let elem_size = T::size(); + self.align(items.len() * elem_size, T::alignment().max_of(SIZE_UOFFSET)); + for i in (0..items.len()).rev() { + self.push(items[i]); + } + WIPOffset::new(self.push::<UOffsetT>(items.len() as UOffsetT).value()) + } + + /// Get the byte slice for the data that has been written, regardless of + /// whether it has been finished. + #[inline] + pub fn unfinished_data(&self) -> &[u8] { + &self.owned_buf[self.head..] + } + /// Get the byte slice for the data that has been written after a call to + /// one of the `finish` functions. + #[inline] + pub fn finished_data(&self) -> &[u8] { + self.assert_finished("finished_bytes cannot be called when the buffer is not yet finished"); + &self.owned_buf[self.head..] + } + /// Assert that a field is present in the just-finished Table. + /// + /// This is somewhat low-level and is mostly used by the generated code. + #[inline] + pub fn required(&self, + tab_revloc: WIPOffset<TableFinishedWIPOffset>, + slot_byte_loc: VOffsetT, + assert_msg_name: &'static str) { + let idx = self.used_space() - tab_revloc.value() as usize; + let tab = Table::new(&self.owned_buf[self.head..], idx); + let o = tab.vtable().get(slot_byte_loc) as usize; + assert!(o != 0, "missing required field {}", assert_msg_name); + } + + /// Finalize the FlatBuffer by: aligning it, pushing an optional file + /// identifier on to it, pushing a size prefix on to it, and marking the + /// internal state of the FlatBufferBuilder as `finished`. Afterwards, + /// users can call `finished_data` to get the resulting data. + #[inline] + pub fn finish_size_prefixed<T>(&mut self, root: WIPOffset<T>, file_identifier: Option<&str>) { + self.finish_with_opts(root, file_identifier, true); + } + + /// Finalize the FlatBuffer by: aligning it, pushing an optional file + /// identifier on to it, and marking the internal state of the + /// FlatBufferBuilder as `finished`. Afterwards, users can call + /// `finished_data` to get the resulting data. + #[inline] + pub fn finish<T>(&mut self, root: WIPOffset<T>, file_identifier: Option<&str>) { + self.finish_with_opts(root, file_identifier, false); + } + + /// Finalize the FlatBuffer by: aligning it and marking the internal state + /// of the FlatBufferBuilder as `finished`. Afterwards, users can call + /// `finished_data` to get the resulting data. + #[inline] + pub fn finish_minimal<T>(&mut self, root: WIPOffset<T>) { + self.finish_with_opts(root, None, false); + } + + #[inline] + fn used_space(&self) -> usize { + self.owned_buf.len() - self.head as usize + } + + #[inline] + fn track_field(&mut self, slot_off: VOffsetT, off: UOffsetT) { + let fl = FieldLoc { + id: slot_off, + off: off, + }; + self.field_locs.push(fl); + } + + /// Write the VTable, if it is new. + fn write_vtable(&mut self, table_tail_revloc: WIPOffset<TableUnfinishedWIPOffset>) -> WIPOffset<VTableWIPOffset> { + self.assert_nested("write_vtable"); + + // Write the vtable offset, which is the start of any Table. + // We fill its value later. + let object_revloc_to_vtable: WIPOffset<VTableWIPOffset> = + WIPOffset::new(self.push::<UOffsetT>(0xF0F0F0F0 as UOffsetT).value()); + + // Layout of the data this function will create when a new vtable is + // needed. + // -------------------------------------------------------------------- + // vtable starts here + // | x, x -- vtable len (bytes) [u16] + // | x, x -- object inline len (bytes) [u16] + // | x, x -- zero, or num bytes from start of object to field #0 [u16] + // | ... + // | x, x -- zero, or num bytes from start of object to field #n-1 [u16] + // vtable ends here + // table starts here + // | x, x, x, x -- offset (negative direction) to the vtable [i32] + // | aka "vtableoffset" + // | -- table inline data begins here, we don't touch it -- + // table ends here -- aka "table_start" + // -------------------------------------------------------------------- + // + // Layout of the data this function will create when we re-use an + // existing vtable. + // + // We always serialize this particular vtable, then compare it to the + // other vtables we know about to see if there is a duplicate. If there + // is, then we erase the serialized vtable we just made. + // We serialize it first so that we are able to do byte-by-byte + // comparisons with already-serialized vtables. This 1) saves + // bookkeeping space (we only keep revlocs to existing vtables), 2) + // allows us to convert to little-endian once, then do + // fast memcmp comparisons, and 3) by ensuring we are comparing real + // serialized vtables, we can be more assured that we are doing the + // comparisons correctly. + // + // -------------------------------------------------------------------- + // table starts here + // | x, x, x, x -- offset (negative direction) to an existing vtable [i32] + // | aka "vtableoffset" + // | -- table inline data begins here, we don't touch it -- + // table starts here: aka "table_start" + // -------------------------------------------------------------------- + + // fill the WIP vtable with zeros: + let vtable_byte_len = get_vtable_byte_len(&self.field_locs); + self.make_space(vtable_byte_len); + + // compute the length of the table (not vtable!) in bytes: + let table_object_size = object_revloc_to_vtable.value() - table_tail_revloc.value(); + debug_assert!(table_object_size < 0x10000); // vTable use 16bit offsets. + + // Write the VTable (we may delete it afterwards, if it is a duplicate): + let vt_start_pos = self.head; + let vt_end_pos = self.head + vtable_byte_len; + { + // write the vtable header: + let vtfw = &mut VTableWriter::init(&mut self.owned_buf[vt_start_pos..vt_end_pos]); + vtfw.write_vtable_byte_length(vtable_byte_len as VOffsetT); + vtfw.write_object_inline_size(table_object_size as VOffsetT); + + // serialize every FieldLoc to the vtable: + for &fl in self.field_locs.iter() { + let pos: VOffsetT = (object_revloc_to_vtable.value() - fl.off) as VOffsetT; + debug_assert_eq!(vtfw.get_field_offset(fl.id), + 0, + "tried to write a vtable field multiple times"); + vtfw.write_field_offset(fl.id, pos); + } + } + let dup_vt_use = { + let this_vt = VTable::init(&self.owned_buf[..], self.head); + self.find_duplicate_stored_vtable_revloc(this_vt) + }; + + let vt_use = match dup_vt_use { + Some(n) => { + VTableWriter::init(&mut self.owned_buf[vt_start_pos..vt_end_pos]).clear(); + self.head += vtable_byte_len; + n + } + None => { + let new_vt_use = self.used_space() as UOffsetT; + self.written_vtable_revpos.push(new_vt_use); + new_vt_use + } + }; + + { + let n = self.head + self.used_space() - object_revloc_to_vtable.value() as usize; + let saw = read_scalar::<UOffsetT>(&self.owned_buf[n..n + SIZE_SOFFSET]); + debug_assert_eq!(saw, 0xF0F0F0F0); + emplace_scalar::<SOffsetT>(&mut self.owned_buf[n..n + SIZE_SOFFSET], + vt_use as SOffsetT - object_revloc_to_vtable.value() as SOffsetT); + } + + self.field_locs.clear(); + + object_revloc_to_vtable + } + + #[inline] + fn find_duplicate_stored_vtable_revloc(&self, needle: VTable) -> Option<UOffsetT> { + for &revloc in self.written_vtable_revpos.iter().rev() { + let o = VTable::init(&self.owned_buf[..], self.head + self.used_space() - revloc as usize); + if needle == o { + return Some(revloc); + } + } + None + } + + // Only call this when you know it is safe to double the size of the buffer. + #[inline] + fn grow_owned_buf(&mut self) { + let old_len = self.owned_buf.len(); + let new_len = max(1, old_len * 2); + + let starting_active_size = self.used_space(); + + let diff = new_len - old_len; + self.owned_buf.resize(new_len, 0); + self.head += diff; + + let ending_active_size = self.used_space(); + debug_assert_eq!(starting_active_size, ending_active_size); + + if new_len == 1 { + return; + } + + // calculate the midpoint, and safely copy the old end data to the new + // end position: + let middle = new_len / 2; + { + let (left, right) = &mut self.owned_buf[..].split_at_mut(middle); + right.copy_from_slice(left); + } + // finally, zero out the old end data. + { + let ptr = (&mut self.owned_buf[..middle]).as_mut_ptr(); + unsafe { write_bytes(ptr, 0, middle); } + } + } + + // with or without a size prefix changes how we load the data, so finish* + // functions are split along those lines. + fn finish_with_opts<T>(&mut self, + root: WIPOffset<T>, + file_identifier: Option<&str>, + size_prefixed: bool) { + self.assert_not_finished("buffer cannot be finished when it is already finished"); + self.assert_not_nested("buffer cannot be finished when a table or vector is under construction"); + self.written_vtable_revpos.clear(); + + let to_align = { + // for the root offset: + let a = SIZE_UOFFSET; + // for the size prefix: + let b = if size_prefixed { SIZE_UOFFSET } else { 0 }; + // for the file identifier (a string that is not zero-terminated): + let c = if file_identifier.is_some() { + FILE_IDENTIFIER_LENGTH + } else { + 0 + }; + a + b + c + }; + + { + let ma = PushAlignment::new(self.min_align); + self.align(to_align, ma); + } + + if let Some(ident) = file_identifier { + debug_assert_eq!(ident.len(), FILE_IDENTIFIER_LENGTH); + self.push_bytes_unprefixed(ident.as_bytes()); + } + + self.push(root); + + if size_prefixed { + let sz = self.used_space() as UOffsetT; + self.push::<UOffsetT>(sz); + } + self.finished = true; + } + + #[inline] + fn align(&mut self, len: usize, alignment: PushAlignment) { + self.track_min_align(alignment.value()); + let s = self.used_space() as usize; + self.make_space(padding_bytes(s + len, alignment.value())); + } + + #[inline] + fn track_min_align(&mut self, alignment: usize) { + self.min_align = max(self.min_align, alignment); + } + + #[inline] + fn push_bytes_unprefixed(&mut self, x: &[u8]) -> UOffsetT { + let n = self.make_space(x.len()); + &mut self.owned_buf[n..n + x.len()].copy_from_slice(x); + + n as UOffsetT + } + + #[inline] + fn make_space(&mut self, want: usize) -> usize { + self.ensure_capacity(want); + self.head -= want; + self.head + } + + #[inline] + fn ensure_capacity(&mut self, want: usize) -> usize { + if self.unused_ready_space() >= want { + return want; + } + assert!(want <= FLATBUFFERS_MAX_BUFFER_SIZE, + "cannot grow buffer beyond 2 gigabytes"); + + while self.unused_ready_space() < want { + self.grow_owned_buf(); + } + want + } + #[inline] + fn unused_ready_space(&self) -> usize { + self.head + } + #[inline] + fn assert_nested(&self, fn_name: &'static str) { + // we don't assert that self.field_locs.len() >0 because the vtable + // could be empty (e.g. for empty tables, or for all-default values). + debug_assert!(self.nested, format!("incorrect FlatBufferBuilder usage: {} must be called while in a nested state", fn_name)); + } + #[inline] + fn assert_not_nested(&self, msg: &'static str) { + debug_assert!(!self.nested, msg); + } + #[inline] + fn assert_finished(&self, msg: &'static str) { + debug_assert!(self.finished, msg); + } + #[inline] + fn assert_not_finished(&self, msg: &'static str) { + debug_assert!(!self.finished, msg); + } + +} + +/// Compute the length of the vtable needed to represent the provided FieldLocs. +/// If there are no FieldLocs, then provide the minimum number of bytes +/// required: enough to write the VTable header. +#[inline] +fn get_vtable_byte_len(field_locs: &[FieldLoc]) -> usize { + let max_voffset = field_locs.iter().map(|fl| fl.id).max(); + match max_voffset { + None => { field_index_to_field_offset(0) as usize } + Some(mv) => { mv as usize + SIZE_VOFFSET } + } +} + +#[inline] +fn padding_bytes(buf_size: usize, scalar_size: usize) -> usize { + // ((!buf_size) + 1) & (scalar_size - 1) + (!buf_size).wrapping_add(1) & (scalar_size.wrapping_sub(1)) +} diff --git a/chromium/third_party/flatbuffers/src/rust/flatbuffers/src/endian_scalar.rs b/chromium/third_party/flatbuffers/src/rust/flatbuffers/src/endian_scalar.rs new file mode 100644 index 00000000000..00f2ebef49b --- /dev/null +++ b/chromium/third_party/flatbuffers/src/rust/flatbuffers/src/endian_scalar.rs @@ -0,0 +1,180 @@ +/* + * Copyright 2018 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +use std::mem::size_of; + +/// Trait for values that must be stored in little-endian byte order, but +/// might be represented in memory as big-endian. Every type that implements +/// EndianScalar is a valid FlatBuffers scalar value. +/// +/// The Rust stdlib does not provide a trait to represent scalars, so this trait +/// serves that purpose, too. +/// +/// Note that we do not use the num-traits crate for this, because it provides +/// "too much". For example, num-traits provides i128 support, but that is an +/// invalid FlatBuffers type. +pub trait EndianScalar: Sized + PartialEq + Copy + Clone { + fn to_little_endian(self) -> Self; + fn from_little_endian(self) -> Self; +} + +/// Macro for implementing a no-op endian conversion. This is used for types +/// that are one byte wide. +macro_rules! impl_endian_scalar_noop { + ($ty:ident) => ( + impl EndianScalar for $ty { + #[inline] + fn to_little_endian(self) -> Self { + self + } + #[inline] + fn from_little_endian(self) -> Self { + self + } + } + ) +} + +/// Macro for implementing an endian conversion using the stdlib `to_le` and +/// `from_le` functions. This is used for integer types. It is not used for +/// floats, because the `to_le` and `from_le` are not implemented for them in +/// the stdlib. +macro_rules! impl_endian_scalar_stdlib_le_conversion { + ($ty:ident) => ( + impl EndianScalar for $ty { + #[inline] + fn to_little_endian(self) -> Self { + Self::to_le(self) + } + #[inline] + fn from_little_endian(self) -> Self { + Self::from_le(self) + } + } + ) +} + +impl_endian_scalar_noop!(bool); +impl_endian_scalar_noop!(u8); +impl_endian_scalar_noop!(i8); + +impl_endian_scalar_stdlib_le_conversion!(u16); +impl_endian_scalar_stdlib_le_conversion!(u32); +impl_endian_scalar_stdlib_le_conversion!(u64); +impl_endian_scalar_stdlib_le_conversion!(i16); +impl_endian_scalar_stdlib_le_conversion!(i32); +impl_endian_scalar_stdlib_le_conversion!(i64); + +impl EndianScalar for f32 { + /// Convert f32 from host endian-ness to little-endian. + #[inline] + fn to_little_endian(self) -> Self { + #[cfg(target_endian = "little")] + { + self + } + #[cfg(not(target_endian = "little"))] + { + byte_swap_f32(&self) + } + } + /// Convert f32 from little-endian to host endian-ness. + #[inline] + fn from_little_endian(self) -> Self { + #[cfg(target_endian = "little")] + { + self + } + #[cfg(not(target_endian = "little"))] + { + byte_swap_f32(&self) + } + } +} + +impl EndianScalar for f64 { + /// Convert f64 from host endian-ness to little-endian. + #[inline] + fn to_little_endian(self) -> Self { + #[cfg(target_endian = "little")] + { + self + } + #[cfg(not(target_endian = "little"))] + { + byte_swap_f64(&self) + } + } + /// Convert f64 from little-endian to host endian-ness. + #[inline] + fn from_little_endian(self) -> Self { + #[cfg(target_endian = "little")] + { + self + } + #[cfg(not(target_endian = "little"))] + { + byte_swap_f64(&self) + } + } +} + +/// Swaps the bytes of an f32. +#[allow(dead_code)] +#[inline] +pub fn byte_swap_f32(x: f32) -> f32 { + f32::from_bits(x.to_bits().swap_bytes()) +} + +/// Swaps the bytes of an f64. +#[allow(dead_code)] +#[inline] +pub fn byte_swap_f64(x: f64) -> f64 { + f64::from_bits(x.to_bits().swap_bytes()) +} + +/// Place an EndianScalar into the provided mutable byte slice. Performs +/// endian conversion, if necessary. +#[inline] +pub fn emplace_scalar<T: EndianScalar>(s: &mut [u8], x: T) { + let sz = size_of::<T>(); + let mut_ptr = (&mut s[..sz]).as_mut_ptr() as *mut T; + let val = x.to_little_endian(); + unsafe { + *mut_ptr = val; + } +} + +/// Read an EndianScalar from the provided byte slice at the specified location. +/// Performs endian conversion, if necessary. +#[inline] +pub fn read_scalar_at<T: EndianScalar>(s: &[u8], loc: usize) -> T { + let buf = &s[loc..loc + size_of::<T>()]; + read_scalar(buf) +} + +/// Read an EndianScalar from the provided byte slice. Performs endian +/// conversion, if necessary. +#[inline] +pub fn read_scalar<T: EndianScalar>(s: &[u8]) -> T { + let sz = size_of::<T>(); + + let p = (&s[..sz]).as_ptr() as *const T; + let x = unsafe { *p }; + + x.from_little_endian() +} + diff --git a/chromium/third_party/flatbuffers/src/rust/flatbuffers/src/follow.rs b/chromium/third_party/flatbuffers/src/rust/flatbuffers/src/follow.rs new file mode 100644 index 00000000000..4d3eff77645 --- /dev/null +++ b/chromium/third_party/flatbuffers/src/rust/flatbuffers/src/follow.rs @@ -0,0 +1,62 @@ +/* + * Copyright 2018 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +use std::marker::PhantomData; + +/// Follow is a trait that allows us to access FlatBuffers in a declarative, +/// type safe, and fast way. They compile down to almost no code (after +/// optimizations). Conceptually, Follow lifts the offset-based access +/// patterns of FlatBuffers data into the type system. This trait is used +/// pervasively at read time, to access tables, vtables, vectors, strings, and +/// all other data. At this time, Follow is not utilized much on the write +/// path. +/// +/// Writing a new Follow implementation primarily involves deciding whether +/// you want to return data (of the type Self::Inner) or do you want to +/// continue traversing the FlatBuffer. +pub trait Follow<'a> { + type Inner; + fn follow(buf: &'a [u8], loc: usize) -> Self::Inner; +} + +/// Execute a follow as a top-level function. +#[allow(dead_code)] +#[inline] +pub fn lifted_follow<'a, T: Follow<'a>>(buf: &'a [u8], loc: usize) -> T::Inner { + T::follow(buf, loc) +} + +/// FollowStart wraps a Follow impl in a struct type. This can make certain +/// programming patterns more ergonomic. +#[derive(Debug)] +pub struct FollowStart<T>(PhantomData<T>); +impl<'a, T: Follow<'a> + 'a> FollowStart<T> { + #[inline] + pub fn new() -> Self { + Self { 0: PhantomData } + } + #[inline] + pub fn self_follow(&'a self, buf: &'a [u8], loc: usize) -> T::Inner { + T::follow(buf, loc) + } +} +impl<'a, T: Follow<'a>> Follow<'a> for FollowStart<T> { + type Inner = T::Inner; + #[inline] + fn follow(buf: &'a [u8], loc: usize) -> Self::Inner { + T::follow(buf, loc) + } +} diff --git a/chromium/third_party/flatbuffers/src/rust/flatbuffers/src/lib.rs b/chromium/third_party/flatbuffers/src/rust/flatbuffers/src/lib.rs new file mode 100644 index 00000000000..5e304344c97 --- /dev/null +++ b/chromium/third_party/flatbuffers/src/rust/flatbuffers/src/lib.rs @@ -0,0 +1,52 @@ +/* + * Copyright 2018 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +//! # FlatBuffers +//! +//! A library for memory-efficient serialization of data. +//! +//! This crate provides runtime support for the FlatBuffers format in the Rust programming language. +//! To use this crate, first generate code with the `flatc` compiler, as described here: https://google.github.io/flatbuffers/ +//! Then, include that code into your project. +//! Finally, add this crate to your `Cargo.toml`. +//! +//! At this time, Rust support is experimental, and APIs may change between minor versions. +//! +//! At this time, to generate Rust code, you will need the latest `master` version of `flatc`, available from here: https://github.com/google/flatbuffers +//! (On OSX, you can install FlatBuffers from `HEAD` with the Homebrew package manager.) + +mod builder; +mod endian_scalar; +mod follow; +mod primitives; +mod push; +mod table; +mod vector; +mod vtable; +mod vtable_writer; + +pub use builder::FlatBufferBuilder; +pub use endian_scalar::{EndianScalar, emplace_scalar, read_scalar, read_scalar_at, byte_swap_f32, byte_swap_f64}; +pub use follow::{Follow, FollowStart}; +pub use primitives::*; +pub use push::Push; +pub use table::{Table, buffer_has_identifier, get_root, get_size_prefixed_root}; +pub use vector::{SafeSliceAccess, Vector, follow_cast_ref}; +pub use vtable::field_index_to_field_offset; + +// TODO(rw): Unify `create_vector` and `create_vector_direct` by using +// `Into<Vector<...>>`. +// TODO(rw): Split fill ops in builder into fill_small, fill_big like in C++. diff --git a/chromium/third_party/flatbuffers/src/rust/flatbuffers/src/primitives.rs b/chromium/third_party/flatbuffers/src/rust/flatbuffers/src/primitives.rs new file mode 100644 index 00000000000..59176b8f83a --- /dev/null +++ b/chromium/third_party/flatbuffers/src/rust/flatbuffers/src/primitives.rs @@ -0,0 +1,298 @@ +/* + * Copyright 2018 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +use std::marker::PhantomData; +use std::mem::size_of; +use std::ops::Deref; + +use endian_scalar::{emplace_scalar, read_scalar, read_scalar_at}; +use follow::Follow; +use push::Push; + +pub const FLATBUFFERS_MAX_BUFFER_SIZE: usize = (1u64 << 31) as usize; + +pub const FILE_IDENTIFIER_LENGTH: usize = 4; + +pub const VTABLE_METADATA_FIELDS: usize = 2; + +pub const SIZE_U8: usize = size_of::<u8>(); +pub const SIZE_I8: usize = size_of::<i8>(); + +pub const SIZE_U16: usize = size_of::<u16>(); +pub const SIZE_I16: usize = size_of::<i16>(); + +pub const SIZE_U32: usize = size_of::<u32>(); +pub const SIZE_I32: usize = size_of::<i32>(); + +pub const SIZE_U64: usize = size_of::<u64>(); +pub const SIZE_I64: usize = size_of::<i64>(); + +pub const SIZE_F32: usize = size_of::<f32>(); +pub const SIZE_F64: usize = size_of::<f64>(); + +pub const SIZE_SOFFSET: usize = SIZE_I32; +pub const SIZE_UOFFSET: usize = SIZE_U32; +pub const SIZE_VOFFSET: usize = SIZE_I16; + +pub const SIZE_SIZEPREFIX: usize = SIZE_UOFFSET; + +/// SOffsetT is an i32 that is used by tables to reference their vtables. +pub type SOffsetT = i32; + +/// UOffsetT is a u32 that is used by pervasively to represent both pointers +/// and lengths of vectors. +pub type UOffsetT = u32; + +/// VOffsetT is a i32 that is used by vtables to store field data. +pub type VOffsetT = i16; + +/// TableFinishedWIPOffset marks a WIPOffset as being for a finished table. +pub struct TableFinishedWIPOffset {} + +/// TableUnfinishedWIPOffset marks a WIPOffset as being for an unfinished table. +pub struct TableUnfinishedWIPOffset {} + +/// UnionWIPOffset marks a WIPOffset as being for a union value. +pub struct UnionWIPOffset {} + +/// VTableWIPOffset marks a WIPOffset as being for a vtable. +pub struct VTableWIPOffset {} + +/// WIPOffset contains an UOffsetT with a special meaning: it is the location of +/// data relative to the *end* of an in-progress FlatBuffer. The +/// FlatBufferBuilder uses this to track the location of objects in an absolute +/// way. The impl of Push converts a WIPOffset into a ForwardsUOffset. +#[derive(Debug)] +pub struct WIPOffset<T>(UOffsetT, PhantomData<T>); + +// TODO(rw): why do we need to reimplement (with a default impl) Copy to +// avoid ownership errors? +impl<T> Copy for WIPOffset<T> {} +impl<T> Clone for WIPOffset<T> { + #[inline] + fn clone(&self) -> WIPOffset<T> { + WIPOffset::new(self.0.clone()) + } +} +impl<T> PartialEq for WIPOffset<T> { + fn eq(&self, o: &WIPOffset<T>) -> bool { + self.value() == o.value() + } +} + +impl<T> Deref for WIPOffset<T> { + type Target = UOffsetT; + #[inline] + fn deref(&self) -> &UOffsetT { + &self.0 + } +} +impl<'a, T: 'a> WIPOffset<T> { + /// Create a new WIPOffset. + #[inline] + pub fn new(o: UOffsetT) -> WIPOffset<T> { + WIPOffset { + 0: o, + 1: PhantomData, + } + } + + /// Return a wrapped value that brings its meaning as a union WIPOffset + /// into the type system. + #[inline(always)] + pub fn as_union_value(&self) -> WIPOffset<UnionWIPOffset> { + WIPOffset::new(self.0) + } + /// Get the underlying value. + #[inline(always)] + pub fn value(&self) -> UOffsetT { + self.0 + } +} + +impl<T> Push for WIPOffset<T> { + type Output = ForwardsUOffset<T>; + + #[inline(always)] + fn push(&self, dst: &mut [u8], rest: &[u8]) { + let n = (SIZE_UOFFSET + rest.len() - self.value() as usize) as UOffsetT; + emplace_scalar::<UOffsetT>(dst, n); + } +} + +impl<T> Push for ForwardsUOffset<T> { + type Output = Self; + + #[inline(always)] + fn push(&self, dst: &mut [u8], rest: &[u8]) { + self.value().push(dst, rest); + } +} + +/// ForwardsUOffset is used by Follow to traverse a FlatBuffer: the pointer +/// is incremented by the value contained in this type. +#[derive(Debug)] +pub struct ForwardsUOffset<T>(UOffsetT, PhantomData<T>); +impl<T> ForwardsUOffset<T> { + #[inline(always)] + pub fn value(&self) -> UOffsetT { + self.0 + } +} + +impl<'a, T: Follow<'a>> Follow<'a> for ForwardsUOffset<T> { + type Inner = T::Inner; + #[inline(always)] + fn follow(buf: &'a [u8], loc: usize) -> Self::Inner { + let slice = &buf[loc..loc + SIZE_UOFFSET]; + let off = read_scalar::<u32>(slice) as usize; + T::follow(buf, loc + off) + } +} + +/// ForwardsVOffset is used by Follow to traverse a FlatBuffer: the pointer +/// is incremented by the value contained in this type. +#[derive(Debug)] +pub struct ForwardsVOffset<T>(VOffsetT, PhantomData<T>); +impl<T> ForwardsVOffset<T> { + #[inline(always)] + pub fn value(&self) -> VOffsetT { + self.0 + } +} + +impl<'a, T: Follow<'a>> Follow<'a> for ForwardsVOffset<T> { + type Inner = T::Inner; + #[inline(always)] + fn follow(buf: &'a [u8], loc: usize) -> Self::Inner { + let slice = &buf[loc..loc + SIZE_VOFFSET]; + let off = read_scalar::<VOffsetT>(slice) as usize; + T::follow(buf, loc + off) + } +} + +impl<T> Push for ForwardsVOffset<T> { + type Output = Self; + + #[inline] + fn push(&self, dst: &mut [u8], rest: &[u8]) { + self.value().push(dst, rest); + } +} + +/// ForwardsSOffset is used by Follow to traverse a FlatBuffer: the pointer +/// is incremented by the *negative* of the value contained in this type. +#[derive(Debug)] +pub struct BackwardsSOffset<T>(SOffsetT, PhantomData<T>); +impl<T> BackwardsSOffset<T> { + #[inline(always)] + pub fn value(&self) -> SOffsetT { + self.0 + } +} + +impl<'a, T: Follow<'a>> Follow<'a> for BackwardsSOffset<T> { + type Inner = T::Inner; + #[inline(always)] + fn follow(buf: &'a [u8], loc: usize) -> Self::Inner { + let slice = &buf[loc..loc + SIZE_SOFFSET]; + let off = read_scalar::<SOffsetT>(slice); + T::follow(buf, (loc as SOffsetT - off) as usize) + } +} + +impl<T> Push for BackwardsSOffset<T> { + type Output = Self; + + #[inline] + fn push(&self, dst: &mut [u8], rest: &[u8]) { + self.value().push(dst, rest); + } +} + +/// SkipSizePrefix is used by Follow to traverse a FlatBuffer: the pointer is +/// incremented by a fixed constant in order to skip over the size prefix value. +pub struct SkipSizePrefix<T>(PhantomData<T>); +impl<'a, T: Follow<'a> + 'a> Follow<'a> for SkipSizePrefix<T> { + type Inner = T::Inner; + #[inline(always)] + fn follow(buf: &'a [u8], loc: usize) -> Self::Inner { + T::follow(buf, loc + SIZE_SIZEPREFIX) + } +} + +/// SkipRootOffset is used by Follow to traverse a FlatBuffer: the pointer is +/// incremented by a fixed constant in order to skip over the root offset value. +pub struct SkipRootOffset<T>(PhantomData<T>); +impl<'a, T: Follow<'a> + 'a> Follow<'a> for SkipRootOffset<T> { + type Inner = T::Inner; + #[inline(always)] + fn follow(buf: &'a [u8], loc: usize) -> Self::Inner { + T::follow(buf, loc + SIZE_UOFFSET) + } +} + +/// FileIdentifier is used by Follow to traverse a FlatBuffer: the pointer is +/// dereferenced into a byte slice, whose bytes are the file identifer value. +pub struct FileIdentifier; +impl<'a> Follow<'a> for FileIdentifier { + type Inner = &'a [u8]; + #[inline(always)] + fn follow(buf: &'a [u8], loc: usize) -> Self::Inner { + &buf[loc..loc + FILE_IDENTIFIER_LENGTH] + } +} + +/// SkipFileIdentifier is used by Follow to traverse a FlatBuffer: the pointer +/// is incremented by a fixed constant in order to skip over the file +/// identifier value. +pub struct SkipFileIdentifier<T>(PhantomData<T>); +impl<'a, T: Follow<'a> + 'a> Follow<'a> for SkipFileIdentifier<T> { + type Inner = T::Inner; + #[inline(always)] + fn follow(buf: &'a [u8], loc: usize) -> Self::Inner { + T::follow(buf, loc + FILE_IDENTIFIER_LENGTH) + } +} + +/// Follow trait impls for primitive types. +/// +/// Ideally, these would be implemented as a single impl using trait bounds on +/// EndianScalar, but implementing Follow that way causes a conflict with +/// other impls. +macro_rules! impl_follow_for_endian_scalar { + ($ty:ident) => ( + impl<'a> Follow<'a> for $ty { + type Inner = $ty; + #[inline(always)] + fn follow(buf: &'a [u8], loc: usize) -> Self::Inner { + read_scalar_at::<$ty>(buf, loc) + } + } + ) +} + +impl_follow_for_endian_scalar!(bool); +impl_follow_for_endian_scalar!(u8); +impl_follow_for_endian_scalar!(u16); +impl_follow_for_endian_scalar!(u32); +impl_follow_for_endian_scalar!(u64); +impl_follow_for_endian_scalar!(i8); +impl_follow_for_endian_scalar!(i16); +impl_follow_for_endian_scalar!(i32); +impl_follow_for_endian_scalar!(i64); +impl_follow_for_endian_scalar!(f32); +impl_follow_for_endian_scalar!(f64); diff --git a/chromium/third_party/flatbuffers/src/rust/flatbuffers/src/push.rs b/chromium/third_party/flatbuffers/src/rust/flatbuffers/src/push.rs new file mode 100644 index 00000000000..2b307a3a783 --- /dev/null +++ b/chromium/third_party/flatbuffers/src/rust/flatbuffers/src/push.rs @@ -0,0 +1,81 @@ +/* + * Copyright 2018 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +use std::cmp::max; +use std::mem::{align_of, size_of}; + +use endian_scalar::emplace_scalar; + +/// Trait to abstract over functionality needed to write values (either owned +/// or referenced). Used in FlatBufferBuilder and implemented for generated +/// types. +pub trait Push: Sized { + type Output; + fn push(&self, dst: &mut [u8], _rest: &[u8]); + #[inline] + fn size() -> usize { + size_of::<Self::Output>() + } + #[inline] + fn alignment() -> PushAlignment { + PushAlignment::new(align_of::<Self::Output>()) + } +} + +/// Ensure Push alignment calculations are typesafe (because this helps reduce +/// implementation issues when using FlatBufferBuilder::align). +pub struct PushAlignment(usize); +impl PushAlignment { + #[inline] + pub fn new(x: usize) -> Self { + PushAlignment { 0: x } + } + #[inline] + pub fn value(&self) -> usize { + self.0 + } + #[inline] + pub fn max_of(&self, o: usize) -> Self { + PushAlignment::new(max(self.0, o)) + } +} + +/// Macro to implement Push for EndianScalar types. +macro_rules! impl_push_for_endian_scalar { + ($ty:ident) => ( + impl Push for $ty { + type Output = $ty; + + #[inline] + fn push(&self, dst: &mut [u8], _rest: &[u8]) { + emplace_scalar::<$ty>(dst, *self); + } + + } + ) +} + +impl_push_for_endian_scalar!(bool); +impl_push_for_endian_scalar!(u8); +impl_push_for_endian_scalar!(i8); +impl_push_for_endian_scalar!(u16); +impl_push_for_endian_scalar!(i16); +impl_push_for_endian_scalar!(u32); +impl_push_for_endian_scalar!(i32); +impl_push_for_endian_scalar!(u64); +impl_push_for_endian_scalar!(i64); +impl_push_for_endian_scalar!(f32); +impl_push_for_endian_scalar!(f64); diff --git a/chromium/third_party/flatbuffers/src/rust/flatbuffers/src/table.rs b/chromium/third_party/flatbuffers/src/rust/flatbuffers/src/table.rs new file mode 100644 index 00000000000..7b1c4a542e1 --- /dev/null +++ b/chromium/third_party/flatbuffers/src/rust/flatbuffers/src/table.rs @@ -0,0 +1,77 @@ +/* + * Copyright 2018 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +use follow::Follow; +use primitives::*; +use vtable::VTable; + +#[derive(Clone, Copy, Debug, PartialEq)] +pub struct Table<'a> { + pub buf: &'a [u8], + pub loc: usize, +} + +impl<'a> Table<'a> { + #[inline] + pub fn new(buf: &'a [u8], loc: usize) -> Self { + Table { buf: buf, loc: loc } + } + #[inline] + pub fn vtable(&self) -> VTable<'a> { + <BackwardsSOffset<VTable<'a>>>::follow(self.buf, self.loc) + } + #[inline] + pub fn get<T: Follow<'a> + 'a>( + &self, + slot_byte_loc: VOffsetT, + default: Option<T::Inner>, + ) -> Option<T::Inner> { + let o = self.vtable().get(slot_byte_loc) as usize; + if o == 0 { + return default; + } + Some(<T>::follow(self.buf, self.loc + o)) + } +} + +impl<'a> Follow<'a> for Table<'a> { + type Inner = Table<'a>; + #[inline] + fn follow(buf: &'a [u8], loc: usize) -> Self::Inner { + Table { buf: buf, loc: loc } + } +} + +#[inline] +pub fn get_root<'a, T: Follow<'a> + 'a>(data: &'a [u8]) -> T::Inner { + <ForwardsUOffset<T>>::follow(data, 0) +} +#[inline] +pub fn get_size_prefixed_root<'a, T: Follow<'a> + 'a>(data: &'a [u8]) -> T::Inner { + <SkipSizePrefix<ForwardsUOffset<T>>>::follow(data, 0) +} +#[inline] +pub fn buffer_has_identifier(data: &[u8], ident: &str, size_prefixed: bool) -> bool { + assert_eq!(ident.len(), FILE_IDENTIFIER_LENGTH); + + let got = if size_prefixed { + <SkipSizePrefix<SkipRootOffset<FileIdentifier>>>::follow(data, 0) + } else { + <SkipRootOffset<FileIdentifier>>::follow(data, 0) + }; + + ident.as_bytes() == got +} diff --git a/chromium/third_party/flatbuffers/src/rust/flatbuffers/src/vector.rs b/chromium/third_party/flatbuffers/src/rust/flatbuffers/src/vector.rs new file mode 100644 index 00000000000..8c2d6d50916 --- /dev/null +++ b/chromium/third_party/flatbuffers/src/rust/flatbuffers/src/vector.rs @@ -0,0 +1,133 @@ +/* + * Copyright 2018 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +use std::marker::PhantomData; +use std::mem::size_of; +use std::slice::from_raw_parts; +use std::str::from_utf8_unchecked; + +use endian_scalar::{EndianScalar, read_scalar}; +use follow::Follow; +use primitives::*; + +#[derive(Debug)] +pub struct Vector<'a, T: 'a>(&'a [u8], usize, PhantomData<T>); + +impl<'a, T: 'a> Vector<'a, T> { + #[inline(always)] + pub fn new(buf: &'a [u8], loc: usize) -> Self { + Vector { + 0: buf, + 1: loc, + 2: PhantomData, + } + } + + #[inline(always)] + pub fn len(&self) -> usize { + read_scalar::<UOffsetT>(&self.0[self.1 as usize..]) as usize + } +} + +impl<'a, T: Follow<'a> + 'a> Vector<'a, T> { + #[inline(always)] + pub fn get(&self, idx: usize) -> T::Inner { + debug_assert!(idx < read_scalar::<u32>(&self.0[self.1 as usize..]) as usize); + let sz = size_of::<T>(); + debug_assert!(sz > 0); + T::follow(self.0, self.1 as usize + SIZE_UOFFSET + sz * idx) + } +} + +pub trait SafeSliceAccess {} +impl<'a, T: SafeSliceAccess + 'a> Vector<'a, T> { + pub fn safe_slice(self) -> &'a [T] { + let buf = self.0; + let loc = self.1; + let sz = size_of::<T>(); + debug_assert!(sz > 0); + let len = read_scalar::<UOffsetT>(&buf[loc..loc + SIZE_UOFFSET]) as usize; + let data_buf = &buf[loc + SIZE_UOFFSET..loc + SIZE_UOFFSET + len * sz]; + let ptr = data_buf.as_ptr() as *const T; + let s: &'a [T] = unsafe { from_raw_parts(ptr, len) }; + s + } +} + +impl SafeSliceAccess for u8 {} +impl SafeSliceAccess for i8 {} +impl SafeSliceAccess for bool {} + +#[cfg(target_endian = "little")] +mod le_safe_slice_impls { + impl super::SafeSliceAccess for u16 {} + impl super::SafeSliceAccess for u32 {} + impl super::SafeSliceAccess for u64 {} + + impl super::SafeSliceAccess for i16 {} + impl super::SafeSliceAccess for i32 {} + impl super::SafeSliceAccess for i64 {} + + impl super::SafeSliceAccess for f32 {} + impl super::SafeSliceAccess for f64 {} +} + +pub use self::le_safe_slice_impls::*; + +pub fn follow_cast_ref<'a, T: Sized + 'a>(buf: &'a [u8], loc: usize) -> &'a T { + let sz = size_of::<T>(); + let buf = &buf[loc..loc + sz]; + let ptr = buf.as_ptr() as *const T; + unsafe { &*ptr } +} + +impl<'a> Follow<'a> for &'a str { + type Inner = &'a str; + fn follow(buf: &'a [u8], loc: usize) -> Self::Inner { + let len = read_scalar::<UOffsetT>(&buf[loc..loc + SIZE_UOFFSET]) as usize; + let slice = &buf[loc + SIZE_UOFFSET..loc + SIZE_UOFFSET + len]; + let s = unsafe { from_utf8_unchecked(slice) }; + s + } +} + +fn follow_slice_helper<T>(buf: &[u8], loc: usize) -> &[T] { + let sz = size_of::<T>(); + debug_assert!(sz > 0); + let len = read_scalar::<UOffsetT>(&buf[loc..loc + SIZE_UOFFSET]) as usize; + let data_buf = &buf[loc + SIZE_UOFFSET..loc + SIZE_UOFFSET + len * sz]; + let ptr = data_buf.as_ptr() as *const T; + let s: &[T] = unsafe { from_raw_parts(ptr, len) }; + s +} + +/// Implement direct slice access if the host is little-endian. +#[cfg(target_endian = "little")] +impl<'a, T: EndianScalar> Follow<'a> for &'a [T] { + type Inner = &'a [T]; + fn follow(buf: &'a [u8], loc: usize) -> Self::Inner { + follow_slice_helper::<T>(buf, loc) + } +} + +/// Implement Follow for all possible Vectors that have Follow-able elements. +impl<'a, T: Follow<'a> + 'a> Follow<'a> for Vector<'a, T> { + type Inner = Vector<'a, T>; + fn follow(buf: &'a [u8], loc: usize) -> Self::Inner { + Vector::new(buf, loc) + } +} + diff --git a/chromium/third_party/flatbuffers/src/rust/flatbuffers/src/vtable.rs b/chromium/third_party/flatbuffers/src/rust/flatbuffers/src/vtable.rs new file mode 100644 index 00000000000..cd7ede6e446 --- /dev/null +++ b/chromium/third_party/flatbuffers/src/rust/flatbuffers/src/vtable.rs @@ -0,0 +1,95 @@ +/* + * Copyright 2018 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +use endian_scalar::read_scalar_at; +use follow::Follow; +use primitives::*; + +/// VTable encapsulates read-only usage of a vtable. It is only to be used +/// by generated code. +#[derive(Debug)] +pub struct VTable<'a> { + buf: &'a [u8], + loc: usize, +} + +impl<'a> PartialEq for VTable<'a> { + fn eq(&self, other: &VTable) -> bool { + self.as_bytes().eq(other.as_bytes()) + } +} + +impl<'a> VTable<'a> { + pub fn init(buf: &'a [u8], loc: usize) -> Self { + VTable { + buf: buf, + loc: loc, + } + } + pub fn num_fields(&self) -> usize { + (self.num_bytes() / SIZE_VOFFSET) - 2 + } + pub fn num_bytes(&self) -> usize { + read_scalar_at::<VOffsetT>(self.buf, self.loc) as usize + } + pub fn object_inline_num_bytes(&self) -> usize { + let n = read_scalar_at::<VOffsetT>(self.buf, self.loc + SIZE_VOFFSET); + n as usize + } + pub fn get_field(&self, idx: usize) -> VOffsetT { + // TODO(rw): distinguish between None and 0? + if idx > self.num_fields() { + return 0; + } + read_scalar_at::<VOffsetT>( + self.buf, + self.loc + SIZE_VOFFSET + SIZE_VOFFSET + SIZE_VOFFSET * idx, + ) + } + pub fn get(&self, byte_loc: VOffsetT) -> VOffsetT { + // TODO(rw): distinguish between None and 0? + if byte_loc as usize >= self.num_bytes() { + return 0; + } + read_scalar_at::<VOffsetT>(self.buf, self.loc + byte_loc as usize) + } + pub fn as_bytes(&self) -> &[u8] { + let len = self.num_bytes(); + &self.buf[self.loc..self.loc + len] + } +} + + +#[allow(dead_code)] +pub fn field_index_to_field_offset(field_id: VOffsetT) -> VOffsetT { + // Should correspond to what end_table() below builds up. + let fixed_fields = 2; // Vtable size and Object Size. + ((field_id + fixed_fields) * (SIZE_VOFFSET as VOffsetT)) as VOffsetT +} + +#[allow(dead_code)] +pub fn field_offset_to_field_index(field_o: VOffsetT) -> VOffsetT { + debug_assert!(field_o >= 2); + let fixed_fields = 2; // VTable size and Object Size. + (field_o / (SIZE_VOFFSET as VOffsetT)) - fixed_fields +} + +impl<'a> Follow<'a> for VTable<'a> { + type Inner = VTable<'a>; + fn follow(buf: &'a [u8], loc: usize) -> Self::Inner { + VTable::init(buf, loc) + } +} diff --git a/chromium/third_party/flatbuffers/src/rust/flatbuffers/src/vtable_writer.rs b/chromium/third_party/flatbuffers/src/rust/flatbuffers/src/vtable_writer.rs new file mode 100644 index 00000000000..119f794cd1c --- /dev/null +++ b/chromium/third_party/flatbuffers/src/rust/flatbuffers/src/vtable_writer.rs @@ -0,0 +1,85 @@ +/* + * Copyright 2018 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +use std::ptr::write_bytes; + +use endian_scalar::{emplace_scalar, read_scalar}; +use primitives::*; + +/// VTableWriter compartmentalizes actions needed to create a vtable. +#[derive(Debug)] +pub struct VTableWriter<'a> { + buf: &'a mut [u8], +} + +impl<'a> VTableWriter<'a> { + #[inline(always)] + pub fn init(buf: &'a mut [u8]) -> Self { + VTableWriter { buf: buf } + } + + /// Writes the vtable length (in bytes) into the vtable. + /// + /// Note that callers already need to have computed this to initialize + /// a VTableWriter. + /// + /// In debug mode, asserts that the length of the underlying data is equal + /// to the provided value. + #[inline(always)] + pub fn write_vtable_byte_length(&mut self, n: VOffsetT) { + emplace_scalar::<VOffsetT>(&mut self.buf[..SIZE_VOFFSET], n); + debug_assert_eq!(n as usize, self.buf.len()); + } + + /// Writes an object length (in bytes) into the vtable. + #[inline(always)] + pub fn write_object_inline_size(&mut self, n: VOffsetT) { + emplace_scalar::<VOffsetT>(&mut self.buf[SIZE_VOFFSET..2 * SIZE_VOFFSET], n); + } + + /// Gets an object field offset from the vtable. Only used for debugging. + /// + /// Note that this expects field offsets (which are like pointers), not + /// field ids (which are like array indices). + #[inline(always)] + pub fn get_field_offset(&self, vtable_offset: VOffsetT) -> VOffsetT { + let idx = vtable_offset as usize; + read_scalar::<VOffsetT>(&self.buf[idx..idx + SIZE_VOFFSET]) + } + + /// Writes an object field offset into the vtable. + /// + /// Note that this expects field offsets (which are like pointers), not + /// field ids (which are like array indices). + #[inline(always)] + pub fn write_field_offset(&mut self, vtable_offset: VOffsetT, object_data_offset: VOffsetT) { + let idx = vtable_offset as usize; + emplace_scalar::<VOffsetT>(&mut self.buf[idx..idx + SIZE_VOFFSET], object_data_offset); + } + + /// Clears all data in this VTableWriter. Used to cleanly undo a + /// vtable write. + #[inline(always)] + pub fn clear(&mut self) { + // This is the closest thing to memset in Rust right now. + let len = self.buf.len(); + let p = self.buf.as_mut_ptr() as *mut u8; + unsafe { + write_bytes(p, 0, len); + } + } +} + diff --git a/chromium/third_party/flatbuffers/src/samples/android/build.gradle b/chromium/third_party/flatbuffers/src/samples/android/build.gradle index e6af6d6f39a..81c1af0af96 100644 --- a/chromium/third_party/flatbuffers/src/samples/android/build.gradle +++ b/chromium/third_party/flatbuffers/src/samples/android/build.gradle @@ -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" } } } diff --git a/chromium/third_party/flatbuffers/src/samples/csharp_sample.sh b/chromium/third_party/flatbuffers/src/samples/csharp_sample.sh index 2a163f728b3..ea472ed9c05 100755 --- a/chromium/third_party/flatbuffers/src/samples/csharp_sample.sh +++ b/chromium/third_party/flatbuffers/src/samples/csharp_sample.sh @@ -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. diff --git a/chromium/third_party/flatbuffers/src/samples/monster.bfbs b/chromium/third_party/flatbuffers/src/samples/monster.bfbs Binary files differnew file mode 100644 index 00000000000..95a977a36bd --- /dev/null +++ b/chromium/third_party/flatbuffers/src/samples/monster.bfbs diff --git a/chromium/third_party/flatbuffers/src/samples/monster_generated.h b/chromium/third_party/flatbuffers/src/samples/monster_generated.h index 5af2e3bcddb..db79c2e5d0c 100644 --- a/chromium/third_party/flatbuffers/src/samples/monster_generated.h +++ b/chromium/third_party/flatbuffers/src/samples/monster_generated.h @@ -17,6 +17,10 @@ struct MonsterT; struct Weapon; struct WeaponT; +bool operator==(const Vec3 &lhs, const Vec3 &rhs); +bool operator==(const MonsterT &lhs, const MonsterT &rhs); +bool operator==(const WeaponT &lhs, const WeaponT &rhs); + inline const flatbuffers::TypeTable *Vec3TypeTable(); inline const flatbuffers::TypeTable *MonsterTypeTable(); @@ -51,6 +55,7 @@ inline const char * const *EnumNamesColor() { } inline const char *EnumNameColor(Color e) { + if (e < Color_Red || e > Color_Blue) return ""; const size_t index = static_cast<int>(e); return EnumNamesColor()[index]; } @@ -80,6 +85,7 @@ inline const char * const *EnumNamesEquipment() { } inline const char *EnumNameEquipment(Equipment e) { + if (e < Equipment_NONE || e > Equipment_Weapon) return ""; const size_t index = static_cast<int>(e); return EnumNamesEquipment()[index]; } @@ -133,6 +139,22 @@ struct EquipmentUnion { } }; + +inline bool operator==(const EquipmentUnion &lhs, const EquipmentUnion &rhs) { + if (lhs.type != rhs.type) return false; + switch (lhs.type) { + case Equipment_NONE: { + return true; + } + case Equipment_Weapon: { + return *(reinterpret_cast<const WeaponT *>(lhs.value)) == + *(reinterpret_cast<const WeaponT *>(rhs.value)); + } + default: { + return false; + } + } +} 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); @@ -172,6 +194,13 @@ FLATBUFFERS_MANUALLY_ALIGNED_STRUCT(4) Vec3 FLATBUFFERS_FINAL_CLASS { }; FLATBUFFERS_STRUCT_END(Vec3, 12); +inline bool operator==(const Vec3 &lhs, const Vec3 &rhs) { + return + (lhs.x() == rhs.x()) && + (lhs.y() == rhs.y()) && + (lhs.z() == rhs.z()); +} + struct MonsterT : public flatbuffers::NativeTable { typedef Monster TableType; flatbuffers::unique_ptr<Vec3> pos; @@ -189,12 +218,24 @@ struct MonsterT : public flatbuffers::NativeTable { } }; +inline bool operator==(const MonsterT &lhs, const MonsterT &rhs) { + return + (lhs.pos == rhs.pos) && + (lhs.mana == rhs.mana) && + (lhs.hp == rhs.hp) && + (lhs.name == rhs.name) && + (lhs.inventory == rhs.inventory) && + (lhs.color == rhs.color) && + (lhs.weapons == rhs.weapons) && + (lhs.equipped == rhs.equipped); +} + 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, @@ -367,15 +408,18 @@ inline flatbuffers::Offset<Monster> CreateMonsterDirect( const std::vector<flatbuffers::Offset<Weapon>> *weapons = nullptr, Equipment equipped_type = Equipment_NONE, flatbuffers::Offset<void> equipped = 0) { + 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; 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); } @@ -391,12 +435,18 @@ struct WeaponT : public flatbuffers::NativeTable { } }; +inline bool operator==(const WeaponT &lhs, const WeaponT &rhs) { + return + (lhs.name == rhs.name) && + (lhs.damage == rhs.damage); +} + 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 }; @@ -459,9 +509,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); } @@ -659,7 +710,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", diff --git a/chromium/third_party/flatbuffers/src/samples/monster_generated.rs b/chromium/third_party/flatbuffers/src/samples/monster_generated.rs new file mode 100644 index 00000000000..9ec573c7c3b --- /dev/null +++ b/chromium/third_party/flatbuffers/src/samples/monster_generated.rs @@ -0,0 +1,507 @@ +// automatically generated by the FlatBuffers compiler, do not modify + + +pub mod my_game { + #![allow(dead_code)] + #![allow(unused_imports)] + + use std::mem; + use std::marker::PhantomData; + use std::cmp::Ordering; + + extern crate flatbuffers; + use self::flatbuffers::EndianScalar; +pub mod sample { + #![allow(dead_code)] + #![allow(unused_imports)] + + use std::mem; + use std::marker::PhantomData; + use std::cmp::Ordering; + + extern crate flatbuffers; + use self::flatbuffers::EndianScalar; + +#[allow(non_camel_case_types)] +#[repr(i8)] +#[derive(Clone, Copy, PartialEq, Debug)] +pub enum Color { + Red = 0, + Green = 1, + Blue = 2 +} + +const ENUM_MIN_COLOR: i8 = 0; +const ENUM_MAX_COLOR: i8 = 2; + +impl<'a> flatbuffers::Follow<'a> for Color { + type Inner = Self; + #[inline] + fn follow(buf: &'a [u8], loc: usize) -> Self::Inner { + flatbuffers::read_scalar_at::<Self>(buf, loc) + } +} + +impl flatbuffers::EndianScalar for Color { + #[inline] + fn to_little_endian(self) -> Self { + let n = i8::to_le(self as i8); + let p = &n as *const i8 as *const Color; + unsafe { *p } + } + #[inline] + fn from_little_endian(self) -> Self { + let n = i8::from_le(self as i8); + let p = &n as *const i8 as *const Color; + unsafe { *p } + } +} + +impl flatbuffers::Push for Color { + type Output = Color; + #[inline] + fn push(&self, dst: &mut [u8], _rest: &[u8]) { + flatbuffers::emplace_scalar::<Color>(dst, *self); + } +} + +#[allow(non_camel_case_types)] +const ENUM_VALUES_COLOR:[Color; 3] = [ + Color::Red, + Color::Green, + Color::Blue +]; + +#[allow(non_camel_case_types)] +const ENUM_NAMES_COLOR:[&'static str; 3] = [ + "Red", + "Green", + "Blue" +]; + +pub fn enum_name_color(e: Color) -> &'static str { + let index: usize = e as usize; + ENUM_NAMES_COLOR[index] +} + +#[allow(non_camel_case_types)] +#[repr(u8)] +#[derive(Clone, Copy, PartialEq, Debug)] +pub enum Equipment { + NONE = 0, + Weapon = 1 +} + +const ENUM_MIN_EQUIPMENT: u8 = 0; +const ENUM_MAX_EQUIPMENT: u8 = 1; + +impl<'a> flatbuffers::Follow<'a> for Equipment { + type Inner = Self; + #[inline] + fn follow(buf: &'a [u8], loc: usize) -> Self::Inner { + flatbuffers::read_scalar_at::<Self>(buf, loc) + } +} + +impl flatbuffers::EndianScalar for Equipment { + #[inline] + fn to_little_endian(self) -> Self { + let n = u8::to_le(self as u8); + let p = &n as *const u8 as *const Equipment; + unsafe { *p } + } + #[inline] + fn from_little_endian(self) -> Self { + let n = u8::from_le(self as u8); + let p = &n as *const u8 as *const Equipment; + unsafe { *p } + } +} + +impl flatbuffers::Push for Equipment { + type Output = Equipment; + #[inline] + fn push(&self, dst: &mut [u8], _rest: &[u8]) { + flatbuffers::emplace_scalar::<Equipment>(dst, *self); + } +} + +#[allow(non_camel_case_types)] +const ENUM_VALUES_EQUIPMENT:[Equipment; 2] = [ + Equipment::NONE, + Equipment::Weapon +]; + +#[allow(non_camel_case_types)] +const ENUM_NAMES_EQUIPMENT:[&'static str; 2] = [ + "NONE", + "Weapon" +]; + +pub fn enum_name_equipment(e: Equipment) -> &'static str { + let index: usize = e as usize; + ENUM_NAMES_EQUIPMENT[index] +} + +pub struct EquipmentUnionTableOffset {} +// struct Vec3, aligned to 4 +#[repr(C, align(4))] +#[derive(Clone, Copy, Debug, PartialEq)] +pub struct Vec3 { + x_: f32, + y_: f32, + z_: f32, +} // pub struct Vec3 +impl flatbuffers::SafeSliceAccess for Vec3 {} +impl<'a> flatbuffers::Follow<'a> for Vec3 { + type Inner = &'a Vec3; + #[inline] + fn follow(buf: &'a [u8], loc: usize) -> Self::Inner { + <&'a Vec3>::follow(buf, loc) + //flatbuffers::follow_cast_ref::<Vec3>(buf, loc) + } +} +impl<'a> flatbuffers::Follow<'a> for &'a Vec3 { + type Inner = &'a Vec3; + #[inline] + fn follow(buf: &'a [u8], loc: usize) -> Self::Inner { + flatbuffers::follow_cast_ref::<Vec3>(buf, loc) + } +} +impl<'b> flatbuffers::Push for Vec3 { + type Output = Vec3; + #[inline] + fn push(&self, dst: &mut [u8], _rest: &[u8]) { + let src = unsafe { + ::std::slice::from_raw_parts(self as *const Vec3 as *const u8, Self::size()) + }; + dst.copy_from_slice(src); + } +} +impl<'b> flatbuffers::Push for &'b Vec3 { + type Output = Vec3; + + #[inline] + fn push(&self, dst: &mut [u8], _rest: &[u8]) { + let src = unsafe { + ::std::slice::from_raw_parts(*self as *const Vec3 as *const u8, Self::size()) + }; + dst.copy_from_slice(src); + } +} + + +impl Vec3 { + pub fn new<'a>(_x: f32, _y: f32, _z: f32) -> Self { + Vec3 { + x_: _x.to_little_endian(), + y_: _y.to_little_endian(), + z_: _z.to_little_endian(), + + } + } + pub fn x<'a>(&'a self) -> f32 { + self.x_.from_little_endian() + } + pub fn y<'a>(&'a self) -> f32 { + self.y_.from_little_endian() + } + pub fn z<'a>(&'a self) -> f32 { + self.z_.from_little_endian() + } +} + +pub enum MonsterOffset {} +#[derive(Copy, Clone, Debug, PartialEq)] + +pub struct Monster<'a> { + pub _tab: flatbuffers::Table<'a>, +} + +impl<'a> flatbuffers::Follow<'a> for Monster<'a> { + type Inner = Monster<'a>; + #[inline] + fn follow(buf: &'a [u8], loc: usize) -> Self::Inner { + Self { + _tab: flatbuffers::Table { buf: buf, loc: loc }, + } + } +} + +impl<'a> Monster<'a> { + #[inline] + pub fn init_from_table(table: flatbuffers::Table<'a>) -> Self { + Monster { + _tab: table, + } + } + #[allow(unused_mut)] + pub fn create<'bldr: 'args, 'args: 'mut_bldr, 'mut_bldr>( + _fbb: &'mut_bldr mut flatbuffers::FlatBufferBuilder<'bldr>, + args: &'args MonsterArgs<'args>) -> flatbuffers::WIPOffset<Monster<'bldr>> { + let mut builder = MonsterBuilder::new(_fbb); + if let Some(x) = args.equipped { builder.add_equipped(x); } + if let Some(x) = args.weapons { builder.add_weapons(x); } + if let Some(x) = args.inventory { builder.add_inventory(x); } + if let Some(x) = args.name { builder.add_name(x); } + if let Some(x) = args.pos { builder.add_pos(x); } + builder.add_hp(args.hp); + builder.add_mana(args.mana); + builder.add_equipped_type(args.equipped_type); + builder.add_color(args.color); + builder.finish() + } + + pub const VT_POS: flatbuffers::VOffsetT = 4; + pub const VT_MANA: flatbuffers::VOffsetT = 6; + pub const VT_HP: flatbuffers::VOffsetT = 8; + pub const VT_NAME: flatbuffers::VOffsetT = 10; + pub const VT_INVENTORY: flatbuffers::VOffsetT = 14; + pub const VT_COLOR: flatbuffers::VOffsetT = 16; + pub const VT_WEAPONS: flatbuffers::VOffsetT = 18; + pub const VT_EQUIPPED_TYPE: flatbuffers::VOffsetT = 20; + pub const VT_EQUIPPED: flatbuffers::VOffsetT = 22; + + #[inline] + pub fn pos(&'a self) -> Option<&'a Vec3> { + self._tab.get::<Vec3>(Monster::VT_POS, None) + } + #[inline] + pub fn mana(&'a self) -> i16 { + self._tab.get::<i16>(Monster::VT_MANA, Some(150)).unwrap() + } + #[inline] + pub fn hp(&'a self) -> i16 { + self._tab.get::<i16>(Monster::VT_HP, Some(100)).unwrap() + } + #[inline] + pub fn name(&'a self) -> Option<&'a str> { + self._tab.get::<flatbuffers::ForwardsUOffset<&str>>(Monster::VT_NAME, None) + } + #[inline] + pub fn inventory(&'a self) -> Option<&'a [u8]> { + self._tab.get::<flatbuffers::ForwardsUOffset<flatbuffers::Vector<'a, u8>>>(Monster::VT_INVENTORY, None).map(|v| v.safe_slice()) + } + #[inline] + pub fn color(&'a self) -> Color { + self._tab.get::<Color>(Monster::VT_COLOR, Some(Color::Blue)).unwrap() + } + #[inline] + pub fn weapons(&'a self) -> Option<flatbuffers::Vector<flatbuffers::ForwardsUOffset<Weapon<'a>>>> { + self._tab.get::<flatbuffers::ForwardsUOffset<flatbuffers::Vector<flatbuffers::ForwardsUOffset<Weapon<'a>>>>>(Monster::VT_WEAPONS, None) + } + #[inline] + pub fn equipped_type(&'a self) -> Equipment { + self._tab.get::<Equipment>(Monster::VT_EQUIPPED_TYPE, Some(Equipment::NONE)).unwrap() + } + #[inline] + pub fn equipped(&'a self) -> Option<flatbuffers::Table<'a>> { + self._tab.get::<flatbuffers::ForwardsUOffset<flatbuffers::Table<'a>>>(Monster::VT_EQUIPPED, None) + } + #[inline] + #[allow(non_snake_case)] + pub fn equipped_as_weapon(&'a self) -> Option<Weapon> { + if self.equipped_type() == Equipment::Weapon { + self.equipped().map(|u| Weapon::init_from_table(u)) + } else { + None + } + } + +} + +pub struct MonsterArgs<'a> { + pub pos: Option<&'a Vec3>, + pub mana: i16, + pub hp: i16, + pub name: Option<flatbuffers::WIPOffset<&'a str>>, + pub inventory: Option<flatbuffers::WIPOffset<flatbuffers::Vector<'a , u8>>>, + pub color: Color, + pub weapons: Option<flatbuffers::WIPOffset<flatbuffers::Vector<'a , flatbuffers::ForwardsUOffset<Weapon<'a >>>>>, + pub equipped_type: Equipment, + pub equipped: Option<flatbuffers::WIPOffset<flatbuffers::UnionWIPOffset>>, +} +impl<'a> Default for MonsterArgs<'a> { + #[inline] + fn default() -> Self { + MonsterArgs { + pos: None, + mana: 150, + hp: 100, + name: None, + inventory: None, + color: Color::Blue, + weapons: None, + equipped_type: Equipment::NONE, + equipped: None, + } + } +} +pub struct MonsterBuilder<'a: 'b, 'b> { + fbb_: &'b mut flatbuffers::FlatBufferBuilder<'a>, + start_: flatbuffers::WIPOffset<flatbuffers::TableUnfinishedWIPOffset>, +} +impl<'a: 'b, 'b> MonsterBuilder<'a, 'b> { + #[inline] + pub fn add_pos(&mut self, pos: &'b Vec3) { + self.fbb_.push_slot_always::<&Vec3>(Monster::VT_POS, pos); + } + #[inline] + pub fn add_mana(&mut self, mana: i16) { + self.fbb_.push_slot::<i16>(Monster::VT_MANA, mana, 150); + } + #[inline] + pub fn add_hp(&mut self, hp: i16) { + self.fbb_.push_slot::<i16>(Monster::VT_HP, hp, 100); + } + #[inline] + pub fn add_name(&mut self, name: flatbuffers::WIPOffset<&'b str>) { + self.fbb_.push_slot_always::<flatbuffers::WIPOffset<_>>(Monster::VT_NAME, name); + } + #[inline] + pub fn add_inventory(&mut self, inventory: flatbuffers::WIPOffset<flatbuffers::Vector<'b , u8>>) { + self.fbb_.push_slot_always::<flatbuffers::WIPOffset<_>>(Monster::VT_INVENTORY, inventory); + } + #[inline] + pub fn add_color(&mut self, color: Color) { + self.fbb_.push_slot::<Color>(Monster::VT_COLOR, color, Color::Blue); + } + #[inline] + pub fn add_weapons(&mut self, weapons: flatbuffers::WIPOffset<flatbuffers::Vector<'b , flatbuffers::ForwardsUOffset<Weapon<'b >>>>) { + self.fbb_.push_slot_always::<flatbuffers::WIPOffset<_>>(Monster::VT_WEAPONS, weapons); + } + #[inline] + pub fn add_equipped_type(&mut self, equipped_type: Equipment) { + self.fbb_.push_slot::<Equipment>(Monster::VT_EQUIPPED_TYPE, equipped_type, Equipment::NONE); + } + #[inline] + pub fn add_equipped(&mut self, equipped: flatbuffers::WIPOffset<flatbuffers::UnionWIPOffset>) { + self.fbb_.push_slot_always::<flatbuffers::WIPOffset<_>>(Monster::VT_EQUIPPED, equipped); + } + #[inline] + pub fn new(_fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>) -> MonsterBuilder<'a, 'b> { + let start = _fbb.start_table(); + MonsterBuilder { + fbb_: _fbb, + start_: start, + } + } + #[inline] + pub fn finish(self) -> flatbuffers::WIPOffset<Monster<'a>> { + let o = self.fbb_.end_table(self.start_); + flatbuffers::WIPOffset::new(o.value()) + } +} + +pub enum WeaponOffset {} +#[derive(Copy, Clone, Debug, PartialEq)] + +pub struct Weapon<'a> { + pub _tab: flatbuffers::Table<'a>, +} + +impl<'a> flatbuffers::Follow<'a> for Weapon<'a> { + type Inner = Weapon<'a>; + #[inline] + fn follow(buf: &'a [u8], loc: usize) -> Self::Inner { + Self { + _tab: flatbuffers::Table { buf: buf, loc: loc }, + } + } +} + +impl<'a> Weapon<'a> { + #[inline] + pub fn init_from_table(table: flatbuffers::Table<'a>) -> Self { + Weapon { + _tab: table, + } + } + #[allow(unused_mut)] + pub fn create<'bldr: 'args, 'args: 'mut_bldr, 'mut_bldr>( + _fbb: &'mut_bldr mut flatbuffers::FlatBufferBuilder<'bldr>, + args: &'args WeaponArgs<'args>) -> flatbuffers::WIPOffset<Weapon<'bldr>> { + let mut builder = WeaponBuilder::new(_fbb); + if let Some(x) = args.name { builder.add_name(x); } + builder.add_damage(args.damage); + builder.finish() + } + + pub const VT_NAME: flatbuffers::VOffsetT = 4; + pub const VT_DAMAGE: flatbuffers::VOffsetT = 6; + + #[inline] + pub fn name(&'a self) -> Option<&'a str> { + self._tab.get::<flatbuffers::ForwardsUOffset<&str>>(Weapon::VT_NAME, None) + } + #[inline] + pub fn damage(&'a self) -> i16 { + self._tab.get::<i16>(Weapon::VT_DAMAGE, Some(0)).unwrap() + } +} + +pub struct WeaponArgs<'a> { + pub name: Option<flatbuffers::WIPOffset<&'a str>>, + pub damage: i16, +} +impl<'a> Default for WeaponArgs<'a> { + #[inline] + fn default() -> Self { + WeaponArgs { + name: None, + damage: 0, + } + } +} +pub struct WeaponBuilder<'a: 'b, 'b> { + fbb_: &'b mut flatbuffers::FlatBufferBuilder<'a>, + start_: flatbuffers::WIPOffset<flatbuffers::TableUnfinishedWIPOffset>, +} +impl<'a: 'b, 'b> WeaponBuilder<'a, 'b> { + #[inline] + pub fn add_name(&mut self, name: flatbuffers::WIPOffset<&'b str>) { + self.fbb_.push_slot_always::<flatbuffers::WIPOffset<_>>(Weapon::VT_NAME, name); + } + #[inline] + pub fn add_damage(&mut self, damage: i16) { + self.fbb_.push_slot::<i16>(Weapon::VT_DAMAGE, damage, 0); + } + #[inline] + pub fn new(_fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>) -> WeaponBuilder<'a, 'b> { + let start = _fbb.start_table(); + WeaponBuilder { + fbb_: _fbb, + start_: start, + } + } + #[inline] + pub fn finish(self) -> flatbuffers::WIPOffset<Weapon<'a>> { + let o = self.fbb_.end_table(self.start_); + flatbuffers::WIPOffset::new(o.value()) + } +} + +#[inline] +pub fn get_root_as_monster<'a>(buf: &'a [u8]) -> Monster<'a> { + flatbuffers::get_root::<Monster<'a>>(buf) +} + +#[inline] +pub fn get_size_prefixed_root_as_monster<'a>(buf: &'a [u8]) -> Monster<'a> { + flatbuffers::get_size_prefixed_root::<Monster<'a>>(buf) +} + +#[inline] +pub fn finish_monster_buffer<'a, 'b>( + fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>, + root: flatbuffers::WIPOffset<Monster<'a>>) { + fbb.finish(root, None); +} + +#[inline] +pub fn finish_size_prefixed_monster_buffer<'a, 'b>(fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>, root: flatbuffers::WIPOffset<Monster<'a>>) { + fbb.finish_size_prefixed(root, None); +} +} // pub mod Sample +} // pub mod MyGame + diff --git a/chromium/third_party/flatbuffers/src/samples/sample_bfbs.cpp b/chromium/third_party/flatbuffers/src/samples/sample_bfbs.cpp new file mode 100644 index 00000000000..9512e242cf5 --- /dev/null +++ b/chromium/third_party/flatbuffers/src/samples/sample_bfbs.cpp @@ -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"); +} diff --git a/chromium/third_party/flatbuffers/src/samples/sample_binary.rs b/chromium/third_party/flatbuffers/src/samples/sample_binary.rs new file mode 100644 index 00000000000..7a4c2ae0c7a --- /dev/null +++ b/chromium/third_party/flatbuffers/src/samples/sample_binary.rs @@ -0,0 +1,155 @@ +/* + * 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. + */ + +// import the flatbuffers runtime library +extern crate flatbuffers; + +// import the generated code +#[path = "./monster_generated.rs"] +mod monster_generated; +pub use monster_generated::my_game::sample::{get_root_as_monster, + Color, Equipment, + Monster, MonsterArgs, + Vec3, + Weapon, WeaponArgs}; + + +// Example how to use FlatBuffers to create and read binary buffers. + +fn main() { + // Build up a serialized buffer algorithmically. + // Initialize it with a capacity of 1024 bytes. + let mut builder = flatbuffers::FlatBufferBuilder::new_with_capacity(1024); + + // Serialize some weapons for the Monster: A 'sword' and an 'axe'. + let weapon_one_name = builder.create_string("Sword"); + let weapon_two_name = builder.create_string("Axe"); + + // Use the `Weapon::create` shortcut to create Weapons with named field + // arguments. + let sword = Weapon::create(&mut builder, &WeaponArgs{ + name: Some(weapon_one_name), + damage: 3, + }); + let axe = Weapon::create(&mut builder, &WeaponArgs{ + name: Some(weapon_two_name), + damage: 5, + }); + + // Name of the Monster. + let name = builder.create_string("Orc"); + + // Inventory. + let inventory = builder.create_vector(&[0u8, 1, 2, 3, 4, 5, 6, 7, 8, 9]); + + // Create a FlatBuffer `vector` that contains offsets to the sword and axe + // we created above. + let weapons = builder.create_vector(&[sword, axe]); + + // Create the path vector of Vec3 objects: + //let x = Vec3::new(1.0, 2.0, 3.0); + //let y = Vec3::new(4.0, 5.0, 6.0); + //let path = builder.create_vector(&[x, y]); + + // Note that, for convenience, it is also valid to create a vector of + // references to structs, like this: + // let path = builder.create_vector(&[&x, &y]); + + // 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. + let orc = Monster::create(&mut builder, &MonsterArgs{ + pos: Some(&Vec3::new(1.0f32, 2.0f32, 3.0f32)), + mana: 150, + hp: 80, + name: Some(name), + inventory: Some(inventory), + color: Color::Red, + weapons: Some(weapons), + equipped_type: Equipment::Weapon, + equipped: Some(axe.as_union_value()), + //path: Some(path), + ..Default::default() + }); + + // Serialize the root of the object, without providing a file identifier. + builder.finish(orc, None); + + // We now have a FlatBuffer we can store on disk or send over a network. + + // ** file/network code goes here :) ** + + // Instead, we're going to access it right away (as if we just received it). + // This must be called after `finish()`. + let buf = builder.finished_data(); // Of type `&[u8]` + + // Get access to the root: + let monster = get_root_as_monster(buf); + + // Get and test some scalar types from the FlatBuffer. + let hp = monster.hp(); + let mana = monster.mana(); + let name = monster.name(); + + assert_eq!(hp, 80); + assert_eq!(mana, 150); // default + assert_eq!(name, Some("Orc")); + + // Get and test a field of the FlatBuffer's `struct`. + assert!(monster.pos().is_some()); + let pos = monster.pos().unwrap(); + let x = pos.x(); + let y = pos.y(); + let z = pos.z(); + assert_eq!(x, 1.0f32); + assert_eq!(y, 2.0f32); + assert_eq!(z, 3.0f32); + + // Get an element from the `inventory` FlatBuffer's `vector`. + assert!(monster.inventory().is_some()); + let inv = monster.inventory().unwrap(); + + // Note that this vector is returned as a slice, because direct access for + // this type, a u8 vector, is safe on all platforms: + let third_item = inv[2]; + assert_eq!(third_item, 2); + + // Get and test the `weapons` FlatBuffers's `vector`. + assert!(monster.weapons().is_some()); + let weps = monster.weapons().unwrap(); + //let weps_len = weps.len(); + let wep2 = weps.get(1); + let second_weapon_name = wep2.name(); + let second_weapon_damage = wep2.damage(); + assert_eq!(second_weapon_name, Some("Axe")); + assert_eq!(second_weapon_damage, 5); + + // Get and test the `Equipment` union (`equipped` field). + assert_eq!(monster.equipped_type(), Equipment::Weapon); + let equipped = monster.equipped_as_weapon().unwrap(); + let weapon_name = equipped.name(); + let weapon_damage = equipped.damage(); + assert_eq!(weapon_name, Some("Axe")); + assert_eq!(weapon_damage, 5); + + // Get and test the `path` FlatBuffers's `vector`. + //assert_eq!(monster.path().unwrap().len(), 2); + //assert_eq!(monster.path().unwrap()[0].x(), 1.0); + //assert_eq!(monster.path().unwrap()[1].x(), 4.0); + + println!("The FlatBuffer was successfully created and accessed!"); +} diff --git a/chromium/third_party/flatbuffers/src/src/code_generators.cpp b/chromium/third_party/flatbuffers/src/src/code_generators.cpp index 2ecd5e3a7e0..3b10db7f50f 100644 --- a/chromium/third_party/flatbuffers/src/src/code_generators.cpp +++ b/chromium/third_party/flatbuffers/src/src/code_generators.cpp @@ -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) diff --git a/chromium/third_party/flatbuffers/src/src/flatc.cpp b/chromium/third_party/flatbuffers/src/src/flatc.cpp index bcd5c3bff4d..c5ec70ecf8a 100644 --- a/chromium/third_party/flatbuffers/src/src/flatc.cpp +++ b/chromium/third_party/flatbuffers/src/src/flatc.cpp @@ -18,7 +18,7 @@ #include <list> -#define FLATC_VERSION "1.9.0 (" __DATE__ " " __TIME__ ")" +#define FLATC_VERSION "1.10.0" namespace flatbuffers { @@ -36,6 +36,15 @@ void FlatCompiler::ParseFile( 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); } @@ -88,45 +97,53 @@ std::string FlatCompiler::GetUsageString(const char *program_name) const { " --gen-onefile Generate single output file for C# and Go.\n" " --gen-name-strings Generate type name functions for C++.\n" " --gen-object-api Generate an additional object-based API.\n" - " --cpp-ptr-type T Set object API pointer type (default std::unique_ptr)\n" - " --cpp-str-type T Set object API string type (default std::string)\n" - " T::c_str() and T::length() must be supported\n" + " --gen-compare Generate operator== for object-based API types.\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() and T::length() must be supported.\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"; @@ -222,6 +239,8 @@ int FlatCompiler::Compile(int argc, const char **argv) { opts.generate_name_strings = true; } else if (arg == "--gen-object-api") { opts.generate_object_based_api = true; + } else if (arg == "--gen-compare") { + opts.gen_compare = true; } else if (arg == "--cpp-ptr-type") { if (++argi >= argc) Error("missing type following" + arg, true); opts.cpp_object_api_pointer_type = argv[argi]; @@ -230,6 +249,8 @@ int FlatCompiler::Compile(int argc, const char **argv) { opts.cpp_object_api_string_type = argv[argi]; } 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]; @@ -273,6 +294,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") { @@ -317,8 +340,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)); @@ -334,6 +363,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( @@ -360,7 +390,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) { @@ -369,15 +399,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); } @@ -395,7 +429,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 ") + diff --git a/chromium/third_party/flatbuffers/src/src/flatc_main.cpp b/chromium/third_party/flatbuffers/src/src/flatc_main.cpp index 2a3bc98083d..78e66a6f637 100644 --- a/chromium/third_party/flatbuffers/src/src/flatc_main.cpp +++ b/chromium/third_party/flatbuffers/src/src/flatc_main.cpp @@ -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 }, @@ -79,6 +79,10 @@ int main(int argc, const char *argv[]) { flatbuffers::IDLOptions::kLua, "Generate Lua files for tables/structs", flatbuffers::GeneralMakeRule }, + { flatbuffers::GenerateRust, "-r", "--rust", "Rust", true, nullptr, + flatbuffers::IDLOptions::kRust, + "Generate Rust files for tables/structs", + flatbuffers::RustMakeRule }, { flatbuffers::GeneratePhp, nullptr, "--php", "PHP", true, nullptr, flatbuffers::IDLOptions::kPhp, "Generate PHP files for tables/structs", flatbuffers::GeneralMakeRule }, diff --git a/chromium/third_party/flatbuffers/src/src/idl_gen_cpp.cpp b/chromium/third_party/flatbuffers/src/src/idl_gen_cpp.cpp index df4c0ad925d..a25dd6f942b 100644 --- a/chromium/third_party/flatbuffers/src/src/idl_gen_cpp.cpp +++ b/chromium/third_party/flatbuffers/src/src/idl_gen_cpp.cpp @@ -39,7 +39,10 @@ class CppGenerator : public BaseGenerator { CppGenerator(const Parser &parser, const std::string &path, const std::string &file_name) : BaseGenerator(parser, path, file_name, "", "::"), - cur_name_space_(nullptr) { + cur_name_space_(nullptr), + float_const_gen_("std::numeric_limits<double>::", + "std::numeric_limits<float>::", "quiet_NaN()", + "infinity()") { static const char * const keywords[] = { "alignas", "alignof", @@ -145,7 +148,7 @@ class CppGenerator : public BaseGenerator { std::string guard = file_name_; // Remove any non-alpha-numeric characters that may appear in a filename. struct IsAlnum { - bool operator()(char c) const { return !isalnum(c); } + bool operator()(char c) const { return !is_alnum(c); } }; guard.erase(std::remove_if(guard.begin(), guard.end(), IsAlnum()), guard.end()); @@ -226,14 +229,30 @@ class CppGenerator : public BaseGenerator { if (!struct_def.generated) { SetNameSpace(struct_def.defined_namespace); code_ += "struct " + Name(struct_def) + ";"; - if (parser_.opts.generate_object_based_api && !struct_def.fixed) { - code_ += "struct " + - NativeName(Name(struct_def), &struct_def, parser_.opts) + - ";"; + if (parser_.opts.generate_object_based_api) { + auto nativeName = NativeName(Name(struct_def), &struct_def, parser_.opts); + if (!struct_def.fixed) { + code_ += "struct " + nativeName + ";"; + } } code_ += ""; } } + + // Generate forward declarations for all equal operators + if (parser_.opts.generate_object_based_api && parser_.opts.gen_compare) { + for (auto it = parser_.structs_.vec.begin(); + it != parser_.structs_.vec.end(); ++it) { + const auto &struct_def = **it; + if (!struct_def.generated) { + SetNameSpace(struct_def.defined_namespace); + auto nativeName = NativeName(Name(struct_def), &struct_def, parser_.opts); + code_ += "bool operator==(const " + nativeName + " &lhs, const " + nativeName + " &rhs);"; + } + } + code_ += ""; + } + // Generate preablmle code for mini reflection. if (parser_.opts.mini_reflect != IDLOptions::kNone) { // To break cyclic dependencies, first pre-declare all tables/structs. @@ -477,7 +496,8 @@ class CppGenerator : public BaseGenerator { std::string GenTypeBasic(const Type &type, bool user_facing_type) const { static const char * const ctypename[] = { // clang-format off - #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \ + #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, \ + RTYPE) \ #CTYPE, FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD) #undef FLATBUFFERS_TD @@ -561,7 +581,8 @@ class CppGenerator : public BaseGenerator { bool is_constructor) { auto &ptr_type = PtrType(field); if (ptr_type != "naked") { - return ptr_type + "<" + type + ">"; + return (ptr_type != "default_ptr_type" ? ptr_type : + parser_.opts.cpp_object_api_pointer_type) + "<" + type + ">"; } else if (is_constructor) { return ""; } else { @@ -845,7 +866,7 @@ class CppGenerator : public BaseGenerator { code_ += " };"; } if (!vs.empty()) { - code_ += " static const int32_t values[] = { {{VALUES}} };"; + code_ += " static const int64_t values[] = { {{VALUES}} };"; } auto has_names = num_fields && parser_.opts.mini_reflect == IDLOptions::kTypesAndNames; @@ -973,6 +994,10 @@ class CppGenerator : public BaseGenerator { code_ += "inline const char *EnumName{{ENUM_NAME}}({{ENUM_NAME}} e) {"; + code_ += " if (e < " + GetEnumValUse(enum_def, *enum_def.vals.vec.front()) + + " || e > " + GetEnumValUse(enum_def, *enum_def.vals.vec.back()) + + ") return \"\";"; + code_ += " const size_t index = static_cast<int>(e)\\"; if (enum_def.vals.vec.front()->value) { auto vals = GetEnumValUse(enum_def, *enum_def.vals.vec.front()); @@ -1003,7 +1028,7 @@ class CppGenerator : public BaseGenerator { } // Generate type traits for unions to map from a type to union enum value. - if (enum_def.is_union && !enum_def.uses_type_aliases) { + if (enum_def.is_union && !enum_def.uses_multiple_type_instances) { for (auto it = enum_def.vals.vec.begin(); it != enum_def.vals.vec.end(); ++it) { const auto &ev = **it; @@ -1052,7 +1077,7 @@ class CppGenerator : public BaseGenerator { code_ += ""; code_ += " void Reset();"; code_ += ""; - if (!enum_def.uses_type_aliases) { + if (!enum_def.uses_multiple_type_instances) { code_ += "#ifndef FLATBUFFERS_CPP98_STL"; code_ += " template <typename T>"; code_ += " void Set(T&& val) {"; @@ -1095,6 +1120,38 @@ class CppGenerator : public BaseGenerator { } code_ += "};"; code_ += ""; + + if (parser_.opts.gen_compare) { + code_ += ""; + code_ += "inline bool operator==(const {{NAME}}Union &lhs, const {{NAME}}Union &rhs) {"; + code_ += " if (lhs.type != rhs.type) return false;"; + code_ += " switch (lhs.type) {"; + + for (auto it = enum_def.vals.vec.begin(); it != enum_def.vals.vec.end(); + ++it) { + const auto &ev = **it; + code_.SetValue("NATIVE_ID", GetEnumValUse(enum_def, ev)); + if (ev.value) { + const auto native_type = + NativeName(GetUnionElement(ev, true, true, true), + ev.union_type.struct_def, parser_.opts); + code_.SetValue("NATIVE_TYPE", native_type); + code_ += " case {{NATIVE_ID}}: {"; + code_ += " return *(reinterpret_cast<const {{NATIVE_TYPE}} *>(lhs.value)) =="; + code_ += " *(reinterpret_cast<const {{NATIVE_TYPE}} *>(rhs.value));"; + code_ += " }"; + } else { + code_ += " case {{NATIVE_ID}}: {"; + code_ += " return true;"; // "NONE" enum value. + code_ += " }"; + } + } + code_ += " default: {"; + code_ += " return false;"; + code_ += " }"; + code_ += " }"; + code_ += "}"; + } } if (enum_def.is_union) { @@ -1250,7 +1307,8 @@ class CppGenerator : public BaseGenerator { for (auto fit = ev.union_type.struct_def->fields.vec.begin(); fit != ev.union_type.struct_def->fields.vec.end(); ++fit) { const auto &field = **fit; - if (!field.deprecated && field.value.type.struct_def) { + if (!field.deprecated && field.value.type.struct_def && + !field.native_inline) { copyable = false; break; } @@ -1337,9 +1395,10 @@ class CppGenerator : public BaseGenerator { } std::string GenDefaultConstant(const FieldDef &field) { - return field.value.type.base_type == BASE_TYPE_FLOAT - ? field.value.constant + "f" - : field.value.constant; + if(IsFloat(field.value.type.base_type)) + return float_const_gen_.GenFloatConstant(field); + else + return field.value.constant; } std::string GetDefaultScalarValue(const FieldDef &field, bool is_ctor) { @@ -1455,6 +1514,44 @@ class CppGenerator : public BaseGenerator { code_ += " }"; } + void GenCompareOperator(const StructDef &struct_def, std::string accessSuffix = "") { + std::string compare_op; + for (auto it = struct_def.fields.vec.begin(); + it != struct_def.fields.vec.end(); ++it) { + const auto &field = **it; + if (!field.deprecated && // Deprecated fields won't be accessible. + field.value.type.base_type != BASE_TYPE_UTYPE && + (field.value.type.base_type != BASE_TYPE_VECTOR || + field.value.type.element != BASE_TYPE_UTYPE)) { + if (!compare_op.empty()) { + compare_op += " &&\n "; + } + auto accessor = Name(field) + accessSuffix; + compare_op += "(lhs." + accessor + " == rhs." + accessor + ")"; + } + } + + std::string cmp_lhs; + std::string cmp_rhs; + if (compare_op.empty()) { + cmp_lhs = ""; + cmp_rhs = ""; + compare_op = " return true;"; + } else { + cmp_lhs = "lhs"; + cmp_rhs = "rhs"; + compare_op = " return\n " + compare_op + ";"; + } + + code_.SetValue("CMP_OP", compare_op); + code_.SetValue("CMP_LHS", cmp_lhs); + code_.SetValue("CMP_RHS", cmp_rhs); + code_ += ""; + code_ += "inline bool operator==(const {{NATIVE_NAME}} &{{CMP_LHS}}, const {{NATIVE_NAME}} &{{CMP_RHS}}) {"; + code_ += "{{CMP_OP}}"; + code_ += "}"; + } + void GenOperatorNewDelete(const StructDef &struct_def) { if (auto native_custom_alloc = struct_def.attributes.Lookup("native_custom_alloc")) { @@ -1487,6 +1584,7 @@ class CppGenerator : public BaseGenerator { GenOperatorNewDelete(struct_def); GenDefaultConstructor(struct_def); code_ += "};"; + if (parser_.opts.gen_compare) GenCompareOperator(struct_def); code_ += ""; } @@ -1616,7 +1714,7 @@ class CppGenerator : public BaseGenerator { // We need to add a trailing comma to all elements except the last one as // older versions of gcc complain about this. code_.SetValue("SEP", ""); - code_ += " enum {"; + code_ += " enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE {"; for (auto it = struct_def.fields.vec.begin(); it != struct_def.fields.vec.end(); ++it) { const auto &field = **it; @@ -1679,9 +1777,10 @@ class CppGenerator : public BaseGenerator { if (field.value.type.base_type == BASE_TYPE_UNION) { auto u = field.value.type.enum_def; - code_ += - " template<typename T> " - "const T *{{NULLABLE_EXT}}{{FIELD_NAME}}_as() const;"; + if (!field.value.type.enum_def->uses_multiple_type_instances) + code_ += + " template<typename T> " + "const T *{{NULLABLE_EXT}}{{FIELD_NAME}}_as() const;"; for (auto u_it = u->vals.vec.begin(); u_it != u->vals.vec.end(); ++u_it) { @@ -1812,7 +1911,7 @@ class CppGenerator : public BaseGenerator { } auto u = field.value.type.enum_def; - if (u->uses_type_aliases) continue; + if (u->uses_multiple_type_instances) continue; code_.SetValue("FIELD_NAME", Name(field)); @@ -1965,36 +2064,35 @@ class CppGenerator : public BaseGenerator { // Generate a CreateXDirect function with vector types as parameters if (has_string_or_vector_fields) { - code_ += - "inline flatbuffers::Offset<{{STRUCT_NAME}}> " - "Create{{STRUCT_NAME}}Direct("; + code_ += "inline flatbuffers::Offset<{{STRUCT_NAME}}> " + "Create{{STRUCT_NAME}}Direct("; code_ += " flatbuffers::FlatBufferBuilder &_fbb\\"; for (auto it = struct_def.fields.vec.begin(); it != struct_def.fields.vec.end(); ++it) { const auto &field = **it; if (!field.deprecated) { GenParam(field, true, ",\n "); } } - // Need to call "Create" with the struct namespace. const auto qualified_create_name = struct_def.defined_namespace->GetFullyQualifiedName("Create"); code_.SetValue("CREATE_NAME", TranslateNameSpace(qualified_create_name)); - code_ += ") {"; - code_ += " return {{CREATE_NAME}}{{STRUCT_NAME}}("; - code_ += " _fbb\\"; for (auto it = struct_def.fields.vec.begin(); it != struct_def.fields.vec.end(); ++it) { const auto &field = **it; if (!field.deprecated) { code_.SetValue("FIELD_NAME", Name(field)); - if (field.value.type.base_type == BASE_TYPE_STRING) { + if (!field.shared) { + code_.SetValue("CREATE_STRING", "CreateString"); + } else { + code_.SetValue("CREATE_STRING", "CreateSharedString"); + } code_ += - ",\n {{FIELD_NAME}} ? " - "_fbb.CreateString({{FIELD_NAME}}) : 0\\"; + " auto {{FIELD_NAME}}__ = {{FIELD_NAME}} ? " + "_fbb.{{CREATE_STRING}}({{FIELD_NAME}}) : 0;"; } else if (field.value.type.base_type == BASE_TYPE_VECTOR) { - code_ += ",\n {{FIELD_NAME}} ? \\"; + code_ += " auto {{FIELD_NAME}}__ = {{FIELD_NAME}} ? \\"; const auto vtype = field.value.type.VectorType(); if (IsStruct(vtype)) { const auto type = WrapInNameSpace(*vtype.struct_def); @@ -2003,9 +2101,21 @@ class CppGenerator : public BaseGenerator { const auto type = GenTypeWire(vtype, "", false); code_ += "_fbb.CreateVector<" + type + ">\\"; } - code_ += "(*{{FIELD_NAME}}) : 0\\"; - } else { - code_ += ",\n {{FIELD_NAME}}\\"; + code_ += "(*{{FIELD_NAME}}) : 0;"; + } + } + } + code_ += " return {{CREATE_NAME}}{{STRUCT_NAME}}("; + code_ += " _fbb\\"; + for (auto it = struct_def.fields.vec.begin(); + it != struct_def.fields.vec.end(); ++it) { + const auto &field = **it; + if (!field.deprecated) { + code_.SetValue("FIELD_NAME", Name(field)); + code_ += ",\n {{FIELD_NAME}}\\"; + if (field.value.type.base_type == BASE_TYPE_STRING || + field.value.type.base_type == BASE_TYPE_VECTOR) { + code_ += "__\\"; } } } @@ -2059,7 +2169,7 @@ class CppGenerator : public BaseGenerator { break; } } - }; + } std::string GenUnpackFieldStatement(const FieldDef &field, const FieldDef *union_field) { @@ -2069,9 +2179,11 @@ class CppGenerator : public BaseGenerator { auto cpp_type = field.attributes.Lookup("cpp_type"); std::string indexing; if (field.value.type.enum_def) { - indexing += "(" + WrapInNameSpace(*field.value.type.enum_def) + ")"; + indexing += "static_cast<" + + WrapInNameSpace(*field.value.type.enum_def) + ">("; } indexing += "_e->Get(_i)"; + if (field.value.type.enum_def) { indexing += ")"; } if (field.value.type.element == BASE_TYPE_BOOL) { indexing += " != 0"; } // Generate code that pushes data from _e to _o in the form: @@ -2187,8 +2299,16 @@ class CppGenerator : public BaseGenerator { switch (field.value.type.base_type) { // String fields are of the form: // _fbb.CreateString(_o->field) + // or + // _fbb.CreateSharedString(_o->field) case BASE_TYPE_STRING: { - code += "_fbb.CreateString(" + value + ")"; + if (!field.shared) { + code += "_fbb.CreateString("; + } else { + code += "_fbb.CreateSharedString("; + } + code += value; + code.push_back(')'); // For optional fields, check to see if there actually is any data // in _o->field before attempting to access it. If there isn't, @@ -2266,8 +2386,9 @@ class CppGenerator : public BaseGenerator { // the underlying storage type (eg. uint8_t). const auto basetype = GenTypeBasic( field.value.type.enum_def->underlying_type, false); - code += "_fbb.CreateVector((const " + basetype + "*)" + value + - ".data(), " + value + ".size())"; + code += "_fbb.CreateVectorScalarCast<" + basetype + + ">(flatbuffers::data(" + value + "), " + value + + ".size())"; } else if (field.attributes.Lookup("cpp_type")) { auto type = GenTypeBasic(vector_type, false); code += "_fbb.CreateVector<" + type + ">(" + value + ".size(), "; @@ -2599,6 +2720,7 @@ class CppGenerator : public BaseGenerator { code_.SetValue("STRUCT_BYTE_SIZE", NumToString(struct_def.bytesize)); code_ += "FLATBUFFERS_STRUCT_END({{STRUCT_NAME}}, {{STRUCT_BYTE_SIZE}});"; + if (parser_.opts.gen_compare) GenCompareOperator(struct_def, "()"); code_ += ""; } @@ -2640,6 +2762,8 @@ class CppGenerator : public BaseGenerator { cur_name_space_ = ns; } + + const TypedFloatConstantGenerator float_const_gen_; }; } // namespace cpp diff --git a/chromium/third_party/flatbuffers/src/src/idl_gen_dart.cpp b/chromium/third_party/flatbuffers/src/src/idl_gen_dart.cpp index 8af1877df8a..fb7e0bdfee4 100644 --- a/chromium/third_party/flatbuffers/src/src/idl_gen_dart.cpp +++ b/chromium/third_party/flatbuffers/src/src/idl_gen_dart.cpp @@ -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() { diff --git a/chromium/third_party/flatbuffers/src/src/idl_gen_general.cpp b/chromium/third_party/flatbuffers/src/src/idl_gen_general.cpp index 27eb8c40562..bd06f9efd2d 100644 --- a/chromium/third_party/flatbuffers/src/src/idl_gen_general.cpp +++ b/chromium/third_party/flatbuffers/src/src/idl_gen_general.cpp @@ -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; @@ -247,7 +262,7 @@ class GeneralGenerator : public BaseGenerator { // clang-format off static const char * const java_typename[] = { #define FLATBUFFERS_TD(ENUM, IDLTYPE, \ - CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \ + CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE) \ #JTYPE, FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD) #undef FLATBUFFERS_TD @@ -255,7 +270,7 @@ class GeneralGenerator : public BaseGenerator { static const char * const csharp_typename[] = { #define FLATBUFFERS_TD(ENUM, IDLTYPE, \ - CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \ + CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE) \ #NTYPE, FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD) #undef FLATBUFFERS_TD @@ -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 { @@ -504,7 +525,16 @@ class GeneralGenerator : public BaseGenerator { // to map directly to how they're used in C/C++ and file formats. // That, and Java Enums are expensive, and not universally liked. GenComment(enum_def.doc_comment, code_ptr, &lang_.comment_config); - code += std::string("public ") + lang_.enum_decl + enum_def.name; + if (enum_def.attributes.Lookup("private")) { + // For Java, we leave the enum unmarked to indicate package-private + // For C# we mark the enum as internal + if (lang_.language == IDLOptions::kCSharp) { + code += "internal "; + } + } else { + code += "public "; + } + code += lang_.enum_decl + enum_def.name; if (lang_.language == IDLOptions::kCSharp) { code += lang_.inheritance_marker + GenTypeBasic(enum_def.underlying_type, false); @@ -773,7 +803,15 @@ class GeneralGenerator : public BaseGenerator { // int o = __offset(offset); return o != 0 ? bb.getType(o + i) : default; // } GenComment(struct_def.doc_comment, code_ptr, &lang_.comment_config); - code += "public "; + if (struct_def.attributes.Lookup("private")) { + // For Java, we leave the struct unmarked to indicate package-private + // For C# we mark the struct as internal + if (lang_.language == IDLOptions::kCSharp) { + code += "internal "; + } + } else { + code += "public "; + } if (lang_.language == IDLOptions::kCSharp && struct_def.attributes.Lookup("csharp_partial")) { // generate a partial class for this C# struct/table @@ -933,7 +971,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) { @@ -997,6 +1035,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 + " - bb_pos"; } else { code += index; } @@ -1096,12 +1136,21 @@ class GeneralGenerator : public BaseGenerator { code += "); }\n"; break; case IDLOptions::kCSharp: + code += "#if ENABLE_SPAN_T\n"; + code += " public Span<byte> Get"; + code += MakeCamel(field.name, lang_.first_camel_upper); + code += "Bytes() { return "; + code += lang_.accessor_prefix + "__vector_as_span("; + code += NumToString(field.value.offset); + code += "); }\n"; + code += "#else\n"; code += " public ArraySegment<byte>? Get"; code += MakeCamel(field.name, lang_.first_camel_upper); code += "Bytes() { return "; code += lang_.accessor_prefix + "__vector_as_arraysegment("; code += NumToString(field.value.offset); code += "); }\n"; + code += "#endif\n"; // For direct blockcopying the data into a typed array code += " public "; @@ -1246,7 +1295,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."; @@ -1306,7 +1355,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(); diff --git a/chromium/third_party/flatbuffers/src/src/idl_gen_go.cpp b/chromium/third_party/flatbuffers/src/src/idl_gen_go.cpp index c5767b479c0..4a40293609f 100644 --- a/chromium/third_party/flatbuffers/src/src/idl_gen_go.cpp +++ b/chromium/third_party/flatbuffers/src/src/idl_gen_go.cpp @@ -50,14 +50,6 @@ static const char * const g_golang_keywords[] = { "for", "import", "return", "var", }; -static std::string GenGetter(const Type &type); -static std::string GenMethod(const FieldDef &field); -static void GenStructBuilder(const StructDef &struct_def, - std::string *code_ptr); -static void GenReceiver(const StructDef &struct_def, std::string *code_ptr); -static std::string GenTypeBasic(const Type &type); -static std::string GenTypeGet(const Type &type); -static std::string TypeName(const FieldDef &field); static std::string GoIdentity(const std::string &name) { for (size_t i = 0; i < sizeof(g_golang_keywords) / sizeof(g_golang_keywords[0]); i++) { @@ -67,722 +59,737 @@ static std::string GoIdentity(const std::string &name) { return MakeCamel(name, false); } -// Most field accessors need to retrieve and test the field offset first, -// this is the prefix code for that. -std::string OffsetPrefix(const FieldDef &field) { - return "{\n\to := flatbuffers.UOffsetT(rcv._tab.Offset(" + - NumToString(field.value.offset) + "))\n\tif o != 0 {\n"; -} +class GoGenerator : public BaseGenerator { + public: + GoGenerator(const Parser &parser, const std::string &path, + const std::string &file_name, const std::string &go_namespace) + : BaseGenerator(parser, path, file_name, "" /* not used*/, + "" /* not used */), + cur_name_space_(nullptr) { + std::istringstream iss(go_namespace); + std::string component; + while (std::getline(iss, component, '.')) { + go_namespace_.components.push_back(component); + } + } -// Begin a class declaration. -static void BeginClass(const StructDef &struct_def, std::string *code_ptr) { - std::string &code = *code_ptr; + bool generate() { + std::string one_file_code; + for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end(); + ++it) { + tracked_imported_namespaces_.clear(); + std::string enumcode; + GenEnum(**it, &enumcode); + if (parser_.opts.one_file) { + one_file_code += enumcode; + } else { + if (!SaveType(**it, enumcode, false)) return false; + } + } - code += "type " + struct_def.name + " struct {\n\t"; + for (auto it = parser_.structs_.vec.begin(); + it != parser_.structs_.vec.end(); ++it) { + tracked_imported_namespaces_.clear(); + std::string declcode; + GenStruct(**it, &declcode); + if (parser_.opts.one_file) { + one_file_code += declcode; + } else { + if (!SaveType(**it, declcode, true)) return false; + } + } - // _ is reserved in flatbuffers field names, so no chance of name conflict: - code += "_tab "; - code += struct_def.fixed ? "flatbuffers.Struct" : "flatbuffers.Table"; - code += "\n}\n\n"; -} + if (parser_.opts.one_file) { + std::string code = ""; + BeginFile(LastNamespacePart(go_namespace_), true, &code); + code += one_file_code; + const std::string filename = GeneratedFileName(path_, file_name_); + return SaveFile(filename.c_str(), code, false); + } -// Construct the name of the type alias for this enum. -std::string GetEnumTypeName(const EnumDef &enum_def) { - return GoIdentity(enum_def.name); -} + return true; + } -// Create a type for the enum values. -static void GenEnumType(const EnumDef &enum_def, std::string *code_ptr) { - std::string &code = *code_ptr; - code += "type " + GetEnumTypeName(enum_def) + " = "; - code += GenTypeBasic(enum_def.underlying_type) + "\n"; -} + private: + Namespace go_namespace_; + Namespace *cur_name_space_; + std::set<const Namespace*> tracked_imported_namespaces_; + + // Most field accessors need to retrieve and test the field offset first, + // this is the prefix code for that. + std::string OffsetPrefix(const FieldDef &field) { + return "{\n\to := flatbuffers.UOffsetT(rcv._tab.Offset(" + + NumToString(field.value.offset) + "))\n\tif o != 0 {\n"; + } -// Begin enum code with a class declaration. -static void BeginEnum(std::string *code_ptr) { - std::string &code = *code_ptr; - code += "const (\n"; -} + // Begin a class declaration. + void BeginClass(const StructDef &struct_def, std::string *code_ptr) { + std::string &code = *code_ptr; -// A single enum member. -static void EnumMember(const EnumDef &enum_def, const EnumVal ev, - std::string *code_ptr) { - std::string &code = *code_ptr; - code += "\t"; - code += enum_def.name; - code += ev.name; - code += " "; - code += GetEnumTypeName(enum_def); - code += " = "; - code += NumToString(ev.value) + "\n"; -} + code += "type " + struct_def.name + " struct {\n\t"; -// End enum code. -static void EndEnum(std::string *code_ptr) { - std::string &code = *code_ptr; - code += ")\n\n"; -} + // _ is reserved in flatbuffers field names, so no chance of name conflict: + code += "_tab "; + code += struct_def.fixed ? "flatbuffers.Struct" : "flatbuffers.Table"; + code += "\n}\n\n"; + } -// Begin enum name code. -static void BeginEnumNames(const EnumDef &enum_def, std::string *code_ptr) { - std::string &code = *code_ptr; - code += "var EnumNames"; - code += enum_def.name; - code += " = map[" + GetEnumTypeName(enum_def) + "]string{\n"; -} + // Construct the name of the type alias for this enum. + std::string GetEnumTypeName(const EnumDef &enum_def) { + return WrapInNameSpaceAndTrack(cur_name_space_, GoIdentity(enum_def.name)); + } -// A single enum name member. -static void EnumNameMember(const EnumDef &enum_def, const EnumVal ev, - std::string *code_ptr) { - std::string &code = *code_ptr; - code += "\t"; - code += enum_def.name; - code += ev.name; - code += ":\""; - code += ev.name; - code += "\",\n"; -} + // Create a type for the enum values. + void GenEnumType(const EnumDef &enum_def, std::string *code_ptr) { + std::string &code = *code_ptr; + code += "type " + GetEnumTypeName(enum_def) + " = "; + code += GenTypeBasic(enum_def.underlying_type) + "\n"; + } -// End enum name code. -static void EndEnumNames(std::string *code_ptr) { - std::string &code = *code_ptr; - code += "}\n\n"; -} + // Begin enum code with a class declaration. + void BeginEnum(std::string *code_ptr) { + std::string &code = *code_ptr; + code += "const (\n"; + } -// Initialize a new struct or table from existing data. -static void NewRootTypeFromBuffer(const StructDef &struct_def, - std::string *code_ptr) { - std::string &code = *code_ptr; - - code += "func GetRootAs"; - code += struct_def.name; - code += "(buf []byte, offset flatbuffers.UOffsetT) "; - code += "*" + struct_def.name + ""; - code += " {\n"; - code += "\tn := flatbuffers.GetUOffsetT(buf[offset:])\n"; - code += "\tx := &" + struct_def.name + "{}\n"; - code += "\tx.Init(buf, n+offset)\n"; - code += "\treturn x\n"; - code += "}\n\n"; -} + // A single enum member. + void EnumMember(const EnumDef &enum_def, const EnumVal ev, + std::string *code_ptr) { + std::string &code = *code_ptr; + code += "\t"; + code += enum_def.name; + code += ev.name; + code += " "; + code += GetEnumTypeName(enum_def); + code += " = "; + code += NumToString(ev.value) + "\n"; + } -// Initialize an existing object with other data, to avoid an allocation. -static void InitializeExisting(const StructDef &struct_def, - std::string *code_ptr) { - std::string &code = *code_ptr; - - GenReceiver(struct_def, code_ptr); - code += " Init(buf []byte, i flatbuffers.UOffsetT) "; - code += "{\n"; - code += "\trcv._tab.Bytes = buf\n"; - code += "\trcv._tab.Pos = i\n"; - code += "}\n\n"; -} + // End enum code. + void EndEnum(std::string *code_ptr) { + std::string &code = *code_ptr; + code += ")\n\n"; + } -// Implement the table accessor -static void GenTableAccessor(const StructDef &struct_def, - std::string *code_ptr) { - std::string &code = *code_ptr; + // Begin enum name code. + void BeginEnumNames(const EnumDef &enum_def, std::string *code_ptr) { + std::string &code = *code_ptr; + code += "var EnumNames"; + code += enum_def.name; + code += " = map[" + GetEnumTypeName(enum_def) + "]string{\n"; + } - GenReceiver(struct_def, code_ptr); - code += " Table() flatbuffers.Table "; - code += "{\n"; + // A single enum name member. + void EnumNameMember(const EnumDef &enum_def, const EnumVal ev, + std::string *code_ptr) { + std::string &code = *code_ptr; + code += "\t"; + code += enum_def.name; + code += ev.name; + code += ":\""; + code += ev.name; + code += "\",\n"; + } - if (struct_def.fixed) { - code += "\treturn rcv._tab.Table\n"; - } else { - code += "\treturn rcv._tab\n"; + // End enum name code. + void EndEnumNames(std::string *code_ptr) { + std::string &code = *code_ptr; + code += "}\n\n"; } - code += "}\n\n"; -} -// Get the length of a vector. -static void GetVectorLen(const StructDef &struct_def, const FieldDef &field, - std::string *code_ptr) { - std::string &code = *code_ptr; + // Initialize a new struct or table from existing data. + void NewRootTypeFromBuffer(const StructDef &struct_def, + std::string *code_ptr) { + std::string &code = *code_ptr; - GenReceiver(struct_def, code_ptr); - code += " " + MakeCamel(field.name) + "Length("; - code += ") int " + OffsetPrefix(field); - code += "\t\treturn rcv._tab.VectorLen(o)\n\t}\n"; - code += "\treturn 0\n}\n\n"; -} + code += "func GetRootAs"; + code += struct_def.name; + code += "(buf []byte, offset flatbuffers.UOffsetT) "; + code += "*" + struct_def.name + ""; + code += " {\n"; + code += "\tn := flatbuffers.GetUOffsetT(buf[offset:])\n"; + code += "\tx := &" + struct_def.name + "{}\n"; + code += "\tx.Init(buf, n+offset)\n"; + code += "\treturn x\n"; + code += "}\n\n"; + } -// Get a [ubyte] vector as a byte slice. -static void GetUByteSlice(const StructDef &struct_def, const FieldDef &field, - std::string *code_ptr) { - std::string &code = *code_ptr; + // Initialize an existing object with other data, to avoid an allocation. + void InitializeExisting(const StructDef &struct_def, std::string *code_ptr) { + std::string &code = *code_ptr; - GenReceiver(struct_def, code_ptr); - code += " " + MakeCamel(field.name) + "Bytes("; - code += ") []byte " + OffsetPrefix(field); - code += "\t\treturn rcv._tab.ByteVector(o + rcv._tab.Pos)\n\t}\n"; - code += "\treturn nil\n}\n\n"; -} + GenReceiver(struct_def, code_ptr); + code += " Init(buf []byte, i flatbuffers.UOffsetT) "; + code += "{\n"; + code += "\trcv._tab.Bytes = buf\n"; + code += "\trcv._tab.Pos = i\n"; + code += "}\n\n"; + } -// Get the value of a struct's scalar. -static void GetScalarFieldOfStruct(const StructDef &struct_def, - const FieldDef &field, - std::string *code_ptr) { - std::string &code = *code_ptr; - std::string getter = GenGetter(field.value.type); - GenReceiver(struct_def, code_ptr); - code += " " + MakeCamel(field.name); - code += "() " + TypeName(field) + " {\n"; - code += "\treturn " + getter; - code += "(rcv._tab.Pos + flatbuffers.UOffsetT("; - code += NumToString(field.value.offset) + "))\n}\n"; -} + // Implement the table accessor + void GenTableAccessor(const StructDef &struct_def, std::string *code_ptr) { + std::string &code = *code_ptr; -// Get the value of a table's scalar. -static void GetScalarFieldOfTable(const StructDef &struct_def, - const FieldDef &field, - std::string *code_ptr) { - std::string &code = *code_ptr; - std::string getter = GenGetter(field.value.type); - GenReceiver(struct_def, code_ptr); - code += " " + MakeCamel(field.name); - code += "() " + TypeName(field) + " "; - code += OffsetPrefix(field) + "\t\treturn " + getter; - code += "(o + rcv._tab.Pos)\n\t}\n"; - code += "\treturn " + field.value.constant + "\n"; - code += "}\n\n"; -} + GenReceiver(struct_def, code_ptr); + code += " Table() flatbuffers.Table "; + code += "{\n"; -// Get a struct by initializing an existing struct. -// Specific to Struct. -static void GetStructFieldOfStruct(const StructDef &struct_def, - const FieldDef &field, - std::string *code_ptr) { - std::string &code = *code_ptr; - GenReceiver(struct_def, code_ptr); - code += " " + MakeCamel(field.name); - code += "(obj *" + TypeName(field); - code += ") *" + TypeName(field); - code += " {\n"; - code += "\tif obj == nil {\n"; - code += "\t\tobj = new(" + TypeName(field) + ")\n"; - code += "\t}\n"; - code += "\tobj.Init(rcv._tab.Bytes, rcv._tab.Pos+"; - code += NumToString(field.value.offset) + ")"; - code += "\n\treturn obj\n"; - code += "}\n"; -} + if (struct_def.fixed) { + code += "\treturn rcv._tab.Table\n"; + } else { + code += "\treturn rcv._tab\n"; + } + code += "}\n\n"; + } -// Get a struct by initializing an existing struct. -// Specific to Table. -static void GetStructFieldOfTable(const StructDef &struct_def, - const FieldDef &field, - std::string *code_ptr) { - std::string &code = *code_ptr; - GenReceiver(struct_def, code_ptr); - code += " " + MakeCamel(field.name); - code += "(obj *"; - code += TypeName(field); - code += ") *" + TypeName(field) + " " + OffsetPrefix(field); - if (field.value.type.struct_def->fixed) { - code += "\t\tx := o + rcv._tab.Pos\n"; - } else { - code += "\t\tx := rcv._tab.Indirect(o + rcv._tab.Pos)\n"; - } - code += "\t\tif obj == nil {\n"; - code += "\t\t\tobj = new(" + TypeName(field) + ")\n"; - code += "\t\t}\n"; - code += "\t\tobj.Init(rcv._tab.Bytes, x)\n"; - code += "\t\treturn obj\n\t}\n\treturn nil\n"; - code += "}\n\n"; -} + // Get the length of a vector. + void GetVectorLen(const StructDef &struct_def, const FieldDef &field, + std::string *code_ptr) { + std::string &code = *code_ptr; -// Get the value of a string. -static void GetStringField(const StructDef &struct_def, const FieldDef &field, - std::string *code_ptr) { - std::string &code = *code_ptr; - GenReceiver(struct_def, code_ptr); - code += " " + MakeCamel(field.name); - code += "() " + TypeName(field) + " "; - code += OffsetPrefix(field) + "\t\treturn " + GenGetter(field.value.type); - code += "(o + rcv._tab.Pos)\n\t}\n\treturn nil\n"; - code += "}\n\n"; -} + GenReceiver(struct_def, code_ptr); + code += " " + MakeCamel(field.name) + "Length("; + code += ") int " + OffsetPrefix(field); + code += "\t\treturn rcv._tab.VectorLen(o)\n\t}\n"; + code += "\treturn 0\n}\n\n"; + } -// Get the value of a union from an object. -static void GetUnionField(const StructDef &struct_def, const FieldDef &field, - std::string *code_ptr) { - std::string &code = *code_ptr; - GenReceiver(struct_def, code_ptr); - code += " " + MakeCamel(field.name) + "("; - code += "obj " + TypeName(field) + ") bool "; - code += OffsetPrefix(field); - code += "\t\t" + GenGetter(field.value.type); - code += "(obj, o)\n\t\treturn true\n\t}\n"; - code += "\treturn false\n"; - code += "}\n\n"; -} + // Get a [ubyte] vector as a byte slice. + void GetUByteSlice(const StructDef &struct_def, const FieldDef &field, + std::string *code_ptr) { + std::string &code = *code_ptr; -// Get the value of a vector's struct member. -static void GetMemberOfVectorOfStruct(const StructDef &struct_def, - const FieldDef &field, - std::string *code_ptr) { - std::string &code = *code_ptr; - auto vectortype = field.value.type.VectorType(); - - GenReceiver(struct_def, code_ptr); - code += " " + MakeCamel(field.name); - code += "(obj *" + TypeName(field); - code += ", j int) bool " + OffsetPrefix(field); - code += "\t\tx := rcv._tab.Vector(o)\n"; - code += "\t\tx += flatbuffers.UOffsetT(j) * "; - code += NumToString(InlineSize(vectortype)) + "\n"; - if (!(vectortype.struct_def->fixed)) { - code += "\t\tx = rcv._tab.Indirect(x)\n"; - } - code += "\t\tobj.Init(rcv._tab.Bytes, x)\n"; - code += "\t\treturn true\n\t}\n"; - code += "\treturn false\n"; - code += "}\n\n"; -} + GenReceiver(struct_def, code_ptr); + code += " " + MakeCamel(field.name) + "Bytes("; + code += ") []byte " + OffsetPrefix(field); + code += "\t\treturn rcv._tab.ByteVector(o + rcv._tab.Pos)\n\t}\n"; + code += "\treturn nil\n}\n\n"; + } -// Get the value of a vector's non-struct member. Uses a named return -// argument to conveniently set the zero value for the result. -static void GetMemberOfVectorOfNonStruct(const StructDef &struct_def, - const FieldDef &field, - std::string *code_ptr) { - std::string &code = *code_ptr; - auto vectortype = field.value.type.VectorType(); - - GenReceiver(struct_def, code_ptr); - code += " " + MakeCamel(field.name); - code += "(j int) " + TypeName(field) + " "; - code += OffsetPrefix(field); - code += "\t\ta := rcv._tab.Vector(o)\n"; - code += "\t\treturn " + GenGetter(field.value.type) + "("; - code += "a + flatbuffers.UOffsetT(j*"; - code += NumToString(InlineSize(vectortype)) + "))\n"; - code += "\t}\n"; - if (vectortype.base_type == BASE_TYPE_STRING) { - code += "\treturn nil\n"; - } else { - code += "\treturn 0\n"; - } - code += "}\n\n"; -} + // Get the value of a struct's scalar. + void GetScalarFieldOfStruct(const StructDef &struct_def, + const FieldDef &field, + std::string *code_ptr) { + std::string &code = *code_ptr; + std::string getter = GenGetter(field.value.type); + GenReceiver(struct_def, code_ptr); + code += " " + MakeCamel(field.name); + code += "() " + TypeName(field) + " {\n"; + code += "\treturn " + getter; + code += "(rcv._tab.Pos + flatbuffers.UOffsetT("; + code += NumToString(field.value.offset) + "))\n}\n"; + } -// Begin the creator function signature. -static void BeginBuilderArgs(const StructDef &struct_def, + // Get the value of a table's scalar. + void GetScalarFieldOfTable(const StructDef &struct_def, + const FieldDef &field, std::string *code_ptr) { - std::string &code = *code_ptr; + std::string &code = *code_ptr; + std::string getter = GenGetter(field.value.type); + GenReceiver(struct_def, code_ptr); + code += " " + MakeCamel(field.name); + code += "() " + TypeName(field) + " "; + code += OffsetPrefix(field) + "\t\treturn " + getter; + code += "(o + rcv._tab.Pos)\n\t}\n"; + code += "\treturn " + GenConstant(field) + "\n"; + code += "}\n\n"; + } - if (code.substr(code.length() - 2) != "\n\n") { - // a previous mutate has not put an extra new line - code += "\n"; + // Get a struct by initializing an existing struct. + // Specific to Struct. + void GetStructFieldOfStruct(const StructDef &struct_def, + const FieldDef &field, + std::string *code_ptr) { + std::string &code = *code_ptr; + GenReceiver(struct_def, code_ptr); + code += " " + MakeCamel(field.name); + code += "(obj *" + TypeName(field); + code += ") *" + TypeName(field); + code += " {\n"; + code += "\tif obj == nil {\n"; + code += "\t\tobj = new(" + TypeName(field) + ")\n"; + code += "\t}\n"; + code += "\tobj.Init(rcv._tab.Bytes, rcv._tab.Pos+"; + code += NumToString(field.value.offset) + ")"; + code += "\n\treturn obj\n"; + code += "}\n"; } - code += "func Create" + struct_def.name; - code += "(builder *flatbuffers.Builder"; -} -// Recursively generate arguments for a constructor, to deal with nested -// structs. -static void StructBuilderArgs(const StructDef &struct_def, - const char *nameprefix, std::string *code_ptr) { - for (auto it = struct_def.fields.vec.begin(); - it != struct_def.fields.vec.end(); ++it) { - auto &field = **it; - if (IsStruct(field.value.type)) { - // Generate arguments for a struct inside a struct. To ensure names - // don't clash, and to make it obvious these arguments are constructing - // a nested struct, prefix the name with the field name. - StructBuilderArgs(*field.value.type.struct_def, - (nameprefix + (field.name + "_")).c_str(), code_ptr); + // Get a struct by initializing an existing struct. + // Specific to Table. + void GetStructFieldOfTable(const StructDef &struct_def, + const FieldDef &field, + std::string *code_ptr) { + std::string &code = *code_ptr; + GenReceiver(struct_def, code_ptr); + code += " " + MakeCamel(field.name); + code += "(obj *"; + code += TypeName(field); + code += ") *" + TypeName(field) + " " + OffsetPrefix(field); + if (field.value.type.struct_def->fixed) { + code += "\t\tx := o + rcv._tab.Pos\n"; } else { - std::string &code = *code_ptr; - code += (std::string) ", " + nameprefix; - code += GoIdentity(field.name); - code += " " + GenTypeBasic(field.value.type); + code += "\t\tx := rcv._tab.Indirect(o + rcv._tab.Pos)\n"; } + code += "\t\tif obj == nil {\n"; + code += "\t\t\tobj = new(" + TypeName(field) + ")\n"; + code += "\t\t}\n"; + code += "\t\tobj.Init(rcv._tab.Bytes, x)\n"; + code += "\t\treturn obj\n\t}\n\treturn nil\n"; + code += "}\n\n"; } -} -// End the creator function signature. -static void EndBuilderArgs(std::string *code_ptr) { - std::string &code = *code_ptr; - code += ") flatbuffers.UOffsetT {\n"; -} + // Get the value of a string. + void GetStringField(const StructDef &struct_def, + const FieldDef &field, + std::string *code_ptr) { + std::string &code = *code_ptr; + GenReceiver(struct_def, code_ptr); + code += " " + MakeCamel(field.name); + code += "() " + TypeName(field) + " "; + code += OffsetPrefix(field) + "\t\treturn " + GenGetter(field.value.type); + code += "(o + rcv._tab.Pos)\n\t}\n\treturn nil\n"; + code += "}\n\n"; + } + + // Get the value of a union from an object. + void GetUnionField(const StructDef &struct_def, const FieldDef &field, + std::string *code_ptr) { + std::string &code = *code_ptr; + GenReceiver(struct_def, code_ptr); + code += " " + MakeCamel(field.name) + "("; + code += "obj " + TypeName(field) + ") bool "; + code += OffsetPrefix(field); + code += "\t\t" + GenGetter(field.value.type); + code += "(obj, o)\n\t\treturn true\n\t}\n"; + code += "\treturn false\n"; + code += "}\n\n"; + } -// Recursively generate struct construction statements and instert manual -// padding. -static void StructBuilderBody(const StructDef &struct_def, - const char *nameprefix, std::string *code_ptr) { - std::string &code = *code_ptr; - code += "\tbuilder.Prep(" + NumToString(struct_def.minalign) + ", "; - code += NumToString(struct_def.bytesize) + ")\n"; - for (auto it = struct_def.fields.vec.rbegin(); - it != struct_def.fields.vec.rend(); ++it) { - auto &field = **it; - if (field.padding) - code += "\tbuilder.Pad(" + NumToString(field.padding) + ")\n"; - if (IsStruct(field.value.type)) { - StructBuilderBody(*field.value.type.struct_def, - (nameprefix + (field.name + "_")).c_str(), code_ptr); + // Get the value of a vector's struct member. + void GetMemberOfVectorOfStruct(const StructDef &struct_def, + const FieldDef &field, + std::string *code_ptr) { + std::string &code = *code_ptr; + auto vectortype = field.value.type.VectorType(); + + GenReceiver(struct_def, code_ptr); + code += " " + MakeCamel(field.name); + code += "(obj *" + TypeName(field); + code += ", j int) bool " + OffsetPrefix(field); + code += "\t\tx := rcv._tab.Vector(o)\n"; + code += "\t\tx += flatbuffers.UOffsetT(j) * "; + code += NumToString(InlineSize(vectortype)) + "\n"; + if (!(vectortype.struct_def->fixed)) { + code += "\t\tx = rcv._tab.Indirect(x)\n"; + } + code += "\t\tobj.Init(rcv._tab.Bytes, x)\n"; + code += "\t\treturn true\n\t}\n"; + code += "\treturn false\n"; + code += "}\n\n"; + } + + // Get the value of a vector's non-struct member. Uses a named return + // argument to conveniently set the zero value for the result. + void GetMemberOfVectorOfNonStruct(const StructDef &struct_def, + const FieldDef &field, + std::string *code_ptr) { + std::string &code = *code_ptr; + auto vectortype = field.value.type.VectorType(); + + GenReceiver(struct_def, code_ptr); + code += " " + MakeCamel(field.name); + code += "(j int) " + TypeName(field) + " "; + code += OffsetPrefix(field); + code += "\t\ta := rcv._tab.Vector(o)\n"; + code += "\t\treturn " + GenGetter(field.value.type) + "("; + code += "a + flatbuffers.UOffsetT(j*"; + code += NumToString(InlineSize(vectortype)) + "))\n"; + code += "\t}\n"; + if (vectortype.base_type == BASE_TYPE_STRING) { + code += "\treturn nil\n"; + } else if (vectortype.base_type == BASE_TYPE_BOOL) { + code += "\treturn false\n"; } else { - code += "\tbuilder.Prepend" + GenMethod(field) + "("; - code += nameprefix + GoIdentity(field.name) + ")\n"; + code += "\treturn 0\n"; } + code += "}\n\n"; } -} -static void EndBuilderBody(std::string *code_ptr) { - std::string &code = *code_ptr; - code += "\treturn builder.Offset()\n"; - code += "}\n"; -} + // Begin the creator function signature. + void BeginBuilderArgs(const StructDef &struct_def, std::string *code_ptr) { + std::string &code = *code_ptr; -// Get the value of a table's starting offset. -static void GetStartOfTable(const StructDef &struct_def, - std::string *code_ptr) { - std::string &code = *code_ptr; - code += "func " + struct_def.name + "Start"; - code += "(builder *flatbuffers.Builder) {\n"; - code += "\tbuilder.StartObject("; - code += NumToString(struct_def.fields.vec.size()); - code += ")\n}\n"; -} + if (code.substr(code.length() - 2) != "\n\n") { + // a previous mutate has not put an extra new line + code += "\n"; + } + code += "func Create" + struct_def.name; + code += "(builder *flatbuffers.Builder"; + } -// Set the value of a table's field. -static void BuildFieldOfTable(const StructDef &struct_def, - const FieldDef &field, const size_t offset, - std::string *code_ptr) { - std::string &code = *code_ptr; - code += "func " + struct_def.name + "Add" + MakeCamel(field.name); - code += "(builder *flatbuffers.Builder, "; - code += GoIdentity(field.name) + " "; - if (!IsScalar(field.value.type.base_type) && (!struct_def.fixed)) { - code += "flatbuffers.UOffsetT"; - } else { - code += GenTypeBasic(field.value.type); - } - code += ") {\n"; - code += "\tbuilder.Prepend"; - code += GenMethod(field) + "Slot("; - code += NumToString(offset) + ", "; - if (!IsScalar(field.value.type.base_type) && (!struct_def.fixed)) { - code += "flatbuffers.UOffsetT"; - code += "("; - code += GoIdentity(field.name) + ")"; - } else { - code += GoIdentity(field.name); - } - code += ", " + field.value.constant; - code += ")\n}\n"; -} + // Recursively generate arguments for a constructor, to deal with nested + // structs. + void StructBuilderArgs(const StructDef &struct_def, const char *nameprefix, + std::string *code_ptr) { + for (auto it = struct_def.fields.vec.begin(); + it != struct_def.fields.vec.end(); ++it) { + auto &field = **it; + if (IsStruct(field.value.type)) { + // Generate arguments for a struct inside a struct. To ensure names + // don't clash, and to make it obvious these arguments are constructing + // a nested struct, prefix the name with the field name. + StructBuilderArgs(*field.value.type.struct_def, + (nameprefix + (field.name + "_")).c_str(), code_ptr); + } else { + std::string &code = *code_ptr; + code += std::string(", ") + nameprefix; + code += GoIdentity(field.name); + code += " " + GenTypeBasic(field.value.type); + } + } + } -// Set the value of one of the members of a table's vector. -static void BuildVectorOfTable(const StructDef &struct_def, - const FieldDef &field, std::string *code_ptr) { - std::string &code = *code_ptr; - code += "func " + struct_def.name + "Start"; - code += MakeCamel(field.name); - code += "Vector(builder *flatbuffers.Builder, numElems int) "; - code += "flatbuffers.UOffsetT {\n\treturn builder.StartVector("; - auto vector_type = field.value.type.VectorType(); - auto alignment = InlineAlignment(vector_type); - auto elem_size = InlineSize(vector_type); - code += NumToString(elem_size); - code += ", numElems, " + NumToString(alignment); - code += ")\n}\n"; -} + // End the creator function signature. + void EndBuilderArgs(std::string *code_ptr) { + std::string &code = *code_ptr; + code += ") flatbuffers.UOffsetT {\n"; + } -// Get the offset of the end of a table. -static void GetEndOffsetOnTable(const StructDef &struct_def, - std::string *code_ptr) { - std::string &code = *code_ptr; - code += "func " + struct_def.name + "End"; - code += "(builder *flatbuffers.Builder) flatbuffers.UOffsetT "; - code += "{\n\treturn builder.EndObject()\n}\n"; -} + // Recursively generate struct construction statements and instert manual + // padding. + void StructBuilderBody(const StructDef &struct_def, + const char *nameprefix, std::string *code_ptr) { + std::string &code = *code_ptr; + code += "\tbuilder.Prep(" + NumToString(struct_def.minalign) + ", "; + code += NumToString(struct_def.bytesize) + ")\n"; + for (auto it = struct_def.fields.vec.rbegin(); + it != struct_def.fields.vec.rend(); ++it) { + auto &field = **it; + if (field.padding) + code += "\tbuilder.Pad(" + NumToString(field.padding) + ")\n"; + if (IsStruct(field.value.type)) { + StructBuilderBody(*field.value.type.struct_def, + (nameprefix + (field.name + "_")).c_str(), code_ptr); + } else { + code += "\tbuilder.Prepend" + GenMethod(field) + "("; + code += nameprefix + GoIdentity(field.name) + ")\n"; + } + } + } -// Generate the receiver for function signatures. -static void GenReceiver(const StructDef &struct_def, std::string *code_ptr) { - std::string &code = *code_ptr; - code += "func (rcv *" + struct_def.name + ")"; -} + void EndBuilderBody(std::string *code_ptr) { + std::string &code = *code_ptr; + code += "\treturn builder.Offset()\n"; + code += "}\n"; + } -// Generate a struct field getter, conditioned on its child type(s). -static void GenStructAccessor(const StructDef &struct_def, - const FieldDef &field, std::string *code_ptr) { - GenComment(field.doc_comment, code_ptr, nullptr, ""); - if (IsScalar(field.value.type.base_type)) { - if (struct_def.fixed) { - GetScalarFieldOfStruct(struct_def, field, code_ptr); + // Get the value of a table's starting offset. + void GetStartOfTable(const StructDef &struct_def, std::string *code_ptr) { + std::string &code = *code_ptr; + code += "func " + struct_def.name + "Start"; + code += "(builder *flatbuffers.Builder) {\n"; + code += "\tbuilder.StartObject("; + code += NumToString(struct_def.fields.vec.size()); + code += ")\n}\n"; + } + + // Set the value of a table's field. + void BuildFieldOfTable(const StructDef &struct_def, const FieldDef &field, + const size_t offset, std::string *code_ptr) { + std::string &code = *code_ptr; + code += "func " + struct_def.name + "Add" + MakeCamel(field.name); + code += "(builder *flatbuffers.Builder, "; + code += GoIdentity(field.name) + " "; + if (!IsScalar(field.value.type.base_type) && (!struct_def.fixed)) { + code += "flatbuffers.UOffsetT"; } else { - GetScalarFieldOfTable(struct_def, field, code_ptr); + code += GenTypeBasic(field.value.type); } - } else { - switch (field.value.type.base_type) { - case BASE_TYPE_STRUCT: - if (struct_def.fixed) { - GetStructFieldOfStruct(struct_def, field, code_ptr); - } else { - GetStructFieldOfTable(struct_def, field, code_ptr); - } - break; - case BASE_TYPE_STRING: GetStringField(struct_def, field, code_ptr); break; - case BASE_TYPE_VECTOR: { - auto vectortype = field.value.type.VectorType(); - if (vectortype.base_type == BASE_TYPE_STRUCT) { - GetMemberOfVectorOfStruct(struct_def, field, code_ptr); - } else { - GetMemberOfVectorOfNonStruct(struct_def, field, code_ptr); - } - break; - } - case BASE_TYPE_UNION: GetUnionField(struct_def, field, code_ptr); break; - default: FLATBUFFERS_ASSERT(0); + code += ") {\n"; + code += "\tbuilder.Prepend"; + code += GenMethod(field) + "Slot("; + code += NumToString(offset) + ", "; + if (!IsScalar(field.value.type.base_type) && (!struct_def.fixed)) { + code += "flatbuffers.UOffsetT"; + code += "("; + code += GoIdentity(field.name) + ")"; + } else { + code += GoIdentity(field.name); } + code += ", " + GenConstant(field); + code += ")\n}\n"; } - if (field.value.type.base_type == BASE_TYPE_VECTOR) { - GetVectorLen(struct_def, field, code_ptr); - if (field.value.type.element == BASE_TYPE_UCHAR) { - GetUByteSlice(struct_def, field, code_ptr); - } + + // Set the value of one of the members of a table's vector. + void BuildVectorOfTable(const StructDef &struct_def, + const FieldDef &field, std::string *code_ptr) { + std::string &code = *code_ptr; + code += "func " + struct_def.name + "Start"; + code += MakeCamel(field.name); + code += "Vector(builder *flatbuffers.Builder, numElems int) "; + code += "flatbuffers.UOffsetT {\n\treturn builder.StartVector("; + auto vector_type = field.value.type.VectorType(); + auto alignment = InlineAlignment(vector_type); + auto elem_size = InlineSize(vector_type); + code += NumToString(elem_size); + code += ", numElems, " + NumToString(alignment); + code += ")\n}\n"; } -} -// Mutate the value of a struct's scalar. -static void MutateScalarFieldOfStruct(const StructDef &struct_def, - const FieldDef &field, - std::string *code_ptr) { - std::string &code = *code_ptr; - std::string type = MakeCamel(GenTypeBasic(field.value.type)); - std::string setter = "rcv._tab.Mutate" + type; - GenReceiver(struct_def, code_ptr); - code += " Mutate" + MakeCamel(field.name); - code += "(n " + TypeName(field) + ") bool {\n\treturn " + setter; - code += "(rcv._tab.Pos+flatbuffers.UOffsetT("; - code += NumToString(field.value.offset) + "), n)\n}\n\n"; -} + // Get the offset of the end of a table. + void GetEndOffsetOnTable(const StructDef &struct_def, std::string *code_ptr) { + std::string &code = *code_ptr; + code += "func " + struct_def.name + "End"; + code += "(builder *flatbuffers.Builder) flatbuffers.UOffsetT "; + code += "{\n\treturn builder.EndObject()\n}\n"; + } -// Mutate the value of a table's scalar. -static void MutateScalarFieldOfTable(const StructDef &struct_def, - const FieldDef &field, - std::string *code_ptr) { - std::string &code = *code_ptr; - std::string type = MakeCamel(GenTypeBasic(field.value.type)); - std::string setter = "rcv._tab.Mutate" + type + "Slot"; - GenReceiver(struct_def, code_ptr); - code += " Mutate" + MakeCamel(field.name); - code += "(n " + TypeName(field) + ") bool {\n\treturn "; - code += setter + "(" + NumToString(field.value.offset) + ", n)\n"; - code += "}\n\n"; -} + // Generate the receiver for function signatures. + void GenReceiver(const StructDef &struct_def, std::string *code_ptr) { + std::string &code = *code_ptr; + code += "func (rcv *" + struct_def.name + ")"; + } -// Generate a struct field setter, conditioned on its child type(s). -static void GenStructMutator(const StructDef &struct_def, const FieldDef &field, - std::string *code_ptr) { - GenComment(field.doc_comment, code_ptr, nullptr, ""); - if (IsScalar(field.value.type.base_type)) { - if (struct_def.fixed) { - MutateScalarFieldOfStruct(struct_def, field, code_ptr); + // Generate a struct field getter, conditioned on its child type(s). + void GenStructAccessor(const StructDef &struct_def, + const FieldDef &field, std::string *code_ptr) { + GenComment(field.doc_comment, code_ptr, nullptr, ""); + if (IsScalar(field.value.type.base_type)) { + if (struct_def.fixed) { + GetScalarFieldOfStruct(struct_def, field, code_ptr); + } else { + GetScalarFieldOfTable(struct_def, field, code_ptr); + } } else { - MutateScalarFieldOfTable(struct_def, field, code_ptr); + switch (field.value.type.base_type) { + case BASE_TYPE_STRUCT: + if (struct_def.fixed) { + GetStructFieldOfStruct(struct_def, field, code_ptr); + } else { + GetStructFieldOfTable(struct_def, field, code_ptr); + } + break; + case BASE_TYPE_STRING: GetStringField(struct_def, field, code_ptr); break; + case BASE_TYPE_VECTOR: { + auto vectortype = field.value.type.VectorType(); + if (vectortype.base_type == BASE_TYPE_STRUCT) { + GetMemberOfVectorOfStruct(struct_def, field, code_ptr); + } else { + GetMemberOfVectorOfNonStruct(struct_def, field, code_ptr); + } + break; + } + case BASE_TYPE_UNION: GetUnionField(struct_def, field, code_ptr); break; + default: FLATBUFFERS_ASSERT(0); + } + } + if (field.value.type.base_type == BASE_TYPE_VECTOR) { + GetVectorLen(struct_def, field, code_ptr); + if (field.value.type.element == BASE_TYPE_UCHAR) { + GetUByteSlice(struct_def, field, code_ptr); + } } } -} -// Generate table constructors, conditioned on its members' types. -static void GenTableBuilders(const StructDef &struct_def, - std::string *code_ptr) { - GetStartOfTable(struct_def, code_ptr); + // Mutate the value of a struct's scalar. + void MutateScalarFieldOfStruct(const StructDef &struct_def, + const FieldDef &field, + std::string *code_ptr) { + std::string &code = *code_ptr; + std::string type = MakeCamel(GenTypeBasic(field.value.type)); + std::string setter = "rcv._tab.Mutate" + type; + GenReceiver(struct_def, code_ptr); + code += " Mutate" + MakeCamel(field.name); + code += "(n " + TypeName(field) + ") bool {\n\treturn " + setter; + code += "(rcv._tab.Pos+flatbuffers.UOffsetT("; + code += NumToString(field.value.offset) + "), n)\n}\n\n"; + } - for (auto it = struct_def.fields.vec.begin(); - it != struct_def.fields.vec.end(); ++it) { - auto &field = **it; - if (field.deprecated) continue; + // Mutate the value of a table's scalar. + void MutateScalarFieldOfTable(const StructDef &struct_def, + const FieldDef &field, + std::string *code_ptr) { + std::string &code = *code_ptr; + std::string type = MakeCamel(GenTypeBasic(field.value.type)); + std::string setter = "rcv._tab.Mutate" + type + "Slot"; + GenReceiver(struct_def, code_ptr); + code += " Mutate" + MakeCamel(field.name); + code += "(n " + TypeName(field) + ") bool {\n\treturn "; + code += setter + "(" + NumToString(field.value.offset) + ", n)\n"; + code += "}\n\n"; + } - auto offset = it - struct_def.fields.vec.begin(); - BuildFieldOfTable(struct_def, field, offset, code_ptr); - if (field.value.type.base_type == BASE_TYPE_VECTOR) { - BuildVectorOfTable(struct_def, field, code_ptr); + // Generate a struct field setter, conditioned on its child type(s). + void GenStructMutator(const StructDef &struct_def, const FieldDef &field, + std::string *code_ptr) { + GenComment(field.doc_comment, code_ptr, nullptr, ""); + if (IsScalar(field.value.type.base_type)) { + if (struct_def.fixed) { + MutateScalarFieldOfStruct(struct_def, field, code_ptr); + } else { + MutateScalarFieldOfTable(struct_def, field, code_ptr); + } } } - GetEndOffsetOnTable(struct_def, code_ptr); -} + // Generate table constructors, conditioned on its members' types. + void GenTableBuilders(const StructDef &struct_def, std::string *code_ptr) { + GetStartOfTable(struct_def, code_ptr); -// Generate struct or table methods. -static void GenStruct(const StructDef &struct_def, std::string *code_ptr) { - if (struct_def.generated) return; - - GenComment(struct_def.doc_comment, code_ptr, nullptr); - BeginClass(struct_def, code_ptr); - if (!struct_def.fixed) { - // Generate a special accessor for the table that has been declared as - // the root type. - NewRootTypeFromBuffer(struct_def, code_ptr); - } - // Generate the Init method that sets the field in a pre-existing - // accessor object. This is to allow object reuse. - InitializeExisting(struct_def, code_ptr); - // Generate _tab accessor - GenTableAccessor(struct_def, code_ptr); - - // Generate struct fields accessors - for (auto it = struct_def.fields.vec.begin(); - it != struct_def.fields.vec.end(); ++it) { - auto &field = **it; - if (field.deprecated) continue; - - GenStructAccessor(struct_def, field, code_ptr); - GenStructMutator(struct_def, field, code_ptr); - } - - // Generate builders - if (struct_def.fixed) { - // create a struct constructor function - GenStructBuilder(struct_def, code_ptr); - } else { - // Create a set of functions that allow table construction. - GenTableBuilders(struct_def, code_ptr); - } -} - -// Generate enum declarations. -static void GenEnum(const EnumDef &enum_def, std::string *code_ptr) { - if (enum_def.generated) return; + for (auto it = struct_def.fields.vec.begin(); + it != struct_def.fields.vec.end(); ++it) { + auto &field = **it; + if (field.deprecated) continue; - GenComment(enum_def.doc_comment, code_ptr, nullptr); - GenEnumType(enum_def, code_ptr); - BeginEnum(code_ptr); - for (auto it = enum_def.vals.vec.begin(); it != enum_def.vals.vec.end(); - ++it) { - auto &ev = **it; - GenComment(ev.doc_comment, code_ptr, nullptr, "\t"); - EnumMember(enum_def, ev, code_ptr); - } - EndEnum(code_ptr); + auto offset = it - struct_def.fields.vec.begin(); + BuildFieldOfTable(struct_def, field, offset, code_ptr); + if (field.value.type.base_type == BASE_TYPE_VECTOR) { + BuildVectorOfTable(struct_def, field, code_ptr); + } + } - BeginEnumNames(enum_def, code_ptr); - for (auto it = enum_def.vals.vec.begin(); it != enum_def.vals.vec.end(); - ++it) { - auto &ev = **it; - EnumNameMember(enum_def, ev, code_ptr); + GetEndOffsetOnTable(struct_def, code_ptr); } - EndEnumNames(code_ptr); -} -// Returns the function name that is able to read a value of the given type. -static std::string GenGetter(const Type &type) { - switch (type.base_type) { - case BASE_TYPE_STRING: return "rcv._tab.ByteVector"; - case BASE_TYPE_UNION: return "rcv._tab.Union"; - case BASE_TYPE_VECTOR: return GenGetter(type.VectorType()); - default: return "rcv._tab.Get" + MakeCamel(GenTypeGet(type)); - } -} + // Generate struct or table methods. + void GenStruct(const StructDef &struct_def, std::string *code_ptr) { + if (struct_def.generated) return; -// Returns the method name for use with add/put calls. -static std::string GenMethod(const FieldDef &field) { - return IsScalar(field.value.type.base_type) - ? MakeCamel(GenTypeBasic(field.value.type)) - : (IsStruct(field.value.type) ? "Struct" : "UOffsetT"); -} + cur_name_space_ = struct_def.defined_namespace; -static std::string GenTypeBasic(const Type &type) { - static const char *ctypename[] = { - // clang-format off - #define FLATBUFFERS_TD(ENUM, IDLTYPE, \ - CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \ - #GTYPE, - FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD) - #undef FLATBUFFERS_TD - // clang-format on - }; - return ctypename[type.base_type]; -} + GenComment(struct_def.doc_comment, code_ptr, nullptr); + BeginClass(struct_def, code_ptr); + if (!struct_def.fixed) { + // Generate a special accessor for the table that has been declared as + // the root type. + NewRootTypeFromBuffer(struct_def, code_ptr); + } + // Generate the Init method that sets the field in a pre-existing + // accessor object. This is to allow object reuse. + InitializeExisting(struct_def, code_ptr); + // Generate _tab accessor + GenTableAccessor(struct_def, code_ptr); + + // Generate struct fields accessors + for (auto it = struct_def.fields.vec.begin(); + it != struct_def.fields.vec.end(); ++it) { + auto &field = **it; + if (field.deprecated) continue; + + GenStructAccessor(struct_def, field, code_ptr); + GenStructMutator(struct_def, field, code_ptr); + } -static std::string GenTypePointer(const Type &type) { - switch (type.base_type) { - case BASE_TYPE_STRING: return "[]byte"; - case BASE_TYPE_VECTOR: return GenTypeGet(type.VectorType()); - case BASE_TYPE_STRUCT: return type.struct_def->name; - case BASE_TYPE_UNION: - // fall through - default: return "*flatbuffers.Table"; + // Generate builders + if (struct_def.fixed) { + // create a struct constructor function + GenStructBuilder(struct_def, code_ptr); + } else { + // Create a set of functions that allow table construction. + GenTableBuilders(struct_def, code_ptr); + } } -} - -static std::string GenTypeGet(const Type &type) { - return IsScalar(type.base_type) ? GenTypeBasic(type) : GenTypePointer(type); -} -static std::string TypeName(const FieldDef &field) { - return GenTypeGet(field.value.type); -} + // Generate enum declarations. + void GenEnum(const EnumDef &enum_def, std::string *code_ptr) { + if (enum_def.generated) return; -// Create a struct with a builder and the struct's arguments. -static void GenStructBuilder(const StructDef &struct_def, - std::string *code_ptr) { - BeginBuilderArgs(struct_def, code_ptr); - StructBuilderArgs(struct_def, "", code_ptr); - EndBuilderArgs(code_ptr); + cur_name_space_ = enum_def.defined_namespace; - StructBuilderBody(struct_def, "", code_ptr); - EndBuilderBody(code_ptr); -} + GenComment(enum_def.doc_comment, code_ptr, nullptr); + GenEnumType(enum_def, code_ptr); + BeginEnum(code_ptr); + for (auto it = enum_def.vals.vec.begin(); it != enum_def.vals.vec.end(); + ++it) { + auto &ev = **it; + GenComment(ev.doc_comment, code_ptr, nullptr, "\t"); + EnumMember(enum_def, ev, code_ptr); + } + EndEnum(code_ptr); -class GoGenerator : public BaseGenerator { - public: - GoGenerator(const Parser &parser, const std::string &path, - const std::string &file_name, const std::string &go_namespace) - : BaseGenerator(parser, path, file_name, "" /* not used*/, - "" /* not used */) { - std::istringstream iss(go_namespace); - std::string component; - while (std::getline(iss, component, '.')) { - go_namespace_.components.push_back(component); + BeginEnumNames(enum_def, code_ptr); + for (auto it = enum_def.vals.vec.begin(); it != enum_def.vals.vec.end(); + ++it) { + auto &ev = **it; + EnumNameMember(enum_def, ev, code_ptr); } + EndEnumNames(code_ptr); } - bool generate() { - std::string one_file_code; - for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end(); - ++it) { - std::string enumcode; - go::GenEnum(**it, &enumcode); - if (parser_.opts.one_file) { - one_file_code += enumcode; - } else { - if (!SaveType(**it, enumcode, false)) return false; - } + // Returns the function name that is able to read a value of the given type. + std::string GenGetter(const Type &type) { + switch (type.base_type) { + case BASE_TYPE_STRING: return "rcv._tab.ByteVector"; + case BASE_TYPE_UNION: return "rcv._tab.Union"; + case BASE_TYPE_VECTOR: return GenGetter(type.VectorType()); + default: return "rcv._tab.Get" + MakeCamel(GenTypeBasic(type)); } + } - for (auto it = parser_.structs_.vec.begin(); - it != parser_.structs_.vec.end(); ++it) { - std::string declcode; - go::GenStruct(**it, &declcode); - if (parser_.opts.one_file) { - one_file_code += declcode; - } else { - if (!SaveType(**it, declcode, true)) return false; - } + // Returns the method name for use with add/put calls. + std::string GenMethod(const FieldDef &field) { + return IsScalar(field.value.type.base_type) + ? MakeCamel(GenTypeBasic(field.value.type)) + : (IsStruct(field.value.type) ? "Struct" : "UOffsetT"); + } + + std::string GenTypeBasic(const Type &type) { + static const char *ctypename[] = { + // clang-format off + #define FLATBUFFERS_TD(ENUM, IDLTYPE, \ + CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE) \ + #GTYPE, + FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD) + #undef FLATBUFFERS_TD + // clang-format on + }; + return ctypename[type.base_type]; + } + + std::string GenTypePointer(const Type &type) { + switch (type.base_type) { + case BASE_TYPE_STRING: return "[]byte"; + case BASE_TYPE_VECTOR: return GenTypeGet(type.VectorType()); + case BASE_TYPE_STRUCT: return WrapInNameSpaceAndTrack(*type.struct_def); + case BASE_TYPE_UNION: + // fall through + default: return "*flatbuffers.Table"; } + } - if (parser_.opts.one_file) { - std::string code = ""; - BeginFile(LastNamespacePart(go_namespace_), true, &code); - code += one_file_code; - const std::string filename = GeneratedFileName(path_, file_name_); - return SaveFile(filename.c_str(), code, false); + std::string GenTypeGet(const Type &type) { + if (type.enum_def != nullptr && !type.enum_def->is_union) { + return GetEnumTypeName(*type.enum_def); } + return IsScalar(type.base_type) ? GenTypeBasic(type) : GenTypePointer(type); + } - return true; + std::string TypeName(const FieldDef &field) { + return GenTypeGet(field.value.type); } - private: + std::string GenConstant(const FieldDef &field) { + switch (field.value.type.base_type) { + case BASE_TYPE_BOOL: return field.value.constant == "0" ? "false" : "true";; + default: return field.value.constant; + } + } + + // Create a struct with a builder and the struct's arguments. + void GenStructBuilder(const StructDef &struct_def, std::string *code_ptr) { + BeginBuilderArgs(struct_def, code_ptr); + StructBuilderArgs(struct_def, "", code_ptr); + EndBuilderArgs(code_ptr); + + StructBuilderBody(struct_def, "", code_ptr); + EndBuilderBody(code_ptr); + } // Begin by declaring namespace and imports. void BeginFile(const std::string name_space_name, const bool needs_imports, std::string *code_ptr) { std::string &code = *code_ptr; - code = code + "// " + FlatBuffersGeneratedWarning() + "\n\n"; + code = code + "// Code generated by the FlatBuffers compiler. DO NOT EDIT.\n\n"; code += "package " + name_space_name + "\n\n"; if (needs_imports) { code += "import (\n"; @@ -791,6 +798,15 @@ class GoGenerator : public BaseGenerator { } else { code += "\tflatbuffers \"github.com/google/flatbuffers/go\"\n"; } + if (tracked_imported_namespaces_.size() > 0) { + code += "\n"; + for (auto it = tracked_imported_namespaces_.begin(); + it != tracked_imported_namespaces_.end(); + ++it) { + code += "\t" + NamespaceImportName(*it) + " \"" + \ + NamespaceImportPath(*it) + "\"\n"; + } + } code += ")\n\n"; } } @@ -809,7 +825,49 @@ class GoGenerator : public BaseGenerator { return SaveFile(filename.c_str(), code, false); } - Namespace go_namespace_; + // Create the full name of the imported namespace (format: A__B__C). + std::string NamespaceImportName(const Namespace *ns) { + std::string s = ""; + for (auto it = ns->components.begin(); it != ns->components.end(); ++it) { + if (s.size() == 0) { + s += *it; + } else { + s += "__" + *it; + } + } + return s; + } + + // Create the full path for the imported namespace (format: A/B/C). + std::string NamespaceImportPath(const Namespace *ns) { + std::string s = ""; + for (auto it = ns->components.begin(); it != ns->components.end(); ++it) { + if (s.size() == 0) { + s += *it; + } else { + s += "/" + *it; + } + } + return s; + } + + // Ensure that a type is prefixed with its go package import name if it is + // used outside of its namespace. + std::string WrapInNameSpaceAndTrack(const Namespace *ns, + const std::string &name) { + if (CurrentNameSpace() == ns) return name; + + tracked_imported_namespaces_.insert(ns); + + std::string import_name = NamespaceImportName(ns); + return import_name + "." + name; + } + + std::string WrapInNameSpaceAndTrack(const Definition &def) { + return WrapInNameSpaceAndTrack(def.defined_namespace, def.name); + } + + const Namespace *CurrentNameSpace() const { return cur_name_space_; } }; } // namespace go diff --git a/chromium/third_party/flatbuffers/src/src/idl_gen_grpc.cpp b/chromium/third_party/flatbuffers/src/src/idl_gen_grpc.cpp index 06ed765b53a..d682a553629 100644 --- a/chromium/third_party/flatbuffers/src/src/idl_gen_grpc.cpp +++ b/chromium/third_party/flatbuffers/src/src/idl_gen_grpc.cpp @@ -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>( diff --git a/chromium/third_party/flatbuffers/src/src/idl_gen_js.cpp b/chromium/third_party/flatbuffers/src/src/idl_gen_js_ts.cpp index 71e7a54a3df..ff248fc4aca 100644 --- a/chromium/third_party/flatbuffers/src/src/idl_gen_js.cpp +++ b/chromium/third_party/flatbuffers/src/src/idl_gen_js_ts.cpp @@ -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); } @@ -228,7 +225,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"; @@ -355,9 +352,22 @@ class JsGenerator : public BaseGenerator { if (it != enum_def.vals.vec.begin()) { code += '\n'; } GenDocComment(ev.doc_comment, code_ptr, "", " "); } + + // Generate mapping between EnumName: EnumValue(int) code += " " + ev.name; code += lang_.language == IDLOptions::kTs ? "= " : ": "; code += NumToString(ev.value); + + if (lang_.language == IDLOptions::kJs) { + // In pure Javascript, generate mapping between EnumValue(int): + // 'EnumName' so enums can be looked up by their ID. + code += ", "; + + code += NumToString(ev.value); + code += lang_.language == IDLOptions::kTs ? "= " : ": "; + code += "'" + ev.name + "'"; + } + code += (it + 1) != enum_def.vals.vec.end() ? ",\n" : "\n"; if (ev.union_type.struct_def) { @@ -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; @@ -507,14 +518,29 @@ class JsGenerator : public BaseGenerator { } static std::string GenFileNamespacePrefix(const std::string &file) { - return "NS" + std::to_string(static_cast<unsigned long long>( - std::hash<std::string>()(file))); + 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. @@ -522,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; } @@ -669,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; @@ -737,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"; } @@ -850,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"; @@ -1057,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"; } @@ -1074,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"; } @@ -1090,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( @@ -1101,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"; @@ -1196,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"; } @@ -1225,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"; } @@ -1240,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"; } } + + 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 js +} // namespace jsts -bool GenerateJS(const Parser &parser, const std::string &path, - const std::string &file_name) { - js::JsGenerator generator(parser, path, file_name); +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); diff --git a/chromium/third_party/flatbuffers/src/src/idl_gen_lobster.cpp b/chromium/third_party/flatbuffers/src/src/idl_gen_lobster.cpp index 0487d17a7aa..5f199e3a1c9 100644 --- a/chromium/third_party/flatbuffers/src/src/idl_gen_lobster.cpp +++ b/chromium/third_party/flatbuffers/src/src/idl_gen_lobster.cpp @@ -81,7 +81,7 @@ class LobsterGenerator : public BaseGenerator { static const char *ctypename[] = { // clang-format off #define FLATBUFFERS_TD(ENUM, IDLTYPE, \ - CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \ + CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE) \ #PTYPE, FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD) #undef FLATBUFFERS_TD diff --git a/chromium/third_party/flatbuffers/src/src/idl_gen_lua.cpp b/chromium/third_party/flatbuffers/src/src/idl_gen_lua.cpp index 86264918166..e8ae32802c7 100644 --- a/chromium/third_party/flatbuffers/src/src/idl_gen_lua.cpp +++ b/chromium/third_party/flatbuffers/src/src/idl_gen_lua.cpp @@ -362,7 +362,7 @@ namespace lua { } else { std::string &code = *code_ptr; - code += (std::string) ", " + nameprefix; + code += std::string(", ") + nameprefix; code += MakeCamel(NormalizedName(field), false); } } @@ -604,7 +604,7 @@ namespace lua { static const char *ctypename[] = { // clang-format off #define FLATBUFFERS_TD(ENUM, IDLTYPE, \ - CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \ + CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE) \ #PTYPE, FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD) #undef FLATBUFFERS_TD diff --git a/chromium/third_party/flatbuffers/src/src/idl_gen_php.cpp b/chromium/third_party/flatbuffers/src/src/idl_gen_php.cpp index 7d98e00dee9..3c6747e3e47 100644 --- a/chromium/third_party/flatbuffers/src/src/idl_gen_php.cpp +++ b/chromium/third_party/flatbuffers/src/src/idl_gen_php.cpp @@ -31,7 +31,7 @@ class PhpGenerator : public BaseGenerator { public: PhpGenerator(const Parser &parser, const std::string &path, const std::string &file_name) - : BaseGenerator(parser, path, file_name, "\\", "\\"){}; + : BaseGenerator(parser, path, file_name, "\\", "\\") {} bool generate() { if (!GenerateEnums()) return false; if (!GenerateStructs()) return false; @@ -454,7 +454,7 @@ class PhpGenerator : public BaseGenerator { (nameprefix + (field.name + "_")).c_str(), code_ptr); } else { std::string &code = *code_ptr; - code += (std::string) ", $" + nameprefix; + code += std::string(", $") + nameprefix; code += MakeCamel(field.name, false); } } @@ -602,12 +602,12 @@ class PhpGenerator : public BaseGenerator { code += "for ($i = count($data) - 1; $i >= 0; $i--) {\n"; if (IsScalar(field.value.type.VectorType().base_type)) { code += Indent + Indent + Indent; - code += "$builder->add"; + code += "$builder->put"; code += MakeCamel(GenTypeBasic(field.value.type.VectorType())); code += "($data[$i]);\n"; } else { code += Indent + Indent + Indent; - code += "$builder->addOffset($data[$i]);\n"; + code += "$builder->putOffset($data[$i]);\n"; } code += Indent + Indent + "}\n"; code += Indent + Indent + "return $builder->endVector();\n"; @@ -828,7 +828,7 @@ class PhpGenerator : public BaseGenerator { for (auto it = enum_def.vals.vec.begin(); it != enum_def.vals.vec.end(); ++it) { auto &ev = **it; - code += Indent + Indent + "\"" + ev.name + "\",\n"; + code += Indent + Indent + enum_def.name + "::" + ev.name + "=>" + "\"" + ev.name + "\",\n"; } code += Indent + ");\n\n"; @@ -864,7 +864,7 @@ class PhpGenerator : public BaseGenerator { static const char *ctypename[] = { // clang-format off #define FLATBUFFERS_TD(ENUM, IDLTYPE, \ - CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \ + CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE) \ #NTYPE, FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD) #undef FLATBUFFERS_TD diff --git a/chromium/third_party/flatbuffers/src/src/idl_gen_python.cpp b/chromium/third_party/flatbuffers/src/src/idl_gen_python.cpp index e000ada9a29..fbb0805cbfc 100644 --- a/chromium/third_party/flatbuffers/src/src/idl_gen_python.cpp +++ b/chromium/third_party/flatbuffers/src/src/idl_gen_python.cpp @@ -36,7 +36,8 @@ class PythonGenerator : public BaseGenerator { PythonGenerator(const Parser &parser, const std::string &path, const std::string &file_name) : BaseGenerator(parser, path, file_name, "" /* not used */, - "" /* not used */){ + "" /* not used */), + float_const_gen_("float('nan')", "float('inf')", "float('-inf')") { static const char * const keywords[] = { "False", "None", @@ -191,7 +192,7 @@ class PythonGenerator : public BaseGenerator { code += "(self):"; code += OffsetPrefix(field); getter += "o + self._tab.Pos)"; - auto is_bool = field.value.type.base_type == BASE_TYPE_BOOL; + auto is_bool = IsBool(field.value.type.base_type); if (is_bool) { getter = "bool(" + getter + ")"; } @@ -200,7 +201,9 @@ class PythonGenerator : public BaseGenerator { if (is_bool) { default_value = field.value.constant == "0" ? "False" : "True"; } else { - default_value = field.value.constant; + default_value = IsFloat(field.value.type.base_type) + ? float_const_gen_.GenFloatConstant(field) + : field.value.constant; } code += Indent + Indent + "return " + default_value + "\n\n"; } @@ -383,7 +386,7 @@ class PythonGenerator : public BaseGenerator { (nameprefix + (NormalizedName(field) + "_")).c_str(), code_ptr); } else { std::string &code = *code_ptr; - code += (std::string) ", " + nameprefix; + code += std::string(", ") + nameprefix; code += MakeCamel(NormalizedName(field), false); } } @@ -452,7 +455,10 @@ class PythonGenerator : public BaseGenerator { } else { code += MakeCamel(NormalizedName(field), false); } - code += ", " + field.value.constant; + code += ", "; + code += IsFloat(field.value.type.base_type) + ? float_const_gen_.GenFloatConstant(field) + : field.value.constant; code += ")\n"; } @@ -615,7 +621,7 @@ class PythonGenerator : public BaseGenerator { static const char *ctypename[] = { // clang-format off #define FLATBUFFERS_TD(ENUM, IDLTYPE, \ - CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \ + CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE) \ #PTYPE, FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD) #undef FLATBUFFERS_TD @@ -715,6 +721,7 @@ class PythonGenerator : public BaseGenerator { } private: std::unordered_set<std::string> keywords_; + const SimpleFloatConstantGenerator float_const_gen_; }; } // namespace python diff --git a/chromium/third_party/flatbuffers/src/src/idl_gen_rust.cpp b/chromium/third_party/flatbuffers/src/src/idl_gen_rust.cpp new file mode 100644 index 00000000000..861a2e9c0f7 --- /dev/null +++ b/chromium/third_party/flatbuffers/src/src/idl_gen_rust.cpp @@ -0,0 +1,1833 @@ +/* + * 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. + */ + +// independent from idl_parser, since this code is not needed for most clients + +#include "flatbuffers/code_generators.h" +#include "flatbuffers/flatbuffers.h" +#include "flatbuffers/idl.h" +#include "flatbuffers/util.h" + +namespace flatbuffers { + +static std::string GeneratedFileName(const std::string &path, + const std::string &file_name) { + return path + file_name + "_generated.rs"; +} + +// Convert a camelCaseIdentifier or CamelCaseIdentifier to a +// snake_case_indentifier. +std::string MakeSnakeCase(const std::string &in) { + std::string s; + for (size_t i = 0; i < in.length(); i++) { + if (i == 0) { + s += static_cast<char>(tolower(in[0])); + } else if (in[i] == '_') { + s += '_'; + } else if (!islower(in[i])) { + // Prevent duplicate underscores for Upper_Snake_Case strings + // and UPPERCASE strings. + if (islower(in[i - 1])) { + s += '_'; + } + s += static_cast<char>(tolower(in[i])); + } else { + s += in[i]; + } + } + return s; +} + +// Convert a string to all uppercase. +std::string MakeUpper(const std::string &in) { + std::string s; + for (size_t i = 0; i < in.length(); i++) { + s += static_cast<char>(toupper(in[i])); + } + return s; +} + +// Encapsulate all logical field types in this enum. This allows us to write +// field logic based on type switches, instead of branches on the properties +// set on the Type. +// TODO(rw): for backwards compatibility, we can't use a strict `enum class` +// declaration here. could we use the `-Wswitch-enum` warning to +// achieve the same effect? +enum FullType { + ftInteger = 0, + ftFloat = 1, + ftBool = 2, + + ftStruct = 3, + ftTable = 4, + + ftEnumKey = 5, + ftUnionKey = 6, + + ftUnionValue = 7, + + // TODO(rw): bytestring? + ftString = 8, + + ftVectorOfInteger = 9, + ftVectorOfFloat = 10, + ftVectorOfBool = 11, + ftVectorOfEnumKey = 12, + ftVectorOfStruct = 13, + ftVectorOfTable = 14, + ftVectorOfString = 15, + ftVectorOfUnionValue = 16, +}; + +// Convert a Type to a FullType (exhaustive). +FullType GetFullType(const Type &type) { + // N.B. The order of these conditionals matters for some types. + + if (type.base_type == BASE_TYPE_STRING) { + return ftString; + } else if (type.base_type == BASE_TYPE_STRUCT) { + if (type.struct_def->fixed) { + return ftStruct; + } else { + return ftTable; + } + } else if (type.base_type == BASE_TYPE_VECTOR) { + switch (GetFullType(type.VectorType())) { + case ftInteger: { + return ftVectorOfInteger; + } + case ftFloat: { + return ftVectorOfFloat; + } + case ftBool: { + return ftVectorOfBool; + } + case ftStruct: { + return ftVectorOfStruct; + } + case ftTable: { + return ftVectorOfTable; + } + case ftString: { + return ftVectorOfString; + } + case ftEnumKey: { + return ftVectorOfEnumKey; + } + case ftUnionKey: + case ftUnionValue: { + FLATBUFFERS_ASSERT(false && "vectors of unions are unsupported"); + break; + } + default: { + FLATBUFFERS_ASSERT(false && "vector of vectors are unsupported"); + } + } + } else if (type.enum_def != nullptr) { + if (type.enum_def->is_union) { + if (type.base_type == BASE_TYPE_UNION) { + return ftUnionValue; + } else if (IsInteger(type.base_type)) { + return ftUnionKey; + } else { + FLATBUFFERS_ASSERT(false && "unknown union field type"); + } + } else { + return ftEnumKey; + } + } else if (IsScalar(type.base_type)) { + if (IsBool(type.base_type)) { + return ftBool; + } else if (IsInteger(type.base_type)) { + return ftInteger; + } else if (IsFloat(type.base_type)) { + return ftFloat; + } else { + FLATBUFFERS_ASSERT(false && "unknown number type"); + } + } + + FLATBUFFERS_ASSERT(false && "completely unknown type"); + + // this is only to satisfy the compiler's return analysis. + return ftBool; +} + +// If the second parameter is false then wrap the first with Option<...> +std::string WrapInOptionIfNotRequired(std::string s, bool required) { + if (required) { + return s; + } else { + return "Option<" + s + ">"; + } +} + +// If the second parameter is false then add .unwrap() +std::string AddUnwrapIfRequired(std::string s, bool required) { + if (required) { + return s + ".unwrap()"; + } else { + return s; + } +} + +namespace rust { + +class RustGenerator : public BaseGenerator { + public: + RustGenerator(const Parser &parser, const std::string &path, + const std::string &file_name) + : BaseGenerator(parser, path, file_name, "", "::"), + cur_name_space_(nullptr) { + const char *keywords[] = { + // list taken from: + // https://doc.rust-lang.org/book/second-edition/appendix-01-keywords.html + // + // we write keywords one per line so that we can easily compare them with + // changes to that webpage in the future. + + // currently-used keywords + "as", + "break", + "const", + "continue", + "crate", + "else", + "enum", + "extern", + "false", + "fn", + "for", + "if", + "impl", + "in", + "let", + "loop", + "match", + "mod", + "move", + "mut", + "pub", + "ref", + "return", + "Self", + "self", + "static", + "struct", + "super", + "trait", + "true", + "type", + "unsafe", + "use", + "where", + "while", + + // future possible keywords + "abstract", + "alignof", + "become", + "box", + "do", + "final", + "macro", + "offsetof", + "override", + "priv", + "proc", + "pure", + "sizeof", + "typeof", + "unsized", + "virtual", + "yield", + + // other rust terms we should not use + "std", + "usize", + "isize", + "u8", + "i8", + "u16", + "i16", + "u32", + "i32", + "u64", + "i64", + "u128", + "i128", + "f32", + "f64", + + // These are terms the code generator can implement on types. + // + // In Rust, the trait resolution rules (as described at + // https://github.com/rust-lang/rust/issues/26007) mean that, as long + // as we impl table accessors as inherent methods, we'll never create + // conflicts with these keywords. However, that's a fairly nuanced + // implementation detail, and how we implement methods could change in + // the future. as a result, we proactively block these out as reserved + // words. + "follow", + "push", + "size", + "alignment", + "to_little_endian", + "from_little_endian", + nullptr }; + for (auto kw = keywords; *kw; kw++) keywords_.insert(*kw); + } + + // Iterate through all definitions we haven't generated code for (enums, + // structs, and tables) and output them to a single file. + bool generate() { + code_.Clear(); + code_ += "// " + std::string(FlatBuffersGeneratedWarning()) + "\n\n"; + + assert(!cur_name_space_); + + // Generate imports for the global scope in case no namespace is used + // in the schema file. + GenNamespaceImports(0); + code_ += ""; + + // Generate all code in their namespaces, once, because Rust does not + // permit re-opening modules. + // + // TODO(rw): Use a set data structure to reduce namespace evaluations from + // O(n**2) to O(n). + for (auto ns_it = parser_.namespaces_.begin(); + ns_it != parser_.namespaces_.end(); + ++ns_it) { + const auto &ns = *ns_it; + + // Generate code for all the enum declarations. + for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end(); + ++it) { + const auto &enum_def = **it; + if (enum_def.defined_namespace != ns) { continue; } + if (!enum_def.generated) { + SetNameSpace(enum_def.defined_namespace); + GenEnum(enum_def); + } + } + + // Generate code for all structs. + for (auto it = parser_.structs_.vec.begin(); + it != parser_.structs_.vec.end(); ++it) { + const auto &struct_def = **it; + if (struct_def.defined_namespace != ns) { continue; } + if (struct_def.fixed && !struct_def.generated) { + SetNameSpace(struct_def.defined_namespace); + GenStruct(struct_def); + } + } + + // Generate code for all tables. + for (auto it = parser_.structs_.vec.begin(); + it != parser_.structs_.vec.end(); ++it) { + const auto &struct_def = **it; + if (struct_def.defined_namespace != ns) { continue; } + if (!struct_def.fixed && !struct_def.generated) { + SetNameSpace(struct_def.defined_namespace); + GenTable(struct_def); + } + } + + // Generate global helper functions. + if (parser_.root_struct_def_) { + auto &struct_def = *parser_.root_struct_def_; + if (struct_def.defined_namespace != ns) { continue; } + SetNameSpace(struct_def.defined_namespace); + GenRootTableFuncs(struct_def); + } + } + if (cur_name_space_) SetNameSpace(nullptr); + + const auto file_path = GeneratedFileName(path_, file_name_); + const auto final_code = code_.ToString(); + return SaveFile(file_path.c_str(), final_code, false); + } + + private: + CodeWriter code_; + + std::set<std::string> keywords_; + + // This tracks the current namespace so we can insert namespace declarations. + const Namespace *cur_name_space_; + + const Namespace *CurrentNameSpace() const { return cur_name_space_; } + + // Determine if a Type needs a lifetime template parameter when used in the + // Rust builder args. + bool TableBuilderTypeNeedsLifetime(const Type &type) const { + switch (GetFullType(type)) { + case ftInteger: + case ftFloat: + case ftBool: + case ftEnumKey: + case ftUnionKey: + case ftUnionValue: { return false; } + default: { return true; } + } + } + + // Determine if a table args rust type needs a lifetime template parameter. + bool TableBuilderArgsNeedsLifetime(const StructDef &struct_def) const { + FLATBUFFERS_ASSERT(!struct_def.fixed); + + for (auto it = struct_def.fields.vec.begin(); + it != struct_def.fields.vec.end(); ++it) { + const auto &field = **it; + if (field.deprecated) { + continue; + } + + if (TableBuilderTypeNeedsLifetime(field.value.type)) { + return true; + } + } + + return false; + } + + // Determine if a Type needs to be copied (for endian safety) when used in a + // Struct. + bool StructMemberAccessNeedsCopy(const Type &type) const { + switch (GetFullType(type)) { + case ftInteger: // requires endian swap + case ftFloat: // requires endian swap + case ftBool: // no endian-swap, but do the copy for UX consistency + case ftEnumKey: { return true; } // requires endian swap + case ftStruct: { return false; } // no endian swap + default: { + // logic error: no other types can be struct members. + FLATBUFFERS_ASSERT(false && "invalid struct member type"); + return false; // only to satisfy compiler's return analysis + } + } + } + + std::string EscapeKeyword(const std::string &name) const { + return keywords_.find(name) == keywords_.end() ? name : name + "_"; + } + + std::string Name(const Definition &def) const { + return EscapeKeyword(def.name); + } + + std::string Name(const EnumVal &ev) const { return EscapeKeyword(ev.name); } + + std::string WrapInNameSpace(const Definition &def) const { + return WrapInNameSpace(def.defined_namespace, Name(def)); + } + std::string WrapInNameSpace(const Namespace *ns, + const std::string &name) const { + if (CurrentNameSpace() == ns) return name; + std::string prefix = GetRelativeNamespaceTraversal(CurrentNameSpace(), ns); + return prefix + name; + } + + // Determine the namespace traversal needed from the Rust crate root. + // This may be useful in the future for referring to included files, but is + // currently unused. + std::string GetAbsoluteNamespaceTraversal(const Namespace *dst) const { + std::stringstream stream; + + stream << "::"; + for (auto d = dst->components.begin(); d != dst->components.end(); d++) { + stream << MakeSnakeCase(*d) + "::"; + } + return stream.str(); + } + + // Determine the relative namespace traversal needed to reference one + // namespace from another namespace. This is useful because it does not force + // the user to have a particular file layout. (If we output absolute + // namespace paths, that may require users to organize their Rust crates in a + // particular way.) + std::string GetRelativeNamespaceTraversal(const Namespace *src, + const Namespace *dst) const { + // calculate the path needed to reference dst from src. + // example: f(A::B::C, A::B::C) -> (none) + // example: f(A::B::C, A::B) -> super:: + // example: f(A::B::C, A::B::D) -> super::D + // example: f(A::B::C, A) -> super::super:: + // example: f(A::B::C, D) -> super::super::super::D + // example: f(A::B::C, D::E) -> super::super::super::D::E + // example: f(A, D::E) -> super::D::E + // does not include leaf object (typically a struct type). + + size_t i = 0; + std::stringstream stream; + + auto s = src->components.begin(); + auto d = dst->components.begin(); + for(;;) { + if (s == src->components.end()) { break; } + if (d == dst->components.end()) { break; } + if (*s != *d) { break; } + s++; + d++; + i++; + } + + for (; s != src->components.end(); s++) { + stream << "super::"; + } + for (; d != dst->components.end(); d++) { + stream << MakeSnakeCase(*d) + "::"; + } + return stream.str(); + } + + // Generate a comment from the schema. + void GenComment(const std::vector<std::string> &dc, const char *prefix = "") { + std::string text; + ::flatbuffers::GenComment(dc, &text, nullptr, prefix); + code_ += text + "\\"; + } + + // Return a Rust type from the table in idl.h. + std::string GetTypeBasic(const Type &type) const { + switch (GetFullType(type)) { + case ftInteger: + case ftFloat: + case ftBool: + case ftEnumKey: + case ftUnionKey: { break; } + default: { FLATBUFFERS_ASSERT(false && "incorrect type given");} + } + + // clang-format off + static const char * const ctypename[] = { + #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, \ + RTYPE) \ + #RTYPE, + FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD) + #undef FLATBUFFERS_TD + // clang-format on + }; + + if (type.enum_def) { return WrapInNameSpace(*type.enum_def); } + return ctypename[type.base_type]; + } + + // Look up the native type for an enum. This will always be an integer like + // u8, i32, etc. + std::string GetEnumTypeForDecl(const Type &type) { + const auto ft = GetFullType(type); + if (!(ft == ftEnumKey || ft == ftUnionKey)) { + FLATBUFFERS_ASSERT(false && "precondition failed in GetEnumTypeForDecl"); + } + + static const char *ctypename[] = { + // clang-format off + #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, \ + RTYPE) \ + #RTYPE, + FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD) + #undef FLATBUFFERS_TD + // clang-format on + }; + + // Enums can be bools, but their Rust representation must be a u8, as used + // in the repr attribute (#[repr(bool)] is an invalid attribute). + if (type.base_type == BASE_TYPE_BOOL) return "u8"; + return ctypename[type.base_type]; + } + + // Return a Rust type for any type (scalar, table, struct) specifically for + // using a FlatBuffer. + std::string GetTypeGet(const Type &type) const { + switch (GetFullType(type)) { + case ftInteger: + case ftFloat: + case ftBool: + case ftEnumKey: + case ftUnionKey: { + return GetTypeBasic(type); } + case ftTable: { + return WrapInNameSpace(type.struct_def->defined_namespace, + type.struct_def->name) + "<'a>"; } + default: { + return WrapInNameSpace(type.struct_def->defined_namespace, + type.struct_def->name); } + } + } + + std::string GetEnumValUse(const EnumDef &enum_def, + const EnumVal &enum_val) const { + return Name(enum_def) + "::" + Name(enum_val); + } + + // Generate an enum declaration, + // an enum string lookup table, + // an enum match function, + // and an enum array of values + void GenEnum(const EnumDef &enum_def) { + code_.SetValue("ENUM_NAME", Name(enum_def)); + code_.SetValue("BASE_TYPE", GetEnumTypeForDecl(enum_def.underlying_type)); + + GenComment(enum_def.doc_comment); + code_ += "#[allow(non_camel_case_types)]"; + code_ += "#[repr({{BASE_TYPE}})]"; + code_ += "#[derive(Clone, Copy, PartialEq, Debug)]"; + code_ += "pub enum " + Name(enum_def) + " {"; + + int64_t anyv = 0; + const EnumVal *minv = nullptr, *maxv = nullptr; + for (auto it = enum_def.vals.vec.begin(); it != enum_def.vals.vec.end(); + ++it) { + const auto &ev = **it; + + GenComment(ev.doc_comment, " "); + code_.SetValue("KEY", Name(ev)); + code_.SetValue("VALUE", NumToString(ev.value)); + code_ += " {{KEY}} = {{VALUE}},"; + + minv = !minv || minv->value > ev.value ? &ev : minv; + maxv = !maxv || maxv->value < ev.value ? &ev : maxv; + anyv |= ev.value; + } + + code_ += ""; + code_ += "}"; + code_ += ""; + + code_.SetValue("ENUM_NAME", Name(enum_def)); + code_.SetValue("ENUM_NAME_SNAKE", MakeSnakeCase(Name(enum_def))); + code_.SetValue("ENUM_NAME_CAPS", MakeUpper(MakeSnakeCase(Name(enum_def)))); + code_.SetValue("ENUM_MIN_BASE_VALUE", NumToString(minv->value)); + code_.SetValue("ENUM_MAX_BASE_VALUE", NumToString(maxv->value)); + + // Generate enum constants, and impls for Follow, EndianScalar, and Push. + code_ += "const ENUM_MIN_{{ENUM_NAME_CAPS}}: {{BASE_TYPE}} = \\"; + code_ += "{{ENUM_MIN_BASE_VALUE}};"; + code_ += "const ENUM_MAX_{{ENUM_NAME_CAPS}}: {{BASE_TYPE}} = \\"; + code_ += "{{ENUM_MAX_BASE_VALUE}};"; + code_ += ""; + code_ += "impl<'a> flatbuffers::Follow<'a> for {{ENUM_NAME}} {"; + code_ += " type Inner = Self;"; + code_ += " #[inline]"; + code_ += " fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {"; + code_ += " flatbuffers::read_scalar_at::<Self>(buf, loc)"; + code_ += " }"; + code_ += "}"; + code_ += ""; + code_ += "impl flatbuffers::EndianScalar for {{ENUM_NAME}} {"; + code_ += " #[inline]"; + code_ += " fn to_little_endian(self) -> Self {"; + code_ += " let n = {{BASE_TYPE}}::to_le(self as {{BASE_TYPE}});"; + code_ += " let p = &n as *const {{BASE_TYPE}} as *const {{ENUM_NAME}};"; + code_ += " unsafe { *p }"; + code_ += " }"; + code_ += " #[inline]"; + code_ += " fn from_little_endian(self) -> Self {"; + code_ += " let n = {{BASE_TYPE}}::from_le(self as {{BASE_TYPE}});"; + code_ += " let p = &n as *const {{BASE_TYPE}} as *const {{ENUM_NAME}};"; + code_ += " unsafe { *p }"; + code_ += " }"; + code_ += "}"; + code_ += ""; + code_ += "impl flatbuffers::Push for {{ENUM_NAME}} {"; + code_ += " type Output = {{ENUM_NAME}};"; + code_ += " #[inline]"; + code_ += " fn push(&self, dst: &mut [u8], _rest: &[u8]) {"; + code_ += " flatbuffers::emplace_scalar::<{{ENUM_NAME}}>" + "(dst, *self);"; + code_ += " }"; + code_ += "}"; + code_ += ""; + + // Generate an array of all enumeration values. + auto num_fields = NumToString(enum_def.vals.vec.size()); + code_ += "#[allow(non_camel_case_types)]"; + code_ += "const ENUM_VALUES_{{ENUM_NAME_CAPS}}:[{{ENUM_NAME}}; " + + num_fields + "] = ["; + for (auto it = enum_def.vals.vec.begin(); it != enum_def.vals.vec.end(); + ++it) { + const auto &ev = **it; + auto value = GetEnumValUse(enum_def, ev); + auto suffix = *it != enum_def.vals.vec.back() ? "," : ""; + code_ += " " + value + suffix; + } + code_ += "];"; + code_ += ""; + + // Generate a string table for enum values. + // Problem is, if values are very sparse that could generate really big + // tables. Ideally in that case we generate a map lookup instead, but for + // the moment we simply don't output a table at all. + auto range = + enum_def.vals.vec.back()->value - enum_def.vals.vec.front()->value + 1; + // Average distance between values above which we consider a table + // "too sparse". Change at will. + static const int kMaxSparseness = 5; + if (range / static_cast<int64_t>(enum_def.vals.vec.size()) < + kMaxSparseness) { + code_ += "#[allow(non_camel_case_types)]"; + code_ += "const ENUM_NAMES_{{ENUM_NAME_CAPS}}:[&'static str; " + + NumToString(range) + "] = ["; + + auto val = enum_def.vals.vec.front()->value; + for (auto it = enum_def.vals.vec.begin(); it != enum_def.vals.vec.end(); + ++it) { + const auto &ev = **it; + while (val++ != ev.value) { code_ += " \"\","; } + auto suffix = *it != enum_def.vals.vec.back() ? "," : ""; + code_ += " \"" + Name(ev) + "\"" + suffix; + } + code_ += "];"; + code_ += ""; + + code_ += "pub fn enum_name_{{ENUM_NAME_SNAKE}}(e: {{ENUM_NAME}}) -> " + "&'static str {"; + + code_ += " let index: usize = e as usize\\"; + if (enum_def.vals.vec.front()->value) { + auto vals = GetEnumValUse(enum_def, *enum_def.vals.vec.front()); + code_ += " - " + vals + " as usize\\"; + } + code_ += ";"; + + code_ += " ENUM_NAMES_{{ENUM_NAME_CAPS}}[index]"; + code_ += "}"; + code_ += ""; + } + + if (enum_def.is_union) { + // Generate tyoesafe offset(s) for unions + code_.SetValue("NAME", Name(enum_def)); + code_.SetValue("UNION_OFFSET_NAME", Name(enum_def) + "UnionTableOffset"); + code_ += "pub struct {{UNION_OFFSET_NAME}} {}"; + } + } + + std::string GetFieldOffsetName(const FieldDef &field) { + return "VT_" + MakeUpper(Name(field)); + } + + std::string GetDefaultConstant(const FieldDef &field) { + return field.value.type.base_type == BASE_TYPE_FLOAT + ? field.value.constant + "" + : field.value.constant; + } + + std::string GetDefaultScalarValue(const FieldDef &field) { + switch (GetFullType(field.value.type)) { + case ftInteger: { return GetDefaultConstant(field); } + case ftFloat: { return GetDefaultConstant(field); } + case ftBool: { + return field.value.constant == "0" ? "false" : "true"; + } + case ftUnionKey: + case ftEnumKey: { + auto ev = field.value.type.enum_def->ReverseLookup( + StringToInt(field.value.constant.c_str()), false); + assert(ev); + return WrapInNameSpace(field.value.type.enum_def->defined_namespace, + GetEnumValUse(*field.value.type.enum_def, *ev)); + } + + // All pointer-ish types have a default value of None, because they are + // wrapped in Option. + default: { return "None"; } + } + } + + // Create the return type for fields in the *BuilderArgs structs that are + // used to create Tables. + // + // Note: we could make all inputs to the BuilderArgs be an Option, as well + // as all outputs. But, the UX of Flatbuffers is that the user doesn't get to + // know if the value is default or not, because there are three ways to + // return a default value: + // 1) return a stored value that happens to be the default, + // 2) return a hardcoded value because the relevant vtable field is not in + // the vtable, or + // 3) return a hardcoded value because the vtable field value is set to zero. + std::string TableBuilderArgsDefnType(const FieldDef &field, + const std::string lifetime) { + const Type& type = field.value.type; + + switch (GetFullType(type)) { + case ftInteger: + case ftFloat: + case ftBool: { + const auto typname = GetTypeBasic(type); + return typname; + } + case ftStruct: { + const auto typname = WrapInNameSpace(*type.struct_def); + return "Option<&" + lifetime + " " + typname + ">"; + } + case ftTable: { + const auto typname = WrapInNameSpace(*type.struct_def); + return "Option<flatbuffers::WIPOffset<" + typname + "<" + lifetime + \ + ">>>"; + } + case ftString: { + return "Option<flatbuffers::WIPOffset<&" + lifetime + " str>>"; + } + case ftEnumKey: + case ftUnionKey: { + const auto typname = WrapInNameSpace(*type.enum_def); + return typname; + } + case ftUnionValue: { + const auto typname = WrapInNameSpace(*type.enum_def); + return "Option<flatbuffers::WIPOffset<flatbuffers::UnionWIPOffset>>"; + } + + case ftVectorOfInteger: + case ftVectorOfFloat: { + const auto typname = GetTypeBasic(type.VectorType()); + return "Option<flatbuffers::WIPOffset<flatbuffers::Vector<" + \ + lifetime + ", " + typname + ">>>"; + } + case ftVectorOfBool: { + return "Option<flatbuffers::WIPOffset<flatbuffers::Vector<" + \ + lifetime + ", bool>>>"; + } + case ftVectorOfEnumKey: { + const auto typname = WrapInNameSpace(*type.enum_def); + return "Option<flatbuffers::WIPOffset<flatbuffers::Vector<" + \ + lifetime + ", " + typname + ">>>"; + } + case ftVectorOfStruct: { + const auto typname = WrapInNameSpace(*type.struct_def); + return "Option<flatbuffers::WIPOffset<flatbuffers::Vector<" + \ + lifetime + ", " + typname + ">>>"; + } + case ftVectorOfTable: { + const auto typname = WrapInNameSpace(*type.struct_def); + return "Option<flatbuffers::WIPOffset<flatbuffers::Vector<" + \ + lifetime + ", flatbuffers::ForwardsUOffset<" + typname + \ + "<" + lifetime + ">>>>>"; + } + case ftVectorOfString: { + return "Option<flatbuffers::WIPOffset<flatbuffers::Vector<" + \ + lifetime + ", flatbuffers::ForwardsUOffset<&" + lifetime + \ + " str>>>>"; + } + case ftVectorOfUnionValue: { + const auto typname = WrapInNameSpace(*type.enum_def) + \ + "UnionTableOffset"; + return "Option<flatbuffers::WIPOffset<flatbuffers::Vector<" + \ + lifetime + ", flatbuffers::ForwardsUOffset<" + "flatbuffers::Table<" + lifetime + ">>>>"; + } + } + return "INVALID_CODE_GENERATION"; // for return analysis + } + + std::string TableBuilderArgsDefaultValue(const FieldDef &field) { + return GetDefaultScalarValue(field); + } + std::string TableBuilderAddFuncDefaultValue(const FieldDef &field) { + switch (GetFullType(field.value.type)) { + case ftUnionKey: + case ftEnumKey: { + const std::string basetype = GetTypeBasic(field.value.type); + return GetDefaultScalarValue(field); + } + + default: { return GetDefaultScalarValue(field); } + } + } + + std::string TableBuilderArgsAddFuncType(const FieldDef &field, + const std::string lifetime) { + const Type& type = field.value.type; + + switch (GetFullType(field.value.type)) { + case ftVectorOfStruct: { + const auto typname = WrapInNameSpace(*type.struct_def); + return "flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime + \ + ", " + typname + ">>"; + } + case ftVectorOfTable: { + const auto typname = WrapInNameSpace(*type.struct_def); + return "flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime + \ + ", flatbuffers::ForwardsUOffset<" + typname + \ + "<" + lifetime + ">>>>"; + } + case ftVectorOfInteger: + case ftVectorOfFloat: { + const auto typname = GetTypeBasic(type.VectorType()); + return "flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime + \ + ", " + typname + ">>"; + } + case ftVectorOfBool: { + return "flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime + \ + ", bool>>"; + } + case ftVectorOfString: { + return "flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime + \ + ", flatbuffers::ForwardsUOffset<&" + lifetime + " str>>>"; + } + case ftVectorOfEnumKey: { + const auto typname = WrapInNameSpace(*type.enum_def); + return "flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime + \ + ", " + typname + ">>"; + } + case ftVectorOfUnionValue: { + const auto typname = WrapInNameSpace(*type.enum_def); + return "flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime + \ + ", flatbuffers::ForwardsUOffset<flatbuffers::Table<" + \ + lifetime + ">>>"; + } + case ftEnumKey: { + const auto typname = WrapInNameSpace(*type.enum_def); + return typname; + } + case ftStruct: { + const auto typname = WrapInNameSpace(*type.struct_def); + return "&" + lifetime + " " + typname + ""; + } + case ftTable: { + const auto typname = WrapInNameSpace(*type.struct_def); + return "flatbuffers::WIPOffset<" + typname + "<" + lifetime + ">>"; + } + case ftInteger: + case ftFloat: { + const auto typname = GetTypeBasic(type); + return typname; + } + case ftBool: { + return "bool"; + } + case ftString: { + return "flatbuffers::WIPOffset<&" + lifetime + " str>"; + } + case ftUnionKey: { + const auto typname = WrapInNameSpace(*type.enum_def); + return typname; + } + case ftUnionValue: { + const auto typname = WrapInNameSpace(*type.enum_def); + return "flatbuffers::WIPOffset<flatbuffers::UnionWIPOffset>"; + } + } + + return "INVALID_CODE_GENERATION"; // for return analysis + } + + std::string TableBuilderArgsAddFuncBody(const FieldDef &field) { + const Type& type = field.value.type; + + switch (GetFullType(field.value.type)) { + case ftInteger: + case ftFloat: { + const auto typname = GetTypeBasic(field.value.type); + return "self.fbb_.push_slot::<" + typname + ">"; + } + case ftBool: { + return "self.fbb_.push_slot::<bool>"; + } + + case ftEnumKey: + case ftUnionKey: { + const auto underlying_typname = GetTypeBasic(type); + return "self.fbb_.push_slot::<" + underlying_typname + ">"; + } + + case ftStruct: { + const std::string typname = WrapInNameSpace(*type.struct_def); + return "self.fbb_.push_slot_always::<&" + typname + ">"; + } + case ftTable: { + const auto typname = WrapInNameSpace(*type.struct_def); + return "self.fbb_.push_slot_always::<flatbuffers::WIPOffset<" + \ + typname + ">>"; + } + + case ftUnionValue: + case ftString: + case ftVectorOfInteger: + case ftVectorOfFloat: + case ftVectorOfBool: + case ftVectorOfEnumKey: + case ftVectorOfStruct: + case ftVectorOfTable: + case ftVectorOfString: + case ftVectorOfUnionValue: { + return "self.fbb_.push_slot_always::<flatbuffers::WIPOffset<_>>"; + } + } + return "INVALID_CODE_GENERATION"; // for return analysis + } + + std::string GenTableAccessorFuncReturnType(const FieldDef &field, + const std::string lifetime) { + const Type& type = field.value.type; + + switch (GetFullType(field.value.type)) { + case ftInteger: + case ftFloat: { + const auto typname = GetTypeBasic(type); + return typname; + } + case ftBool: { + return "bool"; + } + case ftStruct: { + const auto typname = WrapInNameSpace(*type.struct_def); + return WrapInOptionIfNotRequired("&" + lifetime + " " + typname, field.required); + } + case ftTable: { + const auto typname = WrapInNameSpace(*type.struct_def); + return WrapInOptionIfNotRequired(typname + "<" + lifetime + ">", field.required); + } + case ftEnumKey: + case ftUnionKey: { + const auto typname = WrapInNameSpace(*type.enum_def); + return typname; + } + + case ftUnionValue: { + return WrapInOptionIfNotRequired("flatbuffers::Table<" + lifetime + ">", field.required); + } + case ftString: { + return WrapInOptionIfNotRequired("&" + lifetime + " str", field.required); + } + case ftVectorOfInteger: + case ftVectorOfFloat: { + const auto typname = GetTypeBasic(type.VectorType()); + if (IsOneByte(type.VectorType().base_type)) { + return WrapInOptionIfNotRequired("&" + lifetime + " [" + typname + "]", field.required); + } + return WrapInOptionIfNotRequired("flatbuffers::Vector<" + lifetime + ", " + typname + ">", field.required); + } + case ftVectorOfBool: { + return WrapInOptionIfNotRequired("&" + lifetime + " [bool]", field.required); + } + case ftVectorOfEnumKey: { + const auto typname = WrapInNameSpace(*type.enum_def); + return WrapInOptionIfNotRequired("flatbuffers::Vector<" + lifetime + ", " + typname + ">", field.required); + } + case ftVectorOfStruct: { + const auto typname = WrapInNameSpace(*type.struct_def); + return WrapInOptionIfNotRequired("&" + lifetime + " [" + typname + "]", field.required); + } + case ftVectorOfTable: { + const auto typname = WrapInNameSpace(*type.struct_def); + return WrapInOptionIfNotRequired("flatbuffers::Vector<flatbuffers::ForwardsUOffset<" + \ + typname + "<" + lifetime + ">>>", field.required); + } + case ftVectorOfString: { + return WrapInOptionIfNotRequired("flatbuffers::Vector<flatbuffers::ForwardsUOffset<&" + \ + lifetime + " str>>", field.required); + } + case ftVectorOfUnionValue: { + FLATBUFFERS_ASSERT(false && "vectors of unions are not yet supported"); + // TODO(rw): when we do support these, we should consider using the + // Into trait to convert tables to typesafe union values. + return "INVALID_CODE_GENERATION"; // for return analysis + } + } + return "INVALID_CODE_GENERATION"; // for return analysis + } + + std::string GenTableAccessorFuncBody(const FieldDef &field, + const std::string lifetime, + const std::string offset_prefix) { + const std::string offset_name = offset_prefix + "::" + \ + GetFieldOffsetName(field); + const Type& type = field.value.type; + + switch (GetFullType(field.value.type)) { + case ftInteger: + case ftFloat: + case ftBool: { + const auto typname = GetTypeBasic(type); + const auto default_value = GetDefaultScalarValue(field); + return "self._tab.get::<" + typname + ">(" + offset_name + ", Some(" + \ + default_value + ")).unwrap()"; + } + case ftStruct: { + const auto typname = WrapInNameSpace(*type.struct_def); + return AddUnwrapIfRequired("self._tab.get::<" + typname + ">(" + offset_name + ", None)", field.required); + } + case ftTable: { + const auto typname = WrapInNameSpace(*type.struct_def); + return AddUnwrapIfRequired("self._tab.get::<flatbuffers::ForwardsUOffset<" + \ + typname + "<" + lifetime + ">>>(" + offset_name + ", None)", field.required); + } + case ftUnionValue: { + return AddUnwrapIfRequired("self._tab.get::<flatbuffers::ForwardsUOffset<" + "flatbuffers::Table<" + lifetime + ">>>(" + offset_name + \ + ", None)", field.required); + } + case ftUnionKey: + case ftEnumKey: { + const auto underlying_typname = GetTypeBasic(type); + const auto typname = WrapInNameSpace(*type.enum_def); + const auto default_value = GetDefaultScalarValue(field); + return "self._tab.get::<" + typname + ">(" + offset_name + \ + ", Some(" + default_value + ")).unwrap()"; + } + case ftString: { + return AddUnwrapIfRequired("self._tab.get::<flatbuffers::ForwardsUOffset<&str>>(" + \ + offset_name + ", None)", field.required); + } + + case ftVectorOfInteger: + case ftVectorOfFloat: { + const auto typname = GetTypeBasic(type.VectorType()); + std::string s = "self._tab.get::<flatbuffers::ForwardsUOffset<" + "flatbuffers::Vector<" + lifetime + ", " + typname + \ + ">>>(" + offset_name + ", None)"; + // single-byte values are safe to slice + if (IsOneByte(type.VectorType().base_type)) { + s += ".map(|v| v.safe_slice())"; + } + return AddUnwrapIfRequired(s, field.required); + } + case ftVectorOfBool: { + return AddUnwrapIfRequired("self._tab.get::<flatbuffers::ForwardsUOffset<" + "flatbuffers::Vector<" + lifetime + ", bool>>>(" + \ + offset_name + ", None).map(|v| v.safe_slice())", field.required); + } + case ftVectorOfEnumKey: { + const auto typname = WrapInNameSpace(*type.enum_def); + return AddUnwrapIfRequired("self._tab.get::<flatbuffers::ForwardsUOffset<" + "flatbuffers::Vector<" + lifetime + ", " + typname + ">>>(" + \ + offset_name + ", None)", field.required); + } + case ftVectorOfStruct: { + const auto typname = WrapInNameSpace(*type.struct_def); + return AddUnwrapIfRequired("self._tab.get::<flatbuffers::ForwardsUOffset<" + "flatbuffers::Vector<" + typname + ">>>(" + \ + offset_name + ", None).map(|v| v.safe_slice() )", field.required); + } + case ftVectorOfTable: { + const auto typname = WrapInNameSpace(*type.struct_def); + return AddUnwrapIfRequired("self._tab.get::<flatbuffers::ForwardsUOffset<" + "flatbuffers::Vector<flatbuffers::ForwardsUOffset<" + typname + \ + "<" + lifetime + ">>>>>(" + offset_name + ", None)", field.required); + } + case ftVectorOfString: { + return AddUnwrapIfRequired("self._tab.get::<flatbuffers::ForwardsUOffset<" + "flatbuffers::Vector<flatbuffers::ForwardsUOffset<&" + \ + lifetime + " str>>>>(" + offset_name + ", None)", field.required); + } + case ftVectorOfUnionValue: { + FLATBUFFERS_ASSERT(false && "vectors of unions are not yet supported"); + return "INVALID_CODE_GENERATION"; // for return analysis + } + } + return "INVALID_CODE_GENERATION"; // for return analysis + } + + bool TableFieldReturnsOption(const Type& type) { + switch (GetFullType(type)) { + case ftInteger: + case ftFloat: + case ftBool: + case ftEnumKey: + case ftUnionKey: + return false; + default: return true; + } + } + + // Generate an accessor struct, builder struct, and create function for a + // table. + void GenTable(const StructDef &struct_def) { + GenComment(struct_def.doc_comment); + + code_.SetValue("STRUCT_NAME", Name(struct_def)); + code_.SetValue("OFFSET_TYPELABEL", Name(struct_def) + "Offset"); + code_.SetValue("STRUCT_NAME_SNAKECASE", MakeSnakeCase(Name(struct_def))); + + // Generate an offset type, the base type, the Follow impl, and the + // init_from_table impl. + code_ += "pub enum {{OFFSET_TYPELABEL}} {}"; + code_ += "#[derive(Copy, Clone, Debug, PartialEq)]"; + code_ += ""; + code_ += "pub struct {{STRUCT_NAME}}<'a> {"; + code_ += " pub _tab: flatbuffers::Table<'a>,"; + code_ += "}"; + code_ += ""; + code_ += "impl<'a> flatbuffers::Follow<'a> for {{STRUCT_NAME}}<'a> {"; + code_ += " type Inner = {{STRUCT_NAME}}<'a>;"; + code_ += " #[inline]"; + code_ += " fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {"; + code_ += " Self {"; + code_ += " _tab: flatbuffers::Table { buf: buf, loc: loc },"; + code_ += " }"; + code_ += " }"; + code_ += "}"; + code_ += ""; + code_ += "impl<'a> {{STRUCT_NAME}}<'a> {"; + code_ += " #[inline]"; + code_ += " pub fn init_from_table(table: flatbuffers::Table<'a>) -> " + "Self {"; + code_ += " {{STRUCT_NAME}} {"; + code_ += " _tab: table,"; + code_ += " }"; + code_ += " }"; + + // Generate a convenient create* function that uses the above builder + // to create a table in one function call. + code_.SetValue("MAYBE_US", + struct_def.fields.vec.size() == 0 ? "_" : ""); + code_.SetValue("MAYBE_LT", + TableBuilderArgsNeedsLifetime(struct_def) ? "<'args>" : ""); + code_ += " #[allow(unused_mut)]"; + code_ += " pub fn create<'bldr: 'args, 'args: 'mut_bldr, 'mut_bldr>("; + code_ += " _fbb: " + "&'mut_bldr mut flatbuffers::FlatBufferBuilder<'bldr>,"; + code_ += " {{MAYBE_US}}args: &'args {{STRUCT_NAME}}Args{{MAYBE_LT}})" + " -> flatbuffers::WIPOffset<{{STRUCT_NAME}}<'bldr>> {"; + + code_ += " let mut builder = {{STRUCT_NAME}}Builder::new(_fbb);"; + for (size_t size = struct_def.sortbysize ? sizeof(largest_scalar_t) : 1; + size; size /= 2) { + for (auto it = struct_def.fields.vec.rbegin(); + it != struct_def.fields.vec.rend(); ++it) { + const auto &field = **it; + // TODO(rw): fully understand this sortbysize usage + if (!field.deprecated && (!struct_def.sortbysize || + size == SizeOf(field.value.type.base_type))) { + code_.SetValue("FIELD_NAME", Name(field)); + if (TableFieldReturnsOption(field.value.type)) { + code_ += " if let Some(x) = args.{{FIELD_NAME}} " + "{ builder.add_{{FIELD_NAME}}(x); }"; + } else { + code_ += " builder.add_{{FIELD_NAME}}(args.{{FIELD_NAME}});"; + } + } + } + } + code_ += " builder.finish()"; + code_ += " }"; + code_ += ""; + + // Generate field id constants. + if (struct_def.fields.vec.size() > 0) { + for (auto it = struct_def.fields.vec.begin(); + it != struct_def.fields.vec.end(); ++it) { + const auto &field = **it; + if (field.deprecated) { + // Deprecated fields won't be accessible. + continue; + } + + code_.SetValue("OFFSET_NAME", GetFieldOffsetName(field)); + code_.SetValue("OFFSET_VALUE", NumToString(field.value.offset)); + code_ += " pub const {{OFFSET_NAME}}: flatbuffers::VOffsetT = " + "{{OFFSET_VALUE}};"; + } + code_ += ""; + } + + // Generate the accessors. Each has one of two forms: + // + // If a value can be None: + // pub fn name(&'a self) -> Option<user_facing_type> { + // self._tab.get::<internal_type>(offset, defaultval) + // } + // + // If a value is always Some: + // pub fn name(&'a self) -> user_facing_type { + // self._tab.get::<internal_type>(offset, defaultval).unwrap() + // } + const auto offset_prefix = Name(struct_def); + for (auto it = struct_def.fields.vec.begin(); + it != struct_def.fields.vec.end(); ++it) { + const auto &field = **it; + if (field.deprecated) { + // Deprecated fields won't be accessible. + continue; + } + + code_.SetValue("FIELD_NAME", Name(field)); + code_.SetValue("RETURN_TYPE", + GenTableAccessorFuncReturnType(field, "'a")); + code_.SetValue("FUNC_BODY", + GenTableAccessorFuncBody(field, "'a", offset_prefix)); + + GenComment(field.doc_comment, " "); + code_ += " #[inline]"; + code_ += " pub fn {{FIELD_NAME}}(&self) -> {{RETURN_TYPE}} {"; + code_ += " {{FUNC_BODY}}"; + code_ += " }"; + + // Generate a comparison function for this field if it is a key. + if (field.key) { + GenKeyFieldMethods(field); + } + + // Generate a nested flatbuffer field, if applicable. + auto nested = field.attributes.Lookup("nested_flatbuffer"); + if (nested) { + std::string qualified_name = nested->constant; + auto nested_root = parser_.LookupStruct(nested->constant); + if (nested_root == nullptr) { + qualified_name = parser_.current_namespace_->GetFullyQualifiedName( + nested->constant); + nested_root = parser_.LookupStruct(qualified_name); + } + FLATBUFFERS_ASSERT(nested_root); // Guaranteed to exist by parser. + (void)nested_root; + + code_.SetValue("OFFSET_NAME", + offset_prefix + "::" + GetFieldOffsetName(field)); + code_ += " pub fn {{FIELD_NAME}}_nested_flatbuffer(&'a self) -> " + " Option<{{STRUCT_NAME}}<'a>> {"; + code_ += " match self.{{FIELD_NAME}}() {"; + code_ += " None => { None }"; + code_ += " Some(data) => {"; + code_ += " use self::flatbuffers::Follow;"; + code_ += " Some(<flatbuffers::ForwardsUOffset" + "<{{STRUCT_NAME}}<'a>>>::follow(data, 0))"; + code_ += " },"; + code_ += " }"; + code_ += " }"; + } + } + + // Explicit specializations for union accessors + for (auto it = struct_def.fields.vec.begin(); + it != struct_def.fields.vec.end(); ++it) { + const auto &field = **it; + if (field.deprecated || field.value.type.base_type != BASE_TYPE_UNION) { + continue; + } + + auto u = field.value.type.enum_def; + + code_.SetValue("FIELD_NAME", Name(field)); + + for (auto u_it = u->vals.vec.begin(); u_it != u->vals.vec.end(); ++u_it) { + auto &ev = **u_it; + if (ev.union_type.base_type == BASE_TYPE_NONE) { continue; } + + auto table_init_type = WrapInNameSpace( + ev.union_type.struct_def->defined_namespace, + ev.union_type.struct_def->name); + + code_.SetValue("U_ELEMENT_ENUM_TYPE", + WrapInNameSpace(u->defined_namespace, GetEnumValUse(*u, ev))); + code_.SetValue("U_ELEMENT_TABLE_TYPE", table_init_type); + code_.SetValue("U_ELEMENT_NAME", MakeSnakeCase(Name(ev))); + + code_ += " #[inline]"; + code_ += " #[allow(non_snake_case)]"; + code_ += " pub fn {{FIELD_NAME}}_as_{{U_ELEMENT_NAME}}(&'a self) -> " + "Option<{{U_ELEMENT_TABLE_TYPE}}> {"; + code_ += " if self.{{FIELD_NAME}}_type() == {{U_ELEMENT_ENUM_TYPE}} {"; + code_ += " self.{{FIELD_NAME}}().map(|u| " + "{{U_ELEMENT_TABLE_TYPE}}::init_from_table(u))"; + code_ += " } else {"; + code_ += " None"; + code_ += " }"; + code_ += " }"; + code_ += ""; + } + } + + code_ += "}"; // End of table impl. + code_ += ""; + + // Generate an args struct: + code_.SetValue("MAYBE_LT", + TableBuilderArgsNeedsLifetime(struct_def) ? "<'a>" : ""); + code_ += "pub struct {{STRUCT_NAME}}Args{{MAYBE_LT}} {"; + for (auto it = struct_def.fields.vec.begin(); + it != struct_def.fields.vec.end(); ++it) { + const auto &field = **it; + if (!field.deprecated) { + code_.SetValue("PARAM_NAME", Name(field)); + code_.SetValue("PARAM_TYPE", TableBuilderArgsDefnType(field, "'a ")); + code_ += " pub {{PARAM_NAME}}: {{PARAM_TYPE}},"; + } + } + code_ += "}"; + + // Generate an impl of Default for the *Args type: + code_ += "impl<'a> Default for {{STRUCT_NAME}}Args{{MAYBE_LT}} {"; + code_ += " #[inline]"; + code_ += " fn default() -> Self {"; + code_ += " {{STRUCT_NAME}}Args {"; + for (auto it = struct_def.fields.vec.begin(); + it != struct_def.fields.vec.end(); ++it) { + const auto &field = **it; + if (!field.deprecated) { + code_.SetValue("PARAM_VALUE", TableBuilderArgsDefaultValue(field)); + code_.SetValue("REQ", field.required ? " // required field" : ""); + code_.SetValue("PARAM_NAME", Name(field)); + code_ += " {{PARAM_NAME}}: {{PARAM_VALUE}},{{REQ}}"; + } + } + code_ += " }"; + code_ += " }"; + code_ += "}"; + + // Generate a builder struct: + code_ += "pub struct {{STRUCT_NAME}}Builder<'a: 'b, 'b> {"; + code_ += " fbb_: &'b mut flatbuffers::FlatBufferBuilder<'a>,"; + code_ += " start_: flatbuffers::WIPOffset<" + "flatbuffers::TableUnfinishedWIPOffset>,"; + code_ += "}"; + + // Generate builder functions: + code_ += "impl<'a: 'b, 'b> {{STRUCT_NAME}}Builder<'a, 'b> {"; + for (auto it = struct_def.fields.vec.begin(); + it != struct_def.fields.vec.end(); ++it) { + const auto &field = **it; + if (!field.deprecated) { + const bool is_scalar = IsScalar(field.value.type.base_type); + + std::string offset = GetFieldOffsetName(field); + std::string name = Name(field); + std::string value = GetDefaultScalarValue(field); + + // Generate functions to add data, which take one of two forms. + // + // If a value has a default: + // fn add_x(x_: type) { + // fbb_.push_slot::<type>(offset, x_, Some(default)); + // } + // + // If a value does not have a default: + // fn add_x(x_: type) { + // fbb_.push_slot_always::<type>(offset, x_); + // } + code_.SetValue("FIELD_NAME", Name(field)); + code_.SetValue("FIELD_OFFSET", Name(struct_def) + "::" + offset); + code_.SetValue("FIELD_TYPE", TableBuilderArgsAddFuncType(field, "'b ")); + code_.SetValue("FUNC_BODY", TableBuilderArgsAddFuncBody(field)); + code_ += " #[inline]"; + code_ += " pub fn add_{{FIELD_NAME}}(&mut self, {{FIELD_NAME}}: " + "{{FIELD_TYPE}}) {"; + if (is_scalar) { + code_.SetValue("FIELD_DEFAULT_VALUE", + TableBuilderAddFuncDefaultValue(field)); + code_ += " {{FUNC_BODY}}({{FIELD_OFFSET}}, {{FIELD_NAME}}, " + "{{FIELD_DEFAULT_VALUE}});"; + } else { + code_ += " {{FUNC_BODY}}({{FIELD_OFFSET}}, {{FIELD_NAME}});"; + } + code_ += " }"; + } + } + + // Struct initializer (all fields required); + code_ += " #[inline]"; + code_ += + " pub fn new(_fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>) -> " + "{{STRUCT_NAME}}Builder<'a, 'b> {"; + code_.SetValue("NUM_FIELDS", NumToString(struct_def.fields.vec.size())); + code_ += " let start = _fbb.start_table();"; + code_ += " {{STRUCT_NAME}}Builder {"; + code_ += " fbb_: _fbb,"; + code_ += " start_: start,"; + code_ += " }"; + code_ += " }"; + + // finish() function. + code_ += " #[inline]"; + code_ += " pub fn finish(self) -> " + "flatbuffers::WIPOffset<{{STRUCT_NAME}}<'a>> {"; + code_ += " let o = self.fbb_.end_table(self.start_);"; + + for (auto it = struct_def.fields.vec.begin(); + it != struct_def.fields.vec.end(); ++it) { + const auto &field = **it; + if (!field.deprecated && field.required) { + code_.SetValue("FIELD_NAME", MakeSnakeCase(Name(field))); + code_.SetValue("OFFSET_NAME", GetFieldOffsetName(field)); + code_ += " self.fbb_.required(o, {{STRUCT_NAME}}::{{OFFSET_NAME}}," + "\"{{FIELD_NAME}}\");"; + } + } + code_ += " flatbuffers::WIPOffset::new(o.value())"; + code_ += " }"; + code_ += "}"; + code_ += ""; + } + + // Generate functions to compare tables and structs by key. This function + // must only be called if the field key is defined. + void GenKeyFieldMethods(const FieldDef &field) { + FLATBUFFERS_ASSERT(field.key); + + code_.SetValue("KEY_TYPE", GenTableAccessorFuncReturnType(field, "")); + + code_ += " #[inline]"; + code_ += " pub fn key_compare_less_than(&self, o: &{{STRUCT_NAME}}) -> " + " bool {"; + code_ += " self.{{FIELD_NAME}}() < o.{{FIELD_NAME}}()"; + code_ += " }"; + code_ += ""; + code_ += " #[inline]"; + code_ += " pub fn key_compare_with_value(&self, val: {{KEY_TYPE}}) -> " + " ::std::cmp::Ordering {"; + code_ += " let key = self.{{FIELD_NAME}}();"; + code_ += " key.cmp(&val)"; + code_ += " }"; + } + + // Generate functions for accessing the root table object. This function + // must only be called if the root table is defined. + void GenRootTableFuncs(const StructDef &struct_def) { + FLATBUFFERS_ASSERT(parser_.root_struct_def_ && "root table not defined"); + auto name = Name(struct_def); + + code_.SetValue("STRUCT_NAME", name); + code_.SetValue("STRUCT_NAME_SNAKECASE", MakeSnakeCase(name)); + code_.SetValue("STRUCT_NAME_CAPS", MakeUpper(MakeSnakeCase(name))); + + // The root datatype accessors: + code_ += "#[inline]"; + code_ += + "pub fn get_root_as_{{STRUCT_NAME_SNAKECASE}}<'a>(buf: &'a [u8])" + " -> {{STRUCT_NAME}}<'a> {"; + code_ += " flatbuffers::get_root::<{{STRUCT_NAME}}<'a>>(buf)"; + code_ += "}"; + code_ += ""; + + code_ += "#[inline]"; + code_ += "pub fn get_size_prefixed_root_as_{{STRUCT_NAME_SNAKECASE}}" + "<'a>(buf: &'a [u8]) -> {{STRUCT_NAME}}<'a> {"; + code_ += " flatbuffers::get_size_prefixed_root::<{{STRUCT_NAME}}<'a>>" + "(buf)"; + code_ += "}"; + code_ += ""; + + if (parser_.file_identifier_.length()) { + // Declare the identifier + code_ += "pub const {{STRUCT_NAME_CAPS}}_IDENTIFIER: &'static str\\"; + code_ += " = \"" + parser_.file_identifier_ + "\";"; + code_ += ""; + + // Check if a buffer has the identifier. + code_ += "#[inline]"; + code_ += "pub fn {{STRUCT_NAME_SNAKECASE}}_buffer_has_identifier\\"; + code_ += "(buf: &[u8]) -> bool {"; + code_ += " return flatbuffers::buffer_has_identifier(buf, \\"; + code_ += "{{STRUCT_NAME_CAPS}}_IDENTIFIER, false);"; + code_ += "}"; + code_ += ""; + code_ += "#[inline]"; + code_ += "pub fn {{STRUCT_NAME_SNAKECASE}}_size_prefixed\\"; + code_ += "_buffer_has_identifier(buf: &[u8]) -> bool {"; + code_ += " return flatbuffers::buffer_has_identifier(buf, \\"; + code_ += "{{STRUCT_NAME_CAPS}}_IDENTIFIER, true);"; + code_ += "}"; + code_ += ""; + } + + if (parser_.file_extension_.length()) { + // Return the extension + code_ += "pub const {{STRUCT_NAME_CAPS}}_EXTENSION: &'static str = \\"; + code_ += "\"" + parser_.file_extension_ + "\";"; + code_ += ""; + } + + // Finish a buffer with a given root object: + code_.SetValue("OFFSET_TYPELABEL", Name(struct_def) + "Offset"); + code_ += "#[inline]"; + code_ += "pub fn finish_{{STRUCT_NAME_SNAKECASE}}_buffer<'a, 'b>("; + code_ += " fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>,"; + code_ += " root: flatbuffers::WIPOffset<{{STRUCT_NAME}}<'a>>) {"; + if (parser_.file_identifier_.length()) { + code_ += " fbb.finish(root, Some({{STRUCT_NAME_CAPS}}_IDENTIFIER));"; + } else { + code_ += " fbb.finish(root, None);"; + } + code_ += "}"; + code_ += ""; + code_ += "#[inline]"; + code_ += "pub fn finish_size_prefixed_{{STRUCT_NAME_SNAKECASE}}_buffer" + "<'a, 'b>(" + "fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>, " + "root: flatbuffers::WIPOffset<{{STRUCT_NAME}}<'a>>) {"; + if (parser_.file_identifier_.length()) { + code_ += " fbb.finish_size_prefixed(root, " + "Some({{STRUCT_NAME_CAPS}}_IDENTIFIER));"; + } else { + code_ += " fbb.finish_size_prefixed(root, None);"; + } + code_ += "}"; + } + + static void GenPadding( + const FieldDef &field, std::string *code_ptr, int *id, + const std::function<void(int bits, std::string *code_ptr, int *id)> &f) { + if (field.padding) { + for (int i = 0; i < 4; i++) { + if (static_cast<int>(field.padding) & (1 << i)) { + f((1 << i) * 8, code_ptr, id); + } + } + assert(!(field.padding & ~0xF)); + } + } + + static void PaddingDefinition(int bits, std::string *code_ptr, int *id) { + *code_ptr += " padding" + NumToString((*id)++) + "__: u" + \ + NumToString(bits) + ","; + } + + static void PaddingInitializer(int bits, std::string *code_ptr, int *id) { + (void)bits; + *code_ptr += "padding" + NumToString((*id)++) + "__: 0,"; + } + + // Generate an accessor struct with constructor for a flatbuffers struct. + void GenStruct(const StructDef &struct_def) { + // Generates manual padding and alignment. + // Variables are private because they contain little endian data on all + // platforms. + GenComment(struct_def.doc_comment); + code_.SetValue("ALIGN", NumToString(struct_def.minalign)); + code_.SetValue("STRUCT_NAME", Name(struct_def)); + + code_ += "// struct {{STRUCT_NAME}}, aligned to {{ALIGN}}"; + code_ += "#[repr(C, align({{ALIGN}}))]"; + + // PartialEq is useful to derive because we can correctly compare structs + // for equality by just comparing their underlying byte data. This doesn't + // hold for PartialOrd/Ord. + code_ += "#[derive(Clone, Copy, Debug, PartialEq)]"; + code_ += "pub struct {{STRUCT_NAME}} {"; + + int padding_id = 0; + for (auto it = struct_def.fields.vec.begin(); + it != struct_def.fields.vec.end(); ++it) { + const auto &field = **it; + code_.SetValue("FIELD_TYPE", GetTypeGet(field.value.type)); + code_.SetValue("FIELD_NAME", Name(field)); + code_ += " {{FIELD_NAME}}_: {{FIELD_TYPE}},"; + + if (field.padding) { + std::string padding; + GenPadding(field, &padding, &padding_id, PaddingDefinition); + code_ += padding; + } + } + + code_ += "} // pub struct {{STRUCT_NAME}}"; + + // Generate impls for SafeSliceAccess (because all structs are endian-safe), + // Follow for the value type, Follow for the reference type, Push for the + // value type, and Push for the reference type. + code_ += "impl flatbuffers::SafeSliceAccess for {{STRUCT_NAME}} {}"; + code_ += "impl<'a> flatbuffers::Follow<'a> for {{STRUCT_NAME}} {"; + code_ += " type Inner = &'a {{STRUCT_NAME}};"; + code_ += " #[inline]"; + code_ += " fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {"; + code_ += " <&'a {{STRUCT_NAME}}>::follow(buf, loc)"; + code_ += " }"; + code_ += "}"; + code_ += "impl<'a> flatbuffers::Follow<'a> for &'a {{STRUCT_NAME}} {"; + code_ += " type Inner = &'a {{STRUCT_NAME}};"; + code_ += " #[inline]"; + code_ += " fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {"; + code_ += " flatbuffers::follow_cast_ref::<{{STRUCT_NAME}}>(buf, loc)"; + code_ += " }"; + code_ += "}"; + code_ += "impl<'b> flatbuffers::Push for {{STRUCT_NAME}} {"; + code_ += " type Output = {{STRUCT_NAME}};"; + code_ += " #[inline]"; + code_ += " fn push(&self, dst: &mut [u8], _rest: &[u8]) {"; + code_ += " let src = unsafe {"; + code_ += " ::std::slice::from_raw_parts(" + "self as *const {{STRUCT_NAME}} as *const u8, Self::size())"; + code_ += " };"; + code_ += " dst.copy_from_slice(src);"; + code_ += " }"; + code_ += "}"; + code_ += "impl<'b> flatbuffers::Push for &'b {{STRUCT_NAME}} {"; + code_ += " type Output = {{STRUCT_NAME}};"; + code_ += ""; + code_ += " #[inline]"; + code_ += " fn push(&self, dst: &mut [u8], _rest: &[u8]) {"; + code_ += " let src = unsafe {"; + code_ += " ::std::slice::from_raw_parts(" + "*self as *const {{STRUCT_NAME}} as *const u8, Self::size())"; + code_ += " };"; + code_ += " dst.copy_from_slice(src);"; + code_ += " }"; + code_ += "}"; + code_ += ""; + code_ += ""; + + // Generate a constructor that takes all fields as arguments. + code_ += "impl {{STRUCT_NAME}} {"; + std::string arg_list; + std::string init_list; + padding_id = 0; + for (auto it = struct_def.fields.vec.begin(); + it != struct_def.fields.vec.end(); ++it) { + const auto &field = **it; + const auto member_name = Name(field) + "_"; + const auto reference = StructMemberAccessNeedsCopy(field.value.type) + ? "" : "&'a "; + const auto arg_name = "_" + Name(field); + const auto arg_type = reference + GetTypeGet(field.value.type); + + if (it != struct_def.fields.vec.begin()) { + arg_list += ", "; + } + arg_list += arg_name + ": "; + arg_list += arg_type; + init_list += " " + member_name; + if (StructMemberAccessNeedsCopy(field.value.type)) { + init_list += ": " + arg_name + ".to_little_endian(),\n"; + } else { + init_list += ": *" + arg_name + ",\n"; + } + } + + code_.SetValue("ARG_LIST", arg_list); + code_.SetValue("INIT_LIST", init_list); + code_ += " pub fn new<'a>({{ARG_LIST}}) -> Self {"; + code_ += " {{STRUCT_NAME}} {"; + code_ += "{{INIT_LIST}}"; + padding_id = 0; + for (auto it = struct_def.fields.vec.begin(); + it != struct_def.fields.vec.end(); ++it) { + const auto &field = **it; + if (field.padding) { + std::string padding; + GenPadding(field, &padding, &padding_id, PaddingInitializer); + code_ += " " + padding; + } + } + code_ += " }"; + code_ += " }"; + + // Generate accessor methods for the struct. + for (auto it = struct_def.fields.vec.begin(); + it != struct_def.fields.vec.end(); ++it) { + const auto &field = **it; + + auto field_type = TableBuilderArgsAddFuncType(field, "'a"); + auto member = "self." + Name(field) + "_"; + auto value = StructMemberAccessNeedsCopy(field.value.type) ? + member + ".from_little_endian()" : member; + + code_.SetValue("FIELD_NAME", Name(field)); + code_.SetValue("FIELD_TYPE", field_type); + code_.SetValue("FIELD_VALUE", value); + code_.SetValue("REF", IsStruct(field.value.type) ? "&" : ""); + + GenComment(field.doc_comment, " "); + code_ += " pub fn {{FIELD_NAME}}<'a>(&'a self) -> {{FIELD_TYPE}} {"; + code_ += " {{REF}}{{FIELD_VALUE}}"; + code_ += " }"; + + // Generate a comparison function for this field if it is a key. + if (field.key) { + GenKeyFieldMethods(field); + } + } + code_ += "}"; + code_ += ""; + } + + void GenNamespaceImports(const int white_spaces) { + std::string indent = std::string(white_spaces, ' '); + code_ += indent + "#![allow(dead_code)]"; + code_ += indent + "#![allow(unused_imports)]"; + code_ += ""; + code_ += indent + "use std::mem;"; + code_ += indent + "use std::cmp::Ordering;"; + code_ += ""; + code_ += indent + "extern crate flatbuffers;"; + code_ += indent + "use self::flatbuffers::EndianScalar;"; + } + + // Set up the correct namespace. This opens a namespace if the current + // namespace is different from the target namespace. This function + // closes and opens the namespaces only as necessary. + // + // The file must start and end with an empty (or null) namespace so that + // namespaces are properly opened and closed. + void SetNameSpace(const Namespace *ns) { + if (cur_name_space_ == ns) { return; } + + // Compute the size of the longest common namespace prefix. + // If cur_name_space is A::B::C::D and ns is A::B::E::F::G, + // the common prefix is A::B:: and we have old_size = 4, new_size = 5 + // and common_prefix_size = 2 + size_t old_size = cur_name_space_ ? cur_name_space_->components.size() : 0; + size_t new_size = ns ? ns->components.size() : 0; + + size_t common_prefix_size = 0; + while (common_prefix_size < old_size && common_prefix_size < new_size && + ns->components[common_prefix_size] == + cur_name_space_->components[common_prefix_size]) { + common_prefix_size++; + } + + // Close cur_name_space in reverse order to reach the common prefix. + // In the previous example, D then C are closed. + for (size_t j = old_size; j > common_prefix_size; --j) { + code_ += "} // pub mod " + cur_name_space_->components[j - 1]; + } + if (old_size != common_prefix_size) { code_ += ""; } + + // open namespace parts to reach the ns namespace + // in the previous example, E, then F, then G are opened + for (auto j = common_prefix_size; j != new_size; ++j) { + code_ += "pub mod " + MakeSnakeCase(ns->components[j]) + " {"; + // Generate local namespace imports. + GenNamespaceImports(2); + } + if (new_size != common_prefix_size) { code_ += ""; } + + cur_name_space_ = ns; + } +}; + +} // namespace rust + +bool GenerateRust(const Parser &parser, const std::string &path, + const std::string &file_name) { + rust::RustGenerator generator(parser, path, file_name); + return generator.generate(); +} + +std::string RustMakeRule(const Parser &parser, const std::string &path, + const std::string &file_name) { + std::string filebase = + flatbuffers::StripPath(flatbuffers::StripExtension(file_name)); + std::string make_rule = GeneratedFileName(path, filebase) + ": "; + + auto included_files = parser.GetIncludedFilesRecursive(file_name); + for (auto it = included_files.begin(); it != included_files.end(); ++it) { + make_rule += " " + *it; + } + return make_rule; +} + +} // namespace flatbuffers + +// TODO(rw): Generated code should import other generated files. +// TODO(rw): Generated code should refer to namespaces in included files in a +// way that makes them referrable. +// TODO(rw): Generated code should indent according to nesting level. +// TODO(rw): Generated code should generate endian-safe Debug impls. +// TODO(rw): Generated code could use a Rust-only enum type to access unions, +// instead of making the user use _type() to manually switch. diff --git a/chromium/third_party/flatbuffers/src/src/idl_gen_text.cpp b/chromium/third_party/flatbuffers/src/src/idl_gen_text.cpp index 41d19125ecb..fb75a79556f 100644 --- a/chromium/third_party/flatbuffers/src/src/idl_gen_text.cpp +++ b/chromium/third_party/flatbuffers/src/src/idl_gen_text.cpp @@ -119,7 +119,7 @@ bool Print<const void *>(const void *val, Type type, int indent, break; case BASE_TYPE_STRING: { auto s = reinterpret_cast<const String *>(val); - if (!EscapeString(s->c_str(), s->Length(), _text, opts.allow_non_utf8, + if (!EscapeString(s->c_str(), s->size(), _text, opts.allow_non_utf8, opts.natural_utf8)) { return false; } @@ -131,7 +131,7 @@ bool Print<const void *>(const void *val, Type type, int indent, switch (type.base_type) { // clang-format off #define FLATBUFFERS_TD(ENUM, IDLTYPE, \ - CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \ + CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE) \ case BASE_TYPE_ ## ENUM: \ if (!PrintVector<CTYPE>( \ *reinterpret_cast<const Vector<CTYPE> *>(val), \ @@ -149,19 +149,23 @@ bool Print<const void *>(const void *val, Type type, int indent, return true; } +template<typename T> static T GetFieldDefault(const FieldDef &fd) { + T val; + auto check = StringToNumber(fd.value.constant.c_str(), &val); + (void)check; + FLATBUFFERS_ASSERT(check); + return val; +} + // Generate text for a scalar field. -template<typename T> static bool GenField(const FieldDef &fd, - const Table *table, bool fixed, - const IDLOptions &opts, - int indent, - std::string *_text) { - return Print(fixed ? - reinterpret_cast<const Struct *>(table)->GetField<T>(fd.value.offset) : - table->GetField<T>(fd.value.offset, - IsFloat(fd.value.type.base_type) ? - static_cast<T>(strtod(fd.value.constant.c_str(), nullptr)) : - static_cast<T>(StringToInt(fd.value.constant.c_str()))), - fd.value.type, indent, nullptr, opts, _text); +template<typename T> +static bool GenField(const FieldDef &fd, const Table *table, bool fixed, + const IDLOptions &opts, int indent, std::string *_text) { + return Print( + fixed ? reinterpret_cast<const Struct *>(table)->GetField<T>( + fd.value.offset) + : table->GetField<T>(fd.value.offset, GetFieldDefault<T>(fd)), + fd.value.type, indent, nullptr, opts, _text); } static bool GenStruct(const StructDef &struct_def, const Table *table, @@ -223,7 +227,7 @@ static bool GenStruct(const StructDef &struct_def, const Table *table, switch (fd.value.type.base_type) { // clang-format off #define FLATBUFFERS_TD(ENUM, IDLTYPE, \ - CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \ + CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE) \ case BASE_TYPE_ ## ENUM: \ if (!GenField<CTYPE>(fd, table, struct_def.fixed, \ opts, indent + Indent(opts), _text)) { \ @@ -234,7 +238,7 @@ static bool GenStruct(const StructDef &struct_def, const Table *table, #undef FLATBUFFERS_TD // Generate drop-thru case statements for all pointer types: #define FLATBUFFERS_TD(ENUM, IDLTYPE, \ - CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \ + CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE) \ case BASE_TYPE_ ## ENUM: FLATBUFFERS_GEN_TYPES_POINTER(FLATBUFFERS_TD) #undef FLATBUFFERS_TD diff --git a/chromium/third_party/flatbuffers/src/src/idl_parser.cpp b/chromium/third_party/flatbuffers/src/src/idl_parser.cpp index 366a77be8e7..a9e207e2d33 100644 --- a/chromium/third_party/flatbuffers/src/src/idl_parser.cpp +++ b/chromium/third_party/flatbuffers/src/src/idl_parser.cpp @@ -30,7 +30,7 @@ const double kPi = 3.14159265358979323846; const char *const kTypeNames[] = { // clang-format off #define FLATBUFFERS_TD(ENUM, IDLTYPE, \ - CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \ + CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE) \ IDLTYPE, FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD) #undef FLATBUFFERS_TD @@ -41,7 +41,7 @@ const char *const kTypeNames[] = { const char kTypeSizes[] = { // clang-format off #define FLATBUFFERS_TD(ENUM, IDLTYPE, \ - CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \ + CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE) \ sizeof(CTYPE), FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD) #undef FLATBUFFERS_TD @@ -91,14 +91,22 @@ std::string MakeCamel(const std::string &in, bool first) { return s; } +void DeserializeDoc( std::vector<std::string> &doc, + const Vector<Offset<String>> *documentation) { + if (documentation == nullptr) return; + for (uoffset_t index = 0; index < documentation->size(); index++) + doc.push_back(documentation->Get(index)->str()); +} + void Parser::Message(const std::string &msg) { error_ = file_being_parsed_.length() ? AbsolutePath(file_being_parsed_) : ""; // clang-format off - #ifdef _WIN32 - error_ += "(" + NumToString(line_) + ")"; // MSVC alike - #else + #ifdef _WIN32 // MSVC alike + error_ += + "(" + NumToString(line_) + ", " + NumToString(CursorPosition()) + ")"; + #else // gcc alike if (file_being_parsed_.length()) error_ += ":"; - error_ += NumToString(line_) + ":0"; // gcc alike + error_ += NumToString(line_) + ": " + NumToString(CursorPosition()); #endif // clang-format on error_ += ": " + msg; @@ -114,61 +122,35 @@ CheckedError Parser::Error(const std::string &msg) { inline CheckedError NoError() { return CheckedError(false); } CheckedError Parser::RecurseError() { - return Error("maximum parsing recursion of " + NumToString(kMaxParsingDepth) + - " reached"); + return Error("maximum parsing recursion of " + + NumToString(FLATBUFFERS_MAX_PARSING_DEPTH) + " reached"); } -inline std::string OutOfRangeErrorMsg(int64_t val, const std::string &op, - int64_t limit) { - const std::string cause = NumToString(val) + op + NumToString(limit); - return "constant does not fit (" + cause + ")"; +template<typename F> CheckedError Parser::Recurse(F f) { + if (recurse_protection_counter >= (FLATBUFFERS_MAX_PARSING_DEPTH)) + return RecurseError(); + recurse_protection_counter++; + auto ce = f(); + recurse_protection_counter--; + return ce; } -// Ensure that integer values we parse fit inside the declared integer type. -CheckedError Parser::CheckInRange(int64_t val, int64_t min, int64_t max) { - if (val < min) - return Error(OutOfRangeErrorMsg(val, " < ", min)); - else if (val > max) - return Error(OutOfRangeErrorMsg(val, " > ", max)); - else - return NoError(); +CheckedError Parser::InvalidNumber(const char *number, const std::string &msg) { + return Error("invalid number: \"" + std::string(number) + "\"" + msg); } - // atot: templated version of atoi/atof: convert a string to an instance of T. template<typename T> inline CheckedError atot(const char *s, Parser &parser, T *val) { - int64_t i = StringToInt(s); - const int64_t min = flatbuffers::numeric_limits<T>::min(); - const int64_t max = flatbuffers::numeric_limits<T>::max(); - *val = (T)i; // Assign this first to make ASAN happy. - return parser.CheckInRange(i, min, max); -} -template<> -inline CheckedError atot<uint64_t>(const char *s, Parser &parser, - uint64_t *val) { - (void)parser; - *val = StringToUInt(s); - return NoError(); -} -template<> -inline CheckedError atot<bool>(const char *s, Parser &parser, bool *val) { - (void)parser; - *val = 0 != atoi(s); - return NoError(); -} -template<> -inline CheckedError atot<float>(const char *s, Parser &parser, float *val) { - (void)parser; - *val = static_cast<float>(strtod(s, nullptr)); - return NoError(); -} -template<> -inline CheckedError atot<double>(const char *s, Parser &parser, double *val) { - (void)parser; - *val = strtod(s, nullptr); - return NoError(); -} + auto done = StringToNumber(s, val); + if (done) return NoError(); + return parser.InvalidNumber( + s, (0 == *val) + ? "" + : (", constant does not fit [" + + NumToString(flatbuffers::numeric_limits<T>::lowest()) + "; " + + NumToString(flatbuffers::numeric_limits<T>::max()) + "]")); +} template<> inline CheckedError atot<Offset<void>>(const char *s, Parser &parser, Offset<void> *val) { @@ -217,7 +199,7 @@ static std::string TokenToString(int t) { FLATBUFFERS_GEN_TOKENS(FLATBUFFERS_TOKEN) #undef FLATBUFFERS_TOKEN #define FLATBUFFERS_TD(ENUM, IDLTYPE, \ - CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \ + CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE) \ IDLTYPE, FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD) #undef FLATBUFFERS_TD @@ -238,12 +220,13 @@ std::string Parser::TokenToStringId(int t) const { // Parses exactly nibbles worth of hex digits into a number, or error. CheckedError Parser::ParseHexNum(int nibbles, uint64_t *val) { + FLATBUFFERS_ASSERT(nibbles > 0); for (int i = 0; i < nibbles; i++) - if (!isxdigit(static_cast<unsigned char>(cursor_[i]))) + if (!is_xdigit(cursor_[i])) return Error("escape code must be followed by " + NumToString(nibbles) + " hex digits"); std::string target(cursor_, cursor_ + nibbles); - *val = StringToUInt(target.c_str(), nullptr, 16); + *val = StringToUInt(target.c_str(), 16); cursor_ += nibbles; return NoError(); } @@ -260,14 +243,15 @@ CheckedError Parser::SkipByteOrderMark() { return NoError(); } -bool IsIdentifierStart(char c) { - return isalpha(static_cast<unsigned char>(c)) || c == '_'; +static inline bool IsIdentifierStart(char c) { + return is_alpha(c) || (c == '_'); } CheckedError Parser::Next() { doc_comment_.clear(); bool seen_newline = cursor_ == source_; attribute_.clear(); + attr_is_trivial_ascii_string_ = true; for (;;) { char c = *cursor_++; token_ = c; @@ -280,7 +264,7 @@ CheckedError Parser::Next() { case '\r': case '\t': break; case '\n': - line_++; + MarkNewLine(); seen_newline = true; break; case '{': @@ -293,10 +277,6 @@ CheckedError Parser::Next() { case ':': case ';': case '=': return NoError(); - case '.': - if (!isdigit(static_cast<unsigned char>(*cursor_))) - return NoError(); - return Error("floating point constant can\'t start with \".\""); case '\"': case '\'': { int unicode_high_surrogate = -1; @@ -305,6 +285,7 @@ CheckedError Parser::Next() { if (*cursor_ < ' ' && static_cast<signed char>(*cursor_) >= 0) return Error("illegal character in string constant"); if (*cursor_ == '\\') { + attr_is_trivial_ascii_string_ = false; // has escape sequence cursor_++; if (unicode_high_surrogate != -1 && *cursor_ != 'u') { return Error( @@ -392,6 +373,9 @@ CheckedError Parser::Next() { return Error( "illegal Unicode sequence (unpaired high surrogate)"); } + // reset if non-printable + attr_is_trivial_ascii_string_ &= check_in_range(*cursor_, ' ', '~'); + attribute_ += *cursor_++; } } @@ -399,7 +383,8 @@ CheckedError Parser::Next() { return Error("illegal Unicode sequence (unpaired high surrogate)"); } cursor_++; - if (!opts.allow_non_utf8 && !ValidateUTF8(attribute_)) { + if (!attr_is_trivial_ascii_string_ && !opts.allow_non_utf8 && + !ValidateUTF8(attribute_)) { return Error("illegal UTF-8 sequence"); } token_ = kTokenStringConstant; @@ -420,64 +405,78 @@ CheckedError Parser::Next() { cursor_++; // TODO: make nested. while (*cursor_ != '*' || cursor_[1] != '/') { - if (*cursor_ == '\n') line_++; + if (*cursor_ == '\n') MarkNewLine(); if (!*cursor_) return Error("end of file in comment"); cursor_++; } cursor_ += 2; break; } - // fall thru + FLATBUFFERS_FALLTHROUGH(); // else fall thru default: - if (IsIdentifierStart(c)) { + const auto has_sign = (c == '+') || (c == '-'); + // '-'/'+' and following identifier - can be a predefined constant like: + // NAN, INF, PI, etc. + if (IsIdentifierStart(c) || (has_sign && IsIdentifierStart(*cursor_))) { // Collect all chars of an identifier: const char *start = cursor_ - 1; - while (isalnum(static_cast<unsigned char>(*cursor_)) || *cursor_ == '_') - cursor_++; + while (IsIdentifierStart(*cursor_) || is_digit(*cursor_)) cursor_++; attribute_.append(start, cursor_); - token_ = kTokenIdentifier; + token_ = has_sign ? kTokenStringConstant : kTokenIdentifier; return NoError(); - } else if (isdigit(static_cast<unsigned char>(c)) || c == '-') { - const char *start = cursor_ - 1; - if (c == '-' && *cursor_ == '0' && - (cursor_[1] == 'x' || cursor_[1] == 'X')) { - ++start; - ++cursor_; - attribute_.append(&c, &c + 1); - c = '0'; - } - if (c == '0' && (*cursor_ == 'x' || *cursor_ == 'X')) { - cursor_++; - while (isxdigit(static_cast<unsigned char>(*cursor_))) cursor_++; - attribute_.append(start + 2, cursor_); - attribute_ = NumToString(static_cast<int64_t>( - StringToUInt(attribute_.c_str(), nullptr, 16))); - token_ = kTokenIntegerConstant; - return NoError(); + } + + auto dot_lvl = (c == '.') ? 0 : 1; // dot_lvl==0 <=> exactly one '.' seen + if (!dot_lvl && !is_digit(*cursor_)) return NoError(); // enum? + // Parser accepts hexadecimal-floating-literal (see C++ 5.13.4). + if (is_digit(c) || has_sign || !dot_lvl) { + const auto start = cursor_ - 1; + auto start_digits = !is_digit(c) ? cursor_ : cursor_ - 1; + if (!is_digit(c) && is_digit(*cursor_)){ + start_digits = cursor_; // see digit in cursor_ position + c = *cursor_++; } - while (isdigit(static_cast<unsigned char>(*cursor_))) cursor_++; - if (*cursor_ == '.' || *cursor_ == 'e' || *cursor_ == 'E') { - if (*cursor_ == '.') { - cursor_++; - while (isdigit(static_cast<unsigned char>(*cursor_))) cursor_++; + // hex-float can't begind with '.' + auto use_hex = dot_lvl && (c == '0') && is_alpha_char(*cursor_, 'X'); + if (use_hex) start_digits = ++cursor_; // '0x' is the prefix, skip it + // Read an integer number or mantisa of float-point number. + do { + if (use_hex) { + while (is_xdigit(*cursor_)) cursor_++; + } else { + while (is_digit(*cursor_)) cursor_++; } - // See if this float has a scientific notation suffix. Both JSON - // and C++ (through strtod() we use) have the same format: - if (*cursor_ == 'e' || *cursor_ == 'E') { + } while ((*cursor_ == '.') && (++cursor_) && (--dot_lvl >= 0)); + // Exponent of float-point number. + if ((dot_lvl >= 0) && (cursor_ > start_digits)) { + // The exponent suffix of hexadecimal float number is mandatory. + if (use_hex && !dot_lvl) start_digits = cursor_; + if ((use_hex && is_alpha_char(*cursor_, 'P')) || + is_alpha_char(*cursor_, 'E')) { + dot_lvl = 0; // Emulate dot to signal about float-point number. cursor_++; if (*cursor_ == '+' || *cursor_ == '-') cursor_++; - while (isdigit(static_cast<unsigned char>(*cursor_))) cursor_++; + start_digits = cursor_; // the exponent-part has to have digits + // Exponent is decimal integer number + while (is_digit(*cursor_)) cursor_++; + if (*cursor_ == '.') { + cursor_++; // If see a dot treat it as part of invalid number. + dot_lvl = -1; // Fall thru to Error(). + } } - token_ = kTokenFloatConstant; + } + // Finalize. + if ((dot_lvl >= 0) && (cursor_ > start_digits)) { + attribute_.append(start, cursor_); + token_ = dot_lvl ? kTokenIntegerConstant : kTokenFloatConstant; + return NoError(); } else { - token_ = kTokenIntegerConstant; + return Error("invalid number: " + std::string(start, cursor_)); } - attribute_.append(start, cursor_); - return NoError(); } std::string ch; ch = c; - if (c < ' ' || c > '~') ch = "code: " + NumToString(c); + if (false == check_in_range(c, ' ', '~')) ch = "code: " + NumToString(c); return Error("illegal character: " + ch); } } @@ -673,7 +672,7 @@ CheckedError Parser::ParseField(StructDef &struct_def) { (struct_def.fixed && field->value.constant != "0")) return Error( "default values currently only supported for scalars in tables"); - ECHECK(ParseSingleValue(&field->name, field->value)); + ECHECK(ParseSingleValue(&field->name, field->value, true)); } if (type.enum_def && !type.enum_def->is_union && @@ -683,9 +682,20 @@ CheckedError Parser::ParseField(StructDef &struct_def) { return Error("default value of " + field->value.constant + " for field " + name + " is not part of enum " + type.enum_def->name); } + // Append .0 if the value has not it (skip hex and scientific floats). + // This suffix needed for generated C++ code. if (IsFloat(type.base_type)) { - if (!strpbrk(field->value.constant.c_str(), ".eE")) + auto &text = field->value.constant; + FLATBUFFERS_ASSERT(false == text.empty()); + auto s = text.c_str(); + while(*s == ' ') s++; + if (*s == '-' || *s == '+') s++; + // 1) A float constants (nan, inf, pi, etc) is a kind of identifier. + // 2) A float number needn't ".0" at the end if it has exponent. + if ((false == IsIdentifierStart(*s)) && + (std::string::npos == field->value.constant.find_first_of(".eEpP"))) { field->value.constant += ".0"; + } } if (type.enum_def && IsScalar(type.base_type) && !struct_def.fixed && @@ -757,6 +767,9 @@ CheckedError Parser::ParseField(StructDef &struct_def) { return Error("'key' field must be string or scalar type"); } } + field->shared = field->attributes.Lookup("shared") != nullptr; + if (field->shared && field->value.type.base_type != BASE_TYPE_STRING) + return Error("shared can only be defined on strings"); auto field_native_custom_alloc = field->attributes.Lookup("native_custom_alloc"); @@ -767,7 +780,7 @@ CheckedError Parser::ParseField(StructDef &struct_def) { field->native_inline = field->attributes.Lookup("native_inline") != nullptr; if (field->native_inline && !IsStruct(field->value.type)) - return Error("native_inline can only be defined on structs'"); + return Error("native_inline can only be defined on structs"); auto nested = field->attributes.Lookup("nested_flatbuffer"); if (nested) { @@ -914,11 +927,13 @@ CheckedError Parser::ParseAnyValue(Value &val, FieldDef *field, (token_ == kTokenIdentifier || token_ == kTokenStringConstant)) { ECHECK(ParseHash(val, field)); } else { - ECHECK(ParseSingleValue(field ? &field->name : nullptr, val)); + ECHECK(ParseSingleValue(field ? &field->name : nullptr, val, false)); } break; } - default: ECHECK(ParseSingleValue(field ? &field->name : nullptr, val)); break; + default: + ECHECK(ParseSingleValue(field ? &field->name : nullptr, val, false)); + break; } return NoError(); } @@ -931,10 +946,10 @@ void Parser::SerializeStruct(const StructDef &struct_def, const Value &val) { builder_.AddStructOffset(val.offset, builder_.GetSize()); } +template <typename F> CheckedError Parser::ParseTableDelimiters(size_t &fieldn, const StructDef *struct_def, - ParseTableDelimitersBody body, - void *state) { + F body) { // We allow tables both as JSON object{ .. } with field names // or vector[..] with all fields in order char terminator = '}'; @@ -962,7 +977,7 @@ CheckedError Parser::ParseTableDelimiters(size_t &fieldn, } if (!opts.protobuf_ascii_alike || !(Is('{') || Is('['))) EXPECT(':'); } - ECHECK(body(name, fieldn, struct_def, state)); + ECHECK(body(name, fieldn, struct_def)); if (Is(terminator)) break; ECHECK(ParseComma()); } @@ -978,65 +993,60 @@ CheckedError Parser::ParseTable(const StructDef &struct_def, std::string *value, size_t fieldn_outer = 0; auto err = ParseTableDelimiters( fieldn_outer, &struct_def, - [](const std::string &name, size_t &fieldn, - const StructDef *struct_def_inner, void *state) -> CheckedError { - auto *parser = static_cast<Parser *>(state); + [&](const std::string &name, size_t &fieldn, + const StructDef *struct_def_inner) -> CheckedError { if (name == "$schema") { - ECHECK(parser->Expect(kTokenStringConstant)); + ECHECK(Expect(kTokenStringConstant)); return NoError(); } auto field = struct_def_inner->fields.Lookup(name); if (!field) { - if (!parser->opts.skip_unexpected_fields_in_json) { - return parser->Error("unknown field: " + name); + if (!opts.skip_unexpected_fields_in_json) { + return Error("unknown field: " + name); } else { - ECHECK(parser->SkipAnyJsonValue()); + ECHECK(SkipAnyJsonValue()); } } else { - if (parser->IsIdent("null")) { - ECHECK(parser->Next()); // Ignore this field. + if (IsIdent("null") && !IsScalar(field->value.type.base_type)) { + ECHECK(Next()); // Ignore this field. } else { Value val = field->value; if (field->flexbuffer) { flexbuffers::Builder builder(1024, flexbuffers::BUILDER_FLAG_SHARE_ALL); - ECHECK(parser->ParseFlexBufferValue(&builder)); + ECHECK(ParseFlexBufferValue(&builder)); builder.Finish(); // Force alignment for nested flexbuffer - parser->builder_.ForceVectorAlignment(builder.GetSize(), sizeof(uint8_t), - sizeof(largest_scalar_t)); - auto off = parser->builder_.CreateVector(builder.GetBuffer()); + builder_.ForceVectorAlignment(builder.GetSize(), sizeof(uint8_t), + sizeof(largest_scalar_t)); + auto off = builder_.CreateVector(builder.GetBuffer()); val.constant = NumToString(off.o); } else if (field->nested_flatbuffer) { - ECHECK(parser->ParseNestedFlatbuffer(val, field, fieldn, - struct_def_inner)); + ECHECK( + ParseNestedFlatbuffer(val, field, fieldn, struct_def_inner)); } else { - ECHECK(parser->Recurse([&]() { - return parser->ParseAnyValue(val, field, fieldn, - struct_def_inner); + ECHECK(Recurse([&]() { + return ParseAnyValue(val, field, fieldn, struct_def_inner); })); } // Hardcoded insertion-sort with error-check. // If fields are specified in order, then this loop exits // immediately. - auto elem = parser->field_stack_.rbegin(); - for (; elem != parser->field_stack_.rbegin() + fieldn; ++elem) { + auto elem = field_stack_.rbegin(); + for (; elem != field_stack_.rbegin() + fieldn; ++elem) { auto existing_field = elem->second; if (existing_field == field) - return parser->Error("field set more than once: " + - field->name); + return Error("field set more than once: " + field->name); if (existing_field->value.offset < field->value.offset) break; } // Note: elem points to before the insertion point, thus .base() // points to the correct spot. - parser->field_stack_.insert(elem.base(), - std::make_pair(val, field)); + field_stack_.insert(elem.base(), std::make_pair(val, field)); fieldn++; } } return NoError(); - }, - this); + }); ECHECK(err); // Check if all required fields are parsed. @@ -1077,7 +1087,7 @@ CheckedError Parser::ParseTable(const StructDef &struct_def, std::string *value, switch (field_value.type.base_type) { // clang-format off #define FLATBUFFERS_TD(ENUM, IDLTYPE, \ - CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \ + CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE) \ case BASE_TYPE_ ## ENUM: \ builder_.Pad(field->padding); \ if (struct_def.fixed) { \ @@ -1094,7 +1104,7 @@ CheckedError Parser::ParseTable(const StructDef &struct_def, std::string *value, FLATBUFFERS_GEN_TYPES_SCALAR(FLATBUFFERS_TD); #undef FLATBUFFERS_TD #define FLATBUFFERS_TD(ENUM, IDLTYPE, \ - CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \ + CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE) \ case BASE_TYPE_ ## ENUM: \ builder_.Pad(field->padding); \ if (IsStruct(field->value.type)) { \ @@ -1133,13 +1143,12 @@ CheckedError Parser::ParseTable(const StructDef &struct_def, std::string *value, return NoError(); } -CheckedError Parser::ParseVectorDelimiters(size_t &count, - ParseVectorDelimitersBody body, - void *state) { +template <typename F> +CheckedError Parser::ParseVectorDelimiters(size_t &count, F body) { EXPECT('['); for (;;) { if ((!opts.strict_json || !count) && Is(']')) break; - ECHECK(body(count, state)); + ECHECK(body(count)); count++; if (Is(']')) break; ECHECK(ParseComma()); @@ -1150,22 +1159,13 @@ CheckedError Parser::ParseVectorDelimiters(size_t &count, CheckedError Parser::ParseVector(const Type &type, uoffset_t *ovalue) { size_t count = 0; - std::pair<Parser *, const Type &> parser_and_type_state(this, type); - auto err = ParseVectorDelimiters( - count, - [](size_t &, void *state) -> CheckedError { - auto *parser_and_type = - static_cast<std::pair<Parser *, const Type &> *>(state); - auto *parser = parser_and_type->first; - Value val; - val.type = parser_and_type->second; - ECHECK(parser->Recurse([&]() { - return parser->ParseAnyValue(val, nullptr, 0, nullptr); - })); - parser->field_stack_.push_back(std::make_pair(val, nullptr)); - return NoError(); - }, - &parser_and_type_state); + auto err = ParseVectorDelimiters(count, [&](size_t &) -> CheckedError { + Value val; + val.type = type; + ECHECK(Recurse([&]() { return ParseAnyValue(val, nullptr, 0, nullptr); })); + field_stack_.push_back(std::make_pair(val, nullptr)); + return NoError(); + }); ECHECK(err); builder_.StartVector(count * InlineSize(type) / InlineAlignment(type), @@ -1176,7 +1176,7 @@ CheckedError Parser::ParseVector(const Type &type, uoffset_t *ovalue) { switch (val.type.base_type) { // clang-format off #define FLATBUFFERS_TD(ENUM, IDLTYPE, \ - CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \ + CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE) \ case BASE_TYPE_ ## ENUM: \ if (IsStruct(val.type)) SerializeStruct(*val.type.struct_def, val); \ else { \ @@ -1251,7 +1251,7 @@ CheckedError Parser::ParseMetaData(SymbolTable<Value> *attributes) { attributes->Add(name, e); if (Is(':')) { NEXT(); - ECHECK(ParseSingleValue(&name, *e)); + ECHECK(ParseSingleValue(&name, *e, true)); } if (Is(')')) { NEXT(); @@ -1263,23 +1263,40 @@ CheckedError Parser::ParseMetaData(SymbolTable<Value> *attributes) { return NoError(); } -CheckedError Parser::TryTypedValue(const std::string *name, int dtoken, bool check, Value &e, - BaseType req, bool *destmatch) { +CheckedError Parser::TryTypedValue(const std::string *name, int dtoken, + bool check, Value &e, BaseType req, + bool *destmatch) { bool match = dtoken == token_; if (match) { + FLATBUFFERS_ASSERT(*destmatch == false); *destmatch = true; e.constant = attribute_; + // Check token match if (!check) { if (e.type.base_type == BASE_TYPE_NONE) { e.type.base_type = req; } else { - return Error(std::string("type mismatch: expecting: ") + - kTypeNames[e.type.base_type] + - ", found: " + kTypeNames[req] + - ", name: " + (name ? *name : "") + - ", value: " + e.constant); + return Error( + std::string("type mismatch: expecting: ") + + kTypeNames[e.type.base_type] + ", found: " + kTypeNames[req] + + ", name: " + (name ? *name : "") + ", value: " + e.constant); + } + } + // The exponent suffix of hexadecimal float-point number is mandatory. + // A hex-integer constant is forbidden as an initializer of float number. + if ((kTokenFloatConstant != dtoken) && IsFloat(e.type.base_type)) { + const auto &s = e.constant; + const auto k = s.find_first_of("0123456789."); + if ((std::string::npos != k) && (s.length() > (k + 1)) && + (s.at(k) == '0' && is_alpha_char(s.at(k + 1), 'X')) && + (std::string::npos == s.find_first_of("pP", k + 2))) { + return Error( + "invalid number, the exponent suffix of hexadecimal " + "floating-point literals is mandatory: \"" + + s + "\""); } } + NEXT(); } return NoError(); @@ -1374,20 +1391,29 @@ CheckedError Parser::TokenError() { return Error("cannot parse value starting with: " + TokenToStringId(token_)); } -CheckedError Parser::ParseSingleValue(const std::string *name, Value &e) { +CheckedError Parser::ParseSingleValue(const std::string *name, Value &e, + bool check_now) { // First see if this could be a conversion function: if (token_ == kTokenIdentifier && *cursor_ == '(') { - auto functionname = attribute_; + // todo: Extract processing of conversion functions to ParseFunction. + const auto functionname = attribute_; + if (!IsFloat(e.type.base_type)) { + return Error(functionname + ": type of argument mismatch, expecting: " + + kTypeNames[BASE_TYPE_DOUBLE] + + ", found: " + kTypeNames[e.type.base_type] + + ", name: " + (name ? *name : "") + ", value: " + e.constant); + } NEXT(); EXPECT('('); - ECHECK(ParseSingleValue(name, e)); + ECHECK(Recurse([&]() { return ParseSingleValue(name, e, false); })); EXPECT(')'); + // calculate with double precision + double x, y = 0.0; + ECHECK(atot(e.constant.c_str(), *this, &x)); + auto func_match = false; // clang-format off #define FLATBUFFERS_FN_DOUBLE(name, op) \ - if (functionname == name) { \ - auto x = strtod(e.constant.c_str(), nullptr); \ - e.constant = NumToString(op); \ - } + if (!func_match && functionname == name) { y = op; func_match = true; } FLATBUFFERS_FN_DOUBLE("deg", x / kPi * 180); FLATBUFFERS_FN_DOUBLE("rad", x * kPi / 180); FLATBUFFERS_FN_DOUBLE("sin", sin(x)); @@ -1399,47 +1425,108 @@ CheckedError Parser::ParseSingleValue(const std::string *name, Value &e) { // TODO(wvo): add more useful conversion functions here. #undef FLATBUFFERS_FN_DOUBLE // clang-format on - // Then check if this could be a string/identifier enum value: - } else if (e.type.base_type != BASE_TYPE_STRING && - e.type.base_type != BASE_TYPE_BOOL && - e.type.base_type != BASE_TYPE_NONE && - (token_ == kTokenIdentifier || token_ == kTokenStringConstant)) { - if (IsIdentifierStart(attribute_[0])) { // Enum value. + if (true != func_match) { + return Error(std::string("Unknown conversion function: ") + functionname + + ", field name: " + (name ? *name : "") + + ", value: " + e.constant); + } + e.constant = NumToString(y); + return NoError(); + } + + auto match = false; + // clang-format off + #define TRY_ECHECK(force, dtoken, check, req) \ + if (!match && ((check) || IsConstTrue(force))) \ + ECHECK(TryTypedValue(name, dtoken, check, e, req, &match)) + // clang-format on + + if (token_ == kTokenStringConstant || token_ == kTokenIdentifier) { + const auto kTokenStringOrIdent = token_; + // The string type is a most probable type, check it first. + TRY_ECHECK(false, kTokenStringConstant, + e.type.base_type == BASE_TYPE_STRING, BASE_TYPE_STRING); + + // avoid escaped and non-ascii in the string + if ((token_ == kTokenStringConstant) && IsScalar(e.type.base_type) && + !attr_is_trivial_ascii_string_) { + return Error( + std::string("type mismatch or invalid value, an initializer of " + "non-string field must be trivial ASCII string: type: ") + + kTypeNames[e.type.base_type] + ", name: " + (name ? *name : "") + + ", value: " + attribute_); + } + + // A boolean as true/false. Boolean as Integer check below. + if (!match && IsBool(e.type.base_type)) { + auto is_true = attribute_ == "true"; + if (is_true || attribute_ == "false") { + attribute_ = is_true ? "1" : "0"; + // accepts both kTokenStringConstant and kTokenIdentifier + TRY_ECHECK(false, kTokenStringOrIdent, IsBool(e.type.base_type), + BASE_TYPE_BOOL); + } + } + // Check if this could be a string/identifier enum value. + // Enum can have only true integer base type. + if (!match && IsInteger(e.type.base_type) && !IsBool(e.type.base_type) && + IsIdentifierStart(*attribute_.c_str())) { int64_t val; ECHECK(ParseEnumFromString(e.type, &val)); e.constant = NumToString(val); NEXT(); - } else { // Numeric constant in string. - if (IsInteger(e.type.base_type)) { - char *end; - e.constant = NumToString(StringToInt(attribute_.c_str(), &end)); - if (*end) return Error("invalid integer: " + attribute_); - } else if (IsFloat(e.type.base_type)) { - char *end; - e.constant = NumToString(strtod(attribute_.c_str(), &end)); - if (*end) return Error("invalid float: " + attribute_); - } else { - FLATBUFFERS_ASSERT(0); // Shouldn't happen, we covered all types. - e.constant = "0"; - } - NEXT(); + match = true; } + // float/integer number in string + if ((token_ == kTokenStringConstant) && IsScalar(e.type.base_type)) { + // remove trailing whitespaces from attribute_ + auto last = attribute_.find_last_not_of(' '); + if (std::string::npos != last) // has non-whitespace + attribute_.resize(last + 1); + } + // Float numbers or nan, inf, pi, etc. + TRY_ECHECK(false, kTokenStringOrIdent, IsFloat(e.type.base_type), + BASE_TYPE_FLOAT); + // An integer constant in string. + TRY_ECHECK(false, kTokenStringOrIdent, IsInteger(e.type.base_type), + BASE_TYPE_INT); + // Unknown tokens will be interpreted as string type. + TRY_ECHECK(true, kTokenStringConstant, e.type.base_type == BASE_TYPE_STRING, + BASE_TYPE_STRING); } else { - bool match = false; - ECHECK(TryTypedValue(name, kTokenIntegerConstant, IsScalar(e.type.base_type), e, - BASE_TYPE_INT, &match)); - ECHECK(TryTypedValue(name, kTokenFloatConstant, IsFloat(e.type.base_type), e, - BASE_TYPE_FLOAT, &match)); - ECHECK(TryTypedValue(name, kTokenStringConstant, - e.type.base_type == BASE_TYPE_STRING, e, - BASE_TYPE_STRING, &match)); - auto istrue = IsIdent("true"); - if (istrue || IsIdent("false")) { - attribute_ = NumToString(istrue); - ECHECK(TryTypedValue(name, kTokenIdentifier, IsBool(e.type.base_type), e, - BASE_TYPE_BOOL, &match)); - } - if (!match) return TokenError(); + // Try a float number. + TRY_ECHECK(false, kTokenFloatConstant, IsFloat(e.type.base_type), + BASE_TYPE_FLOAT); + // Integer token can init any scalar (integer of float). + TRY_ECHECK(true, kTokenIntegerConstant, IsScalar(e.type.base_type), + BASE_TYPE_INT); + } + #undef TRY_ECHECK + + if (!match) return TokenError(); + + // The check_now flag must be true when parse a fbs-schema. + // This flag forces to check default scalar values or metadata of field. + // For JSON parser the flag should be false. + // If it is set for JSON each value will be checked twice (see ParseTable). + if (check_now && IsScalar(e.type.base_type)) { + // "re-pack" an integer scalar to remove any ambiguities like leading zeros + // which can be treated as octal-literal (idl_gen_cpp/GenDefaultConstant). + const auto repack = IsInteger(e.type.base_type); + switch (e.type.base_type) { + // clang-format off + #define FLATBUFFERS_TD(ENUM, IDLTYPE, \ + CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE) \ + case BASE_TYPE_ ## ENUM: {\ + CTYPE val; \ + ECHECK(atot(e.constant.c_str(), *this, &val)); \ + if(repack) e.constant = NumToString(val); \ + break; } + FLATBUFFERS_GEN_TYPES_SCALAR(FLATBUFFERS_TD); + #undef FLATBUFFERS_TD + default: break; + // clang-format on + } } return NoError(); } @@ -1517,7 +1604,8 @@ CheckedError Parser::ParseEnum(bool is_union, EnumDef **dest) { } // Specify the integer type underlying this enum. ECHECK(ParseType(enum_def->underlying_type)); - if (!IsInteger(enum_def->underlying_type.base_type)) + if (!IsInteger(enum_def->underlying_type.base_type) || + IsBool(enum_def->underlying_type.base_type)) return Error("underlying enum type must be integral"); // Make this type refer back to the enum it was derived from. enum_def->underlying_type.enum_def = enum_def; @@ -1525,6 +1613,7 @@ CheckedError Parser::ParseEnum(bool is_union, EnumDef **dest) { ECHECK(ParseMetaData(&enum_def->attributes)); EXPECT('{'); if (is_union) enum_def->vals.Add("NONE", new EnumVal("NONE", 0)); + std::set<std::pair<BaseType, StructDef*>> union_types; for (;;) { if (opts.proto_mode && attribute_ == "option") { ECHECK(ParseProtoOption()); @@ -1543,10 +1632,8 @@ CheckedError Parser::ParseEnum(bool is_union, EnumDef **dest) { } } auto prevsize = enum_def->vals.vec.size(); - auto value = !enum_def->vals.vec.empty() - ? enum_def->vals.vec.back()->value + 1 - : 0; - auto &ev = *new EnumVal(value_name, value); + auto prevvalue = prevsize > 0 ? enum_def->vals.vec.back()->value : 0; + auto &ev = *new EnumVal(value_name, 0); if (enum_def->vals.Add(value_name, &ev)) return Error("enum value already exists: " + value_name); ev.doc_comment = value_comment; @@ -1557,23 +1644,56 @@ CheckedError Parser::ParseEnum(bool is_union, EnumDef **dest) { if (ev.union_type.base_type != BASE_TYPE_STRUCT && ev.union_type.base_type != BASE_TYPE_STRING) return Error("union value type may only be table/struct/string"); - enum_def->uses_type_aliases = true; } else { ev.union_type = Type(BASE_TYPE_STRUCT, LookupCreateStruct(full_name)); } + if (!enum_def->uses_multiple_type_instances) { + auto union_type_key = std::make_pair(ev.union_type.base_type, ev.union_type.struct_def); + if (union_types.count(union_type_key) > 0) { + enum_def->uses_multiple_type_instances = true; + } else { + union_types.insert(union_type_key); + } + } } if (Is('=')) { NEXT(); - ev.value = StringToInt(attribute_.c_str()); + ECHECK(atot(attribute_.c_str(), *this, &ev.value)); EXPECT(kTokenIntegerConstant); if (!opts.proto_mode && prevsize && enum_def->vals.vec[prevsize - 1]->value >= ev.value) return Error("enum values must be specified in ascending order"); + } else if (prevsize == 0) { + // already set to zero + } else if (prevvalue != flatbuffers::numeric_limits<int64_t>::max()) { + ev.value = prevvalue + 1; + } else { + return Error("enum value overflows"); } - if (is_union) { - if (ev.value < 0 || ev.value >= 256) - return Error("union enum value must fit in a ubyte"); + + // Check that value fits into the underlying type. + switch (enum_def->underlying_type.base_type) { + // clang-format off + #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, \ + PTYPE, RTYPE) \ + case BASE_TYPE_##ENUM: { \ + int64_t min_value = static_cast<int64_t>( \ + flatbuffers::numeric_limits<CTYPE>::lowest()); \ + int64_t max_value = static_cast<int64_t>( \ + flatbuffers::numeric_limits<CTYPE>::max()); \ + if (ev.value < min_value || ev.value > max_value) { \ + return Error( \ + "enum value does not fit [" + NumToString(min_value) + \ + "; " + NumToString(max_value) + "]"); \ + } \ + break; \ + } + FLATBUFFERS_GEN_TYPES_SCALAR(FLATBUFFERS_TD); + #undef FLATBUFFERS_TD + default: break; + // clang-format on } + if (opts.proto_mode && Is('[')) { NEXT(); // ignore attributes on enums. @@ -1653,6 +1773,21 @@ Namespace *Parser::UniqueNamespace(Namespace *ns) { return ns; } +std::string Parser::UnqualifiedName(std::string full_qualified_name) { + Namespace *ns = new Namespace(); + + std::size_t current, previous = 0; + current = full_qualified_name.find('.'); + while (current != std::string::npos) { + ns->components.push_back( + full_qualified_name.substr(previous, current - previous)); + previous = current + 1; + current = full_qualified_name.find('.', previous); + } + current_namespace_ = UniqueNamespace(ns); + return full_qualified_name.substr(previous, current - previous); +} + static bool compareFieldDefs(const FieldDef *a, const FieldDef *b) { auto a_id = atoi(a->attributes.Lookup("id")->constant.c_str()); auto b_id = atoi(b->attributes.Lookup("id")->constant.c_str()); @@ -1676,21 +1811,24 @@ CheckedError Parser::ParseDecl() { EXPECT('{'); while (token_ != '}') ECHECK(ParseField(*struct_def)); auto force_align = struct_def->attributes.Lookup("force_align"); - if (fixed && force_align) { - auto align = static_cast<size_t>(atoi(force_align->constant.c_str())); - if (force_align->type.base_type != BASE_TYPE_INT || - align < struct_def->minalign || align > FLATBUFFERS_MAX_ALIGNMENT || - align & (align - 1)) - return Error( - "force_align must be a power of two integer ranging from the" - "struct\'s natural alignment to " + - NumToString(FLATBUFFERS_MAX_ALIGNMENT)); - struct_def->minalign = align; + if (fixed) { + if (force_align) { + auto align = static_cast<size_t>(atoi(force_align->constant.c_str())); + if (force_align->type.base_type != BASE_TYPE_INT || + align < struct_def->minalign || align > FLATBUFFERS_MAX_ALIGNMENT || + align & (align - 1)) + return Error( + "force_align must be a power of two integer ranging from the" + "struct\'s natural alignment to " + + NumToString(FLATBUFFERS_MAX_ALIGNMENT)); + struct_def->minalign = align; + } + if (!struct_def->bytesize) return Error("size 0 structs not allowed"); } struct_def->PadLastField(struct_def->minalign); // Check if this is a table that has manual id assignments auto &fields = struct_def->fields.vec; - if (!struct_def->fixed && fields.size()) { + if (!fixed && fields.size()) { size_t num_id_fields = 0; for (auto it = fields.begin(); it != fields.end(); ++it) { if ((*it)->attributes.Lookup("id")) num_id_fields++; @@ -2136,28 +2274,18 @@ CheckedError Parser::SkipAnyJsonValue() { size_t fieldn_outer = 0; return ParseTableDelimiters( fieldn_outer, nullptr, - [](const std::string &, size_t &fieldn, const StructDef *, - void *state) -> CheckedError { - auto *parser = static_cast<Parser *>(state); - ECHECK(parser->Recurse([&]() { - return parser->SkipAnyJsonValue(); - })); + [&](const std::string &, size_t &fieldn, + const StructDef *) -> CheckedError { + ECHECK(Recurse([&]() { return SkipAnyJsonValue(); })); fieldn++; return NoError(); - }, - this); + }); } case '[': { size_t count = 0; - return ParseVectorDelimiters( - count, - [](size_t &, void *state) -> CheckedError { - auto *parser = static_cast<Parser *>(state); - return parser->Recurse([&]() { - return parser->SkipAnyJsonValue(); - }); - }, - this); + return ParseVectorDelimiters(count, [&](size_t &) -> CheckedError { + return Recurse([&]() { return SkipAnyJsonValue(); }); + }); } case kTokenStringConstant: case kTokenIntegerConstant: @@ -2174,25 +2302,17 @@ CheckedError Parser::SkipAnyJsonValue() { CheckedError Parser::ParseFlexBufferValue(flexbuffers::Builder *builder) { switch (token_) { case '{': { - std::pair<Parser *, flexbuffers::Builder *> parser_and_builder_state( - this, builder); auto start = builder->StartMap(); size_t fieldn_outer = 0; - auto err = ParseTableDelimiters( - fieldn_outer, nullptr, - [](const std::string &name, size_t &fieldn, const StructDef *, - void *state) -> CheckedError { - auto *parser_and_builder = - static_cast<std::pair<Parser *, flexbuffers::Builder *> *>( - state); - auto *parser = parser_and_builder->first; - auto *current_builder = parser_and_builder->second; - current_builder->Key(name); - ECHECK(parser->ParseFlexBufferValue(current_builder)); - fieldn++; - return NoError(); - }, - &parser_and_builder_state); + auto err = + ParseTableDelimiters(fieldn_outer, nullptr, + [&](const std::string &name, size_t &fieldn, + const StructDef *) -> CheckedError { + builder->Key(name); + ECHECK(ParseFlexBufferValue(builder)); + fieldn++; + return NoError(); + }); ECHECK(err); builder->EndMap(start); break; @@ -2200,18 +2320,9 @@ CheckedError Parser::ParseFlexBufferValue(flexbuffers::Builder *builder) { case '[': { auto start = builder->StartVector(); size_t count = 0; - std::pair<Parser *, flexbuffers::Builder *> parser_and_builder_state( - this, builder); - ECHECK(ParseVectorDelimiters( - count, - [](size_t &, void *state) -> CheckedError { - auto *parser_and_builder = - static_cast<std::pair<Parser *, flexbuffers::Builder *> *>( - state); - return parser_and_builder->first->ParseFlexBufferValue( - parser_and_builder->second); - }, - &parser_and_builder_state)); + ECHECK(ParseVectorDelimiters(count, [&](size_t &) -> CheckedError { + return ParseFlexBufferValue(builder); + })); builder->EndVector(start, false, false); break; } @@ -2253,14 +2364,17 @@ bool Parser::ParseFlexBuffer(const char *source, const char *source_filename, bool Parser::Parse(const char *source, const char **include_paths, const char *source_filename) { - return !ParseRoot(source, include_paths, source_filename).Check(); + FLATBUFFERS_ASSERT(0 == recurse_protection_counter); + auto r = !ParseRoot(source, include_paths, source_filename).Check(); + FLATBUFFERS_ASSERT(0 == recurse_protection_counter); + return r; } CheckedError Parser::StartParseFile(const char *source, const char *source_filename) { file_being_parsed_ = source_filename ? source_filename : ""; - source_ = cursor_ = source; - line_ = 1; + source_ = source; + ResetState(source_); error_.clear(); ECHECK(SkipByteOrderMark()); NEXT(); @@ -2352,10 +2466,14 @@ CheckedError Parser::ParseRoot(const char *source, const char **include_paths, CheckedError Parser::DoParse(const char *source, const char **include_paths, const char *source_filename, const char *include_filename) { - if (source_filename && - included_files_.find(source_filename) == included_files_.end()) { - included_files_[source_filename] = include_filename ? include_filename : ""; - files_included_per_file_[source_filename] = std::set<std::string>(); + if (source_filename) { + if (included_files_.find(source_filename) == included_files_.end()) { + included_files_[source_filename] = + include_filename ? include_filename : ""; + files_included_per_file_[source_filename] = std::set<std::string>(); + } else { + return NoError(); + } } if (!include_paths) { static const char *current_directory[] = { "", nullptr }; @@ -2416,6 +2534,9 @@ CheckedError Parser::DoParse(const char *source, const char **include_paths, // entered into included_files_. // This is recursive, but only go as deep as the number of include // statements. + if (source_filename) { + included_files_.erase(source_filename); + } return DoParse(source, include_paths, source_filename, include_filename); } @@ -2447,6 +2568,9 @@ CheckedError Parser::DoParse(const char *source, const char **include_paths, ? file_identifier_.c_str() : nullptr); } + // Check that JSON file doesn't contain more objects or IDL directives. + // Comments after JSON are allowed. + EXPECT(kTokenEof); } else if (IsIdent("enum")) { ECHECK(ParseEnum(false, nullptr)); } else if (IsIdent("union")) { @@ -2560,14 +2684,15 @@ void Parser::Serialize() { service_offsets.push_back(offset); (*it)->serialized_location = offset.o; } - auto schema_offset = reflection::CreateSchema( - builder_, - builder_.CreateVectorOfSortedTables(&object_offsets), - builder_.CreateVectorOfSortedTables(&enum_offsets), - builder_.CreateString(file_identifier_), - builder_.CreateString(file_extension_), - (root_struct_def_ ? root_struct_def_->serialized_location : 0), - builder_.CreateVectorOfSortedTables(&service_offsets)); + auto objs__ = builder_.CreateVectorOfSortedTables(&object_offsets); + auto enum__ = builder_.CreateVectorOfSortedTables(&enum_offsets); + auto fiid__ = builder_.CreateString(file_identifier_); + auto fext__ = builder_.CreateString(file_extension_); + auto serv__ = builder_.CreateVectorOfSortedTables(&service_offsets); + auto schema_offset = + reflection::CreateSchema(builder_, objs__, enum__, fiid__, fext__, + (root_struct_def_ ? root_struct_def_->serialized_location : 0), + serv__); if (opts.size_prefixed) { builder_.FinishSizePrefixed(schema_offset, reflection::SchemaIdentifier()); } else { @@ -2575,6 +2700,32 @@ void Parser::Serialize() { } } +static Namespace *GetNamespace( + const std::string &qualified_name, std::vector<Namespace *> &namespaces, + std::map<std::string, Namespace *> &namespaces_index) { + size_t dot = qualified_name.find_last_of('.'); + std::string namespace_name = (dot != std::string::npos) + ? std::string(qualified_name.c_str(), dot) + : ""; + Namespace *&ns = namespaces_index[namespace_name]; + + if (!ns) { + ns = new Namespace(); + namespaces.push_back(ns); + + size_t pos = 0; + + for (;;) { + dot = qualified_name.find('.', pos); + if (dot == std::string::npos) { break; } + ns->components.push_back(qualified_name.substr(pos, dot-pos)); + pos = dot + 1; + } + } + + return ns; +} + Offset<reflection::Object> StructDef::Serialize(FlatBufferBuilder *builder, const Parser &parser) const { std::vector<Offset<reflection::Field>> field_offsets; @@ -2583,47 +2734,131 @@ Offset<reflection::Object> StructDef::Serialize(FlatBufferBuilder *builder, builder, static_cast<uint16_t>(it - fields.vec.begin()), parser)); } auto qualified_name = defined_namespace->GetFullyQualifiedName(name); - return reflection::CreateObject( - *builder, - builder->CreateString(qualified_name), - builder->CreateVectorOfSortedTables(&field_offsets), - fixed, - static_cast<int>(minalign), - static_cast<int>(bytesize), - SerializeAttributes(builder, parser), - parser.opts.binary_schema_comments - ? builder->CreateVectorOfStrings(doc_comment) - : 0); + auto name__ = builder->CreateString(qualified_name); + auto flds__ = builder->CreateVectorOfSortedTables(&field_offsets); + auto attr__ = SerializeAttributes(builder, parser); + auto docs__ = parser.opts.binary_schema_comments + ? builder->CreateVectorOfStrings(doc_comment) + : 0; + return reflection::CreateObject(*builder, name__, flds__, fixed, + static_cast<int>(minalign), + static_cast<int>(bytesize), + attr__, docs__); +} + +bool StructDef::Deserialize(Parser &parser, const reflection::Object *object) { + if (!DeserializeAttributes(parser, object->attributes())) + return false; + DeserializeDoc(doc_comment, object->documentation()); + name = parser.UnqualifiedName(object->name()->str()); + fixed = object->is_struct(); + minalign = object->minalign(); + predecl = false; + sortbysize = attributes.Lookup("original_order") == nullptr && !fixed; + std::vector<uoffset_t> indexes = + std::vector<uoffset_t>(object->fields()->size()); + for (uoffset_t i = 0; i < object->fields()->size(); i++) + indexes[object->fields()->Get(i)->id()] = i; + for (size_t i = 0; i < indexes.size(); i++) { + auto field = object->fields()->Get(indexes[i]); + auto field_def = new FieldDef(); + if (!field_def->Deserialize(parser, field) || + fields.Add(field_def->name, field_def)) { + delete field_def; + return false; + } + if (fixed) { + // Recompute padding since that's currently not serialized. + auto size = InlineSize(field_def->value.type); + auto next_field = + i + 1 < indexes.size() + ? object->fields()->Get(indexes[i+1]) + : nullptr; + bytesize += size; + field_def->padding = + next_field ? (next_field->offset() - field_def->value.offset) - size + : PaddingBytes(bytesize, minalign); + bytesize += field_def->padding; + } + } + FLATBUFFERS_ASSERT(static_cast<int>(bytesize) == object->bytesize()); + return true; } Offset<reflection::Field> FieldDef::Serialize(FlatBufferBuilder *builder, uint16_t id, const Parser &parser) const { - return reflection::CreateField( - *builder, builder->CreateString(name), value.type.Serialize(builder), id, - value.offset, + auto name__ = builder->CreateString(name); + auto type__ = value.type.Serialize(builder); + auto attr__ = SerializeAttributes(builder, parser); + auto docs__ = parser.opts.binary_schema_comments + ? builder->CreateVectorOfStrings(doc_comment) + : 0; + return reflection::CreateField(*builder, name__, type__, id, value.offset, + // Is uint64>max(int64) tested? IsInteger(value.type.base_type) ? StringToInt(value.constant.c_str()) : 0, + // result may be platform-dependent if underlying is float (not double) IsFloat(value.type.base_type) ? strtod(value.constant.c_str(), nullptr) : 0.0, - deprecated, required, key, SerializeAttributes(builder, parser), - parser.opts.binary_schema_comments - ? builder->CreateVectorOfStrings(doc_comment) - : 0); + deprecated, required, key, attr__, docs__); // TODO: value.constant is almost always "0", we could save quite a bit of // space by sharing it. Same for common values of value.type. } +bool FieldDef::Deserialize(Parser &parser, const reflection::Field *field) { + name = parser.UnqualifiedName(field->name()->str()); + defined_namespace = parser.current_namespace_; + if (!value.type.Deserialize(parser, field->type())) + return false; + value.offset = field->offset(); + if (IsInteger(value.type.base_type)) { + value.constant = NumToString(field->default_integer()); + } else if (IsFloat(value.type.base_type)) { + value.constant = FloatToString(field->default_real(), 16); + size_t last_zero = value.constant.find_last_not_of('0'); + if (last_zero != std::string::npos && last_zero != 0) { + value.constant.erase(last_zero, std::string::npos); + } + } + deprecated = field->deprecated(); + required = field->required(); + key = field->key(); + if (!DeserializeAttributes(parser, field->attributes())) + return false; + // TODO: this should probably be handled by a separate attribute + if (attributes.Lookup("flexbuffer")) { + flexbuffer = true; + parser.uses_flexbuffers_ = true; + if (value.type.base_type != BASE_TYPE_VECTOR || + value.type.element != BASE_TYPE_UCHAR) + return false; + } + DeserializeDoc(doc_comment, field->documentation()); + return true; +} + Offset<reflection::RPCCall> RPCCall::Serialize(FlatBufferBuilder *builder, const Parser &parser) const { - return reflection::CreateRPCCall( - *builder, - builder->CreateString(name), - request->serialized_location, - response->serialized_location, - SerializeAttributes(builder, parser), - parser.opts.binary_schema_comments - ? builder->CreateVectorOfStrings(doc_comment) - : 0); + auto name__ = builder->CreateString(name); + auto attr__ = SerializeAttributes(builder, parser); + auto docs__ = parser.opts.binary_schema_comments + ? builder->CreateVectorOfStrings(doc_comment) + : 0; + return reflection::CreateRPCCall(*builder, name__, + request->serialized_location, + response->serialized_location, + attr__, docs__); +} + +bool RPCCall::Deserialize(Parser &parser, const reflection::RPCCall *call) { + name = call->name()->str(); + if (!DeserializeAttributes(parser, call->attributes())) + return false; + DeserializeDoc(doc_comment, call->documentation()); + request = parser.structs_.Lookup(call->request()->name()->str()); + response = parser.structs_.Lookup(call->response()->name()->str()); + if (!request || !response) { return false; } + return true; } Offset<reflection::Service> ServiceDef::Serialize(FlatBufferBuilder *builder, @@ -2633,14 +2868,32 @@ Offset<reflection::Service> ServiceDef::Serialize(FlatBufferBuilder *builder, servicecall_offsets.push_back((*it)->Serialize(builder, parser)); } auto qualified_name = defined_namespace->GetFullyQualifiedName(name); - return reflection::CreateService( - *builder, - builder->CreateString(qualified_name), - builder->CreateVector(servicecall_offsets), - SerializeAttributes(builder, parser), - parser.opts.binary_schema_comments - ? builder->CreateVectorOfStrings(doc_comment) - : 0); + auto name__ = builder->CreateString(qualified_name); + auto call__ = builder->CreateVector(servicecall_offsets); + auto attr__ = SerializeAttributes(builder, parser); + auto docs__ = parser.opts.binary_schema_comments + ? builder->CreateVectorOfStrings(doc_comment) + : 0; + return reflection::CreateService(*builder, name__, call__, attr__, docs__); +} + +bool ServiceDef::Deserialize(Parser &parser, + const reflection::Service *service) { + name = parser.UnqualifiedName(service->name()->str()); + if (service->calls()) { + for (uoffset_t i = 0; i < service->calls()->size(); ++i) { + auto call = new RPCCall(); + if (!call->Deserialize(parser, service->calls()->Get(i)) || + calls.Add(call->name, call)) { + delete call; + return false; + } + } + } + if (!DeserializeAttributes(parser, service->attributes())) + return false; + DeserializeDoc(doc_comment, service->documentation()); + return true; } Offset<reflection::Enum> EnumDef::Serialize(FlatBufferBuilder *builder, @@ -2650,29 +2903,57 @@ Offset<reflection::Enum> EnumDef::Serialize(FlatBufferBuilder *builder, enumval_offsets.push_back((*it)->Serialize(builder, parser)); } auto qualified_name = defined_namespace->GetFullyQualifiedName(name); - return reflection::CreateEnum( - *builder, - builder->CreateString(qualified_name), - builder->CreateVector(enumval_offsets), - is_union, - underlying_type.Serialize(builder), - SerializeAttributes(builder, parser), - parser.opts.binary_schema_comments - ? builder->CreateVectorOfStrings(doc_comment) - : 0); + auto name__ = builder->CreateString(qualified_name); + auto vals__ = builder->CreateVector(enumval_offsets); + auto type__ = underlying_type.Serialize(builder); + auto attr__ = SerializeAttributes(builder, parser); + auto docs__ = parser.opts.binary_schema_comments + ? builder->CreateVectorOfStrings(doc_comment) + : 0; + return reflection::CreateEnum(*builder, name__, vals__, is_union, type__, + attr__, docs__); +} + +bool EnumDef::Deserialize(Parser &parser, const reflection::Enum *_enum) { + name = parser.UnqualifiedName(_enum->name()->str()); + for (uoffset_t i = 0; i < _enum->values()->size(); ++i) { + auto val = new EnumVal(); + if (!val->Deserialize(parser, _enum->values()->Get(i)) || + vals.Add(val->name, val)) { + delete val; + return false; + } + } + is_union = _enum->is_union(); + if (!underlying_type.Deserialize(parser, _enum->underlying_type())) { + return false; + } + if (!DeserializeAttributes(parser, _enum->attributes())) + return false; + DeserializeDoc(doc_comment, _enum->documentation()); + return true; } Offset<reflection::EnumVal> EnumVal::Serialize(FlatBufferBuilder *builder, const Parser &parser) const { - return reflection::CreateEnumVal( - *builder, - builder->CreateString(name), - value, + auto name__ = builder->CreateString(name); + auto type__ = union_type.Serialize(builder); + auto docs__ = parser.opts.binary_schema_comments + ? builder->CreateVectorOfStrings(doc_comment) + : 0; + return reflection::CreateEnumVal(*builder, name__, value, union_type.struct_def ? union_type.struct_def->serialized_location : 0, - union_type.Serialize(builder), - parser.opts.binary_schema_comments - ? builder->CreateVectorOfStrings(doc_comment) - : 0); + type__, docs__); +} + +bool EnumVal::Deserialize(const Parser &parser, + const reflection::EnumVal *val) { + name = val->name()->str(); + value = val->value(); + if (!union_type.Deserialize(parser, val->union_type())) + return false; + DeserializeDoc(doc_comment, val->documentation()); + return true; } Offset<reflection::Type> Type::Serialize(FlatBufferBuilder *builder) const { @@ -2683,6 +2964,31 @@ Offset<reflection::Type> Type::Serialize(FlatBufferBuilder *builder) const { struct_def ? struct_def->index : (enum_def ? enum_def->index : -1)); } +bool Type::Deserialize(const Parser &parser, const reflection::Type *type) { + if (type == nullptr) return true; + base_type = static_cast<BaseType>(type->base_type()); + element = static_cast<BaseType>(type->element()); + if (type->index() >= 0) { + if (type->base_type() == reflection::Obj || + (type->base_type() == reflection::Vector && + type->element() == reflection::Obj)) { + if (static_cast<size_t>(type->index()) < parser.structs_.vec.size()) { + struct_def = parser.structs_.vec[type->index()]; + struct_def->refcount++; + } else { + return false; + } + } else { + if (static_cast<size_t>(type->index()) < parser.enums_.vec.size()) { + enum_def = parser.enums_.vec[type->index()]; + } else { + return false; + } + } + } + return true; +} + flatbuffers::Offset< flatbuffers::Vector<flatbuffers::Offset<reflection::KeyValue>>> Definition::SerializeAttributes(FlatBufferBuilder *builder, @@ -2692,9 +2998,9 @@ Definition::SerializeAttributes(FlatBufferBuilder *builder, auto it = parser.known_attributes_.find(kv->first); FLATBUFFERS_ASSERT(it != parser.known_attributes_.end()); if (parser.opts.binary_schema_builtins || !it->second) { - attrs.push_back(reflection::CreateKeyValue( - *builder, builder->CreateString(kv->first), - builder->CreateString(kv->second->constant))); + auto key = builder->CreateString(kv->first); + auto val = builder->CreateString(kv->second->constant); + attrs.push_back(reflection::CreateKeyValue(*builder, key, val)); } } if (attrs.size()) { @@ -2704,6 +3010,115 @@ Definition::SerializeAttributes(FlatBufferBuilder *builder, } } +bool Definition::DeserializeAttributes( + Parser &parser, const Vector<Offset<reflection::KeyValue>> *attrs) { + if (attrs == nullptr) + return true; + for (uoffset_t i = 0; i < attrs->size(); ++i) { + auto kv = attrs->Get(i); + auto value = new Value(); + if (kv->value()) { value->constant = kv->value()->str(); } + if (attributes.Add(kv->key()->str(), value)) { + delete value; + return false; + } + parser.known_attributes_[kv->key()->str()]; + } + return true; +} + +/************************************************************************/ +/* DESERIALIZATION */ +/************************************************************************/ +bool Parser::Deserialize(const uint8_t *buf, const size_t size) { + flatbuffers::Verifier verifier(reinterpret_cast<const uint8_t *>(buf), size); + bool size_prefixed = false; + if(!reflection::SchemaBufferHasIdentifier(buf)) { + if (!flatbuffers::BufferHasIdentifier(buf, reflection::SchemaIdentifier(), + true)) + return false; + else + size_prefixed = true; + } + auto verify_fn = size_prefixed ? &reflection::VerifySizePrefixedSchemaBuffer + : &reflection::VerifySchemaBuffer; + if (!verify_fn(verifier)) { + return false; + } + auto schema = size_prefixed ? reflection::GetSizePrefixedSchema(buf) + : reflection::GetSchema(buf); + return Deserialize(schema); +} + +bool Parser::Deserialize(const reflection::Schema *schema) { + file_identifier_ = schema->file_ident() ? schema->file_ident()->str() : ""; + file_extension_ = schema->file_ext() ? schema->file_ext()->str() : ""; + std::map<std::string, Namespace *> namespaces_index; + + // Create defs without deserializing so references from fields to structs and + // enums can be resolved. + for (auto it = schema->objects()->begin(); it != schema->objects()->end(); + ++it) { + auto struct_def = new StructDef(); + if (structs_.Add(it->name()->str(), struct_def)) { + delete struct_def; + return false; + } + auto type = new Type(BASE_TYPE_STRUCT, struct_def, nullptr); + if (types_.Add(it->name()->str(), type)) { + delete type; + return false; + } + } + for (auto it = schema->enums()->begin(); it != schema->enums()->end(); ++it) { + auto enum_def = new EnumDef(); + if (enums_.Add(it->name()->str(), enum_def)) { + delete enum_def; + return false; + } + auto type = new Type(BASE_TYPE_UNION, nullptr, enum_def); + if (types_.Add(it->name()->str(), type)) { + delete type; + return false; + } + } + + // Now fields can refer to structs and enums by index. + for (auto it = schema->objects()->begin(); it != schema->objects()->end(); + ++it) { + std::string qualified_name = it->name()->str(); + auto struct_def = structs_.Lookup(qualified_name); + struct_def->defined_namespace = + GetNamespace(qualified_name, namespaces_, namespaces_index); + if (!struct_def->Deserialize(*this, * it)) { return false; } + if (schema->root_table() == *it) { root_struct_def_ = struct_def; } + } + for (auto it = schema->enums()->begin(); it != schema->enums()->end(); ++it) { + std::string qualified_name = it->name()->str(); + auto enum_def = enums_.Lookup(qualified_name); + enum_def->defined_namespace = + GetNamespace(qualified_name, namespaces_, namespaces_index); + if (!enum_def->Deserialize(*this, *it)) { return false; } + } + + if (schema->services()) { + for (auto it = schema->services()->begin(); it != schema->services()->end(); + ++it) { + std::string qualified_name = it->name()->str(); + auto service_def = new ServiceDef(); + service_def->defined_namespace = + GetNamespace(qualified_name, namespaces_, namespaces_index); + if (!service_def->Deserialize(*this, *it) || + services_.Add(qualified_name, service_def)) { + delete service_def; + return false; + } + } + } + + return true; +} + std::string Parser::ConformTo(const Parser &base) { for (auto sit = structs_.vec.begin(); sit != structs_.vec.end(); ++sit) { auto &struct_def = **sit; diff --git a/chromium/third_party/flatbuffers/src/src/reflection.cpp b/chromium/third_party/flatbuffers/src/src/reflection.cpp index 61c1ba7321e..89ce7838569 100644 --- a/chromium/third_party/flatbuffers/src/src/reflection.cpp +++ b/chromium/third_party/flatbuffers/src/src/reflection.cpp @@ -299,13 +299,13 @@ class ResizeContext { void SetString(const reflection::Schema &schema, const std::string &val, const String *str, std::vector<uint8_t> *flatbuf, const reflection::Object *root_table) { - auto delta = static_cast<int>(val.size()) - static_cast<int>(str->Length()); + auto delta = static_cast<int>(val.size()) - static_cast<int>(str->size()); auto str_start = static_cast<uoffset_t>( reinterpret_cast<const uint8_t *>(str) - vector_data(*flatbuf)); auto start = str_start + static_cast<uoffset_t>(sizeof(uoffset_t)); if (delta) { // Clear the old string, since we don't want parts of it remaining. - memset(vector_data(*flatbuf) + start, 0, str->Length()); + memset(vector_data(*flatbuf) + start, 0, str->size()); // Different size, we must expand (or contract). ResizeContext(schema, start, delta, flatbuf, root_table); // Set the new length. @@ -431,7 +431,7 @@ Offset<const Table *> CopyTable(FlatBufferBuilder &fbb, break; } } - // FALL-THRU + FLATBUFFERS_FALLTHROUGH(); // fall thru default: { // Scalars and structs. auto element_size = GetTypeSize(element_base_type); if (elemobjectdef && elemobjectdef->is_struct()) @@ -466,7 +466,7 @@ Offset<const Table *> CopyTable(FlatBufferBuilder &fbb, break; } } - // ELSE FALL-THRU + FLATBUFFERS_FALLTHROUGH(); // fall thru case reflection::Union: case reflection::String: case reflection::Vector: diff --git a/chromium/third_party/flatbuffers/src/src/util.cpp b/chromium/third_party/flatbuffers/src/src/util.cpp index 15a2f53e266..c1bb1975ce2 100644 --- a/chromium/third_party/flatbuffers/src/src/util.cpp +++ b/chromium/third_party/flatbuffers/src/src/util.cpp @@ -14,8 +14,31 @@ * limitations under the License. */ +// clang-format off +// Dont't remove `format off`, it prevent reordering of win-includes. +#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 +// clang-format on + +#include "flatbuffers/base.h" #include "flatbuffers/util.h" +#include <sys/stat.h> +#include <clocale> +#include <fstream> + namespace flatbuffers { bool FileExistsRaw(const char *name) { @@ -58,6 +81,7 @@ bool FileExists(const char *name) { bool DirExists(const char *name) { // clang-format off + #ifdef _WIN32 #define flatbuffers_stat _stat #define FLATBUFFERS_S_IFDIR _S_IFDIR @@ -85,4 +109,140 @@ FileExistsFunction SetFileExistsFunction( return previous_function; } +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(); +} + +// 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 kPathSeparatorWindows = '\\'; +static const char *PathSeparatorSet = "\\/"; // Intentionally no ':' + +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 GetExtension(const std::string &filepath) { + size_t i = filepath.find_last_of("."); + return i != std::string::npos ? filepath.substr(i + 1) : ""; +} + +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 StripFileName(const std::string &filepath) { + size_t i = filepath.find_last_of(PathSeparatorSet); + return i != std::string::npos ? filepath.substr(0, i) : ""; +} + +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 PosixPath(const char *path) { + std::string p = path; + std::replace(p.begin(), p.end(), '\\', '/'); + return p; +} + +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 +} + +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 +} + +// Locale-independent code. +#if defined(FLATBUFFERS_LOCALE_INDEPENDENT) && \ + (FLATBUFFERS_LOCALE_INDEPENDENT > 0) + +// clang-format off +// Allocate locale instance at startup of application. +ClassicLocale ClassicLocale::instance_; + +#ifdef _MSC_VER + ClassicLocale::ClassicLocale() + : locale_(_create_locale(LC_ALL, "C")) {} + ClassicLocale::~ClassicLocale() { _free_locale(locale_); } +#else + ClassicLocale::ClassicLocale() + : locale_(newlocale(LC_ALL, "C", nullptr)) {} + ClassicLocale::~ClassicLocale() { freelocale(locale_); } +#endif +// clang-format on + +#endif // !FLATBUFFERS_LOCALE_INDEPENDENT + +std::string RemoveStringQuotes(const std::string &s) { + auto ch = *s.c_str(); + return ((s.size() >= 2) && (ch == '\"' || ch == '\'') && + (ch == string_back(s))) + ? s.substr(1, s.length() - 2) + : s; +} + +bool SetGlobalTestLocale(const char *locale_name, std::string *_value) { + const auto the_locale = setlocale(LC_ALL, locale_name); + if (!the_locale) return false; + if (_value) *_value = std::string(the_locale); + return true; +} +bool ReadEnvironmentVariable(const char *var_name, std::string *_value) { + #ifdef _MSC_VER + __pragma(warning(disable : 4996)); // _CRT_SECURE_NO_WARNINGS + #endif + auto env_str = std::getenv(var_name); + if (!env_str) return false; + if (_value) *_value = std::string(env_str); + return true; +} + } // namespace flatbuffers |