Remove some unused fbs files
This commit is contained in:
parent
9428761137
commit
d74eaafe64
@ -1,12 +0,0 @@
|
||||
Thank you for submitting an issue!
|
||||
|
||||
Please make sure you include the names of the affected language(s), compiler version(s), operating system version(s), and FlatBuffers version(s) in your issue title.
|
||||
|
||||
This helps us get the correct maintainers to look at your issue. Here are examples of good titles:
|
||||
|
||||
- Crash when accessing FlatBuffer [C++, gcc 4.8, OS X, master]
|
||||
- Flatc converts a protobuf 'bytes' field to 'string' in fbs schema file [all languages, FlatBuffers 1.4]
|
||||
|
||||
Include other details as appropriate.
|
||||
|
||||
Thanks!
|
@ -1,19 +0,0 @@
|
||||
Thank you for submitting a PR!
|
||||
|
||||
Please delete this standard text once you've created your own description.
|
||||
|
||||
If you make changes to any of the code generators (`src/idl_gen*`) be sure to
|
||||
[build](https://google.github.io/flatbuffers/flatbuffers_guide_building.html) your project, as it will generate code based on the changes. If necessary
|
||||
the code generation script can be directly run (`scripts/generate_code.py`),
|
||||
requires Python3. This allows us to better see the effect of the PR.
|
||||
|
||||
If your PR includes C++ code, please adhere to the
|
||||
[Google C++ Style Guide](https://google.github.io/styleguide/cppguide.html),
|
||||
and don't forget we try to support older compilers (e.g. VS2010, GCC 4.6.3),
|
||||
so only some C++11 support is available.
|
||||
|
||||
For any C++ changes, please make sure to run `sh scripts/clang-format-git.sh`
|
||||
|
||||
Include other details as appropriate.
|
||||
|
||||
Thanks!
|
97
third_party/flatbuffers/.github/labeler.yml
vendored
97
third_party/flatbuffers/.github/labeler.yml
vendored
@ -1,97 +0,0 @@
|
||||
# Configuration for Auto Labeler during pull request
|
||||
#
|
||||
# See https://github.com/actions/labeler for file format
|
||||
# and https://github.com/google/flatbuffers/labels for a list of valid labels
|
||||
#
|
||||
# See .github/workflows/label.yml for Github Action workflow script
|
||||
|
||||
c#:
|
||||
- '**/*.cs'
|
||||
- net/**/*
|
||||
- tests/FlatBuffers.Test/**/*
|
||||
- tests/FlatBuffers.Benchmarks/**/*
|
||||
- src/idl_gen_csharp.cpp
|
||||
|
||||
swift:
|
||||
- '**/*.swift'
|
||||
- swift/**/*
|
||||
- tests/swift/**
|
||||
- src/idl_gen_swift.cpp
|
||||
|
||||
nim:
|
||||
- '**/*.nim'
|
||||
- nim/**/*
|
||||
- src/idl_gen_nim.cpp
|
||||
- src/bfbs_gen_nim.cpp
|
||||
|
||||
javascript:
|
||||
- '**/*.js'
|
||||
- src/idl_gen_ts.cpp
|
||||
|
||||
typescript:
|
||||
- '**/*.ts'
|
||||
- src/idl_gen_ts.cpp
|
||||
- grpc/flatbuffers-js-grpc/**/*.ts
|
||||
|
||||
golang:
|
||||
- '**/*.go'
|
||||
- src/idl_gen_go.cpp
|
||||
|
||||
python:
|
||||
- '**/*.py'
|
||||
- src/idl_gen_python.cpp
|
||||
|
||||
java:
|
||||
- '**/*.java'
|
||||
- src/idl_gen_java.cpp
|
||||
|
||||
kotlin:
|
||||
- '**/*.kt'
|
||||
- src/idl_gen_kotlin.cpp
|
||||
- src/idl_gen_kotlin_kmp.cpp
|
||||
|
||||
lua:
|
||||
- '**/*.lua'
|
||||
- lua/**/*
|
||||
- src/bfbs_gen_lua.cpp
|
||||
|
||||
lobster:
|
||||
- '**/*.lobster'
|
||||
- src/idl_gen_lobster.cpp
|
||||
|
||||
php:
|
||||
- '**/*.php'
|
||||
- src/idl_gen_php.cpp
|
||||
|
||||
rust:
|
||||
- '**/*.rs'
|
||||
- rust/**/*
|
||||
- src/idl_gen_rust.cpp
|
||||
|
||||
dart:
|
||||
- '**/*.dart'
|
||||
- src/idl_gen_dart.cpp
|
||||
|
||||
c++:
|
||||
- '**/*.cc'
|
||||
- '**/*.cpp'
|
||||
- '**/*.h'
|
||||
|
||||
json:
|
||||
- '**/*.json'
|
||||
- src/idl_gen_json_schema.cpp
|
||||
|
||||
codegen:
|
||||
- src/**/*
|
||||
|
||||
documentation:
|
||||
- docs/**/*
|
||||
- '**/*.md'
|
||||
|
||||
CI:
|
||||
- '.github/**/*'
|
||||
- '.bazelci/**/*'
|
||||
|
||||
grpc:
|
||||
- grpc/**/*
|
||||
- src/idl_gen_grpc.cpp
|
587
third_party/flatbuffers/.github/workflows/build.yml
vendored
587
third_party/flatbuffers/.github/workflows/build.yml
vendored
@ -1,587 +0,0 @@
|
||||
name: CI
|
||||
permissions: read-all
|
||||
|
||||
on:
|
||||
# For manual tests.
|
||||
workflow_dispatch:
|
||||
push:
|
||||
tags:
|
||||
- "*" # new tag version, like `0.8.4` or else
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
|
||||
jobs:
|
||||
build-linux:
|
||||
permissions:
|
||||
contents: write
|
||||
outputs:
|
||||
digests-gcc: ${{ steps.hash-gcc.outputs.hashes }}
|
||||
digests-clang: ${{ steps.hash-clang.outputs.hashes }}
|
||||
name: Build Linux
|
||||
runs-on: ubuntu-22.04-64core
|
||||
strategy:
|
||||
matrix:
|
||||
cxx: [g++-13, clang++-15]
|
||||
fail-fast: false
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: cmake
|
||||
run: CXX=${{ matrix.cxx }} cmake -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Release -DFLATBUFFERS_STRICT_MODE=ON -DFLATBUFFERS_STATIC_FLATC=ON .
|
||||
- name: build
|
||||
run: make -j
|
||||
- name: test
|
||||
run: ./flattests
|
||||
- name: make flatc executable
|
||||
run: |
|
||||
chmod +x flatc
|
||||
./flatc --version
|
||||
- name: upload build artifacts
|
||||
uses: actions/upload-artifact@v1
|
||||
with:
|
||||
name: Linux flatc binary ${{ matrix.cxx }}
|
||||
path: flatc
|
||||
# Below if only for release.
|
||||
- name: Zip file
|
||||
if: startsWith(github.ref, 'refs/tags/')
|
||||
run: zip Linux.flatc.binary.${{ matrix.cxx }}.zip flatc
|
||||
- name: Release zip file
|
||||
uses: softprops/action-gh-release@v1
|
||||
if: startsWith(github.ref, 'refs/tags/')
|
||||
with:
|
||||
files: Linux.flatc.binary.${{ matrix.cxx }}.zip
|
||||
- name: Generate SLSA subjects - clang
|
||||
if: matrix.cxx == 'clang++-15' && startsWith(github.ref, 'refs/tags/')
|
||||
id: hash-clang
|
||||
run: echo "hashes=$(sha256sum Linux.flatc.binary.${{ matrix.cxx }}.zip | base64 -w0)" >> $GITHUB_OUTPUT
|
||||
- name: Generate SLSA subjects - gcc
|
||||
if: matrix.cxx == 'g++-13' && startsWith(github.ref, 'refs/tags/')
|
||||
id: hash-gcc
|
||||
run: echo "hashes=$(sha256sum Linux.flatc.binary.${{ matrix.cxx }}.zip | base64 -w0)" >> $GITHUB_OUTPUT
|
||||
|
||||
build-linux-no-file-tests:
|
||||
name: Build Linux with -DFLATBUFFERS_NO_FILE_TESTS
|
||||
runs-on: ubuntu-22.04-64core
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: cmake
|
||||
run: CXX=clang++-15 cmake -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Release -DFLATBUFFERS_STRICT_MODE=ON -DFLATBUFFERS_CXX_FLAGS="-DFLATBUFFERS_NO_FILE_TESTS" .
|
||||
- name: build
|
||||
run: make -j
|
||||
- name: test
|
||||
run: ./flattests
|
||||
|
||||
build-linux-out-of-source:
|
||||
name: Build Linux with out-of-source build location
|
||||
runs-on: ubuntu-22.04-64core
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: make build directory
|
||||
run: mkdir build
|
||||
- name: cmake
|
||||
working-directory: build
|
||||
run: >
|
||||
CXX=clang++-15 cmake .. -G "Unix Makefiles" -DFLATBUFFERS_STRICT_MODE=ON
|
||||
-DFLATBUFFERS_BUILD_CPP17=ON -DFLATBUFFERS_CPP_STD=17
|
||||
- name: build
|
||||
working-directory: build
|
||||
run: make -j
|
||||
- name: test
|
||||
working-directory: build
|
||||
run: pwd && ./flattests
|
||||
- name: test C++17
|
||||
working-directory: build
|
||||
run: ./flattests_cpp17
|
||||
|
||||
build-linux-cpp-std:
|
||||
name: Build Linux C++
|
||||
runs-on: ubuntu-22.04-64core
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
std: [11, 14, 17, 20, 23]
|
||||
cxx: [g++-13, clang++-15]
|
||||
exclude:
|
||||
# Clang++15 10.3.0 stdlibc++ doesn't fully support std 23
|
||||
- cxx: clang++-15
|
||||
std: 23
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: cmake
|
||||
run: >
|
||||
CXX=${{ matrix.cxx }} cmake -G "Unix Makefiles"
|
||||
-DCMAKE_BUILD_TYPE=Release -DFLATBUFFERS_STRICT_MODE=ON
|
||||
-DFLATBUFFERS_CPP_STD=${{ matrix.std }}
|
||||
-DFLATBUFFERS_BUILD_CPP17=${{ matrix.std >= 17 && 'On' || 'Off'}}
|
||||
- name: build
|
||||
run: make -j
|
||||
- name: test
|
||||
run: ./flattests
|
||||
- name: test C++17
|
||||
if: matrix.std >= 17
|
||||
run: ./flattests_cpp17
|
||||
|
||||
build-cpp-std:
|
||||
name: Build Windows C++
|
||||
runs-on: windows-2019
|
||||
strategy:
|
||||
matrix:
|
||||
std: [11, 14, 17, 20, 23]
|
||||
fail-fast: false
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Add msbuild to PATH
|
||||
uses: microsoft/setup-msbuild@v1.1
|
||||
- name: cmake
|
||||
run: >
|
||||
cmake -G "Visual Studio 16 2019" -A x64 -DCMAKE_BUILD_TYPE=Release
|
||||
-DFLATBUFFERS_STRICT_MODE=ON
|
||||
-DFLATBUFFERS_CPP_STD=${{ matrix.std }}
|
||||
-DFLATBUFFERS_BUILD_CPP17=${{ matrix.std >= 17 && 'On' || 'Off'}}
|
||||
- name: build
|
||||
run: msbuild.exe FlatBuffers.sln /p:Configuration=Release /p:Platform=x64
|
||||
- name: test
|
||||
run: Release\flattests.exe
|
||||
- name: test C++17
|
||||
if: matrix.std >= 17
|
||||
run: Release\flattests_cpp17.exe
|
||||
|
||||
build-windows:
|
||||
permissions:
|
||||
contents: write
|
||||
outputs:
|
||||
digests: ${{ steps.hash.outputs.hashes }}
|
||||
name: Build Windows 2019
|
||||
runs-on: windows-2019
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Add msbuild to PATH
|
||||
uses: microsoft/setup-msbuild@v1.1
|
||||
- name: cmake
|
||||
run: cmake -G "Visual Studio 16 2019" -A x64 -DCMAKE_BUILD_TYPE=Release -DFLATBUFFERS_BUILD_CPP17=ON -DFLATBUFFERS_STRICT_MODE=ON .
|
||||
- name: build
|
||||
run: msbuild.exe FlatBuffers.sln /p:Configuration=Release /p:Platform=x64
|
||||
- name: test
|
||||
run: Release\flattests.exe
|
||||
- name: upload build artifacts
|
||||
uses: actions/upload-artifact@v1
|
||||
with:
|
||||
name: Windows flatc binary
|
||||
path: Release\flatc.exe
|
||||
# Below if only for release.
|
||||
- name: Zip file
|
||||
if: startsWith(github.ref, 'refs/tags/')
|
||||
run: move Release/flatc.exe . && Compress-Archive flatc.exe Windows.flatc.binary.zip
|
||||
- name: Release binary
|
||||
uses: softprops/action-gh-release@v1
|
||||
if: startsWith(github.ref, 'refs/tags/')
|
||||
with:
|
||||
files: Windows.flatc.binary.zip
|
||||
- name: Generate SLSA subjects
|
||||
if: startsWith(github.ref, 'refs/tags/')
|
||||
id: hash
|
||||
shell: bash
|
||||
run: echo "hashes=$(sha256sum Windows.flatc.binary.zip | base64 -w0)" >> $GITHUB_OUTPUT
|
||||
|
||||
build-dotnet-windows:
|
||||
name: Build .NET Windows
|
||||
runs-on: windows-2022-64core
|
||||
strategy:
|
||||
matrix:
|
||||
configuration: [
|
||||
'',
|
||||
'-p:UnsafeByteBuffer=true',
|
||||
# Fails two tests currently.
|
||||
#'-p:EnableSpanT=true,UnsafeByteBuffer=true'
|
||||
]
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Setup .NET Core SDK
|
||||
uses: actions/setup-dotnet@v3
|
||||
with:
|
||||
dotnet-version: '8.0.x'
|
||||
- name: Build
|
||||
run: |
|
||||
cd tests\FlatBuffers.Test
|
||||
dotnet new sln --force --name FlatBuffers.Test
|
||||
dotnet sln FlatBuffers.Test.sln add FlatBuffers.Test.csproj
|
||||
dotnet build -c Release ${{matrix.configuration}} -o out FlatBuffers.Test.sln
|
||||
- name: Run
|
||||
run: |
|
||||
cd tests\FlatBuffers.Test
|
||||
out\FlatBuffers.Test.exe
|
||||
|
||||
build-mac-intel:
|
||||
permissions:
|
||||
contents: write
|
||||
outputs:
|
||||
digests: ${{ steps.hash.outputs.hashes }}
|
||||
name: Build Mac (for Intel)
|
||||
runs-on: macos-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: cmake
|
||||
run: cmake -G "Xcode" -DCMAKE_BUILD_TYPE=Release -DFLATBUFFERS_STRICT_MODE=ON .
|
||||
- name: build
|
||||
run: xcodebuild -toolchain clang -configuration Release -target flattests
|
||||
- name: check that the binary is x86_64
|
||||
run: |
|
||||
info=$(file Release/flatc)
|
||||
echo $info
|
||||
echo $info | grep "Mach-O 64-bit executable x86_64"
|
||||
- name: test
|
||||
run: Release/flattests
|
||||
- name: make flatc executable
|
||||
run: |
|
||||
chmod +x Release/flatc
|
||||
Release/flatc --version
|
||||
- name: upload build artifacts
|
||||
uses: actions/upload-artifact@v1
|
||||
with:
|
||||
name: Mac flatc binary
|
||||
path: Release/flatc
|
||||
# Below if only for release.
|
||||
- name: Zip file
|
||||
if: startsWith(github.ref, 'refs/tags/')
|
||||
run: mv Release/flatc . && zip MacIntel.flatc.binary.zip flatc
|
||||
- name: Release binary
|
||||
uses: softprops/action-gh-release@v1
|
||||
if: startsWith(github.ref, 'refs/tags/')
|
||||
with:
|
||||
files: MacIntel.flatc.binary.zip
|
||||
- name: Generate SLSA subjects
|
||||
if: startsWith(github.ref, 'refs/tags/')
|
||||
id: hash
|
||||
run: echo "hashes=$(shasum -a 256 MacIntel.flatc.binary.zip | base64)" >> $GITHUB_OUTPUT
|
||||
|
||||
build-mac-universal:
|
||||
permissions:
|
||||
contents: write
|
||||
outputs:
|
||||
digests: ${{ steps.hash.outputs.hashes }}
|
||||
name: Build Mac (universal build)
|
||||
runs-on: macos-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: cmake
|
||||
run: cmake -G "Xcode" -DCMAKE_OSX_ARCHITECTURES="arm64;x86_64" -DCMAKE_BUILD_TYPE=Release -DFLATBUFFERS_STRICT_MODE=ON .
|
||||
- name: build
|
||||
run: xcodebuild -toolchain clang -configuration Release -target flattests
|
||||
- name: check that the binary is "universal"
|
||||
run: |
|
||||
info=$(file Release/flatc)
|
||||
echo $info
|
||||
echo $info | grep "Mach-O universal binary with 2 architectures"
|
||||
- name: test
|
||||
run: Release/flattests
|
||||
- name: make flatc executable
|
||||
run: |
|
||||
chmod +x Release/flatc
|
||||
Release/flatc --version
|
||||
- name: upload build artifacts
|
||||
uses: actions/upload-artifact@v1
|
||||
with:
|
||||
name: Mac flatc binary
|
||||
path: Release/flatc
|
||||
# Below if only for release.
|
||||
- name: Zip file
|
||||
if: startsWith(github.ref, 'refs/tags/')
|
||||
run: mv Release/flatc . && zip Mac.flatc.binary.zip flatc
|
||||
- name: Release binary
|
||||
uses: softprops/action-gh-release@v1
|
||||
if: startsWith(github.ref, 'refs/tags/')
|
||||
with:
|
||||
files: Mac.flatc.binary.zip
|
||||
- name: Generate SLSA subjects
|
||||
if: startsWith(github.ref, 'refs/tags/')
|
||||
id: hash
|
||||
run: echo "hashes=$(shasum -a 256 Mac.flatc.binary.zip | base64)" >> $GITHUB_OUTPUT
|
||||
|
||||
build-android:
|
||||
name: Build Android (on Linux)
|
||||
runs-on: ubuntu-22.04-64core
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: set up Java
|
||||
uses: actions/setup-java@v3
|
||||
with:
|
||||
distribution: 'temurin'
|
||||
java-version: '11'
|
||||
- name: set up flatc
|
||||
run: |
|
||||
cmake -DFLATBUFFERS_BUILD_TESTS=OFF -DFLATBUFFERS_BUILD_FLATLIB=OFF -DFLATBUFFERS_BUILD_FLATHASH=OFF -DFLATBUFFERS_STRICT_MODE=ON .
|
||||
make -j
|
||||
echo "${PWD}" >> $GITHUB_PATH
|
||||
- name: build
|
||||
working-directory: android
|
||||
run: gradle clean build
|
||||
|
||||
build-generator:
|
||||
name: Check Generated Code
|
||||
runs-on: ubuntu-22.04-64core
|
||||
strategy:
|
||||
matrix:
|
||||
cxx: [g++-13, clang++-15]
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: cmake
|
||||
run: CXX=${{ matrix.cxx }} cmake -G "Unix Makefiles" -DFLATBUFFERS_BUILD_TESTS=OFF -DCMAKE_BUILD_TYPE=Release -DFLATBUFFERS_STRICT_MODE=ON . && make -j
|
||||
- name: Generate
|
||||
run: scripts/check_generate_code.py
|
||||
- name: Generate gRPC
|
||||
run: scripts/check-grpc-generated-code.py
|
||||
|
||||
build-generator-windows:
|
||||
name: Check Generated Code on Windows
|
||||
runs-on: windows-2019
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Add msbuild to PATH
|
||||
uses: microsoft/setup-msbuild@v1.1
|
||||
- name: cmake
|
||||
run: cmake -G "Visual Studio 16 2019" -A x64 -DCMAKE_BUILD_TYPE=Release -DFLATBUFFERS_BUILD_CPP17=ON -DFLATBUFFERS_STRICT_MODE=ON .
|
||||
- name: build
|
||||
run: msbuild.exe FlatBuffers.sln /p:Configuration=Release /p:Platform=x64
|
||||
- name: Generate
|
||||
run: python3 scripts/check_generate_code.py --flatc Release\flatc.exe
|
||||
- name: Generate gRPC
|
||||
run: python3 scripts/check-grpc-generated-code.py --flatc Release\flatc.exe
|
||||
|
||||
build-benchmarks:
|
||||
name: Build Benchmarks (on Linux)
|
||||
runs-on: ubuntu-22.04-64core
|
||||
strategy:
|
||||
matrix:
|
||||
cxx: [g++-13]
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: cmake
|
||||
run: CXX=${{ matrix.cxx }} cmake -G "Unix Makefiles" -DFLATBUFFERS_CXX_FLAGS="-Wno-unused-parameter -fno-aligned-new" -DFLATBUFFERS_BUILD_BENCHMARKS=ON -DCMAKE_BUILD_TYPE=Release -DFLATBUFFERS_STRICT_MODE=ON . && make -j
|
||||
- name: Run benchmarks
|
||||
run: ./flatbenchmark --benchmark_repetitions=5 --benchmark_display_aggregates_only=true --benchmark_out_format=console --benchmark_out=benchmarks/results_${{matrix.cxx}}
|
||||
- name: Upload benchmarks results
|
||||
uses: actions/upload-artifact@v1
|
||||
with:
|
||||
name: Linux flatbenchmark results ${{matrix.cxx}}
|
||||
path: benchmarks/results_${{matrix.cxx}}
|
||||
|
||||
build-java:
|
||||
name: Build Java
|
||||
runs-on: ubuntu-22.04-64core
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: test
|
||||
working-directory: java
|
||||
run: mvn test
|
||||
|
||||
build-kotlin-macos:
|
||||
name: Build Kotlin MacOS
|
||||
runs-on: macos-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
- uses: gradle/wrapper-validation-action@v1.0.5
|
||||
- uses: actions/setup-java@v3
|
||||
with:
|
||||
distribution: 'temurin'
|
||||
java-version: '11'
|
||||
- name: Build flatc
|
||||
run: |
|
||||
cmake -DFLATBUFFERS_BUILD_TESTS=OFF -DFLATBUFFERS_BUILD_FLATLIB=OFF -DFLATBUFFERS_BUILD_FLATHASH=OFF .
|
||||
make -j
|
||||
echo "${PWD}" >> $GITHUB_PATH
|
||||
- name: Build
|
||||
working-directory: kotlin
|
||||
run: ./gradlew clean iosSimulatorArm64Test macosX64Test macosArm64Test
|
||||
|
||||
build-kotlin-linux:
|
||||
name: Build Kotlin Linux
|
||||
runs-on: ubuntu-22.04-64core
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
- uses: actions/setup-java@v3
|
||||
with:
|
||||
distribution: 'temurin'
|
||||
java-version: '11'
|
||||
- uses: gradle/wrapper-validation-action@v1.0.5
|
||||
- name: Build flatc
|
||||
run: |
|
||||
cmake -DFLATBUFFERS_BUILD_TESTS=OFF -DFLATBUFFERS_BUILD_FLATLIB=OFF -DFLATBUFFERS_BUILD_FLATHASH=OFF .
|
||||
make -j
|
||||
echo "${PWD}" >> $GITHUB_PATH
|
||||
- name: Build
|
||||
working-directory: kotlin
|
||||
# we are using docker's version of gradle
|
||||
# so no need for wrapper validation or user
|
||||
# gradlew
|
||||
run: gradle jvmMainClasses jvmTest jsTest jsBrowserTest
|
||||
|
||||
build-rust-linux:
|
||||
name: Build Rust Linux
|
||||
runs-on: ubuntu-22.04-64core
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: test
|
||||
working-directory: tests
|
||||
run: bash RustTest.sh
|
||||
|
||||
build-rust-windows:
|
||||
name: Build Rust Windows
|
||||
runs-on: windows-2022-64core
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: test
|
||||
working-directory: tests
|
||||
run: ./RustTest.bat
|
||||
|
||||
build-python:
|
||||
name: Build Python
|
||||
runs-on: ubuntu-22.04-64core
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: flatc
|
||||
# FIXME: make test script not rely on flatc
|
||||
run: cmake -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Release -DFLATBUFFERS_BUILD_TESTS=OFF -DFLATBUFFERS_INSTALL=OFF -DFLATBUFFERS_BUILD_FLATLIB=OFF -DFLATBUFFERS_BUILD_FLATHASH=OFF -DFLATBUFFERS_STRICT_MODE=ON . && make -j
|
||||
- name: test
|
||||
working-directory: tests
|
||||
run: bash PythonTest.sh
|
||||
|
||||
build-go:
|
||||
name: Build Go
|
||||
runs-on: ubuntu-22.04-64core
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: flatc
|
||||
# FIXME: make test script not rely on flatc
|
||||
run: cmake -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Release -DFLATBUFFERS_BUILD_TESTS=OFF -DFLATBUFFERS_INSTALL=OFF -DFLATBUFFERS_BUILD_FLATLIB=OFF -DFLATBUFFERS_BUILD_FLATHASH=OFF -DFLATBUFFERS_STRICT_MODE=ON . && make -j
|
||||
- name: test
|
||||
working-directory: tests
|
||||
run: bash GoTest.sh
|
||||
|
||||
build-php:
|
||||
name: Build PHP
|
||||
runs-on: ubuntu-22.04-64core
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: flatc
|
||||
# FIXME: make test script not rely on flatc
|
||||
run: cmake -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Release -DFLATBUFFERS_BUILD_TESTS=OFF -DFLATBUFFERS_INSTALL=OFF -DFLATBUFFERS_BUILD_FLATLIB=OFF -DFLATBUFFERS_BUILD_FLATHASH=OFF -DFLATBUFFERS_STRICT_MODE=ON . && make -j
|
||||
- name: test
|
||||
working-directory: tests
|
||||
run: |
|
||||
php phpTest.php
|
||||
sh phpUnionVectorTest.sh
|
||||
|
||||
build-swift:
|
||||
name: Build Swift
|
||||
runs-on: ubuntu-22.04-64core
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: test
|
||||
working-directory: tests/swift/tests
|
||||
run: |
|
||||
swift build --build-tests
|
||||
swift test
|
||||
|
||||
build-swift-wasm:
|
||||
name: Build Swift Wasm
|
||||
runs-on: ubuntu-22.04-64core
|
||||
container:
|
||||
image: ghcr.io/swiftwasm/carton:0.15.3
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Setup Wasmer
|
||||
uses: wasmerio/setup-wasmer@v2
|
||||
- name: Test
|
||||
working-directory: tests/swift/Wasm.tests
|
||||
run: carton test
|
||||
|
||||
build-ts:
|
||||
name: Build TS
|
||||
runs-on: ubuntu-22.04-64core
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: flatc
|
||||
# FIXME: make test script not rely on flatc
|
||||
run: cmake -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Release -DFLATBUFFERS_BUILD_TESTS=OFF -DFLATBUFFERS_INSTALL=OFF -DFLATBUFFERS_BUILD_FLATLIB=OFF -DFLATBUFFERS_BUILD_FLATHASH=OFF . && make -j
|
||||
- name: deps
|
||||
run: yarn
|
||||
- name: compile
|
||||
run: yarn compile
|
||||
- name: test
|
||||
working-directory: tests/ts
|
||||
run: |
|
||||
yarn global add esbuild
|
||||
python3 TypeScriptTest.py
|
||||
|
||||
build-dart:
|
||||
name: Build Dart
|
||||
runs-on: ubuntu-22.04-64core
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: dart-lang/setup-dart@v1
|
||||
with:
|
||||
sdk: stable
|
||||
- name: flatc
|
||||
# FIXME: make test script not rely on flatc
|
||||
run: cmake -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Release -DFLATBUFFERS_BUILD_TESTS=OFF -DFLATBUFFERS_INSTALL=OFF -DFLATBUFFERS_BUILD_FLATLIB=OFF -DFLATBUFFERS_BUILD_FLATHASH=OFF -DFLATBUFFERS_STRICT_MODE=ON . && make -j
|
||||
- name: test
|
||||
working-directory: tests
|
||||
run: bash DartTest.sh
|
||||
|
||||
build-nim:
|
||||
name: Build Nim
|
||||
runs-on: ubuntu-22.04-64core
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: flatc
|
||||
# FIXME: make test script not rely on flatc
|
||||
run: cmake -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Release -DFLATBUFFERS_BUILD_TESTS=OFF -DFLATBUFFERS_INSTALL=OFF -DFLATBUFFERS_BUILD_FLATLIB=OFF -DFLATBUFFERS_BUILD_FLATHASH=OFF . && make -j
|
||||
- uses: jiro4989/setup-nim-action@v1
|
||||
- name: install library
|
||||
working-directory: nim
|
||||
run: nimble -y develop && nimble install
|
||||
- name: test
|
||||
working-directory: tests/nim
|
||||
run: python3 testnim.py
|
||||
|
||||
release-digests:
|
||||
if: startsWith(github.ref, 'refs/tags/')
|
||||
needs: [build-linux, build-windows, build-mac-intel, build-mac-universal]
|
||||
outputs:
|
||||
digests: ${{ steps.hash.outputs.digests }}
|
||||
runs-on: ubuntu-22.04-64core
|
||||
steps:
|
||||
- name: Merge results
|
||||
id: hash
|
||||
env:
|
||||
LINUXGCC_DIGESTS: "${{ needs.build-linux.outputs.digests-gcc }}"
|
||||
LINUXCLANG_DIGESTS: "${{ needs.build-linux.outputs.digests-clang }}"
|
||||
MAC_DIGESTS: "${{ needs.build-mac-universal.outputs.digests }}"
|
||||
MACINTEL_DIGESTS: "${{ needs.build-mac-intel.outputs.digests }}"
|
||||
WINDOWS_DIGESTS: "${{ needs.build-windows.outputs.digests }}"
|
||||
run: |
|
||||
set -euo pipefail
|
||||
echo "$LINUXGCC_DIGESTS" | base64 -d > checksums.txt
|
||||
echo "$LINUXCLANG_DIGESTS" | base64 -d >> checksums.txt
|
||||
echo "$MAC_DIGESTS" | base64 -d >> checksums.txt
|
||||
echo "$MACINTEL_DIGESTS" | base64 -d >> checksums.txt
|
||||
echo "$WINDOWS_DIGESTS" | base64 -d >> checksums.txt
|
||||
echo "digests=$(cat checksums.txt | base64 -w0)" >> $GITHUB_OUTPUT
|
||||
|
||||
provenance:
|
||||
if: startsWith(github.ref, 'refs/tags/')
|
||||
needs: [release-digests]
|
||||
permissions:
|
||||
actions: read # To read the workflow path.
|
||||
id-token: write # To sign the provenance.
|
||||
contents: write # To add assets to a release.
|
||||
uses: slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@v1.2.1
|
||||
with:
|
||||
base64-subjects: "${{ needs.release-digests.outputs.digests }}"
|
||||
upload-assets: true # Optional: Upload to a new release
|
||||
compile-generator: true # Workaround for https://github.com/slsa-framework/slsa-github-generator/issues/1163
|
@ -1,71 +0,0 @@
|
||||
# For most projects, this workflow file will not need changing; you simply need
|
||||
# to commit it to your repository.
|
||||
#
|
||||
# You may wish to alter this file to override the set of languages analyzed,
|
||||
# or to provide custom queries or build logic.
|
||||
#
|
||||
# ******** NOTE ********
|
||||
# We have attempted to detect the languages in your repository. Please check
|
||||
# the `language` matrix defined below to confirm you have the correct set of
|
||||
# supported CodeQL languages.
|
||||
#
|
||||
name: "CodeQL"
|
||||
permissions: read-all
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ master ]
|
||||
pull_request:
|
||||
# The branches below must be a subset of the branches above
|
||||
branches: [ master ]
|
||||
schedule:
|
||||
- cron: '16 20 * * 0'
|
||||
|
||||
jobs:
|
||||
analyze:
|
||||
name: Analyze
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
actions: read
|
||||
contents: read
|
||||
security-events: write
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
language: [ 'cpp' ]
|
||||
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
|
||||
# Learn more about CodeQL language support at https://git.io/codeql-language-support
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v2
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||
# By default, queries listed here will override any specified in a config file.
|
||||
# Prefix the list here with "+" to use these queries and those in the config file.
|
||||
# queries: ./path/to/local/query, your-org/your-repo/queries@main
|
||||
|
||||
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
||||
# If this step fails, then you should remove it and run the build manually (see below)
|
||||
# - name: Autobuild
|
||||
# uses: github/codeql-action/autobuild@v2
|
||||
|
||||
# ℹ️ Command-line programs to run using the OS shell.
|
||||
# 📚 https://git.io/JvXDl
|
||||
|
||||
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
|
||||
# and modify them (or add more) to build your code if your project
|
||||
# uses a compiled language
|
||||
|
||||
- run: |
|
||||
cmake -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Release -DFLATBUFFERS_STRICT_MODE=ON .
|
||||
make -j
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v2
|
@ -1,35 +0,0 @@
|
||||
name: Build and unit tests that are more time consuming
|
||||
permissions: read-all
|
||||
|
||||
on:
|
||||
# For manual tests.
|
||||
workflow_dispatch:
|
||||
pull_request:
|
||||
types:
|
||||
- closed
|
||||
schedule:
|
||||
- cron: "30 20 * * *"
|
||||
|
||||
jobs:
|
||||
build-linux-s390x:
|
||||
name: Build Linux on s390x arch and run unit tests
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: uraimo/run-on-arch-action@v2
|
||||
name: Run commands
|
||||
id: runcmd
|
||||
with:
|
||||
arch: s390x
|
||||
distro: ubuntu_latest
|
||||
install: |
|
||||
apt-get update -q -y
|
||||
apt-get -y install cmake
|
||||
apt-get -y install make
|
||||
apt-get -y install g++
|
||||
run: |
|
||||
lscpu | grep Endian
|
||||
cmake -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Release
|
||||
make -j
|
||||
./flattests
|
||||
|
@ -1,24 +0,0 @@
|
||||
# This workflow will triage pull requests and apply a label based on the
|
||||
# paths that are modified in the pull request.
|
||||
#
|
||||
# To use this workflow, you will need to set up a .github/labeler.yml
|
||||
# file with configuration. For more information, see:
|
||||
# https://github.com/actions/labeler
|
||||
|
||||
name: Labeler
|
||||
permissions: read-all
|
||||
|
||||
on: [pull_request_target]
|
||||
|
||||
jobs:
|
||||
label:
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: write
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/labeler@ee18d5d34efd9b4f7dafdb0e363cb688eb438044 # 4.1.0
|
||||
with:
|
||||
repo-token: "${{ secrets.GITHUB_TOKEN }}"
|
@ -1,34 +0,0 @@
|
||||
name: OSS-Fuzz
|
||||
permissions: read-all
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
paths:
|
||||
- include/**
|
||||
- src/**
|
||||
- tests/**.cpp
|
||||
- tests/**.h
|
||||
jobs:
|
||||
Fuzzing:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Build Fuzzers
|
||||
id: build
|
||||
uses: google/oss-fuzz/infra/cifuzz/actions/build_fuzzers@master
|
||||
with:
|
||||
oss-fuzz-project-name: 'flatbuffers'
|
||||
language: c++
|
||||
- name: Run Fuzzers
|
||||
uses: google/oss-fuzz/infra/cifuzz/actions/run_fuzzers@master
|
||||
with:
|
||||
oss-fuzz-project-name: 'flatbuffers'
|
||||
language: c++
|
||||
fuzz-seconds: 60
|
||||
- name: Upload Crash
|
||||
uses: actions/upload-artifact@v1
|
||||
if: failure() && steps.build.outcome == 'success'
|
||||
with:
|
||||
name: artifacts
|
||||
path: ./out/artifacts
|
@ -1,105 +0,0 @@
|
||||
name: Release
|
||||
permissions: read-all
|
||||
|
||||
on:
|
||||
# For manual tests.
|
||||
workflow_dispatch:
|
||||
release:
|
||||
types: [created]
|
||||
|
||||
jobs:
|
||||
publish-npm:
|
||||
name: Publish NPM
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: '20.x'
|
||||
registry-url: 'https://registry.npmjs.org'
|
||||
|
||||
- run: npm publish
|
||||
env:
|
||||
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||
|
||||
publish-pypi:
|
||||
name: Publish PyPi
|
||||
runs-on: ubuntu-latest
|
||||
defaults:
|
||||
run:
|
||||
working-directory: ./python
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: '3.10'
|
||||
|
||||
- name: Install Dependencies
|
||||
run: |
|
||||
python3 -m pip install --upgrade pip
|
||||
python3 -m pip install setuptools wheel twine
|
||||
|
||||
- name: Build
|
||||
run: |
|
||||
python3 setup.py sdist bdist_wheel
|
||||
|
||||
- name: Upload to PyPi
|
||||
run: |
|
||||
python3 -m twine upload dist/*
|
||||
env:
|
||||
TWINE_USERNAME: __token__
|
||||
TWINE_PASSWORD: ${{ secrets.TWINE_TOKEN }}
|
||||
|
||||
publish-nuget:
|
||||
name: Publish NuGet
|
||||
runs-on: windows-latest
|
||||
defaults:
|
||||
run:
|
||||
working-directory: ./net/flatbuffers
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-dotnet@v3
|
||||
with:
|
||||
dotnet-version: '8.0.x'
|
||||
- name: Build
|
||||
run: |
|
||||
dotnet build Google.FlatBuffers.csproj -c Release
|
||||
|
||||
- name: Pack
|
||||
run: |
|
||||
dotnet pack Google.FlatBuffers.csproj -c Release
|
||||
|
||||
- name: Upload to NuGet
|
||||
run: |
|
||||
dotnet nuget push .\bin\Release\Google.FlatBuffers.*.nupkg -k ${{ secrets.NUGET_API_KEY }} -s https://api.nuget.org/v3/index.json
|
||||
|
||||
publish-maven:
|
||||
name: Publish Maven
|
||||
runs-on: ubuntu-latest
|
||||
defaults:
|
||||
run:
|
||||
working-directory: ./java
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Set up Maven Central Repository
|
||||
uses: actions/setup-java@v3
|
||||
with:
|
||||
java-version: '11'
|
||||
distribution: 'adopt'
|
||||
cache: 'maven'
|
||||
server-id: ossrh
|
||||
server-username: OSSRH_USERNAME
|
||||
server-password: OSSRH_PASSWORD
|
||||
gpg-private-key: ${{ secrets.MAVEN_GPG_PRIVATE_KEY }}
|
||||
gpg-passphrase: MAVEN_GPG_PASSPHRASE # this needs to be an env var
|
||||
|
||||
- name: Publish Maven
|
||||
run: mvn --batch-mode clean deploy
|
||||
env:
|
||||
OSSRH_USERNAME: ${{ secrets.OSSRH_USERNAME }}
|
||||
OSSRH_PASSWORD: ${{ secrets.OSSRH_TOKEN }}
|
||||
MAVEN_GPG_PASSPHRASE: ${{ secrets.MAVEN_GPG_PASSPHRASE }}
|
||||
|
||||
|
||||
|
@ -1,55 +0,0 @@
|
||||
name: Scorecards supply-chain security
|
||||
on:
|
||||
# Only the default branch is supported.
|
||||
branch_protection_rule:
|
||||
schedule:
|
||||
- cron: '21 2 * * 5'
|
||||
push:
|
||||
branches: [ master ]
|
||||
|
||||
# Declare default permissions as read only.
|
||||
permissions: read-all
|
||||
|
||||
jobs:
|
||||
analysis:
|
||||
name: Scorecards analysis
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
# Needed to upload the results to code-scanning dashboard.
|
||||
security-events: write
|
||||
actions: read
|
||||
contents: read
|
||||
|
||||
steps:
|
||||
- name: "Checkout code"
|
||||
uses: actions/checkout@a12a3943b4bdde767164f792f33f40b04645d846 # v3.0.0
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: "Run analysis"
|
||||
uses: ossf/scorecard-action@ce330fde6b1a5c9c75b417e7efc510b822a35564 # v1.1.2
|
||||
with:
|
||||
results_file: results.sarif
|
||||
results_format: sarif
|
||||
# Read-only PAT token. To create it,
|
||||
# follow the steps in https://github.com/ossf/scorecard-action#pat-token-creation.
|
||||
repo_token: ${{ secrets.SCORECARD_READ_TOKEN }}
|
||||
# Publish the results to enable scorecard badges. For more details, see
|
||||
# https://github.com/ossf/scorecard-action#publishing-results.
|
||||
# For private repositories, `publish_results` will automatically be set to `false`,
|
||||
# regardless of the value entered here.
|
||||
publish_results: true
|
||||
|
||||
# Upload the results as artifacts (optional).
|
||||
- name: "Upload artifact"
|
||||
uses: actions/upload-artifact@6673cd052c4cd6fcf4b4e6e60ea986c889389535 # v3.0.0
|
||||
with:
|
||||
name: SARIF file
|
||||
path: results.sarif
|
||||
retention-days: 5
|
||||
|
||||
# Upload the results to GitHub's code scanning dashboard.
|
||||
- name: "Upload to code-scanning"
|
||||
uses: github/codeql-action/upload-sarif@5f532563584d71fdef14ee64d17bafb34f751ce5 # v1.0.26
|
||||
with:
|
||||
sarif_file: results.sarif
|
@ -1,37 +0,0 @@
|
||||
name: Mark stale issues and pull requests
|
||||
permissions:
|
||||
issues: write
|
||||
pull-requests: write
|
||||
|
||||
on:
|
||||
# For manual tests.
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
- cron: "30 20 * * *"
|
||||
|
||||
jobs:
|
||||
stale:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/stale@v7.0.0
|
||||
with:
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
operations-per-run: 500
|
||||
exempt-all-milestones: true
|
||||
remove-stale-when-updated: true
|
||||
|
||||
stale-issue-message: 'This issue is stale because it has been open 6 months with no activity. Please comment or label `not-stale`, or this will be closed in 14 days.'
|
||||
close-issue-message: 'This issue was automatically closed due to no activity for 6 months plus the 14 day notice period.'
|
||||
days-before-issue-stale: 182 # 6 months
|
||||
days-before-issue-close: 14 # 2 weeks
|
||||
exempt-issue-labels: not-stale
|
||||
|
||||
stale-pr-message: 'This pull request is stale because it has been open 6 months with no activity. Please comment or label `not-stale`, or this will be closed in 14 days.'
|
||||
close-pr-message: 'This pull request was automatically closed due to no activity for 6 months plus the 14 day notice period.'
|
||||
days-before-pr-stale: 182 # 6 months
|
||||
days-before-pr-close: 14 # 2 week
|
||||
exempt-pr-labels: not-stale
|
||||
exempt-draft-pr: false
|
||||
|
46
third_party/flatbuffers/dart/CHANGELOG.md
vendored
46
third_party/flatbuffers/dart/CHANGELOG.md
vendored
@ -1,46 +0,0 @@
|
||||
# Changelog
|
||||
|
||||
## 23.5.26
|
||||
|
||||
- omit type annotationes for local variables (#7067, #7069, #7070)
|
||||
- remove BSD 3-clause license (#7073)
|
||||
- correctly parse lists of enums (#7157)
|
||||
- align naming conventions for generated code (#7187)
|
||||
- add `putBool` to fix errors when serializing structs with booleans (#7359)
|
||||
- fix handling of +/-inf defaults in codegen (#7588)
|
||||
- fix import issues in generated code (#7621)
|
||||
- Fix incorrect storage of floats as ints in some cases (#7703)
|
||||
- add final modifiers to the library implementation (#7943)
|
||||
|
||||
## 2.0.5
|
||||
|
||||
- switch to null safety (#6696)
|
||||
- add Object APIs (pack/unpack) (#6682, #6723, #6846)
|
||||
- add custom builder buffer allocator support (#6711)
|
||||
- add `Builder.size()` - finished buffer size (#6403)
|
||||
- make `writeString()` argument non-nullable (#6737)
|
||||
- make tables fixed size (expect the number of fields when creating) (#6735)
|
||||
- make table deduplication optional (param `deduplicateTables`) (#6734)
|
||||
- change `Builder.reset()` to reuse an existing buffer (#6661)
|
||||
- change table building to assert() instead of exceptions (#6754)
|
||||
- optimize `writeString()` for ASCII (param `asciiOptimization`) (#6736)
|
||||
- change `StringReader` to make ASCII optimization optional (param `asciiOptimization`) (#6758)
|
||||
- change `[byte]` and `[ubyte]` representation to `dart:typed_data` `Int8List` and `Uint8List` (#6839)
|
||||
- rename `lowFinish()` to `buffer` getter (#6712)
|
||||
- fix `Builder._writeString()` - always write trailing zero byte (#6390)
|
||||
- fix `Builder.reset()` - clear vTables (#6386)
|
||||
- make sure added padding is zeroed, same as in C++ (#6716)
|
||||
- many performance improvements (#6755)
|
||||
|
||||
## 1.9.2
|
||||
|
||||
- Ensure `_writeString` adds enough padding to null terminate strings.
|
||||
|
||||
## 1.9.1
|
||||
|
||||
- Changed constant identifiers to be compatible with Dart 2.x
|
||||
- No longer supports Dart 1.x
|
||||
|
||||
## 1.9.0
|
||||
|
||||
- Initial release, supports Dart 1.x and many dev versions of Dart 2.x
|
201
third_party/flatbuffers/dart/LICENSE
vendored
201
third_party/flatbuffers/dart/LICENSE
vendored
@ -1,201 +0,0 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright 2014 Google Inc.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
15
third_party/flatbuffers/dart/README.md
vendored
15
third_party/flatbuffers/dart/README.md
vendored
@ -1,15 +0,0 @@
|
||||
# FlatBuffers for Dart
|
||||
|
||||
This package is used to read and write [FlatBuffers](https://google.github.io/flatbuffers/).
|
||||
|
||||
Most consumers will want to use the [`flatc` - FlatBuffer compiler](https://github.com/google/flatbuffers) binary for your platform.
|
||||
You can download the flatc version matching your dart package version from [GitHub releases](https://github.com/google/flatbuffers/releases).
|
||||
|
||||
The FlatBuffer compiler `flatc` reads a FlatBuffers IDL schema and generates Dart code.
|
||||
The generated classes can be used to read or write binary data/files that are interoperable with
|
||||
other languages and platforms supported by FlatBuffers, as illustrated in the `example.dart` in the
|
||||
examples folder.
|
||||
|
||||
For more details and documentation, head over to the official site and read the
|
||||
[Tutorial](https://google.github.io/flatbuffers/flatbuffers_guide_tutorial.html) and how to
|
||||
[use FlatBuffers in Dart](https://google.github.io/flatbuffers/flatbuffers_guide_use_dart.html).
|
@ -1 +0,0 @@
|
||||
include: package:lints/recommended.yaml
|
153
third_party/flatbuffers/dart/example/example.dart
vendored
153
third_party/flatbuffers/dart/example/example.dart
vendored
@ -1,153 +0,0 @@
|
||||
/*
|
||||
* Copyright 2018 Dan Field. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import 'package:flat_buffers/flat_buffers.dart' as fb;
|
||||
import './monster_my_game.sample_generated.dart' as my_game;
|
||||
|
||||
// Example how to use FlatBuffers to create and read binary buffers.
|
||||
|
||||
void main() {
|
||||
builderTest();
|
||||
objectBuilderTest();
|
||||
}
|
||||
|
||||
void builderTest() {
|
||||
final builder = fb.Builder(initialSize: 1024);
|
||||
final int? weaponOneName = builder.writeString("Sword");
|
||||
final int weaponOneDamage = 3;
|
||||
|
||||
final int? weaponTwoName = builder.writeString("Axe");
|
||||
final int weaponTwoDamage = 5;
|
||||
|
||||
final swordBuilder = my_game.WeaponBuilder(builder)
|
||||
..begin()
|
||||
..addNameOffset(weaponOneName)
|
||||
..addDamage(weaponOneDamage);
|
||||
final int sword = swordBuilder.finish();
|
||||
|
||||
final axeBuilder = my_game.WeaponBuilder(builder)
|
||||
..begin()
|
||||
..addNameOffset(weaponTwoName)
|
||||
..addDamage(weaponTwoDamage);
|
||||
final int axe = axeBuilder.finish();
|
||||
|
||||
// Serialize a name for our monster, called "Orc".
|
||||
final int? name = builder.writeString('Orc');
|
||||
|
||||
// Create a list representing the inventory of the Orc. Each number
|
||||
// could correspond to an item that can be claimed after he is slain.
|
||||
final List<int> treasure = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
|
||||
final inventory = builder.writeListUint8(treasure);
|
||||
final weapons = builder.writeList([sword, axe]);
|
||||
|
||||
// Struct builders are very easy to reuse.
|
||||
final vec3Builder = my_game.Vec3Builder(builder);
|
||||
|
||||
vec3Builder.finish(4.0, 5.0, 6.0);
|
||||
vec3Builder.finish(1.0, 2.0, 3.0);
|
||||
// Set his hit points to 300 and his mana to 150.
|
||||
final int hp = 300;
|
||||
final int mana = 150;
|
||||
|
||||
final monster = my_game.MonsterBuilder(builder)
|
||||
..begin()
|
||||
..addNameOffset(name)
|
||||
..addInventoryOffset(inventory)
|
||||
..addWeaponsOffset(weapons)
|
||||
..addEquippedType(my_game.EquipmentTypeId.Weapon)
|
||||
..addEquippedOffset(axe)
|
||||
..addHp(hp)
|
||||
..addMana(mana)
|
||||
..addPos(vec3Builder.finish(1.0, 2.0, 3.0))
|
||||
..addColor(my_game.Color.Red);
|
||||
|
||||
final int monsteroff = monster.finish();
|
||||
builder.finish(monsteroff);
|
||||
if (verify(builder.buffer)) {
|
||||
print(
|
||||
"The FlatBuffer was successfully created with a builder and verified!");
|
||||
}
|
||||
}
|
||||
|
||||
void objectBuilderTest() {
|
||||
// Create the builder here so we can use it for both weapons and equipped
|
||||
// the actual data will only be written to the buffer once.
|
||||
var axe = my_game.WeaponObjectBuilder(name: 'Axe', damage: 5);
|
||||
|
||||
var monsterBuilder = my_game.MonsterObjectBuilder(
|
||||
pos: my_game.Vec3ObjectBuilder(x: 1.0, y: 2.0, z: 3.0),
|
||||
mana: 150,
|
||||
hp: 300,
|
||||
name: 'Orc',
|
||||
inventory: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
|
||||
color: my_game.Color.Red,
|
||||
weapons: [my_game.WeaponObjectBuilder(name: 'Sword', damage: 3), axe],
|
||||
equippedType: my_game.EquipmentTypeId.Weapon,
|
||||
equipped: axe,
|
||||
);
|
||||
|
||||
var buffer = monsterBuilder.toBytes();
|
||||
|
||||
// We now have a FlatBuffer we can store on disk or send over a network.
|
||||
|
||||
// ** file/network code goes here :) **
|
||||
|
||||
// Instead, we're going to access it right away (as if we just received it).
|
||||
if (verify(buffer)) {
|
||||
print(
|
||||
"The FlatBuffer was successfully created with an object builder and verified!");
|
||||
}
|
||||
}
|
||||
|
||||
bool verify(List<int> buffer) {
|
||||
// Get access to the root:
|
||||
var monster = my_game.Monster(buffer);
|
||||
|
||||
// Get and test some scalar types from the FlatBuffer.
|
||||
assert(monster.hp == 80);
|
||||
assert(monster.mana == 150); // default
|
||||
assert(monster.name == "MyMonster");
|
||||
|
||||
// Get and test a field of the FlatBuffer's `struct`.
|
||||
var pos = monster.pos!;
|
||||
assert(pos.z == 3.0);
|
||||
|
||||
// Get a test an element from the `inventory` FlatBuffer's `vector`.
|
||||
var inv = monster.inventory!;
|
||||
assert(inv.length == 10);
|
||||
assert(inv[9] == 9);
|
||||
|
||||
// Get and test the `weapons` FlatBuffers's `vector`.
|
||||
var expectedWeaponNames = ["Sword", "Axe"];
|
||||
var expectedWeaponDamages = [3, 5];
|
||||
var weps = monster.weapons!;
|
||||
for (int i = 0; i < weps.length; i++) {
|
||||
assert(weps[i].name == expectedWeaponNames[i]);
|
||||
assert(weps[i].damage == expectedWeaponDamages[i]);
|
||||
}
|
||||
|
||||
// Get and test the `Equipment` union (`equipped` field).
|
||||
assert(monster.equippedType!.value == my_game.EquipmentTypeId.Weapon.value);
|
||||
assert(monster.equippedType == my_game.EquipmentTypeId.Weapon);
|
||||
|
||||
assert(monster.equipped is my_game.Weapon);
|
||||
var equipped = monster.equipped as my_game.Weapon;
|
||||
assert(equipped.name == "Axe");
|
||||
assert(equipped.damage == 5);
|
||||
|
||||
print(monster);
|
||||
return true;
|
||||
}
|
@ -1,423 +0,0 @@
|
||||
// automatically generated by the FlatBuffers compiler, do not modify
|
||||
// ignore_for_file: unused_import, unused_field, unused_element, unused_local_variable
|
||||
|
||||
library my_game.sample;
|
||||
|
||||
import 'dart:typed_data' show Uint8List;
|
||||
import 'package:flat_buffers/flat_buffers.dart' as fb;
|
||||
|
||||
|
||||
class Color {
|
||||
final int value;
|
||||
const Color._(this.value);
|
||||
|
||||
factory Color.fromValue(int value) {
|
||||
final result = values[value];
|
||||
if (result == null) {
|
||||
throw StateError('Invalid value $value for bit flag enum Color');
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static Color? _createOrNull(int? value) =>
|
||||
value == null ? null : Color.fromValue(value);
|
||||
|
||||
static const int minValue = 0;
|
||||
static const int maxValue = 2;
|
||||
static bool containsValue(int value) => values.containsKey(value);
|
||||
|
||||
static const Color Red = Color._(0);
|
||||
static const Color Green = Color._(1);
|
||||
static const Color Blue = Color._(2);
|
||||
static const Map<int, Color> values = {
|
||||
0: Red,
|
||||
1: Green,
|
||||
2: Blue};
|
||||
|
||||
static const fb.Reader<Color> reader = _ColorReader();
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'Color{value: $value}';
|
||||
}
|
||||
}
|
||||
|
||||
class _ColorReader extends fb.Reader<Color> {
|
||||
const _ColorReader();
|
||||
|
||||
@override
|
||||
int get size => 1;
|
||||
|
||||
@override
|
||||
Color read(fb.BufferContext bc, int offset) =>
|
||||
Color.fromValue(const fb.Int8Reader().read(bc, offset));
|
||||
}
|
||||
|
||||
class EquipmentTypeId {
|
||||
final int value;
|
||||
const EquipmentTypeId._(this.value);
|
||||
|
||||
factory EquipmentTypeId.fromValue(int value) {
|
||||
final result = values[value];
|
||||
if (result == null) {
|
||||
throw StateError('Invalid value $value for bit flag enum EquipmentTypeId');
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static EquipmentTypeId? _createOrNull(int? value) =>
|
||||
value == null ? null : EquipmentTypeId.fromValue(value);
|
||||
|
||||
static const int minValue = 0;
|
||||
static const int maxValue = 1;
|
||||
static bool containsValue(int value) => values.containsKey(value);
|
||||
|
||||
static const EquipmentTypeId NONE = EquipmentTypeId._(0);
|
||||
static const EquipmentTypeId Weapon = EquipmentTypeId._(1);
|
||||
static const Map<int, EquipmentTypeId> values = {
|
||||
0: NONE,
|
||||
1: Weapon};
|
||||
|
||||
static const fb.Reader<EquipmentTypeId> reader = _EquipmentTypeIdReader();
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'EquipmentTypeId{value: $value}';
|
||||
}
|
||||
}
|
||||
|
||||
class _EquipmentTypeIdReader extends fb.Reader<EquipmentTypeId> {
|
||||
const _EquipmentTypeIdReader();
|
||||
|
||||
@override
|
||||
int get size => 1;
|
||||
|
||||
@override
|
||||
EquipmentTypeId read(fb.BufferContext bc, int offset) =>
|
||||
EquipmentTypeId.fromValue(const fb.Uint8Reader().read(bc, offset));
|
||||
}
|
||||
|
||||
class Vec3 {
|
||||
Vec3._(this._bc, this._bcOffset);
|
||||
|
||||
static const fb.Reader<Vec3> reader = _Vec3Reader();
|
||||
|
||||
final fb.BufferContext _bc;
|
||||
final int _bcOffset;
|
||||
|
||||
double get x => const fb.Float32Reader().read(_bc, _bcOffset + 0);
|
||||
double get y => const fb.Float32Reader().read(_bc, _bcOffset + 4);
|
||||
double get z => const fb.Float32Reader().read(_bc, _bcOffset + 8);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'Vec3{x: $x, y: $y, z: $z}';
|
||||
}
|
||||
}
|
||||
|
||||
class _Vec3Reader extends fb.StructReader<Vec3> {
|
||||
const _Vec3Reader();
|
||||
|
||||
@override
|
||||
int get size => 12;
|
||||
|
||||
@override
|
||||
Vec3 createObject(fb.BufferContext bc, int offset) =>
|
||||
Vec3._(bc, offset);
|
||||
}
|
||||
|
||||
class Vec3Builder {
|
||||
Vec3Builder(this.fbBuilder);
|
||||
|
||||
final fb.Builder fbBuilder;
|
||||
|
||||
int finish(double x, double y, double z) {
|
||||
fbBuilder.putFloat32(z);
|
||||
fbBuilder.putFloat32(y);
|
||||
fbBuilder.putFloat32(x);
|
||||
return fbBuilder.offset;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class Vec3ObjectBuilder extends fb.ObjectBuilder {
|
||||
final double _x;
|
||||
final double _y;
|
||||
final double _z;
|
||||
|
||||
Vec3ObjectBuilder({
|
||||
required double x,
|
||||
required double y,
|
||||
required double z,
|
||||
})
|
||||
: _x = x,
|
||||
_y = y,
|
||||
_z = z;
|
||||
|
||||
/// Finish building, and store into the [fbBuilder].
|
||||
@override
|
||||
int finish(fb.Builder fbBuilder) {
|
||||
fbBuilder.putFloat32(_z);
|
||||
fbBuilder.putFloat32(_y);
|
||||
fbBuilder.putFloat32(_x);
|
||||
return fbBuilder.offset;
|
||||
}
|
||||
|
||||
/// Convenience method to serialize to byte list.
|
||||
@override
|
||||
Uint8List toBytes([String? fileIdentifier]) {
|
||||
final fbBuilder = fb.Builder(deduplicateTables: false);
|
||||
fbBuilder.finish(finish(fbBuilder), fileIdentifier);
|
||||
return fbBuilder.buffer;
|
||||
}
|
||||
}
|
||||
class Monster {
|
||||
Monster._(this._bc, this._bcOffset);
|
||||
factory Monster(List<int> bytes) {
|
||||
final rootRef = fb.BufferContext.fromBytes(bytes);
|
||||
return reader.read(rootRef, 0);
|
||||
}
|
||||
|
||||
static const fb.Reader<Monster> reader = _MonsterReader();
|
||||
|
||||
final fb.BufferContext _bc;
|
||||
final int _bcOffset;
|
||||
|
||||
Vec3? get pos => Vec3.reader.vTableGetNullable(_bc, _bcOffset, 4);
|
||||
int get mana => const fb.Int16Reader().vTableGet(_bc, _bcOffset, 6, 150);
|
||||
int get hp => const fb.Int16Reader().vTableGet(_bc, _bcOffset, 8, 100);
|
||||
String? get name => const fb.StringReader().vTableGetNullable(_bc, _bcOffset, 10);
|
||||
List<int>? get inventory => const fb.Uint8ListReader().vTableGetNullable(_bc, _bcOffset, 14);
|
||||
Color get color => Color.fromValue(const fb.Int8Reader().vTableGet(_bc, _bcOffset, 16, 2));
|
||||
List<Weapon>? get weapons => const fb.ListReader<Weapon>(Weapon.reader).vTableGetNullable(_bc, _bcOffset, 18);
|
||||
EquipmentTypeId? get equippedType => EquipmentTypeId._createOrNull(const fb.Uint8Reader().vTableGetNullable(_bc, _bcOffset, 20));
|
||||
dynamic get equipped {
|
||||
switch (equippedType?.value) {
|
||||
case 1: return Weapon.reader.vTableGetNullable(_bc, _bcOffset, 22);
|
||||
default: return null;
|
||||
}
|
||||
}
|
||||
List<Vec3>? get path => const fb.ListReader<Vec3>(Vec3.reader).vTableGetNullable(_bc, _bcOffset, 24);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'Monster{pos: $pos, mana: $mana, hp: $hp, name: $name, inventory: $inventory, color: $color, weapons: $weapons, equippedType: $equippedType, equipped: $equipped, path: $path}';
|
||||
}
|
||||
}
|
||||
|
||||
class _MonsterReader extends fb.TableReader<Monster> {
|
||||
const _MonsterReader();
|
||||
|
||||
@override
|
||||
Monster createObject(fb.BufferContext bc, int offset) =>
|
||||
Monster._(bc, offset);
|
||||
}
|
||||
|
||||
class MonsterBuilder {
|
||||
MonsterBuilder(this.fbBuilder);
|
||||
|
||||
final fb.Builder fbBuilder;
|
||||
|
||||
void begin() {
|
||||
fbBuilder.startTable(10);
|
||||
}
|
||||
|
||||
int addPos(int offset) {
|
||||
fbBuilder.addStruct(0, offset);
|
||||
return fbBuilder.offset;
|
||||
}
|
||||
int addMana(int? mana) {
|
||||
fbBuilder.addInt16(1, mana);
|
||||
return fbBuilder.offset;
|
||||
}
|
||||
int addHp(int? hp) {
|
||||
fbBuilder.addInt16(2, hp);
|
||||
return fbBuilder.offset;
|
||||
}
|
||||
int addNameOffset(int? offset) {
|
||||
fbBuilder.addOffset(3, offset);
|
||||
return fbBuilder.offset;
|
||||
}
|
||||
int addInventoryOffset(int? offset) {
|
||||
fbBuilder.addOffset(5, offset);
|
||||
return fbBuilder.offset;
|
||||
}
|
||||
int addColor(Color? color) {
|
||||
fbBuilder.addInt8(6, color?.value);
|
||||
return fbBuilder.offset;
|
||||
}
|
||||
int addWeaponsOffset(int? offset) {
|
||||
fbBuilder.addOffset(7, offset);
|
||||
return fbBuilder.offset;
|
||||
}
|
||||
int addEquippedType(EquipmentTypeId? equippedType) {
|
||||
fbBuilder.addUint8(8, equippedType?.value);
|
||||
return fbBuilder.offset;
|
||||
}
|
||||
int addEquippedOffset(int? offset) {
|
||||
fbBuilder.addOffset(9, offset);
|
||||
return fbBuilder.offset;
|
||||
}
|
||||
int addPathOffset(int? offset) {
|
||||
fbBuilder.addOffset(10, offset);
|
||||
return fbBuilder.offset;
|
||||
}
|
||||
|
||||
int finish() {
|
||||
return fbBuilder.endTable();
|
||||
}
|
||||
}
|
||||
|
||||
class MonsterObjectBuilder extends fb.ObjectBuilder {
|
||||
final Vec3ObjectBuilder? _pos;
|
||||
final int? _mana;
|
||||
final int? _hp;
|
||||
final String? _name;
|
||||
final List<int>? _inventory;
|
||||
final Color? _color;
|
||||
final List<WeaponObjectBuilder>? _weapons;
|
||||
final EquipmentTypeId? _equippedType;
|
||||
final dynamic _equipped;
|
||||
final List<Vec3ObjectBuilder>? _path;
|
||||
|
||||
MonsterObjectBuilder({
|
||||
Vec3ObjectBuilder? pos,
|
||||
int? mana,
|
||||
int? hp,
|
||||
String? name,
|
||||
List<int>? inventory,
|
||||
Color? color,
|
||||
List<WeaponObjectBuilder>? weapons,
|
||||
EquipmentTypeId? equippedType,
|
||||
dynamic equipped,
|
||||
List<Vec3ObjectBuilder>? path,
|
||||
})
|
||||
: _pos = pos,
|
||||
_mana = mana,
|
||||
_hp = hp,
|
||||
_name = name,
|
||||
_inventory = inventory,
|
||||
_color = color,
|
||||
_weapons = weapons,
|
||||
_equippedType = equippedType,
|
||||
_equipped = equipped,
|
||||
_path = path;
|
||||
|
||||
/// Finish building, and store into the [fbBuilder].
|
||||
@override
|
||||
int finish(fb.Builder fbBuilder) {
|
||||
final int? nameOffset = _name == null ? null
|
||||
: fbBuilder.writeString(_name!);
|
||||
final int? inventoryOffset = _inventory == null ? null
|
||||
: fbBuilder.writeListUint8(_inventory!);
|
||||
final int? weaponsOffset = _weapons == null ? null
|
||||
: fbBuilder.writeList(_weapons!.map((b) => b.getOrCreateOffset(fbBuilder)).toList());
|
||||
final int? equippedOffset = _equipped?.getOrCreateOffset(fbBuilder);
|
||||
final int? pathOffset = _path == null ? null
|
||||
: fbBuilder.writeListOfStructs(_path!);
|
||||
fbBuilder.startTable(10);
|
||||
if (_pos != null) {
|
||||
fbBuilder.addStruct(0, _pos!.finish(fbBuilder));
|
||||
}
|
||||
fbBuilder.addInt16(1, _mana);
|
||||
fbBuilder.addInt16(2, _hp);
|
||||
fbBuilder.addOffset(3, nameOffset);
|
||||
fbBuilder.addOffset(5, inventoryOffset);
|
||||
fbBuilder.addInt8(6, _color?.value);
|
||||
fbBuilder.addOffset(7, weaponsOffset);
|
||||
fbBuilder.addUint8(8, _equippedType?.value);
|
||||
fbBuilder.addOffset(9, equippedOffset);
|
||||
fbBuilder.addOffset(10, pathOffset);
|
||||
return fbBuilder.endTable();
|
||||
}
|
||||
|
||||
/// Convenience method to serialize to byte list.
|
||||
@override
|
||||
Uint8List toBytes([String? fileIdentifier]) {
|
||||
final fbBuilder = fb.Builder(deduplicateTables: false);
|
||||
fbBuilder.finish(finish(fbBuilder), fileIdentifier);
|
||||
return fbBuilder.buffer;
|
||||
}
|
||||
}
|
||||
class Weapon {
|
||||
Weapon._(this._bc, this._bcOffset);
|
||||
factory Weapon(List<int> bytes) {
|
||||
final rootRef = fb.BufferContext.fromBytes(bytes);
|
||||
return reader.read(rootRef, 0);
|
||||
}
|
||||
|
||||
static const fb.Reader<Weapon> reader = _WeaponReader();
|
||||
|
||||
final fb.BufferContext _bc;
|
||||
final int _bcOffset;
|
||||
|
||||
String? get name => const fb.StringReader().vTableGetNullable(_bc, _bcOffset, 4);
|
||||
int get damage => const fb.Int16Reader().vTableGet(_bc, _bcOffset, 6, 0);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'Weapon{name: $name, damage: $damage}';
|
||||
}
|
||||
}
|
||||
|
||||
class _WeaponReader extends fb.TableReader<Weapon> {
|
||||
const _WeaponReader();
|
||||
|
||||
@override
|
||||
Weapon createObject(fb.BufferContext bc, int offset) =>
|
||||
Weapon._(bc, offset);
|
||||
}
|
||||
|
||||
class WeaponBuilder {
|
||||
WeaponBuilder(this.fbBuilder);
|
||||
|
||||
final fb.Builder fbBuilder;
|
||||
|
||||
void begin() {
|
||||
fbBuilder.startTable(2);
|
||||
}
|
||||
|
||||
int addNameOffset(int? offset) {
|
||||
fbBuilder.addOffset(0, offset);
|
||||
return fbBuilder.offset;
|
||||
}
|
||||
int addDamage(int? damage) {
|
||||
fbBuilder.addInt16(1, damage);
|
||||
return fbBuilder.offset;
|
||||
}
|
||||
|
||||
int finish() {
|
||||
return fbBuilder.endTable();
|
||||
}
|
||||
}
|
||||
|
||||
class WeaponObjectBuilder extends fb.ObjectBuilder {
|
||||
final String? _name;
|
||||
final int? _damage;
|
||||
|
||||
WeaponObjectBuilder({
|
||||
String? name,
|
||||
int? damage,
|
||||
})
|
||||
: _name = name,
|
||||
_damage = damage;
|
||||
|
||||
/// Finish building, and store into the [fbBuilder].
|
||||
@override
|
||||
int finish(fb.Builder fbBuilder) {
|
||||
final int? nameOffset = _name == null ? null
|
||||
: fbBuilder.writeString(_name!);
|
||||
fbBuilder.startTable(2);
|
||||
fbBuilder.addOffset(0, nameOffset);
|
||||
fbBuilder.addInt16(1, _damage);
|
||||
return fbBuilder.endTable();
|
||||
}
|
||||
|
||||
/// Convenience method to serialize to byte list.
|
||||
@override
|
||||
Uint8List toBytes([String? fileIdentifier]) {
|
||||
final fbBuilder = fb.Builder(deduplicateTables: false);
|
||||
fbBuilder.finish(finish(fbBuilder), fileIdentifier);
|
||||
return fbBuilder.buffer;
|
||||
}
|
||||
}
|
1493
third_party/flatbuffers/dart/lib/flat_buffers.dart
vendored
1493
third_party/flatbuffers/dart/lib/flat_buffers.dart
vendored
File diff suppressed because it is too large
Load Diff
@ -1,2 +0,0 @@
|
||||
export 'src/builder.dart';
|
||||
export 'src/reference.dart';
|
676
third_party/flatbuffers/dart/lib/src/builder.dart
vendored
676
third_party/flatbuffers/dart/lib/src/builder.dart
vendored
@ -1,676 +0,0 @@
|
||||
import 'dart:convert';
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'types.dart';
|
||||
|
||||
/// The main builder class for creation of a FlexBuffer.
|
||||
class Builder {
|
||||
final ByteData _buffer;
|
||||
List<_StackValue> _stack = [];
|
||||
List<_StackPointer> _stackPointers = [];
|
||||
int _offset = 0;
|
||||
bool _finished = false;
|
||||
final Map<String, _StackValue> _stringCache = {};
|
||||
final Map<String, _StackValue> _keyCache = {};
|
||||
final Map<_KeysHash, _StackValue> _keyVectorCache = {};
|
||||
final Map<int, _StackValue> _indirectIntCache = {};
|
||||
final Map<double, _StackValue> _indirectDoubleCache = {};
|
||||
|
||||
/// Instantiate the builder if you intent to gradually build up the buffer by calling
|
||||
/// add... methods and calling [finish] to receive the resulting byte array.
|
||||
///
|
||||
/// The default size of internal buffer is set to 2048. Provide a different value in order to avoid buffer copies.
|
||||
Builder({int size = 2048}) : _buffer = ByteData(size);
|
||||
|
||||
/// Use this method in order to turn an object into a FlexBuffer directly.
|
||||
///
|
||||
/// Use the manual instantiation of the [Builder] and gradual addition of values, if performance is more important than convenience.
|
||||
static ByteBuffer buildFromObject(Object? value) {
|
||||
final builder = Builder();
|
||||
builder._add(value);
|
||||
final buffer = builder.finish();
|
||||
final byteData = ByteData(buffer.lengthInBytes);
|
||||
byteData.buffer.asUint8List().setAll(0, buffer);
|
||||
return byteData.buffer;
|
||||
}
|
||||
|
||||
void _add(Object? value) {
|
||||
if (value == null) {
|
||||
addNull();
|
||||
} else if (value is bool) {
|
||||
addBool(value);
|
||||
} else if (value is int) {
|
||||
addInt(value);
|
||||
} else if (value is double) {
|
||||
addDouble(value);
|
||||
} else if (value is ByteBuffer) {
|
||||
addBlob(value);
|
||||
} else if (value is String) {
|
||||
addString(value);
|
||||
} else if (value is List<dynamic>) {
|
||||
startVector();
|
||||
for (var i = 0; i < value.length; i++) {
|
||||
_add(value[i]);
|
||||
}
|
||||
end();
|
||||
} else if (value is Map<String, dynamic>) {
|
||||
startMap();
|
||||
value.forEach((key, value) {
|
||||
addKey(key);
|
||||
_add(value);
|
||||
});
|
||||
end();
|
||||
} else {
|
||||
throw UnsupportedError('Value of unexpected type: $value');
|
||||
}
|
||||
}
|
||||
|
||||
/// Use this method if you want to store a null value.
|
||||
///
|
||||
/// Specifically useful when building up a vector where values can be null.
|
||||
void addNull() {
|
||||
_integrityCheckOnValueAddition();
|
||||
_stack.add(_StackValue.withNull());
|
||||
}
|
||||
|
||||
/// Adds a string value.
|
||||
void addInt(int value) {
|
||||
_integrityCheckOnValueAddition();
|
||||
_stack.add(_StackValue.withInt(value));
|
||||
}
|
||||
|
||||
/// Adds a bool value.
|
||||
void addBool(bool value) {
|
||||
_integrityCheckOnValueAddition();
|
||||
_stack.add(_StackValue.withBool(value));
|
||||
}
|
||||
|
||||
/// Adds a double value.
|
||||
void addDouble(double value) {
|
||||
_integrityCheckOnValueAddition();
|
||||
_stack.add(_StackValue.withDouble(value));
|
||||
}
|
||||
|
||||
/// Adds a string value.
|
||||
void addString(String value) {
|
||||
_integrityCheckOnValueAddition();
|
||||
if (_stringCache.containsKey(value)) {
|
||||
_stack.add(_stringCache[value]!);
|
||||
return;
|
||||
}
|
||||
final utf8String = utf8.encode(value);
|
||||
final length = utf8String.length;
|
||||
final bitWidth = BitWidthUtil.uwidth(length);
|
||||
final byteWidth = _align(bitWidth);
|
||||
_writeUInt(length, byteWidth);
|
||||
final stringOffset = _offset;
|
||||
final newOffset = _newOffset(length + 1);
|
||||
_pushBuffer(utf8String);
|
||||
_offset = newOffset;
|
||||
final stackValue =
|
||||
_StackValue.withOffset(stringOffset, ValueType.String, bitWidth);
|
||||
_stack.add(stackValue);
|
||||
_stringCache[value] = stackValue;
|
||||
}
|
||||
|
||||
/// This methods adds a key to a map and should be followed by an add... value call.
|
||||
///
|
||||
/// It also implies that you call this method only after you called [startMap].
|
||||
void addKey(String value) {
|
||||
_integrityCheckOnKeyAddition();
|
||||
if (_keyCache.containsKey(value)) {
|
||||
_stack.add(_keyCache[value]!);
|
||||
return;
|
||||
}
|
||||
final utf8String = utf8.encode(value);
|
||||
final length = utf8String.length;
|
||||
final keyOffset = _offset;
|
||||
final newOffset = _newOffset(length + 1);
|
||||
_pushBuffer(utf8String);
|
||||
_offset = newOffset;
|
||||
final stackValue =
|
||||
_StackValue.withOffset(keyOffset, ValueType.Key, BitWidth.width8);
|
||||
_stack.add(stackValue);
|
||||
_keyCache[value] = stackValue;
|
||||
}
|
||||
|
||||
/// Adds a byte array.
|
||||
///
|
||||
/// This method can be used to store any generic BLOB.
|
||||
void addBlob(ByteBuffer value) {
|
||||
_integrityCheckOnValueAddition();
|
||||
final length = value.lengthInBytes;
|
||||
final bitWidth = BitWidthUtil.uwidth(length);
|
||||
final byteWidth = _align(bitWidth);
|
||||
_writeUInt(length, byteWidth);
|
||||
final blobOffset = _offset;
|
||||
final newOffset = _newOffset(length);
|
||||
_pushBuffer(value.asUint8List());
|
||||
_offset = newOffset;
|
||||
final stackValue =
|
||||
_StackValue.withOffset(blobOffset, ValueType.Blob, bitWidth);
|
||||
_stack.add(stackValue);
|
||||
}
|
||||
|
||||
/// Stores int value indirectly in the buffer.
|
||||
///
|
||||
/// Adding large integer values indirectly might be beneficial if those values suppose to be store in a vector together with small integer values.
|
||||
/// This is due to the fact that FlexBuffers will add padding to small integer values, if they are stored together with large integer values.
|
||||
/// When we add integer indirectly the vector of ints will contain not the value itself, but only the relative offset to the value.
|
||||
/// By setting the [cache] parameter to true, you make sure that the builder tracks added int value and performs deduplication.
|
||||
void addIntIndirectly(int value, {bool cache = false}) {
|
||||
_integrityCheckOnValueAddition();
|
||||
if (_indirectIntCache.containsKey(value)) {
|
||||
_stack.add(_indirectIntCache[value]!);
|
||||
return;
|
||||
}
|
||||
final stackValue = _StackValue.withInt(value);
|
||||
final byteWidth = _align(stackValue.width);
|
||||
final newOffset = _newOffset(byteWidth);
|
||||
final valueOffset = _offset;
|
||||
_pushBuffer(stackValue.asU8List(stackValue.width));
|
||||
final stackOffset = _StackValue.withOffset(
|
||||
valueOffset, ValueType.IndirectInt, stackValue.width);
|
||||
_stack.add(stackOffset);
|
||||
_offset = newOffset;
|
||||
if (cache) {
|
||||
_indirectIntCache[value] = stackOffset;
|
||||
}
|
||||
}
|
||||
|
||||
/// Stores double value indirectly in the buffer.
|
||||
///
|
||||
/// Double are stored as 8 or 4 byte values in FlexBuffers. If they are stored in a mixed vector, values which are smaller than 4 / 8 bytes will be padded.
|
||||
/// When we add double indirectly, the vector will contain not the value itself, but only the relative offset to the value. Which could occupy only 1 or 2 bytes, reducing the odds for unnecessary padding.
|
||||
/// By setting the [cache] parameter to true, you make sure that the builder tracks already added double value and performs deduplication.
|
||||
void addDoubleIndirectly(double value, {bool cache = false}) {
|
||||
_integrityCheckOnValueAddition();
|
||||
if (cache && _indirectDoubleCache.containsKey(value)) {
|
||||
_stack.add(_indirectDoubleCache[value]!);
|
||||
return;
|
||||
}
|
||||
final stackValue = _StackValue.withDouble(value);
|
||||
final byteWidth = _align(stackValue.width);
|
||||
final newOffset = _newOffset(byteWidth);
|
||||
final valueOffset = _offset;
|
||||
_pushBuffer(stackValue.asU8List(stackValue.width));
|
||||
final stackOffset = _StackValue.withOffset(
|
||||
valueOffset, ValueType.IndirectFloat, stackValue.width);
|
||||
_stack.add(stackOffset);
|
||||
_offset = newOffset;
|
||||
if (cache) {
|
||||
_indirectDoubleCache[value] = stackOffset;
|
||||
}
|
||||
}
|
||||
|
||||
/// This method starts a vector definition and needs to be followed by 0 to n add... value calls.
|
||||
///
|
||||
/// The vector definition needs to be finished with an [end] call.
|
||||
/// It is also possible to add nested vector or map by calling [startVector] / [startMap].
|
||||
void startVector() {
|
||||
_integrityCheckOnValueAddition();
|
||||
_stackPointers.add(_StackPointer(_stack.length, true));
|
||||
}
|
||||
|
||||
/// This method starts a map definition.
|
||||
///
|
||||
/// This method call needs to be followed by 0 to n [addKey] + add... value calls.
|
||||
/// The map definition needs to be finished with an [end] call.
|
||||
/// It is also possible to add nested vector or map by calling [startVector] / [startMap] after calling [addKey].
|
||||
void startMap() {
|
||||
_integrityCheckOnValueAddition();
|
||||
_stackPointers.add(_StackPointer(_stack.length, false));
|
||||
}
|
||||
|
||||
/// Marks that the addition of values to the last vector, or map have ended.
|
||||
void end() {
|
||||
final pointer = _stackPointers.removeLast();
|
||||
if (pointer.isVector) {
|
||||
_endVector(pointer);
|
||||
} else {
|
||||
_sortKeysAndEndMap(pointer);
|
||||
}
|
||||
}
|
||||
|
||||
/// Finish building the FlatBuffer and return array of bytes.
|
||||
///
|
||||
/// Can be called multiple times, to get the array of bytes.
|
||||
/// After the first call, adding values, or starting vectors / maps will result in an exception.
|
||||
Uint8List finish() {
|
||||
if (_finished == false) {
|
||||
_finish();
|
||||
}
|
||||
return _buffer.buffer.asUint8List(0, _offset);
|
||||
}
|
||||
|
||||
/// Builds a FlatBuffer with current state without finishing the builder.
|
||||
///
|
||||
/// Creates an internal temporary copy of current builder and finishes the copy.
|
||||
/// Use this method, when the state of a long lasting builder need to be persisted periodically.
|
||||
ByteBuffer snapshot() {
|
||||
final tmp = Builder(size: _offset + 200);
|
||||
tmp._offset = _offset;
|
||||
tmp._stack = List.from(_stack);
|
||||
tmp._stackPointers = List.from(_stackPointers);
|
||||
tmp._buffer.buffer
|
||||
.asUint8List()
|
||||
.setAll(0, _buffer.buffer.asUint8List(0, _offset));
|
||||
for (var i = 0; i < tmp._stackPointers.length; i++) {
|
||||
tmp.end();
|
||||
}
|
||||
final buffer = tmp.finish();
|
||||
final bd = ByteData(buffer.lengthInBytes);
|
||||
bd.buffer.asUint8List().setAll(0, buffer);
|
||||
return bd.buffer;
|
||||
}
|
||||
|
||||
void _integrityCheckOnValueAddition() {
|
||||
if (_finished) {
|
||||
throw StateError('Adding values after finish is prohibited');
|
||||
}
|
||||
if (_stackPointers.isNotEmpty && _stackPointers.last.isVector == false) {
|
||||
if (_stack.last.type != ValueType.Key) {
|
||||
throw StateError(
|
||||
'Adding value to a map before adding a key is prohibited');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void _integrityCheckOnKeyAddition() {
|
||||
if (_finished) {
|
||||
throw StateError('Adding values after finish is prohibited');
|
||||
}
|
||||
if (_stackPointers.isEmpty || _stackPointers.last.isVector) {
|
||||
throw StateError('Adding key before staring a map is prohibited');
|
||||
}
|
||||
}
|
||||
|
||||
void _finish() {
|
||||
if (_stack.length != 1) {
|
||||
throw StateError(
|
||||
'Stack has to be exactly 1, but is ${_stack.length}. You have to end all started vectors and maps, before calling [finish]');
|
||||
}
|
||||
final value = _stack[0];
|
||||
final byteWidth = _align(value.elementWidth(_offset, 0));
|
||||
_writeStackValue(value, byteWidth);
|
||||
_writeUInt(value.storedPackedType(), 1);
|
||||
_writeUInt(byteWidth, 1);
|
||||
_finished = true;
|
||||
}
|
||||
|
||||
_StackValue _createVector(int start, int vecLength, int step,
|
||||
[_StackValue? keys]) {
|
||||
var bitWidth = BitWidthUtil.uwidth(vecLength);
|
||||
var prefixElements = 1;
|
||||
if (keys != null) {
|
||||
var elemWidth = keys.elementWidth(_offset, 0);
|
||||
if (elemWidth.index > bitWidth.index) {
|
||||
bitWidth = elemWidth;
|
||||
}
|
||||
prefixElements += 2;
|
||||
}
|
||||
var vectorType = ValueType.Key;
|
||||
var typed = keys == null;
|
||||
for (var i = start; i < _stack.length; i += step) {
|
||||
final elemWidth = _stack[i].elementWidth(_offset, i + prefixElements);
|
||||
if (elemWidth.index > bitWidth.index) {
|
||||
bitWidth = elemWidth;
|
||||
}
|
||||
if (i == start) {
|
||||
vectorType = _stack[i].type;
|
||||
typed &= ValueTypeUtils.isTypedVectorElement(vectorType);
|
||||
} else {
|
||||
if (vectorType != _stack[i].type) {
|
||||
typed = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
final byteWidth = _align(bitWidth);
|
||||
final fix = typed & ValueTypeUtils.isNumber(vectorType) &&
|
||||
vecLength >= 2 &&
|
||||
vecLength <= 4;
|
||||
if (keys != null) {
|
||||
_writeStackValue(keys, byteWidth);
|
||||
_writeUInt(1 << keys.width.index, byteWidth);
|
||||
}
|
||||
if (fix == false) {
|
||||
_writeUInt(vecLength, byteWidth);
|
||||
}
|
||||
final vecOffset = _offset;
|
||||
for (var i = start; i < _stack.length; i += step) {
|
||||
_writeStackValue(_stack[i], byteWidth);
|
||||
}
|
||||
if (typed == false) {
|
||||
for (var i = start; i < _stack.length; i += step) {
|
||||
_writeUInt(_stack[i].storedPackedType(), 1);
|
||||
}
|
||||
}
|
||||
if (keys != null) {
|
||||
return _StackValue.withOffset(vecOffset, ValueType.Map, bitWidth);
|
||||
}
|
||||
if (typed) {
|
||||
final vType =
|
||||
ValueTypeUtils.toTypedVector(vectorType, fix ? vecLength : 0);
|
||||
return _StackValue.withOffset(vecOffset, vType, bitWidth);
|
||||
}
|
||||
return _StackValue.withOffset(vecOffset, ValueType.Vector, bitWidth);
|
||||
}
|
||||
|
||||
void _endVector(_StackPointer pointer) {
|
||||
final vecLength = _stack.length - pointer.stackPosition;
|
||||
final vec = _createVector(pointer.stackPosition, vecLength, 1);
|
||||
_stack.removeRange(pointer.stackPosition, _stack.length);
|
||||
_stack.add(vec);
|
||||
}
|
||||
|
||||
void _sortKeysAndEndMap(_StackPointer pointer) {
|
||||
if (((_stack.length - pointer.stackPosition) & 1) == 1) {
|
||||
throw StateError(
|
||||
'The stack needs to hold key value pairs (even number of elements). Check if you combined [addKey] with add... method calls properly.');
|
||||
}
|
||||
|
||||
var sorted = true;
|
||||
for (var i = pointer.stackPosition; i < _stack.length - 2; i += 2) {
|
||||
if (_shouldFlip(_stack[i], _stack[i + 2])) {
|
||||
sorted = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (sorted == false) {
|
||||
for (var i = pointer.stackPosition; i < _stack.length; i += 2) {
|
||||
var flipIndex = i;
|
||||
for (var j = i + 2; j < _stack.length; j += 2) {
|
||||
if (_shouldFlip(_stack[flipIndex], _stack[j])) {
|
||||
flipIndex = j;
|
||||
}
|
||||
}
|
||||
if (flipIndex != i) {
|
||||
var k = _stack[flipIndex];
|
||||
var v = _stack[flipIndex + 1];
|
||||
_stack[flipIndex] = _stack[i];
|
||||
_stack[flipIndex + 1] = _stack[i + 1];
|
||||
_stack[i] = k;
|
||||
_stack[i + 1] = v;
|
||||
}
|
||||
}
|
||||
}
|
||||
_endMap(pointer);
|
||||
}
|
||||
|
||||
void _endMap(_StackPointer pointer) {
|
||||
final vecLength = (_stack.length - pointer.stackPosition) >> 1;
|
||||
final offsets = <int>[];
|
||||
for (var i = pointer.stackPosition; i < _stack.length; i += 2) {
|
||||
offsets.add(_stack[i].offset!);
|
||||
}
|
||||
final keysHash = _KeysHash(offsets);
|
||||
_StackValue? keysStackValue;
|
||||
if (_keyVectorCache.containsKey(keysHash)) {
|
||||
keysStackValue = _keyVectorCache[keysHash];
|
||||
} else {
|
||||
keysStackValue = _createVector(pointer.stackPosition, vecLength, 2);
|
||||
_keyVectorCache[keysHash] = keysStackValue;
|
||||
}
|
||||
final vec =
|
||||
_createVector(pointer.stackPosition + 1, vecLength, 2, keysStackValue);
|
||||
_stack.removeRange(pointer.stackPosition, _stack.length);
|
||||
_stack.add(vec);
|
||||
}
|
||||
|
||||
bool _shouldFlip(_StackValue v1, _StackValue v2) {
|
||||
if (v1.type != ValueType.Key || v2.type != ValueType.Key) {
|
||||
throw StateError(
|
||||
'Stack values are not keys $v1 | $v2. Check if you combined [addKey] with add... method calls properly.');
|
||||
}
|
||||
|
||||
late int c1, c2;
|
||||
var index = 0;
|
||||
do {
|
||||
c1 = _buffer.getUint8(v1.offset! + index);
|
||||
c2 = _buffer.getUint8(v2.offset! + index);
|
||||
if (c2 < c1) return true;
|
||||
if (c1 < c2) return false;
|
||||
index += 1;
|
||||
} while (c1 != 0 && c2 != 0);
|
||||
return false;
|
||||
}
|
||||
|
||||
int _align(BitWidth width) {
|
||||
final byteWidth = BitWidthUtil.toByteWidth(width);
|
||||
_offset += BitWidthUtil.paddingSize(_offset, byteWidth);
|
||||
return byteWidth;
|
||||
}
|
||||
|
||||
void _writeStackValue(_StackValue value, int byteWidth) {
|
||||
final newOffset = _newOffset(byteWidth);
|
||||
if (value.isOffset) {
|
||||
final relativeOffset = _offset - value.offset!;
|
||||
if (byteWidth == 8 || relativeOffset < (1 << (byteWidth * 8))) {
|
||||
_writeUInt(relativeOffset, byteWidth);
|
||||
} else {
|
||||
throw StateError(
|
||||
'Unexpected size $byteWidth. This might be a bug. Please create an issue https://github.com/google/flatbuffers/issues/new');
|
||||
}
|
||||
} else {
|
||||
_pushBuffer(value.asU8List(BitWidthUtil.fromByteWidth(byteWidth)));
|
||||
}
|
||||
_offset = newOffset;
|
||||
}
|
||||
|
||||
void _writeUInt(int value, int byteWidth) {
|
||||
final newOffset = _newOffset(byteWidth);
|
||||
_pushUInt(value, BitWidthUtil.fromByteWidth(byteWidth));
|
||||
_offset = newOffset;
|
||||
}
|
||||
|
||||
int _newOffset(int newValueSize) {
|
||||
final newOffset = _offset + newValueSize;
|
||||
var size = _buffer.lengthInBytes;
|
||||
final prevSize = size;
|
||||
while (size < newOffset) {
|
||||
size <<= 1;
|
||||
}
|
||||
if (prevSize < size) {
|
||||
final newBuf = ByteData(size);
|
||||
newBuf.buffer.asUint8List().setAll(0, _buffer.buffer.asUint8List());
|
||||
}
|
||||
return newOffset;
|
||||
}
|
||||
|
||||
void _pushInt(int value, BitWidth width) {
|
||||
switch (width) {
|
||||
case BitWidth.width8:
|
||||
_buffer.setInt8(_offset, value);
|
||||
break;
|
||||
case BitWidth.width16:
|
||||
_buffer.setInt16(_offset, value, Endian.little);
|
||||
break;
|
||||
case BitWidth.width32:
|
||||
_buffer.setInt32(_offset, value, Endian.little);
|
||||
break;
|
||||
case BitWidth.width64:
|
||||
_buffer.setInt64(_offset, value, Endian.little);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void _pushUInt(int value, BitWidth width) {
|
||||
switch (width) {
|
||||
case BitWidth.width8:
|
||||
_buffer.setUint8(_offset, value);
|
||||
break;
|
||||
case BitWidth.width16:
|
||||
_buffer.setUint16(_offset, value, Endian.little);
|
||||
break;
|
||||
case BitWidth.width32:
|
||||
_buffer.setUint32(_offset, value, Endian.little);
|
||||
break;
|
||||
case BitWidth.width64:
|
||||
_buffer.setUint64(_offset, value, Endian.little);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void _pushBuffer(List<int> value) {
|
||||
_buffer.buffer.asUint8List().setAll(_offset, value);
|
||||
}
|
||||
}
|
||||
|
||||
class _StackValue {
|
||||
late Object _value;
|
||||
int? _offset;
|
||||
final ValueType _type;
|
||||
final BitWidth _width;
|
||||
|
||||
_StackValue.withNull()
|
||||
: _type = ValueType.Null,
|
||||
_width = BitWidth.width8;
|
||||
|
||||
_StackValue.withInt(int value)
|
||||
: _type = ValueType.Int,
|
||||
_width = BitWidthUtil.width(value),
|
||||
_value = value;
|
||||
|
||||
_StackValue.withBool(bool value)
|
||||
: _type = ValueType.Bool,
|
||||
_width = BitWidth.width8,
|
||||
_value = value;
|
||||
|
||||
_StackValue.withDouble(double value)
|
||||
: _type = ValueType.Float,
|
||||
_width = BitWidthUtil.width(value),
|
||||
_value = value;
|
||||
|
||||
_StackValue.withOffset(int value, ValueType type, BitWidth width)
|
||||
: _offset = value,
|
||||
_type = type,
|
||||
_width = width;
|
||||
|
||||
BitWidth storedWidth({BitWidth width = BitWidth.width8}) {
|
||||
return ValueTypeUtils.isInline(_type)
|
||||
? BitWidthUtil.max(_width, width)
|
||||
: _width;
|
||||
}
|
||||
|
||||
int storedPackedType({BitWidth width = BitWidth.width8}) {
|
||||
return ValueTypeUtils.packedType(_type, storedWidth(width: width));
|
||||
}
|
||||
|
||||
BitWidth elementWidth(int size, int index) {
|
||||
if (ValueTypeUtils.isInline(_type)) return _width;
|
||||
final offset = _offset!;
|
||||
for (var i = 0; i < 4; i++) {
|
||||
final width = 1 << i;
|
||||
final bitWidth = BitWidthUtil.uwidth(size +
|
||||
BitWidthUtil.paddingSize(size, width) +
|
||||
index * width -
|
||||
offset);
|
||||
if (1 << bitWidth.index == width) {
|
||||
return bitWidth;
|
||||
}
|
||||
}
|
||||
throw StateError(
|
||||
'Element is of unknown. Size: $size at index: $index. This might be a bug. Please create an issue https://github.com/google/flatbuffers/issues/new');
|
||||
}
|
||||
|
||||
List<int> asU8List(BitWidth width) {
|
||||
if (ValueTypeUtils.isNumber(_type)) {
|
||||
if (_type == ValueType.Float) {
|
||||
if (width == BitWidth.width32) {
|
||||
final result = ByteData(4);
|
||||
result.setFloat32(0, _value as double, Endian.little);
|
||||
return result.buffer.asUint8List();
|
||||
} else {
|
||||
final result = ByteData(8);
|
||||
result.setFloat64(0, _value as double, Endian.little);
|
||||
return result.buffer.asUint8List();
|
||||
}
|
||||
} else {
|
||||
switch (width) {
|
||||
case BitWidth.width8:
|
||||
final result = ByteData(1);
|
||||
result.setInt8(0, _value as int);
|
||||
return result.buffer.asUint8List();
|
||||
case BitWidth.width16:
|
||||
final result = ByteData(2);
|
||||
result.setInt16(0, _value as int, Endian.little);
|
||||
return result.buffer.asUint8List();
|
||||
case BitWidth.width32:
|
||||
final result = ByteData(4);
|
||||
result.setInt32(0, _value as int, Endian.little);
|
||||
return result.buffer.asUint8List();
|
||||
case BitWidth.width64:
|
||||
final result = ByteData(8);
|
||||
result.setInt64(0, _value as int, Endian.little);
|
||||
return result.buffer.asUint8List();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (_type == ValueType.Null) {
|
||||
final result = ByteData(1);
|
||||
result.setInt8(0, 0);
|
||||
return result.buffer.asUint8List();
|
||||
}
|
||||
if (_type == ValueType.Bool) {
|
||||
final result = ByteData(1);
|
||||
result.setInt8(0, _value as bool ? 1 : 0);
|
||||
return result.buffer.asUint8List();
|
||||
}
|
||||
|
||||
throw StateError(
|
||||
'Unexpected type: $_type. This might be a bug. Please create an issue https://github.com/google/flatbuffers/issues/new');
|
||||
}
|
||||
|
||||
ValueType get type {
|
||||
return _type;
|
||||
}
|
||||
|
||||
BitWidth get width {
|
||||
return _width;
|
||||
}
|
||||
|
||||
bool get isOffset {
|
||||
return !ValueTypeUtils.isInline(_type);
|
||||
}
|
||||
|
||||
int? get offset => _offset;
|
||||
|
||||
bool get isFloat32 {
|
||||
return _type == ValueType.Float && _width == BitWidth.width32;
|
||||
}
|
||||
}
|
||||
|
||||
class _StackPointer {
|
||||
int stackPosition;
|
||||
bool isVector;
|
||||
|
||||
_StackPointer(this.stackPosition, this.isVector);
|
||||
}
|
||||
|
||||
class _KeysHash {
|
||||
final List<int> keys;
|
||||
|
||||
const _KeysHash(this.keys);
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
if (other is _KeysHash) {
|
||||
if (keys.length != other.keys.length) return false;
|
||||
for (var i = 0; i < keys.length; i++) {
|
||||
if (keys[i] != other.keys[i]) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode {
|
||||
var result = 17;
|
||||
for (var i = 0; i < keys.length; i++) {
|
||||
result = result * 23 + keys[i];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
481
third_party/flatbuffers/dart/lib/src/reference.dart
vendored
481
third_party/flatbuffers/dart/lib/src/reference.dart
vendored
@ -1,481 +0,0 @@
|
||||
import 'dart:collection';
|
||||
import 'dart:convert';
|
||||
import 'dart:typed_data';
|
||||
import 'types.dart';
|
||||
|
||||
/// Main class to read a value out of a FlexBuffer.
|
||||
///
|
||||
/// This class let you access values stored in the buffer in a lazy fashion.
|
||||
class Reference {
|
||||
final ByteData _buffer;
|
||||
final int _offset;
|
||||
final BitWidth _parentWidth;
|
||||
final String _path;
|
||||
final int _byteWidth;
|
||||
final ValueType _valueType;
|
||||
int? _length;
|
||||
|
||||
Reference._(
|
||||
this._buffer, this._offset, this._parentWidth, int packedType, this._path,
|
||||
[int? byteWidth, ValueType? valueType])
|
||||
: _byteWidth = byteWidth ?? 1 << (packedType & 3),
|
||||
_valueType = valueType ?? ValueTypeUtils.fromInt(packedType >> 2);
|
||||
|
||||
/// Use this method to access the root value of a FlexBuffer.
|
||||
static Reference fromBuffer(ByteBuffer buffer) {
|
||||
final len = buffer.lengthInBytes;
|
||||
if (len < 3) {
|
||||
throw UnsupportedError('Buffer needs to be bigger than 3');
|
||||
}
|
||||
final byteData = ByteData.view(buffer);
|
||||
final byteWidth = byteData.getUint8(len - 1);
|
||||
final packedType = byteData.getUint8(len - 2);
|
||||
final offset = len - byteWidth - 2;
|
||||
return Reference._(ByteData.view(buffer), offset,
|
||||
BitWidthUtil.fromByteWidth(byteWidth), packedType, "/");
|
||||
}
|
||||
|
||||
/// Returns true if the underlying value is null.
|
||||
bool get isNull => _valueType == ValueType.Null;
|
||||
|
||||
/// Returns true if the underlying value can be represented as [num].
|
||||
bool get isNum =>
|
||||
ValueTypeUtils.isNumber(_valueType) ||
|
||||
ValueTypeUtils.isIndirectNumber(_valueType);
|
||||
|
||||
/// Returns true if the underlying value was encoded as a float (direct or indirect).
|
||||
bool get isDouble =>
|
||||
_valueType == ValueType.Float || _valueType == ValueType.IndirectFloat;
|
||||
|
||||
/// Returns true if the underlying value was encoded as an int or uint (direct or indirect).
|
||||
bool get isInt => isNum && !isDouble;
|
||||
|
||||
/// Returns true if the underlying value was encoded as a string or a key.
|
||||
bool get isString =>
|
||||
_valueType == ValueType.String || _valueType == ValueType.Key;
|
||||
|
||||
/// Returns true if the underlying value was encoded as a bool.
|
||||
bool get isBool => _valueType == ValueType.Bool;
|
||||
|
||||
/// Returns true if the underlying value was encoded as a blob.
|
||||
bool get isBlob => _valueType == ValueType.Blob;
|
||||
|
||||
/// Returns true if the underlying value points to a vector.
|
||||
bool get isVector => ValueTypeUtils.isAVector(_valueType);
|
||||
|
||||
/// Returns true if the underlying value points to a map.
|
||||
bool get isMap => _valueType == ValueType.Map;
|
||||
|
||||
/// If this [isBool], returns the bool value. Otherwise, returns null.
|
||||
bool? get boolValue {
|
||||
if (_valueType == ValueType.Bool) {
|
||||
return _readInt(_offset, _parentWidth) != 0;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// Returns an [int], if the underlying value can be represented as an int.
|
||||
///
|
||||
/// Otherwise returns [null].
|
||||
int? get intValue {
|
||||
if (_valueType == ValueType.Int) {
|
||||
return _readInt(_offset, _parentWidth);
|
||||
}
|
||||
if (_valueType == ValueType.UInt) {
|
||||
return _readUInt(_offset, _parentWidth);
|
||||
}
|
||||
if (_valueType == ValueType.IndirectInt) {
|
||||
return _readInt(_indirect, BitWidthUtil.fromByteWidth(_byteWidth));
|
||||
}
|
||||
if (_valueType == ValueType.IndirectUInt) {
|
||||
return _readUInt(_indirect, BitWidthUtil.fromByteWidth(_byteWidth));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// Returns [double], if the underlying value [isDouble].
|
||||
///
|
||||
/// Otherwise returns [null].
|
||||
double? get doubleValue {
|
||||
if (_valueType == ValueType.Float) {
|
||||
return _readFloat(_offset, _parentWidth);
|
||||
}
|
||||
if (_valueType == ValueType.IndirectFloat) {
|
||||
return _readFloat(_indirect, BitWidthUtil.fromByteWidth(_byteWidth));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// Returns [num], if the underlying value is numeric, be it int uint, or float (direct or indirect).
|
||||
///
|
||||
/// Otherwise returns [null].
|
||||
num? get numValue => doubleValue ?? intValue;
|
||||
|
||||
/// Returns [String] value or null otherwise.
|
||||
///
|
||||
/// This method performers a utf8 decoding, as FlexBuffers format stores strings in utf8 encoding.
|
||||
String? get stringValue {
|
||||
if (_valueType == ValueType.String || _valueType == ValueType.Key) {
|
||||
return utf8.decode(_buffer.buffer.asUint8List(_indirect, length));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// Returns [Uint8List] value or null otherwise.
|
||||
Uint8List? get blobValue {
|
||||
if (_valueType == ValueType.Blob) {
|
||||
return _buffer.buffer.asUint8List(_indirect, length);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// Can be used with an [int] or a [String] value for key.
|
||||
/// If the underlying value in FlexBuffer is a vector, then use [int] for access.
|
||||
/// If the underlying value in FlexBuffer is a map, then use [String] for access.
|
||||
/// Returns [Reference] value. Throws an exception when [key] is not applicable.
|
||||
Reference operator [](Object key) {
|
||||
if (key is int && ValueTypeUtils.isAVector(_valueType)) {
|
||||
final index = key;
|
||||
if (index >= length || index < 0) {
|
||||
throw ArgumentError(
|
||||
'Key: [$key] is not applicable on: $_path of: $_valueType length: $length');
|
||||
}
|
||||
final elementOffset = _indirect + index * _byteWidth;
|
||||
int packedType = 0;
|
||||
int? byteWidth;
|
||||
ValueType? valueType;
|
||||
if (ValueTypeUtils.isTypedVector(_valueType)) {
|
||||
byteWidth = 1;
|
||||
valueType = ValueTypeUtils.typedVectorElementType(_valueType);
|
||||
} else if (ValueTypeUtils.isFixedTypedVector(_valueType)) {
|
||||
byteWidth = 1;
|
||||
valueType = ValueTypeUtils.fixedTypedVectorElementType(_valueType);
|
||||
} else {
|
||||
packedType = _buffer.getUint8(_indirect + length * _byteWidth + index);
|
||||
}
|
||||
return Reference._(
|
||||
_buffer,
|
||||
elementOffset,
|
||||
BitWidthUtil.fromByteWidth(_byteWidth),
|
||||
packedType,
|
||||
"$_path[$index]",
|
||||
byteWidth,
|
||||
valueType);
|
||||
}
|
||||
if (key is String && _valueType == ValueType.Map) {
|
||||
final index = _keyIndex(key);
|
||||
if (index != null) {
|
||||
return _valueForIndexWithKey(index, key);
|
||||
}
|
||||
}
|
||||
throw ArgumentError(
|
||||
'Key: [$key] is not applicable on: $_path of: $_valueType');
|
||||
}
|
||||
|
||||
/// Get an iterable if the underlying flexBuffer value is a vector.
|
||||
/// Otherwise throws an exception.
|
||||
Iterable<Reference> get vectorIterable {
|
||||
if (isVector == false) {
|
||||
throw UnsupportedError('Value is not a vector. It is: $_valueType');
|
||||
}
|
||||
return _VectorIterator(this);
|
||||
}
|
||||
|
||||
/// Get an iterable for keys if the underlying flexBuffer value is a map.
|
||||
/// Otherwise throws an exception.
|
||||
Iterable<String> get mapKeyIterable {
|
||||
if (isMap == false) {
|
||||
throw UnsupportedError('Value is not a map. It is: $_valueType');
|
||||
}
|
||||
return _MapKeyIterator(this);
|
||||
}
|
||||
|
||||
/// Get an iterable for values if the underlying flexBuffer value is a map.
|
||||
/// Otherwise throws an exception.
|
||||
Iterable<Reference> get mapValueIterable {
|
||||
if (isMap == false) {
|
||||
throw UnsupportedError('Value is not a map. It is: $_valueType');
|
||||
}
|
||||
return _MapValueIterator(this);
|
||||
}
|
||||
|
||||
/// Returns the length of the underlying FlexBuffer value.
|
||||
/// If the underlying value is [null] the length is 0.
|
||||
/// If the underlying value is a number, or a bool, the length is 1.
|
||||
/// If the underlying value is a vector, or map, the length reflects number of elements / element pairs.
|
||||
/// If the values is a string or a blob, the length reflects a number of bytes the value occupies (strings are encoded in utf8 format).
|
||||
int get length {
|
||||
if (_length == null) {
|
||||
// needs to be checked before more generic isAVector
|
||||
if (ValueTypeUtils.isFixedTypedVector(_valueType)) {
|
||||
_length = ValueTypeUtils.fixedTypedVectorElementSize(_valueType);
|
||||
} else if (_valueType == ValueType.Blob ||
|
||||
ValueTypeUtils.isAVector(_valueType) ||
|
||||
_valueType == ValueType.Map) {
|
||||
_length = _readUInt(
|
||||
_indirect - _byteWidth, BitWidthUtil.fromByteWidth(_byteWidth));
|
||||
} else if (_valueType == ValueType.Null) {
|
||||
_length = 0;
|
||||
} else if (_valueType == ValueType.String) {
|
||||
final indirect = _indirect;
|
||||
var sizeByteWidth = _byteWidth;
|
||||
var size = _readUInt(indirect - sizeByteWidth,
|
||||
BitWidthUtil.fromByteWidth(sizeByteWidth));
|
||||
while (_buffer.getInt8(indirect + size) != 0) {
|
||||
sizeByteWidth <<= 1;
|
||||
size = _readUInt(indirect - sizeByteWidth,
|
||||
BitWidthUtil.fromByteWidth(sizeByteWidth));
|
||||
}
|
||||
_length = size;
|
||||
} else if (_valueType == ValueType.Key) {
|
||||
final indirect = _indirect;
|
||||
var size = 1;
|
||||
while (_buffer.getInt8(indirect + size) != 0) {
|
||||
size += 1;
|
||||
}
|
||||
_length = size;
|
||||
} else {
|
||||
_length = 1;
|
||||
}
|
||||
}
|
||||
return _length!;
|
||||
}
|
||||
|
||||
/// Returns a minified JSON representation of the underlying FlexBuffer value.
|
||||
///
|
||||
/// This method involves materializing the entire object tree, which may be
|
||||
/// expensive. It is more efficient to work with [Reference] and access only the needed data.
|
||||
/// Blob values are represented as base64 encoded string.
|
||||
String get json {
|
||||
if (_valueType == ValueType.Bool) {
|
||||
return boolValue! ? 'true' : 'false';
|
||||
}
|
||||
if (_valueType == ValueType.Null) {
|
||||
return 'null';
|
||||
}
|
||||
if (ValueTypeUtils.isNumber(_valueType)) {
|
||||
return jsonEncode(numValue);
|
||||
}
|
||||
if (_valueType == ValueType.String) {
|
||||
return jsonEncode(stringValue);
|
||||
}
|
||||
if (_valueType == ValueType.Blob) {
|
||||
return jsonEncode(base64Encode(blobValue!));
|
||||
}
|
||||
if (ValueTypeUtils.isAVector(_valueType)) {
|
||||
final result = StringBuffer();
|
||||
result.write('[');
|
||||
for (var i = 0; i < length; i++) {
|
||||
result.write(this[i].json);
|
||||
if (i < length - 1) {
|
||||
result.write(',');
|
||||
}
|
||||
}
|
||||
result.write(']');
|
||||
return result.toString();
|
||||
}
|
||||
if (_valueType == ValueType.Map) {
|
||||
final result = StringBuffer();
|
||||
result.write('{');
|
||||
for (var i = 0; i < length; i++) {
|
||||
result.write(jsonEncode(_keyForIndex(i)));
|
||||
result.write(':');
|
||||
result.write(_valueForIndex(i).json);
|
||||
if (i < length - 1) {
|
||||
result.write(',');
|
||||
}
|
||||
}
|
||||
result.write('}');
|
||||
return result.toString();
|
||||
}
|
||||
throw UnsupportedError(
|
||||
'Type: $_valueType is not supported for JSON conversion');
|
||||
}
|
||||
|
||||
/// Computes the indirect offset of the value.
|
||||
///
|
||||
/// To optimize for the more common case of being called only once, this
|
||||
/// value is not cached. Callers that need to use it more than once should
|
||||
/// cache the return value in a local variable.
|
||||
int get _indirect {
|
||||
final step = _readUInt(_offset, _parentWidth);
|
||||
return _offset - step;
|
||||
}
|
||||
|
||||
int _readInt(int offset, BitWidth width) {
|
||||
_validateOffset(offset, width);
|
||||
if (width == BitWidth.width8) {
|
||||
return _buffer.getInt8(offset);
|
||||
}
|
||||
if (width == BitWidth.width16) {
|
||||
return _buffer.getInt16(offset, Endian.little);
|
||||
}
|
||||
if (width == BitWidth.width32) {
|
||||
return _buffer.getInt32(offset, Endian.little);
|
||||
}
|
||||
return _buffer.getInt64(offset, Endian.little);
|
||||
}
|
||||
|
||||
int _readUInt(int offset, BitWidth width) {
|
||||
_validateOffset(offset, width);
|
||||
if (width == BitWidth.width8) {
|
||||
return _buffer.getUint8(offset);
|
||||
}
|
||||
if (width == BitWidth.width16) {
|
||||
return _buffer.getUint16(offset, Endian.little);
|
||||
}
|
||||
if (width == BitWidth.width32) {
|
||||
return _buffer.getUint32(offset, Endian.little);
|
||||
}
|
||||
return _buffer.getUint64(offset, Endian.little);
|
||||
}
|
||||
|
||||
double _readFloat(int offset, BitWidth width) {
|
||||
_validateOffset(offset, width);
|
||||
if (width.index < BitWidth.width32.index) {
|
||||
throw StateError('Bad width: $width');
|
||||
}
|
||||
|
||||
if (width == BitWidth.width32) {
|
||||
return _buffer.getFloat32(offset, Endian.little);
|
||||
}
|
||||
|
||||
return _buffer.getFloat64(offset, Endian.little);
|
||||
}
|
||||
|
||||
void _validateOffset(int offset, BitWidth width) {
|
||||
if (_offset < 0 ||
|
||||
_buffer.lengthInBytes <= offset + width.index ||
|
||||
offset & (BitWidthUtil.toByteWidth(width) - 1) != 0) {
|
||||
throw StateError('Bad offset: $offset, width: $width');
|
||||
}
|
||||
}
|
||||
|
||||
int? _keyIndex(String key) {
|
||||
final input = utf8.encode(key);
|
||||
final keysVectorOffset = _indirect - _byteWidth * 3;
|
||||
final indirectOffset = keysVectorOffset -
|
||||
_readUInt(keysVectorOffset, BitWidthUtil.fromByteWidth(_byteWidth));
|
||||
final byteWidth = _readUInt(
|
||||
keysVectorOffset + _byteWidth, BitWidthUtil.fromByteWidth(_byteWidth));
|
||||
var low = 0;
|
||||
var high = length - 1;
|
||||
while (low <= high) {
|
||||
final mid = (high + low) >> 1;
|
||||
final dif = _diffKeys(input, mid, indirectOffset, byteWidth);
|
||||
if (dif == 0) return mid;
|
||||
if (dif < 0) {
|
||||
high = mid - 1;
|
||||
} else {
|
||||
low = mid + 1;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
int _diffKeys(List<int> input, int index, int indirectOffset, int byteWidth) {
|
||||
final keyOffset = indirectOffset + index * byteWidth;
|
||||
final keyIndirectOffset =
|
||||
keyOffset - _readUInt(keyOffset, BitWidthUtil.fromByteWidth(byteWidth));
|
||||
for (var i = 0; i < input.length; i++) {
|
||||
final dif = input[i] - _buffer.getUint8(keyIndirectOffset + i);
|
||||
if (dif != 0) {
|
||||
return dif;
|
||||
}
|
||||
}
|
||||
return (_buffer.getUint8(keyIndirectOffset + input.length) == 0) ? 0 : -1;
|
||||
}
|
||||
|
||||
Reference _valueForIndexWithKey(int index, String key) {
|
||||
final indirect = _indirect;
|
||||
final elementOffset = indirect + index * _byteWidth;
|
||||
final packedType = _buffer.getUint8(indirect + length * _byteWidth + index);
|
||||
return Reference._(_buffer, elementOffset,
|
||||
BitWidthUtil.fromByteWidth(_byteWidth), packedType, "$_path/$key");
|
||||
}
|
||||
|
||||
Reference _valueForIndex(int index) {
|
||||
final indirect = _indirect;
|
||||
final elementOffset = indirect + index * _byteWidth;
|
||||
final packedType = _buffer.getUint8(indirect + length * _byteWidth + index);
|
||||
return Reference._(_buffer, elementOffset,
|
||||
BitWidthUtil.fromByteWidth(_byteWidth), packedType, "$_path/[$index]");
|
||||
}
|
||||
|
||||
String _keyForIndex(int index) {
|
||||
final keysVectorOffset = _indirect - _byteWidth * 3;
|
||||
final indirectOffset = keysVectorOffset -
|
||||
_readUInt(keysVectorOffset, BitWidthUtil.fromByteWidth(_byteWidth));
|
||||
final byteWidth = _readUInt(
|
||||
keysVectorOffset + _byteWidth, BitWidthUtil.fromByteWidth(_byteWidth));
|
||||
final keyOffset = indirectOffset + index * byteWidth;
|
||||
final keyIndirectOffset =
|
||||
keyOffset - _readUInt(keyOffset, BitWidthUtil.fromByteWidth(byteWidth));
|
||||
var length = 0;
|
||||
while (_buffer.getUint8(keyIndirectOffset + length) != 0) {
|
||||
length += 1;
|
||||
}
|
||||
return utf8.decode(_buffer.buffer.asUint8List(keyIndirectOffset, length));
|
||||
}
|
||||
}
|
||||
|
||||
class _VectorIterator
|
||||
with IterableMixin<Reference>
|
||||
implements Iterator<Reference> {
|
||||
final Reference _vector;
|
||||
int index = -1;
|
||||
|
||||
_VectorIterator(this._vector);
|
||||
|
||||
@override
|
||||
Reference get current => _vector[index];
|
||||
|
||||
@override
|
||||
bool moveNext() {
|
||||
index++;
|
||||
return index < _vector.length;
|
||||
}
|
||||
|
||||
@override
|
||||
Iterator<Reference> get iterator => this;
|
||||
}
|
||||
|
||||
class _MapKeyIterator with IterableMixin<String> implements Iterator<String> {
|
||||
final Reference _map;
|
||||
int index = -1;
|
||||
|
||||
_MapKeyIterator(this._map);
|
||||
|
||||
@override
|
||||
String get current => _map._keyForIndex(index);
|
||||
|
||||
@override
|
||||
bool moveNext() {
|
||||
index++;
|
||||
return index < _map.length;
|
||||
}
|
||||
|
||||
@override
|
||||
Iterator<String> get iterator => this;
|
||||
}
|
||||
|
||||
class _MapValueIterator
|
||||
with IterableMixin<Reference>
|
||||
implements Iterator<Reference> {
|
||||
final Reference _map;
|
||||
int index = -1;
|
||||
|
||||
_MapValueIterator(this._map);
|
||||
|
||||
@override
|
||||
Reference get current => _map._valueForIndex(index);
|
||||
|
||||
@override
|
||||
bool moveNext() {
|
||||
index++;
|
||||
return index < _map.length;
|
||||
}
|
||||
|
||||
@override
|
||||
Iterator<Reference> get iterator => this;
|
||||
}
|
190
third_party/flatbuffers/dart/lib/src/types.dart
vendored
190
third_party/flatbuffers/dart/lib/src/types.dart
vendored
@ -1,190 +0,0 @@
|
||||
import 'dart:typed_data';
|
||||
|
||||
/// Represents the number of bits a value occupies.
|
||||
enum BitWidth { width8, width16, width32, width64 }
|
||||
|
||||
class BitWidthUtil {
|
||||
static int toByteWidth(BitWidth self) {
|
||||
return 1 << self.index;
|
||||
}
|
||||
|
||||
static BitWidth width(num value) {
|
||||
if (value is int) {
|
||||
var v = value.toInt().abs();
|
||||
if (v >> 7 == 0) return BitWidth.width8;
|
||||
if (v >> 15 == 0) return BitWidth.width16;
|
||||
if (v >> 31 == 0) return BitWidth.width32;
|
||||
return BitWidth.width64;
|
||||
}
|
||||
return value == _toF32(value as double)
|
||||
? BitWidth.width32
|
||||
: BitWidth.width64;
|
||||
}
|
||||
|
||||
static BitWidth uwidth(num value) {
|
||||
if (value.toInt() == value) {
|
||||
var v = value.toInt().abs();
|
||||
if (v >> 8 == 0) return BitWidth.width8;
|
||||
if (v >> 16 == 0) return BitWidth.width16;
|
||||
if (v >> 32 == 0) return BitWidth.width32;
|
||||
return BitWidth.width64;
|
||||
}
|
||||
return value == _toF32(value as double)
|
||||
? BitWidth.width32
|
||||
: BitWidth.width64;
|
||||
}
|
||||
|
||||
static BitWidth fromByteWidth(int value) {
|
||||
if (value == 1) {
|
||||
return BitWidth.width8;
|
||||
}
|
||||
if (value == 2) {
|
||||
return BitWidth.width16;
|
||||
}
|
||||
if (value == 4) {
|
||||
return BitWidth.width32;
|
||||
}
|
||||
if (value == 8) {
|
||||
return BitWidth.width64;
|
||||
}
|
||||
throw Exception('Unexpected value $value');
|
||||
}
|
||||
|
||||
static int paddingSize(int bufSize, int scalarSize) {
|
||||
return (~bufSize + 1) & (scalarSize - 1);
|
||||
}
|
||||
|
||||
static double _toF32(double value) {
|
||||
var bdata = ByteData(4);
|
||||
bdata.setFloat32(0, value);
|
||||
return bdata.getFloat32(0);
|
||||
}
|
||||
|
||||
static BitWidth max(BitWidth self, BitWidth other) {
|
||||
if (self.index < other.index) {
|
||||
return other;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents all internal FlexBuffer types.
|
||||
enum ValueType {
|
||||
Null,
|
||||
Int,
|
||||
UInt,
|
||||
Float,
|
||||
Key,
|
||||
String,
|
||||
IndirectInt,
|
||||
IndirectUInt,
|
||||
IndirectFloat,
|
||||
Map,
|
||||
Vector,
|
||||
VectorInt,
|
||||
VectorUInt,
|
||||
VectorFloat,
|
||||
VectorKey,
|
||||
@Deprecated(
|
||||
'VectorString is deprecated due to a flaw in the binary format (https://github.com/google/flatbuffers/issues/5627)')
|
||||
VectorString,
|
||||
VectorInt2,
|
||||
VectorUInt2,
|
||||
VectorFloat2,
|
||||
VectorInt3,
|
||||
VectorUInt3,
|
||||
VectorFloat3,
|
||||
VectorInt4,
|
||||
VectorUInt4,
|
||||
VectorFloat4,
|
||||
Blob,
|
||||
Bool,
|
||||
VectorBool
|
||||
}
|
||||
|
||||
class ValueTypeUtils {
|
||||
static int toInt(ValueType self) {
|
||||
if (self == ValueType.VectorBool) return 36;
|
||||
return self.index;
|
||||
}
|
||||
|
||||
static ValueType fromInt(int value) {
|
||||
if (value == 36) return ValueType.VectorBool;
|
||||
return ValueType.values[value];
|
||||
}
|
||||
|
||||
static bool isInline(ValueType self) {
|
||||
return self == ValueType.Bool || toInt(self) <= toInt(ValueType.Float);
|
||||
}
|
||||
|
||||
static bool isNumber(ValueType self) {
|
||||
return toInt(self) >= toInt(ValueType.Int) &&
|
||||
toInt(self) <= toInt(ValueType.Float);
|
||||
}
|
||||
|
||||
static bool isIndirectNumber(ValueType self) {
|
||||
return toInt(self) >= toInt(ValueType.IndirectInt) &&
|
||||
toInt(self) <= toInt(ValueType.IndirectFloat);
|
||||
}
|
||||
|
||||
static bool isTypedVectorElement(ValueType self) {
|
||||
return self == ValueType.Bool ||
|
||||
(toInt(self) >= toInt(ValueType.Int) &&
|
||||
toInt(self) <= toInt(ValueType.String));
|
||||
}
|
||||
|
||||
static bool isTypedVector(ValueType self) {
|
||||
return self == ValueType.VectorBool ||
|
||||
(toInt(self) >= toInt(ValueType.VectorInt) &&
|
||||
toInt(self) <= toInt(ValueType.VectorString));
|
||||
}
|
||||
|
||||
static bool isFixedTypedVector(ValueType self) {
|
||||
return (toInt(self) >= toInt(ValueType.VectorInt2) &&
|
||||
toInt(self) <= toInt(ValueType.VectorFloat4));
|
||||
}
|
||||
|
||||
static bool isAVector(ValueType self) {
|
||||
return (isTypedVector(self) ||
|
||||
isFixedTypedVector(self) ||
|
||||
self == ValueType.Vector);
|
||||
}
|
||||
|
||||
static ValueType toTypedVector(ValueType self, int length) {
|
||||
if (length == 0) {
|
||||
return ValueTypeUtils.fromInt(
|
||||
toInt(self) - toInt(ValueType.Int) + toInt(ValueType.VectorInt));
|
||||
}
|
||||
if (length == 2) {
|
||||
return ValueTypeUtils.fromInt(
|
||||
toInt(self) - toInt(ValueType.Int) + toInt(ValueType.VectorInt2));
|
||||
}
|
||||
if (length == 3) {
|
||||
return ValueTypeUtils.fromInt(
|
||||
toInt(self) - toInt(ValueType.Int) + toInt(ValueType.VectorInt3));
|
||||
}
|
||||
if (length == 4) {
|
||||
return ValueTypeUtils.fromInt(
|
||||
toInt(self) - toInt(ValueType.Int) + toInt(ValueType.VectorInt4));
|
||||
}
|
||||
throw Exception('unexpected length ' + length.toString());
|
||||
}
|
||||
|
||||
static ValueType typedVectorElementType(ValueType self) {
|
||||
return ValueTypeUtils.fromInt(
|
||||
toInt(self) - toInt(ValueType.VectorInt) + toInt(ValueType.Int));
|
||||
}
|
||||
|
||||
static ValueType fixedTypedVectorElementType(ValueType self) {
|
||||
return ValueTypeUtils.fromInt(
|
||||
(toInt(self) - toInt(ValueType.VectorInt2)) % 3 + toInt(ValueType.Int));
|
||||
}
|
||||
|
||||
static int fixedTypedVectorElementSize(ValueType self) {
|
||||
return (toInt(self) - toInt(ValueType.VectorInt2)) ~/ 3 + 2;
|
||||
}
|
||||
|
||||
static int packedType(ValueType self, BitWidth bitWidth) {
|
||||
return bitWidth.index | (toInt(self) << 2);
|
||||
}
|
||||
}
|
36
third_party/flatbuffers/dart/publish.sh
vendored
36
third_party/flatbuffers/dart/publish.sh
vendored
@ -1,36 +0,0 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Copyright 2018 Google Inc. All rights reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
# Note to pub consumers: this file is used to assist with publishing the
|
||||
# pub package from the flatbuffers repository and is not meant for general use.
|
||||
# As pub does not currently provide a way to exclude files, it is included here.
|
||||
set -e
|
||||
|
||||
command -v dart >/dev/null 2>&1 || { echo >&2 "Require `dart` but it's not installed. Aborting."; exit 1; }
|
||||
|
||||
pushd ../tests
|
||||
./DartTest.sh
|
||||
popd
|
||||
|
||||
pushd ../samples
|
||||
./dart_sample.sh
|
||||
popd
|
||||
|
||||
dart pub publish
|
||||
|
||||
rm example/monster.fbs
|
||||
rm test/*.fbs
|
||||
rm -rf test/sub
|
14
third_party/flatbuffers/dart/pubspec.yaml
vendored
14
third_party/flatbuffers/dart/pubspec.yaml
vendored
@ -1,14 +0,0 @@
|
||||
name: flat_buffers
|
||||
version: 24.3.25
|
||||
description: FlatBuffers reading and writing library for Dart. Based on original work by Konstantin Scheglov and Paul Berry of the Dart SDK team.
|
||||
homepage: https://github.com/google/flatbuffers
|
||||
documentation: https://google.github.io/flatbuffers/index.html
|
||||
|
||||
environment:
|
||||
sdk: '>=2.12.0 <4.0.0'
|
||||
|
||||
dev_dependencies:
|
||||
test: ^1.17.7
|
||||
test_reflective_loader: ^0.2.0
|
||||
path: ^1.8.0
|
||||
lints: ^1.0.1
|
@ -1,10 +0,0 @@
|
||||
// Test for #7355
|
||||
table Foo {
|
||||
my_foo : foo_properties;
|
||||
}
|
||||
|
||||
struct foo_properties
|
||||
{
|
||||
a : bool;
|
||||
b : bool;
|
||||
}
|
@ -1,207 +0,0 @@
|
||||
// automatically generated by the FlatBuffers compiler, do not modify
|
||||
// ignore_for_file: unused_import, unused_field, unused_element, unused_local_variable
|
||||
|
||||
import 'dart:typed_data' show Uint8List;
|
||||
import 'package:flat_buffers/flat_buffers.dart' as fb;
|
||||
|
||||
|
||||
class Foo {
|
||||
Foo._(this._bc, this._bcOffset);
|
||||
factory Foo(List<int> bytes) {
|
||||
final rootRef = fb.BufferContext.fromBytes(bytes);
|
||||
return reader.read(rootRef, 0);
|
||||
}
|
||||
|
||||
static const fb.Reader<Foo> reader = _FooReader();
|
||||
|
||||
final fb.BufferContext _bc;
|
||||
final int _bcOffset;
|
||||
|
||||
FooProperties? get myFoo => FooProperties.reader.vTableGetNullable(_bc, _bcOffset, 4);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'Foo{myFoo: ${myFoo}}';
|
||||
}
|
||||
|
||||
FooT unpack() => FooT(
|
||||
myFoo: myFoo?.unpack());
|
||||
|
||||
static int pack(fb.Builder fbBuilder, FooT? object) {
|
||||
if (object == null) return 0;
|
||||
return object.pack(fbBuilder);
|
||||
}
|
||||
}
|
||||
|
||||
class FooT implements fb.Packable {
|
||||
FooPropertiesT? myFoo;
|
||||
|
||||
FooT({
|
||||
this.myFoo});
|
||||
|
||||
@override
|
||||
int pack(fb.Builder fbBuilder) {
|
||||
fbBuilder.startTable(1);
|
||||
if (myFoo != null) {
|
||||
fbBuilder.addStruct(0, myFoo!.pack(fbBuilder));
|
||||
}
|
||||
return fbBuilder.endTable();
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'FooT{myFoo: ${myFoo}}';
|
||||
}
|
||||
}
|
||||
|
||||
class _FooReader extends fb.TableReader<Foo> {
|
||||
const _FooReader();
|
||||
|
||||
@override
|
||||
Foo createObject(fb.BufferContext bc, int offset) =>
|
||||
Foo._(bc, offset);
|
||||
}
|
||||
|
||||
class FooBuilder {
|
||||
FooBuilder(this.fbBuilder);
|
||||
|
||||
final fb.Builder fbBuilder;
|
||||
|
||||
void begin() {
|
||||
fbBuilder.startTable(1);
|
||||
}
|
||||
|
||||
int addMyFoo(int offset) {
|
||||
fbBuilder.addStruct(0, offset);
|
||||
return fbBuilder.offset;
|
||||
}
|
||||
|
||||
int finish() {
|
||||
return fbBuilder.endTable();
|
||||
}
|
||||
}
|
||||
|
||||
class FooObjectBuilder extends fb.ObjectBuilder {
|
||||
final FooPropertiesObjectBuilder? _myFoo;
|
||||
|
||||
FooObjectBuilder({
|
||||
FooPropertiesObjectBuilder? myFoo,
|
||||
})
|
||||
: _myFoo = myFoo;
|
||||
|
||||
/// Finish building, and store into the [fbBuilder].
|
||||
@override
|
||||
int finish(fb.Builder fbBuilder) {
|
||||
fbBuilder.startTable(1);
|
||||
if (_myFoo != null) {
|
||||
fbBuilder.addStruct(0, _myFoo!.finish(fbBuilder));
|
||||
}
|
||||
return fbBuilder.endTable();
|
||||
}
|
||||
|
||||
/// Convenience method to serialize to byte list.
|
||||
@override
|
||||
Uint8List toBytes([String? fileIdentifier]) {
|
||||
final fbBuilder = fb.Builder(deduplicateTables: false);
|
||||
fbBuilder.finish(finish(fbBuilder), fileIdentifier);
|
||||
return fbBuilder.buffer;
|
||||
}
|
||||
}
|
||||
class FooProperties {
|
||||
FooProperties._(this._bc, this._bcOffset);
|
||||
|
||||
static const fb.Reader<FooProperties> reader = _FooPropertiesReader();
|
||||
|
||||
final fb.BufferContext _bc;
|
||||
final int _bcOffset;
|
||||
|
||||
bool get a => const fb.BoolReader().read(_bc, _bcOffset + 0);
|
||||
bool get b => const fb.BoolReader().read(_bc, _bcOffset + 1);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'FooProperties{a: ${a}, b: ${b}}';
|
||||
}
|
||||
|
||||
FooPropertiesT unpack() => FooPropertiesT(
|
||||
a: a,
|
||||
b: b);
|
||||
|
||||
static int pack(fb.Builder fbBuilder, FooPropertiesT? object) {
|
||||
if (object == null) return 0;
|
||||
return object.pack(fbBuilder);
|
||||
}
|
||||
}
|
||||
|
||||
class FooPropertiesT implements fb.Packable {
|
||||
bool a;
|
||||
bool b;
|
||||
|
||||
FooPropertiesT({
|
||||
required this.a,
|
||||
required this.b});
|
||||
|
||||
@override
|
||||
int pack(fb.Builder fbBuilder) {
|
||||
fbBuilder.putBool(b);
|
||||
fbBuilder.putBool(a);
|
||||
return fbBuilder.offset;
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'FooPropertiesT{a: ${a}, b: ${b}}';
|
||||
}
|
||||
}
|
||||
|
||||
class _FooPropertiesReader extends fb.StructReader<FooProperties> {
|
||||
const _FooPropertiesReader();
|
||||
|
||||
@override
|
||||
int get size => 2;
|
||||
|
||||
@override
|
||||
FooProperties createObject(fb.BufferContext bc, int offset) =>
|
||||
FooProperties._(bc, offset);
|
||||
}
|
||||
|
||||
class FooPropertiesBuilder {
|
||||
FooPropertiesBuilder(this.fbBuilder);
|
||||
|
||||
final fb.Builder fbBuilder;
|
||||
|
||||
int finish(bool a, bool b) {
|
||||
fbBuilder.putBool(b);
|
||||
fbBuilder.putBool(a);
|
||||
return fbBuilder.offset;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class FooPropertiesObjectBuilder extends fb.ObjectBuilder {
|
||||
final bool _a;
|
||||
final bool _b;
|
||||
|
||||
FooPropertiesObjectBuilder({
|
||||
required bool a,
|
||||
required bool b,
|
||||
})
|
||||
: _a = a,
|
||||
_b = b;
|
||||
|
||||
/// Finish building, and store into the [fbBuilder].
|
||||
@override
|
||||
int finish(fb.Builder fbBuilder) {
|
||||
fbBuilder.putBool(_b);
|
||||
fbBuilder.putBool(_a);
|
||||
return fbBuilder.offset;
|
||||
}
|
||||
|
||||
/// Convenience method to serialize to byte list.
|
||||
@override
|
||||
Uint8List toBytes([String? fileIdentifier]) {
|
||||
final fbBuilder = fb.Builder(deduplicateTables: false);
|
||||
fbBuilder.finish(finish(fbBuilder), fileIdentifier);
|
||||
return fbBuilder.buffer;
|
||||
}
|
||||
}
|
@ -1,939 +0,0 @@
|
||||
import 'dart:typed_data';
|
||||
import 'dart:io' as io;
|
||||
|
||||
import 'package:path/path.dart' as path;
|
||||
|
||||
import 'package:flat_buffers/flat_buffers.dart';
|
||||
import 'package:test/test.dart';
|
||||
import 'package:test_reflective_loader/test_reflective_loader.dart';
|
||||
|
||||
import './monster_test_my_game.example_generated.dart' as example;
|
||||
import './monster_test_my_game.example2_generated.dart' as example2;
|
||||
import './list_of_enums_generated.dart' as example3;
|
||||
import './bool_structs_generated.dart' as example4;
|
||||
|
||||
main() {
|
||||
defineReflectiveSuite(() {
|
||||
defineReflectiveTests(BuilderTest);
|
||||
defineReflectiveTests(ObjectAPITest);
|
||||
defineReflectiveTests(CheckOtherLangaugesData);
|
||||
defineReflectiveTests(GeneratorTest);
|
||||
defineReflectiveTests(ListOfEnumsTest);
|
||||
});
|
||||
}
|
||||
|
||||
int indexToField(int index) {
|
||||
return (1 + 1 + index) * 2;
|
||||
}
|
||||
|
||||
@reflectiveTest
|
||||
class CheckOtherLangaugesData {
|
||||
test_cppData() async {
|
||||
List<int> data = await io.File(path.join(
|
||||
path.context.current,
|
||||
'test',
|
||||
'monsterdata_test.mon',
|
||||
)).readAsBytes();
|
||||
example.Monster mon = example.Monster(data);
|
||||
expect(mon.hp, 80);
|
||||
expect(mon.mana, 150);
|
||||
expect(mon.name, 'MyMonster');
|
||||
expect(mon.pos!.x, 1.0);
|
||||
expect(mon.pos!.y, 2.0);
|
||||
expect(mon.pos!.z, 3.0);
|
||||
expect(mon.pos!.test1, 3.0);
|
||||
expect(mon.pos!.test2.value, 2.0);
|
||||
expect(mon.pos!.test3.a, 5);
|
||||
expect(mon.pos!.test3.b, 6);
|
||||
expect(mon.testType!.value, example.AnyTypeId.Monster.value);
|
||||
expect(mon.test is example.Monster, true);
|
||||
final monster2 = mon.test as example.Monster;
|
||||
expect(monster2.name, "Fred");
|
||||
|
||||
expect(mon.inventory!.length, 5);
|
||||
expect(mon.inventory!.reduce((cur, next) => cur + next), 10);
|
||||
final test4 = mon.test4!;
|
||||
expect(test4.length, 2);
|
||||
expect(test4[0].a + test4[0].b + test4[1].a + test4[1].b, 100);
|
||||
expect(mon.testarrayofstring!.length, 2);
|
||||
expect(mon.testarrayofstring![0], "test1");
|
||||
expect(mon.testarrayofstring![1], "test2");
|
||||
|
||||
// this will fail if accessing any field fails.
|
||||
expect(
|
||||
mon.toString(),
|
||||
'Monster{'
|
||||
'pos: Vec3{x: 1.0, y: 2.0, z: 3.0, test1: 3.0, test2: Color{value: 2}, test3: Test{a: 5, b: 6}}, '
|
||||
'mana: 150, hp: 80, name: MyMonster, inventory: [0, 1, 2, 3, 4], '
|
||||
'color: Color{value: 8}, testType: AnyTypeId{value: 1}, '
|
||||
'test: Monster{pos: null, mana: 150, hp: 100, name: Fred, '
|
||||
'inventory: null, color: Color{value: 8}, testType: null, '
|
||||
'test: null, test4: null, testarrayofstring: null, '
|
||||
'testarrayoftables: null, enemy: null, testnestedflatbuffer: null, '
|
||||
'testempty: null, testbool: false, testhashs32Fnv1: 0, '
|
||||
'testhashu32Fnv1: 0, testhashs64Fnv1: 0, testhashu64Fnv1: 0, '
|
||||
'testhashs32Fnv1a: 0, testhashu32Fnv1a: 0, testhashs64Fnv1a: 0, '
|
||||
'testhashu64Fnv1a: 0, testarrayofbools: null, testf: 3.14159, '
|
||||
'testf2: 3.0, testf3: 0.0, testarrayofstring2: null, '
|
||||
'testarrayofsortedstruct: null, flex: null, test5: null, '
|
||||
'vectorOfLongs: null, vectorOfDoubles: null, parentNamespaceTest: null, '
|
||||
'vectorOfReferrables: null, singleWeakReference: 0, '
|
||||
'vectorOfWeakReferences: null, vectorOfStrongReferrables: null, '
|
||||
'coOwningReference: 0, vectorOfCoOwningReferences: null, '
|
||||
'nonOwningReference: 0, vectorOfNonOwningReferences: null, '
|
||||
'anyUniqueType: null, anyUnique: null, anyAmbiguousType: null, '
|
||||
'anyAmbiguous: null, vectorOfEnums: null, signedEnum: Race{value: -1}, '
|
||||
'testrequirednestedflatbuffer: null, scalarKeySortedTables: null, '
|
||||
'nativeInline: null, '
|
||||
'longEnumNonEnumDefault: LongEnum{value: 0}, '
|
||||
'longEnumNormalDefault: LongEnum{value: 2}, nanDefault: NaN, '
|
||||
'infDefault: Infinity, positiveInfDefault: Infinity, infinityDefault: '
|
||||
'Infinity, positiveInfinityDefault: Infinity, negativeInfDefault: '
|
||||
'-Infinity, negativeInfinityDefault: -Infinity, doubleInfDefault: Infinity}, '
|
||||
'test4: [Test{a: 10, b: 20}, Test{a: 30, b: 40}], '
|
||||
'testarrayofstring: [test1, test2], testarrayoftables: null, '
|
||||
'enemy: Monster{pos: null, mana: 150, hp: 100, name: Fred, '
|
||||
'inventory: null, color: Color{value: 8}, testType: null, '
|
||||
'test: null, test4: null, testarrayofstring: null, '
|
||||
'testarrayoftables: null, enemy: null, testnestedflatbuffer: null, '
|
||||
'testempty: null, testbool: false, testhashs32Fnv1: 0, '
|
||||
'testhashu32Fnv1: 0, testhashs64Fnv1: 0, testhashu64Fnv1: 0, '
|
||||
'testhashs32Fnv1a: 0, testhashu32Fnv1a: 0, testhashs64Fnv1a: 0, '
|
||||
'testhashu64Fnv1a: 0, testarrayofbools: null, testf: 3.14159, '
|
||||
'testf2: 3.0, testf3: 0.0, testarrayofstring2: null, '
|
||||
'testarrayofsortedstruct: null, flex: null, test5: null, '
|
||||
'vectorOfLongs: null, vectorOfDoubles: null, parentNamespaceTest: null, '
|
||||
'vectorOfReferrables: null, singleWeakReference: 0, '
|
||||
'vectorOfWeakReferences: null, vectorOfStrongReferrables: null, '
|
||||
'coOwningReference: 0, vectorOfCoOwningReferences: null, '
|
||||
'nonOwningReference: 0, vectorOfNonOwningReferences: null, '
|
||||
'anyUniqueType: null, anyUnique: null, anyAmbiguousType: null, '
|
||||
'anyAmbiguous: null, vectorOfEnums: null, signedEnum: Race{value: -1}, '
|
||||
'testrequirednestedflatbuffer: null, scalarKeySortedTables: null, '
|
||||
'nativeInline: null, '
|
||||
'longEnumNonEnumDefault: LongEnum{value: 0}, '
|
||||
'longEnumNormalDefault: LongEnum{value: 2}, nanDefault: NaN, '
|
||||
'infDefault: Infinity, positiveInfDefault: Infinity, infinityDefault: '
|
||||
'Infinity, positiveInfinityDefault: Infinity, negativeInfDefault: '
|
||||
'-Infinity, negativeInfinityDefault: -Infinity, doubleInfDefault: Infinity}, '
|
||||
'testnestedflatbuffer: null, testempty: null, testbool: true, '
|
||||
'testhashs32Fnv1: -579221183, testhashu32Fnv1: 3715746113, '
|
||||
'testhashs64Fnv1: 7930699090847568257, '
|
||||
'testhashu64Fnv1: 7930699090847568257, '
|
||||
'testhashs32Fnv1a: -1904106383, testhashu32Fnv1a: 2390860913, '
|
||||
'testhashs64Fnv1a: 4898026182817603057, '
|
||||
'testhashu64Fnv1a: 4898026182817603057, '
|
||||
'testarrayofbools: [true, false, true], testf: 3.14159, testf2: 3.0, '
|
||||
'testf3: 0.0, testarrayofstring2: null, testarrayofsortedstruct: ['
|
||||
'Ability{id: 0, distance: 45}, Ability{id: 1, distance: 21}, '
|
||||
'Ability{id: 5, distance: 12}], '
|
||||
'flex: null, test5: [Test{a: 10, b: 20}, Test{a: 30, b: 40}], '
|
||||
'vectorOfLongs: [1, 100, 10000, 1000000, 100000000], '
|
||||
'vectorOfDoubles: [-1.7976931348623157e+308, 0.0, 1.7976931348623157e+308], '
|
||||
'parentNamespaceTest: null, vectorOfReferrables: null, '
|
||||
'singleWeakReference: 0, vectorOfWeakReferences: null, '
|
||||
'vectorOfStrongReferrables: null, coOwningReference: 0, '
|
||||
'vectorOfCoOwningReferences: null, nonOwningReference: 0, '
|
||||
'vectorOfNonOwningReferences: null, '
|
||||
'anyUniqueType: null, anyUnique: null, '
|
||||
'anyAmbiguousType: null, '
|
||||
'anyAmbiguous: null, vectorOfEnums: null, signedEnum: Race{value: -1}, '
|
||||
'testrequirednestedflatbuffer: null, scalarKeySortedTables: [Stat{id: '
|
||||
'miss, val: 0, count: 0}, Stat{id: hit, val: 10, count: 1}], '
|
||||
'nativeInline: Test{a: 1, b: 2}, '
|
||||
'longEnumNonEnumDefault: LongEnum{value: 0}, '
|
||||
'longEnumNormalDefault: LongEnum{value: 2}, nanDefault: NaN, '
|
||||
'infDefault: Infinity, positiveInfDefault: Infinity, infinityDefault: '
|
||||
'Infinity, positiveInfinityDefault: Infinity, negativeInfDefault: '
|
||||
'-Infinity, negativeInfinityDefault: -Infinity, doubleInfDefault: Infinity}');
|
||||
}
|
||||
}
|
||||
|
||||
/// Test a custom, fixed-memory allocator (no actual allocations performed)
|
||||
class CustomAllocator extends Allocator {
|
||||
final _memory = ByteData(10 * 1024);
|
||||
int _used = 0;
|
||||
|
||||
Uint8List buffer(int size) => _memory.buffer.asUint8List(_used - size, size);
|
||||
|
||||
@override
|
||||
ByteData allocate(int size) {
|
||||
if (size > _memory.lengthInBytes) {
|
||||
throw UnsupportedError('Trying to allocate too much');
|
||||
}
|
||||
_used = size;
|
||||
return ByteData.sublistView(_memory, 0, size);
|
||||
}
|
||||
|
||||
@override
|
||||
void deallocate(ByteData _) {}
|
||||
}
|
||||
|
||||
@reflectiveTest
|
||||
class BuilderTest {
|
||||
void test_monsterBuilder([Builder? builder]) {
|
||||
final fbBuilder = builder ?? Builder();
|
||||
final str = fbBuilder.writeString('MyMonster');
|
||||
|
||||
fbBuilder.writeString('test1');
|
||||
fbBuilder.writeString('test2', asciiOptimization: true);
|
||||
final testArrayOfString = fbBuilder.endStructVector(2);
|
||||
|
||||
final fred = fbBuilder.writeString('Fred');
|
||||
|
||||
final List<int> treasure = [0, 1, 2, 3, 4];
|
||||
final inventory = fbBuilder.writeListUint8(treasure);
|
||||
|
||||
final monBuilder = example.MonsterBuilder(fbBuilder)
|
||||
..begin()
|
||||
..addNameOffset(fred);
|
||||
final mon2 = monBuilder.finish();
|
||||
|
||||
final testBuilder = example.TestBuilder(fbBuilder);
|
||||
testBuilder.finish(10, 20);
|
||||
testBuilder.finish(30, 40);
|
||||
final test4 = fbBuilder.endStructVector(2);
|
||||
|
||||
monBuilder
|
||||
..begin()
|
||||
..addPos(
|
||||
example.Vec3Builder(fbBuilder).finish(
|
||||
1.0,
|
||||
2.0,
|
||||
3.0,
|
||||
3.0,
|
||||
example.Color.Green,
|
||||
() => testBuilder.finish(5, 6),
|
||||
),
|
||||
)
|
||||
..addHp(80)
|
||||
..addNameOffset(str)
|
||||
..addInventoryOffset(inventory)
|
||||
..addTestType(example.AnyTypeId.Monster)
|
||||
..addTestOffset(mon2)
|
||||
..addTest4Offset(test4)
|
||||
..addTestarrayofstringOffset(testArrayOfString);
|
||||
final mon = monBuilder.finish();
|
||||
fbBuilder.finish(mon);
|
||||
}
|
||||
|
||||
void test_error_addInt32_withoutStartTable([Builder? builder]) {
|
||||
builder ??= Builder();
|
||||
expect(() {
|
||||
builder!.addInt32(0, 0);
|
||||
}, throwsA(isA<AssertionError>()));
|
||||
}
|
||||
|
||||
void test_error_addOffset_withoutStartTable() {
|
||||
Builder builder = Builder();
|
||||
expect(() {
|
||||
builder.addOffset(0, 0);
|
||||
}, throwsA(isA<AssertionError>()));
|
||||
}
|
||||
|
||||
void test_error_endTable_withoutStartTable() {
|
||||
Builder builder = Builder();
|
||||
expect(() {
|
||||
builder.endTable();
|
||||
}, throwsA(isA<AssertionError>()));
|
||||
}
|
||||
|
||||
void test_error_startTable_duringTable() {
|
||||
Builder builder = Builder();
|
||||
builder.startTable(0);
|
||||
expect(() {
|
||||
builder.startTable(0);
|
||||
}, throwsA(isA<AssertionError>()));
|
||||
}
|
||||
|
||||
void test_error_writeString_duringTable() {
|
||||
Builder builder = Builder();
|
||||
builder.startTable(1);
|
||||
expect(() {
|
||||
builder.writeString('12345');
|
||||
}, throwsA(isA<AssertionError>()));
|
||||
}
|
||||
|
||||
void test_file_identifier() {
|
||||
Uint8List byteList;
|
||||
{
|
||||
Builder builder = Builder(initialSize: 0);
|
||||
builder.startTable(0);
|
||||
int offset = builder.endTable();
|
||||
builder.finish(offset, 'Az~ÿ');
|
||||
byteList = builder.buffer;
|
||||
}
|
||||
// Convert byteList to a ByteData so that we can read data from it.
|
||||
ByteData byteData = byteList.buffer.asByteData(byteList.offsetInBytes);
|
||||
// First 4 bytes are an offset to the table data.
|
||||
int tableDataLoc = byteData.getUint32(0, Endian.little);
|
||||
// Next 4 bytes are the file identifier.
|
||||
expect(byteData.getUint8(4), 65); // 'a'
|
||||
expect(byteData.getUint8(5), 122); // 'z'
|
||||
expect(byteData.getUint8(6), 126); // '~'
|
||||
expect(byteData.getUint8(7), 255); // 'ÿ'
|
||||
// First 4 bytes of the table data are a backwards offset to the vtable.
|
||||
int vTableLoc =
|
||||
tableDataLoc - byteData.getInt32(tableDataLoc, Endian.little);
|
||||
// First 2 bytes of the vtable are the size of the vtable in bytes, which
|
||||
// should be 4.
|
||||
expect(byteData.getUint16(vTableLoc, Endian.little), 4);
|
||||
// Next 2 bytes are the size of the object in bytes (including the vtable
|
||||
// pointer), which should be 4.
|
||||
expect(byteData.getUint16(vTableLoc + 2, Endian.little), 4);
|
||||
}
|
||||
|
||||
void test_low() {
|
||||
final allocator = CustomAllocator();
|
||||
final builder = Builder(initialSize: 0, allocator: allocator);
|
||||
|
||||
builder.putUint8(1);
|
||||
expect(allocator.buffer(builder.size()), [1]);
|
||||
|
||||
builder.putUint32(2);
|
||||
expect(allocator.buffer(builder.size()), [2, 0, 0, 0, 0, 0, 0, 1]);
|
||||
|
||||
builder.putUint8(3);
|
||||
expect(
|
||||
allocator.buffer(builder.size()), [0, 0, 0, 3, 2, 0, 0, 0, 0, 0, 0, 1]);
|
||||
|
||||
builder.putUint8(4);
|
||||
expect(
|
||||
allocator.buffer(builder.size()), [0, 0, 4, 3, 2, 0, 0, 0, 0, 0, 0, 1]);
|
||||
|
||||
builder.putUint8(5);
|
||||
expect(
|
||||
allocator.buffer(builder.size()), [0, 5, 4, 3, 2, 0, 0, 0, 0, 0, 0, 1]);
|
||||
|
||||
builder.putUint32(6);
|
||||
expect(allocator.buffer(builder.size()),
|
||||
[6, 0, 0, 0, 0, 5, 4, 3, 2, 0, 0, 0, 0, 0, 0, 1]);
|
||||
}
|
||||
|
||||
void test_table_default() {
|
||||
List<int> byteList;
|
||||
{
|
||||
final builder = Builder(initialSize: 0, allocator: CustomAllocator());
|
||||
builder.startTable(2);
|
||||
builder.addInt32(0, 10, 10);
|
||||
builder.addInt32(1, 20, 10);
|
||||
int offset = builder.endTable();
|
||||
builder.finish(offset);
|
||||
byteList = builder.buffer;
|
||||
expect(builder.size(), byteList.length);
|
||||
}
|
||||
// read and verify
|
||||
BufferContext buffer = BufferContext.fromBytes(byteList);
|
||||
int objectOffset = buffer.derefObject(0);
|
||||
// was not written, so uses the new default value
|
||||
expect(
|
||||
const Int32Reader()
|
||||
.vTableGet(buffer, objectOffset, indexToField(0), 15),
|
||||
15);
|
||||
// has the written value
|
||||
expect(
|
||||
const Int32Reader()
|
||||
.vTableGet(buffer, objectOffset, indexToField(1), 15),
|
||||
20);
|
||||
}
|
||||
|
||||
void test_table_format([Builder? builder]) {
|
||||
Uint8List byteList;
|
||||
{
|
||||
builder ??= Builder(initialSize: 0);
|
||||
builder.startTable(3);
|
||||
builder.addInt32(0, 10);
|
||||
builder.addInt32(1, 20);
|
||||
builder.addInt32(2, 30);
|
||||
builder.finish(builder.endTable());
|
||||
byteList = builder.buffer;
|
||||
}
|
||||
// Convert byteList to a ByteData so that we can read data from it.
|
||||
ByteData byteData = byteList.buffer.asByteData(byteList.offsetInBytes);
|
||||
// First 4 bytes are an offset to the table data.
|
||||
int tableDataLoc = byteData.getUint32(0, Endian.little);
|
||||
// First 4 bytes of the table data are a backwards offset to the vtable.
|
||||
int vTableLoc =
|
||||
tableDataLoc - byteData.getInt32(tableDataLoc, Endian.little);
|
||||
// First 2 bytes of the vtable are the size of the vtable in bytes, which
|
||||
// should be 10.
|
||||
expect(byteData.getUint16(vTableLoc, Endian.little), 10);
|
||||
// Next 2 bytes are the size of the object in bytes (including the vtable
|
||||
// pointer), which should be 16.
|
||||
expect(byteData.getUint16(vTableLoc + 2, Endian.little), 16);
|
||||
// Remaining 6 bytes are the offsets within the object where the ints are
|
||||
// located.
|
||||
for (int i = 0; i < 3; i++) {
|
||||
int offset = byteData.getUint16(vTableLoc + 4 + 2 * i, Endian.little);
|
||||
expect(
|
||||
byteData.getInt32(tableDataLoc + offset, Endian.little), 10 + 10 * i);
|
||||
}
|
||||
}
|
||||
|
||||
void test_table_string() {
|
||||
String latinString = 'test';
|
||||
String unicodeString = 'Проба пера';
|
||||
List<int> byteList;
|
||||
{
|
||||
Builder builder = Builder(initialSize: 0);
|
||||
int? latinStringOffset =
|
||||
builder.writeString(latinString, asciiOptimization: true);
|
||||
int? unicodeStringOffset =
|
||||
builder.writeString(unicodeString, asciiOptimization: true);
|
||||
builder.startTable(2);
|
||||
builder.addOffset(0, latinStringOffset);
|
||||
builder.addOffset(1, unicodeStringOffset);
|
||||
int offset = builder.endTable();
|
||||
builder.finish(offset);
|
||||
byteList = builder.buffer;
|
||||
}
|
||||
// read and verify
|
||||
BufferContext buf = BufferContext.fromBytes(byteList);
|
||||
int objectOffset = buf.derefObject(0);
|
||||
expect(
|
||||
const StringReader()
|
||||
.vTableGetNullable(buf, objectOffset, indexToField(0)),
|
||||
latinString);
|
||||
expect(
|
||||
const StringReader(asciiOptimization: true)
|
||||
.vTableGetNullable(buf, objectOffset, indexToField(1)),
|
||||
unicodeString);
|
||||
}
|
||||
|
||||
void test_table_types([Builder? builder]) {
|
||||
List<int> byteList;
|
||||
{
|
||||
builder ??= Builder(initialSize: 0);
|
||||
int? stringOffset = builder.writeString('12345');
|
||||
builder.startTable(7);
|
||||
builder.addBool(0, true);
|
||||
builder.addInt8(1, 10);
|
||||
builder.addInt32(2, 20);
|
||||
builder.addOffset(3, stringOffset);
|
||||
builder.addInt32(4, 40);
|
||||
builder.addUint32(5, 0x9ABCDEF0);
|
||||
builder.addUint8(6, 0x9A);
|
||||
int offset = builder.endTable();
|
||||
builder.finish(offset);
|
||||
byteList = builder.buffer;
|
||||
}
|
||||
// read and verify
|
||||
BufferContext buf = BufferContext.fromBytes(byteList);
|
||||
int objectOffset = buf.derefObject(0);
|
||||
expect(
|
||||
const BoolReader()
|
||||
.vTableGetNullable(buf, objectOffset, indexToField(0)),
|
||||
true);
|
||||
expect(
|
||||
const Int8Reader()
|
||||
.vTableGetNullable(buf, objectOffset, indexToField(1)),
|
||||
10);
|
||||
expect(
|
||||
const Int32Reader()
|
||||
.vTableGetNullable(buf, objectOffset, indexToField(2)),
|
||||
20);
|
||||
expect(
|
||||
const StringReader()
|
||||
.vTableGetNullable(buf, objectOffset, indexToField(3)),
|
||||
'12345');
|
||||
expect(
|
||||
const Int32Reader()
|
||||
.vTableGetNullable(buf, objectOffset, indexToField(4)),
|
||||
40);
|
||||
expect(
|
||||
const Uint32Reader()
|
||||
.vTableGetNullable(buf, objectOffset, indexToField(5)),
|
||||
0x9ABCDEF0);
|
||||
expect(
|
||||
const Uint8Reader()
|
||||
.vTableGetNullable(buf, objectOffset, indexToField(6)),
|
||||
0x9A);
|
||||
}
|
||||
|
||||
void test_writeList_of_Uint32() {
|
||||
List<int> values = <int>[10, 100, 12345, 0x9abcdef0];
|
||||
// write
|
||||
List<int> byteList;
|
||||
{
|
||||
Builder builder = Builder(initialSize: 0);
|
||||
int offset = builder.writeListUint32(values);
|
||||
builder.finish(offset);
|
||||
byteList = builder.buffer;
|
||||
}
|
||||
// read and verify
|
||||
BufferContext buf = BufferContext.fromBytes(byteList);
|
||||
List<int> items = const Uint32ListReader().read(buf, 0);
|
||||
expect(items, hasLength(4));
|
||||
expect(items, orderedEquals(values));
|
||||
}
|
||||
|
||||
void test_writeList_ofBool() {
|
||||
void verifyListBooleans(int len, List<int> trueBits) {
|
||||
// write
|
||||
List<int> byteList;
|
||||
{
|
||||
Builder builder = Builder(initialSize: 0);
|
||||
List<bool> values = List<bool>.filled(len, false);
|
||||
for (int bit in trueBits) {
|
||||
values[bit] = true;
|
||||
}
|
||||
int offset = builder.writeListBool(values);
|
||||
builder.finish(offset);
|
||||
byteList = builder.buffer;
|
||||
}
|
||||
// read and verify
|
||||
BufferContext buf = BufferContext.fromBytes(byteList);
|
||||
List<bool> items = const BoolListReader().read(buf, 0);
|
||||
expect(items, hasLength(len));
|
||||
for (int i = 0; i < items.length; i++) {
|
||||
expect(items[i], trueBits.contains(i), reason: 'bit $i of $len');
|
||||
}
|
||||
}
|
||||
|
||||
verifyListBooleans(0, <int>[]);
|
||||
verifyListBooleans(1, <int>[]);
|
||||
verifyListBooleans(1, <int>[0]);
|
||||
verifyListBooleans(31, <int>[0, 1]);
|
||||
verifyListBooleans(31, <int>[1, 2, 24, 25, 30]);
|
||||
verifyListBooleans(31, <int>[0, 30]);
|
||||
verifyListBooleans(32, <int>[1, 2, 24, 25, 31]);
|
||||
verifyListBooleans(33, <int>[1, 2, 24, 25, 32]);
|
||||
verifyListBooleans(33, <int>[1, 2, 24, 25, 31, 32]);
|
||||
verifyListBooleans(63, <int>[]);
|
||||
verifyListBooleans(63, <int>[0, 1, 2, 61, 62]);
|
||||
verifyListBooleans(63, List<int>.generate(63, (i) => i));
|
||||
verifyListBooleans(64, <int>[]);
|
||||
verifyListBooleans(64, <int>[0, 1, 2, 61, 62, 63]);
|
||||
verifyListBooleans(64, <int>[1, 2, 62]);
|
||||
verifyListBooleans(64, <int>[0, 1, 2, 63]);
|
||||
verifyListBooleans(64, List<int>.generate(64, (i) => i));
|
||||
verifyListBooleans(100, <int>[0, 3, 30, 60, 90, 99]);
|
||||
}
|
||||
|
||||
void test_writeList_ofInt32() {
|
||||
List<int> byteList;
|
||||
{
|
||||
Builder builder = Builder(initialSize: 0);
|
||||
int offset = builder.writeListInt32(<int>[1, 2, 3, 4, 5]);
|
||||
builder.finish(offset);
|
||||
byteList = builder.buffer;
|
||||
}
|
||||
// read and verify
|
||||
BufferContext buf = BufferContext.fromBytes(byteList);
|
||||
List<int> items = const ListReader<int>(Int32Reader()).read(buf, 0);
|
||||
expect(items, hasLength(5));
|
||||
expect(items, orderedEquals(<int>[1, 2, 3, 4, 5]));
|
||||
}
|
||||
|
||||
void test_writeList_ofFloat64() {
|
||||
List<double> values = <double>[-1.234567, 3.4E+9, -5.6E-13, 7.8, 12.13];
|
||||
// write
|
||||
List<int> byteList;
|
||||
{
|
||||
Builder builder = Builder(initialSize: 0);
|
||||
int offset = builder.writeListFloat64(values);
|
||||
builder.finish(offset);
|
||||
byteList = builder.buffer;
|
||||
}
|
||||
|
||||
// read and verify
|
||||
BufferContext buf = BufferContext.fromBytes(byteList);
|
||||
List<double> items = const Float64ListReader().read(buf, 0);
|
||||
|
||||
expect(items, hasLength(values.length));
|
||||
for (int i = 0; i < values.length; i++) {
|
||||
expect(values[i], closeTo(items[i], .001));
|
||||
}
|
||||
}
|
||||
|
||||
void test_writeList_ofFloat32() {
|
||||
List<double> values = [1.0, 2.23, -3.213, 7.8, 12.13];
|
||||
// write
|
||||
List<int> byteList;
|
||||
{
|
||||
Builder builder = Builder(initialSize: 0);
|
||||
int offset = builder.writeListFloat32(values);
|
||||
builder.finish(offset);
|
||||
byteList = builder.buffer;
|
||||
}
|
||||
// read and verify
|
||||
BufferContext buf = BufferContext.fromBytes(byteList);
|
||||
List<double> items = const Float32ListReader().read(buf, 0);
|
||||
expect(items, hasLength(5));
|
||||
for (int i = 0; i < values.length; i++) {
|
||||
expect(values[i], closeTo(items[i], .001));
|
||||
}
|
||||
}
|
||||
|
||||
void test_writeList_ofObjects([Builder? builder]) {
|
||||
List<int> byteList;
|
||||
{
|
||||
builder ??= Builder(initialSize: 0);
|
||||
// write the object #1
|
||||
int object1;
|
||||
{
|
||||
builder.startTable(2);
|
||||
builder.addInt32(0, 10);
|
||||
builder.addInt32(1, 20);
|
||||
object1 = builder.endTable();
|
||||
}
|
||||
// write the object #1
|
||||
int object2;
|
||||
{
|
||||
builder.startTable(2);
|
||||
builder.addInt32(0, 100);
|
||||
builder.addInt32(1, 200);
|
||||
object2 = builder.endTable();
|
||||
}
|
||||
// write the list
|
||||
int offset = builder.writeList([object1, object2]);
|
||||
builder.finish(offset);
|
||||
byteList = builder.buffer;
|
||||
}
|
||||
// read and verify
|
||||
BufferContext buf = BufferContext.fromBytes(byteList);
|
||||
List<TestPointImpl> items =
|
||||
const ListReader<TestPointImpl>(TestPointReader()).read(buf, 0);
|
||||
expect(items, hasLength(2));
|
||||
expect(items[0].x, 10);
|
||||
expect(items[0].y, 20);
|
||||
expect(items[1].x, 100);
|
||||
expect(items[1].y, 200);
|
||||
}
|
||||
|
||||
void test_writeList_ofStrings_asRoot() {
|
||||
List<int> byteList;
|
||||
{
|
||||
Builder builder = Builder(initialSize: 0);
|
||||
int? str1 = builder.writeString('12345');
|
||||
int? str2 = builder.writeString('ABC');
|
||||
int offset = builder.writeList([str1, str2]);
|
||||
builder.finish(offset);
|
||||
byteList = builder.buffer;
|
||||
}
|
||||
// read and verify
|
||||
BufferContext buf = BufferContext.fromBytes(byteList);
|
||||
List<String> items = const ListReader<String>(StringReader()).read(buf, 0);
|
||||
expect(items, hasLength(2));
|
||||
expect(items, contains('12345'));
|
||||
expect(items, contains('ABC'));
|
||||
}
|
||||
|
||||
void test_writeList_ofStrings_inObject([Builder? builder]) {
|
||||
List<int> byteList;
|
||||
{
|
||||
builder ??= Builder(initialSize: 0);
|
||||
int listOffset = builder.writeList(
|
||||
[builder.writeString('12345'), builder.writeString('ABC')]);
|
||||
builder.startTable(1);
|
||||
builder.addOffset(0, listOffset);
|
||||
int offset = builder.endTable();
|
||||
builder.finish(offset);
|
||||
byteList = builder.buffer;
|
||||
}
|
||||
// read and verify
|
||||
BufferContext buf = BufferContext.fromBytes(byteList);
|
||||
StringListWrapperImpl reader = StringListWrapperReader().read(buf, 0);
|
||||
List<String>? items = reader.items;
|
||||
expect(items, hasLength(2));
|
||||
expect(items, contains('12345'));
|
||||
expect(items, contains('ABC'));
|
||||
}
|
||||
|
||||
void test_writeList_ofUint32() {
|
||||
List<int> byteList;
|
||||
{
|
||||
Builder builder = Builder(initialSize: 0);
|
||||
int offset = builder.writeListUint32(<int>[1, 2, 0x9ABCDEF0]);
|
||||
builder.finish(offset);
|
||||
byteList = builder.buffer;
|
||||
}
|
||||
// read and verify
|
||||
BufferContext buf = BufferContext.fromBytes(byteList);
|
||||
List<int> items = const Uint32ListReader().read(buf, 0);
|
||||
expect(items, hasLength(3));
|
||||
expect(items, orderedEquals(<int>[1, 2, 0x9ABCDEF0]));
|
||||
}
|
||||
|
||||
void test_writeList_ofUint16() {
|
||||
List<int> byteList;
|
||||
{
|
||||
Builder builder = Builder(initialSize: 0);
|
||||
int offset = builder.writeListUint16(<int>[1, 2, 60000]);
|
||||
builder.finish(offset);
|
||||
byteList = builder.buffer;
|
||||
}
|
||||
// read and verify
|
||||
BufferContext buf = BufferContext.fromBytes(byteList);
|
||||
List<int> items = const Uint16ListReader().read(buf, 0);
|
||||
expect(items, hasLength(3));
|
||||
expect(items, orderedEquals(<int>[1, 2, 60000]));
|
||||
}
|
||||
|
||||
void test_writeList_ofUint8() {
|
||||
List<int> byteList;
|
||||
{
|
||||
Builder builder = Builder(initialSize: 0);
|
||||
int offset = builder.writeListUint8(<int>[1, 2, 3, 4, 0x9A, 0xFA]);
|
||||
builder.finish(offset);
|
||||
byteList = builder.buffer;
|
||||
}
|
||||
// read and verify
|
||||
BufferContext buf = BufferContext.fromBytes(byteList);
|
||||
const buffOffset = 8; // 32-bit offset to the list, + 32-bit length
|
||||
for (final lazy in [true, false]) {
|
||||
List<int> items = Uint8ListReader(lazy: lazy).read(buf, 0);
|
||||
expect(items, hasLength(6));
|
||||
expect(items, orderedEquals(<int>[1, 2, 3, 4, 0x9A, 0xFA]));
|
||||
|
||||
// overwrite the buffer to verify the laziness
|
||||
buf.buffer.setUint8(buffOffset + 1, 99);
|
||||
expect(items, orderedEquals(<int>[1, lazy ? 99 : 2, 3, 4, 0x9A, 0xFA]));
|
||||
|
||||
// restore the previous value for the next loop
|
||||
buf.buffer.setUint8(buffOffset + 1, 2);
|
||||
}
|
||||
}
|
||||
|
||||
void test_reset() {
|
||||
// We'll run a selection of tests , reusing the builder between them.
|
||||
final testCases = <void Function(Builder?)>[
|
||||
test_monsterBuilder,
|
||||
test_error_addInt32_withoutStartTable,
|
||||
test_table_format,
|
||||
test_table_types,
|
||||
test_writeList_ofObjects,
|
||||
test_writeList_ofStrings_inObject
|
||||
];
|
||||
|
||||
// Execute all test cases in all permutations of their order.
|
||||
// To do that, we generate permutations of test case indexes.
|
||||
final testCasesPermutations =
|
||||
_permutationsOf(List.generate(testCases.length, (index) => index));
|
||||
expect(testCasesPermutations.length, _factorial(testCases.length));
|
||||
|
||||
for (var indexes in testCasesPermutations) {
|
||||
// print the order so failures are reproducible
|
||||
printOnFailure('Running reset() test cases in order: $indexes');
|
||||
|
||||
Builder? builder;
|
||||
for (var index in indexes) {
|
||||
if (builder == null) {
|
||||
// Initial size small enough so at least one test case increases it.
|
||||
// On the other hand, it's large enough so that some test cases don't.
|
||||
builder = Builder(initialSize: 32);
|
||||
} else {
|
||||
builder.reset();
|
||||
}
|
||||
testCases[index](builder);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Generate permutations of the given list
|
||||
List<List<T>> _permutationsOf<T>(List<T> source) {
|
||||
final result = <List<T>>[];
|
||||
|
||||
void permutate(List<T> items, int startAt) {
|
||||
for (var i = startAt; i < items.length; i++) {
|
||||
List<T> permutation = items.toList(growable: false);
|
||||
permutation[i] = items[startAt];
|
||||
permutation[startAt] = items[i];
|
||||
|
||||
// add the current list upon reaching the end
|
||||
if (startAt == items.length - 1) {
|
||||
result.add(items);
|
||||
} else {
|
||||
permutate(permutation, startAt + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
permutate(source, 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
// a very simple implementation of n!
|
||||
int _factorial(int n) {
|
||||
var result = 1;
|
||||
for (var i = 2; i <= n; i++) {
|
||||
result *= i;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@reflectiveTest
|
||||
class ObjectAPITest {
|
||||
void test_tableStat() {
|
||||
final object1 = example.StatT(count: 3, id: "foo", val: 4);
|
||||
final fbb = Builder();
|
||||
fbb.finish(object1.pack(fbb));
|
||||
final object2 = example.Stat(fbb.buffer).unpack();
|
||||
expect(object2.count, object1.count);
|
||||
expect(object2.id, object1.id);
|
||||
expect(object2.val, object1.val);
|
||||
expect(object2.toString(), object1.toString());
|
||||
}
|
||||
|
||||
void test_tableMonster() {
|
||||
final monster = example.MonsterT()
|
||||
..pos = example.Vec3T(
|
||||
x: 1,
|
||||
y: 2,
|
||||
z: 3,
|
||||
test1: 4.0,
|
||||
test2: example.Color.Red,
|
||||
test3: example.TestT(a: 1, b: 2))
|
||||
..mana = 2
|
||||
..name = 'Monstrous'
|
||||
..inventory = [24, 42]
|
||||
..color = example.Color.Green
|
||||
// TODO be smarter for unions and automatically set the `type` field?
|
||||
..testType = example.AnyTypeId.MyGame_Example2_Monster
|
||||
..test = example2.MonsterT()
|
||||
..test4 = [example.TestT(a: 3, b: 4), example.TestT(a: 5, b: 6)]
|
||||
..testarrayofstring = ["foo", "bar"]
|
||||
..testarrayoftables = [example.MonsterT(name: 'Oof')]
|
||||
..enemy = example.MonsterT(name: 'Enemy')
|
||||
..testarrayofbools = [false, true, false]
|
||||
..testf = 42.24
|
||||
..testarrayofsortedstruct = [
|
||||
example.AbilityT(id: 1, distance: 5),
|
||||
example.AbilityT(id: 3, distance: 7)
|
||||
]
|
||||
..vectorOfLongs = [5, 6, 7]
|
||||
..vectorOfDoubles = [8.9, 9.0, 10.1, 11.2]
|
||||
..anyAmbiguousType = example.AnyAmbiguousAliasesTypeId.M2
|
||||
..anyAmbiguous = null
|
||||
..vectorOfEnums = [example.Color.Blue, example.Color.Green]
|
||||
..signedEnum = example.Race.None;
|
||||
|
||||
final fbBuilder = Builder();
|
||||
final offset = monster.pack(fbBuilder);
|
||||
expect(offset, isNonZero);
|
||||
fbBuilder.finish(offset);
|
||||
final data = fbBuilder.buffer;
|
||||
|
||||
// TODO currently broken because of struct builder issue, see #6688
|
||||
// final monster2 = example.Monster(data); // Monster (reader)
|
||||
// expect(
|
||||
// // map Monster => MonsterT, Vec3 => Vec3T, ...
|
||||
// monster2.toString().replaceAllMapped(
|
||||
// RegExp('([a-zA-z0-9]+){'), (match) => match.group(1) + 'T{'),
|
||||
// monster.toString());
|
||||
//
|
||||
// final monster3 = monster2.unpack(); // MonsterT
|
||||
// expect(monster3.toString(), monster.toString());
|
||||
}
|
||||
|
||||
void test_Lists() {
|
||||
// Ensure unpack() reads lists eagerly by reusing the same builder and
|
||||
// overwriting data. Why: because standard reader reads lists lazily...
|
||||
final fbb = Builder();
|
||||
|
||||
final object1 = example.TypeAliasesT(v8: [1, 2, 3], vf64: [5, 6]);
|
||||
fbb.finish(object1.pack(fbb));
|
||||
final object1Read = example.TypeAliases(fbb.buffer).unpack();
|
||||
|
||||
// overwrite the original buffer by writing to the same builder
|
||||
fbb.reset();
|
||||
final object2 = example.TypeAliasesT(v8: [7, 8, 9], vf64: [10, 11]);
|
||||
fbb.finish(object2.pack(fbb));
|
||||
final object2Read = example.TypeAliases(fbb.buffer).unpack();
|
||||
|
||||
// this is fine even with lazy lists:
|
||||
expect(object2.toString(), object2Read.toString());
|
||||
|
||||
// this fails with lazy lists:
|
||||
expect(object1.toString(), object1Read.toString());
|
||||
|
||||
// empty list must be serialized as such (were stored NULL before v2.0)
|
||||
fbb.reset();
|
||||
final object3 = example.TypeAliasesT(v8: [], vf64: null);
|
||||
fbb.finish(object3.pack(fbb));
|
||||
final object3Read = example.TypeAliases(fbb.buffer).unpack();
|
||||
expect(object3.toString(), object3Read.toString());
|
||||
}
|
||||
}
|
||||
|
||||
class StringListWrapperImpl {
|
||||
final BufferContext bp;
|
||||
final int offset;
|
||||
|
||||
StringListWrapperImpl(this.bp, this.offset);
|
||||
|
||||
List<String>? get items => const ListReader<String>(StringReader())
|
||||
.vTableGetNullable(bp, offset, indexToField(0));
|
||||
}
|
||||
|
||||
class StringListWrapperReader extends TableReader<StringListWrapperImpl> {
|
||||
const StringListWrapperReader();
|
||||
|
||||
@override
|
||||
StringListWrapperImpl createObject(BufferContext object, int offset) {
|
||||
return StringListWrapperImpl(object, offset);
|
||||
}
|
||||
}
|
||||
|
||||
class TestPointImpl {
|
||||
final BufferContext bp;
|
||||
final int offset;
|
||||
|
||||
TestPointImpl(this.bp, this.offset);
|
||||
|
||||
int get x => const Int32Reader().vTableGet(bp, offset, indexToField(0), 0);
|
||||
|
||||
int get y => const Int32Reader().vTableGet(bp, offset, indexToField(1), 0);
|
||||
}
|
||||
|
||||
class TestPointReader extends TableReader<TestPointImpl> {
|
||||
const TestPointReader();
|
||||
|
||||
@override
|
||||
TestPointImpl createObject(BufferContext object, int offset) {
|
||||
return TestPointImpl(object, offset);
|
||||
}
|
||||
}
|
||||
|
||||
@reflectiveTest
|
||||
class GeneratorTest {
|
||||
void test_constantEnumValues() async {
|
||||
expect(example.Color.values, same(example.Color.values));
|
||||
expect(example.Race.values, same(example.Race.values));
|
||||
expect(example.AnyTypeId.values, same(example.AnyTypeId.values));
|
||||
expect(example.AnyUniqueAliasesTypeId.values,
|
||||
same(example.AnyUniqueAliasesTypeId.values));
|
||||
expect(example.AnyAmbiguousAliasesTypeId.values,
|
||||
same(example.AnyAmbiguousAliasesTypeId.values));
|
||||
}
|
||||
}
|
||||
|
||||
// See #6869
|
||||
@reflectiveTest
|
||||
class ListOfEnumsTest {
|
||||
void test_listOfEnums() async {
|
||||
var mytable = example3.MyTableObjectBuilder(options: [
|
||||
example3.OptionsEnum.A,
|
||||
example3.OptionsEnum.B,
|
||||
example3.OptionsEnum.C
|
||||
]);
|
||||
var bytes = mytable.toBytes();
|
||||
var mytable_read = example3.MyTable(bytes);
|
||||
expect(mytable_read.options![0].value, example3.OptionsEnum.A.value);
|
||||
expect(mytable_read.options![1].value, example3.OptionsEnum.B.value);
|
||||
expect(mytable_read.options![2].value, example3.OptionsEnum.C.value);
|
||||
}
|
||||
}
|
||||
|
||||
@reflectiveTest
|
||||
class BoolInStructTest {
|
||||
void test_boolInStruct() async {
|
||||
var mystruct = example4.FooObjectBuilder(
|
||||
myFoo: example4.FooPropertiesObjectBuilder(a: true, b: false));
|
||||
var bytes = mystruct.toBytes();
|
||||
var mystruct_read = example4.Foo(bytes);
|
||||
expect(mystruct_read.myFoo!.a, true);
|
||||
expect(mystruct_read.myFoo!.b, false);
|
||||
}
|
||||
}
|
@ -1,597 +0,0 @@
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:flat_buffers/flex_buffers.dart' show Builder;
|
||||
import 'package:test/test.dart';
|
||||
|
||||
void main() {
|
||||
test('build with single value', () {
|
||||
{
|
||||
var flx = Builder();
|
||||
flx.addNull();
|
||||
expect(flx.finish(), [0, 0, 1]);
|
||||
}
|
||||
{
|
||||
var flx = Builder();
|
||||
flx.addBool(true);
|
||||
expect(flx.finish(), [1, 104, 1]);
|
||||
}
|
||||
{
|
||||
var flx = Builder();
|
||||
flx.addBool(false);
|
||||
expect(flx.finish(), [0, 104, 1]);
|
||||
}
|
||||
{
|
||||
var flx = Builder();
|
||||
flx.addInt(1);
|
||||
expect(flx.finish(), [1, 4, 1]);
|
||||
}
|
||||
{
|
||||
var flx = Builder();
|
||||
flx.addInt(230);
|
||||
expect(flx.finish(), [230, 0, 5, 2]);
|
||||
}
|
||||
{
|
||||
var flx = Builder();
|
||||
flx.addInt(1025);
|
||||
expect(flx.finish(), [1, 4, 5, 2]);
|
||||
}
|
||||
{
|
||||
var flx = Builder();
|
||||
flx.addInt(-1025);
|
||||
expect(flx.finish(), [255, 251, 5, 2]);
|
||||
}
|
||||
{
|
||||
var builder = Builder()..addDouble(1.0);
|
||||
expect(builder.finish(), [0, 0, 128, 63, 14, 4]);
|
||||
}
|
||||
{
|
||||
var flx = Builder();
|
||||
flx.addDouble(0.1);
|
||||
expect(flx.finish(), [154, 153, 153, 153, 153, 153, 185, 63, 15, 8]);
|
||||
}
|
||||
{
|
||||
var flx = Builder();
|
||||
flx.addDouble(0.5);
|
||||
expect(flx.finish(), [0, 0, 0, 63, 14, 4]);
|
||||
}
|
||||
{
|
||||
var flx = Builder();
|
||||
flx.addString('Maxim');
|
||||
expect(flx.finish(), [5, 77, 97, 120, 105, 109, 0, 6, 20, 1]);
|
||||
}
|
||||
{
|
||||
var flx = Builder();
|
||||
flx.addString('hello 😱');
|
||||
expect(flx.finish(),
|
||||
[10, 104, 101, 108, 108, 111, 32, 240, 159, 152, 177, 0, 11, 20, 1]);
|
||||
}
|
||||
});
|
||||
|
||||
test('build vector', () {
|
||||
{
|
||||
var flx = Builder()
|
||||
..startVector()
|
||||
..addInt(1)
|
||||
..addInt(2)
|
||||
..end();
|
||||
expect(flx.finish(), [1, 2, 2, 64, 1]);
|
||||
}
|
||||
{
|
||||
var flx = Builder()
|
||||
..startVector()
|
||||
..addInt(-1)
|
||||
..addInt(256)
|
||||
..end();
|
||||
expect(flx.finish(), [255, 255, 0, 1, 4, 65, 1]);
|
||||
}
|
||||
{
|
||||
var flx = Builder()
|
||||
..startVector()
|
||||
..addInt(-45)
|
||||
..addInt(256000)
|
||||
..end();
|
||||
expect(flx.finish(), [211, 255, 255, 255, 0, 232, 3, 0, 8, 66, 1]);
|
||||
}
|
||||
{
|
||||
var flx = Builder()
|
||||
..startVector()
|
||||
..addDouble(1.1)
|
||||
..addDouble(-256)
|
||||
..end();
|
||||
expect(flx.finish(), [
|
||||
154,
|
||||
153,
|
||||
153,
|
||||
153,
|
||||
153,
|
||||
153,
|
||||
241,
|
||||
63,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
112,
|
||||
192,
|
||||
16,
|
||||
75,
|
||||
1
|
||||
]);
|
||||
}
|
||||
{
|
||||
var flx = Builder()
|
||||
..startVector()
|
||||
..addInt(1)
|
||||
..addInt(2)
|
||||
..addInt(4)
|
||||
..end();
|
||||
expect(flx.finish(), [1, 2, 4, 3, 76, 1]);
|
||||
}
|
||||
{
|
||||
var flx = Builder()
|
||||
..startVector()
|
||||
..addInt(-1)
|
||||
..addInt(256)
|
||||
..addInt(4)
|
||||
..end();
|
||||
expect(flx.finish(), [255, 255, 0, 1, 4, 0, 6, 77, 1]);
|
||||
}
|
||||
{
|
||||
var flx = Builder()
|
||||
..startVector()
|
||||
..startVector()
|
||||
..addInt(61)
|
||||
..end()
|
||||
..addInt(64)
|
||||
..end();
|
||||
expect(flx.finish(), [1, 61, 2, 2, 64, 44, 4, 4, 40, 1]);
|
||||
}
|
||||
{
|
||||
var flx = Builder()
|
||||
..startVector()
|
||||
..addString('foo')
|
||||
..addString('bar')
|
||||
..addString('baz')
|
||||
..end();
|
||||
expect(flx.finish(), [
|
||||
3,
|
||||
102,
|
||||
111,
|
||||
111,
|
||||
0,
|
||||
3,
|
||||
98,
|
||||
97,
|
||||
114,
|
||||
0,
|
||||
3,
|
||||
98,
|
||||
97,
|
||||
122,
|
||||
0,
|
||||
3,
|
||||
15,
|
||||
11,
|
||||
7,
|
||||
3,
|
||||
60,
|
||||
1
|
||||
]);
|
||||
}
|
||||
{
|
||||
var flx = Builder()
|
||||
..startVector()
|
||||
..addString('foo')
|
||||
..addString('bar')
|
||||
..addString('baz')
|
||||
..addString('foo')
|
||||
..addString('bar')
|
||||
..addString('baz')
|
||||
..end();
|
||||
expect(flx.finish(), [
|
||||
3,
|
||||
102,
|
||||
111,
|
||||
111,
|
||||
0,
|
||||
3,
|
||||
98,
|
||||
97,
|
||||
114,
|
||||
0,
|
||||
3,
|
||||
98,
|
||||
97,
|
||||
122,
|
||||
0,
|
||||
6,
|
||||
15,
|
||||
11,
|
||||
7,
|
||||
18,
|
||||
14,
|
||||
10,
|
||||
6,
|
||||
60,
|
||||
1
|
||||
]);
|
||||
}
|
||||
{
|
||||
var flx = Builder()
|
||||
..startVector()
|
||||
..addBool(true)
|
||||
..addBool(false)
|
||||
..addBool(true)
|
||||
..end();
|
||||
expect(flx.finish(), [3, 1, 0, 1, 3, 144, 1]);
|
||||
}
|
||||
{
|
||||
var flx = Builder()
|
||||
..startVector()
|
||||
..addString('foo')
|
||||
..addInt(1)
|
||||
..addInt(-5)
|
||||
..addDouble(1.3)
|
||||
..addBool(true)
|
||||
..end();
|
||||
expect(flx.finish(), [
|
||||
3,
|
||||
102,
|
||||
111,
|
||||
111,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
5,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
15,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
251,
|
||||
255,
|
||||
255,
|
||||
255,
|
||||
255,
|
||||
255,
|
||||
255,
|
||||
255,
|
||||
205,
|
||||
204,
|
||||
204,
|
||||
204,
|
||||
204,
|
||||
204,
|
||||
244,
|
||||
63,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
20,
|
||||
4,
|
||||
4,
|
||||
15,
|
||||
104,
|
||||
45,
|
||||
43,
|
||||
1
|
||||
]);
|
||||
}
|
||||
});
|
||||
|
||||
test('build map', () {
|
||||
{
|
||||
var flx = Builder()
|
||||
..startMap()
|
||||
..addKey('a')
|
||||
..addInt(12)
|
||||
..end();
|
||||
expect(flx.finish(), [97, 0, 1, 3, 1, 1, 1, 12, 4, 2, 36, 1]);
|
||||
}
|
||||
{
|
||||
var flx = Builder()
|
||||
..startMap()
|
||||
..addKey('a')
|
||||
..addInt(12)
|
||||
..addKey('')
|
||||
..addInt(45)
|
||||
..end();
|
||||
expect(
|
||||
flx.finish(), [97, 0, 0, 2, 2, 5, 2, 1, 2, 45, 12, 4, 4, 4, 36, 1]);
|
||||
}
|
||||
{
|
||||
var flx = Builder()
|
||||
..startVector()
|
||||
..startMap()
|
||||
..addKey('something')
|
||||
..addInt(12)
|
||||
..end()
|
||||
..startMap()
|
||||
..addKey('something')
|
||||
..addInt(45)
|
||||
..end()
|
||||
..end();
|
||||
expect(flx.finish(), [
|
||||
115,
|
||||
111,
|
||||
109,
|
||||
101,
|
||||
116,
|
||||
104,
|
||||
105,
|
||||
110,
|
||||
103,
|
||||
0,
|
||||
1,
|
||||
11,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
12,
|
||||
4,
|
||||
6,
|
||||
1,
|
||||
1,
|
||||
45,
|
||||
4,
|
||||
2,
|
||||
8,
|
||||
4,
|
||||
36,
|
||||
36,
|
||||
4,
|
||||
40,
|
||||
1
|
||||
]);
|
||||
}
|
||||
});
|
||||
|
||||
test('build blob', () {
|
||||
{
|
||||
var flx = Builder()..addBlob(Uint8List.fromList([1, 2, 3]).buffer);
|
||||
expect(flx.finish(), [3, 1, 2, 3, 3, 100, 1]);
|
||||
}
|
||||
});
|
||||
|
||||
test('build from object', () {
|
||||
expect(
|
||||
Builder.buildFromObject(Uint8List.fromList([1, 2, 3]).buffer)
|
||||
.asUint8List(),
|
||||
[3, 1, 2, 3, 3, 100, 1]);
|
||||
expect(Builder.buildFromObject(null).asUint8List(), [0, 0, 1]);
|
||||
expect(Builder.buildFromObject(true).asUint8List(), [1, 104, 1]);
|
||||
expect(Builder.buildFromObject(false).asUint8List(), [0, 104, 1]);
|
||||
expect(Builder.buildFromObject(25).asUint8List(), [25, 4, 1]);
|
||||
expect(Builder.buildFromObject(-250).asUint8List(), [6, 255, 5, 2]);
|
||||
expect(
|
||||
Builder.buildFromObject(-2.50).asUint8List(), [0, 0, 32, 192, 14, 4]);
|
||||
expect(Builder.buildFromObject('Maxim').asUint8List(),
|
||||
[5, 77, 97, 120, 105, 109, 0, 6, 20, 1]);
|
||||
expect(
|
||||
Builder.buildFromObject([1, 3.3, 'max', true, null, false])
|
||||
.asUint8List(),
|
||||
[
|
||||
3,
|
||||
109,
|
||||
97,
|
||||
120,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
6,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
102,
|
||||
102,
|
||||
102,
|
||||
102,
|
||||
102,
|
||||
102,
|
||||
10,
|
||||
64,
|
||||
31,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
4,
|
||||
15,
|
||||
20,
|
||||
104,
|
||||
0,
|
||||
104,
|
||||
54,
|
||||
43,
|
||||
1
|
||||
]);
|
||||
expect(
|
||||
Builder.buildFromObject([
|
||||
{'something': 12},
|
||||
{'something': 45}
|
||||
]).asUint8List(),
|
||||
[
|
||||
115,
|
||||
111,
|
||||
109,
|
||||
101,
|
||||
116,
|
||||
104,
|
||||
105,
|
||||
110,
|
||||
103,
|
||||
0,
|
||||
1,
|
||||
11,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
12,
|
||||
4,
|
||||
6,
|
||||
1,
|
||||
1,
|
||||
45,
|
||||
4,
|
||||
2,
|
||||
8,
|
||||
4,
|
||||
36,
|
||||
36,
|
||||
4,
|
||||
40,
|
||||
1
|
||||
]);
|
||||
});
|
||||
|
||||
test('add double indirectly', () {
|
||||
var flx = Builder()..addDoubleIndirectly(0.1);
|
||||
expect(flx.finish(), [154, 153, 153, 153, 153, 153, 185, 63, 8, 35, 1]);
|
||||
});
|
||||
|
||||
test('add double indirectly to vector with cache', () {
|
||||
var flx = Builder()
|
||||
..startVector()
|
||||
..addDoubleIndirectly(0.1, cache: true)
|
||||
..addDoubleIndirectly(0.1, cache: true)
|
||||
..addDoubleIndirectly(0.1, cache: true)
|
||||
..addDoubleIndirectly(0.1, cache: true)
|
||||
..end();
|
||||
expect(flx.finish(), [
|
||||
154,
|
||||
153,
|
||||
153,
|
||||
153,
|
||||
153,
|
||||
153,
|
||||
185,
|
||||
63,
|
||||
4,
|
||||
9,
|
||||
10,
|
||||
11,
|
||||
12,
|
||||
35,
|
||||
35,
|
||||
35,
|
||||
35,
|
||||
8,
|
||||
40,
|
||||
1
|
||||
]);
|
||||
});
|
||||
|
||||
test('add int indirectly', () {
|
||||
var flx = Builder()..addIntIndirectly(2345234523452345);
|
||||
expect(flx.finish(), [185, 115, 175, 118, 250, 84, 8, 0, 8, 27, 1]);
|
||||
});
|
||||
|
||||
test('add int indirectly to vector with cache', () {
|
||||
var flx = Builder()
|
||||
..startVector()
|
||||
..addIntIndirectly(2345234523452345, cache: true)
|
||||
..addIntIndirectly(2345234523452345, cache: true)
|
||||
..addIntIndirectly(2345234523452345, cache: true)
|
||||
..addIntIndirectly(2345234523452345, cache: true)
|
||||
..end();
|
||||
expect(flx.finish(), [
|
||||
185,
|
||||
115,
|
||||
175,
|
||||
118,
|
||||
250,
|
||||
84,
|
||||
8,
|
||||
0,
|
||||
4,
|
||||
9,
|
||||
10,
|
||||
11,
|
||||
12,
|
||||
27,
|
||||
27,
|
||||
27,
|
||||
27,
|
||||
8,
|
||||
40,
|
||||
1
|
||||
]);
|
||||
});
|
||||
|
||||
test('snapshot', () {
|
||||
var flx = Builder();
|
||||
flx.startVector();
|
||||
flx.addInt(12);
|
||||
expect(flx.snapshot().asUint8List(), [1, 12, 1, 44, 1]);
|
||||
flx.addInt(24);
|
||||
expect(flx.snapshot().asUint8List(), [12, 24, 2, 64, 1]);
|
||||
flx.addInt(45);
|
||||
expect(flx.snapshot().asUint8List(), [12, 24, 45, 3, 76, 1]);
|
||||
});
|
||||
}
|
@ -1,991 +0,0 @@
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:flat_buffers/flex_buffers.dart' show Reference, Builder;
|
||||
import 'package:test/test.dart';
|
||||
|
||||
void main() {
|
||||
test('is null', () {
|
||||
expect(Reference.fromBuffer(b([0, 0, 1])).isNull, isTrue);
|
||||
});
|
||||
|
||||
test('bool value', () {
|
||||
expect(Reference.fromBuffer(b([1, 104, 1])).boolValue, isTrue);
|
||||
expect(Reference.fromBuffer(b([0, 104, 1])).boolValue, isFalse);
|
||||
});
|
||||
test('int value', () {
|
||||
expect(Reference.fromBuffer(b([25, 4, 1])).intValue, 25);
|
||||
expect(Reference.fromBuffer(b([231, 4, 1])).intValue, -25);
|
||||
expect(Reference.fromBuffer(b([230, 8, 1])).intValue, 230);
|
||||
expect(Reference.fromBuffer(b([230, 0, 5, 2])).intValue, 230);
|
||||
expect(Reference.fromBuffer(b([1, 4, 5, 2])).intValue, 1025);
|
||||
expect(Reference.fromBuffer(b([255, 251, 5, 2])).intValue, -1025);
|
||||
expect(Reference.fromBuffer(b([1, 4, 9, 2])).intValue, 1025);
|
||||
expect(Reference.fromBuffer(b([255, 255, 255, 127, 6, 4])).intValue,
|
||||
2147483647);
|
||||
expect(Reference.fromBuffer(b([0, 0, 0, 128, 6, 4])).intValue, -2147483648);
|
||||
expect(
|
||||
Reference.fromBuffer(b([255, 255, 255, 255, 0, 0, 0, 0, 7, 8]))
|
||||
.intValue,
|
||||
4294967295);
|
||||
expect(
|
||||
Reference.fromBuffer(b([255, 255, 255, 255, 255, 255, 255, 127, 7, 8]))
|
||||
.intValue,
|
||||
9223372036854775807);
|
||||
expect(Reference.fromBuffer(b([0, 0, 0, 0, 0, 0, 0, 128, 7, 8])).intValue,
|
||||
-9223372036854775808);
|
||||
// Dart does not really support UInt64
|
||||
// expect(FlxValue.fromBuffer(b([255, 255, 255, 255, 255, 255, 255, 255, 11, 8])).intValue, 18446744073709551615);
|
||||
});
|
||||
test('double value', () {
|
||||
expect(Reference.fromBuffer(b([0, 0, 128, 63, 14, 4])).doubleValue, 1.0);
|
||||
expect(Reference.fromBuffer(b([0, 0, 144, 64, 14, 4])).doubleValue, 4.5);
|
||||
expect(Reference.fromBuffer(b([205, 204, 204, 61, 14, 4])).doubleValue,
|
||||
closeTo(.1, .001));
|
||||
expect(
|
||||
Reference.fromBuffer(b([154, 153, 153, 153, 153, 153, 185, 63, 15, 8]))
|
||||
.doubleValue,
|
||||
.1);
|
||||
});
|
||||
test('num value', () {
|
||||
expect(Reference.fromBuffer(b([0, 0, 144, 64, 14, 4])).numValue, 4.5);
|
||||
expect(Reference.fromBuffer(b([205, 204, 204, 61, 14, 4])).numValue,
|
||||
closeTo(.1, .001));
|
||||
expect(
|
||||
Reference.fromBuffer(b([154, 153, 153, 153, 153, 153, 185, 63, 15, 8]))
|
||||
.numValue,
|
||||
.1);
|
||||
expect(Reference.fromBuffer(b([255, 251, 5, 2])).numValue, -1025);
|
||||
});
|
||||
test('string value', () {
|
||||
expect(
|
||||
Reference.fromBuffer(b([5, 77, 97, 120, 105, 109, 0, 6, 20, 1]))
|
||||
.stringValue,
|
||||
'Maxim');
|
||||
expect(
|
||||
Reference.fromBuffer(b([
|
||||
10,
|
||||
104,
|
||||
101,
|
||||
108,
|
||||
108,
|
||||
111,
|
||||
32,
|
||||
240,
|
||||
159,
|
||||
152,
|
||||
177,
|
||||
0,
|
||||
11,
|
||||
20,
|
||||
1
|
||||
])).stringValue,
|
||||
'hello 😱');
|
||||
});
|
||||
test('blob value', () {
|
||||
expect(
|
||||
Reference.fromBuffer(b([3, 1, 2, 3, 3, 100, 1])).blobValue, [1, 2, 3]);
|
||||
});
|
||||
test('bool vector', () {
|
||||
var flx = Reference.fromBuffer(b([3, 1, 0, 1, 3, 144, 1]));
|
||||
expect(flx[0].boolValue, true);
|
||||
expect(flx[1].boolValue, false);
|
||||
expect(flx[2].boolValue, true);
|
||||
});
|
||||
test('number vector', () {
|
||||
testNumbers([3, 1, 2, 3, 3, 44, 1], [1, 2, 3]);
|
||||
testNumbers([3, 255, 2, 3, 3, 44, 1], [-1, 2, 3]);
|
||||
testNumbers([3, 0, 1, 0, 43, 2, 3, 0, 6, 45, 1], [1, 555, 3]);
|
||||
testNumbers([3, 0, 0, 0, 1, 0, 0, 0, 204, 216, 0, 0, 3, 0, 0, 0, 12, 46, 1],
|
||||
[1, 55500, 3]);
|
||||
testNumbers([
|
||||
3,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
172,
|
||||
128,
|
||||
94,
|
||||
239,
|
||||
12,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
3,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
24,
|
||||
47,
|
||||
1
|
||||
], [
|
||||
1,
|
||||
55555555500,
|
||||
3
|
||||
]);
|
||||
testNumbers(
|
||||
[3, 0, 0, 0, 0, 0, 192, 63, 0, 0, 32, 64, 0, 0, 96, 64, 12, 54, 1],
|
||||
[1.5, 2.5, 3.5]);
|
||||
testNumbers([
|
||||
3,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
154,
|
||||
153,
|
||||
153,
|
||||
153,
|
||||
153,
|
||||
153,
|
||||
241,
|
||||
63,
|
||||
154,
|
||||
153,
|
||||
153,
|
||||
153,
|
||||
153,
|
||||
153,
|
||||
1,
|
||||
64,
|
||||
102,
|
||||
102,
|
||||
102,
|
||||
102,
|
||||
102,
|
||||
102,
|
||||
10,
|
||||
64,
|
||||
24,
|
||||
55,
|
||||
1
|
||||
], [
|
||||
1.1,
|
||||
2.2,
|
||||
3.3
|
||||
]);
|
||||
});
|
||||
test('number vector, fixed type', () {
|
||||
testNumbers([1, 2, 2, 64, 1], [1, 2]);
|
||||
testNumbers([255, 255, 0, 1, 4, 65, 1], [-1, 256]);
|
||||
testNumbers([211, 255, 255, 255, 0, 232, 3, 0, 8, 66, 1], [-45, 256000]);
|
||||
testNumbers([
|
||||
211,
|
||||
255,
|
||||
255,
|
||||
255,
|
||||
255,
|
||||
255,
|
||||
255,
|
||||
255,
|
||||
255,
|
||||
255,
|
||||
255,
|
||||
255,
|
||||
255,
|
||||
255,
|
||||
255,
|
||||
127,
|
||||
16,
|
||||
67,
|
||||
1
|
||||
], [
|
||||
-45,
|
||||
9223372036854775807
|
||||
]);
|
||||
|
||||
testNumbers([1, 2, 2, 68, 1], [1, 2]);
|
||||
testNumbers([1, 0, 0, 1, 4, 69, 1], [1, 256]);
|
||||
testNumbers([45, 0, 0, 0, 0, 232, 3, 0, 8, 70, 1], [45, 256000]);
|
||||
|
||||
testNumbers([205, 204, 140, 63, 0, 0, 0, 192, 8, 74, 1], [1.1, -2]);
|
||||
testNumbers([
|
||||
154,
|
||||
153,
|
||||
153,
|
||||
153,
|
||||
153,
|
||||
153,
|
||||
241,
|
||||
63,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
112,
|
||||
192,
|
||||
16,
|
||||
75,
|
||||
1
|
||||
], [
|
||||
1.1,
|
||||
-256
|
||||
]);
|
||||
|
||||
testNumbers([211, 255, 255, 255, 0, 232, 3, 0, 4, 0, 0, 0, 12, 78, 1],
|
||||
[-45, 256000, 4]);
|
||||
|
||||
testNumbers([
|
||||
211,
|
||||
255,
|
||||
255,
|
||||
255,
|
||||
255,
|
||||
255,
|
||||
255,
|
||||
255,
|
||||
255,
|
||||
255,
|
||||
255,
|
||||
255,
|
||||
255,
|
||||
255,
|
||||
255,
|
||||
127,
|
||||
4,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
9,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
32,
|
||||
91,
|
||||
1
|
||||
], [
|
||||
-45,
|
||||
9223372036854775807,
|
||||
4,
|
||||
9
|
||||
]);
|
||||
|
||||
testNumbers([
|
||||
45,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
255,
|
||||
255,
|
||||
255,
|
||||
255,
|
||||
255,
|
||||
255,
|
||||
255,
|
||||
127,
|
||||
4,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
9,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
32,
|
||||
95,
|
||||
1
|
||||
], [
|
||||
45,
|
||||
9223372036854775807,
|
||||
4,
|
||||
9
|
||||
]);
|
||||
|
||||
testNumbers([
|
||||
154,
|
||||
153,
|
||||
153,
|
||||
153,
|
||||
153,
|
||||
153,
|
||||
241,
|
||||
63,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
112,
|
||||
64,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
16,
|
||||
64,
|
||||
24,
|
||||
87,
|
||||
1
|
||||
], [
|
||||
1.1,
|
||||
256,
|
||||
4
|
||||
]);
|
||||
|
||||
testNumbers([
|
||||
154,
|
||||
153,
|
||||
153,
|
||||
153,
|
||||
153,
|
||||
153,
|
||||
241,
|
||||
63,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
112,
|
||||
64,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
16,
|
||||
64,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
34,
|
||||
64,
|
||||
32,
|
||||
99,
|
||||
1
|
||||
], [
|
||||
1.1,
|
||||
256,
|
||||
4,
|
||||
9
|
||||
]);
|
||||
});
|
||||
test('string vector', () {
|
||||
testStrings([
|
||||
3,
|
||||
102,
|
||||
111,
|
||||
111,
|
||||
0,
|
||||
3,
|
||||
98,
|
||||
97,
|
||||
114,
|
||||
0,
|
||||
3,
|
||||
98,
|
||||
97,
|
||||
122,
|
||||
0,
|
||||
3,
|
||||
15,
|
||||
11,
|
||||
7,
|
||||
3,
|
||||
60,
|
||||
1
|
||||
], [
|
||||
'foo',
|
||||
'bar',
|
||||
'baz'
|
||||
]);
|
||||
testStrings([
|
||||
3,
|
||||
102,
|
||||
111,
|
||||
111,
|
||||
0,
|
||||
3,
|
||||
98,
|
||||
97,
|
||||
114,
|
||||
0,
|
||||
3,
|
||||
98,
|
||||
97,
|
||||
122,
|
||||
0,
|
||||
6,
|
||||
15,
|
||||
11,
|
||||
7,
|
||||
18,
|
||||
14,
|
||||
10,
|
||||
6,
|
||||
60,
|
||||
1
|
||||
], [
|
||||
'foo',
|
||||
'bar',
|
||||
'baz',
|
||||
'foo',
|
||||
'bar',
|
||||
'baz'
|
||||
]);
|
||||
});
|
||||
test('mixed vector', () {
|
||||
var flx = Reference.fromBuffer(b([
|
||||
3,
|
||||
102,
|
||||
111,
|
||||
111,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
5,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
15,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
251,
|
||||
255,
|
||||
255,
|
||||
255,
|
||||
255,
|
||||
255,
|
||||
255,
|
||||
255,
|
||||
205,
|
||||
204,
|
||||
204,
|
||||
204,
|
||||
204,
|
||||
204,
|
||||
244,
|
||||
63,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
20,
|
||||
4,
|
||||
4,
|
||||
15,
|
||||
104,
|
||||
45,
|
||||
43,
|
||||
1
|
||||
]));
|
||||
expect(flx.length, 5);
|
||||
expect(flx[0].stringValue, 'foo');
|
||||
expect(flx[1].numValue, 1);
|
||||
expect(flx[2].numValue, -5);
|
||||
expect(flx[3].numValue, 1.3);
|
||||
expect(flx[4].boolValue, true);
|
||||
});
|
||||
|
||||
test('single value map', () {
|
||||
var flx = Reference.fromBuffer(b([97, 0, 1, 3, 1, 1, 1, 12, 4, 2, 36, 1]));
|
||||
expect(flx.length, 1);
|
||||
expect(flx['a'].numValue, 12);
|
||||
});
|
||||
test('two value map', () {
|
||||
var flx = Reference.fromBuffer(
|
||||
b([0, 97, 0, 2, 4, 4, 2, 1, 2, 45, 12, 4, 4, 4, 36, 1]));
|
||||
expect(flx.length, 2);
|
||||
expect(flx['a'].numValue, 12);
|
||||
expect(flx[''].numValue, 45);
|
||||
});
|
||||
test('complex map', () {
|
||||
var flx = complexMap();
|
||||
expect(flx.length, 5);
|
||||
expect(flx['age'].numValue, 35);
|
||||
expect(flx['weight'].numValue, 72.5);
|
||||
expect(flx['name'].stringValue, 'Maxim');
|
||||
|
||||
expect(flx['flags'].length, 4);
|
||||
expect(flx['flags'][0].boolValue, true);
|
||||
expect(flx['flags'][1].boolValue, false);
|
||||
expect(flx['flags'][2].boolValue, true);
|
||||
expect(flx['flags'][3].boolValue, true);
|
||||
|
||||
expect(flx['address'].length, 3);
|
||||
expect(flx['address']['city'].stringValue, 'Bla');
|
||||
expect(flx['address']['zip'].stringValue, '12345');
|
||||
expect(flx['address']['countryCode'].stringValue, 'XX');
|
||||
|
||||
expect(
|
||||
() => flx['address']['country'].stringValue,
|
||||
throwsA(predicate((dynamic e) =>
|
||||
e is ArgumentError &&
|
||||
e.message ==
|
||||
'Key: [country] is not applicable on: //address of: ValueType.Map')));
|
||||
expect(
|
||||
() => flx['address']['countryCode'][0],
|
||||
throwsA(predicate((dynamic e) =>
|
||||
e is ArgumentError &&
|
||||
e.message ==
|
||||
'Key: [0] is not applicable on: //address/countryCode of: ValueType.String')));
|
||||
expect(
|
||||
() => flx[1],
|
||||
throwsA(predicate((dynamic e) =>
|
||||
e is ArgumentError &&
|
||||
e.message ==
|
||||
'Key: [1] is not applicable on: / of: ValueType.Map')));
|
||||
expect(
|
||||
() => flx['flags'][4],
|
||||
throwsA(predicate((dynamic e) =>
|
||||
e is ArgumentError &&
|
||||
e.message ==
|
||||
'Key: [4] is not applicable on: //flags of: ValueType.VectorBool length: 4')));
|
||||
expect(
|
||||
() => flx['flags'][-1],
|
||||
throwsA(predicate((dynamic e) =>
|
||||
e is ArgumentError &&
|
||||
e.message ==
|
||||
'Key: [-1] is not applicable on: //flags of: ValueType.VectorBool length: 4')));
|
||||
});
|
||||
test('complex map to json', () {
|
||||
var flx = complexMap();
|
||||
expect(flx.json,
|
||||
'{"address":{"city":"Bla","countryCode":"XX","zip":"12345"},"age":35,"flags":[true,false,true,true],"name":"Maxim","weight":72.5}');
|
||||
});
|
||||
|
||||
test('complex map iterators', () {
|
||||
var flx = complexMap();
|
||||
expect(flx.mapKeyIterable.map((e) => e).toList(),
|
||||
['address', 'age', 'flags', 'name', 'weight']);
|
||||
expect(flx.mapValueIterable.map((e) => e.json).toList(), [
|
||||
flx['address'].json,
|
||||
flx['age'].json,
|
||||
flx['flags'].json,
|
||||
flx['name'].json,
|
||||
flx['weight'].json
|
||||
]);
|
||||
expect(flx['flags'].vectorIterable.map((e) => e.boolValue).toList(),
|
||||
[true, false, true, true]);
|
||||
});
|
||||
|
||||
test('bug where offest were stored as int instead of uint', () {
|
||||
const data = [
|
||||
99,
|
||||
104,
|
||||
97,
|
||||
110,
|
||||
110,
|
||||
101,
|
||||
108,
|
||||
115,
|
||||
95,
|
||||
105,
|
||||
110,
|
||||
0,
|
||||
100,
|
||||
105,
|
||||
108,
|
||||
97,
|
||||
116,
|
||||
105,
|
||||
111,
|
||||
110,
|
||||
95,
|
||||
104,
|
||||
101,
|
||||
105,
|
||||
103,
|
||||
104,
|
||||
116,
|
||||
95,
|
||||
102,
|
||||
97,
|
||||
99,
|
||||
116,
|
||||
111,
|
||||
114,
|
||||
0,
|
||||
100,
|
||||
105,
|
||||
108,
|
||||
97,
|
||||
116,
|
||||
105,
|
||||
111,
|
||||
110,
|
||||
95,
|
||||
119,
|
||||
105,
|
||||
100,
|
||||
116,
|
||||
104,
|
||||
95,
|
||||
102,
|
||||
97,
|
||||
99,
|
||||
116,
|
||||
111,
|
||||
114,
|
||||
0,
|
||||
102,
|
||||
117,
|
||||
115,
|
||||
101,
|
||||
100,
|
||||
95,
|
||||
97,
|
||||
99,
|
||||
116,
|
||||
105,
|
||||
118,
|
||||
97,
|
||||
116,
|
||||
105,
|
||||
111,
|
||||
110,
|
||||
95,
|
||||
102,
|
||||
117,
|
||||
110,
|
||||
99,
|
||||
116,
|
||||
105,
|
||||
111,
|
||||
110,
|
||||
0,
|
||||
112,
|
||||
97,
|
||||
100,
|
||||
95,
|
||||
118,
|
||||
97,
|
||||
108,
|
||||
117,
|
||||
101,
|
||||
115,
|
||||
0,
|
||||
112,
|
||||
97,
|
||||
100,
|
||||
100,
|
||||
105,
|
||||
110,
|
||||
103,
|
||||
0,
|
||||
115,
|
||||
116,
|
||||
114,
|
||||
105,
|
||||
100,
|
||||
101,
|
||||
95,
|
||||
104,
|
||||
101,
|
||||
105,
|
||||
103,
|
||||
104,
|
||||
116,
|
||||
0,
|
||||
115,
|
||||
116,
|
||||
114,
|
||||
105,
|
||||
100,
|
||||
101,
|
||||
95,
|
||||
119,
|
||||
105,
|
||||
100,
|
||||
116,
|
||||
104,
|
||||
0,
|
||||
8,
|
||||
130,
|
||||
119,
|
||||
97,
|
||||
76,
|
||||
51,
|
||||
41,
|
||||
34,
|
||||
21,
|
||||
8,
|
||||
1,
|
||||
8,
|
||||
64,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
0,
|
||||
1,
|
||||
1,
|
||||
4,
|
||||
4,
|
||||
4,
|
||||
4,
|
||||
4,
|
||||
4,
|
||||
4,
|
||||
4,
|
||||
16,
|
||||
36,
|
||||
1
|
||||
];
|
||||
var flx = Reference.fromBuffer(b(data));
|
||||
expect(flx.json,
|
||||
'{"channels_in":64,"dilation_height_factor":1,"dilation_width_factor":1,"fused_activation_function":1,"pad_values":1,"padding":0,"stride_height":1,"stride_width":1}');
|
||||
const object = {
|
||||
"channels_in": 64,
|
||||
"dilation_height_factor": 1,
|
||||
"dilation_width_factor": 1,
|
||||
"fused_activation_function": 1,
|
||||
"pad_values": 1,
|
||||
"padding": 0,
|
||||
"stride_height": 1,
|
||||
"stride_width": 1
|
||||
};
|
||||
var data1 = Builder.buildFromObject(object).asUint8List();
|
||||
expect(data1.length, data.length);
|
||||
var flx1 = Reference.fromBuffer(b(data1));
|
||||
expect(flx1.json,
|
||||
'{"channels_in":64,"dilation_height_factor":1,"dilation_width_factor":1,"fused_activation_function":1,"pad_values":1,"padding":0,"stride_height":1,"stride_width":1}');
|
||||
});
|
||||
}
|
||||
|
||||
ByteBuffer b(List<int> values) {
|
||||
var data = Uint8List.fromList(values);
|
||||
return data.buffer;
|
||||
}
|
||||
|
||||
void testNumbers(List<int> buffer, List<num> numbers) {
|
||||
var flx = Reference.fromBuffer(b(buffer));
|
||||
expect(flx.length, numbers.length);
|
||||
for (var i = 0; i < flx.length; i++) {
|
||||
expect(flx[i].numValue, closeTo(numbers[i], 0.001));
|
||||
}
|
||||
}
|
||||
|
||||
void testStrings(List<int> buffer, List<String> numbers) {
|
||||
var flx = Reference.fromBuffer(b(buffer));
|
||||
expect(flx.length, numbers.length);
|
||||
for (var i = 0; i < flx.length; i++) {
|
||||
expect(flx[i].stringValue, numbers[i]);
|
||||
}
|
||||
}
|
||||
|
||||
Reference complexMap() {
|
||||
// {
|
||||
// "age": 35,
|
||||
// "flags": [True, False, True, True],
|
||||
// "weight": 72.5,
|
||||
// "name": "Maxim",
|
||||
// "address": {
|
||||
// "city": "Bla",
|
||||
// "zip": "12345",
|
||||
// "countryCode": "XX",
|
||||
// }
|
||||
// }
|
||||
return Reference.fromBuffer(b([
|
||||
97,
|
||||
100,
|
||||
100,
|
||||
114,
|
||||
101,
|
||||
115,
|
||||
115,
|
||||
0,
|
||||
99,
|
||||
105,
|
||||
116,
|
||||
121,
|
||||
0,
|
||||
3,
|
||||
66,
|
||||
108,
|
||||
97,
|
||||
0,
|
||||
99,
|
||||
111,
|
||||
117,
|
||||
110,
|
||||
116,
|
||||
114,
|
||||
121,
|
||||
67,
|
||||
111,
|
||||
100,
|
||||
101,
|
||||
0,
|
||||
2,
|
||||
88,
|
||||
88,
|
||||
0,
|
||||
122,
|
||||
105,
|
||||
112,
|
||||
0,
|
||||
5,
|
||||
49,
|
||||
50,
|
||||
51,
|
||||
52,
|
||||
53,
|
||||
0,
|
||||
3,
|
||||
38,
|
||||
29,
|
||||
14,
|
||||
3,
|
||||
1,
|
||||
3,
|
||||
38,
|
||||
22,
|
||||
15,
|
||||
20,
|
||||
20,
|
||||
20,
|
||||
97,
|
||||
103,
|
||||
101,
|
||||
0,
|
||||
102,
|
||||
108,
|
||||
97,
|
||||
103,
|
||||
115,
|
||||
0,
|
||||
4,
|
||||
1,
|
||||
0,
|
||||
1,
|
||||
1,
|
||||
110,
|
||||
97,
|
||||
109,
|
||||
101,
|
||||
0,
|
||||
5,
|
||||
77,
|
||||
97,
|
||||
120,
|
||||
105,
|
||||
109,
|
||||
0,
|
||||
119,
|
||||
101,
|
||||
105,
|
||||
103,
|
||||
104,
|
||||
116,
|
||||
0,
|
||||
5,
|
||||
93,
|
||||
36,
|
||||
33,
|
||||
23,
|
||||
12,
|
||||
0,
|
||||
0,
|
||||
7,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
5,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
60,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
35,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
51,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
45,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
145,
|
||||
66,
|
||||
36,
|
||||
4,
|
||||
144,
|
||||
20,
|
||||
14,
|
||||
25,
|
||||
38,
|
||||
1
|
||||
]));
|
||||
}
|
@ -1,184 +0,0 @@
|
||||
import 'package:flat_buffers/src/types.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
void main() {
|
||||
test('is inline', () {
|
||||
expect(ValueTypeUtils.isInline(ValueType.Bool), isTrue);
|
||||
expect(ValueTypeUtils.isInline(ValueType.Int), isTrue);
|
||||
expect(ValueTypeUtils.isInline(ValueType.UInt), isTrue);
|
||||
expect(ValueTypeUtils.isInline(ValueType.Float), isTrue);
|
||||
expect(ValueTypeUtils.isInline(ValueType.Null), isTrue);
|
||||
expect(ValueTypeUtils.isInline(ValueType.String), isFalse);
|
||||
});
|
||||
test('is type vector element', () {
|
||||
expect(ValueTypeUtils.isTypedVectorElement(ValueType.Bool), isTrue);
|
||||
expect(ValueTypeUtils.isTypedVectorElement(ValueType.Int), isTrue);
|
||||
expect(ValueTypeUtils.isTypedVectorElement(ValueType.UInt), isTrue);
|
||||
expect(ValueTypeUtils.isTypedVectorElement(ValueType.Float), isTrue);
|
||||
expect(ValueTypeUtils.isTypedVectorElement(ValueType.Key), isTrue);
|
||||
expect(ValueTypeUtils.isTypedVectorElement(ValueType.String), isTrue);
|
||||
|
||||
expect(ValueTypeUtils.isTypedVectorElement(ValueType.Null), isFalse);
|
||||
expect(ValueTypeUtils.isTypedVectorElement(ValueType.Blob), isFalse);
|
||||
});
|
||||
test('is typed vector', () {
|
||||
expect(ValueTypeUtils.isTypedVector(ValueType.VectorInt), isTrue);
|
||||
expect(ValueTypeUtils.isTypedVector(ValueType.VectorUInt), isTrue);
|
||||
expect(ValueTypeUtils.isTypedVector(ValueType.VectorFloat), isTrue);
|
||||
expect(ValueTypeUtils.isTypedVector(ValueType.VectorBool), isTrue);
|
||||
expect(ValueTypeUtils.isTypedVector(ValueType.VectorKey), isTrue);
|
||||
expect(ValueTypeUtils.isTypedVector(ValueType.VectorString), isTrue);
|
||||
|
||||
expect(ValueTypeUtils.isTypedVector(ValueType.Vector), isFalse);
|
||||
expect(ValueTypeUtils.isTypedVector(ValueType.Map), isFalse);
|
||||
expect(ValueTypeUtils.isTypedVector(ValueType.Bool), isFalse);
|
||||
expect(ValueTypeUtils.isTypedVector(ValueType.VectorInt2), isFalse);
|
||||
});
|
||||
test('is fixed typed vector', () {
|
||||
expect(ValueTypeUtils.isFixedTypedVector(ValueType.VectorInt2), isTrue);
|
||||
expect(ValueTypeUtils.isFixedTypedVector(ValueType.VectorInt3), isTrue);
|
||||
expect(ValueTypeUtils.isFixedTypedVector(ValueType.VectorInt4), isTrue);
|
||||
expect(ValueTypeUtils.isFixedTypedVector(ValueType.VectorUInt2), isTrue);
|
||||
expect(ValueTypeUtils.isFixedTypedVector(ValueType.VectorUInt3), isTrue);
|
||||
expect(ValueTypeUtils.isFixedTypedVector(ValueType.VectorUInt4), isTrue);
|
||||
expect(ValueTypeUtils.isFixedTypedVector(ValueType.VectorFloat2), isTrue);
|
||||
expect(ValueTypeUtils.isFixedTypedVector(ValueType.VectorFloat3), isTrue);
|
||||
expect(ValueTypeUtils.isFixedTypedVector(ValueType.VectorFloat4), isTrue);
|
||||
|
||||
expect(ValueTypeUtils.isFixedTypedVector(ValueType.VectorInt), isFalse);
|
||||
});
|
||||
test('to typed vector', () {
|
||||
expect(ValueTypeUtils.toTypedVector(ValueType.Int, 0),
|
||||
equals(ValueType.VectorInt));
|
||||
expect(ValueTypeUtils.toTypedVector(ValueType.UInt, 0),
|
||||
equals(ValueType.VectorUInt));
|
||||
expect(ValueTypeUtils.toTypedVector(ValueType.Bool, 0),
|
||||
equals(ValueType.VectorBool));
|
||||
expect(ValueTypeUtils.toTypedVector(ValueType.Float, 0),
|
||||
equals(ValueType.VectorFloat));
|
||||
expect(ValueTypeUtils.toTypedVector(ValueType.Key, 0),
|
||||
equals(ValueType.VectorKey));
|
||||
expect(ValueTypeUtils.toTypedVector(ValueType.String, 0),
|
||||
equals(ValueType.VectorString));
|
||||
|
||||
expect(ValueTypeUtils.toTypedVector(ValueType.Int, 2),
|
||||
equals(ValueType.VectorInt2));
|
||||
expect(ValueTypeUtils.toTypedVector(ValueType.UInt, 2),
|
||||
equals(ValueType.VectorUInt2));
|
||||
expect(ValueTypeUtils.toTypedVector(ValueType.Float, 2),
|
||||
equals(ValueType.VectorFloat2));
|
||||
|
||||
expect(ValueTypeUtils.toTypedVector(ValueType.Int, 3),
|
||||
equals(ValueType.VectorInt3));
|
||||
expect(ValueTypeUtils.toTypedVector(ValueType.UInt, 3),
|
||||
equals(ValueType.VectorUInt3));
|
||||
expect(ValueTypeUtils.toTypedVector(ValueType.Float, 3),
|
||||
equals(ValueType.VectorFloat3));
|
||||
|
||||
expect(ValueTypeUtils.toTypedVector(ValueType.Int, 4),
|
||||
equals(ValueType.VectorInt4));
|
||||
expect(ValueTypeUtils.toTypedVector(ValueType.UInt, 4),
|
||||
equals(ValueType.VectorUInt4));
|
||||
expect(ValueTypeUtils.toTypedVector(ValueType.Float, 4),
|
||||
equals(ValueType.VectorFloat4));
|
||||
});
|
||||
test('typed vector element type', () {
|
||||
expect(ValueTypeUtils.typedVectorElementType(ValueType.VectorInt),
|
||||
equals(ValueType.Int));
|
||||
expect(ValueTypeUtils.typedVectorElementType(ValueType.VectorUInt),
|
||||
equals(ValueType.UInt));
|
||||
expect(ValueTypeUtils.typedVectorElementType(ValueType.VectorFloat),
|
||||
equals(ValueType.Float));
|
||||
expect(ValueTypeUtils.typedVectorElementType(ValueType.VectorString),
|
||||
equals(ValueType.String));
|
||||
expect(ValueTypeUtils.typedVectorElementType(ValueType.VectorKey),
|
||||
equals(ValueType.Key));
|
||||
expect(ValueTypeUtils.typedVectorElementType(ValueType.VectorBool),
|
||||
equals(ValueType.Bool));
|
||||
});
|
||||
test('fixed typed vector element type', () {
|
||||
expect(ValueTypeUtils.fixedTypedVectorElementType(ValueType.VectorInt2),
|
||||
equals(ValueType.Int));
|
||||
expect(ValueTypeUtils.fixedTypedVectorElementType(ValueType.VectorInt3),
|
||||
equals(ValueType.Int));
|
||||
expect(ValueTypeUtils.fixedTypedVectorElementType(ValueType.VectorInt4),
|
||||
equals(ValueType.Int));
|
||||
|
||||
expect(ValueTypeUtils.fixedTypedVectorElementType(ValueType.VectorUInt2),
|
||||
equals(ValueType.UInt));
|
||||
expect(ValueTypeUtils.fixedTypedVectorElementType(ValueType.VectorUInt3),
|
||||
equals(ValueType.UInt));
|
||||
expect(ValueTypeUtils.fixedTypedVectorElementType(ValueType.VectorUInt4),
|
||||
equals(ValueType.UInt));
|
||||
|
||||
expect(ValueTypeUtils.fixedTypedVectorElementType(ValueType.VectorFloat2),
|
||||
equals(ValueType.Float));
|
||||
expect(ValueTypeUtils.fixedTypedVectorElementType(ValueType.VectorFloat3),
|
||||
equals(ValueType.Float));
|
||||
expect(ValueTypeUtils.fixedTypedVectorElementType(ValueType.VectorFloat4),
|
||||
equals(ValueType.Float));
|
||||
});
|
||||
test('fixed typed vector element size', () {
|
||||
expect(ValueTypeUtils.fixedTypedVectorElementSize(ValueType.VectorInt2),
|
||||
equals(2));
|
||||
expect(ValueTypeUtils.fixedTypedVectorElementSize(ValueType.VectorInt3),
|
||||
equals(3));
|
||||
expect(ValueTypeUtils.fixedTypedVectorElementSize(ValueType.VectorInt4),
|
||||
equals(4));
|
||||
|
||||
expect(ValueTypeUtils.fixedTypedVectorElementSize(ValueType.VectorUInt2),
|
||||
equals(2));
|
||||
expect(ValueTypeUtils.fixedTypedVectorElementSize(ValueType.VectorUInt3),
|
||||
equals(3));
|
||||
expect(ValueTypeUtils.fixedTypedVectorElementSize(ValueType.VectorUInt4),
|
||||
equals(4));
|
||||
|
||||
expect(ValueTypeUtils.fixedTypedVectorElementSize(ValueType.VectorFloat2),
|
||||
equals(2));
|
||||
expect(ValueTypeUtils.fixedTypedVectorElementSize(ValueType.VectorFloat3),
|
||||
equals(3));
|
||||
expect(ValueTypeUtils.fixedTypedVectorElementSize(ValueType.VectorFloat4),
|
||||
equals(4));
|
||||
});
|
||||
test('packed type', () {
|
||||
expect(
|
||||
ValueTypeUtils.packedType(ValueType.Null, BitWidth.width8), equals(0));
|
||||
expect(
|
||||
ValueTypeUtils.packedType(ValueType.Null, BitWidth.width16), equals(1));
|
||||
expect(
|
||||
ValueTypeUtils.packedType(ValueType.Null, BitWidth.width32), equals(2));
|
||||
expect(
|
||||
ValueTypeUtils.packedType(ValueType.Null, BitWidth.width64), equals(3));
|
||||
|
||||
expect(
|
||||
ValueTypeUtils.packedType(ValueType.Int, BitWidth.width8), equals(4));
|
||||
expect(
|
||||
ValueTypeUtils.packedType(ValueType.Int, BitWidth.width16), equals(5));
|
||||
expect(
|
||||
ValueTypeUtils.packedType(ValueType.Int, BitWidth.width32), equals(6));
|
||||
expect(
|
||||
ValueTypeUtils.packedType(ValueType.Int, BitWidth.width64), equals(7));
|
||||
});
|
||||
test('bit width', () {
|
||||
expect(BitWidthUtil.width(0), BitWidth.width8);
|
||||
expect(BitWidthUtil.width(-20), BitWidth.width8);
|
||||
expect(BitWidthUtil.width(127), BitWidth.width8);
|
||||
expect(BitWidthUtil.width(128), BitWidth.width16);
|
||||
expect(BitWidthUtil.width(128123), BitWidth.width32);
|
||||
expect(BitWidthUtil.width(12812324534), BitWidth.width64);
|
||||
expect(BitWidthUtil.width(-127), BitWidth.width8);
|
||||
expect(BitWidthUtil.width(-128), BitWidth.width16);
|
||||
expect(BitWidthUtil.width(-12812324534), BitWidth.width64);
|
||||
expect(BitWidthUtil.width(-0.1), BitWidth.width64);
|
||||
expect(BitWidthUtil.width(0.25), BitWidth.width32);
|
||||
});
|
||||
test('padding size', () {
|
||||
expect(BitWidthUtil.paddingSize(10, 8), 6);
|
||||
expect(BitWidthUtil.paddingSize(10, 4), 2);
|
||||
expect(BitWidthUtil.paddingSize(15, 4), 1);
|
||||
expect(BitWidthUtil.paddingSize(15, 2), 1);
|
||||
expect(BitWidthUtil.paddingSize(15, 1), 0);
|
||||
expect(BitWidthUtil.paddingSize(16, 8), 0);
|
||||
expect(BitWidthUtil.paddingSize(17, 8), 7);
|
||||
});
|
||||
}
|
@ -1,109 +0,0 @@
|
||||
// automatically generated by the FlatBuffers compiler, do not modify
|
||||
// ignore_for_file: unused_import, unused_field, unused_element, unused_local_variable
|
||||
|
||||
import 'dart:typed_data' show Uint8List;
|
||||
import 'package:flat_buffers/flat_buffers.dart' as fb;
|
||||
|
||||
|
||||
import './include_test2_my_game.other_name_space_generated.dart' as my_game_other_name_space;
|
||||
|
||||
class TableA {
|
||||
TableA._(this._bc, this._bcOffset);
|
||||
factory TableA(List<int> bytes) {
|
||||
final rootRef = fb.BufferContext.fromBytes(bytes);
|
||||
return reader.read(rootRef, 0);
|
||||
}
|
||||
|
||||
static const fb.Reader<TableA> reader = _TableAReader();
|
||||
|
||||
final fb.BufferContext _bc;
|
||||
final int _bcOffset;
|
||||
|
||||
my_game_other_name_space.TableB? get b => my_game_other_name_space.TableB.reader.vTableGetNullable(_bc, _bcOffset, 4);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'TableA{b: ${b}}';
|
||||
}
|
||||
|
||||
TableAT unpack() => TableAT(
|
||||
b: b?.unpack());
|
||||
|
||||
static int pack(fb.Builder fbBuilder, TableAT? object) {
|
||||
if (object == null) return 0;
|
||||
return object.pack(fbBuilder);
|
||||
}
|
||||
}
|
||||
|
||||
class TableAT implements fb.Packable {
|
||||
my_game_other_name_space.TableBT? b;
|
||||
|
||||
TableAT({
|
||||
this.b});
|
||||
|
||||
@override
|
||||
int pack(fb.Builder fbBuilder) {
|
||||
final int? bOffset = b?.pack(fbBuilder);
|
||||
fbBuilder.startTable(1);
|
||||
fbBuilder.addOffset(0, bOffset);
|
||||
return fbBuilder.endTable();
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'TableAT{b: ${b}}';
|
||||
}
|
||||
}
|
||||
|
||||
class _TableAReader extends fb.TableReader<TableA> {
|
||||
const _TableAReader();
|
||||
|
||||
@override
|
||||
TableA createObject(fb.BufferContext bc, int offset) =>
|
||||
TableA._(bc, offset);
|
||||
}
|
||||
|
||||
class TableABuilder {
|
||||
TableABuilder(this.fbBuilder);
|
||||
|
||||
final fb.Builder fbBuilder;
|
||||
|
||||
void begin() {
|
||||
fbBuilder.startTable(1);
|
||||
}
|
||||
|
||||
int addBOffset(int? offset) {
|
||||
fbBuilder.addOffset(0, offset);
|
||||
return fbBuilder.offset;
|
||||
}
|
||||
|
||||
int finish() {
|
||||
return fbBuilder.endTable();
|
||||
}
|
||||
}
|
||||
|
||||
class TableAObjectBuilder extends fb.ObjectBuilder {
|
||||
final my_game_other_name_space.TableBObjectBuilder? _b;
|
||||
|
||||
TableAObjectBuilder({
|
||||
my_game_other_name_space.TableBObjectBuilder? b,
|
||||
})
|
||||
: _b = b;
|
||||
|
||||
/// Finish building, and store into the [fbBuilder].
|
||||
@override
|
||||
int finish(fb.Builder fbBuilder) {
|
||||
final int? bOffset = _b?.getOrCreateOffset(fbBuilder);
|
||||
fbBuilder.startTable(1);
|
||||
fbBuilder.addOffset(0, bOffset);
|
||||
return fbBuilder.endTable();
|
||||
}
|
||||
|
||||
/// Convenience method to serialize to byte list.
|
||||
@override
|
||||
Uint8List toBytes([String? fileIdentifier]) {
|
||||
final fbBuilder = fb.Builder(deduplicateTables: false);
|
||||
fbBuilder.finish(finish(fbBuilder), fileIdentifier);
|
||||
return fbBuilder.buffer;
|
||||
}
|
||||
}
|
@ -1,241 +0,0 @@
|
||||
// automatically generated by the FlatBuffers compiler, do not modify
|
||||
// ignore_for_file: unused_import, unused_field, unused_element, unused_local_variable
|
||||
|
||||
library my_game.other_name_space;
|
||||
|
||||
import 'dart:typed_data' show Uint8List;
|
||||
import 'package:flat_buffers/flat_buffers.dart' as fb;
|
||||
|
||||
|
||||
import './include_test1_generated.dart';
|
||||
|
||||
class FromInclude {
|
||||
final int value;
|
||||
const FromInclude._(this.value);
|
||||
|
||||
factory FromInclude.fromValue(int value) {
|
||||
final result = values[value];
|
||||
if (result == null) {
|
||||
throw StateError('Invalid value $value for bit flag enum FromInclude');
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static FromInclude? _createOrNull(int? value) =>
|
||||
value == null ? null : FromInclude.fromValue(value);
|
||||
|
||||
static const int minValue = 0;
|
||||
static const int maxValue = 0;
|
||||
static bool containsValue(int value) => values.containsKey(value);
|
||||
|
||||
static const FromInclude IncludeVal = FromInclude._(0);
|
||||
static const Map<int, FromInclude> values = {
|
||||
0: IncludeVal};
|
||||
|
||||
static const fb.Reader<FromInclude> reader = _FromIncludeReader();
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'FromInclude{value: $value}';
|
||||
}
|
||||
}
|
||||
|
||||
class _FromIncludeReader extends fb.Reader<FromInclude> {
|
||||
const _FromIncludeReader();
|
||||
|
||||
@override
|
||||
int get size => 8;
|
||||
|
||||
@override
|
||||
FromInclude read(fb.BufferContext bc, int offset) =>
|
||||
FromInclude.fromValue(const fb.Int64Reader().read(bc, offset));
|
||||
}
|
||||
|
||||
class Unused {
|
||||
Unused._(this._bc, this._bcOffset);
|
||||
|
||||
static const fb.Reader<Unused> reader = _UnusedReader();
|
||||
|
||||
final fb.BufferContext _bc;
|
||||
final int _bcOffset;
|
||||
|
||||
int get a => const fb.Int32Reader().read(_bc, _bcOffset + 0);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'Unused{a: ${a}}';
|
||||
}
|
||||
|
||||
UnusedT unpack() => UnusedT(
|
||||
a: a);
|
||||
|
||||
static int pack(fb.Builder fbBuilder, UnusedT? object) {
|
||||
if (object == null) return 0;
|
||||
return object.pack(fbBuilder);
|
||||
}
|
||||
}
|
||||
|
||||
class UnusedT implements fb.Packable {
|
||||
int a;
|
||||
|
||||
UnusedT({
|
||||
required this.a});
|
||||
|
||||
@override
|
||||
int pack(fb.Builder fbBuilder) {
|
||||
fbBuilder.putInt32(a);
|
||||
return fbBuilder.offset;
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'UnusedT{a: ${a}}';
|
||||
}
|
||||
}
|
||||
|
||||
class _UnusedReader extends fb.StructReader<Unused> {
|
||||
const _UnusedReader();
|
||||
|
||||
@override
|
||||
int get size => 4;
|
||||
|
||||
@override
|
||||
Unused createObject(fb.BufferContext bc, int offset) =>
|
||||
Unused._(bc, offset);
|
||||
}
|
||||
|
||||
class UnusedBuilder {
|
||||
UnusedBuilder(this.fbBuilder);
|
||||
|
||||
final fb.Builder fbBuilder;
|
||||
|
||||
int finish(int a) {
|
||||
fbBuilder.putInt32(a);
|
||||
return fbBuilder.offset;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class UnusedObjectBuilder extends fb.ObjectBuilder {
|
||||
final int _a;
|
||||
|
||||
UnusedObjectBuilder({
|
||||
required int a,
|
||||
})
|
||||
: _a = a;
|
||||
|
||||
/// Finish building, and store into the [fbBuilder].
|
||||
@override
|
||||
int finish(fb.Builder fbBuilder) {
|
||||
fbBuilder.putInt32(_a);
|
||||
return fbBuilder.offset;
|
||||
}
|
||||
|
||||
/// Convenience method to serialize to byte list.
|
||||
@override
|
||||
Uint8List toBytes([String? fileIdentifier]) {
|
||||
final fbBuilder = fb.Builder(deduplicateTables: false);
|
||||
fbBuilder.finish(finish(fbBuilder), fileIdentifier);
|
||||
return fbBuilder.buffer;
|
||||
}
|
||||
}
|
||||
class TableB {
|
||||
TableB._(this._bc, this._bcOffset);
|
||||
factory TableB(List<int> bytes) {
|
||||
final rootRef = fb.BufferContext.fromBytes(bytes);
|
||||
return reader.read(rootRef, 0);
|
||||
}
|
||||
|
||||
static const fb.Reader<TableB> reader = _TableBReader();
|
||||
|
||||
final fb.BufferContext _bc;
|
||||
final int _bcOffset;
|
||||
|
||||
TableA? get a => TableA.reader.vTableGetNullable(_bc, _bcOffset, 4);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'TableB{a: ${a}}';
|
||||
}
|
||||
|
||||
TableBT unpack() => TableBT(
|
||||
a: a?.unpack());
|
||||
|
||||
static int pack(fb.Builder fbBuilder, TableBT? object) {
|
||||
if (object == null) return 0;
|
||||
return object.pack(fbBuilder);
|
||||
}
|
||||
}
|
||||
|
||||
class TableBT implements fb.Packable {
|
||||
TableAT? a;
|
||||
|
||||
TableBT({
|
||||
this.a});
|
||||
|
||||
@override
|
||||
int pack(fb.Builder fbBuilder) {
|
||||
final int? aOffset = a?.pack(fbBuilder);
|
||||
fbBuilder.startTable(1);
|
||||
fbBuilder.addOffset(0, aOffset);
|
||||
return fbBuilder.endTable();
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'TableBT{a: ${a}}';
|
||||
}
|
||||
}
|
||||
|
||||
class _TableBReader extends fb.TableReader<TableB> {
|
||||
const _TableBReader();
|
||||
|
||||
@override
|
||||
TableB createObject(fb.BufferContext bc, int offset) =>
|
||||
TableB._(bc, offset);
|
||||
}
|
||||
|
||||
class TableBBuilder {
|
||||
TableBBuilder(this.fbBuilder);
|
||||
|
||||
final fb.Builder fbBuilder;
|
||||
|
||||
void begin() {
|
||||
fbBuilder.startTable(1);
|
||||
}
|
||||
|
||||
int addAOffset(int? offset) {
|
||||
fbBuilder.addOffset(0, offset);
|
||||
return fbBuilder.offset;
|
||||
}
|
||||
|
||||
int finish() {
|
||||
return fbBuilder.endTable();
|
||||
}
|
||||
}
|
||||
|
||||
class TableBObjectBuilder extends fb.ObjectBuilder {
|
||||
final TableAObjectBuilder? _a;
|
||||
|
||||
TableBObjectBuilder({
|
||||
TableAObjectBuilder? a,
|
||||
})
|
||||
: _a = a;
|
||||
|
||||
/// Finish building, and store into the [fbBuilder].
|
||||
@override
|
||||
int finish(fb.Builder fbBuilder) {
|
||||
final int? aOffset = _a?.getOrCreateOffset(fbBuilder);
|
||||
fbBuilder.startTable(1);
|
||||
fbBuilder.addOffset(0, aOffset);
|
||||
return fbBuilder.endTable();
|
||||
}
|
||||
|
||||
/// Convenience method to serialize to byte list.
|
||||
@override
|
||||
Uint8List toBytes([String? fileIdentifier]) {
|
||||
final fbBuilder = fb.Builder(deduplicateTables: false);
|
||||
fbBuilder.finish(finish(fbBuilder), fileIdentifier);
|
||||
return fbBuilder.buffer;
|
||||
}
|
||||
}
|
@ -1,399 +0,0 @@
|
||||
// automatically generated by the FlatBuffers compiler, do not modify
|
||||
// ignore_for_file: unused_import, unused_field, unused_element, unused_local_variable
|
||||
|
||||
library keyword_test;
|
||||
|
||||
import 'dart:typed_data' show Uint8List;
|
||||
import 'package:flat_buffers/flat_buffers.dart' as fb;
|
||||
|
||||
|
||||
class Abc {
|
||||
final int value;
|
||||
const Abc._(this.value);
|
||||
|
||||
factory Abc.fromValue(int value) {
|
||||
final result = values[value];
|
||||
if (result == null) {
|
||||
throw StateError('Invalid value $value for bit flag enum Abc');
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static Abc? _createOrNull(int? value) =>
|
||||
value == null ? null : Abc.fromValue(value);
|
||||
|
||||
static const int minValue = 0;
|
||||
static const int maxValue = 2;
|
||||
static bool containsValue(int value) => values.containsKey(value);
|
||||
|
||||
static const Abc $void = Abc._(0);
|
||||
static const Abc where = Abc._(1);
|
||||
static const Abc stackalloc = Abc._(2);
|
||||
static const Map<int, Abc> values = {
|
||||
0: $void,
|
||||
1: where,
|
||||
2: stackalloc};
|
||||
|
||||
static const fb.Reader<Abc> reader = _AbcReader();
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'Abc{value: $value}';
|
||||
}
|
||||
}
|
||||
|
||||
class _AbcReader extends fb.Reader<Abc> {
|
||||
const _AbcReader();
|
||||
|
||||
@override
|
||||
int get size => 4;
|
||||
|
||||
@override
|
||||
Abc read(fb.BufferContext bc, int offset) =>
|
||||
Abc.fromValue(const fb.Int32Reader().read(bc, offset));
|
||||
}
|
||||
|
||||
class Public {
|
||||
final int value;
|
||||
const Public._(this.value);
|
||||
|
||||
factory Public.fromValue(int value) {
|
||||
final result = values[value];
|
||||
if (result == null) {
|
||||
throw StateError('Invalid value $value for bit flag enum Public');
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static Public? _createOrNull(int? value) =>
|
||||
value == null ? null : Public.fromValue(value);
|
||||
|
||||
static const int minValue = 0;
|
||||
static const int maxValue = 0;
|
||||
static bool containsValue(int value) => values.containsKey(value);
|
||||
|
||||
static const Public NONE = Public._(0);
|
||||
static const Map<int, Public> values = {
|
||||
0: NONE};
|
||||
|
||||
static const fb.Reader<Public> reader = _PublicReader();
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'Public{value: $value}';
|
||||
}
|
||||
}
|
||||
|
||||
class _PublicReader extends fb.Reader<Public> {
|
||||
const _PublicReader();
|
||||
|
||||
@override
|
||||
int get size => 4;
|
||||
|
||||
@override
|
||||
Public read(fb.BufferContext bc, int offset) =>
|
||||
Public.fromValue(const fb.Int32Reader().read(bc, offset));
|
||||
}
|
||||
|
||||
class KeywordsInUnionTypeId {
|
||||
final int value;
|
||||
const KeywordsInUnionTypeId._(this.value);
|
||||
|
||||
factory KeywordsInUnionTypeId.fromValue(int value) {
|
||||
final result = values[value];
|
||||
if (result == null) {
|
||||
throw StateError('Invalid value $value for bit flag enum KeywordsInUnionTypeId');
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static KeywordsInUnionTypeId? _createOrNull(int? value) =>
|
||||
value == null ? null : KeywordsInUnionTypeId.fromValue(value);
|
||||
|
||||
static const int minValue = 0;
|
||||
static const int maxValue = 2;
|
||||
static bool containsValue(int value) => values.containsKey(value);
|
||||
|
||||
static const KeywordsInUnionTypeId NONE = KeywordsInUnionTypeId._(0);
|
||||
static const KeywordsInUnionTypeId $static = KeywordsInUnionTypeId._(1);
|
||||
static const KeywordsInUnionTypeId internal = KeywordsInUnionTypeId._(2);
|
||||
static const Map<int, KeywordsInUnionTypeId> values = {
|
||||
0: NONE,
|
||||
1: $static,
|
||||
2: internal};
|
||||
|
||||
static const fb.Reader<KeywordsInUnionTypeId> reader = _KeywordsInUnionTypeIdReader();
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'KeywordsInUnionTypeId{value: $value}';
|
||||
}
|
||||
}
|
||||
|
||||
class _KeywordsInUnionTypeIdReader extends fb.Reader<KeywordsInUnionTypeId> {
|
||||
const _KeywordsInUnionTypeIdReader();
|
||||
|
||||
@override
|
||||
int get size => 1;
|
||||
|
||||
@override
|
||||
KeywordsInUnionTypeId read(fb.BufferContext bc, int offset) =>
|
||||
KeywordsInUnionTypeId.fromValue(const fb.Uint8Reader().read(bc, offset));
|
||||
}
|
||||
|
||||
class KeywordsInTable {
|
||||
KeywordsInTable._(this._bc, this._bcOffset);
|
||||
factory KeywordsInTable(List<int> bytes) {
|
||||
final rootRef = fb.BufferContext.fromBytes(bytes);
|
||||
return reader.read(rootRef, 0);
|
||||
}
|
||||
|
||||
static const fb.Reader<KeywordsInTable> reader = _KeywordsInTableReader();
|
||||
|
||||
final fb.BufferContext _bc;
|
||||
final int _bcOffset;
|
||||
|
||||
Abc get $is => Abc.fromValue(const fb.Int32Reader().vTableGet(_bc, _bcOffset, 4, 0));
|
||||
Public get private => Public.fromValue(const fb.Int32Reader().vTableGet(_bc, _bcOffset, 6, 0));
|
||||
int get type => const fb.Int32Reader().vTableGet(_bc, _bcOffset, 8, 0);
|
||||
bool get $default => const fb.BoolReader().vTableGet(_bc, _bcOffset, 10, false);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'KeywordsInTable{\$is: ${$is}, private: ${private}, type: ${type}, \$default: ${$default}}';
|
||||
}
|
||||
|
||||
KeywordsInTableT unpack() => KeywordsInTableT(
|
||||
$is: $is,
|
||||
private: private,
|
||||
type: type,
|
||||
$default: $default);
|
||||
|
||||
static int pack(fb.Builder fbBuilder, KeywordsInTableT? object) {
|
||||
if (object == null) return 0;
|
||||
return object.pack(fbBuilder);
|
||||
}
|
||||
}
|
||||
|
||||
class KeywordsInTableT implements fb.Packable {
|
||||
Abc $is;
|
||||
Public private;
|
||||
int type;
|
||||
bool $default;
|
||||
|
||||
KeywordsInTableT({
|
||||
this.$is = Abc.$void,
|
||||
this.private = Public.NONE,
|
||||
this.type = 0,
|
||||
this.$default = false});
|
||||
|
||||
@override
|
||||
int pack(fb.Builder fbBuilder) {
|
||||
fbBuilder.startTable(4);
|
||||
fbBuilder.addInt32(0, $is.value);
|
||||
fbBuilder.addInt32(1, private.value);
|
||||
fbBuilder.addInt32(2, type);
|
||||
fbBuilder.addBool(3, $default);
|
||||
return fbBuilder.endTable();
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'KeywordsInTableT{\$is: ${$is}, private: ${private}, type: ${type}, \$default: ${$default}}';
|
||||
}
|
||||
}
|
||||
|
||||
class _KeywordsInTableReader extends fb.TableReader<KeywordsInTable> {
|
||||
const _KeywordsInTableReader();
|
||||
|
||||
@override
|
||||
KeywordsInTable createObject(fb.BufferContext bc, int offset) =>
|
||||
KeywordsInTable._(bc, offset);
|
||||
}
|
||||
|
||||
class KeywordsInTableBuilder {
|
||||
KeywordsInTableBuilder(this.fbBuilder);
|
||||
|
||||
final fb.Builder fbBuilder;
|
||||
|
||||
void begin() {
|
||||
fbBuilder.startTable(4);
|
||||
}
|
||||
|
||||
int addIs(Abc? $is) {
|
||||
fbBuilder.addInt32(0, $is?.value);
|
||||
return fbBuilder.offset;
|
||||
}
|
||||
int addPrivate(Public? private) {
|
||||
fbBuilder.addInt32(1, private?.value);
|
||||
return fbBuilder.offset;
|
||||
}
|
||||
int addType(int? type) {
|
||||
fbBuilder.addInt32(2, type);
|
||||
return fbBuilder.offset;
|
||||
}
|
||||
int addDefault(bool? $default) {
|
||||
fbBuilder.addBool(3, $default);
|
||||
return fbBuilder.offset;
|
||||
}
|
||||
|
||||
int finish() {
|
||||
return fbBuilder.endTable();
|
||||
}
|
||||
}
|
||||
|
||||
class KeywordsInTableObjectBuilder extends fb.ObjectBuilder {
|
||||
final Abc? _$is;
|
||||
final Public? _private;
|
||||
final int? _type;
|
||||
final bool? _$default;
|
||||
|
||||
KeywordsInTableObjectBuilder({
|
||||
Abc? $is,
|
||||
Public? private,
|
||||
int? type,
|
||||
bool? $default,
|
||||
})
|
||||
: _$is = $is,
|
||||
_private = private,
|
||||
_type = type,
|
||||
_$default = $default;
|
||||
|
||||
/// Finish building, and store into the [fbBuilder].
|
||||
@override
|
||||
int finish(fb.Builder fbBuilder) {
|
||||
fbBuilder.startTable(4);
|
||||
fbBuilder.addInt32(0, _$is?.value);
|
||||
fbBuilder.addInt32(1, _private?.value);
|
||||
fbBuilder.addInt32(2, _type);
|
||||
fbBuilder.addBool(3, _$default);
|
||||
return fbBuilder.endTable();
|
||||
}
|
||||
|
||||
/// Convenience method to serialize to byte list.
|
||||
@override
|
||||
Uint8List toBytes([String? fileIdentifier]) {
|
||||
final fbBuilder = fb.Builder(deduplicateTables: false);
|
||||
fbBuilder.finish(finish(fbBuilder), fileIdentifier);
|
||||
return fbBuilder.buffer;
|
||||
}
|
||||
}
|
||||
class Table2 {
|
||||
Table2._(this._bc, this._bcOffset);
|
||||
factory Table2(List<int> bytes) {
|
||||
final rootRef = fb.BufferContext.fromBytes(bytes);
|
||||
return reader.read(rootRef, 0);
|
||||
}
|
||||
|
||||
static const fb.Reader<Table2> reader = _Table2Reader();
|
||||
|
||||
final fb.BufferContext _bc;
|
||||
final int _bcOffset;
|
||||
|
||||
KeywordsInUnionTypeId? get typeType => KeywordsInUnionTypeId._createOrNull(const fb.Uint8Reader().vTableGetNullable(_bc, _bcOffset, 4));
|
||||
dynamic get type {
|
||||
switch (typeType?.value) {
|
||||
case 1: return KeywordsInTable.reader.vTableGetNullable(_bc, _bcOffset, 6);
|
||||
case 2: return KeywordsInTable.reader.vTableGetNullable(_bc, _bcOffset, 6);
|
||||
default: return null;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'Table2{typeType: ${typeType}, type: ${type}}';
|
||||
}
|
||||
|
||||
Table2T unpack() => Table2T(
|
||||
typeType: typeType,
|
||||
type: type);
|
||||
|
||||
static int pack(fb.Builder fbBuilder, Table2T? object) {
|
||||
if (object == null) return 0;
|
||||
return object.pack(fbBuilder);
|
||||
}
|
||||
}
|
||||
|
||||
class Table2T implements fb.Packable {
|
||||
KeywordsInUnionTypeId? typeType;
|
||||
dynamic type;
|
||||
|
||||
Table2T({
|
||||
this.typeType,
|
||||
this.type});
|
||||
|
||||
@override
|
||||
int pack(fb.Builder fbBuilder) {
|
||||
final int? typeOffset = type?.pack(fbBuilder);
|
||||
fbBuilder.startTable(2);
|
||||
fbBuilder.addUint8(0, typeType?.value);
|
||||
fbBuilder.addOffset(1, typeOffset);
|
||||
return fbBuilder.endTable();
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'Table2T{typeType: ${typeType}, type: ${type}}';
|
||||
}
|
||||
}
|
||||
|
||||
class _Table2Reader extends fb.TableReader<Table2> {
|
||||
const _Table2Reader();
|
||||
|
||||
@override
|
||||
Table2 createObject(fb.BufferContext bc, int offset) =>
|
||||
Table2._(bc, offset);
|
||||
}
|
||||
|
||||
class Table2Builder {
|
||||
Table2Builder(this.fbBuilder);
|
||||
|
||||
final fb.Builder fbBuilder;
|
||||
|
||||
void begin() {
|
||||
fbBuilder.startTable(2);
|
||||
}
|
||||
|
||||
int addTypeType(KeywordsInUnionTypeId? typeType) {
|
||||
fbBuilder.addUint8(0, typeType?.value);
|
||||
return fbBuilder.offset;
|
||||
}
|
||||
int addTypeOffset(int? offset) {
|
||||
fbBuilder.addOffset(1, offset);
|
||||
return fbBuilder.offset;
|
||||
}
|
||||
|
||||
int finish() {
|
||||
return fbBuilder.endTable();
|
||||
}
|
||||
}
|
||||
|
||||
class Table2ObjectBuilder extends fb.ObjectBuilder {
|
||||
final KeywordsInUnionTypeId? _typeType;
|
||||
final dynamic _type;
|
||||
|
||||
Table2ObjectBuilder({
|
||||
KeywordsInUnionTypeId? typeType,
|
||||
dynamic type,
|
||||
})
|
||||
: _typeType = typeType,
|
||||
_type = type;
|
||||
|
||||
/// Finish building, and store into the [fbBuilder].
|
||||
@override
|
||||
int finish(fb.Builder fbBuilder) {
|
||||
final int? typeOffset = _type?.getOrCreateOffset(fbBuilder);
|
||||
fbBuilder.startTable(2);
|
||||
fbBuilder.addUint8(0, _typeType?.value);
|
||||
fbBuilder.addOffset(1, typeOffset);
|
||||
return fbBuilder.endTable();
|
||||
}
|
||||
|
||||
/// Convenience method to serialize to byte list.
|
||||
@override
|
||||
Uint8List toBytes([String? fileIdentifier]) {
|
||||
final fbBuilder = fb.Builder(deduplicateTables: false);
|
||||
fbBuilder.finish(finish(fbBuilder), fileIdentifier);
|
||||
return fbBuilder.buffer;
|
||||
}
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
enum OptionsEnum : uint32
|
||||
{
|
||||
A = 1,
|
||||
B = 2,
|
||||
C = 3
|
||||
}
|
||||
|
||||
table MyTable {
|
||||
options : [OptionsEnum];
|
||||
}
|
@ -1,155 +0,0 @@
|
||||
// automatically generated by the FlatBuffers compiler, do not modify
|
||||
// ignore_for_file: unused_import, unused_field, unused_element, unused_local_variable
|
||||
|
||||
import 'dart:typed_data' show Uint8List;
|
||||
import 'package:flat_buffers/flat_buffers.dart' as fb;
|
||||
|
||||
|
||||
class OptionsEnum {
|
||||
final int value;
|
||||
const OptionsEnum._(this.value);
|
||||
|
||||
factory OptionsEnum.fromValue(int value) {
|
||||
final result = values[value];
|
||||
if (result == null) {
|
||||
throw StateError('Invalid value $value for bit flag enum OptionsEnum');
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static OptionsEnum? _createOrNull(int? value) =>
|
||||
value == null ? null : OptionsEnum.fromValue(value);
|
||||
|
||||
static const int minValue = 1;
|
||||
static const int maxValue = 3;
|
||||
static bool containsValue(int value) => values.containsKey(value);
|
||||
|
||||
static const OptionsEnum A = OptionsEnum._(1);
|
||||
static const OptionsEnum B = OptionsEnum._(2);
|
||||
static const OptionsEnum C = OptionsEnum._(3);
|
||||
static const Map<int, OptionsEnum> values = {
|
||||
1: A,
|
||||
2: B,
|
||||
3: C};
|
||||
|
||||
static const fb.Reader<OptionsEnum> reader = _OptionsEnumReader();
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'OptionsEnum{value: $value}';
|
||||
}
|
||||
}
|
||||
|
||||
class _OptionsEnumReader extends fb.Reader<OptionsEnum> {
|
||||
const _OptionsEnumReader();
|
||||
|
||||
@override
|
||||
int get size => 4;
|
||||
|
||||
@override
|
||||
OptionsEnum read(fb.BufferContext bc, int offset) =>
|
||||
OptionsEnum.fromValue(const fb.Uint32Reader().read(bc, offset));
|
||||
}
|
||||
|
||||
class MyTable {
|
||||
MyTable._(this._bc, this._bcOffset);
|
||||
factory MyTable(List<int> bytes) {
|
||||
final rootRef = fb.BufferContext.fromBytes(bytes);
|
||||
return reader.read(rootRef, 0);
|
||||
}
|
||||
|
||||
static const fb.Reader<MyTable> reader = _MyTableReader();
|
||||
|
||||
final fb.BufferContext _bc;
|
||||
final int _bcOffset;
|
||||
|
||||
List<OptionsEnum>? get options => const fb.ListReader<OptionsEnum>(OptionsEnum.reader).vTableGetNullable(_bc, _bcOffset, 4);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'MyTable{options: ${options}}';
|
||||
}
|
||||
|
||||
MyTableT unpack() => MyTableT(
|
||||
options: const fb.ListReader<OptionsEnum>(OptionsEnum.reader, lazy: false).vTableGetNullable(_bc, _bcOffset, 4));
|
||||
|
||||
static int pack(fb.Builder fbBuilder, MyTableT? object) {
|
||||
if (object == null) return 0;
|
||||
return object.pack(fbBuilder);
|
||||
}
|
||||
}
|
||||
|
||||
class MyTableT implements fb.Packable {
|
||||
List<OptionsEnum>? options;
|
||||
|
||||
MyTableT({
|
||||
this.options});
|
||||
|
||||
@override
|
||||
int pack(fb.Builder fbBuilder) {
|
||||
final int? optionsOffset = options == null ? null
|
||||
: fbBuilder.writeListUint32(options!.map((f) => f.value).toList());
|
||||
fbBuilder.startTable(1);
|
||||
fbBuilder.addOffset(0, optionsOffset);
|
||||
return fbBuilder.endTable();
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'MyTableT{options: ${options}}';
|
||||
}
|
||||
}
|
||||
|
||||
class _MyTableReader extends fb.TableReader<MyTable> {
|
||||
const _MyTableReader();
|
||||
|
||||
@override
|
||||
MyTable createObject(fb.BufferContext bc, int offset) =>
|
||||
MyTable._(bc, offset);
|
||||
}
|
||||
|
||||
class MyTableBuilder {
|
||||
MyTableBuilder(this.fbBuilder);
|
||||
|
||||
final fb.Builder fbBuilder;
|
||||
|
||||
void begin() {
|
||||
fbBuilder.startTable(1);
|
||||
}
|
||||
|
||||
int addOptionsOffset(int? offset) {
|
||||
fbBuilder.addOffset(0, offset);
|
||||
return fbBuilder.offset;
|
||||
}
|
||||
|
||||
int finish() {
|
||||
return fbBuilder.endTable();
|
||||
}
|
||||
}
|
||||
|
||||
class MyTableObjectBuilder extends fb.ObjectBuilder {
|
||||
final List<OptionsEnum>? _options;
|
||||
|
||||
MyTableObjectBuilder({
|
||||
List<OptionsEnum>? options,
|
||||
})
|
||||
: _options = options;
|
||||
|
||||
/// Finish building, and store into the [fbBuilder].
|
||||
@override
|
||||
int finish(fb.Builder fbBuilder) {
|
||||
final int? optionsOffset = _options == null ? null
|
||||
: fbBuilder.writeListUint32(_options!.map((f) => f.value).toList());
|
||||
fbBuilder.startTable(1);
|
||||
fbBuilder.addOffset(0, optionsOffset);
|
||||
return fbBuilder.endTable();
|
||||
}
|
||||
|
||||
/// Convenience method to serialize to byte list.
|
||||
@override
|
||||
Uint8List toBytes([String? fileIdentifier]) {
|
||||
final fbBuilder = fb.Builder(deduplicateTables: false);
|
||||
fbBuilder.finish(finish(fbBuilder), fileIdentifier);
|
||||
return fbBuilder.buffer;
|
||||
}
|
||||
}
|
180
third_party/flatbuffers/dart/test/monster_test.fbs
vendored
180
third_party/flatbuffers/dart/test/monster_test.fbs
vendored
@ -1,180 +0,0 @@
|
||||
// test schema file
|
||||
|
||||
include "include_test1.fbs";
|
||||
|
||||
namespace MyGame;
|
||||
|
||||
table InParentNamespace {}
|
||||
|
||||
namespace MyGame.Example2;
|
||||
|
||||
table Monster {} // Test having same name as below, but in different namespace.
|
||||
|
||||
namespace MyGame.Example;
|
||||
|
||||
attribute "priority";
|
||||
|
||||
/// Composite components of Monster color.
|
||||
enum Color:ubyte (bit_flags) {
|
||||
Red = 0, // color Red = (1u << 0)
|
||||
/// \brief color Green
|
||||
/// Green is bit_flag with value (1u << 1)
|
||||
Green,
|
||||
/// \brief color Blue (1u << 3)
|
||||
Blue = 3,
|
||||
}
|
||||
|
||||
enum Race:byte {
|
||||
None = -1,
|
||||
Human = 0,
|
||||
Dwarf,
|
||||
Elf,
|
||||
}
|
||||
|
||||
enum LongEnum:ulong (bit_flags) {
|
||||
LongOne = 1,
|
||||
LongTwo = 2,
|
||||
// Because this is a bitflag, 40 will be out of range of a 32-bit integer,
|
||||
// allowing us to exercise any logic special to big numbers.
|
||||
LongBig = 40,
|
||||
}
|
||||
|
||||
union Any { Monster, TestSimpleTableWithEnum, MyGame.Example2.Monster }
|
||||
|
||||
union AnyUniqueAliases { M: Monster, TS: TestSimpleTableWithEnum, M2: MyGame.Example2.Monster }
|
||||
union AnyAmbiguousAliases { M1: Monster, M2: Monster, M3: Monster }
|
||||
|
||||
struct Test { a:short; b:byte; }
|
||||
|
||||
table TestSimpleTableWithEnum (csharp_partial, private) {
|
||||
color: Color = Green;
|
||||
}
|
||||
|
||||
struct Vec3 (force_align: 8) {
|
||||
x:float;
|
||||
y:float;
|
||||
z:float;
|
||||
test1:double;
|
||||
test2:Color;
|
||||
test3:Test;
|
||||
}
|
||||
|
||||
struct Ability {
|
||||
id:uint(key);
|
||||
distance:uint;
|
||||
}
|
||||
|
||||
struct StructOfStructs {
|
||||
a: Ability;
|
||||
b: Test;
|
||||
c: Ability;
|
||||
}
|
||||
|
||||
struct StructOfStructsOfStructs {
|
||||
a: StructOfStructs;
|
||||
}
|
||||
|
||||
table Stat {
|
||||
id:string;
|
||||
val:long;
|
||||
count:ushort (key);
|
||||
}
|
||||
|
||||
table Referrable {
|
||||
id:ulong(key, hash:"fnv1a_64");
|
||||
}
|
||||
|
||||
/// an example documentation comment: "monster object"
|
||||
table Monster {
|
||||
pos:Vec3 (id: 0);
|
||||
hp:short = 100 (id: 2);
|
||||
mana:short = 150 (id: 1);
|
||||
name:string (id: 3, key);
|
||||
color:Color = Blue (id: 6);
|
||||
inventory:[ubyte] (id: 5);
|
||||
friendly:bool = false (deprecated, priority: 1, id: 4);
|
||||
/// an example documentation comment: this will end up in the generated code
|
||||
/// multiline too
|
||||
testarrayoftables:[Monster] (id: 11);
|
||||
testarrayofstring:[string] (id: 10);
|
||||
testarrayofstring2:[string] (id: 28);
|
||||
testarrayofbools:[bool] (id: 24);
|
||||
testarrayofsortedstruct:[Ability] (id: 29);
|
||||
enemy:MyGame.Example.Monster (id:12); // Test referring by full namespace.
|
||||
test:Any (id: 8);
|
||||
test4:[Test] (id: 9);
|
||||
test5:[Test] (id: 31);
|
||||
testnestedflatbuffer:[ubyte] (id:13, nested_flatbuffer: "Monster");
|
||||
testempty:Stat (id:14);
|
||||
testbool:bool (id:15);
|
||||
testhashs32_fnv1:int (id:16, hash:"fnv1_32");
|
||||
testhashu32_fnv1:uint (id:17, hash:"fnv1_32");
|
||||
testhashs64_fnv1:long (id:18, hash:"fnv1_64");
|
||||
testhashu64_fnv1:ulong (id:19, hash:"fnv1_64");
|
||||
testhashs32_fnv1a:int (id:20, hash:"fnv1a_32");
|
||||
testhashu32_fnv1a:uint (id:21, hash:"fnv1a_32", cpp_type:"Stat");
|
||||
testhashs64_fnv1a:long (id:22, hash:"fnv1a_64");
|
||||
testhashu64_fnv1a:ulong (id:23, hash:"fnv1a_64");
|
||||
testf:float = 3.14159 (id:25);
|
||||
testf2:float = 3 (id:26);
|
||||
testf3:float (id:27);
|
||||
flex:[ubyte] (id:30, flexbuffer);
|
||||
vector_of_longs:[long] (id:32);
|
||||
vector_of_doubles:[double] (id:33);
|
||||
parent_namespace_test:InParentNamespace (id:34);
|
||||
vector_of_referrables:[Referrable](id:35);
|
||||
single_weak_reference:ulong(id:36, hash:"fnv1a_64", cpp_type:"ReferrableT");
|
||||
vector_of_weak_references:[ulong](id:37, hash:"fnv1a_64", cpp_type:"ReferrableT");
|
||||
vector_of_strong_referrables:[Referrable](id:38, cpp_ptr_type:"default_ptr_type"); //was shared_ptr
|
||||
co_owning_reference:ulong(id:39, hash:"fnv1a_64", cpp_type:"ReferrableT", cpp_ptr_type:"naked"); //was shared_ptr as well
|
||||
vector_of_co_owning_references:[ulong](id:40, hash:"fnv1a_64", cpp_type:"ReferrableT", cpp_ptr_type:"default_ptr_type", cpp_ptr_type_get:".get()"); //was shared_ptr
|
||||
non_owning_reference:ulong(id:41, hash:"fnv1a_64", cpp_type:"ReferrableT", cpp_ptr_type:"naked", cpp_ptr_type_get:""); //was weak_ptr
|
||||
vector_of_non_owning_references:[ulong](id:42, hash:"fnv1a_64", cpp_type:"ReferrableT", cpp_ptr_type:"naked", cpp_ptr_type_get:""); //was weak_ptr
|
||||
any_unique:AnyUniqueAliases(id:44);
|
||||
any_ambiguous:AnyAmbiguousAliases (id:46);
|
||||
vector_of_enums:[Color] (id:47);
|
||||
signed_enum:Race = None (id:48);
|
||||
testrequirednestedflatbuffer:[ubyte] (id:49, nested_flatbuffer: "Monster");
|
||||
scalar_key_sorted_tables:[Stat] (id: 50);
|
||||
native_inline:Test (id: 51, native_inline);
|
||||
// The default value of this enum will be a numeric zero, which isn't a valid
|
||||
// enum value.
|
||||
long_enum_non_enum_default:LongEnum (id: 52);
|
||||
long_enum_normal_default:LongEnum = LongOne (id: 53);
|
||||
// Test that default values nan and +/-inf work.
|
||||
nan_default:float = nan (id: 54);
|
||||
inf_default:float = inf (id: 55);
|
||||
positive_inf_default:float = +inf (id: 56);
|
||||
infinity_default:float = infinity (id: 57);
|
||||
positive_infinity_default:float = +infinity (id: 58);
|
||||
negative_inf_default:float = -inf (id: 59);
|
||||
negative_infinity_default:float = -infinity (id: 60);
|
||||
double_inf_default:double = inf (id: 61);
|
||||
}
|
||||
|
||||
table TypeAliases {
|
||||
i8:int8;
|
||||
u8:uint8;
|
||||
i16:int16;
|
||||
u16:uint16;
|
||||
i32:int32;
|
||||
u32:uint32;
|
||||
i64:int64;
|
||||
u64:uint64;
|
||||
f32:float32;
|
||||
f64:float64;
|
||||
v8:[int8];
|
||||
vf64:[float64];
|
||||
}
|
||||
|
||||
rpc_service MonsterStorage {
|
||||
Store(Monster):Stat (streaming: "none");
|
||||
Retrieve(Stat):Monster (streaming: "server", idempotent);
|
||||
GetMaxHitPoint(Monster):Stat (streaming: "client");
|
||||
GetMinMaxHitPoints(Monster):Stat (streaming: "bidi");
|
||||
}
|
||||
|
||||
root_type Monster;
|
||||
|
||||
file_identifier "MONS";
|
||||
file_extension "mon";
|
@ -1,79 +0,0 @@
|
||||
// automatically generated by the FlatBuffers compiler, do not modify
|
||||
// ignore_for_file: unused_import, unused_field, unused_element, unused_local_variable
|
||||
|
||||
library my_game.example2;
|
||||
|
||||
import 'dart:typed_data' show Uint8List;
|
||||
import 'package:flat_buffers/flat_buffers.dart' as fb;
|
||||
|
||||
import './monster_test_my_game_generated.dart' as my_game;
|
||||
import './monster_test_my_game.example_generated.dart' as my_game_example;
|
||||
|
||||
import './include_test1_generated.dart';
|
||||
|
||||
class Monster {
|
||||
Monster._(this._bc, this._bcOffset);
|
||||
factory Monster(List<int> bytes) {
|
||||
final rootRef = fb.BufferContext.fromBytes(bytes);
|
||||
return reader.read(rootRef, 0);
|
||||
}
|
||||
|
||||
static const fb.Reader<Monster> reader = _MonsterReader();
|
||||
|
||||
final fb.BufferContext _bc;
|
||||
final int _bcOffset;
|
||||
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'Monster{}';
|
||||
}
|
||||
|
||||
MonsterT unpack() => MonsterT();
|
||||
|
||||
static int pack(fb.Builder fbBuilder, MonsterT? object) {
|
||||
if (object == null) return 0;
|
||||
return object.pack(fbBuilder);
|
||||
}
|
||||
}
|
||||
|
||||
class MonsterT implements fb.Packable {
|
||||
@override
|
||||
int pack(fb.Builder fbBuilder) {
|
||||
fbBuilder.startTable(0);
|
||||
return fbBuilder.endTable();
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'MonsterT{}';
|
||||
}
|
||||
}
|
||||
|
||||
class _MonsterReader extends fb.TableReader<Monster> {
|
||||
const _MonsterReader();
|
||||
|
||||
@override
|
||||
Monster createObject(fb.BufferContext bc, int offset) =>
|
||||
Monster._(bc, offset);
|
||||
}
|
||||
|
||||
class MonsterObjectBuilder extends fb.ObjectBuilder {
|
||||
|
||||
MonsterObjectBuilder();
|
||||
|
||||
/// Finish building, and store into the [fbBuilder].
|
||||
@override
|
||||
int finish(fb.Builder fbBuilder) {
|
||||
fbBuilder.startTable(0);
|
||||
return fbBuilder.endTable();
|
||||
}
|
||||
|
||||
/// Convenience method to serialize to byte list.
|
||||
@override
|
||||
Uint8List toBytes([String? fileIdentifier]) {
|
||||
final fbBuilder = fb.Builder(deduplicateTables: false);
|
||||
fbBuilder.finish(finish(fbBuilder), fileIdentifier);
|
||||
return fbBuilder.buffer;
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,79 +0,0 @@
|
||||
// automatically generated by the FlatBuffers compiler, do not modify
|
||||
// ignore_for_file: unused_import, unused_field, unused_element, unused_local_variable
|
||||
|
||||
library my_game;
|
||||
|
||||
import 'dart:typed_data' show Uint8List;
|
||||
import 'package:flat_buffers/flat_buffers.dart' as fb;
|
||||
|
||||
import './monster_test_my_game.example_generated.dart' as my_game_example;
|
||||
import './monster_test_my_game.example2_generated.dart' as my_game_example2;
|
||||
|
||||
import './include_test1_generated.dart';
|
||||
|
||||
class InParentNamespace {
|
||||
InParentNamespace._(this._bc, this._bcOffset);
|
||||
factory InParentNamespace(List<int> bytes) {
|
||||
final rootRef = fb.BufferContext.fromBytes(bytes);
|
||||
return reader.read(rootRef, 0);
|
||||
}
|
||||
|
||||
static const fb.Reader<InParentNamespace> reader = _InParentNamespaceReader();
|
||||
|
||||
final fb.BufferContext _bc;
|
||||
final int _bcOffset;
|
||||
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'InParentNamespace{}';
|
||||
}
|
||||
|
||||
InParentNamespaceT unpack() => InParentNamespaceT();
|
||||
|
||||
static int pack(fb.Builder fbBuilder, InParentNamespaceT? object) {
|
||||
if (object == null) return 0;
|
||||
return object.pack(fbBuilder);
|
||||
}
|
||||
}
|
||||
|
||||
class InParentNamespaceT implements fb.Packable {
|
||||
@override
|
||||
int pack(fb.Builder fbBuilder) {
|
||||
fbBuilder.startTable(0);
|
||||
return fbBuilder.endTable();
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'InParentNamespaceT{}';
|
||||
}
|
||||
}
|
||||
|
||||
class _InParentNamespaceReader extends fb.TableReader<InParentNamespace> {
|
||||
const _InParentNamespaceReader();
|
||||
|
||||
@override
|
||||
InParentNamespace createObject(fb.BufferContext bc, int offset) =>
|
||||
InParentNamespace._(bc, offset);
|
||||
}
|
||||
|
||||
class InParentNamespaceObjectBuilder extends fb.ObjectBuilder {
|
||||
|
||||
InParentNamespaceObjectBuilder();
|
||||
|
||||
/// Finish building, and store into the [fbBuilder].
|
||||
@override
|
||||
int finish(fb.Builder fbBuilder) {
|
||||
fbBuilder.startTable(0);
|
||||
return fbBuilder.endTable();
|
||||
}
|
||||
|
||||
/// Convenience method to serialize to byte list.
|
||||
@override
|
||||
Uint8List toBytes([String? fileIdentifier]) {
|
||||
final fbBuilder = fb.Builder(deduplicateTables: false);
|
||||
fbBuilder.finish(finish(fbBuilder), fileIdentifier);
|
||||
return fbBuilder.buffer;
|
||||
}
|
||||
}
|
Binary file not shown.
@ -1,27 +0,0 @@
|
||||
# Go Echo Example
|
||||
|
||||
A simple example demonstrating how to send flatbuffers over the network in Go.
|
||||
|
||||
## Generate flatbuffer code
|
||||
|
||||
```
|
||||
flatc -g --gen-object-api --go-module-name echo hero.fbs net.fbs
|
||||
```
|
||||
|
||||
## Running example
|
||||
|
||||
1. Run go mod tidy to get dependencies
|
||||
```
|
||||
go mod tidy
|
||||
```
|
||||
|
||||
2. Start a server
|
||||
```
|
||||
go run server/server.go
|
||||
```
|
||||
|
||||
3. Run the client in another terminal
|
||||
```
|
||||
go run client/client.go
|
||||
```
|
||||
|
@ -1,51 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
|
||||
"echo/hero"
|
||||
"echo/net"
|
||||
|
||||
flatbuffers "github.com/google/flatbuffers/go"
|
||||
)
|
||||
|
||||
func RequestBody() *bytes.Reader {
|
||||
b := flatbuffers.NewBuilder(0)
|
||||
r := net.RequestT{Player: &hero.WarriorT{Name: "Krull", Hp: 100}}
|
||||
b.Finish(r.Pack(b))
|
||||
return bytes.NewReader(b.FinishedBytes())
|
||||
}
|
||||
|
||||
func ReadResponse(r *http.Response) {
|
||||
body, err := ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
fmt.Printf("Unable to read request body: %v\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
res := net.GetRootAsResponse(body, 0)
|
||||
player := res.Player(nil)
|
||||
|
||||
fmt.Printf("Got response (name: %v, hp: %v)\n", string(player.Name()), player.Hp())
|
||||
}
|
||||
|
||||
func main() {
|
||||
body := RequestBody()
|
||||
req, err := http.NewRequest("POST", "http://localhost:8080/echo", body)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
client := http.DefaultClient
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
ReadResponse(resp)
|
||||
}
|
@ -1,5 +0,0 @@
|
||||
module echo
|
||||
|
||||
go 1.19
|
||||
|
||||
require github.com/google/flatbuffers v22.10.26+incompatible
|
@ -1,6 +0,0 @@
|
||||
namespace hero;
|
||||
|
||||
table Warrior {
|
||||
name: string;
|
||||
hp: uint32;
|
||||
}
|
@ -1,100 +0,0 @@
|
||||
// Code generated by the FlatBuffers compiler. DO NOT EDIT.
|
||||
|
||||
package hero
|
||||
|
||||
import (
|
||||
flatbuffers "github.com/google/flatbuffers/go"
|
||||
)
|
||||
|
||||
type WarriorT struct {
|
||||
Name string `json:"name"`
|
||||
Hp uint32 `json:"hp"`
|
||||
}
|
||||
|
||||
func (t *WarriorT) Pack(builder *flatbuffers.Builder) flatbuffers.UOffsetT {
|
||||
if t == nil {
|
||||
return 0
|
||||
}
|
||||
nameOffset := flatbuffers.UOffsetT(0)
|
||||
if t.Name != "" {
|
||||
nameOffset = builder.CreateString(t.Name)
|
||||
}
|
||||
WarriorStart(builder)
|
||||
WarriorAddName(builder, nameOffset)
|
||||
WarriorAddHp(builder, t.Hp)
|
||||
return WarriorEnd(builder)
|
||||
}
|
||||
|
||||
func (rcv *Warrior) UnPackTo(t *WarriorT) {
|
||||
t.Name = string(rcv.Name())
|
||||
t.Hp = rcv.Hp()
|
||||
}
|
||||
|
||||
func (rcv *Warrior) UnPack() *WarriorT {
|
||||
if rcv == nil {
|
||||
return nil
|
||||
}
|
||||
t := &WarriorT{}
|
||||
rcv.UnPackTo(t)
|
||||
return t
|
||||
}
|
||||
|
||||
type Warrior struct {
|
||||
_tab flatbuffers.Table
|
||||
}
|
||||
|
||||
func GetRootAsWarrior(buf []byte, offset flatbuffers.UOffsetT) *Warrior {
|
||||
n := flatbuffers.GetUOffsetT(buf[offset:])
|
||||
x := &Warrior{}
|
||||
x.Init(buf, n+offset)
|
||||
return x
|
||||
}
|
||||
|
||||
func GetSizePrefixedRootAsWarrior(buf []byte, offset flatbuffers.UOffsetT) *Warrior {
|
||||
n := flatbuffers.GetUOffsetT(buf[offset+flatbuffers.SizeUint32:])
|
||||
x := &Warrior{}
|
||||
x.Init(buf, n+offset+flatbuffers.SizeUint32)
|
||||
return x
|
||||
}
|
||||
|
||||
func (rcv *Warrior) Init(buf []byte, i flatbuffers.UOffsetT) {
|
||||
rcv._tab.Bytes = buf
|
||||
rcv._tab.Pos = i
|
||||
}
|
||||
|
||||
func (rcv *Warrior) Table() flatbuffers.Table {
|
||||
return rcv._tab
|
||||
}
|
||||
|
||||
func (rcv *Warrior) Name() []byte {
|
||||
o := flatbuffers.UOffsetT(rcv._tab.Offset(4))
|
||||
if o != 0 {
|
||||
return rcv._tab.ByteVector(o + rcv._tab.Pos)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (rcv *Warrior) Hp() uint32 {
|
||||
o := flatbuffers.UOffsetT(rcv._tab.Offset(6))
|
||||
if o != 0 {
|
||||
return rcv._tab.GetUint32(o + rcv._tab.Pos)
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (rcv *Warrior) MutateHp(n uint32) bool {
|
||||
return rcv._tab.MutateUint32Slot(6, n)
|
||||
}
|
||||
|
||||
func WarriorStart(builder *flatbuffers.Builder) {
|
||||
builder.StartObject(2)
|
||||
}
|
||||
func WarriorAddName(builder *flatbuffers.Builder, name flatbuffers.UOffsetT) {
|
||||
builder.PrependUOffsetTSlot(0, flatbuffers.UOffsetT(name), 0)
|
||||
}
|
||||
func WarriorAddHp(builder *flatbuffers.Builder, hp uint32) {
|
||||
builder.PrependUint32Slot(1, hp, 0)
|
||||
}
|
||||
func WarriorEnd(builder *flatbuffers.Builder) flatbuffers.UOffsetT {
|
||||
return builder.EndObject()
|
||||
}
|
11
third_party/flatbuffers/examples/go-echo/net.fbs
vendored
11
third_party/flatbuffers/examples/go-echo/net.fbs
vendored
@ -1,11 +0,0 @@
|
||||
include "hero.fbs";
|
||||
|
||||
namespace net;
|
||||
|
||||
table Request {
|
||||
player: hero.Warrior;
|
||||
}
|
||||
|
||||
table Response {
|
||||
player: hero.Warrior;
|
||||
}
|
@ -1,86 +0,0 @@
|
||||
// Code generated by the FlatBuffers compiler. DO NOT EDIT.
|
||||
|
||||
package net
|
||||
|
||||
import (
|
||||
flatbuffers "github.com/google/flatbuffers/go"
|
||||
|
||||
hero "echo/hero"
|
||||
)
|
||||
|
||||
type RequestT struct {
|
||||
Player *hero.WarriorT `json:"player"`
|
||||
}
|
||||
|
||||
func (t *RequestT) Pack(builder *flatbuffers.Builder) flatbuffers.UOffsetT {
|
||||
if t == nil {
|
||||
return 0
|
||||
}
|
||||
playerOffset := t.Player.Pack(builder)
|
||||
RequestStart(builder)
|
||||
RequestAddPlayer(builder, playerOffset)
|
||||
return RequestEnd(builder)
|
||||
}
|
||||
|
||||
func (rcv *Request) UnPackTo(t *RequestT) {
|
||||
t.Player = rcv.Player(nil).UnPack()
|
||||
}
|
||||
|
||||
func (rcv *Request) UnPack() *RequestT {
|
||||
if rcv == nil {
|
||||
return nil
|
||||
}
|
||||
t := &RequestT{}
|
||||
rcv.UnPackTo(t)
|
||||
return t
|
||||
}
|
||||
|
||||
type Request struct {
|
||||
_tab flatbuffers.Table
|
||||
}
|
||||
|
||||
func GetRootAsRequest(buf []byte, offset flatbuffers.UOffsetT) *Request {
|
||||
n := flatbuffers.GetUOffsetT(buf[offset:])
|
||||
x := &Request{}
|
||||
x.Init(buf, n+offset)
|
||||
return x
|
||||
}
|
||||
|
||||
func GetSizePrefixedRootAsRequest(buf []byte, offset flatbuffers.UOffsetT) *Request {
|
||||
n := flatbuffers.GetUOffsetT(buf[offset+flatbuffers.SizeUint32:])
|
||||
x := &Request{}
|
||||
x.Init(buf, n+offset+flatbuffers.SizeUint32)
|
||||
return x
|
||||
}
|
||||
|
||||
func (rcv *Request) Init(buf []byte, i flatbuffers.UOffsetT) {
|
||||
rcv._tab.Bytes = buf
|
||||
rcv._tab.Pos = i
|
||||
}
|
||||
|
||||
func (rcv *Request) Table() flatbuffers.Table {
|
||||
return rcv._tab
|
||||
}
|
||||
|
||||
func (rcv *Request) Player(obj *hero.Warrior) *hero.Warrior {
|
||||
o := flatbuffers.UOffsetT(rcv._tab.Offset(4))
|
||||
if o != 0 {
|
||||
x := rcv._tab.Indirect(o + rcv._tab.Pos)
|
||||
if obj == nil {
|
||||
obj = new(hero.Warrior)
|
||||
}
|
||||
obj.Init(rcv._tab.Bytes, x)
|
||||
return obj
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func RequestStart(builder *flatbuffers.Builder) {
|
||||
builder.StartObject(1)
|
||||
}
|
||||
func RequestAddPlayer(builder *flatbuffers.Builder, player flatbuffers.UOffsetT) {
|
||||
builder.PrependUOffsetTSlot(0, flatbuffers.UOffsetT(player), 0)
|
||||
}
|
||||
func RequestEnd(builder *flatbuffers.Builder) flatbuffers.UOffsetT {
|
||||
return builder.EndObject()
|
||||
}
|
@ -1,86 +0,0 @@
|
||||
// Code generated by the FlatBuffers compiler. DO NOT EDIT.
|
||||
|
||||
package net
|
||||
|
||||
import (
|
||||
flatbuffers "github.com/google/flatbuffers/go"
|
||||
|
||||
hero "echo/hero"
|
||||
)
|
||||
|
||||
type ResponseT struct {
|
||||
Player *hero.WarriorT `json:"player"`
|
||||
}
|
||||
|
||||
func (t *ResponseT) Pack(builder *flatbuffers.Builder) flatbuffers.UOffsetT {
|
||||
if t == nil {
|
||||
return 0
|
||||
}
|
||||
playerOffset := t.Player.Pack(builder)
|
||||
ResponseStart(builder)
|
||||
ResponseAddPlayer(builder, playerOffset)
|
||||
return ResponseEnd(builder)
|
||||
}
|
||||
|
||||
func (rcv *Response) UnPackTo(t *ResponseT) {
|
||||
t.Player = rcv.Player(nil).UnPack()
|
||||
}
|
||||
|
||||
func (rcv *Response) UnPack() *ResponseT {
|
||||
if rcv == nil {
|
||||
return nil
|
||||
}
|
||||
t := &ResponseT{}
|
||||
rcv.UnPackTo(t)
|
||||
return t
|
||||
}
|
||||
|
||||
type Response struct {
|
||||
_tab flatbuffers.Table
|
||||
}
|
||||
|
||||
func GetRootAsResponse(buf []byte, offset flatbuffers.UOffsetT) *Response {
|
||||
n := flatbuffers.GetUOffsetT(buf[offset:])
|
||||
x := &Response{}
|
||||
x.Init(buf, n+offset)
|
||||
return x
|
||||
}
|
||||
|
||||
func GetSizePrefixedRootAsResponse(buf []byte, offset flatbuffers.UOffsetT) *Response {
|
||||
n := flatbuffers.GetUOffsetT(buf[offset+flatbuffers.SizeUint32:])
|
||||
x := &Response{}
|
||||
x.Init(buf, n+offset+flatbuffers.SizeUint32)
|
||||
return x
|
||||
}
|
||||
|
||||
func (rcv *Response) Init(buf []byte, i flatbuffers.UOffsetT) {
|
||||
rcv._tab.Bytes = buf
|
||||
rcv._tab.Pos = i
|
||||
}
|
||||
|
||||
func (rcv *Response) Table() flatbuffers.Table {
|
||||
return rcv._tab
|
||||
}
|
||||
|
||||
func (rcv *Response) Player(obj *hero.Warrior) *hero.Warrior {
|
||||
o := flatbuffers.UOffsetT(rcv._tab.Offset(4))
|
||||
if o != 0 {
|
||||
x := rcv._tab.Indirect(o + rcv._tab.Pos)
|
||||
if obj == nil {
|
||||
obj = new(hero.Warrior)
|
||||
}
|
||||
obj.Init(rcv._tab.Bytes, x)
|
||||
return obj
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func ResponseStart(builder *flatbuffers.Builder) {
|
||||
builder.StartObject(1)
|
||||
}
|
||||
func ResponseAddPlayer(builder *flatbuffers.Builder, player flatbuffers.UOffsetT) {
|
||||
builder.PrependUOffsetTSlot(0, flatbuffers.UOffsetT(player), 0)
|
||||
}
|
||||
func ResponseEnd(builder *flatbuffers.Builder) flatbuffers.UOffsetT {
|
||||
return builder.EndObject()
|
||||
}
|
@ -1,29 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"echo/net"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func echo(w http.ResponseWriter, r *http.Request) {
|
||||
body, err := ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
fmt.Printf("Unable to read request body: %v\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
req := net.GetRootAsRequest(body, 0)
|
||||
player := req.Player(nil)
|
||||
|
||||
fmt.Printf("Got request (name: %v, hp: %v)\n", string(player.Name()), player.Hp())
|
||||
w.Write(body)
|
||||
}
|
||||
|
||||
func main() {
|
||||
http.HandleFunc("/echo", echo)
|
||||
|
||||
fmt.Println("Listening on port :8080")
|
||||
http.ListenAndServe(":8080", nil)
|
||||
}
|
23
third_party/flatbuffers/go/BUILD.bazel
vendored
23
third_party/flatbuffers/go/BUILD.bazel
vendored
@ -1,23 +0,0 @@
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||
|
||||
alias(
|
||||
name = "go_default_library",
|
||||
actual = ":go",
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go",
|
||||
srcs = [
|
||||
"builder.go",
|
||||
"doc.go",
|
||||
"encode.go",
|
||||
"grpc.go",
|
||||
"lib.go",
|
||||
"sizes.go",
|
||||
"struct.go",
|
||||
"table.go",
|
||||
],
|
||||
importpath = "github.com/google/flatbuffers/go",
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
856
third_party/flatbuffers/go/builder.go
vendored
856
third_party/flatbuffers/go/builder.go
vendored
@ -1,856 +0,0 @@
|
||||
package flatbuffers
|
||||
|
||||
import "sort"
|
||||
|
||||
// Builder is a state machine for creating FlatBuffer objects.
|
||||
// Use a Builder to construct object(s) starting from leaf nodes.
|
||||
//
|
||||
// A Builder constructs byte buffers in a last-first manner for simplicity and
|
||||
// performance.
|
||||
type Builder struct {
|
||||
// `Bytes` gives raw access to the buffer. Most users will want to use
|
||||
// FinishedBytes() instead.
|
||||
Bytes []byte
|
||||
|
||||
minalign int
|
||||
vtable []UOffsetT
|
||||
objectEnd UOffsetT
|
||||
vtables []UOffsetT
|
||||
head UOffsetT
|
||||
nested bool
|
||||
finished bool
|
||||
|
||||
sharedStrings map[string]UOffsetT
|
||||
}
|
||||
|
||||
const fileIdentifierLength = 4
|
||||
const sizePrefixLength = 4
|
||||
|
||||
// NewBuilder initializes a Builder of size `initial_size`.
|
||||
// The internal buffer is grown as needed.
|
||||
func NewBuilder(initialSize int) *Builder {
|
||||
if initialSize <= 0 {
|
||||
initialSize = 0
|
||||
}
|
||||
|
||||
b := &Builder{}
|
||||
b.Bytes = make([]byte, initialSize)
|
||||
b.head = UOffsetT(initialSize)
|
||||
b.minalign = 1
|
||||
b.vtables = make([]UOffsetT, 0, 16) // sensible default capacity
|
||||
return b
|
||||
}
|
||||
|
||||
// Reset truncates the underlying Builder buffer, facilitating alloc-free
|
||||
// reuse of a Builder. It also resets bookkeeping data.
|
||||
func (b *Builder) Reset() {
|
||||
if b.Bytes != nil {
|
||||
b.Bytes = b.Bytes[:cap(b.Bytes)]
|
||||
}
|
||||
|
||||
if b.vtables != nil {
|
||||
b.vtables = b.vtables[:0]
|
||||
}
|
||||
|
||||
if b.vtable != nil {
|
||||
b.vtable = b.vtable[:0]
|
||||
}
|
||||
|
||||
if b.sharedStrings != nil {
|
||||
for key := range b.sharedStrings {
|
||||
delete(b.sharedStrings, key)
|
||||
}
|
||||
}
|
||||
|
||||
b.head = UOffsetT(len(b.Bytes))
|
||||
b.minalign = 1
|
||||
b.nested = false
|
||||
b.finished = false
|
||||
}
|
||||
|
||||
// FinishedBytes returns a pointer to the written data in the byte buffer.
|
||||
// Panics if the builder is not in a finished state (which is caused by calling
|
||||
// `Finish()`).
|
||||
func (b *Builder) FinishedBytes() []byte {
|
||||
b.assertFinished()
|
||||
return b.Bytes[b.Head():]
|
||||
}
|
||||
|
||||
// StartObject initializes bookkeeping for writing a new object.
|
||||
func (b *Builder) StartObject(numfields int) {
|
||||
b.assertNotNested()
|
||||
b.nested = true
|
||||
|
||||
// use 32-bit offsets so that arithmetic doesn't overflow.
|
||||
if cap(b.vtable) < numfields || b.vtable == nil {
|
||||
b.vtable = make([]UOffsetT, numfields)
|
||||
} else {
|
||||
b.vtable = b.vtable[:numfields]
|
||||
for i := 0; i < len(b.vtable); i++ {
|
||||
b.vtable[i] = 0
|
||||
}
|
||||
}
|
||||
|
||||
b.objectEnd = b.Offset()
|
||||
}
|
||||
|
||||
// WriteVtable serializes the vtable for the current object, if applicable.
|
||||
//
|
||||
// Before writing out the vtable, this checks pre-existing vtables for equality
|
||||
// to this one. If an equal vtable is found, point the object to the existing
|
||||
// vtable and return.
|
||||
//
|
||||
// Because vtable values are sensitive to alignment of object data, not all
|
||||
// logically-equal vtables will be deduplicated.
|
||||
//
|
||||
// A vtable has the following format:
|
||||
// <VOffsetT: size of the vtable in bytes, including this value>
|
||||
// <VOffsetT: size of the object in bytes, including the vtable offset>
|
||||
// <VOffsetT: offset for a field> * N, where N is the number of fields in
|
||||
// the schema for this type. Includes deprecated fields.
|
||||
// Thus, a vtable is made of 2 + N elements, each SizeVOffsetT bytes wide.
|
||||
//
|
||||
// An object has the following format:
|
||||
// <SOffsetT: offset to this object's vtable (may be negative)>
|
||||
// <byte: data>+
|
||||
func (b *Builder) WriteVtable() (n UOffsetT) {
|
||||
// Prepend a zero scalar to the object. Later in this function we'll
|
||||
// write an offset here that points to the object's vtable:
|
||||
b.PrependSOffsetT(0)
|
||||
|
||||
objectOffset := b.Offset()
|
||||
existingVtable := UOffsetT(0)
|
||||
|
||||
// Trim vtable of trailing zeroes.
|
||||
i := len(b.vtable) - 1
|
||||
for ; i >= 0 && b.vtable[i] == 0; i-- {
|
||||
}
|
||||
b.vtable = b.vtable[:i+1]
|
||||
|
||||
// Search backwards through existing vtables, because similar vtables
|
||||
// are likely to have been recently appended. See
|
||||
// BenchmarkVtableDeduplication for a case in which this heuristic
|
||||
// saves about 30% of the time used in writing objects with duplicate
|
||||
// tables.
|
||||
for i := len(b.vtables) - 1; i >= 0; i-- {
|
||||
// Find the other vtable, which is associated with `i`:
|
||||
vt2Offset := b.vtables[i]
|
||||
vt2Start := len(b.Bytes) - int(vt2Offset)
|
||||
vt2Len := GetVOffsetT(b.Bytes[vt2Start:])
|
||||
|
||||
metadata := VtableMetadataFields * SizeVOffsetT
|
||||
vt2End := vt2Start + int(vt2Len)
|
||||
vt2 := b.Bytes[vt2Start+metadata : vt2End]
|
||||
|
||||
// Compare the other vtable to the one under consideration.
|
||||
// If they are equal, store the offset and break:
|
||||
if vtableEqual(b.vtable, objectOffset, vt2) {
|
||||
existingVtable = vt2Offset
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if existingVtable == 0 {
|
||||
// Did not find a vtable, so write this one to the buffer.
|
||||
|
||||
// Write out the current vtable in reverse , because
|
||||
// serialization occurs in last-first order:
|
||||
for i := len(b.vtable) - 1; i >= 0; i-- {
|
||||
var off UOffsetT
|
||||
if b.vtable[i] != 0 {
|
||||
// Forward reference to field;
|
||||
// use 32bit number to assert no overflow:
|
||||
off = objectOffset - b.vtable[i]
|
||||
}
|
||||
|
||||
b.PrependVOffsetT(VOffsetT(off))
|
||||
}
|
||||
|
||||
// The two metadata fields are written last.
|
||||
|
||||
// First, store the object bytesize:
|
||||
objectSize := objectOffset - b.objectEnd
|
||||
b.PrependVOffsetT(VOffsetT(objectSize))
|
||||
|
||||
// Second, store the vtable bytesize:
|
||||
vBytes := (len(b.vtable) + VtableMetadataFields) * SizeVOffsetT
|
||||
b.PrependVOffsetT(VOffsetT(vBytes))
|
||||
|
||||
// Next, write the offset to the new vtable in the
|
||||
// already-allocated SOffsetT at the beginning of this object:
|
||||
objectStart := SOffsetT(len(b.Bytes)) - SOffsetT(objectOffset)
|
||||
WriteSOffsetT(b.Bytes[objectStart:],
|
||||
SOffsetT(b.Offset())-SOffsetT(objectOffset))
|
||||
|
||||
// Finally, store this vtable in memory for future
|
||||
// deduplication:
|
||||
b.vtables = append(b.vtables, b.Offset())
|
||||
} else {
|
||||
// Found a duplicate vtable.
|
||||
|
||||
objectStart := SOffsetT(len(b.Bytes)) - SOffsetT(objectOffset)
|
||||
b.head = UOffsetT(objectStart)
|
||||
|
||||
// Write the offset to the found vtable in the
|
||||
// already-allocated SOffsetT at the beginning of this object:
|
||||
WriteSOffsetT(b.Bytes[b.head:],
|
||||
SOffsetT(existingVtable)-SOffsetT(objectOffset))
|
||||
}
|
||||
|
||||
b.vtable = b.vtable[:0]
|
||||
return objectOffset
|
||||
}
|
||||
|
||||
// EndObject writes data necessary to finish object construction.
|
||||
func (b *Builder) EndObject() UOffsetT {
|
||||
b.assertNested()
|
||||
n := b.WriteVtable()
|
||||
b.nested = false
|
||||
return n
|
||||
}
|
||||
|
||||
// Doubles the size of the byteslice, and copies the old data towards the
|
||||
// end of the new byteslice (since we build the buffer backwards).
|
||||
func (b *Builder) growByteBuffer() {
|
||||
if (int64(len(b.Bytes)) & int64(0xC0000000)) != 0 {
|
||||
panic("cannot grow buffer beyond 2 gigabytes")
|
||||
}
|
||||
newLen := len(b.Bytes) * 2
|
||||
if newLen == 0 {
|
||||
newLen = 1
|
||||
}
|
||||
|
||||
if cap(b.Bytes) >= newLen {
|
||||
b.Bytes = b.Bytes[:newLen]
|
||||
} else {
|
||||
extension := make([]byte, newLen-len(b.Bytes))
|
||||
b.Bytes = append(b.Bytes, extension...)
|
||||
}
|
||||
|
||||
middle := newLen / 2
|
||||
copy(b.Bytes[middle:], b.Bytes[:middle])
|
||||
}
|
||||
|
||||
// Head gives the start of useful data in the underlying byte buffer.
|
||||
// Note: unlike other functions, this value is interpreted as from the left.
|
||||
func (b *Builder) Head() UOffsetT {
|
||||
return b.head
|
||||
}
|
||||
|
||||
// Offset relative to the end of the buffer.
|
||||
func (b *Builder) Offset() UOffsetT {
|
||||
return UOffsetT(len(b.Bytes)) - b.head
|
||||
}
|
||||
|
||||
// Pad places zeros at the current offset.
|
||||
func (b *Builder) Pad(n int) {
|
||||
for i := 0; i < n; i++ {
|
||||
b.PlaceByte(0)
|
||||
}
|
||||
}
|
||||
|
||||
// Prep prepares to write an element of `size` after `additional_bytes`
|
||||
// have been written, e.g. if you write a string, you need to align such
|
||||
// the int length field is aligned to SizeInt32, and the string data follows it
|
||||
// directly.
|
||||
// If all you need to do is align, `additionalBytes` will be 0.
|
||||
func (b *Builder) Prep(size, additionalBytes int) {
|
||||
// Track the biggest thing we've ever aligned to.
|
||||
if size > b.minalign {
|
||||
b.minalign = size
|
||||
}
|
||||
// Find the amount of alignment needed such that `size` is properly
|
||||
// aligned after `additionalBytes`:
|
||||
alignSize := (^(len(b.Bytes) - int(b.Head()) + additionalBytes)) + 1
|
||||
alignSize &= (size - 1)
|
||||
|
||||
// Reallocate the buffer if needed:
|
||||
for int(b.head) <= alignSize+size+additionalBytes {
|
||||
oldBufSize := len(b.Bytes)
|
||||
b.growByteBuffer()
|
||||
b.head += UOffsetT(len(b.Bytes) - oldBufSize)
|
||||
}
|
||||
b.Pad(alignSize)
|
||||
}
|
||||
|
||||
// PrependSOffsetT prepends an SOffsetT, relative to where it will be written.
|
||||
func (b *Builder) PrependSOffsetT(off SOffsetT) {
|
||||
b.Prep(SizeSOffsetT, 0) // Ensure alignment is already done.
|
||||
if !(UOffsetT(off) <= b.Offset()) {
|
||||
panic("unreachable: off <= b.Offset()")
|
||||
}
|
||||
off2 := SOffsetT(b.Offset()) - off + SOffsetT(SizeSOffsetT)
|
||||
b.PlaceSOffsetT(off2)
|
||||
}
|
||||
|
||||
// PrependUOffsetT prepends an UOffsetT, relative to where it will be written.
|
||||
func (b *Builder) PrependUOffsetT(off UOffsetT) {
|
||||
b.Prep(SizeUOffsetT, 0) // Ensure alignment is already done.
|
||||
if !(off <= b.Offset()) {
|
||||
panic("unreachable: off <= b.Offset()")
|
||||
}
|
||||
off2 := b.Offset() - off + UOffsetT(SizeUOffsetT)
|
||||
b.PlaceUOffsetT(off2)
|
||||
}
|
||||
|
||||
// StartVector initializes bookkeeping for writing a new vector.
|
||||
//
|
||||
// A vector has the following format:
|
||||
// <UOffsetT: number of elements in this vector>
|
||||
// <T: data>+, where T is the type of elements of this vector.
|
||||
func (b *Builder) StartVector(elemSize, numElems, alignment int) UOffsetT {
|
||||
b.assertNotNested()
|
||||
b.nested = true
|
||||
b.Prep(SizeUint32, elemSize*numElems)
|
||||
b.Prep(alignment, elemSize*numElems) // Just in case alignment > int.
|
||||
return b.Offset()
|
||||
}
|
||||
|
||||
// EndVector writes data necessary to finish vector construction.
|
||||
func (b *Builder) EndVector(vectorNumElems int) UOffsetT {
|
||||
b.assertNested()
|
||||
|
||||
// we already made space for this, so write without PrependUint32
|
||||
b.PlaceUOffsetT(UOffsetT(vectorNumElems))
|
||||
|
||||
b.nested = false
|
||||
return b.Offset()
|
||||
}
|
||||
|
||||
// CreateVectorOfTables serializes slice of table offsets into a vector.
|
||||
func (b *Builder) CreateVectorOfTables(offsets []UOffsetT) UOffsetT {
|
||||
b.assertNotNested()
|
||||
b.StartVector(4, len(offsets), 4)
|
||||
for i := len(offsets) - 1; i >= 0; i-- {
|
||||
b.PrependUOffsetT(offsets[i])
|
||||
}
|
||||
return b.EndVector(len(offsets))
|
||||
}
|
||||
|
||||
type KeyCompare func(o1, o2 UOffsetT, buf []byte) bool
|
||||
|
||||
func (b *Builder) CreateVectorOfSortedTables(offsets []UOffsetT, keyCompare KeyCompare) UOffsetT {
|
||||
sort.Slice(offsets, func(i, j int) bool {
|
||||
return keyCompare(offsets[i], offsets[j], b.Bytes)
|
||||
})
|
||||
return b.CreateVectorOfTables(offsets)
|
||||
}
|
||||
|
||||
// CreateSharedString Checks if the string is already written
|
||||
// to the buffer before calling CreateString
|
||||
func (b *Builder) CreateSharedString(s string) UOffsetT {
|
||||
if b.sharedStrings == nil {
|
||||
b.sharedStrings = make(map[string]UOffsetT)
|
||||
}
|
||||
if v, ok := b.sharedStrings[s]; ok {
|
||||
return v
|
||||
}
|
||||
off := b.CreateString(s)
|
||||
b.sharedStrings[s] = off
|
||||
return off
|
||||
}
|
||||
|
||||
// CreateString writes a null-terminated string as a vector.
|
||||
func (b *Builder) CreateString(s string) UOffsetT {
|
||||
b.assertNotNested()
|
||||
b.nested = true
|
||||
|
||||
b.Prep(int(SizeUOffsetT), (len(s)+1)*SizeByte)
|
||||
b.PlaceByte(0)
|
||||
|
||||
l := UOffsetT(len(s))
|
||||
|
||||
b.head -= l
|
||||
copy(b.Bytes[b.head:b.head+l], s)
|
||||
|
||||
return b.EndVector(len(s))
|
||||
}
|
||||
|
||||
// CreateByteString writes a byte slice as a string (null-terminated).
|
||||
func (b *Builder) CreateByteString(s []byte) UOffsetT {
|
||||
b.assertNotNested()
|
||||
b.nested = true
|
||||
|
||||
b.Prep(int(SizeUOffsetT), (len(s)+1)*SizeByte)
|
||||
b.PlaceByte(0)
|
||||
|
||||
l := UOffsetT(len(s))
|
||||
|
||||
b.head -= l
|
||||
copy(b.Bytes[b.head:b.head+l], s)
|
||||
|
||||
return b.EndVector(len(s))
|
||||
}
|
||||
|
||||
// CreateByteVector writes a ubyte vector
|
||||
func (b *Builder) CreateByteVector(v []byte) UOffsetT {
|
||||
b.assertNotNested()
|
||||
b.nested = true
|
||||
|
||||
b.Prep(int(SizeUOffsetT), len(v)*SizeByte)
|
||||
|
||||
l := UOffsetT(len(v))
|
||||
|
||||
b.head -= l
|
||||
copy(b.Bytes[b.head:b.head+l], v)
|
||||
|
||||
return b.EndVector(len(v))
|
||||
}
|
||||
|
||||
func (b *Builder) assertNested() {
|
||||
// If you get this assert, you're in an object while trying to write
|
||||
// data that belongs outside of an object.
|
||||
// To fix this, write non-inline data (like vectors) before creating
|
||||
// objects.
|
||||
if !b.nested {
|
||||
panic("Incorrect creation order: must be inside object.")
|
||||
}
|
||||
}
|
||||
|
||||
func (b *Builder) assertNotNested() {
|
||||
// If you hit this, you're trying to construct a Table/Vector/String
|
||||
// during the construction of its parent table (between the MyTableBuilder
|
||||
// and builder.Finish()).
|
||||
// Move the creation of these sub-objects to above the MyTableBuilder to
|
||||
// not get this assert.
|
||||
// Ignoring this assert may appear to work in simple cases, but the reason
|
||||
// it is here is that storing objects in-line may cause vtable offsets
|
||||
// to not fit anymore. It also leads to vtable duplication.
|
||||
if b.nested {
|
||||
panic("Incorrect creation order: object must not be nested.")
|
||||
}
|
||||
}
|
||||
|
||||
func (b *Builder) assertFinished() {
|
||||
// If you get this assert, you're attempting to get access a buffer
|
||||
// which hasn't been finished yet. Be sure to call builder.Finish()
|
||||
// with your root table.
|
||||
// If you really need to access an unfinished buffer, use the Bytes
|
||||
// buffer directly.
|
||||
if !b.finished {
|
||||
panic("Incorrect use of FinishedBytes(): must call 'Finish' first.")
|
||||
}
|
||||
}
|
||||
|
||||
// PrependBoolSlot prepends a bool onto the object at vtable slot `o`.
|
||||
// If value `x` equals default `d`, then the slot will be set to zero and no
|
||||
// other data will be written.
|
||||
func (b *Builder) PrependBoolSlot(o int, x, d bool) {
|
||||
val := byte(0)
|
||||
if x {
|
||||
val = 1
|
||||
}
|
||||
def := byte(0)
|
||||
if d {
|
||||
def = 1
|
||||
}
|
||||
b.PrependByteSlot(o, val, def)
|
||||
}
|
||||
|
||||
// PrependByteSlot prepends a byte onto the object at vtable slot `o`.
|
||||
// If value `x` equals default `d`, then the slot will be set to zero and no
|
||||
// other data will be written.
|
||||
func (b *Builder) PrependByteSlot(o int, x, d byte) {
|
||||
if x != d {
|
||||
b.PrependByte(x)
|
||||
b.Slot(o)
|
||||
}
|
||||
}
|
||||
|
||||
// PrependUint8Slot prepends a uint8 onto the object at vtable slot `o`.
|
||||
// If value `x` equals default `d`, then the slot will be set to zero and no
|
||||
// other data will be written.
|
||||
func (b *Builder) PrependUint8Slot(o int, x, d uint8) {
|
||||
if x != d {
|
||||
b.PrependUint8(x)
|
||||
b.Slot(o)
|
||||
}
|
||||
}
|
||||
|
||||
// PrependUint16Slot prepends a uint16 onto the object at vtable slot `o`.
|
||||
// If value `x` equals default `d`, then the slot will be set to zero and no
|
||||
// other data will be written.
|
||||
func (b *Builder) PrependUint16Slot(o int, x, d uint16) {
|
||||
if x != d {
|
||||
b.PrependUint16(x)
|
||||
b.Slot(o)
|
||||
}
|
||||
}
|
||||
|
||||
// PrependUint32Slot prepends a uint32 onto the object at vtable slot `o`.
|
||||
// If value `x` equals default `d`, then the slot will be set to zero and no
|
||||
// other data will be written.
|
||||
func (b *Builder) PrependUint32Slot(o int, x, d uint32) {
|
||||
if x != d {
|
||||
b.PrependUint32(x)
|
||||
b.Slot(o)
|
||||
}
|
||||
}
|
||||
|
||||
// PrependUint64Slot prepends a uint64 onto the object at vtable slot `o`.
|
||||
// If value `x` equals default `d`, then the slot will be set to zero and no
|
||||
// other data will be written.
|
||||
func (b *Builder) PrependUint64Slot(o int, x, d uint64) {
|
||||
if x != d {
|
||||
b.PrependUint64(x)
|
||||
b.Slot(o)
|
||||
}
|
||||
}
|
||||
|
||||
// PrependInt8Slot prepends a int8 onto the object at vtable slot `o`.
|
||||
// If value `x` equals default `d`, then the slot will be set to zero and no
|
||||
// other data will be written.
|
||||
func (b *Builder) PrependInt8Slot(o int, x, d int8) {
|
||||
if x != d {
|
||||
b.PrependInt8(x)
|
||||
b.Slot(o)
|
||||
}
|
||||
}
|
||||
|
||||
// PrependInt16Slot prepends a int16 onto the object at vtable slot `o`.
|
||||
// If value `x` equals default `d`, then the slot will be set to zero and no
|
||||
// other data will be written.
|
||||
func (b *Builder) PrependInt16Slot(o int, x, d int16) {
|
||||
if x != d {
|
||||
b.PrependInt16(x)
|
||||
b.Slot(o)
|
||||
}
|
||||
}
|
||||
|
||||
// PrependInt32Slot prepends a int32 onto the object at vtable slot `o`.
|
||||
// If value `x` equals default `d`, then the slot will be set to zero and no
|
||||
// other data will be written.
|
||||
func (b *Builder) PrependInt32Slot(o int, x, d int32) {
|
||||
if x != d {
|
||||
b.PrependInt32(x)
|
||||
b.Slot(o)
|
||||
}
|
||||
}
|
||||
|
||||
// PrependInt64Slot prepends a int64 onto the object at vtable slot `o`.
|
||||
// If value `x` equals default `d`, then the slot will be set to zero and no
|
||||
// other data will be written.
|
||||
func (b *Builder) PrependInt64Slot(o int, x, d int64) {
|
||||
if x != d {
|
||||
b.PrependInt64(x)
|
||||
b.Slot(o)
|
||||
}
|
||||
}
|
||||
|
||||
// PrependFloat32Slot prepends a float32 onto the object at vtable slot `o`.
|
||||
// If value `x` equals default `d`, then the slot will be set to zero and no
|
||||
// other data will be written.
|
||||
func (b *Builder) PrependFloat32Slot(o int, x, d float32) {
|
||||
if x != d {
|
||||
b.PrependFloat32(x)
|
||||
b.Slot(o)
|
||||
}
|
||||
}
|
||||
|
||||
// PrependFloat64Slot prepends a float64 onto the object at vtable slot `o`.
|
||||
// If value `x` equals default `d`, then the slot will be set to zero and no
|
||||
// other data will be written.
|
||||
func (b *Builder) PrependFloat64Slot(o int, x, d float64) {
|
||||
if x != d {
|
||||
b.PrependFloat64(x)
|
||||
b.Slot(o)
|
||||
}
|
||||
}
|
||||
|
||||
// PrependUOffsetTSlot prepends an UOffsetT onto the object at vtable slot `o`.
|
||||
// If value `x` equals default `d`, then the slot will be set to zero and no
|
||||
// other data will be written.
|
||||
func (b *Builder) PrependUOffsetTSlot(o int, x, d UOffsetT) {
|
||||
if x != d {
|
||||
b.PrependUOffsetT(x)
|
||||
b.Slot(o)
|
||||
}
|
||||
}
|
||||
|
||||
// PrependStructSlot prepends a struct onto the object at vtable slot `o`.
|
||||
// Structs are stored inline, so nothing additional is being added.
|
||||
// In generated code, `d` is always 0.
|
||||
func (b *Builder) PrependStructSlot(voffset int, x, d UOffsetT) {
|
||||
if x != d {
|
||||
b.assertNested()
|
||||
if x != b.Offset() {
|
||||
panic("inline data write outside of object")
|
||||
}
|
||||
b.Slot(voffset)
|
||||
}
|
||||
}
|
||||
|
||||
// Slot sets the vtable key `voffset` to the current location in the buffer.
|
||||
func (b *Builder) Slot(slotnum int) {
|
||||
b.vtable[slotnum] = UOffsetT(b.Offset())
|
||||
}
|
||||
|
||||
// FinishWithFileIdentifier finalizes a buffer, pointing to the given `rootTable`.
|
||||
// as well as applys a file identifier
|
||||
func (b *Builder) FinishWithFileIdentifier(rootTable UOffsetT, fid []byte) {
|
||||
if fid == nil || len(fid) != fileIdentifierLength {
|
||||
panic("incorrect file identifier length")
|
||||
}
|
||||
// In order to add a file identifier to the flatbuffer message, we need
|
||||
// to prepare an alignment and file identifier length
|
||||
b.Prep(b.minalign, SizeInt32+fileIdentifierLength)
|
||||
for i := fileIdentifierLength - 1; i >= 0; i-- {
|
||||
// place the file identifier
|
||||
b.PlaceByte(fid[i])
|
||||
}
|
||||
// finish
|
||||
b.Finish(rootTable)
|
||||
}
|
||||
|
||||
// FinishSizePrefixed finalizes a buffer, pointing to the given `rootTable`.
|
||||
// The buffer is prefixed with the size of the buffer, excluding the size
|
||||
// of the prefix itself.
|
||||
func (b *Builder) FinishSizePrefixed(rootTable UOffsetT) {
|
||||
b.finish(rootTable, true)
|
||||
}
|
||||
|
||||
// FinishSizePrefixedWithFileIdentifier finalizes a buffer, pointing to the given `rootTable`
|
||||
// and applies a file identifier. The buffer is prefixed with the size of the buffer,
|
||||
// excluding the size of the prefix itself.
|
||||
func (b *Builder) FinishSizePrefixedWithFileIdentifier(rootTable UOffsetT, fid []byte) {
|
||||
if fid == nil || len(fid) != fileIdentifierLength {
|
||||
panic("incorrect file identifier length")
|
||||
}
|
||||
// In order to add a file identifier and size prefix to the flatbuffer message,
|
||||
// we need to prepare an alignment, a size prefix length, and file identifier length
|
||||
b.Prep(b.minalign, SizeInt32+fileIdentifierLength+sizePrefixLength)
|
||||
for i := fileIdentifierLength - 1; i >= 0; i-- {
|
||||
// place the file identifier
|
||||
b.PlaceByte(fid[i])
|
||||
}
|
||||
// finish
|
||||
b.finish(rootTable, true)
|
||||
}
|
||||
|
||||
// Finish finalizes a buffer, pointing to the given `rootTable`.
|
||||
func (b *Builder) Finish(rootTable UOffsetT) {
|
||||
b.finish(rootTable, false)
|
||||
}
|
||||
|
||||
// finish finalizes a buffer, pointing to the given `rootTable`
|
||||
// with an optional size prefix.
|
||||
func (b *Builder) finish(rootTable UOffsetT, sizePrefix bool) {
|
||||
b.assertNotNested()
|
||||
|
||||
if sizePrefix {
|
||||
b.Prep(b.minalign, SizeUOffsetT+sizePrefixLength)
|
||||
} else {
|
||||
b.Prep(b.minalign, SizeUOffsetT)
|
||||
}
|
||||
|
||||
b.PrependUOffsetT(rootTable)
|
||||
|
||||
if sizePrefix {
|
||||
b.PlaceUint32(uint32(b.Offset()))
|
||||
}
|
||||
|
||||
b.finished = true
|
||||
}
|
||||
|
||||
// vtableEqual compares an unwritten vtable to a written vtable.
|
||||
func vtableEqual(a []UOffsetT, objectStart UOffsetT, b []byte) bool {
|
||||
if len(a)*SizeVOffsetT != len(b) {
|
||||
return false
|
||||
}
|
||||
|
||||
for i := 0; i < len(a); i++ {
|
||||
x := GetVOffsetT(b[i*SizeVOffsetT : (i+1)*SizeVOffsetT])
|
||||
|
||||
// Skip vtable entries that indicate a default value.
|
||||
if x == 0 && a[i] == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
y := SOffsetT(objectStart) - SOffsetT(a[i])
|
||||
if SOffsetT(x) != y {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// PrependBool prepends a bool to the Builder buffer.
|
||||
// Aligns and checks for space.
|
||||
func (b *Builder) PrependBool(x bool) {
|
||||
b.Prep(SizeBool, 0)
|
||||
b.PlaceBool(x)
|
||||
}
|
||||
|
||||
// PrependUint8 prepends a uint8 to the Builder buffer.
|
||||
// Aligns and checks for space.
|
||||
func (b *Builder) PrependUint8(x uint8) {
|
||||
b.Prep(SizeUint8, 0)
|
||||
b.PlaceUint8(x)
|
||||
}
|
||||
|
||||
// PrependUint16 prepends a uint16 to the Builder buffer.
|
||||
// Aligns and checks for space.
|
||||
func (b *Builder) PrependUint16(x uint16) {
|
||||
b.Prep(SizeUint16, 0)
|
||||
b.PlaceUint16(x)
|
||||
}
|
||||
|
||||
// PrependUint32 prepends a uint32 to the Builder buffer.
|
||||
// Aligns and checks for space.
|
||||
func (b *Builder) PrependUint32(x uint32) {
|
||||
b.Prep(SizeUint32, 0)
|
||||
b.PlaceUint32(x)
|
||||
}
|
||||
|
||||
// PrependUint64 prepends a uint64 to the Builder buffer.
|
||||
// Aligns and checks for space.
|
||||
func (b *Builder) PrependUint64(x uint64) {
|
||||
b.Prep(SizeUint64, 0)
|
||||
b.PlaceUint64(x)
|
||||
}
|
||||
|
||||
// PrependInt8 prepends a int8 to the Builder buffer.
|
||||
// Aligns and checks for space.
|
||||
func (b *Builder) PrependInt8(x int8) {
|
||||
b.Prep(SizeInt8, 0)
|
||||
b.PlaceInt8(x)
|
||||
}
|
||||
|
||||
// PrependInt16 prepends a int16 to the Builder buffer.
|
||||
// Aligns and checks for space.
|
||||
func (b *Builder) PrependInt16(x int16) {
|
||||
b.Prep(SizeInt16, 0)
|
||||
b.PlaceInt16(x)
|
||||
}
|
||||
|
||||
// PrependInt32 prepends a int32 to the Builder buffer.
|
||||
// Aligns and checks for space.
|
||||
func (b *Builder) PrependInt32(x int32) {
|
||||
b.Prep(SizeInt32, 0)
|
||||
b.PlaceInt32(x)
|
||||
}
|
||||
|
||||
// PrependInt64 prepends a int64 to the Builder buffer.
|
||||
// Aligns and checks for space.
|
||||
func (b *Builder) PrependInt64(x int64) {
|
||||
b.Prep(SizeInt64, 0)
|
||||
b.PlaceInt64(x)
|
||||
}
|
||||
|
||||
// PrependFloat32 prepends a float32 to the Builder buffer.
|
||||
// Aligns and checks for space.
|
||||
func (b *Builder) PrependFloat32(x float32) {
|
||||
b.Prep(SizeFloat32, 0)
|
||||
b.PlaceFloat32(x)
|
||||
}
|
||||
|
||||
// PrependFloat64 prepends a float64 to the Builder buffer.
|
||||
// Aligns and checks for space.
|
||||
func (b *Builder) PrependFloat64(x float64) {
|
||||
b.Prep(SizeFloat64, 0)
|
||||
b.PlaceFloat64(x)
|
||||
}
|
||||
|
||||
// PrependByte prepends a byte to the Builder buffer.
|
||||
// Aligns and checks for space.
|
||||
func (b *Builder) PrependByte(x byte) {
|
||||
b.Prep(SizeByte, 0)
|
||||
b.PlaceByte(x)
|
||||
}
|
||||
|
||||
// PrependVOffsetT prepends a VOffsetT to the Builder buffer.
|
||||
// Aligns and checks for space.
|
||||
func (b *Builder) PrependVOffsetT(x VOffsetT) {
|
||||
b.Prep(SizeVOffsetT, 0)
|
||||
b.PlaceVOffsetT(x)
|
||||
}
|
||||
|
||||
// PlaceBool prepends a bool to the Builder, without checking for space.
|
||||
func (b *Builder) PlaceBool(x bool) {
|
||||
b.head -= UOffsetT(SizeBool)
|
||||
WriteBool(b.Bytes[b.head:], x)
|
||||
}
|
||||
|
||||
// PlaceUint8 prepends a uint8 to the Builder, without checking for space.
|
||||
func (b *Builder) PlaceUint8(x uint8) {
|
||||
b.head -= UOffsetT(SizeUint8)
|
||||
WriteUint8(b.Bytes[b.head:], x)
|
||||
}
|
||||
|
||||
// PlaceUint16 prepends a uint16 to the Builder, without checking for space.
|
||||
func (b *Builder) PlaceUint16(x uint16) {
|
||||
b.head -= UOffsetT(SizeUint16)
|
||||
WriteUint16(b.Bytes[b.head:], x)
|
||||
}
|
||||
|
||||
// PlaceUint32 prepends a uint32 to the Builder, without checking for space.
|
||||
func (b *Builder) PlaceUint32(x uint32) {
|
||||
b.head -= UOffsetT(SizeUint32)
|
||||
WriteUint32(b.Bytes[b.head:], x)
|
||||
}
|
||||
|
||||
// PlaceUint64 prepends a uint64 to the Builder, without checking for space.
|
||||
func (b *Builder) PlaceUint64(x uint64) {
|
||||
b.head -= UOffsetT(SizeUint64)
|
||||
WriteUint64(b.Bytes[b.head:], x)
|
||||
}
|
||||
|
||||
// PlaceInt8 prepends a int8 to the Builder, without checking for space.
|
||||
func (b *Builder) PlaceInt8(x int8) {
|
||||
b.head -= UOffsetT(SizeInt8)
|
||||
WriteInt8(b.Bytes[b.head:], x)
|
||||
}
|
||||
|
||||
// PlaceInt16 prepends a int16 to the Builder, without checking for space.
|
||||
func (b *Builder) PlaceInt16(x int16) {
|
||||
b.head -= UOffsetT(SizeInt16)
|
||||
WriteInt16(b.Bytes[b.head:], x)
|
||||
}
|
||||
|
||||
// PlaceInt32 prepends a int32 to the Builder, without checking for space.
|
||||
func (b *Builder) PlaceInt32(x int32) {
|
||||
b.head -= UOffsetT(SizeInt32)
|
||||
WriteInt32(b.Bytes[b.head:], x)
|
||||
}
|
||||
|
||||
// PlaceInt64 prepends a int64 to the Builder, without checking for space.
|
||||
func (b *Builder) PlaceInt64(x int64) {
|
||||
b.head -= UOffsetT(SizeInt64)
|
||||
WriteInt64(b.Bytes[b.head:], x)
|
||||
}
|
||||
|
||||
// PlaceFloat32 prepends a float32 to the Builder, without checking for space.
|
||||
func (b *Builder) PlaceFloat32(x float32) {
|
||||
b.head -= UOffsetT(SizeFloat32)
|
||||
WriteFloat32(b.Bytes[b.head:], x)
|
||||
}
|
||||
|
||||
// PlaceFloat64 prepends a float64 to the Builder, without checking for space.
|
||||
func (b *Builder) PlaceFloat64(x float64) {
|
||||
b.head -= UOffsetT(SizeFloat64)
|
||||
WriteFloat64(b.Bytes[b.head:], x)
|
||||
}
|
||||
|
||||
// PlaceByte prepends a byte to the Builder, without checking for space.
|
||||
func (b *Builder) PlaceByte(x byte) {
|
||||
b.head -= UOffsetT(SizeByte)
|
||||
WriteByte(b.Bytes[b.head:], x)
|
||||
}
|
||||
|
||||
// PlaceVOffsetT prepends a VOffsetT to the Builder, without checking for space.
|
||||
func (b *Builder) PlaceVOffsetT(x VOffsetT) {
|
||||
b.head -= UOffsetT(SizeVOffsetT)
|
||||
WriteVOffsetT(b.Bytes[b.head:], x)
|
||||
}
|
||||
|
||||
// PlaceSOffsetT prepends a SOffsetT to the Builder, without checking for space.
|
||||
func (b *Builder) PlaceSOffsetT(x SOffsetT) {
|
||||
b.head -= UOffsetT(SizeSOffsetT)
|
||||
WriteSOffsetT(b.Bytes[b.head:], x)
|
||||
}
|
||||
|
||||
// PlaceUOffsetT prepends a UOffsetT to the Builder, without checking for space.
|
||||
func (b *Builder) PlaceUOffsetT(x UOffsetT) {
|
||||
b.head -= UOffsetT(SizeUOffsetT)
|
||||
WriteUOffsetT(b.Bytes[b.head:], x)
|
||||
}
|
3
third_party/flatbuffers/go/doc.go
vendored
3
third_party/flatbuffers/go/doc.go
vendored
@ -1,3 +0,0 @@
|
||||
// Package flatbuffers provides facilities to read and write flatbuffers
|
||||
// objects.
|
||||
package flatbuffers
|
238
third_party/flatbuffers/go/encode.go
vendored
238
third_party/flatbuffers/go/encode.go
vendored
@ -1,238 +0,0 @@
|
||||
package flatbuffers
|
||||
|
||||
import (
|
||||
"math"
|
||||
)
|
||||
|
||||
type (
|
||||
// A SOffsetT stores a signed offset into arbitrary data.
|
||||
SOffsetT int32
|
||||
// A UOffsetT stores an unsigned offset into vector data.
|
||||
UOffsetT uint32
|
||||
// A VOffsetT stores an unsigned offset in a vtable.
|
||||
VOffsetT uint16
|
||||
)
|
||||
|
||||
const (
|
||||
// VtableMetadataFields is the count of metadata fields in each vtable.
|
||||
VtableMetadataFields = 2
|
||||
)
|
||||
|
||||
// GetByte decodes a little-endian byte from a byte slice.
|
||||
func GetByte(buf []byte) byte {
|
||||
return byte(GetUint8(buf))
|
||||
}
|
||||
|
||||
// GetBool decodes a little-endian bool from a byte slice.
|
||||
func GetBool(buf []byte) bool {
|
||||
return buf[0] == 1
|
||||
}
|
||||
|
||||
// GetUint8 decodes a little-endian uint8 from a byte slice.
|
||||
func GetUint8(buf []byte) (n uint8) {
|
||||
n = uint8(buf[0])
|
||||
return
|
||||
}
|
||||
|
||||
// GetUint16 decodes a little-endian uint16 from a byte slice.
|
||||
func GetUint16(buf []byte) (n uint16) {
|
||||
_ = buf[1] // Force one bounds check. See: golang.org/issue/14808
|
||||
n |= uint16(buf[0])
|
||||
n |= uint16(buf[1]) << 8
|
||||
return
|
||||
}
|
||||
|
||||
// GetUint32 decodes a little-endian uint32 from a byte slice.
|
||||
func GetUint32(buf []byte) (n uint32) {
|
||||
_ = buf[3] // Force one bounds check. See: golang.org/issue/14808
|
||||
n |= uint32(buf[0])
|
||||
n |= uint32(buf[1]) << 8
|
||||
n |= uint32(buf[2]) << 16
|
||||
n |= uint32(buf[3]) << 24
|
||||
return
|
||||
}
|
||||
|
||||
// GetUint64 decodes a little-endian uint64 from a byte slice.
|
||||
func GetUint64(buf []byte) (n uint64) {
|
||||
_ = buf[7] // Force one bounds check. See: golang.org/issue/14808
|
||||
n |= uint64(buf[0])
|
||||
n |= uint64(buf[1]) << 8
|
||||
n |= uint64(buf[2]) << 16
|
||||
n |= uint64(buf[3]) << 24
|
||||
n |= uint64(buf[4]) << 32
|
||||
n |= uint64(buf[5]) << 40
|
||||
n |= uint64(buf[6]) << 48
|
||||
n |= uint64(buf[7]) << 56
|
||||
return
|
||||
}
|
||||
|
||||
// GetInt8 decodes a little-endian int8 from a byte slice.
|
||||
func GetInt8(buf []byte) (n int8) {
|
||||
n = int8(buf[0])
|
||||
return
|
||||
}
|
||||
|
||||
// GetInt16 decodes a little-endian int16 from a byte slice.
|
||||
func GetInt16(buf []byte) (n int16) {
|
||||
_ = buf[1] // Force one bounds check. See: golang.org/issue/14808
|
||||
n |= int16(buf[0])
|
||||
n |= int16(buf[1]) << 8
|
||||
return
|
||||
}
|
||||
|
||||
// GetInt32 decodes a little-endian int32 from a byte slice.
|
||||
func GetInt32(buf []byte) (n int32) {
|
||||
_ = buf[3] // Force one bounds check. See: golang.org/issue/14808
|
||||
n |= int32(buf[0])
|
||||
n |= int32(buf[1]) << 8
|
||||
n |= int32(buf[2]) << 16
|
||||
n |= int32(buf[3]) << 24
|
||||
return
|
||||
}
|
||||
|
||||
// GetInt64 decodes a little-endian int64 from a byte slice.
|
||||
func GetInt64(buf []byte) (n int64) {
|
||||
_ = buf[7] // Force one bounds check. See: golang.org/issue/14808
|
||||
n |= int64(buf[0])
|
||||
n |= int64(buf[1]) << 8
|
||||
n |= int64(buf[2]) << 16
|
||||
n |= int64(buf[3]) << 24
|
||||
n |= int64(buf[4]) << 32
|
||||
n |= int64(buf[5]) << 40
|
||||
n |= int64(buf[6]) << 48
|
||||
n |= int64(buf[7]) << 56
|
||||
return
|
||||
}
|
||||
|
||||
// GetFloat32 decodes a little-endian float32 from a byte slice.
|
||||
func GetFloat32(buf []byte) float32 {
|
||||
x := GetUint32(buf)
|
||||
return math.Float32frombits(x)
|
||||
}
|
||||
|
||||
// GetFloat64 decodes a little-endian float64 from a byte slice.
|
||||
func GetFloat64(buf []byte) float64 {
|
||||
x := GetUint64(buf)
|
||||
return math.Float64frombits(x)
|
||||
}
|
||||
|
||||
// GetUOffsetT decodes a little-endian UOffsetT from a byte slice.
|
||||
func GetUOffsetT(buf []byte) UOffsetT {
|
||||
return UOffsetT(GetUint32(buf))
|
||||
}
|
||||
|
||||
// GetSOffsetT decodes a little-endian SOffsetT from a byte slice.
|
||||
func GetSOffsetT(buf []byte) SOffsetT {
|
||||
return SOffsetT(GetInt32(buf))
|
||||
}
|
||||
|
||||
// GetVOffsetT decodes a little-endian VOffsetT from a byte slice.
|
||||
func GetVOffsetT(buf []byte) VOffsetT {
|
||||
return VOffsetT(GetUint16(buf))
|
||||
}
|
||||
|
||||
// WriteByte encodes a little-endian uint8 into a byte slice.
|
||||
func WriteByte(buf []byte, n byte) {
|
||||
WriteUint8(buf, uint8(n))
|
||||
}
|
||||
|
||||
// WriteBool encodes a little-endian bool into a byte slice.
|
||||
func WriteBool(buf []byte, b bool) {
|
||||
buf[0] = 0
|
||||
if b {
|
||||
buf[0] = 1
|
||||
}
|
||||
}
|
||||
|
||||
// WriteUint8 encodes a little-endian uint8 into a byte slice.
|
||||
func WriteUint8(buf []byte, n uint8) {
|
||||
buf[0] = byte(n)
|
||||
}
|
||||
|
||||
// WriteUint16 encodes a little-endian uint16 into a byte slice.
|
||||
func WriteUint16(buf []byte, n uint16) {
|
||||
_ = buf[1] // Force one bounds check. See: golang.org/issue/14808
|
||||
buf[0] = byte(n)
|
||||
buf[1] = byte(n >> 8)
|
||||
}
|
||||
|
||||
// WriteUint32 encodes a little-endian uint32 into a byte slice.
|
||||
func WriteUint32(buf []byte, n uint32) {
|
||||
_ = buf[3] // Force one bounds check. See: golang.org/issue/14808
|
||||
buf[0] = byte(n)
|
||||
buf[1] = byte(n >> 8)
|
||||
buf[2] = byte(n >> 16)
|
||||
buf[3] = byte(n >> 24)
|
||||
}
|
||||
|
||||
// WriteUint64 encodes a little-endian uint64 into a byte slice.
|
||||
func WriteUint64(buf []byte, n uint64) {
|
||||
_ = buf[7] // Force one bounds check. See: golang.org/issue/14808
|
||||
buf[0] = byte(n)
|
||||
buf[1] = byte(n >> 8)
|
||||
buf[2] = byte(n >> 16)
|
||||
buf[3] = byte(n >> 24)
|
||||
buf[4] = byte(n >> 32)
|
||||
buf[5] = byte(n >> 40)
|
||||
buf[6] = byte(n >> 48)
|
||||
buf[7] = byte(n >> 56)
|
||||
}
|
||||
|
||||
// WriteInt8 encodes a little-endian int8 into a byte slice.
|
||||
func WriteInt8(buf []byte, n int8) {
|
||||
buf[0] = byte(n)
|
||||
}
|
||||
|
||||
// WriteInt16 encodes a little-endian int16 into a byte slice.
|
||||
func WriteInt16(buf []byte, n int16) {
|
||||
_ = buf[1] // Force one bounds check. See: golang.org/issue/14808
|
||||
buf[0] = byte(n)
|
||||
buf[1] = byte(n >> 8)
|
||||
}
|
||||
|
||||
// WriteInt32 encodes a little-endian int32 into a byte slice.
|
||||
func WriteInt32(buf []byte, n int32) {
|
||||
_ = buf[3] // Force one bounds check. See: golang.org/issue/14808
|
||||
buf[0] = byte(n)
|
||||
buf[1] = byte(n >> 8)
|
||||
buf[2] = byte(n >> 16)
|
||||
buf[3] = byte(n >> 24)
|
||||
}
|
||||
|
||||
// WriteInt64 encodes a little-endian int64 into a byte slice.
|
||||
func WriteInt64(buf []byte, n int64) {
|
||||
_ = buf[7] // Force one bounds check. See: golang.org/issue/14808
|
||||
buf[0] = byte(n)
|
||||
buf[1] = byte(n >> 8)
|
||||
buf[2] = byte(n >> 16)
|
||||
buf[3] = byte(n >> 24)
|
||||
buf[4] = byte(n >> 32)
|
||||
buf[5] = byte(n >> 40)
|
||||
buf[6] = byte(n >> 48)
|
||||
buf[7] = byte(n >> 56)
|
||||
}
|
||||
|
||||
// WriteFloat32 encodes a little-endian float32 into a byte slice.
|
||||
func WriteFloat32(buf []byte, n float32) {
|
||||
WriteUint32(buf, math.Float32bits(n))
|
||||
}
|
||||
|
||||
// WriteFloat64 encodes a little-endian float64 into a byte slice.
|
||||
func WriteFloat64(buf []byte, n float64) {
|
||||
WriteUint64(buf, math.Float64bits(n))
|
||||
}
|
||||
|
||||
// WriteVOffsetT encodes a little-endian VOffsetT into a byte slice.
|
||||
func WriteVOffsetT(buf []byte, n VOffsetT) {
|
||||
WriteUint16(buf, uint16(n))
|
||||
}
|
||||
|
||||
// WriteSOffsetT encodes a little-endian SOffsetT into a byte slice.
|
||||
func WriteSOffsetT(buf []byte, n SOffsetT) {
|
||||
WriteInt32(buf, int32(n))
|
||||
}
|
||||
|
||||
// WriteUOffsetT encodes a little-endian UOffsetT into a byte slice.
|
||||
func WriteUOffsetT(buf []byte, n UOffsetT) {
|
||||
WriteUint32(buf, uint32(n))
|
||||
}
|
38
third_party/flatbuffers/go/grpc.go
vendored
38
third_party/flatbuffers/go/grpc.go
vendored
@ -1,38 +0,0 @@
|
||||
package flatbuffers
|
||||
|
||||
// Codec implements gRPC-go Codec which is used to encode and decode messages.
|
||||
var Codec = "flatbuffers"
|
||||
|
||||
// FlatbuffersCodec defines the interface gRPC uses to encode and decode messages. Note
|
||||
// that implementations of this interface must be thread safe; a Codec's
|
||||
// methods can be called from concurrent goroutines.
|
||||
type FlatbuffersCodec struct{}
|
||||
|
||||
// Marshal returns the wire format of v.
|
||||
func (FlatbuffersCodec) Marshal(v interface{}) ([]byte, error) {
|
||||
return v.(*Builder).FinishedBytes(), nil
|
||||
}
|
||||
|
||||
// Unmarshal parses the wire format into v.
|
||||
func (FlatbuffersCodec) Unmarshal(data []byte, v interface{}) error {
|
||||
v.(flatbuffersInit).Init(data, GetUOffsetT(data))
|
||||
return nil
|
||||
}
|
||||
|
||||
// String old gRPC Codec interface func
|
||||
func (FlatbuffersCodec) String() string {
|
||||
return Codec
|
||||
}
|
||||
|
||||
// Name returns the name of the Codec implementation. The returned string
|
||||
// will be used as part of content type in transmission. The result must be
|
||||
// static; the result cannot change between calls.
|
||||
//
|
||||
// add Name() for ForceCodec interface
|
||||
func (FlatbuffersCodec) Name() string {
|
||||
return Codec
|
||||
}
|
||||
|
||||
type flatbuffersInit interface {
|
||||
Init(data []byte, i UOffsetT)
|
||||
}
|
50
third_party/flatbuffers/go/lib.go
vendored
50
third_party/flatbuffers/go/lib.go
vendored
@ -1,50 +0,0 @@
|
||||
package flatbuffers
|
||||
|
||||
// FlatBuffer is the interface that represents a flatbuffer.
|
||||
type FlatBuffer interface {
|
||||
Table() Table
|
||||
Init(buf []byte, i UOffsetT)
|
||||
}
|
||||
|
||||
// GetRootAs is a generic helper to initialize a FlatBuffer with the provided buffer bytes and its data offset.
|
||||
func GetRootAs(buf []byte, offset UOffsetT, fb FlatBuffer) {
|
||||
n := GetUOffsetT(buf[offset:])
|
||||
fb.Init(buf, n+offset)
|
||||
}
|
||||
|
||||
// GetSizePrefixedRootAs is a generic helper to initialize a FlatBuffer with the provided size-prefixed buffer
|
||||
// bytes and its data offset
|
||||
func GetSizePrefixedRootAs(buf []byte, offset UOffsetT, fb FlatBuffer) {
|
||||
n := GetUOffsetT(buf[offset+sizePrefixLength:])
|
||||
fb.Init(buf, n+offset+sizePrefixLength)
|
||||
}
|
||||
|
||||
// GetSizePrefix reads the size from a size-prefixed flatbuffer
|
||||
func GetSizePrefix(buf []byte, offset UOffsetT) uint32 {
|
||||
return GetUint32(buf[offset:])
|
||||
}
|
||||
|
||||
// GetIndirectOffset retrives the relative offset in the provided buffer stored at `offset`.
|
||||
func GetIndirectOffset(buf []byte, offset UOffsetT) UOffsetT {
|
||||
return offset + GetUOffsetT(buf[offset:])
|
||||
}
|
||||
|
||||
// GetBufferIdentifier returns the file identifier as string
|
||||
func GetBufferIdentifier(buf []byte) string {
|
||||
return string(buf[SizeUOffsetT:][:fileIdentifierLength])
|
||||
}
|
||||
|
||||
// GetBufferIdentifier returns the file identifier as string for a size-prefixed buffer
|
||||
func GetSizePrefixedBufferIdentifier(buf []byte) string {
|
||||
return string(buf[SizeUOffsetT+sizePrefixLength:][:fileIdentifierLength])
|
||||
}
|
||||
|
||||
// BufferHasIdentifier checks if the identifier in a buffer has the expected value
|
||||
func BufferHasIdentifier(buf []byte, identifier string) bool {
|
||||
return GetBufferIdentifier(buf) == identifier
|
||||
}
|
||||
|
||||
// BufferHasIdentifier checks if the identifier in a buffer has the expected value for a size-prefixed buffer
|
||||
func SizePrefixedBufferHasIdentifier(buf []byte, identifier string) bool {
|
||||
return GetSizePrefixedBufferIdentifier(buf) == identifier
|
||||
}
|
55
third_party/flatbuffers/go/sizes.go
vendored
55
third_party/flatbuffers/go/sizes.go
vendored
@ -1,55 +0,0 @@
|
||||
package flatbuffers
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
const (
|
||||
// See http://golang.org/ref/spec#Numeric_types
|
||||
|
||||
// SizeUint8 is the byte size of a uint8.
|
||||
SizeUint8 = 1
|
||||
// SizeUint16 is the byte size of a uint16.
|
||||
SizeUint16 = 2
|
||||
// SizeUint32 is the byte size of a uint32.
|
||||
SizeUint32 = 4
|
||||
// SizeUint64 is the byte size of a uint64.
|
||||
SizeUint64 = 8
|
||||
|
||||
// SizeInt8 is the byte size of a int8.
|
||||
SizeInt8 = 1
|
||||
// SizeInt16 is the byte size of a int16.
|
||||
SizeInt16 = 2
|
||||
// SizeInt32 is the byte size of a int32.
|
||||
SizeInt32 = 4
|
||||
// SizeInt64 is the byte size of a int64.
|
||||
SizeInt64 = 8
|
||||
|
||||
// SizeFloat32 is the byte size of a float32.
|
||||
SizeFloat32 = 4
|
||||
// SizeFloat64 is the byte size of a float64.
|
||||
SizeFloat64 = 8
|
||||
|
||||
// SizeByte is the byte size of a byte.
|
||||
// The `byte` type is aliased (by Go definition) to uint8.
|
||||
SizeByte = 1
|
||||
|
||||
// SizeBool is the byte size of a bool.
|
||||
// The `bool` type is aliased (by flatbuffers convention) to uint8.
|
||||
SizeBool = 1
|
||||
|
||||
// SizeSOffsetT is the byte size of an SOffsetT.
|
||||
// The `SOffsetT` type is aliased (by flatbuffers convention) to int32.
|
||||
SizeSOffsetT = 4
|
||||
// SizeUOffsetT is the byte size of an UOffsetT.
|
||||
// The `UOffsetT` type is aliased (by flatbuffers convention) to uint32.
|
||||
SizeUOffsetT = 4
|
||||
// SizeVOffsetT is the byte size of an VOffsetT.
|
||||
// The `VOffsetT` type is aliased (by flatbuffers convention) to uint16.
|
||||
SizeVOffsetT = 2
|
||||
)
|
||||
|
||||
// byteSliceToString converts a []byte to string without a heap allocation.
|
||||
func byteSliceToString(b []byte) string {
|
||||
return *(*string)(unsafe.Pointer(&b))
|
||||
}
|
8
third_party/flatbuffers/go/struct.go
vendored
8
third_party/flatbuffers/go/struct.go
vendored
@ -1,8 +0,0 @@
|
||||
package flatbuffers
|
||||
|
||||
// Struct wraps a byte slice and provides read access to its data.
|
||||
//
|
||||
// Structs do not have a vtable.
|
||||
type Struct struct {
|
||||
Table
|
||||
}
|
505
third_party/flatbuffers/go/table.go
vendored
505
third_party/flatbuffers/go/table.go
vendored
@ -1,505 +0,0 @@
|
||||
package flatbuffers
|
||||
|
||||
// Table wraps a byte slice and provides read access to its data.
|
||||
//
|
||||
// The variable `Pos` indicates the root of the FlatBuffers object therein.
|
||||
type Table struct {
|
||||
Bytes []byte
|
||||
Pos UOffsetT // Always < 1<<31.
|
||||
}
|
||||
|
||||
// Offset provides access into the Table's vtable.
|
||||
//
|
||||
// Fields which are deprecated are ignored by checking against the vtable's length.
|
||||
func (t *Table) Offset(vtableOffset VOffsetT) VOffsetT {
|
||||
vtable := UOffsetT(SOffsetT(t.Pos) - t.GetSOffsetT(t.Pos))
|
||||
if vtableOffset < t.GetVOffsetT(vtable) {
|
||||
return t.GetVOffsetT(vtable + UOffsetT(vtableOffset))
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// Indirect retrieves the relative offset stored at `offset`.
|
||||
func (t *Table) Indirect(off UOffsetT) UOffsetT {
|
||||
return off + GetUOffsetT(t.Bytes[off:])
|
||||
}
|
||||
|
||||
// String gets a string from data stored inside the flatbuffer.
|
||||
func (t *Table) String(off UOffsetT) string {
|
||||
b := t.ByteVector(off)
|
||||
return byteSliceToString(b)
|
||||
}
|
||||
|
||||
// ByteVector gets a byte slice from data stored inside the flatbuffer.
|
||||
func (t *Table) ByteVector(off UOffsetT) []byte {
|
||||
off += GetUOffsetT(t.Bytes[off:])
|
||||
start := off + UOffsetT(SizeUOffsetT)
|
||||
length := GetUOffsetT(t.Bytes[off:])
|
||||
return t.Bytes[start : start+length]
|
||||
}
|
||||
|
||||
// VectorLen retrieves the length of the vector whose offset is stored at
|
||||
// "off" in this object.
|
||||
func (t *Table) VectorLen(off UOffsetT) int {
|
||||
off += t.Pos
|
||||
off += GetUOffsetT(t.Bytes[off:])
|
||||
return int(GetUOffsetT(t.Bytes[off:]))
|
||||
}
|
||||
|
||||
// Vector retrieves the start of data of the vector whose offset is stored
|
||||
// at "off" in this object.
|
||||
func (t *Table) Vector(off UOffsetT) UOffsetT {
|
||||
off += t.Pos
|
||||
x := off + GetUOffsetT(t.Bytes[off:])
|
||||
// data starts after metadata containing the vector length
|
||||
x += UOffsetT(SizeUOffsetT)
|
||||
return x
|
||||
}
|
||||
|
||||
// Union initializes any Table-derived type to point to the union at the given
|
||||
// offset.
|
||||
func (t *Table) Union(t2 *Table, off UOffsetT) {
|
||||
off += t.Pos
|
||||
t2.Pos = off + t.GetUOffsetT(off)
|
||||
t2.Bytes = t.Bytes
|
||||
}
|
||||
|
||||
// GetBool retrieves a bool at the given offset.
|
||||
func (t *Table) GetBool(off UOffsetT) bool {
|
||||
return GetBool(t.Bytes[off:])
|
||||
}
|
||||
|
||||
// GetByte retrieves a byte at the given offset.
|
||||
func (t *Table) GetByte(off UOffsetT) byte {
|
||||
return GetByte(t.Bytes[off:])
|
||||
}
|
||||
|
||||
// GetUint8 retrieves a uint8 at the given offset.
|
||||
func (t *Table) GetUint8(off UOffsetT) uint8 {
|
||||
return GetUint8(t.Bytes[off:])
|
||||
}
|
||||
|
||||
// GetUint16 retrieves a uint16 at the given offset.
|
||||
func (t *Table) GetUint16(off UOffsetT) uint16 {
|
||||
return GetUint16(t.Bytes[off:])
|
||||
}
|
||||
|
||||
// GetUint32 retrieves a uint32 at the given offset.
|
||||
func (t *Table) GetUint32(off UOffsetT) uint32 {
|
||||
return GetUint32(t.Bytes[off:])
|
||||
}
|
||||
|
||||
// GetUint64 retrieves a uint64 at the given offset.
|
||||
func (t *Table) GetUint64(off UOffsetT) uint64 {
|
||||
return GetUint64(t.Bytes[off:])
|
||||
}
|
||||
|
||||
// GetInt8 retrieves a int8 at the given offset.
|
||||
func (t *Table) GetInt8(off UOffsetT) int8 {
|
||||
return GetInt8(t.Bytes[off:])
|
||||
}
|
||||
|
||||
// GetInt16 retrieves a int16 at the given offset.
|
||||
func (t *Table) GetInt16(off UOffsetT) int16 {
|
||||
return GetInt16(t.Bytes[off:])
|
||||
}
|
||||
|
||||
// GetInt32 retrieves a int32 at the given offset.
|
||||
func (t *Table) GetInt32(off UOffsetT) int32 {
|
||||
return GetInt32(t.Bytes[off:])
|
||||
}
|
||||
|
||||
// GetInt64 retrieves a int64 at the given offset.
|
||||
func (t *Table) GetInt64(off UOffsetT) int64 {
|
||||
return GetInt64(t.Bytes[off:])
|
||||
}
|
||||
|
||||
// GetFloat32 retrieves a float32 at the given offset.
|
||||
func (t *Table) GetFloat32(off UOffsetT) float32 {
|
||||
return GetFloat32(t.Bytes[off:])
|
||||
}
|
||||
|
||||
// GetFloat64 retrieves a float64 at the given offset.
|
||||
func (t *Table) GetFloat64(off UOffsetT) float64 {
|
||||
return GetFloat64(t.Bytes[off:])
|
||||
}
|
||||
|
||||
// GetUOffsetT retrieves a UOffsetT at the given offset.
|
||||
func (t *Table) GetUOffsetT(off UOffsetT) UOffsetT {
|
||||
return GetUOffsetT(t.Bytes[off:])
|
||||
}
|
||||
|
||||
// GetVOffsetT retrieves a VOffsetT at the given offset.
|
||||
func (t *Table) GetVOffsetT(off UOffsetT) VOffsetT {
|
||||
return GetVOffsetT(t.Bytes[off:])
|
||||
}
|
||||
|
||||
// GetSOffsetT retrieves a SOffsetT at the given offset.
|
||||
func (t *Table) GetSOffsetT(off UOffsetT) SOffsetT {
|
||||
return GetSOffsetT(t.Bytes[off:])
|
||||
}
|
||||
|
||||
// GetBoolSlot retrieves the bool that the given vtable location
|
||||
// points to. If the vtable value is zero, the default value `d`
|
||||
// will be returned.
|
||||
func (t *Table) GetBoolSlot(slot VOffsetT, d bool) bool {
|
||||
off := t.Offset(slot)
|
||||
if off == 0 {
|
||||
return d
|
||||
}
|
||||
|
||||
return t.GetBool(t.Pos + UOffsetT(off))
|
||||
}
|
||||
|
||||
// GetByteSlot retrieves the byte that the given vtable location
|
||||
// points to. If the vtable value is zero, the default value `d`
|
||||
// will be returned.
|
||||
func (t *Table) GetByteSlot(slot VOffsetT, d byte) byte {
|
||||
off := t.Offset(slot)
|
||||
if off == 0 {
|
||||
return d
|
||||
}
|
||||
|
||||
return t.GetByte(t.Pos + UOffsetT(off))
|
||||
}
|
||||
|
||||
// GetInt8Slot retrieves the int8 that the given vtable location
|
||||
// points to. If the vtable value is zero, the default value `d`
|
||||
// will be returned.
|
||||
func (t *Table) GetInt8Slot(slot VOffsetT, d int8) int8 {
|
||||
off := t.Offset(slot)
|
||||
if off == 0 {
|
||||
return d
|
||||
}
|
||||
|
||||
return t.GetInt8(t.Pos + UOffsetT(off))
|
||||
}
|
||||
|
||||
// GetUint8Slot retrieves the uint8 that the given vtable location
|
||||
// points to. If the vtable value is zero, the default value `d`
|
||||
// will be returned.
|
||||
func (t *Table) GetUint8Slot(slot VOffsetT, d uint8) uint8 {
|
||||
off := t.Offset(slot)
|
||||
if off == 0 {
|
||||
return d
|
||||
}
|
||||
|
||||
return t.GetUint8(t.Pos + UOffsetT(off))
|
||||
}
|
||||
|
||||
// GetInt16Slot retrieves the int16 that the given vtable location
|
||||
// points to. If the vtable value is zero, the default value `d`
|
||||
// will be returned.
|
||||
func (t *Table) GetInt16Slot(slot VOffsetT, d int16) int16 {
|
||||
off := t.Offset(slot)
|
||||
if off == 0 {
|
||||
return d
|
||||
}
|
||||
|
||||
return t.GetInt16(t.Pos + UOffsetT(off))
|
||||
}
|
||||
|
||||
// GetUint16Slot retrieves the uint16 that the given vtable location
|
||||
// points to. If the vtable value is zero, the default value `d`
|
||||
// will be returned.
|
||||
func (t *Table) GetUint16Slot(slot VOffsetT, d uint16) uint16 {
|
||||
off := t.Offset(slot)
|
||||
if off == 0 {
|
||||
return d
|
||||
}
|
||||
|
||||
return t.GetUint16(t.Pos + UOffsetT(off))
|
||||
}
|
||||
|
||||
// GetInt32Slot retrieves the int32 that the given vtable location
|
||||
// points to. If the vtable value is zero, the default value `d`
|
||||
// will be returned.
|
||||
func (t *Table) GetInt32Slot(slot VOffsetT, d int32) int32 {
|
||||
off := t.Offset(slot)
|
||||
if off == 0 {
|
||||
return d
|
||||
}
|
||||
|
||||
return t.GetInt32(t.Pos + UOffsetT(off))
|
||||
}
|
||||
|
||||
// GetUint32Slot retrieves the uint32 that the given vtable location
|
||||
// points to. If the vtable value is zero, the default value `d`
|
||||
// will be returned.
|
||||
func (t *Table) GetUint32Slot(slot VOffsetT, d uint32) uint32 {
|
||||
off := t.Offset(slot)
|
||||
if off == 0 {
|
||||
return d
|
||||
}
|
||||
|
||||
return t.GetUint32(t.Pos + UOffsetT(off))
|
||||
}
|
||||
|
||||
// GetInt64Slot retrieves the int64 that the given vtable location
|
||||
// points to. If the vtable value is zero, the default value `d`
|
||||
// will be returned.
|
||||
func (t *Table) GetInt64Slot(slot VOffsetT, d int64) int64 {
|
||||
off := t.Offset(slot)
|
||||
if off == 0 {
|
||||
return d
|
||||
}
|
||||
|
||||
return t.GetInt64(t.Pos + UOffsetT(off))
|
||||
}
|
||||
|
||||
// GetUint64Slot retrieves the uint64 that the given vtable location
|
||||
// points to. If the vtable value is zero, the default value `d`
|
||||
// will be returned.
|
||||
func (t *Table) GetUint64Slot(slot VOffsetT, d uint64) uint64 {
|
||||
off := t.Offset(slot)
|
||||
if off == 0 {
|
||||
return d
|
||||
}
|
||||
|
||||
return t.GetUint64(t.Pos + UOffsetT(off))
|
||||
}
|
||||
|
||||
// GetFloat32Slot retrieves the float32 that the given vtable location
|
||||
// points to. If the vtable value is zero, the default value `d`
|
||||
// will be returned.
|
||||
func (t *Table) GetFloat32Slot(slot VOffsetT, d float32) float32 {
|
||||
off := t.Offset(slot)
|
||||
if off == 0 {
|
||||
return d
|
||||
}
|
||||
|
||||
return t.GetFloat32(t.Pos + UOffsetT(off))
|
||||
}
|
||||
|
||||
// GetFloat64Slot retrieves the float64 that the given vtable location
|
||||
// points to. If the vtable value is zero, the default value `d`
|
||||
// will be returned.
|
||||
func (t *Table) GetFloat64Slot(slot VOffsetT, d float64) float64 {
|
||||
off := t.Offset(slot)
|
||||
if off == 0 {
|
||||
return d
|
||||
}
|
||||
|
||||
return t.GetFloat64(t.Pos + UOffsetT(off))
|
||||
}
|
||||
|
||||
// GetVOffsetTSlot retrieves the VOffsetT that the given vtable location
|
||||
// points to. If the vtable value is zero, the default value `d`
|
||||
// will be returned.
|
||||
func (t *Table) GetVOffsetTSlot(slot VOffsetT, d VOffsetT) VOffsetT {
|
||||
off := t.Offset(slot)
|
||||
if off == 0 {
|
||||
return d
|
||||
}
|
||||
return VOffsetT(off)
|
||||
}
|
||||
|
||||
// MutateBool updates a bool at the given offset.
|
||||
func (t *Table) MutateBool(off UOffsetT, n bool) bool {
|
||||
WriteBool(t.Bytes[off:], n)
|
||||
return true
|
||||
}
|
||||
|
||||
// MutateByte updates a Byte at the given offset.
|
||||
func (t *Table) MutateByte(off UOffsetT, n byte) bool {
|
||||
WriteByte(t.Bytes[off:], n)
|
||||
return true
|
||||
}
|
||||
|
||||
// MutateUint8 updates a Uint8 at the given offset.
|
||||
func (t *Table) MutateUint8(off UOffsetT, n uint8) bool {
|
||||
WriteUint8(t.Bytes[off:], n)
|
||||
return true
|
||||
}
|
||||
|
||||
// MutateUint16 updates a Uint16 at the given offset.
|
||||
func (t *Table) MutateUint16(off UOffsetT, n uint16) bool {
|
||||
WriteUint16(t.Bytes[off:], n)
|
||||
return true
|
||||
}
|
||||
|
||||
// MutateUint32 updates a Uint32 at the given offset.
|
||||
func (t *Table) MutateUint32(off UOffsetT, n uint32) bool {
|
||||
WriteUint32(t.Bytes[off:], n)
|
||||
return true
|
||||
}
|
||||
|
||||
// MutateUint64 updates a Uint64 at the given offset.
|
||||
func (t *Table) MutateUint64(off UOffsetT, n uint64) bool {
|
||||
WriteUint64(t.Bytes[off:], n)
|
||||
return true
|
||||
}
|
||||
|
||||
// MutateInt8 updates a Int8 at the given offset.
|
||||
func (t *Table) MutateInt8(off UOffsetT, n int8) bool {
|
||||
WriteInt8(t.Bytes[off:], n)
|
||||
return true
|
||||
}
|
||||
|
||||
// MutateInt16 updates a Int16 at the given offset.
|
||||
func (t *Table) MutateInt16(off UOffsetT, n int16) bool {
|
||||
WriteInt16(t.Bytes[off:], n)
|
||||
return true
|
||||
}
|
||||
|
||||
// MutateInt32 updates a Int32 at the given offset.
|
||||
func (t *Table) MutateInt32(off UOffsetT, n int32) bool {
|
||||
WriteInt32(t.Bytes[off:], n)
|
||||
return true
|
||||
}
|
||||
|
||||
// MutateInt64 updates a Int64 at the given offset.
|
||||
func (t *Table) MutateInt64(off UOffsetT, n int64) bool {
|
||||
WriteInt64(t.Bytes[off:], n)
|
||||
return true
|
||||
}
|
||||
|
||||
// MutateFloat32 updates a Float32 at the given offset.
|
||||
func (t *Table) MutateFloat32(off UOffsetT, n float32) bool {
|
||||
WriteFloat32(t.Bytes[off:], n)
|
||||
return true
|
||||
}
|
||||
|
||||
// MutateFloat64 updates a Float64 at the given offset.
|
||||
func (t *Table) MutateFloat64(off UOffsetT, n float64) bool {
|
||||
WriteFloat64(t.Bytes[off:], n)
|
||||
return true
|
||||
}
|
||||
|
||||
// MutateUOffsetT updates a UOffsetT at the given offset.
|
||||
func (t *Table) MutateUOffsetT(off UOffsetT, n UOffsetT) bool {
|
||||
WriteUOffsetT(t.Bytes[off:], n)
|
||||
return true
|
||||
}
|
||||
|
||||
// MutateVOffsetT updates a VOffsetT at the given offset.
|
||||
func (t *Table) MutateVOffsetT(off UOffsetT, n VOffsetT) bool {
|
||||
WriteVOffsetT(t.Bytes[off:], n)
|
||||
return true
|
||||
}
|
||||
|
||||
// MutateSOffsetT updates a SOffsetT at the given offset.
|
||||
func (t *Table) MutateSOffsetT(off UOffsetT, n SOffsetT) bool {
|
||||
WriteSOffsetT(t.Bytes[off:], n)
|
||||
return true
|
||||
}
|
||||
|
||||
// MutateBoolSlot updates the bool at given vtable location
|
||||
func (t *Table) MutateBoolSlot(slot VOffsetT, n bool) bool {
|
||||
if off := t.Offset(slot); off != 0 {
|
||||
t.MutateBool(t.Pos+UOffsetT(off), n)
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// MutateByteSlot updates the byte at given vtable location
|
||||
func (t *Table) MutateByteSlot(slot VOffsetT, n byte) bool {
|
||||
if off := t.Offset(slot); off != 0 {
|
||||
t.MutateByte(t.Pos+UOffsetT(off), n)
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// MutateInt8Slot updates the int8 at given vtable location
|
||||
func (t *Table) MutateInt8Slot(slot VOffsetT, n int8) bool {
|
||||
if off := t.Offset(slot); off != 0 {
|
||||
t.MutateInt8(t.Pos+UOffsetT(off), n)
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// MutateUint8Slot updates the uint8 at given vtable location
|
||||
func (t *Table) MutateUint8Slot(slot VOffsetT, n uint8) bool {
|
||||
if off := t.Offset(slot); off != 0 {
|
||||
t.MutateUint8(t.Pos+UOffsetT(off), n)
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// MutateInt16Slot updates the int16 at given vtable location
|
||||
func (t *Table) MutateInt16Slot(slot VOffsetT, n int16) bool {
|
||||
if off := t.Offset(slot); off != 0 {
|
||||
t.MutateInt16(t.Pos+UOffsetT(off), n)
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// MutateUint16Slot updates the uint16 at given vtable location
|
||||
func (t *Table) MutateUint16Slot(slot VOffsetT, n uint16) bool {
|
||||
if off := t.Offset(slot); off != 0 {
|
||||
t.MutateUint16(t.Pos+UOffsetT(off), n)
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// MutateInt32Slot updates the int32 at given vtable location
|
||||
func (t *Table) MutateInt32Slot(slot VOffsetT, n int32) bool {
|
||||
if off := t.Offset(slot); off != 0 {
|
||||
t.MutateInt32(t.Pos+UOffsetT(off), n)
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// MutateUint32Slot updates the uint32 at given vtable location
|
||||
func (t *Table) MutateUint32Slot(slot VOffsetT, n uint32) bool {
|
||||
if off := t.Offset(slot); off != 0 {
|
||||
t.MutateUint32(t.Pos+UOffsetT(off), n)
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// MutateInt64Slot updates the int64 at given vtable location
|
||||
func (t *Table) MutateInt64Slot(slot VOffsetT, n int64) bool {
|
||||
if off := t.Offset(slot); off != 0 {
|
||||
t.MutateInt64(t.Pos+UOffsetT(off), n)
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// MutateUint64Slot updates the uint64 at given vtable location
|
||||
func (t *Table) MutateUint64Slot(slot VOffsetT, n uint64) bool {
|
||||
if off := t.Offset(slot); off != 0 {
|
||||
t.MutateUint64(t.Pos+UOffsetT(off), n)
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// MutateFloat32Slot updates the float32 at given vtable location
|
||||
func (t *Table) MutateFloat32Slot(slot VOffsetT, n float32) bool {
|
||||
if off := t.Offset(slot); off != 0 {
|
||||
t.MutateFloat32(t.Pos+UOffsetT(off), n)
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// MutateFloat64Slot updates the float64 at given vtable location
|
||||
func (t *Table) MutateFloat64Slot(slot VOffsetT, n float64) bool {
|
||||
if off := t.Offset(slot); off != 0 {
|
||||
t.MutateFloat64(t.Pos+UOffsetT(off), n)
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
1
third_party/flatbuffers/js/README.md
vendored
1
third_party/flatbuffers/js/README.md
vendored
@ -1 +0,0 @@
|
||||
This folder is intentionally empty and will contain transpiled js modules in Common JS format after compiling with tsc.
|
@ -1,152 +0,0 @@
|
||||
import groovy.xml.XmlParser
|
||||
|
||||
plugins {
|
||||
kotlin("multiplatform")
|
||||
id("org.jetbrains.kotlinx.benchmark")
|
||||
id("io.morethan.jmhreport")
|
||||
id("de.undercouch.download")
|
||||
}
|
||||
|
||||
group = "com.google.flatbuffers.jmh"
|
||||
version = "2.0.0-SNAPSHOT"
|
||||
|
||||
// Reads latest version from Java's runtime pom.xml,
|
||||
// so we can use it for benchmarking against Kotlin's
|
||||
// runtime
|
||||
fun readJavaFlatBufferVersion(): String {
|
||||
val pom = XmlParser().parse(File("../java/pom.xml"))
|
||||
val versionTag = pom.children().find {
|
||||
val node = it as groovy.util.Node
|
||||
node.name().toString().contains("version")
|
||||
} as groovy.util.Node
|
||||
return versionTag.value().toString()
|
||||
}
|
||||
|
||||
// This plugin generates a static html page with the aggregation
|
||||
// of all benchmarks ran. very useful visualization tool.
|
||||
jmhReport {
|
||||
val baseFolder = project.file("build/reports/benchmarks/main").absolutePath
|
||||
val lastFolder = project.file(baseFolder).list()?.sortedArray()?.lastOrNull() ?: ""
|
||||
jmhResultPath = "$baseFolder/$lastFolder/jvm.json"
|
||||
jmhReportOutput = "$baseFolder/$lastFolder"
|
||||
}
|
||||
|
||||
// For now we benchmark on JVM only
|
||||
benchmark {
|
||||
configurations {
|
||||
this.getByName("main") {
|
||||
iterations = 5
|
||||
iterationTime = 300
|
||||
iterationTimeUnit = "ms"
|
||||
// uncomment for benchmarking JSON op only
|
||||
include(".*FlatbufferBenchmark.*")
|
||||
}
|
||||
}
|
||||
targets {
|
||||
register("jvm")
|
||||
}
|
||||
}
|
||||
|
||||
kotlin {
|
||||
jvm {
|
||||
compilations {
|
||||
val main by getting { }
|
||||
// custom benchmark compilation
|
||||
val benchmarks by compilations.creating {
|
||||
defaultSourceSet {
|
||||
dependencies {
|
||||
// Compile against the main compilation's compile classpath and outputs:
|
||||
implementation(main.compileDependencyFiles + main.output.classesDirs)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
val jvmMain by getting {
|
||||
dependencies {
|
||||
implementation(kotlin("stdlib-common"))
|
||||
implementation(project(":flatbuffers-kotlin"))
|
||||
implementation(libs.kotlinx.benchmark.runtime)
|
||||
// json serializers
|
||||
implementation(libs.moshi.kotlin)
|
||||
implementation(libs.gson)
|
||||
}
|
||||
kotlin.srcDir("src/jvmMain/generated/kotlin/")
|
||||
kotlin.srcDir("src/jvmMain/generated/java/")
|
||||
kotlin.srcDir("../../java/src/main/java")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This task download all JSON files used for benchmarking
|
||||
tasks.register<de.undercouch.gradle.tasks.download.Download>("downloadMultipleFiles") {
|
||||
// We are downloading json benchmark samples from serdes-rs project.
|
||||
// see: https://github.com/serde-rs/json-benchmark/blob/master/data
|
||||
val baseUrl = "https://github.com/serde-rs/json-benchmark/raw/master/data/"
|
||||
src(listOf("$baseUrl/canada.json", "$baseUrl/twitter.json", "$baseUrl/citm_catalog.json"))
|
||||
dest(File("${project.projectDir.absolutePath}/src/jvmMain/resources"))
|
||||
overwrite(false)
|
||||
}
|
||||
|
||||
abstract class GenerateFBTestClasses : DefaultTask() {
|
||||
@get:InputFiles
|
||||
abstract val inputFiles: ConfigurableFileCollection
|
||||
|
||||
@get:Input
|
||||
abstract val includeFolder: Property<String>
|
||||
|
||||
@get:Input
|
||||
abstract val outputFolder: Property<String>
|
||||
|
||||
@get:Input
|
||||
abstract val variants: ListProperty<String>
|
||||
|
||||
@Inject
|
||||
protected open fun getExecActionFactory(): org.gradle.process.internal.ExecActionFactory? {
|
||||
throw UnsupportedOperationException()
|
||||
}
|
||||
|
||||
init {
|
||||
includeFolder.set("")
|
||||
}
|
||||
|
||||
@TaskAction
|
||||
fun compile() {
|
||||
val execAction = getExecActionFactory()!!.newExecAction()
|
||||
val sources = inputFiles.asPath.split(":")
|
||||
val langs = variants.get().map { "--$it" }
|
||||
val args = mutableListOf("flatc","-o", outputFolder.get(), *langs.toTypedArray())
|
||||
if (includeFolder.get().isNotEmpty()) {
|
||||
args.add("-I")
|
||||
args.add(includeFolder.get())
|
||||
}
|
||||
args.addAll(sources)
|
||||
println(args)
|
||||
execAction.commandLine = args
|
||||
print(execAction.execute())
|
||||
}
|
||||
}
|
||||
|
||||
// Use the default greeting
|
||||
tasks.register<GenerateFBTestClasses>("generateFBTestClassesKt") {
|
||||
inputFiles.setFrom("$projectDir/monster_test_kotlin.fbs")
|
||||
includeFolder.set("$rootDir/../tests/include_test")
|
||||
outputFolder.set("${projectDir}/src/jvmMain/generated/kotlin/")
|
||||
variants.addAll("kotlin-kmp")
|
||||
}
|
||||
|
||||
tasks.register<GenerateFBTestClasses>("generateFBTestClassesJava") {
|
||||
inputFiles.setFrom("$projectDir/monster_test_java.fbs")
|
||||
includeFolder.set("$rootDir/../tests/include_test")
|
||||
outputFolder.set("${projectDir}/src/jvmMain/generated/java/")
|
||||
variants.addAll("kotlin")
|
||||
}
|
||||
|
||||
project.tasks.forEach {
|
||||
if (it.name.contains("compileKotlin")) {
|
||||
it.dependsOn("generateFBTestClassesKt")
|
||||
it.dependsOn("generateFBTestClassesJava")
|
||||
}
|
||||
}
|
@ -1,37 +0,0 @@
|
||||
// Example IDL file for our monster's schema.
|
||||
|
||||
namespace jmonster;
|
||||
|
||||
enum JColor:byte { Red = 0, Green, Blue = 2 }
|
||||
|
||||
union JEquipment { JWeapon } // Optionally add more tables.
|
||||
|
||||
struct JVec3 {
|
||||
x:float;
|
||||
y:float;
|
||||
z:float;
|
||||
}
|
||||
|
||||
table JMonster {
|
||||
pos:JVec3;
|
||||
mana:short = 150;
|
||||
hp:short = 100;
|
||||
name:string;
|
||||
friendly:bool = false (deprecated);
|
||||
inventory:[ubyte];
|
||||
color:JColor = Blue;
|
||||
weapons:[JWeapon];
|
||||
equipped:JEquipment;
|
||||
path:[JVec3];
|
||||
}
|
||||
|
||||
table JWeapon {
|
||||
name:string;
|
||||
damage:short;
|
||||
}
|
||||
|
||||
table JAllMonsters {
|
||||
monsters: [JMonster];
|
||||
}
|
||||
|
||||
root_type JAllMonsters;
|
@ -1,37 +0,0 @@
|
||||
// Example IDL file for our monster's schema.
|
||||
|
||||
namespace monster;
|
||||
|
||||
enum Color:byte { Red = 0, Green, Blue = 2 }
|
||||
|
||||
union Equipment { Weapon } // Optionally add more tables.
|
||||
|
||||
struct Vec3 {
|
||||
x:float;
|
||||
y:float;
|
||||
z:float;
|
||||
}
|
||||
|
||||
table Monster {
|
||||
pos:Vec3;
|
||||
mana:short = 150;
|
||||
hp:short = 100;
|
||||
name:string;
|
||||
friendly:bool = false (deprecated);
|
||||
inventory:[ubyte];
|
||||
color:Color = Blue;
|
||||
weapons:[Weapon];
|
||||
equipped:Equipment;
|
||||
path:[Vec3];
|
||||
}
|
||||
|
||||
table Weapon {
|
||||
name:string;
|
||||
damage:short;
|
||||
}
|
||||
|
||||
table AllMonsters {
|
||||
monsters: [Monster];
|
||||
}
|
||||
|
||||
root_type AllMonsters;
|
@ -1,129 +0,0 @@
|
||||
@file:OptIn(ExperimentalUnsignedTypes::class)
|
||||
|
||||
package com.google.flatbuffers.kotlin.benchmark
|
||||
|
||||
|
||||
import com.google.flatbuffers.kotlin.FlatBufferBuilder
|
||||
import jmonster.JAllMonsters
|
||||
import jmonster.JColor
|
||||
import jmonster.JMonster
|
||||
import jmonster.JVec3
|
||||
import monster.AllMonsters
|
||||
import monster.AllMonsters.Companion.createAllMonsters
|
||||
import monster.AllMonsters.Companion.createMonstersVector
|
||||
import monster.Monster
|
||||
import monster.Monster.Companion.createInventoryVector
|
||||
import monster.MonsterOffsetArray
|
||||
import monster.Vec3
|
||||
import org.openjdk.jmh.annotations.*
|
||||
import org.openjdk.jmh.infra.Blackhole
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
@State(Scope.Benchmark)
|
||||
@BenchmarkMode(Mode.AverageTime)
|
||||
@OutputTimeUnit(TimeUnit.NANOSECONDS)
|
||||
@Measurement(iterations = 20, time = 1, timeUnit = TimeUnit.NANOSECONDS)
|
||||
open class FlatbufferBenchmark {
|
||||
|
||||
val repetition = 1000000
|
||||
val fbKotlin = FlatBufferBuilder(1024 * repetition)
|
||||
val fbDeserializationKotlin = FlatBufferBuilder(1024 * repetition)
|
||||
val fbJava = com.google.flatbuffers.FlatBufferBuilder(1024 * repetition)
|
||||
val fbDeserializationJava = com.google.flatbuffers.FlatBufferBuilder(1024 * repetition)
|
||||
|
||||
init {
|
||||
populateMosterKotlin(fbDeserializationKotlin)
|
||||
populateMosterJava(fbDeserializationJava)
|
||||
}
|
||||
@OptIn(ExperimentalUnsignedTypes::class)
|
||||
private fun populateMosterKotlin(fb: FlatBufferBuilder) {
|
||||
fb.clear()
|
||||
val monsterName = fb.createString("MonsterName");
|
||||
val items = ubyteArrayOf(0u, 1u, 2u, 3u, 4u)
|
||||
val inv = createInventoryVector(fb, items)
|
||||
val monsterOffsets: MonsterOffsetArray = MonsterOffsetArray(repetition) {
|
||||
Monster.startMonster(fb)
|
||||
Monster.addName(fb, monsterName)
|
||||
Monster.addPos(fb, Vec3.createVec3(fb, 1.0f, 2.0f, 3.0f))
|
||||
Monster.addHp(fb, 80)
|
||||
Monster.addMana(fb, 150)
|
||||
Monster.addInventory(fb, inv)
|
||||
Monster.addColor(fb, monster.Color.Red)
|
||||
Monster.endMonster(fb)
|
||||
}
|
||||
val monsters = createMonstersVector(fb, monsterOffsets)
|
||||
val allMonsters = createAllMonsters(fb, monsters)
|
||||
fb.finish(allMonsters)
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalUnsignedTypes::class)
|
||||
private fun populateMosterJava(fb: com.google.flatbuffers.FlatBufferBuilder){
|
||||
fb.clear()
|
||||
val monsterName = fb.createString("MonsterName");
|
||||
val inv = JMonster.createInventoryVector(fb, ubyteArrayOf(0u, 1u, 2u, 3u, 4u))
|
||||
val monsters = JAllMonsters.createMonstersVector(fb, IntArray(repetition) {
|
||||
JMonster.startJMonster(fb)
|
||||
JMonster.addName(fb, monsterName)
|
||||
JMonster.addPos(fb, JVec3.createJVec3(fb, 1.0f, 2.0f, 3.0f))
|
||||
JMonster.addHp(fb, 80)
|
||||
JMonster.addMana(fb, 150)
|
||||
JMonster.addInventory(fb, inv)
|
||||
JMonster.addColor(fb, JColor.Red)
|
||||
JMonster.endJMonster(fb)
|
||||
})
|
||||
val allMonsters = JAllMonsters.createJAllMonsters(fb, monsters)
|
||||
fb.finish(allMonsters)
|
||||
}
|
||||
@Benchmark
|
||||
fun monstersSerializationKotlin() {
|
||||
populateMosterKotlin(fbKotlin)
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalUnsignedTypes::class)
|
||||
@Benchmark
|
||||
fun monstersDeserializationKotlin(hole: Blackhole) {
|
||||
val monstersRef = AllMonsters.asRoot(fbDeserializationKotlin.dataBuffer())
|
||||
|
||||
for (i in 0 until monstersRef.monstersLength) {
|
||||
val monster = monstersRef.monsters(i)!!
|
||||
val pos = monster.pos!!
|
||||
hole.consume(monster.name)
|
||||
hole.consume(pos.x)
|
||||
hole.consume(pos.y)
|
||||
hole.consume(pos.z)
|
||||
hole.consume(monster.hp)
|
||||
hole.consume(monster.mana)
|
||||
hole.consume(monster.color)
|
||||
hole.consume(monster.inventory(0).toByte())
|
||||
hole.consume(monster.inventory(1))
|
||||
hole.consume(monster.inventory(2))
|
||||
hole.consume(monster.inventory(3))
|
||||
}
|
||||
}
|
||||
@Benchmark
|
||||
fun monstersSerializationJava() {
|
||||
populateMosterJava(fbJava)
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
fun monstersDeserializationJava(hole: Blackhole) {
|
||||
val monstersRef = JAllMonsters.getRootAsJAllMonsters(fbDeserializationJava.dataBuffer())
|
||||
|
||||
for (i in 0 until monstersRef.monstersLength) {
|
||||
val monster = monstersRef.monsters(i)!!
|
||||
val pos = monster.pos!!
|
||||
hole.consume(monster.name)
|
||||
hole.consume(pos.x)
|
||||
hole.consume(pos.y)
|
||||
hole.consume(pos.z)
|
||||
hole.consume(monster.hp)
|
||||
hole.consume(monster.mana)
|
||||
hole.consume(monster.color)
|
||||
hole.consume(monster.inventory(0))
|
||||
hole.consume(monster.inventory(1))
|
||||
hole.consume(monster.inventory(2))
|
||||
hole.consume(monster.inventory(3))
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,199 +0,0 @@
|
||||
/*
|
||||
* Copyright 2021 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.
|
||||
*/
|
||||
@file:OptIn(ExperimentalUnsignedTypes::class)
|
||||
|
||||
package com.google.flatbuffers.kotlin.benchmark
|
||||
import com.google.flatbuffers.ArrayReadWriteBuf
|
||||
import com.google.flatbuffers.FlexBuffers
|
||||
import com.google.flatbuffers.FlexBuffersBuilder.BUILDER_FLAG_SHARE_ALL
|
||||
import com.google.flatbuffers.kotlin.FlexBuffersBuilder
|
||||
import com.google.flatbuffers.kotlin.getRoot
|
||||
import kotlinx.benchmark.Blackhole
|
||||
import org.openjdk.jmh.annotations.Benchmark
|
||||
import org.openjdk.jmh.annotations.BenchmarkMode
|
||||
import org.openjdk.jmh.annotations.Measurement
|
||||
import org.openjdk.jmh.annotations.Mode
|
||||
import org.openjdk.jmh.annotations.OutputTimeUnit
|
||||
import org.openjdk.jmh.annotations.Scope
|
||||
import org.openjdk.jmh.annotations.Setup
|
||||
import org.openjdk.jmh.annotations.State
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
@State(Scope.Benchmark)
|
||||
@BenchmarkMode(Mode.AverageTime)
|
||||
@OutputTimeUnit(TimeUnit.NANOSECONDS)
|
||||
@Measurement(iterations = 20, time = 1, timeUnit = TimeUnit.NANOSECONDS)
|
||||
open class FlexBuffersBenchmark {
|
||||
|
||||
var initialCapacity = 1024
|
||||
var value: Double = 0.0
|
||||
val stringKey = Array(500) { "Ḧ̵̘́ȩ̵̐myFairlyBigKey$it" }
|
||||
val stringValue = Array(500) { "Ḧ̵̘́ȩ̵̐myFairlyBigValue$it" }
|
||||
val bigIntArray = IntArray(5000) { it }
|
||||
|
||||
@Setup
|
||||
fun setUp() {
|
||||
value = 3.0
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
open fun mapKotlin(blackhole: Blackhole) {
|
||||
val kBuilder = FlexBuffersBuilder(initialCapacity, FlexBuffersBuilder.SHARE_KEYS_AND_STRINGS)
|
||||
kBuilder.putMap {
|
||||
this["hello"] = "world"
|
||||
this["int"] = 10
|
||||
this["float"] = 12.3
|
||||
this["intarray"] = bigIntArray
|
||||
this.putMap("myMap") {
|
||||
this["cool"] = "beans"
|
||||
}
|
||||
}
|
||||
val ref = getRoot(kBuilder.finish())
|
||||
val map = ref.toMap()
|
||||
blackhole.consume(map.size)
|
||||
blackhole.consume(map["hello"].toString())
|
||||
blackhole.consume(map["int"].toInt())
|
||||
blackhole.consume(map["float"].toDouble())
|
||||
blackhole.consume(map["intarray"].toIntArray())
|
||||
blackhole.consume(ref["myMap"]["cool"].toString())
|
||||
blackhole.consume(ref["invalid_key"].isNull)
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
open fun mapJava(blackhole: Blackhole) {
|
||||
val jBuilder = com.google.flatbuffers.FlexBuffersBuilder(ArrayReadWriteBuf(initialCapacity), BUILDER_FLAG_SHARE_ALL)
|
||||
val startMap = jBuilder.startMap()
|
||||
jBuilder.putString("hello", "world")
|
||||
jBuilder.putInt("int", 10)
|
||||
jBuilder.putFloat("float", 12.3)
|
||||
|
||||
val startVec = jBuilder.startVector()
|
||||
bigIntArray.forEach { jBuilder.putInt(it) }
|
||||
jBuilder.endVector("intarray", startVec, true, false)
|
||||
|
||||
val startInnerMap = jBuilder.startMap()
|
||||
jBuilder.putString("cool", "beans")
|
||||
jBuilder.endMap("myMap", startInnerMap)
|
||||
|
||||
jBuilder.endMap(null, startMap)
|
||||
val ref = FlexBuffers.getRoot(jBuilder.finish())
|
||||
val map = ref.asMap()
|
||||
blackhole.consume(map.size())
|
||||
blackhole.consume(map.get("hello").toString())
|
||||
blackhole.consume(map.get("int").asInt())
|
||||
blackhole.consume(map.get("float").asFloat())
|
||||
val vec = map.get("intarray").asVector()
|
||||
blackhole.consume(IntArray(vec.size()) { vec.get(it).asInt() })
|
||||
|
||||
blackhole.consume(ref.asMap()["myMap"].asMap()["cool"].toString())
|
||||
blackhole.consume(ref.asMap()["invalid_key"].isNull)
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
open fun intArrayKotlin(blackhole: Blackhole) {
|
||||
val kBuilder = FlexBuffersBuilder(initialCapacity, FlexBuffersBuilder.SHARE_KEYS_AND_STRINGS)
|
||||
kBuilder.put(bigIntArray)
|
||||
val root = getRoot(kBuilder.finish())
|
||||
blackhole.consume(root.toIntArray())
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
open fun intArrayJava(blackhole: Blackhole) {
|
||||
val jBuilder = com.google.flatbuffers.FlexBuffersBuilder(ArrayReadWriteBuf(initialCapacity), BUILDER_FLAG_SHARE_ALL)
|
||||
val v = jBuilder.startVector()
|
||||
bigIntArray.forEach { jBuilder.putInt(it) }
|
||||
jBuilder.endVector(null, v, true, false)
|
||||
jBuilder.finish()
|
||||
val root = FlexBuffers.getRoot(jBuilder.buffer)
|
||||
val vec = root.asVector()
|
||||
blackhole.consume(
|
||||
IntArray(vec.size()) {
|
||||
vec[it].asInt()
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
open fun stringArrayKotlin(blackhole: Blackhole) {
|
||||
val kBuilder = FlexBuffersBuilder(initialCapacity, FlexBuffersBuilder.SHARE_KEYS_AND_STRINGS)
|
||||
kBuilder.putVector { stringValue.forEach { kBuilder.put(it) } }
|
||||
kBuilder.finish()
|
||||
val root = getRoot(kBuilder.buffer)
|
||||
val vec = root.toVector()
|
||||
blackhole.consume(Array(vec.size) { vec[it].toString() })
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
open fun stringArrayJava(blackhole: Blackhole) {
|
||||
val jBuilder = com.google.flatbuffers.FlexBuffersBuilder(ArrayReadWriteBuf(initialCapacity), BUILDER_FLAG_SHARE_ALL)
|
||||
val v = jBuilder.startVector()
|
||||
stringValue.forEach { jBuilder.putString(it) }
|
||||
jBuilder.endVector(null, v, false, false)
|
||||
jBuilder.finish()
|
||||
val root = FlexBuffers.getRoot(jBuilder.buffer)
|
||||
val vec = root.asVector()
|
||||
blackhole.consume(Array(vec.size()) { vec[it].toString() })
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
open fun stringMapKotlin(blackhole: Blackhole) {
|
||||
val kBuilder = FlexBuffersBuilder(initialCapacity, FlexBuffersBuilder.SHARE_KEYS_AND_STRINGS)
|
||||
val pos = kBuilder.startMap()
|
||||
for (i in stringKey.indices) {
|
||||
kBuilder[stringKey[i]] = stringValue[i]
|
||||
}
|
||||
kBuilder.endMap(pos)
|
||||
val ref = getRoot(kBuilder.finish())
|
||||
val map = ref.toMap()
|
||||
val keys = map.keys
|
||||
|
||||
for (key in keys) {
|
||||
blackhole.consume(map[key.toString()].toString())
|
||||
}
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
open fun stringMapBytIndexKotlin(blackhole: Blackhole) {
|
||||
val kBuilder = FlexBuffersBuilder(initialCapacity, FlexBuffersBuilder.SHARE_KEYS_AND_STRINGS)
|
||||
val pos = kBuilder.startMap()
|
||||
for (i in stringKey.indices) {
|
||||
kBuilder[stringKey[i]] = stringValue[i]
|
||||
}
|
||||
kBuilder.endMap(pos)
|
||||
val ref = getRoot(kBuilder.finish())
|
||||
val map = ref.toMap()
|
||||
for (index in 0 until map.size) {
|
||||
blackhole.consume(map[index].toString())
|
||||
}
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
open fun stringMapJava(blackhole: Blackhole) {
|
||||
val jBuilder = com.google.flatbuffers.FlexBuffersBuilder(ArrayReadWriteBuf(initialCapacity), BUILDER_FLAG_SHARE_ALL)
|
||||
val v = jBuilder.startMap()
|
||||
for (i in stringKey.indices) {
|
||||
jBuilder.putString(stringKey[i], stringValue[i])
|
||||
}
|
||||
jBuilder.endMap(null, v)
|
||||
val ref = FlexBuffers.getRoot(jBuilder.finish())
|
||||
val map = ref.asMap()
|
||||
val keyVec = map.keys()
|
||||
for (i in 0 until keyVec.size()) {
|
||||
val s = keyVec[i].toString()
|
||||
blackhole.consume(map[s].toString())
|
||||
}
|
||||
}
|
||||
}
|
@ -1,122 +0,0 @@
|
||||
/*
|
||||
* Copyright 2021 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.kotlin.benchmark
|
||||
|
||||
import com.google.flatbuffers.kotlin.ArrayReadBuffer
|
||||
import com.google.flatbuffers.kotlin.JSONParser
|
||||
import com.google.flatbuffers.kotlin.Reference
|
||||
import com.google.flatbuffers.kotlin.toJson
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.JsonObject
|
||||
import com.google.gson.JsonParser
|
||||
import com.squareup.moshi.Moshi
|
||||
import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory
|
||||
import kotlinx.benchmark.Blackhole
|
||||
import okio.Buffer
|
||||
import org.openjdk.jmh.annotations.Benchmark
|
||||
import org.openjdk.jmh.annotations.BenchmarkMode
|
||||
import org.openjdk.jmh.annotations.Measurement
|
||||
import org.openjdk.jmh.annotations.Mode
|
||||
import org.openjdk.jmh.annotations.OutputTimeUnit
|
||||
import org.openjdk.jmh.annotations.Scope
|
||||
import org.openjdk.jmh.annotations.State
|
||||
import java.io.ByteArrayInputStream
|
||||
import java.io.InputStreamReader
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
@State(Scope.Benchmark)
|
||||
@BenchmarkMode(Mode.AverageTime)
|
||||
@OutputTimeUnit(TimeUnit.MICROSECONDS)
|
||||
@Measurement(iterations = 100, time = 1, timeUnit = TimeUnit.MICROSECONDS)
|
||||
open class JsonBenchmark {
|
||||
|
||||
final val moshi = Moshi.Builder()
|
||||
.addLast(KotlinJsonAdapterFactory())
|
||||
.build()
|
||||
final val moshiAdapter = moshi.adapter(Map::class.java)
|
||||
|
||||
final val gson = Gson()
|
||||
final val gsonParser = JsonParser()
|
||||
|
||||
val fbParser = JSONParser()
|
||||
|
||||
final val classLoader = this.javaClass.classLoader
|
||||
final val twitterData = classLoader.getResourceAsStream("twitter.json")!!.readBytes()
|
||||
final val canadaData = classLoader.getResourceAsStream("canada.json")!!.readBytes()
|
||||
final val citmData = classLoader.getResourceAsStream("citm_catalog.json")!!.readBytes()
|
||||
|
||||
val fbCitmRef = JSONParser().parse(ArrayReadBuffer(citmData))
|
||||
val moshiCitmRef = moshi.adapter(Map::class.java).fromJson(citmData.decodeToString())
|
||||
val gsonCitmRef = gsonParser.parse(citmData.decodeToString())
|
||||
|
||||
fun readFlexBuffers(data: ByteArray): Reference = fbParser.parse(ArrayReadBuffer(data))
|
||||
|
||||
fun readMoshi(data: ByteArray): Map<*, *>? {
|
||||
val buffer = Buffer().write(data)
|
||||
return moshiAdapter.fromJson(buffer)
|
||||
}
|
||||
|
||||
fun readGson(data: ByteArray): JsonObject {
|
||||
val parser = JsonParser()
|
||||
val jsonReader = InputStreamReader(ByteArrayInputStream(data))
|
||||
return parser.parse(jsonReader).asJsonObject
|
||||
}
|
||||
|
||||
// TWITTER
|
||||
@Benchmark
|
||||
open fun readTwitterFlexBuffers(hole: Blackhole? = null) = hole?.consume(readFlexBuffers(twitterData))
|
||||
@Benchmark
|
||||
open fun readTwitterMoshi(hole: Blackhole?) = hole?.consume(readMoshi(twitterData))
|
||||
@Benchmark
|
||||
open fun readTwitterGson(hole: Blackhole?) = hole?.consume(readGson(twitterData))
|
||||
|
||||
@Benchmark
|
||||
open fun roundTripTwitterFlexBuffers(hole: Blackhole? = null) = hole?.consume(readFlexBuffers(twitterData).toJson())
|
||||
@Benchmark
|
||||
open fun roundTripTwitterMoshi(hole: Blackhole?) = hole?.consume(moshiAdapter.toJson(readMoshi(twitterData)))
|
||||
@Benchmark
|
||||
open fun roundTripTwitterGson(hole: Blackhole?) = hole?.consume(gson.toJson(readGson(twitterData)))
|
||||
|
||||
// CITM
|
||||
@Benchmark
|
||||
open fun readCITMFlexBuffers(hole: Blackhole? = null) = hole?.consume(readFlexBuffers(citmData))
|
||||
@Benchmark
|
||||
open fun readCITMMoshi(hole: Blackhole?) = hole?.consume(moshiAdapter.toJson(readMoshi(citmData)))
|
||||
@Benchmark
|
||||
open fun readCITMGson(hole: Blackhole?) = hole?.consume(gson.toJson(readGson(citmData)))
|
||||
|
||||
@Benchmark
|
||||
open fun roundTripCITMFlexBuffers(hole: Blackhole? = null) = hole?.consume(readFlexBuffers(citmData).toJson())
|
||||
@Benchmark
|
||||
open fun roundTripCITMMoshi(hole: Blackhole?) = hole?.consume(moshiAdapter.toJson(readMoshi(citmData)))
|
||||
@Benchmark
|
||||
open fun roundTripCITMGson(hole: Blackhole?) = hole?.consume(gson.toJson(readGson(citmData)))
|
||||
|
||||
@Benchmark
|
||||
open fun writeCITMFlexBuffers(hole: Blackhole? = null) = hole?.consume(fbCitmRef.toJson())
|
||||
@Benchmark
|
||||
open fun writeCITMMoshi(hole: Blackhole?) = hole?.consume(moshiAdapter.toJson(moshiCitmRef))
|
||||
@Benchmark
|
||||
open fun writeCITMGson(hole: Blackhole?) = hole?.consume(gson.toJson(gsonCitmRef))
|
||||
|
||||
// CANADA
|
||||
@Benchmark
|
||||
open fun readCanadaFlexBuffers(hole: Blackhole? = null) = hole?.consume(readFlexBuffers(canadaData))
|
||||
@Benchmark
|
||||
open fun readCanadaMoshi(hole: Blackhole?) = hole?.consume(readMoshi(canadaData))
|
||||
@Benchmark
|
||||
open fun readCanadaGson(hole: Blackhole?) = hole?.consume(readGson(canadaData))
|
||||
}
|
@ -1,235 +0,0 @@
|
||||
/*
|
||||
* Copyright 2021 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.kotlin.benchmark
|
||||
|
||||
import com.google.flatbuffers.kotlin.ArrayReadWriteBuffer
|
||||
import com.google.flatbuffers.kotlin.Key
|
||||
import com.google.flatbuffers.kotlin.Utf8
|
||||
import kotlinx.benchmark.Blackhole
|
||||
import org.openjdk.jmh.annotations.Benchmark
|
||||
import org.openjdk.jmh.annotations.BenchmarkMode
|
||||
import org.openjdk.jmh.annotations.Measurement
|
||||
import org.openjdk.jmh.annotations.Mode
|
||||
import org.openjdk.jmh.annotations.OutputTimeUnit
|
||||
import org.openjdk.jmh.annotations.Scope
|
||||
import org.openjdk.jmh.annotations.Setup
|
||||
import org.openjdk.jmh.annotations.State
|
||||
import java.nio.ByteBuffer
|
||||
import java.util.concurrent.TimeUnit
|
||||
import kotlin.random.Random
|
||||
|
||||
@State(Scope.Benchmark)
|
||||
@BenchmarkMode(Mode.AverageTime)
|
||||
@OutputTimeUnit(TimeUnit.MICROSECONDS)
|
||||
@Measurement(iterations = 100, time = 1, timeUnit = TimeUnit.MICROSECONDS)
|
||||
open class UTF8Benchmark {
|
||||
|
||||
private val sampleSize = 5000
|
||||
private val stringSize = 25
|
||||
private var sampleSmallUtf8 = (0..sampleSize).map { populateUTF8(stringSize) }.toList()
|
||||
private var sampleSmallUtf8Decoded = sampleSmallUtf8.map { it.encodeToByteArray() }.toList()
|
||||
private var sampleSmallAscii = (0..sampleSize).map { populateAscii(stringSize) }.toList()
|
||||
private var sampleSmallAsciiDecoded = sampleSmallAscii.map { it.encodeToByteArray() }.toList()
|
||||
|
||||
@Setup
|
||||
fun setUp() {
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
fun encodeUtf8KotlinStandard(blackhole: Blackhole) {
|
||||
for (i in sampleSmallUtf8) {
|
||||
blackhole.consume(i.encodeToByteArray())
|
||||
}
|
||||
}
|
||||
@Benchmark
|
||||
fun encodeUtf8KotlinFlatbuffers(blackhole: Blackhole) {
|
||||
for (i in sampleSmallUtf8) {
|
||||
val byteArray = ByteArray((i.length * 4))
|
||||
blackhole.consume(Utf8.encodeUtf8Array(i, byteArray, 0, byteArray.size))
|
||||
}
|
||||
}
|
||||
@Benchmark
|
||||
fun encodeUtf8JavaFlatbuffers(blackhole: Blackhole) {
|
||||
val javaUtf8 = com.google.flatbuffers.Utf8.getDefault()
|
||||
for (i in sampleSmallUtf8) {
|
||||
val byteBuffer = ByteBuffer.wrap(ByteArray(i.length * 4))
|
||||
blackhole.consume(javaUtf8.encodeUtf8(i, byteBuffer))
|
||||
}
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
fun decodeUtf8KotlinStandard(blackhole: Blackhole) {
|
||||
for (ary in sampleSmallUtf8Decoded) {
|
||||
blackhole.consume(ary.decodeToString())
|
||||
}
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
fun decodeUtf8KotlinFlatbuffers(blackhole: Blackhole) {
|
||||
for (ary in sampleSmallUtf8Decoded) {
|
||||
blackhole.consume(Utf8.decodeUtf8Array(ary, 0, ary.size))
|
||||
}
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
fun decodeUtf8JavaFlatbuffers(blackhole: Blackhole) {
|
||||
val javaUtf8 = com.google.flatbuffers.Utf8.getDefault()
|
||||
for (ary in sampleSmallUtf8Decoded) {
|
||||
val byteBuffer = ByteBuffer.wrap(ary)
|
||||
blackhole.consume(javaUtf8.decodeUtf8(byteBuffer, 0, ary.size))
|
||||
}
|
||||
}
|
||||
|
||||
// ASCII TESTS
|
||||
|
||||
@Benchmark
|
||||
fun encodeAsciiKotlinStandard(blackhole: Blackhole) {
|
||||
for (i in sampleSmallAscii) {
|
||||
blackhole.consume(i.encodeToByteArray())
|
||||
}
|
||||
}
|
||||
@Benchmark
|
||||
fun encodeAsciiKotlinFlatbuffers(blackhole: Blackhole) {
|
||||
for (i in sampleSmallAscii) {
|
||||
val byteArray = ByteArray(i.length) // Utf8.encodedLength(i))
|
||||
blackhole.consume(Utf8.encodeUtf8Array(i, byteArray, 0, byteArray.size))
|
||||
}
|
||||
}
|
||||
@Benchmark
|
||||
fun encodeAsciiJavaFlatbuffers(blackhole: Blackhole) {
|
||||
val javaUtf8 = com.google.flatbuffers.Utf8.getDefault()
|
||||
for (i in sampleSmallAscii) {
|
||||
val byteBuffer = ByteBuffer.wrap(ByteArray(i.length))
|
||||
blackhole.consume(javaUtf8.encodeUtf8(i, byteBuffer))
|
||||
}
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
fun decodeAsciiKotlinStandard(blackhole: Blackhole) {
|
||||
|
||||
for (ary in sampleSmallAsciiDecoded) {
|
||||
String(ary)
|
||||
blackhole.consume(ary.decodeToString())
|
||||
}
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
fun decodeAsciiKotlinFlatbuffers(blackhole: Blackhole) {
|
||||
for (ary in sampleSmallAsciiDecoded) {
|
||||
blackhole.consume(Utf8.decodeUtf8Array(ary, 0, ary.size))
|
||||
}
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
fun decodeAsciiJavaFlatbuffers(blackhole: Blackhole) {
|
||||
val javaUtf8 = com.google.flatbuffers.Utf8.getDefault()
|
||||
for (ary in sampleSmallAsciiDecoded) {
|
||||
val byteBuffer = ByteBuffer.wrap(ary)
|
||||
blackhole.consume(javaUtf8.decodeUtf8(byteBuffer, 0, ary.size))
|
||||
}
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
fun readAllCharsString(blackhole: Blackhole) {
|
||||
for (ary in sampleSmallAsciiDecoded) {
|
||||
val key = Utf8.decodeUtf8Array(ary, 0, ary.size)
|
||||
for (i in key.indices) {
|
||||
blackhole.consume(key[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
fun readAllCharsCharSequence(blackhole: Blackhole) {
|
||||
for (ary in sampleSmallAsciiDecoded) {
|
||||
val key = Key(ArrayReadWriteBuffer(ary), 0, ary.size)
|
||||
for (i in 0 until key.sizeInChars) {
|
||||
blackhole.consume(key[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun populateAscii(size: Int): String {
|
||||
val data = ByteArray(size)
|
||||
for (i in data.indices) {
|
||||
data[i] = Random.nextInt(0, 127).toByte()
|
||||
}
|
||||
|
||||
return String(data, 0, data.size)
|
||||
}
|
||||
|
||||
// generate a string having at least length N
|
||||
// can exceed by up to 3 chars, returns the actual length
|
||||
fun populateUTF8(size: Int): String {
|
||||
val data = ByteArray(size + 3)
|
||||
var i = 0
|
||||
while (i < size) {
|
||||
val w = Random.nextInt() and 0xFF
|
||||
when {
|
||||
w < 0x80 -> data[i++] = 0x20; // w;
|
||||
w < 0xE0 -> {
|
||||
data[i++] = (0xC2 + Random.nextInt() % (0xDF - 0xC2 + 1)).toByte()
|
||||
data[i++] = (0x80 + Random.nextInt() % (0xBF - 0x80 + 1)).toByte()
|
||||
}
|
||||
w == 0xE0 -> {
|
||||
data[i++] = w.toByte()
|
||||
data[i++] = (0xA0 + Random.nextInt() % (0xBF - 0xA0 + 1)).toByte()
|
||||
data[i++] = (0x80 + Random.nextInt() % (0xBF - 0x80 + 1)).toByte()
|
||||
}
|
||||
w <= 0xEC -> {
|
||||
data[i++] = w.toByte()
|
||||
data[i++] = (0x80 + Random.nextInt() % (0xBF - 0x80 + 1)).toByte()
|
||||
data[i++] = (0x80 + Random.nextInt() % (0xBF - 0x80 + 1)).toByte()
|
||||
}
|
||||
w == 0xED -> {
|
||||
data[i++] = w.toByte()
|
||||
data[i++] = (0x80 + Random.nextInt() % (0x9F - 0x80 + 1)).toByte()
|
||||
data[i++] = (0x80 + Random.nextInt() % (0xBF - 0x80 + 1)).toByte()
|
||||
}
|
||||
w <= 0xEF -> {
|
||||
data[i++] = w.toByte()
|
||||
data[i++] = (0x80 + Random.nextInt() % (0xBF - 0x80 + 1)).toByte()
|
||||
data[i++] = (0x80 + Random.nextInt() % (0xBF - 0x80 + 1)).toByte()
|
||||
}
|
||||
w < 0xF0 -> {
|
||||
data[i++] = (0xF1 + Random.nextInt() % (0xF3 - 0xF1 + 1)).toByte()
|
||||
data[i++] = (0x80 + Random.nextInt() % (0xBF - 0x80 + 1)).toByte()
|
||||
data[i++] = (0x80 + Random.nextInt() % (0xBF - 0x80 + 1)).toByte()
|
||||
data[i++] = (0x80 + Random.nextInt() % (0xBF - 0x80 + 1)).toByte()
|
||||
}
|
||||
w == 0xF0 -> {
|
||||
data[i++] = w.toByte()
|
||||
data[i++] = (0x90 + Random.nextInt() % (0xBF - 0x90 + 1)).toByte()
|
||||
data[i++] = (0x80 + Random.nextInt() % (0xBF - 0x80 + 1)).toByte()
|
||||
data[i++] = (0x80 + Random.nextInt() % (0xBF - 0x80 + 1)).toByte()
|
||||
}
|
||||
w <= 0xF3 -> {
|
||||
data[i++] = (0xF1 + Random.nextInt() % (0xF3 - 0xF1 + 1)).toByte()
|
||||
data[i++] = (0x80 + Random.nextInt() % (0xBF - 0x80 + 1)).toByte()
|
||||
data[i++] = (0x80 + Random.nextInt() % (0xBF - 0x80 + 1)).toByte()
|
||||
data[i++] = (0x80 + Random.nextInt() % (0xBF - 0x80 + 1)).toByte()
|
||||
}
|
||||
w == 0xF4 -> {
|
||||
data[i++] = w.toByte()
|
||||
data[i++] = (0x80 + Random.nextInt() % (0x8F - 0x80 + 1)).toByte()
|
||||
data[i++] = (0x80 + Random.nextInt() % (0xBF - 0x80 + 1)).toByte()
|
||||
data[i++] = (0x80 + Random.nextInt() % (0xBF - 0x80 + 1)).toByte()
|
||||
}
|
||||
}
|
||||
}
|
||||
return String(data, 0, i)
|
||||
}
|
||||
}
|
44
third_party/flatbuffers/kotlin/build.gradle.kts
vendored
44
third_party/flatbuffers/kotlin/build.gradle.kts
vendored
@ -1,44 +0,0 @@
|
||||
import org.gradle.internal.impldep.org.testng.ITestResult.STARTED
|
||||
import org.jetbrains.kotlin.gradle.dsl.KotlinCommonOptions
|
||||
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
|
||||
import java.nio.charset.StandardCharsets
|
||||
|
||||
buildscript {
|
||||
repositories {
|
||||
gradlePluginPortal()
|
||||
google()
|
||||
mavenCentral()
|
||||
}
|
||||
dependencies {
|
||||
classpath(libs.plugin.kotlin.gradle)
|
||||
classpath(libs.plugin.kotlinx.benchmark)
|
||||
classpath(libs.plugin.jmhreport)
|
||||
classpath(libs.plugin.download)
|
||||
}
|
||||
}
|
||||
|
||||
allprojects {
|
||||
repositories {
|
||||
google()
|
||||
mavenCentral()
|
||||
}
|
||||
}
|
||||
|
||||
tasks.withType<org.jetbrains.kotlin.gradle.dsl.KotlinCompile<KotlinCommonOptions>>().configureEach {
|
||||
kotlinOptions {
|
||||
freeCompilerArgs += "-progressive" // https://kotlinlang.org/docs/whatsnew13.html#progressive-mode
|
||||
}
|
||||
}
|
||||
|
||||
tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinJvmCompile>().configureEach {
|
||||
kotlinOptions {
|
||||
jvmTarget = JavaVersion.VERSION_1_8.toString()
|
||||
freeCompilerArgs += "-Xjvm-default=all"
|
||||
}
|
||||
}
|
||||
|
||||
tasks.withType<JavaCompile> {
|
||||
options.encoding = StandardCharsets.UTF_8.toString()
|
||||
sourceCompatibility = JavaVersion.VERSION_1_8.toString()
|
||||
targetCompatibility = JavaVersion.VERSION_1_8.toString()
|
||||
}
|
@ -1,142 +0,0 @@
|
||||
import org.gradle.internal.impldep.org.fusesource.jansi.AnsiRenderer.test
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.apple.XCFramework
|
||||
import org.jetbrains.kotlin.cli.common.toBooleanLenient
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.NativeBuildType
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.apple.XCFrameworkConfig
|
||||
|
||||
plugins {
|
||||
kotlin("multiplatform")
|
||||
}
|
||||
|
||||
|
||||
val libName = "Flatbuffers"
|
||||
group = "com.google.flatbuffers.kotlin"
|
||||
version = "2.0.0-SNAPSHOT"
|
||||
|
||||
kotlin {
|
||||
explicitApi()
|
||||
jvm()
|
||||
js(IR) {
|
||||
browser {
|
||||
testTask {
|
||||
enabled = false
|
||||
}
|
||||
}
|
||||
binaries.executable()
|
||||
}
|
||||
macosX64()
|
||||
macosArm64()
|
||||
iosArm64()
|
||||
iosSimulatorArm64()
|
||||
|
||||
sourceSets {
|
||||
|
||||
val commonMain by getting {
|
||||
dependencies {
|
||||
implementation(kotlin("stdlib-common"))
|
||||
}
|
||||
}
|
||||
|
||||
val commonTest by getting {
|
||||
dependencies {
|
||||
implementation(kotlin("test"))
|
||||
}
|
||||
|
||||
kotlin.srcDir("src/commonTest/generated/kotlin/")
|
||||
}
|
||||
val jvmTest by getting {
|
||||
dependencies {
|
||||
implementation(kotlin("test-junit"))
|
||||
implementation("com.google.flatbuffers:flatbuffers-java:2.0.3")
|
||||
}
|
||||
}
|
||||
val jvmMain by getting {
|
||||
}
|
||||
|
||||
val macosX64Main by getting
|
||||
val macosArm64Main by getting
|
||||
val iosArm64Main by getting
|
||||
val iosSimulatorArm64Main by getting
|
||||
|
||||
val nativeMain by creating {
|
||||
// this sourceSet will hold common cold for all iOS targets
|
||||
dependsOn(commonMain)
|
||||
macosArm64Main.dependsOn(this)
|
||||
macosX64Main.dependsOn(this)
|
||||
iosArm64Main.dependsOn(this)
|
||||
iosSimulatorArm64Main.dependsOn(this)
|
||||
}
|
||||
|
||||
all {
|
||||
languageSettings.optIn("kotlin.ExperimentalUnsignedTypes")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Fixes JS issue: https://youtrack.jetbrains.com/issue/KT-49109
|
||||
rootProject.plugins.withType<org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootPlugin> {
|
||||
rootProject.the<org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootExtension>().nodeVersion = "16.0.0"
|
||||
|
||||
}
|
||||
|
||||
// Use the default greeting
|
||||
tasks.register<GenerateFBTestClasses>("generateFBTestClassesKt") {
|
||||
inputFiles.setFrom("$rootDir/../tests/monster_test.fbs",
|
||||
"$rootDir/../tests/dictionary_lookup.fbs",
|
||||
// @todo Seems like nesting code generation is broken for all generators.
|
||||
// disabling test for now.
|
||||
// "$rootDir/../tests/namespace_test/namespace_test1.fbs",
|
||||
// "$rootDir/../tests/namespace_test/namespace_test2.fbs",
|
||||
"$rootDir/../tests/union_vector/union_vector.fbs",
|
||||
"$rootDir/../tests/optional_scalars.fbs")
|
||||
includeFolder.set("$rootDir/../tests/include_test")
|
||||
outputFolder.set("${projectDir}/src/commonTest/generated/kotlin/")
|
||||
variant.set("kotlin-kmp")
|
||||
}
|
||||
|
||||
|
||||
project.tasks.forEach {
|
||||
if (it.name.contains("compileKotlin"))
|
||||
it.dependsOn("generateFBTestClassesKt")
|
||||
}
|
||||
|
||||
fun String.intProperty() = findProperty(this).toString().toInt()
|
||||
|
||||
abstract class GenerateFBTestClasses : DefaultTask() {
|
||||
@get:InputFiles
|
||||
abstract val inputFiles: ConfigurableFileCollection
|
||||
|
||||
@get:Input
|
||||
abstract val includeFolder: Property<String>
|
||||
|
||||
@get:Input
|
||||
abstract val outputFolder: Property<String>
|
||||
|
||||
@get:Input
|
||||
abstract val variant: Property<String>
|
||||
|
||||
@Inject
|
||||
protected open fun getExecActionFactory(): org.gradle.process.internal.ExecActionFactory? {
|
||||
throw UnsupportedOperationException()
|
||||
}
|
||||
|
||||
init {
|
||||
includeFolder.set("")
|
||||
}
|
||||
|
||||
@TaskAction
|
||||
fun compile() {
|
||||
val execAction = getExecActionFactory()!!.newExecAction()
|
||||
val sources = inputFiles.asPath.split(":")
|
||||
val args = mutableListOf("flatc","-o", outputFolder.get(), "--${variant.get()}")
|
||||
if (includeFolder.get().isNotEmpty()) {
|
||||
args.add("-I")
|
||||
args.add(includeFolder.get())
|
||||
}
|
||||
args.addAll(sources)
|
||||
println(args)
|
||||
execAction.commandLine = args
|
||||
print(execAction.execute())
|
||||
}
|
||||
}
|
@ -1,616 +0,0 @@
|
||||
/*
|
||||
* Copyright 2021 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.kotlin
|
||||
|
||||
import kotlin.math.max
|
||||
import kotlin.math.min
|
||||
|
||||
/**
|
||||
* Represent a chunk of data, where FlexBuffers will be read from.
|
||||
*/
|
||||
public interface ReadBuffer {
|
||||
|
||||
/**
|
||||
* Scan through the buffer for first byte matching value.
|
||||
* @param value to be match
|
||||
* @param start inclusive initial position to start searching
|
||||
* @param end exclusive final position of the search
|
||||
* @return position of a match or -1
|
||||
*/
|
||||
public fun findFirst(value: Byte, start: Int, end: Int = limit): Int
|
||||
|
||||
/**
|
||||
* Read boolean from the buffer. Booleans as stored as a single byte
|
||||
* @param index position of the element in [ReadBuffer]
|
||||
* @return [Boolean] element
|
||||
*/
|
||||
public fun getBoolean(index: Int): Boolean
|
||||
|
||||
/**
|
||||
* Read a [Byte] from the buffer.
|
||||
* @param index position of the element in [ReadBuffer]
|
||||
* @return a byte
|
||||
*/
|
||||
public operator fun get(index: Int): Byte
|
||||
|
||||
/**
|
||||
* Read a [UByte] from the buffer.
|
||||
* @param index position of the element in [ReadBuffer]
|
||||
* @return a [UByte]
|
||||
*/
|
||||
public fun getUByte(index: Int): UByte
|
||||
|
||||
/**
|
||||
* Read a [Short] from the buffer.
|
||||
* @param index position of the element in [ReadBuffer]
|
||||
* @return a [Short]
|
||||
*/
|
||||
public fun getShort(index: Int): Short
|
||||
|
||||
/**
|
||||
* Read a [UShort] from the buffer.
|
||||
* @param index position of the element in [ReadBuffer]
|
||||
* @return a [UShort]
|
||||
*/
|
||||
public fun getUShort(index: Int): UShort
|
||||
|
||||
/**
|
||||
* Read a [Int] from the buffer.
|
||||
* @param index position of the element in [ReadBuffer]
|
||||
* @return an [Int]
|
||||
*/
|
||||
public fun getInt(index: Int): Int
|
||||
|
||||
/**
|
||||
* Read a [UInt] from the buffer.
|
||||
* @param index position of the element in [ReadBuffer]
|
||||
* @return an [UInt]
|
||||
*/
|
||||
public fun getUInt(index: Int): UInt
|
||||
|
||||
/**
|
||||
* Read a [Long] from the buffer.
|
||||
* @param index position of the element in [ReadBuffer]
|
||||
* @return a [Long]
|
||||
*/
|
||||
public fun getLong(index: Int): Long
|
||||
|
||||
/**
|
||||
* Read a [ULong] from the buffer.
|
||||
* @param index position of the element in [ReadBuffer]
|
||||
* @return a [ULong]
|
||||
*/
|
||||
public fun getULong(index: Int): ULong
|
||||
|
||||
/**
|
||||
* Read a 32-bit float from the buffer.
|
||||
* @param index position of the element in [ReadBuffer]
|
||||
* @return a float
|
||||
*/
|
||||
public fun getFloat(index: Int): Float
|
||||
|
||||
/**
|
||||
* Read a 64-bit float from the buffer.
|
||||
* @param index position of the element in [ReadBuffer]
|
||||
* @return a double
|
||||
*/
|
||||
public fun getDouble(index: Int): Double
|
||||
|
||||
/**
|
||||
* Read a UTF-8 string from the buffer.
|
||||
* @param start initial element of the string
|
||||
* @param size size of the string in bytes.
|
||||
* @return a `String`
|
||||
*/
|
||||
public fun getString(start: Int = 0, size: Int = limit): String
|
||||
|
||||
/**
|
||||
* Read a ByteArray from the buffer.
|
||||
* @param start position from the [ReadBuffer] to be read
|
||||
* @param length maximum number of bytes to be written in the buffer
|
||||
*/
|
||||
public fun getBytes(array: ByteArray, start: Int, length: Int = array.size)
|
||||
|
||||
/**
|
||||
* Expose [ReadBuffer] as an array of bytes.
|
||||
* This method is meant to be as efficient as possible, so for an array-backed [ReadBuffer], it should
|
||||
* return its own internal data. In case access to internal data is not possible,
|
||||
* a copy of the data into an array of bytes might occur.
|
||||
* @return [ReadBuffer] as an array of bytes
|
||||
*/
|
||||
public fun data(): ByteArray
|
||||
|
||||
/**
|
||||
* Creates a new [ReadBuffer] point to a region of the current buffer, starting at [start] with size [size].
|
||||
* @param start starting position of the [ReadBuffer]
|
||||
* @param size in bytes of the [ReadBuffer]
|
||||
* @return [ReadBuffer] slice.
|
||||
*/
|
||||
public fun slice(start: Int, size: Int): ReadBuffer
|
||||
|
||||
/**
|
||||
* Defines the size of the message in the buffer. It also determines last position that buffer
|
||||
* can be read. Last byte to be accessed is in position `limit() -1`.
|
||||
* @return indicate last position
|
||||
*/
|
||||
public val limit: Int
|
||||
}
|
||||
|
||||
/**
|
||||
* Interface to represent a read-write buffers. This interface will be used to access and write FlexBuffer messages.
|
||||
*/
|
||||
public interface ReadWriteBuffer : ReadBuffer {
|
||||
/**
|
||||
* Clears (resets) the buffer so that it can be reused. Write position will be set to the start.
|
||||
*/
|
||||
public fun clear()
|
||||
|
||||
/**
|
||||
* Request capacity of the buffer relative to [writePosition]. In case buffer is already larger
|
||||
* than the requested, this method will just return true. Otherwise,
|
||||
* It might try to resize the buffer. In case of being unable to allocate
|
||||
* enough memory, an exception will be thrown.
|
||||
* @param additional capacity in bytes to be added on top of [writePosition]
|
||||
* @param copyAtEnd copy current data at the end of new underlying buffer
|
||||
* @return new capacity in bytes
|
||||
*/
|
||||
public fun requestAdditionalCapacity(additional: Int, copyAtEnd: Boolean = false): Int =
|
||||
requestCapacity(writePosition + additional, copyAtEnd)
|
||||
|
||||
/**
|
||||
* Request capacity of the buffer in absolute values. In case buffer is already larger
|
||||
* than the requested the method is a no-op. Otherwise,
|
||||
* It might try to resize the buffer. In case of being unable to allocate
|
||||
* enough memory, an exception will be thrown.
|
||||
* @param capacity new capacity
|
||||
* @param copyAtEnd copy current data at the end of new underlying buffer
|
||||
* @return new capacity in bytes
|
||||
*/
|
||||
public fun requestCapacity(capacity: Int, copyAtEnd: Boolean = false): Int
|
||||
|
||||
/**
|
||||
* Put a [Boolean] into the buffer at [writePosition] . Booleans as stored as single byte.
|
||||
* Write position will be incremented.
|
||||
* @return [Boolean] element
|
||||
*/
|
||||
public fun put(value: Boolean)
|
||||
|
||||
/**
|
||||
* Put an array of bytes into the buffer at [writePosition]. Write position will be incremented.
|
||||
* @param value the data to be copied
|
||||
* @param start initial position on value to be copied
|
||||
* @param length amount of bytes to be copied
|
||||
*/
|
||||
public fun put(value: ByteArray, start: Int = 0, length: Int = value.size)
|
||||
|
||||
/**
|
||||
* Put an array of bytes into the buffer at [writePosition]. Write position will be incremented.
|
||||
* @param value [ReadBuffer] the data to be copied
|
||||
* @param start initial position on value to be copied
|
||||
* @param length amount of bytes to be copied
|
||||
*/
|
||||
public fun put(value: ReadBuffer, start: Int = 0, length: Int = value.limit - start)
|
||||
|
||||
/**
|
||||
* Write a [Byte] into the buffer at [writePosition]. Write position will be incremented.
|
||||
*/
|
||||
public fun put(value: Byte)
|
||||
|
||||
/**
|
||||
* Write a [UByte] into the buffer at [writePosition]. Write position will be incremented.
|
||||
*/
|
||||
public fun put(value: UByte)
|
||||
|
||||
/**
|
||||
* Write a [Short] into in the buffer at [writePosition]. Write position will be incremented.
|
||||
*/
|
||||
public fun put(value: Short)
|
||||
|
||||
/**
|
||||
* Write a [UShort] into in the buffer at [writePosition]. Write position will be incremented.
|
||||
*/
|
||||
public fun put(value: UShort)
|
||||
|
||||
/**
|
||||
* Write a [Int] in the buffer at [writePosition]. Write position will be incremented.
|
||||
*/
|
||||
public fun put(value: Int)
|
||||
|
||||
/**
|
||||
* Write a [UInt] into in the buffer at [writePosition]. Write position will be incremented.
|
||||
*/
|
||||
public fun put(value: UInt)
|
||||
|
||||
/**
|
||||
* Write a [Long] into in the buffer at [writePosition]. Write position will be
|
||||
* incremented.
|
||||
*/
|
||||
public fun put(value: Long)
|
||||
|
||||
/**
|
||||
* Write a [ULong] into in the buffer at [writePosition]. Write position will be
|
||||
* incremented.
|
||||
*/
|
||||
public fun put(value: ULong)
|
||||
|
||||
/**
|
||||
* Write a 32-bit [Float] into the buffer at [writePosition]. Write position will be
|
||||
* incremented.
|
||||
*/
|
||||
public fun put(value: Float)
|
||||
|
||||
/**
|
||||
* Write a 64-bit [Double] into the buffer at [writePosition]. Write position will be
|
||||
* incremented.
|
||||
*/
|
||||
public fun put(value: Double)
|
||||
|
||||
/**
|
||||
* Write a [String] encoded as UTF-8 into the buffer at [writePosition]. Write position will be incremented.
|
||||
* @return size in bytes of the encoded string
|
||||
*/
|
||||
public fun put(value: CharSequence, encodedLength: Int = -1): Int
|
||||
|
||||
/**
|
||||
* Write an array of bytes into the buffer.
|
||||
* @param dstIndex initial position where [src] will be copied into.
|
||||
* @param src the data to be copied.
|
||||
* @param srcStart initial position on [src] that will be copied.
|
||||
* @param srcLength amount of bytes to be copied
|
||||
*/
|
||||
public fun set(dstIndex: Int, src: ByteArray, srcStart: Int = 0, srcLength: Int = src.size)
|
||||
|
||||
/**
|
||||
* Write an array of bytes into the buffer.
|
||||
* @param dstIndex initial position where [src] will be copied into.
|
||||
* @param src the data to be copied.
|
||||
* @param srcStart initial position on [src] that will be copied.
|
||||
* @param srcLength amount of bytes to be copied
|
||||
*/
|
||||
public operator fun set(dstIndex: Int, src: ReadBuffer, srcStart: Int = 0, srcLength: Int)
|
||||
|
||||
/**
|
||||
* Write [Boolean] into a given position [index] on the buffer. Booleans as stored as single byte.
|
||||
* @param index position of the element in buffer
|
||||
*/
|
||||
public operator fun set(index: Int, value: Boolean)
|
||||
|
||||
/**
|
||||
* Write [Byte] into a given position [index] on the buffer.
|
||||
* @param index position of the element in the buffer
|
||||
*/
|
||||
public operator fun set(index: Int, value: Byte)
|
||||
|
||||
/**
|
||||
* Write [UByte] into a given position [index] on the buffer.
|
||||
* @param index position of the element in the buffer
|
||||
*/
|
||||
public operator fun set(index: Int, value: UByte)
|
||||
|
||||
/**
|
||||
Short
|
||||
* @param index position of the element in [ReadBuffer]
|
||||
*/
|
||||
public fun set(index: Int, value: Short)
|
||||
|
||||
/**
|
||||
* Write [UShort] into a given position [index] on the buffer.
|
||||
* @param index position of the element in [ReadBuffer]
|
||||
*/
|
||||
public fun set(index: Int, value: UShort)
|
||||
|
||||
/**
|
||||
* Write [Int] into a given position [index] on the buffer.
|
||||
* @param index position of the element in [ReadBuffer]
|
||||
*/
|
||||
public fun set(index: Int, value: Int)
|
||||
|
||||
/**
|
||||
* Write [UInt] into a given position [index] on the buffer.
|
||||
* @param index position of the element in [ReadBuffer]
|
||||
*/
|
||||
public fun set(index: Int, value: UInt)
|
||||
|
||||
/**
|
||||
* Write [Long] into a given position [index] on the buffer.
|
||||
* @param index position of the element in [ReadBuffer]
|
||||
*/
|
||||
public fun set(index: Int, value: Long)
|
||||
|
||||
/**
|
||||
* Write [ULong] into a given position [index] on the buffer.
|
||||
* @param index position of the element in [ReadBuffer]
|
||||
*/
|
||||
public fun set(index: Int, value: ULong)
|
||||
|
||||
/**
|
||||
* Write [Float] into a given position [index] on the buffer.
|
||||
* @param index position of the element in [ReadBuffer]
|
||||
*/
|
||||
public fun set(index: Int, value: Float)
|
||||
|
||||
/**
|
||||
* Write [Double] into a given position [index] on the buffer.
|
||||
* @param index position of the element in [ReadBuffer]
|
||||
*/
|
||||
public fun set(index: Int, value: Double)
|
||||
|
||||
public fun fill(value: Byte, start: Int, end: Int)
|
||||
|
||||
/**
|
||||
* Current position of the buffer to be written. It will be automatically updated on [put] operations.
|
||||
*/
|
||||
public var writePosition: Int
|
||||
|
||||
/**
|
||||
* Creates a new [ReadWriteBuffer] point to a region of the current buffer, starting at [offset] with size [size].
|
||||
* @param offset starting position of the [ReadWriteBuffer]
|
||||
* @param size in bytes of the [ReadWriteBuffer]
|
||||
* @return [ReadWriteBuffer] slice.
|
||||
*/
|
||||
public fun writeSlice(offset: Int, size: Int): ReadWriteBuffer
|
||||
|
||||
/**
|
||||
* Special operation where we increase the backed buffer size to [capacity]
|
||||
* and shift all already written data to the end of the buffer.
|
||||
*
|
||||
* This function is mostly used when creating a Flatbuffer message, as
|
||||
* data is written from the end of the buffer towards index 0.
|
||||
* @param capacity required in bytes
|
||||
* @return new capacity in bytes
|
||||
*/
|
||||
public fun moveWrittenDataToEnd(capacity: Int): Int
|
||||
|
||||
/**
|
||||
* Maximum size in bytes that the backed buffer supports.
|
||||
*/
|
||||
public val capacity: Int
|
||||
|
||||
/**
|
||||
* Defines last relative position of the backed buffer that can be written.
|
||||
* Any addition to the buffer that goes beyond will throw an exception
|
||||
* instead of regrow the buffer (default behavior).
|
||||
*/
|
||||
public val writeLimit: Int
|
||||
}
|
||||
|
||||
public open class ArrayReadBuffer(protected var buffer: ByteArray,
|
||||
// offsets writePosition against backed buffer e.g. offset = 1, writePosition = 1
|
||||
// will write first byte at position 2 of the backed buffer
|
||||
internal val offset: Int = 0,
|
||||
override val limit: Int = buffer.size - offset) : ReadBuffer {
|
||||
|
||||
|
||||
override fun findFirst(value: Byte, start: Int, end: Int): Int {
|
||||
val e = min(end, limit)
|
||||
val s = max(0, this.offset + start)
|
||||
for (i in s until e) if (buffer[i] == value) return i
|
||||
return -1
|
||||
}
|
||||
|
||||
override fun getBoolean(index: Int): Boolean = buffer[offset + index] != 0.toByte()
|
||||
|
||||
override operator fun get(index: Int): Byte = buffer[offset + index]
|
||||
|
||||
override fun getUByte(index: Int): UByte = buffer.getUByte(offset + index)
|
||||
|
||||
override fun getShort(index: Int): Short = buffer.getShort(offset + index)
|
||||
|
||||
override fun getUShort(index: Int): UShort = buffer.getUShort(offset + index)
|
||||
|
||||
override fun getInt(index: Int): Int = buffer.getInt(offset + index)
|
||||
|
||||
override fun getUInt(index: Int): UInt = buffer.getUInt(offset + index)
|
||||
|
||||
override fun getLong(index: Int): Long = buffer.getLong(offset + index)
|
||||
|
||||
override fun getULong(index: Int): ULong = buffer.getULong(offset + index)
|
||||
|
||||
override fun getFloat(index: Int): Float = buffer.getFloat(offset + index)
|
||||
|
||||
override fun getDouble(index: Int): Double = buffer.getDouble(offset + index)
|
||||
|
||||
override fun getString(start: Int, size: Int): String = buffer.decodeToString(this.offset + start,
|
||||
this.offset + start + size)
|
||||
|
||||
override fun getBytes(array: ByteArray, start: Int, length: Int) {
|
||||
val end = min(this.offset + start + length, buffer.size)
|
||||
var j = 0
|
||||
for (i in this.offset + start until end) {
|
||||
array[j++] = buffer[i]
|
||||
}
|
||||
}
|
||||
|
||||
override fun data(): ByteArray = buffer
|
||||
|
||||
override fun slice(start: Int, size: Int): ReadBuffer = ArrayReadBuffer(buffer, this.offset + start, size)
|
||||
}
|
||||
/**
|
||||
* Implements `[ReadWriteBuffer]` using [ByteArray] as backing buffer. Using array of bytes are
|
||||
* usually faster than `ByteBuffer`.
|
||||
*
|
||||
* This class is not thread-safe, meaning that
|
||||
* it must operate on a single thread. Operating from
|
||||
* multiple thread leads into an undefined behavior
|
||||
*
|
||||
* All operations assume Little Endian byte order.
|
||||
*/
|
||||
|
||||
public class ArrayReadWriteBuffer(
|
||||
buffer: ByteArray,
|
||||
offset: Int = 0,
|
||||
// Defines last position of the backed buffer that can be written.
|
||||
// Any addition to the buffer that goes beyond will throw an exception
|
||||
// instead of regrow the buffer (default behavior).
|
||||
public override val writeLimit: Int = -1,
|
||||
override var writePosition: Int = offset
|
||||
) : ArrayReadBuffer(buffer, offset, writePosition), ReadWriteBuffer {
|
||||
|
||||
public constructor(initialCapacity: Int = 10) : this(ByteArray(initialCapacity))
|
||||
|
||||
override val limit: Int get() = writePosition
|
||||
|
||||
override fun clear(): Unit = run { writePosition = 0 }
|
||||
|
||||
override fun put(value: Boolean) {
|
||||
set(writePosition, value)
|
||||
writePosition++
|
||||
}
|
||||
|
||||
override fun put(value: ByteArray, start: Int, length: Int) {
|
||||
set(writePosition, value, start, length)
|
||||
writePosition += length
|
||||
}
|
||||
|
||||
override fun put(value: ReadBuffer, start: Int, length: Int) {
|
||||
set(writePosition, value, start, length)
|
||||
writePosition += length
|
||||
}
|
||||
|
||||
override fun put(value: Byte) {
|
||||
set(writePosition, value)
|
||||
writePosition++
|
||||
}
|
||||
|
||||
override fun put(value: UByte) {
|
||||
set(writePosition, value)
|
||||
writePosition++
|
||||
}
|
||||
|
||||
override fun put(value: Short) {
|
||||
set(writePosition, value)
|
||||
writePosition += 2
|
||||
}
|
||||
|
||||
override fun put(value: UShort) {
|
||||
set(writePosition, value)
|
||||
writePosition += 2
|
||||
}
|
||||
|
||||
override fun put(value: Int) {
|
||||
set(writePosition, value)
|
||||
writePosition += 4
|
||||
}
|
||||
|
||||
override fun put(value: UInt) {
|
||||
set(writePosition, value)
|
||||
writePosition += 4
|
||||
}
|
||||
|
||||
override fun put(value: Long) {
|
||||
set(writePosition, value)
|
||||
writePosition += 8
|
||||
}
|
||||
|
||||
override fun put(value: ULong) {
|
||||
set(writePosition, value)
|
||||
writePosition += 8
|
||||
}
|
||||
|
||||
override fun put(value: Float) {
|
||||
set(writePosition, value)
|
||||
writePosition += 4
|
||||
}
|
||||
|
||||
override fun put(value: Double) {
|
||||
set(writePosition, value)
|
||||
writePosition += 8
|
||||
}
|
||||
|
||||
override fun put(value: CharSequence, encodedLength: Int): Int {
|
||||
val length = if (encodedLength != -1) encodedLength else Utf8.encodedLength(value)
|
||||
writePosition = buffer.setCharSequence(writePosition, value)
|
||||
return length
|
||||
}
|
||||
|
||||
override fun set(index: Int, value: Boolean) {
|
||||
buffer[index] = if (value) 1.toByte() else 0.toByte()
|
||||
}
|
||||
|
||||
override fun set(dstIndex: Int, src: ByteArray, srcStart: Int, srcLength: Int) {
|
||||
src.copyInto(buffer, dstIndex, srcStart, srcStart + srcLength)
|
||||
}
|
||||
|
||||
override operator fun set(dstIndex: Int, src: ReadBuffer, srcStart: Int, srcLength: Int) {
|
||||
when(src) {
|
||||
is ArrayReadBuffer -> {
|
||||
src.data().copyInto(buffer, dstIndex, src.offset + srcStart, src.offset + srcStart + srcLength)
|
||||
}
|
||||
else -> {
|
||||
for (i in 0 until srcLength) {
|
||||
buffer[dstIndex + i] = src[srcStart + i]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override operator fun set(index: Int, value: Byte) { buffer[index] = value }
|
||||
override operator fun set(index: Int, value: UByte) { buffer.setUByte(index, value) }
|
||||
override operator fun set(index: Int, value: Short) { buffer.setShort(index, value) }
|
||||
override operator fun set(index: Int, value: UShort) { buffer.setUShort(index, value) }
|
||||
override operator fun set(index: Int, value: Int) { buffer.setInt(index, value) }
|
||||
override operator fun set(index: Int, value: UInt) { buffer.setUInt(index, value) }
|
||||
override operator fun set(index: Int, value: Long) { buffer.setLong(index, value) }
|
||||
override operator fun set(index: Int, value: ULong) { buffer.setULong(index, value) }
|
||||
override operator fun set(index: Int, value: Float) { buffer.setFloat(index, value) }
|
||||
override operator fun set(index: Int, value: Double) { buffer.setDouble(index, value) }
|
||||
override fun fill(value: Byte, start: Int, end: Int) { buffer.fill(value, start, end) }
|
||||
|
||||
/**
|
||||
* Request capacity of the buffer. In case buffer is already larger
|
||||
* than the requested, it is a no-op. Otherwise,
|
||||
* It might try to resize the buffer. In case of being unable to allocate
|
||||
* enough memory, an exception will be thrown.
|
||||
* @param capacity new capacity
|
||||
* @param copyAtEnd copy current data at the end of new underlying buffer
|
||||
*/
|
||||
override fun requestCapacity(capacity: Int, copyAtEnd: Boolean): Int {
|
||||
if (capacity < 0) error("Capacity may not be negative (likely a previous int overflow)")
|
||||
|
||||
if (buffer.size >= capacity) return buffer.size
|
||||
|
||||
if (writeLimit > 0 && writeLimit + offset >= buffer.size) error("Buffer in writeLimit mode. In writeLimit mode" +
|
||||
" the buffer does not grow automatically and any write beyond writeLimit will throw exception. " +
|
||||
"(writeLimit: $writeLimit, newCapacity: $capacity")
|
||||
// implemented in the same growing fashion as ArrayList
|
||||
val oldCapacity = buffer.size
|
||||
if (oldCapacity == Int.MAX_VALUE - 8) { // Ensure we don't grow beyond what fits in an int.
|
||||
error("FlatBuffers: cannot grow buffer beyond 2 gigabytes.")
|
||||
}
|
||||
//(old_buf_size & 0xC0000000) != 0 ? MAX_BUFFER_SIZE : old_buf_size << 1;
|
||||
var newCapacity = 8
|
||||
while (newCapacity < capacity) { // Note: this also catches newCapacity int overflow
|
||||
newCapacity = if (newCapacity and -0x40000000 != 0) Int.MAX_VALUE - 8 else newCapacity shl 1
|
||||
}
|
||||
val newBuffer = ByteArray(newCapacity)
|
||||
|
||||
buffer.copyInto(newBuffer, if (copyAtEnd) newBuffer.size - buffer.size else 0)
|
||||
buffer = newBuffer
|
||||
return newCapacity
|
||||
}
|
||||
|
||||
override fun writeSlice(offset: Int, size: Int): ReadWriteBuffer {
|
||||
return ArrayReadWriteBuffer(this.buffer, offset=offset, writeLimit=size)
|
||||
}
|
||||
|
||||
override fun moveWrittenDataToEnd(capacity: Int): Int = requestCapacity(capacity, true)
|
||||
|
||||
override val capacity: Int
|
||||
get() = buffer.size
|
||||
|
||||
}
|
||||
|
||||
public val emptyBuffer: ReadWriteBuffer = ArrayReadWriteBuffer(ByteArray(1))
|
@ -1,124 +0,0 @@
|
||||
/*
|
||||
* Copyright 2021 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.
|
||||
*/
|
||||
@file:Suppress("NOTHING_TO_INLINE")
|
||||
|
||||
package com.google.flatbuffers.kotlin
|
||||
|
||||
import kotlin.experimental.and
|
||||
|
||||
internal fun ByteArray.getString(index: Int, size: Int): String = Utf8.decodeUtf8Array(this, index, size)
|
||||
|
||||
internal fun ByteArray.setCharSequence(index: Int, value: CharSequence): Int =
|
||||
Utf8.encodeUtf8Array(value, this, index, this.size - index)
|
||||
|
||||
// List of functions that needs to be implemented on all platforms.
|
||||
internal expect inline fun ByteArray.getUByte(index: Int): UByte
|
||||
internal expect inline fun ByteArray.getShort(index: Int): Short
|
||||
internal expect inline fun ByteArray.getUShort(index: Int): UShort
|
||||
internal expect inline fun ByteArray.getInt(index: Int): Int
|
||||
internal expect inline fun ByteArray.getUInt(index: Int): UInt
|
||||
internal expect inline fun ByteArray.getLong(index: Int): Long
|
||||
internal expect inline fun ByteArray.getULong(index: Int): ULong
|
||||
internal expect inline fun ByteArray.getFloat(index: Int): Float
|
||||
internal expect inline fun ByteArray.getDouble(index: Int): Double
|
||||
|
||||
internal expect inline fun ByteArray.setUByte(index: Int, value: UByte)
|
||||
public expect inline fun ByteArray.setShort(index: Int, value: Short)
|
||||
internal expect inline fun ByteArray.setUShort(index: Int, value: UShort)
|
||||
internal expect inline fun ByteArray.setInt(index: Int, value: Int)
|
||||
internal expect inline fun ByteArray.setUInt(index: Int, value: UInt)
|
||||
internal expect inline fun ByteArray.setLong(index: Int, value: Long)
|
||||
internal expect inline fun ByteArray.setULong(index: Int, value: ULong)
|
||||
internal expect inline fun ByteArray.setFloat(index: Int, value: Float)
|
||||
internal expect inline fun ByteArray.setDouble(index: Int, value: Double)
|
||||
|
||||
/**
|
||||
* This implementation uses Little Endian order.
|
||||
*/
|
||||
public object ByteArrayOps {
|
||||
public inline fun getUByte(ary: ByteArray, index: Int): UByte = ary[index].toUByte()
|
||||
public inline fun getShort(ary: ByteArray, index: Int): Short {
|
||||
return (ary[index + 1].toInt() shl 8 or (ary[index].toInt() and 0xff)).toShort()
|
||||
}
|
||||
|
||||
public inline fun getUShort(ary: ByteArray, index: Int): UShort = getShort(ary, index).toUShort()
|
||||
|
||||
public inline fun getInt(ary: ByteArray, index: Int): Int {
|
||||
return (
|
||||
(ary[index + 3].toInt() shl 24) or
|
||||
((ary[index + 2].toInt() and 0xff) shl 16) or
|
||||
((ary[index + 1].toInt() and 0xff) shl 8) or
|
||||
((ary[index].toInt() and 0xff))
|
||||
)
|
||||
}
|
||||
|
||||
public inline fun getUInt(ary: ByteArray, index: Int): UInt = getInt(ary, index).toUInt()
|
||||
|
||||
public inline fun getLong(ary: ByteArray, index: Int): Long {
|
||||
var idx = index
|
||||
return ary[idx++].toLong() and 0xff or
|
||||
(ary[idx++].toLong() and 0xff shl 8) or
|
||||
(ary[idx++].toLong() and 0xff shl 16) or
|
||||
(ary[idx++].toLong() and 0xff shl 24) or
|
||||
(ary[idx++].toLong() and 0xff shl 32) or
|
||||
(ary[idx++].toLong() and 0xff shl 40) or
|
||||
(ary[idx++].toLong() and 0xff shl 48) or
|
||||
(ary[idx].toLong() shl 56)
|
||||
}
|
||||
|
||||
public inline fun getULong(ary: ByteArray, index: Int): ULong = getLong(ary, index).toULong()
|
||||
|
||||
public inline fun setUByte(ary: ByteArray, index: Int, value: UByte) {
|
||||
ary[index] = value.toByte()
|
||||
}
|
||||
public inline fun setShort(ary: ByteArray, index: Int, value: Short) {
|
||||
var idx = index
|
||||
ary[idx++] = (value and 0xff).toByte()
|
||||
ary[idx] = (value.toInt() shr 8 and 0xff).toByte()
|
||||
}
|
||||
|
||||
public inline fun setUShort(ary: ByteArray, index: Int, value: UShort): Unit = setShort(ary, index, value.toShort())
|
||||
|
||||
public inline fun setInt(ary: ByteArray, index: Int, value: Int) {
|
||||
var idx = index
|
||||
ary[idx++] = (value and 0xff).toByte()
|
||||
ary[idx++] = (value shr 8 and 0xff).toByte()
|
||||
ary[idx++] = (value shr 16 and 0xff).toByte()
|
||||
ary[idx] = (value shr 24 and 0xff).toByte()
|
||||
}
|
||||
|
||||
public inline fun setUInt(ary: ByteArray, index: Int, value: UInt): Unit = setInt(ary, index, value.toInt())
|
||||
|
||||
public inline fun setLong(ary: ByteArray, index: Int, value: Long) {
|
||||
var i = value.toInt()
|
||||
setInt(ary, index, i)
|
||||
i = (value shr 32).toInt()
|
||||
setInt(ary, index + 4, i)
|
||||
}
|
||||
|
||||
public inline fun setULong(ary: ByteArray, index: Int, value: ULong): Unit = setLong(ary, index, value.toLong())
|
||||
|
||||
public inline fun setFloat(ary: ByteArray, index: Int, value: Float) {
|
||||
setInt(ary, index, value.toRawBits())
|
||||
}
|
||||
|
||||
public inline fun setDouble(ary: ByteArray, index: Int, value: Double) {
|
||||
setLong(ary, index, value.toRawBits())
|
||||
}
|
||||
|
||||
public inline fun getFloat(ary: ByteArray, index: Int): Float = Float.fromBits(getInt(ary, index))
|
||||
public inline fun getDouble(ary: ByteArray, index: Int): Double = Double.fromBits(getLong(ary, index))
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,367 +0,0 @@
|
||||
/*
|
||||
* Copyright 2021 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.kotlin
|
||||
|
||||
import kotlin.jvm.JvmInline
|
||||
import kotlin.math.min
|
||||
|
||||
// For now a typealias to guarantee type safety.
|
||||
public typealias UnionOffset = Offset<Any>
|
||||
public typealias UnionOffsetArray = OffsetArray<Any>
|
||||
public typealias StringOffsetArray = OffsetArray<String>
|
||||
|
||||
public inline fun UnionOffsetArray(size: Int, crossinline call: (Int) -> Offset<Any>): UnionOffsetArray =
|
||||
UnionOffsetArray(IntArray(size) { call(it).value })
|
||||
public inline fun StringOffsetArray(size: Int, crossinline call: (Int) -> Offset<String>): StringOffsetArray =
|
||||
StringOffsetArray(IntArray(size) { call(it).value })
|
||||
/**
|
||||
* Represents a "pointer" to a pointer types (table, string, struct) within the buffer
|
||||
*/
|
||||
@JvmInline
|
||||
public value class Offset<T>(public val value: Int) {
|
||||
public fun toUnion(): UnionOffset = UnionOffset(value)
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents an array of offsets. Used to avoid boxing
|
||||
* offset types.
|
||||
*/
|
||||
@JvmInline
|
||||
public value class OffsetArray<T>(public val value: IntArray) {
|
||||
public inline val size: Int
|
||||
get() = value.size
|
||||
public inline operator fun get(index: Int): Offset<T> = Offset(value[index])
|
||||
}
|
||||
|
||||
public inline fun <T> OffsetArray(size: Int, crossinline call: (Int) -> Offset<T>): OffsetArray<T> {
|
||||
return OffsetArray(IntArray(size) { call(it).value })
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Represents a "pointer" to a vector type with elements T
|
||||
*/
|
||||
@JvmInline
|
||||
public value class VectorOffset<T>(public val value: Int)
|
||||
|
||||
public fun <T> Int.toOffset(): Offset<T> = Offset(this)
|
||||
|
||||
public operator fun <T> Offset<T>.minus(other: Int): Offset<T> = Offset(this.value - other)
|
||||
|
||||
public operator fun <T> Int.minus(other: Offset<T>): Int {
|
||||
return this - other.value
|
||||
}
|
||||
/**
|
||||
* All tables in the generated code derive from this class, and add their own accessors.
|
||||
*/
|
||||
public open class Table {
|
||||
|
||||
/** Used to hold the position of the `bb` buffer. */
|
||||
public var bufferPos: Int = 0
|
||||
|
||||
/** The underlying ReadWriteBuffer to hold the data of the Table. */
|
||||
public var bb: ReadWriteBuffer = emptyBuffer
|
||||
|
||||
/** Used to hold the vtable position. */
|
||||
public var vtableStart: Int = 0
|
||||
|
||||
/** Used to hold the vtable size. */
|
||||
public var vtableSize: Int = 0
|
||||
|
||||
protected inline fun <reified T> Int.invalid(default: T, crossinline valid: (Int) -> T) : T =
|
||||
if (this != 0) valid(this) else default
|
||||
|
||||
protected inline fun <reified T> lookupField(i: Int, default: T, crossinline found: (Int) -> T) : T =
|
||||
offset(i).invalid(default) { found(it) }
|
||||
|
||||
/**
|
||||
* Look up a field in the vtable.
|
||||
*
|
||||
* @param vtableOffset An `int` offset to the vtable in the Table's ReadWriteBuffer.
|
||||
* @return Returns an offset into the object, or `0` if the field is not present.
|
||||
*/
|
||||
public fun offset(vtableOffset: Int): Int =
|
||||
if (vtableOffset < vtableSize) bb.getShort(vtableStart + vtableOffset).toInt() else 0
|
||||
|
||||
/**
|
||||
* Retrieve a relative offset.
|
||||
*
|
||||
* @param offset An `int` index into the Table's ReadWriteBuffer containing the relative offset.
|
||||
* @return Returns the relative offset stored at `offset`.
|
||||
*/
|
||||
public fun indirect(offset: Int): Int = offset + bb.getInt(offset)
|
||||
|
||||
/**
|
||||
* Create a Java `String` from UTF-8 data stored inside the FlatBuffer.
|
||||
*
|
||||
* This allocates a new string and converts to wide chars upon each access,
|
||||
* which is not very efficient. Instead, each FlatBuffer string also comes with an
|
||||
* accessor based on __vector_as_ReadWriteBuffer below, which is much more efficient,
|
||||
* assuming your Java program can handle UTF-8 data directly.
|
||||
*
|
||||
* @param offset An `int` index into the Table's ReadWriteBuffer.
|
||||
* @return Returns a `String` from the data stored inside the FlatBuffer at `offset`.
|
||||
*/
|
||||
public fun string(offset: Int): String = string(offset, bb)
|
||||
|
||||
/**
|
||||
* Get the length of a vector.
|
||||
*
|
||||
* @param offset An `int` index into the Table's ReadWriteBuffer.
|
||||
* @return Returns the length of the vector whose offset is stored at `offset`.
|
||||
*/
|
||||
public fun vectorLength(offset: Int): Int {
|
||||
var newOffset = offset
|
||||
newOffset += bufferPos
|
||||
newOffset += bb.getInt(newOffset)
|
||||
return bb.getInt(newOffset)
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the start data of a vector.
|
||||
*
|
||||
* @param offset An `int` index into the Table's ReadWriteBuffer.
|
||||
* @return Returns the start of the vector data whose offset is stored at `offset`.
|
||||
*/
|
||||
public fun vector(offset: Int): Int {
|
||||
var newOffset = offset
|
||||
newOffset += bufferPos
|
||||
return newOffset + bb.getInt(newOffset) + Int.SIZE_BYTES // data starts after the length
|
||||
}
|
||||
/**
|
||||
* Initialize vector as a ReadWriteBuffer.
|
||||
*
|
||||
* This is more efficient than using duplicate, since it doesn't copy the data
|
||||
* nor allocates a new [ReadBuffer], creating no garbage to be collected.
|
||||
*
|
||||
* @param buffer The [ReadBuffer] for the array
|
||||
* @param vectorOffset The position of the vector in the byte buffer
|
||||
* @param elemSize The size of each element in the array
|
||||
* @return The [ReadBuffer] for the array
|
||||
*/
|
||||
public fun vectorAsBuffer(buffer: ReadWriteBuffer, vectorOffset: Int, elemSize: Int): ReadBuffer {
|
||||
val o = offset(vectorOffset)
|
||||
if (o == 0) return emptyBuffer
|
||||
val vectorStart = vector(o)
|
||||
return buffer.slice(vectorStart, vectorLength(o) * elemSize)
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize any Table-derived type to point to the union at the given `offset`.
|
||||
*
|
||||
* @param t A `Table`-derived type that should point to the union at `offset`.
|
||||
* @param offset An `int` index into the Table's ReadWriteBuffer.
|
||||
* @return Returns the Table that points to the union at `offset`.
|
||||
*/
|
||||
public fun union(t: Table, offset: Int): Table = union(t, offset, bb)
|
||||
|
||||
/**
|
||||
* Sort tables by the key.
|
||||
*
|
||||
* @param offsets An 'int' indexes of the tables into the bb.
|
||||
* @param bb A `ReadWriteBuffer` to get the tables.
|
||||
*/
|
||||
public fun <T> sortTables(offsets: Array<Offset<T>>, bb: ReadWriteBuffer) {
|
||||
val off = offsets.sortedWith { o1, o2 -> keysCompare(o1, o2, bb) }
|
||||
for (i in offsets.indices) offsets[i] = off[i]
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare two tables by the key.
|
||||
*
|
||||
* @param o1 An 'Integer' index of the first key into the bb.
|
||||
* @param o2 An 'Integer' index of the second key into the bb.
|
||||
* @param buffer A `ReadWriteBuffer` to get the keys.
|
||||
*/
|
||||
public open fun keysCompare(o1: Offset<*>, o2: Offset<*>, buffer: ReadWriteBuffer): Int = 0
|
||||
|
||||
/**
|
||||
* Re-init the internal state with an external buffer `ReadWriteBuffer` and an offset within.
|
||||
*
|
||||
* This method exists primarily to allow recycling Table instances without risking memory leaks
|
||||
* due to `ReadWriteBuffer` references.
|
||||
*/
|
||||
public inline fun <reified T: Table> reset(i: Int, reuseBuffer: ReadWriteBuffer): T {
|
||||
bb = reuseBuffer
|
||||
if (bb != emptyBuffer) {
|
||||
bufferPos = i
|
||||
vtableStart = bufferPos - bb.getInt(bufferPos)
|
||||
vtableSize = bb.getShort(vtableStart).toInt()
|
||||
} else {
|
||||
bufferPos = 0
|
||||
vtableStart = 0
|
||||
vtableSize = 0
|
||||
}
|
||||
return this as T
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the internal state with a null `ReadWriteBuffer` and a zero position.
|
||||
*
|
||||
* This method exists primarily to allow recycling Table instances without risking memory leaks
|
||||
* due to `ReadWriteBuffer` references. The instance will be unusable until it is assigned
|
||||
* again to a `ReadWriteBuffer`.
|
||||
*/
|
||||
public inline fun <reified T: Table> reset(): T = reset(0, emptyBuffer)
|
||||
|
||||
public companion object {
|
||||
|
||||
public fun offset(vtableOffset: Int, offset: Offset<*>, bb: ReadWriteBuffer): Int {
|
||||
val vtable: Int = bb.capacity - offset.value
|
||||
return bb.getShort(vtable + vtableOffset - bb.getInt(vtable)) + vtable
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a relative offset.
|
||||
*
|
||||
* @param offset An `int` index into a ReadWriteBuffer containing the relative offset.
|
||||
* @param bb from which the relative offset will be retrieved.
|
||||
* @return Returns the relative offset stored at `offset`.
|
||||
*/
|
||||
public fun indirect(offset: Int, bb: ReadWriteBuffer): Int {
|
||||
return offset + bb.getInt(offset)
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a Java `String` from UTF-8 data stored inside the FlatBuffer.
|
||||
*
|
||||
* This allocates a new string and converts to wide chars upon each access,
|
||||
* which is not very efficient. Instead, each FlatBuffer string also comes with an
|
||||
* accessor based on __vector_as_ReadWriteBuffer below, which is much more efficient,
|
||||
* assuming your Java program can handle UTF-8 data directly.
|
||||
*
|
||||
* @param offset An `int` index into the Table's ReadWriteBuffer.
|
||||
* @param bb Table ReadWriteBuffer used to read a string at given offset.
|
||||
* @return Returns a `String` from the data stored inside the FlatBuffer at `offset`.
|
||||
*/
|
||||
public fun string(offset: Int, bb: ReadWriteBuffer): String {
|
||||
var newOffset = offset
|
||||
newOffset += bb.getInt(newOffset)
|
||||
val length: Int = bb.getInt(newOffset)
|
||||
return bb.getString(newOffset + Int.SIZE_BYTES, length)
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize any Table-derived type to point to the union at the given `offset`.
|
||||
*
|
||||
* @param t A `Table`-derived type that should point to the union at `offset`.
|
||||
* @param offset An `int` index into the Table's ReadWriteBuffer.
|
||||
* @param bb Table ReadWriteBuffer used to initialize the object Table-derived type.
|
||||
* @return Returns the Table that points to the union at `offset`.
|
||||
*/
|
||||
public fun union(t: Table, offset: Int, bb: ReadWriteBuffer): Table =
|
||||
t.reset(indirect(offset, bb), bb)
|
||||
|
||||
/**
|
||||
* Check if a [ReadWriteBuffer] contains a file identifier.
|
||||
*
|
||||
* @param bb A `ReadWriteBuffer` to check if it contains the identifier
|
||||
* `ident`.
|
||||
* @param ident A `String` identifier of the FlatBuffer file.
|
||||
* @return True if the buffer contains the file identifier
|
||||
*/
|
||||
public fun hasIdentifier(bb: ReadWriteBuffer?, ident: String): Boolean {
|
||||
val identifierLength = 4
|
||||
if (ident.length != identifierLength)
|
||||
throw AssertionError("FlatBuffers: file identifier must be length $identifierLength")
|
||||
for (i in 0 until identifierLength) {
|
||||
if (ident[i].code.toByte() != bb!![bb.limit + Int.SIZE_BYTES + i]) return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare two strings in the buffer.
|
||||
*
|
||||
* @param offsetA An 'int' index of the first string into the bb.
|
||||
* @param offsetB An 'int' index of the second string into the bb.
|
||||
* @param bb A `ReadWriteBuffer` to get the strings.
|
||||
*/
|
||||
public fun compareStrings(offsetA: Int, offsetB: Int, bb: ReadWriteBuffer): Int {
|
||||
var offset1 = offsetA
|
||||
var offset2 = offsetB
|
||||
offset1 += bb.getInt(offset1)
|
||||
offset2 += bb.getInt(offset2)
|
||||
val len1: Int = bb.getInt(offset1)
|
||||
val len2: Int = bb.getInt(offset2)
|
||||
val startPos1: Int = offset1 + Int.SIZE_BYTES
|
||||
val startPos2: Int = offset2 + Int.SIZE_BYTES
|
||||
val len: Int = min(len1, len2)
|
||||
for (i in 0 until len) {
|
||||
if (bb[i + startPos1] != bb[i + startPos2]) {
|
||||
return bb[i + startPos1] - bb[i + startPos2]
|
||||
}
|
||||
}
|
||||
return len1 - len2
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare string from the buffer with the 'String' object.
|
||||
*
|
||||
* @param offset An 'int' index of the first string into the bb.
|
||||
* @param key Second string as a byte array.
|
||||
* @param bb A `ReadWriteBuffer` to get the first string.
|
||||
*/
|
||||
public fun compareStrings(offset: Int, key: ByteArray, bb: ReadWriteBuffer): Int {
|
||||
var offset1 = offset
|
||||
offset1 += bb.getInt(offset1)
|
||||
val len1: Int = bb.getInt(offset1)
|
||||
val len2 = key.size
|
||||
val startPos: Int = offset1 + Int.SIZE_BYTES
|
||||
val len: Int = min(len1, len2)
|
||||
for (i in 0 until len) {
|
||||
if (bb[i + startPos] != key[i]) return bb[i + startPos] - key[i]
|
||||
}
|
||||
return len1 - len2
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* All structs in the generated code derive from this class, and add their own accessors.
|
||||
*/
|
||||
public open class Struct {
|
||||
/** Used to hold the position of the `bb` buffer. */
|
||||
protected var bufferPos: Int = 0
|
||||
|
||||
/** The underlying ByteBuffer to hold the data of the Struct. */
|
||||
protected var bb: ReadWriteBuffer = emptyBuffer
|
||||
|
||||
/**
|
||||
* Re-init the internal state with an external buffer `ByteBuffer` and an offset within.
|
||||
*
|
||||
* This method exists primarily to allow recycling Table instances without risking memory leaks
|
||||
* due to `ByteBuffer` references.
|
||||
*/
|
||||
protected inline fun <reified T: Struct> reset(i: Int, reuseBuffer: ReadWriteBuffer): T {
|
||||
bb = reuseBuffer
|
||||
bufferPos = if (bb != emptyBuffer) i else 0
|
||||
return this as T
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets internal state with a null `ByteBuffer` and a zero position.
|
||||
*
|
||||
* This method exists primarily to allow recycling Struct instances without risking memory leaks
|
||||
* due to `ByteBuffer` references. The instance will be unusable until it is assigned
|
||||
* again to a `ByteBuffer`.
|
||||
*/
|
||||
private inline fun <reified T: Struct> reset(): T = reset(0, emptyBuffer)
|
||||
}
|
||||
|
||||
public inline val <T> T.value: T get() = this
|
||||
|
||||
public const val VERSION_2_0_8: Int = 1
|
@ -1,915 +0,0 @@
|
||||
/*
|
||||
* Copyright 2021 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.
|
||||
*/
|
||||
@file:Suppress("NOTHING_TO_INLINE")
|
||||
@file:JvmName("FlexBuffers")
|
||||
package com.google.flatbuffers.kotlin
|
||||
|
||||
import kotlin.jvm.JvmName
|
||||
|
||||
/**
|
||||
* Reads a FlexBuffer message in ReadBuf and returns [Reference] to
|
||||
* the root element.
|
||||
* @param buffer ReadBuf containing FlexBuffer message
|
||||
* @return [Reference] to the root object
|
||||
*/
|
||||
public fun getRoot(buffer: ReadBuffer): Reference {
|
||||
var end: Int = buffer.limit
|
||||
val byteWidth = buffer[--end].toInt()
|
||||
val packetType = buffer[--end].toInt()
|
||||
end -= byteWidth // The root data item.
|
||||
return Reference(buffer, end, ByteWidth(byteWidth), packetType)
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents an generic element in the buffer. It can be specialized into scalar types, using for example,
|
||||
* [Reference.toInt], or casted into Flexbuffer object types, like [Reference.toMap] or [Reference.toBlob].
|
||||
*/
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
public class Reference internal constructor(
|
||||
internal val buffer: ReadBuffer,
|
||||
internal val end: Int,
|
||||
internal val parentWidth: ByteWidth,
|
||||
internal val byteWidth: ByteWidth,
|
||||
public val type: FlexBufferType
|
||||
) {
|
||||
|
||||
internal constructor(bb: ReadBuffer, end: Int, parentWidth: ByteWidth, packedType: Int) :
|
||||
this(bb, end, parentWidth, ByteWidth(1 shl (packedType and 3)), FlexBufferType((packedType shr 2)))
|
||||
|
||||
/**
|
||||
* Checks whether the element is null type
|
||||
* @return true if null type
|
||||
*/
|
||||
public val isNull: Boolean get() = type == T_NULL
|
||||
|
||||
/**
|
||||
* Checks whether the element is boolean type
|
||||
* @return true if boolean type
|
||||
*/
|
||||
public val isBoolean: Boolean get() = type == T_BOOL
|
||||
|
||||
/**
|
||||
* Checks whether the element type is numeric (signed/unsigned integers and floats)
|
||||
* @return true if numeric type
|
||||
*/
|
||||
public val isNumeric: Boolean get() = isIntOrUInt || isFloat
|
||||
|
||||
/**
|
||||
* Checks whether the element type is signed or unsigned integers
|
||||
* @return true if an integer type
|
||||
*/
|
||||
public val isIntOrUInt: Boolean get() = isInt || isUInt
|
||||
|
||||
/**
|
||||
* Checks whether the element type is float
|
||||
* @return true if a float type
|
||||
*/
|
||||
public val isFloat: Boolean get() = type == T_FLOAT || type == T_INDIRECT_FLOAT
|
||||
|
||||
/**
|
||||
* Checks whether the element type is signed integer
|
||||
* @return true if a signed integer type
|
||||
*/
|
||||
public val isInt: Boolean get() = type == T_INT || type == T_INDIRECT_INT
|
||||
|
||||
/**
|
||||
* Checks whether the element type is signed integer
|
||||
* @return true if a signed integer type
|
||||
*/
|
||||
public val isUInt: Boolean get() = type == T_UINT || type == T_INDIRECT_UINT
|
||||
|
||||
/**
|
||||
* Checks whether the element type is string
|
||||
* @return true if a string type
|
||||
*/
|
||||
public val isString: Boolean get() = type == T_STRING
|
||||
|
||||
/**
|
||||
* Checks whether the element type is key
|
||||
* @return true if a key type
|
||||
*/
|
||||
public val isKey: Boolean get() = type == T_KEY
|
||||
|
||||
/**
|
||||
* Checks whether the element type is vector or a map. [TypedVector] are considered different types and will return
|
||||
* false.
|
||||
* @return true if a vector type
|
||||
*/
|
||||
public val isVector: Boolean get() = type == T_VECTOR || type == T_MAP
|
||||
|
||||
/**
|
||||
* Checks whether the element type is typed vector
|
||||
* @return true if a typed vector type
|
||||
*/
|
||||
public val isTypedVector: Boolean get() = type.isTypedVector()
|
||||
|
||||
/**
|
||||
* Checks whether the element type is a map
|
||||
* @return true if a map type
|
||||
*/
|
||||
public val isMap: Boolean get() = type == T_MAP
|
||||
|
||||
/**
|
||||
* Checks whether the element type is a blob
|
||||
* @return true if a blob type
|
||||
*/
|
||||
public val isBlob: Boolean get() = type == T_BLOB
|
||||
|
||||
/**
|
||||
* Assumes [Reference] as a [Vector] and returns a [Reference] at index [index].
|
||||
*/
|
||||
public operator fun get(index: Int): Reference = toVector()[index]
|
||||
|
||||
/**
|
||||
* Assumes [Reference] as a [Map] and returns a [Reference] for the value at key [key].
|
||||
*/
|
||||
public operator fun get(key: String): Reference = toMap()[key]
|
||||
|
||||
/**
|
||||
* Returns element as a [Boolean].
|
||||
* If element type is not boolean, it will be casted to integer and compared against 0
|
||||
* @return element as [Boolean]
|
||||
*/
|
||||
public fun toBoolean(): Boolean = if (isBoolean) buffer.getBoolean(end) else toUInt() != 0u
|
||||
|
||||
/**
|
||||
* Returns element as [Byte].
|
||||
* For vector types, it will return size of the vector.
|
||||
* For String type, it will be parsed as integer.
|
||||
* Unsigned elements will become signed (with possible overflow).
|
||||
* Float elements will be casted to [Byte].
|
||||
* @return [Byte] or 0 if fail to convert element to integer.
|
||||
*/
|
||||
public fun toByte(): Byte = toULong().toByte()
|
||||
|
||||
/**
|
||||
* Returns element as [Short].
|
||||
* For vector types, it will return size of the vector.
|
||||
* For String type, it will type to be parsed as integer.
|
||||
* Unsigned elements will become signed (with possible overflow).
|
||||
* Float elements will be casted to [Short]
|
||||
* @return [Short] or 0 if fail to convert element to integer.
|
||||
*/
|
||||
public fun toShort(): Short = toULong().toShort()
|
||||
|
||||
/**
|
||||
* Returns element as [Int].
|
||||
* For vector types, it will return size of the vector.
|
||||
* For String type, it will type to be parsed as integer.
|
||||
* Unsigned elements will become signed (with possible overflow).
|
||||
* Float elements will be casted to [Int]
|
||||
* @return [Int] or 0 if fail to convert element to integer.
|
||||
*/
|
||||
public fun toInt(): Int = toULong().toInt()
|
||||
|
||||
/**
|
||||
* Returns element as [Long].
|
||||
* For vector types, it will return size of the vector
|
||||
* For String type, it will type to be parsed as integer
|
||||
* Unsigned elements will become negative
|
||||
* Float elements will be casted to integer
|
||||
* @return [Long] integer or 0 if fail to convert element to long.
|
||||
*/
|
||||
public fun toLong(): Long = toULong().toLong()
|
||||
|
||||
/**
|
||||
* Returns element as [UByte].
|
||||
* For vector types, it will return size of the vector.
|
||||
* For String type, it will type to be parsed as integer.
|
||||
* Negative elements will become unsigned counterpart.
|
||||
* Float elements will be casted to [UByte]
|
||||
* @return [UByte] or 0 if fail to convert element to integer.
|
||||
*/
|
||||
public fun toUByte(): UByte = toULong().toUByte()
|
||||
|
||||
/**
|
||||
* Returns element as [UShort].
|
||||
* For vector types, it will return size of the vector.
|
||||
* For String type, it will type to be parsed as integer.
|
||||
* Negative elements will become unsigned counterpart.
|
||||
* Float elements will be casted to [UShort]
|
||||
* @return [UShort] or 0 if fail to convert element to integer.
|
||||
*/
|
||||
public fun toUShort(): UShort = toULong().toUShort()
|
||||
|
||||
/**
|
||||
* Returns element as [UInt].
|
||||
* For vector types, it will return size of the vector.
|
||||
* For String type, it will type to be parsed as integer.
|
||||
* Negative elements will become unsigned counterpart.
|
||||
* Float elements will be casted to [UInt]
|
||||
* @return [UInt] or 0 if fail to convert element to integer.
|
||||
*/
|
||||
public fun toUInt(): UInt = toULong().toUInt()
|
||||
|
||||
/**
|
||||
* Returns element as [ULong] integer.
|
||||
* For vector types, it will return size of the vector
|
||||
* For String type, it will type to be parsed as integer
|
||||
* Negative elements will become unsigned counterpart.
|
||||
* Float elements will be casted to integer
|
||||
* @return [ULong] integer or 0 if fail to convert element to long.
|
||||
*/
|
||||
public fun toULong(): ULong = resolve { pos: Int, width: ByteWidth ->
|
||||
when (type) {
|
||||
T_INDIRECT_INT, T_INDIRECT_UINT, T_INT, T_BOOL, T_UINT -> buffer.readULong(pos, width)
|
||||
T_FLOAT, T_INDIRECT_FLOAT -> buffer.readFloat(pos, width).toULong()
|
||||
T_STRING -> toString().toULong()
|
||||
T_VECTOR -> toVector().size.toULong()
|
||||
else -> 0UL
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns element as [Float].
|
||||
* For vector types, it will return size of the vector
|
||||
* For String type, it will type to be parsed as [Float]
|
||||
* Float elements will be casted to integer
|
||||
* @return [Float] integer or 0 if fail to convert element to long.
|
||||
*/
|
||||
public fun toFloat(): Float = resolve { pos: Int, width: ByteWidth ->
|
||||
when (type) {
|
||||
T_INDIRECT_FLOAT, T_FLOAT -> buffer.readFloat(pos, width).toFloat()
|
||||
T_INT -> buffer.readInt(end, parentWidth).toFloat()
|
||||
T_UINT, T_BOOL -> buffer.readUInt(end, parentWidth).toFloat()
|
||||
T_INDIRECT_INT -> buffer.readInt(pos, width).toFloat()
|
||||
T_INDIRECT_UINT -> buffer.readUInt(pos, width).toFloat()
|
||||
T_NULL -> 0.0f
|
||||
T_STRING -> toString().toFloat()
|
||||
T_VECTOR -> toVector().size.toFloat()
|
||||
else -> 0f
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns element as [Double].
|
||||
* For vector types, it will return size of the vector
|
||||
* For String type, it will type to be parsed as [Double]
|
||||
* @return [Float] integer or 0 if fail to convert element to long.
|
||||
*/
|
||||
public fun toDouble(): Double = resolve { pos: Int, width: ByteWidth ->
|
||||
when (type) {
|
||||
T_INDIRECT_FLOAT, T_FLOAT -> buffer.readFloat(pos, width)
|
||||
T_INT -> buffer.readInt(pos, width).toDouble()
|
||||
T_UINT, T_BOOL -> buffer.readUInt(pos, width).toDouble()
|
||||
T_INDIRECT_INT -> buffer.readInt(pos, width).toDouble()
|
||||
T_INDIRECT_UINT -> buffer.readUInt(pos, width).toDouble()
|
||||
T_NULL -> 0.0
|
||||
T_STRING -> toString().toDouble()
|
||||
T_VECTOR -> toVector().size.toDouble()
|
||||
else -> 0.0
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns element as [Key] or invalid key.
|
||||
*/
|
||||
public fun toKey(): Key = when (type) {
|
||||
T_KEY -> Key(buffer, buffer.indirect(end, parentWidth))
|
||||
else -> nullKey()
|
||||
}
|
||||
/**
|
||||
* Returns element as a [String]
|
||||
* @return element as [String] or empty [String] if fail
|
||||
*/
|
||||
override fun toString(): String = when (type) {
|
||||
T_STRING -> {
|
||||
val start = buffer.indirect(end, parentWidth)
|
||||
val size = buffer.readULong(start - byteWidth, byteWidth).toInt()
|
||||
buffer.getString(start, size)
|
||||
}
|
||||
T_KEY -> buffer.getKeyString(buffer.indirect(end, parentWidth))
|
||||
T_MAP -> "{ ${toMap().entries.joinToString(", ") { "${it.key}: ${it.value}"}} }"
|
||||
T_VECTOR, T_VECTOR_BOOL, T_VECTOR_FLOAT, T_VECTOR_INT,
|
||||
T_VECTOR_UINT, T_VECTOR_KEY, T_VECTOR_STRING_DEPRECATED ->
|
||||
"[ ${toVector().joinToString(", ") { it.toString() }} ]"
|
||||
T_INT -> toLong().toString()
|
||||
T_UINT -> toULong().toString()
|
||||
T_FLOAT -> toDouble().toString()
|
||||
else -> "${type.typeToString()}(end=$end)"
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns element as a [ByteArray], converting scalar types when possible.
|
||||
* @return element as [ByteArray] or empty [ByteArray] if fail.
|
||||
*/
|
||||
public fun toByteArray(): ByteArray {
|
||||
val vec = TypedVector(type.toElementTypedVector(), buffer, buffer.indirect(end, parentWidth), byteWidth)
|
||||
return when (type) {
|
||||
T_VECTOR_INT -> ByteArray(vec.size) { vec.getInt(it).toByte() }
|
||||
T_VECTOR_UINT -> ByteArray(vec.size) { vec.getUInt(it).toByte() }
|
||||
T_VECTOR -> ByteArray(vec.size) { vec[it].toByte() }
|
||||
T_VECTOR_FLOAT -> ByteArray(vec.size) { vec.getFloat(it).toInt().toByte() }
|
||||
else -> ByteArray(0)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns element as a [ByteArray], converting scalar types when possible.
|
||||
* @return element as [ByteArray] or empty [ByteArray] if fail.
|
||||
*/
|
||||
public fun toShortArray(): ShortArray {
|
||||
val vec = TypedVector(type.toElementTypedVector(), buffer, buffer.indirect(end, parentWidth), byteWidth)
|
||||
return when (type) {
|
||||
T_VECTOR_INT -> ShortArray(vec.size) { vec.getInt(it).toShort() }
|
||||
T_VECTOR_UINT -> ShortArray(vec.size) { vec.getUInt(it).toShort() }
|
||||
T_VECTOR -> ShortArray(vec.size) { vec[it].toShort() }
|
||||
T_VECTOR_FLOAT -> ShortArray(vec.size) { vec.getFloat(it).toInt().toShort() }
|
||||
else -> ShortArray(0)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns element as a [IntArray], converting scalar types when possible.
|
||||
* @return element as [IntArray] or empty [IntArray] if fail.
|
||||
*/
|
||||
public fun toIntArray(): IntArray {
|
||||
val vec = TypedVector(type.toElementTypedVector(), buffer, buffer.indirect(end, parentWidth), byteWidth)
|
||||
return when (type) {
|
||||
T_VECTOR_INT -> IntArray(vec.size) { vec.getInt(it).toInt() }
|
||||
T_VECTOR_UINT -> IntArray(vec.size) { vec.getUInt(it).toInt() }
|
||||
T_VECTOR -> IntArray(vec.size) { vec[it].toInt() }
|
||||
T_VECTOR_FLOAT -> IntArray(vec.size) { vec.getFloat(it).toInt() }
|
||||
else -> IntArray(0)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns element as a [LongArray], converting scalar types when possible.
|
||||
* @return element as [LongArray] or empty [LongArray] if fail.
|
||||
*/
|
||||
public fun toLongArray(): LongArray {
|
||||
val vec = TypedVector(type.toElementTypedVector(), buffer, buffer.indirect(end, parentWidth), byteWidth)
|
||||
return when (type) {
|
||||
T_VECTOR_INT -> LongArray(vec.size) { vec.getInt(it) }
|
||||
T_VECTOR_UINT -> LongArray(vec.size) { vec.getInt(it) }
|
||||
T_VECTOR -> LongArray(vec.size) { vec[it].toLong() }
|
||||
T_VECTOR_FLOAT -> LongArray(vec.size) { vec.getFloat(it).toLong() }
|
||||
else -> LongArray(0)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns element as a [UByteArray], converting scalar types when possible.
|
||||
* @return element as [UByteArray] or empty [UByteArray] if fail.
|
||||
*/
|
||||
public fun toUByteArray(): UByteArray {
|
||||
val vec = TypedVector(type.toElementTypedVector(), buffer, buffer.indirect(end, parentWidth), byteWidth)
|
||||
return when (type) {
|
||||
T_VECTOR_INT -> UByteArray(vec.size) { vec.getInt(it).toUByte() }
|
||||
T_VECTOR_UINT -> UByteArray(vec.size) { vec.getUInt(it).toUByte() }
|
||||
T_VECTOR -> UByteArray(vec.size) { vec[it].toUByte() }
|
||||
T_VECTOR_FLOAT -> UByteArray(vec.size) { vec.getFloat(it).toInt().toUByte() }
|
||||
else -> UByteArray(0)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns element as a [UIntArray], converting scalar types when possible.
|
||||
* @return element as [UIntArray] or empty [UIntArray] if fail.
|
||||
*/
|
||||
public fun toUShortArray(): UShortArray {
|
||||
val vec = TypedVector(type.toElementTypedVector(), buffer, buffer.indirect(end, parentWidth), byteWidth)
|
||||
return when (type) {
|
||||
T_VECTOR_INT -> UShortArray(vec.size) { vec.getInt(it).toUShort() }
|
||||
T_VECTOR_UINT -> UShortArray(vec.size) { vec.getUInt(it).toUShort() }
|
||||
T_VECTOR -> UShortArray(vec.size) { vec[it].toUShort() }
|
||||
T_VECTOR_FLOAT -> UShortArray(vec.size) { vec.getFloat(it).toUInt().toUShort() }
|
||||
else -> UShortArray(0)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns element as a [UIntArray], converting scalar types when possible.
|
||||
* @return element as [UIntArray] or empty [UIntArray] if fail.
|
||||
*/
|
||||
public fun toUIntArray(): UIntArray {
|
||||
val vec = TypedVector(type.toElementTypedVector(), buffer, buffer.indirect(end, parentWidth), byteWidth)
|
||||
return when (type) {
|
||||
T_VECTOR_INT -> UIntArray(vec.size) { vec.getInt(it).toUInt() }
|
||||
T_VECTOR_UINT -> UIntArray(vec.size) { vec.getUInt(it).toUInt() }
|
||||
T_VECTOR -> UIntArray(vec.size) { vec[it].toUInt() }
|
||||
T_VECTOR_FLOAT -> UIntArray(vec.size) { vec.getFloat(it).toUInt() }
|
||||
else -> UIntArray(0)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns element as a [ULongArray], converting scalar types when possible.
|
||||
* @return element as [ULongArray] or empty [ULongArray] if fail.
|
||||
*/
|
||||
public fun toULongArray(): ULongArray {
|
||||
val vec = TypedVector(type.toElementTypedVector(), buffer, buffer.indirect(end, parentWidth), byteWidth)
|
||||
return when (type) {
|
||||
T_VECTOR_INT -> ULongArray(vec.size) { vec.getUInt(it) }
|
||||
T_VECTOR_UINT -> ULongArray(vec.size) { vec.getUInt(it) }
|
||||
T_VECTOR -> ULongArray(vec.size) { vec[it].toULong() }
|
||||
T_VECTOR_FLOAT -> ULongArray(vec.size) { vec.getFloat(it).toULong() }
|
||||
else -> ULongArray(0)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns element as a [FloatArray], converting scalar types when possible.
|
||||
* @return element as [FloatArray] or empty [FloatArray] if fail.
|
||||
*/
|
||||
public fun toFloatArray(): FloatArray {
|
||||
val vec = TypedVector(type.toElementTypedVector(), buffer, buffer.indirect(end, parentWidth), byteWidth)
|
||||
return when (type) {
|
||||
T_VECTOR_FLOAT -> FloatArray(vec.size) { vec.getFloat(it).toFloat() }
|
||||
T_VECTOR_INT -> FloatArray(vec.size) { vec.getInt(it).toFloat() }
|
||||
T_VECTOR_UINT -> FloatArray(vec.size) { vec.getUInt(it).toFloat() }
|
||||
T_VECTOR -> FloatArray(vec.size) { vec[it].toFloat() }
|
||||
else -> FloatArray(0)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns element as a [DoubleArray], converting scalar types when possible.
|
||||
* @return element as [DoubleArray] or empty [DoubleArray] if fail.
|
||||
*/
|
||||
public fun toDoubleArray(): DoubleArray {
|
||||
val vec = TypedVector(type.toElementTypedVector(), buffer, buffer.indirect(end, parentWidth), byteWidth)
|
||||
return when (type) {
|
||||
T_VECTOR_FLOAT -> DoubleArray(vec.size) { vec[it].toDouble() }
|
||||
T_VECTOR_INT -> DoubleArray(vec.size) { vec[it].toDouble() }
|
||||
T_VECTOR_UINT -> DoubleArray(vec.size) { vec[it].toDouble() }
|
||||
T_VECTOR -> DoubleArray(vec.size) { vec[it].toDouble() }
|
||||
else -> DoubleArray(0)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns element as a [Vector]
|
||||
* @return element as [Vector] or empty [Vector] if fail
|
||||
*/
|
||||
public fun toVector(): Vector {
|
||||
return when {
|
||||
isVector -> Vector(buffer, buffer.indirect(end, parentWidth), byteWidth)
|
||||
isTypedVector -> TypedVector(type.toElementTypedVector(), buffer, buffer.indirect(end, parentWidth), byteWidth)
|
||||
else -> emptyVector()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns element as a [Blob]
|
||||
* @return element as [Blob] or empty [Blob] if fail
|
||||
*/
|
||||
public fun toBlob(): Blob {
|
||||
return when (type) {
|
||||
T_BLOB, T_STRING -> Blob(buffer, buffer.indirect(end, parentWidth), byteWidth)
|
||||
else -> emptyBlob()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns element as a [Map].
|
||||
* @return element as [Map] or empty [Map] if fail
|
||||
*/
|
||||
public fun toMap(): Map = when (type) {
|
||||
T_MAP -> Map(buffer, buffer.indirect(end, parentWidth), byteWidth)
|
||||
else -> emptyMap()
|
||||
}
|
||||
|
||||
private inline fun <T> resolve(crossinline block: (pos: Int, width: ByteWidth) -> T): T {
|
||||
return if (type.isIndirectScalar()) {
|
||||
block(buffer.indirect(end, byteWidth), byteWidth)
|
||||
} else {
|
||||
block(end, parentWidth)
|
||||
}
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (other == null || this::class != other::class) return false
|
||||
other as Reference
|
||||
if (buffer != other.buffer ||
|
||||
end != other.end ||
|
||||
parentWidth != other.parentWidth ||
|
||||
byteWidth != other.byteWidth ||
|
||||
type != other.type
|
||||
) return false
|
||||
return true
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
var result = buffer.hashCode()
|
||||
result = 31 * result + end
|
||||
result = 31 * result + parentWidth.value
|
||||
result = 31 * result + byteWidth.value
|
||||
result = 31 * result + type.hashCode()
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents any element that has a size property to it, like: [Map], [Vector] and [TypedVector].
|
||||
*/
|
||||
public open class Sized internal constructor(
|
||||
public val buffer: ReadBuffer,
|
||||
public val end: Int,
|
||||
public val byteWidth: ByteWidth
|
||||
) {
|
||||
public open val size: Int = buffer.readSize(end, byteWidth)
|
||||
}
|
||||
|
||||
/**
|
||||
* Represent an array of bytes in the buffer.
|
||||
*/
|
||||
public open class Blob internal constructor(
|
||||
buffer: ReadBuffer,
|
||||
end: Int,
|
||||
byteWidth: ByteWidth
|
||||
) : Sized(buffer, end, byteWidth) {
|
||||
/**
|
||||
* Return [Blob] as [ReadBuffer]
|
||||
* @return blob as [ReadBuffer]
|
||||
*/
|
||||
public fun data(): ReadBuffer = buffer.slice(end, size)
|
||||
|
||||
/**
|
||||
* Copy [Blob] into a [ByteArray]
|
||||
* @return A [ByteArray] containing the blob data.
|
||||
*/
|
||||
public fun toByteArray(): ByteArray {
|
||||
val result = ByteArray(size)
|
||||
for (i in 0 until size) {
|
||||
result[i] = buffer[end + i]
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
/**
|
||||
* Return individual byte at a given position
|
||||
* @param pos position of the byte to be read
|
||||
*/
|
||||
public operator fun get(pos: Int): Byte {
|
||||
if (pos !in 0..size) error("$pos index out of bounds. Should be in range 0..$size")
|
||||
return buffer[end + pos]
|
||||
}
|
||||
|
||||
override fun toString(): String = buffer.getString(end, size)
|
||||
}
|
||||
|
||||
/**
|
||||
* [Vector] represents an array of elements in the buffer. The element can be of any type.
|
||||
*/
|
||||
public open class Vector internal constructor(
|
||||
buffer: ReadBuffer,
|
||||
end: Int,
|
||||
byteWidth: ByteWidth
|
||||
) : Collection<Reference>,
|
||||
Sized(buffer, end, byteWidth) {
|
||||
|
||||
/**
|
||||
* Returns a [Reference] from the [Vector] at position [index]. Returns a null reference
|
||||
* @param index position in the vector.
|
||||
* @return [Reference] for a key or a null [Reference] if not found.
|
||||
*/
|
||||
public open operator fun get(index: Int): Reference {
|
||||
if (index >= size) return nullReference()
|
||||
val packedType = buffer[(end + size * byteWidth.value + index)].toInt()
|
||||
val objEnd = end + index * byteWidth
|
||||
return Reference(buffer, objEnd, byteWidth, packedType)
|
||||
}
|
||||
|
||||
// overrides from Collection<Reference>
|
||||
|
||||
override fun contains(element: Reference): Boolean = find { it == element } != null
|
||||
|
||||
override fun containsAll(elements: Collection<Reference>): Boolean {
|
||||
elements.forEach { if (!contains(it)) return false }
|
||||
return true
|
||||
}
|
||||
|
||||
override fun isEmpty(): Boolean = size == 0
|
||||
|
||||
override fun iterator(): Iterator<Reference> = object : Iterator<Reference> {
|
||||
var position = 0
|
||||
override fun hasNext(): Boolean = position != size
|
||||
override fun next(): Reference = get(position++)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* [TypedVector] represents an array of scalar elements of the same type in the buffer.
|
||||
*/
|
||||
public open class TypedVector(
|
||||
private val elementType: FlexBufferType,
|
||||
buffer: ReadBuffer,
|
||||
end: Int,
|
||||
byteWidth: ByteWidth
|
||||
) : Vector(buffer, end, byteWidth) {
|
||||
|
||||
/**
|
||||
* Returns a [Reference] from the [TypedVector] at position [index]. Returns a null reference
|
||||
* @param index position in the vector.
|
||||
* @return [Reference] for a key or a null [Reference] if not found.
|
||||
*/
|
||||
override operator fun get(index: Int): Reference {
|
||||
if (index >= size) return nullReference()
|
||||
val childPos: Int = end + index * byteWidth
|
||||
return Reference(buffer, childPos, byteWidth, ByteWidth(1), elementType)
|
||||
}
|
||||
|
||||
private inline fun <T> resolveAt(index: Int, crossinline block: (Int, ByteWidth) -> T): T {
|
||||
val childPos: Int = end + index * byteWidth
|
||||
return block(childPos, byteWidth)
|
||||
}
|
||||
|
||||
internal fun getBoolean(index: Int): Boolean = resolveAt(index) {
|
||||
pos: Int, _: ByteWidth -> buffer.getBoolean(pos)
|
||||
}
|
||||
internal fun getInt(index: Int): Long = resolveAt(index) {
|
||||
pos: Int, width: ByteWidth -> buffer.readLong(pos, width)
|
||||
}
|
||||
internal fun getUInt(index: Int): ULong = resolveAt(index) {
|
||||
pos: Int, width: ByteWidth -> buffer.readULong(pos, width)
|
||||
}
|
||||
internal fun getFloat(index: Int): Double = resolveAt(index) {
|
||||
pos: Int, width: ByteWidth -> buffer.readFloat(pos, width)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a key element in the buffer. Keys are
|
||||
* used to reference objects in a [Map]
|
||||
*/
|
||||
public data class Key(
|
||||
public val buffer: ReadBuffer,
|
||||
public val start: Int,
|
||||
public val end: Int = buffer.findFirst(ZeroByte, start)
|
||||
) {
|
||||
|
||||
val sizeInBytes: Int = end - start
|
||||
|
||||
private val codePoint = CharArray(2)
|
||||
|
||||
val sizeInChars: Int
|
||||
get() {
|
||||
var count = 0
|
||||
var i = start
|
||||
while (i < end) {
|
||||
val size = codePointSizeInBytes(i)
|
||||
i += size
|
||||
count += if (size == 4) 2 else 1
|
||||
}
|
||||
return count
|
||||
}
|
||||
|
||||
public operator fun get(index: Int): Char {
|
||||
var count = 0
|
||||
var i = start
|
||||
var size = 0
|
||||
// we loop over the bytes to find the right position for the "char" at index i
|
||||
while (i < end && count < index) {
|
||||
size = codePointSizeInBytes(i)
|
||||
i += size
|
||||
// 4 bytes utf8 are 2 chars wide, the rest is on char.
|
||||
count += if (size == 4) 2 else 1
|
||||
}
|
||||
return when {
|
||||
count == index -> {
|
||||
Utf8.decodeUtf8CodePoint(buffer, i, codePoint)
|
||||
codePoint[0]
|
||||
}
|
||||
count == index + 1 && size == 4 -> {
|
||||
Utf8.decodeUtf8CodePoint(buffer, i - size, codePoint)
|
||||
codePoint[1]
|
||||
}
|
||||
else -> error("Invalid count=$count, index=$index")
|
||||
}
|
||||
}
|
||||
|
||||
private inline fun codePointSizeInBytes(pos: Int): Int {
|
||||
val b = buffer[pos]
|
||||
return when {
|
||||
Utf8.isOneByte(b) -> 1
|
||||
Utf8.isTwoBytes(b) -> 2
|
||||
Utf8.isThreeBytes(b) -> 3
|
||||
else -> 4
|
||||
}
|
||||
}
|
||||
|
||||
override fun toString(): String = if (sizeInBytes > 0) buffer.getString(start, sizeInBytes) else ""
|
||||
|
||||
/**
|
||||
* Checks whether Key is invalid or not.
|
||||
*/
|
||||
public fun isInvalid(): Boolean = sizeInBytes <= 0
|
||||
}
|
||||
|
||||
/**
|
||||
* A Map class that provide support to access Key-Value data from Flexbuffers.
|
||||
*/
|
||||
public class Map
|
||||
internal constructor(buffer: ReadBuffer, end: Int, byteWidth: ByteWidth):
|
||||
Sized(buffer, end, byteWidth),
|
||||
kotlin.collections.Map<Key, Reference> {
|
||||
|
||||
// used for accessing the key vector elements
|
||||
private var keyVectorEnd: Int
|
||||
private var keyVectorByteWidth: ByteWidth
|
||||
init {
|
||||
val keysOffset = end - (3 * byteWidth) // 3 is number of prefixed fields
|
||||
keyVectorEnd = buffer.indirect(keysOffset, byteWidth)
|
||||
keyVectorByteWidth = ByteWidth(buffer.readInt(keysOffset + byteWidth, byteWidth))
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a [Reference] from the [Map] at position [index]. Returns a null reference
|
||||
* @param index position in the map
|
||||
* @return [Reference] for a key or a null [Reference] if not found.
|
||||
*/
|
||||
public operator fun get(index: Int): Reference {
|
||||
if (index >= size) return nullReference()
|
||||
val packedPos = end + size * byteWidth + index
|
||||
val packedType = buffer[packedPos].toInt()
|
||||
val objEnd = end + index * byteWidth
|
||||
return Reference(buffer, objEnd, byteWidth, packedType)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a [Reference] from the [Map] for a given [String] [key].
|
||||
* @param key access key to element on map
|
||||
* @return [Reference] for a key or a null [Reference] if not found.
|
||||
*/
|
||||
public operator fun get(key: String): Reference {
|
||||
val index: Int = binarySearch(key)
|
||||
return if (index in 0 until size) {
|
||||
get(index)
|
||||
} else nullReference()
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a [Reference] from the [Map] for a given [Key] [key].
|
||||
* @param key access key to element on map
|
||||
* @return [Reference] for a key or a null [Reference] if not found.
|
||||
*/
|
||||
override operator fun get(key: Key): Reference {
|
||||
val index = binarySearch(key)
|
||||
return if (index in 0 until size) {
|
||||
get(index)
|
||||
} else nullReference()
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the map contains a [key].
|
||||
* @param key [String]
|
||||
* @return true if key is found in the map, otherwise false.
|
||||
*/
|
||||
public operator fun contains(key: String): Boolean = binarySearch(key) >= 0
|
||||
|
||||
/**
|
||||
* Returns a [Key] for a given position [index] in the [Map].
|
||||
* @param index of the key in the map
|
||||
* @return a Key for the given index. Out of bounds indexes returns invalid keys.
|
||||
*/
|
||||
public fun keyAt(index: Int): Key {
|
||||
val childPos: Int = keyVectorEnd + index * keyVectorByteWidth
|
||||
return Key(buffer, buffer.indirect(childPos, keyVectorByteWidth))
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a [Key] as [String] for a given position [index] in the [Map].
|
||||
* @param index of the key in the map
|
||||
* @return a Key for the given index. Out of bounds indexes returns empty string.
|
||||
*/
|
||||
public fun keyAsString(index: Int): String {
|
||||
val childPos: Int = keyVectorEnd + index * keyVectorByteWidth
|
||||
val start = buffer.indirect(childPos, keyVectorByteWidth)
|
||||
val end = buffer.findFirst(ZeroByte, start)
|
||||
return if (end > start) buffer.getString(start, end - start) else ""
|
||||
}
|
||||
|
||||
// Overrides from kotlin.collections.Map<Key, Reference>
|
||||
|
||||
public data class Entry(override val key: Key, override val value: Reference) :
|
||||
kotlin.collections.Map.Entry<Key, Reference>
|
||||
|
||||
override val entries: Set<kotlin.collections.Map.Entry<Key, Reference>>
|
||||
get() = keys.map { Entry(it, get(it.toString())) }.toSet()
|
||||
|
||||
override val keys: Set<Key>
|
||||
get() {
|
||||
val set = LinkedHashSet<Key>(size)
|
||||
for (i in 0 until size) {
|
||||
val key = keyAt(i)
|
||||
set.add(key)
|
||||
}
|
||||
return set
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a [Vector] for accessing all values in the [Map].
|
||||
* @return [Vector] of values.
|
||||
*/
|
||||
override val values: Collection<Reference>
|
||||
get() = Vector(buffer, end, byteWidth)
|
||||
|
||||
override fun containsKey(key: Key): Boolean {
|
||||
for (i in 0 until size) {
|
||||
if (key == keyAt(i))
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
override fun containsValue(value: Reference): Boolean = values.contains(value)
|
||||
|
||||
override fun isEmpty(): Boolean = size == 0
|
||||
|
||||
// Performs a binary search on a key vector and return index of the key in key vector
|
||||
private fun binarySearch(searchedKey: String) = binarySearch { compareCharSequence(it, searchedKey) }
|
||||
// Performs a binary search on a key vector and return index of the key in key vector
|
||||
private fun binarySearch(key: Key): Int = binarySearch { compareKeys(it, key.start) }
|
||||
|
||||
private inline fun binarySearch(crossinline comparisonBlock: (Int) -> Int): Int {
|
||||
var low = 0
|
||||
var high = size - 1
|
||||
while (low <= high) {
|
||||
val mid = low + high ushr 1
|
||||
val keyPos: Int = buffer.indirect(keyVectorEnd + mid * keyVectorByteWidth, keyVectorByteWidth)
|
||||
val cmp: Int = comparisonBlock(keyPos)
|
||||
if (cmp < 0) low = mid + 1 else if (cmp > 0) high = mid - 1 else return mid // key found
|
||||
}
|
||||
return -(low + 1) // key not found
|
||||
}
|
||||
|
||||
// compares a CharSequence against a T_KEY
|
||||
private fun compareKeys(start: Int, other: Int): Int {
|
||||
var bufferPos = start
|
||||
var otherPos = other
|
||||
val limit: Int = buffer.limit
|
||||
var c1: Byte = ZeroByte
|
||||
var c2: Byte = ZeroByte
|
||||
while (otherPos < limit) {
|
||||
c1 = buffer[bufferPos++]
|
||||
c2 = buffer[otherPos++]
|
||||
when {
|
||||
c1 == ZeroByte -> return c1 - c2
|
||||
c1 != c2 -> return c1 - c2
|
||||
}
|
||||
}
|
||||
return c1 - c2
|
||||
}
|
||||
|
||||
// compares a CharSequence against a [CharSequence]
|
||||
private fun compareCharSequence(start: Int, other: CharSequence): Int {
|
||||
var bufferPos = start
|
||||
var otherPos = 0
|
||||
val limit: Int = buffer.limit
|
||||
val otherLimit = other.length
|
||||
// special loop for ASCII characters. Most of keys should be ASCII only, so this
|
||||
// loop should be optimized for that.
|
||||
// breaks if a multi-byte character is found
|
||||
while (otherPos < otherLimit) {
|
||||
val c2 = other[otherPos]
|
||||
// not a single byte codepoint
|
||||
if (c2.code >= 0x80) {
|
||||
break
|
||||
}
|
||||
val b: Byte = buffer[bufferPos]
|
||||
when {
|
||||
b == ZeroByte -> return -c2.code
|
||||
b < 0 -> break
|
||||
b != c2.code.toByte() -> return b - c2.code.toByte()
|
||||
}
|
||||
++bufferPos
|
||||
++otherPos
|
||||
}
|
||||
if (bufferPos < limit)
|
||||
return 0
|
||||
|
||||
val comparisonBuffer = ByteArray(4)
|
||||
while (bufferPos < limit) {
|
||||
val sizeInBuff = Utf8.encodeUtf8CodePoint(other, otherPos, comparisonBuffer)
|
||||
if (sizeInBuff == 0) {
|
||||
return buffer[bufferPos].toInt()
|
||||
}
|
||||
for (i in 0 until sizeInBuff) {
|
||||
val bufferByte: Byte = buffer[bufferPos++]
|
||||
val otherByte: Byte = comparisonBuffer[i]
|
||||
when {
|
||||
bufferByte == ZeroByte -> return -otherByte
|
||||
bufferByte != otherByte -> return bufferByte - otherByte
|
||||
}
|
||||
}
|
||||
otherPos += if (sizeInBuff == 4) 2 else 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
}
|
@ -1,786 +0,0 @@
|
||||
/*
|
||||
* Copyright 2021 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.
|
||||
*/
|
||||
@file:Suppress("NOTHING_TO_INLINE")
|
||||
|
||||
package com.google.flatbuffers.kotlin
|
||||
|
||||
@ExperimentalUnsignedTypes
|
||||
public class FlexBuffersBuilder(
|
||||
public val buffer: ReadWriteBuffer,
|
||||
private val shareFlag: Int = SHARE_KEYS
|
||||
) {
|
||||
|
||||
public constructor(initialCapacity: Int = 1024, shareFlag: Int = SHARE_KEYS) :
|
||||
this(ArrayReadWriteBuffer(initialCapacity), shareFlag)
|
||||
|
||||
private val stringValuePool: HashMap<String, Value> = HashMap()
|
||||
private val stringKeyPool: HashMap<String, Int> = HashMap()
|
||||
private val stack: MutableList<Value> = mutableListOf()
|
||||
private var finished: Boolean = false
|
||||
|
||||
/**
|
||||
* Reset the FlexBuffersBuilder by purging all data that it holds. Buffer might
|
||||
* keep its capacity after a reset.
|
||||
*/
|
||||
public fun clear() {
|
||||
buffer.clear()
|
||||
stringValuePool.clear()
|
||||
stringKeyPool.clear()
|
||||
stack.clear()
|
||||
finished = false
|
||||
}
|
||||
|
||||
/**
|
||||
* Finish writing the message into the buffer. After that no other element must
|
||||
* be inserted into the buffer. Also, you must call this function before start using the
|
||||
* FlexBuffer message
|
||||
* @return [ReadBuffer] containing the FlexBuffer message
|
||||
*/
|
||||
public fun finish(): ReadBuffer {
|
||||
// If you hit this, you likely have objects that were never included
|
||||
// in a parent. You need to have exactly one root to finish a buffer.
|
||||
// Check your Start/End calls are matched, and all objects are inside
|
||||
// some other object.
|
||||
if (stack.size != 1) error("There is must be only on object as root. Current ${stack.size}.")
|
||||
// Write root value.
|
||||
val byteWidth = align(stack[0].elemWidth(buffer.writePosition, 0))
|
||||
buffer.requestAdditionalCapacity(byteWidth.value + 2)
|
||||
writeAny(stack[0], byteWidth)
|
||||
// Write root type.
|
||||
buffer.put(stack[0].storedPackedType())
|
||||
// Write root size. Normally determined by parent, but root has no parent :)
|
||||
buffer.put(byteWidth.value.toByte())
|
||||
this.finished = true
|
||||
return buffer // TODO: make a read-only shallow copy
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert a single [Boolean] into the buffer
|
||||
* @param value true or false
|
||||
*/
|
||||
public fun put(value: Boolean): Unit = run { this[null] = value }
|
||||
|
||||
/**
|
||||
* Insert a null reference into the buffer. A key must be present if element is inserted into a map.
|
||||
*/
|
||||
public fun putNull(key: String? = null): Unit =
|
||||
run { stack.add(Value(T_NULL, putKey(key), W_8, 0UL)) }
|
||||
|
||||
/**
|
||||
* Insert a single [Boolean] into the buffer. A key must be present if element is inserted into a map.
|
||||
*/
|
||||
public operator fun set(key: String? = null, value: Boolean): Unit =
|
||||
run { stack.add(Value(T_BOOL, putKey(key), W_8, if (value) 1UL else 0UL)) }
|
||||
|
||||
/**
|
||||
* Insert a single [Byte] into the buffer
|
||||
*/
|
||||
public fun put(value: Byte): Unit = set(null, value.toLong())
|
||||
|
||||
/**
|
||||
* Insert a single [Byte] into the buffer. A key must be present if element is inserted into a map.
|
||||
*/
|
||||
public operator fun set(key: String? = null, value: Byte): Unit = set(key, value.toLong())
|
||||
|
||||
/**
|
||||
* Insert a single [Short] into the buffer.
|
||||
*/
|
||||
public fun put(value: Short): Unit = set(null, value.toLong())
|
||||
|
||||
/**
|
||||
* Insert a single [Short] into the buffer. A key must be present if element is inserted into a map.
|
||||
*/
|
||||
public inline operator fun set(key: String? = null, value: Short): Unit = set(key, value.toLong())
|
||||
|
||||
/**
|
||||
* Insert a single [Int] into the buffer.
|
||||
*/
|
||||
public fun put(value: Int): Unit = set(null, value.toLong())
|
||||
|
||||
/**
|
||||
* Insert a single [Int] into the buffer. A key must be present if element is inserted into a map.
|
||||
*/
|
||||
public inline operator fun set(key: String? = null, value: Int): Unit = set(key, value.toLong())
|
||||
|
||||
/**
|
||||
* Insert a single [Long] into the buffer.
|
||||
*/
|
||||
public fun put(value: Long): Unit = set(null, value)
|
||||
|
||||
/**
|
||||
* Insert a single [Long] into the buffer. A key must be present if element is inserted into a map.
|
||||
*/
|
||||
public operator fun set(key: String? = null, value: Long): Unit =
|
||||
run { stack.add(Value(T_INT, putKey(key), value.toULong().widthInUBits(), value.toULong())) }
|
||||
|
||||
/**
|
||||
* Insert a single [UByte] into the buffer
|
||||
*/
|
||||
public fun put(value: UByte): Unit = set(null, value.toULong())
|
||||
|
||||
/**
|
||||
* Insert a single [UByte] into the buffer. A key must be present if element is inserted into a map.
|
||||
*/
|
||||
public inline operator fun set(key: String? = null, value: UByte): Unit = set(key, value.toULong())
|
||||
|
||||
/**
|
||||
* Insert a single [UShort] into the buffer.
|
||||
*/
|
||||
public fun put(value: UShort): Unit = set(null, value.toULong())
|
||||
|
||||
/**
|
||||
* Insert a single [UShort] into the buffer. A key must be present if element is inserted into a map.
|
||||
*/
|
||||
private inline operator fun set(key: String? = null, value: UShort): Unit = set(key, value.toULong())
|
||||
|
||||
/**
|
||||
* Insert a single [UInt] into the buffer.
|
||||
*/
|
||||
public fun put(value: UInt): Unit = set(null, value.toULong())
|
||||
|
||||
/**
|
||||
* Insert a single [UInt] into the buffer. A key must be present if element is inserted into a map.
|
||||
*/
|
||||
private inline operator fun set(key: String? = null, value: UInt): Unit = set(key, value.toULong())
|
||||
|
||||
/**
|
||||
* Insert a single [ULong] into the buffer.
|
||||
*/
|
||||
public fun put(value: ULong): Unit = set(null, value)
|
||||
|
||||
/**
|
||||
* Insert a single [ULong] into the buffer. A key must be present if element is inserted into a map.
|
||||
*/
|
||||
public operator fun set(key: String? = null, value: ULong): Unit =
|
||||
run { stack.add(Value(T_UINT, putKey(key), value.widthInUBits(), value)) }
|
||||
|
||||
/**
|
||||
* Insert a single [Float] into the buffer.
|
||||
*/
|
||||
public fun put(value: Float): Unit = run { this[null] = value }
|
||||
|
||||
/**
|
||||
* Insert a single [Float] into the buffer. A key must be present if element is inserted into a map.
|
||||
*/
|
||||
public operator fun set(key: String? = null, value: Float): Unit =
|
||||
run { stack.add(Value(T_FLOAT, putKey(key), W_32, dValue = value.toDouble())) }
|
||||
|
||||
/**
|
||||
* Insert a single [Double] into the buffer.
|
||||
*/
|
||||
public fun put(value: Double): Unit = run { this[null] = value }
|
||||
|
||||
/**
|
||||
* Insert a single [Double] into the buffer. A key must be present if element is inserted into a map.
|
||||
*/
|
||||
public operator fun set(key: String? = null, value: Double): Unit =
|
||||
run { stack.add(Value(T_FLOAT, putKey(key), W_64, dValue = value)) }
|
||||
|
||||
/**
|
||||
* Insert a single [String] into the buffer.
|
||||
*/
|
||||
public fun put(value: String): Int = set(null, value)
|
||||
|
||||
/**
|
||||
* Insert a single [String] into the buffer. A key must be present if element is inserted into a map.
|
||||
*/
|
||||
public operator fun set(key: String? = null, value: String): Int {
|
||||
val iKey = putKey(key)
|
||||
val holder = if (shareFlag and SHARE_STRINGS != 0) {
|
||||
stringValuePool.getOrPut(value) {
|
||||
writeString(iKey, value).also { stringValuePool[value] = it }
|
||||
}.copy(key = iKey)
|
||||
} else {
|
||||
writeString(iKey, value)
|
||||
}
|
||||
stack.add(holder)
|
||||
return holder.iValue.toInt()
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a [ByteArray] into the message as a [Blob].
|
||||
* @param value byte array
|
||||
* @return position in buffer as the start of byte array
|
||||
*/
|
||||
public fun put(value: ByteArray): Int = set(null, value)
|
||||
|
||||
/**
|
||||
* Adds a [ByteArray] into the message as a [Blob]. A key must be present if element is inserted into a map.
|
||||
* @param value byte array
|
||||
* @return position in buffer as the start of byte array
|
||||
*/
|
||||
public operator fun set(key: String? = null, value: ByteArray): Int {
|
||||
val element = writeBlob(putKey(key), value, T_BLOB, false)
|
||||
stack.add(element)
|
||||
return element.iValue.toInt()
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a [IntArray] into the message as a typed vector of fixed size.
|
||||
* @param value [IntArray]
|
||||
* @return position in buffer as the start of byte array
|
||||
*/
|
||||
public fun put(value: IntArray): Int = set(null, value)
|
||||
|
||||
/**
|
||||
* Adds a [IntArray] into the message as a typed vector of fixed size.
|
||||
* A key must be present if element is inserted into a map.
|
||||
* @param value [IntArray]
|
||||
* @return position in buffer as the start of byte array
|
||||
*/
|
||||
public operator fun set(key: String? = null, value: IntArray): Int =
|
||||
setTypedVector(key, value.size, T_VECTOR_INT, value.widthInUBits()) { writeIntArray(value, it) }
|
||||
|
||||
/**
|
||||
* Adds a [ShortArray] into the message as a typed vector of fixed size.
|
||||
* @param value [ShortArray]
|
||||
* @return position in buffer as the start of byte array
|
||||
*/
|
||||
public fun put(value: ShortArray): Int = set(null, value)
|
||||
|
||||
/**
|
||||
* Adds a [ShortArray] into the message as a typed vector of fixed size.
|
||||
* A key must be present if element is inserted into a map.
|
||||
* @param value [ShortArray]
|
||||
* @return position in buffer as the start of byte array
|
||||
*/
|
||||
public operator fun set(key: String? = null, value: ShortArray): Int =
|
||||
setTypedVector(key, value.size, T_VECTOR_INT, value.widthInUBits()) { writeIntArray(value, it) }
|
||||
|
||||
/**
|
||||
* Adds a [LongArray] into the message as a typed vector of fixed size.
|
||||
* @param value [LongArray]
|
||||
* @return position in buffer as the start of byte array
|
||||
*/
|
||||
public fun put(value: LongArray): Int = set(null, value)
|
||||
|
||||
/**
|
||||
* Adds a [LongArray] into the message as a typed vector of fixed size.
|
||||
* A key must be present if element is inserted into a map.
|
||||
* @param value [LongArray]
|
||||
* @return position in buffer as the start of byte array
|
||||
*/
|
||||
public operator fun set(key: String? = null, value: LongArray): Int =
|
||||
setTypedVector(key, value.size, T_VECTOR_INT, value.widthInUBits()) { writeIntArray(value, it) }
|
||||
|
||||
/**
|
||||
* Adds a [FloatArray] into the message as a typed vector of fixed size.
|
||||
* @param value [FloatArray]
|
||||
* @return position in buffer as the start of byte array
|
||||
*/
|
||||
public fun put(value: FloatArray): Int = set(null, value)
|
||||
|
||||
/**
|
||||
* Adds a [FloatArray] into the message as a typed vector of fixed size.
|
||||
* A key must be present if element is inserted into a map.
|
||||
* @param value [FloatArray]
|
||||
* @return position in buffer as the start of byte array
|
||||
*/
|
||||
public operator fun set(key: String? = null, value: FloatArray): Int =
|
||||
setTypedVector(key, value.size, T_VECTOR_FLOAT, W_32) { writeFloatArray(value) }
|
||||
|
||||
/**
|
||||
* Adds a [DoubleArray] into the message as a typed vector of fixed size.
|
||||
* @param value [DoubleArray]
|
||||
* @return position in buffer as the start of byte array
|
||||
*/
|
||||
public fun put(value: DoubleArray): Int = set(null, value)
|
||||
|
||||
/**
|
||||
* Adds a [DoubleArray] into the message as a typed vector of fixed size.
|
||||
* A key must be present if element is inserted into a map.
|
||||
* @param value [DoubleArray]
|
||||
* @return position in buffer as the start of byte array
|
||||
*/
|
||||
public operator fun set(key: String? = null, value: DoubleArray): Int =
|
||||
setTypedVector(key, value.size, T_VECTOR_FLOAT, W_64) { writeFloatArray(value) }
|
||||
|
||||
/**
|
||||
* Adds a [UByteArray] into the message as a typed vector of fixed size.
|
||||
* @param value [UByteArray]
|
||||
* @return position in buffer as the start of byte array
|
||||
*/
|
||||
public fun put(value: UByteArray): Int = set(null, value)
|
||||
|
||||
/**
|
||||
* Adds a [UByteArray] into the message as a typed vector of fixed size.
|
||||
* A key must be present if element is inserted into a map.
|
||||
* @param value [UByteArray]
|
||||
* @return position in buffer as the start of byte array
|
||||
*/
|
||||
public operator fun set(key: String? = null, value: UByteArray): Int =
|
||||
setTypedVec(key) { value.forEach { put(it) } }
|
||||
|
||||
/**
|
||||
* Adds a [UShortArray] into the message as a typed vector of fixed size.
|
||||
* @param value [UShortArray]
|
||||
* @return position in buffer as the start of byte array
|
||||
*/
|
||||
public fun put(value: UShortArray): Int = set(null, value)
|
||||
|
||||
/**
|
||||
* Adds a [UShortArray] into the message as a typed vector of fixed size.
|
||||
* A key must be present if element is inserted into a map.
|
||||
* @param value [UShortArray]
|
||||
* @return position in buffer as the start of byte array
|
||||
*/
|
||||
public operator fun set(key: String? = null, value: UShortArray): Int =
|
||||
setTypedVec(key) { value.forEach { put(it) } }
|
||||
|
||||
/**
|
||||
* Adds a [UIntArray] into the message as a typed vector of fixed size.
|
||||
* @param value [UIntArray]
|
||||
* @return position in buffer as the start of byte array
|
||||
*/
|
||||
public fun put(value: UIntArray): Int = set(null, value)
|
||||
|
||||
/**
|
||||
* Adds a [UIntArray] into the message as a typed vector of fixed size.
|
||||
* A key must be present if element is inserted into a map.
|
||||
* @param value [UIntArray]
|
||||
* @return position in buffer as the start of byte array
|
||||
*/
|
||||
public fun set(key: String? = null, value: UIntArray): Int =
|
||||
setTypedVec(key) { value.forEach { put(it) } }
|
||||
|
||||
/**
|
||||
* Adds a [ULongArray] into the message as a typed vector of fixed size.
|
||||
* @param value [ULongArray]
|
||||
* @return position in buffer as the start of byte array
|
||||
*/
|
||||
public fun put(value: ULongArray): Int = set(null, value)
|
||||
|
||||
/**
|
||||
* Adds a [ULongArray] into the message as a typed vector of fixed size.
|
||||
* A key must be present if element is inserted into a map.
|
||||
* @param value [ULongArray]
|
||||
* @return position in buffer as the start of byte array
|
||||
*/
|
||||
public operator fun set(key: String? = null, value: ULongArray): Int =
|
||||
setTypedVec(key) { value.forEach { put(it) } }
|
||||
|
||||
/**
|
||||
* Creates a new vector will all elements inserted in [block].
|
||||
* @param block where elements will be inserted
|
||||
* @return position in buffer as the start of byte array
|
||||
*/
|
||||
public inline fun putVector(crossinline block: FlexBuffersBuilder.() -> Unit): Int {
|
||||
val pos = startVector()
|
||||
this.block()
|
||||
return endVector(pos)
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new typed vector will all elements inserted in [block].
|
||||
* @param block where elements will be inserted
|
||||
* @return position in buffer as the start of byte array
|
||||
*/
|
||||
public inline fun putTypedVector(crossinline block: FlexBuffersBuilder.() -> Unit): Int {
|
||||
val pos = startVector()
|
||||
this.block()
|
||||
return endTypedVector(pos)
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to return position for starting a new vector.
|
||||
*/
|
||||
public fun startVector(): Int = stack.size
|
||||
|
||||
/**
|
||||
* Finishes a vector element. The initial position of the vector must be passed
|
||||
* @param position position at the start of the vector
|
||||
*/
|
||||
public fun endVector(position: Int): Int = endVector(null, position)
|
||||
|
||||
/**
|
||||
* Finishes a vector element. The initial position of the vector must be passed
|
||||
* @param position position at the start of the vector
|
||||
*/
|
||||
public fun endVector(key: String? = null, position: Int): Int =
|
||||
endAnyVector(position) { createVector(putKey(key), position, stack.size - position) }
|
||||
/**
|
||||
* Finishes a typed vector element. The initial position of the vector must be passed
|
||||
* @param position position at the start of the vector
|
||||
*/
|
||||
public fun endTypedVector(position: Int): Int = endTypedVector(position, null)
|
||||
|
||||
/**
|
||||
* Helper function to return position for starting a new vector.
|
||||
*/
|
||||
public fun startMap(): Int = stack.size
|
||||
|
||||
/**
|
||||
* Creates a new map will all elements inserted in [block].
|
||||
* @param block where elements will be inserted
|
||||
* @return position in buffer as the start of byte array
|
||||
*/
|
||||
public inline fun putMap(key: String? = null, crossinline block: FlexBuffersBuilder.() -> Unit): Int {
|
||||
val pos = startMap()
|
||||
this.block()
|
||||
return endMap(pos, key)
|
||||
}
|
||||
|
||||
/**
|
||||
* Finishes a map, but writing the information in the buffer
|
||||
* @param key key used to store element in map
|
||||
* @return Reference to the map
|
||||
*/
|
||||
public fun endMap(start: Int, key: String? = null): Int {
|
||||
stack.subList(start, stack.size).sortWith(keyComparator)
|
||||
val length = stack.size - start
|
||||
val keys = createKeyVector(start, length)
|
||||
val vec = putMap(putKey(key), start, length, keys)
|
||||
// Remove temp elements and return map.
|
||||
while (stack.size > start) {
|
||||
stack.removeAt(stack.size - 1)
|
||||
}
|
||||
stack.add(vec)
|
||||
return vec.iValue.toInt()
|
||||
}
|
||||
|
||||
private inline fun setTypedVector(
|
||||
key: String? = null,
|
||||
length: Int,
|
||||
vecType: FlexBufferType,
|
||||
bitWidth: BitWidth,
|
||||
crossinline writeBlock: (ByteWidth) -> Unit
|
||||
): Int {
|
||||
val keyPos = putKey(key)
|
||||
val byteWidth = align(bitWidth)
|
||||
// Write vector. First the keys width/offset if available, and size.
|
||||
// write the size
|
||||
writeInt(length, byteWidth)
|
||||
|
||||
// Then the actual data.
|
||||
val vloc: Int = buffer.writePosition
|
||||
writeBlock(byteWidth)
|
||||
stack.add(Value(vecType, keyPos, bitWidth, vloc.toULong()))
|
||||
return vloc
|
||||
}
|
||||
|
||||
private inline fun setTypedVec(key: String? = null, crossinline block: FlexBuffersBuilder.() -> Unit): Int {
|
||||
val pos = startVector()
|
||||
this.block()
|
||||
return endTypedVector(pos, key)
|
||||
}
|
||||
|
||||
public fun endTypedVector(position: Int, key: String? = null): Int =
|
||||
endAnyVector(position) { createTypedVector(putKey(key), position, stack.size - position) }
|
||||
|
||||
private inline fun endAnyVector(start: Int, crossinline creationBlock: () -> Value): Int {
|
||||
val vec = creationBlock()
|
||||
// Remove temp elements and return vector.
|
||||
while (stack.size > start) {
|
||||
stack.removeLast()
|
||||
}
|
||||
stack.add(vec)
|
||||
return vec.iValue.toInt()
|
||||
}
|
||||
|
||||
private inline fun putKey(key: String? = null): Int {
|
||||
if (key == null) return -1
|
||||
return if ((shareFlag and SHARE_KEYS) != 0) {
|
||||
stringKeyPool.getOrPut(key) {
|
||||
val pos: Int = buffer.writePosition
|
||||
val encodedKeySize = Utf8.encodedLength(key)
|
||||
buffer.requestAdditionalCapacity(encodedKeySize + 1)
|
||||
buffer.put(key, encodedKeySize)
|
||||
buffer.put(ZeroByte)
|
||||
pos
|
||||
}
|
||||
} else {
|
||||
val pos: Int = buffer.writePosition
|
||||
val encodedKeySize = Utf8.encodedLength(key)
|
||||
buffer.requestAdditionalCapacity(encodedKeySize + 1)
|
||||
buffer.put(key, encodedKeySize)
|
||||
buffer.put(ZeroByte)
|
||||
pos
|
||||
}
|
||||
}
|
||||
|
||||
private fun writeAny(toWrite: Value, byteWidth: ByteWidth) = when (toWrite.type) {
|
||||
T_NULL, T_BOOL, T_INT, T_UINT -> writeInt(toWrite.iValue, byteWidth)
|
||||
T_FLOAT -> writeDouble(toWrite.dValue, byteWidth)
|
||||
else -> writeOffset(toWrite.iValue.toInt(), byteWidth)
|
||||
}
|
||||
|
||||
private fun writeString(key: Int, s: String): Value {
|
||||
val encodedSize = Utf8.encodedLength(s)
|
||||
val bitWidth = encodedSize.toULong().widthInUBits()
|
||||
val byteWidth = align(bitWidth)
|
||||
|
||||
writeInt(encodedSize, byteWidth)
|
||||
|
||||
buffer.requestAdditionalCapacity(encodedSize + 1)
|
||||
val sloc: Int = buffer.writePosition
|
||||
if (encodedSize > 0)
|
||||
buffer.put(s, encodedSize)
|
||||
buffer.put(ZeroByte)
|
||||
return Value(T_STRING, key, bitWidth, sloc.toULong())
|
||||
}
|
||||
|
||||
private fun writeDouble(toWrite: Double, byteWidth: ByteWidth) {
|
||||
buffer.requestAdditionalCapacity(byteWidth.value)
|
||||
when (byteWidth.value) {
|
||||
4 -> buffer.put(toWrite.toFloat())
|
||||
8 -> buffer.put(toWrite)
|
||||
else -> Unit
|
||||
}
|
||||
}
|
||||
|
||||
private fun writeOffset(toWrite: Int, byteWidth: ByteWidth) {
|
||||
buffer.requestAdditionalCapacity(byteWidth.value)
|
||||
val relativeOffset = (buffer.writePosition - toWrite)
|
||||
if (byteWidth.value != 8 && relativeOffset >= 1L shl byteWidth.value * 8) error("invalid offset $relativeOffset, writer pos ${buffer.writePosition}")
|
||||
writeInt(relativeOffset, byteWidth)
|
||||
}
|
||||
|
||||
private inline fun writeBlob(key: Int, blob: ByteArray, type: FlexBufferType, trailing: Boolean): Value {
|
||||
val bitWidth = blob.size.toULong().widthInUBits()
|
||||
val byteWidth = align(bitWidth)
|
||||
|
||||
writeInt(blob.size, byteWidth)
|
||||
|
||||
val sloc: Int = buffer.writePosition
|
||||
buffer.requestAdditionalCapacity(blob.size + trailing.compareTo(false))
|
||||
buffer.put(blob, 0, blob.size)
|
||||
if (trailing) {
|
||||
buffer.put(ZeroByte)
|
||||
}
|
||||
return Value(type, key, bitWidth, sloc.toULong())
|
||||
}
|
||||
|
||||
private fun writeIntArray(value: IntArray, byteWidth: ByteWidth) =
|
||||
writeIntegerArray(0, value.size, byteWidth) { value[it].toULong() }
|
||||
|
||||
private fun writeIntArray(value: ShortArray, byteWidth: ByteWidth) =
|
||||
writeIntegerArray(0, value.size, byteWidth) { value[it].toULong() }
|
||||
|
||||
private fun writeIntArray(value: LongArray, byteWidth: ByteWidth) =
|
||||
writeIntegerArray(0, value.size, byteWidth) { value[it].toULong() }
|
||||
|
||||
private fun writeFloatArray(value: FloatArray) {
|
||||
buffer.requestAdditionalCapacity(Float.SIZE_BYTES * value.size)
|
||||
value.forEach { buffer.put(it) }
|
||||
}
|
||||
|
||||
private fun writeFloatArray(value: DoubleArray) {
|
||||
buffer.requestAdditionalCapacity(Double.SIZE_BYTES * value.size)
|
||||
value.forEach { buffer.put(it) }
|
||||
}
|
||||
|
||||
private inline fun writeIntegerArray(
|
||||
start: Int,
|
||||
size: Int,
|
||||
byteWidth: ByteWidth,
|
||||
crossinline valueBlock: (Int) -> ULong
|
||||
) {
|
||||
buffer.requestAdditionalCapacity(size * byteWidth.value)
|
||||
return when (byteWidth.value) {
|
||||
1 -> for (i in start until start + size) {
|
||||
buffer.put(valueBlock(i).toUByte())
|
||||
}
|
||||
2 -> for (i in start until start + size) {
|
||||
buffer.put(valueBlock(i).toUShort())
|
||||
}
|
||||
4 -> for (i in start until start + size) {
|
||||
buffer.put(valueBlock(i).toUInt())
|
||||
}
|
||||
8 -> for (i in start until start + size) {
|
||||
buffer.put(valueBlock(i))
|
||||
}
|
||||
else -> Unit
|
||||
}
|
||||
}
|
||||
|
||||
private fun writeInt(value: Int, byteWidth: ByteWidth) {
|
||||
buffer.requestAdditionalCapacity(byteWidth.value)
|
||||
when (byteWidth.value) {
|
||||
1 -> buffer.put(value.toUByte())
|
||||
2 -> buffer.put(value.toUShort())
|
||||
4 -> buffer.put(value.toUInt())
|
||||
8 -> buffer.put(value.toULong())
|
||||
else -> Unit
|
||||
}
|
||||
}
|
||||
|
||||
private fun writeInt(value: ULong, byteWidth: ByteWidth) {
|
||||
buffer.requestAdditionalCapacity(byteWidth.value)
|
||||
when(byteWidth.value) {
|
||||
1 -> buffer.put(value.toUByte())
|
||||
2 -> buffer.put(value.toUShort())
|
||||
4 -> buffer.put(value.toUInt())
|
||||
8 -> buffer.put(value)
|
||||
else -> Unit
|
||||
}
|
||||
}
|
||||
|
||||
// Align to prepare for writing a scalar with a certain size.
|
||||
// returns the amounts of bytes needed to be written.
|
||||
private fun align(alignment: BitWidth): ByteWidth {
|
||||
val byteWidth = 1 shl alignment.value
|
||||
var padBytes = paddingBytes(buffer.writePosition, byteWidth)
|
||||
buffer.requestCapacity(buffer.capacity + padBytes)
|
||||
while (padBytes-- != 0) {
|
||||
buffer.put(ZeroByte)
|
||||
}
|
||||
return ByteWidth(byteWidth)
|
||||
}
|
||||
|
||||
private fun calculateKeyVectorBitWidth(start: Int, length: Int): BitWidth {
|
||||
val bitWidth = length.toULong().widthInUBits()
|
||||
var width = bitWidth
|
||||
val prefixElems = 1
|
||||
// Check bit widths and types for all elements.
|
||||
for (i in start until stack.size) {
|
||||
val elemWidth = elemWidth(T_KEY, W_8, stack[i].key.toLong(), buffer.writePosition, i + prefixElems)
|
||||
width = width.max(elemWidth)
|
||||
}
|
||||
return width
|
||||
}
|
||||
|
||||
private fun createKeyVector(start: Int, length: Int): Value {
|
||||
// Figure out smallest bit width we can store this vector with.
|
||||
val bitWidth = calculateKeyVectorBitWidth(start, length)
|
||||
val byteWidth = align(bitWidth)
|
||||
// Write vector. First the keys width/offset if available, and size.
|
||||
writeInt(length, byteWidth)
|
||||
// Then the actual data.
|
||||
val vloc = buffer.writePosition.toULong()
|
||||
for (i in start until stack.size) {
|
||||
val pos = stack[i].key
|
||||
if (pos == -1) error("invalid position $pos for key")
|
||||
writeOffset(stack[i].key, byteWidth)
|
||||
}
|
||||
// Then the types.
|
||||
return Value(T_VECTOR_KEY, -1, bitWidth, vloc)
|
||||
}
|
||||
|
||||
private inline fun createVector(key: Int, start: Int, length: Int, keys: Value? = null): Value {
|
||||
return createAnyVector(key, start, length, T_VECTOR, keys) {
|
||||
// add types since we are not creating a typed vector.
|
||||
buffer.requestAdditionalCapacity(stack.size)
|
||||
for (i in start until stack.size) {
|
||||
buffer.put(stack[i].storedPackedType(it))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun putMap(key: Int, start: Int, length: Int, keys: Value? = null): Value {
|
||||
return createAnyVector(key, start, length, T_MAP, keys) {
|
||||
// add types since we are not creating a typed vector.
|
||||
buffer.requestAdditionalCapacity(stack.size)
|
||||
for (i in start until stack.size) {
|
||||
buffer.put(stack[i].storedPackedType(it))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private inline fun createTypedVector(key: Int, start: Int, length: Int, keys: Value? = null): Value {
|
||||
// We assume the callers of this method guarantees all elements are of the same type.
|
||||
val elementType: FlexBufferType = stack[start].type
|
||||
for (i in start + 1 until length) {
|
||||
if (elementType != stack[i].type) error("TypedVector does not support array of different element types")
|
||||
}
|
||||
if (!elementType.isTypedVectorElementType()) error("TypedVector does not support this element type")
|
||||
return createAnyVector(key, start, length, elementType.toTypedVector(), keys)
|
||||
}
|
||||
|
||||
private inline fun createAnyVector(
|
||||
key: Int,
|
||||
start: Int,
|
||||
length: Int,
|
||||
type: FlexBufferType,
|
||||
keys: Value? = null,
|
||||
crossinline typeBlock: (BitWidth) -> Unit = {}
|
||||
): Value {
|
||||
// Figure out the smallest bit width we can store this vector with.
|
||||
var bitWidth = W_8.max(length.toULong().widthInUBits())
|
||||
var prefixElems = 1
|
||||
if (keys != null) {
|
||||
// If this vector is part of a map, we will pre-fix an offset to the keys
|
||||
// to this vector.
|
||||
bitWidth = bitWidth.max(keys.elemWidth(buffer.writePosition, 0))
|
||||
prefixElems += 2
|
||||
}
|
||||
// Check bit widths and types for all elements.
|
||||
for (i in start until stack.size) {
|
||||
val elemWidth = stack[i].elemWidth(buffer.writePosition, i + prefixElems)
|
||||
bitWidth = bitWidth.max(elemWidth)
|
||||
}
|
||||
val byteWidth = align(bitWidth)
|
||||
// Write vector. First the keys width/offset if available, and size.
|
||||
if (keys != null) {
|
||||
writeOffset(keys.iValue.toInt(), byteWidth)
|
||||
writeInt(1 shl keys.minBitWidth.value, byteWidth)
|
||||
}
|
||||
// write the size
|
||||
writeInt(length, byteWidth)
|
||||
|
||||
// Then the actual data.
|
||||
val vloc: Int = buffer.writePosition
|
||||
for (i in start until stack.size) {
|
||||
writeAny(stack[i], byteWidth)
|
||||
}
|
||||
|
||||
// Optionally you can introduce the types for non-typed vector
|
||||
typeBlock(bitWidth)
|
||||
return Value(type, key, bitWidth, vloc.toULong())
|
||||
}
|
||||
|
||||
// A lambda to sort map keys
|
||||
internal val keyComparator = object : Comparator<Value> {
|
||||
override fun compare(a: Value, b: Value): Int {
|
||||
var ia: Int = a.key
|
||||
var io: Int = b.key
|
||||
var c1: Byte
|
||||
var c2: Byte
|
||||
do {
|
||||
c1 = buffer[ia]
|
||||
c2 = buffer[io]
|
||||
if (c1.toInt() == 0) return c1 - c2
|
||||
ia++
|
||||
io++
|
||||
} while (c1 == c2)
|
||||
return c1 - c2
|
||||
}
|
||||
}
|
||||
|
||||
public companion object {
|
||||
/**
|
||||
* No keys or strings will be shared
|
||||
*/
|
||||
public const val SHARE_NONE: Int = 0
|
||||
|
||||
/**
|
||||
* Keys will be shared between elements. Identical keys will only be serialized once, thus possibly saving space.
|
||||
* But serialization performance might be slower and consumes more memory.
|
||||
*/
|
||||
public const val SHARE_KEYS: Int = 1
|
||||
|
||||
/**
|
||||
* Strings will be shared between elements. Identical strings will only be serialized once, thus possibly saving space.
|
||||
* But serialization performance might be slower and consumes more memory. This is ideal if you expect many repeated
|
||||
* strings on the message.
|
||||
*/
|
||||
public const val SHARE_STRINGS: Int = 2
|
||||
|
||||
/**
|
||||
* Strings and keys will be shared between elements.
|
||||
*/
|
||||
public const val SHARE_KEYS_AND_STRINGS: Int = 3
|
||||
}
|
||||
}
|
@ -1,257 +0,0 @@
|
||||
/*
|
||||
* Copyright 2021 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.
|
||||
*/
|
||||
@file:Suppress("NOTHING_TO_INLINE")
|
||||
|
||||
package com.google.flatbuffers.kotlin
|
||||
|
||||
import kotlin.jvm.JvmInline
|
||||
|
||||
@JvmInline
|
||||
public value class BitWidth(public val value: Int) {
|
||||
public inline fun max(other: BitWidth): BitWidth = if (this.value >= other.value) this else other
|
||||
}
|
||||
|
||||
@JvmInline
|
||||
public value class ByteWidth(public val value: Int)
|
||||
|
||||
@JvmInline
|
||||
public value class FlexBufferType(public val value: Int) {
|
||||
public operator fun minus(other: FlexBufferType): FlexBufferType = FlexBufferType(this.value - other.value)
|
||||
public operator fun plus(other: FlexBufferType): FlexBufferType = FlexBufferType(this.value + other.value)
|
||||
public operator fun compareTo(other: FlexBufferType): Int = this.value - other.value
|
||||
}
|
||||
|
||||
internal operator fun Int.times(width: ByteWidth): Int = this * width.value
|
||||
internal operator fun Int.minus(width: ByteWidth): Int = this - width.value
|
||||
internal operator fun Int.plus(width: ByteWidth): Int = this + width.value
|
||||
internal operator fun Int.minus(type: FlexBufferType): Int = this - type.value
|
||||
|
||||
// Returns a Key string from the buffer starting at index [start]. Key Strings are stored as
|
||||
// C-Strings, ending with '\0'. If zero byte not found returns empty string.
|
||||
internal inline fun ReadBuffer.getKeyString(start: Int): String {
|
||||
val i = findFirst(0.toByte(), start)
|
||||
return if (i >= 0) getString(start, i - start) else ""
|
||||
}
|
||||
|
||||
// read unsigned int with size byteWidth and return as a 64-bit integer
|
||||
internal inline fun ReadBuffer.readULong(end: Int, byteWidth: ByteWidth): ULong {
|
||||
return when (byteWidth.value) {
|
||||
1 -> this.getUByte(end).toULong()
|
||||
2 -> this.getUShort(end).toULong()
|
||||
4 -> this.getUInt(end).toULong()
|
||||
8 -> this.getULong(end)
|
||||
else -> error("invalid byte width $byteWidth for scalar unsigned integer")
|
||||
}
|
||||
}
|
||||
|
||||
internal inline fun ReadBuffer.readFloat(end: Int, byteWidth: ByteWidth): Double {
|
||||
return when (byteWidth.value) {
|
||||
4 -> this.getFloat(end).toDouble()
|
||||
8 -> this.getDouble(end)
|
||||
else -> error("invalid byte width $byteWidth for floating point scalar") // we should never reach here
|
||||
}
|
||||
}
|
||||
// return position on the [ReadBuffer] of the element that the offset is pointing to
|
||||
// we assume all offset fits on a int, since ReadBuffer operates with that assumption
|
||||
internal inline fun ReadBuffer.indirect(offset: Int, byteWidth: ByteWidth): Int = offset - readInt(offset, byteWidth)
|
||||
// returns the size of an array-like element from [ReadBuffer].
|
||||
internal inline fun ReadBuffer.readSize(end: Int, byteWidth: ByteWidth) = readInt(end - byteWidth, byteWidth)
|
||||
internal inline fun ReadBuffer.readUInt(end: Int, byteWidth: ByteWidth): UInt = readULong(end, byteWidth).toUInt()
|
||||
internal inline fun ReadBuffer.readInt(end: Int, byteWidth: ByteWidth): Int = readULong(end, byteWidth).toInt()
|
||||
internal inline fun ReadBuffer.readLong(end: Int, byteWidth: ByteWidth): Long = readULong(end, byteWidth).toLong()
|
||||
|
||||
internal fun IntArray.widthInUBits(): BitWidth = arrayWidthInUBits(this.size) { this[it].toULong().widthInUBits() }
|
||||
internal fun ShortArray.widthInUBits(): BitWidth = arrayWidthInUBits(this.size) { this[it].toULong().widthInUBits() }
|
||||
internal fun LongArray.widthInUBits(): BitWidth = arrayWidthInUBits(this.size) { this[it].toULong().widthInUBits() }
|
||||
|
||||
private inline fun arrayWidthInUBits(size: Int, crossinline elemWidthBlock: (Int) -> BitWidth): BitWidth {
|
||||
// Figure out smallest bit width we can store this vector with.
|
||||
var bitWidth = W_8.max(size.toULong().widthInUBits())
|
||||
// Check bit widths and types for all elements.
|
||||
for (i in 0 until size) {
|
||||
// since we know its inline types we can just assume elmentWidth to be the value width in bits.
|
||||
bitWidth = bitWidth.max(elemWidthBlock(i))
|
||||
}
|
||||
return bitWidth
|
||||
}
|
||||
|
||||
internal fun ULong.widthInUBits(): BitWidth = when {
|
||||
this <= MAX_UBYTE_ULONG -> W_8
|
||||
this <= UShort.MAX_VALUE -> W_16
|
||||
this <= UInt.MAX_VALUE -> W_32
|
||||
else -> W_64
|
||||
}
|
||||
|
||||
// returns the number of bytes needed for padding the scalar of size scalarSize.
|
||||
internal inline fun paddingBytes(bufSize: Int, scalarSize: Int): Int = bufSize.inv() + 1 and scalarSize - 1
|
||||
|
||||
internal inline fun FlexBufferType.isInline(): Boolean = this.value <= T_FLOAT.value || this == T_BOOL
|
||||
|
||||
internal fun FlexBufferType.isScalar(): Boolean = when (this) {
|
||||
T_INT, T_UINT, T_FLOAT, T_BOOL -> true
|
||||
else -> false
|
||||
}
|
||||
|
||||
internal fun FlexBufferType.isIndirectScalar(): Boolean = when (this) {
|
||||
T_INDIRECT_INT, T_INDIRECT_UINT, T_INDIRECT_FLOAT -> true
|
||||
else -> false
|
||||
}
|
||||
|
||||
internal fun FlexBufferType.isTypedVector(): Boolean =
|
||||
this >= T_VECTOR_INT && this <= T_VECTOR_STRING_DEPRECATED || this == T_VECTOR_BOOL
|
||||
|
||||
internal fun FlexBufferType.isTypedVectorElementType(): Boolean =
|
||||
(this.value in T_INT.value..T_KEY.value) || this == T_BOOL
|
||||
|
||||
// returns the typed vector of a given scalar type.
|
||||
internal fun FlexBufferType.toTypedVector(): FlexBufferType = (this - T_INT) + T_VECTOR_INT
|
||||
// returns the element type of given typed vector.
|
||||
internal fun FlexBufferType.toElementTypedVector(): FlexBufferType = this - T_VECTOR_INT + T_INT
|
||||
|
||||
// Holds information about the elements inserted on the buffer.
|
||||
internal data class Value(
|
||||
var type: FlexBufferType = T_INT,
|
||||
var key: Int = -1,
|
||||
var minBitWidth: BitWidth = W_8,
|
||||
var iValue: ULong = 0UL, // integer value
|
||||
var dValue: Double = 0.0 // TODO(paulovap): maybe we can keep floating type on iValue as well.
|
||||
) { // float value
|
||||
|
||||
inline fun storedPackedType(parentBitWidth: BitWidth = W_8): Byte = packedType(storedWidth(parentBitWidth), type)
|
||||
|
||||
private inline fun packedType(bitWidth: BitWidth, type: FlexBufferType): Byte =
|
||||
(bitWidth.value or (type.value shl 2)).toByte()
|
||||
|
||||
private inline fun storedWidth(parentBitWidth: BitWidth): BitWidth =
|
||||
if (type.isInline()) minBitWidth.max(parentBitWidth) else minBitWidth
|
||||
|
||||
fun elemWidth(bufSize: Int, elemIndex: Int): BitWidth =
|
||||
elemWidth(type, minBitWidth, iValue.toLong(), bufSize, elemIndex)
|
||||
}
|
||||
|
||||
internal fun elemWidth(
|
||||
type: FlexBufferType,
|
||||
minBitWidth: BitWidth,
|
||||
iValue: Long,
|
||||
bufSize: Int,
|
||||
elemIndex: Int
|
||||
): BitWidth {
|
||||
if (type.isInline()) return minBitWidth
|
||||
|
||||
// We have an absolute offset, but want to store a relative offset
|
||||
// elem_index elements beyond the current buffer end. Since whether
|
||||
// the relative offset fits in a certain byte_width depends on
|
||||
// the size of the elements before it (and their alignment), we have
|
||||
// to test for each size in turn.
|
||||
// Original implementation checks for largest scalar
|
||||
// which is long unsigned int
|
||||
var byteWidth = 1
|
||||
while (byteWidth <= 32) {
|
||||
// Where are we going to write this offset?
|
||||
val offsetLoc: Int = bufSize + paddingBytes(bufSize, byteWidth) + elemIndex * byteWidth
|
||||
// Compute relative offset.
|
||||
val offset: Int = offsetLoc - iValue.toInt()
|
||||
// Does it fit?
|
||||
val bitWidth = offset.toULong().widthInUBits()
|
||||
if (1 shl bitWidth.value == byteWidth) return bitWidth
|
||||
byteWidth *= 2
|
||||
}
|
||||
return W_64
|
||||
}
|
||||
|
||||
// For debugging purposes, convert type to a human-readable string.
|
||||
internal fun FlexBufferType.typeToString(): String = when (this) {
|
||||
T_NULL -> "Null"
|
||||
T_INT -> "Int"
|
||||
T_UINT -> "UInt"
|
||||
T_FLOAT -> "Float"
|
||||
T_KEY -> "Key"
|
||||
T_STRING -> "String"
|
||||
T_INDIRECT_INT -> "IndirectInt"
|
||||
T_INDIRECT_UINT -> "IndirectUInt"
|
||||
T_INDIRECT_FLOAT -> "IndirectFloat"
|
||||
T_MAP -> "Map"
|
||||
T_VECTOR -> "Vector"
|
||||
T_VECTOR_INT -> "IntVector"
|
||||
T_VECTOR_UINT -> "UIntVector"
|
||||
T_VECTOR_FLOAT -> "FloatVector"
|
||||
T_VECTOR_KEY -> "KeyVector"
|
||||
T_VECTOR_STRING_DEPRECATED -> "StringVectorDeprecated"
|
||||
T_VECTOR_INT2 -> "Int2Vector"
|
||||
T_VECTOR_UINT2 -> "UInt2Vector"
|
||||
T_VECTOR_FLOAT2 -> "Float2Vector"
|
||||
T_VECTOR_INT3 -> "Int3Vector"
|
||||
T_VECTOR_UINT3 -> "UInt3Vector"
|
||||
T_VECTOR_FLOAT3 -> "Float3Vector"
|
||||
T_VECTOR_INT4 -> "Int4Vector"
|
||||
T_VECTOR_UINT4 -> "UInt4Vector"
|
||||
T_VECTOR_FLOAT4 -> "Float4Vector"
|
||||
T_BLOB -> "BlobVector"
|
||||
T_BOOL -> "BoolVector"
|
||||
T_VECTOR_BOOL -> "BoolVector"
|
||||
else -> "UnknownType"
|
||||
}
|
||||
|
||||
// Few repeated values used in hot path is cached here
|
||||
internal fun emptyBlob() = Blob(emptyBuffer, 1, ByteWidth(1))
|
||||
internal fun emptyVector() = Vector(emptyBuffer, 1, ByteWidth(1))
|
||||
internal fun emptyMap() = Map(ArrayReadWriteBuffer(3), 3, ByteWidth(1))
|
||||
internal fun nullReference() = Reference(emptyBuffer, 1, ByteWidth(0), T_NULL.value)
|
||||
internal fun nullKey() = Key(emptyBuffer, 1)
|
||||
|
||||
internal const val ZeroByte = 0.toByte()
|
||||
internal const val MAX_UBYTE_ULONG = 255UL
|
||||
internal const val MAX_UBYTE = 255
|
||||
internal const val MAX_USHORT = 65535
|
||||
|
||||
// value bit width possible sizes
|
||||
internal val W_8 = BitWidth(0)
|
||||
internal val W_16 = BitWidth(1)
|
||||
internal val W_32 = BitWidth(2)
|
||||
internal val W_64 = BitWidth(3)
|
||||
|
||||
// These are used as the upper 6 bits of a type field to indicate the actual type.
|
||||
internal val T_INVALID = FlexBufferType(-1)
|
||||
internal val T_NULL = FlexBufferType(0)
|
||||
internal val T_INT = FlexBufferType(1)
|
||||
internal val T_UINT = FlexBufferType(2)
|
||||
internal val T_FLOAT = FlexBufferType(3) // Types above stored inline, types below are stored in an offset.
|
||||
internal val T_KEY = FlexBufferType(4)
|
||||
internal val T_STRING = FlexBufferType(5)
|
||||
internal val T_INDIRECT_INT = FlexBufferType(6)
|
||||
internal val T_INDIRECT_UINT = FlexBufferType(7)
|
||||
internal val T_INDIRECT_FLOAT = FlexBufferType(8)
|
||||
internal val T_MAP = FlexBufferType(9)
|
||||
internal val T_VECTOR = FlexBufferType(10) // Untyped.
|
||||
internal val T_VECTOR_INT = FlexBufferType(11) // Typed any size = stores no type table).
|
||||
internal val T_VECTOR_UINT = FlexBufferType(12)
|
||||
internal val T_VECTOR_FLOAT = FlexBufferType(13)
|
||||
internal val T_VECTOR_KEY = FlexBufferType(14)
|
||||
// DEPRECATED, use FBT_VECTOR or FBT_VECTOR_KEY instead.
|
||||
// more info on https://github.com/google/flatbuffers/issues/5627.
|
||||
internal val T_VECTOR_STRING_DEPRECATED = FlexBufferType(15)
|
||||
internal val T_VECTOR_INT2 = FlexBufferType(16) // Typed tuple = no type table; no size field).
|
||||
internal val T_VECTOR_UINT2 = FlexBufferType(17)
|
||||
internal val T_VECTOR_FLOAT2 = FlexBufferType(18)
|
||||
internal val T_VECTOR_INT3 = FlexBufferType(19) // Typed triple = no type table; no size field).
|
||||
internal val T_VECTOR_UINT3 = FlexBufferType(20)
|
||||
internal val T_VECTOR_FLOAT3 = FlexBufferType(21)
|
||||
internal val T_VECTOR_INT4 = FlexBufferType(22) // Typed quad = no type table; no size field).
|
||||
internal val T_VECTOR_UINT4 = FlexBufferType(23)
|
||||
internal val T_VECTOR_FLOAT4 = FlexBufferType(24)
|
||||
internal val T_BLOB = FlexBufferType(25)
|
||||
internal val T_BOOL = FlexBufferType(26)
|
||||
internal val T_VECTOR_BOOL = FlexBufferType(36) // To Allow the same type of conversion of type to vector type
|
@ -1,420 +0,0 @@
|
||||
/*
|
||||
* Copyright 2021 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.
|
||||
*/
|
||||
@file:Suppress("NOTHING_TO_INLINE")
|
||||
|
||||
package com.google.flatbuffers.kotlin
|
||||
|
||||
public object Utf8 {
|
||||
/**
|
||||
* Returns the number of bytes in the UTF-8-encoded form of `sequence`. For a string,
|
||||
* this method is equivalent to `string.getBytes(UTF_8).length`, but is more efficient in
|
||||
* both time and space.
|
||||
*
|
||||
* @throws IllegalArgumentException if `sequence` contains ill-formed UTF-16 (unpaired
|
||||
* surrogates)
|
||||
*/
|
||||
private fun computeEncodedLength(sequence: CharSequence): Int {
|
||||
// Warning to maintainers: this implementation is highly optimized.
|
||||
val utf16Length = sequence.length
|
||||
var utf8Length = utf16Length
|
||||
var i = 0
|
||||
|
||||
// This loop optimizes for pure ASCII.
|
||||
while (i < utf16Length && sequence[i].code < 0x80) {
|
||||
i++
|
||||
}
|
||||
|
||||
// This loop optimizes for chars less than 0x800.
|
||||
while (i < utf16Length) {
|
||||
val c = sequence[i]
|
||||
if (c.code < 0x800) {
|
||||
utf8Length += 0x7f - c.code ushr 31 // branch free!
|
||||
} else {
|
||||
utf8Length += encodedLengthGeneral(sequence, i)
|
||||
break
|
||||
}
|
||||
i++
|
||||
}
|
||||
if (utf8Length < utf16Length) {
|
||||
// Necessary and sufficient condition for overflow because of maximum 3x expansion
|
||||
error("UTF-8 length does not fit in int: ${(utf8Length + (1L shl 32))}")
|
||||
}
|
||||
return utf8Length
|
||||
}
|
||||
|
||||
private fun encodedLengthGeneral(sequence: CharSequence, start: Int): Int {
|
||||
val utf16Length = sequence.length
|
||||
var utf8Length = 0
|
||||
var i = start
|
||||
while (i < utf16Length) {
|
||||
val c = sequence[i]
|
||||
if (c.code < 0x800) {
|
||||
utf8Length += 0x7f - c.code ushr 31 // branch free!
|
||||
} else {
|
||||
utf8Length += 2
|
||||
if (c.isSurrogate()) {
|
||||
// Check that we have a well-formed surrogate pair.
|
||||
val cp: Int = codePointAt(sequence, i)
|
||||
if (cp < MIN_SUPPLEMENTARY_CODE_POINT) {
|
||||
errorSurrogate(i, utf16Length)
|
||||
}
|
||||
i++
|
||||
}
|
||||
}
|
||||
i++
|
||||
}
|
||||
return utf8Length
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of bytes in the UTF-8-encoded form of `sequence`. For a string,
|
||||
* this method is equivalent to `string.getBytes(UTF_8).length`, but is more efficient in
|
||||
* both time and space.
|
||||
*
|
||||
* @throws IllegalArgumentException if `sequence` contains ill-formed UTF-16 (unpaired
|
||||
* surrogates)
|
||||
*/
|
||||
public fun encodedLength(sequence: CharSequence): Int = computeEncodedLength(sequence)
|
||||
|
||||
/**
|
||||
* Returns whether this is a single-byte codepoint (i.e., ASCII) with the form '0XXXXXXX'.
|
||||
*/
|
||||
public inline fun isOneByte(b: Byte): Boolean = b >= 0
|
||||
|
||||
/**
|
||||
* Returns whether this is a two-byte codepoint with the form 110xxxxx 0xC0..0xDF.
|
||||
*/
|
||||
public inline fun isTwoBytes(b: Byte): Boolean = b < 0xE0.toByte()
|
||||
|
||||
/**
|
||||
* Returns whether this is a three-byte codepoint with the form 1110xxxx 0xE0..0xEF.
|
||||
*/
|
||||
public inline fun isThreeBytes(b: Byte): Boolean = b < 0xF0.toByte()
|
||||
|
||||
/**
|
||||
* Returns whether this is a four-byte codepoint with the form 11110xxx 0xF0..0xF4.
|
||||
*/
|
||||
public inline fun isFourByte(b: Byte): Boolean = b < 0xF8.toByte()
|
||||
|
||||
public fun handleOneByte(byte1: Byte, resultArr: CharArray, resultPos: Int) {
|
||||
resultArr[resultPos] = byte1.toInt().toChar()
|
||||
}
|
||||
|
||||
public fun handleTwoBytes(
|
||||
byte1: Byte,
|
||||
byte2: Byte,
|
||||
resultArr: CharArray,
|
||||
resultPos: Int
|
||||
) {
|
||||
// Simultaneously checks for illegal trailing-byte in leading position (<= '11000000') and
|
||||
// overlong 2-byte, '11000001'.
|
||||
if (byte1 < 0xC2.toByte()) {
|
||||
error("Invalid UTF-8: Illegal leading byte in 2 bytes utf")
|
||||
}
|
||||
if (isNotTrailingByte(byte2)) {
|
||||
error("Invalid UTF-8: Illegal trailing byte in 2 bytes utf")
|
||||
}
|
||||
resultArr[resultPos] = (byte1.toInt() and 0x1F shl 6 or trailingByteValue(byte2)).toChar()
|
||||
}
|
||||
|
||||
public fun handleThreeBytes(
|
||||
byte1: Byte,
|
||||
byte2: Byte,
|
||||
byte3: Byte,
|
||||
resultArr: CharArray,
|
||||
resultPos: Int
|
||||
) {
|
||||
if (isNotTrailingByte(byte2) || // overlong? 5 most significant bits must not all be zero
|
||||
byte1 == 0xE0.toByte() && byte2 < 0xA0.toByte() || // check for illegal surrogate codepoints
|
||||
byte1 == 0xED.toByte() && byte2 >= 0xA0.toByte() ||
|
||||
isNotTrailingByte(byte3)
|
||||
) {
|
||||
error("Invalid UTF-8")
|
||||
}
|
||||
resultArr[resultPos] =
|
||||
(byte1.toInt() and 0x0F shl 12 or (trailingByteValue(byte2) shl 6) or trailingByteValue(byte3)).toChar()
|
||||
}
|
||||
|
||||
public fun handleFourBytes(
|
||||
byte1: Byte,
|
||||
byte2: Byte,
|
||||
byte3: Byte,
|
||||
byte4: Byte,
|
||||
resultArr: CharArray,
|
||||
resultPos: Int
|
||||
) {
|
||||
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.toInt() shl 28) + (byte2 - 0x90.toByte()) shr 30 != 0 || isNotTrailingByte(byte3) ||
|
||||
isNotTrailingByte(byte4)
|
||||
) {
|
||||
error("Invalid UTF-8")
|
||||
}
|
||||
val codepoint: Int = (
|
||||
byte1.toInt() and 0x07 shl 18
|
||||
or (trailingByteValue(byte2) shl 12)
|
||||
or (trailingByteValue(byte3) shl 6)
|
||||
or trailingByteValue(byte4)
|
||||
)
|
||||
resultArr[resultPos] = highSurrogate(codepoint)
|
||||
resultArr[resultPos + 1] = lowSurrogate(codepoint)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the byte is not a valid continuation of the form '10XXXXXX'.
|
||||
*/
|
||||
private fun isNotTrailingByte(b: Byte): Boolean = b > 0xBF.toByte()
|
||||
|
||||
/**
|
||||
* Returns the actual value of the trailing byte (removes the prefix '10') for composition.
|
||||
*/
|
||||
private fun trailingByteValue(b: Byte): Int = b.toInt() and 0x3F
|
||||
|
||||
private fun highSurrogate(codePoint: Int): Char =
|
||||
(
|
||||
Char.MIN_HIGH_SURROGATE - (MIN_SUPPLEMENTARY_CODE_POINT ushr 10) +
|
||||
(codePoint ushr 10)
|
||||
)
|
||||
|
||||
private fun lowSurrogate(codePoint: Int): Char = (Char.MIN_LOW_SURROGATE + (codePoint and 0x3ff))
|
||||
|
||||
/**
|
||||
* Encode a [CharSequence] UTF8 codepoint into a byte array.
|
||||
* @param `in` CharSequence to be encoded
|
||||
* @param start start position of the first char in the codepoint
|
||||
* @param out byte array of 4 bytes to be filled
|
||||
* @return return the amount of bytes occupied by the codepoint
|
||||
*/
|
||||
public fun encodeUtf8CodePoint(input: CharSequence, start: Int, out: ByteArray): Int {
|
||||
// utf8 codepoint needs at least 4 bytes
|
||||
val inLength = input.length
|
||||
if (start >= inLength) {
|
||||
return 0
|
||||
}
|
||||
val c = input[start]
|
||||
return if (c.code < 0x80) {
|
||||
// One byte (0xxx xxxx)
|
||||
out[0] = c.code.toByte()
|
||||
1
|
||||
} else if (c.code < 0x800) {
|
||||
// Two bytes (110x xxxx 10xx xxxx)
|
||||
out[0] = (0xC0 or (c.code ushr 6)).toByte()
|
||||
out[1] = (0x80 or (0x3F and c.code)).toByte()
|
||||
2
|
||||
} else if (c < Char.MIN_SURROGATE || Char.MAX_SURROGATE < c) {
|
||||
// Three bytes (1110 xxxx 10xx xxxx 10xx xxxx)
|
||||
// Maximum single-char code point is 0xFFFF, 16 bits.
|
||||
out[0] = (0xE0 or (c.code ushr 12)).toByte()
|
||||
out[1] = (0x80 or (0x3F and (c.code ushr 6))).toByte()
|
||||
out[2] = (0x80 or (0x3F and c.code)).toByte()
|
||||
3
|
||||
} 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
|
||||
val low: Char = input[start + 1]
|
||||
if (start + 1 == inLength || !(c.isHighSurrogate() and low.isLowSurrogate())) {
|
||||
errorSurrogate(start, inLength)
|
||||
}
|
||||
val codePoint: Int = toCodePoint(c, low)
|
||||
out[0] = (0xF shl 4 or (codePoint ushr 18)).toByte()
|
||||
out[1] = (0x80 or (0x3F and (codePoint ushr 12))).toByte()
|
||||
out[2] = (0x80 or (0x3F and (codePoint ushr 6))).toByte()
|
||||
out[3] = (0x80 or (0x3F and codePoint)).toByte()
|
||||
4
|
||||
}
|
||||
}
|
||||
|
||||
// Decodes a code point starting at index into out. Out parameter
|
||||
// should have at least 2 chars.
|
||||
public fun decodeUtf8CodePoint(bytes: ReadBuffer, index: Int, out: CharArray) {
|
||||
// Bitwise OR combines the sign bits so any negative value fails the check.
|
||||
val b1 = bytes[index]
|
||||
when {
|
||||
isOneByte(b1) -> handleOneByte(b1, out, 0)
|
||||
isTwoBytes(b1) -> handleTwoBytes(b1, bytes[index + 1], out, 0)
|
||||
isThreeBytes(b1) -> handleThreeBytes(b1, bytes[index + 1], bytes[index + 2], out, 0)
|
||||
else -> handleFourBytes(b1, bytes[index + 1], bytes[index + 2], bytes[index + 3], out, 0)
|
||||
}
|
||||
}
|
||||
|
||||
public fun decodeUtf8Array(bytes: ByteArray, index: Int = 0, size: Int = bytes.size): String {
|
||||
// Bitwise OR combines the sign bits so any negative value fails the check.
|
||||
if (index or size or bytes.size - index - size < 0) {
|
||||
error("buffer length=${bytes.size}, index=$index, size=$size")
|
||||
}
|
||||
var offset = index
|
||||
val 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.
|
||||
val resultArr = CharArray(size)
|
||||
var 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) {
|
||||
val b = bytes[offset]
|
||||
if (!isOneByte(b)) {
|
||||
break
|
||||
}
|
||||
offset++
|
||||
handleOneByte(b, resultArr, resultPos++)
|
||||
}
|
||||
while (offset < limit) {
|
||||
val byte1 = bytes[offset++]
|
||||
if (isOneByte(byte1)) {
|
||||
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) {
|
||||
val b = bytes[offset]
|
||||
if (!isOneByte(b)) {
|
||||
break
|
||||
}
|
||||
offset++
|
||||
handleOneByte(b, resultArr, resultPos++)
|
||||
}
|
||||
} else if (isTwoBytes(byte1)) {
|
||||
if (offset >= limit) {
|
||||
error("Invalid UTF-8")
|
||||
}
|
||||
handleTwoBytes(
|
||||
byte1, /* byte2 */
|
||||
bytes[offset++], resultArr, resultPos++
|
||||
)
|
||||
} else if (isThreeBytes(byte1)) {
|
||||
if (offset >= limit - 1) {
|
||||
error("Invalid UTF-8")
|
||||
}
|
||||
handleThreeBytes(
|
||||
byte1, /* byte2 */
|
||||
bytes[offset++], /* byte3 */
|
||||
bytes[offset++],
|
||||
resultArr,
|
||||
resultPos++
|
||||
)
|
||||
} else {
|
||||
if (offset >= limit - 2) {
|
||||
error("Invalid UTF-8")
|
||||
}
|
||||
handleFourBytes(
|
||||
byte1, /* byte2 */
|
||||
bytes[offset++], /* byte3 */
|
||||
bytes[offset++], /* byte4 */
|
||||
bytes[offset++],
|
||||
resultArr,
|
||||
resultPos++
|
||||
)
|
||||
// 4-byte case requires two chars.
|
||||
resultPos++
|
||||
}
|
||||
}
|
||||
return resultArr.concatToString(0, resultPos)
|
||||
}
|
||||
|
||||
public fun encodeUtf8Array(input: CharSequence,
|
||||
out: ByteArray,
|
||||
offset: Int = 0,
|
||||
length: Int = out.size - offset): Int {
|
||||
val utf16Length = input.length
|
||||
var j = offset
|
||||
var i = 0
|
||||
val limit = offset + length
|
||||
// Designed to take advantage of
|
||||
// https://wikis.oracle.com/display/HotSpotInternals/RangeCheckElimination
|
||||
|
||||
if (utf16Length == 0)
|
||||
return 0
|
||||
var cc: Char = input[i]
|
||||
while (i < utf16Length && i + j < limit && input[i].also { cc = it }.code < 0x80) {
|
||||
out[j + i] = cc.code.toByte()
|
||||
i++
|
||||
}
|
||||
if (i == utf16Length) {
|
||||
return j + utf16Length
|
||||
}
|
||||
j += i
|
||||
var c: Char
|
||||
while (i < utf16Length) {
|
||||
c = input[i]
|
||||
if (c.code < 0x80 && j < limit) {
|
||||
out[j++] = c.code.toByte()
|
||||
} else if (c.code < 0x800 && j <= limit - 2) { // 11 bits, two UTF-8 bytes
|
||||
out[j++] = (0xF shl 6 or (c.code ushr 6)).toByte()
|
||||
out[j++] = (0x80 or (0x3F and c.code)).toByte()
|
||||
} else if ((c < Char.MIN_SURROGATE || Char.MAX_SURROGATE < c) && j <= limit - 3) {
|
||||
// Maximum single-char code point is 0xFFFF, 16 bits, three UTF-8 bytes
|
||||
out[j++] = (0xF shl 5 or (c.code ushr 12)).toByte()
|
||||
out[j++] = (0x80 or (0x3F and (c.code ushr 6))).toByte()
|
||||
out[j++] = (0x80 or (0x3F and c.code)).toByte()
|
||||
} else if (j <= limit - 4) {
|
||||
// Minimum code point represented by a surrogate pair is 0x10000, 17 bits,
|
||||
// four UTF-8 bytes
|
||||
var low: Char = Char.MIN_VALUE
|
||||
if (i + 1 == input.length ||
|
||||
!isSurrogatePair(c, input[++i].also { low = it })
|
||||
) {
|
||||
errorSurrogate(i - 1, utf16Length)
|
||||
}
|
||||
val codePoint: Int = toCodePoint(c, low)
|
||||
out[j++] = (0xF shl 4 or (codePoint ushr 18)).toByte()
|
||||
out[j++] = (0x80 or (0x3F and (codePoint ushr 12))).toByte()
|
||||
out[j++] = (0x80 or (0x3F and (codePoint ushr 6))).toByte()
|
||||
out[j++] = (0x80 or (0x3F and codePoint)).toByte()
|
||||
} else {
|
||||
// If we are surrogates and we're not a surrogate pair, always throw an
|
||||
// UnpairedSurrogateException instead of an ArrayOutOfBoundsException.
|
||||
if (Char.MIN_SURROGATE <= c && c <= Char.MAX_SURROGATE &&
|
||||
(i + 1 == input.length || !isSurrogatePair(c, input[i + 1]))
|
||||
) {
|
||||
errorSurrogate(i, utf16Length)
|
||||
}
|
||||
error("Failed writing character ${c.code.toShort().toString(radix = 16)} at index $j")
|
||||
}
|
||||
i++
|
||||
}
|
||||
return j
|
||||
}
|
||||
|
||||
public fun codePointAt(seq: CharSequence, position: Int): Int {
|
||||
var index = position
|
||||
val c1 = seq[index]
|
||||
if (c1.isHighSurrogate() && ++index < seq.length) {
|
||||
val c2 = seq[index]
|
||||
if (c2.isLowSurrogate()) {
|
||||
return toCodePoint(c1, c2)
|
||||
}
|
||||
}
|
||||
return c1.code
|
||||
}
|
||||
|
||||
private fun isSurrogatePair(high: Char, low: Char) = high.isHighSurrogate() and low.isLowSurrogate()
|
||||
|
||||
private fun toCodePoint(high: Char, low: Char): Int = (high.code shl 10) + low.code +
|
||||
(MIN_SUPPLEMENTARY_CODE_POINT - (Char.MIN_HIGH_SURROGATE.code shl 10) - Char.MIN_LOW_SURROGATE.code)
|
||||
|
||||
private fun errorSurrogate(i: Int, utf16Length: Int): Unit =
|
||||
error("Unpaired surrogate at index $i of $utf16Length length")
|
||||
|
||||
// The minimum value of Unicode supplementary code point, constant `U+10000`.
|
||||
private const val MIN_SUPPLEMENTARY_CODE_POINT = 0x010000
|
||||
}
|
@ -1,832 +0,0 @@
|
||||
/*
|
||||
* Copyright 2021 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.
|
||||
*/
|
||||
@file:Suppress("NOTHING_TO_INLINE")
|
||||
|
||||
package com.google.flatbuffers.kotlin
|
||||
|
||||
import com.google.flatbuffers.kotlin.FlexBuffersBuilder.Companion.SHARE_KEYS_AND_STRINGS
|
||||
import kotlin.experimental.and
|
||||
import kotlin.jvm.JvmInline
|
||||
import kotlin.math.pow
|
||||
|
||||
/**
|
||||
* Returns a minified version of this FlexBuffer as a JSON.
|
||||
*/
|
||||
public fun Reference.toJson(): String = ArrayReadWriteBuffer(1024).let {
|
||||
toJson(it)
|
||||
val data = it.data() // it.getString(0, it.writePosition)
|
||||
return data.decodeToString(0, it.writePosition)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a minified version of this FlexBuffer as a JSON.
|
||||
* @param out [ReadWriteBuffer] the JSON will be written.
|
||||
*/
|
||||
public fun Reference.toJson(out: ReadWriteBuffer) {
|
||||
when (type) {
|
||||
T_STRING -> {
|
||||
val start = buffer.indirect(end, parentWidth)
|
||||
val size = buffer.readULong(start - byteWidth, byteWidth).toInt()
|
||||
out.jsonEscape(buffer, start, size)
|
||||
}
|
||||
T_KEY -> {
|
||||
val start = buffer.indirect(end, parentWidth)
|
||||
val end = buffer.findFirst(0.toByte(), start)
|
||||
out.jsonEscape(buffer, start, end - start)
|
||||
}
|
||||
T_BLOB -> {
|
||||
val blob = toBlob()
|
||||
out.jsonEscape(out, blob.end, blob.size)
|
||||
}
|
||||
T_INT -> out.put(toLong().toString())
|
||||
T_UINT -> out.put(toULong().toString())
|
||||
T_FLOAT -> out.put(toDouble().toString())
|
||||
T_NULL -> out.put("null")
|
||||
T_BOOL -> out.put(toBoolean().toString())
|
||||
T_MAP -> toMap().toJson(out)
|
||||
T_VECTOR, T_VECTOR_BOOL, T_VECTOR_FLOAT, T_VECTOR_INT,
|
||||
T_VECTOR_UINT, T_VECTOR_KEY, T_VECTOR_STRING_DEPRECATED -> toVector().toJson(out)
|
||||
else -> error("Unable to convert type ${type.typeToString()} to JSON")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a minified version of this FlexBuffer as a JSON.
|
||||
*/
|
||||
public fun Map.toJson(): String = ArrayReadWriteBuffer(1024).let { toJson(it); it.toString() }
|
||||
|
||||
/**
|
||||
* Returns a minified version of this FlexBuffer as a JSON.
|
||||
* @param out [ReadWriteBuffer] the JSON will be written.
|
||||
*/
|
||||
public fun Map.toJson(out: ReadWriteBuffer) {
|
||||
out.put('{'.code.toByte())
|
||||
// key values pairs
|
||||
for (i in 0 until size) {
|
||||
val key = keyAt(i)
|
||||
out.jsonEscape(buffer, key.start, key.sizeInBytes)
|
||||
out.put(':'.code.toByte())
|
||||
get(i).toJson(out)
|
||||
if (i != size - 1) {
|
||||
out.put(','.code.toByte())
|
||||
}
|
||||
}
|
||||
// close bracket
|
||||
out.put('}'.code.toByte())
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a minified version of this FlexBuffer as a JSON.
|
||||
*/
|
||||
public fun Vector.toJson(): String = ArrayReadWriteBuffer(1024).let { toJson(it); it.toString() }
|
||||
|
||||
/**
|
||||
* Returns a minified version of this FlexBuffer as a JSON.
|
||||
* @param out that the JSON is being concatenated.
|
||||
*/
|
||||
public fun Vector.toJson(out: ReadWriteBuffer) {
|
||||
out.put('['.code.toByte())
|
||||
for (i in indices) {
|
||||
get(i).toJson(out)
|
||||
if (i != size - 1) {
|
||||
out.put(','.code.toByte())
|
||||
}
|
||||
}
|
||||
out.put(']'.code.toByte())
|
||||
}
|
||||
|
||||
/**
|
||||
* JSONParser class is used to parse a JSON as FlexBuffers. Calling [JSONParser.parse] fiils [output]
|
||||
* and returns a [Reference] ready to be used.
|
||||
*/
|
||||
@ExperimentalUnsignedTypes
|
||||
public class JSONParser(public var output: FlexBuffersBuilder = FlexBuffersBuilder(1024, SHARE_KEYS_AND_STRINGS)) {
|
||||
private var readPos = 0
|
||||
private var scopes = ScopeStack()
|
||||
|
||||
/**
|
||||
* Parse a json as [String] and returns a [Reference] to a FlexBuffer.
|
||||
*/
|
||||
public fun parse(data: String): Reference = parse(ArrayReadBuffer(data.encodeToByteArray()))
|
||||
|
||||
/**
|
||||
* Parse a json as [ByteArray] and returns a [Reference] to a FlexBuffer.
|
||||
*/
|
||||
public fun parse(data: ByteArray): Reference = parse(ArrayReadBuffer(data))
|
||||
|
||||
/**
|
||||
* Parse a json as [ReadBuffer] and returns a [Reference] to a FlexBuffer.
|
||||
*/
|
||||
public fun parse(data: ReadBuffer): Reference {
|
||||
reset()
|
||||
parseValue(data, nextToken(data), null)
|
||||
if (readPos < data.limit) {
|
||||
val tok = skipWhitespace(data)
|
||||
if (tok != CHAR_EOF) {
|
||||
makeError(data, "Extraneous charaters after parse has finished", tok)
|
||||
}
|
||||
}
|
||||
output.finish()
|
||||
return getRoot(output.buffer)
|
||||
}
|
||||
|
||||
private fun parseValue(data: ReadBuffer, token: Token, key: String? = null): FlexBufferType {
|
||||
return when (token) {
|
||||
TOK_BEGIN_OBJECT -> parseObject(data, key)
|
||||
TOK_BEGIN_ARRAY -> parseArray(data, key)
|
||||
TOK_TRUE -> T_BOOL.also { output[key] = true }
|
||||
TOK_FALSE -> T_BOOL.also { output[key] = false }
|
||||
TOK_NULL -> T_NULL.also { output.putNull(key) }
|
||||
TOK_BEGIN_QUOTE -> parseString(data, key)
|
||||
TOK_NUMBER -> parseNumber(data, data.data(), key)
|
||||
else -> makeError(data, "Unexpected Character while parsing", 'x'.code.toByte())
|
||||
}
|
||||
}
|
||||
|
||||
private fun parseObject(data: ReadBuffer, key: String? = null): FlexBufferType {
|
||||
this.scopes.push(SCOPE_OBJ_EMPTY)
|
||||
|
||||
val fPos = output.startMap()
|
||||
val limit = data.limit
|
||||
while (readPos <= limit) {
|
||||
when (val tok = nextToken(data)) {
|
||||
TOK_END_OBJECT -> {
|
||||
this.scopes.pop()
|
||||
output.endMap(fPos, key); return T_MAP
|
||||
}
|
||||
TOK_BEGIN_QUOTE -> {
|
||||
val childKey = readString(data)
|
||||
parseValue(data, nextToken(data), childKey)
|
||||
}
|
||||
else -> makeError(data, "Expecting start of object key", tok)
|
||||
}
|
||||
}
|
||||
makeError(data, "Unable to parse the object", "x".toByte())
|
||||
}
|
||||
|
||||
private fun parseArray(data: ReadBuffer, key: String? = null): FlexBufferType {
|
||||
this.scopes.push(SCOPE_ARRAY_EMPTY)
|
||||
val fPos = output.startVector()
|
||||
var elementType = T_INVALID
|
||||
var multiType = false
|
||||
val limit = data.limit
|
||||
|
||||
while (readPos <= limit) {
|
||||
when (val tok = nextToken(data)) {
|
||||
TOK_END_ARRAY -> {
|
||||
this.scopes.pop()
|
||||
return if (!multiType && elementType.isScalar()) {
|
||||
output.endTypedVector(fPos, key)
|
||||
elementType.toElementTypedVector()
|
||||
} else {
|
||||
output.endVector(key, fPos)
|
||||
T_VECTOR
|
||||
}
|
||||
}
|
||||
|
||||
else -> {
|
||||
val newType = parseValue(data, tok, null)
|
||||
|
||||
if (elementType == T_INVALID) {
|
||||
elementType = newType
|
||||
} else if (newType != elementType) {
|
||||
multiType = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
makeError(data, "Unable to parse the array")
|
||||
}
|
||||
|
||||
private fun parseNumber(data: ReadBuffer, array: ByteArray, key: String?): FlexBufferType {
|
||||
val ary = array
|
||||
var cursor = readPos
|
||||
var c = data[readPos++]
|
||||
var useDouble = false
|
||||
val limit = ary.size
|
||||
var sign = 1
|
||||
var double: Double
|
||||
var long = 0L
|
||||
var digits = 0
|
||||
|
||||
if (c == CHAR_MINUS) {
|
||||
cursor++
|
||||
checkEOF(data, cursor)
|
||||
c = ary[cursor]
|
||||
sign = -1
|
||||
}
|
||||
|
||||
// peek first byte
|
||||
when (c) {
|
||||
CHAR_0 -> {
|
||||
cursor++
|
||||
if (cursor != limit) {
|
||||
c = ary[cursor]
|
||||
}
|
||||
}
|
||||
!in CHAR_0..CHAR_9 -> makeError(data, "Invalid Number", c)
|
||||
else -> {
|
||||
do {
|
||||
val digit = c - CHAR_0
|
||||
// double = 10.0 * double + digit
|
||||
long = 10 * long + digit
|
||||
digits++
|
||||
cursor++
|
||||
if (cursor == limit) break
|
||||
c = ary[cursor]
|
||||
} while (c in CHAR_0..CHAR_9)
|
||||
}
|
||||
}
|
||||
|
||||
var exponent = 0
|
||||
// If we find '.' we need to convert to double
|
||||
if (c == CHAR_DOT) {
|
||||
useDouble = true
|
||||
checkEOF(data, cursor)
|
||||
c = ary[++cursor]
|
||||
if (c < CHAR_0 || c > CHAR_9) {
|
||||
makeError(data, "Invalid Number", c)
|
||||
}
|
||||
do {
|
||||
// double = double * 10 + (tok - CHAR_0)
|
||||
long = 10 * long + (c - CHAR_0)
|
||||
digits++
|
||||
--exponent
|
||||
cursor++
|
||||
if (cursor == limit) break
|
||||
c = ary[cursor]
|
||||
} while (c in CHAR_0..CHAR_9)
|
||||
}
|
||||
|
||||
// If we find 'e' we need to convert to double
|
||||
if (c == CHAR_e || c == CHAR_E) {
|
||||
useDouble = true
|
||||
++cursor
|
||||
checkEOF(data, cursor)
|
||||
c = ary[cursor]
|
||||
var negativeExponent = false
|
||||
if (c == CHAR_MINUS) {
|
||||
++cursor
|
||||
checkEOF(data, cursor)
|
||||
negativeExponent = true
|
||||
c = ary[cursor]
|
||||
} else if (c == CHAR_PLUS) {
|
||||
++cursor
|
||||
checkEOF(data, cursor)
|
||||
c = ary[cursor]
|
||||
}
|
||||
if (c < CHAR_0 || c > CHAR_9) {
|
||||
makeError(data, "Missing exponent", c)
|
||||
}
|
||||
var exp = 0
|
||||
do {
|
||||
val digit = c - CHAR_0
|
||||
exp = 10 * exp + digit
|
||||
++cursor
|
||||
if (cursor == limit) break
|
||||
c = ary[cursor]
|
||||
} while (c in CHAR_0..CHAR_9)
|
||||
|
||||
exponent += if (negativeExponent) -exp else exp
|
||||
}
|
||||
|
||||
if (digits > 17 || exponent < -19 || exponent > 19) {
|
||||
// if the float number is not simple enough
|
||||
// we use language's Double parsing, which is slower but
|
||||
// produce more expected results for extreme numbers.
|
||||
val firstPos = readPos - 1
|
||||
val str = data.getString(firstPos, cursor - firstPos)
|
||||
if (useDouble) {
|
||||
double = str.toDouble()
|
||||
output[key] = double
|
||||
} else {
|
||||
long = str.toLong()
|
||||
output[key] = long
|
||||
}
|
||||
} else {
|
||||
// this happens on single numbers outside any object
|
||||
// or array
|
||||
if (useDouble || exponent != 0) {
|
||||
double = if (long == 0L) 0.0 else long.toDouble() * 10.0.pow(exponent)
|
||||
double *= sign
|
||||
output[key] = double
|
||||
} else {
|
||||
long *= sign
|
||||
output[key] = long
|
||||
}
|
||||
}
|
||||
readPos = cursor
|
||||
return if (useDouble) T_FLOAT else T_INT
|
||||
}
|
||||
|
||||
private fun parseString(data: ReadBuffer, key: String?): FlexBufferType {
|
||||
output[key] = readString(data)
|
||||
return T_STRING
|
||||
}
|
||||
|
||||
private fun readString(data: ReadBuffer): String {
|
||||
val limit = data.limit
|
||||
if (data is ArrayReadBuffer) {
|
||||
val ary = data.data()
|
||||
// enables range check elimination
|
||||
return readString(data, limit) { ary[it] }
|
||||
}
|
||||
return readString(data, limit) { data[it] }
|
||||
}
|
||||
|
||||
private inline fun readString(data: ReadBuffer, limit: Int, crossinline fetch: (Int) -> Byte): String {
|
||||
var cursorPos = readPos
|
||||
var foundEscape = false
|
||||
var currentChar: Byte = 0
|
||||
// we loop over every 4 bytes until find any non-plain char
|
||||
while (limit - cursorPos >= 4) {
|
||||
currentChar = fetch(cursorPos)
|
||||
if (!isPlainStringChar(currentChar)) {
|
||||
foundEscape = true
|
||||
break
|
||||
}
|
||||
currentChar = fetch(cursorPos + 1)
|
||||
if (!isPlainStringChar(currentChar)) {
|
||||
cursorPos += 1
|
||||
foundEscape = true
|
||||
break
|
||||
}
|
||||
currentChar = fetch(cursorPos + 2)
|
||||
if (!isPlainStringChar(currentChar)) {
|
||||
cursorPos += 2
|
||||
foundEscape = true
|
||||
break
|
||||
}
|
||||
currentChar = fetch(cursorPos + 3)
|
||||
if (!isPlainStringChar(currentChar)) {
|
||||
cursorPos += 3
|
||||
foundEscape = true
|
||||
break
|
||||
}
|
||||
cursorPos += 4
|
||||
}
|
||||
if (!foundEscape) {
|
||||
// if non-plain string char is not found we loop over
|
||||
// the remaining bytes
|
||||
while (true) {
|
||||
if (cursorPos >= limit) {
|
||||
error("Unexpected end of string")
|
||||
}
|
||||
currentChar = fetch(cursorPos)
|
||||
if (!isPlainStringChar(currentChar)) {
|
||||
break
|
||||
}
|
||||
++cursorPos
|
||||
}
|
||||
}
|
||||
if (currentChar == CHAR_DOUBLE_QUOTE) {
|
||||
val str = data.getString(readPos, cursorPos - readPos)
|
||||
readPos = cursorPos + 1
|
||||
return str
|
||||
}
|
||||
if (currentChar in 0..0x1f) {
|
||||
error("Illegal Codepoint")
|
||||
} else {
|
||||
// backslash or >0x7f
|
||||
return readStringSlow(data, currentChar, cursorPos)
|
||||
}
|
||||
}
|
||||
|
||||
private fun readStringSlow(data: ReadBuffer, first: Byte, lastPos: Int): String {
|
||||
var cursorPos = lastPos
|
||||
|
||||
var endOfString = lastPos
|
||||
while (true) {
|
||||
val pos = data.findFirst(CHAR_DOUBLE_QUOTE, endOfString)
|
||||
when {
|
||||
pos == -1 -> makeError(data, "Unexpected EOF, missing end of string '\"'", first)
|
||||
data[pos - 1] == CHAR_BACKSLASH && data[pos - 2] != CHAR_BACKSLASH -> {
|
||||
// here we are checking for double quotes preceded by backslash. eg \"
|
||||
// we have to look past pos -2 to make sure that the backlash is not
|
||||
// part of a previous escape, eg "\\"
|
||||
endOfString = pos + 1
|
||||
}
|
||||
else -> {
|
||||
endOfString = pos; break
|
||||
}
|
||||
}
|
||||
}
|
||||
// copy everything before the escape
|
||||
val builder = StringBuilder(data.getString(readPos, lastPos - readPos))
|
||||
while (true) {
|
||||
when (val pos = data.findFirst(CHAR_BACKSLASH, cursorPos, endOfString)) {
|
||||
-1 -> {
|
||||
val doubleQuotePos = data.findFirst(CHAR_DOUBLE_QUOTE, cursorPos)
|
||||
if (doubleQuotePos == -1) makeError(data, "Reached EOF before enclosing string", first)
|
||||
val rest = data.getString(cursorPos, doubleQuotePos - cursorPos)
|
||||
builder.append(rest)
|
||||
readPos = doubleQuotePos + 1
|
||||
return builder.toString()
|
||||
}
|
||||
|
||||
else -> {
|
||||
// we write everything up to \
|
||||
builder.append(data.getString(cursorPos, pos - cursorPos))
|
||||
val c = data[pos + 1]
|
||||
builder.append(readEscapedChar(data, c, pos))
|
||||
cursorPos = pos + if (c == CHAR_u) 6 else 2
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private inline fun isPlainStringChar(c: Byte): Boolean {
|
||||
val flags = parseFlags
|
||||
// return c in 0x20..0x7f && c != 0x22.toByte() && c != 0x5c.toByte()
|
||||
return (flags[c.toInt() and 0xFF] and 1) != 0.toByte()
|
||||
}
|
||||
|
||||
private inline fun isWhitespace(c: Byte): Boolean {
|
||||
val flags = parseFlags
|
||||
// return c == '\r'.toByte() || c == '\n'.toByte() || c == '\t'.toByte() || c == ' '.toByte()
|
||||
return (flags[c.toInt() and 0xFF] and 2) != 0.toByte()
|
||||
}
|
||||
|
||||
private fun reset() {
|
||||
readPos = 0
|
||||
output.clear()
|
||||
scopes.reset()
|
||||
}
|
||||
|
||||
private fun nextToken(data: ReadBuffer): Token {
|
||||
val scope = this.scopes.last
|
||||
|
||||
when (scope) {
|
||||
SCOPE_ARRAY_EMPTY -> this.scopes.last = SCOPE_ARRAY_FILLED
|
||||
SCOPE_ARRAY_FILLED -> {
|
||||
when (val c = skipWhitespace(data)) {
|
||||
CHAR_CLOSE_ARRAY -> return TOK_END_ARRAY
|
||||
CHAR_COMMA -> Unit
|
||||
else -> makeError(data, "Unfinished Array", c)
|
||||
}
|
||||
}
|
||||
SCOPE_OBJ_EMPTY, SCOPE_OBJ_FILLED -> {
|
||||
this.scopes.last = SCOPE_OBJ_KEY
|
||||
// Look for a comma before the next element.
|
||||
if (scope == SCOPE_OBJ_FILLED) {
|
||||
when (val c = skipWhitespace(data)) {
|
||||
CHAR_CLOSE_OBJECT -> return TOK_END_OBJECT
|
||||
CHAR_COMMA -> Unit
|
||||
else -> makeError(data, "Unfinished Object", c)
|
||||
}
|
||||
}
|
||||
return when (val c = skipWhitespace(data)) {
|
||||
CHAR_DOUBLE_QUOTE -> TOK_BEGIN_QUOTE
|
||||
CHAR_CLOSE_OBJECT -> if (scope != SCOPE_OBJ_FILLED) {
|
||||
TOK_END_OBJECT
|
||||
} else {
|
||||
makeError(data, "Expected Key", c)
|
||||
}
|
||||
else -> {
|
||||
makeError(data, "Expected Key/Value", c)
|
||||
}
|
||||
}
|
||||
}
|
||||
SCOPE_OBJ_KEY -> {
|
||||
this.scopes.last = SCOPE_OBJ_FILLED
|
||||
when (val c = skipWhitespace(data)) {
|
||||
CHAR_COLON -> Unit
|
||||
else -> makeError(data, "Expect ${CHAR_COLON.print()}", c)
|
||||
}
|
||||
}
|
||||
SCOPE_DOC_EMPTY -> this.scopes.last = SCOPE_DOC_FILLED
|
||||
SCOPE_DOC_FILLED -> {
|
||||
val c = skipWhitespace(data)
|
||||
if (c != CHAR_EOF)
|
||||
makeError(data, "Root object already finished", c)
|
||||
return TOK_EOF
|
||||
}
|
||||
}
|
||||
|
||||
val c = skipWhitespace(data)
|
||||
when (c) {
|
||||
CHAR_CLOSE_ARRAY -> if (scope == SCOPE_ARRAY_EMPTY) return TOK_END_ARRAY
|
||||
CHAR_COLON -> makeError(data, "Unexpected character", c)
|
||||
CHAR_DOUBLE_QUOTE -> return TOK_BEGIN_QUOTE
|
||||
CHAR_OPEN_ARRAY -> return TOK_BEGIN_ARRAY
|
||||
CHAR_OPEN_OBJECT -> return TOK_BEGIN_OBJECT
|
||||
CHAR_t -> {
|
||||
checkEOF(data, readPos + 2)
|
||||
// 0x65757274 is equivalent to ['t', 'r', 'u', 'e' ] as a 4 byte Int
|
||||
if (data.getInt(readPos - 1) != 0x65757274) {
|
||||
makeError(data, "Expecting keyword \"true\"", c)
|
||||
}
|
||||
readPos += 3
|
||||
return TOK_TRUE
|
||||
}
|
||||
CHAR_n -> {
|
||||
checkEOF(data, readPos + 2)
|
||||
// 0x6c6c756e is equivalent to ['n', 'u', 'l', 'l' ] as a 4 byte Int
|
||||
if (data.getInt(readPos - 1) != 0x6c6c756e) {
|
||||
makeError(data, "Expecting keyword \"null\"", c)
|
||||
}
|
||||
readPos += 3
|
||||
return TOK_NULL
|
||||
}
|
||||
CHAR_f -> {
|
||||
checkEOF(data, readPos + 3)
|
||||
// 0x65736c61 is equivalent to ['a', 'l', 's', 'e' ] as a 4 byte Int
|
||||
if (data.getInt(readPos) != 0x65736c61) {
|
||||
makeError(data, "Expecting keyword \"false\"", c)
|
||||
}
|
||||
readPos += 4
|
||||
return TOK_FALSE
|
||||
}
|
||||
CHAR_0, CHAR_1, CHAR_2, CHAR_3, CHAR_4, CHAR_5,
|
||||
CHAR_6, CHAR_7, CHAR_8, CHAR_9, CHAR_MINUS -> return TOK_NUMBER.also {
|
||||
readPos-- // rewind one position so we don't lose first digit
|
||||
}
|
||||
}
|
||||
makeError(data, "Expecting element", c)
|
||||
}
|
||||
|
||||
// keeps increasing [readPos] until finds a non-whitespace byte
|
||||
private inline fun skipWhitespace(data: ReadBuffer): Byte {
|
||||
val limit = data.limit
|
||||
if (data is ArrayReadBuffer) {
|
||||
// enables range check elimination
|
||||
val ary = data.data()
|
||||
return skipWhitespace(limit) { ary[it] }
|
||||
}
|
||||
return skipWhitespace(limit) { data[it] }
|
||||
}
|
||||
|
||||
private inline fun skipWhitespace(limit: Int, crossinline fetch: (Int) -> Byte): Byte {
|
||||
var pos = readPos
|
||||
while (pos < limit) {
|
||||
val d = fetch(pos++)
|
||||
if (!isWhitespace(d)) {
|
||||
readPos = pos
|
||||
return d
|
||||
}
|
||||
}
|
||||
readPos = limit
|
||||
return CHAR_EOF
|
||||
}
|
||||
|
||||
// byte1 is expected to be first char before `\`
|
||||
private fun readEscapedChar(data: ReadBuffer, byte1: Byte, cursorPos: Int): Char {
|
||||
return when (byte1) {
|
||||
CHAR_u -> {
|
||||
checkEOF(data, cursorPos + 1 + 4)
|
||||
var result: Char = 0.toChar()
|
||||
var i = cursorPos + 2 // cursorPos is on '\\', cursorPos + 1 is 'u'
|
||||
val end = i + 4
|
||||
while (i < end) {
|
||||
val part: Byte = data[i]
|
||||
result = (result.code shl 4).toChar()
|
||||
result += when (part) {
|
||||
in CHAR_0..CHAR_9 -> part - CHAR_0
|
||||
in CHAR_a..CHAR_f -> part - CHAR_a + 10
|
||||
in CHAR_A..CHAR_F -> part - CHAR_A + 10
|
||||
else -> makeError(data, "Invalid utf8 escaped character", -1)
|
||||
}
|
||||
i++
|
||||
}
|
||||
result
|
||||
}
|
||||
CHAR_b -> '\b'
|
||||
CHAR_t -> '\t'
|
||||
CHAR_r -> '\r'
|
||||
CHAR_n -> '\n'
|
||||
CHAR_f -> 12.toChar() // '\f'
|
||||
CHAR_DOUBLE_QUOTE, CHAR_BACKSLASH, CHAR_FORWARDSLASH -> byte1.toInt().toChar()
|
||||
else -> makeError(data, "Invalid escape sequence.", byte1)
|
||||
}
|
||||
}
|
||||
|
||||
private fun Byte.print(): String = when (this) {
|
||||
in 0x21..0x7E -> "'${this.toInt().toChar()}'" // visible ascii chars
|
||||
CHAR_EOF -> "EOF"
|
||||
else -> "'0x${this.toString(16)}'"
|
||||
}
|
||||
|
||||
private inline fun makeError(data: ReadBuffer, msg: String, tok: Byte? = null): Nothing {
|
||||
val (line, column) = calculateErrorPosition(data, readPos)
|
||||
if (tok != null) {
|
||||
error("Error At ($line, $column): $msg, got ${tok.print()}")
|
||||
} else {
|
||||
error("Error At ($line, $column): $msg")
|
||||
}
|
||||
}
|
||||
|
||||
private inline fun makeError(data: ReadBuffer, msg: String, tok: Token): Nothing {
|
||||
val (line, column) = calculateErrorPosition(data, readPos)
|
||||
error("Error At ($line, $column): $msg, got ${tok.print()}")
|
||||
}
|
||||
|
||||
private inline fun checkEOF(data: ReadBuffer, pos: Int) {
|
||||
if (pos >= data.limit)
|
||||
makeError(data, "Unexpected end of file", -1)
|
||||
}
|
||||
|
||||
private fun calculateErrorPosition(data: ReadBuffer, endPos: Int): Pair<Int, Int> {
|
||||
var line = 1
|
||||
var column = 1
|
||||
var current = 0
|
||||
while (current < endPos - 1) {
|
||||
if (data[current++] == CHAR_NEWLINE) {
|
||||
++line
|
||||
column = 1
|
||||
} else {
|
||||
++column
|
||||
}
|
||||
}
|
||||
return Pair(line, column)
|
||||
}
|
||||
}
|
||||
|
||||
internal inline fun Int.toPaddedHex(): String = "\\u${this.toString(16).padStart(4, '0')}"
|
||||
|
||||
private inline fun ReadWriteBuffer.jsonEscape(data: ReadBuffer, start: Int, size: Int) {
|
||||
val replacements = JSON_ESCAPE_CHARS
|
||||
put(CHAR_DOUBLE_QUOTE)
|
||||
var last = start
|
||||
val length: Int = size
|
||||
val ary = data.data()
|
||||
for (i in start until start + length) {
|
||||
val c = ary[i].toUByte()
|
||||
var replacement: ByteArray?
|
||||
if (c.toInt() < 128) {
|
||||
replacement = replacements[c.toInt()]
|
||||
if (replacement == null) {
|
||||
continue
|
||||
}
|
||||
} else {
|
||||
continue
|
||||
}
|
||||
if (last < i) {
|
||||
put(ary, last, i - last)
|
||||
}
|
||||
put(replacement, 0, replacement.size)
|
||||
last = i + 1
|
||||
}
|
||||
if (last < (last + length)) {
|
||||
put(ary, last, (start + length) - last)
|
||||
}
|
||||
put(CHAR_DOUBLE_QUOTE)
|
||||
}
|
||||
|
||||
// Following escape strategy defined in RFC7159.
|
||||
private val JSON_ESCAPE_CHARS: Array<ByteArray?> = arrayOfNulls<ByteArray>(128).apply {
|
||||
this['\n'.code] = "\\n".encodeToByteArray()
|
||||
this['\t'.code] = "\\t".encodeToByteArray()
|
||||
this['\r'.code] = "\\r".encodeToByteArray()
|
||||
this['\b'.code] = "\\b".encodeToByteArray()
|
||||
this[0x0c] = "\\f".encodeToByteArray()
|
||||
this['"'.code] = "\\\"".encodeToByteArray()
|
||||
this['\\'.code] = "\\\\".encodeToByteArray()
|
||||
for (i in 0..0x1f) {
|
||||
this[i] = "\\u${i.toPaddedHex()}".encodeToByteArray()
|
||||
}
|
||||
}
|
||||
|
||||
// Scope is used to the define current space that the scanner is operating.
|
||||
@JvmInline
|
||||
private value class Scope(val id: Int)
|
||||
private val SCOPE_DOC_EMPTY = Scope(0)
|
||||
private val SCOPE_DOC_FILLED = Scope(1)
|
||||
private val SCOPE_OBJ_EMPTY = Scope(2)
|
||||
private val SCOPE_OBJ_KEY = Scope(3)
|
||||
private val SCOPE_OBJ_FILLED = Scope(4)
|
||||
private val SCOPE_ARRAY_EMPTY = Scope(5)
|
||||
private val SCOPE_ARRAY_FILLED = Scope(6)
|
||||
|
||||
// Keeps the stack state of the scopes being scanned. Currently defined to have a
|
||||
// max stack size of 22, as per tests cases defined in http://json.org/JSON_checker/
|
||||
private class ScopeStack(
|
||||
private val ary: IntArray = IntArray(22) { SCOPE_DOC_EMPTY.id },
|
||||
var lastPos: Int = 0
|
||||
) {
|
||||
var last: Scope
|
||||
get() = Scope(ary[lastPos])
|
||||
set(x) {
|
||||
ary[lastPos] = x.id
|
||||
}
|
||||
|
||||
fun reset() {
|
||||
lastPos = 0
|
||||
ary[0] = SCOPE_DOC_EMPTY.id
|
||||
}
|
||||
|
||||
fun pop(): Scope {
|
||||
// println("Popping: ${last.print()}")
|
||||
return Scope(ary[lastPos--])
|
||||
}
|
||||
|
||||
fun push(scope: Scope): Scope {
|
||||
if (lastPos == ary.size - 1)
|
||||
error("Too much nesting reached. Max nesting is ${ary.size} levels")
|
||||
// println("PUSHING : ${scope.print()}")
|
||||
ary[++lastPos] = scope.id
|
||||
return scope
|
||||
}
|
||||
}
|
||||
|
||||
@JvmInline
|
||||
private value class Token(val id: Int) {
|
||||
fun print(): String = when (this) {
|
||||
TOK_EOF -> "TOK_EOF"
|
||||
TOK_NONE -> "TOK_NONE"
|
||||
TOK_BEGIN_OBJECT -> "TOK_BEGIN_OBJECT"
|
||||
TOK_END_OBJECT -> "TOK_END_OBJECT"
|
||||
TOK_BEGIN_ARRAY -> "TOK_BEGIN_ARRAY"
|
||||
TOK_END_ARRAY -> "TOK_END_ARRAY"
|
||||
TOK_NUMBER -> "TOK_NUMBER"
|
||||
TOK_TRUE -> "TOK_TRUE"
|
||||
TOK_FALSE -> "TOK_FALSE"
|
||||
TOK_NULL -> "TOK_NULL"
|
||||
TOK_BEGIN_QUOTE -> "TOK_BEGIN_QUOTE"
|
||||
else -> this.toString()
|
||||
}
|
||||
}
|
||||
|
||||
private val TOK_EOF = Token(-1)
|
||||
private val TOK_NONE = Token(0)
|
||||
private val TOK_BEGIN_OBJECT = Token(1)
|
||||
private val TOK_END_OBJECT = Token(2)
|
||||
private val TOK_BEGIN_ARRAY = Token(3)
|
||||
private val TOK_END_ARRAY = Token(4)
|
||||
private val TOK_NUMBER = Token(5)
|
||||
private val TOK_TRUE = Token(6)
|
||||
private val TOK_FALSE = Token(7)
|
||||
private val TOK_NULL = Token(8)
|
||||
private val TOK_BEGIN_QUOTE = Token(9)
|
||||
|
||||
private const val CHAR_NEWLINE = '\n'.code.toByte()
|
||||
private const val CHAR_OPEN_OBJECT = '{'.code.toByte()
|
||||
private const val CHAR_COLON = ':'.code.toByte()
|
||||
private const val CHAR_CLOSE_OBJECT = '}'.code.toByte()
|
||||
private const val CHAR_OPEN_ARRAY = '['.code.toByte()
|
||||
private const val CHAR_CLOSE_ARRAY = ']'.code.toByte()
|
||||
private const val CHAR_DOUBLE_QUOTE = '"'.code.toByte()
|
||||
private const val CHAR_BACKSLASH = '\\'.code.toByte()
|
||||
private const val CHAR_FORWARDSLASH = '/'.code.toByte()
|
||||
private const val CHAR_f = 'f'.code.toByte()
|
||||
private const val CHAR_a = 'a'.code.toByte()
|
||||
private const val CHAR_r = 'r'.code.toByte()
|
||||
private const val CHAR_t = 't'.code.toByte()
|
||||
private const val CHAR_n = 'n'.code.toByte()
|
||||
private const val CHAR_b = 'b'.code.toByte()
|
||||
private const val CHAR_e = 'e'.code.toByte()
|
||||
private const val CHAR_E = 'E'.code.toByte()
|
||||
private const val CHAR_u = 'u'.code.toByte()
|
||||
private const val CHAR_A = 'A'.code.toByte()
|
||||
private const val CHAR_F = 'F'.code.toByte()
|
||||
private const val CHAR_EOF = (-1).toByte()
|
||||
private const val CHAR_COMMA = ','.code.toByte()
|
||||
private const val CHAR_0 = '0'.code.toByte()
|
||||
private const val CHAR_1 = '1'.code.toByte()
|
||||
private const val CHAR_2 = '2'.code.toByte()
|
||||
private const val CHAR_3 = '3'.code.toByte()
|
||||
private const val CHAR_4 = '4'.code.toByte()
|
||||
private const val CHAR_5 = '5'.code.toByte()
|
||||
private const val CHAR_6 = '6'.code.toByte()
|
||||
private const val CHAR_7 = '7'.code.toByte()
|
||||
private const val CHAR_8 = '8'.code.toByte()
|
||||
private const val CHAR_9 = '9'.code.toByte()
|
||||
private const val CHAR_MINUS = '-'.code.toByte()
|
||||
private const val CHAR_PLUS = '+'.code.toByte()
|
||||
private const val CHAR_DOT = '.'.code.toByte()
|
||||
|
||||
// This template utilizes the One Definition Rule to create global arrays in a
|
||||
// header. As seen in:
|
||||
// https://github.com/chadaustin/sajson/blob/master/include/sajson.h
|
||||
// bit 0 (1) - set if: plain ASCII string character
|
||||
// bit 1 (2) - set if: whitespace
|
||||
// bit 4 (0x10) - set if: 0-9 e E .
|
||||
private val parseFlags = byteArrayOf(
|
||||
// 0 1 2 3 4 5 6 7 8 9 A B C D E F
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 2, 0, 0, // 0
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1
|
||||
3, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0x11, 1, // 2
|
||||
0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 1, 1, 1, 1, 1, 1, // 3
|
||||
1, 1, 1, 1, 1, 0x11, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, // 5
|
||||
1, 1, 1, 1, 1, 0x11, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7
|
||||
|
||||
// 128-255
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||
)
|
@ -1,55 +0,0 @@
|
||||
package com.google.flatbuffers.kotlin
|
||||
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
fun <T> assertArrayEquals(expected: Array<out T>, actual: Array<out T>) =
|
||||
assertTrue(expected contentEquals actual, arrayFailMessage(expected, actual))
|
||||
|
||||
fun assertArrayEquals(expected: IntArray, actual: IntArray) =
|
||||
assertTrue(expected contentEquals actual, arrayFailMessage(expected, actual))
|
||||
|
||||
fun assertArrayEquals(expected: ShortArray, actual: ShortArray) =
|
||||
assertTrue(expected contentEquals actual, arrayFailMessage(expected, actual))
|
||||
|
||||
fun assertArrayEquals(expected: LongArray, actual: LongArray) =
|
||||
assertTrue(expected contentEquals actual, arrayFailMessage(expected, actual))
|
||||
|
||||
fun assertArrayEquals(expected: ByteArray, actual: ByteArray) =
|
||||
assertTrue(expected contentEquals actual, arrayFailMessage(expected, actual))
|
||||
|
||||
fun assertArrayEquals(expected: DoubleArray, actual: DoubleArray) =
|
||||
assertTrue(expected contentEquals actual, arrayFailMessage(expected, actual))
|
||||
|
||||
fun assertArrayEquals(expected: FloatArray, actual: FloatArray) =
|
||||
assertTrue(expected contentEquals actual, arrayFailMessage(expected, actual))
|
||||
|
||||
fun <T> arrayFailMessage(expected: Array<out T>, actual: Array<out T>): String =
|
||||
failMessage(expected.contentToString(), actual.contentToString())
|
||||
|
||||
fun arrayFailMessage(expected: IntArray, actual: IntArray): String =
|
||||
failMessage(expected.contentToString(), actual.contentToString())
|
||||
|
||||
fun arrayFailMessage(expected: ShortArray, actual: ShortArray): String =
|
||||
failMessage(expected.contentToString(), actual.contentToString())
|
||||
|
||||
fun arrayFailMessage(expected: LongArray, actual: LongArray): String =
|
||||
failMessage(expected.contentToString(), actual.contentToString())
|
||||
|
||||
fun failMessage(expected: String, actual: String): String =
|
||||
"Expected: $expected\nActual: $actual"
|
||||
|
||||
fun arrayFailMessage(expected: FloatArray, actual: FloatArray): String {
|
||||
return "Expected: ${expected.contentToString()}\nActual: ${actual.contentToString()}"
|
||||
}
|
||||
|
||||
fun arrayFailMessage(expected: DoubleArray, actual: DoubleArray): String {
|
||||
return "Expected: ${expected.contentToString()}\nActual: ${actual.contentToString()}"
|
||||
}
|
||||
|
||||
fun arrayFailMessage(expected: BooleanArray, actual: BooleanArray): String {
|
||||
return "Expected: ${expected.contentToString()}\nActual: ${actual.contentToString()}"
|
||||
}
|
||||
|
||||
fun arrayFailMessage(expected: ByteArray, actual: ByteArray): String {
|
||||
return "Expected: ${expected.contentToString()}\nActual: ${actual.contentToString()}"
|
||||
}
|
@ -1,78 +0,0 @@
|
||||
package com.google.flatbuffers.kotlin
|
||||
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertFailsWith
|
||||
|
||||
class BuffersTest {
|
||||
|
||||
@Test
|
||||
fun readBufferStringTest() {
|
||||
val text = "Hello world!"
|
||||
val bytes = text.encodeToByteArray()
|
||||
val fullRead = ArrayReadBuffer(bytes)
|
||||
val helloRead = ArrayReadBuffer(bytes, limit = 5)
|
||||
val worldRead = fullRead.slice(6, 6)
|
||||
|
||||
assertEquals(bytes.size, fullRead.limit)
|
||||
assertEquals(text, fullRead.getString(0, fullRead.limit))
|
||||
assertEquals("Hello" , helloRead.getString(0, helloRead.limit))
|
||||
assertEquals("world!" , worldRead.getString())
|
||||
assertEquals(fullRead.getString(0, 5) , helloRead.getString(0, helloRead.limit))
|
||||
assertEquals(fullRead.getString(6, 6) , worldRead.getString(0, worldRead.limit))
|
||||
|
||||
for (i in 0 until helloRead.limit) {
|
||||
assertEquals(fullRead[i], helloRead[i])
|
||||
}
|
||||
for (i in 0 until worldRead.limit) {
|
||||
assertEquals(fullRead[6 + i], worldRead[i])
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun readWriteBufferPrimitivesTest() {
|
||||
val text = "Hello world!"
|
||||
val bytes = text.encodeToByteArray()
|
||||
val wt = ArrayReadWriteBuffer(bytes)
|
||||
wt.requestCapacity(4096)
|
||||
wt.put("Tests")
|
||||
val str1 = wt.writePosition
|
||||
assertEquals("Tests world!", wt.getString(0, bytes.size))
|
||||
assertEquals("Tests", wt.getString(0, str1))
|
||||
wt.put(Int.MAX_VALUE)
|
||||
assertEquals(Int.MAX_VALUE, wt.getInt(str1))
|
||||
|
||||
val pos = wt.writePosition
|
||||
wt.put(Double.NEGATIVE_INFINITY)
|
||||
assertEquals(Double.NEGATIVE_INFINITY, wt.getDouble(pos))
|
||||
|
||||
val jap = " are really すごい!".encodeToByteArray()
|
||||
wt.writePosition = str1
|
||||
wt.put(jap)
|
||||
assertEquals("Tests are really すごい!", wt.getString())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun readWriteBufferGrowthTest() {
|
||||
val a = ArrayReadWriteBuffer(1)
|
||||
assertEquals(1, a.capacity)
|
||||
a.put(0.toByte())
|
||||
assertEquals(1, a.capacity)
|
||||
assertFailsWith(IndexOutOfBoundsException::class) { a.put(0xFF.toShort()) }
|
||||
a.requestCapacity(8)
|
||||
a.writePosition = 0
|
||||
a.put(0xFF.toShort())
|
||||
assertEquals(8, a.capacity)
|
||||
assertEquals(0xFF, a.getShort(0))
|
||||
|
||||
a.requestCapacity(8 + 12)
|
||||
a.put(ByteArray(12) { it.toByte() })
|
||||
|
||||
// we grow as power or two, so 20 jumps to 32
|
||||
assertEquals(32, a.capacity)
|
||||
a.requestCapacity(513, false)
|
||||
assertEquals(1024, a.capacity)
|
||||
a.requestCapacity(234, false)
|
||||
assertEquals(1024, a.capacity)
|
||||
}
|
||||
}
|
@ -1,147 +0,0 @@
|
||||
/*
|
||||
* Copyright 2021 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.kotlin
|
||||
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
class ByteArrayTest {
|
||||
|
||||
@Test
|
||||
fun testByte() {
|
||||
val testSet = arrayOf(
|
||||
67.toByte() to byteArrayOf(67),
|
||||
Byte.MIN_VALUE to byteArrayOf(-128),
|
||||
Byte.MAX_VALUE to byteArrayOf(127),
|
||||
0.toByte() to byteArrayOf(0)
|
||||
)
|
||||
val data = ByteArray(1)
|
||||
testSet.forEach {
|
||||
data[0] = it.first
|
||||
assertArrayEquals(data, it.second)
|
||||
assertEquals(it.first, data[0])
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testShort() {
|
||||
val testSet = arrayOf(
|
||||
6712.toShort() to byteArrayOf(56, 26),
|
||||
Short.MIN_VALUE to byteArrayOf(0, -128),
|
||||
Short.MAX_VALUE to byteArrayOf(-1, 127),
|
||||
0.toShort() to byteArrayOf(0, 0,)
|
||||
)
|
||||
|
||||
val data = ByteArray(Short.SIZE_BYTES)
|
||||
testSet.forEach {
|
||||
data.setShort(0, it.first)
|
||||
assertArrayEquals(data, it.second)
|
||||
assertEquals(it.first, data.getShort(0))
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testInt() {
|
||||
val testSet = arrayOf(
|
||||
33333500 to byteArrayOf(-4, -96, -4, 1),
|
||||
Int.MIN_VALUE to byteArrayOf(0, 0, 0, -128),
|
||||
Int.MAX_VALUE to byteArrayOf(-1, -1, -1, 127),
|
||||
0 to byteArrayOf(0, 0, 0, 0)
|
||||
)
|
||||
val data = ByteArray(Int.SIZE_BYTES)
|
||||
testSet.forEach {
|
||||
data.setInt(0, it.first)
|
||||
assertArrayEquals(data, it.second)
|
||||
assertEquals(it.first, data.getInt(0))
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testLong() {
|
||||
val testSet = arrayOf(
|
||||
1234567123122890123L to byteArrayOf(-117, -91, 29, -23, 65, 16, 34, 17),
|
||||
-1L to byteArrayOf(-1, -1, -1, -1, -1, -1, -1, -1),
|
||||
Long.MIN_VALUE to byteArrayOf(0, 0, 0, 0, 0, 0, 0, -128),
|
||||
Long.MAX_VALUE to byteArrayOf(-1, -1, -1, -1, -1, -1, -1, 127),
|
||||
0L to byteArrayOf(0, 0, 0, 0, 0, 0, 0, 0)
|
||||
)
|
||||
val data = ByteArray(Long.SIZE_BYTES)
|
||||
testSet.forEach {
|
||||
data.setLong(0, it.first)
|
||||
assertArrayEquals(data, it.second)
|
||||
assertEquals(it.first, data.getLong(0))
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testULong() {
|
||||
val testSet = arrayOf(
|
||||
1234567123122890123UL to byteArrayOf(-117, -91, 29, -23, 65, 16, 34, 17),
|
||||
ULong.MIN_VALUE to byteArrayOf(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
(-1L).toULong() to byteArrayOf(-1, -1, -1, -1, -1, -1, -1, -1),
|
||||
0UL to byteArrayOf(0, 0, 0, 0, 0, 0, 0, 0)
|
||||
)
|
||||
val data = ByteArray(ULong.SIZE_BYTES)
|
||||
testSet.forEach {
|
||||
data.setULong(0, it.first)
|
||||
assertArrayEquals(it.second, data)
|
||||
assertEquals(it.first, data.getULong(0))
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testFloat() {
|
||||
val testSet = arrayOf(
|
||||
3545.56337f to byteArrayOf(4, -103, 93, 69),
|
||||
Float.MIN_VALUE to byteArrayOf(1, 0, 0, 0),
|
||||
Float.MAX_VALUE to byteArrayOf(-1, -1, 127, 127),
|
||||
0f to byteArrayOf(0, 0, 0, 0)
|
||||
)
|
||||
val data = ByteArray(Float.SIZE_BYTES)
|
||||
testSet.forEach {
|
||||
data.setFloat(0, it.first)
|
||||
assertArrayEquals(data, it.second)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testDouble() {
|
||||
val testSet = arrayOf(
|
||||
123456.523423423412 to byteArrayOf(88, 61, -15, 95, 8, 36, -2, 64),
|
||||
Double.MIN_VALUE to byteArrayOf(1, 0, 0, 0, 0, 0, 0, 0),
|
||||
Double.MAX_VALUE to byteArrayOf(-1, -1, -1, -1, -1, -1, -17, 127),
|
||||
0.0 to byteArrayOf(0, 0, 0, 0, 0, 0, 0, 0)
|
||||
)
|
||||
val data = ByteArray(Long.SIZE_BYTES)
|
||||
testSet.forEach {
|
||||
data.setDouble(0, it.first)
|
||||
assertArrayEquals(data, it.second)
|
||||
assertEquals(it.first, data.getDouble(0))
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testString() {
|
||||
val testSet = "∮ E⋅da = Q"
|
||||
val encoded = testSet.encodeToByteArray()
|
||||
val data = ByteArray(encoded.size)
|
||||
data.setCharSequence(0, testSet)
|
||||
assertArrayEquals(encoded, data)
|
||||
assertEquals(testSet, data.getString(0, encoded.size))
|
||||
}
|
||||
}
|
||||
|
@ -1,575 +0,0 @@
|
||||
/*
|
||||
* Copyright 2021 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.
|
||||
*/
|
||||
@file:Suppress("UNCHECKED_CAST")
|
||||
|
||||
package com.google.flatbuffers.kotlin
|
||||
|
||||
import Attacker
|
||||
import AttackerOffsetArray
|
||||
import CharacterEArray
|
||||
import dictionaryLookup.LongFloatEntry
|
||||
import dictionaryLookup.LongFloatMap
|
||||
import Movie
|
||||
import dictionaryLookup.LongFloatEntryOffsetArray
|
||||
import myGame.example.*
|
||||
import myGame.example.Test.Companion.createTest
|
||||
import optionalScalars.OptionalByte
|
||||
import optionalScalars.ScalarStuff
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
|
||||
@ExperimentalUnsignedTypes
|
||||
class FlatBufferBuilderTest {
|
||||
|
||||
@Test
|
||||
fun testSingleTable() {
|
||||
val fbb = FlatBufferBuilder()
|
||||
val name = fbb.createString("Frodo")
|
||||
val invValues = ubyteArrayOf(10u, 11u, 12u, 13u, 14u)
|
||||
val inv = Monster.createInventoryVector(fbb, invValues)
|
||||
Monster.startMonster(fbb)
|
||||
Monster.addPos(
|
||||
fbb, Vec3.createVec3(
|
||||
fbb, 1.0f, 2.0f, 3.0f, 3.0,
|
||||
Color.Green, 5.toShort(), 6.toByte()
|
||||
)
|
||||
)
|
||||
Monster.addHp(fbb, 80.toShort())
|
||||
Monster.addName(fbb, name)
|
||||
Monster.addMana(fbb, 150)
|
||||
Monster.addInventory(fbb, inv)
|
||||
Monster.addTestType(fbb, AnyE.Monster)
|
||||
Monster.addTestbool(fbb, true)
|
||||
Monster.addTesthashu32Fnv1(fbb, (Int.MAX_VALUE + 1L).toUInt())
|
||||
val root = Monster.endMonster(fbb)
|
||||
fbb.finish(root)
|
||||
|
||||
val monster = Monster.asRoot(fbb.dataBuffer())
|
||||
assertEquals(monster.name, "Frodo")
|
||||
assertEquals(monster.mana, 150.toShort())
|
||||
assertEquals(monster.hp, 80)
|
||||
|
||||
val pos = monster.pos!!
|
||||
assertEquals(monster.inventory(0), invValues[0])
|
||||
assertEquals(monster.inventory(1), invValues[1])
|
||||
assertEquals(monster.inventory(2), invValues[2])
|
||||
assertEquals(monster.inventory(3), invValues[3])
|
||||
assertEquals(pos.x, 1.0f)
|
||||
assertEquals(pos.y, 2.0f)
|
||||
assertEquals(pos.z, 3.0f)
|
||||
assertEquals(pos.test1, 3.0)
|
||||
assertEquals(pos.test2, Color.Green)
|
||||
assertEquals(pos.test3!!.a, 5.toShort())
|
||||
assertEquals(pos.test3!!.b, 6.toByte())
|
||||
|
||||
val inventoryBuffer = monster.inventoryAsBuffer()
|
||||
assertEquals(invValues.size, inventoryBuffer.limit)
|
||||
for (i in invValues.indices) {
|
||||
assertEquals(invValues[i], inventoryBuffer.getUByte(i))
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testSortedVector() {
|
||||
val fbb = FlatBufferBuilder()
|
||||
val names = arrayOf(fbb.createString("Frodo"), fbb.createString("Barney"), fbb.createString("Wilma"))
|
||||
val monsters = MonsterOffsetArray(3) {
|
||||
Monster.startMonster(fbb)
|
||||
Monster.addName(fbb, names[it])
|
||||
Monster.endMonster(fbb)
|
||||
}
|
||||
val ary = Monster.createTestarrayoftablesVector(fbb, monsters)
|
||||
Monster.startMonster(fbb)
|
||||
Monster.addName(fbb, names[0])
|
||||
Monster.addTestarrayoftables(fbb, ary)
|
||||
val root = Monster.endMonster(fbb)
|
||||
fbb.finish(root)
|
||||
val a = Monster.asRoot(fbb.dataBuffer())
|
||||
assertEquals(a.name, "Frodo")
|
||||
assertEquals(a.testarrayoftablesLength, 3)
|
||||
val monster0 = a.testarrayoftables(0)!!
|
||||
val monster1 = a.testarrayoftables(1)!!
|
||||
val monster2 = a.testarrayoftables(2)!!
|
||||
assertEquals(monster0.name, "Frodo")
|
||||
assertEquals(monster1.name, "Barney")
|
||||
assertEquals(monster2.name, "Wilma")
|
||||
|
||||
// test AsBuffer feature
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testCreateBufferVector() {
|
||||
val fbb = FlatBufferBuilder(16)
|
||||
val str = fbb.createString("MyMonster")
|
||||
val inventory = ubyteArrayOf(0u, 1u, 2u, 3u, 4u, 5u, 6u, 88u, 99u, 122u, 1u)
|
||||
val vec = Monster.createInventoryVector(fbb, inventory)
|
||||
Monster.startMonster(fbb)
|
||||
Monster.addInventory(fbb, vec)
|
||||
Monster.addName(fbb, str)
|
||||
val monster1 = Monster.endMonster(fbb)
|
||||
Monster.finishMonsterBuffer(fbb, monster1)
|
||||
val monsterObject: Monster = Monster.asRoot(fbb.dataBuffer())
|
||||
val iBuffer = monsterObject.inventoryAsBuffer()
|
||||
|
||||
assertEquals(monsterObject.inventoryLength, inventory.size)
|
||||
assertEquals(iBuffer.limit, inventory.size)
|
||||
|
||||
for (i in inventory.indices) {
|
||||
assertEquals(inventory[i], monsterObject.inventory(i))
|
||||
assertEquals(inventory[i], iBuffer.getUByte(i))
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testCreateUninitializedVector() {
|
||||
val fbb = FlatBufferBuilder(16)
|
||||
val str = fbb.createString("MyMonster")
|
||||
val inventory = byteArrayOf(10, 11, 12, 13, 14)
|
||||
val uninitializedBuffer = fbb.createUnintializedVector(1, inventory.size, 1)
|
||||
for (i in inventory) {
|
||||
uninitializedBuffer.put(i)
|
||||
}
|
||||
val vec = fbb.endVector<UByte>()
|
||||
Monster.startMonster(fbb)
|
||||
Monster.addInventory(fbb, vec)
|
||||
Monster.addName(fbb, str)
|
||||
val monster1 = Monster.endMonster(fbb)
|
||||
Monster.finishMonsterBuffer(fbb, monster1)
|
||||
val monsterObject: Monster = Monster.asRoot(fbb.dataBuffer())
|
||||
assertEquals(inventory[1].toUByte(), monsterObject.inventory(1))
|
||||
assertEquals(inventory.size, monsterObject.inventoryLength)
|
||||
val inventoryBuffer = monsterObject.inventoryAsBuffer()
|
||||
assertEquals(inventory[1].toInt().toUByte(), inventoryBuffer.getUByte(1))
|
||||
assertEquals(inventory.size, inventoryBuffer.limit)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testBuilderBasics() {
|
||||
val fbb = FlatBufferBuilder()
|
||||
val names = arrayOf(fbb.createString("Frodo"), fbb.createString("Barney"), fbb.createString("Wilma"))
|
||||
val off = Array<Offset<Monster>>(3) { Offset(0) }
|
||||
Monster.startMonster(fbb)
|
||||
Monster.addName(fbb, names[0])
|
||||
off[0] = Monster.endMonster(fbb)
|
||||
Monster.startMonster(fbb)
|
||||
Monster.addName(fbb, names[1])
|
||||
off[1] = Monster.endMonster(fbb)
|
||||
Monster.startMonster(fbb)
|
||||
Monster.addName(fbb, names[2])
|
||||
off[2] = Monster.endMonster(fbb)
|
||||
val sortMons = fbb.createSortedVectorOfTables(Monster(), off)
|
||||
|
||||
// We set up the same values as monsterdata.json:
|
||||
|
||||
val inv = Monster.createInventoryVector(fbb, byteArrayOf(0,1,2,3,4).toUByteArray())
|
||||
|
||||
val fred = fbb.createString("Fred")
|
||||
Monster.startMonster(fbb)
|
||||
Monster.addName(fbb, fred)
|
||||
val mon2 = Monster.endMonster(fbb)
|
||||
|
||||
Monster.startTest4Vector(fbb, 2)
|
||||
createTest(fbb, 10.toShort(), 20.toByte())
|
||||
createTest(fbb, 30.toShort(), 40.toByte())
|
||||
val test4 = fbb.endVector<myGame.example.Test>()
|
||||
|
||||
val strings = StringOffsetArray(2) { fbb.createString("test$it") }
|
||||
val testArrayOfString =
|
||||
Monster.createTestarrayofstringVector(fbb, strings)
|
||||
|
||||
Monster.startMonster(fbb)
|
||||
Monster.addName(fbb, names[0])
|
||||
Monster.addPos(fbb, Vec3.createVec3(
|
||||
fbb, 1.0f, 2.0f, 3.0f, 3.0,
|
||||
Color.Green, 5.toShort(), 6.toByte()
|
||||
))
|
||||
Monster.addHp(fbb, 80)
|
||||
Monster.addMana(fbb, 150)
|
||||
Monster.addInventory(fbb, inv)
|
||||
Monster.addTestType(fbb, AnyE.Monster)
|
||||
Monster.addTest(fbb, mon2.toUnion())
|
||||
Monster.addTest4(fbb, test4)
|
||||
Monster.addTestarrayofstring(fbb, testArrayOfString)
|
||||
Monster.addTestbool(fbb, true)
|
||||
Monster.addTesthashu32Fnv1(fbb, (Int.MAX_VALUE + 1L).toUInt())
|
||||
Monster.addTestarrayoftables(fbb, sortMons)
|
||||
val mon = Monster.endMonster(fbb)
|
||||
Monster.finishMonsterBuffer(fbb, mon)
|
||||
//Attempt to mutate Monster fields and check whether the buffer has been mutated properly
|
||||
// revert to original values after testing
|
||||
val monster = Monster.asRoot(fbb.dataBuffer())
|
||||
|
||||
// mana is optional and does not exist in the buffer so the mutation should fail
|
||||
// the mana field should retain its default value
|
||||
assertEquals(monster.mana, 150.toShort())
|
||||
assertEquals(monster.hp, 80)
|
||||
|
||||
// Accessing a vector of sorted by the key tables
|
||||
assertEquals(monster.testarrayoftables(0)!!.name, "Barney")
|
||||
assertEquals(monster.testarrayoftables(1)!!.name, "Frodo")
|
||||
assertEquals(monster.testarrayoftables(2)!!.name, "Wilma")
|
||||
|
||||
// Example of searching for a table by the key
|
||||
assertEquals(monster.testarrayoftablesByKey("Frodo")!!.name, "Frodo")
|
||||
assertEquals(monster.testarrayoftablesByKey("Barney")!!.name, "Barney")
|
||||
assertEquals(monster.testarrayoftablesByKey("Wilma")!!.name, "Wilma")
|
||||
|
||||
for (i in 0 until monster.inventoryLength) {
|
||||
assertEquals(monster.inventory(i), (i).toUByte())
|
||||
}
|
||||
|
||||
// get a struct field and edit one of its fields
|
||||
val pos2 = monster.pos!!
|
||||
assertEquals(pos2.x, 1.0f)
|
||||
assertEquals(pos2.test2, Color.Green)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testVectorOfUnions() {
|
||||
val fbb = FlatBufferBuilder()
|
||||
val swordAttackDamage = 1
|
||||
val attacker = Attacker.createAttacker(fbb, swordAttackDamage).toUnion()
|
||||
val attackers = UnionOffsetArray(1) { attacker }
|
||||
val characters = CharacterEArray(1)
|
||||
characters[0] = CharacterE.MuLan.value
|
||||
|
||||
Movie.finishMovieBuffer(
|
||||
fbb,
|
||||
Movie.createMovie(
|
||||
fbb,
|
||||
CharacterE.MuLan,
|
||||
attacker,
|
||||
Movie.createCharactersTypeVector(fbb, characters),
|
||||
Movie.createCharactersVector(fbb, attackers)
|
||||
)
|
||||
)
|
||||
|
||||
val movie: Movie = Movie.asRoot(fbb.dataBuffer())
|
||||
|
||||
|
||||
|
||||
assertEquals(movie.charactersTypeLength, 1)
|
||||
assertEquals(movie.charactersLength, 1)
|
||||
|
||||
assertEquals(movie.charactersType(0), CharacterE.MuLan)
|
||||
assertEquals((movie.characters(Attacker(), 0) as Attacker).swordAttackDamage, swordAttackDamage)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun TestVectorOfBytes() {
|
||||
val fbb = FlatBufferBuilder(16)
|
||||
var str = fbb.createString("ByteMonster")
|
||||
val data = ubyteArrayOf(0u, 1u, 2u, 3u, 4u, 5u, 6u, 7u, 8u, 9u)
|
||||
var offset = Monster.createInventoryVector(fbb, data)
|
||||
Monster.startMonster(fbb)
|
||||
Monster.addName(fbb, str)
|
||||
Monster.addInventory(fbb, offset)
|
||||
var monster1 = Monster.endMonster(fbb)
|
||||
Monster.finishMonsterBuffer(fbb, monster1)
|
||||
|
||||
val monsterObject = Monster.asRoot(fbb.dataBuffer())
|
||||
assertEquals("ByteMonster", monsterObject.name)
|
||||
assertEquals(data.size, monsterObject.inventoryLength)
|
||||
assertEquals(monsterObject.inventory(4), data[4])
|
||||
offset = fbb.createByteVector(data.toByteArray()) as VectorOffset<UByte> // TODO: fix me
|
||||
str = fbb.createString("ByteMonster")
|
||||
Monster.startMonster(fbb)
|
||||
Monster.addName(fbb, str)
|
||||
Monster.addInventory(fbb, offset)
|
||||
monster1 = Monster.endMonster(fbb)
|
||||
Monster.finishMonsterBuffer(fbb, monster1)
|
||||
|
||||
val monsterObject2 = Monster.asRoot(fbb.dataBuffer())
|
||||
assertEquals(monsterObject2.inventoryLength, data.size)
|
||||
for (i in data.indices) {
|
||||
assertEquals(monsterObject2.inventory(i), data[i])
|
||||
}
|
||||
fbb.clear()
|
||||
offset = fbb.createByteVector(data.toByteArray(), 3, 4) as VectorOffset<UByte>
|
||||
str = fbb.createString("ByteMonster")
|
||||
Monster.startMonster(fbb)
|
||||
Monster.addName(fbb, str)
|
||||
Monster.addInventory(fbb, offset)
|
||||
monster1 = Monster.endMonster(fbb)
|
||||
Monster.finishMonsterBuffer(fbb, monster1)
|
||||
|
||||
val monsterObject3 = Monster.asRoot(fbb.dataBuffer())
|
||||
assertEquals(monsterObject3.inventoryLength, 4)
|
||||
assertEquals(monsterObject3.inventory(0), data[3])
|
||||
fbb.clear()
|
||||
offset = Monster.createInventoryVector(fbb, data)
|
||||
str = fbb.createString("ByteMonster")
|
||||
Monster.startMonster(fbb)
|
||||
Monster.addName(fbb, str)
|
||||
Monster.addInventory(fbb, offset)
|
||||
monster1 = Monster.endMonster(fbb)
|
||||
Monster.finishMonsterBuffer(fbb, monster1)
|
||||
|
||||
val monsterObject4 = Monster.asRoot(fbb.dataBuffer())
|
||||
assertEquals(monsterObject4.inventoryLength, data.size)
|
||||
assertEquals(monsterObject4.inventory(8), 8u)
|
||||
fbb.clear()
|
||||
|
||||
val largeData = ByteArray(1024)
|
||||
offset = fbb.createByteVector(largeData) as VectorOffset<UByte> //TODO: fix me
|
||||
str = fbb.createString("ByteMonster")
|
||||
Monster.startMonster(fbb)
|
||||
Monster.addName(fbb, str)
|
||||
Monster.addInventory(fbb, offset)
|
||||
monster1 = Monster.endMonster(fbb)
|
||||
Monster.finishMonsterBuffer(fbb, monster1)
|
||||
|
||||
val monsterObject5 = Monster.asRoot(fbb.dataBuffer())
|
||||
assertEquals(monsterObject5.inventoryLength, largeData.size)
|
||||
assertEquals(monsterObject5.inventory(25), largeData[25].toUByte())
|
||||
fbb.clear()
|
||||
|
||||
var bb = ArrayReadBuffer(largeData, 512)
|
||||
offset = fbb.createByteVector(bb) as VectorOffset<UByte> //TODO: fix me
|
||||
str = fbb.createString("ByteMonster")
|
||||
Monster.startMonster(fbb)
|
||||
Monster.addName(fbb, str)
|
||||
Monster.addInventory(fbb, offset)
|
||||
monster1 = Monster.endMonster(fbb)
|
||||
Monster.finishMonsterBuffer(fbb, monster1)
|
||||
val monsterObject6 = Monster.asRoot(fbb.dataBuffer())
|
||||
assertEquals(monsterObject6.inventoryLength, 512)
|
||||
assertEquals(monsterObject6.inventory(0), largeData[0].toUByte())
|
||||
fbb.clear()
|
||||
|
||||
bb = ArrayReadBuffer(largeData, largeData.size - 216)
|
||||
val stringBuffer = ArrayReadBuffer("AlreadyBufferedString".encodeToByteArray())
|
||||
offset = fbb.createByteVector(bb) as VectorOffset<UByte> //TODO: fix me
|
||||
str = fbb.createString(stringBuffer)
|
||||
Monster.startMonster(fbb)
|
||||
Monster.addName(fbb, str)
|
||||
Monster.addInventory(fbb, offset)
|
||||
monster1 = Monster.endMonster(fbb)
|
||||
Monster.finishMonsterBuffer(fbb, monster1)
|
||||
|
||||
val monsterObject7 = Monster.asRoot(fbb.dataBuffer())
|
||||
assertEquals(monsterObject7.inventoryLength, 216)
|
||||
assertEquals("AlreadyBufferedString", monsterObject7.name)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testEnums() {
|
||||
assertEquals(Color.name(Color.Red), "Red")
|
||||
assertEquals(Color.name(Color.Blue), "Blue")
|
||||
assertEquals(AnyE.name(AnyE.None), "NONE")
|
||||
assertEquals(AnyE.name(AnyE.Monster), "Monster")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testSharedStringPool() {
|
||||
val fb = FlatBufferBuilder(1)
|
||||
val testString = "My string"
|
||||
val offset = fb.createSharedString(testString)
|
||||
for (i in 0..9) {
|
||||
assertEquals(offset, fb.createSharedString(testString))
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testScalarOptional() {
|
||||
val fbb = FlatBufferBuilder(1)
|
||||
ScalarStuff.startScalarStuff(fbb)
|
||||
var pos = ScalarStuff.endScalarStuff(fbb)
|
||||
fbb.finish(pos)
|
||||
var scalarStuff: ScalarStuff = ScalarStuff.asRoot(fbb.dataBuffer())
|
||||
assertEquals(scalarStuff.justI8, 0.toByte())
|
||||
assertEquals(scalarStuff.maybeI8, null)
|
||||
assertEquals(scalarStuff.defaultI8, 42.toByte())
|
||||
assertEquals(scalarStuff.justU8, 0u)
|
||||
assertEquals(scalarStuff.maybeU8, null)
|
||||
assertEquals(scalarStuff.defaultU8, 42u)
|
||||
assertEquals(scalarStuff.justI16, 0.toShort())
|
||||
assertEquals(scalarStuff.maybeI16, null)
|
||||
assertEquals(scalarStuff.defaultI16, 42.toShort())
|
||||
assertEquals(scalarStuff.justU16, 0u)
|
||||
assertEquals(scalarStuff.maybeU16, null)
|
||||
assertEquals(scalarStuff.defaultU16, 42u)
|
||||
assertEquals(scalarStuff.justI32, 0)
|
||||
assertEquals(scalarStuff.maybeI32, null)
|
||||
assertEquals(scalarStuff.defaultI32, 42)
|
||||
assertEquals(scalarStuff.justU32, 0u)
|
||||
assertEquals(scalarStuff.maybeU32, null)
|
||||
assertEquals(scalarStuff.defaultU32, 42u)
|
||||
assertEquals(scalarStuff.justI64, 0L)
|
||||
assertEquals(scalarStuff.maybeI64, null)
|
||||
assertEquals(scalarStuff.defaultI64, 42L)
|
||||
assertEquals(scalarStuff.justU64, 0UL)
|
||||
assertEquals(scalarStuff.maybeU64, null)
|
||||
assertEquals(scalarStuff.defaultU64, 42UL)
|
||||
assertEquals(scalarStuff.justF32, 0.0f)
|
||||
assertEquals(scalarStuff.maybeF32, null)
|
||||
assertEquals(scalarStuff.defaultF32, 42.0f)
|
||||
assertEquals(scalarStuff.justF64, 0.0)
|
||||
assertEquals(scalarStuff.maybeF64, null)
|
||||
assertEquals(scalarStuff.defaultF64, 42.0)
|
||||
assertEquals(scalarStuff.justBool, false)
|
||||
assertEquals(scalarStuff.maybeBool, null)
|
||||
assertEquals(scalarStuff.defaultBool, true)
|
||||
assertEquals(scalarStuff.justEnum, OptionalByte.None)
|
||||
assertEquals(scalarStuff.maybeEnum, null)
|
||||
assertEquals(scalarStuff.defaultEnum, OptionalByte.One)
|
||||
fbb.clear()
|
||||
ScalarStuff.startScalarStuff(fbb)
|
||||
ScalarStuff.addJustI8(fbb, 5.toByte())
|
||||
ScalarStuff.addMaybeI8(fbb, 5.toByte())
|
||||
ScalarStuff.addDefaultI8(fbb, 5.toByte())
|
||||
ScalarStuff.addJustU8(fbb, 6u)
|
||||
ScalarStuff.addMaybeU8(fbb, 6u)
|
||||
ScalarStuff.addDefaultU8(fbb, 6u)
|
||||
ScalarStuff.addJustI16(fbb, 7.toShort())
|
||||
ScalarStuff.addMaybeI16(fbb, 7.toShort())
|
||||
ScalarStuff.addDefaultI16(fbb, 7.toShort())
|
||||
ScalarStuff.addJustU16(fbb, 8u)
|
||||
ScalarStuff.addMaybeU16(fbb, 8u)
|
||||
ScalarStuff.addDefaultU16(fbb, 8u)
|
||||
ScalarStuff.addJustI32(fbb, 9)
|
||||
ScalarStuff.addMaybeI32(fbb, 9)
|
||||
ScalarStuff.addDefaultI32(fbb, 9)
|
||||
ScalarStuff.addJustU32(fbb, 10u)
|
||||
ScalarStuff.addMaybeU32(fbb, 10u)
|
||||
ScalarStuff.addDefaultU32(fbb, 10u)
|
||||
ScalarStuff.addJustI64(fbb, 11L)
|
||||
ScalarStuff.addMaybeI64(fbb, 11L)
|
||||
ScalarStuff.addDefaultI64(fbb, 11L)
|
||||
ScalarStuff.addJustU64(fbb, 12UL)
|
||||
ScalarStuff.addMaybeU64(fbb, 12UL)
|
||||
ScalarStuff.addDefaultU64(fbb, 12UL)
|
||||
ScalarStuff.addJustF32(fbb, 13.0f)
|
||||
ScalarStuff.addMaybeF32(fbb, 13.0f)
|
||||
ScalarStuff.addDefaultF32(fbb, 13.0f)
|
||||
ScalarStuff.addJustF64(fbb, 14.0)
|
||||
ScalarStuff.addMaybeF64(fbb, 14.0)
|
||||
ScalarStuff.addDefaultF64(fbb, 14.0)
|
||||
ScalarStuff.addJustBool(fbb, true)
|
||||
ScalarStuff.addMaybeBool(fbb, true)
|
||||
ScalarStuff.addDefaultBool(fbb, true)
|
||||
ScalarStuff.addJustEnum(fbb, OptionalByte.Two)
|
||||
ScalarStuff.addMaybeEnum(fbb, OptionalByte.Two)
|
||||
ScalarStuff.addDefaultEnum(fbb, OptionalByte.Two)
|
||||
pos = ScalarStuff.endScalarStuff(fbb)
|
||||
fbb.finish(pos)
|
||||
scalarStuff = ScalarStuff.asRoot(fbb.dataBuffer())
|
||||
assertEquals(scalarStuff.justI8, 5.toByte())
|
||||
assertEquals(scalarStuff.maybeI8, 5.toByte())
|
||||
assertEquals(scalarStuff.defaultI8, 5.toByte())
|
||||
assertEquals(scalarStuff.justU8, 6u)
|
||||
assertEquals(scalarStuff.maybeU8, 6u)
|
||||
assertEquals(scalarStuff.defaultU8, 6u)
|
||||
assertEquals(scalarStuff.justI16, 7.toShort())
|
||||
assertEquals(scalarStuff.maybeI16, 7.toShort())
|
||||
assertEquals(scalarStuff.defaultI16, 7.toShort())
|
||||
assertEquals(scalarStuff.justU16, 8u)
|
||||
assertEquals(scalarStuff.maybeU16, 8u)
|
||||
assertEquals(scalarStuff.defaultU16, 8u)
|
||||
assertEquals(scalarStuff.justI32, 9)
|
||||
assertEquals(scalarStuff.maybeI32, 9)
|
||||
assertEquals(scalarStuff.defaultI32, 9)
|
||||
assertEquals(scalarStuff.justU32, 10u)
|
||||
assertEquals(scalarStuff.maybeU32, 10u)
|
||||
assertEquals(scalarStuff.defaultU32, 10u)
|
||||
assertEquals(scalarStuff.justI64, 11L)
|
||||
assertEquals(scalarStuff.maybeI64, 11L)
|
||||
assertEquals(scalarStuff.defaultI64, 11L)
|
||||
assertEquals(scalarStuff.justU64, 12UL)
|
||||
assertEquals(scalarStuff.maybeU64, 12UL)
|
||||
assertEquals(scalarStuff.defaultU64, 12UL)
|
||||
assertEquals(scalarStuff.justF32, 13.0f)
|
||||
assertEquals(scalarStuff.maybeF32, 13.0f)
|
||||
assertEquals(scalarStuff.defaultF32, 13.0f)
|
||||
assertEquals(scalarStuff.justF64, 14.0)
|
||||
assertEquals(scalarStuff.maybeF64, 14.0)
|
||||
assertEquals(scalarStuff.defaultF64, 14.0)
|
||||
assertEquals(scalarStuff.justBool, true)
|
||||
assertEquals(scalarStuff.maybeBool, true)
|
||||
assertEquals(scalarStuff.defaultBool, true)
|
||||
assertEquals(scalarStuff.justEnum, OptionalByte.Two)
|
||||
assertEquals(scalarStuff.maybeEnum, OptionalByte.Two)
|
||||
assertEquals(scalarStuff.defaultEnum, OptionalByte.Two)
|
||||
}
|
||||
|
||||
// @todo Seems like nesting code generation is broken for all generators.
|
||||
// disabling test for now.
|
||||
// @Test
|
||||
// fun testNamespaceNesting() {
|
||||
// // reference / manipulate these to verify compilation
|
||||
// val fbb = FlatBufferBuilder(1)
|
||||
// TableInNestedNS.startTableInNestedNS(fbb)
|
||||
// TableInNestedNS.addFoo(fbb, 1234)
|
||||
// val nestedTableOff = TableInNestedNS.endTableInNestedNs(fbb)
|
||||
// TableInFirstNS.startTableInFirstNS(fbb)
|
||||
// TableInFirstNS.addFooTable(fbb, nestedTableOff)
|
||||
// TableInFirstNS.endTableInFirstNs(fbb)
|
||||
// }
|
||||
|
||||
@Test
|
||||
fun testNestedFlatBuffer() {
|
||||
val nestedMonsterName = "NestedMonsterName"
|
||||
val nestedMonsterHp: Short = 600
|
||||
val nestedMonsterMana: Short = 1024
|
||||
val fbb1 = FlatBufferBuilder(16)
|
||||
val str1 = fbb1.createString(nestedMonsterName)
|
||||
Monster.startMonster(fbb1)
|
||||
Monster.addName(fbb1, str1)
|
||||
Monster.addHp(fbb1, nestedMonsterHp)
|
||||
Monster.addMana(fbb1, nestedMonsterMana)
|
||||
val monster1 = Monster.endMonster(fbb1)
|
||||
Monster.finishMonsterBuffer(fbb1, monster1)
|
||||
val fbb1Bytes: ByteArray = fbb1.sizedByteArray()
|
||||
val fbb2 = FlatBufferBuilder(16)
|
||||
val str2 = fbb2.createString("My Monster")
|
||||
val nestedBuffer = Monster.createTestnestedflatbufferVector(fbb2, fbb1Bytes.toUByteArray())
|
||||
Monster.startMonster(fbb2)
|
||||
Monster.addName(fbb2, str2)
|
||||
Monster.addHp(fbb2, 50.toShort())
|
||||
Monster.addMana(fbb2, 32.toShort())
|
||||
Monster.addTestnestedflatbuffer(fbb2, nestedBuffer)
|
||||
val monster = Monster.endMonster(fbb2)
|
||||
Monster.finishMonsterBuffer(fbb2, monster)
|
||||
|
||||
// Now test the data extracted from the nested buffer
|
||||
val mons = Monster.asRoot(fbb2.dataBuffer())
|
||||
val nestedMonster = mons.testnestedflatbufferAsMonster
|
||||
assertEquals(nestedMonsterMana, nestedMonster!!.mana)
|
||||
assertEquals(nestedMonsterHp, nestedMonster.hp)
|
||||
assertEquals(nestedMonsterName, nestedMonster.name)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testDictionaryLookup() {
|
||||
val fbb = FlatBufferBuilder(16)
|
||||
val lfIndex = LongFloatEntry.createLongFloatEntry(fbb, 0, 99.0f)
|
||||
val vectorEntriesIdx = LongFloatMap.createEntriesVector(fbb, LongFloatEntryOffsetArray(1) { lfIndex })
|
||||
val rootIdx = LongFloatMap.createLongFloatMap(fbb, vectorEntriesIdx)
|
||||
LongFloatMap.finishLongFloatMapBuffer(fbb, rootIdx)
|
||||
val map: LongFloatMap = LongFloatMap.asRoot(fbb.dataBuffer())
|
||||
|
||||
assertEquals(1, map.entriesLength)
|
||||
|
||||
val e: LongFloatEntry = map.entries(0)!!
|
||||
assertEquals(0L, e.key)
|
||||
assertEquals(99.0f, e.value)
|
||||
val e2: LongFloatEntry = map.entriesByKey(0)!!
|
||||
assertEquals(0L, e2.key)
|
||||
assertEquals(99.0f, e2.value)
|
||||
}
|
||||
}
|
@ -1,302 +0,0 @@
|
||||
/*
|
||||
* Copyright 2021 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.kotlin
|
||||
|
||||
import com.google.flatbuffers.kotlin.FlexBuffersBuilder.Companion.SHARE_NONE
|
||||
import kotlin.random.Random
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
class FlexBuffersTest {
|
||||
|
||||
@Test
|
||||
fun testWriteInt() {
|
||||
val values = listOf(
|
||||
Byte.MAX_VALUE.toLong() to 3,
|
||||
Short.MAX_VALUE.toLong() to 4,
|
||||
Int.MAX_VALUE.toLong() to 6,
|
||||
Long.MAX_VALUE to 10
|
||||
)
|
||||
val builder = FlexBuffersBuilder()
|
||||
values.forEach {
|
||||
builder.clear()
|
||||
builder.put(it.first)
|
||||
val data = builder.finish()
|
||||
val ref = getRoot(data)
|
||||
// although we put a long, it is shrink to a byte
|
||||
assertEquals(it.second, data.limit)
|
||||
assertEquals(it.first, ref.toLong())
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testWriteUInt() {
|
||||
val values = listOf(
|
||||
UByte.MAX_VALUE.toULong() to 3,
|
||||
UShort.MAX_VALUE.toULong() to 4,
|
||||
UInt.MAX_VALUE.toULong() to 6,
|
||||
ULong.MAX_VALUE to 10
|
||||
)
|
||||
val builder = FlexBuffersBuilder()
|
||||
values.forEach {
|
||||
builder.clear()
|
||||
builder.put(it.first)
|
||||
val data = builder.finish()
|
||||
val ref = getRoot(data)
|
||||
// although we put a long, it is shrink to a byte
|
||||
assertEquals(it.second, data.limit)
|
||||
assertEquals(it.first, ref.toULong())
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testWriteString() {
|
||||
val text = "Ḧ̵̘́ȩ̵̐l̶̿͜l̶͚͝o̷̦̚ ̷̫̊w̴̤͊ö̸̞́r̴͎̾l̷͚̐d̶̰̍"
|
||||
val builder = FlexBuffersBuilder()
|
||||
builder.put(text)
|
||||
val data = builder.finish()
|
||||
val ref = getRoot(data)
|
||||
assertEquals(text, ref.toString())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testInt8Array() {
|
||||
val ary = intArrayOf(1, 2, 3, 4)
|
||||
val builder = FlexBuffersBuilder()
|
||||
builder.put(intArrayOf(1, 2, 3, 4))
|
||||
val data = builder.finish()
|
||||
val ref = getRoot(data)
|
||||
// although we put a long, it is shrink to a byte
|
||||
assertEquals(8, data.limit)
|
||||
assertArrayEquals(ary, ref.toIntArray())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testShortArray() {
|
||||
val builder = FlexBuffersBuilder(ArrayReadWriteBuffer(20))
|
||||
val numbers = ShortArray(10) { it.toShort() }
|
||||
builder.put(numbers)
|
||||
val data = builder.finish()
|
||||
val ref = getRoot(data)
|
||||
assertArrayEquals(numbers, ref.toShortArray())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testHugeArray() {
|
||||
val builder = FlexBuffersBuilder()
|
||||
val numbers = IntArray(1024) { it }
|
||||
builder.put(numbers)
|
||||
val data = builder.finish()
|
||||
val ref = getRoot(data)
|
||||
assertArrayEquals(numbers, ref.toIntArray())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testFloatArray() {
|
||||
val builder = FlexBuffersBuilder()
|
||||
val numbers = FloatArray(1024) { it * 0.05f }
|
||||
builder.put(numbers)
|
||||
val data = builder.finish()
|
||||
val ref = getRoot(data)
|
||||
assertArrayEquals(numbers, ref.toFloatArray())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testDoubleArray() {
|
||||
val builder = FlexBuffersBuilder()
|
||||
val numbers = DoubleArray(1024) { it * 0.0005 }
|
||||
builder.put(numbers)
|
||||
val data = builder.finish()
|
||||
val ref = getRoot(data)
|
||||
assertArrayEquals(numbers, ref.toDoubleArray())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testLongArray() {
|
||||
val ary: LongArray = longArrayOf(0, Short.MIN_VALUE.toLong(), Int.MAX_VALUE.toLong(), Long.MAX_VALUE)
|
||||
val builder = FlexBuffersBuilder()
|
||||
builder.put(ary)
|
||||
val data = builder.finish()
|
||||
val ref = getRoot(data)
|
||||
// although we put a long, it is shrink to a byte
|
||||
assertArrayEquals(ary, ref.toLongArray())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testStringArray() {
|
||||
val ary = Array(5) { "Hello world number: $it" }
|
||||
val builder = FlexBuffersBuilder(ArrayReadWriteBuffer(20), SHARE_NONE)
|
||||
builder.putVector {
|
||||
ary.forEach { put(it) }
|
||||
}
|
||||
val data = builder.finish()
|
||||
val vec = getRoot(data).toVector()
|
||||
// although we put a long, it is shrink to a byte
|
||||
assertEquals(5, vec.size)
|
||||
val stringAry = vec.map { it.toString() }.toTypedArray()
|
||||
// although we put a long, it is shrink to a byte
|
||||
assertArrayEquals(ary, stringAry)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testBlobArray() {
|
||||
val ary = ByteArray(1000) { Random.nextInt().toByte() }
|
||||
val builder = FlexBuffersBuilder()
|
||||
builder.put(ary)
|
||||
val data = builder.finish()
|
||||
val blob = getRoot(data).toBlob()
|
||||
// although we put a long, it is shrink to a byte
|
||||
assertArrayEquals(ary, blob.toByteArray())
|
||||
for (i in 0 until blob.size) {
|
||||
assertEquals(ary[i], blob[i])
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testArrays() {
|
||||
val builder = FlexBuffersBuilder()
|
||||
val ary: Array<String> = Array(5) { "Hello world number: $it" }
|
||||
val numbers = IntArray(10) { it }
|
||||
val doubles = DoubleArray(10) { it * 0.35 }
|
||||
|
||||
// add 3 level array of arrays in the following way
|
||||
// [ [ "..", ...] [ "..", ..., [ "..", ...] ] ]
|
||||
val vec = builder.startVector()
|
||||
|
||||
// [0, 1, 2, 3 ,4 ,5 ,6 ,7 ,8, 9]
|
||||
val vec1 = builder.startVector()
|
||||
numbers.forEach { builder.put(it) }
|
||||
builder.endTypedVector(vec1)
|
||||
|
||||
// [0, 2, 4, 6 , 8, 10, 12, 14, 16, 18]
|
||||
builder.putTypedVector { doubles.forEach { put(it) } }
|
||||
|
||||
// nested array
|
||||
// [ "He..", "He..", "He..", "He..", "He..", [ "He..", "He..", "He..", "He..", "He.." ] ]
|
||||
val vec3 = builder.startVector()
|
||||
ary.forEach { builder.put(it) }
|
||||
builder.putVector { ary.forEach { put("inner: $it") } }
|
||||
builder.endVector(vec3)
|
||||
|
||||
builder.endVector(vec)
|
||||
|
||||
val data = builder.finish()
|
||||
val ref = getRoot(data)
|
||||
val vecRef = getRoot(data).toVector()
|
||||
// although we put a long, it is shrink to a byte
|
||||
assertEquals(3, vecRef.size)
|
||||
|
||||
assertArrayEquals(numbers, vecRef[0].toVector().map { it.toInt() }.toIntArray())
|
||||
assertArrayEquals(doubles, ref[1].toDoubleArray())
|
||||
assertEquals("Hello world number: 4", vecRef[2][4].toString())
|
||||
assertEquals("inner: Hello world number: 4", vecRef[2][5][4].toString())
|
||||
assertEquals("inner: Hello world number: 4", ref[2][5][4].toString())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testMap() {
|
||||
val builder = FlexBuffersBuilder(shareFlag = FlexBuffersBuilder.SHARE_KEYS_AND_STRINGS)
|
||||
builder.putVector {
|
||||
put(10)
|
||||
putMap {
|
||||
this["chello"] = "world"
|
||||
this["aint"] = 10
|
||||
this["bfloat"] = 12.3
|
||||
}
|
||||
put("aString")
|
||||
}
|
||||
|
||||
val ref = getRoot(builder.finish())
|
||||
val map = ref.toVector()
|
||||
assertEquals(3, map.size)
|
||||
assertEquals(10, map[0].toInt())
|
||||
assertEquals("aString", map[2].toString())
|
||||
assertEquals("world", map[1]["chello"].toString())
|
||||
assertEquals(10, map[1]["aint"].toInt())
|
||||
assertEquals(12.3, map[1]["bfloat"].toDouble())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testMultiMap() {
|
||||
val builder = FlexBuffersBuilder(shareFlag = FlexBuffersBuilder.SHARE_KEYS_AND_STRINGS)
|
||||
builder.putMap {
|
||||
this["hello"] = "world"
|
||||
this["int"] = 10
|
||||
this["float"] = 12.3
|
||||
this["intarray"] = intArrayOf(1, 2, 3, 4, 5)
|
||||
this.putMap("myMap") {
|
||||
this["cool"] = "beans"
|
||||
}
|
||||
}
|
||||
|
||||
val ref = getRoot(builder.finish())
|
||||
val map = ref.toMap()
|
||||
assertEquals(5, map.size)
|
||||
assertEquals("world", map["hello"].toString())
|
||||
assertEquals(10, map["int"].toInt())
|
||||
assertEquals(12.3, map["float"].toDouble())
|
||||
assertArrayEquals(intArrayOf(1, 2, 3, 4, 5), map["intarray"].toIntArray())
|
||||
assertEquals("beans", ref["myMap"]["cool"].toString())
|
||||
assertEquals(true, "myMap" in map)
|
||||
assertEquals(true, "cool" in map["myMap"].toMap())
|
||||
|
||||
// testing null values
|
||||
assertEquals(true, ref["invalid_key"].isNull)
|
||||
|
||||
val keys = map.keys.toTypedArray()
|
||||
arrayOf("hello", "int", "float", "intarray", "myMap").sortedArray().forEachIndexed { i: Int, it: String ->
|
||||
assertEquals(it, keys[i].toString())
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testBigStringMap() {
|
||||
val builder = FlexBuffersBuilder(shareFlag = FlexBuffersBuilder.SHARE_KEYS_AND_STRINGS)
|
||||
|
||||
val stringKey = Array(10000) { "Ḧ̵̘́ȩ̵̐myFairlyBigKey$it" }
|
||||
val stringValue = Array(10000) { "Ḧ̵̘́ȩ̵̐myFairlyBigValue$it" }
|
||||
val hashMap = mutableMapOf<String, String>()
|
||||
val pos = builder.startMap()
|
||||
for (i in stringKey.indices) {
|
||||
builder[stringKey[i]] = stringValue[i]
|
||||
hashMap[stringKey[i]] = stringValue[i]
|
||||
}
|
||||
builder.endMap(pos)
|
||||
val ref = getRoot(builder.finish())
|
||||
val map = ref.toMap()
|
||||
val sortedKeys = stringKey.sortedArray()
|
||||
val size = map.size
|
||||
for (i in 0 until size) {
|
||||
assertEquals(sortedKeys[i], map.keyAsString(i))
|
||||
assertEquals(sortedKeys[i], map.keyAt(i).toString())
|
||||
assertEquals(hashMap[sortedKeys[i]], map[map.keyAt(i)].toString())
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testKeysAccess() {
|
||||
for (i in 1 until 1000) {
|
||||
val utf8String = "ሰማይ አይታረስ ንጉሥ አይከሰስ።$i"
|
||||
val bytes = ByteArray(Utf8.encodedLength(utf8String))
|
||||
val pos = Utf8.encodeUtf8Array(utf8String, bytes)
|
||||
val key = Key(ArrayReadWriteBuffer(bytes), 0, pos)
|
||||
assertEquals(utf8String.length, key.sizeInChars)
|
||||
for (j in utf8String.indices) {
|
||||
assertEquals(utf8String[j], key[j])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,427 +0,0 @@
|
||||
/*
|
||||
* Copyright 2021 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.kotlin
|
||||
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
class JSONTest {
|
||||
|
||||
@Test
|
||||
fun parse2Test() {
|
||||
val dataStr = """
|
||||
{ "myKey" : [1, "yay"] }
|
||||
""".trimIndent()
|
||||
val data = dataStr.encodeToByteArray()
|
||||
val buffer = ArrayReadWriteBuffer(data, writePosition = data.size)
|
||||
val parser = JSONParser()
|
||||
val root = parser.parse(buffer)
|
||||
println(root.toJson())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun parseSample() {
|
||||
val dataStr = """
|
||||
{
|
||||
"ary" : [1, 2, 3],
|
||||
"boolean_false": false,
|
||||
"boolean_true": true, "double": 1.2E33,
|
||||
"hello":"world"
|
||||
,"interesting": "value",
|
||||
|
||||
"null_value": null,
|
||||
|
||||
|
||||
"object" : {
|
||||
"field1": "hello"
|
||||
}
|
||||
}
|
||||
"""
|
||||
val data = dataStr.encodeToByteArray()
|
||||
val root = JSONParser().parse(ArrayReadWriteBuffer(data, writePosition = data.size))
|
||||
println(root.toJson())
|
||||
val map = root.toMap()
|
||||
|
||||
assertEquals(8, map.size)
|
||||
assertEquals("world", map["hello"].toString())
|
||||
assertEquals("value", map["interesting"].toString())
|
||||
assertEquals(12e32, map["double"].toDouble())
|
||||
assertArrayEquals(intArrayOf(1, 2, 3), map["ary"].toIntArray())
|
||||
assertEquals(true, map["boolean_true"].toBoolean())
|
||||
assertEquals(false, map["boolean_false"].toBoolean())
|
||||
assertEquals(true, map["null_value"].isNull)
|
||||
assertEquals("hello", map["object"]["field1"].toString())
|
||||
|
||||
val obj = map["object"]
|
||||
assertEquals(true, obj.isMap)
|
||||
assertEquals("{\"field1\":\"hello\"}", obj.toJson())
|
||||
// TODO: Kotlin Double.toString() produce different strings dependending on the platform, so on JVM
|
||||
// is 1.2E33, while on js is 1.2e+33. For now we are disabling this test.
|
||||
//
|
||||
// val minified = data.filterNot { it == ' '.toByte() || it == '\n'.toByte() }.toByteArray().decodeToString()
|
||||
// assertEquals(minified, root.toJson())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testDoubles() {
|
||||
val values = arrayOf(
|
||||
"-0.0",
|
||||
"1.0",
|
||||
"1.7976931348613157",
|
||||
"0.0",
|
||||
"-0.5",
|
||||
"3.141592653589793",
|
||||
"2.718281828459045E-3",
|
||||
"2.2250738585072014E-308",
|
||||
"4.9E-15",
|
||||
)
|
||||
val parser = JSONParser()
|
||||
assertEquals(-0.0, parser.parse(values[0]).toDouble())
|
||||
assertEquals(1.0, parser.parse(values[1]).toDouble())
|
||||
assertEquals(1.7976931348613157, parser.parse(values[2]).toDouble())
|
||||
assertEquals(0.0, parser.parse(values[3]).toDouble())
|
||||
assertEquals(-0.5, parser.parse(values[4]).toDouble())
|
||||
assertEquals(3.141592653589793, parser.parse(values[5]).toDouble())
|
||||
assertEquals(2.718281828459045e-3, parser.parse(values[6]).toDouble())
|
||||
assertEquals(2.2250738585072014E-308, parser.parse(values[7]).toDouble())
|
||||
assertEquals(4.9E-15, parser.parse(values[8]).toDouble())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testInts() {
|
||||
val values = arrayOf(
|
||||
"-0",
|
||||
"0",
|
||||
"-1",
|
||||
"${Int.MAX_VALUE}",
|
||||
"${Int.MIN_VALUE}",
|
||||
"${Long.MAX_VALUE}",
|
||||
"${Long.MIN_VALUE}",
|
||||
)
|
||||
val parser = JSONParser()
|
||||
|
||||
assertEquals(parser.parse(values[0]).toInt(), 0)
|
||||
assertEquals(parser.parse(values[1]).toInt(), 0)
|
||||
assertEquals(parser.parse(values[2]).toInt(), -1)
|
||||
assertEquals(parser.parse(values[3]).toInt(), Int.MAX_VALUE)
|
||||
assertEquals(parser.parse(values[4]).toInt(), Int.MIN_VALUE)
|
||||
assertEquals(parser.parse(values[5]).toLong(), Long.MAX_VALUE)
|
||||
assertEquals(parser.parse(values[6]).toLong(), Long.MIN_VALUE)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testBooleansAndNull() {
|
||||
val values = arrayOf(
|
||||
"true",
|
||||
"false",
|
||||
"null"
|
||||
)
|
||||
val parser = JSONParser()
|
||||
|
||||
assertEquals(true, parser.parse(values[0]).toBoolean())
|
||||
assertEquals(false, parser.parse(values[1]).toBoolean())
|
||||
assertEquals(true, parser.parse(values[2]).isNull)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testStrings() {
|
||||
val values = arrayOf(
|
||||
"\"\"",
|
||||
"\"a\"",
|
||||
"\"hello world\"",
|
||||
"\"\\\"\\\\\\/\\b\\f\\n\\r\\t cool\"",
|
||||
"\"\\u0000\"",
|
||||
"\"\\u0021\"",
|
||||
"\"hell\\u24AC\\n\\ro wor \\u0021 ld\"",
|
||||
"\"\\/_\\\\_\\\"_\\uCAFE\\uBABE\\uAB98\\uFCDE\\ubcda\\uef4A\\b\\n\\r\\t`1~!@#\$%^&*()_+-=[]{}|;:',./<>?\"",
|
||||
)
|
||||
val parser = JSONParser()
|
||||
|
||||
// empty
|
||||
var ref = parser.parse(values[0])
|
||||
assertEquals(true, ref.isString)
|
||||
assertEquals("", ref.toString())
|
||||
// a
|
||||
ref = parser.parse(values[1])
|
||||
assertEquals(true, ref.isString)
|
||||
assertEquals("a", ref.toString())
|
||||
// hello world
|
||||
ref = parser.parse(values[2])
|
||||
assertEquals(true, ref.isString)
|
||||
assertEquals("hello world", ref.toString())
|
||||
// "\\\"\\\\\\/\\b\\f\\n\\r\\t\""
|
||||
ref = parser.parse(values[3])
|
||||
assertEquals(true, ref.isString)
|
||||
assertEquals("\"\\/\b${12.toChar()}\n\r\t cool", ref.toString())
|
||||
// 0
|
||||
ref = parser.parse(values[4])
|
||||
assertEquals(true, ref.isString)
|
||||
assertEquals(0.toChar().toString(), ref.toString())
|
||||
// u0021
|
||||
ref = parser.parse(values[5])
|
||||
assertEquals(true, ref.isString)
|
||||
assertEquals(0x21.toChar().toString(), ref.toString())
|
||||
// "\"hell\\u24AC\\n\\ro wor \\u0021 ld\"",
|
||||
ref = parser.parse(values[6])
|
||||
assertEquals(true, ref.isString)
|
||||
assertEquals("hell${0x24AC.toChar()}\n\ro wor ${0x21.toChar()} ld", ref.toString())
|
||||
|
||||
ref = parser.parse(values[7])
|
||||
println(ref.toJson())
|
||||
assertEquals(true, ref.isString)
|
||||
assertEquals("/_\\_\"_쫾몾ꮘﳞ볚\b\n\r\t`1~!@#$%^&*()_+-=[]{}|;:',./<>?", ref.toString())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testUnicode() {
|
||||
// took from test/unicode_test.json
|
||||
val data = """
|
||||
{
|
||||
"name": "unicode_test",
|
||||
"testarrayofstring": [
|
||||
"Цлїςσδε",
|
||||
"フムアムカモケモ",
|
||||
"フムヤムカモケモ",
|
||||
"㊀㊁㊂㊃㊄",
|
||||
"☳☶☲",
|
||||
"𡇙𝌆"
|
||||
],
|
||||
"testarrayoftables": [
|
||||
{
|
||||
"name": "Цлїςσδε"
|
||||
},
|
||||
{
|
||||
"name": "☳☶☲"
|
||||
},
|
||||
{
|
||||
"name": "フムヤムカモケモ"
|
||||
},
|
||||
{
|
||||
"name": "㊀㊁㊂㊃㊄"
|
||||
},
|
||||
{
|
||||
"name": "フムアムカモケモ"
|
||||
},
|
||||
{
|
||||
"name": "𡇙𝌆"
|
||||
}
|
||||
]
|
||||
}
|
||||
""".trimIndent()
|
||||
val parser = JSONParser()
|
||||
val ref = parser.parse(data)
|
||||
|
||||
// name
|
||||
assertEquals(3, ref.toMap().size)
|
||||
assertEquals("unicode_test", ref["name"].toString())
|
||||
// testarrayofstring
|
||||
assertEquals(6, ref["testarrayofstring"].toVector().size)
|
||||
assertEquals("Цлїςσδε", ref["testarrayofstring"][0].toString())
|
||||
assertEquals("フムアムカモケモ", ref["testarrayofstring"][1].toString())
|
||||
assertEquals("フムヤムカモケモ", ref["testarrayofstring"][2].toString())
|
||||
assertEquals("㊀㊁㊂㊃㊄", ref["testarrayofstring"][3].toString())
|
||||
assertEquals("☳☶☲", ref["testarrayofstring"][4].toString())
|
||||
assertEquals("𡇙𝌆", ref["testarrayofstring"][5].toString())
|
||||
// testarrayoftables
|
||||
assertEquals(6, ref["testarrayoftables"].toVector().size)
|
||||
assertEquals("Цлїςσδε", ref["testarrayoftables"][0]["name"].toString())
|
||||
assertEquals("☳☶☲", ref["testarrayoftables"][1]["name"].toString())
|
||||
assertEquals("フムヤムカモケモ", ref["testarrayoftables"][2]["name"].toString())
|
||||
assertEquals("㊀㊁㊂㊃㊄", ref["testarrayoftables"][3]["name"].toString())
|
||||
assertEquals("フムアムカモケモ", ref["testarrayoftables"][4]["name"].toString())
|
||||
assertEquals("𡇙𝌆", ref["testarrayoftables"][5]["name"].toString())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testArrays() {
|
||||
val values = arrayOf(
|
||||
"[]",
|
||||
"[1]",
|
||||
"[0,1, 2,3 , 4 ]",
|
||||
"[1.0, 2.2250738585072014E-308, 4.9E-320]",
|
||||
"[1.0, 2, \"hello world\"] ",
|
||||
"[ 1.1, 2, [ \"hello\" ] ]",
|
||||
"[[[1]]]"
|
||||
)
|
||||
val parser = JSONParser()
|
||||
|
||||
// empty
|
||||
var ref = parser.parse(values[0])
|
||||
assertEquals(true, ref.isVector)
|
||||
assertEquals(0, parser.parse(values[0]).toVector().size)
|
||||
// single
|
||||
ref = parser.parse(values[1])
|
||||
assertEquals(true, ref.isTypedVector)
|
||||
assertEquals(1, ref[0].toInt())
|
||||
// ints
|
||||
ref = parser.parse(values[2])
|
||||
assertEquals(true, ref.isTypedVector)
|
||||
assertEquals(T_VECTOR_INT, ref.type)
|
||||
assertEquals(5, ref.toVector().size)
|
||||
for (i in 0..4) {
|
||||
assertEquals(i, ref[i].toInt())
|
||||
}
|
||||
// floats
|
||||
ref = parser.parse(values[3])
|
||||
assertEquals(true, ref.isTypedVector)
|
||||
assertEquals(T_VECTOR_FLOAT, ref.type)
|
||||
assertEquals(3, ref.toVector().size)
|
||||
assertEquals(1.0, ref[0].toDouble())
|
||||
assertEquals(2.2250738585072014E-308, ref[1].toDouble())
|
||||
assertEquals(4.9E-320, ref[2].toDouble())
|
||||
// mixed
|
||||
ref = parser.parse(values[4])
|
||||
assertEquals(false, ref.isTypedVector)
|
||||
assertEquals(T_VECTOR, ref.type)
|
||||
assertEquals(1.0, ref[0].toDouble())
|
||||
assertEquals(2, ref[1].toInt())
|
||||
assertEquals("hello world", ref[2].toString())
|
||||
// nester array
|
||||
ref = parser.parse(values[5])
|
||||
assertEquals(false, ref.isTypedVector)
|
||||
assertEquals(T_VECTOR, ref.type)
|
||||
assertEquals(1.1, ref[0].toDouble())
|
||||
assertEquals(2, ref[1].toInt())
|
||||
assertEquals("hello", ref[2][0].toString())
|
||||
}
|
||||
|
||||
/**
|
||||
* Several test cases provided by json.org
|
||||
* For more details, see: http://json.org/JSON_checker/, with only
|
||||
* one exception. Single strings are considered accepted, whereas on
|
||||
* the test suit is should fail.
|
||||
*/
|
||||
@Test
|
||||
fun testParseMustFail() {
|
||||
val failList = listOf(
|
||||
"[\"Unclosed array\"",
|
||||
"{unquoted_key: \"keys must be quoted\"}",
|
||||
"[\"extra comma\",]",
|
||||
"[\"double extra comma\",,]",
|
||||
"[ , \"<-- missing value\"]",
|
||||
"[\"Comma after the close\"],",
|
||||
"[\"Extra close\"]]",
|
||||
"{\"Extra comma\": true,}",
|
||||
"{\"Extra value after close\": true} \"misplaced quoted value\"",
|
||||
"{\"Illegal expression\": 1 + 2}",
|
||||
"{\"Illegal invocation\": alert()}",
|
||||
"{\"Numbers cannot have leading zeroes\": 013}",
|
||||
"{\"Numbers cannot be hex\": 0x14}",
|
||||
"[\"Illegal backslash escape: \\x15\"]",
|
||||
"[\\naked]",
|
||||
"[\"Illegal backslash escape: \\017\"]",
|
||||
"[[[[[[[[[[[[[[[[[[[[[[[\"Too deep\"]]]]]]]]]]]]]]]]]]]]]]]",
|
||||
"{\"Missing colon\" null}",
|
||||
"{\"Double colon\":: null}",
|
||||
"{\"Comma instead of colon\", null}",
|
||||
"[\"Colon instead of comma\": false]",
|
||||
"[\"Bad value\", truth]",
|
||||
"['single quote']",
|
||||
"[\"\ttab\tcharacter\tin\tstring\t\"]",
|
||||
"[\"tab\\ character\\ in\\ string\\ \"]",
|
||||
"[\"line\nbreak\"]",
|
||||
"[\"line\\\nbreak\"]",
|
||||
"[0e]",
|
||||
"[0e+]",
|
||||
"[0e+-1]",
|
||||
"{\"Comma instead if closing brace\": true,",
|
||||
"[\"mismatch\"}"
|
||||
)
|
||||
for (data in failList) {
|
||||
try {
|
||||
JSONParser().parse(ArrayReadBuffer(data.encodeToByteArray()))
|
||||
assertTrue(false, "SHOULD NOT PASS: $data")
|
||||
} catch (e: IllegalStateException) {
|
||||
println("FAIL $e")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testParseMustPass() {
|
||||
val passList = listOf(
|
||||
"[\n" +
|
||||
" \"JSON Test Pattern pass1\",\n" +
|
||||
" {\"object with 1 member\":[\"array with 1 element\"]},\n" +
|
||||
" {},\n" +
|
||||
" [],\n" +
|
||||
" -42,\n" +
|
||||
" true,\n" +
|
||||
" false,\n" +
|
||||
" null,\n" +
|
||||
" {\n" +
|
||||
" \"integer\": 1234567890,\n" +
|
||||
" \"real\": -9876.543210,\n" +
|
||||
" \"e\": 0.123456789e-12,\n" +
|
||||
" \"E\": 1.234567890E+34,\n" +
|
||||
" \"\": 23456789012E66,\n" +
|
||||
" \"zero\": 0,\n" +
|
||||
" \"one\": 1,\n" +
|
||||
" \"space\": \" \",\n" +
|
||||
" \"quote\": \"\\\"\",\n" +
|
||||
" \"backslash\": \"\\\\\",\n" +
|
||||
" \"controls\": \"\\b\\f\\n\\r\\t\",\n" +
|
||||
" \"slash\": \"/ & \\/\",\n" +
|
||||
" \"alpha\": \"abcdefghijklmnopqrstuvwyz\",\n" +
|
||||
" \"ALPHA\": \"ABCDEFGHIJKLMNOPQRSTUVWYZ\",\n" +
|
||||
" \"digit\": \"0123456789\",\n" +
|
||||
" \"0123456789\": \"digit\",\n" +
|
||||
" \"special\": \"`1~!@#\$%^&*()_+-={':[,]}|;.</>?\",\n" +
|
||||
" \"hex\": \"\\u0123\\u4567\\u89AB\\uCDEF\\uabcd\\uef4A\",\n" +
|
||||
" \"true\": true,\n" +
|
||||
" \"false\": false,\n" +
|
||||
" \"null\": null,\n" +
|
||||
" \"array\":[ ],\n" +
|
||||
" \"object\":{ },\n" +
|
||||
" \"address\": \"50 St. James Street\",\n" +
|
||||
" \"url\": \"http://www.JSON.org/\",\n" +
|
||||
" \"comment\": \"// /* <!-- --\",\n" +
|
||||
" \"# -- --> */\": \" \",\n" +
|
||||
" \" s p a c e d \" :[1,2 , 3\n" +
|
||||
"\n" +
|
||||
",\n" +
|
||||
"\n" +
|
||||
"4 , 5 , 6 ,7 ],\"compact\":[1,2,3,4,5,6,7],\n" +
|
||||
" \"jsontext\": \"{\\\"object with 1 member\\\":[\\\"array with 1 element\\\"]}\",\n" +
|
||||
" \"quotes\": \"" \\u0022 %22 0x22 034 "\",\n" +
|
||||
" \"\\/\\\\\\\"\\uCAFE\\uBABE\\uAB98\\uFCDE\\ubcda\\uef4A\\b\\f\\n\\r\\t`1~!@#\$%^&*()_+-=[]{}|;:',./<>?\"\n" +
|
||||
": \"A key can be any string\"\n" +
|
||||
" },\n" +
|
||||
" 0.5 ,98.6\n" +
|
||||
",\n" +
|
||||
"99.44\n" +
|
||||
",\n" +
|
||||
"\n" +
|
||||
"1066,\n" +
|
||||
"1e1,\n" +
|
||||
"0.1e1,\n" +
|
||||
"1e-1,\n" +
|
||||
"1e00,2e+00,2e-00\n" +
|
||||
",\"rosebud\"]",
|
||||
"{\n" +
|
||||
" \"JSON Test Pattern pass3\": {\n" +
|
||||
" \"The outermost value\": \"must be an object or array.\",\n" +
|
||||
" \"In this test\": \"It is an object.\"\n" +
|
||||
" }\n" +
|
||||
"}",
|
||||
"[[[[[[[[[[[[[[[[[[[\"Not too deep\"]]]]]]]]]]]]]]]]]]]",
|
||||
)
|
||||
for (data in passList) {
|
||||
JSONParser().parse(ArrayReadBuffer(data.encodeToByteArray()))
|
||||
}
|
||||
}
|
||||
}
|
@ -1,41 +0,0 @@
|
||||
/*
|
||||
* Copyright 2021 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.
|
||||
*/
|
||||
@file:Suppress("NOTHING_TO_INLINE")
|
||||
|
||||
package com.google.flatbuffers.kotlin
|
||||
|
||||
/**
|
||||
* This implementation uses Little Endian order.
|
||||
*/
|
||||
public actual inline fun ByteArray.getUByte(index: Int): UByte = ByteArrayOps.getUByte(this, index)
|
||||
public actual inline fun ByteArray.getShort(index: Int): Short = ByteArrayOps.getShort(this, index)
|
||||
public actual inline fun ByteArray.getUShort(index: Int): UShort = ByteArrayOps.getUShort(this, index)
|
||||
public actual inline fun ByteArray.getInt(index: Int): Int = ByteArrayOps.getInt(this, index)
|
||||
public actual inline fun ByteArray.getUInt(index: Int): UInt = ByteArrayOps.getUInt(this, index)
|
||||
public actual inline fun ByteArray.getLong(index: Int): Long = ByteArrayOps.getLong(this, index)
|
||||
public actual inline fun ByteArray.getULong(index: Int): ULong = ByteArrayOps.getULong(this, index)
|
||||
public actual inline fun ByteArray.getFloat(index: Int): Float = ByteArrayOps.getFloat(this, index)
|
||||
public actual inline fun ByteArray.getDouble(index: Int): Double = ByteArrayOps.getDouble(this, index)
|
||||
|
||||
public actual inline fun ByteArray.setUByte(index: Int, value: UByte): Unit = ByteArrayOps.setUByte(this, index, value)
|
||||
public actual inline fun ByteArray.setShort(index: Int, value: Short): Unit = ByteArrayOps.setShort(this, index, value)
|
||||
public actual inline fun ByteArray.setUShort(index: Int, value: UShort): Unit = ByteArrayOps.setUShort(this, index, value)
|
||||
public actual inline fun ByteArray.setInt(index: Int, value: Int): Unit = ByteArrayOps.setInt(this, index, value)
|
||||
public actual inline fun ByteArray.setUInt(index: Int, value: UInt): Unit = ByteArrayOps.setUInt(this, index, value)
|
||||
public actual inline fun ByteArray.setLong(index: Int, value: Long): Unit = ByteArrayOps.setLong(this, index, value)
|
||||
public actual inline fun ByteArray.setULong(index: Int, value: ULong): Unit = ByteArrayOps.setULong(this, index, value)
|
||||
public actual inline fun ByteArray.setFloat(index: Int, value: Float): Unit = ByteArrayOps.setFloat(this, index, value)
|
||||
public actual inline fun ByteArray.setDouble(index: Int, value: Double): Unit = ByteArrayOps.setDouble(this, index, value)
|
@ -1,43 +0,0 @@
|
||||
/*
|
||||
* Copyright 2021 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.
|
||||
*/
|
||||
|
||||
@file:JvmName("JVMByteArray")
|
||||
@file:Suppress("NOTHING_TO_INLINE")
|
||||
|
||||
package com.google.flatbuffers.kotlin
|
||||
|
||||
/**
|
||||
* This implementation uses Little Endian order.
|
||||
*/
|
||||
public actual inline fun ByteArray.getUByte(index: Int): UByte = ByteArrayOps.getUByte(this, index)
|
||||
public actual inline fun ByteArray.getShort(index: Int): Short = ByteArrayOps.getShort(this, index)
|
||||
public actual inline fun ByteArray.getUShort(index: Int): UShort = ByteArrayOps.getUShort(this, index)
|
||||
public actual inline fun ByteArray.getInt(index: Int): Int = ByteArrayOps.getInt(this, index)
|
||||
public actual inline fun ByteArray.getUInt(index: Int): UInt = ByteArrayOps.getUInt(this, index)
|
||||
public actual inline fun ByteArray.getLong(index: Int): Long = ByteArrayOps.getLong(this, index)
|
||||
public actual inline fun ByteArray.getULong(index: Int): ULong = ByteArrayOps.getULong(this, index)
|
||||
public actual inline fun ByteArray.getFloat(index: Int): Float = ByteArrayOps.getFloat(this, index)
|
||||
public actual inline fun ByteArray.getDouble(index: Int): Double = ByteArrayOps.getDouble(this, index)
|
||||
|
||||
public actual inline fun ByteArray.setUByte(index: Int, value: UByte): Unit = ByteArrayOps.setUByte(this, index, value)
|
||||
public actual inline fun ByteArray.setShort(index: Int, value: Short): Unit = ByteArrayOps.setShort(this, index, value)
|
||||
public actual inline fun ByteArray.setUShort(index: Int, value: UShort): Unit = ByteArrayOps.setUShort(this, index, value)
|
||||
public actual inline fun ByteArray.setInt(index: Int, value: Int): Unit = ByteArrayOps.setInt(this, index, value)
|
||||
public actual inline fun ByteArray.setUInt(index: Int, value: UInt): Unit = ByteArrayOps.setUInt(this, index, value)
|
||||
public actual inline fun ByteArray.setLong(index: Int, value: Long): Unit = ByteArrayOps.setLong(this, index, value)
|
||||
public actual inline fun ByteArray.setULong(index: Int, value: ULong): Unit = ByteArrayOps.setULong(this, index, value)
|
||||
public actual inline fun ByteArray.setFloat(index: Int, value: Float): Unit = ByteArrayOps.setFloat(this, index, value)
|
||||
public actual inline fun ByteArray.setDouble(index: Int, value: Double): Unit = ByteArrayOps.setDouble(this, index, value)
|
@ -1,40 +0,0 @@
|
||||
/*
|
||||
* Copyright 2021 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.kotlin
|
||||
|
||||
import org.junit.Test
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
class Utf8Test {
|
||||
|
||||
@Test
|
||||
fun testUtf8EncodingDecoding() {
|
||||
val classLoader = this.javaClass.classLoader
|
||||
val utf8Lines = String(classLoader.getResourceAsStream("utf8_sample.txt")!!.readBytes())
|
||||
.split("\n")
|
||||
.filter { it.trim().isNotEmpty() }
|
||||
|
||||
val utf8Bytes = utf8Lines.map {
|
||||
s -> ByteArray(Utf8.encodedLength(s)).also {
|
||||
Utf8.encodeUtf8Array(s, it)
|
||||
}
|
||||
}
|
||||
utf8Bytes.indices.forEach {
|
||||
assertArrayEquals(utf8Lines[it].encodeToByteArray(), utf8Bytes[it])
|
||||
assertEquals(utf8Lines[it], Utf8.decodeUtf8Array(utf8Bytes[it]))
|
||||
}
|
||||
}
|
||||
}
|
@ -1,201 +0,0 @@
|
||||
Markus Kuhn <http://www.cl.cam.ac.uk/~mgk25/> - 2015-08-28 - CC BY 4.0
|
||||
UTF-8 encoded sample plain-text file
|
||||
‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
|
||||
Markus Kuhn [ˈmaʳkʊs kuːn] <mkuhn@acm.org> — 1999-08-20
|
||||
|
||||
The ASCII compatible UTF-8 encoding of ISO 10646 and Unicode
|
||||
plain-text files is defined in RFC 2279 and in ISO 10646-1 Annex R.
|
||||
|
||||
|
||||
Using Unicode/UTF-8, you can write in emails and source code things such as
|
||||
|
||||
Mathematics and Sciences:
|
||||
|
||||
∮ E⋅da = Q, n → ∞, ∑ f(i) = ∏ g(i), ∀x∈ℝ: ⌈x⌉ = −⌊−x⌋, α ∧ ¬β = ¬(¬α ∨ β),
|
||||
|
||||
ℕ ⊆ ℕ₀ ⊂ ℤ ⊂ ℚ ⊂ ℝ ⊂ ℂ, ⊥ < a ≠ b ≡ c ≤ d ≪ ⊤ ⇒ (A ⇔ B),
|
||||
|
||||
2H₂ + O₂ ⇌ 2H₂O, R = 4.7 kΩ, ⌀ 200 mm
|
||||
|
||||
Linguistics and dictionaries:
|
||||
|
||||
ði ıntəˈnæʃənəl fəˈnɛtık əsoʊsiˈeıʃn
|
||||
Y [ˈʏpsilɔn], Yen [jɛn], Yoga [ˈjoːgɑ]
|
||||
|
||||
APL:
|
||||
|
||||
((V⍳V)=⍳⍴V)/V←,V ⌷←⍳→⍴∆∇⊃‾⍎⍕⌈
|
||||
|
||||
Nicer typography in plain text files:
|
||||
|
||||
╔══════════════════════════════════════════╗
|
||||
║ ║
|
||||
║ • ‘single’ and “double” quotes ║
|
||||
║ ║
|
||||
║ • Curly apostrophes: “We’ve been here” ║
|
||||
║ ║
|
||||
║ • Latin-1 apostrophe and accents: '´` ║
|
||||
║ ║
|
||||
║ • ‚deutsche‘ „Anführungszeichen“ ║
|
||||
║ ║
|
||||
║ • †, ‡, ‰, •, 3–4, —, −5/+5, ™, … ║
|
||||
║ ║
|
||||
║ • ASCII safety test: 1lI|, 0OD, 8B ║
|
||||
║ ╭─────────╮ ║
|
||||
║ • the euro symbol: │ 14.95 € │ ║
|
||||
║ ╰─────────╯ ║
|
||||
╚══════════════════════════════════════════╝
|
||||
|
||||
Greek (in Polytonic):
|
||||
|
||||
The Greek anthem:
|
||||
|
||||
Σὲ γνωρίζω ἀπὸ τὴν κόψη
|
||||
τοῦ σπαθιοῦ τὴν τρομερή,
|
||||
σὲ γνωρίζω ἀπὸ τὴν ὄψη
|
||||
ποὺ μὲ βία μετράει τὴ γῆ.
|
||||
|
||||
᾿Απ᾿ τὰ κόκκαλα βγαλμένη
|
||||
τῶν ῾Ελλήνων τὰ ἱερά
|
||||
καὶ σὰν πρῶτα ἀνδρειωμένη
|
||||
χαῖρε, ὦ χαῖρε, ᾿Ελευθεριά!
|
||||
|
||||
From a speech of Demosthenes in the 4th century BC:
|
||||
|
||||
Οὐχὶ ταὐτὰ παρίσταταί μοι γιγνώσκειν, ὦ ἄνδρες ᾿Αθηναῖοι,
|
||||
ὅταν τ᾿ εἰς τὰ πράγματα ἀποβλέψω καὶ ὅταν πρὸς τοὺς
|
||||
λόγους οὓς ἀκούω· τοὺς μὲν γὰρ λόγους περὶ τοῦ
|
||||
τιμωρήσασθαι Φίλιππον ὁρῶ γιγνομένους, τὰ δὲ πράγματ᾿
|
||||
εἰς τοῦτο προήκοντα, ὥσθ᾿ ὅπως μὴ πεισόμεθ᾿ αὐτοὶ
|
||||
πρότερον κακῶς σκέψασθαι δέον. οὐδέν οὖν ἄλλο μοι δοκοῦσιν
|
||||
οἱ τὰ τοιαῦτα λέγοντες ἢ τὴν ὑπόθεσιν, περὶ ἧς βουλεύεσθαι,
|
||||
οὐχὶ τὴν οὖσαν παριστάντες ὑμῖν ἁμαρτάνειν. ἐγὼ δέ, ὅτι μέν
|
||||
ποτ᾿ ἐξῆν τῇ πόλει καὶ τὰ αὑτῆς ἔχειν ἀσφαλῶς καὶ Φίλιππον
|
||||
τιμωρήσασθαι, καὶ μάλ᾿ ἀκριβῶς οἶδα· ἐπ᾿ ἐμοῦ γάρ, οὐ πάλαι
|
||||
γέγονεν ταῦτ᾿ ἀμφότερα· νῦν μέντοι πέπεισμαι τοῦθ᾿ ἱκανὸν
|
||||
προλαβεῖν ἡμῖν εἶναι τὴν πρώτην, ὅπως τοὺς συμμάχους
|
||||
σώσομεν. ἐὰν γὰρ τοῦτο βεβαίως ὑπάρξῃ, τότε καὶ περὶ τοῦ
|
||||
τίνα τιμωρήσεταί τις καὶ ὃν τρόπον ἐξέσται σκοπεῖν· πρὶν δὲ
|
||||
τὴν ἀρχὴν ὀρθῶς ὑποθέσθαι, μάταιον ἡγοῦμαι περὶ τῆς
|
||||
τελευτῆς ὁντινοῦν ποιεῖσθαι λόγον.
|
||||
|
||||
Δημοσθένους, Γ´ ᾿Ολυνθιακὸς
|
||||
|
||||
Georgian:
|
||||
|
||||
From a Unicode conference invitation:
|
||||
|
||||
გთხოვთ ახლავე გაიაროთ რეგისტრაცია Unicode-ის მეათე საერთაშორისო
|
||||
კონფერენციაზე დასასწრებად, რომელიც გაიმართება 10-12 მარტს,
|
||||
ქ. მაინცში, გერმანიაში. კონფერენცია შეჰკრებს ერთად მსოფლიოს
|
||||
ექსპერტებს ისეთ დარგებში როგორიცაა ინტერნეტი და Unicode-ი,
|
||||
ინტერნაციონალიზაცია და ლოკალიზაცია, Unicode-ის გამოყენება
|
||||
ოპერაციულ სისტემებსა, და გამოყენებით პროგრამებში, შრიფტებში,
|
||||
ტექსტების დამუშავებასა და მრავალენოვან კომპიუტერულ სისტემებში.
|
||||
|
||||
Russian:
|
||||
|
||||
From a Unicode conference invitation:
|
||||
|
||||
Зарегистрируйтесь сейчас на Десятую Международную Конференцию по
|
||||
Unicode, которая состоится 10-12 марта 1997 года в Майнце в Германии.
|
||||
Конференция соберет широкий круг экспертов по вопросам глобального
|
||||
Интернета и Unicode, локализации и интернационализации, воплощению и
|
||||
применению Unicode в различных операционных системах и программных
|
||||
приложениях, шрифтах, верстке и многоязычных компьютерных системах.
|
||||
|
||||
Thai (UCS Level 2):
|
||||
|
||||
Excerpt from a poetry on The Romance of The Three Kingdoms (a Chinese
|
||||
classic 'San Gua'):
|
||||
|
||||
[----------------------------|------------------------]
|
||||
๏ แผ่นดินฮั่นเสื่อมโทรมแสนสังเวช พระปกเกศกองบู๊กู้ขึ้นใหม่
|
||||
สิบสองกษัตริย์ก่อนหน้าแลถัดไป สององค์ไซร้โง่เขลาเบาปัญญา
|
||||
ทรงนับถือขันทีเป็นที่พึ่ง บ้านเมืองจึงวิปริตเป็นนักหนา
|
||||
โฮจิ๋นเรียกทัพทั่วหัวเมืองมา หมายจะฆ่ามดชั่วตัวสำคัญ
|
||||
เหมือนขับไสไล่เสือจากเคหา รับหมาป่าเข้ามาเลยอาสัญ
|
||||
ฝ่ายอ้องอุ้นยุแยกให้แตกกัน ใช้สาวนั้นเป็นชนวนชื่นชวนใจ
|
||||
พลันลิฉุยกุยกีกลับก่อเหตุ ช่างอาเพศจริงหนาฟ้าร้องไห้
|
||||
ต้องรบราฆ่าฟันจนบรรลัย ฤๅหาใครค้ำชูกู้บรรลังก์ ฯ
|
||||
|
||||
(The above is a two-column text. If combining characters are handled
|
||||
correctly, the lines of the second column should be aligned with the
|
||||
| character above.)
|
||||
|
||||
Ethiopian:
|
||||
|
||||
Proverbs in the Amharic language:
|
||||
|
||||
ሰማይ አይታረስ ንጉሥ አይከሰስ።
|
||||
ብላ ካለኝ እንደአባቴ በቆመጠኝ።
|
||||
ጌጥ ያለቤቱ ቁምጥና ነው።
|
||||
ደሀ በሕልሙ ቅቤ ባይጠጣ ንጣት በገደለው።
|
||||
የአፍ ወለምታ በቅቤ አይታሽም።
|
||||
አይጥ በበላ ዳዋ ተመታ።
|
||||
ሲተረጉሙ ይደረግሙ።
|
||||
ቀስ በቀስ፥ ዕንቁላል በእግሩ ይሄዳል።
|
||||
ድር ቢያብር አንበሳ ያስር።
|
||||
ሰው እንደቤቱ እንጅ እንደ ጉረቤቱ አይተዳደርም።
|
||||
እግዜር የከፈተውን ጉሮሮ ሳይዘጋው አይድርም።
|
||||
የጎረቤት ሌባ፥ ቢያዩት ይስቅ ባያዩት ያጠልቅ።
|
||||
ሥራ ከመፍታት ልጄን ላፋታት።
|
||||
ዓባይ ማደሪያ የለው፥ ግንድ ይዞ ይዞራል።
|
||||
የእስላም አገሩ መካ የአሞራ አገሩ ዋርካ።
|
||||
ተንጋሎ ቢተፉ ተመልሶ ባፉ።
|
||||
ወዳጅህ ማር ቢሆን ጨርስህ አትላሰው።
|
||||
እግርህን በፍራሽህ ልክ ዘርጋ።
|
||||
|
||||
Runes:
|
||||
|
||||
ᚻᛖ ᚳᚹᚫᚦ ᚦᚫᛏ ᚻᛖ ᛒᚢᛞᛖ ᚩᚾ ᚦᚫᛗ ᛚᚪᚾᛞᛖ ᚾᚩᚱᚦᚹᛖᚪᚱᛞᚢᛗ ᚹᛁᚦ ᚦᚪ ᚹᛖᛥᚫ
|
||||
|
||||
(Old English, which transcribed into Latin reads 'He cwaeth that he
|
||||
bude thaem lande northweardum with tha Westsae.' and means 'He said
|
||||
that he lived in the northern land near the Western Sea.')
|
||||
|
||||
Braille:
|
||||
|
||||
⡌⠁⠧⠑ ⠼⠁⠒ ⡍⠜⠇⠑⠹⠰⠎ ⡣⠕⠌
|
||||
|
||||
⡍⠜⠇⠑⠹ ⠺⠁⠎ ⠙⠑⠁⠙⠒ ⠞⠕ ⠃⠑⠛⠔ ⠺⠊⠹⠲ ⡹⠻⠑ ⠊⠎ ⠝⠕ ⠙⠳⠃⠞
|
||||
⠱⠁⠞⠑⠧⠻ ⠁⠃⠳⠞ ⠹⠁⠞⠲ ⡹⠑ ⠗⠑⠛⠊⠌⠻ ⠕⠋ ⠙⠊⠎ ⠃⠥⠗⠊⠁⠇ ⠺⠁⠎
|
||||
⠎⠊⠛⠝⠫ ⠃⠹ ⠹⠑ ⠊⠇⠻⠛⠹⠍⠁⠝⠂ ⠹⠑ ⠊⠇⠻⠅⠂ ⠹⠑ ⠥⠝⠙⠻⠞⠁⠅⠻⠂
|
||||
⠁⠝⠙ ⠹⠑ ⠡⠊⠑⠋ ⠍⠳⠗⠝⠻⠲ ⡎⠊⠗⠕⠕⠛⠑ ⠎⠊⠛⠝⠫ ⠊⠞⠲ ⡁⠝⠙
|
||||
⡎⠊⠗⠕⠕⠛⠑⠰⠎ ⠝⠁⠍⠑ ⠺⠁⠎ ⠛⠕⠕⠙ ⠥⠏⠕⠝ ⠰⡡⠁⠝⠛⠑⠂ ⠋⠕⠗ ⠁⠝⠹⠹⠔⠛ ⠙⠑
|
||||
⠡⠕⠎⠑ ⠞⠕ ⠏⠥⠞ ⠙⠊⠎ ⠙⠁⠝⠙ ⠞⠕⠲
|
||||
|
||||
⡕⠇⠙ ⡍⠜⠇⠑⠹ ⠺⠁⠎ ⠁⠎ ⠙⠑⠁⠙ ⠁⠎ ⠁ ⠙⠕⠕⠗⠤⠝⠁⠊⠇⠲
|
||||
|
||||
⡍⠔⠙⠖ ⡊ ⠙⠕⠝⠰⠞ ⠍⠑⠁⠝ ⠞⠕ ⠎⠁⠹ ⠹⠁⠞ ⡊ ⠅⠝⠪⠂ ⠕⠋ ⠍⠹
|
||||
⠪⠝ ⠅⠝⠪⠇⠫⠛⠑⠂ ⠱⠁⠞ ⠹⠻⠑ ⠊⠎ ⠏⠜⠞⠊⠊⠥⠇⠜⠇⠹ ⠙⠑⠁⠙ ⠁⠃⠳⠞
|
||||
⠁ ⠙⠕⠕⠗⠤⠝⠁⠊⠇⠲ ⡊ ⠍⠊⠣⠞ ⠙⠁⠧⠑ ⠃⠑⠲ ⠔⠊⠇⠔⠫⠂ ⠍⠹⠎⠑⠇⠋⠂ ⠞⠕
|
||||
⠗⠑⠛⠜⠙ ⠁ ⠊⠕⠋⠋⠔⠤⠝⠁⠊⠇ ⠁⠎ ⠹⠑ ⠙⠑⠁⠙⠑⠌ ⠏⠊⠑⠊⠑ ⠕⠋ ⠊⠗⠕⠝⠍⠕⠝⠛⠻⠹
|
||||
⠔ ⠹⠑ ⠞⠗⠁⠙⠑⠲ ⡃⠥⠞ ⠹⠑ ⠺⠊⠎⠙⠕⠍ ⠕⠋ ⠳⠗ ⠁⠝⠊⠑⠌⠕⠗⠎
|
||||
⠊⠎ ⠔ ⠹⠑ ⠎⠊⠍⠊⠇⠑⠆ ⠁⠝⠙ ⠍⠹ ⠥⠝⠙⠁⠇⠇⠪⠫ ⠙⠁⠝⠙⠎
|
||||
⠩⠁⠇⠇ ⠝⠕⠞ ⠙⠊⠌⠥⠗⠃ ⠊⠞⠂ ⠕⠗ ⠹⠑ ⡊⠳⠝⠞⠗⠹⠰⠎ ⠙⠕⠝⠑ ⠋⠕⠗⠲ ⡹⠳
|
||||
⠺⠊⠇⠇ ⠹⠻⠑⠋⠕⠗⠑ ⠏⠻⠍⠊⠞ ⠍⠑ ⠞⠕ ⠗⠑⠏⠑⠁⠞⠂ ⠑⠍⠏⠙⠁⠞⠊⠊⠁⠇⠇⠹⠂ ⠹⠁⠞
|
||||
⡍⠜⠇⠑⠹ ⠺⠁⠎ ⠁⠎ ⠙⠑⠁⠙ ⠁⠎ ⠁ ⠙⠕⠕⠗⠤⠝⠁⠊⠇⠲
|
||||
|
||||
(The first couple of paragraphs of "A Christmas Carol" by Dickens)
|
||||
|
||||
Compact font selection example text:
|
||||
|
||||
ABCDEFGHIJKLMNOPQRSTUVWXYZ /0123456789
|
||||
abcdefghijklmnopqrstuvwxyz £©µÀÆÖÞßéöÿ
|
||||
–—‘“”„†•…‰™œŠŸž€ ΑΒΓΔΩαβγδω АБВГДабвгд
|
||||
∀∂∈ℝ∧∪≡∞ ↑↗↨↻⇣ ┐┼╔╘░►☺♀ fi<>⑀₂ἠḂӥẄɐː⍎אԱა
|
||||
|
||||
Greetings in various languages:
|
||||
|
||||
Hello world, Καλημέρα κόσμε, コンニチハ
|
||||
|
||||
Box drawing alignment tests: █
|
||||
▉
|
||||
╔══╦══╗ ┌──┬──┐ ╭──┬──╮ ╭──┬──╮ ┏━━┳━━┓ ┎┒┏┑ ╷ ╻ ┏┯┓ ┌┰┐ ▊ ╱╲╱╲╳╳╳
|
||||
║┌─╨─┐║ │╔═╧═╗│ │╒═╪═╕│ │╓─╁─╖│ ┃┌─╂─┐┃ ┗╃╄┙ ╶┼╴╺╋╸┠┼┨ ┝╋┥ ▋ ╲╱╲╱╳╳╳
|
||||
║│╲ ╱│║ │║ ║│ ││ │ ││ │║ ┃ ║│ ┃│ ╿ │┃ ┍╅╆┓ ╵ ╹ ┗┷┛ └┸┘ ▌ ╱╲╱╲╳╳╳
|
||||
╠╡ ╳ ╞╣ ├╢ ╟┤ ├┼─┼─┼┤ ├╫─╂─╫┤ ┣┿╾┼╼┿┫ ┕┛┖┚ ┌┄┄┐ ╎ ┏┅┅┓ ┋ ▍ ╲╱╲╱╳╳╳
|
||||
║│╱ ╲│║ │║ ║│ ││ │ ││ │║ ┃ ║│ ┃│ ╽ │┃ ░░▒▒▓▓██ ┊ ┆ ╎ ╏ ┇ ┋ ▎
|
||||
║└─╥─┘║ │╚═╤═╝│ │╘═╪═╛│ │╙─╀─╜│ ┃└─╂─┘┃ ░░▒▒▓▓██ ┊ ┆ ╎ ╏ ┇ ┋ ▏
|
||||
╚══╩══╝ └──┴──┘ ╰──┴──╯ ╰──┴──╯ ┗━━┻━━┛ └╌╌┘ ╎ ┗╍╍┛ ┋ ▁▂▃▄▅▆▇█
|
@ -1,42 +0,0 @@
|
||||
/*
|
||||
* Copyright 2021 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.
|
||||
*/
|
||||
@file:Suppress("NOTHING_TO_INLINE")
|
||||
|
||||
package com.google.flatbuffers.kotlin
|
||||
|
||||
/**
|
||||
* This implementation assumes that of native macOSX64 the byte order of the implementation is Little Endian.
|
||||
*/
|
||||
|
||||
public actual inline fun ByteArray.getUByte(index: Int): UByte = getUByteAt(index)
|
||||
public actual inline fun ByteArray.getShort(index: Int): Short = getShortAt(index)
|
||||
public actual inline fun ByteArray.getUShort(index: Int): UShort = getUShortAt(index)
|
||||
public actual inline fun ByteArray.getInt(index: Int): Int = getIntAt(index)
|
||||
public actual inline fun ByteArray.getUInt(index: Int): UInt = getUIntAt(index)
|
||||
public actual inline fun ByteArray.getLong(index: Int): Long = getLongAt(index)
|
||||
public actual inline fun ByteArray.getULong(index: Int): ULong = getULongAt(index)
|
||||
|
||||
public actual inline fun ByteArray.setUByte(index: Int, value: UByte): Unit = setUByteAt(index, value)
|
||||
public actual inline fun ByteArray.setShort(index: Int, value: Short): Unit = setShortAt(index, value)
|
||||
public actual inline fun ByteArray.setUShort(index: Int, value: UShort): Unit = setUShortAt(index, value)
|
||||
public actual inline fun ByteArray.setInt(index: Int, value: Int): Unit = setIntAt(index, value)
|
||||
public actual inline fun ByteArray.setUInt(index: Int, value: UInt): Unit = setUIntAt(index, value)
|
||||
public actual inline fun ByteArray.setLong(index: Int, value: Long): Unit = setLongAt(index, value)
|
||||
public actual inline fun ByteArray.setULong(index: Int, value: ULong): Unit = setULongAt(index, value)
|
||||
public actual inline fun ByteArray.setFloat(index: Int, value: Float): Unit = setFloatAt(index, value)
|
||||
public actual inline fun ByteArray.setDouble(index: Int, value: Double): Unit = setDoubleAt(index, value)
|
||||
public actual inline fun ByteArray.getFloat(index: Int): Float = Float.fromBits(getIntAt(index))
|
||||
public actual inline fun ByteArray.getDouble(index: Int): Double = Double.fromBits(getLongAt(index))
|
20
third_party/flatbuffers/kotlin/gradle.properties
vendored
20
third_party/flatbuffers/kotlin/gradle.properties
vendored
@ -1,20 +0,0 @@
|
||||
#Gradle
|
||||
group = "com.google.flatbuffers"
|
||||
version = "2.0.0-SNAPSHOT"
|
||||
|
||||
org.gradle.parallel=true
|
||||
org.gradle.caching=true
|
||||
|
||||
#Kotlin
|
||||
kotlin.code.style=official
|
||||
|
||||
#MPP
|
||||
kotlin.js.compiler=ir
|
||||
kotlin.native.ignoreDisabledTargets=true
|
||||
kotlin.mpp.stability.nowarn=true
|
||||
kotlin.incremental.multiplatform=true
|
||||
kotlin.native.binary.memoryModel=experimental
|
||||
|
||||
kotlin.native.distribution.type=prebuilt
|
||||
|
||||
org.gradle.jvmargs="-XX:+HeapDumpOnOutOfMemoryError"
|
@ -1,25 +0,0 @@
|
||||
[versions]
|
||||
kotlin = "1.8.21"
|
||||
plugin-kotlin = "1.6.10"
|
||||
plugin-gver = "0.42.0"
|
||||
kotlinx-benchmark = "0.4.8"
|
||||
junit = "4.12"
|
||||
gson = "2.8.5"
|
||||
moshi-kotlin = "1.11.0"
|
||||
|
||||
[libraries]
|
||||
kotlin-compiler = { module = "org.jetbrains.kotlin:kotlin-compiler", version.ref = "kotlin" }
|
||||
moshi-kotlin = { module = "com.squareup.moshi:moshi-kotlin", version.ref = "moshi-kotlin" }
|
||||
gson = { module = "com.google.code.gson:gson", version.ref = "gson" }
|
||||
kotlinx-benchmark-runtime = { module = "org.jetbrains.kotlinx:kotlinx-benchmark-runtime", version.ref = "kotlinx-benchmark" }
|
||||
|
||||
junit = { module="junit:junit", version.ref="junit"}
|
||||
kotlin-allopen = { module = "org.jetbrains.kotlin:kotlin-allopen", version.ref = "kotlin"}
|
||||
|
||||
plugin-kotlin-gradle = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", version.ref = "kotlin" }
|
||||
plugin-kotlinx-benchmark = { module="org.jetbrains.kotlinx:kotlinx-benchmark-plugin", version.ref="kotlinx-benchmark"}
|
||||
plugin-jmhreport = { module = "gradle.plugin.io.morethan.jmhreport:gradle-jmh-report", version="0.9.0" }
|
||||
plugin-download = { module = "de.undercouch:gradle-download-task", version = "5.3.0"}
|
||||
|
||||
|
||||
|
Binary file not shown.
@ -1,5 +0,0 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.0.1-bin.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
234
third_party/flatbuffers/kotlin/gradlew
vendored
234
third_party/flatbuffers/kotlin/gradlew
vendored
@ -1,234 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
#
|
||||
# Copyright © 2015-2021 the original authors.
|
||||
#
|
||||
# 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
|
||||
#
|
||||
# https://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.
|
||||
#
|
||||
|
||||
##############################################################################
|
||||
#
|
||||
# Gradle start up script for POSIX generated by Gradle.
|
||||
#
|
||||
# Important for running:
|
||||
#
|
||||
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
|
||||
# noncompliant, but you have some other compliant shell such as ksh or
|
||||
# bash, then to run this script, type that shell name before the whole
|
||||
# command line, like:
|
||||
#
|
||||
# ksh Gradle
|
||||
#
|
||||
# Busybox and similar reduced shells will NOT work, because this script
|
||||
# requires all of these POSIX shell features:
|
||||
# * functions;
|
||||
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
|
||||
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
|
||||
# * compound commands having a testable exit status, especially «case»;
|
||||
# * various built-in commands including «command», «set», and «ulimit».
|
||||
#
|
||||
# Important for patching:
|
||||
#
|
||||
# (2) This script targets any POSIX shell, so it avoids extensions provided
|
||||
# by Bash, Ksh, etc; in particular arrays are avoided.
|
||||
#
|
||||
# The "traditional" practice of packing multiple parameters into a
|
||||
# space-separated string is a well documented source of bugs and security
|
||||
# problems, so this is (mostly) avoided, by progressively accumulating
|
||||
# options in "$@", and eventually passing that to Java.
|
||||
#
|
||||
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
|
||||
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
|
||||
# see the in-line comments for details.
|
||||
#
|
||||
# There are tweaks for specific operating systems such as AIX, CygWin,
|
||||
# Darwin, MinGW, and NonStop.
|
||||
#
|
||||
# (3) This script is generated from the Groovy template
|
||||
# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||
# within the Gradle project.
|
||||
#
|
||||
# You can find Gradle at https://github.com/gradle/gradle/.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
# Attempt to set APP_HOME
|
||||
|
||||
# Resolve links: $0 may be a link
|
||||
app_path=$0
|
||||
|
||||
# Need this for daisy-chained symlinks.
|
||||
while
|
||||
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
|
||||
[ -h "$app_path" ]
|
||||
do
|
||||
ls=$( ls -ld "$app_path" )
|
||||
link=${ls#*' -> '}
|
||||
case $link in #(
|
||||
/*) app_path=$link ;; #(
|
||||
*) app_path=$APP_HOME$link ;;
|
||||
esac
|
||||
done
|
||||
|
||||
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
|
||||
|
||||
APP_NAME="Gradle"
|
||||
APP_BASE_NAME=${0##*/}
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD=maximum
|
||||
|
||||
warn () {
|
||||
echo "$*"
|
||||
} >&2
|
||||
|
||||
die () {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
exit 1
|
||||
} >&2
|
||||
|
||||
# OS specific support (must be 'true' or 'false').
|
||||
cygwin=false
|
||||
msys=false
|
||||
darwin=false
|
||||
nonstop=false
|
||||
case "$( uname )" in #(
|
||||
CYGWIN* ) cygwin=true ;; #(
|
||||
Darwin* ) darwin=true ;; #(
|
||||
MSYS* | MINGW* ) msys=true ;; #(
|
||||
NONSTOP* ) nonstop=true ;;
|
||||
esac
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
|
||||
|
||||
# Determine the Java command to use to start the JVM.
|
||||
if [ -n "$JAVA_HOME" ] ; then
|
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||
# IBM's JDK on AIX uses strange locations for the executables
|
||||
JAVACMD=$JAVA_HOME/jre/sh/java
|
||||
else
|
||||
JAVACMD=$JAVA_HOME/bin/java
|
||||
fi
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
else
|
||||
JAVACMD=java
|
||||
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
||||
case $MAX_FD in #(
|
||||
max*)
|
||||
MAX_FD=$( ulimit -H -n ) ||
|
||||
warn "Could not query maximum file descriptor limit"
|
||||
esac
|
||||
case $MAX_FD in #(
|
||||
'' | soft) :;; #(
|
||||
*)
|
||||
ulimit -n "$MAX_FD" ||
|
||||
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
||||
esac
|
||||
fi
|
||||
|
||||
# Collect all arguments for the java command, stacking in reverse order:
|
||||
# * args from the command line
|
||||
# * the main class name
|
||||
# * -classpath
|
||||
# * -D...appname settings
|
||||
# * --module-path (only if needed)
|
||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
|
||||
|
||||
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||
if "$cygwin" || "$msys" ; then
|
||||
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
|
||||
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
|
||||
|
||||
JAVACMD=$( cygpath --unix "$JAVACMD" )
|
||||
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
for arg do
|
||||
if
|
||||
case $arg in #(
|
||||
-*) false ;; # don't mess with options #(
|
||||
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
|
||||
[ -e "$t" ] ;; #(
|
||||
*) false ;;
|
||||
esac
|
||||
then
|
||||
arg=$( cygpath --path --ignore --mixed "$arg" )
|
||||
fi
|
||||
# Roll the args list around exactly as many times as the number of
|
||||
# args, so each arg winds up back in the position where it started, but
|
||||
# possibly modified.
|
||||
#
|
||||
# NB: a `for` loop captures its iteration list before it begins, so
|
||||
# changing the positional parameters here affects neither the number of
|
||||
# iterations, nor the values presented in `arg`.
|
||||
shift # remove old arg
|
||||
set -- "$@" "$arg" # push replacement arg
|
||||
done
|
||||
fi
|
||||
|
||||
# Collect all arguments for the java command;
|
||||
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
|
||||
# shell script including quotes and variable substitutions, so put them in
|
||||
# double quotes to make sure that they get re-expanded; and
|
||||
# * put everything else in single quotes, so that it's not re-expanded.
|
||||
|
||||
set -- \
|
||||
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
||||
-classpath "$CLASSPATH" \
|
||||
org.gradle.wrapper.GradleWrapperMain \
|
||||
"$@"
|
||||
|
||||
# Use "xargs" to parse quoted args.
|
||||
#
|
||||
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
|
||||
#
|
||||
# In Bash we could simply go:
|
||||
#
|
||||
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
|
||||
# set -- "${ARGS[@]}" "$@"
|
||||
#
|
||||
# but POSIX shell has neither arrays nor command substitution, so instead we
|
||||
# post-process each arg (as a line of input to sed) to backslash-escape any
|
||||
# character that might be a shell metacharacter, then use eval to reverse
|
||||
# that process (while maintaining the separation between arguments), and wrap
|
||||
# the whole thing up as a single "set" statement.
|
||||
#
|
||||
# This will of course break if any of these variables contains a newline or
|
||||
# an unmatched quote.
|
||||
#
|
||||
|
||||
eval "set -- $(
|
||||
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
|
||||
xargs -n1 |
|
||||
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
|
||||
tr '\n' ' '
|
||||
)" '"$@"'
|
||||
|
||||
exec "$JAVACMD" "$@"
|
89
third_party/flatbuffers/kotlin/gradlew.bat
vendored
89
third_party/flatbuffers/kotlin/gradlew.bat
vendored
@ -1,89 +0,0 @@
|
||||
@rem
|
||||
@rem Copyright 2015 the original author or authors.
|
||||
@rem
|
||||
@rem Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@rem you may not use this file except in compliance with the License.
|
||||
@rem You may obtain a copy of the License at
|
||||
@rem
|
||||
@rem https://www.apache.org/licenses/LICENSE-2.0
|
||||
@rem
|
||||
@rem Unless required by applicable law or agreed to in writing, software
|
||||
@rem distributed under the License is distributed on an "AS IS" BASIS,
|
||||
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@rem See the License for the specific language governing permissions and
|
||||
@rem limitations under the License.
|
||||
@rem
|
||||
|
||||
@if "%DEBUG%" == "" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@rem Gradle startup script for Windows
|
||||
@rem
|
||||
@rem ##########################################################################
|
||||
|
||||
@rem Set local scope for the variables with windows NT shell
|
||||
if "%OS%"=="Windows_NT" setlocal
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%" == "" set DIRNAME=.
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
|
||||
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
|
||||
|
||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
|
||||
|
||||
@rem Find java.exe
|
||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if "%ERRORLEVEL%" == "0" goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:findJavaFromJavaHome
|
||||
set JAVA_HOME=%JAVA_HOME:"=%
|
||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||
|
||||
if exist "%JAVA_EXE%" goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if "%ERRORLEVEL%"=="0" goto mainEnd
|
||||
|
||||
:fail
|
||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||
rem the _cmd.exe /c_ return code!
|
||||
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
|
||||
exit /b 1
|
||||
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
||||
|
||||
:omega
|
@ -1,3 +0,0 @@
|
||||
rootProject.name = "flatbuffers-kotlin"
|
||||
include("flatbuffers-kotlin")
|
||||
include("benchmark")
|
@ -1,15 +0,0 @@
|
||||
/*
|
||||
* Copyright $YEAR 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.
|
||||
*/
|
498
third_party/flatbuffers/php/ByteBuffer.php
vendored
498
third_party/flatbuffers/php/ByteBuffer.php
vendored
@ -1,498 +0,0 @@
|
||||
<?php
|
||||
/*
|
||||
* Copyright 2015 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
namespace Google\FlatBuffers;
|
||||
|
||||
class ByteBuffer
|
||||
{
|
||||
/**
|
||||
* @var string $_buffer;
|
||||
*/
|
||||
public $_buffer;
|
||||
|
||||
/**
|
||||
* @var int $_pos;
|
||||
*/
|
||||
private $_pos;
|
||||
|
||||
/**
|
||||
* @var bool $_is_little_endian
|
||||
*/
|
||||
private static $_is_little_endian = null;
|
||||
|
||||
public static function wrap($bytes)
|
||||
{
|
||||
$bb = new ByteBuffer(0);
|
||||
$bb->_buffer = $bytes;
|
||||
|
||||
return $bb;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $size
|
||||
*/
|
||||
public function __construct($size)
|
||||
{
|
||||
$this->_buffer = str_repeat("\0", $size);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function capacity()
|
||||
{
|
||||
return strlen($this->_buffer);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getPosition()
|
||||
{
|
||||
return $this->_pos;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $pos
|
||||
*/
|
||||
public function setPosition($pos)
|
||||
{
|
||||
$this->_pos = $pos;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function reset()
|
||||
{
|
||||
$this->_pos = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function length()
|
||||
{
|
||||
return strlen($this->_buffer);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function data()
|
||||
{
|
||||
return substr($this->_buffer, $this->_pos);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public static function isLittleEndian()
|
||||
{
|
||||
if (ByteBuffer::$_is_little_endian === null) {
|
||||
ByteBuffer::$_is_little_endian = unpack('S', "\x01\x00")[1] === 1;
|
||||
}
|
||||
|
||||
return ByteBuffer::$_is_little_endian;
|
||||
}
|
||||
|
||||
/**
|
||||
* write little endian value to the buffer.
|
||||
*
|
||||
* @param $offset
|
||||
* @param $count byte length
|
||||
* @param $data actual values
|
||||
*/
|
||||
public function writeLittleEndian($offset, $count, $data)
|
||||
{
|
||||
if (ByteBuffer::isLittleEndian()) {
|
||||
for ($i = 0; $i < $count; $i++) {
|
||||
$this->_buffer[$offset + $i] = chr($data >> $i * 8);
|
||||
}
|
||||
} else {
|
||||
for ($i = 0; $i < $count; $i++) {
|
||||
$this->_buffer[$offset + $count - 1 - $i] = chr($data >> $i * 8);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* read little endian value from the buffer
|
||||
*
|
||||
* @param $offset
|
||||
* @param $count acutal size
|
||||
* @return int
|
||||
*/
|
||||
public function readLittleEndian($offset, $count, $force_bigendian = false)
|
||||
{
|
||||
$this->assertOffsetAndLength($offset, $count);
|
||||
$r = 0;
|
||||
|
||||
if (ByteBuffer::isLittleEndian() && $force_bigendian == false) {
|
||||
for ($i = 0; $i < $count; $i++) {
|
||||
$r |= ord($this->_buffer[$offset + $i]) << $i * 8;
|
||||
}
|
||||
} else {
|
||||
for ($i = 0; $i < $count; $i++) {
|
||||
$r |= ord($this->_buffer[$offset + $count -1 - $i]) << $i * 8;
|
||||
}
|
||||
}
|
||||
|
||||
return $r;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $offset
|
||||
* @param $length
|
||||
*/
|
||||
public function assertOffsetAndLength($offset, $length)
|
||||
{
|
||||
if ($offset < 0 ||
|
||||
$offset >= strlen($this->_buffer) ||
|
||||
$offset + $length > strlen($this->_buffer)) {
|
||||
throw new \OutOfRangeException(sprintf("offset: %d, length: %d, buffer; %d", $offset, $length, strlen($this->_buffer)));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $offset
|
||||
* @param $value
|
||||
* @return mixed
|
||||
*/
|
||||
public function putSbyte($offset, $value)
|
||||
{
|
||||
self::validateValue(-128, 127, $value, "sbyte");
|
||||
|
||||
$length = strlen($value);
|
||||
$this->assertOffsetAndLength($offset, $length);
|
||||
return $this->_buffer[$offset] = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $offset
|
||||
* @param $value
|
||||
* @return mixed
|
||||
*/
|
||||
public function putByte($offset, $value)
|
||||
{
|
||||
self::validateValue(0, 255, $value, "byte");
|
||||
|
||||
$length = strlen($value);
|
||||
$this->assertOffsetAndLength($offset, $length);
|
||||
return $this->_buffer[$offset] = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $offset
|
||||
* @param $value
|
||||
*/
|
||||
public function put($offset, $value)
|
||||
{
|
||||
$length = strlen($value);
|
||||
$this->assertOffsetAndLength($offset, $length);
|
||||
for ($i = 0; $i < $length; $i++) {
|
||||
$this->_buffer[$offset + $i] = $value[$i];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $offset
|
||||
* @param $value
|
||||
*/
|
||||
public function putShort($offset, $value)
|
||||
{
|
||||
self::validateValue(-32768, 32767, $value, "short");
|
||||
|
||||
$this->assertOffsetAndLength($offset, 2);
|
||||
$this->writeLittleEndian($offset, 2, $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $offset
|
||||
* @param $value
|
||||
*/
|
||||
public function putUshort($offset, $value)
|
||||
{
|
||||
self::validateValue(0, 65535, $value, "short");
|
||||
|
||||
$this->assertOffsetAndLength($offset, 2);
|
||||
$this->writeLittleEndian($offset, 2, $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $offset
|
||||
* @param $value
|
||||
*/
|
||||
public function putInt($offset, $value)
|
||||
{
|
||||
// 2147483647 = (1 << 31) -1 = Maximum signed 32-bit int
|
||||
// -2147483648 = -1 << 31 = Minimum signed 32-bit int
|
||||
self::validateValue(-2147483648, 2147483647, $value, "int");
|
||||
|
||||
$this->assertOffsetAndLength($offset, 4);
|
||||
$this->writeLittleEndian($offset, 4, $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $offset
|
||||
* @param $value
|
||||
*/
|
||||
public function putUint($offset, $value)
|
||||
{
|
||||
// NOTE: We can't put big integer value. this is PHP limitation.
|
||||
// 4294967295 = (1 << 32) -1 = Maximum unsigned 32-bin int
|
||||
self::validateValue(0, 4294967295, $value, "uint", " php has big numbers limitation. check your PHP_INT_MAX");
|
||||
|
||||
$this->assertOffsetAndLength($offset, 4);
|
||||
$this->writeLittleEndian($offset, 4, $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $offset
|
||||
* @param $value
|
||||
*/
|
||||
public function putLong($offset, $value)
|
||||
{
|
||||
// NOTE: We can't put big integer value. this is PHP limitation.
|
||||
self::validateValue(~PHP_INT_MAX, PHP_INT_MAX, $value, "long", " php has big numbers limitation. check your PHP_INT_MAX");
|
||||
|
||||
$this->assertOffsetAndLength($offset, 8);
|
||||
$this->writeLittleEndian($offset, 8, $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $offset
|
||||
* @param $value
|
||||
*/
|
||||
public function putUlong($offset, $value)
|
||||
{
|
||||
// NOTE: We can't put big integer value. this is PHP limitation.
|
||||
self::validateValue(0, PHP_INT_MAX, $value, "long", " php has big numbers limitation. check your PHP_INT_MAX");
|
||||
|
||||
$this->assertOffsetAndLength($offset, 8);
|
||||
$this->writeLittleEndian($offset, 8, $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $offset
|
||||
* @param $value
|
||||
*/
|
||||
public function putFloat($offset, $value)
|
||||
{
|
||||
$this->assertOffsetAndLength($offset, 4);
|
||||
|
||||
$floathelper = pack("f", $value);
|
||||
$v = unpack("V", $floathelper);
|
||||
$this->writeLittleEndian($offset, 4, $v[1]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $offset
|
||||
* @param $value
|
||||
*/
|
||||
public function putDouble($offset, $value)
|
||||
{
|
||||
$this->assertOffsetAndLength($offset, 8);
|
||||
|
||||
$floathelper = pack("d", $value);
|
||||
$v = unpack("V*", $floathelper);
|
||||
|
||||
$this->writeLittleEndian($offset, 4, $v[1]);
|
||||
$this->writeLittleEndian($offset + 4, 4, $v[2]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $index
|
||||
* @return mixed
|
||||
*/
|
||||
public function getByte($index)
|
||||
{
|
||||
return ord($this->_buffer[$index]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $index
|
||||
* @return mixed
|
||||
*/
|
||||
public function getSbyte($index)
|
||||
{
|
||||
$v = unpack("c", $this->_buffer[$index]);
|
||||
return $v[1];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $buffer
|
||||
*/
|
||||
public function getX(&$buffer)
|
||||
{
|
||||
for ($i = $this->_pos, $j = 0; $j < strlen($buffer); $i++, $j++) {
|
||||
$buffer[$j] = $this->_buffer[$i];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $index
|
||||
* @return mixed
|
||||
*/
|
||||
public function get($index)
|
||||
{
|
||||
$this->assertOffsetAndLength($index, 1);
|
||||
return $this->_buffer[$index];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $index
|
||||
* @return mixed
|
||||
*/
|
||||
public function getBool($index)
|
||||
{
|
||||
return (bool)ord($this->_buffer[$index]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $index
|
||||
* @return int
|
||||
*/
|
||||
public function getShort($index)
|
||||
{
|
||||
$result = $this->readLittleEndian($index, 2);
|
||||
|
||||
$sign = $index + (ByteBuffer::isLittleEndian() ? 1 : 0);
|
||||
$issigned = isset($this->_buffer[$sign]) && ord($this->_buffer[$sign]) & 0x80;
|
||||
|
||||
// 65536 = 1 << 16 = Maximum unsigned 16-bit int
|
||||
return $issigned ? $result - 65536 : $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $index
|
||||
* @return int
|
||||
*/
|
||||
public function getUShort($index)
|
||||
{
|
||||
return $this->readLittleEndian($index, 2);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $index
|
||||
* @return int
|
||||
*/
|
||||
public function getInt($index)
|
||||
{
|
||||
$result = $this->readLittleEndian($index, 4);
|
||||
|
||||
$sign = $index + (ByteBuffer::isLittleEndian() ? 3 : 0);
|
||||
$issigned = isset($this->_buffer[$sign]) && ord($this->_buffer[$sign]) & 0x80;
|
||||
|
||||
if (PHP_INT_SIZE > 4) {
|
||||
// 4294967296 = 1 << 32 = Maximum unsigned 32-bit int
|
||||
return $issigned ? $result - 4294967296 : $result;
|
||||
} else {
|
||||
// 32bit / Windows treated number as signed integer.
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $index
|
||||
* @return int
|
||||
*/
|
||||
public function getUint($index)
|
||||
{
|
||||
return $this->readLittleEndian($index, 4);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $index
|
||||
* @return int
|
||||
*/
|
||||
public function getLong($index)
|
||||
{
|
||||
return $this->readLittleEndian($index, 8);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $index
|
||||
* @return int
|
||||
*/
|
||||
public function getUlong($index)
|
||||
{
|
||||
return $this->readLittleEndian($index, 8);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $index
|
||||
* @return mixed
|
||||
*/
|
||||
public function getFloat($index)
|
||||
{
|
||||
$i = $this->readLittleEndian($index, 4);
|
||||
|
||||
return self::convertHelper(self::__FLOAT, $i);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $index
|
||||
* @return float
|
||||
*/
|
||||
public function getDouble($index)
|
||||
{
|
||||
$i = $this->readLittleEndian($index, 4);
|
||||
$i2 = $this->readLittleEndian($index + 4, 4);
|
||||
|
||||
return self::convertHelper(self::__DOUBLE, $i, $i2);
|
||||
}
|
||||
|
||||
const __SHORT = 1;
|
||||
const __INT = 2;
|
||||
const __LONG = 3;
|
||||
const __FLOAT = 4;
|
||||
const __DOUBLE = 5;
|
||||
private static function convertHelper($type, $value, $value2 = null) {
|
||||
// readLittleEndian construct unsigned integer value from bytes. we have to encode this value to
|
||||
// correct bytes, and decode as expected types with `unpack` function.
|
||||
// then it returns correct type value.
|
||||
// see also: http://php.net/manual/en/function.pack.php
|
||||
|
||||
switch ($type) {
|
||||
case self::__FLOAT:
|
||||
$inthelper = pack("V", $value);
|
||||
$v = unpack("f", $inthelper);
|
||||
return $v[1];
|
||||
break;
|
||||
case self::__DOUBLE:
|
||||
$inthelper = pack("VV", $value, $value2);
|
||||
$v = unpack("d", $inthelper);
|
||||
return $v[1];
|
||||
break;
|
||||
default:
|
||||
throw new \Exception(sprintf("unexpected type %d specified", $type));
|
||||
}
|
||||
}
|
||||
|
||||
private static function validateValue($min, $max, $value, $type, $additional_notes = "") {
|
||||
if (
|
||||
!(
|
||||
($type === "byte" && $min <= ord($value) && ord($value) <= $max) ||
|
||||
($min <= $value && $value <= $max)
|
||||
)
|
||||
) {
|
||||
throw new \InvalidArgumentException(sprintf("bad number %s for type %s.%s", $value, $type, $additional_notes));
|
||||
}
|
||||
}
|
||||
}
|
25
third_party/flatbuffers/php/Constants.php
vendored
25
third_party/flatbuffers/php/Constants.php
vendored
@ -1,25 +0,0 @@
|
||||
<?php
|
||||
/*
|
||||
* Copyright 2015 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
namespace Google\FlatBuffers;
|
||||
|
||||
class Constants
|
||||
{
|
||||
const SIZEOF_SHORT = 2;
|
||||
const SIZEOF_INT = 4;
|
||||
const FILE_IDENTIFIER_LENGTH = 4;
|
||||
}
|
977
third_party/flatbuffers/php/FlatbufferBuilder.php
vendored
977
third_party/flatbuffers/php/FlatbufferBuilder.php
vendored
@ -1,977 +0,0 @@
|
||||
<?php
|
||||
/*
|
||||
* Copyright 2015 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/// @file
|
||||
/// @addtogroup flatbuffers_php_api
|
||||
/// @{
|
||||
|
||||
namespace Google\FlatBuffers;
|
||||
|
||||
final class FlatbufferBuilder
|
||||
{
|
||||
/**
|
||||
* Internal ByteBuffer for the FlatBuffer data.
|
||||
* @var ByteBuffer $bb
|
||||
*/
|
||||
public $bb;
|
||||
|
||||
/// @cond FLATBUFFERS_INTERNAL
|
||||
/**
|
||||
* @var int $space
|
||||
*/
|
||||
protected $space;
|
||||
|
||||
/**
|
||||
* @var int $minalign
|
||||
*/
|
||||
protected $minalign = 1;
|
||||
|
||||
/**
|
||||
* @var array $vtable
|
||||
*/
|
||||
protected $vtable;
|
||||
|
||||
/**
|
||||
* @var int $vtable_in_use
|
||||
*/
|
||||
protected $vtable_in_use = 0;
|
||||
|
||||
/**
|
||||
* @var bool $nested
|
||||
*/
|
||||
protected $nested = false;
|
||||
|
||||
/**
|
||||
* @var int $object_start
|
||||
*/
|
||||
protected $object_start;
|
||||
|
||||
/**
|
||||
* @var array $vtables
|
||||
*/
|
||||
protected $vtables = array();
|
||||
|
||||
/**
|
||||
* @var int $num_vtables
|
||||
*/
|
||||
protected $num_vtables = 0;
|
||||
|
||||
/**
|
||||
* @var int $vector_num_elems
|
||||
*/
|
||||
protected $vector_num_elems = 0;
|
||||
|
||||
/**
|
||||
* @var bool $force_defaults
|
||||
*/
|
||||
protected $force_defaults = false;
|
||||
/// @endcond
|
||||
|
||||
/**
|
||||
* Create a FlatBufferBuilder with a given initial size.
|
||||
*
|
||||
* @param $initial_size initial byte buffer size.
|
||||
*/
|
||||
public function __construct($initial_size)
|
||||
{
|
||||
if ($initial_size <= 0) {
|
||||
$initial_size = 1;
|
||||
}
|
||||
$this->space = $initial_size;
|
||||
$this->bb = $this->newByteBuffer($initial_size);
|
||||
}
|
||||
|
||||
/// @cond FLATBUFFERS_INTERNAL
|
||||
/**
|
||||
* create new bytebuffer
|
||||
*
|
||||
* @param $size
|
||||
* @return ByteBuffer
|
||||
*/
|
||||
private function newByteBuffer($size)
|
||||
{
|
||||
return new ByteBuffer($size);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current ByteBuffer offset.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function offset()
|
||||
{
|
||||
return $this->bb->capacity() - $this->space;
|
||||
}
|
||||
|
||||
/**
|
||||
* padding buffer
|
||||
*
|
||||
* @param $byte_size
|
||||
*/
|
||||
public function pad($byte_size)
|
||||
{
|
||||
for ($i = 0; $i < $byte_size; $i++) {
|
||||
$this->bb->putByte(--$this->space, "\0");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* prepare bytebuffer
|
||||
*
|
||||
* @param $size
|
||||
* @param $additional_bytes
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function prep($size, $additional_bytes)
|
||||
{
|
||||
if ($size > $this->minalign) {
|
||||
$this->minalign = $size;
|
||||
}
|
||||
|
||||
$align_size = ((~($this->bb->capacity() - $this->space + $additional_bytes)) + 1) & ($size - 1);
|
||||
while ($this->space < $align_size + $size + $additional_bytes) {
|
||||
$old_buf_size = $this->bb->capacity();
|
||||
$this->bb = $this->growByteBuffer($this->bb);
|
||||
$this->space += $this->bb->capacity() - $old_buf_size;
|
||||
}
|
||||
|
||||
$this->pad($align_size);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ByteBuffer $bb
|
||||
* @return ByteBuffer
|
||||
* @throws \Exception
|
||||
*/
|
||||
private static function growByteBuffer(ByteBuffer $bb)
|
||||
{
|
||||
$old_buf_size = $bb->capacity();
|
||||
if (($old_buf_size & 0xC0000000) != 0) {
|
||||
throw new \Exception("FlatBuffers: cannot grow buffer beyond 2 gigabytes");
|
||||
}
|
||||
$new_buf_size = $old_buf_size << 1;
|
||||
|
||||
$bb->setPosition(0);
|
||||
$nbb = new ByteBuffer($new_buf_size);
|
||||
|
||||
$nbb->setPosition($new_buf_size - $old_buf_size);
|
||||
|
||||
// TODO(chobie): is this little bit faster?
|
||||
//$nbb->_buffer = substr_replace($nbb->_buffer, $bb->_buffer, $new_buf_size - $old_buf_size, strlen($bb->_buffer));
|
||||
for ($i = $new_buf_size - $old_buf_size, $j = 0; $j < strlen($bb->_buffer); $i++, $j++) {
|
||||
$nbb->_buffer[$i] = $bb->_buffer[$j];
|
||||
}
|
||||
|
||||
return $nbb;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $x
|
||||
*/
|
||||
public function putBool($x)
|
||||
{
|
||||
$this->bb->put($this->space -= 1, chr((int)(bool)($x)));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $x
|
||||
*/
|
||||
public function putByte($x)
|
||||
{
|
||||
$this->bb->put($this->space -= 1, chr($x));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $x
|
||||
*/
|
||||
public function putSbyte($x)
|
||||
{
|
||||
$this->bb->put($this->space -= 1, chr($x));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $x
|
||||
*/
|
||||
public function putShort($x)
|
||||
{
|
||||
$this->bb->putShort($this->space -= 2, $x);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $x
|
||||
*/
|
||||
public function putUshort($x)
|
||||
{
|
||||
$this->bb->putUshort($this->space -= 2, $x);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $x
|
||||
*/
|
||||
public function putInt($x)
|
||||
{
|
||||
$this->bb->putInt($this->space -= 4, $x);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $x
|
||||
*/
|
||||
public function putUint($x)
|
||||
{
|
||||
if ($x > PHP_INT_MAX) {
|
||||
throw new \InvalidArgumentException("your platform can't handle uint correctly. use 64bit machine.");
|
||||
}
|
||||
|
||||
$this->bb->putUint($this->space -= 4, $x);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $x
|
||||
*/
|
||||
public function putLong($x)
|
||||
{
|
||||
if ($x > PHP_INT_MAX) {
|
||||
throw new \InvalidArgumentException("Your platform can't handle long correctly. Use a 64bit machine.");
|
||||
}
|
||||
|
||||
$this->bb->putLong($this->space -= 8, $x);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $x
|
||||
*/
|
||||
public function putUlong($x)
|
||||
{
|
||||
if ($x > PHP_INT_MAX) {
|
||||
throw new \InvalidArgumentException("Your platform can't handle ulong correctly. This is a php limitation. Please wait for the extension release.");
|
||||
}
|
||||
|
||||
$this->bb->putUlong($this->space -= 8, $x);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $x
|
||||
*/
|
||||
public function putFloat($x)
|
||||
{
|
||||
$this->bb->putFloat($this->space -= 4, $x);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $x
|
||||
*/
|
||||
public function putDouble($x)
|
||||
{
|
||||
$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
|
||||
|
||||
/**
|
||||
* Add a `bool` to the buffer, properly aligned, and grows the buffer (if necessary).
|
||||
* @param $x The `bool` to add to the buffer.
|
||||
*/
|
||||
public function addBool($x)
|
||||
{
|
||||
$this->prep(1, 0);
|
||||
$this->putBool($x);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a `byte` to the buffer, properly aligned, and grows the buffer (if necessary).
|
||||
* @param $x The `byte` to add to the buffer.
|
||||
*/
|
||||
public function addByte($x)
|
||||
{
|
||||
$this->prep(1, 0);
|
||||
$this->putByte($x);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a `signed byte` to the buffer, properly aligned, and grows the buffer (if necessary).
|
||||
* @param $x The `signed byte` to add to the buffer.
|
||||
*/
|
||||
public function addSbyte($x)
|
||||
{
|
||||
$this->prep(1, 0);
|
||||
$this->putSbyte($x);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a `short` to the buffer, properly aligned, and grows the buffer (if necessary).
|
||||
* @param $x The `short` to add to the buffer.
|
||||
*/
|
||||
public function addShort($x)
|
||||
{
|
||||
$this->prep(2, 0);
|
||||
$this->putShort($x);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an `unsigned short` to the buffer, properly aligned, and grows the buffer (if necessary).
|
||||
* @param $x The `unsigned short` to add to the buffer.
|
||||
*/
|
||||
public function addUshort($x)
|
||||
{
|
||||
$this->prep(2, 0);
|
||||
$this->putUshort($x);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an `int` to the buffer, properly aligned, and grows the buffer (if necessary).
|
||||
* @param $x The `int` to add to the buffer.
|
||||
*/
|
||||
public function addInt($x)
|
||||
{
|
||||
$this->prep(4, 0);
|
||||
$this->putInt($x);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an `unsigned int` to the buffer, properly aligned, and grows the buffer (if necessary).
|
||||
* @param $x The `unsigned int` to add to the buffer.
|
||||
*/
|
||||
public function addUint($x)
|
||||
{
|
||||
$this->prep(4, 0);
|
||||
$this->putUint($x);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a `long` to the buffer, properly aligned, and grows the buffer (if necessary).
|
||||
* @param $x The `long` to add to the buffer.
|
||||
*/
|
||||
public function addLong($x)
|
||||
{
|
||||
$this->prep(8, 0);
|
||||
$this->putLong($x);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an `unsigned long` to the buffer, properly aligned, and grows the buffer (if necessary).
|
||||
* @param $x The `unsigned long` to add to the buffer.
|
||||
*/
|
||||
public function addUlong($x)
|
||||
{
|
||||
$this->prep(8, 0);
|
||||
$this->putUlong($x);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a `float` to the buffer, properly aligned, and grows the buffer (if necessary).
|
||||
* @param $x The `float` to add to the buffer.
|
||||
*/
|
||||
public function addFloat($x)
|
||||
{
|
||||
$this->prep(4, 0);
|
||||
$this->putFloat($x);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a `double` to the buffer, properly aligned, and grows the buffer (if necessary).
|
||||
* @param $x The `double` to add to the buffer.
|
||||
*/
|
||||
public function addDouble($x)
|
||||
{
|
||||
$this->prep(8, 0);
|
||||
$this->putDouble($x);
|
||||
}
|
||||
|
||||
/// @cond FLATBUFFERS_INTERNAL
|
||||
/**
|
||||
* @param $o
|
||||
* @param $x
|
||||
* @param $d
|
||||
*/
|
||||
public function addBoolX($o, $x, $d)
|
||||
{
|
||||
if ($this->force_defaults || $x != $d) {
|
||||
$this->addBool($x);
|
||||
$this->slot($o);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $o
|
||||
* @param $x
|
||||
* @param $d
|
||||
*/
|
||||
public function addByteX($o, $x, $d)
|
||||
{
|
||||
if ($this->force_defaults || $x != $d) {
|
||||
$this->addByte($x);
|
||||
$this->slot($o);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $o
|
||||
* @param $x
|
||||
* @param $d
|
||||
*/
|
||||
public function addSbyteX($o, $x, $d)
|
||||
{
|
||||
if ($this->force_defaults || $x != $d) {
|
||||
$this->addSbyte($x);
|
||||
$this->slot($o);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $o
|
||||
* @param $x
|
||||
* @param $d
|
||||
*/
|
||||
public function addShortX($o, $x, $d)
|
||||
{
|
||||
if ($this->force_defaults || $x != $d) {
|
||||
$this->addShort($x);
|
||||
$this->slot($o);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $o
|
||||
* @param $x
|
||||
* @param $d
|
||||
*/
|
||||
public function addUshortX($o, $x, $d)
|
||||
{
|
||||
if ($this->force_defaults || $x != $d) {
|
||||
$this->addUshort($x);
|
||||
$this->slot($o);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $o
|
||||
* @param $x
|
||||
* @param $d
|
||||
*/
|
||||
public function addIntX($o, $x, $d)
|
||||
{
|
||||
if ($this->force_defaults || $x != $d) {
|
||||
$this->addInt($x);
|
||||
$this->slot($o);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $o
|
||||
* @param $x
|
||||
* @param $d
|
||||
*/
|
||||
public function addUintX($o, $x, $d)
|
||||
{
|
||||
if ($this->force_defaults || $x != $d) {
|
||||
$this->addUint($x);
|
||||
$this->slot($o);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $o
|
||||
* @param $x
|
||||
* @param $d
|
||||
*/
|
||||
public function addLongX($o, $x, $d)
|
||||
{
|
||||
if ($this->force_defaults || $x != $d) {
|
||||
$this->addLong($x);
|
||||
$this->slot($o);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $o
|
||||
* @param $x
|
||||
* @param $d
|
||||
*/
|
||||
public function addUlongX($o, $x, $d)
|
||||
{
|
||||
if ($this->force_defaults || $x != $d) {
|
||||
$this->addUlong($x);
|
||||
$this->slot($o);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $o
|
||||
* @param $x
|
||||
* @param $d
|
||||
*/
|
||||
public function addFloatX($o, $x, $d)
|
||||
{
|
||||
if ($this->force_defaults || $x != $d) {
|
||||
$this->addFloat($x);
|
||||
$this->slot($o);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $o
|
||||
* @param $x
|
||||
* @param $d
|
||||
*/
|
||||
public function addDoubleX($o, $x, $d)
|
||||
{
|
||||
if ($this->force_defaults || $x != $d) {
|
||||
$this->addDouble($x);
|
||||
$this->slot($o);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $o
|
||||
* @param $x
|
||||
* @param $d
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function addOffsetX($o, $x, $d)
|
||||
{
|
||||
if ($this->force_defaults || $x != $d) {
|
||||
$this->addOffset($x);
|
||||
$this->slot($o);
|
||||
}
|
||||
}
|
||||
/// @endcond
|
||||
|
||||
/**
|
||||
* Adds on offset, relative to where it will be written.
|
||||
* @param $off The offset to add to the buffer.
|
||||
* @throws \Exception Throws an exception if `$off` is greater than the underlying ByteBuffer's
|
||||
* offest.
|
||||
*/
|
||||
public function addOffset($off)
|
||||
{
|
||||
$this->prep(Constants::SIZEOF_INT, 0); // Ensure alignment is already done
|
||||
if ($off > $this->offset()) {
|
||||
throw new \Exception("");
|
||||
}
|
||||
$this->putOffset($off);
|
||||
}
|
||||
|
||||
/// @cond FLATBUFFERS_INTERNAL
|
||||
/**
|
||||
* @param $elem_size
|
||||
* @param $num_elems
|
||||
* @param $alignment
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function startVector($elem_size, $num_elems, $alignment)
|
||||
{
|
||||
$this->notNested();
|
||||
$this->vector_num_elems = $num_elems;
|
||||
$this->prep(Constants::SIZEOF_INT, $elem_size * $num_elems);
|
||||
$this->prep($alignment, $elem_size * $num_elems); // Just in case alignemnt > int;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function endVector()
|
||||
{
|
||||
$this->putUint($this->vector_num_elems);
|
||||
return $this->offset();
|
||||
}
|
||||
|
||||
protected function is_utf8($bytes)
|
||||
{
|
||||
if (function_exists('mb_detect_encoding')) {
|
||||
return (bool) mb_detect_encoding($bytes, 'UTF-8', true);
|
||||
}
|
||||
|
||||
$len = strlen($bytes);
|
||||
if ($len < 1) {
|
||||
/* NOTE: always return 1 when passed string is null */
|
||||
return true;
|
||||
}
|
||||
|
||||
for ($j = 0, $i = 0; $i < $len; $i++) {
|
||||
// check ACII
|
||||
if ($bytes[$j] == "\x09" ||
|
||||
$bytes[$j] == "\x0A" ||
|
||||
$bytes[$j] == "\x0D" ||
|
||||
($bytes[$j] >= "\x20" && $bytes[$j] <= "\x7E")) {
|
||||
$j++;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* non-overlong 2-byte */
|
||||
if ((($i+1) <= $len) &&
|
||||
($bytes[$j] >= "\xC2" && $bytes[$j] <= "\xDF" &&
|
||||
($bytes[$j+1] >= "\x80" && $bytes[$j+1] <= "\xBF"))) {
|
||||
$j += 2;
|
||||
$i++;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* excluding overlongs */
|
||||
if ((($i + 2) <= $len) &&
|
||||
$bytes[$j] == "\xE0" &&
|
||||
($bytes[$j+1] >= "\xA0" && $bytes[$j+1] <= "\xBF" &&
|
||||
($bytes[$j+2] >= "\x80" && $bytes[$j+2] <= "\xBF"))) {
|
||||
$bytes += 3;
|
||||
$i +=2;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* straight 3-byte */
|
||||
if ((($i+2) <= $len) &&
|
||||
(($bytes[$j] >= "\xE1" && $bytes[$j] <= "\xEC") ||
|
||||
$bytes[$j] == "\xEE" ||
|
||||
$bytes[$j] = "\xEF") &&
|
||||
($bytes[$j+1] >= "\x80" && $bytes[$j+1] <= "\xBF") &&
|
||||
($bytes[$j+2] >= "\x80" && $bytes[$j+2] <= "\xBF")) {
|
||||
$j += 3;
|
||||
$i += 2;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* excluding surrogates */
|
||||
if ((($i+2) <= $len) &&
|
||||
$bytes[$j] == "\xED" &&
|
||||
($bytes[$j+1] >= "\x80" && $bytes[$j+1] <= "\x9f" &&
|
||||
($bytes[$j+2] >= "\x80" && $bytes[$j+2] <= "\xBF"))) {
|
||||
$j += 3;
|
||||
$i += 2;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* planes 1-3 */
|
||||
if ((($i + 3) <= $len) &&
|
||||
$bytes[$j] == "\xF0" &&
|
||||
($bytes[$j+1] >= "\x90" && $bytes[$j+1] <= "\xBF") &&
|
||||
($bytes[$j+2] >= "\x80" && $bytes[$j+2] <= "\xBF") &&
|
||||
($bytes[$j+3] >= "\x80" && $bytes[$j+3] <= "\xBF")) {
|
||||
$j += 4;
|
||||
$i += 3;
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
/* planes 4-15 */
|
||||
if ((($i+3) <= $len) &&
|
||||
$bytes[$j] >= "\xF1" && $bytes[$j] <= "\xF3" &&
|
||||
$bytes[$j+1] >= "\x80" && $bytes[$j+1] <= "\xBF" &&
|
||||
$bytes[$j+2] >= "\x80" && $bytes[$j+2] <= "\xBF" &&
|
||||
$bytes[$j+3] >= "\x80" && $bytes[$j+3] <= "\xBF"
|
||||
) {
|
||||
$j += 4;
|
||||
$i += 3;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* plane 16 */
|
||||
if ((($i+3) <= $len) &&
|
||||
$bytes[$j] == "\xF4" &&
|
||||
($bytes[$j+1] >= "\x80" && $bytes[$j+1] <= "\x8F") &&
|
||||
($bytes[$j+2] >= "\x80" && $bytes[$j+2] <= "\xBF") &&
|
||||
($bytes[$j+3] >= "\x80" && $bytes[$j+3] <= "\xBF")
|
||||
) {
|
||||
$bytes += 4;
|
||||
$i += 3;
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
/// @endcond
|
||||
|
||||
/**
|
||||
* Encode the string `$s` in the buffer using UTF-8.
|
||||
* @param string $s The string to encode.
|
||||
* @return int The offset in the buffer where the encoded string starts.
|
||||
* @throws InvalidArgumentException Thrown if the input string `$s` is not
|
||||
* UTF-8.
|
||||
*/
|
||||
public function createString($s)
|
||||
{
|
||||
if (!$this->is_utf8($s)) {
|
||||
throw new \InvalidArgumentException("string must be utf-8 encoded value.");
|
||||
}
|
||||
|
||||
$this->notNested();
|
||||
$this->addByte(0); // null terminated
|
||||
$this->startVector(1, strlen($s), 1);
|
||||
$this->space -= strlen($s);
|
||||
for ($i = $this->space, $j = 0 ; $j < strlen($s) ; $i++, $j++) {
|
||||
$this->bb->_buffer[$i] = $s[$j];
|
||||
}
|
||||
return $this->endVector();
|
||||
}
|
||||
|
||||
/// @cond FLATBUFFERS_INTERNAL
|
||||
/**
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function notNested()
|
||||
{
|
||||
if ($this->nested) {
|
||||
throw new \Exception("FlatBuffers; object serialization must not be nested");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $obj
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function nested($obj)
|
||||
{
|
||||
if ($obj != $this->offset()) {
|
||||
throw new \Exception("FlatBuffers: struct must be serialized inline");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $numfields
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function startObject($numfields)
|
||||
{
|
||||
$this->notNested();
|
||||
if ($this->vtable == null || count($this->vtable) < $numfields) {
|
||||
$this->vtable = array();
|
||||
}
|
||||
|
||||
$this->vtable_in_use = $numfields;
|
||||
for ($i = 0; $i < $numfields; $i++) {
|
||||
$this->vtable[$i] = 0;
|
||||
}
|
||||
|
||||
$this->nested = true;
|
||||
$this->object_start = $this->offset();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $voffset
|
||||
* @param $x
|
||||
* @param $d
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function addStructX($voffset, $x, $d)
|
||||
{
|
||||
if ($x != $d) {
|
||||
$this->nested($x);
|
||||
$this->slot($voffset);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $voffset
|
||||
* @param $x
|
||||
* @param $d
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function addStruct($voffset, $x, $d)
|
||||
{
|
||||
if ($x != $d) {
|
||||
$this->nested($x);
|
||||
$this->slot($voffset);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $voffset
|
||||
*/
|
||||
public function slot($voffset)
|
||||
{
|
||||
$this->vtable[$voffset] = $this->offset();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function endObject()
|
||||
{
|
||||
if ($this->vtable == null || !$this->nested) {
|
||||
throw new \Exception("FlatBuffers: endObject called without startObject");
|
||||
}
|
||||
|
||||
$this->addInt(0);
|
||||
$vtableloc = $this->offset();
|
||||
|
||||
$i = $this->vtable_in_use -1;
|
||||
// Trim trailing zeroes.
|
||||
for (; $i >= 0 && $this->vtable[$i] == 0; $i--) {}
|
||||
$trimmed_size = $i + 1;
|
||||
for (; $i >= 0; $i--) {
|
||||
$off = ($this->vtable[$i] != 0) ? $vtableloc - $this->vtable[$i] : 0;
|
||||
$this->addShort($off);
|
||||
}
|
||||
|
||||
$standard_fields = 2; // the fields below
|
||||
$this->addShort($vtableloc - $this->object_start);
|
||||
$this->addShort(($trimmed_size + $standard_fields) * Constants::SIZEOF_SHORT);
|
||||
|
||||
// search for an existing vtable that matches the current one.
|
||||
$existing_vtable = 0;
|
||||
|
||||
for ($i = 0; $i < $this->num_vtables; $i++) {
|
||||
$vt1 = $this->bb->capacity() - $this->vtables[$i];
|
||||
$vt2 = $this->space;
|
||||
|
||||
$len = $this->bb->getShort($vt1);
|
||||
|
||||
if ($len == $this->bb->getShort($vt2)) {
|
||||
for ($j = Constants::SIZEOF_SHORT; $j < $len; $j += Constants::SIZEOF_SHORT) {
|
||||
if ($this->bb->getShort($vt1 + $j) != $this->bb->getShort($vt2 + $j)) {
|
||||
continue 2;
|
||||
}
|
||||
}
|
||||
$existing_vtable = $this->vtables[$i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ($existing_vtable != 0) {
|
||||
// Found a match:
|
||||
// Remove the current vtable
|
||||
$this->space = $this->bb->capacity() - $vtableloc;
|
||||
$this->bb->putInt($this->space, $existing_vtable - $vtableloc);
|
||||
} else {
|
||||
// No Match:
|
||||
// Add the location of the current vtable to the list of vtables
|
||||
if ($this->num_vtables == count($this->vtables)) {
|
||||
$vtables = $this->vtables;
|
||||
$this->vtables = array();
|
||||
// copy of
|
||||
for ($i = 0; $i < count($vtables) * 2; $i++) {
|
||||
$this->vtables[$i] = ($i < count($vtables)) ? $vtables[$i] : 0;
|
||||
}
|
||||
}
|
||||
$this->vtables[$this->num_vtables++] = $this->offset();
|
||||
$this->bb->putInt($this->bb->capacity() - $vtableloc, $this->offset() - $vtableloc);
|
||||
}
|
||||
|
||||
$this->nested = false;
|
||||
$this->vtable = null;
|
||||
return $vtableloc;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $table
|
||||
* @param $field
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function required($table, $field)
|
||||
{
|
||||
$table_start = $this->bb->capacity() - $table;
|
||||
$vtable_start = $table_start - $this->bb->getInt($table_start);
|
||||
$ok = $this->bb->getShort($vtable_start + $field) != 0;
|
||||
|
||||
if (!$ok) {
|
||||
throw new \Exception("FlatBuffers: field " . $field . " must be set");
|
||||
}
|
||||
}
|
||||
/// @endcond
|
||||
|
||||
/**
|
||||
* Finalize a buffer, pointing to the given `$root_table`.
|
||||
* @param $root_table An offest to be added to the buffer.
|
||||
* @param $file_identifier A FlatBuffer file identifier to be added to the
|
||||
* buffer before `$root_table`. This defaults to `null`.
|
||||
* @throws InvalidArgumentException Thrown if an invalid `$identifier` is
|
||||
* given, where its length is not equal to
|
||||
* `Constants::FILE_IDENTIFIER_LENGTH`.
|
||||
*/
|
||||
public function finish($root_table, $identifier = null)
|
||||
{
|
||||
if ($identifier == null) {
|
||||
$this->prep($this->minalign, Constants::SIZEOF_INT);
|
||||
$this->addOffset($root_table);
|
||||
$this->bb->setPosition($this->space);
|
||||
} else {
|
||||
$this->prep($this->minalign, Constants::SIZEOF_INT + Constants::FILE_IDENTIFIER_LENGTH);
|
||||
if (strlen($identifier) != Constants::FILE_IDENTIFIER_LENGTH) {
|
||||
throw new \InvalidArgumentException(
|
||||
sprintf("FlatBuffers: file identifier must be length %d",
|
||||
Constants::FILE_IDENTIFIER_LENGTH));
|
||||
}
|
||||
|
||||
for ($i = Constants::FILE_IDENTIFIER_LENGTH - 1; $i >= 0;
|
||||
$i--) {
|
||||
$this->addByte(ord($identifier[$i]));
|
||||
}
|
||||
$this->finish($root_table);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* In order to save space, fields that are set to their default value don't
|
||||
* get serialized into the buffer.
|
||||
* @param bool $forceDefaults When set to `true`, always serializes default
|
||||
* values.
|
||||
*/
|
||||
public function forceDefaults($forceDefaults)
|
||||
{
|
||||
$this->force_defaults = $forceDefaults;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the ByteBuffer representing the FlatBuffer.
|
||||
* @return ByteBuffer The ByteBuffer containing the FlatBuffer data.
|
||||
*/
|
||||
public function dataBuffer()
|
||||
{
|
||||
return $this->bb;
|
||||
}
|
||||
|
||||
/// @cond FLATBUFFERS_INTERNAL
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function dataStart()
|
||||
{
|
||||
return $this->space;
|
||||
}
|
||||
/// @endcond
|
||||
|
||||
/**
|
||||
* Utility function to copy and return the FlatBuffer data from the
|
||||
* underlying ByteBuffer.
|
||||
* @return string A string (representing a byte[]) that contains a copy
|
||||
* of the FlatBuffer data.
|
||||
*/
|
||||
public function sizedByteArray()
|
||||
{
|
||||
$start = $this->space;
|
||||
$length = $this->bb->capacity() - $this->space;
|
||||
|
||||
$result = str_repeat("\0", $length);
|
||||
$this->bb->setPosition($start);
|
||||
$this->bb->getX($result);
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
|
||||
/// @}
|
41
third_party/flatbuffers/php/Struct.php
vendored
41
third_party/flatbuffers/php/Struct.php
vendored
@ -1,41 +0,0 @@
|
||||
<?php
|
||||
/*
|
||||
* Copyright 2015 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
namespace Google\FlatBuffers;
|
||||
|
||||
abstract class Struct
|
||||
{
|
||||
/**
|
||||
* @var int $bb_pos
|
||||
*/
|
||||
protected $bb_pos;
|
||||
|
||||
/**
|
||||
* @var ByteBuffer $bb
|
||||
*/
|
||||
protected $bb;
|
||||
|
||||
public function setByteBufferPos($pos)
|
||||
{
|
||||
$this->bb_pos = $pos;
|
||||
}
|
||||
|
||||
public function setByteBuffer($bb)
|
||||
{
|
||||
$this->bb = $bb;
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user