Remove some unused fbs files

This commit is contained in:
Siarhei Fedartsou 2024-07-09 19:53:09 +02:00
parent 9428761137
commit d74eaafe64
155 changed files with 0 additions and 33132 deletions

View File

@ -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!

View File

@ -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!

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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 }}"

View File

@ -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

View File

@ -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 }}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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.

View File

@ -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).

View File

@ -1 +0,0 @@
include: package:lints/recommended.yaml

View File

@ -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;
}

View File

@ -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;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,2 +0,0 @@
export 'src/builder.dart';
export 'src/reference.dart';

View File

@ -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;
}
}

View File

@ -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;
}

View File

@ -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);
}
}

View File

@ -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

View File

@ -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

View File

@ -1,10 +0,0 @@
// Test for #7355
table Foo {
my_foo : foo_properties;
}
struct foo_properties
{
a : bool;
b : bool;
}

View File

@ -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;
}
}

View File

@ -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);
}
}

View File

@ -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]);
});
}

View File

@ -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
]));
}

View File

@ -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);
});
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -1,10 +0,0 @@
enum OptionsEnum : uint32
{
A = 1,
B = 2,
C = 3
}
table MyTable {
options : [OptionsEnum];
}

View File

@ -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;
}
}

View File

@ -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";

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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
```

View File

@ -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)
}

View File

@ -1,5 +0,0 @@
module echo
go 1.19
require github.com/google/flatbuffers v22.10.26+incompatible

View File

@ -1,6 +0,0 @@
namespace hero;
table Warrior {
name: string;
hp: uint32;
}

View File

@ -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()
}

View File

@ -1,11 +0,0 @@
include "hero.fbs";
namespace net;
table Request {
player: hero.Warrior;
}
table Response {
player: hero.Warrior;
}

View File

@ -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()
}

View File

@ -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()
}

View File

@ -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)
}

View File

@ -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"],
)

View File

@ -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)
}

View File

@ -1,3 +0,0 @@
// Package flatbuffers provides facilities to read and write flatbuffers
// objects.
package flatbuffers

View File

@ -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))
}

View File

@ -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)
}

View File

@ -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
}

View File

@ -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))
}

View File

@ -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
}

View File

@ -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
}

View File

@ -1 +0,0 @@
This folder is intentionally empty and will contain transpiled js modules in Common JS format after compiling with tsc.

View File

@ -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")
}
}

View File

@ -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;

View File

@ -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;

View File

@ -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))
}
}
}

View File

@ -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())
}
}
}

View File

@ -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))
}

View File

@ -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)
}
}

View File

@ -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()
}

View File

@ -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())
}
}

View File

@ -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))

View File

@ -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))
}

View File

@ -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

View File

@ -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
}
}

View File

@ -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
}
}

View File

@ -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

View File

@ -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
}

View File

@ -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
)

View File

@ -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()}"
}

View File

@ -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)
}
}

View File

@ -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))
}
}

View File

@ -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)
}
}

View File

@ -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])
}
}
}
}

View File

@ -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\": \"&#34; \\u0022 %22 0x22 034 &#x22;\",\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()))
}
}
}

View File

@ -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)

View File

@ -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)

View File

@ -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]))
}
}
}

View File

@ -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:
((VV)=V)/V←,V ⌷←⍳→⍴∆∇⊃‾⍎⍕⌈
Nicer typography in plain text files:
╔══════════════════════════════════════════╗
║ ║
║ • single and “double” quotes ║
║ ║
║ • Curly apostrophes: “Weve been here” ║
║ ║
║ • Latin-1 apostrophe and accents: '´` ║
║ ║
║ • deutsche „Anführungszeichen“ ║
║ ║
║ • †, ‡, ‰, •, 34, —, 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: █
╔══╦══╗ ┌──┬──┐ ╭──┬──╮ ╭──┬──╮ ┏━━┳━━┓ ┎┒┏┑ ╷ ╻ ┏┯┓ ┌┰┐ ▊ ╱╲╱╲╳╳╳
║┌─╨─┐║ │╔═╧═╗│ │╒═╪═╕│ │╓─╁─╖│ ┃┌─╂─┐┃ ┗╃╄┙ ╶┼╴╺╋╸┠┼┨ ┝╋┥ ▋ ╲╱╲╱╳╳╳
║│╲ ╱│║ │║ ║│ ││ │ ││ │║ ┃ ║│ ┃│ ╿ │┃ ┍╅╆┓ ╵ ╹ ┗┷┛ └┸┘ ▌ ╱╲╱╲╳╳╳
╠╡ ╞╣ ├╢ ╟┤ ├┼─┼─┼┤ ├╫─╂─╫┤ ┣┿╾┼╼┿┫ ┕┛┖┚ ┌┄┄┐ ╎ ┏┅┅┓ ┋ ▍ ╲╱╲╱╳╳╳
║│╱ ╲│║ │║ ║│ ││ │ ││ │║ ┃ ║│ ┃│ ╽ │┃ ░░▒▒▓▓██ ┊ ┆ ╎ ╏ ┇ ┋ ▎
║└─╥─┘║ │╚═╤═╝│ │╘═╪═╛│ │╙─╀─╜│ ┃└─╂─┘┃ ░░▒▒▓▓██ ┊ ┆ ╎ ╏ ┇ ┋ ▏
╚══╩══╝ └──┴──┘ ╰──┴──╯ ╰──┴──╯ ┗━━┻━━┛ └╌╌┘ ╎ ┗╍╍┛ ┋ ▁▂▃▄▅▆▇█

View File

@ -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))

View File

@ -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"

View File

@ -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"}

View File

@ -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

View File

@ -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" "$@"

View File

@ -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

View File

@ -1,3 +0,0 @@
rootProject.name = "flatbuffers-kotlin"
include("flatbuffers-kotlin")
include("benchmark")

View File

@ -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.
*/

View File

@ -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));
}
}
}

View File

@ -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;
}

View File

@ -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;
}
}
/// @}

View File

@ -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