mirror of
https://github.com/simdjson/simdjson
synced 2026-06-08 17:27:07 +00:00
Compare commits
67 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 17f3148ac7 | |||
| 35b4a48e99 | |||
| c0d18452fc | |||
| e5c9a310cf | |||
| 6d308a08c5 | |||
| 9e477ddb00 | |||
| b7c4d1eeef | |||
| 4a2f10ebcf | |||
| 41cb909604 | |||
| 91908ade4d | |||
| 9a32c48098 | |||
| d996ffc494 | |||
| d56fdc3d04 | |||
| 1dce4fed6e | |||
| cae5e5342f | |||
| 4e609aa955 | |||
| d28e5534d9 | |||
| 3bd8b0b575 | |||
| af4ff7cc33 | |||
| c9179ad81d | |||
| d6b5124c88 | |||
| 64b62fd3b3 | |||
| cebe3fb299 | |||
| ed7343f7f2 | |||
| 35158257c6 | |||
| b935ce2e06 | |||
| 4afe7565b4 | |||
| 6bed34ad61 | |||
| 0ad52a7e22 | |||
| aa52cf6868 | |||
| cd11838e5f | |||
| c31157bafe | |||
| 419b7b2ce8 | |||
| ca3f3cc49d | |||
| d3f0e2afb3 | |||
| eac3832ec0 | |||
| db19c7675f | |||
| d036fdf919 | |||
| fc0934755a | |||
| de4deb8c4e | |||
| ba46616cbc | |||
| a552638373 | |||
| e30123d58f | |||
| b7dee3e9c8 | |||
| 717d0c24a6 | |||
| 40813752f4 | |||
| 19902abaf8 | |||
| 06643fc9f5 | |||
| 0fa68d8930 | |||
| cc98358453 | |||
| 5f0b35b2c5 | |||
| bd0f5e9322 | |||
| cb0e4b23c7 | |||
| d83e69d977 | |||
| f657516a7e | |||
| 8d29c5f931 | |||
| eeac91579c | |||
| e5a4b8b81b | |||
| 7b8f775893 | |||
| c6ef2105ab | |||
| e681234e45 | |||
| eb93b98d6a | |||
| 7d887fdc1e | |||
| 9d405a5df4 | |||
| 18c003e8bf | |||
| ec4316aa84 | |||
| b79261eebc |
+5
-5
@@ -15,22 +15,22 @@ environment:
|
||||
- job_name: VS2019
|
||||
CMAKE_ARGS: -A %Platform%
|
||||
- job_name: VS2019ARM
|
||||
CMAKE_ARGS: -A ARM64 -DCMAKE_CROSSCOMPILING=1 -D SIMDJSON_GOOGLE_BENCHMARKS=OFF # Does Google Benchmark builds under VS ARM?
|
||||
CMAKE_ARGS: -A ARM64 -DSIMDJSON_DEVELOPER_MODE=ON -DCMAKE_CROSSCOMPILING=1 -D SIMDJSON_GOOGLE_BENCHMARKS=OFF # Does Google Benchmark builds under VS ARM?
|
||||
- job_name: VS2017 (Static, No Threads)
|
||||
image: Visual Studio 2017
|
||||
CMAKE_ARGS: -A %Platform% -DBUILD_SHARED_LIBS=OFF -DSIMDJSON_ENABLE_THREADS=OFF
|
||||
CMAKE_ARGS: -A %Platform% -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF -DSIMDJSON_ENABLE_THREADS=OFF
|
||||
CTEST_ARGS: -LE explicitonly
|
||||
- job_name: VS2019 (Win32)
|
||||
platform: Win32
|
||||
CMAKE_ARGS: -A %Platform% -DBUILD_SHARED_LIBS=ON -DSIMDJSON_ENABLE_THREADS=ON # This should be the default. Testing anyway.
|
||||
CMAKE_ARGS: -A %Platform% -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=ON -DSIMDJSON_ENABLE_THREADS=ON # This should be the default. Testing anyway.
|
||||
CTEST_ARGS: -LE explicitonly
|
||||
- job_name: VS2019 (Win32, No Exceptions)
|
||||
platform: Win32
|
||||
CMAKE_ARGS: -A %Platform% -DBUILD_SHARED_LIBS=ON -DSIMDJSON_ENABLE_THREADS=ON -DSIMDJSON_EXCEPTIONS=OFF
|
||||
CMAKE_ARGS: -A %Platform% -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=ON -DSIMDJSON_ENABLE_THREADS=ON -DSIMDJSON_EXCEPTIONS=OFF
|
||||
CTEST_ARGS: -LE explicitonly
|
||||
- job_name: VS2015
|
||||
image: Visual Studio 2015
|
||||
CMAKE_ARGS: -A %Platform% -DBUILD_SHARED_LIBS=OFF -DSIMDJSON_ENABLE_THREADS=OFF
|
||||
CMAKE_ARGS: -A %Platform% -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF -DSIMDJSON_ENABLE_THREADS=OFF
|
||||
CTEST_ARGS: -LE explicitonly
|
||||
|
||||
build_script:
|
||||
|
||||
+10
-18
@@ -1,7 +1,7 @@
|
||||
version: 2.1
|
||||
|
||||
|
||||
# We constantly run out of memory so please do not use parallelism (-j, -j4).
|
||||
# We constantly run out of memory so please do not use parallelism (-j, -j4).
|
||||
|
||||
# Reusable image / compiler definitions
|
||||
executors:
|
||||
@@ -48,7 +48,7 @@ executors:
|
||||
CXX: clang++-9
|
||||
CC: clang-9
|
||||
CMAKE_BUILD_FLAGS:
|
||||
CTEST_FLAGS: --output-on-failure
|
||||
CTEST_FLAGS: --output-on-failure
|
||||
|
||||
clang6:
|
||||
docker:
|
||||
@@ -88,13 +88,13 @@ commands:
|
||||
steps:
|
||||
- cmake_prep
|
||||
- dependency_restore
|
||||
- run: cmake $CMAKE_FLAGS -DCMAKE_INSTALL_PREFIX:PATH=destination -B build .
|
||||
- run: cmake -DSIMDJSON_DEVELOPER_MODE=ON $CMAKE_FLAGS -DCMAKE_INSTALL_PREFIX:PATH=destination -B build .
|
||||
- dependency_cache # dependencies are produced in the configure step
|
||||
|
||||
cmake_build:
|
||||
steps:
|
||||
- cmake_build_cache
|
||||
- run: cmake --build build
|
||||
- run: cmake --build build
|
||||
|
||||
cmake_test:
|
||||
steps:
|
||||
@@ -130,7 +130,7 @@ commands:
|
||||
- cmake_build_cache
|
||||
- run: |
|
||||
cmake -DSIMDJSON_ENABLE_DOM_CHECKPERF=ON --build build --target checkperf &&
|
||||
cd build &&
|
||||
cd build &&
|
||||
ctest --output-on-failure -R checkperf
|
||||
|
||||
# we not only want cmake to build and run tests, but we want also a successful installation from which we can build, link and run programs
|
||||
@@ -191,12 +191,12 @@ jobs:
|
||||
sanitize-gcc10:
|
||||
description: Build and run tests on GCC 10 and AVX 2 with a cmake sanitize build
|
||||
executor: gcc10
|
||||
environment: { CMAKE_FLAGS: -DBUILD_SHARED_LIBS=ON -DSIMDJSON_SANITIZE=ON, CTEST_FLAGS: --output-on-failure -LE explicitonly }
|
||||
environment: { CMAKE_FLAGS: -DCMAKE_BUILD_TYPE=Debug -DBUILD_SHARED_LIBS=ON -DSIMDJSON_SANITIZE=ON, CTEST_FLAGS: --output-on-failure -LE explicitonly }
|
||||
steps: [ cmake_test ]
|
||||
sanitize-clang10:
|
||||
description: Build and run tests on clang 10 and AVX 2 with a cmake sanitize build
|
||||
executor: clang10
|
||||
environment: { CMAKE_FLAGS: -DBUILD_SHARED_LIBS=ON -DSIMDJSON_SANITIZE=ON, CTEST_FLAGS: --output-on-failure -LE explicitonly }
|
||||
environment: { CMAKE_FLAGS: -DBUILD_SHARED_LIBS=ON -DSIMDJSON_NO_FORCE_INLINING=ON -DSIMDJSON_SANITIZE=ON, CTEST_FLAGS: --output-on-failure -LE explicitonly }
|
||||
steps: [ cmake_test ]
|
||||
threadsanitize-gcc10:
|
||||
description: Build and run tests on GCC 10 and AVX 2 with a cmake sanitize build
|
||||
@@ -206,15 +206,7 @@ jobs:
|
||||
threadsanitize-clang10:
|
||||
description: Build and run tests on clang 10 and AVX 2 with a cmake sanitize build
|
||||
executor: clang10
|
||||
environment: { CMAKE_FLAGS: -DBUILD_SHARED_LIBS=ON -DSIMDJSON_SANITIZE_THREADS=ON, CTEST_FLAGS: --output-on-failure -LE explicitonly }
|
||||
steps: [ cmake_test ]
|
||||
nocheckeof-clang10:
|
||||
description: Validate that when __SIMDJSON_CHECK_EOF=0, everything still succeeds
|
||||
environment:
|
||||
CXXFLAGS: -D__SIMDJSON_CHECK_EOF=0
|
||||
CMAKE_BUILD_FLAGS: --target ondemand_tests
|
||||
CTEST_FLAGS: --output-on-failure -R ondemand_
|
||||
executor: clang10
|
||||
environment: { CMAKE_FLAGS: -DBUILD_SHARED_LIBS=ON -DSIMDJSON_NO_FORCE_INLINING=ON -DSIMDJSON_SANITIZE_THREADS=ON, CTEST_FLAGS: --output-on-failure -LE explicitonly }
|
||||
steps: [ cmake_test ]
|
||||
# dynamic
|
||||
dynamic-gcc10:
|
||||
@@ -270,12 +262,12 @@ jobs:
|
||||
sanitize-haswell-gcc10:
|
||||
description: Build and run tests on GCC 10 and AVX 2 with a cmake sanitize build
|
||||
executor: gcc10
|
||||
environment: { CXXFLAGS: -march=haswell, CMAKE_FLAGS: -DBUILD_SHARED_LIBS=ON -DSIMDJSON_SANITIZE=ON, CTEST_FLAGS: --output-on-failure -LE explicitonly }
|
||||
environment: { CXXFLAGS: -march=haswell, CMAKE_FLAGS: -DCMAKE_BUILD_TYPE=Debug -DBUILD_SHARED_LIBS=ON -DSIMDJSON_SANITIZE=ON, CTEST_FLAGS: --output-on-failure -LE explicitonly }
|
||||
steps: [ cmake_test ]
|
||||
sanitize-haswell-clang10:
|
||||
description: Build and run tests on clang 10 and AVX 2 with a cmake sanitize build
|
||||
executor: clang10
|
||||
environment: { CXXFLAGS: -march=haswell, CMAKE_FLAGS: -DBUILD_SHARED_LIBS=ON -DSIMDJSON_SANITIZE=ON, CTEST_FLAGS: --output-on-failure -LE explicitonly }
|
||||
environment: { CXXFLAGS: -march=haswell, CMAKE_FLAGS: -DBUILD_SHARED_LIBS=ON -DSIMDJSON_NO_FORCE_INLINING=ON -DSIMDJSON_SANITIZE=ON, CTEST_FLAGS: --output-on-failure -LE explicitonly }
|
||||
steps: [ cmake_test ]
|
||||
|
||||
workflows:
|
||||
|
||||
-42
@@ -1,46 +1,4 @@
|
||||
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
|
||||
platform: { os: linux, arch: amd64 }
|
||||
steps:
|
||||
|
||||
@@ -1,12 +1,6 @@
|
||||
name: Alpine Linux
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
ubuntu-build:
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
name: Detect trailing whitespace
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
whitespace:
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
name: Macos (Xcode 11)
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
macos-build:
|
||||
if: >-
|
||||
! contains(toJSON(github.event.commits.*.message), '[skip ci]') &&
|
||||
! contains(toJSON(github.event.commits.*.message), '[skip github]')
|
||||
runs-on: macos-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/cache@v2
|
||||
with:
|
||||
path: dependencies/.cache
|
||||
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
||||
- name: Use cmake
|
||||
run: |
|
||||
xcversion select 11.7
|
||||
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 .
|
||||
@@ -0,0 +1,33 @@
|
||||
name: Macos
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
macos-build:
|
||||
if: >-
|
||||
! contains(toJSON(github.event.commits.*.message), '[skip ci]') &&
|
||||
! contains(toJSON(github.event.commits.*.message), '[skip github]')
|
||||
runs-on: macos-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/cache@v2
|
||||
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,12 +1,7 @@
|
||||
name: MinGW32-CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
on: [push, pull_request]
|
||||
|
||||
|
||||
# Important: scoop will either install 32-bit GCC or 64-bit GCC, not both.
|
||||
|
||||
@@ -47,7 +42,7 @@ jobs:
|
||||
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 git --global
|
||||
sudo scoop install ninja --global
|
||||
sudo scoop install cmake --global
|
||||
sudo scoop install gcc --arch 32bit --global
|
||||
|
||||
@@ -1,12 +1,7 @@
|
||||
name: MinGW64-CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
on: [push, pull_request]
|
||||
|
||||
|
||||
# Important: scoop will either install 32-bit GCC or 64-bit GCC, not both.
|
||||
|
||||
|
||||
@@ -1,12 +1,7 @@
|
||||
name: MSYS2-CLANG-CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
on: [push, pull_request]
|
||||
|
||||
|
||||
jobs:
|
||||
windows-mingw:
|
||||
@@ -22,15 +17,9 @@ jobs:
|
||||
- msystem: "MINGW64"
|
||||
install: mingw-w64-x86_64-libxml2 mingw-w64-x86_64-cmake mingw-w64-x86_64-ninja mingw-w64-x86_64-clang
|
||||
type: Release
|
||||
- msystem: "MINGW32"
|
||||
install: mingw-w64-i686-libxml2 mingw-w64-i686-cmake mingw-w64-i686-ninja mingw-w64-i686-clang
|
||||
type: Release
|
||||
- msystem: "MINGW64"
|
||||
install: mingw-w64-x86_64-libxml2 mingw-w64-x86_64-cmake mingw-w64-x86_64-ninja mingw-w64-x86_64-clang
|
||||
type: Debug
|
||||
- msystem: "MINGW32"
|
||||
install: mingw-w64-i686-libxml2 mingw-w64-i686-cmake mingw-w64-i686-ninja mingw-w64-i686-clang
|
||||
type: Debug
|
||||
env:
|
||||
CMAKE_GENERATOR: Ninja
|
||||
|
||||
|
||||
@@ -1,12 +1,6 @@
|
||||
name: MSYS2-CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
windows-mingw:
|
||||
@@ -25,15 +19,9 @@ jobs:
|
||||
- msystem: "MINGW64"
|
||||
install: mingw-w64-x86_64-cmake mingw-w64-x86_64-ninja mingw-w64-x86_64-gcc
|
||||
type: Release
|
||||
- msystem: "MINGW32"
|
||||
install: mingw-w64-i686-cmake mingw-w64-i686-ninja mingw-w64-i686-gcc
|
||||
type: Release
|
||||
- msystem: "MINGW64"
|
||||
install: mingw-w64-x86_64-cmake mingw-w64-x86_64-ninja mingw-w64-x86_64-gcc
|
||||
type: Debug
|
||||
- msystem: "MINGW32"
|
||||
install: mingw-w64-i686-cmake mingw-w64-i686-ninja mingw-w64-i686-gcc
|
||||
type: Debug
|
||||
env:
|
||||
CMAKE_GENERATOR: Ninja
|
||||
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
name: Ubuntu 18.04 CI (LLVM 7)
|
||||
|
||||
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-18.04
|
||||
|
||||
env:
|
||||
CC: clang-7
|
||||
CXX: clang++-7
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/cache@v2
|
||||
with:
|
||||
path: dependencies/.cache
|
||||
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
||||
- name: install clang 7
|
||||
run: |
|
||||
sudo apt update
|
||||
sudo apt install clang-7
|
||||
- name: Use cmake
|
||||
run: |
|
||||
mkdir build &&
|
||||
cd build &&
|
||||
cmake -DSIMDJSON_DEVELOPER_MODE=ON -DSIMDJSON_GOOGLE_BENCHMARKS=ON -DBUILD_SHARED_LIBS=OFF -DCMAKE_INSTALL_PREFIX:PATH=destination .. &&
|
||||
cmake --build . &&
|
||||
ctest -j --output-on-failure -LE explicitonly
|
||||
@@ -1,12 +1,7 @@
|
||||
name: Ubuntu 18.04 CI (GCC 7) with Thread Sanitizer
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
on: [push, pull_request]
|
||||
|
||||
|
||||
jobs:
|
||||
ubuntu-build:
|
||||
|
||||
@@ -1,12 +1,6 @@
|
||||
name: Ubuntu 18.04 CI (GCC 7)
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
ubuntu-build:
|
||||
|
||||
@@ -1,12 +1,6 @@
|
||||
name: Ubuntu 20.04 CI (GCC 9) without exceptions
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
ubuntu-build:
|
||||
|
||||
@@ -1,12 +1,6 @@
|
||||
name: Ubuntu 20.04 CI (GCC 9) without threads
|
||||
name: Ubuntu 20.04 CI (GCC 9) Without Threads
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
ubuntu-build:
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
name: Ubuntu 20.04 CI (GCC 9) With Memory Sanitizer
|
||||
|
||||
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
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/cache@v2
|
||||
with:
|
||||
path: dependencies/.cache
|
||||
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
||||
- name: Use cmake
|
||||
run: |
|
||||
mkdir builddebug &&
|
||||
cd builddebug &&
|
||||
cmake -DSIMDJSON_SANITIZE=ON -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
|
||||
@@ -1,12 +1,6 @@
|
||||
name: Ubuntu 20.04 CI (GCC 9) with Thread Sanitizer
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
ubuntu-build:
|
||||
|
||||
@@ -1,12 +1,6 @@
|
||||
name: Ubuntu 20.04 CI (GCC 9)
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
ubuntu-build:
|
||||
|
||||
@@ -1,12 +1,6 @@
|
||||
name: VS15-CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
ci:
|
||||
|
||||
@@ -1,12 +1,6 @@
|
||||
name: VS16-CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
ci:
|
||||
|
||||
@@ -1,12 +1,6 @@
|
||||
name: VS16-CLANG-CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
ci:
|
||||
@@ -31,7 +25,7 @@ jobs:
|
||||
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,12 +1,6 @@
|
||||
name: VS16-Ninja-CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
ci:
|
||||
|
||||
@@ -1,12 +1,6 @@
|
||||
name: VS16-NoExcept-CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
ci:
|
||||
|
||||
Vendored
+3
-2
@@ -17,7 +17,6 @@
|
||||
"__errc": "cpp",
|
||||
"__functional_base": "cpp",
|
||||
"__hash_table": "cpp",
|
||||
"__locale": "cpp",
|
||||
"__mutex_base": "cpp",
|
||||
"__node_handle": "cpp",
|
||||
"__nullptr": "cpp",
|
||||
@@ -85,6 +84,8 @@
|
||||
"utility": "cpp",
|
||||
"valarray": "cpp",
|
||||
"vector": "cpp",
|
||||
"*.ipp": "cpp"
|
||||
"*.ipp": "cpp",
|
||||
"__functional_base_03": "cpp",
|
||||
"filesystem": "cpp"
|
||||
}
|
||||
}
|
||||
+3
-3
@@ -3,7 +3,7 @@ cmake_minimum_required(VERSION 3.14)
|
||||
project(
|
||||
simdjson
|
||||
# The version number is modified by tools/release.py
|
||||
VERSION 0.9.1
|
||||
VERSION 1.0.2
|
||||
DESCRIPTION "Parsing gigabytes of JSON per second"
|
||||
HOMEPAGE_URL "https://simdjson.org/"
|
||||
LANGUAGES CXX C
|
||||
@@ -20,8 +20,8 @@ string(
|
||||
# ---- Options, variables ----
|
||||
|
||||
# These version numbers are modified by tools/release.py
|
||||
set(SIMDJSON_LIB_VERSION "8.0.0" CACHE STRING "simdjson library version")
|
||||
set(SIMDJSON_LIB_SOVERSION "8" CACHE STRING "simdjson library soversion")
|
||||
set(SIMDJSON_LIB_VERSION "9.0.0" CACHE STRING "simdjson library version")
|
||||
set(SIMDJSON_LIB_SOVERSION "9" CACHE STRING "simdjson library soversion")
|
||||
|
||||
option(SIMDJSON_ENABLE_THREADS "Link with thread support" ON)
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ PROJECT_NAME = simdjson
|
||||
# could be handy for archiving the generated documentation or if some version
|
||||
# control system is used.
|
||||
|
||||
PROJECT_NUMBER = "0.9.1"
|
||||
PROJECT_NUMBER = "1.0.2"
|
||||
|
||||
# Using the PROJECT_BRIEF tag one can provide an optional one line description
|
||||
# for a project that appears at the top of each page and should give viewer a
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
[/badge.svg)](https://simdjson.org/plots.html)
|
||||

|
||||

|
||||
[![][license img]][license] [](https://simdjson.org/api/0.9.0/index.html)
|
||||
[![][license img]][license] [](https://simdjson.org/api/1.0.0/index.html)
|
||||
|
||||
simdjson : Parsing gigabytes of JSON per second
|
||||
===============================================
|
||||
@@ -53,6 +53,7 @@ The simdjson library is easily consumable with a single .h and .cpp file.
|
||||
2. Create `quickstart.cpp`:
|
||||
|
||||
```c++
|
||||
#include <iostream>
|
||||
#include "simdjson.h"
|
||||
using namespace simdjson;
|
||||
int main(void) {
|
||||
@@ -78,7 +79,7 @@ Usage documentation is available:
|
||||
* [Performance](doc/performance.md) shows some more advanced scenarios and how to tune for them.
|
||||
* [Implementation Selection](doc/implementation-selection.md) describes runtime CPU detection and
|
||||
how you can work with it.
|
||||
* [API](https://simdjson.org/api/0.9.0/annotated.html) contains the automatically generated API documentation.
|
||||
* [API](https://simdjson.org/api/1.0.0/annotated.html) contains the automatically generated API documentation.
|
||||
|
||||
Performance results
|
||||
-------------------
|
||||
@@ -158,7 +159,7 @@ We also have an informal [blog post providing some background and context](https
|
||||
|
||||
For the video inclined, <br />
|
||||
[](http://www.youtube.com/watch?v=wlvKAT7SZIQ)<br />
|
||||
(it was the best voted talk, we're kinda proud of it).
|
||||
(It was the best voted talk, we're kinda proud of it.)
|
||||
|
||||
Funding
|
||||
-------
|
||||
|
||||
@@ -18,7 +18,7 @@ struct simdjson_ondemand {
|
||||
ondemand::document_stream::iterator i = stream.begin();
|
||||
++i; // Skip first line
|
||||
for (;i != stream.end(); ++i) {
|
||||
auto & doc = *i;
|
||||
auto doc = *i;
|
||||
size_t index{0};
|
||||
StringType copy;
|
||||
double rating;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include <benchmark/benchmark.h>
|
||||
#include <iostream>
|
||||
#include "simdjson.h"
|
||||
#include <sstream>
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include <benchmark/benchmark.h>
|
||||
#include <iostream>
|
||||
#include "simdjson.h"
|
||||
using namespace simdjson;
|
||||
using namespace benchmark;
|
||||
|
||||
@@ -18,7 +18,7 @@ struct simdjson_ondemand {
|
||||
ondemand::document_stream::iterator i = stream.begin();
|
||||
++i; // Skip first line
|
||||
for (;i != stream.end(); ++i) {
|
||||
auto & doc = *i;
|
||||
auto doc = *i;
|
||||
size_t index{0};
|
||||
StringType copy;
|
||||
double rating;
|
||||
|
||||
@@ -3,6 +3,12 @@
|
||||
#
|
||||
add_library(simdjson-internal-flags INTERFACE)
|
||||
|
||||
|
||||
option(SIMDJSON_CHECK_EOF "Check for the end of the input buffer. The setting is unnecessary since we require padding of the inputs. You should expect tests to fail with this option turned on." OFF)
|
||||
if(SIMDJSON_CHECK_EOF)
|
||||
add_compile_definitions(SIMDJSON_CHECK_EOF=1)
|
||||
endif()
|
||||
|
||||
option(SIMDJSON_SANITIZE_UNDEFINED "Sanitize undefined behavior" OFF)
|
||||
if(SIMDJSON_SANITIZE_UNDEFINED)
|
||||
add_compile_options(-fsanitize=undefined -fno-sanitize-recover=all)
|
||||
|
||||
Vendored
+2
-1
@@ -13,8 +13,9 @@ cmake_dependent_option(SIMDJSON_GOOGLE_BENCHMARKS "compile the Google Benchmark
|
||||
if(SIMDJSON_GOOGLE_BENCHMARKS)
|
||||
set_off(BENCHMARK_ENABLE_TESTING)
|
||||
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)
|
||||
endif()
|
||||
|
||||
|
||||
+757
-344
File diff suppressed because it is too large
Load Diff
@@ -1,3 +1,5 @@
|
||||
We take our documentation seriously. Please start reading the documentation before you attempt to use simdjson. We hope you will enjoy reading us.
|
||||
|
||||
* Basics: https://github.com/simdjson/simdjson/blob/master/doc/basics.md is an overview of how to use simdjson and its APIs.
|
||||
* parse_many: https://github.com/simdjson/simdjson/blob/master/doc/parse_many.md describes an interface providing features to work with files or streams containing multiple small JSON documents. As fast and convenient as possible.
|
||||
* Performance: https://github.com/simdjson/simdjson/blob/master/doc/performance.md shows some more advanced scenarios and how to tune for them.
|
||||
|
||||
+4
-1
@@ -64,7 +64,7 @@ Once you have an element, you can navigate it with idiomatic C++ iterators, oper
|
||||
|
||||
* **Extracting Values (with exceptions):** You can cast a JSON element to a native type: `double(element)` or
|
||||
`double x = json_element`. This works for double, uint64_t, int64_t, bool,
|
||||
dom::object and dom::array. An exception is thrown if the cast is not possible.
|
||||
dom::object and dom::array. An exception (`simdjson::simdjson_error`) is thrown if the cast is not possible.
|
||||
* **Extracting Values (without exceptions):** You can use a variant usage of `get()` with error codes to avoid exceptions. You first declare the variable of the appropriate type (`double`, `uint64_t`, `int64_t`, `bool`,
|
||||
`dom::object` and `dom::array`) and pass it by reference to `get()` which gives you back an error code: e.g.,
|
||||
```c++
|
||||
@@ -274,6 +274,7 @@ Our program loads the file, selects value corresponding to key "search_metadata"
|
||||
it selects the key "count" within that object.
|
||||
|
||||
```C++
|
||||
#include <iostream>
|
||||
#include "simdjson.h"
|
||||
|
||||
int main(void) {
|
||||
@@ -301,6 +302,7 @@ triggering exceptions. To do this, we use `["statuses"].at(0)["id"]`. We break t
|
||||
Observe how we use the `at` method when querying an index into an array, and not the bracket operator.
|
||||
|
||||
```C++
|
||||
#include <iostream>
|
||||
#include "simdjson.h"
|
||||
|
||||
int main(void) {
|
||||
@@ -457,6 +459,7 @@ program from continuing if there was an error.
|
||||
If one is willing to trigger exceptions, it is possible to write simpler code:
|
||||
|
||||
```C++
|
||||
#include <iostream>
|
||||
#include "simdjson.h"
|
||||
|
||||
int main(void) {
|
||||
|
||||
+15
-5
@@ -1,8 +1,16 @@
|
||||
iterate_many
|
||||
==========
|
||||
|
||||
An interface providing features to work with files or streams containing multiple small JSON documents.
|
||||
As fast and convenient as possible.
|
||||
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
|
||||
{"text":"a"}
|
||||
{"text":"b"}
|
||||
{"text":"c"}
|
||||
...
|
||||
```
|
||||
... you want to read the entries (individual JSON documents) as quickly and as conveniently as possible. Importantly, the input might span several gigabytes, but you want to use a small (fixed) amount of memory. Ideally, you'd also like the parallelize the processing (using more than one core) to speed up the process.
|
||||
|
||||
Contents
|
||||
--------
|
||||
@@ -108,7 +116,9 @@ Whitespace Characters:
|
||||
- **Linefeed**
|
||||
- **Carriage return**
|
||||
- **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)**:
|
||||
- [Newline-Delimited JSON (NDJSON)](http://ndjson.org/)
|
||||
@@ -175,7 +185,7 @@ Let us illustrate the idea with code:
|
||||
auto i = stream.begin();
|
||||
size_t count{0};
|
||||
for(; i != stream.end(); ++i) {
|
||||
auto & doc = *i;
|
||||
auto doc = *i;
|
||||
if(!i.error()) {
|
||||
std::cout << "got full document at " << i.current_index() << std::endl;
|
||||
std::cout << i.source() << std::endl;
|
||||
@@ -226,4 +236,4 @@ This will print:
|
||||
39 bytes
|
||||
```
|
||||
|
||||
Importantly, you should only call `truncated_bytes()` after iterating through all of the documents since the stream cannot tell whether there are truncated documents at the very end when it may not have accessed that part of the data yet.
|
||||
Importantly, you should only call `truncated_bytes()` after iterating through all of the documents since the stream cannot tell whether there are truncated documents at the very end when it may not have accessed that part of the data yet.
|
||||
|
||||
@@ -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
|
||||
|
||||
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.
|
||||
* 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
|
||||
|
||||
|
||||
+9
-3
@@ -1,8 +1,14 @@
|
||||
parse_many
|
||||
==========
|
||||
|
||||
An interface providing features to work with files or streams containing multiple small JSON documents.
|
||||
As fast and convenient as possible.
|
||||
An interface providing features to work with files or streams containing multiple small JSON documents. Given an input such as
|
||||
```JSON
|
||||
{"text":"a"}
|
||||
{"text":"b"}
|
||||
{"text":"c"}
|
||||
...
|
||||
```
|
||||
... you want to read the entries (individual JSON documents) as quickly and as conveniently as possible. Importantly, the input might span several gigabytes, but you want to use a small (fixed) amount of memory. Ideally, you'd also like the parallelize the processing (using more than one core) to speed up the process.
|
||||
|
||||
Contents
|
||||
--------
|
||||
@@ -227,4 +233,4 @@ Consider the following example where a truncated document (`{"key":"intentionall
|
||||
```
|
||||
|
||||
|
||||
Importantly, you should only call `truncated_bytes()` after iterating through all of the documents since the stream cannot tell whether there are truncated documents at the very end when it may not have accessed that part of the data yet.
|
||||
Importantly, you should only call `truncated_bytes()` after iterating through all of the documents since the stream cannot tell whether there are truncated documents at the very end when it may not have accessed that part of the data yet.
|
||||
|
||||
+41
-8
@@ -10,7 +10,7 @@ are still some scenarios where tuning can enhance performance.
|
||||
* [Large files and huge page support](#large-files-and-huge-page-support)
|
||||
* [Number parsing](#number-parsing)
|
||||
* [Visual Studio](#visual-studio)
|
||||
* [Downclocking](#downclocking)
|
||||
* [Power Usage and Downclocking](#power-usage-and-downclocking)
|
||||
|
||||
Reusing the parser for maximum efficiency
|
||||
-----------------------------------------
|
||||
@@ -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
|
||||
---------------------------------
|
||||
|
||||
@@ -110,19 +147,15 @@ Recent versions of Microsoft Visual Studio on Windows provides support for the L
|
||||
Under Windows, we also support the GNU GCC compiler via MSYS2. The performance of 64-bit MSYS2 under Windows excellent (on par with Linux).
|
||||
|
||||
|
||||
Downclocking
|
||||
Power Usage and Downclocking
|
||||
--------------
|
||||
|
||||
|
||||
|
||||
SIMD instructions are the public transportation of computing. Instead of using 4 distinct instructions to add numbers, you can replace them with a single instruction that does the same work. Though the one instruction is slightly more expensive, the energy used per unit of work is much less with SIMD. If you can increase your speed using SIMD instructions (NEON, SSE, AVX), you should expect to reduce your power usage.
|
||||
The simdjson library relies on SIMD instructions. SIMD instructions are the public transportation of computing. Instead of using 4 distinct instructions to add numbers, you can replace them with a single instruction that does the same work. Though the one instruction is slightly more expensive, the energy used per unit of work is much less with SIMD. If you can increase your speed using SIMD instructions (NEON, SSE, AVX), you should expect to reduce your power usage.
|
||||
|
||||
The SIMD instructions that simdjson relies upon (SSE and AVX under x64, NEON under ARM, ALTIVEC under PPC) are routinely part of runtime libraries (e.g., [Go](https://golang.org/src/runtime/memmove_amd64.s), [Glibc](https://github.com/ihtsae/glibc/commit/5f3d0b78e011d2a72f9e88b0e9ef5bc081d18f97), [LLVM](https://github.com/llvm/llvm-project/blob/96f3ea0d21b48ca088355db10d4d1a2e9bc9f884/lldb/tools/debugserver/source/MacOSX/i386/DNBArchImplI386.cpp), [Rust](https://github.com/rust-lang/rust/commit/070fad1701fb36b112853b0a6a9787a7bb7ff34c), [Java](http://hg.openjdk.java.net/jdk8u/jdk8u/hotspot/file/c1374141598c/src/cpu/x86/vm/stubGenerator_x86_64.cpp#l1297), [PHP](https://github.com/php/php-src/blob/e5cb53ec68603d4dbdd780fd3ecfca943b4fd383/ext/standard/string.c)). What distinguishes the simdjson library is that it is built from the ground up to benefit from these instructions.
|
||||
|
||||
|
||||
You should not expect the simdjson library to cause *downclocking* of your recent Intel CPU cores.
|
||||
|
||||
On some Intel processors, using SIMD instructions in a sustained manner on the same CPU core may result in a phenomenon called downclocking whereas the processor initially runs these instructions at a slow speed before reducing the frequency of the core for a short time (milliseconds). Intel refers to these states as licenses. On some current Intel processors, it occurs under two scenarios:
|
||||
You should not expect the simdjson library to cause *downclocking* of your recent Intel CPU cores. On some Intel processors, using SIMD instructions in a sustained manner on the same CPU core may result in a phenomenon called downclocking whereas the processor initially runs these instructions at a slow speed before reducing the frequency of the core for a short time (milliseconds). Intel refers to these states as licenses. On some current Intel processors, it occurs under two scenarios:
|
||||
|
||||
- [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).
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
#include <iostream>
|
||||
#include "simdjson.h"
|
||||
|
||||
int main(void) {
|
||||
simdjson::dom::parser parser;
|
||||
simdjson::dom::element tweets = parser.load("twitter.json");
|
||||
std::cout << tweets["search_metadata"]["count"] << " results." << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#include <iostream>
|
||||
#include "simdjson.h"
|
||||
|
||||
int main(void) {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#include <iostream>
|
||||
#include "simdjson.h"
|
||||
|
||||
int main(void) {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#include <iostream>
|
||||
#include "simdjson.h"
|
||||
|
||||
int main(void) {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#include <iostream>
|
||||
#include "simdjson.h"
|
||||
using namespace simdjson;
|
||||
int main(void) {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#include <iostream>
|
||||
#include "simdjson.h"
|
||||
using namespace simdjson;
|
||||
int main(void) {
|
||||
|
||||
+2
-2
@@ -18,7 +18,7 @@ The fuzzers are used in several ways.
|
||||
* oss-fuzz - heavy duty 24/7 fuzzing provided by the google driven oss-fuzz project
|
||||
|
||||
## Local fuzzing
|
||||
Just invoke fuzz/quick_check.sh, it will download the latest corpus from bintray (kept up to date by the CI fuzzers) and run the fuzzers for a short time. In case you want to run the fuzzers for longer, modify the timeout value in the script or invoke the fuzzer directly.
|
||||
Just invoke fuzz/quick_check.sh, it will download the latest corpus (kept up to date by the CI fuzzers) and run the fuzzers for a short time. In case you want to run the fuzzers for longer, modify the timeout value in the script or invoke the fuzzer directly.
|
||||
|
||||
This requires linux with clang and cmake installed (recent Debian and Ubuntu are known to work fine).
|
||||
|
||||
@@ -69,7 +69,7 @@ As little code as possible is kept at oss-fuzz since it is inconvenient to chang
|
||||
|
||||
The simdjson library does not benefit from a corpus as much as other projects, because the library is very fast and explores the input space very well. With that said, it is still beneficial to have one. The CI job stores the corpus on a remote server between runs, and is available at [www.pauldreik.se](https://readonly:readonly@www.pauldreik.se/fuzzdata/index.php?project=simdjson).
|
||||
|
||||
One can also grab the corpus as an artifact from the github actions job. Pick a run, then go to artifacts and download.
|
||||
One can also grab the corpus as an artifact from the github actions job if you are logged in at github. Pick a run, then go to artifacts and download.
|
||||
|
||||
## Fuzzing coverage
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <array>
|
||||
#include "supported_implementations.h"
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include "simdjson.h"
|
||||
#include <cstddef>
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include "supported_implementations.h"
|
||||
|
||||
|
||||
+17
-15
@@ -8,24 +8,26 @@
|
||||
|
||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
|
||||
FuzzData fd(Data, Size);
|
||||
const auto batch_size=static_cast<size_t>(fd.getInt<0,1000>());
|
||||
const auto json=simdjson::padded_string{fd.remainder_as_stringview()};
|
||||
const auto batch_size = static_cast<size_t>(fd.getInt<0,1000>());
|
||||
const auto json = simdjson::padded_string{fd.remainder_as_stringview()};
|
||||
simdjson::dom::parser parser;
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
try {
|
||||
#endif
|
||||
simdjson::dom::document_stream docs;
|
||||
if(parser.parse_many(json,batch_size).get(docs)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t bool_count=0;
|
||||
simdjson::dom::document_stream docs;
|
||||
if(parser.parse_many(json,batch_size).get(docs)) { return 0; }
|
||||
size_t bool_count1 = 0;
|
||||
size_t total_count1 = 0;
|
||||
for (auto doc : docs) {
|
||||
bool_count+=doc.is_bool();
|
||||
total_count1++;
|
||||
bool_count1 += doc.is_bool();
|
||||
}
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
} catch(...) {
|
||||
// Restart, if we made it this far, the document *must* be accessible.
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include "simdjson.h"
|
||||
#include <cstddef>
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
#include "supported_implementations.h"
|
||||
|
||||
extern "C" int VerboseTestOneInput(const uint8_t *Data, size_t Size) {
|
||||
|
||||
+4
-5
@@ -4,7 +4,7 @@
|
||||
# good when working locally developing the fuzzers or making
|
||||
# sure code changes still pass the fuzzers.
|
||||
#
|
||||
# It will download the corpus from bintray (kept up to date
|
||||
# It will download the corpus from external store (kept up to date
|
||||
# by the crontab github actions) unless a local out/ directory
|
||||
# already exists.
|
||||
#
|
||||
@@ -23,10 +23,9 @@ done
|
||||
|
||||
#download the corpus if it does not already exist
|
||||
if [ ! -d out ] ; then
|
||||
# ideally, we would download the github artifact but that requires being logged in which can not
|
||||
# easily be fixed from this shell script.
|
||||
echo "NOTE! please go to the artifacts page on https://github.com/simdjson/simdjson/actions/workflows/fuzzers.yml and download the latest corpus.tar.zip artifact manually to speed up fuzzing"
|
||||
sleep 5s
|
||||
# the corpus is also available for download from the artifacts page on https://github.com/simdjson/simdjson/actions/workflows/fuzzers.yml
|
||||
# but that requires being logged in so can not be easily done from this script.
|
||||
wget -O - https://readonly:readonly@www.pauldreik.se/fuzzdata/index.php?project=simdjson |tar xzf -
|
||||
fi
|
||||
|
||||
# By default, use the debug friendly variant since this script is intended
|
||||
|
||||
@@ -19,7 +19,7 @@ static simdjson_really_inline uint32_t parse_eight_digits_unrolled(const uint8_t
|
||||
} // namespace SIMDJSON_IMPLEMENTATION
|
||||
} // namespace simdjson
|
||||
|
||||
#define SWAR_NUMBER_PARSING
|
||||
#define SIMDJSON_SWAR_NUMBER_PARSING 1
|
||||
|
||||
#include "simdjson/generic/numberparsing.h"
|
||||
|
||||
|
||||
@@ -57,6 +57,19 @@ simdjson_really_inline uint8x16_t make_uint8x16_t(uint8_t x1, uint8_t x2, uint
|
||||
return x;
|
||||
}
|
||||
|
||||
simdjson_really_inline uint8x8_t make_uint8x8_t(uint8_t x1, uint8_t x2, uint8_t x3, uint8_t x4,
|
||||
uint8_t x5, uint8_t x6, uint8_t x7, uint8_t x8) {
|
||||
uint8x8_t x{};
|
||||
x = vset_lane_u8(x1, x, 0);
|
||||
x = vset_lane_u8(x2, x, 1);
|
||||
x = vset_lane_u8(x3, x, 2);
|
||||
x = vset_lane_u8(x4, x, 3);
|
||||
x = vset_lane_u8(x5, x, 4);
|
||||
x = vset_lane_u8(x6, x, 5);
|
||||
x = vset_lane_u8(x7, x, 6);
|
||||
x = vset_lane_u8(x8, x, 7);
|
||||
return x;
|
||||
}
|
||||
|
||||
// We have to do the same work for make_int8x16_t
|
||||
simdjson_really_inline int8x16_t make_int8x16_t(int8_t x1, int8_t x2, int8_t x3, int8_t x4,
|
||||
@@ -289,6 +302,27 @@ simdjson_really_inline int8x16_t make_int8x16_t(int8_t x1, int8_t x2, int8_t x
|
||||
vst1q_u8(reinterpret_cast<uint8_t*>(output), answer);
|
||||
}
|
||||
|
||||
// Copies all bytes corresponding to a 0 in the low half of the mask (interpreted as a
|
||||
// bitset) to output1, then those corresponding to a 0 in the high half to output2.
|
||||
template<typename L>
|
||||
simdjson_really_inline void compress_halves(uint16_t mask, L *output1, L *output2) const {
|
||||
using internal::thintable_epi8;
|
||||
uint8_t mask1 = uint8_t(mask); // least significant 8 bits
|
||||
uint8_t mask2 = uint8_t(mask >> 8); // most significant 8 bits
|
||||
uint8x8_t compactmask1 = vcreate_u8(thintable_epi8[mask1]);
|
||||
uint8x8_t compactmask2 = vcreate_u8(thintable_epi8[mask2]);
|
||||
// we increment by 0x08 the second half of the mask
|
||||
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||
uint8x8_t inc = make_uint8x8_t(0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08);
|
||||
#else
|
||||
uint8x8_t inc = {0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08};
|
||||
#endif
|
||||
compactmask2 = vadd_u8(compactmask2, inc);
|
||||
// store each result (with the second store possibly overlapping the first)
|
||||
vst1_u8((uint8_t*)output1, vqtbl1_u8(*this, compactmask1));
|
||||
vst1_u8((uint8_t*)output2, vqtbl1_u8(*this, compactmask2));
|
||||
}
|
||||
|
||||
template<typename L>
|
||||
simdjson_really_inline simd8<L> lookup_16(
|
||||
L replace0, L replace1, L replace2, L replace3,
|
||||
@@ -439,11 +473,15 @@ simdjson_really_inline int8x16_t make_int8x16_t(int8_t x1, int8_t x2, int8_t x
|
||||
}
|
||||
|
||||
|
||||
simdjson_really_inline void compress(uint64_t mask, T * output) const {
|
||||
this->chunks[0].compress(uint16_t(mask), output);
|
||||
this->chunks[1].compress(uint16_t(mask >> 16), output + 16 - count_ones(mask & 0xFFFF));
|
||||
this->chunks[2].compress(uint16_t(mask >> 32), output + 32 - count_ones(mask & 0xFFFFFFFF));
|
||||
this->chunks[3].compress(uint16_t(mask >> 48), output + 48 - count_ones(mask & 0xFFFFFFFFFFFF));
|
||||
simdjson_really_inline uint64_t compress(uint64_t mask, T * output) const {
|
||||
uint64_t popcounts = vget_lane_u64(vreinterpret_u64_u8(vcnt_u8(vcreate_u8(~mask))), 0);
|
||||
// compute the prefix sum of the popcounts of each byte
|
||||
uint64_t offsets = popcounts * 0x0101010101010101;
|
||||
this->chunks[0].compress_halves(uint16_t(mask), output, &output[popcounts & 0xFF]);
|
||||
this->chunks[1].compress_halves(uint16_t(mask >> 16), &output[(offsets >> 8) & 0xFF], &output[(offsets >> 16) & 0xFF]);
|
||||
this->chunks[2].compress_halves(uint16_t(mask >> 32), &output[(offsets >> 24) & 0xFF], &output[(offsets >> 32) & 0xFF]);
|
||||
this->chunks[3].compress_halves(uint16_t(mask >> 48), &output[(offsets >> 40) & 0xFF], &output[(offsets >> 48) & 0xFF]);
|
||||
return offsets >> 56;
|
||||
}
|
||||
|
||||
simdjson_really_inline uint64_t to_bitmask() const {
|
||||
|
||||
@@ -253,11 +253,8 @@ namespace std {
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Feature flag for partially-implemented "don't require padding" feature
|
||||
// TODO remove once feature complete.
|
||||
#ifndef __SIMDJSON_CHECK_EOF
|
||||
# define __SIMDJSON_CHECK_EOF 1
|
||||
#endif
|
||||
// The SIMDJSON_CHECK_EOF macro is a feature flag for the "don't require padding"
|
||||
// feature.
|
||||
|
||||
#if SIMDJSON_CPLUSPLUS17
|
||||
// if we have C++, then fallthrough is a default attribute
|
||||
@@ -268,11 +265,11 @@ namespace std {
|
||||
#if __has_attribute(__fallthrough__)
|
||||
// we are good to go:
|
||||
# define simdjson_fallthrough __attribute__((__fallthrough__))
|
||||
#endif
|
||||
#endif
|
||||
#endif // __has_attribute(__fallthrough__)
|
||||
#endif // SIMDJSON_CPLUSPLUS17
|
||||
// on some systems, we simply do not have support for fallthrough, so use a default:
|
||||
#ifndef simdjson_fallthrough
|
||||
# define simdjson_fallthrough do {} while (0) /* fallthrough */
|
||||
#endif
|
||||
#endif // simdjson_fallthrough
|
||||
|
||||
#endif // SIMDJSON_COMMON_DEFS_H
|
||||
|
||||
@@ -256,6 +256,7 @@ inline size_t document_stream::size_in_bytes() const noexcept {
|
||||
}
|
||||
|
||||
inline size_t document_stream::truncated_bytes() const noexcept {
|
||||
if(error == CAPACITY) { return len - batch_start; }
|
||||
return parser->implementation->structural_indexes[parser->implementation->n_structural_indexes] - parser->implementation->structural_indexes[parser->implementation->n_structural_indexes + 1];
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <ostream>
|
||||
#include <iterator>
|
||||
#include <limits>
|
||||
#include <stdexcept>
|
||||
|
||||
@@ -157,7 +157,10 @@ simdjson_really_inline void mini_formatter::string(std::string_view unescaped) {
|
||||
size_t i = 0;
|
||||
// Fast path for the case where we have no control character, no ", and no backslash.
|
||||
// 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,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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};
|
||||
for(;i + 8 <= unescaped.length(); i += 8) {
|
||||
// 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])]
|
||||
| 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])]
|
||||
|
||||
@@ -38,6 +38,8 @@ enum error_code {
|
||||
OUT_OF_ORDER_ITERATION, ///< tried to iterate an array or object out of order
|
||||
INSUFFICIENT_PADDING, ///< The JSON doesn't have enough padding for simdjson to safely parse it.
|
||||
INCOMPLETE_ARRAY_OR_OBJECT, ///< The document ends early.
|
||||
SCALAR_DOCUMENT_AS_VALUE, ///< A scalar document is treated as a value.
|
||||
OUT_OF_BOUNDS, ///< Attempted to access location outside of document.
|
||||
NUM_ERROR_CODES
|
||||
};
|
||||
|
||||
@@ -287,7 +289,7 @@ struct simdjson_result : public internal::simdjson_result_base<T> {
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
|
||||
template<typename T>
|
||||
inline std::ostream& operator<<(std::ostream& out, simdjson_result<T> value) noexcept { return out << value.value(); }
|
||||
inline std::ostream& operator<<(std::ostream& out, simdjson_result<T> value) { return out << value.value(); }
|
||||
#endif // SIMDJSON_EXCEPTIONS
|
||||
|
||||
#ifndef SIMDJSON_DISABLE_DEPRECATED_API
|
||||
|
||||
@@ -27,7 +27,8 @@ static simdjson_really_inline uint32_t parse_eight_digits_unrolled(const uint8_t
|
||||
} // namespace SIMDJSON_IMPLEMENTATION
|
||||
} // namespace simdjson
|
||||
|
||||
#define SWAR_NUMBER_PARSING
|
||||
#define SIMDJSON_SWAR_NUMBER_PARSING 1
|
||||
|
||||
#include "simdjson/generic/numberparsing.h"
|
||||
|
||||
#endif // SIMDJSON_FALLBACK_NUMBERPARSING_H
|
||||
|
||||
@@ -49,18 +49,23 @@ simdjson_really_inline implementation_simdjson_result_base<T>::operator T&&() &&
|
||||
return std::forward<implementation_simdjson_result_base<T>>(*this).take_value();
|
||||
}
|
||||
|
||||
#endif // SIMDJSON_EXCEPTIONS
|
||||
|
||||
template<typename T>
|
||||
simdjson_really_inline const T& implementation_simdjson_result_base<T>::value_unsafe() const& noexcept {
|
||||
return this->first;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
simdjson_really_inline T& implementation_simdjson_result_base<T>::value_unsafe() & noexcept {
|
||||
return this->first;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
simdjson_really_inline T&& implementation_simdjson_result_base<T>::value_unsafe() && noexcept {
|
||||
return std::forward<T>(this->first);
|
||||
}
|
||||
|
||||
#endif // SIMDJSON_EXCEPTIONS
|
||||
|
||||
template<typename T>
|
||||
simdjson_really_inline implementation_simdjson_result_base<T>::implementation_simdjson_result_base(T &&value, error_code error) noexcept
|
||||
: first{std::forward<T>(value)}, second{error} {}
|
||||
|
||||
@@ -97,22 +97,28 @@ struct implementation_simdjson_result_base {
|
||||
*/
|
||||
simdjson_really_inline operator T&&() && noexcept(false);
|
||||
|
||||
|
||||
#endif // SIMDJSON_EXCEPTIONS
|
||||
|
||||
/**
|
||||
* Get the result value. This function is safe if and only
|
||||
* the error() method returns a value that evaluates to false.
|
||||
*/
|
||||
simdjson_really_inline const T& value_unsafe() const& noexcept;
|
||||
|
||||
/**
|
||||
* Get the result value. This function is safe if and only
|
||||
* the error() method returns a value that evaluates to false.
|
||||
*/
|
||||
simdjson_really_inline T& value_unsafe() & noexcept;
|
||||
/**
|
||||
* Take the result value (move it). This function is safe if and only
|
||||
* the error() method returns a value that evaluates to false.
|
||||
*/
|
||||
simdjson_really_inline T&& value_unsafe() && noexcept;
|
||||
|
||||
#endif // SIMDJSON_EXCEPTIONS
|
||||
|
||||
T first{};
|
||||
error_code second{UNINITIALIZED};
|
||||
protected:
|
||||
/** users should never directly access first and second. **/
|
||||
T first{}; /** Users should never directly access 'first'. **/
|
||||
error_code second{UNINITIALIZED}; /** Users should never directly access 'second'. **/
|
||||
}; // struct implementation_simdjson_result_base
|
||||
|
||||
} // namespace SIMDJSON_IMPLEMENTATION
|
||||
|
||||
@@ -3,6 +3,18 @@
|
||||
|
||||
namespace simdjson {
|
||||
namespace SIMDJSON_IMPLEMENTATION {
|
||||
|
||||
namespace ondemand {
|
||||
/**
|
||||
* The type of a JSON number
|
||||
*/
|
||||
enum class number_type {
|
||||
floating_point_number=1, /// a binary64 number
|
||||
signed_integer, /// a signed integer that fits in a 64-bit word using two's complement
|
||||
unsigned_integer /// a positive integer larger or equal to 1<<63
|
||||
};
|
||||
}
|
||||
|
||||
namespace {
|
||||
/// @private
|
||||
namespace numberparsing {
|
||||
@@ -367,14 +379,16 @@ simdjson_really_inline error_code parse_decimal(simdjson_unused const uint8_t *c
|
||||
// the integer into a float in a lossless manner.
|
||||
const uint8_t *const first_after_period = p;
|
||||
|
||||
#ifdef SWAR_NUMBER_PARSING
|
||||
#ifdef SIMDJSON_SWAR_NUMBER_PARSING
|
||||
#if SIMDJSON_SWAR_NUMBER_PARSING
|
||||
// this helps if we have lots of decimals!
|
||||
// this turns out to be frequent enough.
|
||||
if (is_made_of_eight_digits_fast(p)) {
|
||||
i = i * 100000000 + parse_eight_digits_unrolled(p);
|
||||
p += 8;
|
||||
}
|
||||
#endif
|
||||
#endif // SIMDJSON_SWAR_NUMBER_PARSING
|
||||
#endif // #ifdef SIMDJSON_SWAR_NUMBER_PARSING
|
||||
// Unrolling the first digit makes a small difference on some implementations (e.g. westmere)
|
||||
if (parse_digit(*p, i)) { ++p; }
|
||||
while (parse_digit(*p, i)) { p++; }
|
||||
@@ -441,9 +455,7 @@ simdjson_really_inline size_t significant_digits(const uint8_t * start_digits, s
|
||||
// It is possible that the integer had an overflow.
|
||||
// We have to handle the case where we have 0.0000somenumber.
|
||||
const uint8_t *start = start_digits;
|
||||
while ((*start == '0') || (*start == '.')) {
|
||||
start++;
|
||||
}
|
||||
while ((*start == '0') || (*start == '.')) { ++start; }
|
||||
// we over-decrement by one when there is a '.'
|
||||
return digit_count - size_t(start - start_digits);
|
||||
}
|
||||
@@ -513,7 +525,12 @@ simdjson_really_inline error_code parse_number(const uint8_t *const, W &writer)
|
||||
simdjson_unused simdjson_really_inline simdjson_result<uint64_t> parse_unsigned(const uint8_t * const src) noexcept { return 0; }
|
||||
simdjson_unused simdjson_really_inline simdjson_result<int64_t> parse_integer(const uint8_t * const src) noexcept { return 0; }
|
||||
simdjson_unused simdjson_really_inline simdjson_result<double> parse_double(const uint8_t * const src) noexcept { return 0; }
|
||||
|
||||
simdjson_unused simdjson_really_inline simdjson_result<uint64_t> parse_unsigned_in_string(const uint8_t * const src) noexcept { return 0; }
|
||||
simdjson_unused simdjson_really_inline simdjson_result<int64_t> parse_integer_in_string(const uint8_t * const src) noexcept { return 0; }
|
||||
simdjson_unused simdjson_really_inline simdjson_result<double> parse_double_in_string(const uint8_t * const src) noexcept { return 0; }
|
||||
simdjson_unused simdjson_really_inline bool is_negative(const uint8_t * src) noexcept { return false; }
|
||||
simdjson_unused simdjson_really_inline simdjson_result<bool> is_integer(const uint8_t * src) noexcept { return false; }
|
||||
simdjson_unused simdjson_really_inline simdjson_result<ondemand::number_type> get_number_type(const uint8_t * src) noexcept { return ondemand::number_type::signed_integer; }
|
||||
#else
|
||||
|
||||
// parse the number at src
|
||||
@@ -592,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:
|
||||
// 10,000,000,000,000,000,000.
|
||||
// - 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); }
|
||||
}
|
||||
@@ -715,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:
|
||||
// 10,000,000,000,000,000,000.
|
||||
// - 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; }
|
||||
}
|
||||
@@ -765,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:
|
||||
// 10,000,000,000,000,000,000.
|
||||
// - 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; }
|
||||
}
|
||||
@@ -773,6 +790,56 @@ simdjson_unused simdjson_really_inline simdjson_result<uint64_t> parse_unsigned(
|
||||
return i;
|
||||
}
|
||||
|
||||
// Parse any number from 0 to 18,446,744,073,709,551,615
|
||||
simdjson_unused simdjson_really_inline simdjson_result<uint64_t> parse_unsigned_in_string(const uint8_t * const src) noexcept {
|
||||
const uint8_t *p = src + 1;
|
||||
//
|
||||
// Parse the integer part.
|
||||
//
|
||||
// PERF NOTE: we don't use is_made_of_eight_digits_fast because large integers like 123456789 are rare
|
||||
const uint8_t *const start_digits = p;
|
||||
uint64_t i = 0;
|
||||
while (parse_digit(*p, i)) { p++; }
|
||||
|
||||
// If there were no digits, or if the integer starts with 0 and has more than one digit, it's an error.
|
||||
// Optimization note: size_t is expected to be unsigned.
|
||||
size_t digit_count = size_t(p - start_digits);
|
||||
// The longest positive 64-bit number is 20 digits.
|
||||
// We do it this way so we don't trigger this branch unless we must.
|
||||
// Optimization note: the compiler can probably merge
|
||||
// ((digit_count == 0) || (digit_count > 20))
|
||||
// into a single branch since digit_count is unsigned.
|
||||
if ((digit_count == 0) || (digit_count > 20)) { return INCORRECT_TYPE; }
|
||||
// Here digit_count > 0.
|
||||
if (('0' == *start_digits) && (digit_count > 1)) { return NUMBER_ERROR; }
|
||||
// We can do the following...
|
||||
// if (!jsoncharutils::is_structural_or_whitespace(*p)) {
|
||||
// return (*p == '.' || *p == 'e' || *p == 'E') ? INCORRECT_TYPE : NUMBER_ERROR;
|
||||
// }
|
||||
// as a single table lookup:
|
||||
if (*p != '"') { return NUMBER_ERROR; }
|
||||
|
||||
if (digit_count == 20) {
|
||||
// Positive overflow check:
|
||||
// - A 20 digit number starting with 2-9 is overflow, because 18,446,744,073,709,551,615 is the
|
||||
// biggest uint64_t.
|
||||
// - A 20 digit number starting with 1 is overflow if it is less than INT64_MAX.
|
||||
// If we got here, it's a 20 digit number starting with the digit "1".
|
||||
// - If a 20 digit number starting with 1 overflowed (i*10+digit), the result will be smaller
|
||||
// than 1,553,255,926,290,448,384.
|
||||
// - That is smaller than the smallest possible 20-digit number the user could write:
|
||||
// 10,000,000,000,000,000,000.
|
||||
// - 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 INT64_MAX.
|
||||
//
|
||||
// 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;
|
||||
}
|
||||
|
||||
// Parse any number from -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807
|
||||
simdjson_unused simdjson_really_inline simdjson_result<int64_t> parse_integer(const uint8_t *src) noexcept {
|
||||
//
|
||||
@@ -859,6 +926,48 @@ simdjson_unused simdjson_really_inline simdjson_result<int64_t> parse_integer(co
|
||||
return negative ? (~i+1) : i;
|
||||
}
|
||||
|
||||
// Parse any number from -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807
|
||||
simdjson_unused simdjson_really_inline simdjson_result<int64_t> parse_integer_in_string(const uint8_t *src) noexcept {
|
||||
//
|
||||
// Check for minus sign
|
||||
//
|
||||
bool negative = (*(src + 1) == '-');
|
||||
const uint8_t *p = src + negative + 1;
|
||||
|
||||
//
|
||||
// Parse the integer part.
|
||||
//
|
||||
// PERF NOTE: we don't use is_made_of_eight_digits_fast because large integers like 123456789 are rare
|
||||
const uint8_t *const start_digits = p;
|
||||
uint64_t i = 0;
|
||||
while (parse_digit(*p, i)) { p++; }
|
||||
|
||||
// If there were no digits, or if the integer starts with 0 and has more than one digit, it's an error.
|
||||
// Optimization note: size_t is expected to be unsigned.
|
||||
size_t digit_count = size_t(p - start_digits);
|
||||
// We go from
|
||||
// -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807
|
||||
// so we can never represent numbers that have more than 19 digits.
|
||||
size_t longest_digit_count = 19;
|
||||
// Optimization note: the compiler can probably merge
|
||||
// ((digit_count == 0) || (digit_count > longest_digit_count))
|
||||
// into a single branch since digit_count is unsigned.
|
||||
if ((digit_count == 0) || (digit_count > longest_digit_count)) { return INCORRECT_TYPE; }
|
||||
// Here digit_count > 0.
|
||||
if (('0' == *start_digits) && (digit_count > 1)) { return NUMBER_ERROR; }
|
||||
// We can do the following...
|
||||
// if (!jsoncharutils::is_structural_or_whitespace(*p)) {
|
||||
// return (*p == '.' || *p == 'e' || *p == 'E') ? INCORRECT_TYPE : NUMBER_ERROR;
|
||||
// }
|
||||
// as a single table lookup:
|
||||
if(*p != '"') { return NUMBER_ERROR; }
|
||||
// Negative numbers have can go down to - INT64_MAX - 1 whereas positive numbers are limited to INT64_MAX.
|
||||
// Performance note: This check is only needed when digit_count == longest_digit_count but it is
|
||||
// so cheap that we might as well always make it.
|
||||
if(i > uint64_t(INT64_MAX) + uint64_t(negative)) { return INCORRECT_TYPE; }
|
||||
return negative ? (~i+1) : i;
|
||||
}
|
||||
|
||||
simdjson_unused simdjson_really_inline simdjson_result<double> parse_double(const uint8_t * src) noexcept {
|
||||
//
|
||||
// Check for minus sign
|
||||
@@ -937,6 +1046,38 @@ simdjson_unused simdjson_really_inline simdjson_result<double> parse_double(cons
|
||||
return d;
|
||||
}
|
||||
|
||||
simdjson_unused simdjson_really_inline bool is_negative(const uint8_t * src) noexcept {
|
||||
return (*src == '-');
|
||||
}
|
||||
|
||||
simdjson_unused simdjson_really_inline simdjson_result<bool> is_integer(const uint8_t * src) noexcept {
|
||||
bool negative = (*src == '-');
|
||||
src += negative;
|
||||
const uint8_t *p = src;
|
||||
while(static_cast<uint8_t>(*p - '0') <= 9) { p++; }
|
||||
if ( p == src ) { return NUMBER_ERROR; }
|
||||
if (jsoncharutils::is_structural_or_whitespace(*p)) { return true; }
|
||||
return false;
|
||||
}
|
||||
|
||||
simdjson_unused simdjson_really_inline simdjson_result<ondemand::number_type> get_number_type(const uint8_t * src) noexcept {
|
||||
bool negative = (*src == '-');
|
||||
src += negative;
|
||||
const uint8_t *p = src;
|
||||
while(static_cast<uint8_t>(*p - '0') <= 9) { p++; }
|
||||
if ( p == src ) { return NUMBER_ERROR; }
|
||||
if (jsoncharutils::is_structural_or_whitespace(*p)) {
|
||||
int digit_count = int(p - src);
|
||||
if(digit_count >= 19) {
|
||||
const uint8_t * smaller_big_integer = reinterpret_cast<const uint8_t *>("9223372036854775808");
|
||||
if((digit_count >= 20) || (memcmp(src, smaller_big_integer, 19) >= 0)) {
|
||||
return ondemand::number_type::unsigned_integer;
|
||||
}
|
||||
}
|
||||
return ondemand::number_type::signed_integer;
|
||||
}
|
||||
return ondemand::number_type::floating_point_number;
|
||||
}
|
||||
|
||||
// Never read at src_end or beyond
|
||||
simdjson_unused simdjson_really_inline simdjson_result<double> parse_double(const uint8_t * src, const uint8_t * const src_end) noexcept {
|
||||
@@ -1020,6 +1161,83 @@ simdjson_unused simdjson_really_inline simdjson_result<double> parse_double(cons
|
||||
return d;
|
||||
}
|
||||
|
||||
simdjson_unused simdjson_really_inline simdjson_result<double> parse_double_in_string(const uint8_t * src) noexcept {
|
||||
//
|
||||
// Check for minus sign
|
||||
//
|
||||
bool negative = (*(src + 1) == '-');
|
||||
src += negative + 1;
|
||||
|
||||
//
|
||||
// Parse the integer part.
|
||||
//
|
||||
uint64_t i = 0;
|
||||
const uint8_t *p = src;
|
||||
p += parse_digit(*p, i);
|
||||
bool leading_zero = (i == 0);
|
||||
while (parse_digit(*p, i)) { p++; }
|
||||
// no integer digits, or 0123 (zero must be solo)
|
||||
if ( p == src ) { return INCORRECT_TYPE; }
|
||||
if ( (leading_zero && p != src+1)) { return NUMBER_ERROR; }
|
||||
|
||||
//
|
||||
// Parse the decimal part.
|
||||
//
|
||||
int64_t exponent = 0;
|
||||
bool overflow;
|
||||
if (simdjson_likely(*p == '.')) {
|
||||
p++;
|
||||
const uint8_t *start_decimal_digits = p;
|
||||
if (!parse_digit(*p, i)) { return NUMBER_ERROR; } // no decimal digits
|
||||
p++;
|
||||
while (parse_digit(*p, i)) { p++; }
|
||||
exponent = -(p - start_decimal_digits);
|
||||
|
||||
// Overflow check. More than 19 digits (minus the decimal) may be overflow.
|
||||
overflow = p-src-1 > 19;
|
||||
if (simdjson_unlikely(overflow && leading_zero)) {
|
||||
// Skip leading 0.00000 and see if it still overflows
|
||||
const uint8_t *start_digits = src + 2;
|
||||
while (*start_digits == '0') { start_digits++; }
|
||||
overflow = start_digits-src > 19;
|
||||
}
|
||||
} else {
|
||||
overflow = p-src > 19;
|
||||
}
|
||||
|
||||
//
|
||||
// Parse the exponent
|
||||
//
|
||||
if (*p == 'e' || *p == 'E') {
|
||||
p++;
|
||||
bool exp_neg = *p == '-';
|
||||
p += exp_neg || *p == '+';
|
||||
|
||||
uint64_t exp = 0;
|
||||
const uint8_t *start_exp_digits = p;
|
||||
while (parse_digit(*p, exp)) { p++; }
|
||||
// no exp digits, or 20+ exp digits
|
||||
if (p-start_exp_digits == 0 || p-start_exp_digits > 19) { return NUMBER_ERROR; }
|
||||
|
||||
exponent += exp_neg ? 0-exp : exp;
|
||||
}
|
||||
|
||||
if (*p != '"') { return NUMBER_ERROR; }
|
||||
|
||||
overflow = overflow || exponent < simdjson::internal::smallest_power || exponent > simdjson::internal::largest_power;
|
||||
|
||||
//
|
||||
// Assemble (or slow-parse) the float
|
||||
//
|
||||
double d;
|
||||
if (simdjson_likely(!overflow)) {
|
||||
if (compute_float_64(exponent, i, negative, d)) { return d; }
|
||||
}
|
||||
if (!parse_float_fallback(src-negative, &d)) {
|
||||
return NUMBER_ERROR;
|
||||
}
|
||||
return d;
|
||||
}
|
||||
} //namespace {}
|
||||
#endif // SIMDJSON_SKIPNUMBERPARSING
|
||||
|
||||
|
||||
@@ -82,10 +82,14 @@ simdjson_really_inline simdjson_result<std::string_view> array::raw_json() noexc
|
||||
const uint8_t * starting_point{iter.peek_start()};
|
||||
auto error = consume();
|
||||
if(error) { return error; }
|
||||
const uint8_t * final_point{iter._json_iter->peek(0)};
|
||||
// After 'consume()', we could be left pointing just beyond the document, but that
|
||||
// is ok because we are not going to dereference the final pointer position, we just
|
||||
// use it to compute the length in bytes.
|
||||
const uint8_t * final_point{iter._json_iter->unsafe_pointer()};
|
||||
return std::string_view(reinterpret_cast<const char*>(starting_point), size_t(final_point - starting_point));
|
||||
}
|
||||
|
||||
SIMDJSON_DISABLE_STRICT_OVERFLOW_WARNING
|
||||
simdjson_really_inline simdjson_result<size_t> array::count_elements() & noexcept {
|
||||
size_t count{0};
|
||||
// Important: we do not consume any of the values.
|
||||
@@ -98,6 +102,17 @@ simdjson_really_inline simdjson_result<size_t> array::count_elements() & noexcep
|
||||
return count;
|
||||
}
|
||||
|
||||
simdjson_really_inline simdjson_result<bool> array::is_empty() & noexcept {
|
||||
bool is_not_empty;
|
||||
auto error = iter.reset_array().get(is_not_empty);
|
||||
if(error) { return error; }
|
||||
return !is_not_empty;
|
||||
}
|
||||
|
||||
inline simdjson_result<bool> array::reset() & noexcept {
|
||||
return iter.reset_array();
|
||||
}
|
||||
|
||||
inline simdjson_result<value> array::at_pointer(std::string_view json_pointer) noexcept {
|
||||
if (json_pointer[0] != '/') { return INVALID_JSON_POINTER; }
|
||||
json_pointer = json_pointer.substr(1);
|
||||
@@ -176,6 +191,10 @@ simdjson_really_inline simdjson_result<size_t> simdjson_result<SIMDJSON_IMPLEME
|
||||
if (error()) { return error(); }
|
||||
return first.count_elements();
|
||||
}
|
||||
simdjson_really_inline simdjson_result<bool> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array>::is_empty() & noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.is_empty();
|
||||
}
|
||||
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array>::at(size_t index) noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.at(index);
|
||||
|
||||
@@ -41,9 +41,32 @@ public:
|
||||
* 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 array is empty, it is more performant to use
|
||||
* the is_empty() method.
|
||||
*/
|
||||
simdjson_really_inline simdjson_result<size_t> count_elements() & noexcept;
|
||||
|
||||
/**
|
||||
* This method scans the beginning of the array and checks whether the
|
||||
* array is empty.
|
||||
* The runtime complexity is constant time. After
|
||||
* calling this function, if successful, the array 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.
|
||||
*/
|
||||
simdjson_really_inline simdjson_result<bool> is_empty() & noexcept;
|
||||
/**
|
||||
* Reset the iterator so that we are pointing back at the
|
||||
* beginning of the array. You should still consume values only once even if you
|
||||
* can iterate through the array more than once. If you unescape a string
|
||||
* within the array more than once, you have unsafe code. Note that rewinding
|
||||
* an array means that you may need to reparse it anew: it is not a free
|
||||
* operation.
|
||||
*
|
||||
* @returns true if the array contains some elements (not empty)
|
||||
*/
|
||||
inline simdjson_result<bool> reset() & noexcept;
|
||||
/**
|
||||
* Get the value associated with the given JSON pointer. We use the RFC 6901
|
||||
* https://tools.ietf.org/html/rfc6901 standard, interpreting the current node
|
||||
@@ -79,6 +102,14 @@ public:
|
||||
*/
|
||||
simdjson_really_inline simdjson_result<std::string_view> raw_json() noexcept;
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @return The value at the given index, or:
|
||||
* - INDEX_OUT_OF_BOUNDS if the array index is larger than an array length
|
||||
*/
|
||||
simdjson_really_inline simdjson_result<value> at(size_t index) noexcept;
|
||||
protected:
|
||||
/**
|
||||
* Go to the end of the array, no matter where you are right now.
|
||||
@@ -121,15 +152,6 @@ protected:
|
||||
*/
|
||||
simdjson_really_inline array(const value_iterator &iter) noexcept;
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @return The value at the given index, or:
|
||||
* - INDEX_OUT_OF_BOUNDS if the array index is larger than an array length
|
||||
*/
|
||||
simdjson_really_inline simdjson_result<value> at(size_t index) noexcept;
|
||||
|
||||
/**
|
||||
* Iterator marking current position.
|
||||
*
|
||||
@@ -159,7 +181,9 @@ public:
|
||||
|
||||
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<size_t> count_elements() & noexcept;
|
||||
inline simdjson_result<size_t> count_elements() & noexcept;
|
||||
inline simdjson_result<bool> is_empty() & noexcept;
|
||||
inline simdjson_result<bool> reset() & 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_pointer(std::string_view json_pointer) noexcept;
|
||||
};
|
||||
|
||||
@@ -20,6 +20,13 @@ inline std::string document::to_debug_string() noexcept {
|
||||
return iter.to_string();
|
||||
}
|
||||
|
||||
inline simdjson_result<const char *> document::current_location() noexcept {
|
||||
return iter.current_location();
|
||||
}
|
||||
|
||||
inline bool document::is_alive() noexcept {
|
||||
return iter.is_alive();
|
||||
}
|
||||
simdjson_really_inline value_iterator document::resume_value_iterator() noexcept {
|
||||
return value_iterator(&iter, 1, iter.root_position());
|
||||
}
|
||||
@@ -33,24 +40,19 @@ simdjson_really_inline simdjson_result<object> document::start_or_resume_object(
|
||||
return object::resume(resume_value_iterator());
|
||||
}
|
||||
}
|
||||
simdjson_really_inline simdjson_result<value> document::get_value_unsafe() noexcept {
|
||||
simdjson_really_inline simdjson_result<value> document::get_value() noexcept {
|
||||
// Make sure we start any arrays or objects before returning, so that start_root_<object/array>()
|
||||
// gets called.
|
||||
iter.assert_at_document_depth();
|
||||
switch (*iter.peek()) {
|
||||
case '[': {
|
||||
array result;
|
||||
SIMDJSON_TRY( get_array().get(result) );
|
||||
return value(result.iter);
|
||||
}
|
||||
case '{': {
|
||||
object result;
|
||||
SIMDJSON_TRY( get_object().get(result) );
|
||||
return value(result.iter);
|
||||
}
|
||||
default:
|
||||
// TODO it is still wrong to convert this to a value! get_root_bool / etc. will not be
|
||||
// called if you do this.
|
||||
case '[':
|
||||
case '{':
|
||||
return value(get_root_value_iterator());
|
||||
default:
|
||||
// Unfortunately, scalar documents are a special case in simdjson and they cannot
|
||||
// be safely converted to value instances.
|
||||
return SCALAR_DOCUMENT_AS_VALUE;
|
||||
// return value(get_root_value_iterator());
|
||||
}
|
||||
}
|
||||
simdjson_really_inline simdjson_result<array> document::get_array() & noexcept {
|
||||
@@ -64,12 +66,21 @@ simdjson_really_inline simdjson_result<object> document::get_object() & noexcept
|
||||
simdjson_really_inline simdjson_result<uint64_t> document::get_uint64() noexcept {
|
||||
return get_root_value_iterator().get_root_uint64();
|
||||
}
|
||||
simdjson_really_inline simdjson_result<uint64_t> document::get_uint64_in_string() noexcept {
|
||||
return get_root_value_iterator().get_root_uint64_in_string();
|
||||
}
|
||||
simdjson_really_inline simdjson_result<int64_t> document::get_int64() noexcept {
|
||||
return get_root_value_iterator().get_root_int64();
|
||||
}
|
||||
simdjson_really_inline simdjson_result<int64_t> document::get_int64_in_string() noexcept {
|
||||
return get_root_value_iterator().get_root_int64_in_string();
|
||||
}
|
||||
simdjson_really_inline simdjson_result<double> document::get_double() noexcept {
|
||||
return get_root_value_iterator().get_root_double();
|
||||
}
|
||||
simdjson_really_inline simdjson_result<double> document::get_double_in_string() noexcept {
|
||||
return get_root_value_iterator().get_root_double_in_string();
|
||||
}
|
||||
simdjson_really_inline simdjson_result<std::string_view> document::get_string() noexcept {
|
||||
return get_root_value_iterator().get_root_string();
|
||||
}
|
||||
@@ -91,6 +102,7 @@ template<> simdjson_really_inline simdjson_result<double> document::get() & noex
|
||||
template<> simdjson_really_inline simdjson_result<uint64_t> document::get() & noexcept { return get_uint64(); }
|
||||
template<> simdjson_really_inline simdjson_result<int64_t> document::get() & noexcept { return get_int64(); }
|
||||
template<> simdjson_really_inline simdjson_result<bool> document::get() & noexcept { return get_bool(); }
|
||||
template<> simdjson_really_inline simdjson_result<value> document::get() & noexcept { return get_value(); }
|
||||
|
||||
template<> simdjson_really_inline simdjson_result<raw_json_string> document::get() && noexcept { return get_raw_json_string(); }
|
||||
template<> simdjson_really_inline simdjson_result<std::string_view> document::get() && noexcept { return get_string(); }
|
||||
@@ -98,6 +110,7 @@ template<> simdjson_really_inline simdjson_result<double> document::get() && noe
|
||||
template<> simdjson_really_inline simdjson_result<uint64_t> document::get() && noexcept { return std::forward<document>(*this).get_uint64(); }
|
||||
template<> simdjson_really_inline simdjson_result<int64_t> document::get() && noexcept { return std::forward<document>(*this).get_int64(); }
|
||||
template<> simdjson_really_inline simdjson_result<bool> document::get() && noexcept { return std::forward<document>(*this).get_bool(); }
|
||||
template<> simdjson_really_inline simdjson_result<value> document::get() && noexcept { return get_value(); }
|
||||
|
||||
template<typename T> simdjson_really_inline error_code document::get(T &out) & noexcept {
|
||||
return get<T>().get(out);
|
||||
@@ -115,14 +128,33 @@ simdjson_really_inline document::operator double() noexcept(false) { return get_
|
||||
simdjson_really_inline document::operator std::string_view() noexcept(false) { return get_string(); }
|
||||
simdjson_really_inline document::operator raw_json_string() noexcept(false) { return get_raw_json_string(); }
|
||||
simdjson_really_inline document::operator bool() noexcept(false) { return get_bool(); }
|
||||
simdjson_really_inline document::operator value() noexcept(false) { return get_value(); }
|
||||
|
||||
#endif
|
||||
simdjson_really_inline simdjson_result<size_t> document::count_elements() & noexcept {
|
||||
auto a = get_array();
|
||||
simdjson_result<size_t> answer = a.count_elements();
|
||||
/* If there was an array, we are now left pointing at its first element. */
|
||||
if(answer.error() == SUCCESS) { iter._depth -= 1 ; /* undoing the increment so we go back at the doc depth.*/ }
|
||||
if(answer.error() == SUCCESS) {
|
||||
iter._depth = 1 ; /* undoing the increment so we go back at the doc depth.*/
|
||||
iter.assert_at_document_depth();
|
||||
}
|
||||
return answer;
|
||||
}
|
||||
simdjson_really_inline simdjson_result<size_t> document::count_fields() & noexcept {
|
||||
auto a = get_object();
|
||||
simdjson_result<size_t> answer = a.count_fields();
|
||||
/* If there was an array, we are now left pointing at its first element. */
|
||||
if(answer.error() == SUCCESS) {
|
||||
iter._depth = 1 ; /* undoing the increment so we go back at the doc depth.*/
|
||||
iter.assert_at_document_depth();
|
||||
}
|
||||
return answer;
|
||||
}
|
||||
simdjson_really_inline simdjson_result<value> document::at(size_t index) & noexcept {
|
||||
auto a = get_array();
|
||||
return a.at(index);
|
||||
}
|
||||
simdjson_really_inline simdjson_result<array_iterator> document::begin() & noexcept {
|
||||
return get_array().begin();
|
||||
}
|
||||
@@ -156,12 +188,14 @@ simdjson_really_inline error_code document::consume() noexcept {
|
||||
}
|
||||
|
||||
simdjson_really_inline simdjson_result<std::string_view> document::raw_json() noexcept {
|
||||
printf("document::raw_json()\n");
|
||||
auto _iter = get_root_value_iterator();
|
||||
const uint8_t * starting_point{_iter.peek_start()};
|
||||
auto error = consume();
|
||||
if(error) { return error; }
|
||||
const uint8_t * final_point{iter.peek(0)};
|
||||
// After 'consume()', we could be left pointing just beyond the document, but that
|
||||
// is ok because we are not going to dereference the final pointer position, we just
|
||||
// use it to compute the length in bytes.
|
||||
const uint8_t * final_point{iter.unsafe_pointer()};
|
||||
return std::string_view(reinterpret_cast<const char*>(starting_point), size_t(final_point - starting_point));
|
||||
}
|
||||
|
||||
@@ -169,6 +203,30 @@ simdjson_really_inline simdjson_result<json_type> document::type() noexcept {
|
||||
return get_root_value_iterator().type();
|
||||
}
|
||||
|
||||
simdjson_really_inline simdjson_result<bool> document::is_scalar() noexcept {
|
||||
json_type this_type;
|
||||
auto error = type().get(this_type);
|
||||
if(error) { return error; }
|
||||
return ! ((this_type == json_type::array) || (this_type == json_type::object));
|
||||
}
|
||||
|
||||
simdjson_really_inline bool document::is_negative() noexcept {
|
||||
return get_root_value_iterator().is_root_negative();
|
||||
}
|
||||
|
||||
simdjson_really_inline simdjson_result<bool> document::is_integer() noexcept {
|
||||
return get_root_value_iterator().is_root_integer();
|
||||
}
|
||||
|
||||
simdjson_really_inline simdjson_result<number_type> document::get_number_type() noexcept {
|
||||
return get_root_value_iterator().get_root_number_type();
|
||||
}
|
||||
|
||||
simdjson_really_inline simdjson_result<number> document::get_number() noexcept {
|
||||
return get_root_value_iterator().get_root_number();
|
||||
}
|
||||
|
||||
|
||||
simdjson_really_inline simdjson_result<std::string_view> document::raw_json_token() noexcept {
|
||||
auto _iter = get_root_value_iterator();
|
||||
return std::string_view(reinterpret_cast<const char*>(_iter.peek_start()), _iter.peek_start_length());
|
||||
@@ -177,7 +235,7 @@ simdjson_really_inline simdjson_result<std::string_view> document::raw_json_toke
|
||||
simdjson_really_inline simdjson_result<value> document::at_pointer(std::string_view json_pointer) noexcept {
|
||||
rewind(); // Rewind the document each time at_pointer is called
|
||||
if (json_pointer.empty()) {
|
||||
return this->get_value_unsafe();
|
||||
return this->get_value();
|
||||
}
|
||||
json_type t;
|
||||
SIMDJSON_TRY(type().get(t));
|
||||
@@ -218,6 +276,14 @@ simdjson_really_inline simdjson_result<size_t> simdjson_result<SIMDJSON_IMPLEMEN
|
||||
if (error()) { return error(); }
|
||||
return first.count_elements();
|
||||
}
|
||||
simdjson_really_inline simdjson_result<size_t> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document>::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::document>::at(size_t index) & noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.at(index);
|
||||
}
|
||||
simdjson_really_inline error_code simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document>::rewind() noexcept {
|
||||
if (error()) { return error(); }
|
||||
first.rewind();
|
||||
@@ -286,6 +352,10 @@ simdjson_really_inline simdjson_result<bool> simdjson_result<SIMDJSON_IMPLEMENTA
|
||||
if (error()) { return error(); }
|
||||
return first.get_bool();
|
||||
}
|
||||
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document>::get_value() noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.get_value();
|
||||
}
|
||||
simdjson_really_inline bool simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document>::is_null() noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.is_null();
|
||||
@@ -329,6 +399,33 @@ simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::json_t
|
||||
return first.type();
|
||||
}
|
||||
|
||||
simdjson_really_inline simdjson_result<bool> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document>::is_scalar() noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.is_scalar();
|
||||
}
|
||||
|
||||
|
||||
simdjson_really_inline bool simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document>::is_negative() noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.is_negative();
|
||||
}
|
||||
|
||||
simdjson_really_inline simdjson_result<bool> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document>::is_integer() noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.is_integer();
|
||||
}
|
||||
|
||||
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::number_type> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document>::get_number_type() noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.get_number_type();
|
||||
}
|
||||
|
||||
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::number> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document>::get_number() noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.get_number();
|
||||
}
|
||||
|
||||
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document>::operator SIMDJSON_IMPLEMENTATION::ondemand::array() & noexcept(false) {
|
||||
if (error()) { throw simdjson_error(error()); }
|
||||
@@ -362,8 +459,18 @@ simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::docume
|
||||
if (error()) { throw simdjson_error(error()); }
|
||||
return first;
|
||||
}
|
||||
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document>::operator SIMDJSON_IMPLEMENTATION::ondemand::value() noexcept(false) {
|
||||
if (error()) { throw simdjson_error(error()); }
|
||||
return first;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
simdjson_really_inline simdjson_result<const char *> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document>::current_location() noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.current_location();
|
||||
}
|
||||
|
||||
simdjson_really_inline simdjson_result<std::string_view> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document>::raw_json_token() noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.raw_json_token();
|
||||
@@ -374,4 +481,238 @@ simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>
|
||||
return first.at_pointer(json_pointer);
|
||||
}
|
||||
|
||||
|
||||
} // namespace simdjson
|
||||
|
||||
|
||||
namespace simdjson {
|
||||
namespace SIMDJSON_IMPLEMENTATION {
|
||||
namespace ondemand {
|
||||
|
||||
simdjson_really_inline document_reference::document_reference() noexcept : doc{nullptr} {}
|
||||
simdjson_really_inline document_reference::document_reference(document &d) noexcept : doc(&d) {}
|
||||
simdjson_really_inline void document_reference::rewind() noexcept { doc->rewind(); }
|
||||
simdjson_really_inline simdjson_result<array> document_reference::get_array() & noexcept { return doc->get_array(); }
|
||||
simdjson_really_inline simdjson_result<object> document_reference::get_object() & noexcept { return doc->get_object(); }
|
||||
simdjson_really_inline simdjson_result<uint64_t> document_reference::get_uint64() noexcept { return doc->get_uint64(); }
|
||||
simdjson_really_inline simdjson_result<int64_t> document_reference::get_int64() noexcept { return doc->get_int64(); }
|
||||
simdjson_really_inline simdjson_result<double> document_reference::get_double() noexcept { return doc->get_double(); }
|
||||
simdjson_really_inline simdjson_result<std::string_view> document_reference::get_string() noexcept { return doc->get_string(); }
|
||||
simdjson_really_inline simdjson_result<raw_json_string> document_reference::get_raw_json_string() noexcept { return doc->get_raw_json_string(); }
|
||||
simdjson_really_inline simdjson_result<bool> document_reference::get_bool() noexcept { return doc->get_bool(); }
|
||||
simdjson_really_inline simdjson_result<value> document_reference::get_value() noexcept { return doc->get_value(); }
|
||||
simdjson_really_inline bool document_reference::is_null() noexcept { return doc->is_null(); }
|
||||
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
simdjson_really_inline document_reference::operator array() & noexcept(false) { return array(*doc); }
|
||||
simdjson_really_inline document_reference::operator object() & noexcept(false) { return object(*doc); }
|
||||
simdjson_really_inline document_reference::operator uint64_t() noexcept(false) { return uint64_t(*doc); }
|
||||
simdjson_really_inline document_reference::operator int64_t() noexcept(false) { return int64_t(*doc); }
|
||||
simdjson_really_inline document_reference::operator double() noexcept(false) { return double(*doc); }
|
||||
simdjson_really_inline document_reference::operator std::string_view() noexcept(false) { return std::string_view(*doc); }
|
||||
simdjson_really_inline document_reference::operator raw_json_string() noexcept(false) { return raw_json_string(*doc); }
|
||||
simdjson_really_inline document_reference::operator bool() noexcept(false) { return bool(*doc); }
|
||||
simdjson_really_inline document_reference::operator value() noexcept(false) { return value(*doc); }
|
||||
#endif
|
||||
simdjson_really_inline simdjson_result<size_t> document_reference::count_elements() & noexcept { return doc->count_elements(); }
|
||||
simdjson_really_inline simdjson_result<size_t> document_reference::count_fields() & noexcept { return doc->count_fields(); }
|
||||
simdjson_really_inline simdjson_result<value> document_reference::at(size_t index) & noexcept { return doc->at(index); }
|
||||
simdjson_really_inline simdjson_result<array_iterator> document_reference::begin() & noexcept { return doc->begin(); }
|
||||
simdjson_really_inline simdjson_result<array_iterator> document_reference::end() & noexcept { return doc->end(); }
|
||||
simdjson_really_inline simdjson_result<value> document_reference::find_field(std::string_view key) & noexcept { return doc->find_field(key); }
|
||||
simdjson_really_inline simdjson_result<value> document_reference::find_field(const char *key) & noexcept { return doc->find_field(key); }
|
||||
simdjson_really_inline simdjson_result<value> document_reference::operator[](std::string_view key) & noexcept { return (*doc)[key]; }
|
||||
simdjson_really_inline simdjson_result<value> document_reference::operator[](const char *key) & noexcept { return (*doc)[key]; }
|
||||
simdjson_really_inline simdjson_result<value> document_reference::find_field_unordered(std::string_view 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<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 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<number_type> document_reference::get_number_type() noexcept { return doc->get_number_type(); }
|
||||
simdjson_really_inline simdjson_result<number> document_reference::get_number() noexcept { return doc->get_number(); }
|
||||
simdjson_really_inline simdjson_result<std::string_view> document_reference::raw_json_token() noexcept { return doc->raw_json_token(); }
|
||||
simdjson_really_inline simdjson_result<value> document_reference::at_pointer(std::string_view json_pointer) noexcept { return doc->at_pointer(json_pointer); }
|
||||
simdjson_really_inline simdjson_result<std::string_view> document_reference::raw_json() noexcept { return doc->raw_json();}
|
||||
simdjson_really_inline document_reference::operator document&() const noexcept { return *doc; }
|
||||
|
||||
} // namespace ondemand
|
||||
} // namespace SIMDJSON_IMPLEMENTATION
|
||||
} // namespace simdjson
|
||||
|
||||
|
||||
|
||||
namespace simdjson {
|
||||
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document_reference>::simdjson_result(SIMDJSON_IMPLEMENTATION::ondemand::document_reference value, error_code error)
|
||||
noexcept : implementation_simdjson_result_base<SIMDJSON_IMPLEMENTATION::ondemand::document_reference>(std::forward<SIMDJSON_IMPLEMENTATION::ondemand::document_reference>(value), error) {}
|
||||
|
||||
|
||||
simdjson_really_inline simdjson_result<size_t> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document_reference>::count_elements() & noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.count_elements();
|
||||
}
|
||||
simdjson_really_inline simdjson_result<size_t> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document_reference>::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::document_reference>::at(size_t index) & noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.at(index);
|
||||
}
|
||||
simdjson_really_inline error_code simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document_reference>::rewind() noexcept {
|
||||
if (error()) { return error(); }
|
||||
first.rewind();
|
||||
return SUCCESS;
|
||||
}
|
||||
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array_iterator> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document_reference>::begin() & noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.begin();
|
||||
}
|
||||
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array_iterator> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document_reference>::end() & noexcept {
|
||||
return {};
|
||||
}
|
||||
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document_reference>::find_field_unordered(std::string_view key) & noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.find_field_unordered(key);
|
||||
}
|
||||
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document_reference>::find_field_unordered(const char *key) & noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.find_field_unordered(key);
|
||||
}
|
||||
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document_reference>::operator[](std::string_view key) & noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first[key];
|
||||
}
|
||||
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document_reference>::operator[](const char *key) & noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first[key];
|
||||
}
|
||||
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document_reference>::find_field(std::string_view key) & noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.find_field(key);
|
||||
}
|
||||
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document_reference>::find_field(const char *key) & noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.find_field(key);
|
||||
}
|
||||
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document_reference>::get_array() & noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.get_array();
|
||||
}
|
||||
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document_reference>::get_object() & noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.get_object();
|
||||
}
|
||||
simdjson_really_inline simdjson_result<uint64_t> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document_reference>::get_uint64() noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.get_uint64();
|
||||
}
|
||||
simdjson_really_inline simdjson_result<int64_t> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document_reference>::get_int64() noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.get_int64();
|
||||
}
|
||||
simdjson_really_inline simdjson_result<double> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document_reference>::get_double() noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.get_double();
|
||||
}
|
||||
simdjson_really_inline simdjson_result<std::string_view> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document_reference>::get_string() noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.get_string();
|
||||
}
|
||||
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::raw_json_string> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document_reference>::get_raw_json_string() noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.get_raw_json_string();
|
||||
}
|
||||
simdjson_really_inline simdjson_result<bool> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document_reference>::get_bool() noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.get_bool();
|
||||
}
|
||||
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document_reference>::get_value() noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.get_value();
|
||||
}
|
||||
simdjson_really_inline bool simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document_reference>::is_null() noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.is_null();
|
||||
}
|
||||
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::json_type> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document_reference>::type() noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.type();
|
||||
}
|
||||
simdjson_really_inline simdjson_result<bool> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document_reference>::is_scalar() noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.is_scalar();
|
||||
}
|
||||
simdjson_really_inline bool simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document_reference>::is_negative() noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.is_negative();
|
||||
}
|
||||
simdjson_really_inline simdjson_result<bool> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document_reference>::is_integer() noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.is_integer();
|
||||
}
|
||||
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::number_type> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document_reference>::get_number_type() noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.get_number_type();
|
||||
}
|
||||
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::number> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document_reference>::get_number() noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.get_number();
|
||||
}
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document_reference>::operator SIMDJSON_IMPLEMENTATION::ondemand::array() & noexcept(false) {
|
||||
if (error()) { throw simdjson_error(error()); }
|
||||
return first;
|
||||
}
|
||||
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document_reference>::operator SIMDJSON_IMPLEMENTATION::ondemand::object() & noexcept(false) {
|
||||
if (error()) { throw simdjson_error(error()); }
|
||||
return first;
|
||||
}
|
||||
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document_reference>::operator uint64_t() noexcept(false) {
|
||||
if (error()) { throw simdjson_error(error()); }
|
||||
return first;
|
||||
}
|
||||
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document_reference>::operator int64_t() noexcept(false) {
|
||||
if (error()) { throw simdjson_error(error()); }
|
||||
return first;
|
||||
}
|
||||
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document_reference>::operator double() noexcept(false) {
|
||||
if (error()) { throw simdjson_error(error()); }
|
||||
return first;
|
||||
}
|
||||
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document_reference>::operator std::string_view() noexcept(false) {
|
||||
if (error()) { throw simdjson_error(error()); }
|
||||
return first;
|
||||
}
|
||||
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document_reference>::operator SIMDJSON_IMPLEMENTATION::ondemand::raw_json_string() noexcept(false) {
|
||||
if (error()) { throw simdjson_error(error()); }
|
||||
return first;
|
||||
}
|
||||
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document_reference>::operator bool() noexcept(false) {
|
||||
if (error()) { throw simdjson_error(error()); }
|
||||
return first;
|
||||
}
|
||||
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document_reference>::operator SIMDJSON_IMPLEMENTATION::ondemand::value() noexcept(false) {
|
||||
if (error()) { throw simdjson_error(error()); }
|
||||
return first;
|
||||
}
|
||||
#endif
|
||||
|
||||
simdjson_really_inline simdjson_result<const char *> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document_reference>::current_location() noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.current_location();
|
||||
}
|
||||
|
||||
simdjson_really_inline simdjson_result<std::string_view> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document_reference>::raw_json_token() noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.raw_json_token();
|
||||
}
|
||||
|
||||
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document_reference>::at_pointer(std::string_view json_pointer) noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.at_pointer(json_pointer);
|
||||
}
|
||||
|
||||
|
||||
} // namespace simdjson
|
||||
|
||||
@@ -13,7 +13,7 @@ class array_iterator;
|
||||
class document_stream;
|
||||
|
||||
/**
|
||||
* A JSON document iteration.
|
||||
* A JSON document. It holds a json_iterator instance.
|
||||
*
|
||||
* Used by tokens to get text, and string buffer location.
|
||||
*
|
||||
@@ -27,7 +27,7 @@ public:
|
||||
* Exists so you can declare a variable and later assign to it before use.
|
||||
*/
|
||||
simdjson_really_inline document() noexcept = default;
|
||||
simdjson_really_inline document(const document &other) noexcept = delete;
|
||||
simdjson_really_inline document(const document &other) noexcept = delete; // pass your documents by reference, not by copy
|
||||
simdjson_really_inline document(document &&other) noexcept = default;
|
||||
simdjson_really_inline document &operator=(const document &other) noexcept = delete;
|
||||
simdjson_really_inline document &operator=(document &&other) noexcept = default;
|
||||
@@ -53,6 +53,13 @@ public:
|
||||
* @returns INCORRECT_TYPE If the JSON value is not a 64-bit unsigned integer.
|
||||
*/
|
||||
simdjson_really_inline simdjson_result<uint64_t> get_uint64() noexcept;
|
||||
/**
|
||||
* Cast this JSON value (inside string) to an unsigned integer.
|
||||
*
|
||||
* @returns A signed 64-bit integer.
|
||||
* @returns INCORRECT_TYPE If the JSON value is not a 64-bit unsigned integer.
|
||||
*/
|
||||
simdjson_really_inline simdjson_result<uint64_t> get_uint64_in_string() noexcept;
|
||||
/**
|
||||
* Cast this JSON value to a signed integer.
|
||||
*
|
||||
@@ -60,6 +67,13 @@ public:
|
||||
* @returns INCORRECT_TYPE If the JSON value is not a 64-bit integer.
|
||||
*/
|
||||
simdjson_really_inline simdjson_result<int64_t> get_int64() noexcept;
|
||||
/**
|
||||
* Cast this JSON value (inside string) to a signed integer.
|
||||
*
|
||||
* @returns A signed 64-bit integer.
|
||||
* @returns INCORRECT_TYPE If the JSON value is not a 64-bit integer.
|
||||
*/
|
||||
simdjson_really_inline simdjson_result<int64_t> get_int64_in_string() noexcept;
|
||||
/**
|
||||
* Cast this JSON value to a double.
|
||||
*
|
||||
@@ -67,6 +81,14 @@ public:
|
||||
* @returns INCORRECT_TYPE If the JSON value is not a valid floating-point number.
|
||||
*/
|
||||
simdjson_really_inline simdjson_result<double> get_double() noexcept;
|
||||
|
||||
/**
|
||||
* Cast this JSON value (inside string) to a double.
|
||||
*
|
||||
* @returns A double.
|
||||
* @returns INCORRECT_TYPE If the JSON value is not a valid floating-point number.
|
||||
*/
|
||||
simdjson_really_inline simdjson_result<double> get_double_in_string() noexcept;
|
||||
/**
|
||||
* Cast this JSON value to a string.
|
||||
*
|
||||
@@ -93,6 +115,14 @@ public:
|
||||
* @returns INCORRECT_TYPE if the JSON value is not true or false.
|
||||
*/
|
||||
simdjson_really_inline simdjson_result<bool> get_bool() noexcept;
|
||||
/**
|
||||
* Cast this JSON value to a value when the document is an object or an array.
|
||||
*
|
||||
* @returns A value if a JSON array or object cannot be found.
|
||||
* @returns SCALAR_DOCUMENT_AS_VALUE error is the document is a scalar (see is_scalar() function).
|
||||
*/
|
||||
simdjson_really_inline simdjson_result<value> get_value() noexcept;
|
||||
|
||||
/**
|
||||
* Checks if this JSON value is null.
|
||||
*
|
||||
@@ -126,7 +156,9 @@ public:
|
||||
/**
|
||||
* Get this value as the given type.
|
||||
*
|
||||
* Supported types: object, array, raw_json_string, string_view, uint64_t, int64_t, double, bool
|
||||
* Supported types: object, array, raw_json_string, string_view, uint64_t, int64_t, double, bool, value
|
||||
*
|
||||
* Be mindful that the document instance must remain in scope while you are accessing object, array and value instances.
|
||||
*
|
||||
* @param out This is set to a value of the given type, parsed from the JSON. If there is an error, this may not be initialized.
|
||||
* @returns INCORRECT_TYPE If the JSON value is not an object.
|
||||
@@ -198,6 +230,13 @@ public:
|
||||
* @exception simdjson_error(INCORRECT_TYPE) if the JSON value is not true or false.
|
||||
*/
|
||||
simdjson_really_inline operator bool() noexcept(false);
|
||||
/**
|
||||
* Cast this JSON value to a value.
|
||||
*
|
||||
* @returns A value value.
|
||||
* @exception if a JSON value cannot be found
|
||||
*/
|
||||
simdjson_really_inline operator value() noexcept(false);
|
||||
#endif
|
||||
/**
|
||||
* This method scans the array and counts the number of elements.
|
||||
@@ -211,6 +250,29 @@ public:
|
||||
* safe to continue.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
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.
|
||||
* This function should only be called once as the array iterator is not reset between each call.
|
||||
*
|
||||
* @return The value at the given index, or:
|
||||
* - INDEX_OUT_OF_BOUNDS if the array index is larger than an array length
|
||||
*/
|
||||
simdjson_really_inline simdjson_result<value> at(size_t index) & noexcept;
|
||||
/**
|
||||
* Begin array iteration.
|
||||
*
|
||||
@@ -241,6 +303,14 @@ public:
|
||||
* **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 }`.
|
||||
*
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* @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.
|
||||
*/
|
||||
@@ -264,6 +334,13 @@ public:
|
||||
* 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).
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* @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.
|
||||
*/
|
||||
@@ -286,6 +363,77 @@ public:
|
||||
*/
|
||||
simdjson_really_inline simdjson_result<json_type> type() noexcept;
|
||||
|
||||
/**
|
||||
* Checks whether the document is a scalar (string, number, null, Boolean).
|
||||
* Returns false when there it is an array or object.
|
||||
*
|
||||
* @returns true if the type is string, number, null, Boolean
|
||||
* @error TAPE_ERROR when the JSON value is a bad token like "}" "," or "alse".
|
||||
*/
|
||||
simdjson_really_inline simdjson_result<bool> is_scalar() noexcept;
|
||||
|
||||
/**
|
||||
* Checks whether the document is a negative number.
|
||||
*
|
||||
* @returns true if the number if negative.
|
||||
*/
|
||||
simdjson_really_inline bool is_negative() noexcept;
|
||||
/**
|
||||
* Checks whether the document is an integer number. Note that
|
||||
* this requires to partially parse the number string. If
|
||||
* the value is determined to be an integer, it may still
|
||||
* not parse properly as an integer in subsequent steps
|
||||
* (e.g., it might overflow).
|
||||
*
|
||||
* @returns true if the number if negative.
|
||||
*/
|
||||
simdjson_really_inline simdjson_result<bool> is_integer() noexcept;
|
||||
/**
|
||||
* Determine the number type (integer or floating-point number).
|
||||
*
|
||||
* get_number_type() is number_type::unsigned_integer if we have
|
||||
* an integer greater or equal to 9223372036854775808
|
||||
* get_number_type() is number_type::signed_integer if we have an
|
||||
* integer that is less than 9223372036854775808
|
||||
* Otherwise, get_number_type() has value number_type::floating_point_number
|
||||
*
|
||||
* This function req
|
||||
* uires processing the number string, but it is expected
|
||||
* to be faster than get_number().get_number_type() because it is does not
|
||||
* parse the number value.
|
||||
*
|
||||
* @returns the type of the number
|
||||
*/
|
||||
simdjson_really_inline simdjson_result<number_type> get_number_type() noexcept;
|
||||
|
||||
/**
|
||||
* Attempt to parse an ondemand::number. An ondemand::number may
|
||||
* contain an integer value or a floating-point value, the simdjson
|
||||
* library will autodetect the type. Thus it is a dynamically typed
|
||||
* number. Before accessing the value, you must determine the detected
|
||||
* type.
|
||||
*
|
||||
* number.get_number_type() is number_type::signed_integer if we have
|
||||
* an integer in [-9223372036854775808,9223372036854775808)
|
||||
* You can recover the value by calling number.get_int64() and you
|
||||
* have that number.is_int64() is true.
|
||||
*
|
||||
* number.get_number_type() is number_type::unsigned_integer if we have
|
||||
* an integer in [9223372036854775808,18446744073709551616)
|
||||
* You can recover the value by calling number.get_uint64() and you
|
||||
* have that number.is_uint64() is true.
|
||||
*
|
||||
* Otherwise, number.get_number_type() has value number_type::floating_point_number
|
||||
* and we have a binary64 number.
|
||||
* You can recover the value by calling number.get_double() and you
|
||||
* have that number.is_double() is true.
|
||||
*
|
||||
* You must check the type before accessing the value: it is an error
|
||||
* to call "get_int64()" when number.get_number_type() is not
|
||||
* number_type::signed_integer and when number.is_int64() is false.
|
||||
*/
|
||||
simdjson_warn_unused simdjson_really_inline simdjson_result<number> get_number() noexcept;
|
||||
|
||||
/**
|
||||
* Get the raw JSON for this token.
|
||||
*
|
||||
@@ -320,6 +468,16 @@ public:
|
||||
* Returns debugging information.
|
||||
*/
|
||||
inline std::string to_debug_string() noexcept;
|
||||
/**
|
||||
* Some unrecoverable error conditions may render the document instance unusable.
|
||||
* The is_alive() method returns true when the document is still suitable.
|
||||
*/
|
||||
inline bool is_alive() noexcept;
|
||||
|
||||
/**
|
||||
* Returns the current location in the document if in bounds.
|
||||
*/
|
||||
inline simdjson_result<const char *> current_location() noexcept;
|
||||
|
||||
/**
|
||||
* Get the value associated with the given JSON pointer. We use the RFC 6901
|
||||
@@ -350,6 +508,7 @@ public:
|
||||
* - INDEX_OUT_OF_BOUNDS if an array index is larger than an array length
|
||||
* - INCORRECT_TYPE if a non-integer is used to access an array
|
||||
* - INVALID_JSON_POINTER if the JSON pointer is invalid and cannot be parsed
|
||||
* - SCALAR_DOCUMENT_AS_VALUE if the json_pointer is empty and the document is not a scalar (see is_scalar() function).
|
||||
*/
|
||||
simdjson_really_inline simdjson_result<value> at_pointer(std::string_view json_pointer) noexcept;
|
||||
/**
|
||||
@@ -369,7 +528,6 @@ protected:
|
||||
|
||||
simdjson_really_inline value_iterator resume_value_iterator() noexcept;
|
||||
simdjson_really_inline value_iterator get_root_value_iterator() noexcept;
|
||||
simdjson_really_inline simdjson_result<value> get_value_unsafe() noexcept;
|
||||
simdjson_really_inline simdjson_result<object> start_or_resume_object() noexcept;
|
||||
static simdjson_really_inline document start(ondemand::json_iterator &&iter) noexcept;
|
||||
|
||||
@@ -389,6 +547,67 @@ protected:
|
||||
friend class document_stream;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* A document_reference is a thin wrapper around a document reference instance.
|
||||
*/
|
||||
class document_reference {
|
||||
public:
|
||||
simdjson_really_inline document_reference() 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& operator=(const document_reference &other) noexcept = default;
|
||||
simdjson_really_inline void rewind() noexcept;
|
||||
simdjson_really_inline simdjson_result<array> get_array() & noexcept;
|
||||
simdjson_really_inline simdjson_result<object> get_object() & noexcept;
|
||||
simdjson_really_inline simdjson_result<uint64_t> get_uint64() noexcept;
|
||||
simdjson_really_inline simdjson_result<int64_t> get_int64() noexcept;
|
||||
simdjson_really_inline simdjson_result<double> get_double() noexcept;
|
||||
simdjson_really_inline simdjson_result<std::string_view> get_string() noexcept;
|
||||
simdjson_really_inline simdjson_result<raw_json_string> get_raw_json_string() noexcept;
|
||||
simdjson_really_inline simdjson_result<bool> get_bool() noexcept;
|
||||
simdjson_really_inline simdjson_result<value> get_value() noexcept;
|
||||
|
||||
simdjson_really_inline bool is_null() noexcept;
|
||||
simdjson_really_inline simdjson_result<std::string_view> raw_json() noexcept;
|
||||
simdjson_really_inline operator document&() const noexcept;
|
||||
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
simdjson_really_inline operator array() & noexcept(false);
|
||||
simdjson_really_inline operator object() & noexcept(false);
|
||||
simdjson_really_inline operator uint64_t() noexcept(false);
|
||||
simdjson_really_inline operator int64_t() noexcept(false);
|
||||
simdjson_really_inline operator double() noexcept(false);
|
||||
simdjson_really_inline operator std::string_view() noexcept(false);
|
||||
simdjson_really_inline operator raw_json_string() noexcept(false);
|
||||
simdjson_really_inline operator bool() noexcept(false);
|
||||
simdjson_really_inline operator value() noexcept(false);
|
||||
#endif
|
||||
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<value> at(size_t index) & noexcept;
|
||||
simdjson_really_inline simdjson_result<array_iterator> begin() & noexcept;
|
||||
simdjson_really_inline simdjson_result<array_iterator> end() & noexcept;
|
||||
simdjson_really_inline simdjson_result<value> find_field(std::string_view key) & noexcept;
|
||||
simdjson_really_inline simdjson_result<value> find_field(const char *key) & noexcept;
|
||||
simdjson_really_inline simdjson_result<value> operator[](std::string_view key) & noexcept;
|
||||
simdjson_really_inline simdjson_result<value> operator[](const char *key) & noexcept;
|
||||
simdjson_really_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept;
|
||||
simdjson_really_inline simdjson_result<value> find_field_unordered(const char *key) & noexcept;
|
||||
|
||||
simdjson_really_inline simdjson_result<json_type> type() noexcept;
|
||||
simdjson_really_inline simdjson_result<bool> is_scalar() noexcept;
|
||||
|
||||
simdjson_really_inline simdjson_result<const char *> current_location() noexcept;
|
||||
simdjson_really_inline bool is_negative() 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> get_number() noexcept;
|
||||
simdjson_really_inline simdjson_result<std::string_view> raw_json_token() noexcept;
|
||||
simdjson_really_inline simdjson_result<value> at_pointer(std::string_view json_pointer) noexcept;
|
||||
private:
|
||||
document *doc{nullptr};
|
||||
};
|
||||
} // namespace ondemand
|
||||
} // namespace SIMDJSON_IMPLEMENTATION
|
||||
} // namespace simdjson
|
||||
@@ -408,9 +627,11 @@ public:
|
||||
simdjson_really_inline simdjson_result<uint64_t> get_uint64() noexcept;
|
||||
simdjson_really_inline simdjson_result<int64_t> get_int64() noexcept;
|
||||
simdjson_really_inline simdjson_result<double> get_double() noexcept;
|
||||
simdjson_really_inline simdjson_result<double> get_double_from_string() noexcept;
|
||||
simdjson_really_inline simdjson_result<std::string_view> get_string() noexcept;
|
||||
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::raw_json_string> get_raw_json_string() noexcept;
|
||||
simdjson_really_inline simdjson_result<bool> get_bool() noexcept;
|
||||
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> get_value() noexcept;
|
||||
simdjson_really_inline bool is_null() noexcept;
|
||||
|
||||
template<typename T> simdjson_really_inline simdjson_result<T> get() & noexcept;
|
||||
@@ -428,8 +649,11 @@ public:
|
||||
simdjson_really_inline operator std::string_view() noexcept(false);
|
||||
simdjson_really_inline operator SIMDJSON_IMPLEMENTATION::ondemand::raw_json_string() noexcept(false);
|
||||
simdjson_really_inline operator bool() noexcept(false);
|
||||
simdjson_really_inline operator SIMDJSON_IMPLEMENTATION::ondemand::value() noexcept(false);
|
||||
#endif
|
||||
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::array_iterator> begin() & noexcept;
|
||||
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array_iterator> end() & noexcept;
|
||||
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> find_field(std::string_view key) & noexcept;
|
||||
@@ -438,13 +662,78 @@ public:
|
||||
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> operator[](const char *key) & noexcept;
|
||||
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> find_field_unordered(std::string_view key) & noexcept;
|
||||
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> find_field_unordered(const char *key) & 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<const char *> current_location() noexcept;
|
||||
simdjson_really_inline bool is_negative() 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> get_number() noexcept;
|
||||
/** @copydoc simdjson_really_inline std::string_view document::raw_json_token() const noexcept */
|
||||
simdjson_really_inline simdjson_result<std::string_view> raw_json_token() noexcept;
|
||||
|
||||
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> at_pointer(std::string_view json_pointer) noexcept;
|
||||
};
|
||||
|
||||
|
||||
} // namespace simdjson
|
||||
|
||||
|
||||
|
||||
namespace simdjson {
|
||||
|
||||
template<>
|
||||
struct simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document_reference> : public SIMDJSON_IMPLEMENTATION::implementation_simdjson_result_base<SIMDJSON_IMPLEMENTATION::ondemand::document_reference> {
|
||||
public:
|
||||
simdjson_really_inline simdjson_result(SIMDJSON_IMPLEMENTATION::ondemand::document_reference value, error_code error) noexcept;
|
||||
simdjson_really_inline simdjson_result() noexcept = default;
|
||||
simdjson_really_inline error_code rewind() noexcept;
|
||||
|
||||
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array> get_array() & noexcept;
|
||||
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object> get_object() & noexcept;
|
||||
simdjson_really_inline simdjson_result<uint64_t> get_uint64() noexcept;
|
||||
simdjson_really_inline simdjson_result<int64_t> get_int64() noexcept;
|
||||
simdjson_really_inline simdjson_result<double> get_double() noexcept;
|
||||
simdjson_really_inline simdjson_result<std::string_view> get_string() noexcept;
|
||||
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::raw_json_string> get_raw_json_string() noexcept;
|
||||
simdjson_really_inline simdjson_result<bool> get_bool() noexcept;
|
||||
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> get_value() noexcept;
|
||||
simdjson_really_inline bool is_null() noexcept;
|
||||
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
simdjson_really_inline operator SIMDJSON_IMPLEMENTATION::ondemand::array() & noexcept(false);
|
||||
simdjson_really_inline operator SIMDJSON_IMPLEMENTATION::ondemand::object() & noexcept(false);
|
||||
simdjson_really_inline operator uint64_t() noexcept(false);
|
||||
simdjson_really_inline operator int64_t() noexcept(false);
|
||||
simdjson_really_inline operator double() noexcept(false);
|
||||
simdjson_really_inline operator std::string_view() noexcept(false);
|
||||
simdjson_really_inline operator SIMDJSON_IMPLEMENTATION::ondemand::raw_json_string() noexcept(false);
|
||||
simdjson_really_inline operator bool() noexcept(false);
|
||||
simdjson_really_inline operator SIMDJSON_IMPLEMENTATION::ondemand::value() noexcept(false);
|
||||
#endif
|
||||
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::array_iterator> begin() & noexcept;
|
||||
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array_iterator> end() & noexcept;
|
||||
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> find_field(std::string_view key) & noexcept;
|
||||
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> find_field(const char *key) & noexcept;
|
||||
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> operator[](std::string_view key) & noexcept;
|
||||
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> operator[](const char *key) & noexcept;
|
||||
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> find_field_unordered(std::string_view key) & noexcept;
|
||||
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> find_field_unordered(const char *key) & 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<const char *> current_location() noexcept;
|
||||
simdjson_really_inline bool is_negative() 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> get_number() noexcept;
|
||||
/** @copydoc simdjson_really_inline std::string_view document_reference::raw_json_token() const noexcept */
|
||||
simdjson_really_inline simdjson_result<std::string_view> raw_json_token() noexcept;
|
||||
|
||||
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> at_pointer(std::string_view json_pointer) noexcept;
|
||||
};
|
||||
|
||||
|
||||
} // namespace simdjson
|
||||
@@ -126,6 +126,7 @@ inline size_t document_stream::size_in_bytes() const noexcept {
|
||||
}
|
||||
|
||||
inline size_t document_stream::truncated_bytes() const noexcept {
|
||||
if(error == CAPACITY) { return len - batch_start; }
|
||||
return parser->implementation->structural_indexes[parser->implementation->n_structural_indexes] - parser->implementation->structural_indexes[parser->implementation->n_structural_indexes + 1];
|
||||
}
|
||||
|
||||
@@ -137,8 +138,9 @@ simdjson_really_inline document_stream::iterator::iterator(document_stream* _str
|
||||
: stream{_stream}, finished{is_end} {
|
||||
}
|
||||
|
||||
simdjson_really_inline ondemand::document& document_stream::iterator::operator*() noexcept {
|
||||
return stream->doc;
|
||||
simdjson_really_inline simdjson_result<ondemand::document_reference> document_stream::iterator::operator*() noexcept {
|
||||
//if(stream->error) { return stream->error; }
|
||||
return simdjson_result<ondemand::document_reference>(stream->doc, stream->error);
|
||||
}
|
||||
|
||||
simdjson_really_inline document_stream::iterator& document_stream::iterator::operator++() noexcept {
|
||||
|
||||
@@ -130,7 +130,7 @@ public:
|
||||
/**
|
||||
* Get the current document (or error).
|
||||
*/
|
||||
simdjson_really_inline ondemand::document& operator*() noexcept;
|
||||
simdjson_really_inline simdjson_result<ondemand::document_reference> operator*() noexcept;
|
||||
/**
|
||||
* Advance to the next document (prefix).
|
||||
*/
|
||||
|
||||
@@ -35,7 +35,9 @@ simdjson_really_inline json_iterator::json_iterator(const uint8_t *buf, ondemand
|
||||
|
||||
{
|
||||
logger::log_headers();
|
||||
#if SIMDJSON_CHECK_EOF
|
||||
assert_more_tokens();
|
||||
#endif
|
||||
}
|
||||
|
||||
inline void json_iterator::rewind() noexcept {
|
||||
@@ -51,17 +53,6 @@ inline void json_iterator::rewind() noexcept {
|
||||
SIMDJSON_PUSH_DISABLE_WARNINGS
|
||||
SIMDJSON_DISABLE_STRICT_OVERFLOW_WARNING
|
||||
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; }
|
||||
switch (*return_current_and_advance()) {
|
||||
// TODO consider whether matching braces is a requirement: if non-matching braces indicates
|
||||
@@ -84,24 +75,23 @@ simdjson_warn_unused simdjson_really_inline error_code json_iterator::skip_child
|
||||
logger::log_end_value(*this, "skip");
|
||||
_depth--;
|
||||
if (depth() <= parent_depth) { return SUCCESS; }
|
||||
#if __SIMDJSON_CHECK_EOF
|
||||
#if SIMDJSON_CHECK_EOF
|
||||
// If there are no more tokens, the parent is incomplete.
|
||||
if (at_end()) { return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "Missing [ or { at start"); }
|
||||
#endif // __SIMDJSON_CHECK_EOF
|
||||
#endif // SIMDJSON_CHECK_EOF
|
||||
break;
|
||||
/*case '"':
|
||||
case '"':
|
||||
if(*peek() == ':') {
|
||||
// we are at a key!!! This is
|
||||
// only possible if someone searched
|
||||
// for a key in an object and the key
|
||||
// was not found but our code then
|
||||
// decided the consume the separating
|
||||
// comma before returning.
|
||||
// We are at a key!!!
|
||||
// This might happen if you just started an object and you skip it immediately.
|
||||
// Performance note: it would be nice to get rid of this check as it is somewhat
|
||||
// expensive.
|
||||
// https://github.com/simdjson/simdjson/issues/1742
|
||||
logger::log_value(*this, "key");
|
||||
advance(); // eat up the ':'
|
||||
return_current_and_advance(); // eat up the ':'
|
||||
break; // important!!!
|
||||
}
|
||||
simdjson_fallthrough;*/
|
||||
simdjson_fallthrough;
|
||||
// Anything else must be a scalar value
|
||||
default:
|
||||
// For the first scalar, we will have incremented depth already, so we decrement it here.
|
||||
@@ -151,6 +141,10 @@ simdjson_really_inline token_position json_iterator::root_position() const noexc
|
||||
return _root;
|
||||
}
|
||||
|
||||
simdjson_really_inline void json_iterator::assert_at_document_depth() const noexcept {
|
||||
SIMDJSON_ASSUME( _depth == 1 );
|
||||
}
|
||||
|
||||
simdjson_really_inline void json_iterator::assert_at_root() const noexcept {
|
||||
SIMDJSON_ASSUME( _depth == 1 );
|
||||
#ifndef SIMDJSON_CLANG_VISUAL_STUDIO
|
||||
@@ -189,6 +183,20 @@ inline std::string json_iterator::to_string() const noexcept {
|
||||
+ std::string(" ]");
|
||||
}
|
||||
|
||||
inline simdjson_result<const char *> json_iterator::current_location() noexcept {
|
||||
if (!is_alive()) { // Unrecoverable error
|
||||
if (!at_root()) {
|
||||
return reinterpret_cast<const char *>(token.peek(-1));
|
||||
} else {
|
||||
return reinterpret_cast<const char *>(token.peek());
|
||||
}
|
||||
}
|
||||
if (at_end()) {
|
||||
return OUT_OF_BOUNDS;
|
||||
}
|
||||
return reinterpret_cast<const char *>(token.peek());
|
||||
}
|
||||
|
||||
simdjson_really_inline bool json_iterator::is_alive() const noexcept {
|
||||
return parser;
|
||||
}
|
||||
@@ -199,23 +207,28 @@ simdjson_really_inline void json_iterator::abandon() noexcept {
|
||||
}
|
||||
|
||||
simdjson_really_inline const uint8_t *json_iterator::return_current_and_advance() noexcept {
|
||||
// The following assert_more_tokens is currently disabled because rely on end-of-file buffering.
|
||||
// assert_more_tokens();
|
||||
// This is almost surely related to __SIMDJSON_CHECK_EOF but given that __SIMDJSON_CHECK_EOF
|
||||
// is ON by default, we have no choice but to disable it for real with a comment.
|
||||
#if SIMDJSON_CHECK_EOF
|
||||
assert_more_tokens();
|
||||
#endif // SIMDJSON_CHECK_EOF
|
||||
return token.return_current_and_advance();
|
||||
}
|
||||
|
||||
simdjson_really_inline const uint8_t *json_iterator::unsafe_pointer() const noexcept {
|
||||
// deliberately done without safety guard:
|
||||
return token.peek(0);
|
||||
}
|
||||
|
||||
simdjson_really_inline const uint8_t *json_iterator::peek(int32_t delta) const noexcept {
|
||||
// The following assert_more_tokens is currently disabled because rely on end-of-file buffering.
|
||||
// assert_more_tokens(delta+1);
|
||||
// This is almost surely related to __SIMDJSON_CHECK_EOF but given that __SIMDJSON_CHECK_EOF
|
||||
// is ON by default, we have no choice but to disable it for real with a comment.
|
||||
#if SIMDJSON_CHECK_EOF
|
||||
assert_more_tokens(delta+1);
|
||||
#endif // SIMDJSON_CHECK_EOF
|
||||
return token.peek(delta);
|
||||
}
|
||||
|
||||
simdjson_really_inline uint32_t json_iterator::peek_length(int32_t delta) const noexcept {
|
||||
#if SIMDJSON_CHECK_EOF
|
||||
assert_more_tokens(delta+1);
|
||||
#endif // #if SIMDJSON_CHECK_EOF
|
||||
return token.peek_length(delta);
|
||||
}
|
||||
|
||||
@@ -223,17 +236,15 @@ simdjson_really_inline const uint8_t *json_iterator::peek(token_position positio
|
||||
// todo: currently we require end-of-string buffering, but the following
|
||||
// assert_valid_position should be turned on if/when we lift that condition.
|
||||
// assert_valid_position(position);
|
||||
// This is almost surely related to __SIMDJSON_CHECK_EOF but given that __SIMDJSON_CHECK_EOF
|
||||
// This is almost surely related to SIMDJSON_CHECK_EOF but given that SIMDJSON_CHECK_EOF
|
||||
// is ON by default, we have no choice but to disable it for real with a comment.
|
||||
return token.peek(position);
|
||||
}
|
||||
|
||||
simdjson_really_inline uint32_t json_iterator::peek_length(token_position position) const noexcept {
|
||||
// todo: currently we require end-of-string buffering, but the following
|
||||
// assert_valid_position should be turned on if/when we lift that condition.
|
||||
// assert_valid_position(position);
|
||||
// This is almost surely related to __SIMDJSON_CHECK_EOF but given that __SIMDJSON_CHECK_EOF
|
||||
// is ON by default, we have no choice but to disable it for real with a comment.
|
||||
#if SIMDJSON_CHECK_EOF
|
||||
assert_valid_position(position);
|
||||
#endif // SIMDJSON_CHECK_EOF
|
||||
return token.peek_length(position);
|
||||
}
|
||||
|
||||
|
||||
@@ -88,9 +88,12 @@ public:
|
||||
* Get the root value iterator
|
||||
*/
|
||||
simdjson_really_inline token_position root_position() const noexcept;
|
||||
|
||||
/**
|
||||
* Assert if the iterator is not at the start
|
||||
* Assert that we are at the document depth (== 1)
|
||||
*/
|
||||
simdjson_really_inline void assert_at_document_depth() const noexcept;
|
||||
/**
|
||||
* Assert that we are at the root of the document
|
||||
*/
|
||||
simdjson_really_inline void assert_at_root() const noexcept;
|
||||
|
||||
@@ -145,12 +148,21 @@ public:
|
||||
* @param delta The relative position of the token to retrieve. e.g. 0 = next token, -1 = prev token.
|
||||
*/
|
||||
simdjson_really_inline uint32_t peek_length(int32_t delta=0) const noexcept;
|
||||
/**
|
||||
* Get a pointer to the current location in the input buffer.
|
||||
*
|
||||
* 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
|
||||
* safe to derefence this pointer.
|
||||
*/
|
||||
simdjson_really_inline const uint8_t *unsafe_pointer() const noexcept;
|
||||
/**
|
||||
* Get the JSON text for a given token.
|
||||
*
|
||||
* This is not null-terminated; it is a view into the JSON.
|
||||
*
|
||||
* @param index The position of the token to retrieve.
|
||||
* @param position The position of the token to retrieve.
|
||||
*
|
||||
* TODO consider a string_view, assuming the length will get stripped out by the optimizer when
|
||||
* it isn't used ...
|
||||
@@ -161,7 +173,7 @@ public:
|
||||
*
|
||||
* The length will include any whitespace at the end of the token.
|
||||
*
|
||||
* @param index The position of the token to retrieve.
|
||||
* @param position The position of the token to retrieve.
|
||||
*/
|
||||
simdjson_really_inline uint32_t peek_length(token_position position) const noexcept;
|
||||
/**
|
||||
@@ -204,7 +216,7 @@ public:
|
||||
simdjson_really_inline uint8_t *&string_buf_loc() noexcept;
|
||||
|
||||
/**
|
||||
* Report an error, preventing further iteration.
|
||||
* Report an unrecoverable error, preventing further iteration.
|
||||
*
|
||||
* @param error The error to report. Must not be SUCCESS, UNINITIALIZED, INCORRECT_TYPE, or NO_SUCH_FIELD.
|
||||
* @param message An error message to report with the error.
|
||||
@@ -228,6 +240,12 @@ public:
|
||||
#endif
|
||||
/* Useful for debugging and logging purposes. */
|
||||
inline std::string to_string() const noexcept;
|
||||
|
||||
/**
|
||||
* Returns the current location in the document if in bounds.
|
||||
*/
|
||||
inline simdjson_result<const char *> current_location() noexcept;
|
||||
|
||||
/**
|
||||
* Updates this json iterator so that it is back at the beginning of the document,
|
||||
* as if it had just been created.
|
||||
|
||||
@@ -15,12 +15,93 @@ inline std::ostream& operator<<(std::ostream& out, json_type type) noexcept {
|
||||
return out;
|
||||
}
|
||||
|
||||
inline std::ostream& operator<<(std::ostream& out, number_type type) noexcept {
|
||||
switch (type) {
|
||||
case number_type::signed_integer: out << "integer in [-9223372036854775808,9223372036854775808)"; break;
|
||||
case number_type::unsigned_integer: out << "unsigned integer in [9223372036854775808,18446744073709551616)"; break;
|
||||
case number_type::floating_point_number: out << "floating-point number (binary64)"; break;
|
||||
default: SIMDJSON_UNREACHABLE();
|
||||
}
|
||||
return out;
|
||||
}
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
inline std::ostream& operator<<(std::ostream& out, simdjson_result<json_type> &type) noexcept(false) {
|
||||
return out << type.value();
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
simdjson_really_inline number_type number::get_number_type() const noexcept {
|
||||
return type;
|
||||
}
|
||||
|
||||
simdjson_really_inline bool number::is_uint64() const noexcept {
|
||||
return get_number_type() == number_type::unsigned_integer;
|
||||
}
|
||||
|
||||
simdjson_really_inline uint64_t number::get_uint64() const noexcept {
|
||||
return payload.unsigned_integer;
|
||||
}
|
||||
|
||||
simdjson_really_inline number::operator uint64_t() const noexcept {
|
||||
return get_uint64();
|
||||
}
|
||||
|
||||
|
||||
simdjson_really_inline bool number::is_int64() const noexcept {
|
||||
return get_number_type() == number_type::signed_integer;
|
||||
}
|
||||
|
||||
simdjson_really_inline int64_t number::get_int64() const noexcept {
|
||||
return payload.signed_integer;
|
||||
}
|
||||
|
||||
simdjson_really_inline number::operator int64_t() const noexcept {
|
||||
return get_int64();
|
||||
}
|
||||
|
||||
simdjson_really_inline bool number::is_double() const noexcept {
|
||||
return get_number_type() == number_type::floating_point_number;
|
||||
}
|
||||
|
||||
simdjson_really_inline double number::get_double() const noexcept {
|
||||
return payload.floating_point_number;
|
||||
}
|
||||
|
||||
simdjson_really_inline number::operator double() const noexcept {
|
||||
return get_double();
|
||||
}
|
||||
|
||||
simdjson_really_inline double number::as_double() const noexcept {
|
||||
if(is_double()) {
|
||||
return payload.floating_point_number;
|
||||
}
|
||||
if(is_int64()) {
|
||||
return double(payload.signed_integer);
|
||||
}
|
||||
return double(payload.unsigned_integer);
|
||||
}
|
||||
|
||||
simdjson_really_inline void number::append_s64(int64_t value) noexcept {
|
||||
payload.signed_integer = value;
|
||||
type = number_type::signed_integer;
|
||||
}
|
||||
|
||||
simdjson_really_inline void number::append_u64(uint64_t value) noexcept {
|
||||
payload.unsigned_integer = value;
|
||||
type = number_type::unsigned_integer;
|
||||
}
|
||||
|
||||
simdjson_really_inline void number::append_double(double value) noexcept {
|
||||
payload.floating_point_number = value;
|
||||
type = number_type::floating_point_number;
|
||||
}
|
||||
|
||||
simdjson_really_inline void number::skip_double() noexcept {
|
||||
type = number_type::floating_point_number;
|
||||
}
|
||||
|
||||
} // namespace ondemand
|
||||
} // namespace SIMDJSON_IMPLEMENTATION
|
||||
} // namespace simdjson
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
namespace simdjson {
|
||||
namespace SIMDJSON_IMPLEMENTATION {
|
||||
namespace ondemand {
|
||||
|
||||
/**
|
||||
* The type of a JSON value.
|
||||
*/
|
||||
@@ -15,6 +14,106 @@ enum class json_type {
|
||||
null ///< A JSON null (null)
|
||||
};
|
||||
|
||||
class value_iterator;
|
||||
|
||||
/**
|
||||
* A type representing a JSON number.
|
||||
* The design of the struct is deliberately straight-forward. All
|
||||
* functions return standard values with no error check.
|
||||
*/
|
||||
struct number {
|
||||
|
||||
/**
|
||||
* return the automatically determined type of
|
||||
* the number: number_type::floating_point_number,
|
||||
* number_type::signed_integer or number_type::unsigned_integer.
|
||||
*
|
||||
* enum class number_type {
|
||||
* floating_point_number=1, /// a binary64 number
|
||||
* signed_integer, /// a signed integer that fits in a 64-bit word using two's complement
|
||||
* unsigned_integer /// a positive integer larger or equal to 1<<63
|
||||
* };
|
||||
*/
|
||||
simdjson_really_inline number_type get_number_type() const noexcept;
|
||||
/**
|
||||
* return true if the automatically determined type of
|
||||
* the number is number_type::unsigned_integer.
|
||||
*/
|
||||
simdjson_really_inline bool is_uint64() const noexcept;
|
||||
/**
|
||||
* return the value as a uint64_t, only valid if is_uint64() is true.
|
||||
*/
|
||||
simdjson_really_inline uint64_t get_uint64() const noexcept;
|
||||
simdjson_really_inline operator uint64_t() const noexcept;
|
||||
|
||||
/**
|
||||
* return true if the automatically determined type of
|
||||
* the number is number_type::signed_integer.
|
||||
*/
|
||||
simdjson_really_inline bool is_int64() const noexcept;
|
||||
/**
|
||||
* return the value as a int64_t, only valid if is_int64() is true.
|
||||
*/
|
||||
simdjson_really_inline int64_t get_int64() const noexcept;
|
||||
simdjson_really_inline operator int64_t() const noexcept;
|
||||
|
||||
|
||||
/**
|
||||
* return true if the automatically determined type of
|
||||
* the number is number_type::floating_point_number.
|
||||
*/
|
||||
simdjson_really_inline bool is_double() const noexcept;
|
||||
/**
|
||||
* return the value as a double, only valid if is_double() is true.
|
||||
*/
|
||||
simdjson_really_inline double get_double() const noexcept;
|
||||
simdjson_really_inline operator double() const noexcept;
|
||||
|
||||
/**
|
||||
* Convert the number to a double. Though it always succeed, the conversion
|
||||
* may be lossy if the number cannot be represented exactly.
|
||||
*/
|
||||
simdjson_really_inline double as_double() const noexcept;
|
||||
|
||||
|
||||
protected:
|
||||
/**
|
||||
* The next block of declaration is designed so that we can call the number parsing
|
||||
* functions on a number type. They are protected and should never be used outside
|
||||
* of the core simdjson library.
|
||||
*/
|
||||
friend class value_iterator;
|
||||
template<typename W>
|
||||
friend error_code numberparsing::write_float(const uint8_t *const src, bool negative, uint64_t i, const uint8_t * start_digits, size_t digit_count, int64_t exponent, W &writer);
|
||||
template<typename W>
|
||||
friend error_code numberparsing::parse_number(const uint8_t *const src, W &writer);
|
||||
template<typename W>
|
||||
friend error_code numberparsing::slow_float_parsing(simdjson_unused const uint8_t * src, W writer);
|
||||
/** Store a signed 64-bit value to the number. */
|
||||
simdjson_really_inline void append_s64(int64_t value) noexcept;
|
||||
/** Store an unsigned 64-bit value to the number. */
|
||||
simdjson_really_inline void append_u64(uint64_t value) noexcept;
|
||||
/** Store a double value to the number. */
|
||||
simdjson_really_inline void append_double(double value) noexcept;
|
||||
/** Specifies that the value is a double, but leave it undefined. */
|
||||
simdjson_really_inline void skip_double() noexcept;
|
||||
/**
|
||||
* End of friend declarations.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Our attributes are a union type (size = 64 bits)
|
||||
* followed by a type indicator.
|
||||
*/
|
||||
union {
|
||||
double floating_point_number;
|
||||
int64_t signed_integer;
|
||||
uint64_t unsigned_integer;
|
||||
} payload{0};
|
||||
number_type type{number_type::signed_integer};
|
||||
friend class value_iterator;
|
||||
};
|
||||
|
||||
/**
|
||||
* Write the JSON type to the output stream
|
||||
*
|
||||
@@ -22,6 +121,7 @@ enum class json_type {
|
||||
* @param type The json_type.
|
||||
*/
|
||||
inline std::ostream& operator<<(std::ostream& out, json_type type) noexcept;
|
||||
inline std::ostream& operator<<(std::ostream& out, number_type type) noexcept;
|
||||
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
/**
|
||||
|
||||
@@ -139,6 +139,29 @@ inline simdjson_result<value> object::at_pointer(std::string_view json_pointer)
|
||||
return child;
|
||||
}
|
||||
|
||||
simdjson_really_inline simdjson_result<size_t> object::count_fields() & noexcept {
|
||||
size_t count{0};
|
||||
// Important: we do not consume any of the values.
|
||||
for(simdjson_unused auto v : *this) { count++; }
|
||||
// The above loop will always succeed, but we want to report errors.
|
||||
if(iter.error()) { return iter.error(); }
|
||||
// We need to move back at the start because we expect users to iterate through
|
||||
// the object after counting the number of elements.
|
||||
iter.reset_object();
|
||||
return count;
|
||||
}
|
||||
|
||||
simdjson_really_inline simdjson_result<bool> object::is_empty() & noexcept {
|
||||
bool is_not_empty;
|
||||
auto error = iter.reset_object().get(is_not_empty);
|
||||
if(error) { return error; }
|
||||
return !is_not_empty;
|
||||
}
|
||||
|
||||
simdjson_really_inline simdjson_result<bool> object::reset() & noexcept {
|
||||
return iter.reset_object();
|
||||
}
|
||||
|
||||
} // namespace ondemand
|
||||
} // namespace SIMDJSON_IMPLEMENTATION
|
||||
} // namespace simdjson
|
||||
@@ -188,4 +211,19 @@ simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>
|
||||
return first.at_pointer(json_pointer);
|
||||
}
|
||||
|
||||
inline simdjson_result<bool> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object>::reset() noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.reset();
|
||||
}
|
||||
|
||||
inline simdjson_result<bool> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object>::is_empty() noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.is_empty();
|
||||
}
|
||||
|
||||
simdjson_really_inline simdjson_result<size_t> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object>::count_fields() & noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.count_fields();
|
||||
}
|
||||
|
||||
} // namespace simdjson
|
||||
|
||||
@@ -37,6 +37,13 @@ public:
|
||||
* **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 }`.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* @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.
|
||||
*/
|
||||
@@ -63,6 +70,13 @@ public:
|
||||
* If you have multiple fields with a matching key ({"x": 1, "x": 1}) be mindful
|
||||
* 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.
|
||||
*
|
||||
* @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.
|
||||
*/
|
||||
@@ -110,6 +124,41 @@ public:
|
||||
*/
|
||||
inline simdjson_result<value> at_pointer(std::string_view json_pointer) noexcept;
|
||||
|
||||
/**
|
||||
* Reset the iterator so that we are pointing back at the
|
||||
* beginning of the object. You should still consume values only once even if you
|
||||
* can iterate through the object more than once. If you unescape a string within
|
||||
* the object more than once, you have unsafe code. Note that rewinding an object
|
||||
* means that you may need to reparse it anew: it is not a free operation.
|
||||
*
|
||||
* @returns true if the object contains some elements (not empty)
|
||||
*/
|
||||
inline simdjson_result<bool> reset() & noexcept;
|
||||
/**
|
||||
* This method scans the beginning of the object and checks whether the
|
||||
* object is empty.
|
||||
* The runtime complexity is constant time. 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.
|
||||
*/
|
||||
inline simdjson_result<bool> is_empty() & 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.
|
||||
*/
|
||||
simdjson_really_inline simdjson_result<size_t> count_fields() & noexcept;
|
||||
/**
|
||||
* 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
|
||||
@@ -159,6 +208,10 @@ public:
|
||||
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> operator[](std::string_view key) & noexcept;
|
||||
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> operator[](std::string_view key) && noexcept;
|
||||
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> at_pointer(std::string_view json_pointer) noexcept;
|
||||
inline simdjson_result<bool> reset() noexcept;
|
||||
inline simdjson_result<bool> is_empty() noexcept;
|
||||
inline simdjson_result<size_t> count_fields() & noexcept;
|
||||
|
||||
};
|
||||
|
||||
} // namespace simdjson
|
||||
|
||||
@@ -54,6 +54,11 @@ public:
|
||||
* ondemand::parser parser;
|
||||
* 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
|
||||
*
|
||||
* Calling iterate on an invalid JSON document may not immediately trigger an error. The call to
|
||||
@@ -123,14 +128,15 @@ public:
|
||||
* iteration to ensure intermediate buffers can be accessed. Any document must be destroyed before
|
||||
* you call parse() again or destroy the parser.
|
||||
*
|
||||
* The ondemand::document instance holds the iterator. The document must remain in scope
|
||||
* while you are accessing instances of ondemand::value, ondemand::object, ondemand::array.
|
||||
*
|
||||
* ### REQUIRED: Buffer Padding
|
||||
*
|
||||
* The buffer must have at least SIMDJSON_PADDING extra allocated bytes. It does not matter what
|
||||
* those bytes are initialized to, as long as they are allocated.
|
||||
*
|
||||
* @param json The JSON to parse.
|
||||
* @param len The length of the JSON.
|
||||
* @param allocated The number of bytes allocated in the JSON (must be at least len+SIMDJSON_PADDING).
|
||||
*
|
||||
* @return The iterator, or an error:
|
||||
* - INSUFFICIENT_PADDING if the input has less than SIMDJSON_PADDING extra bytes.
|
||||
@@ -143,6 +149,69 @@ public:
|
||||
*/
|
||||
simdjson_warn_unused simdjson_result<json_iterator> iterate_raw(padded_string_view json) & noexcept;
|
||||
|
||||
|
||||
/**
|
||||
* Parse a buffer containing many JSON documents.
|
||||
*
|
||||
* auto json = R"({ "foo": 1 } { "foo": 2 } { "foo": 3 } )"_padded;
|
||||
* ondemand::parser parser;
|
||||
* ondemand::document_stream docs = parser.iterate_many(json);
|
||||
* for (auto & doc : docs) {
|
||||
* std::cout << doc["foo"] << std::endl;
|
||||
* }
|
||||
* // Prints 1 2 3
|
||||
*
|
||||
* No copy of the input buffer is made.
|
||||
*
|
||||
* The function is lazy: it may be that no more than one JSON document at a time is parsed.
|
||||
*
|
||||
* The caller is responsabile to ensure that the input string data remains unchanged and is
|
||||
* not deleted during the loop.
|
||||
*
|
||||
* ### Format
|
||||
*
|
||||
* The buffer must contain a series of one or more JSON documents, concatenated into a single
|
||||
* 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
|
||||
* lookahead than you might think, though.)
|
||||
*
|
||||
* 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
|
||||
* 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.
|
||||
* Setting batch_size to excessively large or excesively small values may impact negatively the
|
||||
* performance.
|
||||
*
|
||||
* ### REQUIRED: Buffer Padding
|
||||
*
|
||||
* The buffer must have at least SIMDJSON_PADDING extra allocated bytes. It does not matter what
|
||||
* those bytes are initialized to, as long as they are allocated.
|
||||
*
|
||||
* ### Threads
|
||||
*
|
||||
* When compiled with SIMDJSON_THREADS_ENABLED, this method will use a single thread under the
|
||||
* hood to do some lookahead.
|
||||
*
|
||||
* ### Parser Capacity
|
||||
*
|
||||
* If the parser's current capacity is less than batch_size, it will allocate enough capacity
|
||||
* to handle it (up to max_capacity).
|
||||
*
|
||||
* @param buf The concatenated JSON to parse.
|
||||
* @param len The length of the concatenated JSON.
|
||||
* @param batch_size The batch size to use. MUST be larger than the largest document. The sweet
|
||||
* spot is cache-related: small enough to fit in cache, yet big enough to
|
||||
* parse as many documents as possible in one tight loop.
|
||||
* Defaults to 10MB, which has been a reasonable sweet spot in our tests.
|
||||
* @return The stream, or an error. An empty input will yield 0 documents rather than an EMPTY error. Errors:
|
||||
* - MEMALLOC if the parser does not have enough capacity and memory allocation fails
|
||||
* - CAPACITY if the parser does not have enough capacity and batch_size > max_capacity.
|
||||
* - other json errors if parsing fails. You should not rely on these errors to always the same for the
|
||||
* same document: they may vary under runtime dispatch (so they may vary depending on your system and hardware).
|
||||
*/
|
||||
inline simdjson_result<document_stream> iterate_many(const uint8_t *buf, size_t len, size_t batch_size = DEFAULT_BATCH_SIZE) noexcept;
|
||||
/** @overload parse_many(const uint8_t *buf, size_t len, size_t batch_size) */
|
||||
inline simdjson_result<document_stream> iterate_many(const char *buf, size_t len, size_t batch_size = DEFAULT_BATCH_SIZE) noexcept;
|
||||
|
||||
@@ -20,6 +20,13 @@ inline simdjson_result<std::string_view> to_json_string(SIMDJSON_IMPLEMENTATION:
|
||||
return trim(v);
|
||||
}
|
||||
|
||||
inline simdjson_result<std::string_view> to_json_string(SIMDJSON_IMPLEMENTATION::ondemand::document_reference& x) noexcept {
|
||||
std::string_view v;
|
||||
auto error = x.raw_json().get(v);
|
||||
if(error) {return error; }
|
||||
return trim(v);
|
||||
}
|
||||
|
||||
inline simdjson_result<std::string_view> to_json_string(SIMDJSON_IMPLEMENTATION::ondemand::value& x) noexcept {
|
||||
/**
|
||||
* If we somehow receive a value that has already been consumed,
|
||||
@@ -66,28 +73,30 @@ inline simdjson_result<std::string_view> to_json_string(SIMDJSON_IMPLEMENTATION:
|
||||
return trim(v);
|
||||
}
|
||||
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
|
||||
inline simdjson_result<std::string_view> to_json_string(simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document> x) {
|
||||
if (x.error()) { return x.error(); }
|
||||
return to_json_string(x.value());
|
||||
return to_json_string(x.value_unsafe());
|
||||
}
|
||||
|
||||
inline simdjson_result<std::string_view> to_json_string(simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document_reference> x) {
|
||||
if (x.error()) { return x.error(); }
|
||||
return to_json_string(x.value_unsafe());
|
||||
}
|
||||
|
||||
inline simdjson_result<std::string_view> to_json_string(simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> x) {
|
||||
if (x.error()) { return x.error(); }
|
||||
return to_json_string(x.value());
|
||||
return to_json_string(x.value_unsafe());
|
||||
}
|
||||
|
||||
inline simdjson_result<std::string_view> to_json_string(simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object> x) {
|
||||
if (x.error()) { return x.error(); }
|
||||
return to_json_string(x.value());
|
||||
return to_json_string(x.value_unsafe());
|
||||
}
|
||||
|
||||
inline simdjson_result<std::string_view> to_json_string(simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array> x) {
|
||||
if (x.error()) { return x.error(); }
|
||||
return to_json_string(x.value());
|
||||
return to_json_string(x.value_unsafe());
|
||||
}
|
||||
#endif
|
||||
} // namespace simdjson
|
||||
|
||||
|
||||
@@ -153,7 +162,20 @@ inline std::ostream& operator<<(std::ostream& out, simdjson::SIMDJSON_IMPLEMENTA
|
||||
throw simdjson::simdjson_error(error);
|
||||
}
|
||||
}
|
||||
inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::SIMDJSON_IMPLEMENTATION::ondemand::document> x) {
|
||||
inline std::ostream& operator<<(std::ostream& out, simdjson::SIMDJSON_IMPLEMENTATION::ondemand::document_reference& value) {
|
||||
std::string_view v;
|
||||
auto error = simdjson::to_json_string(value).get(v);
|
||||
if(error == simdjson::SUCCESS) {
|
||||
return (out << v);
|
||||
} else {
|
||||
throw simdjson::simdjson_error(error);
|
||||
}
|
||||
}
|
||||
inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::SIMDJSON_IMPLEMENTATION::ondemand::document>&& x) {
|
||||
if (x.error()) { throw simdjson::simdjson_error(x.error()); }
|
||||
return (out << x.value());
|
||||
}
|
||||
inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::SIMDJSON_IMPLEMENTATION::ondemand::document_reference>&& x) {
|
||||
if (x.error()) { throw simdjson::simdjson_error(x.error()); }
|
||||
return (out << x.value());
|
||||
}
|
||||
|
||||
@@ -23,12 +23,10 @@ inline simdjson_result<std::string_view> to_json_string(SIMDJSON_IMPLEMENTATION:
|
||||
* contains JSON text that is suitable to be parsed as JSON again.
|
||||
*/
|
||||
inline simdjson_result<std::string_view> to_json_string(SIMDJSON_IMPLEMENTATION::ondemand::array& x) noexcept;
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
inline simdjson_result<std::string_view> to_json_string(simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document> x);
|
||||
inline simdjson_result<std::string_view> to_json_string(simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> x);
|
||||
inline simdjson_result<std::string_view> to_json_string(simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object> x);
|
||||
inline simdjson_result<std::string_view> to_json_string(simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array> x);
|
||||
#endif
|
||||
} // namespace simdjson
|
||||
|
||||
|
||||
@@ -63,7 +61,11 @@ inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<sim
|
||||
*/
|
||||
inline std::ostream& operator<<(std::ostream& out, simdjson::SIMDJSON_IMPLEMENTATION::ondemand::document& value);
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::SIMDJSON_IMPLEMENTATION::ondemand::document> x);
|
||||
inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::SIMDJSON_IMPLEMENTATION::ondemand::document>&& x);
|
||||
#endif
|
||||
inline std::ostream& operator<<(std::ostream& out, simdjson::SIMDJSON_IMPLEMENTATION::ondemand::document_reference& value);
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::SIMDJSON_IMPLEMENTATION::ondemand::document_reference>&& x);
|
||||
#endif
|
||||
/**
|
||||
* Print JSON to an output stream.
|
||||
|
||||
@@ -36,12 +36,21 @@ simdjson_really_inline simdjson_result<std::string_view> value::get_string() noe
|
||||
simdjson_really_inline simdjson_result<double> value::get_double() noexcept {
|
||||
return iter.get_double();
|
||||
}
|
||||
simdjson_really_inline simdjson_result<double> value::get_double_in_string() noexcept {
|
||||
return iter.get_double_in_string();
|
||||
}
|
||||
simdjson_really_inline simdjson_result<uint64_t> value::get_uint64() noexcept {
|
||||
return iter.get_uint64();
|
||||
}
|
||||
simdjson_really_inline simdjson_result<uint64_t> value::get_uint64_in_string() noexcept {
|
||||
return iter.get_uint64_in_string();
|
||||
}
|
||||
simdjson_really_inline simdjson_result<int64_t> value::get_int64() noexcept {
|
||||
return iter.get_int64();
|
||||
}
|
||||
simdjson_really_inline simdjson_result<int64_t> value::get_int64_in_string() noexcept {
|
||||
return iter.get_int64_in_string();
|
||||
}
|
||||
simdjson_really_inline simdjson_result<bool> value::get_bool() noexcept {
|
||||
return iter.get_bool();
|
||||
}
|
||||
@@ -105,6 +114,17 @@ simdjson_really_inline simdjson_result<size_t> value::count_elements() & noexcep
|
||||
iter.move_at_start();
|
||||
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 {
|
||||
auto a = get_array();
|
||||
return a.at(index);
|
||||
}
|
||||
|
||||
simdjson_really_inline simdjson_result<value> value::find_field(std::string_view key) noexcept {
|
||||
return start_or_resume_object().find_field(key);
|
||||
@@ -131,10 +151,35 @@ simdjson_really_inline simdjson_result<json_type> value::type() noexcept {
|
||||
return iter.type();
|
||||
}
|
||||
|
||||
simdjson_really_inline simdjson_result<bool> value::is_scalar() noexcept {
|
||||
json_type this_type;
|
||||
auto error = type().get(this_type);
|
||||
if(error) { return error; }
|
||||
return ! ((this_type == json_type::array) || (this_type == json_type::object));
|
||||
}
|
||||
|
||||
simdjson_really_inline bool value::is_negative() noexcept {
|
||||
return iter.is_negative();
|
||||
}
|
||||
|
||||
simdjson_really_inline simdjson_result<bool> value::is_integer() noexcept {
|
||||
return iter.is_integer();
|
||||
}
|
||||
simdjson_warn_unused simdjson_really_inline simdjson_result<number_type> value::get_number_type() noexcept {
|
||||
return iter.get_number_type();
|
||||
}
|
||||
simdjson_warn_unused simdjson_really_inline simdjson_result<number> value::get_number() noexcept {
|
||||
return iter.get_number();
|
||||
}
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
simdjson_really_inline simdjson_result<const char *> value::current_location() noexcept {
|
||||
return iter.json_iter().current_location();
|
||||
}
|
||||
|
||||
simdjson_really_inline simdjson_result<value> value::at_pointer(std::string_view json_pointer) noexcept {
|
||||
json_type t;
|
||||
SIMDJSON_TRY(type().get(t));
|
||||
@@ -173,6 +218,14 @@ simdjson_really_inline simdjson_result<size_t> simdjson_result<SIMDJSON_IMPLEMEN
|
||||
if (error()) { return error(); }
|
||||
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 {
|
||||
if (error()) { return error(); }
|
||||
return first.at(index);
|
||||
}
|
||||
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array_iterator> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>::begin() & noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.begin();
|
||||
@@ -221,14 +274,26 @@ simdjson_really_inline simdjson_result<uint64_t> simdjson_result<SIMDJSON_IMPLEM
|
||||
if (error()) { return error(); }
|
||||
return first.get_uint64();
|
||||
}
|
||||
simdjson_really_inline simdjson_result<uint64_t> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>::get_uint64_in_string() noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.get_uint64_in_string();
|
||||
}
|
||||
simdjson_really_inline simdjson_result<int64_t> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>::get_int64() noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.get_int64();
|
||||
}
|
||||
simdjson_really_inline simdjson_result<int64_t> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>::get_int64_in_string() noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.get_int64_in_string();
|
||||
}
|
||||
simdjson_really_inline simdjson_result<double> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>::get_double() noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.get_double();
|
||||
}
|
||||
simdjson_really_inline simdjson_result<double> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>::get_double_in_string() noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.get_double_in_string();
|
||||
}
|
||||
simdjson_really_inline simdjson_result<std::string_view> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>::get_string() noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.get_string();
|
||||
@@ -269,7 +334,26 @@ simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::json_t
|
||||
if (error()) { return error(); }
|
||||
return first.type();
|
||||
}
|
||||
|
||||
simdjson_really_inline simdjson_result<bool> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>::is_scalar() noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.is_scalar();
|
||||
}
|
||||
simdjson_really_inline simdjson_result<bool> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>::is_negative() noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.is_negative();
|
||||
}
|
||||
simdjson_really_inline simdjson_result<bool> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>::is_integer() noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.is_integer();
|
||||
}
|
||||
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::number_type> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>::get_number_type() noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.get_number_type();
|
||||
}
|
||||
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::number> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>::get_number() noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.get_number();
|
||||
}
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>::operator SIMDJSON_IMPLEMENTATION::ondemand::array() noexcept(false) {
|
||||
if (error()) { throw simdjson_error(error()); }
|
||||
@@ -310,6 +394,11 @@ simdjson_really_inline simdjson_result<std::string_view> simdjson_result<SIMDJSO
|
||||
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 simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>::at_pointer(std::string_view json_pointer) noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.at_pointer(json_pointer);
|
||||
|
||||
@@ -69,11 +69,19 @@ public:
|
||||
/**
|
||||
* Cast this JSON value to an unsigned integer.
|
||||
*
|
||||
* @returns A signed 64-bit integer.
|
||||
* @returns A unsigned 64-bit integer.
|
||||
* @returns INCORRECT_TYPE If the JSON value is not a 64-bit unsigned integer.
|
||||
*/
|
||||
simdjson_really_inline simdjson_result<uint64_t> get_uint64() noexcept;
|
||||
|
||||
/**
|
||||
* Cast this JSON value (inside string) to a unsigned integer.
|
||||
*
|
||||
* @returns A unsigned 64-bit integer.
|
||||
* @returns INCORRECT_TYPE If the JSON value is not a 64-bit unsigned integer.
|
||||
*/
|
||||
simdjson_really_inline simdjson_result<uint64_t> get_uint64_in_string() noexcept;
|
||||
|
||||
/**
|
||||
* Cast this JSON value to a signed integer.
|
||||
*
|
||||
@@ -82,6 +90,14 @@ public:
|
||||
*/
|
||||
simdjson_really_inline simdjson_result<int64_t> get_int64() noexcept;
|
||||
|
||||
/**
|
||||
* Cast this JSON value (inside string) to a signed integer.
|
||||
*
|
||||
* @returns A signed 64-bit integer.
|
||||
* @returns INCORRECT_TYPE If the JSON value is not a 64-bit integer.
|
||||
*/
|
||||
simdjson_really_inline simdjson_result<int64_t> get_int64_in_string() noexcept;
|
||||
|
||||
/**
|
||||
* Cast this JSON value to a double.
|
||||
*
|
||||
@@ -90,6 +106,14 @@ public:
|
||||
*/
|
||||
simdjson_really_inline simdjson_result<double> get_double() noexcept;
|
||||
|
||||
/**
|
||||
* Cast this JSON value (inside string) to a double
|
||||
*
|
||||
* @returns A double.
|
||||
* @returns INCORRECT_TYPE If the JSON value is not a valid floating-point number.
|
||||
*/
|
||||
simdjson_really_inline simdjson_result<double> get_double_in_string() noexcept;
|
||||
|
||||
/**
|
||||
* Cast this JSON value to a string.
|
||||
*
|
||||
@@ -220,6 +244,29 @@ public:
|
||||
* safe to continue.
|
||||
*/
|
||||
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.
|
||||
* This function should only be called once as the array iterator is not reset between each call.
|
||||
*
|
||||
* @return The value at the given index, or:
|
||||
* - INDEX_OUT_OF_BOUNDS if the array index is larger than an array length
|
||||
*/
|
||||
simdjson_really_inline simdjson_result<value> at(size_t index) noexcept;
|
||||
/**
|
||||
* Look up a field by name on an object (order-sensitive).
|
||||
*
|
||||
@@ -289,6 +336,85 @@ public:
|
||||
*/
|
||||
simdjson_really_inline simdjson_result<json_type> type() noexcept;
|
||||
|
||||
/**
|
||||
* Checks whether the value is a scalar (string, number, null, Boolean).
|
||||
* Returns false when there it is an array or object.
|
||||
*
|
||||
* @returns true if the type is string, number, null, Boolean
|
||||
* @error TAPE_ERROR when the JSON value is a bad token like "}" "," or "alse".
|
||||
*/
|
||||
simdjson_really_inline simdjson_result<bool> is_scalar() noexcept;
|
||||
|
||||
/**
|
||||
* Checks whether the value is a negative number.
|
||||
*
|
||||
* @returns true if the number if negative.
|
||||
*/
|
||||
simdjson_really_inline bool is_negative() noexcept;
|
||||
/**
|
||||
* Checks whether the value is an integer number. Note that
|
||||
* this requires to partially parse the number string. If
|
||||
* the value is determined to be an integer, it may still
|
||||
* not parse properly as an integer in subsequent steps
|
||||
* (e.g., it might overflow).
|
||||
*
|
||||
* Performance note: if you call this function systematically
|
||||
* before parsing a number, you may have fallen for a performance
|
||||
* anti-pattern.
|
||||
*
|
||||
* @returns true if the number if negative.
|
||||
*/
|
||||
simdjson_really_inline simdjson_result<bool> is_integer() noexcept;
|
||||
/**
|
||||
* Determine the number type (integer or floating-point number).
|
||||
*
|
||||
* get_number_type() is number_type::unsigned_integer if we have
|
||||
* an integer greater or equal to 9223372036854775808
|
||||
* get_number_type() is number_type::signed_integer if we have an
|
||||
* integer that is less than 9223372036854775808
|
||||
* Otherwise, get_number_type() has value number_type::floating_point_number
|
||||
*
|
||||
* This function requires processing the number string, but it is expected
|
||||
* to be faster than get_number().get_number_type() because it is does not
|
||||
* parse the number value.
|
||||
*
|
||||
* @returns the type of the number
|
||||
*/
|
||||
simdjson_really_inline simdjson_result<number_type> get_number_type() noexcept;
|
||||
|
||||
/**
|
||||
* Attempt to parse an ondemand::number. An ondemand::number may
|
||||
* contain an integer value or a floating-point value, the simdjson
|
||||
* library will autodetect the type. Thus it is a dynamically typed
|
||||
* number. Before accessing the value, you must determine the detected
|
||||
* type.
|
||||
*
|
||||
* number.get_number_type() is number_type::signed_integer if we have
|
||||
* an integer in [-9223372036854775808,9223372036854775808)
|
||||
* You can recover the value by calling number.get_int64() and you
|
||||
* have that number.is_int64() is true.
|
||||
*
|
||||
* number.get_number_type() is number_type::unsigned_integer if we have
|
||||
* an integer in [9223372036854775808,18446744073709551616)
|
||||
* You can recover the value by calling number.get_uint64() and you
|
||||
* have that number.is_uint64() is true.
|
||||
*
|
||||
* Otherwise, number.get_number_type() has value number_type::floating_point_number
|
||||
* and we have a binary64 number.
|
||||
* You can recover the value by calling number.get_double() and you
|
||||
* have that number.is_double() is true.
|
||||
*
|
||||
* You must check the type before accessing the value: it is an error
|
||||
* to call "get_int64()" when number.get_number_type() is not
|
||||
* number_type::signed_integer and when number.is_int64() is false.
|
||||
*
|
||||
* Performance note: this 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.
|
||||
*/
|
||||
simdjson_warn_unused simdjson_really_inline simdjson_result<number> get_number() noexcept;
|
||||
|
||||
|
||||
/**
|
||||
* Get the raw JSON for this token.
|
||||
*
|
||||
@@ -314,6 +440,11 @@ public:
|
||||
*/
|
||||
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;
|
||||
|
||||
/**
|
||||
* Get the value associated with the given JSON pointer. We use the RFC 6901
|
||||
* https://tools.ietf.org/html/rfc6901 standard.
|
||||
@@ -416,8 +547,11 @@ public:
|
||||
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object> get_object() noexcept;
|
||||
|
||||
simdjson_really_inline simdjson_result<uint64_t> get_uint64() noexcept;
|
||||
simdjson_really_inline simdjson_result<uint64_t> get_uint64_in_string() noexcept;
|
||||
simdjson_really_inline simdjson_result<int64_t> get_int64() noexcept;
|
||||
simdjson_really_inline simdjson_result<int64_t> get_int64_in_string() noexcept;
|
||||
simdjson_really_inline simdjson_result<double> get_double() noexcept;
|
||||
simdjson_really_inline simdjson_result<double> get_double_in_string() noexcept;
|
||||
simdjson_really_inline simdjson_result<std::string_view> get_string() noexcept;
|
||||
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::raw_json_string> get_raw_json_string() noexcept;
|
||||
simdjson_really_inline simdjson_result<bool> get_bool() noexcept;
|
||||
@@ -438,6 +572,8 @@ public:
|
||||
simdjson_really_inline operator bool() noexcept(false);
|
||||
#endif
|
||||
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::array_iterator> begin() & noexcept;
|
||||
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array_iterator> end() & noexcept;
|
||||
|
||||
@@ -500,10 +636,18 @@ public:
|
||||
* let it throw an exception).
|
||||
*/
|
||||
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_negative() 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> get_number() 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;
|
||||
|
||||
/** @copydoc simdjson_really_inline simdjson_result<const char *> current_location() noexcept */
|
||||
simdjson_really_inline simdjson_result<const char *> current_location() noexcept;
|
||||
|
||||
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> at_pointer(std::string_view json_pointer) noexcept;
|
||||
};
|
||||
|
||||
|
||||
@@ -40,16 +40,17 @@ simdjson_warn_unused simdjson_really_inline simdjson_result<bool> value_iterator
|
||||
// Note that adding a check for 'streaming' is not expensive since we only have at most
|
||||
// one root element.
|
||||
if (! _json_iter->streaming() && (*_json_iter->peek_last() != '}')) {
|
||||
_json_iter->abandon();
|
||||
return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "missing } at end");
|
||||
}
|
||||
return started_object();
|
||||
}
|
||||
|
||||
simdjson_warn_unused simdjson_really_inline error_code value_iterator::end_container() noexcept {
|
||||
#if __SIMDJSON_CHECK_EOF
|
||||
#if SIMDJSON_CHECK_EOF
|
||||
if (depth() > 1 && at_end()) { return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "missing parent ] or }"); }
|
||||
// if (depth() <= 1 && !at_end()) { return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "missing [ or { at start"); }
|
||||
#endif // __SIMDJSON_CHECK_EOF
|
||||
#endif // SIMDJSON_CHECK_EOF
|
||||
_json_iter->ascend_to(depth()-1);
|
||||
return SUCCESS;
|
||||
}
|
||||
@@ -130,6 +131,7 @@ simdjson_warn_unused simdjson_really_inline simdjson_result<bool> value_iterator
|
||||
// Get the key and colon, stopping at the value.
|
||||
raw_json_string actual_key;
|
||||
// size_t max_key_length = _json_iter->peek_length() - 2; // -2 for the two quotes
|
||||
// Note: _json_iter->peek_length() - 2 might overflow if _json_iter->peek_length() < 2.
|
||||
// field_key() advances the pointer and checks that '"' is found (corresponding to a key).
|
||||
// The depth is left unchanged by field_key().
|
||||
if ((error = field_key().get(actual_key) )) { abandon(); return error; };
|
||||
@@ -260,6 +262,7 @@ simdjson_warn_unused simdjson_really_inline simdjson_result<bool> value_iterator
|
||||
// Get the key and colon, stopping at the value.
|
||||
raw_json_string actual_key;
|
||||
// size_t max_key_length = _json_iter->peek_length() - 2; // -2 for the two quotes
|
||||
// Note: _json_iter->peek_length() - 2 might overflow if _json_iter->peek_length() < 2.
|
||||
// field_key() advances the pointer and checks that '"' is found (corresponding to a key).
|
||||
// The depth is left unchanged by field_key().
|
||||
if ((error = field_key().get(actual_key) )) { abandon(); return error; };
|
||||
@@ -309,6 +312,7 @@ simdjson_warn_unused simdjson_really_inline simdjson_result<bool> value_iterator
|
||||
// Get the key and colon, stopping at the value.
|
||||
raw_json_string actual_key;
|
||||
// size_t max_key_length = _json_iter->peek_length() - 2; // -2 for the two quotes
|
||||
// Note: _json_iter->peek_length() - 2 might overflow if _json_iter->peek_length() < 2.
|
||||
// field_key() advances the pointer and checks that '"' is found (corresponding to a key).
|
||||
// The depth is left unchanged by field_key().
|
||||
error = field_key().get(actual_key); SIMDJSON_ASSUME(!error);
|
||||
@@ -405,6 +409,7 @@ simdjson_warn_unused simdjson_really_inline simdjson_result<bool> value_iterator
|
||||
// Note that adding a check for 'streaming' is not expensive since we only have at most
|
||||
// one root element.
|
||||
if ( ! _json_iter->streaming() && (*_json_iter->peek_last() != ']')) {
|
||||
_json_iter->abandon();
|
||||
return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "missing ] at end");
|
||||
}
|
||||
return started_array();
|
||||
@@ -449,22 +454,37 @@ simdjson_warn_unused simdjson_really_inline simdjson_result<raw_json_string> val
|
||||
}
|
||||
simdjson_warn_unused simdjson_really_inline simdjson_result<uint64_t> value_iterator::get_uint64() noexcept {
|
||||
auto result = numberparsing::parse_unsigned(peek_non_root_scalar("uint64"));
|
||||
if(result.error() != INCORRECT_TYPE) { advance_non_root_scalar("uint64"); }
|
||||
if(result.error() == SUCCESS) { advance_non_root_scalar("uint64"); }
|
||||
return result;
|
||||
}
|
||||
simdjson_warn_unused simdjson_really_inline simdjson_result<uint64_t> value_iterator::get_uint64_in_string() noexcept {
|
||||
auto result = numberparsing::parse_unsigned_in_string(peek_non_root_scalar("uint64"));
|
||||
if(result.error() == SUCCESS) { advance_non_root_scalar("uint64"); }
|
||||
return result;
|
||||
}
|
||||
simdjson_warn_unused simdjson_really_inline simdjson_result<int64_t> value_iterator::get_int64() noexcept {
|
||||
auto result = numberparsing::parse_integer(peek_non_root_scalar("int64"));
|
||||
if(result.error() != INCORRECT_TYPE) { advance_non_root_scalar("int64"); }
|
||||
if(result.error() == SUCCESS) { advance_non_root_scalar("int64"); }
|
||||
return result;
|
||||
}
|
||||
simdjson_warn_unused simdjson_really_inline simdjson_result<int64_t> value_iterator::get_int64_in_string() noexcept {
|
||||
auto result = numberparsing::parse_integer_in_string(peek_non_root_scalar("int64"));
|
||||
if(result.error() == SUCCESS) { advance_non_root_scalar("int64"); }
|
||||
return result;
|
||||
}
|
||||
simdjson_warn_unused simdjson_really_inline simdjson_result<double> value_iterator::get_double() noexcept {
|
||||
auto result = numberparsing::parse_double(peek_non_root_scalar("double"));
|
||||
if(result.error() != INCORRECT_TYPE) { advance_non_root_scalar("double"); }
|
||||
if(result.error() == SUCCESS) { advance_non_root_scalar("double"); }
|
||||
return result;
|
||||
}
|
||||
simdjson_warn_unused simdjson_really_inline simdjson_result<double> value_iterator::get_double_in_string() noexcept {
|
||||
auto result = numberparsing::parse_double_in_string(peek_non_root_scalar("double"));
|
||||
if(result.error() == SUCCESS) { advance_non_root_scalar("double"); }
|
||||
return result;
|
||||
}
|
||||
simdjson_warn_unused simdjson_really_inline simdjson_result<bool> value_iterator::get_bool() noexcept {
|
||||
auto result = parse_bool(peek_non_root_scalar("bool"));
|
||||
if(result.error() != INCORRECT_TYPE) { advance_non_root_scalar("bool"); }
|
||||
if(result.error() == SUCCESS) { advance_non_root_scalar("bool"); }
|
||||
return result;
|
||||
}
|
||||
simdjson_really_inline bool value_iterator::is_null() noexcept {
|
||||
@@ -472,8 +492,65 @@ simdjson_really_inline bool value_iterator::is_null() noexcept {
|
||||
if(result) { advance_non_root_scalar("null"); }
|
||||
return result;
|
||||
}
|
||||
simdjson_really_inline bool value_iterator::is_negative() noexcept {
|
||||
return numberparsing::is_negative(peek_non_root_scalar("numbersign"));
|
||||
}
|
||||
simdjson_really_inline bool value_iterator::is_root_negative() noexcept {
|
||||
return numberparsing::is_negative(peek_root_scalar("numbersign"));
|
||||
}
|
||||
simdjson_really_inline simdjson_result<bool> value_iterator::is_integer() noexcept {
|
||||
return numberparsing::is_integer(peek_non_root_scalar("integer"));
|
||||
}
|
||||
simdjson_really_inline simdjson_result<number_type> value_iterator::get_number_type() noexcept {
|
||||
return numberparsing::get_number_type(peek_non_root_scalar("integer"));
|
||||
}
|
||||
simdjson_really_inline simdjson_result<number> value_iterator::get_number() noexcept {
|
||||
number num;
|
||||
error_code error = numberparsing::parse_number(peek_non_root_scalar("number"), num);
|
||||
if(error) { return error; }
|
||||
return num;
|
||||
}
|
||||
|
||||
constexpr const uint32_t MAX_INT_LENGTH = 1024;
|
||||
simdjson_really_inline simdjson_result<bool> value_iterator::is_root_integer() noexcept {
|
||||
auto max_len = peek_start_length();
|
||||
auto json = peek_root_scalar("is_root_integer");
|
||||
uint8_t tmpbuf[20+1]; // <20 digits> is the longest possible unsigned integer
|
||||
if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf)) {
|
||||
return false; // if there are more than 20 characters, it cannot be represented as an integer.
|
||||
}
|
||||
return numberparsing::is_integer(tmpbuf);
|
||||
}
|
||||
|
||||
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::number_type> value_iterator::get_root_number_type() noexcept {
|
||||
auto max_len = peek_start_length();
|
||||
auto json = peek_root_scalar("number");
|
||||
// Per https://www.exploringbinary.com/maximum-number-of-decimal-digits-in-binary-floating-point-numbers/,
|
||||
// 1074 is the maximum number of significant fractional digits. Add 8 more digits for the biggest
|
||||
// number: -0.<fraction>e-308.
|
||||
uint8_t tmpbuf[1074+8+1];
|
||||
if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf)) {
|
||||
logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 1082 characters");
|
||||
return NUMBER_ERROR;
|
||||
}
|
||||
return numberparsing::get_number_type(tmpbuf);
|
||||
}
|
||||
simdjson_really_inline simdjson_result<number> value_iterator::get_root_number() noexcept {
|
||||
auto max_len = peek_start_length();
|
||||
auto json = peek_root_scalar("number");
|
||||
// Per https://www.exploringbinary.com/maximum-number-of-decimal-digits-in-binary-floating-point-numbers/,
|
||||
// 1074 is the maximum number of significant fractional digits. Add 8 more digits for the biggest
|
||||
// number: -0.<fraction>e-308.
|
||||
uint8_t tmpbuf[1074+8+1];
|
||||
if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf)) {
|
||||
logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 1082 characters");
|
||||
return NUMBER_ERROR;
|
||||
}
|
||||
number num;
|
||||
error_code error = numberparsing::parse_number(tmpbuf, num);
|
||||
if(error) { return error; }
|
||||
advance_root_scalar("number");
|
||||
return num;
|
||||
}
|
||||
|
||||
simdjson_warn_unused simdjson_really_inline simdjson_result<std::string_view> value_iterator::get_root_string() noexcept {
|
||||
return get_string();
|
||||
@@ -490,7 +567,19 @@ simdjson_warn_unused simdjson_really_inline simdjson_result<uint64_t> value_iter
|
||||
return NUMBER_ERROR;
|
||||
}
|
||||
auto result = numberparsing::parse_unsigned(tmpbuf);
|
||||
if(result.error() != INCORRECT_TYPE) { advance_root_scalar("uint64"); }
|
||||
if(result.error() == SUCCESS) { advance_root_scalar("uint64"); }
|
||||
return result;
|
||||
}
|
||||
simdjson_warn_unused simdjson_really_inline simdjson_result<uint64_t> value_iterator::get_root_uint64_in_string() noexcept {
|
||||
auto max_len = peek_start_length();
|
||||
auto json = peek_root_scalar("uint64");
|
||||
uint8_t tmpbuf[20+1]; // <20 digits> is the longest possible unsigned integer
|
||||
if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf)) {
|
||||
logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 20 characters");
|
||||
return NUMBER_ERROR;
|
||||
}
|
||||
auto result = numberparsing::parse_unsigned_in_string(tmpbuf);
|
||||
if(result.error() == SUCCESS) { advance_root_scalar("uint64"); }
|
||||
return result;
|
||||
}
|
||||
simdjson_warn_unused simdjson_really_inline simdjson_result<int64_t> value_iterator::get_root_int64() noexcept {
|
||||
@@ -503,7 +592,20 @@ simdjson_warn_unused simdjson_really_inline simdjson_result<int64_t> value_itera
|
||||
}
|
||||
|
||||
auto result = numberparsing::parse_integer(tmpbuf);
|
||||
if(result.error() != INCORRECT_TYPE) { advance_root_scalar("int64"); }
|
||||
if(result.error() == SUCCESS) { advance_root_scalar("int64"); }
|
||||
return result;
|
||||
}
|
||||
simdjson_warn_unused simdjson_really_inline simdjson_result<int64_t> value_iterator::get_root_int64_in_string() noexcept {
|
||||
auto max_len = peek_start_length();
|
||||
auto json = peek_root_scalar("int64");
|
||||
uint8_t tmpbuf[20+1]; // -<19 digits> is the longest possible integer
|
||||
if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf)) {
|
||||
logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 20 characters");
|
||||
return NUMBER_ERROR;
|
||||
}
|
||||
|
||||
auto result = numberparsing::parse_integer_in_string(tmpbuf);
|
||||
if(result.error() == SUCCESS) { advance_root_scalar("int64"); }
|
||||
return result;
|
||||
}
|
||||
simdjson_warn_unused simdjson_really_inline simdjson_result<double> value_iterator::get_root_double() noexcept {
|
||||
@@ -518,7 +620,23 @@ simdjson_warn_unused simdjson_really_inline simdjson_result<double> value_iterat
|
||||
return NUMBER_ERROR;
|
||||
}
|
||||
auto result = numberparsing::parse_double(tmpbuf);
|
||||
if(result.error() != INCORRECT_TYPE) { advance_root_scalar("double"); }
|
||||
if(result.error() == SUCCESS) { advance_root_scalar("double"); }
|
||||
return result;
|
||||
}
|
||||
|
||||
simdjson_warn_unused simdjson_really_inline simdjson_result<double> value_iterator::get_root_double_in_string() noexcept {
|
||||
auto max_len = peek_start_length();
|
||||
auto json = peek_root_scalar("double");
|
||||
// Per https://www.exploringbinary.com/maximum-number-of-decimal-digits-in-binary-floating-point-numbers/,
|
||||
// 1074 is the maximum number of significant fractional digits. Add 8 more digits for the biggest
|
||||
// number: -0.<fraction>e-308.
|
||||
uint8_t tmpbuf[1074+8+1];
|
||||
if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf)) {
|
||||
logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 1082 characters");
|
||||
return NUMBER_ERROR;
|
||||
}
|
||||
auto result = numberparsing::parse_double_in_string(tmpbuf);
|
||||
if(result.error() == SUCCESS) { advance_root_scalar("double"); }
|
||||
return result;
|
||||
}
|
||||
simdjson_warn_unused simdjson_really_inline simdjson_result<bool> value_iterator::get_root_bool() noexcept {
|
||||
@@ -526,13 +644,14 @@ simdjson_warn_unused simdjson_really_inline simdjson_result<bool> value_iterator
|
||||
auto json = peek_root_scalar("bool");
|
||||
uint8_t tmpbuf[5+1];
|
||||
if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf)) { return incorrect_type_error("Not a boolean"); }
|
||||
advance_root_scalar("bool");
|
||||
return parse_bool(tmpbuf);
|
||||
auto result = parse_bool(tmpbuf);
|
||||
if(result.error() == SUCCESS) { advance_root_scalar("bool"); }
|
||||
return result;
|
||||
}
|
||||
simdjson_really_inline bool value_iterator::is_root_null() noexcept {
|
||||
auto max_len = peek_start_length();
|
||||
auto json = peek_root_scalar("null");
|
||||
auto result = (max_len >= 4 && !atomparsing::str4ncmp(json, "null") &&
|
||||
bool result = (max_len >= 4 && !atomparsing::str4ncmp(json, "null") &&
|
||||
(max_len == 4 || jsoncharutils::is_structural_or_whitespace(json[5])));
|
||||
if(result) { advance_root_scalar("null"); }
|
||||
return result;
|
||||
|
||||
@@ -283,17 +283,31 @@ public:
|
||||
simdjson_warn_unused simdjson_really_inline simdjson_result<std::string_view> get_string() noexcept;
|
||||
simdjson_warn_unused simdjson_really_inline simdjson_result<raw_json_string> get_raw_json_string() noexcept;
|
||||
simdjson_warn_unused simdjson_really_inline simdjson_result<uint64_t> get_uint64() noexcept;
|
||||
simdjson_warn_unused simdjson_really_inline simdjson_result<uint64_t> get_uint64_in_string() noexcept;
|
||||
simdjson_warn_unused simdjson_really_inline simdjson_result<int64_t> get_int64() noexcept;
|
||||
simdjson_warn_unused simdjson_really_inline simdjson_result<int64_t> get_int64_in_string() noexcept;
|
||||
simdjson_warn_unused simdjson_really_inline simdjson_result<double> get_double() noexcept;
|
||||
simdjson_warn_unused simdjson_really_inline simdjson_result<double> get_double_in_string() noexcept;
|
||||
simdjson_warn_unused simdjson_really_inline simdjson_result<bool> get_bool() noexcept;
|
||||
simdjson_really_inline bool is_null() noexcept;
|
||||
simdjson_warn_unused simdjson_really_inline bool is_negative() noexcept;
|
||||
simdjson_warn_unused simdjson_really_inline simdjson_result<bool> is_integer() noexcept;
|
||||
simdjson_warn_unused simdjson_really_inline simdjson_result<number_type> get_number_type() noexcept;
|
||||
simdjson_warn_unused simdjson_really_inline simdjson_result<number> get_number() noexcept;
|
||||
|
||||
simdjson_warn_unused simdjson_really_inline simdjson_result<std::string_view> get_root_string() noexcept;
|
||||
simdjson_warn_unused simdjson_really_inline simdjson_result<raw_json_string> get_root_raw_json_string() noexcept;
|
||||
simdjson_warn_unused simdjson_really_inline simdjson_result<uint64_t> get_root_uint64() noexcept;
|
||||
simdjson_warn_unused simdjson_really_inline simdjson_result<uint64_t> get_root_uint64_in_string() noexcept;
|
||||
simdjson_warn_unused simdjson_really_inline simdjson_result<int64_t> get_root_int64() noexcept;
|
||||
simdjson_warn_unused simdjson_really_inline simdjson_result<int64_t> get_root_int64_in_string() noexcept;
|
||||
simdjson_warn_unused simdjson_really_inline simdjson_result<double> get_root_double() noexcept;
|
||||
simdjson_warn_unused simdjson_really_inline simdjson_result<double> get_root_double_in_string() noexcept;
|
||||
simdjson_warn_unused simdjson_really_inline simdjson_result<bool> get_root_bool() noexcept;
|
||||
simdjson_warn_unused simdjson_really_inline bool is_root_negative() noexcept;
|
||||
simdjson_warn_unused simdjson_really_inline simdjson_result<bool> is_root_integer() noexcept;
|
||||
simdjson_warn_unused simdjson_really_inline simdjson_result<number_type> get_root_number_type() noexcept;
|
||||
simdjson_warn_unused simdjson_really_inline simdjson_result<number> get_root_number() noexcept;
|
||||
simdjson_really_inline bool is_root_null() noexcept;
|
||||
|
||||
simdjson_really_inline error_code error() const noexcept;
|
||||
|
||||
@@ -27,7 +27,7 @@ static simdjson_really_inline uint32_t parse_eight_digits_unrolled(const uint8_t
|
||||
} // namespace SIMDJSON_IMPLEMENTATION
|
||||
} // namespace simdjson
|
||||
|
||||
#define SWAR_NUMBER_PARSING
|
||||
#define SIMDJSON_SWAR_NUMBER_PARSING 1
|
||||
|
||||
#include "simdjson/generic/numberparsing.h"
|
||||
|
||||
|
||||
@@ -303,11 +303,12 @@ namespace simd {
|
||||
simdjson_really_inline simd8x64(const simd8<T> chunk0, const simd8<T> chunk1) : chunks{chunk0, chunk1} {}
|
||||
simdjson_really_inline simd8x64(const T ptr[64]) : chunks{simd8<T>::load(ptr), simd8<T>::load(ptr+32)} {}
|
||||
|
||||
simdjson_really_inline void compress(uint64_t mask, T * output) const {
|
||||
simdjson_really_inline uint64_t compress(uint64_t mask, T * output) const {
|
||||
uint32_t mask1 = uint32_t(mask);
|
||||
uint32_t mask2 = uint32_t(mask >> 32);
|
||||
this->chunks[0].compress(mask1, output);
|
||||
this->chunks[1].compress(mask2, output + 32 - count_ones(mask1));
|
||||
return 64 - count_ones(mask);
|
||||
}
|
||||
|
||||
simdjson_really_inline void store(T ptr[64]) const {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#define SIMDJSON_INTERNAL_JSONFORMATUTILS_H
|
||||
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <ostream>
|
||||
#include <sstream>
|
||||
|
||||
namespace simdjson {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2017-2019 by Martin Moene
|
||||
// Copyright 2017-2020 by Martin Moene
|
||||
//
|
||||
// string-view lite, a C++17-like string_view for C++98 and later.
|
||||
// For more information see https://github.com/martinmoene/string-view-lite
|
||||
@@ -12,7 +12,7 @@
|
||||
#define NONSTD_SV_LITE_H_INCLUDED
|
||||
|
||||
#define string_view_lite_MAJOR 1
|
||||
#define string_view_lite_MINOR 4
|
||||
#define string_view_lite_MINOR 6
|
||||
#define string_view_lite_PATCH 0
|
||||
|
||||
#define string_view_lite_VERSION nssv_STRINGIFY(string_view_lite_MAJOR) "." nssv_STRINGIFY(string_view_lite_MINOR) "." nssv_STRINGIFY(string_view_lite_PATCH)
|
||||
@@ -26,12 +26,22 @@
|
||||
#define nssv_STRING_VIEW_NONSTD 1
|
||||
#define nssv_STRING_VIEW_STD 2
|
||||
|
||||
#if !defined( nssv_CONFIG_SELECT_STRING_VIEW )
|
||||
# define nssv_CONFIG_SELECT_STRING_VIEW ( nssv_HAVE_STD_STRING_VIEW ? nssv_STRING_VIEW_STD : nssv_STRING_VIEW_NONSTD )
|
||||
// tweak header support:
|
||||
|
||||
#ifdef __has_include
|
||||
# if __has_include(<nonstd/string_view.tweak.hpp>)
|
||||
# include <nonstd/string_view.tweak.hpp>
|
||||
# endif
|
||||
#define nssv_HAVE_TWEAK_HEADER 1
|
||||
#else
|
||||
#define nssv_HAVE_TWEAK_HEADER 0
|
||||
//# pragma message("string_view.hpp: Note: Tweak header not supported.")
|
||||
#endif
|
||||
|
||||
#if defined( nssv_CONFIG_SELECT_STD_STRING_VIEW ) || defined( nssv_CONFIG_SELECT_NONSTD_STRING_VIEW )
|
||||
# error nssv_CONFIG_SELECT_STD_STRING_VIEW and nssv_CONFIG_SELECT_NONSTD_STRING_VIEW are deprecated and removed, please use nssv_CONFIG_SELECT_STRING_VIEW=nssv_STRING_VIEW_...
|
||||
// string_view selection and configuration:
|
||||
|
||||
#if !defined( nssv_CONFIG_SELECT_STRING_VIEW )
|
||||
# define nssv_CONFIG_SELECT_STRING_VIEW ( nssv_HAVE_STD_STRING_VIEW ? nssv_STRING_VIEW_STD : nssv_STRING_VIEW_NONSTD )
|
||||
#endif
|
||||
|
||||
#ifndef nssv_CONFIG_STD_SV_OPERATOR
|
||||
@@ -55,10 +65,17 @@
|
||||
# define nssv_CONFIG_CONVERSION_STD_STRING_FREE_FUNCTIONS 1
|
||||
#endif
|
||||
|
||||
#ifndef nssv_CONFIG_NO_STREAM_INSERTION
|
||||
# define nssv_CONFIG_NO_STREAM_INSERTION 0
|
||||
#endif
|
||||
|
||||
// Control presence of exception handling (try and auto discover):
|
||||
|
||||
#ifndef nssv_CONFIG_NO_EXCEPTIONS
|
||||
# if defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND)
|
||||
# if _MSC_VER
|
||||
# include <cstddef> // for _HAS_EXCEPTIONS
|
||||
# endif
|
||||
# if defined(__cpp_exceptions) || defined(__EXCEPTIONS) || (_HAS_EXCEPTIONS)
|
||||
# define nssv_CONFIG_NO_EXCEPTIONS 0
|
||||
# else
|
||||
# define nssv_CONFIG_NO_EXCEPTIONS 1
|
||||
@@ -221,16 +238,21 @@ using std::operator<<;
|
||||
|
||||
#define nssv_COMPILER_VERSION( major, minor, patch ) ( 10 * ( 10 * (major) + (minor) ) + (patch) )
|
||||
|
||||
#if defined(__clang__)
|
||||
# define nssv_COMPILER_CLANG_VERSION nssv_COMPILER_VERSION(__clang_major__, __clang_minor__, __clang_patchlevel__)
|
||||
#if defined( __apple_build_version__ )
|
||||
# define nssv_COMPILER_APPLECLANG_VERSION nssv_COMPILER_VERSION(__clang_major__, __clang_minor__, __clang_patchlevel__)
|
||||
# define nssv_COMPILER_CLANG_VERSION 0
|
||||
#elif defined( __clang__ )
|
||||
# define nssv_COMPILER_APPLECLANG_VERSION 0
|
||||
# define nssv_COMPILER_CLANG_VERSION nssv_COMPILER_VERSION(__clang_major__, __clang_minor__, __clang_patchlevel__)
|
||||
#else
|
||||
# define nssv_COMPILER_CLANG_VERSION 0
|
||||
# define nssv_COMPILER_APPLECLANG_VERSION 0
|
||||
# define nssv_COMPILER_CLANG_VERSION 0
|
||||
#endif
|
||||
|
||||
#if defined(__GNUC__) && !defined(__clang__)
|
||||
# define nssv_COMPILER_GNUC_VERSION nssv_COMPILER_VERSION(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__)
|
||||
#else
|
||||
# define nssv_COMPILER_GNUC_VERSION 0
|
||||
# define nssv_COMPILER_GNUC_VERSION 0
|
||||
#endif
|
||||
|
||||
// half-open range [lo..hi):
|
||||
@@ -292,6 +314,45 @@ using std::operator<<;
|
||||
|
||||
#define nssv_HAVE_STD_HASH nssv_CPP11_120
|
||||
|
||||
// Presence of compiler intrinsics:
|
||||
|
||||
// Providing char-type specializations for compare() and length() that
|
||||
// use compiler intrinsics can improve compile- and run-time performance.
|
||||
//
|
||||
// The challenge is in using the right combinations of builtin availability
|
||||
// and its constexpr-ness.
|
||||
//
|
||||
// | compiler | __builtin_memcmp (constexpr) | memcmp (constexpr) |
|
||||
// |----------|------------------------------|---------------------|
|
||||
// | clang | 4.0 (>= 4.0 ) | any (? ) |
|
||||
// | clang-a | 9.0 (>= 9.0 ) | any (? ) |
|
||||
// | gcc | any (constexpr) | any (? ) |
|
||||
// | msvc | >= 14.2 C++17 (>= 14.2 ) | any (? ) |
|
||||
|
||||
#define nssv_HAVE_BUILTIN_VER ( (nssv_CPP17_000 && nssv_COMPILER_MSVC_VERSION >= 142) || nssv_COMPILER_GNUC_VERSION > 0 || nssv_COMPILER_CLANG_VERSION >= 400 || nssv_COMPILER_APPLECLANG_VERSION >= 900 )
|
||||
#define nssv_HAVE_BUILTIN_CE ( nssv_HAVE_BUILTIN_VER )
|
||||
|
||||
#define nssv_HAVE_BUILTIN_MEMCMP ( (nssv_HAVE_CONSTEXPR_14 && nssv_HAVE_BUILTIN_CE) || !nssv_HAVE_CONSTEXPR_14 )
|
||||
#define nssv_HAVE_BUILTIN_STRLEN ( (nssv_HAVE_CONSTEXPR_11 && nssv_HAVE_BUILTIN_CE) || !nssv_HAVE_CONSTEXPR_11 )
|
||||
|
||||
#ifdef __has_builtin
|
||||
# define nssv_HAVE_BUILTIN( x ) __has_builtin( x )
|
||||
#else
|
||||
# define nssv_HAVE_BUILTIN( x ) 0
|
||||
#endif
|
||||
|
||||
#if nssv_HAVE_BUILTIN(__builtin_memcmp) || nssv_HAVE_BUILTIN_VER
|
||||
# define nssv_BUILTIN_MEMCMP __builtin_memcmp
|
||||
#else
|
||||
# define nssv_BUILTIN_MEMCMP memcmp
|
||||
#endif
|
||||
|
||||
#if nssv_HAVE_BUILTIN(__builtin_strlen) || nssv_HAVE_BUILTIN_VER
|
||||
# define nssv_BUILTIN_STRLEN __builtin_strlen
|
||||
#else
|
||||
# define nssv_BUILTIN_STRLEN strlen
|
||||
#endif
|
||||
|
||||
// C++ feature usage:
|
||||
|
||||
#if nssv_HAVE_CONSTEXPR_11
|
||||
@@ -350,9 +411,12 @@ using std::operator<<;
|
||||
#include <cassert>
|
||||
#include <iterator>
|
||||
#include <limits>
|
||||
#include <ostream>
|
||||
#include <string> // std::char_traits<>
|
||||
|
||||
#if ! nssv_CONFIG_NO_STREAM_INSERTION
|
||||
# include <ostream>
|
||||
#endif
|
||||
|
||||
#if ! nssv_CONFIG_NO_EXCEPTIONS
|
||||
# include <stdexcept>
|
||||
#endif
|
||||
@@ -405,40 +469,75 @@ nssv_DISABLE_MSVC_WARNINGS( 4455 26481 26472 )
|
||||
|
||||
namespace nonstd { namespace sv_lite {
|
||||
|
||||
#if nssv_CPP11_OR_GREATER
|
||||
|
||||
namespace detail {
|
||||
|
||||
#if nssv_CPP14_OR_GREATER
|
||||
// support constexpr comparison in C++14;
|
||||
// for C++17 and later, use provided traits:
|
||||
|
||||
template< typename CharT >
|
||||
inline constexpr std::size_t length( CharT * s, std::size_t result = 0 )
|
||||
inline nssv_constexpr14 int compare( CharT const * s1, CharT const * s2, std::size_t count )
|
||||
{
|
||||
CharT * v = s;
|
||||
std::size_t r = result;
|
||||
while ( *v != '\0' ) {
|
||||
++v;
|
||||
++r;
|
||||
while ( count-- != 0 )
|
||||
{
|
||||
if ( *s1 < *s2 ) return -1;
|
||||
if ( *s1 > *s2 ) return +1;
|
||||
++s1; ++s2;
|
||||
}
|
||||
return r;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else // nssv_CPP14_OR_GREATER
|
||||
#if nssv_HAVE_BUILTIN_MEMCMP
|
||||
|
||||
// specialization of compare() for char, see also generic compare() above:
|
||||
|
||||
inline nssv_constexpr14 int compare( char const * s1, char const * s2, std::size_t count )
|
||||
{
|
||||
return nssv_BUILTIN_MEMCMP( s1, s2, count );
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if nssv_HAVE_BUILTIN_STRLEN
|
||||
|
||||
// specialization of length() for char, see also generic length() further below:
|
||||
|
||||
inline nssv_constexpr std::size_t length( char const * s )
|
||||
{
|
||||
return nssv_BUILTIN_STRLEN( s );
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(__OPTIMIZE__)
|
||||
|
||||
// gcc, clang provide __OPTIMIZE__
|
||||
// Expect tail call optimization to make length() non-recursive:
|
||||
|
||||
template< typename CharT >
|
||||
inline constexpr std::size_t length( CharT * s, std::size_t result = 0 )
|
||||
inline nssv_constexpr std::size_t length( CharT * s, std::size_t result = 0 )
|
||||
{
|
||||
return *s == '\0' ? result : length( s + 1, result + 1 );
|
||||
}
|
||||
|
||||
#endif // nssv_CPP14_OR_GREATER
|
||||
#else // OPTIMIZE
|
||||
|
||||
// non-recursive:
|
||||
|
||||
template< typename CharT >
|
||||
inline nssv_constexpr14 std::size_t length( CharT * s )
|
||||
{
|
||||
std::size_t result = 0;
|
||||
while ( *s++ != '\0' )
|
||||
{
|
||||
++result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif // OPTIMIZE
|
||||
|
||||
} // namespace detail
|
||||
|
||||
#endif // nssv_CPP11_OR_GREATER
|
||||
|
||||
template
|
||||
<
|
||||
class CharT,
|
||||
@@ -589,9 +688,9 @@ public:
|
||||
|
||||
nssv_constexpr14 void swap( basic_string_view & other ) nssv_noexcept
|
||||
{
|
||||
using std::swap;
|
||||
swap( data_, other.data_ );
|
||||
swap( size_, other.size_ );
|
||||
const basic_string_view tmp(other);
|
||||
other = *this;
|
||||
*this = tmp;
|
||||
}
|
||||
|
||||
// 24.4.2.6 String operations:
|
||||
@@ -630,7 +729,11 @@ public:
|
||||
|
||||
nssv_constexpr14 int compare( basic_string_view other ) const nssv_noexcept // (1)
|
||||
{
|
||||
#if nssv_CPP17_OR_GREATER
|
||||
if ( const int result = Traits::compare( data(), other.data(), (std::min)( size(), other.size() ) ) )
|
||||
#else
|
||||
if ( const int result = detail::compare( data(), other.data(), (std::min)( size(), other.size() ) ) )
|
||||
#endif
|
||||
{
|
||||
return result;
|
||||
}
|
||||
@@ -874,7 +977,7 @@ private:
|
||||
{
|
||||
const basic_string_view v;
|
||||
|
||||
nssv_constexpr explicit not_in_view( basic_string_view v ) : v( v ) {}
|
||||
nssv_constexpr explicit not_in_view( basic_string_view v_ ) : v( v_ ) {}
|
||||
|
||||
nssv_constexpr bool operator()( CharT c ) const
|
||||
{
|
||||
@@ -964,37 +1067,37 @@ template< class CharT, class Traits >
|
||||
nssv_constexpr bool operator== (
|
||||
basic_string_view <CharT, Traits> lhs,
|
||||
basic_string_view <CharT, Traits> rhs ) nssv_noexcept
|
||||
{ return lhs.compare( rhs ) == 0 ; }
|
||||
{ return lhs.size() == rhs.size() && lhs.compare( rhs ) == 0; }
|
||||
|
||||
template< class CharT, class Traits >
|
||||
nssv_constexpr bool operator!= (
|
||||
basic_string_view <CharT, Traits> lhs,
|
||||
basic_string_view <CharT, Traits> rhs ) nssv_noexcept
|
||||
{ return lhs.compare( rhs ) != 0 ; }
|
||||
{ return !( lhs == rhs ); }
|
||||
|
||||
template< class CharT, class Traits >
|
||||
nssv_constexpr bool operator< (
|
||||
basic_string_view <CharT, Traits> lhs,
|
||||
basic_string_view <CharT, Traits> rhs ) nssv_noexcept
|
||||
{ return lhs.compare( rhs ) < 0 ; }
|
||||
{ return lhs.compare( rhs ) < 0; }
|
||||
|
||||
template< class CharT, class Traits >
|
||||
nssv_constexpr bool operator<= (
|
||||
basic_string_view <CharT, Traits> lhs,
|
||||
basic_string_view <CharT, Traits> rhs ) nssv_noexcept
|
||||
{ return lhs.compare( rhs ) <= 0 ; }
|
||||
{ return lhs.compare( rhs ) <= 0; }
|
||||
|
||||
template< class CharT, class Traits >
|
||||
nssv_constexpr bool operator> (
|
||||
basic_string_view <CharT, Traits> lhs,
|
||||
basic_string_view <CharT, Traits> rhs ) nssv_noexcept
|
||||
{ return lhs.compare( rhs ) > 0 ; }
|
||||
{ return lhs.compare( rhs ) > 0; }
|
||||
|
||||
template< class CharT, class Traits >
|
||||
nssv_constexpr bool operator>= (
|
||||
basic_string_view <CharT, Traits> lhs,
|
||||
basic_string_view <CharT, Traits> rhs ) nssv_noexcept
|
||||
{ return lhs.compare( rhs ) >= 0 ; }
|
||||
{ return lhs.compare( rhs ) >= 0; }
|
||||
|
||||
// Let S be basic_string_view<CharT, Traits>, and sv be an instance of S.
|
||||
// Implementations shall provide sufficient additional overloads marked
|
||||
@@ -1003,21 +1106,21 @@ nssv_constexpr bool operator>= (
|
||||
|
||||
#if ! nssv_CPP11_OR_GREATER || nssv_BETWEEN( nssv_COMPILER_MSVC_VERSION, 100, 141 )
|
||||
|
||||
// accomodate for older compilers:
|
||||
// accommodate for older compilers:
|
||||
|
||||
// ==
|
||||
|
||||
template< class CharT, class Traits>
|
||||
nssv_constexpr bool operator==(
|
||||
basic_string_view<CharT, Traits> lhs,
|
||||
char const * rhs ) nssv_noexcept
|
||||
{ return lhs.compare( rhs ) == 0; }
|
||||
CharT const * rhs ) nssv_noexcept
|
||||
{ return lhs.size() == detail::length( rhs ) && lhs.compare( rhs ) == 0; }
|
||||
|
||||
template< class CharT, class Traits>
|
||||
nssv_constexpr bool operator==(
|
||||
char const * lhs,
|
||||
CharT const * lhs,
|
||||
basic_string_view<CharT, Traits> rhs ) nssv_noexcept
|
||||
{ return rhs.compare( lhs ) == 0; }
|
||||
{ return detail::length( lhs ) == rhs.size() && rhs.compare( lhs ) == 0; }
|
||||
|
||||
template< class CharT, class Traits>
|
||||
nssv_constexpr bool operator==(
|
||||
@@ -1036,38 +1139,38 @@ nssv_constexpr bool operator==(
|
||||
template< class CharT, class Traits>
|
||||
nssv_constexpr bool operator!=(
|
||||
basic_string_view<CharT, Traits> lhs,
|
||||
char const * rhs ) nssv_noexcept
|
||||
{ return lhs.compare( rhs ) != 0; }
|
||||
CharT const * rhs ) nssv_noexcept
|
||||
{ return !( lhs == rhs ); }
|
||||
|
||||
template< class CharT, class Traits>
|
||||
nssv_constexpr bool operator!=(
|
||||
char const * lhs,
|
||||
CharT const * lhs,
|
||||
basic_string_view<CharT, Traits> rhs ) nssv_noexcept
|
||||
{ return rhs.compare( lhs ) != 0; }
|
||||
{ return !( lhs == rhs ); }
|
||||
|
||||
template< class CharT, class Traits>
|
||||
nssv_constexpr bool operator!=(
|
||||
basic_string_view<CharT, Traits> lhs,
|
||||
std::basic_string<CharT, Traits> rhs ) nssv_noexcept
|
||||
{ return lhs.size() != rhs.size() && lhs.compare( rhs ) != 0; }
|
||||
{ return !( lhs == rhs ); }
|
||||
|
||||
template< class CharT, class Traits>
|
||||
nssv_constexpr bool operator!=(
|
||||
std::basic_string<CharT, Traits> rhs,
|
||||
basic_string_view<CharT, Traits> lhs ) nssv_noexcept
|
||||
{ return lhs.size() != rhs.size() || rhs.compare( lhs ) != 0; }
|
||||
{ return !( lhs == rhs ); }
|
||||
|
||||
// <
|
||||
|
||||
template< class CharT, class Traits>
|
||||
nssv_constexpr bool operator<(
|
||||
basic_string_view<CharT, Traits> lhs,
|
||||
char const * rhs ) nssv_noexcept
|
||||
CharT const * rhs ) nssv_noexcept
|
||||
{ return lhs.compare( rhs ) < 0; }
|
||||
|
||||
template< class CharT, class Traits>
|
||||
nssv_constexpr bool operator<(
|
||||
char const * lhs,
|
||||
CharT const * lhs,
|
||||
basic_string_view<CharT, Traits> rhs ) nssv_noexcept
|
||||
{ return rhs.compare( lhs ) > 0; }
|
||||
|
||||
@@ -1088,12 +1191,12 @@ nssv_constexpr bool operator<(
|
||||
template< class CharT, class Traits>
|
||||
nssv_constexpr bool operator<=(
|
||||
basic_string_view<CharT, Traits> lhs,
|
||||
char const * rhs ) nssv_noexcept
|
||||
CharT const * rhs ) nssv_noexcept
|
||||
{ return lhs.compare( rhs ) <= 0; }
|
||||
|
||||
template< class CharT, class Traits>
|
||||
nssv_constexpr bool operator<=(
|
||||
char const * lhs,
|
||||
CharT const * lhs,
|
||||
basic_string_view<CharT, Traits> rhs ) nssv_noexcept
|
||||
{ return rhs.compare( lhs ) >= 0; }
|
||||
|
||||
@@ -1114,12 +1217,12 @@ nssv_constexpr bool operator<=(
|
||||
template< class CharT, class Traits>
|
||||
nssv_constexpr bool operator>(
|
||||
basic_string_view<CharT, Traits> lhs,
|
||||
char const * rhs ) nssv_noexcept
|
||||
CharT const * rhs ) nssv_noexcept
|
||||
{ return lhs.compare( rhs ) > 0; }
|
||||
|
||||
template< class CharT, class Traits>
|
||||
nssv_constexpr bool operator>(
|
||||
char const * lhs,
|
||||
CharT const * lhs,
|
||||
basic_string_view<CharT, Traits> rhs ) nssv_noexcept
|
||||
{ return rhs.compare( lhs ) < 0; }
|
||||
|
||||
@@ -1140,12 +1243,12 @@ nssv_constexpr bool operator>(
|
||||
template< class CharT, class Traits>
|
||||
nssv_constexpr bool operator>=(
|
||||
basic_string_view<CharT, Traits> lhs,
|
||||
char const * rhs ) nssv_noexcept
|
||||
CharT const * rhs ) nssv_noexcept
|
||||
{ return lhs.compare( rhs ) >= 0; }
|
||||
|
||||
template< class CharT, class Traits>
|
||||
nssv_constexpr bool operator>=(
|
||||
char const * lhs,
|
||||
CharT const * lhs,
|
||||
basic_string_view<CharT, Traits> rhs ) nssv_noexcept
|
||||
{ return rhs.compare( lhs ) <= 0; }
|
||||
|
||||
@@ -1165,7 +1268,7 @@ nssv_constexpr bool operator>=(
|
||||
|
||||
#define nssv_BASIC_STRING_VIEW_I(T,U) typename std::decay< basic_string_view<T,U> >::type
|
||||
|
||||
#if nssv_BETWEEN( nssv_COMPILER_MSVC_VERSION, 140, 150 )
|
||||
#if defined(_MSC_VER) // issue 40
|
||||
# define nssv_MSVC_ORDER(x) , int=x
|
||||
#else
|
||||
# define nssv_MSVC_ORDER(x) /*, int=x*/
|
||||
@@ -1177,7 +1280,7 @@ template< class CharT, class Traits nssv_MSVC_ORDER(1) >
|
||||
nssv_constexpr bool operator==(
|
||||
basic_string_view <CharT, Traits> lhs,
|
||||
nssv_BASIC_STRING_VIEW_I(CharT, Traits) rhs ) nssv_noexcept
|
||||
{ return lhs.compare( rhs ) == 0; }
|
||||
{ return lhs.size() == rhs.size() && lhs.compare( rhs ) == 0; }
|
||||
|
||||
template< class CharT, class Traits nssv_MSVC_ORDER(2) >
|
||||
nssv_constexpr bool operator==(
|
||||
@@ -1191,13 +1294,13 @@ template< class CharT, class Traits nssv_MSVC_ORDER(1) >
|
||||
nssv_constexpr bool operator!= (
|
||||
basic_string_view < CharT, Traits > lhs,
|
||||
nssv_BASIC_STRING_VIEW_I( CharT, Traits ) rhs ) nssv_noexcept
|
||||
{ return lhs.size() != rhs.size() || lhs.compare( rhs ) != 0 ; }
|
||||
{ return !( lhs == rhs ); }
|
||||
|
||||
template< class CharT, class Traits nssv_MSVC_ORDER(2) >
|
||||
nssv_constexpr bool operator!= (
|
||||
nssv_BASIC_STRING_VIEW_I( CharT, Traits ) lhs,
|
||||
basic_string_view < CharT, Traits > rhs ) nssv_noexcept
|
||||
{ return lhs.compare( rhs ) != 0 ; }
|
||||
{ return !( lhs == rhs ); }
|
||||
|
||||
// <
|
||||
|
||||
@@ -1205,13 +1308,13 @@ template< class CharT, class Traits nssv_MSVC_ORDER(1) >
|
||||
nssv_constexpr bool operator< (
|
||||
basic_string_view < CharT, Traits > lhs,
|
||||
nssv_BASIC_STRING_VIEW_I( CharT, Traits ) rhs ) nssv_noexcept
|
||||
{ return lhs.compare( rhs ) < 0 ; }
|
||||
{ return lhs.compare( rhs ) < 0; }
|
||||
|
||||
template< class CharT, class Traits nssv_MSVC_ORDER(2) >
|
||||
nssv_constexpr bool operator< (
|
||||
nssv_BASIC_STRING_VIEW_I( CharT, Traits ) lhs,
|
||||
basic_string_view < CharT, Traits > rhs ) nssv_noexcept
|
||||
{ return lhs.compare( rhs ) < 0 ; }
|
||||
{ return lhs.compare( rhs ) < 0; }
|
||||
|
||||
// <=
|
||||
|
||||
@@ -1219,13 +1322,13 @@ template< class CharT, class Traits nssv_MSVC_ORDER(1) >
|
||||
nssv_constexpr bool operator<= (
|
||||
basic_string_view < CharT, Traits > lhs,
|
||||
nssv_BASIC_STRING_VIEW_I( CharT, Traits ) rhs ) nssv_noexcept
|
||||
{ return lhs.compare( rhs ) <= 0 ; }
|
||||
{ return lhs.compare( rhs ) <= 0; }
|
||||
|
||||
template< class CharT, class Traits nssv_MSVC_ORDER(2) >
|
||||
nssv_constexpr bool operator<= (
|
||||
nssv_BASIC_STRING_VIEW_I( CharT, Traits ) lhs,
|
||||
basic_string_view < CharT, Traits > rhs ) nssv_noexcept
|
||||
{ return lhs.compare( rhs ) <= 0 ; }
|
||||
{ return lhs.compare( rhs ) <= 0; }
|
||||
|
||||
// >
|
||||
|
||||
@@ -1233,13 +1336,13 @@ template< class CharT, class Traits nssv_MSVC_ORDER(1) >
|
||||
nssv_constexpr bool operator> (
|
||||
basic_string_view < CharT, Traits > lhs,
|
||||
nssv_BASIC_STRING_VIEW_I( CharT, Traits ) rhs ) nssv_noexcept
|
||||
{ return lhs.compare( rhs ) > 0 ; }
|
||||
{ return lhs.compare( rhs ) > 0; }
|
||||
|
||||
template< class CharT, class Traits nssv_MSVC_ORDER(2) >
|
||||
nssv_constexpr bool operator> (
|
||||
nssv_BASIC_STRING_VIEW_I( CharT, Traits ) lhs,
|
||||
basic_string_view < CharT, Traits > rhs ) nssv_noexcept
|
||||
{ return lhs.compare( rhs ) > 0 ; }
|
||||
{ return lhs.compare( rhs ) > 0; }
|
||||
|
||||
// >=
|
||||
|
||||
@@ -1247,13 +1350,13 @@ template< class CharT, class Traits nssv_MSVC_ORDER(1) >
|
||||
nssv_constexpr bool operator>= (
|
||||
basic_string_view < CharT, Traits > lhs,
|
||||
nssv_BASIC_STRING_VIEW_I( CharT, Traits ) rhs ) nssv_noexcept
|
||||
{ return lhs.compare( rhs ) >= 0 ; }
|
||||
{ return lhs.compare( rhs ) >= 0; }
|
||||
|
||||
template< class CharT, class Traits nssv_MSVC_ORDER(2) >
|
||||
nssv_constexpr bool operator>= (
|
||||
nssv_BASIC_STRING_VIEW_I( CharT, Traits ) lhs,
|
||||
basic_string_view < CharT, Traits > rhs ) nssv_noexcept
|
||||
{ return lhs.compare( rhs ) >= 0 ; }
|
||||
{ return lhs.compare( rhs ) >= 0; }
|
||||
|
||||
#undef nssv_MSVC_ORDER
|
||||
#undef nssv_BASIC_STRING_VIEW_I
|
||||
@@ -1262,6 +1365,8 @@ nssv_constexpr bool operator>= (
|
||||
|
||||
// 24.4.4 Inserters and extractors:
|
||||
|
||||
#if ! nssv_CONFIG_NO_STREAM_INSERTION
|
||||
|
||||
namespace detail {
|
||||
|
||||
template< class Stream >
|
||||
@@ -1311,6 +1416,8 @@ operator<<(
|
||||
return detail::write_to_stream( os, sv );
|
||||
}
|
||||
|
||||
#endif // nssv_CONFIG_NO_STREAM_INSERTION
|
||||
|
||||
// Several typedefs for common character types are provided:
|
||||
|
||||
typedef basic_string_view<char> string_view;
|
||||
@@ -1459,7 +1566,9 @@ using sv_lite::operator<=;
|
||||
using sv_lite::operator>;
|
||||
using sv_lite::operator>=;
|
||||
|
||||
#if ! nssv_CONFIG_NO_STREAM_INSERTION
|
||||
using sv_lite::operator<<;
|
||||
#endif
|
||||
|
||||
#if nssv_CONFIG_CONVERSION_STD_STRING_FREE_FUNCTIONS
|
||||
using sv_lite::to_string;
|
||||
@@ -1526,4 +1635,4 @@ public:
|
||||
nssv_RESTORE_WARNINGS()
|
||||
|
||||
#endif // nssv_HAVE_STD_STRING_VIEW
|
||||
#endif // NONSTD_SV_LITE_H_INCLUDED
|
||||
#endif // NONSTD_SV_LITE_H_INCLUDED
|
||||
|
||||
@@ -25,7 +25,7 @@ parse_eight_digits_unrolled(const uint8_t *chars) {
|
||||
} // namespace SIMDJSON_IMPLEMENTATION
|
||||
} // namespace simdjson
|
||||
|
||||
#define SWAR_NUMBER_PARSING
|
||||
#define SIMDJSON_SWAR_NUMBER_PARSING 1
|
||||
|
||||
#include "simdjson/generic/numberparsing.h"
|
||||
|
||||
|
||||
@@ -422,7 +422,7 @@ template <typename T> struct simd8x64 {
|
||||
(this->chunks[2] | this->chunks[3]);
|
||||
}
|
||||
|
||||
simdjson_really_inline void compress(uint64_t mask, T *output) const {
|
||||
simdjson_really_inline uint64_t compress(uint64_t mask, T *output) const {
|
||||
this->chunks[0].compress(uint16_t(mask), output);
|
||||
this->chunks[1].compress(uint16_t(mask >> 16),
|
||||
output + 16 - count_ones(mask & 0xFFFF));
|
||||
@@ -430,6 +430,7 @@ template <typename T> struct simd8x64 {
|
||||
output + 32 - count_ones(mask & 0xFFFFFFFF));
|
||||
this->chunks[3].compress(uint16_t(mask >> 48),
|
||||
output + 48 - count_ones(mask & 0xFFFFFFFFFFFF));
|
||||
return 64 - count_ones(mask);
|
||||
}
|
||||
|
||||
simdjson_really_inline uint64_t to_bitmask() const {
|
||||
|
||||
@@ -4,22 +4,22 @@
|
||||
#define SIMDJSON_SIMDJSON_VERSION_H
|
||||
|
||||
/** The version of simdjson being used (major.minor.revision) */
|
||||
#define SIMDJSON_VERSION 0.9.1
|
||||
#define SIMDJSON_VERSION 1.0.2
|
||||
|
||||
namespace simdjson {
|
||||
enum {
|
||||
/**
|
||||
* The major version (MAJOR.minor.revision) of simdjson being used.
|
||||
*/
|
||||
SIMDJSON_VERSION_MAJOR = 0,
|
||||
SIMDJSON_VERSION_MAJOR = 1,
|
||||
/**
|
||||
* The minor version (major.MINOR.revision) of simdjson being used.
|
||||
*/
|
||||
SIMDJSON_VERSION_MINOR = 9,
|
||||
SIMDJSON_VERSION_MINOR = 0,
|
||||
/**
|
||||
* The revision (major.minor.REVISION) of simdjson being used.
|
||||
*/
|
||||
SIMDJSON_VERSION_REVISION = 1
|
||||
SIMDJSON_VERSION_REVISION = 2
|
||||
};
|
||||
} // namespace simdjson
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ static simdjson_really_inline uint32_t parse_eight_digits_unrolled(const uint8_t
|
||||
} // namespace SIMDJSON_IMPLEMENTATION
|
||||
} // namespace simdjson
|
||||
|
||||
#define SWAR_NUMBER_PARSING
|
||||
#define SIMDJSON_SWAR_NUMBER_PARSING 1
|
||||
|
||||
#include "simdjson/generic/numberparsing.h"
|
||||
|
||||
|
||||
@@ -284,11 +284,12 @@ namespace simd {
|
||||
return (this->chunks[0] | this->chunks[1]) | (this->chunks[2] | this->chunks[3]);
|
||||
}
|
||||
|
||||
simdjson_really_inline void compress(uint64_t mask, T * output) const {
|
||||
simdjson_really_inline uint64_t compress(uint64_t mask, T * output) const {
|
||||
this->chunks[0].compress(uint16_t(mask), output);
|
||||
this->chunks[1].compress(uint16_t(mask >> 16), output + 16 - count_ones(mask & 0xFFFF));
|
||||
this->chunks[2].compress(uint16_t(mask >> 32), output + 32 - count_ones(mask & 0xFFFFFFFF));
|
||||
this->chunks[3].compress(uint16_t(mask >> 48), output + 48 - count_ones(mask & 0xFFFFFFFFFFFF));
|
||||
return 64 - count_ones(mask);
|
||||
}
|
||||
|
||||
simdjson_really_inline uint64_t to_bitmask() const {
|
||||
|
||||
@@ -1,35 +1,70 @@
|
||||
#include <iostream>
|
||||
#include "simdjson.h"
|
||||
#include "simdjson.cpp"
|
||||
#include "simdjson.h"
|
||||
#include <iostream>
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
if(argc < 2) {
|
||||
std::cerr << "Please specify at least one file name. " << std::endl;
|
||||
if (argc < 2) {
|
||||
std::cerr << "Please specify at least one file name and" << std::endl;
|
||||
std::cerr << "up to two files." << std::endl;
|
||||
std::cerr << "The first file should be a JSON document." << std::endl;
|
||||
std::cerr << "The second file should container many JSON documents."
|
||||
<< std::endl;
|
||||
std::cerr << "Try the test files: jsonexamples/twitter.json "
|
||||
"jsonexamples/amazon_cellphones.ndjson"
|
||||
<< std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
const char * filename = argv[1];
|
||||
simdjson::dom::parser parser;
|
||||
simdjson::dom::element elem;
|
||||
auto error = parser.load(filename).get(elem); // do the parsing
|
||||
const char *filename = argv[1];
|
||||
|
||||
simdjson::padded_string json;
|
||||
std::cout << "loading: " << filename << std::endl;
|
||||
auto error = simdjson::padded_string::load(filename).get(json);
|
||||
if (error) {
|
||||
std::cout << "parse failed" << std::endl;
|
||||
std::cout << "could not load the file " << filename << std::endl;
|
||||
std::cout << "error code: " << error << std::endl;
|
||||
std::cout << error << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
} else {
|
||||
std::cout << "parse valid: " << elem << std::endl;
|
||||
std::cout << "loaded: " << json.size() << " bytes." << std::endl;
|
||||
}
|
||||
if(argc == 2) {
|
||||
simdjson::ondemand::parser parser;
|
||||
simdjson::ondemand::document doc;
|
||||
error = parser.iterate(json).get(doc);
|
||||
if (error) {
|
||||
std::cout << error << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
simdjson::ondemand::json_type type;
|
||||
error = doc.type().get(type);
|
||||
if (error) {
|
||||
std::cout << error << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
std::cout << "if valid, the document has the following type at the root: " << type
|
||||
<< std::endl;
|
||||
|
||||
if (argc == 2) {
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
// parse_many
|
||||
const char * filename2 = argv[2];
|
||||
simdjson::dom::document_stream stream;
|
||||
error = parser.load_many(filename2).get(stream);
|
||||
// iterate_many
|
||||
const char *filename2 = argv[2];
|
||||
std::cout << "loading: " << filename2 << std::endl;
|
||||
simdjson::padded_string json2;
|
||||
error = simdjson::padded_string::load(filename2).get(json2);
|
||||
if (error) {
|
||||
std::cout << "could not load the file " << filename2 << std::endl;
|
||||
std::cout << "error code: " << error << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
} else {
|
||||
std::cout << "loaded: " << json2.size() << " bytes." << std::endl;
|
||||
}
|
||||
simdjson::ondemand::document_stream stream;
|
||||
error = parser.iterate_many(json2).get(stream);
|
||||
size_t counter{0};
|
||||
if (!error) {
|
||||
for (auto result : stream) {
|
||||
error = result.error();
|
||||
counter++;
|
||||
}
|
||||
}
|
||||
if (error) {
|
||||
@@ -38,8 +73,9 @@ int main(int argc, char *argv[]) {
|
||||
std::cout << error << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
} else {
|
||||
std::cout << "parse_many valid" << std::endl;
|
||||
std::cout << "I found " << counter << " potential JSON documents." << std::endl;
|
||||
}
|
||||
std::cout << "For more information on how simdjson works, please refer to our documentation." << std::endl;
|
||||
std::cout << "https://github.com/simdjson/simdjson/blob/master/doc/basics.md" << std::endl;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
+795
-146
File diff suppressed because it is too large
Load Diff
+6441
-677
File diff suppressed because it is too large
Load Diff
@@ -27,8 +27,7 @@ private:
|
||||
|
||||
simdjson_really_inline void json_minifier::next(const simd::simd8x64<uint8_t>& in, const json_block& block) {
|
||||
uint64_t mask = block.whitespace();
|
||||
in.compress(mask, dst);
|
||||
dst += 64 - count_ones(mask);
|
||||
dst += in.compress(mask, dst);
|
||||
}
|
||||
|
||||
simdjson_really_inline error_code json_minifier::finish(uint8_t *dst_start, size_t &dst_len) {
|
||||
|
||||
@@ -30,8 +30,10 @@ namespace internal {
|
||||
{ UNEXPECTED_ERROR, "Unexpected error, consider reporting this problem as you may have found a bug in simdjson" },
|
||||
{ PARSER_IN_USE, "Cannot parse a new document while a document is still in use." },
|
||||
{ OUT_OF_ORDER_ITERATION, "Objects and arrays can only be iterated when they are first encountered." },
|
||||
{ INSUFFICIENT_PADDING, "simdjson requires the input JSON string to have at least SIMDJSON_PADDING extra bytes allocated, beyond the string's length." },
|
||||
{ INCOMPLETE_ARRAY_OR_OBJECT, "JSON document ended early in the middle of an object or array." }
|
||||
{ INSUFFICIENT_PADDING, "simdjson requires the input JSON string to have at least SIMDJSON_PADDING extra bytes allocated, beyond the string's length. Consider using the simdjson::padded_string class if needed." },
|
||||
{ INCOMPLETE_ARRAY_OR_OBJECT, "JSON document ended early in the middle of an object or array." },
|
||||
{ SCALAR_DOCUMENT_AS_VALUE, "A JSON document made of a scalar (number, Boolean, null or string) is treated as a value. Use get_bool(), get_double(), etc. on the document instead. "},
|
||||
{ OUT_OF_BOUNDS, "Attempted to access location outside of document."}
|
||||
}; // error_messages[]
|
||||
|
||||
} // namespace internal
|
||||
|
||||
@@ -2116,7 +2116,20 @@ namespace to_string_tests {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool simple_overflows() {
|
||||
std::cout << "Running " << __func__ << std::endl;
|
||||
simdjson::dom::parser parser;
|
||||
simdjson::dom::element doc;
|
||||
ASSERT_ERROR( parser.parse(std::string("[f]")).get(doc), simdjson::F_ATOM_ERROR);
|
||||
ASSERT_ERROR( parser.parse(std::string("[t]")).get(doc), simdjson::T_ATOM_ERROR);
|
||||
ASSERT_ERROR( parser.parse(std::string("[n]")).get(doc), simdjson::N_ATOM_ERROR);
|
||||
ASSERT_ERROR( parser.parse(std::string("[-]")).get(doc), simdjson::NUMBER_ERROR);
|
||||
ASSERT_ERROR( parser.parse(std::string("{\"a\":f}")).get(doc), simdjson::F_ATOM_ERROR);
|
||||
ASSERT_ERROR( parser.parse(std::string("{\"a\":t}")).get(doc), simdjson::T_ATOM_ERROR);
|
||||
ASSERT_ERROR( parser.parse(std::string("{\"a\":n}")).get(doc), simdjson::N_ATOM_ERROR);
|
||||
ASSERT_ERROR( parser.parse(std::string("{\"a\":-}")).get(doc), simdjson::NUMBER_ERROR);
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
std::cout << std::unitbuf;
|
||||
@@ -2141,7 +2154,6 @@ int main(int argc, char *argv[]) {
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
// this is put here deliberately to check that the documentation is correct (README),
|
||||
// should this fail to compile, you should update the documentation:
|
||||
if (simdjson::active_implementation->name() == "unsupported") {
|
||||
@@ -2153,7 +2165,8 @@ int main(int argc, char *argv[]) {
|
||||
std::cout << "------------------------------------------------------------" << std::endl;
|
||||
|
||||
std::cout << "Running basic tests." << std::endl;
|
||||
if (to_string_tests::run() &&
|
||||
if (simple_overflows() &&
|
||||
to_string_tests::run() &&
|
||||
validate_tests::run() &&
|
||||
minify_tests::run() &&
|
||||
parse_api_tests::run() &&
|
||||
|
||||
@@ -611,6 +611,43 @@ namespace document_stream_tests {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool issue1668() {
|
||||
TEST_START();
|
||||
auto json = R"([1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100])"_padded;
|
||||
simdjson::dom::parser odparser;
|
||||
simdjson::dom::document_stream odstream;
|
||||
ASSERT_SUCCESS( odparser.parse_many(json.data(), json.length(), 50).get(odstream) );
|
||||
for (auto doc: odstream) {
|
||||
simdjson::dom::element val;
|
||||
ASSERT_ERROR(doc.at_pointer("/40").get(val), simdjson::CAPACITY);
|
||||
ASSERT_EQUAL(odstream.truncated_bytes(), json.length());
|
||||
}
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool issue1668_long() {
|
||||
TEST_START();
|
||||
auto json = R"([1,2,3,4,5] [1,2,3,4,5] [1,2,3,4,5] [1,2,3,4,5] [1,2,3,4,5] [1,2,3,4,5] [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100])"_padded;
|
||||
simdjson::dom::parser odparser;
|
||||
simdjson::dom::document_stream odstream;
|
||||
size_t counter{0};
|
||||
ASSERT_SUCCESS( odparser.parse_many(json.data(), json.length(), 50).get(odstream) );
|
||||
for (auto doc: odstream) {
|
||||
if(counter < 6) {
|
||||
int64_t val;
|
||||
ASSERT_SUCCESS(doc.at_pointer("/4").get(val));
|
||||
ASSERT_EQUAL(val, 5);
|
||||
} else {
|
||||
simdjson::dom::element val;
|
||||
ASSERT_ERROR(doc.at_pointer("/4").get(val), simdjson::CAPACITY);
|
||||
// We left 293 bytes unprocessed.
|
||||
ASSERT_EQUAL(odstream.truncated_bytes(), 293);
|
||||
}
|
||||
counter++;
|
||||
}
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool small_window() {
|
||||
std::cout << "Running " << __func__ << std::endl;
|
||||
std::vector<char> input;
|
||||
@@ -735,7 +772,7 @@ namespace document_stream_tests {
|
||||
bool document_stream_test() {
|
||||
std::cout << "Running " << __func__ << std::endl;
|
||||
fflush(NULL);
|
||||
const size_t n_records = 10000;
|
||||
const size_t n_records = 100;
|
||||
std::string data;
|
||||
std::vector<char> buf(1024);
|
||||
for (size_t i = 0; i < n_records; ++i) {
|
||||
@@ -775,7 +812,7 @@ namespace document_stream_tests {
|
||||
bool document_stream_utf8_test() {
|
||||
std::cout << "Running " << __func__ << std::endl;
|
||||
fflush(NULL);
|
||||
const size_t n_records = 10000;
|
||||
const size_t n_records = 100;
|
||||
std::string data;
|
||||
std::vector<char> buf(1024);
|
||||
for (size_t i = 0; i < n_records; ++i) {
|
||||
@@ -821,7 +858,24 @@ namespace document_stream_tests {
|
||||
for (auto doc : docs) {
|
||||
bool_count += doc.is_bool();
|
||||
}
|
||||
return true;
|
||||
return (bool_count == 0);
|
||||
}
|
||||
|
||||
bool fuzzaccess() {
|
||||
std::cout << "Running " << __func__ << std::endl;
|
||||
// Issue 38801 in oss-fuzz
|
||||
auto json = "\xff \n~~\n{}"_padded;
|
||||
simdjson::dom::parser parser;
|
||||
simdjson::dom::document_stream docs;
|
||||
ASSERT_SUCCESS(parser.parse_many(json).get(docs));
|
||||
size_t bool_count = 0;
|
||||
size_t total_count = 0;
|
||||
|
||||
for (auto doc : docs) {
|
||||
total_count++;
|
||||
bool_count += doc.is_bool();
|
||||
}
|
||||
return (bool_count == 0) && (total_count == 1);
|
||||
}
|
||||
|
||||
bool baby_fuzzer() {
|
||||
@@ -855,7 +909,8 @@ namespace document_stream_tests {
|
||||
}
|
||||
|
||||
bool run() {
|
||||
return baby_fuzzer() &&
|
||||
return fuzzaccess() &&
|
||||
baby_fuzzer() &&
|
||||
issue1649() &&
|
||||
adversarial_single_document_array() &&
|
||||
adversarial_single_document() &&
|
||||
|
||||
@@ -108,7 +108,7 @@ namespace document_tests {
|
||||
// returns true if successful
|
||||
bool skyprophet_test() {
|
||||
std::cout << "Running " << __func__ << std::endl;
|
||||
const size_t n_records = 100000;
|
||||
const size_t n_records = 100;
|
||||
std::vector<std::string> data;
|
||||
std::vector<char> buf(1024);
|
||||
for (size_t i = 0; i < n_records; ++i) {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user