mirror of
https://github.com/simdjson/simdjson
synced 2026-06-08 17:27:07 +00:00
Compare commits
94 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| db91f62bd7 | |||
| 20cd6e30ee | |||
| e45d8edbd6 | |||
| 6efb8d81bd | |||
| f562878afc | |||
| 60aa25a0c2 | |||
| d01662560d | |||
| a63c77a977 | |||
| bbb3cb80a6 | |||
| 43219e50e0 | |||
| 49b9860899 | |||
| 0388d79770 | |||
| c0fa1aec66 | |||
| 6e61b7f6ef | |||
| a76e778804 | |||
| ccf8694510 | |||
| 9b67497ed0 | |||
| 0336684df7 | |||
| c19320dd6e | |||
| 412a5680e8 | |||
| a05a56856d | |||
| 58173a6a1f | |||
| 1721032cfd | |||
| b73877f95e | |||
| 09723897e9 | |||
| 49e231b634 | |||
| acdbbab916 | |||
| 5090247c34 | |||
| 4180e05730 | |||
| feea2bce2c | |||
| 692f43cd84 | |||
| 3240d55bcc | |||
| 66fd28fc00 | |||
| 5f638951c6 | |||
| 3e94eea939 | |||
| 0e8311f812 | |||
| 3620e9d151 | |||
| d017cd7ca4 | |||
| d9d1ff5856 | |||
| eb8f2bce14 | |||
| 2a4ff73468 | |||
| 77fc2b8447 | |||
| ba8b66a633 | |||
| 66eec5feaf | |||
| 3964f3e5d2 | |||
| ee8515122d | |||
| 5d35e7ca1f | |||
| deefc88b9c | |||
| c80dda7c58 | |||
| d2954ef68b | |||
| ac719827ff | |||
| 6ea77392a7 | |||
| e2f879751c | |||
| bf7834179c | |||
| 69ab8848bf | |||
| 7288323e36 | |||
| 3f381cf3ee | |||
| 52406402ed | |||
| 799d8e3fc9 | |||
| 6c647d9f3b | |||
| 8519e24f12 | |||
| fffb62743c | |||
| c888075f8d | |||
| 9b8aac5f22 | |||
| 40b414d184 | |||
| c85e8a7db1 | |||
| 83f390f8e7 | |||
| 82563dcf70 | |||
| 646bd3f2c3 | |||
| 4b0a908bb2 | |||
| 4c98e51c53 | |||
| 58e3d5d9cc | |||
| a22a92dc72 | |||
| c4654553dd | |||
| 5997f82c37 | |||
| bee410b315 | |||
| b115e3ef61 | |||
| 669229df5d | |||
| b6a2286e62 | |||
| 3a97c57773 | |||
| e1c6a778f8 | |||
| d413dd5b0e | |||
| a33fdc2770 | |||
| 87f5f7a250 | |||
| 9923d27994 | |||
| 876be23545 | |||
| 2028bdaeac | |||
| 1ac3a00ca9 | |||
| 6d7cc2c7c1 | |||
| 61a52287fc | |||
| 37a9aaad48 | |||
| 78325888ea | |||
| a90cb5d900 | |||
| 34a01ec3af |
@@ -0,0 +1 @@
|
||||
blank_issues_enabled: false
|
||||
@@ -18,7 +18,7 @@ We do not make changes to simdjson without clearly identifiable benefits, which
|
||||
|
||||
Is your issue:
|
||||
|
||||
1. A bug report? If so, please point at a reproducible test. Indicate whether you are willing or able to provide a bug fix as a pull request.
|
||||
1. A bug report? If so, please point at a reproducible test. Indicate whether you are willing or able to provide a bug fix as a pull request. As a matter of policy, we do not consider a compiler warning to be a bug.
|
||||
|
||||
2. A build issue? If so, provide all possible details regarding your system configuration. If we cannot reproduce your issue, we cannot fix it.
|
||||
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
name: Ubuntu ppc64le (GCC 11)
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: uraimo/run-on-arch-action@v2
|
||||
name: Test
|
||||
id: runcmd
|
||||
with:
|
||||
arch: aarch64
|
||||
distro: ubuntu_latest
|
||||
githubToken: ${{ github.token }}
|
||||
install: |
|
||||
apt-get update -q -y
|
||||
apt-get install -y cmake make g++
|
||||
run: |
|
||||
cmake -DSIMDJSON_SANITIZE_UNDEFINED=ON -DSIMDJSON_DEVELOPER_MODE=ON -DSIMDJSON_COMPETITION=OFF -B build
|
||||
cmake --build build -j=2
|
||||
ctest --output-on-failure --test-dir build
|
||||
@@ -10,7 +10,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/cache@v3
|
||||
- uses: actions/cache@v4
|
||||
with:
|
||||
path: dependencies/.cache
|
||||
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
||||
|
||||
@@ -17,7 +17,7 @@ jobs:
|
||||
fuzz-seconds: 600
|
||||
dry-run: false
|
||||
- name: Upload Crash
|
||||
uses: actions/upload-artifact@v1
|
||||
uses: actions/upload-artifact@v4
|
||||
if: failure() && steps.build.outcome == 'success'
|
||||
with:
|
||||
name: artifacts
|
||||
|
||||
@@ -24,7 +24,7 @@ jobs:
|
||||
echo "no trailing whitespace found, good!"
|
||||
fi
|
||||
- name: Archive whitespace patch
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v4
|
||||
if: always()
|
||||
with:
|
||||
name: whitespace-patch
|
||||
|
||||
@@ -34,18 +34,18 @@ jobs:
|
||||
sudo apt update
|
||||
sudo apt-get install --quiet ninja-build valgrind zip unzip lsb-release wget software-properties-common gnupg
|
||||
wget https://apt.llvm.org/llvm.sh
|
||||
sudo apt-get purge --auto-remove llvm python3-lldb-14 llvm-14
|
||||
sudo apt-get purge --auto-remove llvm python3-lldb-15 llvm-15
|
||||
chmod +x llvm.sh
|
||||
sudo ./llvm.sh $CLANGVERSION
|
||||
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: actions/cache@v3
|
||||
- uses: actions/cache@v4
|
||||
with:
|
||||
path: dependencies/.cache
|
||||
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
||||
|
||||
- uses: actions/cache@v3
|
||||
- uses: actions/cache@v4
|
||||
id: cache-corpus
|
||||
with:
|
||||
path: out/
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
name: LoongArch64-CI
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
loongarch64:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
platform:
|
||||
- { toolchain-version: 2023.08.08 }
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Install build requirements
|
||||
run: |
|
||||
sudo apt-get update -y
|
||||
sudo apt-get install -y --no-install-recommends cmake
|
||||
|
||||
- uses: actions/cache/restore@v4
|
||||
id: restore-cache
|
||||
with:
|
||||
path: /opt/cross-tools
|
||||
key: loongarch64-${{ matrix.platform.toolchain-version }}
|
||||
|
||||
- name: Download LoongArch64 gcc+glibc toolchain
|
||||
if: ${{ !steps.restore-cache.outputs.cache-hit }}
|
||||
run: |
|
||||
url="https://github.com/loongson/build-tools/releases/download/${{ matrix.platform.toolchain-version }}/x86_64-cross-tools-loongarch64-gcc-libc.tar.xz"
|
||||
|
||||
wget "$url" -O /tmp/toolchain.tar.xz
|
||||
|
||||
mkdir -p /opt
|
||||
tar -C /opt -x -f /tmp/toolchain.tar.xz
|
||||
|
||||
- uses: actions/cache/save@v3
|
||||
if: ${{ !steps.restore-cache.outputs.cache-hit }}
|
||||
with:
|
||||
path: /opt/cross-tools
|
||||
key: loongarch64-${{ matrix.platform.toolchain-version }}
|
||||
|
||||
- name: setup Loongarch64 build environment
|
||||
run: |
|
||||
echo "/opt/cross-tools/bin" >> $GITHUB_PATH
|
||||
echo "CC=loongarch64-unknown-linux-gnu-gcc" >> $GITHUB_ENV
|
||||
echo "CXX=loongarch64-unknown-linux-gnu-g++" >> $GITHUB_ENV
|
||||
- name: configure
|
||||
run: cmake -B build -DCMAKE_SYSTEM_PROCESSOR=loongarch64 -DARCH=lonngarch64 -DCMAKE_SYSTEM_NAME=Linux -DCMAKE_C_COMPILER=loongarch64-unknown-linux-gnu-gcc -DCMAKE_CXX_COMPILER=loongarch64-unknown-linux-gnu-g++
|
||||
- name: build
|
||||
run: cmake --build build
|
||||
@@ -10,7 +10,7 @@ jobs:
|
||||
runs-on: macos-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/cache@v3
|
||||
- uses: actions/cache@v4
|
||||
with:
|
||||
path: dependencies/.cache
|
||||
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
||||
|
||||
@@ -20,12 +20,15 @@ jobs:
|
||||
- msystem: "MINGW64"
|
||||
install: mingw-w64-x86_64-libxml2 mingw-w64-x86_64-cmake mingw-w64-x86_64-ninja mingw-w64-x86_64-clang
|
||||
type: Debug
|
||||
- msystem: "MINGW64"
|
||||
install: mingw-w64-x86_64-libxml2 mingw-w64-x86_64-cmake mingw-w64-x86_64-ninja mingw-w64-x86_64-clang
|
||||
type: RelWithDebInfo
|
||||
env:
|
||||
CMAKE_GENERATOR: Ninja
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/cache@v3
|
||||
- uses: actions/cache@v4
|
||||
with:
|
||||
path: dependencies/.cache
|
||||
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
||||
|
||||
@@ -22,12 +22,15 @@ jobs:
|
||||
- msystem: "MINGW64"
|
||||
install: mingw-w64-x86_64-cmake mingw-w64-x86_64-ninja mingw-w64-x86_64-gcc
|
||||
type: Debug
|
||||
- msystem: "MINGW64"
|
||||
install: mingw-w64-x86_64-cmake mingw-w64-x86_64-ninja mingw-w64-x86_64-gcc
|
||||
type: RelWithDebInfo
|
||||
env:
|
||||
CMAKE_GENERATOR: Ninja
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/cache@v3
|
||||
- uses: actions/cache@v4
|
||||
with:
|
||||
path: dependencies/.cache
|
||||
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
||||
|
||||
@@ -1,71 +0,0 @@
|
||||
name: short fuzz on the power arch
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ master ]
|
||||
pull_request:
|
||||
branches: [ master ]
|
||||
|
||||
jobs:
|
||||
armv7_job:
|
||||
if: >-
|
||||
! contains(toJSON(github.event.commits.*.message), '[skip ci]') &&
|
||||
! contains(toJSON(github.event.commits.*.message), '[skip github]')
|
||||
# The host should always be Linux
|
||||
runs-on: ubuntu-20.04
|
||||
name: Build on ubuntu-20.04 ppc64le
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: uraimo/run-on-arch-action@v2.0.5
|
||||
name: Run commands
|
||||
id: runcmd
|
||||
env:
|
||||
DEBIAN_FRONTEND: noninteractive
|
||||
with:
|
||||
arch: ppc64le
|
||||
distro: buster
|
||||
|
||||
# Not required, but speeds up builds by storing container images in
|
||||
# a GitHub package registry.
|
||||
githubToken: ${{ github.token }}
|
||||
|
||||
run: |
|
||||
export CLANGSUFFIX="-7"
|
||||
apt-get -qq update
|
||||
apt-get install -q -y clang-7 libfuzzer-7-dev git wget zip ninja-build gnupg software-properties-common
|
||||
wget -q -O - "https://raw.githubusercontent.com/simdjson/debian-ppa/master/key.gpg" | apt-key add -
|
||||
apt-add-repository "deb https://raw.githubusercontent.com/simdjson/debian-ppa/master simdjson main"
|
||||
apt-get -qq update
|
||||
apt-get purge cmake cmake-data
|
||||
apt-get -t simdjson -y install cmake
|
||||
mkdir -p build ; cd build
|
||||
cmake .. -GNinja \
|
||||
-DCMAKE_CXX_COMPILER=clang++$CLANGSUFFIX \
|
||||
-DCMAKE_C_COMPILER=clang$CLANGSUFFIX \
|
||||
-DBUILD_SHARED_LIBS=OFF \
|
||||
-DSIMDJSON_DEVELOPER_MODE=ON \
|
||||
-DSIMDJSON_ENABLE_FUZZING=On \
|
||||
-DSIMDJSON_COMPETITION=OFF \
|
||||
-DSIMDJSON_GOOGLE_BENCHMARKS=OFF \
|
||||
-DSIMDJSON_DISABLE_DEPRECATED_API=On \
|
||||
-DSIMDJSON_FUZZ_LDFLAGS=-lFuzzer \
|
||||
-DCMAKE_CXX_FLAGS="-fsanitize=fuzzer-no-link -DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION=" \
|
||||
-DCMAKE_C_FLAGS="-fsanitize=fuzzer-no-link" \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DSIMDJSON_FUZZ_LINKMAIN=Off
|
||||
cd ..
|
||||
builddir=build
|
||||
cmake --build $builddir
|
||||
wget -O corpus.tar.gz https://readonly:readonly@www.pauldreik.se/fuzzdata/index.php?project=simdjson
|
||||
tar xf corpus.tar.gz
|
||||
fuzzernames=$(cmake --build $builddir --target print_all_fuzzernames |tail -n1)
|
||||
for fuzzer in $fuzzernames ; do
|
||||
exe=$builddir/fuzz/$fuzzer
|
||||
shortname=$(echo $fuzzer |cut -f2- -d_)
|
||||
echo found fuzzer $shortname with executable $exe
|
||||
mkdir -p out/$shortname
|
||||
others=$(find out -type d -not -name $shortname -not -name out -not -name cmin)
|
||||
$exe -max_total_time=20 -max_len=4000 out/$shortname $others
|
||||
echo "*************************************************************************"
|
||||
done
|
||||
echo "all is good, no errors found in any of these fuzzers: $fuzzernames"
|
||||
@@ -24,6 +24,6 @@ jobs:
|
||||
apt-get update -q -y
|
||||
apt-get install -y cmake make g++
|
||||
run: |
|
||||
cmake -DCMAKE_BUILD_TYPE=Release -B build
|
||||
cmake -DCMAKE_BUILD_TYPE=Release -DSIMDJSON_DEVELOPER_MODE=ON -DSIMDJSON_COMPETITION=OFF -B build
|
||||
cmake --build build -j=2
|
||||
ctest --output-on-failure --test-dir build
|
||||
|
||||
@@ -24,6 +24,6 @@ jobs:
|
||||
apt-get update -q -y
|
||||
apt-get install -y cmake make g++
|
||||
run: |
|
||||
cmake -DCMAKE_BUILD_TYPE=Release -B build
|
||||
cmake -DCMAKE_BUILD_TYPE=Release -DSIMDJSON_DEVELOPER_MODE=ON -DSIMDJSON_COMPETITION=OFF -B build
|
||||
cmake --build build -j=2
|
||||
ctest --output-on-failure --test-dir build
|
||||
|
||||
@@ -24,6 +24,6 @@ jobs:
|
||||
apt-get update -q -y
|
||||
apt-get install -y cmake make g++
|
||||
run: |
|
||||
cmake -DCMAKE_BUILD_TYPE=Release -B build
|
||||
cmake -DCMAKE_BUILD_TYPE=Release -DSIMDJSON_DEVELOPER_MODE=ON -DSIMDJSON_COMPETITION=OFF -B build
|
||||
cmake --build build -j=2
|
||||
ctest --output-on-failure --test-dir build
|
||||
|
||||
@@ -16,7 +16,7 @@ jobs:
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/cache@v3
|
||||
- uses: actions/cache@v4
|
||||
with:
|
||||
path: dependencies/.cache
|
||||
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
||||
|
||||
@@ -13,7 +13,7 @@ jobs:
|
||||
CC: gcc-8
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/cache@v3
|
||||
- uses: actions/cache@v4
|
||||
with:
|
||||
path: dependencies/.cache
|
||||
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
||||
|
||||
@@ -10,7 +10,7 @@ jobs:
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/cache@v3
|
||||
- uses: actions/cache@v4
|
||||
with:
|
||||
path: dependencies/.cache
|
||||
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
||||
|
||||
@@ -10,7 +10,7 @@ jobs:
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/cache@v3
|
||||
- uses: actions/cache@v4
|
||||
with:
|
||||
path: dependencies/.cache
|
||||
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
||||
|
||||
@@ -10,7 +10,7 @@ jobs:
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/cache@v3
|
||||
- uses: actions/cache@v4
|
||||
with:
|
||||
path: dependencies/.cache
|
||||
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
||||
@@ -28,7 +28,7 @@ jobs:
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/cache@v3
|
||||
- uses: actions/cache@v4
|
||||
with:
|
||||
path: dependencies/.cache
|
||||
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
||||
|
||||
@@ -10,7 +10,7 @@ jobs:
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/cache@v3
|
||||
- uses: actions/cache@v4
|
||||
with:
|
||||
path: dependencies/.cache
|
||||
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
||||
|
||||
@@ -10,7 +10,7 @@ jobs:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/cache@v3
|
||||
- uses: actions/cache@v4
|
||||
with:
|
||||
path: dependencies/.cache
|
||||
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
||||
|
||||
@@ -10,7 +10,7 @@ jobs:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/cache@v3
|
||||
- uses: actions/cache@v4
|
||||
with:
|
||||
path: dependencies/.cache
|
||||
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
||||
|
||||
@@ -10,7 +10,7 @@ jobs:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/cache@v3
|
||||
- uses: actions/cache@v4
|
||||
with:
|
||||
path: dependencies/.cache
|
||||
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
||||
|
||||
@@ -10,7 +10,7 @@ jobs:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/cache@v3
|
||||
- uses: actions/cache@v4
|
||||
with:
|
||||
path: dependencies/.cache
|
||||
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
name: Ubuntu 22.04 CI (GCC 13)
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
ubuntu-build:
|
||||
if: >-
|
||||
! contains(toJSON(github.event.commits.*.message), '[skip ci]') &&
|
||||
! contains(toJSON(github.event.commits.*.message), '[skip github]')
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/cache@v3
|
||||
with:
|
||||
path: dependencies/.cache
|
||||
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
||||
- name: Use cmake
|
||||
run: |
|
||||
mkdir build &&
|
||||
cd build &&
|
||||
CXX=g++-13 cmake -DSIMDJSON_DEVELOPER_MODE=ON .. &&
|
||||
cmake --build . &&
|
||||
ctest --output-on-failure -LE explicitonly -j
|
||||
@@ -9,7 +9,7 @@ jobs:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/cache@v3
|
||||
- uses: actions/cache@v4
|
||||
with:
|
||||
path: dependencies/.cache
|
||||
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
name: Ubuntu 22.04 CI (GCC 11) with Thread Sanitizer
|
||||
name: Ubuntu 22.04 CI (GCC 12) with Thread Sanitizer
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
@@ -10,7 +10,7 @@ jobs:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/cache@v3
|
||||
- uses: actions/cache@v4
|
||||
with:
|
||||
path: dependencies/.cache
|
||||
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
||||
@@ -18,7 +18,7 @@ jobs:
|
||||
run: |
|
||||
mkdir build &&
|
||||
cd build &&
|
||||
cmake -DSIMDJSON_DEVELOPER_MODE=ON -DSIMDJSON_SANITIZE_THREADS=ON .. &&
|
||||
CXX=g++-12 cmake -DSIMDJSON_DEVELOPER_MODE=ON -DSIMDJSON_SANITIZE_THREADS=ON .. &&
|
||||
cmake --build . --target document_stream_tests --target ondemand_document_stream_tests --target parse_many_test &&
|
||||
ctest --output-on-failure -R parse_many_test &&
|
||||
ctest --output-on-failure -R document_stream_tests
|
||||
@@ -10,7 +10,7 @@ jobs:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/cache@v3
|
||||
- uses: actions/cache@v4
|
||||
with:
|
||||
path: dependencies/.cache
|
||||
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
name: Ubuntu 24.04 CI (CXX 20)
|
||||
|
||||
on: [push, pull_request]
|
||||
jobs:
|
||||
ubuntu-build:
|
||||
if: >-
|
||||
! contains(toJSON(github.event.commits.*.message), '[skip ci]') &&
|
||||
! contains(toJSON(github.event.commits.*.message), '[skip github]')
|
||||
runs-on: ubuntu-24.04
|
||||
strategy:
|
||||
matrix:
|
||||
cxx: [g++-13, clang++-16]
|
||||
steps:
|
||||
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
|
||||
- name: Prepare
|
||||
run: cmake -DSIMDJSON_CXX_STANDARD=20 -DSIMDJSON_DEVELOPER_MODE=ON -B build
|
||||
env:
|
||||
CXX: ${{matrix.cxx}}
|
||||
- name: Build
|
||||
run: cmake --build build -j=2
|
||||
- name: Test
|
||||
run: ctest --output-on-failure --test-dir build
|
||||
@@ -0,0 +1,25 @@
|
||||
name: Ubuntu 24.04 CI
|
||||
|
||||
on: [push, pull_request]
|
||||
jobs:
|
||||
ubuntu-build:
|
||||
if: >-
|
||||
! contains(toJSON(github.event.commits.*.message), '[skip ci]') &&
|
||||
! contains(toJSON(github.event.commits.*.message), '[skip github]')
|
||||
runs-on: ubuntu-24.04
|
||||
strategy:
|
||||
matrix:
|
||||
shared: [ON, OFF]
|
||||
cxx: [g++-13, clang++-16]
|
||||
sanitizer: [ON, OFF]
|
||||
build_type: [RelWithDebInfo, Debug, Release]
|
||||
steps:
|
||||
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
|
||||
- name: Prepare
|
||||
run: cmake -DCMAKE_BUILD_TYPE=${{matrix.build_type}} -DSIMDJSON_DEVELOPER_MODE=ON -DSIMDJSON_SANITIZE=${{matrix.sanitizer}} -DBUILD_SHARED_LIBS=${{matrix.shared}} -B build
|
||||
env:
|
||||
CXX: ${{matrix.cxx}}
|
||||
- name: Build
|
||||
run: cmake --build build -j=2
|
||||
- name: Test
|
||||
run: ctest --output-on-failure --test-dir build
|
||||
@@ -12,10 +12,11 @@ jobs:
|
||||
include:
|
||||
- {arch: ARM}
|
||||
- {arch: ARM64}
|
||||
- {arch: ARM64EC}
|
||||
steps:
|
||||
- name: checkout
|
||||
uses: actions/checkout@v4
|
||||
- name: Use cmake
|
||||
run: |
|
||||
cmake -A ${{ matrix.arch }} -DCMAKE_CROSSCOMPILING=1 -DSIMDJSON_DEVELOPER_MODE=ON -D SIMDJSON_GOOGLE_BENCHMARKS=OFF -DSIMDJSON_EXCEPTIONS=OFF -B build &&
|
||||
cmake -A ${{ matrix.arch }} -DCMAKE_SYSTEM_VERSION="10.0.22621.0" -DCMAKE_CROSSCOMPILING=1 -DSIMDJSON_DEVELOPER_MODE=ON -D SIMDJSON_GOOGLE_BENCHMARKS=OFF -DSIMDJSON_EXCEPTIONS=OFF -B build &&
|
||||
cmake --build build --verbose
|
||||
@@ -13,10 +13,12 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- {gen: Visual Studio 17 2022, arch: Win32, shared: ON}
|
||||
- {gen: Visual Studio 17 2022, arch: Win32, shared: OFF}
|
||||
- {gen: Visual Studio 17 2022, arch: x64, shared: ON}
|
||||
- {gen: Visual Studio 17 2022, arch: x64, shared: OFF}
|
||||
- {gen: Visual Studio 17 2022, arch: Win32, shared: ON, build_type: Release}
|
||||
- {gen: Visual Studio 17 2022, arch: Win32, shared: OFF, build_type: Release}
|
||||
- {gen: Visual Studio 17 2022, arch: x64, shared: ON, build_type: Release}
|
||||
- {gen: Visual Studio 17 2022, arch: x64, shared: OFF, build_type: Debug}
|
||||
- {gen: Visual Studio 17 2022, arch: x64, shared: OFF, build_type: Release}
|
||||
- {gen: Visual Studio 17 2022, arch: x64, shared: OFF, build_type: RelWithDebInfo}
|
||||
steps:
|
||||
- name: checkout
|
||||
uses: actions/checkout@v4
|
||||
@@ -24,21 +26,15 @@ jobs:
|
||||
run: |
|
||||
cmake -G "${{matrix.gen}}" -A ${{matrix.arch}} -DSIMDJSON_DEVELOPER_MODE=ON -DSIMDJSON_COMPETITION=OFF -DBUILD_SHARED_LIBS=${{matrix.shared}} -B build
|
||||
- name: Build Debug
|
||||
run: cmake --build build --config Debug --verbose
|
||||
- name: Build Release
|
||||
run: cmake --build build --config Release --verbose
|
||||
- name: Run Release tests
|
||||
run: cmake --build build --config ${{matrix.build_type}} --verbose
|
||||
- name: Run tests
|
||||
run: |
|
||||
cd build
|
||||
ctest -C Release -LE explicitonly --output-on-failure
|
||||
- name: Run Debug tests
|
||||
run: |
|
||||
cd build
|
||||
ctest -C Debug -LE explicitonly --output-on-failure
|
||||
ctest -C ${{matrix.build_type}} -LE explicitonly --output-on-failure
|
||||
- name: Install
|
||||
run: |
|
||||
cmake --install build --config Release
|
||||
cmake --install build --config ${{matrix.build_type}}
|
||||
- name: Test Installation
|
||||
run: |
|
||||
cmake -G "${{matrix.gen}}" -A ${{matrix.arch}} -B build_install_test tests/installation_tests/find
|
||||
cmake --build build_install_test --config Release
|
||||
cmake --build build_install_test --config ${{matrix.build_type}}
|
||||
@@ -0,0 +1,37 @@
|
||||
name: VS17-CLANG-CI
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
ci:
|
||||
if: >-
|
||||
! contains(toJSON(github.event.commits.*.message), '[skip ci]') &&
|
||||
! contains(toJSON(github.event.commits.*.message), '[skip github]')
|
||||
name: windows-vs17
|
||||
runs-on: windows-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- {gen: Visual Studio 17 2022, arch: x64, build_type: Debug}
|
||||
- {gen: Visual Studio 17 2022, arch: x64, build_type: Release}
|
||||
- {gen: Visual Studio 17 2022, arch: x64, build_type: RelWithDebInfo}
|
||||
steps:
|
||||
- name: checkout
|
||||
uses: actions/checkout@v4
|
||||
- name: Configure
|
||||
run: |
|
||||
cmake -G "${{matrix.gen}}" -A ${{matrix.arch}} -T ClangCL -DSIMDJSON_DEVELOPER_MODE=ON -DSIMDJSON_COMPETITION=OFF -B build
|
||||
- name: Build
|
||||
run: cmake --build build --config ${{matrix.build_type}} --verbose
|
||||
- name: Run tests
|
||||
run: |
|
||||
cd build
|
||||
ctest -C ${{matrix.build_type}} -LE explicitonly --output-on-failure
|
||||
- name: Install
|
||||
run: |
|
||||
cmake --install build --config ${{matrix.build_type}}
|
||||
- name: Test Installation
|
||||
run: |
|
||||
cmake -G "${{matrix.gen}}" -A ${{matrix.arch}} -B build_install_test tests/installation_tests/find
|
||||
cmake --build build_install_test --config ${{matrix.build_type}}
|
||||
@@ -13,29 +13,25 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- {gen: Visual Studio 17 2022, arch: x64}
|
||||
- {gen: Visual Studio 17 2022, arch: x64, build_type: Debug}
|
||||
- {gen: Visual Studio 17 2022, arch: x64, build_type: Release}
|
||||
- {gen: Visual Studio 17 2022, arch: x64, build_type: RelWithDebInfo}
|
||||
steps:
|
||||
- name: checkout
|
||||
uses: actions/checkout@v4
|
||||
- name: Configure
|
||||
run: |
|
||||
cmake -G "${{matrix.gen}}" -A ${{matrix.arch}} -T ClangCL -DSIMDJSON_DEVELOPER_MODE=ON -DSIMDJSON_COMPETITION=OFF -B build
|
||||
- name: Build Debug
|
||||
run: cmake --build build --config Debug --verbose
|
||||
- name: Build Release
|
||||
run: cmake --build build --config Release --verbose
|
||||
- name: Run Release tests
|
||||
- name: Build
|
||||
run: cmake --build build --config ${{matrix.build_type}} --verbose
|
||||
- name: Run tests
|
||||
run: |
|
||||
cd build
|
||||
ctest -C Release -LE explicitonly --output-on-failure
|
||||
- name: Run Debug tests
|
||||
run: |
|
||||
cd build
|
||||
ctest -C Debug -LE explicitonly --output-on-failure
|
||||
ctest -C ${{matrix.build_type}} -LE explicitonly --output-on-failure
|
||||
- name: Install
|
||||
run: |
|
||||
cmake --install build --config Release
|
||||
cmake --install build --config ${{matrix.build_type}}
|
||||
- name: Test Installation
|
||||
run: |
|
||||
cmake -G "${{matrix.gen}}" -A ${{matrix.arch}} -B build_install_test tests/installation_tests/find
|
||||
cmake --build build_install_test --config Release
|
||||
cmake --build build_install_test --config ${{matrix.build_type}}
|
||||
@@ -8,7 +8,7 @@ jobs:
|
||||
runs-on: windows-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/cache@v3
|
||||
- uses: actions/cache@v4
|
||||
with:
|
||||
path: dependencies/.cache
|
||||
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
||||
|
||||
Vendored
+24
-1
@@ -103,6 +103,29 @@
|
||||
"charconv": "cpp",
|
||||
"source_location": "cpp",
|
||||
"strstream": "cpp",
|
||||
"typeindex": "cpp"
|
||||
"typeindex": "cpp",
|
||||
"*.tcc": "cpp",
|
||||
"memory_resource": "cpp",
|
||||
"numbers": "cpp",
|
||||
"semaphore": "cpp",
|
||||
"stop_token": "cpp",
|
||||
"cfenv": "cpp",
|
||||
"format": "cpp",
|
||||
"xlocmes": "cpp",
|
||||
"xlocmon": "cpp",
|
||||
"xlocnum": "cpp",
|
||||
"xloctime": "cpp",
|
||||
"xutility": "cpp",
|
||||
"coroutine": "cpp",
|
||||
"xfacet": "cpp",
|
||||
"xhash": "cpp",
|
||||
"xiosbase": "cpp",
|
||||
"xlocale": "cpp",
|
||||
"xlocbuf": "cpp",
|
||||
"xlocinfo": "cpp",
|
||||
"xmemory": "cpp",
|
||||
"xstring": "cpp",
|
||||
"xtr1common": "cpp",
|
||||
"xtree": "cpp"
|
||||
}
|
||||
}
|
||||
+21
-3
@@ -3,7 +3,7 @@ cmake_minimum_required(VERSION 3.14)
|
||||
project(
|
||||
simdjson
|
||||
# The version number is modified by tools/release.py
|
||||
VERSION 3.7.0
|
||||
VERSION 3.10.0
|
||||
DESCRIPTION "Parsing gigabytes of JSON per second"
|
||||
HOMEPAGE_URL "https://simdjson.org/"
|
||||
LANGUAGES CXX C
|
||||
@@ -20,8 +20,8 @@ string(
|
||||
# ---- Options, variables ----
|
||||
|
||||
# These version numbers are modified by tools/release.py
|
||||
set(SIMDJSON_LIB_VERSION "20.0.0" CACHE STRING "simdjson library version")
|
||||
set(SIMDJSON_LIB_SOVERSION "20" CACHE STRING "simdjson library soversion")
|
||||
set(SIMDJSON_LIB_VERSION "23.0.0" CACHE STRING "simdjson library version")
|
||||
set(SIMDJSON_LIB_SOVERSION "23" CACHE STRING "simdjson library soversion")
|
||||
|
||||
option(SIMDJSON_BUILD_STATIC_LIB "Build simdjson_static library along with simdjson" OFF)
|
||||
|
||||
@@ -106,6 +106,24 @@ if(
|
||||
)
|
||||
endif()
|
||||
|
||||
if(CMAKE_SYSTEM_PROCESSOR MATCHES "^(loongarch64)$")
|
||||
option(SIMDJSON_PREFER_LSX "Prefer LoongArch SX" ON)
|
||||
include(CheckCXXCompilerFlag)
|
||||
check_cxx_compiler_flag(-mlasx COMPILER_SUPPORTS_LASX)
|
||||
check_cxx_compiler_flag(-mlsx COMPILER_SUPPORTS_LSX)
|
||||
if(COMPILER_SUPPORTS_LASX AND NOT SIMDJSON_PREFER_LSX)
|
||||
simdjson_add_props(
|
||||
target_compile_options PRIVATE
|
||||
-mlasx
|
||||
)
|
||||
elseif(COMPILER_SUPPORTS_LSX)
|
||||
simdjson_add_props(
|
||||
target_compile_options PRIVATE
|
||||
-mlsx
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# GCC and Clang have horrendous Debug builds when using SIMD.
|
||||
# A common fix is to use '-Og' instead.
|
||||
# bug https://gcc.gnu.org/bugzilla/show_bug.cgi?id=54412
|
||||
|
||||
@@ -38,7 +38,7 @@ PROJECT_NAME = simdjson
|
||||
# could be handy for archiving the generated documentation or if some version
|
||||
# control system is used.
|
||||
|
||||
PROJECT_NUMBER = "3.7.0"
|
||||
PROJECT_NUMBER = "3.10.0"
|
||||
|
||||
# Using the PROJECT_BRIEF tag one can provide an optional one line description
|
||||
# for a project that appears at the top of each page and should give viewer a
|
||||
|
||||
+3
-7
@@ -88,8 +88,8 @@ simdjson's source structure, from the top level, looks like this:
|
||||
* simdjson/ondemand.h: the `simdjson::ondemand` namespace. Includes all public ondemand classes.
|
||||
* simdjson/builtin.h: the `simdjson::builtin` namespace. Aliased to the most universal implementation available.
|
||||
* simdjson/builtin/ondemand.h: the `simdjson::builtin::ondemand` namespace.
|
||||
* simdjson/arm64|fallback|haswell|icelake|ppc64|westmere/ondemand.h: the `simdjson::<implementation>::ondemand` namespace. on demand compiled for the specific implementation.
|
||||
* simdjson/generic/ondemand/*.h: individual on demand classes, generically written.
|
||||
* simdjson/arm64|fallback|haswell|icelake|ppc64|westmere/ondemand.h: the `simdjson::<implementation>::ondemand` namespace. On-Demand compiled for the specific implementation.
|
||||
* simdjson/generic/ondemand/*.h: individual On-Demand classes, generically written.
|
||||
* simdjson/generic/ondemand/dependencies.h: dependencies on common, non-implementation-specific simdjson classes. This will be included before including amalgamated.h.
|
||||
* simdjson/generic/ondemand/amalgamated.h: all generic ondemand classes for an implementation.
|
||||
* **src:** The source files for non-inlined functionality (e.g. the architecture-specific parser
|
||||
@@ -99,7 +99,7 @@ simdjson's source structure, from the top level, looks like this:
|
||||
* *.cpp: other misc. implementations, such as `simdjson::implementation` and the minifier.
|
||||
* arm64|fallback|haswell|icelake|ppc64|westmere.cpp: Architecture-specific parser implementations.
|
||||
* generic/*.h: `simdjson::<implementation>` namespace. Generic implementation of the parser, particularly the `dom_parser_implementation`.
|
||||
* generic/stage1/*.h: `simdjson::<implementation>::stage1` namespace. Generic implementation of the simd-heavy tokenizer/indexer pass of the simdjson parser. Used for the On Demand interface
|
||||
* generic/stage1/*.h: `simdjson::<implementation>::stage1` namespace. Generic implementation of the simd-heavy tokenizer/indexer pass of the simdjson parser. Used for the On-Demand interface
|
||||
* generic/stage2/*.h: `simdjson::<implementation>::stage2` namespace. Generic implementation of the tape creator, which consumes the index from stage 1 and actually parses numbers and string and such. Used for the DOM interface.
|
||||
|
||||
Other important files and directories:
|
||||
@@ -283,8 +283,6 @@ If your compiler does not default on C++11 support or better you may get failing
|
||||
|
||||
Note that the name of directory (`build`) is arbitrary, you can name it as you want (e.g., `buildgcc`) and you can have as many different such directories as you would like (one per configuration).
|
||||
|
||||
|
||||
|
||||
## Usage (CMake on 64-bit Windows using Visual Studio 2019 or better)
|
||||
|
||||
Recent versions of Visual Studio support CMake natively, [please refer to the Visual Studio documentation](https://learn.microsoft.com/en-us/cpp/build/cmake-projects-in-visual-studio?view=msvc-170).
|
||||
@@ -309,13 +307,11 @@ Though having Visual Studio installed is necessary, one can build simdjson using
|
||||
|
||||
Furthermore, if you have installed LLVM clang on Windows, for example as a component of Visual Studio 2019, you can configure and build simdjson using LLVM clang on Windows using cmake:
|
||||
|
||||
|
||||
- `mkdir build`
|
||||
- `cd build`
|
||||
- `cmake -T ClangCL ..`
|
||||
- `cmake --build . --config Release`
|
||||
|
||||
|
||||
## Various References
|
||||
|
||||
- [How to implement atoi using SIMD?](https://stackoverflow.com/questions/35127060/how-to-implement-atoi-using-simd)
|
||||
|
||||
@@ -46,6 +46,7 @@ Real-world usage
|
||||
- [Meta Velox](https://velox-lib.io)
|
||||
- [Google Pax](https://github.com/google/paxml)
|
||||
- [milvus](https://github.com/milvus-io/milvus)
|
||||
- [QuestDB](https://questdb.io/blog/questdb-release-8-0-3/)
|
||||
- [Clang Build Analyzer](https://github.com/aras-p/ClangBuildAnalyzer)
|
||||
- [Shopify HeapProfiler](https://github.com/Shopify/heap-profiler)
|
||||
- [StarRocks](https://github.com/StarRocks/starrocks)
|
||||
@@ -59,6 +60,7 @@ Real-world usage
|
||||
- [vast](https://github.com/tenzir/vast)
|
||||
- [ada-url](https://github.com/ada-url/ada)
|
||||
- [fastgron](https://github.com/adamritter/fastgron)
|
||||
- [WasmEdge](https://wasmedge.org)
|
||||
|
||||
If you are planning to use simdjson in a product, please work from one of our releases.
|
||||
|
||||
@@ -169,6 +171,7 @@ We distinguish between "bindings" (which just wrap the C++ code) and a port to a
|
||||
- [JSON-Simd](https://github.com/rawleyfowler/JSON-simd): Raku bindings.
|
||||
- [JSON::SIMD](https://metacpan.org/pod/JSON::SIMD): Perl bindings; fully-featured JSON module that uses simdjson for decoding.
|
||||
- [gemmaJSON](https://github.com/sainttttt/gemmaJSON): Nim JSON parser based on simdjson bindings.
|
||||
- [simdjson-java](https://github.com/simdjson/simdjson-java): Java port.
|
||||
|
||||
About simdjson
|
||||
--------------
|
||||
@@ -177,9 +180,9 @@ The simdjson library takes advantage of modern microarchitectures, parallelizing
|
||||
instructions, reducing branch misprediction, and reducing data dependency to take advantage of each
|
||||
CPU's multiple execution cores.
|
||||
|
||||
Our default front-end is called On Demand, and we wrote a paper about it:
|
||||
Our default front-end is called On-Demand, and we wrote a paper about it:
|
||||
|
||||
- John Keiser, Daniel Lemire, [On-Demand JSON: A Better Way to Parse Documents?](http://arxiv.org/abs/2312.17149), Software: Practice and Experience (to appear)
|
||||
- John Keiser, Daniel Lemire, [On-Demand JSON: A Better Way to Parse Documents?](http://arxiv.org/abs/2312.17149), Software: Practice and Experience 54 (6), 2024.
|
||||
|
||||
Some people [enjoy reading the first (2019) simdjson paper](https://arxiv.org/abs/1902.08318): A description of the design
|
||||
and implementation of simdjson is in our research article:
|
||||
|
||||
@@ -993,7 +993,6 @@ struct AppleEvents {
|
||||
// check permission
|
||||
int force_ctrs = 0;
|
||||
if (kpc_force_all_ctrs_get(&force_ctrs)) {
|
||||
printf("Permission denied, xnu/kpc requires root privileges.\n");
|
||||
return (worked = false);
|
||||
}
|
||||
int ret;
|
||||
|
||||
@@ -13,7 +13,7 @@ struct nlohmann_json {
|
||||
auto root = nlohmann::json::parse(json.data(), json.data() + json.size());
|
||||
for (auto tweet : root["statuses"]) {
|
||||
if (tweet["id"] == find_id) {
|
||||
result = tweet["text"];
|
||||
result = to_string(tweet["text"]);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ class OnDemand {
|
||||
public:
|
||||
OnDemand() {
|
||||
if(!displayed_implementation) {
|
||||
std::cout << "On Demand implementation: " << builtin_implementation()->name() << std::endl;
|
||||
std::cout << "On-Demand implementation: " << builtin_implementation()->name() << std::endl;
|
||||
displayed_implementation = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,8 +26,8 @@ struct nlohmann_json {
|
||||
}
|
||||
}
|
||||
|
||||
result.text = top_tweet["text"];
|
||||
result.screen_name = top_tweet["user"]["screen_name"];
|
||||
result.text = to_string(top_tweet["text"]);
|
||||
result.screen_name = to_string(top_tweet["user"]["screen_name"]);
|
||||
return result.retweet_count != -1;
|
||||
}
|
||||
};
|
||||
|
||||
Vendored
+5
-5
@@ -22,7 +22,7 @@ endif()
|
||||
# The bulk of our benchmarking and testing data has been moved simdjson/simdjson-data
|
||||
import_dependency(simdjson-data simdjson/simdjson-data a5b13babe65c1bba7186b41b43d4cbdc20a5c470)
|
||||
add_dependency(simdjson-data)
|
||||
|
||||
option(SIMDJSON_USE_BOOST_JSON "Try to include BOOST_JSON, this may break your binaries under some systems." OFF)
|
||||
# This prevents variables declared with set() from unnecessarily escaping and
|
||||
# should not be called more than once
|
||||
function(competition_scope_)
|
||||
@@ -36,8 +36,8 @@ function(competition_scope_)
|
||||
#endif
|
||||
|
||||
int main() {}
|
||||
]] USE_BOOST_JSON)
|
||||
if(USE_BOOST_JSON)
|
||||
]] SIMDJSON_FOUND_STRING_VIEW)
|
||||
if(SIMDJSON_FOUND_STRING_VIEW AND SIMDJSON_USE_BOOST_JSON)
|
||||
import_dependency(boostjson boostorg/json ee8d72d)
|
||||
add_library(boostjson STATIC "${boostjson_SOURCE_DIR}/src/src.cpp")
|
||||
target_compile_definitions(boostjson PUBLIC BOOST_JSON_STANDALONE)
|
||||
@@ -134,7 +134,7 @@ int main() {}
|
||||
add_library(competition-core INTERFACE)
|
||||
target_link_libraries(competition-core INTERFACE nlohmann_json rapidjson sajson cjson jsmn yyjson)
|
||||
|
||||
if(USE_BOOST_JSON)
|
||||
if(TARGET boostjson)
|
||||
target_compile_definitions(boostjson INTERFACE HAS_BOOST_JSON)
|
||||
target_link_libraries(competition-core INTERFACE boostjson)
|
||||
endif()
|
||||
@@ -155,6 +155,6 @@ if(SIMDJSON_CXXOPTS)
|
||||
set_off(CXXOPTS_BUILD_TESTS)
|
||||
set_off(CXXOPTS_ENABLE_INSTALL)
|
||||
|
||||
import_dependency(cxxopts jarro2783/cxxopts 794c975)
|
||||
import_dependency(cxxopts jarro2783/cxxopts 5965670)
|
||||
add_dependency(cxxopts)
|
||||
endif()
|
||||
|
||||
+465
-101
File diff suppressed because it is too large
Load Diff
+8
-2
@@ -3,7 +3,7 @@ The Document-Object-Model (DOM) front-end
|
||||
|
||||
An overview of what you need to know to use simdjson, with examples.
|
||||
|
||||
* [DOM vs On Demand](#dom-vs-on-demand)
|
||||
* [DOM vs On-Demand](#dom-vs-on-demand)
|
||||
* [The Basics: Loading and Parsing JSON Documents](#the-basics-loading-and-parsing-json-documents-using-the-dom-front-end)
|
||||
* [Using the Parsed JSON](#using-the-parsed-json)
|
||||
* [C++17 Support](#c17-support)
|
||||
@@ -18,7 +18,7 @@ An overview of what you need to know to use simdjson, with examples.
|
||||
* [Padding and Temporary Copies](#padding-and-temporary-copies)
|
||||
* [Performance Tips](#performance-tips)
|
||||
|
||||
DOM vs On Demand
|
||||
DOM vs On-Demand
|
||||
----------------------------------------------
|
||||
|
||||
The simdjson library offers two distinct approaches on how to access a JSON document. We support
|
||||
@@ -71,6 +71,12 @@ For best performance, a `parser` instance should be reused over several files: o
|
||||
If you need a lower-level interface, you may call the function `parser.parse(const char * p, size_t l)` on a pointer `p` while specifying the
|
||||
length of your input `l` in bytes. To see how to get the very best performance from a low-level approach, you way want to read our [performance notes](https://github.com/simdjson/simdjson/blob/master/doc/performance.md#padding-and-temporary-copies) on this topic (see the Padding and Temporary Copies section).
|
||||
|
||||
*Windows-specific*: Windows users who need to read files with
|
||||
non-ANSI characters in the name should set their code page to
|
||||
UTF-8 (65001). This should be the default with Windows 11 and better.
|
||||
Further, they may use the AreFileApisANSI function to determine whether
|
||||
the filename is interpreted using the ANSI or the system default OEM
|
||||
codepage, and they may call SetFileApisToOEM accordingly.
|
||||
|
||||
Using the Parsed JSON
|
||||
---------------------
|
||||
|
||||
@@ -24,6 +24,8 @@ The current implementations are:
|
||||
* westmere: SSE4.2 (2010 Westmere or later).
|
||||
* arm64: 64-bit ARMv8-A NEON
|
||||
* ppc64: 64-bit POWER8 and POWER9 with VSX and ALTIVEC extensions. Both big endian and little endian are implemented, depending on the compiler you are using. The library is tested on recent, little-endian, POWER systems.
|
||||
* lasx: Loongson Advanced SIMD EXtension (LASX), a 256-bit vector expansion for the LoongArch architecture.
|
||||
* lsx: Loongson SIMD EXtension (LSX), a 128-bit vector expansion for the LoongArch architecture.
|
||||
* fallback: A generic implementation that runs on any 64-bit processor.
|
||||
|
||||
In many cases, you don't know where your compiled binary is going to run, so simdjson automatically
|
||||
@@ -33,7 +35,7 @@ it will include 2 (ppc64 and fallback).
|
||||
|
||||
If you know more about where you're going to run and want to save the space, you can disable any of
|
||||
these implementations at compile time with `-DSIMDJSON_IMPLEMENTATION_X=0` (where X is ICELAKE, HASWELL,
|
||||
WESTMERE, ARM64, PPC64 and FALLBACK).
|
||||
WESTMERE, ARM64, PPC64, LSX, LASX and FALLBACK).
|
||||
|
||||
The simdjson library automatically sets header flags for each implementation as it compiles; there
|
||||
is no need to set architecture-specific flags yourself (e.g., `-mavx2`, `/AVX2` or
|
||||
|
||||
+30
-30
@@ -9,8 +9,8 @@ Whether we parse JSON or XML, or any other serialized format, there are relative
|
||||
- Another popular approach is the schema-based deserialization model.
|
||||
|
||||
We propose an approach that is as easy to use and often as flexible as the DOM approach, yet as fast and
|
||||
efficient as the schema-based or event-based approaches. We call this new approach "On Demand". The
|
||||
simdjson On Demand API offers a familiar, friendly DOM API and
|
||||
efficient as the schema-based or event-based approaches. We call this new approach "On-Demand". The
|
||||
simdjson On-Demand API offers a familiar, friendly DOM API and
|
||||
provides the performance of just-in-time parsing on top of the simdjson superior performance.
|
||||
|
||||
To achieve ease of use, we mimicked the *form* of a traditional DOM API: you can iterate over
|
||||
@@ -18,7 +18,7 @@ arrays, look up fields in objects, and extract native values like `double`, `uin
|
||||
|
||||
To achieve performance, we introduced some key limitations that make the DOM API *streaming*:
|
||||
array/object iteration cannot be restarted, and string/number values can only be parsed once. If
|
||||
these limitations are acceptable to you, the On Demand API could help you write maintainable
|
||||
these limitations are acceptable to you, the On-Demand API could help you write maintainable
|
||||
applications with a computation efficiency that is difficult to surpass.
|
||||
|
||||
A code example illustrates our API from a programmer's point of view:
|
||||
@@ -72,24 +72,24 @@ This streaming approach means that unused fields and values are not parsed or
|
||||
converted, thus saving space and time. In our example, the `"name"`, `"followers_count"`,
|
||||
and `"friends_count"` keys and matching values are skipped.
|
||||
|
||||
Further, the On Demand API does not parse a value *at all* until you try to convert it (e.g., to `double`,
|
||||
Further, the On-Demand API does not parse a value *at all* until you try to convert it (e.g., to `double`,
|
||||
`int`, `string`, or `bool`). In our example, when accessing the key-value pair `"retweet_count": 82`, the parser
|
||||
may not convert the pair of characters `82` to the binary integer 82. Because the programmer specifies the data
|
||||
type, we avoid branch mispredictions related to data type determination and improve the performance.
|
||||
|
||||
|
||||
We expect users of an On Demand API to work in terms of a JSON dialect, which is a set of expectations and
|
||||
We expect users of an On-Demand API to work in terms of a JSON dialect, which is a set of expectations and
|
||||
specifications that come in addition to the [JSON specification](https://www.rfc-editor.org/rfc/rfc8259.txt).
|
||||
The On Demand approach is designed around several principles:
|
||||
The On-Demand approach is designed around several principles:
|
||||
|
||||
* **Streaming (\*):** It avoids preparsing values, keeping the memory usage and the latency down.
|
||||
* **Forward-Only:** To prevent reiteration of the same values and to keep the number of variables down (literally), only a single index is maintained and everything uses it (even if you have nested for loops). This means when you are going through an array of arrays, for example, that the inner array loop will advance the index to the next comma, and the array can just pick it up and look at it.
|
||||
* **Natural Iteration:** A JSON array or object can be iterated with a normal C++ for loop. Nested arrays and objects are supported by nested for loops.
|
||||
* **Use-Specific Parsing:** Parsing is always specific to the type required by the programmer. For example, if the programmer asks for an unsigned integer, we just start parsing digits. If there were no digits, we toss an error. There are even different parsers for `double`, `uint64_t` and `int64_t` values. This use-specific parsing avoids the branchiness of a generic "type switch," and makes the code more inlineable and compact.
|
||||
* **Validate What You Use:** On Demand deliberately validates the values you use and the structure leading to it, but nothing else. The goal is a guarantee that the value you asked for is the correct one and is not malformed: there must be no confusion over whether you got the right value.
|
||||
* **Validate What You Use:** On-Demand deliberately validates the values you use and the structure leading to it, but nothing else. The goal is a guarantee that the value you asked for is the correct one and is not malformed: there must be no confusion over whether you got the right value.
|
||||
|
||||
|
||||
To understand why On Demand is different, it is helpful to review the major
|
||||
To understand why On-Demand is different, it is helpful to review the major
|
||||
approaches to parsing and parser APIs in use today.
|
||||
|
||||
### DOM Parsers
|
||||
@@ -106,7 +106,7 @@ DOM tree is often easy enough that many users use the DOM as-is instead of creat
|
||||
their own custom data structures.
|
||||
|
||||
The DOM approach was the only way to parse JSON documents up to version 0.6 of the simdjson library.
|
||||
Our DOM API looks similar to our On Demand example, except
|
||||
Our DOM API looks similar to our On-Demand example, except
|
||||
it calls `parse` instead of `iterate`:
|
||||
|
||||
```c++
|
||||
@@ -152,7 +152,7 @@ a tweet right now, or is this from some other place in the document
|
||||
entirely? Though an event-based approach may allow superior performance, it is demanding of the programmer
|
||||
who must efficiently keep track of its current state within the JSON input.
|
||||
|
||||
The following is event-based example of the Twitter problem we have reviewed in the DOM and On Demand
|
||||
The following is event-based example of the Twitter problem we have reviewed in the DOM and On-Demand
|
||||
examples. To make it short enough to use as an example at all, it has heavily redacted: it only solves
|
||||
a part of the problem (does not get user.screen_name), it has bugs (it does not handle sub-objects
|
||||
in a tweet at all), and it uses a theoretical, simple event-based API that minimizes ceremony.
|
||||
@@ -257,7 +257,7 @@ stress the branch prediction. Though branch predictors improve with each new gen
|
||||
the cost of branch mispredictions also tends to increase as pipelines expand, and the processors become
|
||||
able to schedule longer streams of instructions.
|
||||
|
||||
On Demand parsing is tailor-made to solve this problem at the source, parsing values only after the
|
||||
On-Demand parsing is tailor-made to solve this problem at the source, parsing values only after the
|
||||
user declares their type by asking for a `double`, an `int`, a `string`, etc. It attempts to do so while
|
||||
preserving most of the flexibility of DOM parsing.
|
||||
|
||||
@@ -297,7 +297,7 @@ To help visualize the algorithm, we'll walk through the example C++ given at the
|
||||
|
||||
Since this is the first time this parser has been used, `iterate()` first allocates internal
|
||||
parser buffers if this is the first time through. When reusing an existing parser, allocation
|
||||
only happens if the new document is bigger than internal buffers can handle. The On Demand
|
||||
only happens if the new document is bigger than internal buffers can handle. The On-Demand
|
||||
API only ever allocates memory in the `iterate()` function call.
|
||||
|
||||
The simdjson library then preprocesses the JSON text at high speed, finding all tokens (i.e. the starting
|
||||
@@ -492,7 +492,7 @@ To help visualize the algorithm, we'll walk through the example C++ given at the
|
||||
Because of the cast to uint64_t, simdjson knows it's parsing an unsigned integer. This lets
|
||||
us use a fast parser which *only* knows how to parse digits. It validates that it is an integer
|
||||
by rejecting negative numbers, strings, and other values based on the fact that they are not the
|
||||
digits 0-9. This type specificity is part of why parsing with on demand is so fast: you lose all
|
||||
digits 0-9. This type specificity is part of why parsing with On-Demand is so fast: you lose all
|
||||
the code that has to understand those other types.
|
||||
|
||||
The iterator is advanced to the `}`, and depth decreased back to 3 (root > statuses > tweet).
|
||||
@@ -597,7 +597,7 @@ To help visualize the algorithm, we'll walk through the example C++ given at the
|
||||
|
||||
This means you can very efficiently do things like read a single value from a JSON file, or take
|
||||
the top N, for example. It also means the things you don't use won't be fully validated. This is
|
||||
a general principle of On Demand: don't validate what you don't use. We still fully validate
|
||||
a general principle of On-Demand: don't validate what you don't use. We still fully validate
|
||||
values you do use, however, as well as the objects and arrays that lead to them, so that you can
|
||||
be sure you get the information you need.
|
||||
|
||||
@@ -654,7 +654,7 @@ for(auto field : doc.get_object()) {
|
||||
|
||||
### Iteration Safety
|
||||
|
||||
The On Demand API is powerful. To compensate, we add some safeguards to ensure that it can be used without fear
|
||||
The On-Demand API is powerful. To compensate, we add some safeguards to ensure that it can be used without fear
|
||||
in production systems:
|
||||
|
||||
- If the value fails to be parsed as one type, the program can try to parse it as something else until the program succeeds. Thus
|
||||
@@ -667,7 +667,7 @@ in production systems:
|
||||
if it was `nullptr` but did not care what the actual value was--it will iterate. The destructor automates
|
||||
the iteration.
|
||||
|
||||
Some care is needed when using the On Demand API in scenarios where you need to access several sibling arrays or objects because
|
||||
Some care is needed when using the On-Demand API in scenarios where you need to access several sibling arrays or objects because
|
||||
only one object or array can be active at any one time. Let us consider the following example:
|
||||
|
||||
```C++
|
||||
@@ -709,36 +709,36 @@ A correct usage is given by the following example:
|
||||
}
|
||||
```
|
||||
|
||||
### Benefits of the On Demand Approach
|
||||
### Benefits of the On-Demand Approach
|
||||
|
||||
We expect that the On Demand approach has many of the performance benefits of the schema-based approach, while providing a flexibility that is similar to that of the DOM-based approach.
|
||||
We expect that the On-Demand approach has many of the performance benefits of the schema-based approach, while providing a flexibility that is similar to that of the DOM-based approach.
|
||||
|
||||
* Faster than DOM in some cases. Reduced memory usage.
|
||||
* Straightforward, programmer-friendly interface (arrays and objects).
|
||||
* Highly expressive, beyond deserialization and pointer queries: many tasks can be accomplished with little code.
|
||||
|
||||
### Limitations of the On Demand Approach
|
||||
### Limitations of the On-Demand Approach
|
||||
|
||||
The On Demand approach has some limitations:
|
||||
The On-Demand approach has some limitations:
|
||||
|
||||
* Because it operates in streaming mode, you only have access to the current element in the JSON document. Furthermore, the document is traversed in order so the code is sensitive to the order of the JSON nodes in the same manner as an event-based approach (e.g., SAX). (The one exception to this is field lookup, which is more *performant* when the order of lookups matches the order of fields in the document, but which will still work with out-of-order fields, with a performance hit.)
|
||||
* The On Demand approach is less safe than DOM: we only validate the components of the JSON document that are used and it is possible to begin ingesting an invalid document only to find out later that the document is invalid. Are you fine ingesting a large JSON document that starts with well formed JSON but ends with invalid JSON content?
|
||||
* The On-Demand approach is less safe than DOM: we only validate the components of the JSON document that are used and it is possible to begin ingesting an invalid document only to find out later that the document is invalid. Are you fine ingesting a large JSON document that starts with well formed JSON but ends with invalid JSON content?
|
||||
|
||||
There are currently additional technical limitations which we expect to resolve in future releases of the simdjson library:
|
||||
|
||||
* The simdjson library offers runtime dispatching which allows you to compile one binary and have it run at full speed on different processors, taking advantage of the specific features of the processor. The On Demand API has limited runtime dispatch support. Under x64 systems, to fully benefit from the On Demand API, we recommend that you compile your code for a specific processor. E.g., if your processor supports AVX2 instructions, you should compile your binary executable with AVX2 instruction support (by using your compiler's commands). If you are sufficiently technically proficient, you can implement runtime dispatching within your application, by compiling your On Demand code for different processors.
|
||||
* The simdjson library offers runtime dispatching which allows you to compile one binary and have it run at full speed on different processors, taking advantage of the specific features of the processor. The On-Demand API has limited runtime dispatch support. Under x64 systems, to fully benefit from the On-Demand API, we recommend that you compile your code for a specific processor. E.g., if your processor supports AVX2 instructions, you should compile your binary executable with AVX2 instruction support (by using your compiler's commands). If you are sufficiently technically proficient, you can implement runtime dispatching within your application, by compiling your On-Demand code for different processors.
|
||||
* There is an initial phase which scans the entire document quickly, irrespective of the size of the document. We plan to break this phase into distinct steps for large files in a future release as we have done with other components of our API (e.g., `parse_many`).
|
||||
|
||||
### Applicability of the On Demand Approach
|
||||
### Applicability of the On-Demand Approach
|
||||
|
||||
At this time we recommend the On Demand API in the following cases:
|
||||
At this time we recommend the On-Demand API in the following cases:
|
||||
|
||||
1. The 64-bit hardware (CPU) used to run the software is known at compile time. If you need runtime dispatching because you cannot be certain of the hardware used to run your software, you will be better served with the core simdjson API. (This only applies to x64 (AMD/Intel). On 64-bit ARM hardware, runtime dispatching is unnecessary.)
|
||||
2. The used parts of JSON files do not need to be validated and the layout of the nodes follows a strict JSON dialect. If you are receiving JSON from other systems, you might be better served with core simdjson API as it fully validates the JSON inputs and allows you to navigate through the document at will.
|
||||
3. Speed and efficiency are of the utmost importance. Keep in mind that the core simdjson API is highly efficient so adopting the On Demand API is not necessary for high efficiency.
|
||||
3. Speed and efficiency are of the utmost importance. Keep in mind that the core simdjson API is highly efficient so adopting the On-Demand API is not necessary for high efficiency.
|
||||
4. As a developer, you value a clean, flexible and maintainable API.
|
||||
|
||||
Good applications for the On Demand API might be:
|
||||
Good applications for the On-Demand API might be:
|
||||
|
||||
* You are working from pre-existing large JSON files that have been vetted. You expect them to be well formed according to a known JSON dialect and to have a consistent layout. For example, you might be doing biomedical research or machine learning on top of static data dumps in JSON.
|
||||
* Both the generation and the consumption of JSON data is within your system. Your team controls both the software that produces the JSON and the software the parses it, your team knows and control the hardware. Thus you can fully test your system.
|
||||
@@ -746,13 +746,13 @@ Good applications for the On Demand API might be:
|
||||
|
||||
## Checking Your CPU Selection (x64 systems)
|
||||
|
||||
The On Demand API uses advanced architecture-specific code for many common processors to make JSON preprocessing and string parsing faster. By default, however, most c++ compilers will compile to the least common denominator (since the program could theoretically be run anywhere). Since On Demand is inlined into your own code, it cannot always use these advanced versions unless the compiler is told to target them.
|
||||
The On-Demand API uses advanced architecture-specific code for many common processors to make JSON preprocessing and string parsing faster. By default, however, most c++ compilers will compile to the least common denominator (since the program could theoretically be run anywhere). Since On-Demand is inlined into your own code, it cannot always use these advanced versions unless the compiler is told to target them.
|
||||
|
||||
On relevant systems, the On Demand API provides some support for runtime dispatching: that is, it will attempt to detect, at runtime, the instructions that your processor supports and optimize the code accordingly. However, it cannot always make full use of the features of your processor.
|
||||
On relevant systems, the On-Demand API provides some support for runtime dispatching: that is, it will attempt to detect, at runtime, the instructions that your processor supports and optimize the code accordingly. However, it cannot always make full use of the features of your processor.
|
||||
|
||||
Some users wish to run at the best possible speed. Under recent Intel and AMD processors, these users should take additional steps to verify that their code is well optimized.
|
||||
|
||||
Given that the On Demand API offer limited runtime dispatching, it matters that your code is compiled against a specific CPU target. You should verify that the code is compiled against the target you expect. Thankfully, the simdjson library will tell you exactly what it detects as an implementation: `icelake` (AVX512 x64 processors), `haswell` (AVX2 x64 processors), `westmere` (SSE4 x64 processors), `arm64` (64-bit ARM), `ppc64` (64-bit POWER), `fallback` (others). Under x64 processors, many programmers will want to target `haswell` whereas under ARM, most programmers will want to target `arm64` (and it should do so automatically). The `fallback` is probably only good for testing purposes, not for deployment.
|
||||
Given that the On-Demand API offer limited runtime dispatching, it matters that your code is compiled against a specific CPU target. You should verify that the code is compiled against the target you expect. Thankfully, the simdjson library will tell you exactly what it detects as an implementation: `icelake` (AVX512 x64 processors), `haswell` (AVX2 x64 processors), `westmere` (SSE4 x64 processors), `arm64` (64-bit ARM), `ppc64` (64-bit POWER), `lasx` (LoongArch), `lsx` (LoongArch), `fallback` (others). Under x64 processors, many programmers will want to target `haswell` whereas under ARM, most programmers will want to target `arm64` (and it should do so automatically). The `fallback` is probably only good for testing purposes, not for deployment.
|
||||
|
||||
```C++
|
||||
std::cout << simdjson::builtin_implementation()->name() << std::endl;
|
||||
@@ -777,6 +777,6 @@ In these examples, the `-march=haswell` flags targets a haswell processor and th
|
||||
|
||||
Instead of specifying a specific microarchitecture, you can let your compiler do the work. The `-march=native` flags says "target the current computer," which is a reasonable default for many applications which both compile and run on the same processor.
|
||||
|
||||
Passing `-march=native` to the compiler may make On Demand faster by allowing it to use optimizations specific to your machine. You cannot do this, however, if you are compiling code that might be run on less advanced machines. That is, be mindful that when compiling with the `-march=native` flag, the resulting binary will run on the current system but may not run on other systems (e.g., on an old processor).
|
||||
Passing `-march=native` to the compiler may make On-Demand faster by allowing it to use optimizations specific to your machine. You cannot do this, however, if you are compiling code that might be run on less advanced machines. That is, be mindful that when compiling with the `-march=native` flag, the resulting binary will run on the current system but may not run on other systems (e.g., on an old processor).
|
||||
|
||||
If you are compiling on an ARM or POWER system, you do not need to be concerned with CPU selection during compilation. The `-march=native` flag is useful for best performance on x64 (e.g., Intel) systems but it is generally unsupported on some platforms such as ARM (aarch64) or POWER.
|
||||
|
||||
+109
-1
@@ -14,6 +14,7 @@ testing and get the best performance.
|
||||
* [Number parsing](#number-parsing)
|
||||
* [Visual Studio](#visual-studio)
|
||||
* [Power Usage and Downclocking](#power-usage-and-downclocking)
|
||||
* [Free Padding](#free-padding)
|
||||
|
||||
|
||||
NDEBUG directive
|
||||
@@ -74,7 +75,7 @@ or simply
|
||||
Server Loops: Long-Running Processes and Memory Capacity
|
||||
---------------------------------
|
||||
|
||||
The On Demand approach also automatically expands its memory capacity when larger documents are parsed. However, for longer processes where very large files are processed (such as server loops), this capacity is not resized down. On Demand also lets you adjust the maximal capacity that the parser can process:
|
||||
The On-Demand approach also automatically expands its memory capacity when larger documents are parsed. However, for longer processes where very large files are processed (such as server loops), this capacity is not resized down. On-Demand also lets you adjust the maximal capacity that the parser can process:
|
||||
|
||||
* You can set an upper bound (*max_capacity*) when construction the parser:
|
||||
```C++
|
||||
@@ -179,3 +180,110 @@ The simdjson library does not generally make use of heavy 256-bit instructions.
|
||||
the macro `SIMDJSON_AVX512_ALLOWED` to `0` in C++ prior to importing the headers.
|
||||
|
||||
You may still be worried about which SIMD instruction set is used by simdjson. Thankfully, [you can always determine and change which architecture-specific implementation is used](implementation-selection.md) by simdjson. Thus even if your CPU supports AVX2, you do not need to use AVX2. You are in control.
|
||||
|
||||
|
||||
Free Padding
|
||||
-------
|
||||
|
||||
For performance reasons, the simdjson library requires that the JSON input contain at least
|
||||
`simdjson::SIMDJSON_PADDING` bytes at the end of the stream. The value `simdjson::SIMDJSON_PADDING` is
|
||||
small (e.g., 64 bytes). On modern systems, you can safely read beyond an allocated buffers,
|
||||
as long as you remain within an allocated page. Pages on modern systems span at least 4 kilobytes,
|
||||
but can be significantly larger. E.g., Apple systems favour pages spanning 16 kilobytes.
|
||||
|
||||
In effect, it means that you can almost always read a few bytes beyond your current buffer---without
|
||||
allocating extra memory. However, tools such as valgrind or memory sanitizers will flag such behavior as unsafe.
|
||||
Nevertheless, you can still make sure of this capability in your code if you are an expert
|
||||
programmer and you are willing to silence sanitizer warnings. The following code provides
|
||||
a portable example.
|
||||
|
||||
|
||||
The conditional compilation checks for the `_MSC_VER` macro (indicating Microsoft Visual Studio)
|
||||
and includes platform-specific headers accordingly.
|
||||
The `page_size()` function determines the default size of a memory page in bytes on the system.
|
||||
On Windows (when `_WIN32` is defined), it uses `GetSystemInfo()` to retrieve system information and obtain the page size.
|
||||
On other platforms (non-Windows), it uses `sysconf(_SC_PAGESIZE)` to get the page size.
|
||||
The function returns the page size.
|
||||
The `need_allocation()` function checks whether the buffer (given by `buf`) plus the specified length (`len`) is near a page boundary.
|
||||
If the buffer extends beyond the current page when padded by `simdjson::SIMDJSON_PADDING`, it returns true, indicating that reallocation is needed.
|
||||
Otherwise, it returns false.
|
||||
The `get_padded_string_view()` creates a `padded_string_view` from the input buffer.
|
||||
If reallocation is needed (unlikely case), it allocates a new padded_string and assigns it to `jsonbuffer`.
|
||||
Otherwise (very likely), it creates a `padded_string_view` directly from the buffer.
|
||||
The `simdjson::SIMDJSON_PADDING` ensures that there is additional padding for parsing efficiency.
|
||||
The calling code just needs to provide `jsonbuffer` (an instance of `simdjson::padded_string`)
|
||||
and pass `get_padded_string_view(buf, len, jsonbuffer)` to `parser.iterate`. Most of the time,
|
||||
this code will not allocate new memory.
|
||||
|
||||
|
||||
```cpp
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#include <sysinfoapi.h>
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include "simdjson.h"
|
||||
#include <cstdio>
|
||||
|
||||
// Returns the default size of the page in bytes on this system.
|
||||
long page_size() {
|
||||
#ifdef _WIN32
|
||||
SYSTEM_INFO sysInfo;
|
||||
GetSystemInfo(&sysInfo);
|
||||
long pagesize = sysInfo.dwPageSize;
|
||||
#else
|
||||
long pagesize = sysconf(_SC_PAGESIZE);
|
||||
#endif
|
||||
return pagesize;
|
||||
}
|
||||
|
||||
// Returns true if the buffer + len + simdjson::SIMDJSON_PADDING crosses the
|
||||
// page boundary.
|
||||
bool need_allocation(const char *buf, size_t len) {
|
||||
return ((reinterpret_cast<uintptr_t>(buf + len - 1) % page_size()) <
|
||||
simdjson::SIMDJSON_PADDING);
|
||||
}
|
||||
|
||||
simdjson::padded_string_view
|
||||
get_padded_string_view(const char *buf, size_t len,
|
||||
simdjson::padded_string &jsonbuffer) {
|
||||
if (need_allocation(buf, len)) { // unlikely case
|
||||
jsonbuffer = simdjson::padded_string(buf, len);
|
||||
return jsonbuffer;
|
||||
} else { // no reallcation needed (very likely)
|
||||
return simdjson::padded_string_view(buf, len,
|
||||
len + simdjson::SIMDJSON_PADDING);
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
printf("page_size: %ld\n", page_size());
|
||||
const char *jsonpoiner = R"(
|
||||
{
|
||||
"key": "value"
|
||||
}
|
||||
)";
|
||||
size_t len = strlen(jsonpoiner);
|
||||
simdjson::padded_string jsonbuffer; // only allocate if needed
|
||||
simdjson::ondemand::parser parser;
|
||||
simdjson::ondemand::document doc;
|
||||
simdjson::error_code error =
|
||||
parser.iterate(get_padded_string_view(jsonpoiner, len, jsonbuffer))
|
||||
.get(doc);
|
||||
if (error) {
|
||||
printf("error: %s\n", simdjson::error_message(error));
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
std::string_view value;
|
||||
error = doc["key"].get_string().get(value);
|
||||
if (error) {
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
printf("Value: \"%.*s\"\n", (int)value.size(), value.data());
|
||||
if (value != "value") {
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
```
|
||||
@@ -25,7 +25,7 @@ IF(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
|
||||
add_quickstart_test(quickstart2_noexceptions quickstart2_noexceptions.cpp NO_EXCEPTIONS LABELS acceptance)
|
||||
add_quickstart_test(quickstart2_noexceptions11 quickstart2_noexceptions.cpp NO_EXCEPTIONS CXX_STANDARD c++11)
|
||||
|
||||
# On Demand Quick Start
|
||||
# On-Demand Quick Start
|
||||
if (SIMDJSON_EXCEPTIONS)
|
||||
add_quickstart_test(quickstart_ondemand quickstart_ondemand.cpp LABELS quickstart_ondemand acceptance)
|
||||
add_quickstart_test(quickstart_ondemand11 quickstart_ondemand.cpp CXX_STANDARD c++11 LABELS quickstart_ondemand acceptance)
|
||||
|
||||
@@ -9,10 +9,10 @@
|
||||
|
||||
#include <cstring>
|
||||
|
||||
#if _M_ARM64
|
||||
#if SIMDJSON_REGULAR_VISUAL_STUDIO && SIMDJSON_IS_ARM64
|
||||
// __umulh requires intrin.h
|
||||
#include <intrin.h>
|
||||
#endif // _M_ARM64
|
||||
#endif // SIMDJSON_REGULAR_VISUAL_STUDIO && SIMDJSON_IS_ARM64
|
||||
|
||||
namespace simdjson {
|
||||
namespace arm64 {
|
||||
@@ -32,13 +32,13 @@ static simdjson_inline uint32_t parse_eight_digits_unrolled(const uint8_t *chars
|
||||
simdjson_inline internal::value128 full_multiplication(uint64_t value1, uint64_t value2) {
|
||||
internal::value128 answer;
|
||||
#if SIMDJSON_REGULAR_VISUAL_STUDIO || SIMDJSON_IS_32BITS
|
||||
#ifdef _M_ARM64
|
||||
#if SIMDJSON_IS_ARM64
|
||||
// ARM64 has native support for 64-bit multiplications, no need to emultate
|
||||
answer.high = __umulh(value1, value2);
|
||||
answer.low = value1 * value2;
|
||||
#else
|
||||
answer.low = _umul128(value1, value2, &answer.high); // _umul128 not available on ARM64
|
||||
#endif // _M_ARM64
|
||||
#endif // SIMDJSON_IS_ARM64
|
||||
#else // SIMDJSON_REGULAR_VISUAL_STUDIO || SIMDJSON_IS_32BITS
|
||||
__uint128_t r = (static_cast<__uint128_t>(value1)) * value2;
|
||||
answer.low = uint64_t(r);
|
||||
|
||||
@@ -134,7 +134,7 @@ namespace {
|
||||
tmp = vpaddq_u8(tmp, tmp);
|
||||
return vgetq_lane_u16(vreinterpretq_u16_u8(tmp), 0);
|
||||
}
|
||||
simdjson_inline bool any() const { return vmaxvq_u8(*this) != 0; }
|
||||
simdjson_inline bool any() const { return vmaxvq_u32(vreinterpretq_u32_u8(*this)) != 0; }
|
||||
};
|
||||
|
||||
// Unsigned bytes
|
||||
|
||||
@@ -20,6 +20,10 @@
|
||||
#include "simdjson/ppc64.h"
|
||||
#elif SIMDJSON_BUILTIN_IMPLEMENTATION_IS(westmere)
|
||||
#include "simdjson/westmere.h"
|
||||
#elif SIMDJSON_BUILTIN_IMPLEMENTATION_IS(lsx)
|
||||
#include "simdjson/lsx.h"
|
||||
#elif SIMDJSON_BUILTIN_IMPLEMENTATION_IS(lasx)
|
||||
#include "simdjson/lasx.h"
|
||||
#else
|
||||
#error Unknown SIMDJSON_BUILTIN_IMPLEMENTATION
|
||||
#endif
|
||||
|
||||
@@ -17,6 +17,10 @@ namespace simdjson {
|
||||
namespace ppc64 {}
|
||||
#elif SIMDJSON_BUILTIN_IMPLEMENTATION_IS(westmere)
|
||||
namespace westmere {}
|
||||
#elif SIMDJSON_BUILTIN_IMPLEMENTATION_IS(lsx)
|
||||
namespace lsx {}
|
||||
#elif SIMDJSON_BUILTIN_IMPLEMENTATION_IS(lasx)
|
||||
namespace lasx {}
|
||||
#else
|
||||
#error Unknown SIMDJSON_BUILTIN_IMPLEMENTATION
|
||||
#endif
|
||||
|
||||
@@ -19,6 +19,10 @@
|
||||
#include "simdjson/ppc64/implementation.h"
|
||||
#elif SIMDJSON_BUILTIN_IMPLEMENTATION_IS(westmere)
|
||||
#include "simdjson/westmere/implementation.h"
|
||||
#elif SIMDJSON_BUILTIN_IMPLEMENTATION_IS(lsx)
|
||||
#include "simdjson/lsx/implementation.h"
|
||||
#elif SIMDJSON_BUILTIN_IMPLEMENTATION_IS(lasx)
|
||||
#include "simdjson/lasx/implementation.h"
|
||||
#else
|
||||
#error Unknown SIMDJSON_BUILTIN_IMPLEMENTATION
|
||||
#endif
|
||||
|
||||
@@ -20,6 +20,10 @@
|
||||
#include "simdjson/ppc64/ondemand.h"
|
||||
#elif SIMDJSON_BUILTIN_IMPLEMENTATION_IS(westmere)
|
||||
#include "simdjson/westmere/ondemand.h"
|
||||
#elif SIMDJSON_BUILTIN_IMPLEMENTATION_IS(lsx)
|
||||
#include "simdjson/lsx/ondemand.h"
|
||||
#elif SIMDJSON_BUILTIN_IMPLEMENTATION_IS(lasx)
|
||||
#include "simdjson/lasx/ondemand.h"
|
||||
#else
|
||||
#error Unknown SIMDJSON_BUILTIN_IMPLEMENTATION
|
||||
#endif
|
||||
|
||||
@@ -13,6 +13,16 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// C++ 23
|
||||
#if !defined(SIMDJSON_CPLUSPLUS23) && (SIMDJSON_CPLUSPLUS >= 202302L)
|
||||
#define SIMDJSON_CPLUSPLUS23 1
|
||||
#endif
|
||||
|
||||
// C++ 20
|
||||
#if !defined(SIMDJSON_CPLUSPLUS20) && (SIMDJSON_CPLUSPLUS >= 202002L)
|
||||
#define SIMDJSON_CPLUSPLUS20 1
|
||||
#endif
|
||||
|
||||
// C++ 17
|
||||
#if !defined(SIMDJSON_CPLUSPLUS17) && (SIMDJSON_CPLUSPLUS >= 201703L)
|
||||
#define SIMDJSON_CPLUSPLUS17 1
|
||||
@@ -40,4 +50,16 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef __has_include
|
||||
#if __has_include(<version>)
|
||||
#include <version>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef __cpp_concepts
|
||||
#include <utility>
|
||||
#define SIMDJSON_SUPPORTS_DESERIALIZATION 1
|
||||
#else // __cpp_concepts
|
||||
#define SIMDJSON_SUPPORTS_DESERIALIZATION 0
|
||||
#endif
|
||||
#endif // SIMDJSON_COMPILER_CHECK_H
|
||||
|
||||
@@ -123,6 +123,10 @@ inline simdjson_result<element> array::at(size_t index) const noexcept {
|
||||
return INDEX_OUT_OF_BOUNDS;
|
||||
}
|
||||
|
||||
inline array::operator element() const noexcept {
|
||||
return element(tape);
|
||||
}
|
||||
|
||||
//
|
||||
// array::iterator inline implementation
|
||||
//
|
||||
|
||||
@@ -126,6 +126,11 @@ public:
|
||||
*/
|
||||
inline simdjson_result<element> at(size_t index) const noexcept;
|
||||
|
||||
/**
|
||||
* Implicitly convert object to element
|
||||
*/
|
||||
inline operator element() const noexcept;
|
||||
|
||||
private:
|
||||
simdjson_inline array(const internal::tape_ref &tape) noexcept;
|
||||
internal::tape_ref tape;
|
||||
|
||||
@@ -223,7 +223,11 @@ simdjson_inline std::string_view document_stream::iterator::source() const noexc
|
||||
return std::string_view(start, next_doc_index - current_index() + 1);
|
||||
} else {
|
||||
size_t next_doc_index = stream->batch_start + stream->parser->implementation->structural_indexes[stream->parser->implementation->next_structural_index];
|
||||
return std::string_view(reinterpret_cast<const char*>(stream->buf) + current_index(), next_doc_index - current_index() - 1);
|
||||
size_t svlen = next_doc_index - current_index();
|
||||
while(svlen > 1 && (std::isspace(start[svlen-1]) || start[svlen-1] == '\0')) {
|
||||
svlen--;
|
||||
}
|
||||
return std::string_view(start, svlen);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -375,6 +375,23 @@ inline simdjson_result<element> element::operator[](const char *key) const noexc
|
||||
return at_key(key);
|
||||
}
|
||||
|
||||
inline bool is_pointer_well_formed(std::string_view json_pointer) noexcept {
|
||||
if (simdjson_unlikely(json_pointer[0] != '/')) {
|
||||
return false;
|
||||
}
|
||||
size_t escape = json_pointer.find('~');
|
||||
if (escape == std::string_view::npos) {
|
||||
return true;
|
||||
}
|
||||
if (escape == json_pointer.size() - 1) {
|
||||
return false;
|
||||
}
|
||||
if (json_pointer[escape + 1] != '0' && json_pointer[escape + 1] != '1') {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
inline simdjson_result<element> element::at_pointer(std::string_view json_pointer) const noexcept {
|
||||
SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
|
||||
switch (tape.tape_ref_type()) {
|
||||
@@ -383,7 +400,10 @@ inline simdjson_result<element> element::at_pointer(std::string_view json_pointe
|
||||
case internal::tape_type::START_ARRAY:
|
||||
return array(tape).at_pointer(json_pointer);
|
||||
default: {
|
||||
if(!json_pointer.empty()) { // a non-empty string is invalid on an atom
|
||||
if (!json_pointer.empty()) { // a non-empty string can be invalid, or accessing a primitive (issue 2154)
|
||||
if (is_pointer_well_formed(json_pointer)) {
|
||||
return NO_SUCH_FIELD;
|
||||
}
|
||||
return INVALID_JSON_POINTER;
|
||||
}
|
||||
// an empty string means that we return the current node
|
||||
|
||||
@@ -153,6 +153,10 @@ inline simdjson_result<element> object::at_key_case_insensitive(std::string_view
|
||||
return NO_SUCH_FIELD;
|
||||
}
|
||||
|
||||
inline object::operator element() const noexcept {
|
||||
return element(tape);
|
||||
}
|
||||
|
||||
//
|
||||
// object::iterator inline implementation
|
||||
//
|
||||
|
||||
@@ -200,6 +200,11 @@ public:
|
||||
*/
|
||||
inline simdjson_result<element> at_key_case_insensitive(std::string_view key) const noexcept;
|
||||
|
||||
/**
|
||||
* Implicitly convert object to element
|
||||
*/
|
||||
inline operator element() const noexcept;
|
||||
|
||||
private:
|
||||
simdjson_inline object(const internal::tape_ref &tape) noexcept;
|
||||
|
||||
|
||||
@@ -191,7 +191,7 @@ simdjson_inline size_t parser::capacity() const noexcept {
|
||||
simdjson_inline size_t parser::max_capacity() const noexcept {
|
||||
return _max_capacity;
|
||||
}
|
||||
simdjson_inline size_t parser::max_depth() const noexcept {
|
||||
simdjson_pure simdjson_inline size_t parser::max_depth() const noexcept {
|
||||
return implementation ? implementation->max_depth() : DEFAULT_MAX_DEPTH;
|
||||
}
|
||||
|
||||
|
||||
@@ -83,6 +83,15 @@ public:
|
||||
* If the parser's current capacity is less than the file length, it will allocate enough capacity
|
||||
* to handle it (up to max_capacity).
|
||||
*
|
||||
* ## Windows and Unicode
|
||||
*
|
||||
* Windows users who need to read files with non-ANSI characters in the
|
||||
* name should set their code page to UTF-8 (65001) before calling this
|
||||
* function. This should be the default with Windows 11 and better.
|
||||
* Further, they may use the AreFileApisANSI function to determine whether
|
||||
* the filename is interpreted using the ANSI or the system default OEM
|
||||
* codepage, and they may call SetFileApisToOEM accordingly.
|
||||
*
|
||||
* @param path The path to load.
|
||||
* @return The document, or an error:
|
||||
* - IO_ERROR if there was an error opening or reading the file.
|
||||
@@ -518,7 +527,7 @@ public:
|
||||
*
|
||||
* @return Maximum depth, in bytes.
|
||||
*/
|
||||
simdjson_inline size_t max_depth() const noexcept;
|
||||
simdjson_pure simdjson_inline size_t max_depth() const noexcept;
|
||||
|
||||
/**
|
||||
* Set max_capacity. This is the largest document this parser can automatically support.
|
||||
|
||||
@@ -57,15 +57,15 @@ public:
|
||||
simdjson_inline void one_char(char c);
|
||||
|
||||
simdjson_inline void call_print_newline() {
|
||||
this->print_newline();
|
||||
static_cast<formatter*>(this)->print_newline();
|
||||
}
|
||||
|
||||
simdjson_inline void call_print_indents(size_t depth) {
|
||||
this->print_indents(depth);
|
||||
static_cast<formatter*>(this)->print_indents(depth);
|
||||
}
|
||||
|
||||
simdjson_inline void call_print_space() {
|
||||
this->print_space();
|
||||
static_cast<formatter*>(this)->print_space();
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
@@ -27,6 +27,7 @@ enum error_code {
|
||||
F_ATOM_ERROR, ///< Problem while parsing an atom starting with the letter 'f'
|
||||
N_ATOM_ERROR, ///< Problem while parsing an atom starting with the letter 'n'
|
||||
NUMBER_ERROR, ///< Problem while parsing a number
|
||||
BIGINT_ERROR, ///< The integer value exceeds 64 bits
|
||||
UTF8_ERROR, ///< the input is not valid UTF-8
|
||||
UNINITIALIZED, ///< unknown error, or uninitialized document
|
||||
EMPTY, ///< no structural element found
|
||||
@@ -38,7 +39,7 @@ enum error_code {
|
||||
INDEX_OUT_OF_BOUNDS, ///< JSON array index too large
|
||||
NO_SUCH_FIELD, ///< JSON field not found in object
|
||||
IO_ERROR, ///< Error reading a file
|
||||
INVALID_JSON_POINTER, ///< Invalid JSON pointer reference
|
||||
INVALID_JSON_POINTER, ///< Invalid JSON pointer syntax
|
||||
INVALID_URI_FRAGMENT, ///< Invalid URI fragment
|
||||
UNEXPECTED_ERROR, ///< indicative of a bug in simdjson
|
||||
PARSER_IN_USE, ///< parser is already in use.
|
||||
|
||||
@@ -56,13 +56,13 @@ static simdjson_inline uint64_t _umul128(uint64_t ab, uint64_t cd, uint64_t *hi)
|
||||
simdjson_inline internal::value128 full_multiplication(uint64_t value1, uint64_t value2) {
|
||||
internal::value128 answer;
|
||||
#if SIMDJSON_REGULAR_VISUAL_STUDIO || SIMDJSON_IS_32BITS
|
||||
#ifdef _M_ARM64
|
||||
#if SIMDJSON_IS_ARM64
|
||||
// ARM64 has native support for 64-bit multiplications, no need to emultate
|
||||
answer.high = __umulh(value1, value2);
|
||||
answer.low = value1 * value2;
|
||||
#else
|
||||
answer.low = _umul128(value1, value2, &answer.high); // _umul128 not available on ARM64
|
||||
#endif // _M_ARM64
|
||||
#endif // SIMDJSON_IS_ARM64
|
||||
#else // SIMDJSON_REGULAR_VISUAL_STUDIO || SIMDJSON_IS_32BITS
|
||||
__uint128_t r = (static_cast<__uint128_t>(value1)) * value2;
|
||||
answer.low = uint64_t(r);
|
||||
|
||||
@@ -17,6 +17,10 @@
|
||||
#include "simdjson/arm64/begin.h"
|
||||
#elif SIMDJSON_IMPLEMENTATION_PPC64
|
||||
#include "simdjson/ppc64/begin.h"
|
||||
#elif SIMDJSON_IMPLEMENTATION_LSX
|
||||
#include "simdjson/lsx/begin.h"
|
||||
#elif SIMDJSON_IMPLEMENTATION_LASX
|
||||
#include "simdjson/lasx/begin.h"
|
||||
#elif SIMDJSON_IMPLEMENTATION_FALLBACK
|
||||
#include "simdjson/fallback/begin.h"
|
||||
#else
|
||||
@@ -37,7 +41,8 @@ class dom_parser_implementation;
|
||||
enum class number_type {
|
||||
floating_point_number=1, /// a binary64 number
|
||||
signed_integer, /// a signed integer that fits in a 64-bit word using two's complement
|
||||
unsigned_integer /// a positive integer larger or equal to 1<<63
|
||||
unsigned_integer, /// a positive integer larger or equal to 1<<63
|
||||
big_integer /// a big integer that does not fit in a 64-bit word
|
||||
};
|
||||
|
||||
} // namespace SIMDJSON_IMPLEMENTATION
|
||||
|
||||
@@ -20,11 +20,13 @@ namespace numberparsing {
|
||||
#define WRITE_INTEGER(VALUE, SRC, WRITER) (found_integer((VALUE), (SRC)), (WRITER).append_s64((VALUE)))
|
||||
#define WRITE_UNSIGNED(VALUE, SRC, WRITER) (found_unsigned_integer((VALUE), (SRC)), (WRITER).append_u64((VALUE)))
|
||||
#define WRITE_DOUBLE(VALUE, SRC, WRITER) (found_float((VALUE), (SRC)), (WRITER).append_double((VALUE)))
|
||||
#define BIGINT_NUMBER(SRC) (found_invalid_number((SRC)), BIGINT_ERROR)
|
||||
#else
|
||||
#define INVALID_NUMBER(SRC) (NUMBER_ERROR)
|
||||
#define WRITE_INTEGER(VALUE, SRC, WRITER) (WRITER).append_s64((VALUE))
|
||||
#define WRITE_UNSIGNED(VALUE, SRC, WRITER) (WRITER).append_u64((VALUE))
|
||||
#define WRITE_DOUBLE(VALUE, SRC, WRITER) (WRITER).append_double((VALUE))
|
||||
#define BIGINT_NUMBER(SRC) (BIGINT_ERROR)
|
||||
#endif
|
||||
|
||||
namespace {
|
||||
@@ -355,6 +357,10 @@ simdjson_inline bool parse_digit(const uint8_t c, I &i) {
|
||||
return true;
|
||||
}
|
||||
|
||||
simdjson_inline bool is_digit(const uint8_t c) {
|
||||
return static_cast<uint8_t>(c - '0') <= 9;
|
||||
}
|
||||
|
||||
simdjson_inline error_code parse_decimal_after_separator(simdjson_unused const uint8_t *const src, const uint8_t *&p, uint64_t &i, int64_t &exponent) {
|
||||
// we continue with the fiction that we have an integer. If the
|
||||
// floating point number is representable as x * 10^z for some integer
|
||||
@@ -434,6 +440,23 @@ simdjson_inline error_code parse_exponent(simdjson_unused const uint8_t *const s
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
simdjson_inline bool check_if_integer(const uint8_t *const src, size_t max_length) {
|
||||
const uint8_t *const srcend = src + max_length;
|
||||
bool negative = (*src == '-'); // we can always read at least one character after the '-'
|
||||
const uint8_t *p = src + uint8_t(negative);
|
||||
if(p == srcend) { return false; }
|
||||
if(*p == '0') {
|
||||
++p;
|
||||
if(p == srcend) { return true; }
|
||||
if(jsoncharutils::is_not_structural_or_whitespace(*p)) { return false; }
|
||||
return true;
|
||||
}
|
||||
while(p != srcend && is_digit(*p)) { ++p; }
|
||||
if(p == srcend) { return true; }
|
||||
if(jsoncharutils::is_not_structural_or_whitespace(*p)) { return false; }
|
||||
return true;
|
||||
}
|
||||
|
||||
simdjson_inline size_t significant_digits(const uint8_t * start_digits, size_t digit_count) {
|
||||
// It is possible that the integer had an overflow.
|
||||
// We have to handle the case where we have 0.0000somenumber.
|
||||
@@ -508,6 +531,18 @@ simdjson_inline error_code write_float(const uint8_t *const src, bool negative,
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
// parse the number at src
|
||||
// define JSON_TEST_NUMBERS for unit testing
|
||||
//
|
||||
// It is assumed that the number is followed by a structural ({,},],[) character
|
||||
// or a white space character. If that is not the case (e.g., when the JSON
|
||||
// document is made of a single number), then it is necessary to copy the
|
||||
// content and append a space before calling this function.
|
||||
//
|
||||
// Our objective is accurate parsing (ULP of 0) at high speed.
|
||||
template<typename W>
|
||||
simdjson_inline error_code parse_number(const uint8_t *const src, W &writer);
|
||||
|
||||
// for performance analysis, it is sometimes useful to skip parsing
|
||||
#ifdef SIMDJSON_SKIPNUMBERPARSING
|
||||
|
||||
@@ -586,11 +621,11 @@ simdjson_inline error_code parse_number(const uint8_t *const src, W &writer) {
|
||||
// The longest positive 64-bit number is 20 digits.
|
||||
// We do it this way so we don't trigger this branch unless we must.
|
||||
size_t longest_digit_count = negative ? 19 : 20;
|
||||
if (digit_count > longest_digit_count) { return INVALID_NUMBER(src); }
|
||||
if (digit_count > longest_digit_count) { return BIGINT_NUMBER(src); }
|
||||
if (digit_count == longest_digit_count) {
|
||||
if (negative) {
|
||||
// Anything negative above INT64_MAX+1 is invalid
|
||||
if (i > uint64_t(INT64_MAX)+1) { return INVALID_NUMBER(src); }
|
||||
if (i > uint64_t(INT64_MAX)+1) { return BIGINT_NUMBER(src); }
|
||||
WRITE_INTEGER(~i+1, src, writer);
|
||||
if (jsoncharutils::is_not_structural_or_whitespace(*p)) { return INVALID_NUMBER(src); }
|
||||
return SUCCESS;
|
||||
@@ -1060,19 +1095,32 @@ simdjson_unused simdjson_inline simdjson_result<number_type> get_number_type(con
|
||||
src += uint8_t(negative);
|
||||
const uint8_t *p = src;
|
||||
while(static_cast<uint8_t>(*p - '0') <= 9) { p++; }
|
||||
size_t digit_count = size_t(p - src);
|
||||
if ( p == src ) { return NUMBER_ERROR; }
|
||||
if (jsoncharutils::is_structural_or_whitespace(*p)) {
|
||||
static const uint8_t * smaller_big_integer = reinterpret_cast<const uint8_t *>("9223372036854775808");
|
||||
// We have an integer.
|
||||
if(simdjson_unlikely(digit_count > 20)) {
|
||||
return number_type::big_integer;
|
||||
}
|
||||
// If the number is negative and valid, it must be a signed integer.
|
||||
if(negative) { return number_type::signed_integer; }
|
||||
if(negative) {
|
||||
if (simdjson_unlikely(digit_count > 19)) return number_type::big_integer;
|
||||
if (simdjson_unlikely(digit_count == 19 && memcmp(src, smaller_big_integer, 19) > 0)) {
|
||||
return number_type::big_integer;
|
||||
}
|
||||
return number_type::signed_integer;
|
||||
}
|
||||
// Let us check if we have a big integer (>=2**64).
|
||||
static const uint8_t * two_to_sixtyfour = reinterpret_cast<const uint8_t *>("18446744073709551616");
|
||||
if((digit_count > 20) || (digit_count == 20 && memcmp(src, two_to_sixtyfour, 20) >= 0)) {
|
||||
return number_type::big_integer;
|
||||
}
|
||||
// The number is positive and smaller than 18446744073709551616 (or 2**64).
|
||||
// We want values larger or equal to 9223372036854775808 to be unsigned
|
||||
// integers, and the other values to be signed integers.
|
||||
int digit_count = int(p - src);
|
||||
if(digit_count >= 19) {
|
||||
const uint8_t * smaller_big_integer = reinterpret_cast<const uint8_t *>("9223372036854775808");
|
||||
if((digit_count >= 20) || (memcmp(src, smaller_big_integer, 19) >= 0)) {
|
||||
return number_type::unsigned_integer;
|
||||
}
|
||||
if((digit_count == 20) || (digit_count >= 19 && memcmp(src, smaller_big_integer, 19) >= 0)) {
|
||||
return number_type::unsigned_integer;
|
||||
}
|
||||
return number_type::signed_integer;
|
||||
}
|
||||
@@ -1250,6 +1298,7 @@ inline std::ostream& operator<<(std::ostream& out, number_type type) noexcept {
|
||||
case number_type::signed_integer: out << "integer in [-9223372036854775808,9223372036854775808)"; break;
|
||||
case number_type::unsigned_integer: out << "unsigned integer in [9223372036854775808,18446744073709551616)"; break;
|
||||
case number_type::floating_point_number: out << "floating-point number (binary64)"; break;
|
||||
case number_type::big_integer: out << "big integer"; break;
|
||||
default: SIMDJSON_UNREACHABLE();
|
||||
}
|
||||
return out;
|
||||
@@ -1258,4 +1307,4 @@ inline std::ostream& operator<<(std::ostream& out, number_type type) noexcept {
|
||||
} // namespace SIMDJSON_IMPLEMENTATION
|
||||
} // namespace simdjson
|
||||
|
||||
#endif // SIMDJSON_GENERIC_NUMBERPARSING_H
|
||||
#endif // SIMDJSON_GENERIC_NUMBERPARSING_H
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
// Stuff other things depend on
|
||||
#include "simdjson/generic/ondemand/base.h"
|
||||
#include "simdjson/generic/ondemand/deserialize.h"
|
||||
#include "simdjson/generic/ondemand/value_iterator.h"
|
||||
#include "simdjson/generic/ondemand/value.h"
|
||||
#include "simdjson/generic/ondemand/logger.h"
|
||||
@@ -23,9 +24,13 @@
|
||||
#include "simdjson/generic/ondemand/object_iterator.h"
|
||||
#include "simdjson/generic/ondemand/serialization.h"
|
||||
|
||||
// Deserialization for standard types
|
||||
#include "simdjson/generic/ondemand/std_deserialize.h"
|
||||
|
||||
// Inline definitions
|
||||
#include "simdjson/generic/ondemand/array-inl.h"
|
||||
#include "simdjson/generic/ondemand/array_iterator-inl.h"
|
||||
#include "simdjson/generic/ondemand/value-inl.h"
|
||||
#include "simdjson/generic/ondemand/document-inl.h"
|
||||
#include "simdjson/generic/ondemand/document_stream-inl.h"
|
||||
#include "simdjson/generic/ondemand/field-inl.h"
|
||||
@@ -38,5 +43,6 @@
|
||||
#include "simdjson/generic/ondemand/raw_json_string-inl.h"
|
||||
#include "simdjson/generic/ondemand/serialization-inl.h"
|
||||
#include "simdjson/generic/ondemand/token_iterator-inl.h"
|
||||
#include "simdjson/generic/ondemand/value-inl.h"
|
||||
#include "simdjson/generic/ondemand/value_iterator-inl.h"
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,114 @@
|
||||
#if SIMDJSON_SUPPORTS_DESERIALIZATION
|
||||
|
||||
#ifndef SIMDJSON_ONDEMAND_DESERIALIZE_H
|
||||
#ifndef SIMDJSON_CONDITIONAL_INCLUDE
|
||||
#define SIMDJSON_ONDEMAND_DESERIALIZE_H
|
||||
#include "simdjson/generic/ondemand/base.h"
|
||||
#include "simdjson/generic/ondemand/array.h"
|
||||
#endif // SIMDJSON_CONDITIONAL_INCLUDE
|
||||
|
||||
#include <concepts>
|
||||
namespace simdjson {
|
||||
|
||||
namespace tag_invoke_fn_ns {
|
||||
void tag_invoke();
|
||||
|
||||
struct tag_invoke_fn {
|
||||
template <typename Tag, typename... Args>
|
||||
requires requires(Tag tag, Args &&...args) {
|
||||
tag_invoke(std::forward<Tag>(tag), std::forward<Args>(args)...);
|
||||
}
|
||||
constexpr auto operator()(Tag tag, Args &&...args) const
|
||||
noexcept(noexcept(tag_invoke(std::forward<Tag>(tag),
|
||||
std::forward<Args>(args)...)))
|
||||
-> decltype(tag_invoke(std::forward<Tag>(tag),
|
||||
std::forward<Args>(args)...)) {
|
||||
return tag_invoke(std::forward<Tag>(tag), std::forward<Args>(args)...);
|
||||
}
|
||||
};
|
||||
} // namespace tag_invoke_fn_ns
|
||||
|
||||
inline namespace tag_invoke_ns {
|
||||
inline constexpr tag_invoke_fn_ns::tag_invoke_fn tag_invoke = {};
|
||||
} // namespace tag_invoke_ns
|
||||
|
||||
template <typename Tag, typename... Args>
|
||||
concept tag_invocable = requires(Tag tag, Args... args) {
|
||||
tag_invoke(std::forward<Tag>(tag), std::forward<Args>(args)...);
|
||||
};
|
||||
|
||||
template <typename Tag, typename... Args>
|
||||
concept nothrow_tag_invocable =
|
||||
tag_invocable<Tag, Args...> && requires(Tag tag, Args... args) {
|
||||
{
|
||||
tag_invoke(std::forward<Tag>(tag), std::forward<Args>(args)...)
|
||||
} noexcept;
|
||||
};
|
||||
|
||||
template <typename Tag, typename... Args>
|
||||
using tag_invoke_result =
|
||||
std::invoke_result<decltype(tag_invoke), Tag, Args...>;
|
||||
|
||||
template <typename Tag, typename... Args>
|
||||
using tag_invoke_result_t =
|
||||
std::invoke_result_t<decltype(tag_invoke), Tag, Args...>;
|
||||
|
||||
template <auto &Tag> using tag_t = std::decay_t<decltype(Tag)>;
|
||||
|
||||
|
||||
struct deserialize_tag;
|
||||
|
||||
/// These types are deserializable in a built-in way
|
||||
template <typename> struct is_builtin_deserializable : std::false_type {};
|
||||
template <> struct is_builtin_deserializable<int64_t> : std::true_type {};
|
||||
template <> struct is_builtin_deserializable<uint64_t> : std::true_type {};
|
||||
template <> struct is_builtin_deserializable<double> : std::true_type {};
|
||||
template <> struct is_builtin_deserializable<bool> : std::true_type {};
|
||||
template <> struct is_builtin_deserializable<SIMDJSON_IMPLEMENTATION::ondemand::array> : std::true_type {};
|
||||
template <> struct is_builtin_deserializable<SIMDJSON_IMPLEMENTATION::ondemand::object> : std::true_type {};
|
||||
template <> struct is_builtin_deserializable<SIMDJSON_IMPLEMENTATION::ondemand::value> : std::true_type {};
|
||||
template <> struct is_builtin_deserializable<SIMDJSON_IMPLEMENTATION::ondemand::raw_json_string> : std::true_type {};
|
||||
template <> struct is_builtin_deserializable<std::string_view> : std::true_type {};
|
||||
|
||||
template <typename T>
|
||||
concept is_builtin_deserializable_v = is_builtin_deserializable<T>::value;
|
||||
|
||||
template <typename T, typename ValT = SIMDJSON_IMPLEMENTATION::ondemand::value>
|
||||
concept custom_deserializable = tag_invocable<deserialize_tag, ValT&, T&>;
|
||||
|
||||
template <typename T, typename ValT = SIMDJSON_IMPLEMENTATION::ondemand::value>
|
||||
concept deserializable = custom_deserializable<T, ValT> || is_builtin_deserializable_v<T>;
|
||||
|
||||
template <typename T, typename ValT = SIMDJSON_IMPLEMENTATION::ondemand::value>
|
||||
concept nothrow_custom_deserializable = nothrow_tag_invocable<deserialize_tag, ValT&, T&>;
|
||||
|
||||
// built-in types are noexcept and if an error happens, the value simply gets ignored and the error is returned.
|
||||
template <typename T, typename ValT = SIMDJSON_IMPLEMENTATION::ondemand::value>
|
||||
concept nothrow_deserializable = nothrow_custom_deserializable<T, ValT> || is_builtin_deserializable_v<T>;
|
||||
|
||||
/// Deserialize Tag
|
||||
inline constexpr struct deserialize_tag {
|
||||
using value_type = SIMDJSON_IMPLEMENTATION::ondemand::value;
|
||||
using document_type = SIMDJSON_IMPLEMENTATION::ondemand::document;
|
||||
|
||||
// Customization Point for value
|
||||
template <typename T>
|
||||
requires custom_deserializable<T, value_type>
|
||||
[[nodiscard]] constexpr /* error_code */ auto operator()(value_type &object, T& output) const noexcept(nothrow_custom_deserializable<T, value_type>) {
|
||||
return tag_invoke(*this, object, output);
|
||||
}
|
||||
|
||||
// Customization Point for document
|
||||
template <typename T>
|
||||
requires custom_deserializable<T, document_type>
|
||||
[[nodiscard]] constexpr /* error_code */ auto operator()(document_type &object, T& output) const noexcept(nothrow_custom_deserializable<T, document_type>) {
|
||||
return tag_invoke(*this, object, output);
|
||||
}
|
||||
|
||||
} deserialize{};
|
||||
|
||||
} // namespace simdjson
|
||||
|
||||
#endif // SIMDJSON_ONDEMAND_DESERIALIZE_H
|
||||
#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
|
||||
|
||||
@@ -13,7 +13,9 @@
|
||||
#include "simdjson/generic/ondemand/object-inl.h"
|
||||
#include "simdjson/generic/ondemand/raw_json_string.h"
|
||||
#include "simdjson/generic/ondemand/value.h"
|
||||
#include "simdjson/generic/ondemand/value-inl.h"
|
||||
#include "simdjson/generic/ondemand/value_iterator-inl.h"
|
||||
#include "simdjson/generic/ondemand/deserialize.h"
|
||||
#endif // SIMDJSON_CONDITIONAL_INCLUDE
|
||||
|
||||
namespace simdjson {
|
||||
@@ -167,20 +169,16 @@ template<> simdjson_inline simdjson_result<int64_t> document::get() & noexcept {
|
||||
template<> simdjson_inline simdjson_result<bool> document::get() & noexcept { return get_bool(); }
|
||||
template<> simdjson_inline simdjson_result<value> document::get() & noexcept { return get_value(); }
|
||||
|
||||
template<> simdjson_inline simdjson_result<raw_json_string> document::get() && noexcept { return get_raw_json_string(); }
|
||||
template<> simdjson_inline simdjson_result<std::string_view> document::get() && noexcept { return get_string(false); }
|
||||
template<> simdjson_inline simdjson_result<double> document::get() && noexcept { return std::forward<document>(*this).get_double(); }
|
||||
template<> simdjson_inline simdjson_result<uint64_t> document::get() && noexcept { return std::forward<document>(*this).get_uint64(); }
|
||||
template<> simdjson_inline simdjson_result<int64_t> document::get() && noexcept { return std::forward<document>(*this).get_int64(); }
|
||||
template<> simdjson_inline simdjson_result<bool> document::get() && noexcept { return std::forward<document>(*this).get_bool(); }
|
||||
template<> simdjson_inline simdjson_result<value> document::get() && noexcept { return get_value(); }
|
||||
template<> simdjson_inline error_code document::get(array& out) & noexcept { return get_array().get(out); }
|
||||
template<> simdjson_inline error_code document::get(object& out) & noexcept { return get_object().get(out); }
|
||||
template<> simdjson_inline error_code document::get(raw_json_string& out) & noexcept { return get_raw_json_string().get(out); }
|
||||
template<> simdjson_inline error_code document::get(std::string_view& out) & noexcept { return get_string(false).get(out); }
|
||||
template<> simdjson_inline error_code document::get(double& out) & noexcept { return get_double().get(out); }
|
||||
template<> simdjson_inline error_code document::get(uint64_t& out) & noexcept { return get_uint64().get(out); }
|
||||
template<> simdjson_inline error_code document::get(int64_t& out) & noexcept { return get_int64().get(out); }
|
||||
template<> simdjson_inline error_code document::get(bool& out) & noexcept { return get_bool().get(out); }
|
||||
template<> simdjson_inline error_code document::get(value& out) & noexcept { return get_value().get(out); }
|
||||
|
||||
template<typename T> simdjson_inline error_code document::get(T &out) & noexcept {
|
||||
return get<T>().get(out);
|
||||
}
|
||||
template<typename T> simdjson_inline error_code document::get(T &out) && noexcept {
|
||||
return std::forward<document>(*this).get<T>().get(out);
|
||||
}
|
||||
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
template <class T>
|
||||
@@ -295,7 +293,7 @@ simdjson_inline simdjson_result<number> document::get_number() noexcept {
|
||||
|
||||
simdjson_inline simdjson_result<std::string_view> document::raw_json_token() noexcept {
|
||||
auto _iter = get_root_value_iterator();
|
||||
return std::string_view(reinterpret_cast<const char*>(_iter.peek_start()), _iter.peek_start_length());
|
||||
return std::string_view(reinterpret_cast<const char*>(_iter.peek_start()), _iter.peek_root_length());
|
||||
}
|
||||
|
||||
simdjson_inline simdjson_result<value> document::at_pointer(std::string_view json_pointer) noexcept {
|
||||
@@ -535,6 +533,11 @@ simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::number> simdj
|
||||
|
||||
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
template <class T, typename std::enable_if<std::is_same<T, SIMDJSON_IMPLEMENTATION::ondemand::document>::value == false>::type>
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document>::operator T() noexcept(false) {
|
||||
if (error()) { throw simdjson_error(error()); }
|
||||
return first;
|
||||
}
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document>::operator SIMDJSON_IMPLEMENTATION::ondemand::array() & noexcept(false) {
|
||||
if (error()) { throw simdjson_error(error()); }
|
||||
return first;
|
||||
@@ -842,6 +845,11 @@ simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::number> simdj
|
||||
return first.get_number();
|
||||
}
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
template <class T, typename std::enable_if<std::is_same<T, SIMDJSON_IMPLEMENTATION::ondemand::document_reference>::value == false>::type>
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document_reference>::operator T() noexcept(false) {
|
||||
if (error()) { throw simdjson_error(error()); }
|
||||
return first;
|
||||
}
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document_reference>::operator SIMDJSON_IMPLEMENTATION::ondemand::array() & noexcept(false) {
|
||||
if (error()) { throw simdjson_error(error()); }
|
||||
return first;
|
||||
|
||||
@@ -4,8 +4,11 @@
|
||||
#define SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_H
|
||||
#include "simdjson/generic/ondemand/base.h"
|
||||
#include "simdjson/generic/ondemand/json_iterator.h"
|
||||
#include "simdjson/generic/ondemand/deserialize.h"
|
||||
#include "simdjson/generic/ondemand/value.h"
|
||||
#endif // SIMDJSON_CONDITIONAL_INCLUDE
|
||||
|
||||
|
||||
namespace simdjson {
|
||||
namespace SIMDJSON_IMPLEMENTATION {
|
||||
namespace ondemand {
|
||||
@@ -178,22 +181,39 @@ public:
|
||||
* @returns A value of the given type, parsed from the JSON.
|
||||
* @returns INCORRECT_TYPE If the JSON value is not the given type.
|
||||
*/
|
||||
template<typename T> simdjson_inline simdjson_result<T> get() & noexcept {
|
||||
// Unless the simdjson library provides an inline implementation, calling this method should
|
||||
// immediately fail.
|
||||
static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. "
|
||||
"The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, "
|
||||
"int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), "
|
||||
" get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template.");
|
||||
template <typename T>
|
||||
simdjson_inline simdjson_result<T> get() &
|
||||
#if SIMDJSON_SUPPORTS_DESERIALIZATION
|
||||
noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document> : true)
|
||||
#else
|
||||
noexcept
|
||||
#endif
|
||||
{
|
||||
static_assert(std::is_default_constructible<T>::value, "Cannot initialize the specified type.");
|
||||
T out{};
|
||||
SIMDJSON_TRY(get<T>(out));
|
||||
return out;
|
||||
}
|
||||
/** @overload template<typename T> simdjson_result<T> get() & noexcept */
|
||||
template<typename T> simdjson_inline simdjson_result<T> get() && noexcept {
|
||||
// Unless the simdjson library provides an inline implementation, calling this method should
|
||||
// immediately fail.
|
||||
static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. "
|
||||
"The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, "
|
||||
"int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), "
|
||||
" get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template.");
|
||||
/**
|
||||
* @overload template<typename T> simdjson_result<T> get() & noexcept
|
||||
*
|
||||
* We disallow the use tag_invoke CPO on a moved document; it may create UB
|
||||
* if user uses `ondemand::array` or `ondemand::object` in their custom type.
|
||||
*
|
||||
* The member function is still remains specialize-able for compatibility
|
||||
* reasons, but we completely disallow its use when a tag_invoke customization
|
||||
* is provided.
|
||||
*/
|
||||
template<typename T>
|
||||
simdjson_inline simdjson_result<T> get() &&
|
||||
#if SIMDJSON_SUPPORTS_DESERIALIZATION
|
||||
noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document> : true)
|
||||
#else
|
||||
noexcept
|
||||
#endif
|
||||
{
|
||||
static_assert(!std::is_same<T, array>::value && !std::is_same<T, object>::value, "You should never hold either an ondemand::array or ondemand::object without a corresponding ondemand::document being alive; that would be Undefined Behaviour.");
|
||||
return static_cast<document&>(*this).get<T>();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -207,11 +227,45 @@ public:
|
||||
* @returns INCORRECT_TYPE If the JSON value is not an object.
|
||||
* @returns SUCCESS If the parse succeeded and the out parameter was set to the value.
|
||||
*/
|
||||
template<typename T> simdjson_inline error_code get(T &out) & noexcept;
|
||||
template<typename T>
|
||||
simdjson_inline error_code get(T &out) &
|
||||
#if SIMDJSON_SUPPORTS_DESERIALIZATION
|
||||
noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document> : true)
|
||||
#else
|
||||
noexcept
|
||||
#endif
|
||||
{
|
||||
#if SIMDJSON_SUPPORTS_DESERIALIZATION
|
||||
if constexpr (custom_deserializable<T, document>) {
|
||||
return deserialize(*this, out);
|
||||
} else {
|
||||
#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
|
||||
// Unless the simdjson library or the user provides an inline implementation, calling this method should
|
||||
// immediately fail.
|
||||
static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. "
|
||||
"The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, "
|
||||
"int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), "
|
||||
" get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template."
|
||||
" You may also add support for custom types, see our documentation.");
|
||||
static_cast<void>(out); // to get rid of unused errors
|
||||
return UNINITIALIZED;
|
||||
#if SIMDJSON_SUPPORTS_DESERIALIZATION
|
||||
}
|
||||
#endif
|
||||
}
|
||||
/** @overload template<typename T> error_code get(T &out) & noexcept */
|
||||
template<typename T> simdjson_inline error_code get(T &out) && noexcept;
|
||||
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
/**
|
||||
* Cast this JSON value to an instance of type T. The programmer is responsible for
|
||||
* providing an implementation of get<T> for the type T, if T is not one of the types
|
||||
* supported by the library (object, array, raw_json_string, string_view, uint64_t, etc.)
|
||||
*
|
||||
* See https://github.com/simdjson/simdjson/blob/master/doc/basics.md#adding-support-for-custom-types
|
||||
*
|
||||
* @returns An instance of type T
|
||||
*/
|
||||
template <class T>
|
||||
explicit simdjson_inline operator T() noexcept(false);
|
||||
/**
|
||||
@@ -386,7 +440,7 @@ public:
|
||||
* APIs assume this. Therefore, you must be explicit if you want to treat objects as out of order.
|
||||
*
|
||||
* Use find_field() if you are sure fields will be in order (or are willing to treat it as if the
|
||||
* field wasn't there when they aren't).
|
||||
* field was not there when they are not in order).
|
||||
*
|
||||
* You must consume the fields on an object one at a time. A request for a new key
|
||||
* invalidates previous field values: it makes them unsafe. E.g., the array
|
||||
@@ -467,9 +521,11 @@ public:
|
||||
* get_number().get_number_type().
|
||||
*
|
||||
* get_number_type() is number_type::unsigned_integer if we have
|
||||
* an integer greater or equal to 9223372036854775808
|
||||
* an integer greater or equal to 9223372036854775808 and no larger than 18446744073709551615.
|
||||
* get_number_type() is number_type::signed_integer if we have an
|
||||
* integer that is less than 9223372036854775808
|
||||
* integer that is less than 9223372036854775808 and greater or equal to -9223372036854775808.
|
||||
* get_number_type() is number_type::big_integer if we have an integer outside
|
||||
* of those ranges (either larger than 18446744073709551615 or smaller than -9223372036854775808).
|
||||
* Otherwise, get_number_type() has value number_type::floating_point_number
|
||||
*
|
||||
* This function requires processing the number string, but it is expected
|
||||
@@ -782,7 +838,7 @@ public:
|
||||
template<typename T> simdjson_inline error_code get(T &out) & noexcept;
|
||||
template<typename T> simdjson_inline error_code get(T &out) && noexcept;
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
template <class T>
|
||||
template <class T, typename std::enable_if<std::is_same<T, SIMDJSON_IMPLEMENTATION::ondemand::document>::value == false>::type>
|
||||
explicit simdjson_inline operator T() noexcept(false);
|
||||
simdjson_inline operator SIMDJSON_IMPLEMENTATION::ondemand::array() & noexcept(false);
|
||||
simdjson_inline operator SIMDJSON_IMPLEMENTATION::ondemand::object() & noexcept(false);
|
||||
@@ -853,7 +909,7 @@ public:
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> get_value() noexcept;
|
||||
simdjson_inline simdjson_result<bool> is_null() noexcept;
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
template <class T>
|
||||
template <class T, typename std::enable_if<std::is_same<T, SIMDJSON_IMPLEMENTATION::ondemand::document_reference>::value == false>::type>
|
||||
explicit simdjson_inline operator T() noexcept(false);
|
||||
simdjson_inline operator SIMDJSON_IMPLEMENTATION::ondemand::array() & noexcept(false);
|
||||
simdjson_inline operator SIMDJSON_IMPLEMENTATION::ondemand::object() & noexcept(false);
|
||||
|
||||
@@ -342,9 +342,18 @@ simdjson_inline std::string_view document_stream::iterator::source() const noexc
|
||||
depth--;
|
||||
break;
|
||||
default: // Scalar value document
|
||||
// TODO: Remove any trailing whitespaces
|
||||
// TODO: We could remove trailing whitespaces
|
||||
// This returns a string spanning from start of value to the beginning of the next document (excluded)
|
||||
return std::string_view(reinterpret_cast<const char*>(stream->buf) + current_index(), stream->parser->implementation->structural_indexes[++cur_struct_index] - current_index() - 1);
|
||||
{
|
||||
auto next_index = stream->parser->implementation->structural_indexes[++cur_struct_index];
|
||||
// normally the length would be next_index - current_index() - 1, except for the last document
|
||||
size_t svlen = next_index - current_index();
|
||||
const char *start = reinterpret_cast<const char*>(stream->buf) + current_index();
|
||||
while(svlen > 1 && (std::isspace(start[svlen-1]) || start[svlen-1] == '\0')) {
|
||||
svlen--;
|
||||
}
|
||||
return std::string_view(start, svlen);
|
||||
}
|
||||
}
|
||||
cur_struct_index++;
|
||||
}
|
||||
|
||||
@@ -38,6 +38,14 @@ simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> field::un
|
||||
return answer;
|
||||
}
|
||||
|
||||
template <typename string_type>
|
||||
simdjson_inline simdjson_warn_unused error_code field::unescaped_key(string_type& receiver, bool allow_replacement) noexcept {
|
||||
std::string_view key;
|
||||
SIMDJSON_TRY( unescaped_key(allow_replacement).get(key) );
|
||||
receiver = key;
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
simdjson_inline raw_json_string field::key() const noexcept {
|
||||
SIMDJSON_ASSUME(first.buf != nullptr); // We would like to call .alive() by Visual Studio won't let us.
|
||||
return first;
|
||||
@@ -49,6 +57,13 @@ simdjson_inline std::string_view field::key_raw_json_token() const noexcept {
|
||||
return std::string_view(reinterpret_cast<const char*>(first.buf-1), second.iter._json_iter->token.peek(-1) - first.buf + 1);
|
||||
}
|
||||
|
||||
simdjson_inline std::string_view field::escaped_key() const noexcept {
|
||||
SIMDJSON_ASSUME(first.buf != nullptr); // We would like to call .alive() by Visual Studio won't let us.
|
||||
auto end_quote = second.iter._json_iter->token.peek(-1);
|
||||
while(*end_quote != '"') end_quote--;
|
||||
return std::string_view(reinterpret_cast<const char*>(first.buf), end_quote - first.buf);
|
||||
}
|
||||
|
||||
simdjson_inline value &field::value() & noexcept {
|
||||
return second;
|
||||
}
|
||||
@@ -88,11 +103,22 @@ simdjson_inline simdjson_result<std::string_view> simdjson_result<SIMDJSON_IMPLE
|
||||
return first.key_raw_json_token();
|
||||
}
|
||||
|
||||
simdjson_inline simdjson_result<std::string_view> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::field>::escaped_key() noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.escaped_key();
|
||||
}
|
||||
|
||||
simdjson_inline simdjson_result<std::string_view> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::field>::unescaped_key(bool allow_replacement) noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.unescaped_key(allow_replacement);
|
||||
}
|
||||
|
||||
template<typename string_type>
|
||||
simdjson_inline error_code simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::field>::unescaped_key(string_type &receiver, bool allow_replacement) noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.unescaped_key(receiver, allow_replacement);
|
||||
}
|
||||
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::field>::value() noexcept {
|
||||
if (error()) { return error(); }
|
||||
return std::move(first.value());
|
||||
|
||||
@@ -36,17 +36,39 @@ public:
|
||||
* This consumes the key: once you have called unescaped_key(), you cannot
|
||||
* call it again nor can you call key().
|
||||
*/
|
||||
simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> unescaped_key(bool allow_replacement) noexcept;
|
||||
simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> unescaped_key(bool allow_replacement = false) noexcept;
|
||||
/**
|
||||
* Get the key as a string_view (for higher speed, consider raw_key).
|
||||
* We deliberately use a more cumbersome name (unescaped_key) to force users
|
||||
* to think twice about using it. The content is stored in the receiver.
|
||||
*
|
||||
* This consumes the key: once you have called unescaped_key(), you cannot
|
||||
* call it again nor can you call key().
|
||||
*/
|
||||
template <typename string_type>
|
||||
simdjson_inline simdjson_warn_unused error_code unescaped_key(string_type& receiver, bool allow_replacement = false) noexcept;
|
||||
/**
|
||||
* Get the key as a raw_json_string. Can be used for direct comparison with
|
||||
* an unescaped C string: e.g., key() == "test".
|
||||
* an unescaped C string: e.g., key() == "test". This does not count as
|
||||
* consumption of the content: you can safely call it repeatedly.
|
||||
* See escaped_key() for a similar function which returns
|
||||
* a more convenient std::string_view result.
|
||||
*/
|
||||
simdjson_inline raw_json_string key() const noexcept;
|
||||
/**
|
||||
* Get the unprocessed key as a string_view. This includes the quotes and may include
|
||||
* some spaces after the last quote.
|
||||
* some spaces after the last quote. This does not count as
|
||||
* consumption of the content: you can safely call it repeatedly.
|
||||
* See escaped_key().
|
||||
*/
|
||||
simdjson_inline std::string_view key_raw_json_token() const noexcept;
|
||||
/**
|
||||
* Get the key as a string_view. This does not include the quotes and
|
||||
* the string is unprocessed key so it may contain escape characters
|
||||
* (e.g., \uXXXX or \n). It does not count as a consumption of the content:
|
||||
* you can safely call it repeatedly. Use unescaped_key() to get the unescaped key.
|
||||
*/
|
||||
simdjson_inline std::string_view escaped_key() const noexcept;
|
||||
/**
|
||||
* Get the field value.
|
||||
*/
|
||||
@@ -78,8 +100,11 @@ public:
|
||||
simdjson_inline simdjson_result() noexcept = default;
|
||||
|
||||
simdjson_inline simdjson_result<std::string_view> unescaped_key(bool allow_replacement = false) noexcept;
|
||||
template<typename string_type>
|
||||
simdjson_inline error_code unescaped_key(string_type &receiver, bool allow_replacement = false) noexcept;
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::raw_json_string> key() noexcept;
|
||||
simdjson_inline simdjson_result<std::string_view> key_raw_json_token() noexcept;
|
||||
simdjson_inline simdjson_result<std::string_view> escaped_key() noexcept;
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> value() noexcept;
|
||||
};
|
||||
|
||||
|
||||
@@ -54,6 +54,23 @@ simdjson_inline json_iterator::json_iterator(const uint8_t *buf, ondemand::parse
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
|
||||
simdjson_inline json_iterator::json_iterator(const uint8_t *buf, ondemand::parser *_parser, bool streaming) noexcept
|
||||
: token(buf, &_parser->implementation->structural_indexes[0]),
|
||||
parser{_parser},
|
||||
_string_buf_loc{parser->string_buf.get()},
|
||||
_depth{1},
|
||||
_root{parser->implementation->structural_indexes.get()},
|
||||
_streaming{streaming}
|
||||
|
||||
{
|
||||
logger::log_headers();
|
||||
#if SIMDJSON_CHECK_EOF
|
||||
assert_more_tokens();
|
||||
#endif
|
||||
}
|
||||
#endif // SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
|
||||
|
||||
inline void json_iterator::rewind() noexcept {
|
||||
token.set_position( root_position() );
|
||||
logger::log_headers(); // We start again
|
||||
@@ -286,6 +303,12 @@ simdjson_inline uint32_t json_iterator::peek_length(token_position position) con
|
||||
#endif // SIMDJSON_CHECK_EOF
|
||||
return token.peek_length(position);
|
||||
}
|
||||
simdjson_inline uint32_t json_iterator::peek_root_length(token_position position) const noexcept {
|
||||
#if SIMDJSON_CHECK_EOF
|
||||
assert_valid_position(position);
|
||||
#endif // SIMDJSON_CHECK_EOF
|
||||
return token.peek_root_length(position);
|
||||
}
|
||||
|
||||
simdjson_inline token_position json_iterator::last_position() const noexcept {
|
||||
// The following line fails under some compilers...
|
||||
@@ -331,11 +354,23 @@ simdjson_inline token_position json_iterator::position() const noexcept {
|
||||
}
|
||||
|
||||
simdjson_inline simdjson_result<std::string_view> json_iterator::unescape(raw_json_string in, bool allow_replacement) noexcept {
|
||||
#if SIMDJSON_DEVELOPMENT_CHECKS
|
||||
auto result = parser->unescape(in, _string_buf_loc, allow_replacement);
|
||||
SIMDJSON_ASSUME(!parser->string_buffer_overflow(_string_buf_loc));
|
||||
return result;
|
||||
#else
|
||||
return parser->unescape(in, _string_buf_loc, allow_replacement);
|
||||
#endif
|
||||
}
|
||||
|
||||
simdjson_inline simdjson_result<std::string_view> json_iterator::unescape_wobbly(raw_json_string in) noexcept {
|
||||
#if SIMDJSON_DEVELOPMENT_CHECKS
|
||||
auto result = parser->unescape_wobbly(in, _string_buf_loc);
|
||||
SIMDJSON_ASSUME(!parser->string_buffer_overflow(_string_buf_loc));
|
||||
return result;
|
||||
#else
|
||||
return parser->unescape_wobbly(in, _string_buf_loc);
|
||||
#endif
|
||||
}
|
||||
|
||||
simdjson_inline void json_iterator::reenter_child(token_position position, depth_t child_depth) noexcept {
|
||||
|
||||
@@ -185,6 +185,14 @@ public:
|
||||
* @param position The position of the token to retrieve.
|
||||
*/
|
||||
simdjson_inline uint32_t peek_length(token_position position) const noexcept;
|
||||
/**
|
||||
* Get the maximum length of the JSON text for the current root token.
|
||||
*
|
||||
* The length will include any whitespace at the end of the token.
|
||||
*
|
||||
* @param position The position of the token to retrieve.
|
||||
*/
|
||||
simdjson_inline uint32_t peek_root_length(token_position position) const noexcept;
|
||||
/**
|
||||
* Get the JSON text for the last token in the document.
|
||||
*
|
||||
@@ -285,6 +293,9 @@ public:
|
||||
inline bool balanced() const noexcept;
|
||||
protected:
|
||||
simdjson_inline json_iterator(const uint8_t *buf, ondemand::parser *parser) noexcept;
|
||||
#ifdef SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
|
||||
simdjson_inline json_iterator(const uint8_t *buf, ondemand::parser *parser, bool streaming) noexcept;
|
||||
#endif // SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
|
||||
/// The last token before the end
|
||||
simdjson_inline token_position last_position() const noexcept;
|
||||
/// The token *at* the end. This points at gibberish and should only be used for comparison.
|
||||
|
||||
@@ -48,7 +48,6 @@ simdjson_inline number::operator uint64_t() const noexcept {
|
||||
return get_uint64();
|
||||
}
|
||||
|
||||
|
||||
simdjson_inline bool number::is_int64() const noexcept {
|
||||
return get_number_type() == number_type::signed_integer;
|
||||
}
|
||||
|
||||
@@ -56,6 +56,8 @@ public:
|
||||
* key a single time. Doing object["mykey"].to_string() and then again object["mykey"].to_string()
|
||||
* is an error.
|
||||
*
|
||||
* If you expect to have keys with escape characters, please review our documentation.
|
||||
*
|
||||
* @param key The key to look up.
|
||||
* @returns The value of the field, or NO_SUCH_FIELD if the field is not in the object.
|
||||
*/
|
||||
@@ -77,7 +79,7 @@ public:
|
||||
* APIs assume this. Therefore, you must be explicit if you want to treat objects as out of order.
|
||||
*
|
||||
* Use find_field() if you are sure fields will be in order (or are willing to treat it as if the
|
||||
* field wasn't there when they aren't).
|
||||
* field was not there when they are not in order).
|
||||
*
|
||||
* If you have multiple fields with a matching key ({"x": 1, "x": 1}) be mindful
|
||||
* that only one field is returned.
|
||||
@@ -93,6 +95,8 @@ public:
|
||||
* You are expected to access keys only once. You should access the value corresponding to a key
|
||||
* a single time. Doing object["mykey"].to_string() and then again object["mykey"].to_string() is an error.
|
||||
*
|
||||
* If you expect to have keys with escape characters, please review our documentation.
|
||||
*
|
||||
* @param key The key to look up.
|
||||
* @returns The value of the field, or NO_SUCH_FIELD if the field is not in the object.
|
||||
*/
|
||||
@@ -156,8 +160,8 @@ public:
|
||||
/**
|
||||
* Reset the iterator so that we are pointing back at the
|
||||
* beginning of the object. You should still consume values only once even if you
|
||||
* can iterate through the object more than once. If you unescape a string within
|
||||
* the object more than once, you have unsafe code. Note that rewinding an object
|
||||
* can iterate through the object more than once. If you unescape a string or a key
|
||||
* within the object more than once, you have unsafe code. Note that rewinding an object
|
||||
* means that you may need to reparse it anew: it is not a free operation.
|
||||
*
|
||||
* @returns true if the object contains some elements (not empty)
|
||||
|
||||
@@ -42,6 +42,11 @@ simdjson_warn_unused simdjson_inline error_code parser::allocate(size_t new_capa
|
||||
_max_depth = new_max_depth;
|
||||
return SUCCESS;
|
||||
}
|
||||
#if SIMDJSON_DEVELOPMENT_CHECKS
|
||||
simdjson_inline simdjson_warn_unused bool parser::string_buffer_overflow(const uint8_t *string_buf_loc) const noexcept {
|
||||
return (string_buf_loc < string_buf.get()) || (size_t(string_buf_loc - string_buf.get()) >= capacity());
|
||||
}
|
||||
#endif
|
||||
|
||||
simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(padded_string_view json) & noexcept {
|
||||
if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
|
||||
@@ -58,6 +63,27 @@ simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(p
|
||||
return document::start({ reinterpret_cast<const uint8_t *>(json.data()), this });
|
||||
}
|
||||
|
||||
#ifdef SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
|
||||
simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate_allow_incomplete_json(padded_string_view json) & noexcept {
|
||||
if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
|
||||
|
||||
json.remove_utf8_bom();
|
||||
|
||||
// Allocate if needed
|
||||
if (capacity() < json.length() || !string_buf) {
|
||||
SIMDJSON_TRY( allocate(json.length(), max_depth()) );
|
||||
}
|
||||
|
||||
// Run stage 1.
|
||||
const simdjson::error_code err = implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.length(), stage1_mode::regular);
|
||||
if (err) {
|
||||
if (err != UNCLOSED_STRING)
|
||||
return err;
|
||||
}
|
||||
return document::start({ reinterpret_cast<const uint8_t *>(json.data()), this, true });
|
||||
}
|
||||
#endif // SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
|
||||
|
||||
simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const char *json, size_t len, size_t allocated) & noexcept {
|
||||
return iterate(padded_string_view(json, len, allocated));
|
||||
}
|
||||
@@ -129,13 +155,13 @@ inline simdjson_result<document_stream> parser::iterate_many(const padded_string
|
||||
return iterate_many(s.data(), s.length(), batch_size, allow_comma_separated);
|
||||
}
|
||||
|
||||
simdjson_inline size_t parser::capacity() const noexcept {
|
||||
simdjson_pure simdjson_inline size_t parser::capacity() const noexcept {
|
||||
return _capacity;
|
||||
}
|
||||
simdjson_inline size_t parser::max_capacity() const noexcept {
|
||||
simdjson_pure simdjson_inline size_t parser::max_capacity() const noexcept {
|
||||
return _max_capacity;
|
||||
}
|
||||
simdjson_inline size_t parser::max_depth() const noexcept {
|
||||
simdjson_pure simdjson_inline size_t parser::max_depth() const noexcept {
|
||||
return _max_depth;
|
||||
}
|
||||
|
||||
|
||||
@@ -13,8 +13,8 @@ namespace SIMDJSON_IMPLEMENTATION {
|
||||
namespace ondemand {
|
||||
|
||||
/**
|
||||
* The default batch size for document_stream instances for this On Demand kernel.
|
||||
* Note that different On Demand kernel may use a different DEFAULT_BATCH_SIZE value
|
||||
* The default batch size for document_stream instances for this On-Demand kernel.
|
||||
* Note that different On-Demand kernel may use a different DEFAULT_BATCH_SIZE value
|
||||
* in the future.
|
||||
*/
|
||||
static constexpr size_t DEFAULT_BATCH_SIZE = 1000000;
|
||||
@@ -98,6 +98,9 @@ public:
|
||||
* - UNCLOSED_STRING if there is an unclosed string in the document.
|
||||
*/
|
||||
simdjson_warn_unused simdjson_result<document> iterate(padded_string_view json) & noexcept;
|
||||
#ifdef SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
|
||||
simdjson_warn_unused simdjson_result<document> iterate_allow_incomplete_json(padded_string_view json) & noexcept;
|
||||
#endif // SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
|
||||
/** @overload simdjson_result<document> iterate(padded_string_view json) & noexcept */
|
||||
simdjson_warn_unused simdjson_result<document> iterate(const char *json, size_t len, size_t capacity) & noexcept;
|
||||
/** @overload simdjson_result<document> iterate(padded_string_view json) & noexcept */
|
||||
@@ -242,9 +245,9 @@ public:
|
||||
simdjson_result<document_stream> iterate_many(const char *buf, size_t batch_size = DEFAULT_BATCH_SIZE) noexcept = delete;
|
||||
|
||||
/** The capacity of this parser (the largest document it can process). */
|
||||
simdjson_inline size_t capacity() const noexcept;
|
||||
simdjson_pure simdjson_inline size_t capacity() const noexcept;
|
||||
/** The maximum capacity of this parser (the largest document it is allowed to process). */
|
||||
simdjson_inline size_t max_capacity() const noexcept;
|
||||
simdjson_pure simdjson_inline size_t max_capacity() const noexcept;
|
||||
simdjson_inline void set_max_capacity(size_t max_capacity) noexcept;
|
||||
/**
|
||||
* The maximum depth of this parser (the most deeply nested objects and arrays it can process).
|
||||
@@ -252,7 +255,7 @@ public:
|
||||
* The document's instance current_depth() method should be used to monitor the parsing
|
||||
* depth and limit it if desired.
|
||||
*/
|
||||
simdjson_inline size_t max_depth() const noexcept;
|
||||
simdjson_pure simdjson_inline size_t max_depth() const noexcept;
|
||||
|
||||
/**
|
||||
* Ensure this parser has enough memory to process JSON documents up to `capacity` bytes in length
|
||||
@@ -324,6 +327,17 @@ public:
|
||||
*/
|
||||
simdjson_inline simdjson_result<std::string_view> unescape_wobbly(raw_json_string in, uint8_t *&dst) const noexcept;
|
||||
|
||||
#if SIMDJSON_DEVELOPMENT_CHECKS
|
||||
/**
|
||||
* Returns true if string_buf_loc is outside of the allocated range for the
|
||||
* the string buffer. When true, it indicates that the string buffer has overflowed.
|
||||
* This is a development-time check that is not needed in production. It can be
|
||||
* used to detect buffer overflows in the string buffer and usafe usage of the
|
||||
* string buffer.
|
||||
*/
|
||||
bool string_buffer_overflow(const uint8_t *string_buf_loc) const noexcept;
|
||||
#endif
|
||||
|
||||
private:
|
||||
/** @private [for benchmarking access] The implementation to use */
|
||||
std::unique_ptr<internal::dom_parser_implementation> implementation{};
|
||||
|
||||
@@ -0,0 +1,196 @@
|
||||
#if SIMDJSON_SUPPORTS_DESERIALIZATION
|
||||
|
||||
#ifndef SIMDJSON_ONDEMAND_DESERIALIZE_H
|
||||
#ifndef SIMDJSON_CONDITIONAL_INCLUDE
|
||||
#define SIMDJSON_ONDEMAND_DESERIALIZE_H
|
||||
#include "simdjson/generic/ondemand/base.h"
|
||||
#include "simdjson/generic/ondemand/array.h"
|
||||
#endif // SIMDJSON_CONDITIONAL_INCLUDE
|
||||
|
||||
#include <concepts>
|
||||
#include <limits>
|
||||
#include <list>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace simdjson {
|
||||
|
||||
//////////////////////////////
|
||||
// Number deserialization
|
||||
//////////////////////////////
|
||||
|
||||
template <std::unsigned_integral T>
|
||||
error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept {
|
||||
using limits = std::numeric_limits<T>;
|
||||
|
||||
uint64_t x;
|
||||
SIMDJSON_TRY(val.get_uint64().get(x));
|
||||
if (x > (limits::max)()) {
|
||||
return NUMBER_OUT_OF_RANGE;
|
||||
}
|
||||
out = static_cast<T>(x);
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
template <std::floating_point T>
|
||||
error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept {
|
||||
double x;
|
||||
SIMDJSON_TRY(val.get_double().get(x));
|
||||
out = static_cast<T>(x);
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
template <std::signed_integral T>
|
||||
error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept {
|
||||
using limits = std::numeric_limits<T>;
|
||||
|
||||
int64_t x;
|
||||
SIMDJSON_TRY(val.get_int64().get(x));
|
||||
if (x > (limits::max)() || x < (limits::min)()) {
|
||||
return NUMBER_OUT_OF_RANGE;
|
||||
}
|
||||
out = static_cast<T>(x);
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
// STL list deserialization
|
||||
//////////////////////////////
|
||||
|
||||
template <typename T, typename AllocT, typename ValT>
|
||||
error_code tag_invoke(deserialize_tag, ValT &val,
|
||||
std::list<T, AllocT> &out) noexcept(false) {
|
||||
|
||||
// For better error messages, don't use these as constraints on
|
||||
// the tag_invoke CPO.
|
||||
static_assert(
|
||||
deserializable<T, ValT>,
|
||||
"The specified type inside the list must itself be deserializable");
|
||||
static_assert(
|
||||
std::is_default_constructible_v<T>,
|
||||
"The specified type inside the list must default constructible.");
|
||||
|
||||
SIMDJSON_IMPLEMENTATION::ondemand::array arr;
|
||||
SIMDJSON_TRY(val.get_array().get(arr));
|
||||
for (auto v : arr) {
|
||||
if (auto const err = v.get<T>().get(out.emplace_back()); err) {
|
||||
// If an error occurs, the empty element that we just inserted gets
|
||||
// removed. We're not using a temp variable because if T is a heavy type,
|
||||
// we want the valid path to be the fast path and the slow path be the
|
||||
// path that has errors in it.
|
||||
static_cast<void>(out.pop_back());
|
||||
return err;
|
||||
}
|
||||
}
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
// std::string deserialization
|
||||
//////////////////////////////
|
||||
|
||||
template <typename CharT,
|
||||
typename TraitsT,
|
||||
typename AllocT,
|
||||
typename ValT>
|
||||
error_code tag_invoke(deserialize_tag, ValT &val, std::basic_string<CharT, TraitsT, AllocT> &out) noexcept(false) {
|
||||
using string_type = std::basic_string<CharT, TraitsT, AllocT>;
|
||||
|
||||
if constexpr (std::same_as<string_type, string_type>) {
|
||||
SIMDJSON_TRY(val.get_string(out));
|
||||
} else {
|
||||
// todo: optimize performance
|
||||
std::string tmp;
|
||||
SIMDJSON_TRY(val.get_string(tmp));
|
||||
for (auto const ch : tmp) {
|
||||
out.push_back(ch);
|
||||
}
|
||||
}
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
// STL Vector deserialization
|
||||
//////////////////////////////
|
||||
|
||||
/**
|
||||
* STL containers have several constructors including one that takes a single
|
||||
* size argument. Thus, some compilers (Visual Studio) will not be able to
|
||||
* disambiguate between the size and container constructor. Users should
|
||||
* explicitly specify the type of the container as needed: e.g.,
|
||||
* doc.get<std::vector<int>>().
|
||||
*/
|
||||
template <typename T, typename AllocT, typename ValT>
|
||||
error_code tag_invoke(deserialize_tag, ValT &val,
|
||||
std::vector<T, AllocT> &out) noexcept(false) {
|
||||
|
||||
// For better error messages, don't use these as constraints on
|
||||
// the tag_invoke CPO.
|
||||
static_assert(
|
||||
deserializable<T, ValT>,
|
||||
"The specified type inside the vector must itself be deserializable");
|
||||
static_assert(
|
||||
std::is_default_constructible_v<T>,
|
||||
"The specified type inside the vector must default constructible.");
|
||||
|
||||
SIMDJSON_IMPLEMENTATION::ondemand::array arr;
|
||||
SIMDJSON_TRY(val.get_array().get(arr));
|
||||
for (auto v : arr) {
|
||||
if (auto const err = v.get<T>().get(out.emplace_back()); err) {
|
||||
// If an error occurs, the empty element that we just inserted gets
|
||||
// removed. We're not using a temp variable because if T is a heavy type,
|
||||
// we want the valid path to be the fast path and the slow path be the
|
||||
// path that has errors in it.
|
||||
static_cast<void>(out.pop_back());
|
||||
return err;
|
||||
}
|
||||
}
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
// std::unique_ptr deserialization
|
||||
//////////////////////////////
|
||||
|
||||
/**
|
||||
* This CPO (Customization Point Object) will help deserialize into
|
||||
* `unique_ptr`s.
|
||||
*
|
||||
* If constructing T is nothrow, this conversion should be nothrow as well since
|
||||
* we return MEMALLOC if we're not able to allocate memory instead of throwing
|
||||
* the the error message.
|
||||
*
|
||||
* @tparam T The type inside the unique_ptr
|
||||
* @tparam Deleter The Deleter of the unique_ptr
|
||||
* @tparam ValT document/value type
|
||||
* @param val document/value
|
||||
* @param out output unique_ptr
|
||||
* @return status of the conversion
|
||||
*/
|
||||
template <typename T, typename Deleter, typename ValT>
|
||||
error_code tag_invoke(deserialize_tag, ValT &val,
|
||||
std::unique_ptr<T, Deleter>
|
||||
&out) noexcept(nothrow_deserializable<T, ValT>) {
|
||||
|
||||
// For better error messages, don't use these as constraints on
|
||||
// the tag_invoke CPO.
|
||||
static_assert(
|
||||
deserializable<T, ValT>,
|
||||
"The specified type inside the unique_ptr must itself be deserializable");
|
||||
static_assert(
|
||||
std::is_default_constructible_v<T>,
|
||||
"The specified type inside the unique_ptr must default constructible.");
|
||||
|
||||
auto ptr = new (std::nothrow) T();
|
||||
if (ptr == nullptr) {
|
||||
return MEMALLOC;
|
||||
}
|
||||
SIMDJSON_TRY(val.template get<T>(*ptr));
|
||||
out.reset(ptr);
|
||||
return SUCCESS;
|
||||
}
|
||||
} // namespace simdjson
|
||||
|
||||
#endif // SIMDJSON_ONDEMAND_DESERIALIZE_H
|
||||
#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
|
||||
@@ -37,6 +37,11 @@ simdjson_inline uint32_t token_iterator::peek_length(token_position position) co
|
||||
return *(position+1) - *position;
|
||||
}
|
||||
|
||||
simdjson_inline uint32_t token_iterator::peek_root_length(token_position position) const noexcept {
|
||||
return *(position+2) - *(position) > *(position+1) - *(position) ?
|
||||
*(position+1) - *(position)
|
||||
: *(position+2) - *(position);
|
||||
}
|
||||
simdjson_inline const uint8_t *token_iterator::peek(int32_t delta) const noexcept {
|
||||
return &buf[*(_position+delta)];
|
||||
}
|
||||
|
||||
@@ -77,7 +77,14 @@ public:
|
||||
* @param position The position of the token.
|
||||
*/
|
||||
simdjson_inline uint32_t peek_length(token_position position) const noexcept;
|
||||
|
||||
/**
|
||||
* Get the maximum length of the JSON text for a root token.
|
||||
*
|
||||
* The length will include any whitespace at the end of the token.
|
||||
*
|
||||
* @param position The position of the token (start of the document).
|
||||
*/
|
||||
simdjson_inline uint32_t peek_root_length(token_position position) const noexcept;
|
||||
/**
|
||||
* Return the current index.
|
||||
*/
|
||||
|
||||
@@ -80,6 +80,7 @@ simdjson_inline simdjson_result<bool> value::get_bool() noexcept {
|
||||
simdjson_inline simdjson_result<bool> value::is_null() noexcept {
|
||||
return iter.is_null();
|
||||
}
|
||||
|
||||
template<> simdjson_inline simdjson_result<array> value::get() noexcept { return get_array(); }
|
||||
template<> simdjson_inline simdjson_result<object> value::get() noexcept { return get_object(); }
|
||||
template<> simdjson_inline simdjson_result<raw_json_string> value::get() noexcept { return get_raw_json_string(); }
|
||||
@@ -90,9 +91,16 @@ template<> simdjson_inline simdjson_result<uint64_t> value::get() noexcept { ret
|
||||
template<> simdjson_inline simdjson_result<int64_t> value::get() noexcept { return get_int64(); }
|
||||
template<> simdjson_inline simdjson_result<bool> value::get() noexcept { return get_bool(); }
|
||||
|
||||
template<typename T> simdjson_inline error_code value::get(T &out) noexcept {
|
||||
return get<T>().get(out);
|
||||
}
|
||||
|
||||
template<> simdjson_inline error_code value::get(array& out) noexcept { return get_array().get(out); }
|
||||
template<> simdjson_inline error_code value::get(object& out) noexcept { return get_object().get(out); }
|
||||
template<> simdjson_inline error_code value::get(raw_json_string& out) noexcept { return get_raw_json_string().get(out); }
|
||||
template<> simdjson_inline error_code value::get(std::string_view& out) noexcept { return get_string(false).get(out); }
|
||||
template<> simdjson_inline error_code value::get(number& out) noexcept { return get_number().get(out); }
|
||||
template<> simdjson_inline error_code value::get(double& out) noexcept { return get_double().get(out); }
|
||||
template<> simdjson_inline error_code value::get(uint64_t& out) noexcept { return get_uint64().get(out); }
|
||||
template<> simdjson_inline error_code value::get(int64_t& out) noexcept { return get_int64().get(out); }
|
||||
template<> simdjson_inline error_code value::get(bool& out) noexcept { return get_bool().get(out); }
|
||||
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
template <class T>
|
||||
@@ -239,6 +247,26 @@ simdjson_inline int32_t value::current_depth() const noexcept{
|
||||
return iter.json_iter().depth();
|
||||
}
|
||||
|
||||
inline bool is_pointer_well_formed(std::string_view json_pointer) noexcept {
|
||||
if (simdjson_unlikely(json_pointer.empty())) { // can't be
|
||||
return false;
|
||||
}
|
||||
if (simdjson_unlikely(json_pointer[0] != '/')) {
|
||||
return false;
|
||||
}
|
||||
size_t escape = json_pointer.find('~');
|
||||
if (escape == std::string_view::npos) {
|
||||
return true;
|
||||
}
|
||||
if (escape == json_pointer.size() - 1) {
|
||||
return false;
|
||||
}
|
||||
if (json_pointer[escape + 1] != '0' && json_pointer[escape + 1] != '1') {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
simdjson_inline simdjson_result<value> value::at_pointer(std::string_view json_pointer) noexcept {
|
||||
json_type t;
|
||||
SIMDJSON_TRY(type().get(t));
|
||||
@@ -249,6 +277,10 @@ simdjson_inline simdjson_result<value> value::at_pointer(std::string_view json_p
|
||||
case json_type::object:
|
||||
return (*this).get_object().at_pointer(json_pointer);
|
||||
default:
|
||||
// a non-empty string can be invalid, or accessing a primitive (issue 2154)
|
||||
if (is_pointer_well_formed(json_pointer)) {
|
||||
return NO_SUCH_FIELD;
|
||||
}
|
||||
return INVALID_JSON_POINTER;
|
||||
}
|
||||
}
|
||||
@@ -392,6 +424,12 @@ simdjson_inline simdjson_result<bool> simdjson_result<SIMDJSON_IMPLEMENTATION::o
|
||||
return first.is_null();
|
||||
}
|
||||
|
||||
template<> simdjson_inline error_code simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>::get<SIMDJSON_IMPLEMENTATION::ondemand::value>(SIMDJSON_IMPLEMENTATION::ondemand::value &out) noexcept {
|
||||
if (error()) { return error(); }
|
||||
out = first;
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
template<typename T> simdjson_inline simdjson_result<T> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>::get() noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.get<T>();
|
||||
@@ -405,11 +443,6 @@ template<> simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::va
|
||||
if (error()) { return error(); }
|
||||
return std::move(first);
|
||||
}
|
||||
template<> simdjson_inline error_code simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>::get<SIMDJSON_IMPLEMENTATION::ondemand::value>(SIMDJSON_IMPLEMENTATION::ondemand::value &out) noexcept {
|
||||
if (error()) { return error(); }
|
||||
out = first;
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::json_type> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>::type() noexcept {
|
||||
if (error()) { return error(); }
|
||||
@@ -443,7 +476,7 @@ simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::number> simdj
|
||||
template <class T>
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>::operator T() noexcept(false) {
|
||||
if (error()) { throw simdjson_error(error()); }
|
||||
return static_cast<T>(first);
|
||||
return first.get<T>();
|
||||
}
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>::operator SIMDJSON_IMPLEMENTATION::ondemand::array() noexcept(false) {
|
||||
if (error()) { throw simdjson_error(error()); }
|
||||
|
||||
@@ -5,12 +5,15 @@
|
||||
#include "simdjson/generic/ondemand/base.h"
|
||||
#include "simdjson/generic/implementation_simdjson_result_base.h"
|
||||
#include "simdjson/generic/ondemand/value_iterator.h"
|
||||
#include "simdjson/generic/ondemand/deserialize.h"
|
||||
#endif // SIMDJSON_CONDITIONAL_INCLUDE
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
namespace simdjson {
|
||||
|
||||
namespace SIMDJSON_IMPLEMENTATION {
|
||||
namespace ondemand {
|
||||
|
||||
/**
|
||||
* An ephemeral JSON value returned during iteration. It is only valid for as long as you do
|
||||
* not access more data in the JSON document.
|
||||
@@ -35,15 +38,21 @@ public:
|
||||
* @returns A value of the given type, parsed from the JSON.
|
||||
* @returns INCORRECT_TYPE If the JSON value is not the given type.
|
||||
*/
|
||||
template<typename T> simdjson_inline simdjson_result<T> get() noexcept {
|
||||
// Unless the simdjson library provides an inline implementation, calling this method should
|
||||
// immediately fail.
|
||||
static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. "
|
||||
"The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, "
|
||||
"int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), "
|
||||
" get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template.");
|
||||
template <typename T>
|
||||
simdjson_inline simdjson_result<T> get()
|
||||
#if SIMDJSON_SUPPORTS_DESERIALIZATION
|
||||
noexcept(custom_deserializable<T, value> ? nothrow_custom_deserializable<T, value> : true)
|
||||
#else
|
||||
noexcept
|
||||
#endif
|
||||
{
|
||||
static_assert(std::is_default_constructible<T>::value, "The specified type is not default constructible.");
|
||||
T out{};
|
||||
SIMDJSON_TRY(get<T>(out));
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get this value as the given type.
|
||||
*
|
||||
@@ -53,7 +62,32 @@ public:
|
||||
* @returns INCORRECT_TYPE If the JSON value is not an object.
|
||||
* @returns SUCCESS If the parse succeeded and the out parameter was set to the value.
|
||||
*/
|
||||
template<typename T> simdjson_inline error_code get(T &out) noexcept;
|
||||
template <typename T>
|
||||
simdjson_inline error_code get(T &out)
|
||||
#if SIMDJSON_SUPPORTS_DESERIALIZATION
|
||||
noexcept(custom_deserializable<T, value> ? nothrow_custom_deserializable<T, value> : true)
|
||||
#else
|
||||
noexcept
|
||||
#endif
|
||||
{
|
||||
#if SIMDJSON_SUPPORTS_DESERIALIZATION
|
||||
if constexpr (custom_deserializable<T, value>) {
|
||||
return deserialize(*this, out);
|
||||
} else {
|
||||
#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
|
||||
// Unless the simdjson library or the user provides an inline implementation, calling this method should
|
||||
// immediately fail.
|
||||
static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. "
|
||||
"The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, "
|
||||
"int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), "
|
||||
" get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template."
|
||||
" You may also add support for custom types, see our documentation.");
|
||||
static_cast<void>(out); // to get rid of unused errors
|
||||
return UNINITIALIZED;
|
||||
#if SIMDJSON_SUPPORTS_DESERIALIZATION
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Cast this JSON value to an array.
|
||||
@@ -196,7 +230,10 @@ public:
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
/**
|
||||
* Cast this JSON value to an instance of type T. The programmer is responsible for
|
||||
* providing an implementation of get<T> for the type T.
|
||||
* providing an implementation of get<T> for the type T, if T is not one of the types
|
||||
* supported by the library (object, array, raw_json_string, string_view, uint64_t, etc.).
|
||||
*
|
||||
* See https://github.com/simdjson/simdjson/blob/master/doc/basics.md#adding-support-for-custom-types
|
||||
*
|
||||
* @returns An instance of type T
|
||||
*/
|
||||
@@ -365,7 +402,7 @@ public:
|
||||
* that only one field is returned.
|
||||
*
|
||||
* Use find_field() if you are sure fields will be in order (or are willing to treat it as if the
|
||||
* field wasn't there when they aren't).
|
||||
* field as not there when they are not in order).
|
||||
*
|
||||
* @param key The key to look up.
|
||||
* @returns The value of the field, or NO_SUCH_FIELD if the field is not in the object.
|
||||
@@ -440,10 +477,12 @@ public:
|
||||
* get_number().get_number_type().
|
||||
*
|
||||
* get_number_type() is number_type::unsigned_integer if we have
|
||||
* an integer greater or equal to 9223372036854775808
|
||||
* an integer greater or equal to 9223372036854775808.
|
||||
* get_number_type() is number_type::signed_integer if we have an
|
||||
* integer that is less than 9223372036854775808
|
||||
* Otherwise, get_number_type() has value number_type::floating_point_number
|
||||
* integer that is less than 9223372036854775808.
|
||||
* get_number_type() is number_type::big_integer for integers that do not fit in 64 bits,
|
||||
* in which case the digit_count is set to the length of the big integer string.
|
||||
* Otherwise, get_number_type() has value number_type::floating_point_number.
|
||||
*
|
||||
* This function requires processing the number string, but it is expected
|
||||
* to be faster than get_number().get_number_type() because it is does not
|
||||
@@ -470,6 +509,8 @@ public:
|
||||
* You can recover the value by calling number.get_uint64() and you
|
||||
* have that number.is_uint64() is true.
|
||||
*
|
||||
* For integers that do not fit in 64 bits, the function returns BIGINT_ERROR error code.
|
||||
*
|
||||
* Otherwise, number.get_number_type() has value number_type::floating_point_number
|
||||
* and we have a binary64 number.
|
||||
* You can recover the value by calling number.get_double() and you
|
||||
@@ -485,7 +526,6 @@ public:
|
||||
*/
|
||||
simdjson_warn_unused simdjson_inline simdjson_result<number> get_number() noexcept;
|
||||
|
||||
|
||||
/**
|
||||
* Get the raw JSON for this token.
|
||||
*
|
||||
@@ -729,7 +769,7 @@ public:
|
||||
* APIs assume this. Therefore, you must be explicit if you want to treat objects as out of order.
|
||||
*
|
||||
* Use find_field() if you are sure fields will be in order (or are willing to treat it as if the
|
||||
* field wasn't there when they aren't).
|
||||
* field as not there when they are not in order).
|
||||
*
|
||||
* @param key The key to look up.
|
||||
* @returns The value of the field, or NO_SUCH_FIELD if the field is not in the object.
|
||||
|
||||
@@ -137,7 +137,7 @@ simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::find_
|
||||
} else if (!is_open()) {
|
||||
#if SIMDJSON_DEVELOPMENT_CHECKS
|
||||
// If we're past the end of the object, we're being iterated out of order.
|
||||
// Note: this isn't perfect detection. It's possible the user is inside some other object; if so,
|
||||
// Note: this is not perfect detection. It's possible the user is inside some other object; if so,
|
||||
// this object iterator will blithely scan that object for fields.
|
||||
if (_json_iter->depth() < depth() - 1) { return OUT_OF_ORDER_ITERATION; }
|
||||
#endif
|
||||
@@ -249,7 +249,7 @@ simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::find_
|
||||
|
||||
#if SIMDJSON_DEVELOPMENT_CHECKS
|
||||
// If we're past the end of the object, we're being iterated out of order.
|
||||
// Note: this isn't perfect detection. It's possible the user is inside some other object; if so,
|
||||
// Note: this is not perfect detection. It's possible the user is inside some other object; if so,
|
||||
// this object iterator will blithely scan that object for fields.
|
||||
if (_json_iter->depth() < depth() - 1) { return OUT_OF_ORDER_ITERATION; }
|
||||
#endif
|
||||
@@ -591,7 +591,7 @@ simdjson_inline simdjson_result<number> value_iterator::get_number() noexcept {
|
||||
}
|
||||
|
||||
simdjson_inline simdjson_result<bool> value_iterator::is_root_integer(bool check_trailing) noexcept {
|
||||
auto max_len = peek_start_length();
|
||||
auto max_len = peek_root_length();
|
||||
auto json = peek_root_scalar("is_root_integer");
|
||||
uint8_t tmpbuf[20+1+1]{}; // <20 digits> is the longest possible unsigned integer
|
||||
tmpbuf[20+1] = '\0'; // make sure that buffer is always null terminated.
|
||||
@@ -607,7 +607,7 @@ simdjson_inline simdjson_result<bool> value_iterator::is_root_integer(bool check
|
||||
}
|
||||
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::number_type> value_iterator::get_root_number_type(bool check_trailing) noexcept {
|
||||
auto max_len = peek_start_length();
|
||||
auto max_len = peek_root_length();
|
||||
auto json = peek_root_scalar("number");
|
||||
// Per https://www.exploringbinary.com/maximum-number-of-decimal-digits-in-binary-floating-point-numbers/,
|
||||
// 1074 is the maximum number of significant fractional digits. Add 8 more digits for the biggest
|
||||
@@ -615,7 +615,12 @@ simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::number_type> value_iter
|
||||
uint8_t tmpbuf[1074+8+1+1];
|
||||
tmpbuf[1074+8+1] = '\0'; // make sure that buffer is always null terminated.
|
||||
if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 1074+8+1)) {
|
||||
logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 1082 characters");
|
||||
if(numberparsing::check_if_integer(json, max_len)) {
|
||||
if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
|
||||
logger::log_error(*_json_iter, start_position(), depth(), "Found big integer");
|
||||
return number_type::big_integer;
|
||||
}
|
||||
logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 1082 characters and not a big integer");
|
||||
return NUMBER_ERROR;
|
||||
}
|
||||
auto answer = numberparsing::get_number_type(tmpbuf);
|
||||
@@ -623,15 +628,21 @@ simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::number_type> value_iter
|
||||
return answer;
|
||||
}
|
||||
simdjson_inline simdjson_result<number> value_iterator::get_root_number(bool check_trailing) noexcept {
|
||||
auto max_len = peek_start_length();
|
||||
auto max_len = peek_root_length();
|
||||
auto json = peek_root_scalar("number");
|
||||
// Per https://www.exploringbinary.com/maximum-number-of-decimal-digits-in-binary-floating-point-numbers/,
|
||||
// 1074 is the maximum number of significant fractional digits. Add 8 more digits for the biggest
|
||||
// number: -0.<fraction>e-308.
|
||||
// NOTE: the current approach doesn't work for very big integer numbers containing more than 1074 digits.
|
||||
uint8_t tmpbuf[1074+8+1+1];
|
||||
tmpbuf[1074+8+1] = '\0'; // make sure that buffer is always null terminated.
|
||||
if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 1074+8+1)) {
|
||||
logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 1082 characters");
|
||||
if(numberparsing::check_if_integer(json, max_len)) {
|
||||
if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
|
||||
logger::log_error(*_json_iter, start_position(), depth(), "Found big integer");
|
||||
return BIGINT_ERROR;
|
||||
}
|
||||
logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 1082 characters and not a big integer");
|
||||
return NUMBER_ERROR;
|
||||
}
|
||||
number num;
|
||||
@@ -663,7 +674,7 @@ simdjson_warn_unused simdjson_inline simdjson_result<raw_json_string> value_iter
|
||||
return raw_json_string(json+1);
|
||||
}
|
||||
simdjson_warn_unused simdjson_inline simdjson_result<uint64_t> value_iterator::get_root_uint64(bool check_trailing) noexcept {
|
||||
auto max_len = peek_start_length();
|
||||
auto max_len = peek_root_length();
|
||||
auto json = peek_root_scalar("uint64");
|
||||
uint8_t tmpbuf[20+1+1]{}; // <20 digits> is the longest possible unsigned integer
|
||||
tmpbuf[20+1] = '\0'; // make sure that buffer is always null terminated.
|
||||
@@ -679,7 +690,7 @@ simdjson_warn_unused simdjson_inline simdjson_result<uint64_t> value_iterator::g
|
||||
return result;
|
||||
}
|
||||
simdjson_warn_unused simdjson_inline simdjson_result<uint64_t> value_iterator::get_root_uint64_in_string(bool check_trailing) noexcept {
|
||||
auto max_len = peek_start_length();
|
||||
auto max_len = peek_root_length();
|
||||
auto json = peek_root_scalar("uint64");
|
||||
uint8_t tmpbuf[20+1+1]{}; // <20 digits> is the longest possible unsigned integer
|
||||
tmpbuf[20+1] = '\0'; // make sure that buffer is always null terminated.
|
||||
@@ -695,7 +706,7 @@ simdjson_warn_unused simdjson_inline simdjson_result<uint64_t> value_iterator::g
|
||||
return result;
|
||||
}
|
||||
simdjson_warn_unused simdjson_inline simdjson_result<int64_t> value_iterator::get_root_int64(bool check_trailing) noexcept {
|
||||
auto max_len = peek_start_length();
|
||||
auto max_len = peek_root_length();
|
||||
auto json = peek_root_scalar("int64");
|
||||
uint8_t tmpbuf[20+1+1]; // -<19 digits> is the longest possible integer
|
||||
tmpbuf[20+1] = '\0'; // make sure that buffer is always null terminated.
|
||||
@@ -712,7 +723,7 @@ simdjson_warn_unused simdjson_inline simdjson_result<int64_t> value_iterator::ge
|
||||
return result;
|
||||
}
|
||||
simdjson_warn_unused simdjson_inline simdjson_result<int64_t> value_iterator::get_root_int64_in_string(bool check_trailing) noexcept {
|
||||
auto max_len = peek_start_length();
|
||||
auto max_len = peek_root_length();
|
||||
auto json = peek_root_scalar("int64");
|
||||
uint8_t tmpbuf[20+1+1]; // -<19 digits> is the longest possible integer
|
||||
tmpbuf[20+1] = '\0'; // make sure that buffer is always null terminated.
|
||||
@@ -729,7 +740,7 @@ simdjson_warn_unused simdjson_inline simdjson_result<int64_t> value_iterator::ge
|
||||
return result;
|
||||
}
|
||||
simdjson_warn_unused simdjson_inline simdjson_result<double> value_iterator::get_root_double(bool check_trailing) noexcept {
|
||||
auto max_len = peek_start_length();
|
||||
auto max_len = peek_root_length();
|
||||
auto json = peek_root_scalar("double");
|
||||
// Per https://www.exploringbinary.com/maximum-number-of-decimal-digits-in-binary-floating-point-numbers/,
|
||||
// 1074 is the maximum number of significant fractional digits. Add 8 more digits for the biggest
|
||||
@@ -749,7 +760,7 @@ simdjson_warn_unused simdjson_inline simdjson_result<double> value_iterator::get
|
||||
}
|
||||
|
||||
simdjson_warn_unused simdjson_inline simdjson_result<double> value_iterator::get_root_double_in_string(bool check_trailing) noexcept {
|
||||
auto max_len = peek_start_length();
|
||||
auto max_len = peek_root_length();
|
||||
auto json = peek_root_scalar("double");
|
||||
// Per https://www.exploringbinary.com/maximum-number-of-decimal-digits-in-binary-floating-point-numbers/,
|
||||
// 1074 is the maximum number of significant fractional digits. Add 8 more digits for the biggest
|
||||
@@ -768,7 +779,7 @@ simdjson_warn_unused simdjson_inline simdjson_result<double> value_iterator::get
|
||||
return result;
|
||||
}
|
||||
simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::get_root_bool(bool check_trailing) noexcept {
|
||||
auto max_len = peek_start_length();
|
||||
auto max_len = peek_root_length();
|
||||
auto json = peek_root_scalar("bool");
|
||||
uint8_t tmpbuf[5+1+1]; // +1 for null termination
|
||||
tmpbuf[5+1] = '\0'; // make sure that buffer is always null terminated.
|
||||
@@ -781,7 +792,7 @@ simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::get_r
|
||||
return result;
|
||||
}
|
||||
simdjson_inline simdjson_result<bool> value_iterator::is_root_null(bool check_trailing) noexcept {
|
||||
auto max_len = peek_start_length();
|
||||
auto max_len = peek_root_length();
|
||||
auto json = peek_root_scalar("null");
|
||||
bool result = (max_len >= 4 && !atomparsing::str4ncmp(json, "null") &&
|
||||
(max_len == 4 || jsoncharutils::is_structural_or_whitespace(json[4])));
|
||||
@@ -853,6 +864,9 @@ simdjson_inline const uint8_t *value_iterator::peek_start() const noexcept {
|
||||
simdjson_inline uint32_t value_iterator::peek_start_length() const noexcept {
|
||||
return _json_iter->peek_length(start_position());
|
||||
}
|
||||
simdjson_inline uint32_t value_iterator::peek_root_length() const noexcept {
|
||||
return _json_iter->peek_root_length(start_position());
|
||||
}
|
||||
|
||||
simdjson_inline const uint8_t *value_iterator::peek_scalar(const char *type) noexcept {
|
||||
logger::log_value(*_json_iter, start_position(), depth(), type);
|
||||
|
||||
@@ -375,6 +375,7 @@ protected:
|
||||
simdjson_inline simdjson_result<bool> parse_bool(const uint8_t *json) const noexcept;
|
||||
simdjson_inline const uint8_t *peek_start() const noexcept;
|
||||
simdjson_inline uint32_t peek_start_length() const noexcept;
|
||||
simdjson_inline uint32_t peek_root_length() const noexcept;
|
||||
|
||||
/**
|
||||
* The general idea of the advance_... methods and the peek_* methods
|
||||
|
||||
@@ -37,13 +37,13 @@ static simdjson_inline uint32_t parse_eight_digits_unrolled(const uint8_t *chars
|
||||
simdjson_inline internal::value128 full_multiplication(uint64_t value1, uint64_t value2) {
|
||||
internal::value128 answer;
|
||||
#if SIMDJSON_REGULAR_VISUAL_STUDIO || SIMDJSON_IS_32BITS
|
||||
#ifdef _M_ARM64
|
||||
#if SIMDJSON_IS_ARM64
|
||||
// ARM64 has native support for 64-bit multiplications, no need to emultate
|
||||
answer.high = __umulh(value1, value2);
|
||||
answer.low = value1 * value2;
|
||||
#else
|
||||
answer.low = _umul128(value1, value2, &answer.high); // _umul128 not available on ARM64
|
||||
#endif // _M_ARM64
|
||||
#endif // SIMDJSON_IS_ARM64
|
||||
#else // SIMDJSON_REGULAR_VISUAL_STUDIO || SIMDJSON_IS_32BITS
|
||||
__uint128_t r = (static_cast<__uint128_t>(value1)) * value2;
|
||||
answer.low = uint64_t(r);
|
||||
|
||||
@@ -65,10 +65,10 @@ namespace simd {
|
||||
struct simd8<bool>: base8<bool> {
|
||||
static simdjson_inline simd8<bool> splat(bool _value) { return _mm256_set1_epi8(uint8_t(-(!!_value))); }
|
||||
|
||||
simdjson_inline simd8<bool>() : base8() {}
|
||||
simdjson_inline simd8<bool>(const __m256i _value) : base8<bool>(_value) {}
|
||||
simdjson_inline simd8() : base8() {}
|
||||
simdjson_inline simd8(const __m256i _value) : base8<bool>(_value) {}
|
||||
// Splat constructor
|
||||
simdjson_inline simd8<bool>(bool _value) : base8<bool>(splat(_value)) {}
|
||||
simdjson_inline simd8(bool _value) : base8<bool>(splat(_value)) {}
|
||||
|
||||
simdjson_inline int to_bitmask() const { return _mm256_movemask_epi8(*this); }
|
||||
simdjson_inline bool any() const { return !_mm256_testz_si256(*this, *this); }
|
||||
|
||||
@@ -33,13 +33,13 @@ static simdjson_inline uint32_t parse_eight_digits_unrolled(const uint8_t *chars
|
||||
simdjson_inline internal::value128 full_multiplication(uint64_t value1, uint64_t value2) {
|
||||
internal::value128 answer;
|
||||
#if SIMDJSON_REGULAR_VISUAL_STUDIO || SIMDJSON_IS_32BITS
|
||||
#ifdef _M_ARM64
|
||||
#if SIMDJSON_IS_ARM64
|
||||
// ARM64 has native support for 64-bit multiplications, no need to emultate
|
||||
answer.high = __umulh(value1, value2);
|
||||
answer.low = value1 * value2;
|
||||
#else
|
||||
answer.low = _umul128(value1, value2, &answer.high); // _umul128 not available on ARM64
|
||||
#endif // _M_ARM64
|
||||
#endif // SIMDJSON_IS_ARM64
|
||||
#else // SIMDJSON_REGULAR_VISUAL_STUDIO || SIMDJSON_IS_32BITS
|
||||
__uint128_t r = (static_cast<__uint128_t>(value1)) * value2;
|
||||
answer.low = uint64_t(r);
|
||||
|
||||
@@ -93,10 +93,10 @@ namespace simd {
|
||||
struct simd8<bool>: base8<bool> {
|
||||
static simdjson_inline simd8<bool> splat(bool _value) { return _mm512_set1_epi8(uint8_t(-(!!_value))); }
|
||||
|
||||
simdjson_inline simd8<bool>() : base8() {}
|
||||
simdjson_inline simd8<bool>(const __m512i _value) : base8<bool>(_value) {}
|
||||
simdjson_inline simd8() : base8() {}
|
||||
simdjson_inline simd8(const __m512i _value) : base8<bool>(_value) {}
|
||||
// Splat constructor
|
||||
simdjson_inline simd8<bool>(bool _value) : base8<bool>(splat(_value)) {}
|
||||
simdjson_inline simd8(bool _value) : base8<bool>(splat(_value)) {}
|
||||
simdjson_inline bool any() const { return !!_mm512_test_epi8_mask (*this, *this); }
|
||||
simdjson_inline simd8<bool> operator~() const { return *this ^ true; }
|
||||
};
|
||||
|
||||
@@ -53,7 +53,7 @@ public:
|
||||
*
|
||||
* @return the name of the implementation, e.g. "haswell", "westmere", "arm64".
|
||||
*/
|
||||
virtual const std::string &name() const { return _name; }
|
||||
virtual std::string name() const { return std::string(_name); }
|
||||
|
||||
/**
|
||||
* The description of this implementation.
|
||||
@@ -63,7 +63,7 @@ public:
|
||||
*
|
||||
* @return the description of the implementation, e.g. "Intel/AMD AVX2", "Intel/AMD SSE4.2", "ARM NEON".
|
||||
*/
|
||||
virtual const std::string &description() const { return _description; }
|
||||
virtual std::string description() const { return std::string(_description); }
|
||||
|
||||
/**
|
||||
* The instruction sets this implementation is compiled against
|
||||
@@ -139,18 +139,19 @@ protected:
|
||||
_required_instruction_sets(required_instruction_sets)
|
||||
{
|
||||
}
|
||||
virtual ~implementation()=default;
|
||||
protected:
|
||||
~implementation() = default;
|
||||
|
||||
private:
|
||||
/**
|
||||
* The name of this implementation.
|
||||
*/
|
||||
const std::string _name;
|
||||
std::string_view _name;
|
||||
|
||||
/**
|
||||
* The description of this implementation.
|
||||
*/
|
||||
const std::string _description;
|
||||
std::string_view _description;
|
||||
|
||||
/**
|
||||
* Instruction sets required for this implementation.
|
||||
|
||||
@@ -10,6 +10,8 @@
|
||||
#define SIMDJSON_IMPLEMENTATION_ID_icelake 4
|
||||
#define SIMDJSON_IMPLEMENTATION_ID_ppc64 5
|
||||
#define SIMDJSON_IMPLEMENTATION_ID_westmere 6
|
||||
#define SIMDJSON_IMPLEMENTATION_ID_lsx 7
|
||||
#define SIMDJSON_IMPLEMENTATION_ID_lasx 8
|
||||
|
||||
#define SIMDJSON_IMPLEMENTATION_ID_FOR(IMPL) SIMDJSON_CAT(SIMDJSON_IMPLEMENTATION_ID_, IMPL)
|
||||
#define SIMDJSON_IMPLEMENTATION_ID SIMDJSON_IMPLEMENTATION_ID_FOR(SIMDJSON_IMPLEMENTATION)
|
||||
@@ -24,7 +26,11 @@
|
||||
#ifndef SIMDJSON_IMPLEMENTATION_ARM64
|
||||
#define SIMDJSON_IMPLEMENTATION_ARM64 (SIMDJSON_IS_ARM64)
|
||||
#endif
|
||||
#define SIMDJSON_CAN_ALWAYS_RUN_ARM64 SIMDJSON_IMPLEMENTATION_ARM64 && SIMDJSON_IS_ARM64
|
||||
#if SIMDJSON_IMPLEMENTATION_ARM64 && SIMDJSON_IS_ARM64
|
||||
#define SIMDJSON_CAN_ALWAYS_RUN_ARM64 1
|
||||
#else
|
||||
#define SIMDJSON_CAN_ALWAYS_RUN_ARM64 0
|
||||
#endif
|
||||
|
||||
// Default Icelake to on if this is x86-64. Even if we're not compiled for it, it could be selected
|
||||
// at runtime.
|
||||
@@ -35,9 +41,20 @@
|
||||
#ifdef _MSC_VER
|
||||
// To see why (__BMI__) && (__PCLMUL__) && (__LZCNT__) are not part of this next line, see
|
||||
// https://github.com/simdjson/simdjson/issues/1247
|
||||
#define SIMDJSON_CAN_ALWAYS_RUN_ICELAKE ((SIMDJSON_IMPLEMENTATION_ICELAKE) && (__AVX2__) && (__AVX512F__) && (__AVX512DQ__) && (__AVX512CD__) && (__AVX512BW__) && (__AVX512VL__) && (__AVX512VBMI2__))
|
||||
#if ((SIMDJSON_IMPLEMENTATION_ICELAKE) && (__AVX2__) && (__AVX512F__) && (__AVX512DQ__) && (__AVX512CD__) && (__AVX512BW__) && (__AVX512VL__) && (__AVX512VBMI2__))
|
||||
#define SIMDJSON_CAN_ALWAYS_RUN_ICELAKE 1
|
||||
#else
|
||||
#define SIMDJSON_CAN_ALWAYS_RUN_ICELAKE ((SIMDJSON_IMPLEMENTATION_ICELAKE) && (__AVX2__) && (__BMI__) && (__PCLMUL__) && (__LZCNT__) && (__AVX512F__) && (__AVX512DQ__) && (__AVX512CD__) && (__AVX512BW__) && (__AVX512VL__) && (__AVX512VBMI2__))
|
||||
#define SIMDJSON_CAN_ALWAYS_RUN_ICELAKE 0
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
#if ((SIMDJSON_IMPLEMENTATION_ICELAKE) && (__AVX2__) && (__BMI__) && (__PCLMUL__) && (__LZCNT__) && (__AVX512F__) && (__AVX512DQ__) && (__AVX512CD__) && (__AVX512BW__) && (__AVX512VL__) && (__AVX512VBMI2__))
|
||||
#define SIMDJSON_CAN_ALWAYS_RUN_ICELAKE 1
|
||||
#else
|
||||
#define SIMDJSON_CAN_ALWAYS_RUN_ICELAKE 0
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
// Default Haswell to on if this is x86-64. Even if we're not compiled for it, it could be selected
|
||||
@@ -53,9 +70,20 @@
|
||||
#ifdef _MSC_VER
|
||||
// To see why (__BMI__) && (__PCLMUL__) && (__LZCNT__) are not part of this next line, see
|
||||
// https://github.com/simdjson/simdjson/issues/1247
|
||||
#define SIMDJSON_CAN_ALWAYS_RUN_HASWELL ((SIMDJSON_IMPLEMENTATION_HASWELL) && (SIMDJSON_IS_X86_64) && (__AVX2__))
|
||||
#if ((SIMDJSON_IMPLEMENTATION_HASWELL) && (SIMDJSON_IS_X86_64) && (__AVX2__))
|
||||
#define SIMDJSON_CAN_ALWAYS_RUN_HASWELL 1
|
||||
#else
|
||||
#define SIMDJSON_CAN_ALWAYS_RUN_HASWELL ((SIMDJSON_IMPLEMENTATION_HASWELL) && (SIMDJSON_IS_X86_64) && (__AVX2__) && (__BMI__) && (__PCLMUL__) && (__LZCNT__))
|
||||
#define SIMDJSON_CAN_ALWAYS_RUN_HASWELL 0
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
#if ((SIMDJSON_IMPLEMENTATION_HASWELL) && (SIMDJSON_IS_X86_64) && (__AVX2__) && (__BMI__) && (__PCLMUL__) && (__LZCNT__))
|
||||
#define SIMDJSON_CAN_ALWAYS_RUN_HASWELL 1
|
||||
#else
|
||||
#define SIMDJSON_CAN_ALWAYS_RUN_HASWELL 0
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
// Default Westmere to on if this is x86-64.
|
||||
@@ -67,16 +95,40 @@
|
||||
#define SIMDJSON_IMPLEMENTATION_WESTMERE SIMDJSON_IS_X86_64
|
||||
#endif
|
||||
#endif
|
||||
#define SIMDJSON_CAN_ALWAYS_RUN_WESTMERE (SIMDJSON_IMPLEMENTATION_WESTMERE && SIMDJSON_IS_X86_64 && __SSE4_2__ && __PCLMUL__)
|
||||
|
||||
#if (SIMDJSON_IMPLEMENTATION_WESTMERE && SIMDJSON_IS_X86_64 && __SSE4_2__ && __PCLMUL__)
|
||||
#define SIMDJSON_CAN_ALWAYS_RUN_WESTMERE 1
|
||||
#else
|
||||
#define SIMDJSON_CAN_ALWAYS_RUN_WESTMERE 0
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef SIMDJSON_IMPLEMENTATION_PPC64
|
||||
#define SIMDJSON_IMPLEMENTATION_PPC64 (SIMDJSON_IS_PPC64 && SIMDJSON_IS_PPC64_VMX)
|
||||
#endif
|
||||
#define SIMDJSON_CAN_ALWAYS_RUN_PPC64 SIMDJSON_IMPLEMENTATION_PPC64 && SIMDJSON_IS_PPC64 && SIMDJSON_IS_PPC64_VMX
|
||||
#if SIMDJSON_IMPLEMENTATION_PPC64 && SIMDJSON_IS_PPC64 && SIMDJSON_IS_PPC64_VMX
|
||||
#define SIMDJSON_CAN_ALWAYS_RUN_PPC64 1
|
||||
#else
|
||||
#define SIMDJSON_CAN_ALWAYS_RUN_PPC64 0
|
||||
#endif
|
||||
|
||||
#ifndef SIMDJSON_IMPLEMENTATION_LASX
|
||||
#define SIMDJSON_IMPLEMENTATION_LASX (SIMDJSON_IS_LOONGARCH64 && __loongarch_asx)
|
||||
#endif
|
||||
#define SIMDJSON_CAN_ALWAYS_RUN_LASX (SIMDJSON_IMPLEMENTATION_LASX)
|
||||
|
||||
#ifndef SIMDJSON_IMPLEMENTATION_LSX
|
||||
#if SIMDJSON_CAN_ALWAYS_RUN_LASX
|
||||
#define SIMDJSON_IMPLEMENTATION_LSX 0
|
||||
#else
|
||||
#define SIMDJSON_IMPLEMENTATION_LSX (SIMDJSON_IS_LOONGARCH64 && __loongarch_sx)
|
||||
#endif
|
||||
#endif
|
||||
#define SIMDJSON_CAN_ALWAYS_RUN_LSX (SIMDJSON_IMPLEMENTATION_LSX)
|
||||
|
||||
// Default Fallback to on unless a builtin implementation has already been selected.
|
||||
#ifndef SIMDJSON_IMPLEMENTATION_FALLBACK
|
||||
#if SIMDJSON_CAN_ALWAYS_RUN_ARM64 || SIMDJSON_CAN_ALWAYS_RUN_ICELAKE || SIMDJSON_CAN_ALWAYS_RUN_HASWELL || SIMDJSON_CAN_ALWAYS_RUN_WESTMERE || SIMDJSON_CAN_ALWAYS_RUN_PPC64
|
||||
#if SIMDJSON_CAN_ALWAYS_RUN_ARM64 || SIMDJSON_CAN_ALWAYS_RUN_ICELAKE || SIMDJSON_CAN_ALWAYS_RUN_HASWELL || SIMDJSON_CAN_ALWAYS_RUN_WESTMERE || SIMDJSON_CAN_ALWAYS_RUN_PPC64 || SIMDJSON_CAN_ALWAYS_RUN_LSX || SIMDJSON_CAN_ALWAYS_RUN_LASX
|
||||
// if anything at all except fallback can always run, then disable fallback.
|
||||
#define SIMDJSON_IMPLEMENTATION_FALLBACK 0
|
||||
#else
|
||||
@@ -98,6 +150,10 @@
|
||||
#define SIMDJSON_BUILTIN_IMPLEMENTATION arm64
|
||||
#elif SIMDJSON_CAN_ALWAYS_RUN_PPC64
|
||||
#define SIMDJSON_BUILTIN_IMPLEMENTATION ppc64
|
||||
#elif SIMDJSON_CAN_ALWAYS_RUN_LSX
|
||||
#define SIMDJSON_BUILTIN_IMPLEMENTATION lsx
|
||||
#elif SIMDJSON_CAN_ALWAYS_RUN_LASX
|
||||
#define SIMDJSON_BUILTIN_IMPLEMENTATION lasx
|
||||
#elif SIMDJSON_CAN_ALWAYS_RUN_FALLBACK
|
||||
#define SIMDJSON_BUILTIN_IMPLEMENTATION fallback
|
||||
#else
|
||||
|
||||
@@ -106,7 +106,7 @@ public:
|
||||
* Unescape a valid UTF-8 string from src to dst, stopping at a final unescaped quote. There
|
||||
* must be an unescaped quote terminating the string. It returns the final output
|
||||
* position as pointer. In case of error (e.g., the string has bad escaped codes),
|
||||
* then null_nullptrptr is returned. It is assumed that the output buffer is large
|
||||
* then null_ptr is returned. It is assumed that the output buffer is large
|
||||
* enough. E.g., if src points at 'joe"', then dst needs to have four free bytes +
|
||||
* SIMDJSON_PADDING bytes.
|
||||
*
|
||||
@@ -123,7 +123,7 @@ public:
|
||||
* Unescape a NON-valid UTF-8 string from src to dst, stopping at a final unescaped quote. There
|
||||
* must be an unescaped quote terminating the string. It returns the final output
|
||||
* position as pointer. In case of error (e.g., the string has bad escaped codes),
|
||||
* then null_nullptrptr is returned. It is assumed that the output buffer is large
|
||||
* then null_ptr is returned. It is assumed that the output buffer is large
|
||||
* enough. E.g., if src points at 'joe"', then dst needs to have four free bytes +
|
||||
* SIMDJSON_PADDING bytes.
|
||||
*
|
||||
@@ -177,14 +177,14 @@ public:
|
||||
*
|
||||
* @return Current capacity, in bytes.
|
||||
*/
|
||||
simdjson_inline size_t capacity() const noexcept;
|
||||
simdjson_pure simdjson_inline size_t capacity() const noexcept;
|
||||
|
||||
/**
|
||||
* The maximum level of nested object and arrays supported by this parser.
|
||||
*
|
||||
* @return Maximum depth, in bytes.
|
||||
*/
|
||||
simdjson_inline size_t max_depth() const noexcept;
|
||||
simdjson_pure simdjson_inline size_t max_depth() const noexcept;
|
||||
|
||||
/**
|
||||
* Ensure this parser has enough memory to process JSON documents up to `capacity` bytes in length
|
||||
@@ -225,11 +225,11 @@ simdjson_inline dom_parser_implementation::dom_parser_implementation() noexcept
|
||||
simdjson_inline dom_parser_implementation::dom_parser_implementation(dom_parser_implementation &&other) noexcept = default;
|
||||
simdjson_inline dom_parser_implementation &dom_parser_implementation::operator=(dom_parser_implementation &&other) noexcept = default;
|
||||
|
||||
simdjson_inline size_t dom_parser_implementation::capacity() const noexcept {
|
||||
simdjson_pure simdjson_inline size_t dom_parser_implementation::capacity() const noexcept {
|
||||
return _capacity;
|
||||
}
|
||||
|
||||
simdjson_inline size_t dom_parser_implementation::max_depth() const noexcept {
|
||||
simdjson_pure simdjson_inline size_t dom_parser_implementation::max_depth() const noexcept {
|
||||
return _max_depth;
|
||||
}
|
||||
|
||||
|
||||
@@ -66,7 +66,9 @@ enum instruction_set {
|
||||
AVX512CD = 0x2000,
|
||||
AVX512BW = 0x4000,
|
||||
AVX512VL = 0x8000,
|
||||
AVX512VBMI2 = 0x10000
|
||||
AVX512VBMI2 = 0x10000,
|
||||
LSX = 0x20000,
|
||||
LASX = 0x40000,
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user