mirror of
https://github.com/simdjson/simdjson
synced 2026-06-08 17:27:07 +00:00
Compare commits
77 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 7e1d07ee86 | |||
| 9de1b45e30 | |||
| 7a73230459 | |||
| 667f488c2c | |||
| e6c90b8efb | |||
| 7c450fbb70 | |||
| 4e1e002cb0 | |||
| de196dd7a3 | |||
| 08cb8dd81c | |||
| 57d54792ba | |||
| 79879802f9 | |||
| fbe955e9a4 | |||
| a49ac04046 | |||
| 49c7654a70 | |||
| 3e777c1759 | |||
| a410c723c8 | |||
| f91a1ae07e | |||
| c3954b1fb8 | |||
| ce74ece545 | |||
| dd4dce848e | |||
| e8f370b085 | |||
| 645033a8c8 | |||
| 3b5ceeb80d | |||
| 82433a67f9 | |||
| 8c1bfe782b | |||
| 730939f01c | |||
| b169dc2ea7 | |||
| 1aa1d537fe | |||
| c122462278 | |||
| b6b338bea9 | |||
| f72636b5b0 | |||
| f6a2bac11b | |||
| e4ddc5446b | |||
| e0e0aa9e7b | |||
| 9f0a2e0e86 | |||
| 203c03e90b | |||
| 6698eb96b9 | |||
| 30f7de387c | |||
| e0788507fe | |||
| e4740c87fb | |||
| 5beef701e7 | |||
| c6f9c93c33 | |||
| 3a93e45dd1 | |||
| 6db8ceb46c | |||
| 23651f0d41 | |||
| 7e1893db42 | |||
| b4b1927b0f | |||
| e275589832 | |||
| 69ee84973a | |||
| 76bed68ec3 | |||
| 003d970cd2 | |||
| 4aaf3f030c | |||
| 2763f7e719 | |||
| 39035c39be | |||
| ac179ff40f | |||
| b41bece32c | |||
| 9cb0c5f92d | |||
| 1dec7b04fe | |||
| c6eb6f98b8 | |||
| 1b01969bda | |||
| 17f3148ac7 | |||
| 35b4a48e99 | |||
| c0d18452fc | |||
| e5c9a310cf | |||
| 6d308a08c5 | |||
| 9e477ddb00 | |||
| b7c4d1eeef | |||
| 4a2f10ebcf | |||
| 41cb909604 | |||
| 91908ade4d | |||
| 9a32c48098 | |||
| d996ffc494 | |||
| d56fdc3d04 | |||
| 1dce4fed6e | |||
| cae5e5342f | |||
| 4e609aa955 | |||
| d28e5534d9 |
+8
-46
@@ -1,46 +1,4 @@
|
|||||||
kind: pipeline
|
kind: pipeline
|
||||||
name: i386-gcc # we do not support 32-bit systems, but we run tests
|
|
||||||
platform: { os: linux, arch: amd64 }
|
|
||||||
steps:
|
|
||||||
- name: Build and Test
|
|
||||||
image: i386/ubuntu
|
|
||||||
environment:
|
|
||||||
CC: gcc
|
|
||||||
CXX: g++
|
|
||||||
BUILD_FLAGS: -- -j
|
|
||||||
CMAKE_FLAGS: -DBUILD_SHARED_LIBS=OFF
|
|
||||||
CTEST_FLAGS: -j4 --output-on-failure -LE explicitonly
|
|
||||||
commands:
|
|
||||||
- scripts/addcmakeppa.sh "$(env -i sh -c '. /etc/os-release; echo $VERSION_CODENAME')"
|
|
||||||
- apt-get install -y g++ cmake gcc git
|
|
||||||
- mkdir build
|
|
||||||
- cd build
|
|
||||||
- cmake $CMAKE_FLAGS ..
|
|
||||||
- cmake --build . $BUILD_FLAGS
|
|
||||||
- ctest $CTEST_FLAGS
|
|
||||||
---
|
|
||||||
kind: pipeline
|
|
||||||
name: i386-clang # we do not support 32-bit systems, but we run tests
|
|
||||||
platform: { os: linux, arch: amd64 }
|
|
||||||
steps:
|
|
||||||
- name: Build and Test
|
|
||||||
image: i386/ubuntu
|
|
||||||
environment:
|
|
||||||
CC: clang-6.0
|
|
||||||
CXX: clang++-6.0
|
|
||||||
BUILD_FLAGS: -- -j
|
|
||||||
CMAKE_FLAGS: -DBUILD_SHARED_LIBS=OFF
|
|
||||||
CTEST_FLAGS: -j4 --output-on-failure -LE explicitonly
|
|
||||||
commands:
|
|
||||||
- scripts/addcmakeppa.sh "$(env -i sh -c '. /etc/os-release; echo $VERSION_CODENAME')"
|
|
||||||
- apt-get install -y clang++-6.0 cmake git
|
|
||||||
- mkdir build
|
|
||||||
- cd build
|
|
||||||
- cmake $CMAKE_FLAGS ..
|
|
||||||
- cmake --build . $BUILD_FLAGS
|
|
||||||
- ctest $CTEST_FLAGS
|
|
||||||
---
|
|
||||||
kind: pipeline
|
|
||||||
name: gcc9
|
name: gcc9
|
||||||
platform: { os: linux, arch: amd64 }
|
platform: { os: linux, arch: amd64 }
|
||||||
steps:
|
steps:
|
||||||
@@ -50,7 +8,7 @@ steps:
|
|||||||
CC: gcc
|
CC: gcc
|
||||||
CXX: g++
|
CXX: g++
|
||||||
BUILD_FLAGS: -- -j
|
BUILD_FLAGS: -- -j
|
||||||
CMAKE_FLAGS: -DBUILD_SHARED_LIBS=OFF -DSIMDJSON_IMPLEMENTATION=haswell;westmere;fallback
|
CMAKE_FLAGS: -DBUILD_SHARED_LIBS=OFF -DSIMDJSON_IMPLEMENTATION=icelake;haswell;westmere;fallback
|
||||||
CTEST_FLAGS: -j4 --output-on-failure -LE explicitonly
|
CTEST_FLAGS: -j4 --output-on-failure -LE explicitonly
|
||||||
commands:
|
commands:
|
||||||
- echo "deb http://deb.debian.org/debian buster-backports main" >> /etc/apt/sources.list
|
- echo "deb http://deb.debian.org/debian buster-backports main" >> /etc/apt/sources.list
|
||||||
@@ -61,6 +19,7 @@ steps:
|
|||||||
- cmake $CMAKE_FLAGS ..
|
- cmake $CMAKE_FLAGS ..
|
||||||
- cmake --build . $BUILD_FLAGS
|
- cmake --build . $BUILD_FLAGS
|
||||||
- ctest $CTEST_FLAGS -L acceptance -LE per_implementation
|
- ctest $CTEST_FLAGS -L acceptance -LE per_implementation
|
||||||
|
- SIMDJSON_FORCE_IMPLEMENTATION=icelake ctest $CTEST_FLAGS -L per_implementation
|
||||||
- SIMDJSON_FORCE_IMPLEMENTATION=haswell ctest $CTEST_FLAGS -L per_implementation
|
- SIMDJSON_FORCE_IMPLEMENTATION=haswell ctest $CTEST_FLAGS -L per_implementation
|
||||||
- SIMDJSON_FORCE_IMPLEMENTATION=westmere ctest $CTEST_FLAGS -L per_implementation
|
- SIMDJSON_FORCE_IMPLEMENTATION=westmere ctest $CTEST_FLAGS -L per_implementation
|
||||||
- SIMDJSON_FORCE_IMPLEMENTATION=fallback ctest $CTEST_FLAGS -L per_implementation
|
- SIMDJSON_FORCE_IMPLEMENTATION=fallback ctest $CTEST_FLAGS -L per_implementation
|
||||||
@@ -77,7 +36,7 @@ steps:
|
|||||||
CC: clang-6.0
|
CC: clang-6.0
|
||||||
CXX: clang++-6.0
|
CXX: clang++-6.0
|
||||||
BUILD_FLAGS: -- -j
|
BUILD_FLAGS: -- -j
|
||||||
CMAKE_FLAGS: -DBUILD_SHARED_LIBS=OFF -DSIMDJSON_IMPLEMENTATION=haswell;westmere;fallback
|
CMAKE_FLAGS: -DBUILD_SHARED_LIBS=OFF -DSIMDJSON_IMPLEMENTATION=icelake;haswell;westmere;fallback
|
||||||
CTEST_FLAGS: -j4 --output-on-failure -LE explicitonly
|
CTEST_FLAGS: -j4 --output-on-failure -LE explicitonly
|
||||||
commands:
|
commands:
|
||||||
- mkdir build
|
- mkdir build
|
||||||
@@ -85,6 +44,7 @@ steps:
|
|||||||
- cmake $CMAKE_FLAGS ..
|
- cmake $CMAKE_FLAGS ..
|
||||||
- cmake --build . $BUILD_FLAGS
|
- cmake --build . $BUILD_FLAGS
|
||||||
- ctest $CTEST_FLAGS -L acceptance -LE per_implementation
|
- ctest $CTEST_FLAGS -L acceptance -LE per_implementation
|
||||||
|
- SIMDJSON_FORCE_IMPLEMENTATION=icelake ctest $CTEST_FLAGS -L per_implementation
|
||||||
- SIMDJSON_FORCE_IMPLEMENTATION=haswell ctest $CTEST_FLAGS -L per_implementation
|
- SIMDJSON_FORCE_IMPLEMENTATION=haswell ctest $CTEST_FLAGS -L per_implementation
|
||||||
- SIMDJSON_FORCE_IMPLEMENTATION=westmere ctest $CTEST_FLAGS -L per_implementation
|
- SIMDJSON_FORCE_IMPLEMENTATION=westmere ctest $CTEST_FLAGS -L per_implementation
|
||||||
- SIMDJSON_FORCE_IMPLEMENTATION=fallback ctest $CTEST_FLAGS -L per_implementation
|
- SIMDJSON_FORCE_IMPLEMENTATION=fallback ctest $CTEST_FLAGS -L per_implementation
|
||||||
@@ -142,7 +102,7 @@ steps:
|
|||||||
CC: gcc
|
CC: gcc
|
||||||
CXX: g++
|
CXX: g++
|
||||||
BUILD_FLAGS: -- -j
|
BUILD_FLAGS: -- -j
|
||||||
CMAKE_FLAGS: -DBUILD_SHARED_LIBS=OFF -DSIMDJSON_IMPLEMENTATION=haswell;westmere;fallback
|
CMAKE_FLAGS: -DBUILD_SHARED_LIBS=OFF -DSIMDJSON_IMPLEMENTATION=icelake;haswell;westmere;fallback
|
||||||
CTEST_FLAGS: -j4 --output-on-failure -LE explicitonly
|
CTEST_FLAGS: -j4 --output-on-failure -LE explicitonly
|
||||||
commands:
|
commands:
|
||||||
- echo "deb http://deb.debian.org/debian buster-backports main" >> /etc/apt/sources.list
|
- echo "deb http://deb.debian.org/debian buster-backports main" >> /etc/apt/sources.list
|
||||||
@@ -153,6 +113,7 @@ steps:
|
|||||||
- cmake $CMAKE_FLAGS ..
|
- cmake $CMAKE_FLAGS ..
|
||||||
- cmake --build . $BUILD_FLAGS
|
- cmake --build . $BUILD_FLAGS
|
||||||
- ASAN_OPTIONS="detect_leaks=0" ctest $CTEST_FLAGS -L acceptance -LE per_implementation
|
- ASAN_OPTIONS="detect_leaks=0" ctest $CTEST_FLAGS -L acceptance -LE per_implementation
|
||||||
|
- SIMDJSON_FORCE_IMPLEMENTATION=icelake ASAN_OPTIONS="detect_leaks=0" ctest $CTEST_FLAGS -L per_implementation
|
||||||
- SIMDJSON_FORCE_IMPLEMENTATION=haswell ASAN_OPTIONS="detect_leaks=0" ctest $CTEST_FLAGS -L per_implementation
|
- SIMDJSON_FORCE_IMPLEMENTATION=haswell ASAN_OPTIONS="detect_leaks=0" ctest $CTEST_FLAGS -L per_implementation
|
||||||
- SIMDJSON_FORCE_IMPLEMENTATION=westmere ASAN_OPTIONS="detect_leaks=0" ctest $CTEST_FLAGS -L per_implementation
|
- SIMDJSON_FORCE_IMPLEMENTATION=westmere ASAN_OPTIONS="detect_leaks=0" ctest $CTEST_FLAGS -L per_implementation
|
||||||
- SIMDJSON_FORCE_IMPLEMENTATION=fallback ASAN_OPTIONS="detect_leaks=0" ctest $CTEST_FLAGS -L per_implementation
|
- SIMDJSON_FORCE_IMPLEMENTATION=fallback ASAN_OPTIONS="detect_leaks=0" ctest $CTEST_FLAGS -L per_implementation
|
||||||
@@ -168,7 +129,7 @@ steps:
|
|||||||
environment:
|
environment:
|
||||||
CC: clang-9
|
CC: clang-9
|
||||||
CXX: clang++-9
|
CXX: clang++-9
|
||||||
CMAKE_FLAGS: -DSIMDJSON_SANITIZE=ON -DSIMDJSON_IMPLEMENTATION=haswell;westmere;fallback
|
CMAKE_FLAGS: -DSIMDJSON_SANITIZE=ON -DSIMDJSON_IMPLEMENTATION=icelake;haswell;westmere;fallback
|
||||||
BUILD_FLAGS: -- -j
|
BUILD_FLAGS: -- -j
|
||||||
CTEST_FLAGS: -j4 --output-on-failure -LE explicitonly
|
CTEST_FLAGS: -j4 --output-on-failure -LE explicitonly
|
||||||
commands:
|
commands:
|
||||||
@@ -177,6 +138,7 @@ steps:
|
|||||||
- cmake $CMAKE_FLAGS ..
|
- cmake $CMAKE_FLAGS ..
|
||||||
- cmake --build . $BUILD_FLAGS
|
- cmake --build . $BUILD_FLAGS
|
||||||
- ASAN_OPTIONS="detect_leaks=0" ctest $CTEST_FLAGS -L acceptance -LE per_implementation
|
- ASAN_OPTIONS="detect_leaks=0" ctest $CTEST_FLAGS -L acceptance -LE per_implementation
|
||||||
|
- SIMDJSON_FORCE_IMPLEMENTATION=icelake ASAN_OPTIONS="detect_leaks=0" ctest $CTEST_FLAGS -L per_implementation
|
||||||
- SIMDJSON_FORCE_IMPLEMENTATION=haswell ASAN_OPTIONS="detect_leaks=0" ctest $CTEST_FLAGS -L per_implementation
|
- SIMDJSON_FORCE_IMPLEMENTATION=haswell ASAN_OPTIONS="detect_leaks=0" ctest $CTEST_FLAGS -L per_implementation
|
||||||
- SIMDJSON_FORCE_IMPLEMENTATION=westmere ASAN_OPTIONS="detect_leaks=0" ctest $CTEST_FLAGS -L per_implementation
|
- SIMDJSON_FORCE_IMPLEMENTATION=westmere ASAN_OPTIONS="detect_leaks=0" ctest $CTEST_FLAGS -L per_implementation
|
||||||
- SIMDJSON_FORCE_IMPLEMENTATION=fallback ASAN_OPTIONS="detect_leaks=0" ctest $CTEST_FLAGS -L per_implementation
|
- SIMDJSON_FORCE_IMPLEMENTATION=fallback ASAN_OPTIONS="detect_leaks=0" ctest $CTEST_FLAGS -L per_implementation
|
||||||
|
|||||||
@@ -9,8 +9,8 @@ jobs:
|
|||||||
! contains(toJSON(github.event.commits.*.message), '[skip github]')
|
! contains(toJSON(github.event.commits.*.message), '[skip github]')
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
- uses: actions/cache@v2
|
- uses: actions/cache@v3
|
||||||
with:
|
with:
|
||||||
path: dependencies/.cache
|
path: dependencies/.cache
|
||||||
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
||||||
|
|||||||
@@ -0,0 +1,24 @@
|
|||||||
|
name: CIFuzz
|
||||||
|
on: [pull_request]
|
||||||
|
jobs:
|
||||||
|
Fuzzing:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Build Fuzzers
|
||||||
|
id: build
|
||||||
|
uses: google/oss-fuzz/infra/cifuzz/actions/build_fuzzers@master
|
||||||
|
with:
|
||||||
|
oss-fuzz-project-name: 'simdjson'
|
||||||
|
dry-run: false
|
||||||
|
- name: Run Fuzzers
|
||||||
|
uses: google/oss-fuzz/infra/cifuzz/actions/run_fuzzers@master
|
||||||
|
with:
|
||||||
|
oss-fuzz-project-name: 'simdjson'
|
||||||
|
fuzz-seconds: 600
|
||||||
|
dry-run: false
|
||||||
|
- name: Upload Crash
|
||||||
|
uses: actions/upload-artifact@v1
|
||||||
|
if: failure() && steps.build.outcome == 'success'
|
||||||
|
with:
|
||||||
|
name: artifacts
|
||||||
|
path: ./out/artifacts
|
||||||
@@ -6,7 +6,7 @@ jobs:
|
|||||||
whitespace:
|
whitespace:
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-20.04
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
- name: Remove whitespace and check the diff
|
- name: Remove whitespace and check the diff
|
||||||
run: |
|
run: |
|
||||||
set -eu
|
set -eu
|
||||||
|
|||||||
@@ -37,14 +37,14 @@ jobs:
|
|||||||
chmod +x llvm.sh
|
chmod +x llvm.sh
|
||||||
sudo ./llvm.sh $CLANGVERSION
|
sudo ./llvm.sh $CLANGVERSION
|
||||||
|
|
||||||
- uses: actions/checkout@v1
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
- uses: actions/cache@v2
|
- uses: actions/cache@v3
|
||||||
with:
|
with:
|
||||||
path: dependencies/.cache
|
path: dependencies/.cache
|
||||||
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
||||||
|
|
||||||
- uses: actions/cache@v2
|
- uses: actions/cache@v3
|
||||||
id: cache-corpus
|
id: cache-corpus
|
||||||
with:
|
with:
|
||||||
path: out/
|
path: out/
|
||||||
|
|||||||
@@ -9,14 +9,14 @@ jobs:
|
|||||||
! contains(toJSON(github.event.commits.*.message), '[skip github]')
|
! contains(toJSON(github.event.commits.*.message), '[skip github]')
|
||||||
runs-on: macos-latest
|
runs-on: macos-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
- uses: actions/cache@v2
|
- uses: actions/cache@v3
|
||||||
with:
|
with:
|
||||||
path: dependencies/.cache
|
path: dependencies/.cache
|
||||||
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
||||||
- name: Use cmake
|
- name: Use cmake
|
||||||
run: |
|
run: |
|
||||||
xcversion select 11.2.1
|
xcversion select 11.7
|
||||||
mkdir builddebug &&
|
mkdir builddebug &&
|
||||||
cd builddebug &&
|
cd builddebug &&
|
||||||
cmake -DCMAKE_BUILD_TYPE=Debug -DSIMDJSON_GOOGLE_BENCHMARKS=OFF -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF .. &&
|
cmake -DCMAKE_BUILD_TYPE=Debug -DSIMDJSON_GOOGLE_BENCHMARKS=OFF -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF .. &&
|
||||||
|
|||||||
@@ -9,8 +9,8 @@ jobs:
|
|||||||
! contains(toJSON(github.event.commits.*.message), '[skip github]')
|
! contains(toJSON(github.event.commits.*.message), '[skip github]')
|
||||||
runs-on: macos-latest
|
runs-on: macos-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
- uses: actions/cache@v2
|
- uses: actions/cache@v3
|
||||||
with:
|
with:
|
||||||
path: dependencies/.cache
|
path: dependencies/.cache
|
||||||
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
||||||
|
|||||||
@@ -1,63 +0,0 @@
|
|||||||
name: MinGW32-CI
|
|
||||||
|
|
||||||
on: [push, pull_request]
|
|
||||||
|
|
||||||
|
|
||||||
# Important: scoop will either install 32-bit GCC or 64-bit GCC, not both.
|
|
||||||
|
|
||||||
# It is important to build static libraries because cmake is not smart enough under Windows/mingw to take care of the path. So
|
|
||||||
# with a dynamic library, you could get failures due to the fact that the EXE can't find its DLL.
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
ci:
|
|
||||||
if: >-
|
|
||||||
! contains(toJSON(github.event.commits.*.message), '[skip ci]') &&
|
|
||||||
! contains(toJSON(github.event.commits.*.message), '[skip github]')
|
|
||||||
name: windows-gcc
|
|
||||||
runs-on: windows-2016
|
|
||||||
|
|
||||||
env:
|
|
||||||
CMAKE_GENERATOR: Ninja # This is critical, try ' cmake -GNinja-DBUILD_SHARED_LIBS=OFF .. ' if using the command line
|
|
||||||
CC: gcc
|
|
||||||
CXX: g++
|
|
||||||
|
|
||||||
steps: # To reproduce what is below, start a powershell with administrative rights, using scoop *is* a good idea
|
|
||||||
- uses: actions/checkout@v2
|
|
||||||
|
|
||||||
- uses: actions/cache@v2 # we cache the scoop setup with 32-bit GCC
|
|
||||||
id: cache
|
|
||||||
with:
|
|
||||||
path: |
|
|
||||||
C:\ProgramData\scoop
|
|
||||||
key: scoop32 # static key: should be good forever
|
|
||||||
|
|
||||||
- uses: actions/cache@v2
|
|
||||||
with:
|
|
||||||
path: dependencies/.cache
|
|
||||||
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
|
||||||
|
|
||||||
- name: Setup Windows # This should almost never run if the cache works.
|
|
||||||
if: steps.cache.outputs.cache-hit != 'true'
|
|
||||||
shell: powershell
|
|
||||||
run: |
|
|
||||||
Invoke-Expression (New-Object System.Net.WebClient).DownloadString('https://get.scoop.sh')
|
|
||||||
scoop install sudo --global
|
|
||||||
sudo scoop install git --global
|
|
||||||
sudo scoop install ninja --global
|
|
||||||
sudo scoop install cmake --global
|
|
||||||
sudo scoop install gcc --arch 32bit --global
|
|
||||||
$env:path
|
|
||||||
Write-Host 'Everything has been installed, you are good!'
|
|
||||||
- name: Build and Test 32-bit x86
|
|
||||||
shell: powershell
|
|
||||||
run: |
|
|
||||||
$ENV:PATH="C:\ProgramData\scoop\shims;C:\ProgramData\scoop\apps\gcc\current\bin;C:\ProgramData\scoop\apps\ninja\current;$ENV:PATH"
|
|
||||||
g++ --version
|
|
||||||
cmake --version
|
|
||||||
ninja --version
|
|
||||||
git --version
|
|
||||||
mkdir build32
|
|
||||||
cd build32
|
|
||||||
cmake -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF -DSIMDJSON_COMPETITION=OFF -DSIMDJSON_GOOGLE_BENCHMARKS=OFF -DSIMDJSON_ENABLE_THREADS=OFF ..
|
|
||||||
cmake --build . --target acceptance_tests --verbose
|
|
||||||
ctest -L acceptance --output-on-failure
|
|
||||||
@@ -1,69 +0,0 @@
|
|||||||
name: MinGW64-CI
|
|
||||||
|
|
||||||
on: [push, pull_request]
|
|
||||||
|
|
||||||
|
|
||||||
# Important: scoop will either install 32-bit GCC or 64-bit GCC, not both.
|
|
||||||
|
|
||||||
# It is important to build static libraries because cmake is not smart enough under Windows/mingw to take care of the path. So
|
|
||||||
# with a dynamic library, you could get failures due to the fact that the EXE can't find its DLL.
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
ci:
|
|
||||||
if: >-
|
|
||||||
! contains(toJSON(github.event.commits.*.message), '[skip ci]') &&
|
|
||||||
! contains(toJSON(github.event.commits.*.message), '[skip github]')
|
|
||||||
name: windows-gcc
|
|
||||||
runs-on: windows-2016
|
|
||||||
|
|
||||||
env:
|
|
||||||
CMAKE_GENERATOR: Ninja # This is critical, try ' cmake -GNinja-DBUILD_SHARED_LIBS=OFF .. ' if using the command line
|
|
||||||
CC: gcc
|
|
||||||
CXX: g++
|
|
||||||
|
|
||||||
steps: # To reproduce what is below, start a powershell with administrative rights, using scoop *is* a good idea
|
|
||||||
- uses: actions/checkout@v2
|
|
||||||
|
|
||||||
- uses: actions/cache@v2 # we cache the scoop setup with 64-bit GCC
|
|
||||||
id: cache
|
|
||||||
with:
|
|
||||||
path: |
|
|
||||||
C:\ProgramData\scoop
|
|
||||||
key: scoop64 # static key: should be good forever
|
|
||||||
|
|
||||||
- uses: actions/cache@v2
|
|
||||||
with:
|
|
||||||
path: dependencies/.cache
|
|
||||||
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
|
||||||
|
|
||||||
- name: Setup Windows # This should almost never run if the cache works.
|
|
||||||
if: steps.cache.outputs.cache-hit != 'true'
|
|
||||||
shell: powershell
|
|
||||||
run: |
|
|
||||||
Invoke-Expression (New-Object System.Net.WebClient).DownloadString('https://get.scoop.sh')
|
|
||||||
scoop install sudo --global
|
|
||||||
sudo scoop install git --global
|
|
||||||
sudo scoop install ninja --global
|
|
||||||
sudo scoop install cmake --global
|
|
||||||
sudo scoop install gcc --arch 64bit --global
|
|
||||||
$env:path
|
|
||||||
Write-Host 'Everything has been installed, you are good!'
|
|
||||||
- name: Build and Test 64-bit x64
|
|
||||||
shell: powershell
|
|
||||||
run: |
|
|
||||||
$ENV:PATH="C:\ProgramData\scoop\shims;C:\ProgramData\scoop\apps\gcc\current\bin;C:\ProgramData\scoop\apps\ninja\current;$ENV:PATH"
|
|
||||||
g++ --version
|
|
||||||
cmake --version
|
|
||||||
ninja --version
|
|
||||||
git --version
|
|
||||||
mkdir build64
|
|
||||||
cd build64
|
|
||||||
cmake -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF -DSIMDJSON_COMPETITION=OFF -DSIMDJSON_GOOGLE_BENCHMARKS=OFF -DSIMDJSON_ENABLE_THREADS=OFF ..
|
|
||||||
cmake --build . --target acceptance_tests --verbose
|
|
||||||
ctest -L acceptance --output-on-failure
|
|
||||||
cd ..
|
|
||||||
mkdir build64debug
|
|
||||||
cd build64debug
|
|
||||||
cmake -DSIMDJSON_DEVELOPER_MODE=ON -DCMAKE_BUILD_TYPE=Debug -DBUILD_SHARED_LIBS=OFF -DSIMDJSON_COMPETITION=OFF -DSIMDJSON_GOOGLE_BENCHMARKS=OFF -DSIMDJSON_ENABLE_THREADS=OFF ..
|
|
||||||
cmake --build . --target acceptance_tests --verbose
|
|
||||||
ctest -L acceptance --output-on-failure
|
|
||||||
@@ -17,21 +17,15 @@ jobs:
|
|||||||
- msystem: "MINGW64"
|
- msystem: "MINGW64"
|
||||||
install: mingw-w64-x86_64-libxml2 mingw-w64-x86_64-cmake mingw-w64-x86_64-ninja mingw-w64-x86_64-clang
|
install: mingw-w64-x86_64-libxml2 mingw-w64-x86_64-cmake mingw-w64-x86_64-ninja mingw-w64-x86_64-clang
|
||||||
type: Release
|
type: Release
|
||||||
- msystem: "MINGW32"
|
|
||||||
install: mingw-w64-i686-libxml2 mingw-w64-i686-cmake mingw-w64-i686-ninja mingw-w64-i686-clang
|
|
||||||
type: Release
|
|
||||||
- msystem: "MINGW64"
|
- msystem: "MINGW64"
|
||||||
install: mingw-w64-x86_64-libxml2 mingw-w64-x86_64-cmake mingw-w64-x86_64-ninja mingw-w64-x86_64-clang
|
install: mingw-w64-x86_64-libxml2 mingw-w64-x86_64-cmake mingw-w64-x86_64-ninja mingw-w64-x86_64-clang
|
||||||
type: Debug
|
type: Debug
|
||||||
- msystem: "MINGW32"
|
|
||||||
install: mingw-w64-i686-libxml2 mingw-w64-i686-cmake mingw-w64-i686-ninja mingw-w64-i686-clang
|
|
||||||
type: Debug
|
|
||||||
env:
|
env:
|
||||||
CMAKE_GENERATOR: Ninja
|
CMAKE_GENERATOR: Ninja
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
- uses: actions/cache@v2
|
- uses: actions/cache@v3
|
||||||
with:
|
with:
|
||||||
path: dependencies/.cache
|
path: dependencies/.cache
|
||||||
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
||||||
@@ -44,6 +38,6 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
mkdir build
|
mkdir build
|
||||||
cd build
|
cd build
|
||||||
cmake -DSIMDJSON_DEVELOPER_MODE=ON -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_BUILD_TYPE=${{ matrix.type }} -DSIMDJSON_BUILD_STATIC=ON -DSIMDJSON_DO_NOT_USE_THREADS_NO_MATTER_WHAT=ON ..
|
cmake -DSIMDJSON_DEVELOPER_MODE=ON -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_BUILD_TYPE=${{ matrix.type }} -DBUILD_SHARED_LIBS=OFF -DSIMDJSON_DO_NOT_USE_THREADS_NO_MATTER_WHAT=ON ..
|
||||||
cmake --build . --verbose
|
cmake --build . --verbose
|
||||||
ctest -j4 --output-on-failure -LE explicitonly
|
ctest -j4 --output-on-failure -LE explicitonly
|
||||||
|
|||||||
@@ -19,21 +19,15 @@ jobs:
|
|||||||
- msystem: "MINGW64"
|
- msystem: "MINGW64"
|
||||||
install: mingw-w64-x86_64-cmake mingw-w64-x86_64-ninja mingw-w64-x86_64-gcc
|
install: mingw-w64-x86_64-cmake mingw-w64-x86_64-ninja mingw-w64-x86_64-gcc
|
||||||
type: Release
|
type: Release
|
||||||
- msystem: "MINGW32"
|
|
||||||
install: mingw-w64-i686-cmake mingw-w64-i686-ninja mingw-w64-i686-gcc
|
|
||||||
type: Release
|
|
||||||
- msystem: "MINGW64"
|
- msystem: "MINGW64"
|
||||||
install: mingw-w64-x86_64-cmake mingw-w64-x86_64-ninja mingw-w64-x86_64-gcc
|
install: mingw-w64-x86_64-cmake mingw-w64-x86_64-ninja mingw-w64-x86_64-gcc
|
||||||
type: Debug
|
type: Debug
|
||||||
- msystem: "MINGW32"
|
|
||||||
install: mingw-w64-i686-cmake mingw-w64-i686-ninja mingw-w64-i686-gcc
|
|
||||||
type: Debug
|
|
||||||
env:
|
env:
|
||||||
CMAKE_GENERATOR: Ninja
|
CMAKE_GENERATOR: Ninja
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
- uses: actions/cache@v2
|
- uses: actions/cache@v3
|
||||||
with:
|
with:
|
||||||
path: dependencies/.cache
|
path: dependencies/.cache
|
||||||
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
||||||
|
|||||||
@@ -15,8 +15,8 @@ jobs:
|
|||||||
! contains(toJSON(github.event.commits.*.message), '[skip github]')
|
! contains(toJSON(github.event.commits.*.message), '[skip github]')
|
||||||
runs-on: ubuntu-18.04
|
runs-on: ubuntu-18.04
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
- uses: actions/cache@v2
|
- uses: actions/cache@v3
|
||||||
with:
|
with:
|
||||||
path: dependencies/.cache
|
path: dependencies/.cache
|
||||||
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
||||||
|
|||||||
@@ -13,8 +13,8 @@ jobs:
|
|||||||
CC: clang-7
|
CC: clang-7
|
||||||
CXX: clang++-7
|
CXX: clang++-7
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
- uses: actions/cache@v2
|
- uses: actions/cache@v3
|
||||||
with:
|
with:
|
||||||
path: dependencies/.cache
|
path: dependencies/.cache
|
||||||
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
||||||
|
|||||||
@@ -10,8 +10,8 @@ jobs:
|
|||||||
! contains(toJSON(github.event.commits.*.message), '[skip github]')
|
! contains(toJSON(github.event.commits.*.message), '[skip github]')
|
||||||
runs-on: ubuntu-18.04
|
runs-on: ubuntu-18.04
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
- uses: actions/cache@v2
|
- uses: actions/cache@v3
|
||||||
with:
|
with:
|
||||||
path: dependencies/.cache
|
path: dependencies/.cache
|
||||||
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
||||||
|
|||||||
@@ -9,8 +9,8 @@ jobs:
|
|||||||
! contains(toJSON(github.event.commits.*.message), '[skip github]')
|
! contains(toJSON(github.event.commits.*.message), '[skip github]')
|
||||||
runs-on: ubuntu-18.04
|
runs-on: ubuntu-18.04
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
- uses: actions/cache@v2
|
- uses: actions/cache@v3
|
||||||
with:
|
with:
|
||||||
path: dependencies/.cache
|
path: dependencies/.cache
|
||||||
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
||||||
|
|||||||
@@ -15,8 +15,8 @@ jobs:
|
|||||||
! contains(toJSON(github.event.commits.*.message), '[skip github]')
|
! contains(toJSON(github.event.commits.*.message), '[skip github]')
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-20.04
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
- uses: actions/cache@v2
|
- uses: actions/cache@v3
|
||||||
with:
|
with:
|
||||||
path: dependencies/.cache
|
path: dependencies/.cache
|
||||||
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
||||||
|
|||||||
@@ -0,0 +1,38 @@
|
|||||||
|
name: Ubuntu 20.04 CI (GCC 8)
|
||||||
|
|
||||||
|
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-20.04
|
||||||
|
env:
|
||||||
|
CXX: g++-8
|
||||||
|
CC: gcc-8
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- uses: actions/cache@v3
|
||||||
|
with:
|
||||||
|
path: dependencies/.cache
|
||||||
|
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
||||||
|
- name: Install GCC 8
|
||||||
|
run: sudo apt-get install -y g++-8
|
||||||
|
- name: Use cmake
|
||||||
|
run: |
|
||||||
|
mkdir builddebug &&
|
||||||
|
cd builddebug &&
|
||||||
|
cmake -DCMAKE_BUILD_TYPE=Debug -DSIMDJSON_GOOGLE_BENCHMARKS=OFF -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF .. &&
|
||||||
|
cmake --build . &&
|
||||||
|
ctest -j --output-on-failure -LE explicitonly &&
|
||||||
|
cd .. &&
|
||||||
|
mkdir build &&
|
||||||
|
cd build &&
|
||||||
|
cmake -DSIMDJSON_GOOGLE_BENCHMARKS=ON -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF -DCMAKE_INSTALL_PREFIX:PATH=destination .. &&
|
||||||
|
cmake --build . &&
|
||||||
|
ctest -j --output-on-failure -LE explicitonly &&
|
||||||
|
cmake --install . &&
|
||||||
|
echo -e '#include <simdjson.h>\nint main(int argc,char**argv) {simdjson::dom::parser parser;simdjson::dom::element tweets = parser.load(argv[1]); }' > tmp.cpp && c++ -Idestination/include -Ldestination/lib -std=c++17 -Wl,-rpath,destination/lib -o linkandrun tmp.cpp -lsimdjson && ./linkandrun jsonexamples/twitter.json &&
|
||||||
|
cd ../tests/installation_tests/find &&
|
||||||
|
mkdir build && cd build && cmake -DCMAKE_INSTALL_PREFIX:PATH=../../../build/destination .. && cmake --build .
|
||||||
@@ -9,8 +9,8 @@ jobs:
|
|||||||
! contains(toJSON(github.event.commits.*.message), '[skip github]')
|
! contains(toJSON(github.event.commits.*.message), '[skip github]')
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-20.04
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
- uses: actions/cache@v2
|
- uses: actions/cache@v3
|
||||||
with:
|
with:
|
||||||
path: dependencies/.cache
|
path: dependencies/.cache
|
||||||
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
||||||
|
|||||||
@@ -9,8 +9,8 @@ jobs:
|
|||||||
! contains(toJSON(github.event.commits.*.message), '[skip github]')
|
! contains(toJSON(github.event.commits.*.message), '[skip github]')
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-20.04
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
- uses: actions/cache@v2
|
- uses: actions/cache@v3
|
||||||
with:
|
with:
|
||||||
path: dependencies/.cache
|
path: dependencies/.cache
|
||||||
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
||||||
|
|||||||
@@ -9,8 +9,8 @@ jobs:
|
|||||||
! contains(toJSON(github.event.commits.*.message), '[skip github]')
|
! contains(toJSON(github.event.commits.*.message), '[skip github]')
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-20.04
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
- uses: actions/cache@v2
|
- uses: actions/cache@v3
|
||||||
with:
|
with:
|
||||||
path: dependencies/.cache
|
path: dependencies/.cache
|
||||||
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
||||||
|
|||||||
@@ -9,8 +9,8 @@ jobs:
|
|||||||
! contains(toJSON(github.event.commits.*.message), '[skip github]')
|
! contains(toJSON(github.event.commits.*.message), '[skip github]')
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-20.04
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
- uses: actions/cache@v2
|
- uses: actions/cache@v3
|
||||||
with:
|
with:
|
||||||
path: dependencies/.cache
|
path: dependencies/.cache
|
||||||
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
||||||
|
|||||||
@@ -9,8 +9,8 @@ jobs:
|
|||||||
! contains(toJSON(github.event.commits.*.message), '[skip github]')
|
! contains(toJSON(github.event.commits.*.message), '[skip github]')
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-20.04
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
- uses: actions/cache@v2
|
- uses: actions/cache@v3
|
||||||
with:
|
with:
|
||||||
path: dependencies/.cache
|
path: dependencies/.cache
|
||||||
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
||||||
|
|||||||
@@ -0,0 +1,25 @@
|
|||||||
|
name: Ubuntu 22.04 CI (CLANG 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@v3
|
||||||
|
- uses: actions/cache@v3
|
||||||
|
with:
|
||||||
|
path: dependencies/.cache
|
||||||
|
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
||||||
|
- name: Install clang++-13
|
||||||
|
run: sudo apt-get install -y clang++-13
|
||||||
|
- name: Use cmake
|
||||||
|
run: |
|
||||||
|
mkdir build &&
|
||||||
|
cd build &&
|
||||||
|
CXX=clang++-13 cmake -DSIMDJSON_DEVELOPER_MODE=ON .. &&
|
||||||
|
cmake --build . &&
|
||||||
|
ctest -j --output-on-failure -LE explicitonly
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
name: Ubuntu 22.04 CI (GCC 12)
|
||||||
|
|
||||||
|
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@v3
|
||||||
|
- uses: actions/cache@v3
|
||||||
|
with:
|
||||||
|
path: dependencies/.cache
|
||||||
|
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
||||||
|
- name: Install gcc12
|
||||||
|
run: sudo apt-get install -y g++-12
|
||||||
|
- name: Use cmake
|
||||||
|
run: |
|
||||||
|
mkdir build &&
|
||||||
|
cd build &&
|
||||||
|
CXX=g++-12 cmake -DSIMDJSON_DEVELOPER_MODE=ON .. &&
|
||||||
|
cmake --build . &&
|
||||||
|
ctest -j --output-on-failure -LE explicitonly
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
name: Ubuntu 22.04 CI (GCC 11)
|
||||||
|
|
||||||
|
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@v3
|
||||||
|
- uses: actions/cache@v3
|
||||||
|
with:
|
||||||
|
path: dependencies/.cache
|
||||||
|
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
||||||
|
- name: Use cmake
|
||||||
|
run: |
|
||||||
|
mkdir builddebug &&
|
||||||
|
cd builddebug &&
|
||||||
|
cmake -DCMAKE_BUILD_TYPE=Debug -DSIMDJSON_GOOGLE_BENCHMARKS=OFF -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF .. &&
|
||||||
|
cmake --build . &&
|
||||||
|
ctest -j --output-on-failure -LE explicitonly &&
|
||||||
|
cd .. &&
|
||||||
|
mkdir build &&
|
||||||
|
cd build &&
|
||||||
|
cmake -DSIMDJSON_GOOGLE_BENCHMARKS=ON -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF -DCMAKE_INSTALL_PREFIX:PATH=destination .. &&
|
||||||
|
cmake --build . &&
|
||||||
|
ctest -j --output-on-failure -LE explicitonly &&
|
||||||
|
cmake --install . &&
|
||||||
|
echo -e '#include <simdjson.h>\nint main(int argc,char**argv) {simdjson::dom::parser parser;simdjson::dom::element tweets = parser.load(argv[1]); }' > tmp.cpp && c++ -Idestination/include -Ldestination/lib -std=c++17 -Wl,-rpath,destination/lib -o linkandrun tmp.cpp -lsimdjson && ./linkandrun jsonexamples/twitter.json &&
|
||||||
|
cd ../tests/installation_tests/find &&
|
||||||
|
mkdir build && cd build && cmake -DCMAKE_INSTALL_PREFIX:PATH=../../../build/destination .. && cmake --build .
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
name: VS16-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-vs16
|
|
||||||
runs-on: windows-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v2
|
|
||||||
- uses: actions/cache@v2
|
|
||||||
with:
|
|
||||||
path: dependencies/.cache
|
|
||||||
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
|
||||||
- name: 'Run CMake with VS16 Clang'
|
|
||||||
uses: lukka/run-cmake@v3
|
|
||||||
with:
|
|
||||||
cmakeListsOrSettingsJson: CMakeListsTxtAdvanced
|
|
||||||
cmakeListsTxtPath: '${{ github.workspace }}/CMakeLists.txt'
|
|
||||||
buildDirectory: "${{ github.workspace }}/../../_temp/windows"
|
|
||||||
cmakeBuildType: Release
|
|
||||||
buildWithCMake: true
|
|
||||||
cmakeAppendedArgs: -T ClangCL -DSIMDJSON_COMPETITION=OFF -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF
|
|
||||||
buildWithCMakeArgs: --config Release
|
|
||||||
|
|
||||||
- name: 'Run CTest'
|
|
||||||
run: ctest -C Release -LE explicitonly --output-on-failure
|
|
||||||
working-directory: "${{ github.workspace }}/../../_temp/windows"
|
|
||||||
@@ -1,45 +0,0 @@
|
|||||||
name: VS16-Ninja-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-vs16
|
|
||||||
runs-on: windows-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v2
|
|
||||||
- uses: actions/cache@v2
|
|
||||||
with:
|
|
||||||
path: dependencies/.cache
|
|
||||||
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
|
||||||
- name: 'Run CMake with VS16'
|
|
||||||
uses: lukka/run-cmake@v2
|
|
||||||
with:
|
|
||||||
cmakeListsOrSettingsJson: CMakeListsTxtAdvanced
|
|
||||||
cmakeListsTxtPath: '${{ github.workspace }}/CMakeLists.txt'
|
|
||||||
buildDirectory: "${{ github.workspace }}/../../_temp/windows"
|
|
||||||
cmakeBuildType: Release
|
|
||||||
buildWithCMake: true
|
|
||||||
cmakeAppendedArgs: -G Ninja -DSIMDJSON_COMPETITION=OFF -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF
|
|
||||||
buildWithCMakeArgs: --config Release
|
|
||||||
- name: 'Run CTest'
|
|
||||||
run: ctest -C Release -LE explicitonly --output-on-failure
|
|
||||||
working-directory: "${{ github.workspace }}/../../_temp/windows"
|
|
||||||
- name: 'Install with CMake'
|
|
||||||
uses: lukka/run-cmake@v3
|
|
||||||
with:
|
|
||||||
cmakeListsTxtPath: '${{ github.workspace }}/CMakeLists.txt'
|
|
||||||
buildWithCMakeArgs: '--target install'
|
|
||||||
- name: 'Test Installation with CMake'
|
|
||||||
uses: lukka/run-cmake@v3
|
|
||||||
with:
|
|
||||||
cmakeListsOrSettingsJson: CMakeListsTxtAdvanced
|
|
||||||
cmakeListsTxtPath: '${{ github.workspace }}/tests/installation_tests/find/CMakeLists.txt'
|
|
||||||
cmakeBuildType: Release
|
|
||||||
buildWithCMake: true
|
|
||||||
buildDirectory: '${{ github.workspace }}/tests/installation_tests/find/buildDirectory'
|
|
||||||
cmakeAppendedArgs: -G Ninja
|
|
||||||
buildWithCMakeArgs: '--config Release --verbose'
|
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
name: VS16-ARM-CI
|
name: VS17-ARM-CI
|
||||||
|
|
||||||
on: [push, pull_request]
|
on: [push, pull_request]
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
ci:
|
ci:
|
||||||
name: windows-vs16
|
name: windows-vs17
|
||||||
runs-on: windows-latest
|
runs-on: windows-latest
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
@@ -14,7 +14,7 @@ jobs:
|
|||||||
- {arch: ARM64}
|
- {arch: ARM64}
|
||||||
steps:
|
steps:
|
||||||
- name: checkout
|
- name: checkout
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v3
|
||||||
- name: Use cmake
|
- name: Use cmake
|
||||||
run: |
|
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_CROSSCOMPILING=1 -DSIMDJSON_DEVELOPER_MODE=ON -D SIMDJSON_GOOGLE_BENCHMARKS=OFF -DSIMDJSON_EXCEPTIONS=OFF -B build &&
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
name: VS16-CI
|
name: VS17-CI
|
||||||
|
|
||||||
on: [push, pull_request]
|
on: [push, pull_request]
|
||||||
|
|
||||||
@@ -7,22 +7,22 @@ jobs:
|
|||||||
if: >-
|
if: >-
|
||||||
! contains(toJSON(github.event.commits.*.message), '[skip ci]') &&
|
! contains(toJSON(github.event.commits.*.message), '[skip ci]') &&
|
||||||
! contains(toJSON(github.event.commits.*.message), '[skip github]')
|
! contains(toJSON(github.event.commits.*.message), '[skip github]')
|
||||||
name: windows-vs16
|
name: windows-vs17
|
||||||
runs-on: windows-latest
|
runs-on: windows-latest
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
include:
|
include:
|
||||||
- {gen: Visual Studio 16 2019, arch: Win32, static: ON}
|
- {gen: Visual Studio 17 2022, arch: Win32, shared: ON}
|
||||||
- {gen: Visual Studio 16 2019, arch: Win32, static: OFF}
|
- {gen: Visual Studio 17 2022, arch: Win32, shared: OFF}
|
||||||
- {gen: Visual Studio 16 2019, arch: x64, static: ON}
|
- {gen: Visual Studio 17 2022, arch: x64, shared: ON}
|
||||||
- {gen: Visual Studio 16 2019, arch: x64, static: OFF}
|
- {gen: Visual Studio 17 2022, arch: x64, shared: OFF}
|
||||||
steps:
|
steps:
|
||||||
- name: checkout
|
- name: checkout
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v3
|
||||||
- name: Configure
|
- name: Configure
|
||||||
run: |
|
run: |
|
||||||
cmake -G "${{matrix.gen}}" -A ${{matrix.arch}} -DSIMDJSON_DEVELOPER_MODE=ON -DSIMDJSON_COMPETITION=OFF -DSIMDJSON_BUILD_STATIC=${{matrix.static}} -B build
|
cmake -G "${{matrix.gen}}" -A ${{matrix.arch}} -DSIMDJSON_DEVELOPER_MODE=ON -DSIMDJSON_COMPETITION=OFF -DBUILD_SHARED_LIBS=${{matrix.shared}} -B build
|
||||||
- name: Build Debug
|
- name: Build Debug
|
||||||
run: cmake --build build --config Debug --verbose
|
run: cmake --build build --config Debug --verbose
|
||||||
- name: Build Release
|
- name: Build Release
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
name: VS15-CI
|
name: VS17-CLANG-CI
|
||||||
|
|
||||||
on: [push, pull_request]
|
on: [push, pull_request]
|
||||||
|
|
||||||
@@ -7,22 +7,19 @@ jobs:
|
|||||||
if: >-
|
if: >-
|
||||||
! contains(toJSON(github.event.commits.*.message), '[skip ci]') &&
|
! contains(toJSON(github.event.commits.*.message), '[skip ci]') &&
|
||||||
! contains(toJSON(github.event.commits.*.message), '[skip github]')
|
! contains(toJSON(github.event.commits.*.message), '[skip github]')
|
||||||
name: windows-vs15
|
name: windows-vs17
|
||||||
runs-on: windows-2016
|
runs-on: windows-latest
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
include:
|
include:
|
||||||
- {gen: Visual Studio 15 2017, arch: Win32, static: ON}
|
- {gen: Visual Studio 17 2022, arch: x64}
|
||||||
- {gen: Visual Studio 15 2017, arch: Win32, static: OFF}
|
|
||||||
- {gen: Visual Studio 15 2017, arch: x64, static: ON}
|
|
||||||
- {gen: Visual Studio 15 2017, arch: x64, static: OFF}
|
|
||||||
steps:
|
steps:
|
||||||
- name: checkout
|
- name: checkout
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v3
|
||||||
- name: Configure
|
- name: Configure
|
||||||
run: |
|
run: |
|
||||||
cmake -G "${{matrix.gen}}" -A ${{matrix.arch}} -DSIMDJSON_COMPETITION=OFF -DSIMDJSON_DEVELOPER_MODE=ON -DSIMDJSON_BUILD_STATIC=${{matrix.static}} -B build
|
cmake -G "${{matrix.gen}}" -A ${{matrix.arch}} -T ClangCL -DSIMDJSON_DEVELOPER_MODE=ON -DSIMDJSON_COMPETITION=OFF -B build
|
||||||
- name: Build Debug
|
- name: Build Debug
|
||||||
run: cmake --build build --config Debug --verbose
|
run: cmake --build build --config Debug --verbose
|
||||||
- name: Build Release
|
- name: Build Release
|
||||||
@@ -1,18 +1,18 @@
|
|||||||
name: VS16-NoExcept-CI
|
name: VS17-NoExcept-CI
|
||||||
|
|
||||||
on: [push, pull_request]
|
on: [push, pull_request]
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
ci:
|
ci:
|
||||||
name: windows-vs16
|
name: windows-vs17
|
||||||
runs-on: windows-latest
|
runs-on: windows-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
- uses: actions/cache@v2
|
- uses: actions/cache@v3
|
||||||
with:
|
with:
|
||||||
path: dependencies/.cache
|
path: dependencies/.cache
|
||||||
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
||||||
- name: 'Run CMake with VS16'
|
- name: 'Run CMake with VS17'
|
||||||
uses: lukka/run-cmake@v3
|
uses: lukka/run-cmake@v3
|
||||||
with:
|
with:
|
||||||
cmakeListsOrSettingsJson: CMakeListsTxtAdvanced
|
cmakeListsOrSettingsJson: CMakeListsTxtAdvanced
|
||||||
+5
-13
@@ -3,7 +3,7 @@ cmake_minimum_required(VERSION 3.14)
|
|||||||
project(
|
project(
|
||||||
simdjson
|
simdjson
|
||||||
# The version number is modified by tools/release.py
|
# The version number is modified by tools/release.py
|
||||||
VERSION 1.0.0
|
VERSION 2.0.4
|
||||||
DESCRIPTION "Parsing gigabytes of JSON per second"
|
DESCRIPTION "Parsing gigabytes of JSON per second"
|
||||||
HOMEPAGE_URL "https://simdjson.org/"
|
HOMEPAGE_URL "https://simdjson.org/"
|
||||||
LANGUAGES CXX C
|
LANGUAGES CXX C
|
||||||
@@ -20,8 +20,8 @@ string(
|
|||||||
# ---- Options, variables ----
|
# ---- Options, variables ----
|
||||||
|
|
||||||
# These version numbers are modified by tools/release.py
|
# These version numbers are modified by tools/release.py
|
||||||
set(SIMDJSON_LIB_VERSION "9.0.0" CACHE STRING "simdjson library version")
|
set(SIMDJSON_LIB_VERSION "11.0.0" CACHE STRING "simdjson library version")
|
||||||
set(SIMDJSON_LIB_SOVERSION "9" CACHE STRING "simdjson library soversion")
|
set(SIMDJSON_LIB_SOVERSION "11" CACHE STRING "simdjson library soversion")
|
||||||
|
|
||||||
option(SIMDJSON_ENABLE_THREADS "Link with thread support" ON)
|
option(SIMDJSON_ENABLE_THREADS "Link with thread support" ON)
|
||||||
|
|
||||||
@@ -49,19 +49,10 @@ endif()
|
|||||||
if(is_top_project)
|
if(is_top_project)
|
||||||
option(SIMDJSON_DEVELOPER_MODE "Enable targets for developing simdjson" OFF)
|
option(SIMDJSON_DEVELOPER_MODE "Enable targets for developing simdjson" OFF)
|
||||||
option(BUILD_SHARED_LIBS "Build simdjson as a shared library" OFF)
|
option(BUILD_SHARED_LIBS "Build simdjson as a shared library" OFF)
|
||||||
|
|
||||||
if("$ENV{CI}")
|
|
||||||
set(SIMDJSON_DEVELOPER_MODE ON CACHE INTERNAL "")
|
|
||||||
endif()
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
include(cmake/handle-deprecations.cmake)
|
include(cmake/handle-deprecations.cmake)
|
||||||
|
include(cmake/developer-options.cmake)
|
||||||
if(SIMDJSON_DEVELOPER_MODE)
|
|
||||||
include(cmake/developer-options.cmake)
|
|
||||||
else()
|
|
||||||
message(STATUS "Building only the library. Advanced users may want to turn SIMDJSON_DEVELOPER_MODE to ON, e.g., via -D SIMDJSON_DEVELOPER_MODE=ON.")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# ---- simdjson library ----
|
# ---- simdjson library ----
|
||||||
|
|
||||||
@@ -180,6 +171,7 @@ endif()
|
|||||||
# ---- Developer mode extras ----
|
# ---- Developer mode extras ----
|
||||||
|
|
||||||
if(NOT SIMDJSON_DEVELOPER_MODE)
|
if(NOT SIMDJSON_DEVELOPER_MODE)
|
||||||
|
message(STATUS "Building only the library. Advanced users may want to turn SIMDJSON_DEVELOPER_MODE to ON, e.g., via -D SIMDJSON_DEVELOPER_MODE=ON.")
|
||||||
return()
|
return()
|
||||||
elseif(NOT is_top_project)
|
elseif(NOT is_top_project)
|
||||||
message(AUTHOR_WARNING "Developer mode is intended for developers of simdjson")
|
message(AUTHOR_WARNING "Developer mode is intended for developers of simdjson")
|
||||||
|
|||||||
+4
-4
@@ -62,13 +62,13 @@ Pull Requests
|
|||||||
|
|
||||||
Pull requests are always invited. However, we ask that you follow these guidelines:
|
Pull requests are always invited. However, we ask that you follow these guidelines:
|
||||||
|
|
||||||
- It is wiser to discuss your ideas first as part of an issue before you start coding. If you omit this step and code first, be prepare to have your code receive scrutiny and be dropped.
|
- It is wise to discuss your ideas first as part of an issue before you start coding. If you omit this step and code first, be prepared to have your code receive scrutiny and be dropped.
|
||||||
- Users should provide a rationale for their changes. Does it improve performance? Does it add a feature? Does it improve maintainability? Does fix a bug? This must be explicitly stated as part of the pull request. Do not propose changes based on taste or intuition. We do not delegate programming to tools: that some tool suggested a code change is not reason enough to change the code.
|
- Users should provide a rationale for their changes. Does it improve performance? Does it add a feature? Does it improve maintainability? Does it fix a bug? This must be explicitly stated as part of the pull request. Do not propose changes based on taste or intuition. We do not delegate programming to tools: that some tool suggested a code change is not reason enough to change the code.
|
||||||
1. When your code improves performance, please document the gains with a benchmark using hard numbers.
|
1. When your code improves performance, please document the gains with a benchmark using hard numbers.
|
||||||
2. If your code fixes a bug, please be either fix a failing test, or propose a new test.
|
2. If your code fixes a bug, please either fix a failing test, or propose a new test.
|
||||||
3. Other types of changes must be clearly motivated. We openly discourage changes with no identifiable benefits.
|
3. Other types of changes must be clearly motivated. We openly discourage changes with no identifiable benefits.
|
||||||
- Changes should be focused and minimal. You should change as few lines of code as possible. Please do not reformat or touch files needlessly.
|
- Changes should be focused and minimal. You should change as few lines of code as possible. Please do not reformat or touch files needlessly.
|
||||||
- New features must be accompanied of new tests, in general.
|
- New features must be accompanied by new tests, in general.
|
||||||
- Your code should pass our continuous-integration tests. It is your responsibility to ensure that your proposal pass the tests. We do not merge pull requests that would break our build.
|
- Your code should pass our continuous-integration tests. It is your responsibility to ensure that your proposal pass the tests. We do not merge pull requests that would break our build.
|
||||||
- An exception to this would be changes to non-code files, such as documentation and assets, or trivial changes to code, such as comments, where it is encouraged to explicitly ask for skipping a CI run using the `[skip ci]` prefix in your Pull Request title **and** in the first line of the most recent commit in a push. Example for such a commit: `[skip ci] Fixed typo in power_of_ten's docs`
|
- An exception to this would be changes to non-code files, such as documentation and assets, or trivial changes to code, such as comments, where it is encouraged to explicitly ask for skipping a CI run using the `[skip ci]` prefix in your Pull Request title **and** in the first line of the most recent commit in a push. Example for such a commit: `[skip ci] Fixed typo in power_of_ten's docs`
|
||||||
This benefits the project in such a way that the CI pipeline is not burdened by running jobs on changes that don't change any behavior in the code, which reduces wait times for other Pull Requests that do change behavior and require testing.
|
This benefits the project in such a way that the CI pipeline is not burdened by running jobs on changes that don't change any behavior in the code, which reduces wait times for other Pull Requests that do change behavior and require testing.
|
||||||
|
|||||||
+5
-1
@@ -37,5 +37,9 @@ Furkan Taşkale
|
|||||||
Brendan Knapp
|
Brendan Knapp
|
||||||
Danila Kutenin
|
Danila Kutenin
|
||||||
Pavel Pavlov
|
Pavel Pavlov
|
||||||
# if you have contributed to the project and your name does not
|
Hao Chen
|
||||||
|
Nicolas Boyer
|
||||||
|
Kim Walisch and Jatin Bhateja (AVX-512 bitset decoder)
|
||||||
|
Fangzheng Zhang and Weiqiang Wan (AVX-512 kernel)
|
||||||
|
# if you have contributed to the project and your name does not
|
||||||
# appear in this list, please let us know!
|
# appear in this list, please let us know!
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ PROJECT_NAME = simdjson
|
|||||||
# could be handy for archiving the generated documentation or if some version
|
# could be handy for archiving the generated documentation or if some version
|
||||||
# control system is used.
|
# control system is used.
|
||||||
|
|
||||||
PROJECT_NUMBER = "1.0.0"
|
PROJECT_NUMBER = "2.0.4"
|
||||||
|
|
||||||
# Using the PROJECT_BRIEF tag one can provide an optional one line description
|
# 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
|
# for a project that appears at the top of each page and should give viewer a
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
[/badge.svg)](https://simdjson.org/plots.html)
|
[/badge.svg)](https://simdjson.org/plots.html)
|
||||||

|

|
||||||

|

|
||||||
[![][license img]][license] [](https://simdjson.org/api/1.0.0/index.html)
|
[![][license img]][license] [](https://simdjson.org/api/2.0.0/index.html)
|
||||||
|
|
||||||
simdjson : Parsing gigabytes of JSON per second
|
simdjson : Parsing gigabytes of JSON per second
|
||||||
===============================================
|
===============================================
|
||||||
@@ -138,6 +138,7 @@ We distinguish between "bindings" (which just wrap the C++ code) and a port to a
|
|||||||
- [rcppsimdjson](https://github.com/eddelbuettel/rcppsimdjson): R bindings.
|
- [rcppsimdjson](https://github.com/eddelbuettel/rcppsimdjson): R bindings.
|
||||||
- [simdjson_erlang](https://github.com/ChomperT/simdjson_erlang): erlang bindings.
|
- [simdjson_erlang](https://github.com/ChomperT/simdjson_erlang): erlang bindings.
|
||||||
- [lua-simdjson](https://github.com/FourierTransformer/lua-simdjson): lua bindings.
|
- [lua-simdjson](https://github.com/FourierTransformer/lua-simdjson): lua bindings.
|
||||||
|
- [hermes-json](https://hackage.haskell.org/package/hermes-json): haskell bindings.
|
||||||
|
|
||||||
|
|
||||||
About simdjson
|
About simdjson
|
||||||
|
|||||||
@@ -4,8 +4,12 @@
|
|||||||
#include <map>
|
#include <map>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
|
||||||
namespace amazon_cellphones {
|
namespace amazon_cellphones {
|
||||||
|
|
||||||
|
const bool UNTHREADED = false;
|
||||||
|
const bool THREADED = true;
|
||||||
|
|
||||||
using namespace json_benchmark;
|
using namespace json_benchmark;
|
||||||
|
|
||||||
struct brand {
|
struct brand {
|
||||||
@@ -59,10 +63,11 @@ struct runner : public file_runner<I> {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template<bool threaded>
|
||||||
struct simdjson_dom;
|
struct simdjson_dom;
|
||||||
|
|
||||||
template<typename I> simdjson_really_inline static void amazon_cellphones(benchmark::State &state) {
|
template<typename I> simdjson_really_inline static void amazon_cellphones(benchmark::State &state) {
|
||||||
run_json_benchmark<runner<I>, runner<simdjson_dom>>(state);
|
run_json_benchmark<runner<I>, runner<simdjson_dom<UNTHREADED>>>(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace amazon_cellphones
|
} // namespace amazon_cellphones
|
||||||
@@ -8,12 +8,16 @@ namespace amazon_cellphones {
|
|||||||
|
|
||||||
using namespace simdjson;
|
using namespace simdjson;
|
||||||
|
|
||||||
|
template<bool threaded>
|
||||||
struct simdjson_dom {
|
struct simdjson_dom {
|
||||||
using StringType = std::string;
|
using StringType = std::string;
|
||||||
|
|
||||||
dom::parser parser{};
|
dom::parser parser{};
|
||||||
|
|
||||||
bool run(simdjson::padded_string &json, std::map<StringType, brand> &result) {
|
bool run(simdjson::padded_string &json, std::map<StringType, brand> &result) {
|
||||||
|
#ifdef SIMDJSON_THREADS_ENABLED
|
||||||
|
parser.threaded = threaded;
|
||||||
|
#endif
|
||||||
auto stream = parser.parse_many(json);
|
auto stream = parser.parse_many(json);
|
||||||
auto i = stream.begin();
|
auto i = stream.begin();
|
||||||
++i; // Skip first line
|
++i; // Skip first line
|
||||||
@@ -37,7 +41,10 @@ struct simdjson_dom {
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
BENCHMARK_TEMPLATE(amazon_cellphones, simdjson_dom)->UseManualTime();
|
BENCHMARK_TEMPLATE(amazon_cellphones, simdjson_dom<UNTHREADED>)->UseManualTime();
|
||||||
|
#ifdef SIMDJSON_THREADS_ENABLED
|
||||||
|
BENCHMARK_TEMPLATE(amazon_cellphones, simdjson_dom<THREADED>)->UseManualTime();
|
||||||
|
#endif
|
||||||
|
|
||||||
} // namespace amazon_cellphones
|
} // namespace amazon_cellphones
|
||||||
|
|
||||||
|
|||||||
@@ -8,12 +8,16 @@ namespace amazon_cellphones {
|
|||||||
|
|
||||||
using namespace simdjson;
|
using namespace simdjson;
|
||||||
|
|
||||||
|
template<bool threaded>
|
||||||
struct simdjson_ondemand {
|
struct simdjson_ondemand {
|
||||||
using StringType = std::string;
|
using StringType = std::string;
|
||||||
|
|
||||||
ondemand::parser parser{};
|
ondemand::parser parser{};
|
||||||
|
|
||||||
bool run(simdjson::padded_string &json, std::map<StringType, brand> &result) {
|
bool run(simdjson::padded_string &json, std::map<StringType, brand> &result) {
|
||||||
|
#ifdef SIMDJSON_THREADS_ENABLED
|
||||||
|
parser.threaded = threaded;
|
||||||
|
#endif
|
||||||
ondemand::document_stream stream = parser.iterate_many(json);
|
ondemand::document_stream stream = parser.iterate_many(json);
|
||||||
ondemand::document_stream::iterator i = stream.begin();
|
ondemand::document_stream::iterator i = stream.begin();
|
||||||
++i; // Skip first line
|
++i; // Skip first line
|
||||||
@@ -58,7 +62,10 @@ struct simdjson_ondemand {
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
BENCHMARK_TEMPLATE(amazon_cellphones, simdjson_ondemand)->UseManualTime();
|
BENCHMARK_TEMPLATE(amazon_cellphones, simdjson_ondemand<UNTHREADED>)->UseManualTime();
|
||||||
|
#ifdef SIMDJSON_THREADS_ENABLED
|
||||||
|
BENCHMARK_TEMPLATE(amazon_cellphones, simdjson_ondemand<THREADED>)->UseManualTime();
|
||||||
|
#endif
|
||||||
|
|
||||||
} // namespace amazon_cellphones
|
} // namespace amazon_cellphones
|
||||||
|
|
||||||
|
|||||||
@@ -97,9 +97,9 @@ struct option_struct {
|
|||||||
verbose = true;
|
verbose = true;
|
||||||
break;
|
break;
|
||||||
case 'a': {
|
case 'a': {
|
||||||
auto impl = simdjson::available_implementations[optarg];
|
auto impl = simdjson::get_available_implementations()[optarg];
|
||||||
if(impl && impl->supported_by_runtime_system()) {
|
if(impl && impl->supported_by_runtime_system()) {
|
||||||
simdjson::active_implementation = impl;
|
simdjson::get_active_implementation() = impl;
|
||||||
} else {
|
} else {
|
||||||
std::cerr << "implementation " << optarg << " not found or not supported " << std::endl;
|
std::cerr << "implementation " << optarg << " not found or not supported " << std::endl;
|
||||||
}
|
}
|
||||||
@@ -204,10 +204,13 @@ struct feature_benchmarker {
|
|||||||
}
|
}
|
||||||
// Rate of 1-7-structural misses per 8-structural flip
|
// Rate of 1-7-structural misses per 8-structural flip
|
||||||
double struct1_7_miss_rate(BenchmarkStage stage) const {
|
double struct1_7_miss_rate(BenchmarkStage stage) const {
|
||||||
|
#if SIMDJSON_SIMPLE_PERFORMANCE_COUNTERS
|
||||||
|
return 1;
|
||||||
|
#else
|
||||||
if (!has_events()) { return 1; }
|
if (!has_events()) { return 1; }
|
||||||
return struct7_miss[stage].best.branch_misses() - struct7[stage].best.branch_misses() / double(struct7_miss.stats->blocks_with_1_structural_flipped);
|
return struct7_miss[stage].best.branch_misses() - struct7[stage].best.branch_misses() / double(struct7_miss.stats->blocks_with_1_structural_flipped);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extra cost of an 8-15 structural block over a 1-7 structural block
|
// Extra cost of an 8-15 structural block over a 1-7 structural block
|
||||||
double struct8_15_cost(BenchmarkStage stage) const {
|
double struct8_15_cost(BenchmarkStage stage) const {
|
||||||
return cost_per_block(stage, struct15, struct15.stats->blocks_with_8_structurals, struct7);
|
return cost_per_block(stage, struct15, struct15.stats->blocks_with_8_structurals, struct7);
|
||||||
@@ -218,8 +221,12 @@ struct feature_benchmarker {
|
|||||||
}
|
}
|
||||||
// Rate of 8-15-structural misses per 8-structural flip
|
// Rate of 8-15-structural misses per 8-structural flip
|
||||||
double struct8_15_miss_rate(BenchmarkStage stage) const {
|
double struct8_15_miss_rate(BenchmarkStage stage) const {
|
||||||
|
#if SIMDJSON_SIMPLE_PERFORMANCE_COUNTERS
|
||||||
|
return 1;
|
||||||
|
#else
|
||||||
if (!has_events()) { return 1; }
|
if (!has_events()) { return 1; }
|
||||||
return double(struct15_miss[stage].best.branch_misses() - struct15[stage].best.branch_misses()) / double(struct15_miss.stats->blocks_with_8_structurals_flipped);
|
return double(struct15_miss[stage].best.branch_misses() - struct15[stage].best.branch_misses()) / double(struct15_miss.stats->blocks_with_8_structurals_flipped);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extra cost of a 16+-structural block over an 8-15 structural block (actual varies based on # of structurals!)
|
// Extra cost of a 16+-structural block over an 8-15 structural block (actual varies based on # of structurals!)
|
||||||
@@ -232,10 +239,15 @@ struct feature_benchmarker {
|
|||||||
}
|
}
|
||||||
// Rate of 16-structural misses per 16-structural flip
|
// Rate of 16-structural misses per 16-structural flip
|
||||||
double struct16_miss_rate(BenchmarkStage stage) const {
|
double struct16_miss_rate(BenchmarkStage stage) const {
|
||||||
|
#if SIMDJSON_SIMPLE_PERFORMANCE_COUNTERS
|
||||||
|
return 1;
|
||||||
|
#else
|
||||||
if (!has_events()) { return 1; }
|
if (!has_events()) { return 1; }
|
||||||
return double(struct23_miss[stage].best.branch_misses() - struct23[stage].best.branch_misses()) / double(struct23_miss.stats->blocks_with_16_structurals_flipped);
|
return double(struct23_miss[stage].best.branch_misses() - struct23[stage].best.branch_misses()) / double(struct23_miss.stats->blocks_with_16_structurals_flipped);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Extra cost of having UTF-8 in a block
|
// Extra cost of having UTF-8 in a block
|
||||||
double utf8_cost(BenchmarkStage stage) const {
|
double utf8_cost(BenchmarkStage stage) const {
|
||||||
return cost_per_block(stage, utf8, utf8.stats->blocks_with_utf8, struct7_full);
|
return cost_per_block(stage, utf8, utf8.stats->blocks_with_utf8, struct7_full);
|
||||||
@@ -246,10 +258,13 @@ struct feature_benchmarker {
|
|||||||
}
|
}
|
||||||
// Rate of UTF-8 misses per UTF-8 flip
|
// Rate of UTF-8 misses per UTF-8 flip
|
||||||
double utf8_miss_rate(BenchmarkStage stage) const {
|
double utf8_miss_rate(BenchmarkStage stage) const {
|
||||||
|
#if SIMDJSON_SIMPLE_PERFORMANCE_COUNTERS
|
||||||
|
return 1;
|
||||||
|
#else
|
||||||
if (!has_events()) { return 1; }
|
if (!has_events()) { return 1; }
|
||||||
return double(utf8_miss[stage].best.branch_misses() - utf8[stage].best.branch_misses()) / double(utf8_miss.stats->blocks_with_utf8_flipped);
|
return double(utf8_miss[stage].best.branch_misses() - utf8[stage].best.branch_misses()) / double(utf8_miss.stats->blocks_with_utf8_flipped);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extra cost of having escapes in a block
|
// Extra cost of having escapes in a block
|
||||||
double escape_cost(BenchmarkStage stage) const {
|
double escape_cost(BenchmarkStage stage) const {
|
||||||
return cost_per_block(stage, escape, escape.stats->blocks_with_escapes, struct7_full);
|
return cost_per_block(stage, escape, escape.stats->blocks_with_escapes, struct7_full);
|
||||||
@@ -260,10 +275,15 @@ struct feature_benchmarker {
|
|||||||
}
|
}
|
||||||
// Rate of escape misses per escape flip
|
// Rate of escape misses per escape flip
|
||||||
double escape_miss_rate(BenchmarkStage stage) const {
|
double escape_miss_rate(BenchmarkStage stage) const {
|
||||||
|
#if SIMDJSON_SIMPLE_PERFORMANCE_COUNTERS
|
||||||
|
return 1;
|
||||||
|
#else
|
||||||
if (!has_events()) { return 1; }
|
if (!has_events()) { return 1; }
|
||||||
return double(escape_miss[stage].best.branch_misses() - escape[stage].best.branch_misses()) / double(escape_miss.stats->blocks_with_escapes_flipped);
|
return double(escape_miss[stage].best.branch_misses() - escape[stage].best.branch_misses()) / double(escape_miss.stats->blocks_with_escapes_flipped);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
double calc_expected_feature_cost(BenchmarkStage stage, const benchmarker& file) const {
|
double calc_expected_feature_cost(BenchmarkStage stage, const benchmarker& file) const {
|
||||||
// Expected base ns/block (empty)
|
// Expected base ns/block (empty)
|
||||||
json_stats& stats = *file.stats;
|
json_stats& stats = *file.stats;
|
||||||
@@ -300,7 +320,6 @@ struct feature_benchmarker {
|
|||||||
double calc_expected(BenchmarkStage stage, const benchmarker& file) const {
|
double calc_expected(BenchmarkStage stage, const benchmarker& file) const {
|
||||||
return calc_expected_feature_cost(stage, file) + calc_expected_miss_cost(stage, file);
|
return calc_expected_feature_cost(stage, file) + calc_expected_miss_cost(stage, file);
|
||||||
}
|
}
|
||||||
|
|
||||||
void print(const option_struct& options) const {
|
void print(const option_struct& options) const {
|
||||||
printf("\n");
|
printf("\n");
|
||||||
printf("Features in ns/block (64 bytes):\n");
|
printf("Features in ns/block (64 bytes):\n");
|
||||||
@@ -359,6 +378,22 @@ struct feature_benchmarker {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#if SIMDJSON_SIMPLE_PERFORMANCE_COUNTERS
|
||||||
|
void print_file_effectiveness(BenchmarkStage stage, const char* filename, const benchmarker& results, const feature_benchmarker& features) {
|
||||||
|
double actual = results[stage].best.elapsed_ns() / double(results.stats->blocks);
|
||||||
|
double calc = features.calc_expected(stage, results);
|
||||||
|
double calc_misses = features.calc_expected_misses(stage, results);
|
||||||
|
double calc_miss_cost = features.calc_expected_miss_cost(stage, results);
|
||||||
|
printf(" | %-8s ", benchmark_stage_name(stage));
|
||||||
|
printf("| %-15s ", filename);
|
||||||
|
printf("| %8.3g ", features.calc_expected_feature_cost(stage, results));
|
||||||
|
printf("| %8.3g ", calc_miss_cost);
|
||||||
|
printf("| %8.3g ", calc);
|
||||||
|
printf("| %8.3g ", actual);
|
||||||
|
printf("| %+8.3g ", actual - calc);
|
||||||
|
printf("| %13llu ", (long long unsigned)(calc_misses));
|
||||||
|
}
|
||||||
|
#else
|
||||||
void print_file_effectiveness(BenchmarkStage stage, const char* filename, const benchmarker& results, const feature_benchmarker& features) {
|
void print_file_effectiveness(BenchmarkStage stage, const char* filename, const benchmarker& results, const feature_benchmarker& features) {
|
||||||
double actual = results[stage].best.elapsed_ns() / double(results.stats->blocks);
|
double actual = results[stage].best.elapsed_ns() / double(results.stats->blocks);
|
||||||
double calc = features.calc_expected(stage, results);
|
double calc = features.calc_expected(stage, results);
|
||||||
@@ -382,6 +417,7 @@ void print_file_effectiveness(BenchmarkStage stage, const char* filename, const
|
|||||||
}
|
}
|
||||||
printf("|\n");
|
printf("|\n");
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
// Read options
|
// Read options
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
#define __BENCHMARKER_H
|
#define __BENCHMARKER_H
|
||||||
|
|
||||||
#include "event_counter.h"
|
#include "event_counter.h"
|
||||||
#include "simdjson.h" // For SIMDJSON_DISABLE_DEPRECATED_WARNINGS
|
#include "simdjson.h"
|
||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <cctype>
|
#include <cctype>
|
||||||
@@ -423,7 +423,7 @@ struct benchmarker {
|
|||||||
stage.instructions() / static_cast<double>(stats->structurals),
|
stage.instructions() / static_cast<double>(stats->structurals),
|
||||||
stage.instructions() / static_cast<double>(stage.cycles())
|
stage.instructions() / static_cast<double>(stage.cycles())
|
||||||
);
|
);
|
||||||
|
#if !SIMDJSON_SIMPLE_PERFORMANCE_COUNTERS
|
||||||
// NOTE: removed cycles/miss because it is a somewhat misleading stat
|
// NOTE: removed cycles/miss because it is a somewhat misleading stat
|
||||||
printf("%s%-13s: %7.0f branch misses (%6.2f%%) - %.0f cache misses (%6.2f%%) - %.2f cache references\n",
|
printf("%s%-13s: %7.0f branch misses (%6.2f%%) - %.0f cache misses (%6.2f%%) - %.2f cache references\n",
|
||||||
prefix,
|
prefix,
|
||||||
@@ -434,6 +434,7 @@ struct benchmarker {
|
|||||||
percent(stage.cache_misses(), all_stages_without_allocation.cache_misses()),
|
percent(stage.cache_misses(), all_stages_without_allocation.cache_misses()),
|
||||||
stage.cache_references()
|
stage.cache_references()
|
||||||
);
|
);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ void print_usage(ostream& out) {
|
|||||||
out << "-H - Make the buffers hot (reduce page allocation and related OS tasks during parsing) [default]" << endl;
|
out << "-H - Make the buffers hot (reduce page allocation and related OS tasks during parsing) [default]" << endl;
|
||||||
out << "-a IMPL - Use the given parser implementation. By default, detects the most advanced" << endl;
|
out << "-a IMPL - Use the given parser implementation. By default, detects the most advanced" << endl;
|
||||||
out << " implementation supported on the host machine." << endl;
|
out << " implementation supported on the host machine." << endl;
|
||||||
for (auto impl : simdjson::available_implementations) {
|
for (auto impl : simdjson::get_available_implementations()) {
|
||||||
if(impl->supported_by_runtime_system()) {
|
if(impl->supported_by_runtime_system()) {
|
||||||
out << "-a " << std::left << std::setw(9) << impl->name() << " - Use the " << impl->description() << " parser implementation." << endl;
|
out << "-a " << std::left << std::setw(9) << impl->name() << " - Use the " << impl->description() << " parser implementation." << endl;
|
||||||
}
|
}
|
||||||
@@ -116,10 +116,10 @@ struct option_struct {
|
|||||||
verbose = true;
|
verbose = true;
|
||||||
break;
|
break;
|
||||||
case 'a': {
|
case 'a': {
|
||||||
const implementation *impl = simdjson::available_implementations[optarg];
|
const implementation *impl = simdjson::get_available_implementations()[optarg];
|
||||||
if ((!impl) || (!impl->supported_by_runtime_system())) {
|
if ((!impl) || (!impl->supported_by_runtime_system())) {
|
||||||
std::string exit_message = string("Unsupported option value -a ") + optarg + ": expected -a with one of ";
|
std::string exit_message = string("Unsupported option value -a ") + optarg + ": expected -a with one of ";
|
||||||
for (auto imple : simdjson::available_implementations) {
|
for (auto imple : simdjson::get_available_implementations()) {
|
||||||
if(imple->supported_by_runtime_system()) {
|
if(imple->supported_by_runtime_system()) {
|
||||||
exit_message += imple->name();
|
exit_message += imple->name();
|
||||||
exit_message += " ";
|
exit_message += " ";
|
||||||
@@ -127,7 +127,7 @@ struct option_struct {
|
|||||||
}
|
}
|
||||||
exit_usage(exit_message);
|
exit_usage(exit_message);
|
||||||
}
|
}
|
||||||
simdjson::active_implementation = impl;
|
simdjson::get_active_implementation() = impl;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'C':
|
case 'C':
|
||||||
@@ -175,7 +175,7 @@ int main(int argc, char *argv[]) {
|
|||||||
option_struct options(argc, argv);
|
option_struct options(argc, argv);
|
||||||
if (options.verbose) {
|
if (options.verbose) {
|
||||||
verbose_stream = &cout;
|
verbose_stream = &cout;
|
||||||
verbose() << "Implementation: " << simdjson::active_implementation->name() << endl;
|
verbose() << "Implementation: " << simdjson::get_active_implementation()->name() << endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start collecting events. We put this early so if it prints an error message, it's the
|
// Start collecting events. We put this early so if it prints an error message, it's the
|
||||||
|
|||||||
@@ -50,9 +50,9 @@ simdjson_really_inline void simdjson_process_atom(stat_t &s,
|
|||||||
} else if(element.is<double>()) {
|
} else if(element.is<double>()) {
|
||||||
s.float_count++;
|
s.float_count++;
|
||||||
} else if (element.is<bool>()) {
|
} else if (element.is<bool>()) {
|
||||||
simdjson::error_code err;
|
|
||||||
bool v;
|
bool v;
|
||||||
err = element.get(v);
|
simdjson::error_code error;
|
||||||
|
if ((error = element.get(v))) { std::cerr << error << std::endl; abort(); }
|
||||||
if (v) {
|
if (v) {
|
||||||
s.true_count++;
|
s.true_count++;
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -1,6 +1,15 @@
|
|||||||
#ifndef __EVENT_COUNTER_H
|
#ifndef __EVENT_COUNTER_H
|
||||||
#define __EVENT_COUNTER_H
|
#define __EVENT_COUNTER_H
|
||||||
|
|
||||||
|
#ifndef SIMDJSON_SIMPLE_PERFORMANCE_COUNTERS
|
||||||
|
#ifdef __aarch64__
|
||||||
|
// on ARM, we use just cycles and instructions
|
||||||
|
#define SIMDJSON_SIMPLE_PERFORMANCE_COUNTERS 1
|
||||||
|
#else
|
||||||
|
// elsewhere, we try to use four counters.
|
||||||
|
#define SIMDJSON_SIMPLE_PERFORMANCE_COUNTERS 0
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <cctype>
|
#include <cctype>
|
||||||
#ifndef _MSC_VER
|
#ifndef _MSC_VER
|
||||||
@@ -46,6 +55,12 @@ struct event_count {
|
|||||||
event_count(const event_count& other): elapsed(other.elapsed), event_counts(other.event_counts) { }
|
event_count(const event_count& other): elapsed(other.elapsed), event_counts(other.event_counts) { }
|
||||||
|
|
||||||
// The types of counters (so we can read the getter more easily)
|
// The types of counters (so we can read the getter more easily)
|
||||||
|
#if SIMDJSON_SIMPLE_PERFORMANCE_COUNTERS
|
||||||
|
enum event_counter_types {
|
||||||
|
CPU_CYCLES,
|
||||||
|
INSTRUCTIONS
|
||||||
|
};
|
||||||
|
#else
|
||||||
enum event_counter_types {
|
enum event_counter_types {
|
||||||
CPU_CYCLES,
|
CPU_CYCLES,
|
||||||
INSTRUCTIONS,
|
INSTRUCTIONS,
|
||||||
@@ -53,15 +68,16 @@ struct event_count {
|
|||||||
CACHE_REFERENCES,
|
CACHE_REFERENCES,
|
||||||
CACHE_MISSES
|
CACHE_MISSES
|
||||||
};
|
};
|
||||||
|
#endif
|
||||||
double elapsed_sec() const { return duration<double>(elapsed).count(); }
|
double elapsed_sec() const { return duration<double>(elapsed).count(); }
|
||||||
double elapsed_ns() const { return duration<double, std::nano>(elapsed).count(); }
|
double elapsed_ns() const { return duration<double, std::nano>(elapsed).count(); }
|
||||||
double cycles() const { return static_cast<double>(event_counts[CPU_CYCLES]); }
|
double cycles() const { return static_cast<double>(event_counts[CPU_CYCLES]); }
|
||||||
double instructions() const { return static_cast<double>(event_counts[INSTRUCTIONS]); }
|
double instructions() const { return static_cast<double>(event_counts[INSTRUCTIONS]); }
|
||||||
|
#if !SIMDJSON_SIMPLE_PERFORMANCE_COUNTERS
|
||||||
double branch_misses() const { return static_cast<double>(event_counts[BRANCH_MISSES]); }
|
double branch_misses() const { return static_cast<double>(event_counts[BRANCH_MISSES]); }
|
||||||
double cache_references() const { return static_cast<double>(event_counts[CACHE_REFERENCES]); }
|
double cache_references() const { return static_cast<double>(event_counts[CACHE_REFERENCES]); }
|
||||||
double cache_misses() const { return static_cast<double>(event_counts[CACHE_MISSES]); }
|
double cache_misses() const { return static_cast<double>(event_counts[CACHE_MISSES]); }
|
||||||
|
#endif
|
||||||
event_count& operator=(const event_count& other) {
|
event_count& operator=(const event_count& other) {
|
||||||
this->elapsed = other.elapsed;
|
this->elapsed = other.elapsed;
|
||||||
this->event_counts = other.event_counts;
|
this->event_counts = other.event_counts;
|
||||||
@@ -105,9 +121,11 @@ struct event_aggregate {
|
|||||||
double elapsed_ns() const { return total.elapsed_ns() / iterations; }
|
double elapsed_ns() const { return total.elapsed_ns() / iterations; }
|
||||||
double cycles() const { return total.cycles() / iterations; }
|
double cycles() const { return total.cycles() / iterations; }
|
||||||
double instructions() const { return total.instructions() / iterations; }
|
double instructions() const { return total.instructions() / iterations; }
|
||||||
|
#if !SIMDJSON_SIMPLE_PERFORMANCE_COUNTERS
|
||||||
double branch_misses() const { return total.branch_misses() / iterations; }
|
double branch_misses() const { return total.branch_misses() / iterations; }
|
||||||
double cache_references() const { return total.cache_references() / iterations; }
|
double cache_references() const { return total.cache_references() / iterations; }
|
||||||
double cache_misses() const { return total.cache_misses() / iterations; }
|
double cache_misses() const { return total.cache_misses() / iterations; }
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
struct event_collector {
|
struct event_collector {
|
||||||
@@ -117,11 +135,16 @@ struct event_collector {
|
|||||||
#if defined(__linux__)
|
#if defined(__linux__)
|
||||||
LinuxEvents<PERF_TYPE_HARDWARE> linux_events;
|
LinuxEvents<PERF_TYPE_HARDWARE> linux_events;
|
||||||
event_collector(bool quiet = false) : linux_events(vector<int>{
|
event_collector(bool quiet = false) : linux_events(vector<int>{
|
||||||
|
#if SIMDJSON_SIMPLE_PERFORMANCE_COUNTERS
|
||||||
|
PERF_COUNT_HW_CPU_CYCLES,
|
||||||
|
PERF_COUNT_HW_INSTRUCTIONS,
|
||||||
|
#else
|
||||||
PERF_COUNT_HW_CPU_CYCLES,
|
PERF_COUNT_HW_CPU_CYCLES,
|
||||||
PERF_COUNT_HW_INSTRUCTIONS,
|
PERF_COUNT_HW_INSTRUCTIONS,
|
||||||
PERF_COUNT_HW_BRANCH_MISSES,
|
PERF_COUNT_HW_BRANCH_MISSES,
|
||||||
PERF_COUNT_HW_CACHE_REFERENCES,
|
PERF_COUNT_HW_CACHE_REFERENCES,
|
||||||
PERF_COUNT_HW_CACHE_MISSES
|
PERF_COUNT_HW_CACHE_MISSES
|
||||||
|
#endif
|
||||||
}, quiet) {}
|
}, quiet) {}
|
||||||
bool has_events() {
|
bool has_events() {
|
||||||
return linux_events.is_working();
|
return linux_events.is_working();
|
||||||
|
|||||||
@@ -10,8 +10,8 @@ void maybe_display_implementation() {
|
|||||||
static bool displayed_implementation = false;
|
static bool displayed_implementation = false;
|
||||||
if(!displayed_implementation) {
|
if(!displayed_implementation) {
|
||||||
displayed_implementation = true;
|
displayed_implementation = true;
|
||||||
std::cout << "simdjson::dom implementation: " << simdjson::active_implementation->name() << std::endl;
|
std::cout << "simdjson::dom implementation: " << simdjson::get_active_implementation()->name() << std::endl;
|
||||||
std::cout << "simdjson::ondemand implementation (stage 1): " << simdjson::active_implementation->name() << std::endl;
|
std::cout << "simdjson::ondemand implementation (stage 1): " << simdjson::get_active_implementation()->name() << std::endl;
|
||||||
std::cout << "simdjson::ondemand implementation (stage 2): " << simdjson::builtin_implementation()->name() << std::endl;
|
std::cout << "simdjson::ondemand implementation (stage 2): " << simdjson::builtin_implementation()->name() << std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -58,10 +58,11 @@ template<typename B, typename R> static void run_json_benchmark(benchmark::State
|
|||||||
if (collector.has_events()) {
|
if (collector.has_events()) {
|
||||||
state.counters["instructions"] = events.instructions();
|
state.counters["instructions"] = events.instructions();
|
||||||
state.counters["cycles"] = events.cycles();
|
state.counters["cycles"] = events.cycles();
|
||||||
|
#if !SIMDJSON_SIMPLE_PERFORMANCE_COUNTERS
|
||||||
state.counters["branch_miss"] = events.branch_misses();
|
state.counters["branch_miss"] = events.branch_misses();
|
||||||
state.counters["cache_miss"] = events.cache_misses();
|
state.counters["cache_miss"] = events.cache_misses();
|
||||||
state.counters["cache_ref"] = events.cache_references();
|
state.counters["cache_ref"] = events.cache_references();
|
||||||
|
#endif
|
||||||
state.counters["instructions_per_byte"] = events.instructions() / double(bench.bytes_per_iteration());
|
state.counters["instructions_per_byte"] = events.instructions() / double(bench.bytes_per_iteration());
|
||||||
state.counters["instructions_per_cycle"] = events.instructions() / events.cycles();
|
state.counters["instructions_per_cycle"] = events.instructions() / events.cycles();
|
||||||
state.counters["cycles_per_byte"] = events.cycles() / double(bench.bytes_per_iteration());
|
state.counters["cycles_per_byte"] = events.cycles() / double(bench.bytes_per_iteration());
|
||||||
@@ -69,9 +70,11 @@ template<typename B, typename R> static void run_json_benchmark(benchmark::State
|
|||||||
|
|
||||||
state.counters["best_instructions"] = events.best.instructions();
|
state.counters["best_instructions"] = events.best.instructions();
|
||||||
state.counters["best_cycles"] = events.best.cycles();
|
state.counters["best_cycles"] = events.best.cycles();
|
||||||
|
#if !SIMDJSON_SIMPLE_PERFORMANCE_COUNTERS
|
||||||
state.counters["best_branch_miss"] = events.best.branch_misses();
|
state.counters["best_branch_miss"] = events.best.branch_misses();
|
||||||
state.counters["best_cache_miss"] = events.best.cache_misses();
|
state.counters["best_cache_miss"] = events.best.cache_misses();
|
||||||
state.counters["best_cache_ref"] = events.best.cache_references();
|
state.counters["best_cache_ref"] = events.best.cache_references();
|
||||||
|
#endif
|
||||||
|
|
||||||
state.counters["best_instructions_per_byte"] = events.best.instructions() / double(bench.bytes_per_iteration());
|
state.counters["best_instructions_per_byte"] = events.best.instructions() / double(bench.bytes_per_iteration());
|
||||||
state.counters["best_instructions_per_cycle"] = events.best.instructions() / events.best.cycles();
|
state.counters["best_instructions_per_cycle"] = events.best.instructions() / events.best.cycles();
|
||||||
@@ -92,9 +95,11 @@ template<typename B, typename R> static void run_json_benchmark(benchmark::State
|
|||||||
if (collector.has_events()) {
|
if (collector.has_events()) {
|
||||||
label << " instructions=" << setw(12) << uint64_t(events.best.instructions()) << setw(0);
|
label << " instructions=" << setw(12) << uint64_t(events.best.instructions()) << setw(0);
|
||||||
label << " cycles=" << setw(12) << uint64_t(events.best.cycles()) << setw(0);
|
label << " cycles=" << setw(12) << uint64_t(events.best.cycles()) << setw(0);
|
||||||
|
#if !SIMDJSON_SIMPLE_PERFORMANCE_COUNTERS
|
||||||
label << " branch_miss=" << setw(8) << uint64_t(events.best.branch_misses()) << setw(0);
|
label << " branch_miss=" << setw(8) << uint64_t(events.best.branch_misses()) << setw(0);
|
||||||
label << " cache_miss=" << setw(8) << uint64_t(events.best.cache_misses()) << setw(0);
|
label << " cache_miss=" << setw(8) << uint64_t(events.best.cache_misses()) << setw(0);
|
||||||
label << " cache_ref=" << setw(10) << uint64_t(events.best.cache_references()) << setw(0);
|
label << " cache_ref=" << setw(10) << uint64_t(events.best.cache_references()) << setw(0);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
label << " items=" << setw(10) << bench.items_per_iteration() << setw(0);
|
label << " items=" << setw(10) << bench.items_per_iteration() << setw(0);
|
||||||
|
|||||||
@@ -6,6 +6,9 @@
|
|||||||
|
|
||||||
namespace large_amazon_cellphones {
|
namespace large_amazon_cellphones {
|
||||||
|
|
||||||
|
const bool UNTHREADED = false;
|
||||||
|
const bool THREADED = true;
|
||||||
|
|
||||||
static const simdjson::padded_string &get_built_json();
|
static const simdjson::padded_string &get_built_json();
|
||||||
|
|
||||||
using namespace json_benchmark;
|
using namespace json_benchmark;
|
||||||
@@ -81,11 +84,11 @@ static const simdjson::padded_string &get_built_json() {
|
|||||||
return json;
|
return json;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<bool threaded>
|
||||||
struct simdjson_dom;
|
struct simdjson_dom;
|
||||||
|
|
||||||
template<typename I> simdjson_really_inline static void large_amazon_cellphones(benchmark::State &state) {
|
template<typename I> simdjson_really_inline static void large_amazon_cellphones(benchmark::State &state) {
|
||||||
run_json_benchmark<runner<I>, runner<simdjson_dom>>(state);
|
run_json_benchmark<runner<I>, runner<simdjson_dom<UNTHREADED>>>(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace large_amazon_cellphones
|
} // namespace large_amazon_cellphones
|
||||||
@@ -9,12 +9,16 @@ namespace large_amazon_cellphones {
|
|||||||
|
|
||||||
using namespace simdjson;
|
using namespace simdjson;
|
||||||
|
|
||||||
|
template<bool threaded>
|
||||||
struct simdjson_dom {
|
struct simdjson_dom {
|
||||||
using StringType = std::string;
|
using StringType = std::string;
|
||||||
|
|
||||||
dom::parser parser{};
|
dom::parser parser{};
|
||||||
|
|
||||||
bool run(simdjson::padded_string &json, std::map<StringType, brand> &result) {
|
bool run(simdjson::padded_string &json, std::map<StringType, brand> &result) {
|
||||||
|
#ifdef SIMDJSON_THREADS_ENABLED
|
||||||
|
parser.threaded = threaded;
|
||||||
|
#endif
|
||||||
auto stream = parser.parse_many(json);
|
auto stream = parser.parse_many(json);
|
||||||
auto i = stream.begin();
|
auto i = stream.begin();
|
||||||
++i; // Skip first line
|
++i; // Skip first line
|
||||||
@@ -38,7 +42,10 @@ struct simdjson_dom {
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
BENCHMARK_TEMPLATE(large_amazon_cellphones, simdjson_dom)->UseManualTime();
|
BENCHMARK_TEMPLATE(large_amazon_cellphones, simdjson_dom<UNTHREADED>)->UseManualTime();
|
||||||
|
#ifdef SIMDJSON_THREADS_ENABLED
|
||||||
|
BENCHMARK_TEMPLATE(large_amazon_cellphones, simdjson_dom<THREADED>)->UseManualTime();
|
||||||
|
#endif
|
||||||
|
|
||||||
} // namespace large_amazon_cellphones
|
} // namespace large_amazon_cellphones
|
||||||
|
|
||||||
|
|||||||
@@ -8,12 +8,16 @@ namespace large_amazon_cellphones {
|
|||||||
|
|
||||||
using namespace simdjson;
|
using namespace simdjson;
|
||||||
|
|
||||||
|
template<bool threaded>
|
||||||
struct simdjson_ondemand {
|
struct simdjson_ondemand {
|
||||||
using StringType = std::string;
|
using StringType = std::string;
|
||||||
|
|
||||||
ondemand::parser parser{};
|
ondemand::parser parser{};
|
||||||
|
|
||||||
bool run(simdjson::padded_string &json, std::map<StringType, brand> &result) {
|
bool run(simdjson::padded_string &json, std::map<StringType, brand> &result) {
|
||||||
|
#ifdef SIMDJSON_THREADS_ENABLED
|
||||||
|
parser.threaded = threaded;
|
||||||
|
#endif
|
||||||
ondemand::document_stream stream = parser.iterate_many(json);
|
ondemand::document_stream stream = parser.iterate_many(json);
|
||||||
ondemand::document_stream::iterator i = stream.begin();
|
ondemand::document_stream::iterator i = stream.begin();
|
||||||
++i; // Skip first line
|
++i; // Skip first line
|
||||||
@@ -58,7 +62,10 @@ struct simdjson_ondemand {
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
BENCHMARK_TEMPLATE(large_amazon_cellphones, simdjson_ondemand)->UseManualTime();
|
BENCHMARK_TEMPLATE(large_amazon_cellphones, simdjson_ondemand<UNTHREADED>)->UseManualTime();
|
||||||
|
#ifdef SIMDJSON_THREADS_ENABLED
|
||||||
|
BENCHMARK_TEMPLATE(large_amazon_cellphones, simdjson_ondemand<THREADED>)->UseManualTime();
|
||||||
|
#endif
|
||||||
|
|
||||||
} // namespace amazon_cellphones
|
} // namespace amazon_cellphones
|
||||||
|
|
||||||
|
|||||||
@@ -175,6 +175,18 @@ if(CMAKE_C_COMPILER_ID MATCHES "Intel")
|
|||||||
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -static-intel")
|
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -static-intel")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
option(
|
||||||
|
SIMDJSON_AVX512_ALLOWED
|
||||||
|
"Enable AVX-512 instructions (only affects processors and compilers with AVX-512 support)."
|
||||||
|
ON
|
||||||
|
)
|
||||||
|
if(SIMDJSON_AVX512_ALLOWED)
|
||||||
|
add_compile_definitions(SIMDJSON_AVX512_ALLOWED=1)
|
||||||
|
else()
|
||||||
|
add_compile_definitions(SIMDJSON_AVX512_ALLOWED=0)
|
||||||
|
message(STATUS "AVX-512 instructions are not allowed.")
|
||||||
|
endif()
|
||||||
|
|
||||||
include(CheckSymbolExists)
|
include(CheckSymbolExists)
|
||||||
check_symbol_exists(fork unistd.h HAVE_POSIX_FORK)
|
check_symbol_exists(fork unistd.h HAVE_POSIX_FORK)
|
||||||
check_symbol_exists(wait sys/wait.h HAVE_POSIX_WAIT)
|
check_symbol_exists(wait sys/wait.h HAVE_POSIX_WAIT)
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
#
|
#
|
||||||
# Implementation selection
|
# Implementation selection
|
||||||
#
|
#
|
||||||
set(SIMDJSON_ALL_IMPLEMENTATIONS fallback westmere haswell arm64 ppc64)
|
set(SIMDJSON_ALL_IMPLEMENTATIONS fallback westmere haswell icelake arm64 ppc64)
|
||||||
|
|
||||||
set(
|
set(
|
||||||
SIMDJSON_IMPLEMENTATION ""
|
SIMDJSON_IMPLEMENTATION ""
|
||||||
@@ -15,7 +15,7 @@ set(
|
|||||||
SIMDJSON_EXCLUDE_IMPLEMENTATION ""
|
SIMDJSON_EXCLUDE_IMPLEMENTATION ""
|
||||||
CACHE STRING "\
|
CACHE STRING "\
|
||||||
Semicolon-separated list of implementations to exclude \
|
Semicolon-separated list of implementations to exclude \
|
||||||
(haswell/westmere/arm64/ppc64/fallback). By default, excludes any \
|
(icelake/haswell/westmere/arm64/ppc64/fallback). By default, excludes any \
|
||||||
implementations that are unsupported at compile time or cannot be selected at \
|
implementations that are unsupported at compile time or cannot be selected at \
|
||||||
runtime."
|
runtime."
|
||||||
)
|
)
|
||||||
|
|||||||
Vendored
+2
-1
@@ -13,8 +13,9 @@ cmake_dependent_option(SIMDJSON_GOOGLE_BENCHMARKS "compile the Google Benchmark
|
|||||||
if(SIMDJSON_GOOGLE_BENCHMARKS)
|
if(SIMDJSON_GOOGLE_BENCHMARKS)
|
||||||
set_off(BENCHMARK_ENABLE_TESTING)
|
set_off(BENCHMARK_ENABLE_TESTING)
|
||||||
set_off(BENCHMARK_ENABLE_INSTALL)
|
set_off(BENCHMARK_ENABLE_INSTALL)
|
||||||
|
set_off(BENCHMARK_ENABLE_WERROR)
|
||||||
|
|
||||||
import_dependency(google_benchmarks google/benchmark 8982e1e)
|
import_dependency(google_benchmarks google/benchmark f91b6b4)
|
||||||
add_dependency(google_benchmarks)
|
add_dependency(google_benchmarks)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|||||||
+86
-54
@@ -16,10 +16,10 @@ An overview of what you need to know to use simdjson, with examples.
|
|||||||
* [UTF-8 validation (alone)](#utf-8-validation-alone)
|
* [UTF-8 validation (alone)](#utf-8-validation-alone)
|
||||||
* [JSON Pointer](#json-pointer)
|
* [JSON Pointer](#json-pointer)
|
||||||
* [Error Handling](#error-handling)
|
* [Error Handling](#error-handling)
|
||||||
* [Error Handling Example without Exceptions](#error-handling-example-without-exceptions)
|
* [Error Handling Example without Exceptions](#error-handling-examples-without-exceptions)
|
||||||
* [Disabling Exceptions](#disabling-exceptions)
|
* [Disabling Exceptions](#disabling-exceptions)
|
||||||
* [Exceptions](#exceptions)
|
* [Exceptions](#exceptions)
|
||||||
* [Current location in document](#current-location-in-documnet)
|
* [Current location in document](#current-location-in-document)
|
||||||
* [Rewinding](#rewinding)
|
* [Rewinding](#rewinding)
|
||||||
* [Direct Access to the Raw String](#direct-access-to-the-raw-string)
|
* [Direct Access to the Raw String](#direct-access-to-the-raw-string)
|
||||||
* [Newline-Delimited JSON (ndjson) and JSON lines](#newline-delimited-json-ndjson-and-json-lines)
|
* [Newline-Delimited JSON (ndjson) and JSON lines](#newline-delimited-json-ndjson-and-json-lines)
|
||||||
@@ -32,9 +32,12 @@ An overview of what you need to know to use simdjson, with examples.
|
|||||||
Requirements
|
Requirements
|
||||||
------------------
|
------------------
|
||||||
|
|
||||||
- A recent compiler (LLVM clang6 or better, GNU GCC 7.4 or better, Xcode 11 or better) on a 64-bit (PPC, ARM or x64 Intel/AMD) POSIX systems such as macOS, freeBSD or Linux. We require that the compiler supports the C++11 standard or better.
|
- A recent compiler (LLVM clang 6 or better, GNU GCC 7.4 or better, Xcode 11 or better) on a 64-bit (PPC, ARM or x64 Intel/AMD) POSIX systems such as macOS, freeBSD or Linux. We require that the compiler supports the C++11 standard or better.
|
||||||
- Visual Studio 2017 or better under 64-bit Windows. Users should target a 64-bit build (x64) instead of a 32-bit build (x86). We support the LLVM clang compiler under Visual Studio (clangcl) as well as as the regular Visual Studio compiler. We also support MinGW 64-bit under Windows.
|
- Visual Studio 2017 or better under 64-bit Windows. Users should target a 64-bit build (x64) instead of a 32-bit build (x86). We support the LLVM clang compiler under Visual Studio (clangcl) as well as as the regular Visual Studio compiler. We also support MinGW 64-bit under Windows.
|
||||||
|
|
||||||
|
|
||||||
|
Support for AVX-512 require a processor with AVX512-VBMI2 support (Ice Lake or better) under a 64-bit system and a recent compiler (LLVM clang 6 or better, GCC 8 or better, Visual Studio 2019 or better).
|
||||||
|
|
||||||
Including simdjson
|
Including simdjson
|
||||||
------------------
|
------------------
|
||||||
|
|
||||||
@@ -54,6 +57,7 @@ c++ myproject.cpp simdjson.cpp
|
|||||||
|
|
||||||
Note:
|
Note:
|
||||||
- Users on macOS and other platforms where default compilers do not provide C++11 compliant by default should request it with the appropriate flag (e.g., `c++ -std=c++17 myproject.cpp simdjson.cpp`).
|
- Users on macOS and other platforms where default compilers do not provide C++11 compliant by default should request it with the appropriate flag (e.g., `c++ -std=c++17 myproject.cpp simdjson.cpp`).
|
||||||
|
- The library relies on [runtime CPU detection](implementation-selection.md): avoid specifying an architecture at compile time (e.g., `-march-native`).
|
||||||
|
|
||||||
Using simdjson with package managers
|
Using simdjson with package managers
|
||||||
------------------
|
------------------
|
||||||
@@ -127,19 +131,23 @@ The Basics: Loading and Parsing JSON Documents
|
|||||||
----------------------------------------------
|
----------------------------------------------
|
||||||
|
|
||||||
The simdjson library allows you to navigate and validate JSON documents ([RFC 8259](https://www.tbray.org/ongoing/When/201x/2017/12/14/rfc8259.html)).
|
The simdjson library allows you to navigate and validate JSON documents ([RFC 8259](https://www.tbray.org/ongoing/When/201x/2017/12/14/rfc8259.html)).
|
||||||
As required by the standard, your JSON document should be Unicode (UTF-8) strings.
|
As required by the standard, your JSON document should be in a Unicode (UTF-8) string. The whole
|
||||||
|
string, from the beginning to the end, needs to be valid: we do not attempt to tolerate bad
|
||||||
|
inputs before or after a document.
|
||||||
|
|
||||||
|
The simdjson library offers a tree-like [API](https://en.wikipedia.org/wiki/API), which you can
|
||||||
The simdjson library offers a tree-like [API](https://en.wikipedia.org/wiki/API), which you can access by creating a `ondemand::parser` and calling the `iterate()` method:
|
access by creating a `ondemand::parser` and calling the `iterate()` method. The iterate method
|
||||||
|
quickly indexes the input string and may detect some errors. The following example illustrates
|
||||||
|
how to get started with an input JSON file (`"twitter.json"`):
|
||||||
|
|
||||||
```c++
|
```c++
|
||||||
ondemand::parser parser;
|
ondemand::parser parser;
|
||||||
auto json = padded_string::load("twitter.json");
|
auto json = padded_string::load("twitter.json"); // load JSON file 'twitter.json'.
|
||||||
ondemand::document doc = parser.iterate(json); // position a pointer at the beginning of the JSON data
|
ondemand::document doc = parser.iterate(json); // position a pointer at the beginning of the JSON data
|
||||||
```
|
```
|
||||||
|
|
||||||
Or by creating a padded string---for efficiency reasons, simdjson requires a string with a few
|
You can also create a padded string---for efficiency reasons, simdjson requires a string
|
||||||
bytes (`simdjson::SIMDJSON_PADDING`) at the end---and calling `iterate()`:
|
with a few bytes (`simdjson::SIMDJSON_PADDING`) at the end---and calling `iterate()`:
|
||||||
|
|
||||||
```c++
|
```c++
|
||||||
ondemand::parser parser;
|
ondemand::parser parser;
|
||||||
@@ -196,7 +204,8 @@ allocations during parsing when using simdjson. [See our performance notes for d
|
|||||||
C++11 Support and string_view
|
C++11 Support and string_view
|
||||||
-------------
|
-------------
|
||||||
|
|
||||||
The simdjson library builds on compilers supporting the [C++11 standard](https://en.wikipedia.org/wiki/C%2B%2B11). It is also a strict requirement: we have no plan to support older C++ compilers.
|
The simdjson library builds on compilers supporting the [C++11 standard](https://en.wikipedia.org/wiki/C%2B%2B11).
|
||||||
|
It is also a strict requirement: we have no plan to support older C++ compilers.
|
||||||
|
|
||||||
We represent parsed Unicode (UTF-8) strings in simdjson using the `std::string_view` class. It avoids
|
We represent parsed Unicode (UTF-8) strings in simdjson using the `std::string_view` class. It avoids
|
||||||
the need to copy the data, as would be necessary with the `std::string` class. It also
|
the need to copy the data, as would be necessary with the `std::string` class. It also
|
||||||
@@ -214,7 +223,6 @@ is often best viewed as a temporary string value that is tied to the document yo
|
|||||||
At the cost of some memory allocation, you may convert your `std::string_view` instances for long-term storage into `std::string` instances:
|
At the cost of some memory allocation, you may convert your `std::string_view` instances for long-term storage into `std::string` instances:
|
||||||
`std::string mycopy(view)` (C++17) or `std::string mycopy(view.begin(), view.end())` (prior to C++17).
|
`std::string mycopy(view)` (C++17) or `std::string mycopy(view.begin(), view.end())` (prior to C++17).
|
||||||
|
|
||||||
|
|
||||||
The `std::string_view` class has become standard as part of C++17 but it is not always available
|
The `std::string_view` class has become standard as part of C++17 but it is not always available
|
||||||
on compilers which only supports C++11. When we detect that `string_view` is natively
|
on compilers which only supports C++11. When we detect that `string_view` is natively
|
||||||
available, we define the macro `SIMDJSON_HAS_STRING_VIEW`.
|
available, we define the macro `SIMDJSON_HAS_STRING_VIEW`.
|
||||||
@@ -232,24 +240,38 @@ transcode the UTF-8 strings produced by the simdjson library to other formats. S
|
|||||||
Using the Parsed JSON
|
Using the Parsed JSON
|
||||||
---------------------
|
---------------------
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
We recommend that you first compile and run your code in Debug mode (with `NDEBUG`
|
||||||
|
undefined). When you do so, the simdjson library runs additional sanity tests on
|
||||||
|
your code to help ensure that you are using the library in a safe manner. Once
|
||||||
|
your code has been tested, you can then run it in Release mode (with `NDEBUG`
|
||||||
|
defined) for best performance. Alternatively, you can set the macro
|
||||||
|
`SIMDJSON_DEVELOPMENT_CHECKS` to 1 prior to including the `simdjson.h` header
|
||||||
|
to enable these additional checks: just make sure you remove the definition once your
|
||||||
|
code has been tested.
|
||||||
|
|
||||||
Once you have a document (`simdjson::ondemand::document`), you can navigate it with
|
Once you have a document (`simdjson::ondemand::document`), you can navigate it with
|
||||||
idiomatic C++ iterators, operators and casts. Besides the documents instances and
|
idiomatic C++ iterators, operators and casts. Besides the document instances and
|
||||||
native types (`double`, `uint64_t`, `int64_t`, `bool`), we also access
|
native types (`double`, `uint64_t`, `int64_t`, `bool`), we also access
|
||||||
Unicode (UTF-8) strings (`std::string_view`), objects (`simdjson::ondemand::object`)
|
Unicode (UTF-8) strings (`std::string_view`), objects (`simdjson::ondemand::object`)
|
||||||
and arrays (`simdjson::ondemand::array`).
|
and arrays (`simdjson::ondemand::array`).
|
||||||
We also have a generic type (`simdjson::ondemand::value`) which represent a potential
|
We also have a generic type (`simdjson::ondemand::value`) which represents a potential
|
||||||
array or object, or scalar type (`double`, `uint64_t`, `int64_t`, `bool`, `null`, string) inside an array or an object. Both generic types (`simdjson::ondemand::document` and `simdjson::ondemand::value`) have a `type()` method returning
|
array or object, or scalar type (`double`, `uint64_t`, `int64_t`, `bool`, `null`, string) inside
|
||||||
a `json_type` value describing the value (`json_type::array`, `json_type::object`, `json_type::number`, `json_type::string`, `json_type::boolean`, `json_type::null`).
|
an array or an object. Both generic types (`simdjson::ondemand::document` and
|
||||||
|
`simdjson::ondemand::value`) have a `type()` method returning a `json_type` value describing the
|
||||||
|
value (`json_type::array`, `json_type::object`, `json_type::number`, `json_type::string`, `json_type::boolean`, `json_type::null`).
|
||||||
|
|
||||||
Advanced users who need to determine the number types (integer or float) dynamically,
|
Advanced users who need to determine the number types (integer or float) dynamically,
|
||||||
should review our section [dynamic number types](#dynamic-number-types). Indeed,
|
should review our section [dynamic number types](#dynamic-number-types). Indeed,
|
||||||
we have an additional `ondemand::number` type which may represent either integers
|
we have an additional `ondemand::number` type which may represent either integers
|
||||||
or floating-point values, depending on how the numbers are formatted.
|
or floating-point values, depending on how the numbers are formatted.
|
||||||
floating-point values followed by an integer.
|
floating-point values followed by an integer.
|
||||||
While you are accessing the document, the `document` instance should remain in scope:
|
|
||||||
it is your "iterator" which keeps track of where you are in the JSON document.
|
|
||||||
By design, there is one and only one `document` instance per JSON document.
|
|
||||||
|
|
||||||
|
We invite you to keep the following rules in mind:
|
||||||
|
1. While you are accessing the document, the `document` instance should remain in scope: it is your "iterator" which keeps track of where you are in the JSON document. By design, there is one and only one `document` instance per JSON document.
|
||||||
|
2. Because On Demand is really just an iterator, you must fully consume the current object or array before accessing a sibling object or array.
|
||||||
|
3. Values can only be consumed once, you should get the values and store them if you plan to need them multiple times. You are expected to access the keys of an object just once. You are expected to go through the values of an array just once.
|
||||||
|
|
||||||
The following specific instructions indicate how to use the JSON when exceptions are enabled, but simdjson has full, idiomatic
|
The following specific instructions indicate how to use the JSON when exceptions are enabled, but simdjson has full, idiomatic
|
||||||
support for users who avoid exceptions. See [the simdjson error handling documentation](basics.md#error-handling) for more.
|
support for users who avoid exceptions. See [the simdjson error handling documentation](basics.md#error-handling) for more.
|
||||||
@@ -259,16 +281,24 @@ support for users who avoid exceptions. See [the simdjson error handling documen
|
|||||||
However, it is not fully validated. On Demand only fully validates the values you use and the
|
However, it is not fully validated. On Demand only fully validates the values you use and the
|
||||||
structure leading to it.
|
structure leading to it.
|
||||||
* **Extracting Values:** You can cast a JSON element to a native type:
|
* **Extracting Values:** You can cast a JSON element to a native type:
|
||||||
`double(element)` or `double x = json_element`. This works for `std::string_view`, double, uint64_t, int64_t, bool,
|
`double(element)`. This works for `std::string_view`, double, uint64_t, int64_t, bool,
|
||||||
ondemand::object and ondemand::array. At this point, the number, string or boolean will be parsed,
|
ondemand::object and ondemand::array. We also have explicit methods such as `get_string()`, `get_double()`,
|
||||||
or the initial `[` or `{` will be verified. An exception is thrown if the cast is not possible.
|
`get_uint64()`, `get_int64()`, `get_bool()`, `get_object()` and `get_array()`. After a cast or an explicit method,
|
||||||
|
the number, string or boolean will be parsed, or the initial `[` or `{` will be verified. An exception is thrown if
|
||||||
|
the cast is not possible.
|
||||||
|
|
||||||
> IMPORTANT NOTE: values can only be parsed once. Since documents are *iterators*, once you have
|
> IMPORTANT NOTE: values can only be parsed once. Since documents are *iterators*, once you have
|
||||||
> parsed a value (such as by casting to double), you cannot get at it again.
|
> parsed a value (such as by casting to double), you cannot get at it again. It is an error to call
|
||||||
|
> `get_string()` twice on an object (or to cast an object twice to `std::string_view`).
|
||||||
* **Field Access:** To get the value of the "foo" field in an object, use `object["foo"]`. This will
|
* **Field Access:** To get the value of the "foo" field in an object, use `object["foo"]`. This will
|
||||||
scan through the object looking for the field with the matching string, doing a character-by-character
|
scan through the object looking for the field with the matching string, doing a character-by-character
|
||||||
comparison. For efficiency reason, you should avoid looking up the same field repeatedly: e.g., do
|
comparison. For efficiency reason, you should avoid looking up the same field repeatedly: e.g., do
|
||||||
not do `object["foo"]` followed by `object["foo"]` with the same `object` instance.
|
not do `object["foo"]` followed by `object["foo"]` with the same `object` instance. If you consume an
|
||||||
|
object twice: `std::string_view(object["foo"]` followed by `std::string_view(object["foo"]`, your code
|
||||||
|
is in error. Furthermore, you can only consume one field at a time, on the same object. Thus
|
||||||
|
if you have retrieved `content["bids"].get_array()` and you later call `content["asks"].get_array()`, then the
|
||||||
|
first array should no longer be accessed: it would be unsafe to do so. You can detect such mistakes by first
|
||||||
|
compiling and running the code in Debug mode: an OUT_OF_ORDER_ITERATION error is generated.
|
||||||
|
|
||||||
> NOTE: JSON allows you to escape characters in keys. E.g., the key `"date"` may be written as
|
> NOTE: JSON allows you to escape characters in keys. E.g., the key `"date"` may be written as
|
||||||
> `"\u0064\u0061\u0074\u0065"`. By default, simdjson does *not* unescape keys when matching by default.
|
> `"\u0064\u0061\u0074\u0065"`. By default, simdjson does *not* unescape keys when matching by default.
|
||||||
@@ -683,30 +713,23 @@ auto cars_json = R"( [
|
|||||||
] )"_padded;
|
] )"_padded;
|
||||||
|
|
||||||
ondemand::parser parser;
|
ondemand::parser parser;
|
||||||
ondemand::document cars;
|
|
||||||
std::vector<double> measured;
|
std::vector<double> measured;
|
||||||
parser.iterate(cars_json).get(cars);
|
ondemand::document cars = parser.iterate(cars_json);
|
||||||
std::vector<car_type> content;
|
std::vector<car_type> content;
|
||||||
for (int i = 0; i < 3; i++) {
|
for (int i = 0; i < 3; i++) {
|
||||||
ondemand::object obj;
|
|
||||||
std::string json_pointer = "/" + std::to_string(i);
|
std::string json_pointer = "/" + std::to_string(i);
|
||||||
// Each successive at_pointer call invalidates
|
// Each successive at_pointer call invalidates
|
||||||
// previously parsed values, strings, objects and array.
|
// previously parsed values, strings, objects and array.
|
||||||
cars.at_pointer(json_pointer).get(obj);
|
ondemand::object obj(cars.at_pointer(json_pointer).get_object());
|
||||||
// We materialize the object.
|
// We materialize the object.
|
||||||
std::string_view make;
|
std::string_view make = obj["make"];
|
||||||
ASSERT_SUCCESS(obj["make"].get(make));
|
std::string_view model = obj["model"];
|
||||||
std::string_view model;
|
uint64_t year(obj["year"]);
|
||||||
ASSERT_SUCCESS(obj["model"].get(model));
|
|
||||||
uint64_t year;
|
|
||||||
ASSERT_SUCCESS(obj["year"].get(year));
|
|
||||||
// We materialize the array.
|
// We materialize the array.
|
||||||
ondemand::array arr;
|
ondemand::array arr(obj["tire_pressure"].get_array());
|
||||||
ASSERT_SUCCESS(obj["tire_pressure"].get(arr));
|
|
||||||
std::vector<double> values;
|
std::vector<double> values;
|
||||||
for(auto x : arr) {
|
for(auto x : arr) {
|
||||||
double value_double;
|
double value_double(x.get_double());
|
||||||
ASSERT_SUCCESS(x.get(value_double));
|
|
||||||
values.push_back(value_double);
|
values.push_back(value_double);
|
||||||
}
|
}
|
||||||
content.emplace_back(make, model, year, std::move(values));
|
content.emplace_back(make, model, year, std::move(values));
|
||||||
@@ -741,12 +764,16 @@ The entire simdjson API is usable with and without exceptions. All simdjson APIs
|
|||||||
pair. You can retrieve the value with .get() without generating an exception, like so:
|
pair. You can retrieve the value with .get() without generating an exception, like so:
|
||||||
|
|
||||||
```c++
|
```c++
|
||||||
ondemand::element doc;
|
ondemand::document doc;
|
||||||
auto error = parser.iterate(json).get(doc);
|
auto error = parser.iterate(json).get(doc);
|
||||||
if (error) { cerr << error << endl; exit(1); }
|
if (error) { cerr << error << endl; exit(1); }
|
||||||
```
|
```
|
||||||
|
|
||||||
When you use the code this way, it is your responsibility to check for error before using the
|
When there is no error, the error code simdjson::SUCCESS is returned: it evaluates as false as a Boolean.
|
||||||
|
We have several error codes to indicate errors, they all evaluate to true as a Boolean: your software should not generally not depend on exact
|
||||||
|
error codes. We may change the error codes in future releases and the exact error codes could vary depending on your system.
|
||||||
|
|
||||||
|
When you use the code without exceptions, it is your responsibility to check for error before using the
|
||||||
result: if there is an error, the result value will not be valid and using it will caused undefined behavior. Most compilers should be able to help you if you activate the right
|
result: if there is an error, the result value will not be valid and using it will caused undefined behavior. Most compilers should be able to help you if you activate the right
|
||||||
set of warnings: they can identify variables that are written to but never otherwise accessed.
|
set of warnings: they can identify variables that are written to but never otherwise accessed.
|
||||||
|
|
||||||
@@ -868,6 +895,9 @@ int main(void) {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
The `at` method can only be called once on an array. It cannot be used
|
||||||
|
to iterate through the values of an array.
|
||||||
|
|
||||||
### Error Handling Examples without Exceptions
|
### Error Handling Examples without Exceptions
|
||||||
|
|
||||||
This is how the example in "Using the Parsed JSON" could be written using only error code checking (without exceptions):
|
This is how the example in "Using the Parsed JSON" could be written using only error code checking (without exceptions):
|
||||||
@@ -1119,7 +1149,7 @@ Direct Access to the Raw String
|
|||||||
|
|
||||||
The simdjson library makes explicit assumptions about types. For examples, numbers
|
The simdjson library makes explicit assumptions about types. For examples, numbers
|
||||||
must be integers (up to 64-bit integers) or binary64 floating-point numbers. Some users
|
must be integers (up to 64-bit integers) or binary64 floating-point numbers. Some users
|
||||||
have different needs. For example, some users might want to support big infloating-point number followed by an integer.tegers.
|
have different needs. For example, some users might want to support big integers.
|
||||||
The library makes this possible by providing a `raw_json_token` method which returns
|
The library makes this possible by providing a `raw_json_token` method which returns
|
||||||
a `std::string_view` instance containing the value as a string which you may then
|
a `std::string_view` instance containing the value as a string which you may then
|
||||||
parse as you see fit.
|
parse as you see fit.
|
||||||
@@ -1153,11 +1183,19 @@ The `raw_json_token()` should be fast and free of allocation.
|
|||||||
Newline-Delimited JSON (ndjson) and JSON lines
|
Newline-Delimited JSON (ndjson) and JSON lines
|
||||||
----------------------------------------------
|
----------------------------------------------
|
||||||
|
|
||||||
The simdjson library also supports multithreaded JSON streaming through a large file containing many
|
When processing large inputs (e.g., in the context of data engineering), engineers commonly
|
||||||
smaller JSON documents in either [ndjson](http://ndjson.org) or [JSON lines](http://jsonlines.org)
|
serialize data into streams of multiple JSON documents. That is, instead of one large
|
||||||
format. If your JSON documents all contain arrays or objects, we even support direct file
|
(e.g., 2 GB) JSON document containing multiple records, it is often preferable to
|
||||||
concatenation without whitespace. The concatenated file has no size restrictions (including larger
|
write out multiple records as independent JSON documents, to be read one-by-one.
|
||||||
than 4GB), though each individual document must be no larger than 4 GB.
|
|
||||||
|
The simdjson library also supports multithreaded JSON streaming through a large file
|
||||||
|
containing many smaller JSON documents in either [ndjson](http://ndjson.org)
|
||||||
|
or [JSON lines](http://jsonlines.org) format. If your JSON documents all contain arrays
|
||||||
|
or objects, we even support direct file concatenation without whitespace. However, if there
|
||||||
|
is content between your JSON documents, it should be exclusively ASCII white-space characters.
|
||||||
|
|
||||||
|
The concatenated file has no size restrictions (including larger than 4GB), though each
|
||||||
|
individual document must be no larger than 4 GB.
|
||||||
|
|
||||||
Here is an example:
|
Here is an example:
|
||||||
|
|
||||||
@@ -1366,10 +1404,6 @@ You must check the type before accessing the value: it is an error to call `get_
|
|||||||
|
|
||||||
The `get_number()` function is designed with performance in mind. When calling `get_number()`, you scan the number string only once, determining efficiently the type and storing it in an efficient manner.
|
The `get_number()` function is designed with performance in mind. When calling `get_number()`, you scan the number string only once, determining efficiently the type and storing it in an efficient manner.
|
||||||
|
|
||||||
If you only need to compute `v.get_number().get_number_type()` on
|
|
||||||
a `document` or `value` instance, you should call directly the faster method
|
|
||||||
`v.get_number_type()` which does not generate an
|
|
||||||
intermediate `number` instance.
|
|
||||||
|
|
||||||
Consider the following example:
|
Consider the following example:
|
||||||
```C++
|
```C++
|
||||||
@@ -1382,9 +1416,7 @@ Consider the following example:
|
|||||||
std::cout << "negative: " << val.is_negative() << " ";
|
std::cout << "negative: " << val.is_negative() << " ";
|
||||||
std::cout << "is_integer: " << val.is_integer() << " ";
|
std::cout << "is_integer: " << val.is_integer() << " ";
|
||||||
ondemand::number num = val.get_number();
|
ondemand::number num = val.get_number();
|
||||||
// direct computation without materializing the number:
|
ondemand::number_type t = num.get_number_type();
|
||||||
ondemand::number_type dt = val.get_number_type();
|
|
||||||
if(t != dt) { throw std::runtime_error("bug"); }
|
|
||||||
switch(t) {
|
switch(t) {
|
||||||
case ondemand::number_type::signed_integer:
|
case ondemand::number_type::signed_integer:
|
||||||
std::cout << "integer: " << int64_t(num) << " ";
|
std::cout << "integer: " << int64_t(num) << " ";
|
||||||
@@ -1438,8 +1470,8 @@ The simdjson library is fully compliant with the [RFC 8259](https://www.tbray.o
|
|||||||
- A single string or a single number is considered to be a valid JSON document.
|
- A single string or a single number is considered to be a valid JSON document.
|
||||||
- We fully validate the numbers according to the JSON specification. For example, the string `01` is not valid JSON document since the specification states that *leading zeros are not allowed*.
|
- We fully validate the numbers according to the JSON specification. For example, the string `01` is not valid JSON document since the specification states that *leading zeros are not allowed*.
|
||||||
- The specification allows implementations to set limits on the range and precision of numbers accepted. We support 64-bit floating-point numbers as well as integer values.
|
- The specification allows implementations to set limits on the range and precision of numbers accepted. We support 64-bit floating-point numbers as well as integer values.
|
||||||
- We parse integers and floating-point numbers afloating-point number followed by an integer.s separate types which allows us to support all signed (two's complement) 64-bit integersfloating-point number followed by an integer., like a Java `long` or a C/C++ `long long` and all 64-bit unsigned integers. When we cannot represent exactly an integer as a signed or unsigned 64-bit value, we reject the JSON document.
|
- We parse integers and floating-point numbers as separate types which allows us to support all signed (two's complement) 64-bit integers, like a Java `long` or a C/C++ `long long` and all 64-bit unsigned integers. When we cannot represent exactly an integer as a signed or unsigned 64-bit value, we reject the JSON document.
|
||||||
- We support the full range of 64-bit floating-point numbers (binary64). The values range from `std::numeric_limits<double>::lowest()` to `std::numefloating-point number followed by an integer.ric_limits<double>::max()`, so from -1.7976e308 all the way to 1.7975e308. Extreme values (less or equal to -1e308, greater or equal to 1e308) are rejected: we refuse to parse the input document. Numbers are parsed with a perfect accuracy (ULP 0): the nearest floating-point value is chosen, rounding to even when needed. If you serialized your floating-point numbers with 17floating-point value followed by an integer. significant digits in a standard compliant manner, the simdjson library is guaranfloating-point number followed by an integer.teed to recover the same numbers, exactly.
|
- We support the full range of 64-bit floating-point numbers (binary64). The values range from `std::numeric_limits<double>::lowest()` to `std::numeric_limits<double>::max()`, so from -1.7976e308 all the way to 1.7975e308. Extreme values (less or equal to -1e308, greater or equal to 1e308) are rejected: we refuse to parse the input document. Numbers are parsed with a perfect accuracy (ULP 0): the nearest floating-point value is chosen, rounding to even when needed. If you serialized your floating-point numbers with 17 significant digits in a standard compliant manner, the simdjson library is guaranteed to recover the same numbers, exactly.
|
||||||
- The specification states that JSON text exchanged between systems that are not part of a closed ecosystem MUST be encoded using UTF-8. The simdjson library does full UTF-8 validation as part of the parsing. The specification states that implementations MUST NOT add a byte order mark: the simdjson library rejects documents starting with a byte order mark.
|
- The specification states that JSON text exchanged between systems that are not part of a closed ecosystem MUST be encoded using UTF-8. The simdjson library does full UTF-8 validation as part of the parsing. The specification states that implementations MUST NOT add a byte order mark: the simdjson library rejects documents starting with a byte order mark.
|
||||||
- The simdjson library validates string content for unescaped characters. Unescaped line breaks and tabs in strings are not allowed.
|
- The simdjson library validates string content for unescaped characters. Unescaped line breaks and tabs in strings are not allowed.
|
||||||
- The simdjson library accepts objects with repeated keys: all of the name/value pairs, including duplicates, are reported. We do not enforce key uniqueness.
|
- The simdjson library accepts objects with repeated keys: all of the name/value pairs, including duplicates, are reported. We do not enforce key uniqueness.
|
||||||
|
|||||||
+11
-4
@@ -3,8 +3,8 @@ The Document-Object-Model (DOM) front-end
|
|||||||
|
|
||||||
An overview of what you need to know to use simdjson, with examples.
|
An overview of what you need to know to use simdjson, with examples.
|
||||||
|
|
||||||
* [DOM vs On Demand](#dom-vs-ondemand)
|
* [DOM vs On Demand](#dom-vs-on-demand)
|
||||||
* [The Basics: Loading and Parsing JSON Documents](#the-basics-loading-and-parsing-json-documents)
|
* [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)
|
* [Using the Parsed JSON](#using-the-parsed-json)
|
||||||
* [C++17 Support](#c17-support)
|
* [C++17 Support](#c17-support)
|
||||||
* [JSON Pointer](#json-pointer)
|
* [JSON Pointer](#json-pointer)
|
||||||
@@ -81,7 +81,7 @@ Once you have an element, you can navigate it with idiomatic C++ iterators, oper
|
|||||||
know the type of the value, you can cast it right there, too! `for (double value : array) { ... }`
|
know the type of the value, you can cast it right there, too! `for (double value : array) { ... }`
|
||||||
* **Object Iteration:** You can iterate through an object's fields, too: `for (auto [key, value] : object)`
|
* **Object Iteration:** You can iterate through an object's fields, too: `for (auto [key, value] : object)`
|
||||||
* **Array Index:** To get at an array value by index, use the at() method: `array.at(0)` gets the
|
* **Array Index:** To get at an array value by index, use the at() method: `array.at(0)` gets the
|
||||||
first element.
|
first element. The at() method has linear-time complexity so it should not be used to iterate over the values of an array.
|
||||||
> Note that array[0] does not compile, because implementing [] gives the impression indexing is a
|
> Note that array[0] does not compile, because implementing [] gives the impression indexing is a
|
||||||
> O(1) operation, which it is not presently in simdjson. Instead, you should iterate over the elements
|
> O(1) operation, which it is not presently in simdjson. Instead, you should iterate over the elements
|
||||||
> using a for-loop, as in our examples.
|
> using a for-loop, as in our examples.
|
||||||
@@ -249,7 +249,11 @@ auto error = parser.parse(json).get(doc);
|
|||||||
if (error) { cerr << error << endl; exit(1); }
|
if (error) { cerr << error << endl; exit(1); }
|
||||||
```
|
```
|
||||||
|
|
||||||
When you use the code this way, it is your responsibility to check for error before using the
|
When there is no error, the error code simdjson::SUCCESS is returned: it evaluates as false as a Boolean.
|
||||||
|
We have several error codes to indicate errors, they all evaluate to true as a Boolean: your software should not generally not depend on exact
|
||||||
|
error codes. We may change the error codes in future releases and the exact error codes could vary depending on your system.
|
||||||
|
|
||||||
|
When you use the code without exceptions, it is your responsibility to check for error before using the
|
||||||
result: if there is an error, the result value will not be valid and using it will caused undefined
|
result: if there is an error, the result value will not be valid and using it will caused undefined
|
||||||
behavior.
|
behavior.
|
||||||
|
|
||||||
@@ -318,6 +322,9 @@ int main(void) {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
The `at()` method has linear-time complexity: it should not be used to iterate
|
||||||
|
over the content of an array.
|
||||||
|
|
||||||
### Error Handling Example
|
### Error Handling Example
|
||||||
|
|
||||||
This is how the example in "Using the Parsed JSON" could be written using only error code checking:
|
This is how the example in "Using the Parsed JSON" could be written using only error code checking:
|
||||||
|
|||||||
@@ -50,9 +50,9 @@ Inspecting the Detected Implementation
|
|||||||
You can check what implementation is running with `active_implementation`:
|
You can check what implementation is running with `active_implementation`:
|
||||||
|
|
||||||
```c++
|
```c++
|
||||||
cout << "simdjson v" << STRINGIFY(SIMDJSON_VERSION) << endl;
|
cout << "simdjson v" << SIMDJSON_STRINGIFY(SIMDJSON_VERSION) << endl;
|
||||||
cout << "Detected the best implementation for your machine: " << simdjson::active_implementation->name();
|
cout << "Detected the best implementation for your machine: " << simdjson::get_active_implementation()->name();
|
||||||
cout << "(" << simdjson::active_implementation->description() << ")" << endl;
|
cout << "(" << simdjson::get_active_implementation()->description() << ")" << endl;
|
||||||
```
|
```
|
||||||
|
|
||||||
Implementation detection will happen in this case when you first call `name()`.
|
Implementation detection will happen in this case when you first call `name()`.
|
||||||
@@ -63,7 +63,7 @@ Querying Available Implementations
|
|||||||
You can list all available implementations, regardless of which one was selected:
|
You can list all available implementations, regardless of which one was selected:
|
||||||
|
|
||||||
```c++
|
```c++
|
||||||
for (auto implementation : simdjson::available_implementations) {
|
for (auto implementation : simdjson::get_available_implementations()) {
|
||||||
cout << implementation->name() << ": " << implementation->description() << endl;
|
cout << implementation->name() << ": " << implementation->description() << endl;
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@@ -71,10 +71,10 @@ for (auto implementation : simdjson::available_implementations) {
|
|||||||
And look them up by name:
|
And look them up by name:
|
||||||
|
|
||||||
```c++
|
```c++
|
||||||
cout << simdjson::available_implementations["fallback"]->description() << endl;
|
cout << simdjson::get_available_implementations()["fallback"]->description() << endl;
|
||||||
```
|
```
|
||||||
Though the fallback implementation should always be available, others might be missing. When
|
Though the fallback implementation should always be available, others might be missing. When
|
||||||
an implementation is not available, the bracket call `simdjson::available_implementations[name]`
|
an implementation is not available, the bracket call `simdjson::get_available_implementations()[name]`
|
||||||
will return the null pointer.
|
will return the null pointer.
|
||||||
|
|
||||||
The available implementations have been compiled but may not necessarily be run safely on your system
|
The available implementations have been compiled but may not necessarily be run safely on your system
|
||||||
@@ -90,18 +90,18 @@ can select the CPU architecture yourself:
|
|||||||
|
|
||||||
```c++
|
```c++
|
||||||
// Use the fallback implementation, even though my machine is fast enough for anything
|
// Use the fallback implementation, even though my machine is fast enough for anything
|
||||||
simdjson::active_implementation = simdjson::available_implementations["fallback"];
|
simdjson::get_active_implementation() = simdjson::get_available_implementations()["fallback"];
|
||||||
```
|
```
|
||||||
|
|
||||||
You are responsible for ensuring that the requirements of the selected implementation match your current system.
|
You are responsible for ensuring that the requirements of the selected implementation match your current system.
|
||||||
Furthermore, you should check that the implementation is available before setting it to `simdjson::active_implementation`
|
Furthermore, you should check that the implementation is available before setting it to `simdjson::get_active_implementation()`
|
||||||
by comparing it with the null pointer.
|
by comparing it with the null pointer.
|
||||||
|
|
||||||
```c++
|
```c++
|
||||||
auto my_implementation = simdjson::available_implementations["haswell"];
|
auto my_implementation = simdjson::get_available_implementations()["haswell"];
|
||||||
if(! my_implementation) { exit(1); }
|
if(! my_implementation) { exit(1); }
|
||||||
if(! my_implementation->supported_by_runtime_system()) { exit(1); }
|
if(! my_implementation->supported_by_runtime_system()) { exit(1); }
|
||||||
simdjson::active_implementation = my_implementation;
|
simdjson::get_active_implementation() = my_implementation;
|
||||||
```
|
```
|
||||||
|
|
||||||
Checking that an Implementation can Run on your System
|
Checking that an Implementation can Run on your System
|
||||||
@@ -110,12 +110,12 @@ Checking that an Implementation can Run on your System
|
|||||||
You should call `supported_by_runtime_system()` to compare the processor's features with the need of the implementation.
|
You should call `supported_by_runtime_system()` to compare the processor's features with the need of the implementation.
|
||||||
|
|
||||||
```c++
|
```c++
|
||||||
for (auto implementation : simdjson::available_implementations) {
|
for (auto implementation : simdjson::get_available_implementations()) {
|
||||||
if(implementation->supported_by_runtime_system()) {
|
if(implementation->supported_by_runtime_system()) {
|
||||||
cout << implementation->name() << ": " << implementation->description() << endl;
|
cout << implementation->name() << ": " << implementation->description() << endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
The call to `supported_by_runtime_system()` maybe relatively expensive. Do not call `supported_by_runtime_system()` each
|
The call to `supported_by_runtime_system()` may be relatively expensive. Do not call `supported_by_runtime_system()` each
|
||||||
time you parse a JSON input (for example). It is meant to be called a handful of times at most in the life of a program.
|
time you parse a JSON input (for example). It is meant to be called a handful of times at most in the life of a program.
|
||||||
|
|||||||
+6
-2
@@ -1,7 +1,9 @@
|
|||||||
iterate_many
|
iterate_many
|
||||||
==========
|
==========
|
||||||
|
|
||||||
An interface providing features to work with files or streams containing multiple small JSON documents. Given an input such as
|
When serializing large databases, it is often better to write out many independent JSON
|
||||||
|
documents, instead of one large monolithic document containing many records. The simdjson
|
||||||
|
library provides high-speed access to files or streams containing multiple small JSON documents separated by ASCII white-space characters. Given an input such as
|
||||||
```JSON
|
```JSON
|
||||||
{"text":"a"}
|
{"text":"a"}
|
||||||
{"text":"b"}
|
{"text":"b"}
|
||||||
@@ -114,7 +116,9 @@ Whitespace Characters:
|
|||||||
- **Linefeed**
|
- **Linefeed**
|
||||||
- **Carriage return**
|
- **Carriage return**
|
||||||
- **Horizontal tab**
|
- **Horizontal tab**
|
||||||
- **Nothing**
|
|
||||||
|
If your documents are all objects or arrays, then you may even have nothing between them.
|
||||||
|
E.g., `[1,2]{"32":1}` is recognized as two documents.
|
||||||
|
|
||||||
Some official formats **(non-exhaustive list)**:
|
Some official formats **(non-exhaustive list)**:
|
||||||
- [Newline-Delimited JSON (NDJSON)](http://ndjson.org/)
|
- [Newline-Delimited JSON (NDJSON)](http://ndjson.org/)
|
||||||
|
|||||||
@@ -709,42 +709,6 @@ in production systems:
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
### 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. Similarly to the DOM-based approach (see [here](https://github.com/simdjson/simdjson/blob/master/doc/dom.md#server-loops-long-running-processes-and-memory-capacity)]), 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++
|
|
||||||
ondemand::parser parser(1000*1000); // Never grows past documents > 1 MB
|
|
||||||
auto doc = parser.iterate(json);
|
|
||||||
for (web_request request : listen()) {
|
|
||||||
padded_string json;
|
|
||||||
padded_string json = padded_string::load(request.body);
|
|
||||||
auto error = parser.iterate(json);
|
|
||||||
// If the document was above our limit, emit 413 = payload too large
|
|
||||||
if (error == CAPACITY) { request.respond(413); continue; }
|
|
||||||
// ...
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
The capacity will grow as the parser encounters larger documents up to 1 MB.
|
|
||||||
|
|
||||||
* You can also allocate a *fixed capacity* that will never grow:
|
|
||||||
```C++
|
|
||||||
ondemand::parser parser(1000*1000);
|
|
||||||
parser.allocate(1000*1000) // Fix the capacity to 1 MB
|
|
||||||
auto doc = parser.iterate(json);
|
|
||||||
for (web_request request : listen()) {
|
|
||||||
padded_string json;
|
|
||||||
padded_string json = padded_string::load(request.body);
|
|
||||||
auto error = parser.iterate(json);
|
|
||||||
// If the document was above our limit, emit 413 = payload too large
|
|
||||||
if (error == CAPACITY) { request.respond(413); continue; }
|
|
||||||
// ...
|
|
||||||
}
|
|
||||||
```
|
|
||||||
You can also manually set the maximal capacity using the method `set_max_capacity()`.
|
|
||||||
### 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.
|
||||||
@@ -764,7 +728,6 @@ There are currently additional technical limitations which we expect to resolve
|
|||||||
|
|
||||||
* 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`).
|
* 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`).
|
||||||
* The On Demand API does not support JSON Pointer. This capability is currently limited to our core API.
|
|
||||||
|
|
||||||
### Applicability of the On Demand Approach
|
### Applicability of the On Demand Approach
|
||||||
|
|
||||||
|
|||||||
+40
-1
@@ -56,6 +56,43 @@ 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:
|
||||||
|
|
||||||
|
* You can set an upper bound (*max_capacity*) when construction the parser:
|
||||||
|
```C++
|
||||||
|
ondemand::parser parser(1000*1000); // Never grows past documents > 1 MB
|
||||||
|
auto doc = parser.iterate(json);
|
||||||
|
for (web_request request : listen()) {
|
||||||
|
padded_string json;
|
||||||
|
padded_string json = padded_string::load(request.body);
|
||||||
|
auto error = parser.iterate(json);
|
||||||
|
// If the document was above our limit, emit 413 = payload too large
|
||||||
|
if (error == CAPACITY) { request.respond(413); continue; }
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
The capacity will grow as the parser encounters larger documents up to 1 MB.
|
||||||
|
|
||||||
|
* You can also allocate a *fixed capacity* that will never grow:
|
||||||
|
```C++
|
||||||
|
ondemand::parser parser(1000*1000);
|
||||||
|
parser.allocate(1000*1000) // Fix the capacity to 1 MB
|
||||||
|
auto doc = parser.iterate(json);
|
||||||
|
for (web_request request : listen()) {
|
||||||
|
padded_string json;
|
||||||
|
padded_string json = padded_string::load(request.body);
|
||||||
|
auto error = parser.iterate(json);
|
||||||
|
// If the document was above our limit, emit 413 = payload too large
|
||||||
|
if (error == CAPACITY) { request.respond(413); continue; }
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
You can also manually set the maximal capacity using the method `set_max_capacity()`.
|
||||||
|
|
||||||
Large files and huge page support
|
Large files and huge page support
|
||||||
---------------------------------
|
---------------------------------
|
||||||
|
|
||||||
@@ -123,6 +160,8 @@ You should not expect the simdjson library to cause *downclocking* of your recen
|
|||||||
- [Whenever 512-bit AVX-512 instructions are used](https://lemire.me/blog/2018/09/07/avx-512-when-and-how-to-use-these-new-instructions/).
|
- [Whenever 512-bit AVX-512 instructions are used](https://lemire.me/blog/2018/09/07/avx-512-when-and-how-to-use-these-new-instructions/).
|
||||||
- Whenever heavy 256-bit or wider instructions are used. Heavy instructions are those involving floating point operations or integer multiplications (since these execute on the floating point unit).
|
- Whenever heavy 256-bit or wider instructions are used. Heavy instructions are those involving floating point operations or integer multiplications (since these execute on the floating point unit).
|
||||||
|
|
||||||
The simdjson library does not currently support AVX-512 instructions and it does not make use of heavy 256-bit instructions. We do use vectorized multiplications, but only using 128-bit registers. Thus there should be no downclocking due to simdjson on recent processors.
|
The simdjson library does not make use of heavy 256-bit instructions. We do use vectorized multiplications, but only using 128-bit registers. Thus there should be no downclocking due to simdjson on recent processors, except when AVX-512 is allowed and
|
||||||
|
detected. However, we only allow AVX-512 on recent processors (Ice Lake/Tiger Lake or better) where [little to no frequency throttling is expected](https://travisdowns.github.io/blog/2020/08/19/icl-avx512-freq.html). If you can still concerned, you can easily disable AVX-512 with the CMake option `SIMDJSON_AVX512_ALLOWED` set to `OFF` (e.g., `cmake -D SIMDJSON_AVX512_ALLOWED=OFF -B build && cmake --build build`) or by setting
|
||||||
|
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.
|
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.
|
||||||
|
|||||||
@@ -93,7 +93,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
|
|||||||
std::size_t nerrors=0;
|
std::size_t nerrors=0;
|
||||||
for(std::size_t i=0; i<Nimplementations; ++i) {
|
for(std::size_t i=0; i<Nimplementations; ++i) {
|
||||||
auto& e=implementations[i];
|
auto& e=implementations[i];
|
||||||
simdjson::active_implementation=e.impl;
|
simdjson::get_active_implementation()=e.impl;
|
||||||
e.error=e.parser.parse(Data,Size).get(e.element);
|
e.error=e.parser.parse(Data,Size).get(e.element);
|
||||||
if(e.error) {
|
if(e.error) {
|
||||||
++nerrors;
|
++nerrors;
|
||||||
|
|||||||
+17
-15
@@ -8,24 +8,26 @@
|
|||||||
|
|
||||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
|
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
|
||||||
FuzzData fd(Data, Size);
|
FuzzData fd(Data, Size);
|
||||||
const auto batch_size=static_cast<size_t>(fd.getInt<0,1000>());
|
const auto batch_size = static_cast<size_t>(fd.getInt<0,1000>());
|
||||||
const auto json=simdjson::padded_string{fd.remainder_as_stringview()};
|
const auto json = simdjson::padded_string{fd.remainder_as_stringview()};
|
||||||
simdjson::dom::parser parser;
|
simdjson::dom::parser parser;
|
||||||
#if SIMDJSON_EXCEPTIONS
|
simdjson::dom::document_stream docs;
|
||||||
try {
|
if(parser.parse_many(json,batch_size).get(docs)) { return 0; }
|
||||||
#endif
|
size_t bool_count1 = 0;
|
||||||
simdjson::dom::document_stream docs;
|
size_t total_count1 = 0;
|
||||||
if(parser.parse_many(json,batch_size).get(docs)) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t bool_count=0;
|
|
||||||
for (auto doc : docs) {
|
for (auto doc : docs) {
|
||||||
bool_count+=doc.is_bool();
|
total_count1++;
|
||||||
|
bool_count1 += doc.is_bool();
|
||||||
}
|
}
|
||||||
#if SIMDJSON_EXCEPTIONS
|
// Restart, if we made it this far, the document *must* be accessible.
|
||||||
} catch(...) {
|
if(parser.parse_many(json,batch_size).get(docs)) { return EXIT_FAILURE; }
|
||||||
|
size_t bool_count2 = 0;
|
||||||
|
size_t total_count2 = 0;
|
||||||
|
for (auto doc : docs) {
|
||||||
|
total_count2++;
|
||||||
|
bool_count2 += doc.is_bool();
|
||||||
}
|
}
|
||||||
#endif
|
// They should agree!!!
|
||||||
|
if((total_count2 != total_count1) || (bool_count2 != bool_count1)) { return EXIT_FAILURE; }
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
std::vector<const simdjson::implementation*>
|
std::vector<const simdjson::implementation*>
|
||||||
get_runtime_supported_implementations() {
|
get_runtime_supported_implementations() {
|
||||||
std::vector<const simdjson::implementation*> ret;
|
std::vector<const simdjson::implementation*> ret;
|
||||||
for(auto& e: simdjson::available_implementations) {
|
for(auto& e: simdjson::get_available_implementations()) {
|
||||||
if(e->supported_by_runtime_system()) {
|
if(e->supported_by_runtime_system()) {
|
||||||
ret.emplace_back(e);
|
ret.emplace_back(e);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,6 +34,7 @@
|
|||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "simdjson/simdjson_version.h"
|
||||||
#include "simdjson/dom.h"
|
#include "simdjson/dom.h"
|
||||||
#include "simdjson/builtin.h"
|
#include "simdjson/builtin.h"
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ namespace {
|
|||||||
// We sometimes call trailing_zero on inputs that are zero,
|
// We sometimes call trailing_zero on inputs that are zero,
|
||||||
// but the algorithms do not end up using the returned value.
|
// but the algorithms do not end up using the returned value.
|
||||||
// Sadly, sanitizers are not smart enough to figure it out.
|
// Sadly, sanitizers are not smart enough to figure it out.
|
||||||
NO_SANITIZE_UNDEFINED
|
SIMDJSON_NO_SANITIZE_UNDEFINED
|
||||||
simdjson_really_inline int trailing_zeroes(uint64_t input_num) {
|
simdjson_really_inline int trailing_zeroes(uint64_t input_num) {
|
||||||
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
|
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||||
unsigned long ret;
|
unsigned long ret;
|
||||||
@@ -73,7 +73,7 @@ simdjson_really_inline uint64_t reverse_bits(uint64_t input_num) {
|
|||||||
* greating or equal to 63 in which case we trigger undefined behavior, but the output
|
* greating or equal to 63 in which case we trigger undefined behavior, but the output
|
||||||
* of such undefined behavior is never used.
|
* of such undefined behavior is never used.
|
||||||
**/
|
**/
|
||||||
NO_SANITIZE_UNDEFINED
|
SIMDJSON_NO_SANITIZE_UNDEFINED
|
||||||
simdjson_really_inline uint64_t zero_leading_bit(uint64_t rev_bits, int leading_zeroes) {
|
simdjson_really_inline uint64_t zero_leading_bit(uint64_t rev_bits, int leading_zeroes) {
|
||||||
return rev_bits ^ (uint64_t(0x8000000000000000) >> leading_zeroes);
|
return rev_bits ^ (uint64_t(0x8000000000000000) >> leading_zeroes);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ public:
|
|||||||
) const noexcept final;
|
) const noexcept final;
|
||||||
simdjson_warn_unused error_code minify(const uint8_t *buf, size_t len, uint8_t *dst, size_t &dst_len) const noexcept final;
|
simdjson_warn_unused error_code minify(const uint8_t *buf, size_t len, uint8_t *dst, size_t &dst_len) const noexcept final;
|
||||||
simdjson_warn_unused bool validate_utf8(const char *buf, size_t len) const noexcept final;
|
simdjson_warn_unused bool validate_utf8(const char *buf, size_t len) const noexcept final;
|
||||||
|
simdjson_warn_unused uint8_t *parse_string(const uint8_t *src, uint8_t *dst) const noexcept final;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace arm64
|
} // namespace arm64
|
||||||
|
|||||||
@@ -132,7 +132,7 @@ simdjson_really_inline int8x16_t make_int8x16_t(int8_t x1, int8_t x2, int8_t x
|
|||||||
simdjson_really_inline simd8<T>& operator&=(const simd8<T> other) { auto this_cast = static_cast<simd8<T>*>(this); *this_cast = *this_cast & other; return *this_cast; }
|
simdjson_really_inline simd8<T>& operator&=(const simd8<T> other) { auto this_cast = static_cast<simd8<T>*>(this); *this_cast = *this_cast & other; return *this_cast; }
|
||||||
simdjson_really_inline simd8<T>& operator^=(const simd8<T> other) { auto this_cast = static_cast<simd8<T>*>(this); *this_cast = *this_cast ^ other; return *this_cast; }
|
simdjson_really_inline simd8<T>& operator^=(const simd8<T> other) { auto this_cast = static_cast<simd8<T>*>(this); *this_cast = *this_cast ^ other; return *this_cast; }
|
||||||
|
|
||||||
simdjson_really_inline Mask operator==(const simd8<T> other) const { return vceqq_u8(*this, other); }
|
friend simdjson_really_inline Mask operator==(const simd8<T> lhs, const simd8<T> rhs) { return vceqq_u8(lhs, rhs); }
|
||||||
|
|
||||||
template<int N=1>
|
template<int N=1>
|
||||||
simdjson_really_inline simd8<T> prev(const simd8<T> prev_chunk) const {
|
simdjson_really_inline simd8<T> prev(const simd8<T> prev_chunk) const {
|
||||||
|
|||||||
@@ -5,7 +5,9 @@
|
|||||||
|
|
||||||
// Determine the best builtin implementation
|
// Determine the best builtin implementation
|
||||||
#ifndef SIMDJSON_BUILTIN_IMPLEMENTATION
|
#ifndef SIMDJSON_BUILTIN_IMPLEMENTATION
|
||||||
#if SIMDJSON_CAN_ALWAYS_RUN_HASWELL
|
#if SIMDJSON_CAN_ALWAYS_RUN_ICELAKE
|
||||||
|
#define SIMDJSON_BUILTIN_IMPLEMENTATION icelake
|
||||||
|
#elif SIMDJSON_CAN_ALWAYS_RUN_HASWELL
|
||||||
#define SIMDJSON_BUILTIN_IMPLEMENTATION haswell
|
#define SIMDJSON_BUILTIN_IMPLEMENTATION haswell
|
||||||
#elif SIMDJSON_CAN_ALWAYS_RUN_WESTMERE
|
#elif SIMDJSON_CAN_ALWAYS_RUN_WESTMERE
|
||||||
#define SIMDJSON_BUILTIN_IMPLEMENTATION westmere
|
#define SIMDJSON_BUILTIN_IMPLEMENTATION westmere
|
||||||
|
|||||||
@@ -122,6 +122,9 @@ constexpr size_t DEFAULT_MAX_DEPTH = 1024;
|
|||||||
|
|
||||||
#define SIMDJSON_PUSH_DISABLE_WARNINGS _Pragma("GCC diagnostic push")
|
#define SIMDJSON_PUSH_DISABLE_WARNINGS _Pragma("GCC diagnostic push")
|
||||||
// gcc doesn't seem to disable all warnings with all and extra, add warnings here as necessary
|
// gcc doesn't seem to disable all warnings with all and extra, add warnings here as necessary
|
||||||
|
// We do it separately for clang since it has different warnings.
|
||||||
|
#ifdef __clang__
|
||||||
|
// clang is missing -Wmaybe-uninitialized.
|
||||||
#define SIMDJSON_PUSH_DISABLE_ALL_WARNINGS SIMDJSON_PUSH_DISABLE_WARNINGS \
|
#define SIMDJSON_PUSH_DISABLE_ALL_WARNINGS SIMDJSON_PUSH_DISABLE_WARNINGS \
|
||||||
SIMDJSON_DISABLE_GCC_WARNING(-Weffc++) \
|
SIMDJSON_DISABLE_GCC_WARNING(-Weffc++) \
|
||||||
SIMDJSON_DISABLE_GCC_WARNING(-Wall) \
|
SIMDJSON_DISABLE_GCC_WARNING(-Wall) \
|
||||||
@@ -134,6 +137,22 @@ constexpr size_t DEFAULT_MAX_DEPTH = 1024;
|
|||||||
SIMDJSON_DISABLE_GCC_WARNING(-Wshadow) \
|
SIMDJSON_DISABLE_GCC_WARNING(-Wshadow) \
|
||||||
SIMDJSON_DISABLE_GCC_WARNING(-Wunused-parameter) \
|
SIMDJSON_DISABLE_GCC_WARNING(-Wunused-parameter) \
|
||||||
SIMDJSON_DISABLE_GCC_WARNING(-Wunused-variable)
|
SIMDJSON_DISABLE_GCC_WARNING(-Wunused-variable)
|
||||||
|
#else // __clang__
|
||||||
|
#define SIMDJSON_PUSH_DISABLE_ALL_WARNINGS SIMDJSON_PUSH_DISABLE_WARNINGS \
|
||||||
|
SIMDJSON_DISABLE_GCC_WARNING(-Weffc++) \
|
||||||
|
SIMDJSON_DISABLE_GCC_WARNING(-Wall) \
|
||||||
|
SIMDJSON_DISABLE_GCC_WARNING(-Wconversion) \
|
||||||
|
SIMDJSON_DISABLE_GCC_WARNING(-Wextra) \
|
||||||
|
SIMDJSON_DISABLE_GCC_WARNING(-Wattributes) \
|
||||||
|
SIMDJSON_DISABLE_GCC_WARNING(-Wimplicit-fallthrough) \
|
||||||
|
SIMDJSON_DISABLE_GCC_WARNING(-Wnon-virtual-dtor) \
|
||||||
|
SIMDJSON_DISABLE_GCC_WARNING(-Wreturn-type) \
|
||||||
|
SIMDJSON_DISABLE_GCC_WARNING(-Wshadow) \
|
||||||
|
SIMDJSON_DISABLE_GCC_WARNING(-Wunused-parameter) \
|
||||||
|
SIMDJSON_DISABLE_GCC_WARNING(-Wunused-variable) \
|
||||||
|
SIMDJSON_DISABLE_GCC_WARNING(-Wmaybe-uninitialized)
|
||||||
|
#endif // __clang__
|
||||||
|
|
||||||
#define SIMDJSON_PRAGMA(P) _Pragma(#P)
|
#define SIMDJSON_PRAGMA(P) _Pragma(#P)
|
||||||
#define SIMDJSON_DISABLE_GCC_WARNING(WARNING) SIMDJSON_PRAGMA(GCC diagnostic ignored #WARNING)
|
#define SIMDJSON_DISABLE_GCC_WARNING(WARNING) SIMDJSON_PRAGMA(GCC diagnostic ignored #WARNING)
|
||||||
#if defined(SIMDJSON_CLANG_VISUAL_STUDIO)
|
#if defined(SIMDJSON_CLANG_VISUAL_STUDIO)
|
||||||
|
|||||||
@@ -176,7 +176,7 @@ inline error_code parser::allocate(size_t capacity, size_t max_depth) noexcept {
|
|||||||
if (implementation) {
|
if (implementation) {
|
||||||
err = implementation->allocate(capacity, max_depth);
|
err = implementation->allocate(capacity, max_depth);
|
||||||
} else {
|
} else {
|
||||||
err = simdjson::active_implementation->create_dom_parser_implementation(capacity, max_depth, implementation);
|
err = simdjson::get_active_implementation()->create_dom_parser_implementation(capacity, max_depth, implementation);
|
||||||
}
|
}
|
||||||
if (err) { return err; }
|
if (err) { return err; }
|
||||||
return SUCCESS;
|
return SUCCESS;
|
||||||
|
|||||||
@@ -157,7 +157,10 @@ simdjson_really_inline void mini_formatter::string(std::string_view unescaped) {
|
|||||||
size_t i = 0;
|
size_t i = 0;
|
||||||
// Fast path for the case where we have no control character, no ", and no backslash.
|
// Fast path for the case where we have no control character, no ", and no backslash.
|
||||||
// This should include most keys.
|
// This should include most keys.
|
||||||
constexpr static bool needs_escaping[] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
//
|
||||||
|
// We would like to use 'bool' but some compilers take offense to bitwise operation
|
||||||
|
// with bool types.
|
||||||
|
constexpr static char needs_escaping[] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,
|
||||||
@@ -169,6 +172,8 @@ simdjson_really_inline void mini_formatter::string(std::string_view unescaped) {
|
|||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
|
||||||
for(;i + 8 <= unescaped.length(); i += 8) {
|
for(;i + 8 <= unescaped.length(); i += 8) {
|
||||||
// Poor's man vectorization. This could get much faster if we used SIMD.
|
// Poor's man vectorization. This could get much faster if we used SIMD.
|
||||||
|
//
|
||||||
|
// It is not the case that replacing '|' with '||' would be neutral performance-wise.
|
||||||
if(needs_escaping[uint8_t(unescaped[i])] | needs_escaping[uint8_t(unescaped[i+1])]
|
if(needs_escaping[uint8_t(unescaped[i])] | needs_escaping[uint8_t(unescaped[i+1])]
|
||||||
| needs_escaping[uint8_t(unescaped[i+2])] | needs_escaping[uint8_t(unescaped[i+3])]
|
| needs_escaping[uint8_t(unescaped[i+2])] | needs_escaping[uint8_t(unescaped[i+3])]
|
||||||
| needs_escaping[uint8_t(unescaped[i+4])] | needs_escaping[uint8_t(unescaped[i+5])]
|
| needs_escaping[uint8_t(unescaped[i+4])] | needs_escaping[uint8_t(unescaped[i+5])]
|
||||||
|
|||||||
@@ -7,7 +7,12 @@
|
|||||||
namespace simdjson {
|
namespace simdjson {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* All possible errors returned by simdjson.
|
* All possible errors returned by simdjson. These error codes are subject to change
|
||||||
|
* and not all simdjson kernel returns the same error code given the same input: it is not
|
||||||
|
* well defined which error a given input should produce.
|
||||||
|
*
|
||||||
|
* Only SUCCESS evaluates to false as a Boolean. All other error codes will evaluate
|
||||||
|
* to true as a Boolean.
|
||||||
*/
|
*/
|
||||||
enum error_code {
|
enum error_code {
|
||||||
SUCCESS = 0, ///< No error
|
SUCCESS = 0, ///< No error
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ public:
|
|||||||
) const noexcept final;
|
) const noexcept final;
|
||||||
simdjson_warn_unused error_code minify(const uint8_t *buf, size_t len, uint8_t *dst, size_t &dst_len) const noexcept final;
|
simdjson_warn_unused error_code minify(const uint8_t *buf, size_t len, uint8_t *dst, size_t &dst_len) const noexcept final;
|
||||||
simdjson_warn_unused bool validate_utf8(const char *buf, size_t len) const noexcept final;
|
simdjson_warn_unused bool validate_utf8(const char *buf, size_t len) const noexcept final;
|
||||||
|
simdjson_warn_unused uint8_t *parse_string(const uint8_t *src, uint8_t *dst) const noexcept final;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace fallback
|
} // namespace fallback
|
||||||
|
|||||||
@@ -361,7 +361,7 @@ error_code slow_float_parsing(simdjson_unused const uint8_t * src, W writer) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<typename I>
|
template<typename I>
|
||||||
NO_SANITIZE_UNDEFINED // We deliberately allow overflow here and check later
|
SIMDJSON_NO_SANITIZE_UNDEFINED // We deliberately allow overflow here and check later
|
||||||
simdjson_really_inline bool parse_digit(const uint8_t c, I &i) {
|
simdjson_really_inline bool parse_digit(const uint8_t c, I &i) {
|
||||||
const uint8_t digit = static_cast<uint8_t>(c - '0');
|
const uint8_t digit = static_cast<uint8_t>(c - '0');
|
||||||
if (digit > 9) {
|
if (digit > 9) {
|
||||||
@@ -609,7 +609,7 @@ simdjson_really_inline error_code parse_number(const uint8_t *const src, W &writ
|
|||||||
// - That is smaller than the smallest possible 20-digit number the user could write:
|
// - That is smaller than the smallest possible 20-digit number the user could write:
|
||||||
// 10,000,000,000,000,000,000.
|
// 10,000,000,000,000,000,000.
|
||||||
// - Therefore, if the number is positive and lower than that, it's overflow.
|
// - Therefore, if the number is positive and lower than that, it's overflow.
|
||||||
// - The value we are looking at is less than or equal to 9,223,372,036,854,775,808 (INT64_MAX).
|
// - The value we are looking at is less than or equal to INT64_MAX.
|
||||||
//
|
//
|
||||||
} else if (src[0] != uint8_t('1') || i <= uint64_t(INT64_MAX)) { return INVALID_NUMBER(src); }
|
} else if (src[0] != uint8_t('1') || i <= uint64_t(INT64_MAX)) { return INVALID_NUMBER(src); }
|
||||||
}
|
}
|
||||||
@@ -732,7 +732,7 @@ simdjson_unused simdjson_really_inline simdjson_result<uint64_t> parse_unsigned(
|
|||||||
// - That is smaller than the smallest possible 20-digit number the user could write:
|
// - That is smaller than the smallest possible 20-digit number the user could write:
|
||||||
// 10,000,000,000,000,000,000.
|
// 10,000,000,000,000,000,000.
|
||||||
// - Therefore, if the number is positive and lower than that, it's overflow.
|
// - Therefore, if the number is positive and lower than that, it's overflow.
|
||||||
// - The value we are looking at is less than or equal to 9,223,372,036,854,775,808 (INT64_MAX).
|
// - The value we are looking at is less than or equal to INT64_MAX.
|
||||||
//
|
//
|
||||||
if (src[0] != uint8_t('1') || i <= uint64_t(INT64_MAX)) { return INCORRECT_TYPE; }
|
if (src[0] != uint8_t('1') || i <= uint64_t(INT64_MAX)) { return INCORRECT_TYPE; }
|
||||||
}
|
}
|
||||||
@@ -782,7 +782,7 @@ simdjson_unused simdjson_really_inline simdjson_result<uint64_t> parse_unsigned(
|
|||||||
// - That is smaller than the smallest possible 20-digit number the user could write:
|
// - That is smaller than the smallest possible 20-digit number the user could write:
|
||||||
// 10,000,000,000,000,000,000.
|
// 10,000,000,000,000,000,000.
|
||||||
// - Therefore, if the number is positive and lower than that, it's overflow.
|
// - Therefore, if the number is positive and lower than that, it's overflow.
|
||||||
// - The value we are looking at is less than or equal to 9,223,372,036,854,775,808 (INT64_MAX).
|
// - The value we are looking at is less than or equal to INT64_MAX.
|
||||||
//
|
//
|
||||||
if (src[0] != uint8_t('1') || i <= uint64_t(INT64_MAX)) { return INCORRECT_TYPE; }
|
if (src[0] != uint8_t('1') || i <= uint64_t(INT64_MAX)) { return INCORRECT_TYPE; }
|
||||||
}
|
}
|
||||||
@@ -830,9 +830,11 @@ simdjson_unused simdjson_really_inline simdjson_result<uint64_t> parse_unsigned_
|
|||||||
// - That is smaller than the smallest possible 20-digit number the user could write:
|
// - That is smaller than the smallest possible 20-digit number the user could write:
|
||||||
// 10,000,000,000,000,000,000.
|
// 10,000,000,000,000,000,000.
|
||||||
// - Therefore, if the number is positive and lower than that, it's overflow.
|
// - Therefore, if the number is positive and lower than that, it's overflow.
|
||||||
// - The value we are looking at is less than or equal to 9,223,372,036,854,775,808 (INT64_MAX).
|
// - The value we are looking at is less than or equal to INT64_MAX.
|
||||||
//
|
//
|
||||||
if (src[0] != uint8_t('1') || i <= uint64_t(INT64_MAX)) { return INCORRECT_TYPE; }
|
// Note: we use src[1] and not src[0] because src[0] is the quote character in this
|
||||||
|
// instance.
|
||||||
|
if (src[1] != uint8_t('1') || i <= uint64_t(INT64_MAX)) { return INCORRECT_TYPE; }
|
||||||
}
|
}
|
||||||
|
|
||||||
return i;
|
return i;
|
||||||
@@ -1065,6 +1067,11 @@ simdjson_unused simdjson_really_inline simdjson_result<ondemand::number_type> ge
|
|||||||
while(static_cast<uint8_t>(*p - '0') <= 9) { p++; }
|
while(static_cast<uint8_t>(*p - '0') <= 9) { p++; }
|
||||||
if ( p == src ) { return NUMBER_ERROR; }
|
if ( p == src ) { return NUMBER_ERROR; }
|
||||||
if (jsoncharutils::is_structural_or_whitespace(*p)) {
|
if (jsoncharutils::is_structural_or_whitespace(*p)) {
|
||||||
|
// We have an integer.
|
||||||
|
// If the number is negative and valid, it must be a signed integer.
|
||||||
|
if(negative) { return ondemand::number_type::signed_integer; }
|
||||||
|
// 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);
|
int digit_count = int(p - src);
|
||||||
if(digit_count >= 19) {
|
if(digit_count >= 19) {
|
||||||
const uint8_t * smaller_big_integer = reinterpret_cast<const uint8_t *>("9223372036854775808");
|
const uint8_t * smaller_big_integer = reinterpret_cast<const uint8_t *>("9223372036854775808");
|
||||||
@@ -1074,6 +1081,7 @@ simdjson_unused simdjson_really_inline simdjson_result<ondemand::number_type> ge
|
|||||||
}
|
}
|
||||||
return ondemand::number_type::signed_integer;
|
return ondemand::number_type::signed_integer;
|
||||||
}
|
}
|
||||||
|
// Hopefully, we have 'e' or 'E' or '.'.
|
||||||
return ondemand::number_type::floating_point_number;
|
return ondemand::number_type::floating_point_number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -89,6 +89,7 @@ simdjson_really_inline simdjson_result<std::string_view> array::raw_json() noexc
|
|||||||
return std::string_view(reinterpret_cast<const char*>(starting_point), size_t(final_point - starting_point));
|
return std::string_view(reinterpret_cast<const char*>(starting_point), size_t(final_point - starting_point));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SIMDJSON_PUSH_DISABLE_WARNINGS
|
||||||
SIMDJSON_DISABLE_STRICT_OVERFLOW_WARNING
|
SIMDJSON_DISABLE_STRICT_OVERFLOW_WARNING
|
||||||
simdjson_really_inline simdjson_result<size_t> array::count_elements() & noexcept {
|
simdjson_really_inline simdjson_result<size_t> array::count_elements() & noexcept {
|
||||||
size_t count{0};
|
size_t count{0};
|
||||||
@@ -101,6 +102,7 @@ simdjson_really_inline simdjson_result<size_t> array::count_elements() & noexcep
|
|||||||
iter.reset_array();
|
iter.reset_array();
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
SIMDJSON_POP_DISABLE_WARNINGS
|
||||||
|
|
||||||
simdjson_really_inline simdjson_result<bool> array::is_empty() & noexcept {
|
simdjson_really_inline simdjson_result<bool> array::is_empty() & noexcept {
|
||||||
bool is_not_empty;
|
bool is_not_empty;
|
||||||
|
|||||||
@@ -104,7 +104,7 @@ public:
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value at the given index. This function has linear-time complexity.
|
* Get the value at the given index. This function has linear-time complexity.
|
||||||
* This function should only be called once as the array iterator is not reset between each call.
|
* This function should only be called once on an array instance since the array iterator is not reset between each call.
|
||||||
*
|
*
|
||||||
* @return The value at the given index, or:
|
* @return The value at the given index, or:
|
||||||
* - INDEX_OUT_OF_BOUNDS if the array index is larger than an array length
|
* - INDEX_OUT_OF_BOUNDS if the array index is larger than an array length
|
||||||
|
|||||||
@@ -24,6 +24,10 @@ inline simdjson_result<const char *> document::current_location() noexcept {
|
|||||||
return iter.current_location();
|
return iter.current_location();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline int32_t document::current_depth() const noexcept {
|
||||||
|
return iter.depth();
|
||||||
|
}
|
||||||
|
|
||||||
inline bool document::is_alive() noexcept {
|
inline bool document::is_alive() noexcept {
|
||||||
return iter.is_alive();
|
return iter.is_alive();
|
||||||
}
|
}
|
||||||
@@ -471,6 +475,11 @@ simdjson_really_inline simdjson_result<const char *> simdjson_result<SIMDJSON_IM
|
|||||||
return first.current_location();
|
return first.current_location();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
simdjson_really_inline int32_t simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document>::current_depth() const noexcept {
|
||||||
|
if (error()) { return error(); }
|
||||||
|
return first.current_depth();
|
||||||
|
}
|
||||||
|
|
||||||
simdjson_really_inline simdjson_result<std::string_view> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document>::raw_json_token() noexcept {
|
simdjson_really_inline simdjson_result<std::string_view> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document>::raw_json_token() noexcept {
|
||||||
if (error()) { return error(); }
|
if (error()) { return error(); }
|
||||||
return first.raw_json_token();
|
return first.raw_json_token();
|
||||||
@@ -527,7 +536,8 @@ simdjson_really_inline simdjson_result<value> document_reference::find_field_uno
|
|||||||
simdjson_really_inline simdjson_result<value> document_reference::find_field_unordered(const char *key) & noexcept { return doc->find_field_unordered(key); }
|
simdjson_really_inline simdjson_result<value> document_reference::find_field_unordered(const char *key) & noexcept { return doc->find_field_unordered(key); }
|
||||||
simdjson_really_inline simdjson_result<json_type> document_reference::type() noexcept { return doc->type(); }
|
simdjson_really_inline simdjson_result<json_type> document_reference::type() noexcept { return doc->type(); }
|
||||||
simdjson_really_inline simdjson_result<bool> document_reference::is_scalar() noexcept { return doc->is_scalar(); }
|
simdjson_really_inline simdjson_result<bool> document_reference::is_scalar() noexcept { return doc->is_scalar(); }
|
||||||
simdjson_really_inline simdjson_result<const char *> document_reference::current_location() noexcept { return doc->current_location(); };
|
simdjson_really_inline simdjson_result<const char *> document_reference::current_location() noexcept { return doc->current_location(); }
|
||||||
|
simdjson_really_inline int32_t document_reference::current_depth() const noexcept { return doc->current_depth(); }
|
||||||
simdjson_really_inline bool document_reference::is_negative() noexcept { return doc->is_negative(); }
|
simdjson_really_inline bool document_reference::is_negative() noexcept { return doc->is_negative(); }
|
||||||
simdjson_really_inline simdjson_result<bool> document_reference::is_integer() noexcept { return doc->is_integer(); }
|
simdjson_really_inline simdjson_result<bool> document_reference::is_integer() noexcept { return doc->is_integer(); }
|
||||||
simdjson_really_inline simdjson_result<number_type> document_reference::get_number_type() noexcept { return doc->get_number_type(); }
|
simdjson_really_inline simdjson_result<number_type> document_reference::get_number_type() noexcept { return doc->get_number_type(); }
|
||||||
@@ -715,4 +725,4 @@ simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
} // namespace simdjson
|
} // namespace simdjson
|
||||||
|
|||||||
@@ -94,6 +94,8 @@ public:
|
|||||||
*
|
*
|
||||||
* The string is guaranteed to be valid UTF-8.
|
* The string is guaranteed to be valid UTF-8.
|
||||||
*
|
*
|
||||||
|
* Important: Calling get_string() twice on the same document is an error.
|
||||||
|
*
|
||||||
* @returns An UTF-8 string. The string is stored in the parser and will be invalidated the next
|
* @returns An UTF-8 string. The string is stored in the parser and will be invalidated the next
|
||||||
* time it parses a document or when it is destroyed.
|
* time it parses a document or when it is destroyed.
|
||||||
* @returns INCORRECT_TYPE if the JSON value is not a string.
|
* @returns INCORRECT_TYPE if the JSON value is not a string.
|
||||||
@@ -267,7 +269,7 @@ public:
|
|||||||
simdjson_really_inline simdjson_result<size_t> count_fields() & noexcept;
|
simdjson_really_inline simdjson_result<size_t> count_fields() & noexcept;
|
||||||
/**
|
/**
|
||||||
* Get the value at the given index in the array. This function has linear-time complexity.
|
* Get the value at the given index in the array. This function has linear-time complexity.
|
||||||
* This function should only be called once as the array iterator is not reset between each call.
|
* This function should only be called once on an array instance since the array iterator is not reset between each call.
|
||||||
*
|
*
|
||||||
* @return The value at the given index, or:
|
* @return The value at the given index, or:
|
||||||
* - INDEX_OUT_OF_BOUNDS if the array index is larger than an array length
|
* - INDEX_OUT_OF_BOUNDS if the array index is larger than an array length
|
||||||
@@ -303,6 +305,18 @@ public:
|
|||||||
* **Raw Keys:** The lookup will be done against the *raw* key, and will not unescape keys.
|
* **Raw Keys:** The lookup will be done against the *raw* key, and will not unescape keys.
|
||||||
* e.g. `object["a"]` will match `{ "a": 1 }`, but will *not* match `{ "\u0061": 1 }`.
|
* e.g. `object["a"]` will match `{ "a": 1 }`, but will *not* match `{ "\u0061": 1 }`.
|
||||||
*
|
*
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
* given by content["bids"].get_array() should not be accessed after you have called
|
||||||
|
* content["asks"].get_array(). You can detect such mistakes by first compiling and running
|
||||||
|
* the code in Debug mode (or with the macro `SIMDJSON_DEVELOPMENT_CHECKS` set to 1): an
|
||||||
|
* OUT_OF_ORDER_ITERATION error is generated.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
* @param key The key to look up.
|
* @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.
|
* @returns The value of the field, or NO_SUCH_FIELD if the field is not in the object.
|
||||||
*/
|
*/
|
||||||
@@ -326,6 +340,17 @@ public:
|
|||||||
* Use find_field() if you are sure fields will be in order (or are willing to treat it as if the
|
* 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 wasn't there when they aren't).
|
||||||
*
|
*
|
||||||
|
* 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
|
||||||
|
* given by content["bids"].get_array() should not be accessed after you have called
|
||||||
|
* content["asks"].get_array(). You can detect such mistakes by first compiling and running
|
||||||
|
* the code in Debug mode (or with the macro `SIMDJSON_DEVELOPMENT_CHECKS` set to 1): an
|
||||||
|
* OUT_OF_ORDER_ITERATION error is generated.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
* @param key The key to look up.
|
* @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.
|
* @returns The value of the field, or NO_SUCH_FIELD if the field is not in the object.
|
||||||
*/
|
*/
|
||||||
@@ -374,7 +399,14 @@ public:
|
|||||||
*/
|
*/
|
||||||
simdjson_really_inline simdjson_result<bool> is_integer() noexcept;
|
simdjson_really_inline simdjson_result<bool> is_integer() noexcept;
|
||||||
/**
|
/**
|
||||||
* Determine the number type (integer or floating-point number).
|
* Determine the number type (integer or floating-point number) as quickly
|
||||||
|
* as possible. This function does not fully validate the input. It is
|
||||||
|
* useful when you only need to classify the numbers, without parsing them.
|
||||||
|
*
|
||||||
|
* If you are planning to retrieve the value or you need full validation,
|
||||||
|
* consider using the get_number() method instead: it will fully parse
|
||||||
|
* and validate the input, and give you access to the type:
|
||||||
|
* get_number().get_number_type().
|
||||||
*
|
*
|
||||||
* get_number_type() is number_type::unsigned_integer if we have
|
* 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
|
||||||
@@ -382,8 +414,7 @@ public:
|
|||||||
* integer that is less than 9223372036854775808
|
* integer that is less than 9223372036854775808
|
||||||
* Otherwise, get_number_type() has value number_type::floating_point_number
|
* Otherwise, get_number_type() has value number_type::floating_point_number
|
||||||
*
|
*
|
||||||
* This function req
|
* This function requires processing the number string, but it is expected
|
||||||
* uires processing the number string, but it is expected
|
|
||||||
* to be faster than get_number().get_number_type() because it is does not
|
* to be faster than get_number().get_number_type() because it is does not
|
||||||
* parse the number value.
|
* parse the number value.
|
||||||
*
|
*
|
||||||
@@ -399,7 +430,7 @@ public:
|
|||||||
* type.
|
* type.
|
||||||
*
|
*
|
||||||
* number.get_number_type() is number_type::signed_integer if we have
|
* number.get_number_type() is number_type::signed_integer if we have
|
||||||
* a integer in [-9223372036854775808,9223372036854775808)
|
* an integer in [-9223372036854775808,9223372036854775808)
|
||||||
* You can recover the value by calling number.get_int64() and you
|
* You can recover the value by calling number.get_int64() and you
|
||||||
* have that number.is_int64() is true.
|
* have that number.is_int64() is true.
|
||||||
*
|
*
|
||||||
@@ -464,6 +495,17 @@ public:
|
|||||||
*/
|
*/
|
||||||
inline simdjson_result<const char *> current_location() noexcept;
|
inline simdjson_result<const char *> current_location() noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the current depth in the document if in bounds.
|
||||||
|
*
|
||||||
|
* E.g.,
|
||||||
|
* 0 = finished with document
|
||||||
|
* 1 = document root value (could be [ or {, not yet known)
|
||||||
|
* 2 = , or } inside root array/object
|
||||||
|
* 3 = key or value inside root array/object.
|
||||||
|
*/
|
||||||
|
simdjson_really_inline int32_t current_depth() const noexcept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value associated with the given JSON pointer. We use the RFC 6901
|
* Get the value associated with the given JSON pointer. We use the RFC 6901
|
||||||
* https://tools.ietf.org/html/rfc6901 standard.
|
* https://tools.ietf.org/html/rfc6901 standard.
|
||||||
@@ -498,7 +540,7 @@ public:
|
|||||||
simdjson_really_inline simdjson_result<value> at_pointer(std::string_view json_pointer) noexcept;
|
simdjson_really_inline simdjson_result<value> at_pointer(std::string_view json_pointer) noexcept;
|
||||||
/**
|
/**
|
||||||
* Consumes the document and returns a string_view instance corresponding to the
|
* Consumes the document and returns a string_view instance corresponding to the
|
||||||
* document as represented in JSON. It points inside the original byte array containg
|
* document as represented in JSON. It points inside the original byte array containing
|
||||||
* the JSON document.
|
* the JSON document.
|
||||||
*/
|
*/
|
||||||
simdjson_really_inline simdjson_result<std::string_view> raw_json() noexcept;
|
simdjson_really_inline simdjson_result<std::string_view> raw_json() noexcept;
|
||||||
@@ -541,6 +583,7 @@ public:
|
|||||||
simdjson_really_inline document_reference() noexcept;
|
simdjson_really_inline document_reference() noexcept;
|
||||||
simdjson_really_inline document_reference(document &d) noexcept;
|
simdjson_really_inline document_reference(document &d) noexcept;
|
||||||
simdjson_really_inline document_reference(const document_reference &other) noexcept = default;
|
simdjson_really_inline document_reference(const document_reference &other) noexcept = default;
|
||||||
|
simdjson_really_inline document_reference& operator=(const document_reference &other) noexcept = default;
|
||||||
simdjson_really_inline void rewind() noexcept;
|
simdjson_really_inline void rewind() noexcept;
|
||||||
simdjson_really_inline simdjson_result<array> get_array() & noexcept;
|
simdjson_really_inline simdjson_result<array> get_array() & noexcept;
|
||||||
simdjson_really_inline simdjson_result<object> get_object() & noexcept;
|
simdjson_really_inline simdjson_result<object> get_object() & noexcept;
|
||||||
@@ -583,6 +626,7 @@ public:
|
|||||||
simdjson_really_inline simdjson_result<bool> is_scalar() noexcept;
|
simdjson_really_inline simdjson_result<bool> is_scalar() noexcept;
|
||||||
|
|
||||||
simdjson_really_inline simdjson_result<const char *> current_location() noexcept;
|
simdjson_really_inline simdjson_result<const char *> current_location() noexcept;
|
||||||
|
simdjson_really_inline int32_t current_depth() const noexcept;
|
||||||
simdjson_really_inline bool is_negative() noexcept;
|
simdjson_really_inline bool is_negative() noexcept;
|
||||||
simdjson_really_inline simdjson_result<bool> is_integer() noexcept;
|
simdjson_really_inline simdjson_result<bool> is_integer() noexcept;
|
||||||
simdjson_really_inline simdjson_result<number_type> get_number_type() noexcept;
|
simdjson_really_inline simdjson_result<number_type> get_number_type() noexcept;
|
||||||
@@ -649,6 +693,7 @@ public:
|
|||||||
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::json_type> type() noexcept;
|
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::json_type> type() noexcept;
|
||||||
simdjson_really_inline simdjson_result<bool> is_scalar() noexcept;
|
simdjson_really_inline simdjson_result<bool> is_scalar() noexcept;
|
||||||
simdjson_really_inline simdjson_result<const char *> current_location() noexcept;
|
simdjson_really_inline simdjson_result<const char *> current_location() noexcept;
|
||||||
|
simdjson_really_inline int32_t current_depth() const noexcept;
|
||||||
simdjson_really_inline bool is_negative() noexcept;
|
simdjson_really_inline bool is_negative() noexcept;
|
||||||
simdjson_really_inline simdjson_result<bool> is_integer() noexcept;
|
simdjson_really_inline simdjson_result<bool> is_integer() noexcept;
|
||||||
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::number_type> get_number_type() noexcept;
|
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::number_type> get_number_type() noexcept;
|
||||||
@@ -709,6 +754,7 @@ public:
|
|||||||
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::json_type> type() noexcept;
|
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::json_type> type() noexcept;
|
||||||
simdjson_really_inline simdjson_result<bool> is_scalar() noexcept;
|
simdjson_really_inline simdjson_result<bool> is_scalar() noexcept;
|
||||||
simdjson_really_inline simdjson_result<const char *> current_location() noexcept;
|
simdjson_really_inline simdjson_result<const char *> current_location() noexcept;
|
||||||
|
simdjson_really_inline int32_t current_depth() const noexcept;
|
||||||
simdjson_really_inline bool is_negative() noexcept;
|
simdjson_really_inline bool is_negative() noexcept;
|
||||||
simdjson_really_inline simdjson_result<bool> is_integer() noexcept;
|
simdjson_really_inline simdjson_result<bool> is_integer() noexcept;
|
||||||
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::number_type> get_number_type() noexcept;
|
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::number_type> get_number_type() noexcept;
|
||||||
|
|||||||
@@ -47,23 +47,33 @@ inline void json_iterator::rewind() noexcept {
|
|||||||
_depth = 1;
|
_depth = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline bool json_iterator::balanced() const noexcept {
|
||||||
|
token_iterator ti(token);
|
||||||
|
int32_t count{0};
|
||||||
|
ti.set_position( root_position() );
|
||||||
|
while(ti.peek() <= peek_last()) {
|
||||||
|
switch (*ti.return_current_and_advance())
|
||||||
|
{
|
||||||
|
case '[': case '{':
|
||||||
|
count++;
|
||||||
|
break;
|
||||||
|
case ']': case '}':
|
||||||
|
count--;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return count == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// GCC 7 warns when the first line of this function is inlined away into oblivion due to the caller
|
// GCC 7 warns when the first line of this function is inlined away into oblivion due to the caller
|
||||||
// relating depth and parent_depth, which is a desired effect. The warning does not show up if the
|
// relating depth and parent_depth, which is a desired effect. The warning does not show up if the
|
||||||
// skip_child() function is not marked inline).
|
// skip_child() function is not marked inline).
|
||||||
SIMDJSON_PUSH_DISABLE_WARNINGS
|
SIMDJSON_PUSH_DISABLE_WARNINGS
|
||||||
SIMDJSON_DISABLE_STRICT_OVERFLOW_WARNING
|
SIMDJSON_DISABLE_STRICT_OVERFLOW_WARNING
|
||||||
simdjson_warn_unused simdjson_really_inline error_code json_iterator::skip_child(depth_t parent_depth) noexcept {
|
simdjson_warn_unused simdjson_really_inline error_code json_iterator::skip_child(depth_t parent_depth) noexcept {
|
||||||
/***
|
|
||||||
* WARNING:
|
|
||||||
* Inside an object, a string value is a depth of +1 compared to the object. Yet a key
|
|
||||||
* is at the same depth as the object.
|
|
||||||
* But json_iterator cannot easily tell whether we are pointing at a key or a string value.
|
|
||||||
* Instead, it assumes that if you are pointing at a string, then it is a value, not a key.
|
|
||||||
* To be clear...
|
|
||||||
* the following code assumes that we are *not* pointing at a key. If we are then a bug
|
|
||||||
* will follow. Unfortunately, it is not possible for the json_iterator its to make this
|
|
||||||
* check.
|
|
||||||
*/
|
|
||||||
if (depth() <= parent_depth) { return SUCCESS; }
|
if (depth() <= parent_depth) { return SUCCESS; }
|
||||||
switch (*return_current_and_advance()) {
|
switch (*return_current_and_advance()) {
|
||||||
// TODO consider whether matching braces is a requirement: if non-matching braces indicates
|
// TODO consider whether matching braces is a requirement: if non-matching braces indicates
|
||||||
@@ -91,19 +101,18 @@ simdjson_warn_unused simdjson_really_inline error_code json_iterator::skip_child
|
|||||||
if (at_end()) { return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "Missing [ or { at start"); }
|
if (at_end()) { return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "Missing [ or { at start"); }
|
||||||
#endif // SIMDJSON_CHECK_EOF
|
#endif // SIMDJSON_CHECK_EOF
|
||||||
break;
|
break;
|
||||||
/*case '"':
|
case '"':
|
||||||
if(*peek() == ':') {
|
if(*peek() == ':') {
|
||||||
// we are at a key!!! This is
|
// We are at a key!!!
|
||||||
// only possible if someone searched
|
// This might happen if you just started an object and you skip it immediately.
|
||||||
// for a key in an object and the key
|
// Performance note: it would be nice to get rid of this check as it is somewhat
|
||||||
// was not found but our code then
|
// expensive.
|
||||||
// decided the consume the separating
|
// https://github.com/simdjson/simdjson/issues/1742
|
||||||
// comma before returning.
|
|
||||||
logger::log_value(*this, "key");
|
logger::log_value(*this, "key");
|
||||||
advance(); // eat up the ':'
|
return_current_and_advance(); // eat up the ':'
|
||||||
break; // important!!!
|
break; // important!!!
|
||||||
}
|
}
|
||||||
simdjson_fallthrough;*/
|
simdjson_fallthrough;
|
||||||
// Anything else must be a scalar value
|
// Anything else must be a scalar value
|
||||||
default:
|
default:
|
||||||
// For the first scalar, we will have incremented depth already, so we decrement it here.
|
// For the first scalar, we will have incremented depth already, so we decrement it here.
|
||||||
|
|||||||
@@ -154,7 +154,7 @@ public:
|
|||||||
* This is not null-terminated; it is a view into the JSON.
|
* This is not null-terminated; it is a view into the JSON.
|
||||||
*
|
*
|
||||||
* You may be pointing outside of the input buffer: it is not generally
|
* You may be pointing outside of the input buffer: it is not generally
|
||||||
* safe to derefence this pointer.
|
* safe to dereference this pointer.
|
||||||
*/
|
*/
|
||||||
simdjson_really_inline const uint8_t *unsafe_pointer() const noexcept;
|
simdjson_really_inline const uint8_t *unsafe_pointer() const noexcept;
|
||||||
/**
|
/**
|
||||||
@@ -251,6 +251,13 @@ public:
|
|||||||
* as if it had just been created.
|
* as if it had just been created.
|
||||||
*/
|
*/
|
||||||
inline void rewind() noexcept;
|
inline void rewind() noexcept;
|
||||||
|
/**
|
||||||
|
* This checks whether the {,},[,] are balanced so that the document
|
||||||
|
* ends with proper zero depth. This requires scanning the whole document
|
||||||
|
* and it may be expensive. It is expected that it will be rarely called.
|
||||||
|
* It does not attempt to match { with } and [ with ].
|
||||||
|
*/
|
||||||
|
inline bool balanced() const noexcept;
|
||||||
protected:
|
protected:
|
||||||
simdjson_really_inline json_iterator(const uint8_t *buf, ondemand::parser *parser) noexcept;
|
simdjson_really_inline json_iterator(const uint8_t *buf, ondemand::parser *parser) noexcept;
|
||||||
/// The last token before the end
|
/// The last token before the end
|
||||||
|
|||||||
@@ -111,7 +111,6 @@ protected:
|
|||||||
uint64_t unsigned_integer;
|
uint64_t unsigned_integer;
|
||||||
} payload{0};
|
} payload{0};
|
||||||
number_type type{number_type::signed_integer};
|
number_type type{number_type::signed_integer};
|
||||||
friend class value_iterator;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -85,7 +85,7 @@ inline void log_headers() noexcept {
|
|||||||
printf("# skip says 'this is a structural or value I am skipping'\n");
|
printf("# skip says 'this is a structural or value I am skipping'\n");
|
||||||
printf("# +/-skip says 'this is a start/end array or object I am skipping'\n");
|
printf("# +/-skip says 'this is a start/end array or object I am skipping'\n");
|
||||||
printf("#\n");
|
printf("#\n");
|
||||||
printf("# The identation of the terms (array, string,...) indicates the depth,\n");
|
printf("# The indentation of the terms (array, string,...) indicates the depth,\n");
|
||||||
printf("# in addition to the depth being displayed.\n");
|
printf("# in addition to the depth being displayed.\n");
|
||||||
printf("#\n");
|
printf("#\n");
|
||||||
printf("# Every token in the document has a single depth determined by the tokens before it,\n");
|
printf("# Every token in the document has a single depth determined by the tokens before it,\n");
|
||||||
|
|||||||
@@ -37,6 +37,17 @@ public:
|
|||||||
* **Raw Keys:** The lookup will be done against the *raw* key, and will not unescape keys.
|
* **Raw Keys:** The lookup will be done against the *raw* key, and will not unescape keys.
|
||||||
* e.g. `object["a"]` will match `{ "a": 1 }`, but will *not* match `{ "\u0061": 1 }`.
|
* e.g. `object["a"]` will match `{ "a": 1 }`, but will *not* match `{ "\u0061": 1 }`.
|
||||||
*
|
*
|
||||||
|
* 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
|
||||||
|
* given by content["bids"].get_array() should not be accessed after you have called
|
||||||
|
* content["asks"].get_array(). You can detect such mistakes by first compiling and running
|
||||||
|
* the code in Debug mode (or with the macro `SIMDJSON_DEVELOPMENT_CHECKS` set to 1): an
|
||||||
|
* OUT_OF_ORDER_ITERATION error is generated.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
* @param key The key to look up.
|
* @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.
|
* @returns The value of the field, or NO_SUCH_FIELD if the field is not in the object.
|
||||||
*/
|
*/
|
||||||
@@ -63,6 +74,16 @@ public:
|
|||||||
* If you have multiple fields with a matching key ({"x": 1, "x": 1}) be mindful
|
* If you have multiple fields with a matching key ({"x": 1, "x": 1}) be mindful
|
||||||
* that only one field is returned.
|
* that only one field is returned.
|
||||||
*
|
*
|
||||||
|
* 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
|
||||||
|
* given by content["bids"].get_array() should not be accessed after you have called
|
||||||
|
* content["asks"].get_array(). You can detect such mistakes by first compiling and running
|
||||||
|
* the code in Debug mode (or with the macro `SIMDJSON_DEVELOPMENT_CHECKS` set to 1): an
|
||||||
|
* OUT_OF_ORDER_ITERATION error is generated.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
* @param key The key to look up.
|
* @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.
|
* @returns The value of the field, or NO_SUCH_FIELD if the field is not in the object.
|
||||||
*/
|
*/
|
||||||
@@ -97,7 +118,7 @@ public:
|
|||||||
* instance: there is no rewind and no invalidation.
|
* instance: there is no rewind and no invalidation.
|
||||||
*
|
*
|
||||||
* You may call at_pointer more than once on an object, but each time the pointer is advanced
|
* You may call at_pointer more than once on an object, but each time the pointer is advanced
|
||||||
* to be within the value matched by the key indicated by the JSON pointer query. Thus any preceeding
|
* to be within the value matched by the key indicated by the JSON pointer query. Thus any preceding
|
||||||
* key (as well as the current key) can no longer be used with following JSON pointer calls.
|
* key (as well as the current key) can no longer be used with following JSON pointer calls.
|
||||||
*
|
*
|
||||||
* Also note that at_pointer() relies on find_field() which implies that we do not unescape keys when matching.
|
* Also note that at_pointer() relies on find_field() which implies that we do not unescape keys when matching.
|
||||||
@@ -147,7 +168,7 @@ public:
|
|||||||
simdjson_really_inline simdjson_result<size_t> count_fields() & noexcept;
|
simdjson_really_inline simdjson_result<size_t> count_fields() & noexcept;
|
||||||
/**
|
/**
|
||||||
* Consumes the object and returns a string_view instance corresponding to the
|
* Consumes the object and returns a string_view instance corresponding to the
|
||||||
* object as represented in JSON. It points inside the original byte array containg
|
* object as represented in JSON. It points inside the original byte array containing
|
||||||
* the JSON document.
|
* the JSON document.
|
||||||
*/
|
*/
|
||||||
simdjson_really_inline simdjson_result<std::string_view> raw_json() noexcept;
|
simdjson_really_inline simdjson_result<std::string_view> raw_json() noexcept;
|
||||||
|
|||||||
@@ -26,6 +26,8 @@ simdjson_really_inline bool object_iterator::operator!=(const object_iterator &)
|
|||||||
return iter.is_open();
|
return iter.is_open();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SIMDJSON_PUSH_DISABLE_WARNINGS
|
||||||
|
SIMDJSON_DISABLE_STRICT_OVERFLOW_WARNING
|
||||||
simdjson_really_inline object_iterator &object_iterator::operator++() noexcept {
|
simdjson_really_inline object_iterator &object_iterator::operator++() noexcept {
|
||||||
// TODO this is a safety rail ... users should exit loops as soon as they receive an error.
|
// TODO this is a safety rail ... users should exit loops as soon as they receive an error.
|
||||||
// Nonetheless, let's see if performance is OK with this if statement--the compiler may give it to us for free.
|
// Nonetheless, let's see if performance is OK with this if statement--the compiler may give it to us for free.
|
||||||
@@ -38,6 +40,7 @@ simdjson_really_inline object_iterator &object_iterator::operator++() noexcept {
|
|||||||
if ((error = iter.has_next_field().get(has_value) )) { return *this; };
|
if ((error = iter.has_next_field().get(has_value) )) { return *this; };
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
SIMDJSON_POP_DISABLE_WARNINGS
|
||||||
|
|
||||||
//
|
//
|
||||||
// ### Live States
|
// ### Live States
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ simdjson_warn_unused simdjson_really_inline error_code parser::allocate(size_t n
|
|||||||
SIMDJSON_TRY( implementation->set_capacity(new_capacity) );
|
SIMDJSON_TRY( implementation->set_capacity(new_capacity) );
|
||||||
SIMDJSON_TRY( implementation->set_max_depth(new_max_depth) );
|
SIMDJSON_TRY( implementation->set_max_depth(new_max_depth) );
|
||||||
} else {
|
} else {
|
||||||
SIMDJSON_TRY( simdjson::active_implementation->create_dom_parser_implementation(new_capacity, new_max_depth, implementation) );
|
SIMDJSON_TRY( simdjson::get_active_implementation()->create_dom_parser_implementation(new_capacity, new_max_depth, implementation) );
|
||||||
}
|
}
|
||||||
_capacity = new_capacity;
|
_capacity = new_capacity;
|
||||||
_max_depth = new_max_depth;
|
_max_depth = new_max_depth;
|
||||||
|
|||||||
@@ -54,6 +54,11 @@ public:
|
|||||||
* ondemand::parser parser;
|
* ondemand::parser parser;
|
||||||
* document doc = parser.iterate(json);
|
* document doc = parser.iterate(json);
|
||||||
*
|
*
|
||||||
|
* It is expected that the content is a valid UTF-8 file, containing a valid JSON document.
|
||||||
|
* Otherwise the iterate method may return an error. In particular, the whole input should be
|
||||||
|
* valid: we do not attempt to tolerate incorrect content either before or after a JSON
|
||||||
|
* document.
|
||||||
|
*
|
||||||
* ### IMPORTANT: Validate what you use
|
* ### IMPORTANT: Validate what you use
|
||||||
*
|
*
|
||||||
* Calling iterate on an invalid JSON document may not immediately trigger an error. The call to
|
* Calling iterate on an invalid JSON document may not immediately trigger an error. The call to
|
||||||
@@ -166,16 +171,18 @@ public:
|
|||||||
* ### Format
|
* ### Format
|
||||||
*
|
*
|
||||||
* The buffer must contain a series of one or more JSON documents, concatenated into a single
|
* The buffer must contain a series of one or more JSON documents, concatenated into a single
|
||||||
* buffer, separated by whitespace. It effectively parses until it has a fully valid document,
|
* buffer, separated by ASCII whitespace. It effectively parses until it has a fully valid document,
|
||||||
* then starts parsing the next document at that point. (It does this with more parallelism and
|
* then starts parsing the next document at that point. (It does this with more parallelism and
|
||||||
* lookahead than you might think, though.)
|
* lookahead than you might think, though.)
|
||||||
*
|
*
|
||||||
* documents that consist of an object or array may omit the whitespace between them, concatenating
|
* documents that consist of an object or array may omit the whitespace between them, concatenating
|
||||||
* with no separator. documents that consist of a single primitive (i.e. documents that are not
|
* with no separator. Documents that consist of a single primitive (i.e. documents that are not
|
||||||
* arrays or objects) MUST be separated with whitespace.
|
* arrays or objects) MUST be separated with ASCII whitespace.
|
||||||
|
*
|
||||||
|
* The characters inside a JSON document, and between JSON documents, must be valid Unicode (UTF-8).
|
||||||
*
|
*
|
||||||
* The documents must not exceed batch_size bytes (by default 1MB) or they will fail to parse.
|
* The documents must not exceed batch_size bytes (by default 1MB) or they will fail to parse.
|
||||||
* Setting batch_size to excessively large or excesively small values may impact negatively the
|
* Setting batch_size to excessively large or excessively small values may impact negatively the
|
||||||
* performance.
|
* performance.
|
||||||
*
|
*
|
||||||
* ### REQUIRED: Buffer Padding
|
* ### REQUIRED: Buffer Padding
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ simdjson_really_inline raw_json_string::raw_json_string(const uint8_t * _buf) no
|
|||||||
|
|
||||||
simdjson_really_inline const char * raw_json_string::raw() const noexcept { return reinterpret_cast<const char *>(buf); }
|
simdjson_really_inline const char * raw_json_string::raw() const noexcept { return reinterpret_cast<const char *>(buf); }
|
||||||
simdjson_really_inline simdjson_warn_unused simdjson_result<std::string_view> raw_json_string::unescape(uint8_t *&dst) const noexcept {
|
simdjson_really_inline simdjson_warn_unused simdjson_result<std::string_view> raw_json_string::unescape(uint8_t *&dst) const noexcept {
|
||||||
uint8_t *end = stringparsing::parse_string(buf, dst);
|
uint8_t *end = parse_string(buf, dst);
|
||||||
if (!end) { return STRING_ERROR; }
|
if (!end) { return STRING_ERROR; }
|
||||||
std::string_view result(reinterpret_cast<const char *>(dst), end-dst);
|
std::string_view result(reinterpret_cast<const char *>(dst), end-dst);
|
||||||
dst = end;
|
dst = end;
|
||||||
|
|||||||
@@ -116,6 +116,26 @@ public:
|
|||||||
static simdjson_really_inline bool is_free_from_unescaped_quote(std::string_view target) noexcept;
|
static simdjson_really_inline bool is_free_from_unescaped_quote(std::string_view target) noexcept;
|
||||||
static simdjson_really_inline bool is_free_from_unescaped_quote(const char* target) noexcept;
|
static simdjson_really_inline bool is_free_from_unescaped_quote(const char* target) noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unescape this JSON string, replacing \\ with \, \n with newline, etc. to a user-provided buffer.
|
||||||
|
* The provided pointer is advanced to the end of the string by reference, and a string_view instance
|
||||||
|
* is returned. You can ensure that your buffer is large enough by allocating a block of memory at least
|
||||||
|
* as large as the input JSON plus SIMDJSON_PADDING and then unescape all strings to this one buffer.
|
||||||
|
*
|
||||||
|
* This unescape function is a low-level function. If you want a more user-friendly approach, you should
|
||||||
|
* avoid raw_json_string instances (e.g., by calling unescaped_key() instead of key() or get_string()
|
||||||
|
* instead of get_raw_json_string()).
|
||||||
|
*
|
||||||
|
* ## IMPORTANT: string_view lifetime
|
||||||
|
*
|
||||||
|
* The string_view is only valid as long as the bytes in dst.
|
||||||
|
*
|
||||||
|
* @param dst A pointer to a buffer at least large enough to write this string as well as
|
||||||
|
* an additional SIMDJSON_PADDING bytes.
|
||||||
|
* @return A string_view pointing at the unescaped string in dst
|
||||||
|
* @error STRING_ERROR if escapes are incorrect.
|
||||||
|
*/
|
||||||
|
simdjson_really_inline simdjson_result<std::string_view> unescape(uint8_t *&dst) const noexcept;
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
|
||||||
@@ -130,20 +150,6 @@ private:
|
|||||||
*/
|
*/
|
||||||
simdjson_really_inline simdjson_warn_unused bool alive() const noexcept { return buf != nullptr; }
|
simdjson_really_inline simdjson_warn_unused bool alive() const noexcept { return buf != nullptr; }
|
||||||
|
|
||||||
/**
|
|
||||||
* Unescape this JSON string, replacing \\ with \, \n with newline, etc.
|
|
||||||
*
|
|
||||||
* ## IMPORTANT: string_view lifetime
|
|
||||||
*
|
|
||||||
* The string_view is only valid as long as the bytes in dst.
|
|
||||||
*
|
|
||||||
* @param dst A pointer to a buffer at least large enough to write this string as well as a \0.
|
|
||||||
* dst will be updated to the next unused location (just after the \0 written out at
|
|
||||||
* the end of this string).
|
|
||||||
* @return A string_view pointing at the unescaped string in dst
|
|
||||||
* @error STRING_ERROR if escapes are incorrect.
|
|
||||||
*/
|
|
||||||
simdjson_really_inline simdjson_warn_unused simdjson_result<std::string_view> unescape(uint8_t *&dst) const noexcept;
|
|
||||||
/**
|
/**
|
||||||
* Unescape this JSON string, replacing \\ with \, \n with newline, etc.
|
* Unescape this JSON string, replacing \\ with \, \n with newline, etc.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -99,6 +99,7 @@ inline simdjson_result<std::string_view> to_json_string(simdjson_result<SIMDJSON
|
|||||||
}
|
}
|
||||||
} // namespace simdjson
|
} // namespace simdjson
|
||||||
|
|
||||||
|
namespace simdjson { namespace SIMDJSON_IMPLEMENTATION { namespace ondemand {
|
||||||
|
|
||||||
#if SIMDJSON_EXCEPTIONS
|
#if SIMDJSON_EXCEPTIONS
|
||||||
inline std::ostream& operator<<(std::ostream& out, simdjson::SIMDJSON_IMPLEMENTATION::ondemand::value x) {
|
inline std::ostream& operator<<(std::ostream& out, simdjson::SIMDJSON_IMPLEMENTATION::ondemand::value x) {
|
||||||
@@ -216,3 +217,4 @@ inline std::ostream& operator<<(std::ostream& out, simdjson::SIMDJSON_IMPLEMENTA
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
}}} // namespace simdjson::SIMDJSON_IMPLEMENTATION::ondemand
|
||||||
@@ -29,6 +29,14 @@ inline simdjson_result<std::string_view> to_json_string(simdjson_result<SIMDJSON
|
|||||||
inline simdjson_result<std::string_view> to_json_string(simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array> x);
|
inline simdjson_result<std::string_view> to_json_string(simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array> x);
|
||||||
} // namespace simdjson
|
} // namespace simdjson
|
||||||
|
|
||||||
|
/**
|
||||||
|
* We want to support argument-dependent lookup (ADL).
|
||||||
|
* Hence we should define operator<< in the namespace
|
||||||
|
* where the argument (here value, object, etc.) resides.
|
||||||
|
* Credit: @madhur4127
|
||||||
|
* See https://github.com/simdjson/simdjson/issues/1768
|
||||||
|
*/
|
||||||
|
namespace simdjson { namespace SIMDJSON_IMPLEMENTATION { namespace ondemand {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Print JSON to an output stream.
|
* Print JSON to an output stream.
|
||||||
@@ -78,3 +86,4 @@ inline std::ostream& operator<<(std::ostream& out, simdjson::SIMDJSON_IMPLEMENTA
|
|||||||
#if SIMDJSON_EXCEPTIONS
|
#if SIMDJSON_EXCEPTIONS
|
||||||
inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::SIMDJSON_IMPLEMENTATION::ondemand::object> x);
|
inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::SIMDJSON_IMPLEMENTATION::ondemand::object> x);
|
||||||
#endif
|
#endif
|
||||||
|
}}} // namespace simdjson::SIMDJSON_IMPLEMENTATION::ondemand
|
||||||
@@ -62,6 +62,7 @@ template<> simdjson_really_inline simdjson_result<array> value::get() noexcept {
|
|||||||
template<> simdjson_really_inline simdjson_result<object> value::get() noexcept { return get_object(); }
|
template<> simdjson_really_inline simdjson_result<object> value::get() noexcept { return get_object(); }
|
||||||
template<> simdjson_really_inline simdjson_result<raw_json_string> value::get() noexcept { return get_raw_json_string(); }
|
template<> simdjson_really_inline simdjson_result<raw_json_string> value::get() noexcept { return get_raw_json_string(); }
|
||||||
template<> simdjson_really_inline simdjson_result<std::string_view> value::get() noexcept { return get_string(); }
|
template<> simdjson_really_inline simdjson_result<std::string_view> value::get() noexcept { return get_string(); }
|
||||||
|
template<> simdjson_really_inline simdjson_result<number> value::get() noexcept { return get_number(); }
|
||||||
template<> simdjson_really_inline simdjson_result<double> value::get() noexcept { return get_double(); }
|
template<> simdjson_really_inline simdjson_result<double> value::get() noexcept { return get_double(); }
|
||||||
template<> simdjson_really_inline simdjson_result<uint64_t> value::get() noexcept { return get_uint64(); }
|
template<> simdjson_really_inline simdjson_result<uint64_t> value::get() noexcept { return get_uint64(); }
|
||||||
template<> simdjson_really_inline simdjson_result<int64_t> value::get() noexcept { return get_int64(); }
|
template<> simdjson_really_inline simdjson_result<int64_t> value::get() noexcept { return get_int64(); }
|
||||||
@@ -114,6 +115,13 @@ simdjson_really_inline simdjson_result<size_t> value::count_elements() & noexcep
|
|||||||
iter.move_at_start();
|
iter.move_at_start();
|
||||||
return answer;
|
return answer;
|
||||||
}
|
}
|
||||||
|
simdjson_really_inline simdjson_result<size_t> value::count_fields() & noexcept {
|
||||||
|
simdjson_result<size_t> answer;
|
||||||
|
auto a = get_object();
|
||||||
|
answer = a.count_fields();
|
||||||
|
iter.move_at_start();
|
||||||
|
return answer;
|
||||||
|
}
|
||||||
simdjson_really_inline simdjson_result<value> value::at(size_t index) noexcept {
|
simdjson_really_inline simdjson_result<value> value::at(size_t index) noexcept {
|
||||||
auto a = get_array();
|
auto a = get_array();
|
||||||
return a.at(index);
|
return a.at(index);
|
||||||
@@ -169,6 +177,14 @@ simdjson_really_inline std::string_view value::raw_json_token() noexcept {
|
|||||||
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_start_length());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
simdjson_really_inline simdjson_result<const char *> value::current_location() noexcept {
|
||||||
|
return iter.json_iter().current_location();
|
||||||
|
}
|
||||||
|
|
||||||
|
simdjson_really_inline int32_t value::current_depth() const noexcept{
|
||||||
|
return iter.json_iter().depth();
|
||||||
|
}
|
||||||
|
|
||||||
simdjson_really_inline simdjson_result<value> value::at_pointer(std::string_view json_pointer) noexcept {
|
simdjson_really_inline simdjson_result<value> value::at_pointer(std::string_view json_pointer) noexcept {
|
||||||
json_type t;
|
json_type t;
|
||||||
SIMDJSON_TRY(type().get(t));
|
SIMDJSON_TRY(type().get(t));
|
||||||
@@ -207,6 +223,10 @@ simdjson_really_inline simdjson_result<size_t> simdjson_result<SIMDJSON_IMPLEMEN
|
|||||||
if (error()) { return error(); }
|
if (error()) { return error(); }
|
||||||
return first.count_elements();
|
return first.count_elements();
|
||||||
}
|
}
|
||||||
|
simdjson_really_inline simdjson_result<size_t> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>::count_fields() & noexcept {
|
||||||
|
if (error()) { return error(); }
|
||||||
|
return first.count_fields();
|
||||||
|
}
|
||||||
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>::at(size_t index) noexcept {
|
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>::at(size_t index) noexcept {
|
||||||
if (error()) { return error(); }
|
if (error()) { return error(); }
|
||||||
return first.at(index);
|
return first.at(index);
|
||||||
@@ -379,6 +399,16 @@ simdjson_really_inline simdjson_result<std::string_view> simdjson_result<SIMDJSO
|
|||||||
return first.raw_json_token();
|
return first.raw_json_token();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
simdjson_really_inline simdjson_result<const char *> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>::current_location() noexcept {
|
||||||
|
if (error()) { return error(); }
|
||||||
|
return first.current_location();
|
||||||
|
}
|
||||||
|
|
||||||
|
simdjson_really_inline int32_t simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>::current_depth() const noexcept {
|
||||||
|
if (error()) { return error(); }
|
||||||
|
return first.current_depth();
|
||||||
|
}
|
||||||
|
|
||||||
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>::at_pointer(std::string_view json_pointer) noexcept {
|
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>::at_pointer(std::string_view json_pointer) noexcept {
|
||||||
if (error()) { return error(); }
|
if (error()) { return error(); }
|
||||||
return first.at_pointer(json_pointer);
|
return first.at_pointer(json_pointer);
|
||||||
|
|||||||
@@ -121,6 +121,9 @@ public:
|
|||||||
*
|
*
|
||||||
* Equivalent to get<std::string_view>().
|
* Equivalent to get<std::string_view>().
|
||||||
*
|
*
|
||||||
|
* Important: a value should be consumed once. Calling get_string() twice on the same value
|
||||||
|
* is an error.
|
||||||
|
*
|
||||||
* @returns An UTF-8 string. The string is stored in the parser and will be invalidated the next
|
* @returns An UTF-8 string. The string is stored in the parser and will be invalidated the next
|
||||||
* time it parses a document or when it is destroyed.
|
* time it parses a document or when it is destroyed.
|
||||||
* @returns INCORRECT_TYPE if the JSON value is not a string.
|
* @returns INCORRECT_TYPE if the JSON value is not a string.
|
||||||
@@ -244,9 +247,24 @@ public:
|
|||||||
* safe to continue.
|
* safe to continue.
|
||||||
*/
|
*/
|
||||||
simdjson_really_inline simdjson_result<size_t> count_elements() & noexcept;
|
simdjson_really_inline simdjson_result<size_t> count_elements() & noexcept;
|
||||||
|
/**
|
||||||
|
* This method scans the object and counts the number of key-value pairs.
|
||||||
|
* The count_fields method should always be called before you have begun
|
||||||
|
* iterating through the object: it is expected that you are pointing at
|
||||||
|
* the beginning of the object.
|
||||||
|
* The runtime complexity is linear in the size of the object. After
|
||||||
|
* calling this function, if successful, the object is 'rewinded' at its
|
||||||
|
* beginning as if it had never been accessed. If the JSON is malformed (e.g.,
|
||||||
|
* there is a missing comma), then an error is returned and it is no longer
|
||||||
|
* safe to continue.
|
||||||
|
*
|
||||||
|
* To check that an object is empty, it is more performant to use
|
||||||
|
* the is_empty() method on the object instance.
|
||||||
|
*/
|
||||||
|
simdjson_really_inline simdjson_result<size_t> count_fields() & noexcept;
|
||||||
/**
|
/**
|
||||||
* Get the value at the given index in the array. This function has linear-time complexity.
|
* Get the value at the given index in the array. This function has linear-time complexity.
|
||||||
* This function should only be called once as the array iterator is not reset between each call.
|
* This function should only be called once on an array instance since the array iterator is not reset between each call.
|
||||||
*
|
*
|
||||||
* @return The value at the given index, or:
|
* @return The value at the given index, or:
|
||||||
* - INDEX_OUT_OF_BOUNDS if the array index is larger than an array length
|
* - INDEX_OUT_OF_BOUNDS if the array index is larger than an array length
|
||||||
@@ -351,7 +369,14 @@ public:
|
|||||||
*/
|
*/
|
||||||
simdjson_really_inline simdjson_result<bool> is_integer() noexcept;
|
simdjson_really_inline simdjson_result<bool> is_integer() noexcept;
|
||||||
/**
|
/**
|
||||||
* Determine the number type (integer or floating-point number).
|
* Determine the number type (integer or floating-point number) as quickly
|
||||||
|
* as possible. This function does not fully validate the input. It is
|
||||||
|
* useful when you only need to classify the numbers, without parsing them.
|
||||||
|
*
|
||||||
|
* If you are planning to retrieve the value or you need full validation,
|
||||||
|
* consider using the get_number() method instead: it will fully parse
|
||||||
|
* and validate the input, and give you access to the type:
|
||||||
|
* get_number().get_number_type().
|
||||||
*
|
*
|
||||||
* get_number_type() is number_type::unsigned_integer if we have
|
* 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
|
||||||
@@ -375,7 +400,7 @@ public:
|
|||||||
* type.
|
* type.
|
||||||
*
|
*
|
||||||
* number.get_number_type() is number_type::signed_integer if we have
|
* number.get_number_type() is number_type::signed_integer if we have
|
||||||
* a integer in [-9223372036854775808,9223372036854775808)
|
* an integer in [-9223372036854775808,9223372036854775808)
|
||||||
* You can recover the value by calling number.get_int64() and you
|
* You can recover the value by calling number.get_int64() and you
|
||||||
* have that number.is_int64() is true.
|
* have that number.is_int64() is true.
|
||||||
*
|
*
|
||||||
@@ -425,6 +450,22 @@ public:
|
|||||||
*/
|
*/
|
||||||
simdjson_really_inline std::string_view raw_json_token() noexcept;
|
simdjson_really_inline std::string_view raw_json_token() noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the current location in the document if in bounds.
|
||||||
|
*/
|
||||||
|
simdjson_really_inline simdjson_result<const char *> current_location() noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the current depth in the document if in bounds.
|
||||||
|
*
|
||||||
|
* E.g.,
|
||||||
|
* 0 = finished with document
|
||||||
|
* 1 = document root value (could be [ or {, not yet known)
|
||||||
|
* 2 = , or } inside root array/object
|
||||||
|
* 3 = key or value inside root array/object.
|
||||||
|
*/
|
||||||
|
simdjson_really_inline int32_t current_depth() const noexcept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value associated with the given JSON pointer. We use the RFC 6901
|
* Get the value associated with the given JSON pointer. We use the RFC 6901
|
||||||
* https://tools.ietf.org/html/rfc6901 standard.
|
* https://tools.ietf.org/html/rfc6901 standard.
|
||||||
@@ -456,7 +497,7 @@ public:
|
|||||||
* to call at_pointer on the same array.
|
* to call at_pointer on the same array.
|
||||||
*
|
*
|
||||||
* You may call at_pointer more than once on an object, but each time the pointer is advanced
|
* You may call at_pointer more than once on an object, but each time the pointer is advanced
|
||||||
* to be within the value matched by the key indicated by the JSON pointer query. Thus any preceeding
|
* to be within the value matched by the key indicated by the JSON pointer query. Thus any preceding
|
||||||
* key (as well as the current key) can no longer be used with following JSON pointer calls.
|
* key (as well as the current key) can no longer be used with following JSON pointer calls.
|
||||||
*
|
*
|
||||||
* Also note that at_pointer() relies on find_field() which implies that we do not unescape keys when matching
|
* Also note that at_pointer() relies on find_field() which implies that we do not unescape keys when matching
|
||||||
@@ -552,6 +593,7 @@ public:
|
|||||||
simdjson_really_inline operator bool() noexcept(false);
|
simdjson_really_inline operator bool() noexcept(false);
|
||||||
#endif
|
#endif
|
||||||
simdjson_really_inline simdjson_result<size_t> count_elements() & noexcept;
|
simdjson_really_inline simdjson_result<size_t> count_elements() & noexcept;
|
||||||
|
simdjson_really_inline simdjson_result<size_t> count_fields() & noexcept;
|
||||||
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> at(size_t index) noexcept;
|
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> at(size_t index) noexcept;
|
||||||
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array_iterator> begin() & noexcept;
|
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array_iterator> begin() & noexcept;
|
||||||
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array_iterator> end() & noexcept;
|
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array_iterator> end() & noexcept;
|
||||||
@@ -624,6 +666,10 @@ public:
|
|||||||
/** @copydoc simdjson_really_inline std::string_view value::raw_json_token() const noexcept */
|
/** @copydoc simdjson_really_inline std::string_view value::raw_json_token() const noexcept */
|
||||||
simdjson_really_inline simdjson_result<std::string_view> raw_json_token() noexcept;
|
simdjson_really_inline simdjson_result<std::string_view> raw_json_token() noexcept;
|
||||||
|
|
||||||
|
/** @copydoc simdjson_really_inline simdjson_result<const char *> current_location() noexcept */
|
||||||
|
simdjson_really_inline simdjson_result<const char *> current_location() noexcept;
|
||||||
|
/** @copydoc simdjson_really_inline int32_t current_depth() const noexcept */
|
||||||
|
simdjson_really_inline int32_t current_depth() const noexcept;
|
||||||
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> at_pointer(std::string_view json_pointer) noexcept;
|
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> at_pointer(std::string_view json_pointer) noexcept;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -39,9 +39,22 @@ simdjson_warn_unused simdjson_really_inline simdjson_result<bool> value_iterator
|
|||||||
// current document. It only works in the normal mode where we have indexed a single document.
|
// current document. It only works in the normal mode where we have indexed a single document.
|
||||||
// Note that adding a check for 'streaming' is not expensive since we only have at most
|
// Note that adding a check for 'streaming' is not expensive since we only have at most
|
||||||
// one root element.
|
// one root element.
|
||||||
if (! _json_iter->streaming() && (*_json_iter->peek_last() != '}')) {
|
if ( ! _json_iter->streaming() ) {
|
||||||
_json_iter->abandon();
|
if (*_json_iter->peek_last() != '}') {
|
||||||
return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "missing } at end");
|
_json_iter->abandon();
|
||||||
|
return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "missing } at end");
|
||||||
|
}
|
||||||
|
// If the last character is } *and* the first gibberish character is also '}'
|
||||||
|
// then on-demand could accidentally go over. So we need additional checks.
|
||||||
|
// https://github.com/simdjson/simdjson/issues/1834
|
||||||
|
// Checking that the document is balanced requires a full scan which is potentially
|
||||||
|
// expensive, but it only happens in edge cases where the first padding character is
|
||||||
|
// a closing bracket.
|
||||||
|
if ((*_json_iter->peek(_json_iter->end_position()) == '}') && (!_json_iter->balanced())) {
|
||||||
|
_json_iter->abandon();
|
||||||
|
// The exact error would require more work. It will typically be an unclosed object.
|
||||||
|
return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "the document is unbalanced");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return started_object();
|
return started_object();
|
||||||
}
|
}
|
||||||
@@ -167,6 +180,8 @@ simdjson_warn_unused simdjson_really_inline simdjson_result<bool> value_iterator
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SIMDJSON_PUSH_DISABLE_WARNINGS
|
||||||
|
SIMDJSON_DISABLE_STRICT_OVERFLOW_WARNING
|
||||||
simdjson_warn_unused simdjson_really_inline simdjson_result<bool> value_iterator::find_field_unordered_raw(const std::string_view key) noexcept {
|
simdjson_warn_unused simdjson_really_inline simdjson_result<bool> value_iterator::find_field_unordered_raw(const std::string_view key) noexcept {
|
||||||
/**
|
/**
|
||||||
* When find_field_unordered_raw is called, we can either be pointing at the
|
* When find_field_unordered_raw is called, we can either be pointing at the
|
||||||
@@ -354,6 +369,7 @@ simdjson_warn_unused simdjson_really_inline simdjson_result<bool> value_iterator
|
|||||||
// never reach this point.
|
// never reach this point.
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
SIMDJSON_POP_DISABLE_WARNINGS
|
||||||
|
|
||||||
simdjson_warn_unused simdjson_really_inline simdjson_result<raw_json_string> value_iterator::field_key() noexcept {
|
simdjson_warn_unused simdjson_really_inline simdjson_result<raw_json_string> value_iterator::field_key() noexcept {
|
||||||
assert_at_next();
|
assert_at_next();
|
||||||
@@ -408,9 +424,22 @@ simdjson_warn_unused simdjson_really_inline simdjson_result<bool> value_iterator
|
|||||||
// current document. It only works in the normal mode where we have indexed a single document.
|
// current document. It only works in the normal mode where we have indexed a single document.
|
||||||
// Note that adding a check for 'streaming' is not expensive since we only have at most
|
// Note that adding a check for 'streaming' is not expensive since we only have at most
|
||||||
// one root element.
|
// one root element.
|
||||||
if ( ! _json_iter->streaming() && (*_json_iter->peek_last() != ']')) {
|
if ( ! _json_iter->streaming() ) {
|
||||||
_json_iter->abandon();
|
if (*_json_iter->peek_last() != ']') {
|
||||||
return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "missing ] at end");
|
_json_iter->abandon();
|
||||||
|
return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "missing ] at end");
|
||||||
|
}
|
||||||
|
// If the last character is ] *and* the first gibberish character is also ']'
|
||||||
|
// then on-demand could accidentally go over. So we need additional checks.
|
||||||
|
// https://github.com/simdjson/simdjson/issues/1834
|
||||||
|
// Checking that the document is balanced requires a full scan which is potentially
|
||||||
|
// expensive, but it only happens in edge cases where the first padding character is
|
||||||
|
// a closing bracket.
|
||||||
|
if ((*_json_iter->peek(_json_iter->end_position()) == ']') && (!_json_iter->balanced())) {
|
||||||
|
_json_iter->abandon();
|
||||||
|
// The exact error would require more work. It will typically be an unclosed array.
|
||||||
|
return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "the document is unbalanced");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return started_array();
|
return started_array();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -76,7 +76,7 @@ public:
|
|||||||
/**
|
/**
|
||||||
* Get the depth of this value.
|
* Get the depth of this value.
|
||||||
*/
|
*/
|
||||||
simdjson_really_inline depth_t depth() const noexcept;
|
simdjson_really_inline int32_t depth() const noexcept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the JSON type of this value.
|
* Get the JSON type of this value.
|
||||||
|
|||||||
@@ -1,138 +0,0 @@
|
|||||||
// This file contains the common code every implementation uses
|
|
||||||
// It is intended to be included multiple times and compiled multiple times
|
|
||||||
|
|
||||||
namespace simdjson {
|
|
||||||
namespace SIMDJSON_IMPLEMENTATION {
|
|
||||||
namespace {
|
|
||||||
/// @private
|
|
||||||
namespace stringparsing {
|
|
||||||
|
|
||||||
// begin copypasta
|
|
||||||
// These chars yield themselves: " \ /
|
|
||||||
// b -> backspace, f -> formfeed, n -> newline, r -> cr, t -> horizontal tab
|
|
||||||
// u not handled in this table as it's complex
|
|
||||||
static const uint8_t escape_map[256] = {
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x0.
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0x22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x2f,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x4.
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x5c, 0, 0, 0, // 0x5.
|
|
||||||
0, 0, 0x08, 0, 0, 0, 0x0c, 0, 0, 0, 0, 0, 0, 0, 0x0a, 0, // 0x6.
|
|
||||||
0, 0, 0x0d, 0, 0x09, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x7.
|
|
||||||
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
};
|
|
||||||
|
|
||||||
// handle a unicode codepoint
|
|
||||||
// write appropriate values into dest
|
|
||||||
// src will advance 6 bytes or 12 bytes
|
|
||||||
// dest will advance a variable amount (return via pointer)
|
|
||||||
// return true if the unicode codepoint was valid
|
|
||||||
// We work in little-endian then swap at write time
|
|
||||||
simdjson_warn_unused
|
|
||||||
simdjson_really_inline bool handle_unicode_codepoint(const uint8_t **src_ptr,
|
|
||||||
uint8_t **dst_ptr) {
|
|
||||||
// jsoncharutils::hex_to_u32_nocheck fills high 16 bits of the return value with 1s if the
|
|
||||||
// conversion isn't valid; we defer the check for this to inside the
|
|
||||||
// multilingual plane check
|
|
||||||
uint32_t code_point = jsoncharutils::hex_to_u32_nocheck(*src_ptr + 2);
|
|
||||||
*src_ptr += 6;
|
|
||||||
// check for low surrogate for characters outside the Basic
|
|
||||||
// Multilingual Plane.
|
|
||||||
if (code_point >= 0xd800 && code_point < 0xdc00) {
|
|
||||||
if (((*src_ptr)[0] != '\\') || (*src_ptr)[1] != 'u') {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
uint32_t code_point_2 = jsoncharutils::hex_to_u32_nocheck(*src_ptr + 2);
|
|
||||||
|
|
||||||
// if the first code point is invalid we will get here, as we will go past
|
|
||||||
// the check for being outside the Basic Multilingual plane. If we don't
|
|
||||||
// find a \u immediately afterwards we fail out anyhow, but if we do,
|
|
||||||
// this check catches both the case of the first code point being invalid
|
|
||||||
// or the second code point being invalid.
|
|
||||||
if ((code_point | code_point_2) >> 16) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
code_point =
|
|
||||||
(((code_point - 0xd800) << 10) | (code_point_2 - 0xdc00)) + 0x10000;
|
|
||||||
*src_ptr += 6;
|
|
||||||
}
|
|
||||||
size_t offset = jsoncharutils::codepoint_to_utf8(code_point, *dst_ptr);
|
|
||||||
*dst_ptr += offset;
|
|
||||||
return offset > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Unescape a string from src to dst, stopping at a final unescaped quote. E.g., if src points at 'joe"', then
|
|
||||||
* dst needs to have four free bytes.
|
|
||||||
*/
|
|
||||||
simdjson_warn_unused simdjson_really_inline uint8_t *parse_string(const uint8_t *src, uint8_t *dst) {
|
|
||||||
while (1) {
|
|
||||||
// Copy the next n bytes, and find the backslash and quote in them.
|
|
||||||
auto bs_quote = backslash_and_quote::copy_and_find(src, dst);
|
|
||||||
// If the next thing is the end quote, copy and return
|
|
||||||
if (bs_quote.has_quote_first()) {
|
|
||||||
// we encountered quotes first. Move dst to point to quotes and exit
|
|
||||||
return dst + bs_quote.quote_index();
|
|
||||||
}
|
|
||||||
if (bs_quote.has_backslash()) {
|
|
||||||
/* find out where the backspace is */
|
|
||||||
auto bs_dist = bs_quote.backslash_index();
|
|
||||||
uint8_t escape_char = src[bs_dist + 1];
|
|
||||||
/* we encountered backslash first. Handle backslash */
|
|
||||||
if (escape_char == 'u') {
|
|
||||||
/* move src/dst up to the start; they will be further adjusted
|
|
||||||
within the unicode codepoint handling code. */
|
|
||||||
src += bs_dist;
|
|
||||||
dst += bs_dist;
|
|
||||||
if (!handle_unicode_codepoint(&src, &dst)) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
/* simple 1:1 conversion. Will eat bs_dist+2 characters in input and
|
|
||||||
* write bs_dist+1 characters to output
|
|
||||||
* note this may reach beyond the part of the buffer we've actually
|
|
||||||
* seen. I think this is ok */
|
|
||||||
uint8_t escape_result = escape_map[escape_char];
|
|
||||||
if (escape_result == 0u) {
|
|
||||||
return nullptr; /* bogus escape value is an error */
|
|
||||||
}
|
|
||||||
dst[bs_dist] = escape_result;
|
|
||||||
src += bs_dist + 2;
|
|
||||||
dst += bs_dist + 1;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
/* they are the same. Since they can't co-occur, it means we
|
|
||||||
* encountered neither. */
|
|
||||||
src += backslash_and_quote::BYTES_PROCESSED;
|
|
||||||
dst += backslash_and_quote::BYTES_PROCESSED;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* can't be reached */
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
simdjson_unused simdjson_warn_unused simdjson_really_inline error_code parse_string_to_buffer(const uint8_t *src, uint8_t *¤t_string_buf_loc, std::string_view &s) {
|
|
||||||
if (*(src++) != '"') { return STRING_ERROR; }
|
|
||||||
auto end = stringparsing::parse_string(src, current_string_buf_loc);
|
|
||||||
if (!end) { return STRING_ERROR; }
|
|
||||||
s = std::string_view(reinterpret_cast<const char *>(current_string_buf_loc), end-current_string_buf_loc);
|
|
||||||
current_string_buf_loc = end;
|
|
||||||
return SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace stringparsing
|
|
||||||
} // unnamed namespace
|
|
||||||
} // namespace SIMDJSON_IMPLEMENTATION
|
|
||||||
} // namespace simdjson
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ namespace {
|
|||||||
// We sometimes call trailing_zero on inputs that are zero,
|
// We sometimes call trailing_zero on inputs that are zero,
|
||||||
// but the algorithms do not end up using the returned value.
|
// but the algorithms do not end up using the returned value.
|
||||||
// Sadly, sanitizers are not smart enough to figure it out.
|
// Sadly, sanitizers are not smart enough to figure it out.
|
||||||
NO_SANITIZE_UNDEFINED
|
SIMDJSON_NO_SANITIZE_UNDEFINED
|
||||||
simdjson_really_inline int trailing_zeroes(uint64_t input_num) {
|
simdjson_really_inline int trailing_zeroes(uint64_t input_num) {
|
||||||
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
|
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||||
return (int)_tzcnt_u64(input_num);
|
return (int)_tzcnt_u64(input_num);
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ public:
|
|||||||
) const noexcept final;
|
) const noexcept final;
|
||||||
simdjson_warn_unused error_code minify(const uint8_t *buf, size_t len, uint8_t *dst, size_t &dst_len) const noexcept final;
|
simdjson_warn_unused error_code minify(const uint8_t *buf, size_t len, uint8_t *dst, size_t &dst_len) const noexcept final;
|
||||||
simdjson_warn_unused bool validate_utf8(const char *buf, size_t len) const noexcept final;
|
simdjson_warn_unused bool validate_utf8(const char *buf, size_t len) const noexcept final;
|
||||||
|
simdjson_warn_unused uint8_t *parse_string(const uint8_t *src, uint8_t *dst) const noexcept final;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace haswell
|
} // namespace haswell
|
||||||
|
|||||||
@@ -41,11 +41,7 @@
|
|||||||
// has it as a macro.
|
// has it as a macro.
|
||||||
#ifndef _blsr_u64
|
#ifndef _blsr_u64
|
||||||
// we roll our own
|
// we roll our own
|
||||||
SIMDJSON_TARGET_HASWELL
|
#define _blsr_u64(n) ((n - 1) & n)
|
||||||
static simdjson_really_inline uint64_t _blsr_u64(uint64_t n) {
|
|
||||||
return (n - 1) & n;
|
|
||||||
}
|
|
||||||
SIMDJSON_UNTARGET_HASWELL
|
|
||||||
#endif // _blsr_u64
|
#endif // _blsr_u64
|
||||||
#endif // SIMDJSON_CLANG_VISUAL_STUDIO
|
#endif // SIMDJSON_CLANG_VISUAL_STUDIO
|
||||||
|
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ namespace simd {
|
|||||||
simdjson_really_inline base8() : base<simd8<T>>() {}
|
simdjson_really_inline base8() : base<simd8<T>>() {}
|
||||||
simdjson_really_inline base8(const __m256i _value) : base<simd8<T>>(_value) {}
|
simdjson_really_inline base8(const __m256i _value) : base<simd8<T>>(_value) {}
|
||||||
|
|
||||||
simdjson_really_inline Mask operator==(const simd8<T> other) const { return _mm256_cmpeq_epi8(*this, other); }
|
friend simdjson_really_inline Mask operator==(const simd8<T> lhs, const simd8<T> rhs) { return _mm256_cmpeq_epi8(lhs, rhs); }
|
||||||
|
|
||||||
static const int SIZE = sizeof(base<T>::value);
|
static const int SIZE = sizeof(base<T>::value);
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,47 @@
|
|||||||
|
#ifndef SIMDJSON_ICELAKE_H
|
||||||
|
#define SIMDJSON_ICELAKE_H
|
||||||
|
|
||||||
|
#include "simdjson/implementation-base.h"
|
||||||
|
|
||||||
|
#if SIMDJSON_IMPLEMENTATION_ICELAKE
|
||||||
|
|
||||||
|
#if SIMDJSON_CAN_ALWAYS_RUN_ICELAKE
|
||||||
|
#define SIMDJSON_TARGET_ICELAKE
|
||||||
|
#define SIMDJSON_UNTARGET_ICELAKE
|
||||||
|
#else
|
||||||
|
#define SIMDJSON_TARGET_ICELAKE SIMDJSON_TARGET_REGION("avx512f,avx512dq,avx512cd,avx512bw,avx512vbmi,avx512vbmi2,avx512vl,avx2,bmi,pclmul,lzcnt")
|
||||||
|
#define SIMDJSON_UNTARGET_ICELAKE SIMDJSON_UNTARGET_REGION
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace simdjson {
|
||||||
|
/**
|
||||||
|
* Implementation for Icelake (Intel AVX512).
|
||||||
|
*/
|
||||||
|
namespace icelake {
|
||||||
|
} // namespace icelake
|
||||||
|
} // namespace simdjson
|
||||||
|
|
||||||
|
//
|
||||||
|
// These two need to be included outside SIMDJSON_TARGET_ICELAKE
|
||||||
|
//
|
||||||
|
#include "simdjson/icelake/implementation.h"
|
||||||
|
#include "simdjson/icelake/intrinsics.h"
|
||||||
|
|
||||||
|
//
|
||||||
|
// The rest need to be inside the region
|
||||||
|
//
|
||||||
|
#include "simdjson/icelake/begin.h"
|
||||||
|
|
||||||
|
// Declarations
|
||||||
|
#include "simdjson/generic/dom_parser_implementation.h"
|
||||||
|
#include "simdjson/icelake/bitmanipulation.h"
|
||||||
|
#include "simdjson/icelake/bitmask.h"
|
||||||
|
#include "simdjson/icelake/simd.h"
|
||||||
|
#include "simdjson/generic/jsoncharutils.h"
|
||||||
|
#include "simdjson/generic/atomparsing.h"
|
||||||
|
#include "simdjson/icelake/stringparsing.h"
|
||||||
|
#include "simdjson/icelake/numberparsing.h"
|
||||||
|
#include "simdjson/icelake/end.h"
|
||||||
|
|
||||||
|
#endif // SIMDJSON_IMPLEMENTATION_ICELAKE
|
||||||
|
#endif // SIMDJSON_ICELAKE_H
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
#define SIMDJSON_IMPLEMENTATION icelake
|
||||||
|
SIMDJSON_TARGET_ICELAKE
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
#ifndef SIMDJSON_ICELAKE_BITMANIPULATION_H
|
||||||
|
#define SIMDJSON_ICELAKE_BITMANIPULATION_H
|
||||||
|
|
||||||
|
namespace simdjson {
|
||||||
|
namespace SIMDJSON_IMPLEMENTATION {
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
// We sometimes call trailing_zero on inputs that are zero,
|
||||||
|
// but the algorithms do not end up using the returned value.
|
||||||
|
// Sadly, sanitizers are not smart enough to figure it out.
|
||||||
|
SIMDJSON_NO_SANITIZE_UNDEFINED
|
||||||
|
simdjson_really_inline int trailing_zeroes(uint64_t input_num) {
|
||||||
|
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||||
|
return (int)_tzcnt_u64(input_num);
|
||||||
|
#else // SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||||
|
////////
|
||||||
|
// You might expect the next line to be equivalent to
|
||||||
|
// return (int)_tzcnt_u64(input_num);
|
||||||
|
// but the generated code differs and might be less efficient?
|
||||||
|
////////
|
||||||
|
return __builtin_ctzll(input_num);
|
||||||
|
#endif // SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||||
|
}
|
||||||
|
|
||||||
|
/* result might be undefined when input_num is zero */
|
||||||
|
simdjson_really_inline uint64_t clear_lowest_bit(uint64_t input_num) {
|
||||||
|
return _blsr_u64(input_num);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* result might be undefined when input_num is zero */
|
||||||
|
simdjson_really_inline int leading_zeroes(uint64_t input_num) {
|
||||||
|
return int(_lzcnt_u64(input_num));
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||||
|
simdjson_really_inline unsigned __int64 count_ones(uint64_t input_num) {
|
||||||
|
// note: we do not support legacy 32-bit Windows
|
||||||
|
return __popcnt64(input_num);// Visual Studio wants two underscores
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
simdjson_really_inline long long int count_ones(uint64_t input_num) {
|
||||||
|
return _popcnt64(input_num);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
simdjson_really_inline bool add_overflow(uint64_t value1, uint64_t value2,
|
||||||
|
uint64_t *result) {
|
||||||
|
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||||
|
return _addcarry_u64(0, value1, value2,
|
||||||
|
reinterpret_cast<unsigned __int64 *>(result));
|
||||||
|
#else
|
||||||
|
return __builtin_uaddll_overflow(value1, value2,
|
||||||
|
reinterpret_cast<unsigned long long *>(result));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
} // unnamed namespace
|
||||||
|
} // namespace SIMDJSON_IMPLEMENTATION
|
||||||
|
} // namespace simdjson
|
||||||
|
|
||||||
|
#endif // SIMDJSON_ICELAKE_BITMANIPULATION_H
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
#ifndef SIMDJSON_ICELAKE_BITMASK_H
|
||||||
|
#define SIMDJSON_ICELAKE_BITMASK_H
|
||||||
|
|
||||||
|
namespace simdjson {
|
||||||
|
namespace SIMDJSON_IMPLEMENTATION {
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
//
|
||||||
|
// Perform a "cumulative bitwise xor," flipping bits each time a 1 is encountered.
|
||||||
|
//
|
||||||
|
// For example, prefix_xor(00100100) == 00011100
|
||||||
|
//
|
||||||
|
simdjson_really_inline uint64_t prefix_xor(const uint64_t bitmask) {
|
||||||
|
// There should be no such thing with a processor supporting avx2
|
||||||
|
// but not clmul.
|
||||||
|
__m128i all_ones = _mm_set1_epi8('\xFF');
|
||||||
|
__m128i result = _mm_clmulepi64_si128(_mm_set_epi64x(0ULL, bitmask), all_ones, 0);
|
||||||
|
return _mm_cvtsi128_si64(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // unnamed namespace
|
||||||
|
} // namespace SIMDJSON_IMPLEMENTATION
|
||||||
|
} // namespace simdjson
|
||||||
|
|
||||||
|
#endif // SIMDJSON_ICELAKE_BITMASK_H
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user