Merge pull request #1342 from simdjson/jkeiser/iter-safety

Safety: assert in debug mode when on demand values are used out of order
This commit is contained in:
John Keiser 2020-12-16 15:58:29 -08:00 committed by GitHub
commit f785f76d98
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
34 changed files with 450 additions and 248 deletions

View File

@ -19,7 +19,7 @@ environment:
- job_name: VS2017 (Static, No Threads) - job_name: VS2017 (Static, No Threads)
image: Visual Studio 2017 image: Visual Studio 2017
CMAKE_ARGS: -A %Platform% -DSIMDJSON_BUILD_STATIC=ON -DSIMDJSON_ENABLE_THREADS=OFF CMAKE_ARGS: -A %Platform% -DSIMDJSON_BUILD_STATIC=ON -DSIMDJSON_ENABLE_THREADS=OFF
CTEST_ARGS: -E checkperf CTEST_ARGS: -LE explicitonly
- job_name: VS2019 (Win32) - job_name: VS2019 (Win32)
platform: Win32 platform: Win32
CMAKE_ARGS: -A %Platform% -DSIMDJSON_BUILD_STATIC=OFF -DSIMDJSON_ENABLE_THREADS=ON # This should be the default. Testing anyway. CMAKE_ARGS: -A %Platform% -DSIMDJSON_BUILD_STATIC=OFF -DSIMDJSON_ENABLE_THREADS=ON # This should be the default. Testing anyway.
@ -31,7 +31,7 @@ environment:
- job_name: VS2015 - job_name: VS2015
image: Visual Studio 2015 image: Visual Studio 2015
CMAKE_ARGS: -A %Platform% -DSIMDJSON_BUILD_STATIC=ON -DSIMDJSON_ENABLE_THREADS=OFF CMAKE_ARGS: -A %Platform% -DSIMDJSON_BUILD_STATIC=ON -DSIMDJSON_ENABLE_THREADS=OFF
CTEST_ARGS: -E checkperf CTEST_ARGS: -LE explicitonly
build_script: build_script:
- mkdir build - mkdir build

View File

@ -103,7 +103,14 @@ commands:
cd build && cd build &&
tools/json2json -h && tools/json2json -h &&
ctest $CTEST_FLAGS -L acceptance && ctest $CTEST_FLAGS -L acceptance &&
ctest $CTEST_FLAGS -LE acceptance -E checkperf ctest $CTEST_FLAGS -LE acceptance -LE explicitonly
cmake_assert_test:
steps:
- run: |
cd build &&
tools/json2json -h &&
ctest $CTEST_FLAGS -L assert
cmake_test_all: cmake_test_all:
steps: steps:
@ -112,9 +119,9 @@ commands:
cd build && cd build &&
tools/json2json -h && tools/json2json -h &&
ctest $CTEST_FLAGS -DSIMDJSON_IMPLEMENTATION="haswell;westmere;fallback" -L acceptance -LE per_implementation && ctest $CTEST_FLAGS -DSIMDJSON_IMPLEMENTATION="haswell;westmere;fallback" -L acceptance -LE per_implementation &&
SIMDJSON_FORCE_IMPLEMENTATION=haswell ctest $CTEST_FLAGS -L per_implementation -E checkperf && SIMDJSON_FORCE_IMPLEMENTATION=haswell ctest $CTEST_FLAGS -L per_implementation -LE explicitonly &&
SIMDJSON_FORCE_IMPLEMENTATION=westmere ctest $CTEST_FLAGS -L per_implementation -E checkperf && SIMDJSON_FORCE_IMPLEMENTATION=westmere ctest $CTEST_FLAGS -L per_implementation -LE explicitonly &&
SIMDJSON_FORCE_IMPLEMENTATION=fallback ctest $CTEST_FLAGS -L per_implementation -E checkperf && SIMDJSON_FORCE_IMPLEMENTATION=fallback ctest $CTEST_FLAGS -L per_implementation -LE explicitonly &&
ctest $CTEST_FLAGS -LE "acceptance|per_implementation" # Everything we haven't run yet, run now. ctest $CTEST_FLAGS -LE "acceptance|per_implementation" # Everything we haven't run yet, run now.
@ -144,6 +151,16 @@ jobs:
executor: gcc10 executor: gcc10
environment: { CMAKE_FLAGS: -DSIMDJSON_JUST_LIBRARY=ON } environment: { CMAKE_FLAGS: -DSIMDJSON_JUST_LIBRARY=ON }
steps: [ cmake_build, cmake_install_test, cmake_installed_test_cxx20 ] steps: [ cmake_build, cmake_install_test, cmake_installed_test_cxx20 ]
assert-gcc10:
description: Build the library with asserts on, install it and run tests
executor: gcc10
environment: { CMAKE_FLAGS: -DSIMDJSON_GOOGLE_BENCHMARKS=OFF -DCMAKE_CXX_FLAGS_RELEASE=-O3 }
steps: [ cmake_test, cmake_assert_test ]
assert-clang10:
description: Build just the library, install it and do a basic test
executor: clang10
environment: { CMAKE_FLAGS: -DSIMDJSON_GOOGLE_BENCHMARKS=OFF -DCMAKE_CXX_FLAGS_RELEASE=-O3 }
steps: [ cmake_test, cmake_assert_test ]
gcc10-perftest: gcc10-perftest:
description: Build and run performance tests on GCC 10 and AVX 2 with a cmake static build, this test performance regression description: Build and run performance tests on GCC 10 and AVX 2 with a cmake static build, this test performance regression
executor: gcc10 executor: gcc10
@ -174,22 +191,22 @@ jobs:
sanitize-gcc10: sanitize-gcc10:
description: Build and run tests on GCC 10 and AVX 2 with a cmake sanitize build description: Build and run tests on GCC 10 and AVX 2 with a cmake sanitize build
executor: gcc10 executor: gcc10
environment: { CMAKE_FLAGS: -DSIMDJSON_BUILD_STATIC=OFF -DSIMDJSON_SANITIZE=ON, BUILD_FLAGS: "", CTEST_FLAGS: --output-on-failure -E checkperf } environment: { CMAKE_FLAGS: -DSIMDJSON_BUILD_STATIC=OFF -DSIMDJSON_SANITIZE=ON, BUILD_FLAGS: "", CTEST_FLAGS: --output-on-failure -LE explicitonly }
steps: [ cmake_test ] steps: [ cmake_test ]
sanitize-clang10: sanitize-clang10:
description: Build and run tests on clang 10 and AVX 2 with a cmake sanitize build description: Build and run tests on clang 10 and AVX 2 with a cmake sanitize build
executor: clang10 executor: clang10
environment: { CMAKE_FLAGS: -DSIMDJSON_BUILD_STATIC=OFF -DSIMDJSON_SANITIZE=ON, CTEST_FLAGS: --output-on-failure -E checkperf } environment: { CMAKE_FLAGS: -DSIMDJSON_BUILD_STATIC=OFF -DSIMDJSON_SANITIZE=ON, CTEST_FLAGS: --output-on-failure -LE explicitonly }
steps: [ cmake_test ] steps: [ cmake_test ]
threadsanitize-gcc10: threadsanitize-gcc10:
description: Build and run tests on GCC 10 and AVX 2 with a cmake sanitize build description: Build and run tests on GCC 10 and AVX 2 with a cmake sanitize build
executor: gcc10 executor: gcc10
environment: { CMAKE_FLAGS: -DSIMDJSON_BUILD_STATIC=OFF -DSIMDJSON_SANITIZE_THREADS=ON, BUILD_FLAGS: "", CTEST_FLAGS: --output-on-failure -E checkperf } environment: { CMAKE_FLAGS: -DSIMDJSON_BUILD_STATIC=OFF -DSIMDJSON_SANITIZE_THREADS=ON, BUILD_FLAGS: "", CTEST_FLAGS: --output-on-failure -LE explicitonly }
steps: [ cmake_test ] steps: [ cmake_test ]
threadsanitize-clang10: threadsanitize-clang10:
description: Build and run tests on clang 10 and AVX 2 with a cmake sanitize build description: Build and run tests on clang 10 and AVX 2 with a cmake sanitize build
executor: clang10 executor: clang10
environment: { CMAKE_FLAGS: -DSIMDJSON_BUILD_STATIC=OFF -DSIMDJSON_SANITIZE_THREADS=ON, CTEST_FLAGS: --output-on-failure -E checkperf } environment: { CMAKE_FLAGS: -DSIMDJSON_BUILD_STATIC=OFF -DSIMDJSON_SANITIZE_THREADS=ON, CTEST_FLAGS: --output-on-failure -LE explicitonly }
steps: [ cmake_test ] steps: [ cmake_test ]
# dynamic # dynamic
dynamic-gcc10: dynamic-gcc10:
@ -245,12 +262,12 @@ jobs:
sanitize-haswell-gcc10: sanitize-haswell-gcc10:
description: Build and run tests on GCC 10 and AVX 2 with a cmake sanitize build description: Build and run tests on GCC 10 and AVX 2 with a cmake sanitize build
executor: gcc10 executor: gcc10
environment: { CXXFLAGS: -march=haswell, CMAKE_FLAGS: -DSIMDJSON_BUILD_STATIC=OFF -DSIMDJSON_SANITIZE=ON, BUILD_FLAGS: "", CTEST_FLAGS: --output-on-failure -E checkperf } environment: { CXXFLAGS: -march=haswell, CMAKE_FLAGS: -DSIMDJSON_BUILD_STATIC=OFF -DSIMDJSON_SANITIZE=ON, BUILD_FLAGS: "", CTEST_FLAGS: --output-on-failure -LE explicitonly }
steps: [ cmake_test ] steps: [ cmake_test ]
sanitize-haswell-clang10: sanitize-haswell-clang10:
description: Build and run tests on clang 10 and AVX 2 with a cmake sanitize build description: Build and run tests on clang 10 and AVX 2 with a cmake sanitize build
executor: clang10 executor: clang10
environment: { CXXFLAGS: -march=haswell, CMAKE_FLAGS: -DSIMDJSON_BUILD_STATIC=OFF -DSIMDJSON_SANITIZE=ON, CTEST_FLAGS: --output-on-failure -E checkperf } environment: { CXXFLAGS: -march=haswell, CMAKE_FLAGS: -DSIMDJSON_BUILD_STATIC=OFF -DSIMDJSON_SANITIZE=ON, CTEST_FLAGS: --output-on-failure -LE explicitonly }
steps: [ cmake_test ] steps: [ cmake_test ]
workflows: workflows:
@ -292,4 +309,8 @@ workflows:
# testing "just the library" # testing "just the library"
- justlib-gcc10 - justlib-gcc10
# testing asserts
- assert-gcc10
- assert-clang10
# TODO add windows: https://circleci.com/docs/2.0/configuration-reference/#windows # TODO add windows: https://circleci.com/docs/2.0/configuration-reference/#windows

View File

@ -23,4 +23,4 @@ task:
- make - make
test_script: test_script:
- cd build - cd build
- ctest --output-on-failure -E checkperf - ctest --output-on-failure -LE explicitonly

View File

@ -9,7 +9,7 @@ steps:
CXX: g++ CXX: g++
BUILD_FLAGS: -- -j BUILD_FLAGS: -- -j
CMAKE_FLAGS: -DSIMDJSON_BUILD_STATIC=ON CMAKE_FLAGS: -DSIMDJSON_BUILD_STATIC=ON
CTEST_FLAGS: -j4 --output-on-failure -E checkperf CTEST_FLAGS: -j4 --output-on-failure -LE explicitonly
commands: commands:
- scripts/addcmakeppa.sh "$(env -i sh -c '. /etc/os-release; echo $VERSION_CODENAME')" - scripts/addcmakeppa.sh "$(env -i sh -c '. /etc/os-release; echo $VERSION_CODENAME')"
- apt-get install -y g++ cmake gcc git - apt-get install -y g++ cmake gcc git
@ -30,7 +30,7 @@ steps:
CXX: clang++-6.0 CXX: clang++-6.0
BUILD_FLAGS: -- -j BUILD_FLAGS: -- -j
CMAKE_FLAGS: -DSIMDJSON_BUILD_STATIC=ON CMAKE_FLAGS: -DSIMDJSON_BUILD_STATIC=ON
CTEST_FLAGS: -j4 --output-on-failure -E checkperf CTEST_FLAGS: -j4 --output-on-failure -LE explicitonly
commands: commands:
- scripts/addcmakeppa.sh "$(env -i sh -c '. /etc/os-release; echo $VERSION_CODENAME')" - scripts/addcmakeppa.sh "$(env -i sh -c '. /etc/os-release; echo $VERSION_CODENAME')"
- apt-get install -y clang++-6.0 cmake git - apt-get install -y clang++-6.0 cmake git
@ -51,7 +51,7 @@ steps:
CXX: g++ CXX: g++
BUILD_FLAGS: -- -j BUILD_FLAGS: -- -j
CMAKE_FLAGS: -DSIMDJSON_BUILD_STATIC=ON -DSIMDJSON_IMPLEMENTATION=haswell;westmere;fallback CMAKE_FLAGS: -DSIMDJSON_BUILD_STATIC=ON -DSIMDJSON_IMPLEMENTATION=haswell;westmere;fallback
CTEST_FLAGS: -j4 --output-on-failure -E checkperf CTEST_FLAGS: -j4 --output-on-failure -LE explicitonly
commands: commands:
- echo "deb http://deb.debian.org/debian buster-backports main" >> /etc/apt/sources.list - echo "deb http://deb.debian.org/debian buster-backports main" >> /etc/apt/sources.list
- apt-get update -qq - apt-get update -qq
@ -78,7 +78,7 @@ steps:
CXX: clang++-6.0 CXX: clang++-6.0
BUILD_FLAGS: -- -j BUILD_FLAGS: -- -j
CMAKE_FLAGS: -DSIMDJSON_BUILD_STATIC=ON -DSIMDJSON_IMPLEMENTATION=haswell;westmere;fallback CMAKE_FLAGS: -DSIMDJSON_BUILD_STATIC=ON -DSIMDJSON_IMPLEMENTATION=haswell;westmere;fallback
CTEST_FLAGS: -j4 --output-on-failure -E checkperf CTEST_FLAGS: -j4 --output-on-failure -LE explicitonly
commands: commands:
- mkdir build - mkdir build
- cd build - cd build
@ -101,7 +101,7 @@ steps:
CXX: g++ CXX: g++
BUILD_FLAGS: -- -j BUILD_FLAGS: -- -j
CMAKE_FLAGS: -DSIMDJSON_BUILD_STATIC=OFF CMAKE_FLAGS: -DSIMDJSON_BUILD_STATIC=OFF
CTEST_FLAGS: -j4 --output-on-failure -E checkperf CTEST_FLAGS: -j4 --output-on-failure -LE explicitonly
commands: commands:
- echo "deb http://deb.debian.org/debian buster-backports main" >> /etc/apt/sources.list - echo "deb http://deb.debian.org/debian buster-backports main" >> /etc/apt/sources.list
- apt-get update -qq - apt-get update -qq
@ -124,7 +124,7 @@ steps:
CXX: clang++-9 CXX: clang++-9
CMAKE_FLAGS: -DSIMDJSON_BUILD_STATIC=OFF CMAKE_FLAGS: -DSIMDJSON_BUILD_STATIC=OFF
BUILD_FLAGS: -- -j BUILD_FLAGS: -- -j
CTEST_FLAGS: -j4 --output-on-failure -E checkperf CTEST_FLAGS: -j4 --output-on-failure -LE explicitonly
commands: commands:
- mkdir build - mkdir build
- cd build - cd build
@ -143,7 +143,7 @@ steps:
CXX: g++ CXX: g++
BUILD_FLAGS: -- -j BUILD_FLAGS: -- -j
CMAKE_FLAGS: -DSIMDJSON_BUILD_STATIC=ON -DSIMDJSON_IMPLEMENTATION=haswell;westmere;fallback CMAKE_FLAGS: -DSIMDJSON_BUILD_STATIC=ON -DSIMDJSON_IMPLEMENTATION=haswell;westmere;fallback
CTEST_FLAGS: -j4 --output-on-failure -E checkperf CTEST_FLAGS: -j4 --output-on-failure -LE explicitonly
commands: commands:
- echo "deb http://deb.debian.org/debian buster-backports main" >> /etc/apt/sources.list - echo "deb http://deb.debian.org/debian buster-backports main" >> /etc/apt/sources.list
- apt-get update -qq - apt-get update -qq
@ -170,7 +170,7 @@ steps:
CXX: clang++-9 CXX: clang++-9
CMAKE_FLAGS: -DSIMDJSON_SANITIZE=ON -DSIMDJSON_IMPLEMENTATION=haswell;westmere;fallback CMAKE_FLAGS: -DSIMDJSON_SANITIZE=ON -DSIMDJSON_IMPLEMENTATION=haswell;westmere;fallback
BUILD_FLAGS: -- -j BUILD_FLAGS: -- -j
CTEST_FLAGS: -j4 --output-on-failure -E checkperf CTEST_FLAGS: -j4 --output-on-failure -LE explicitonly
commands: commands:
- mkdir build - mkdir build
- cd build - cd build
@ -194,7 +194,7 @@ steps:
CXX: clang++-11 CXX: clang++-11
CMAKE_FLAGS: -GNinja CMAKE_FLAGS: -GNinja
BUILD_FLAGS: BUILD_FLAGS:
CTEST_FLAGS: -j4 --output-on-failure -E checkperf CTEST_FLAGS: -j4 --output-on-failure -LE explicitonly
CXXFLAGS: -std=c++20 -stdlib=libc++ CXXFLAGS: -std=c++20 -stdlib=libc++
commands: commands:
- mkdir build - mkdir build
@ -214,7 +214,7 @@ steps:
CXX: g++ CXX: g++
BUILD_FLAGS: -- -j BUILD_FLAGS: -- -j
CMAKE_FLAGS: -DSIMDJSON_BUILD_STATIC=ON -DSIMDJSON_IMPLEMENTATION=arm64;fallback CMAKE_FLAGS: -DSIMDJSON_BUILD_STATIC=ON -DSIMDJSON_IMPLEMENTATION=arm64;fallback
CTEST_FLAGS: -j4 --output-on-failure -E checkperf CTEST_FLAGS: -j4 --output-on-failure -LE explicitonly
commands: commands:
- echo "deb http://deb.debian.org/debian buster-backports main" >> /etc/apt/sources.list - echo "deb http://deb.debian.org/debian buster-backports main" >> /etc/apt/sources.list
- apt-get update -qq - apt-get update -qq
@ -239,7 +239,7 @@ steps:
CXX: clang++-6.0 CXX: clang++-6.0
CMAKE_FLAGS: -DSIMDJSON_BUILD_STATIC=OFF CMAKE_FLAGS: -DSIMDJSON_BUILD_STATIC=OFF
BUILD_FLAGS: -- -j BUILD_FLAGS: -- -j
CTEST_FLAGS: -j4 --output-on-failure -E checkperf CTEST_FLAGS: -j4 --output-on-failure -LE explicitonly
commands: commands:
- apt-get -qq update - apt-get -qq update
- apt-get -t buster-backports install -y cmake - apt-get -t buster-backports install -y cmake
@ -261,7 +261,7 @@ steps:
CXX: g++ CXX: g++
BUILD_FLAGS: -- -j BUILD_FLAGS: -- -j
CMAKE_FLAGS: -DSIMDJSON_BUILD_STATIC=OFF CMAKE_FLAGS: -DSIMDJSON_BUILD_STATIC=OFF
CTEST_FLAGS: -j4 --output-on-failure -E checkperf CTEST_FLAGS: -j4 --output-on-failure -LE explicitonly
commands: commands:
- echo "deb http://deb.debian.org/debian buster-backports main" >> /etc/apt/sources.list - echo "deb http://deb.debian.org/debian buster-backports main" >> /etc/apt/sources.list
- apt-get update -qq - apt-get update -qq
@ -283,7 +283,7 @@ steps:
CXX: clang++-6.0 CXX: clang++-6.0
CMAKE_FLAGS: -DSIMDJSON_BUILD_STATIC=OFF CMAKE_FLAGS: -DSIMDJSON_BUILD_STATIC=OFF
BUILD_FLAGS: -- -j BUILD_FLAGS: -- -j
CTEST_FLAGS: -j4 --output-on-failure -E checkperf CTEST_FLAGS: -j4 --output-on-failure -LE explicitonly
commands: commands:
- apt-get -qq update - apt-get -qq update
- apt-get -t buster-backports install -y cmake - apt-get -t buster-backports install -y cmake
@ -303,7 +303,7 @@ steps:
environment: environment:
BUILD_FLAGS: -- -j BUILD_FLAGS: -- -j
CMAKE_FLAGS: -DSIMDJSON_BUILD_STATIC=ON -DSIMDJSON_IMPLEMENTATION=arm64;fallback CMAKE_FLAGS: -DSIMDJSON_BUILD_STATIC=ON -DSIMDJSON_IMPLEMENTATION=arm64;fallback
CTEST_FLAGS: -j4 --output-on-failure -E checkperf CTEST_FLAGS: -j4 --output-on-failure -LE explicitonly
CC: gcc CC: gcc
CXX: g++ CXX: g++
commands: commands:
@ -331,7 +331,7 @@ steps:
CXX: clang++-6.0 CXX: clang++-6.0
CMAKE_FLAGS: -DSIMDJSON_SANITIZE=ON -DSIMDJSON_IMPLEMENTATION=arm64;fallback CMAKE_FLAGS: -DSIMDJSON_SANITIZE=ON -DSIMDJSON_IMPLEMENTATION=arm64;fallback
BUILD_FLAGS: -- -j BUILD_FLAGS: -- -j
CTEST_FLAGS: -j4 --output-on-failure -E checkperf CTEST_FLAGS: -j4 --output-on-failure -LE explicitonly
commands: commands:
- apt-get -qq update - apt-get -qq update
- apt-get -t buster-backports install -y cmake - apt-get -t buster-backports install -y cmake
@ -357,7 +357,7 @@ steps:
CXX: clang++-9 CXX: clang++-9
BUILD_FLAGS: -- -j 4 BUILD_FLAGS: -- -j 4
CMAKE_FLAGS: -GNinja -DSIMDJSON_BUILD_STATIC=ON CMAKE_FLAGS: -GNinja -DSIMDJSON_BUILD_STATIC=ON
CTEST_FLAGS: -j4 --output-on-failure -E checkperf CTEST_FLAGS: -j4 --output-on-failure -LE explicitonly
CXXFLAGS: -stdlib=libc++ CXXFLAGS: -stdlib=libc++
commands: commands:
- mkdir build - mkdir build
@ -378,7 +378,7 @@ steps:
CXX: clang++-9 CXX: clang++-9
BUILD_FLAGS: -- -j BUILD_FLAGS: -- -j
CMAKE_FLAGS: -DSIMDJSON_BUILD_STATIC=ON CMAKE_FLAGS: -DSIMDJSON_BUILD_STATIC=ON
CTEST_FLAGS: -j4 --output-on-failure -E checkperf CTEST_FLAGS: -j4 --output-on-failure -LE explicitonly
CXXFLAGS: -stdlib=libc++ CXXFLAGS: -stdlib=libc++
commands: commands:
- mkdir build - mkdir build
@ -399,7 +399,7 @@ steps:
CXX: clang++-7 CXX: clang++-7
BUILD_FLAGS: -- -j BUILD_FLAGS: -- -j
CMAKE_FLAGS: -DSIMDJSON_BUILD_STATIC=ON CMAKE_FLAGS: -DSIMDJSON_BUILD_STATIC=ON
CTEST_FLAGS: -j4 --output-on-failure -E checkperf CTEST_FLAGS: -j4 --output-on-failure -LE explicitonly
CXXFLAGS: -stdlib=libc++ CXXFLAGS: -stdlib=libc++
commands: commands:
- mkdir build - mkdir build
@ -419,7 +419,7 @@ steps:
CXX: g++ CXX: g++
BUILD_FLAGS: -- -j BUILD_FLAGS: -- -j
CMAKE_FLAGS: -DSIMDJSON_EXCEPTIONS=OFF CMAKE_FLAGS: -DSIMDJSON_EXCEPTIONS=OFF
CTEST_FLAGS: -j4 --output-on-failure -E checkperf CTEST_FLAGS: -j4 --output-on-failure -LE explicitonly
commands: commands:
- echo "deb http://deb.debian.org/debian buster-backports main" >> /etc/apt/sources.list - echo "deb http://deb.debian.org/debian buster-backports main" >> /etc/apt/sources.list
- apt-get update -qq - apt-get update -qq

View File

@ -34,4 +34,4 @@ jobs:
./alpine.sh cmake --build build_for_alpine ./alpine.sh cmake --build build_for_alpine
- name: test - name: test
run: | run: |
./alpine.sh bash -c "cd build_for_alpine && ctest -E checkperf" ./alpine.sh bash -c "cd build_for_alpine && ctest -LE explicitonly"

View File

@ -51,4 +51,4 @@ jobs:
cd build cd build
cmake -DCMAKE_BUILD_TYPE=${{ matrix.type }} -DSIMDJSON_BUILD_STATIC=ON -DSIMDJSON_DO_NOT_USE_THREADS_NO_MATTER_WHAT=ON .. cmake -DCMAKE_BUILD_TYPE=${{ matrix.type }} -DSIMDJSON_BUILD_STATIC=ON -DSIMDJSON_DO_NOT_USE_THREADS_NO_MATTER_WHAT=ON ..
cmake --build . --verbose cmake --build . --verbose
ctest -j4 --output-on-failure -E checkperf ctest -j4 --output-on-failure -LE explicitonly

View File

@ -23,6 +23,6 @@ jobs:
cd build && cd build &&
cmake -DSIMDJSON_GOOGLE_BENCHMARKS=ON -DSIMDJSON_BUILD_STATIC=ON -DCMAKE_INSTALL_PREFIX:PATH=destination .. && cmake -DSIMDJSON_GOOGLE_BENCHMARKS=ON -DSIMDJSON_BUILD_STATIC=ON -DCMAKE_INSTALL_PREFIX:PATH=destination .. &&
cmake --build . && cmake --build . &&
ctest -j --output-on-failure -E checkperf && ctest -j --output-on-failure -LE explicitonly &&
make install && make 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 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

View File

@ -23,6 +23,6 @@ jobs:
cd build && cd build &&
cmake -DSIMDJSON_GOOGLE_BENCHMARKS=ON -DSIMDJSON_BUILD_STATIC=ON -DCMAKE_INSTALL_PREFIX:PATH=destination .. && cmake -DSIMDJSON_GOOGLE_BENCHMARKS=ON -DSIMDJSON_BUILD_STATIC=ON -DCMAKE_INSTALL_PREFIX:PATH=destination .. &&
cmake --build . && cmake --build . &&
ctest -j --output-on-failure -E checkperf && ctest -j --output-on-failure -LE explicitonly &&
make install && make 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 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

View File

@ -31,6 +31,6 @@ jobs:
buildWithCMakeArgs: --config Release buildWithCMakeArgs: --config Release
- name: 'Run CTest' - name: 'Run CTest'
run: ctest -C Release -E checkperf --output-on-failure run: ctest -C Release -LE explicitonly --output-on-failure
working-directory: "${{ github.workspace }}/../../_temp/windows" working-directory: "${{ github.workspace }}/../../_temp/windows"

View File

@ -31,5 +31,5 @@ jobs:
buildWithCMakeArgs: --config Release buildWithCMakeArgs: --config Release
- name: 'Run CTest' - name: 'Run CTest'
run: ctest -C Release -E checkperf --output-on-failure run: ctest -C Release -LE explicitonly --output-on-failure
working-directory: "${{ github.workspace }}/../../_temp/windows" working-directory: "${{ github.workspace }}/../../_temp/windows"

View File

@ -31,6 +31,6 @@ jobs:
buildWithCMakeArgs: --config Release buildWithCMakeArgs: --config Release
- name: 'Run CTest' - name: 'Run CTest'
run: ctest -C Release -E checkperf --output-on-failure run: ctest -C Release -LE explicitonly --output-on-failure
working-directory: "${{ github.workspace }}/../../_temp/windows" working-directory: "${{ github.workspace }}/../../_temp/windows"

View File

@ -176,7 +176,7 @@ install:
- if [[ "${STATIC}" == "on" ]]; then - if [[ "${STATIC}" == "on" ]]; then
export CMAKE_FLAGS="${CMAKE_FLAGS} -DSIMDJSON_BUILD_STATIC=ON"; export CMAKE_FLAGS="${CMAKE_FLAGS} -DSIMDJSON_BUILD_STATIC=ON";
fi fi
- export CTEST_FLAGS="-j4 --output-on-failure -E checkperf" - export CTEST_FLAGS="-j4 --output-on-failure -LE explicitonly"
script: script:
- mkdir build - mkdir build

View File

@ -41,7 +41,7 @@
# #
# Next you can test it as follows: # Next you can test it as follows:
# #
# docker run -it -v $(pwd):/project:Z simdjson sh -c "cd dockerbuild && ctest . --output-on-failure -E checkperf" # docker run -it -v $(pwd):/project:Z simdjson sh -c "cd dockerbuild && ctest . --output-on-failure -LE explicitonly"
# #
# The run the complete tests requires you to have built all of simdjson. # The run the complete tests requires you to have built all of simdjson.
# #

View File

@ -89,7 +89,7 @@ if (Git_FOUND AND (GIT_VERSION_STRING VERSION_GREATER "2.1.4") AND (NOT CMAKE_G
# COMMAND ECHO $<TARGET_FILE:perfdiff> \"$<TARGET_FILE:parse> -t ${SIMDJSON_CHECKPERF_ARGS}\" \"${CHECKPERF_PARSE} -t ${SIMDJSON_CHECKPERF_ARGS}\" } # COMMAND ECHO $<TARGET_FILE:perfdiff> \"$<TARGET_FILE:parse> -t ${SIMDJSON_CHECKPERF_ARGS}\" \"${CHECKPERF_PARSE} -t ${SIMDJSON_CHECKPERF_ARGS}\" }
COMMAND $<TARGET_FILE:perfdiff> $<TARGET_FILE:parse> ${CHECKPERF_PARSE} -H -t ${SIMDJSON_CHECKPERF_ARGS} COMMAND $<TARGET_FILE:perfdiff> $<TARGET_FILE:parse> ${CHECKPERF_PARSE} -H -t ${SIMDJSON_CHECKPERF_ARGS}
) )
set_property(TEST checkperf APPEND PROPERTY LABELS per_implementation) set_property(TEST checkperf APPEND PROPERTY LABELS per_implementation explicitonly)
set_property(TEST checkperf APPEND PROPERTY DEPENDS parse perfdiff ${SIMDJSON_USER_CMAKECACHE}) set_property(TEST checkperf APPEND PROPERTY DEPENDS parse perfdiff ${SIMDJSON_USER_CMAKECACHE})
set_property(TEST checkperf PROPERTY RUN_SERIAL TRUE) set_property(TEST checkperf PROPERTY RUN_SERIAL TRUE)
else() else()

View File

@ -82,14 +82,14 @@ endif()
if(SIMDJSON_VISUAL_STUDIO_BUILD_WITH_DEBUG_INFO_FOR_PROFILING) if(SIMDJSON_VISUAL_STUDIO_BUILD_WITH_DEBUG_INFO_FOR_PROFILING)
target_link_options(simdjson-flags INTERFACE /DEBUG ) target_link_options(simdjson-flags INTERFACE /DEBUG )
target_compile_options(simdjson-flags INTERFACE /Zi) target_compile_options(simdjson-flags INTERFACE /Zi)
endif() endif(SIMDJSON_VISUAL_STUDIO_BUILD_WITH_DEBUG_INFO_FOR_PROFILING)
else() else(MSVC)
if(NOT WIN32) if(NOT WIN32)
target_compile_options(simdjson-internal-flags INTERFACE -fPIC) target_compile_options(simdjson-internal-flags INTERFACE -fPIC)
endif() endif()
target_compile_options(simdjson-internal-flags INTERFACE -Werror -Wall -Wextra -Weffc++) target_compile_options(simdjson-internal-flags INTERFACE -Werror -Wall -Wextra -Weffc++)
target_compile_options(simdjson-internal-flags INTERFACE -Wsign-compare -Wshadow -Wwrite-strings -Wpointer-arith -Winit-self -Wconversion -Wno-sign-conversion) target_compile_options(simdjson-internal-flags INTERFACE -Wsign-compare -Wshadow -Wwrite-strings -Wpointer-arith -Winit-self -Wconversion -Wno-sign-conversion)
endif() endif(MSVC)
# #
# Optional flags # Optional flags
@ -232,5 +232,9 @@ if(${CMAKE_C_COMPILER_ID} MATCHES "Intel") # icc / icpc
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -static-intel") set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -static-intel")
endif() endif()
include (CheckSymbolExists)
CHECK_SYMBOL_EXISTS(fork unistd.h HAVE_POSIX_FORK)
CHECK_SYMBOL_EXISTS(wait sys/wait.h HAVE_POSIX_WAIT)
install(TARGETS simdjson-flags EXPORT simdjson-config) install(TARGETS simdjson-flags EXPORT simdjson-config)
install(TARGETS simdjson-internal-flags EXPORT simdjson-config) install(TARGETS simdjson-internal-flags EXPORT simdjson-config)

View File

@ -5,13 +5,6 @@ namespace SIMDJSON_IMPLEMENTATION {
// internal::implementation_simdjson_result_base<T> inline implementation // internal::implementation_simdjson_result_base<T> inline implementation
// //
/**
* Create a new empty result with error = UNINITIALIZED.
*/
template<typename T>
simdjson_really_inline implementation_simdjson_result_base<T>::~implementation_simdjson_result_base() noexcept {
}
template<typename T> template<typename T>
simdjson_really_inline void implementation_simdjson_result_base<T>::tie(T &value, error_code &error) && noexcept { simdjson_really_inline void implementation_simdjson_result_base<T>::tie(T &value, error_code &error) && noexcept {
// on the clang compiler that comes with current macOS (Apple clang version 11.0.0), // on the clang compiler that comes with current macOS (Apple clang version 11.0.0),
@ -70,9 +63,6 @@ simdjson_really_inline implementation_simdjson_result_base<T>::implementation_si
template<typename T> template<typename T>
simdjson_really_inline implementation_simdjson_result_base<T>::implementation_simdjson_result_base(T &&value) noexcept simdjson_really_inline implementation_simdjson_result_base<T>::implementation_simdjson_result_base(T &&value) noexcept
: implementation_simdjson_result_base(std::forward<T>(value), SUCCESS) {} : implementation_simdjson_result_base(std::forward<T>(value), SUCCESS) {}
template<typename T>
simdjson_really_inline implementation_simdjson_result_base<T>::implementation_simdjson_result_base() noexcept
: implementation_simdjson_result_base(T{}, UNINITIALIZED) {}
} // namespace SIMDJSON_IMPLEMENTATION } // namespace SIMDJSON_IMPLEMENTATION
} // namespace simdjson } // namespace simdjson

View File

@ -30,7 +30,7 @@ struct implementation_simdjson_result_base {
/** /**
* Create a new empty result with error = UNINITIALIZED. * Create a new empty result with error = UNINITIALIZED.
*/ */
simdjson_really_inline implementation_simdjson_result_base() noexcept; simdjson_really_inline implementation_simdjson_result_base() noexcept = default;
/** /**
* Create a new error result. * Create a new error result.
@ -47,21 +47,6 @@ struct implementation_simdjson_result_base {
*/ */
simdjson_really_inline implementation_simdjson_result_base(T &&value, error_code error) noexcept; simdjson_really_inline implementation_simdjson_result_base(T &&value, error_code error) noexcept;
/**
* Move a result.
*/
simdjson_really_inline implementation_simdjson_result_base(implementation_simdjson_result_base<T> &&value) noexcept = default;
/**
* Copy a result.
*/
simdjson_really_inline implementation_simdjson_result_base(const implementation_simdjson_result_base<T> &value) = default;
/**
* Create a new empty result with error = UNINITIALIZED.
*/
simdjson_really_inline ~implementation_simdjson_result_base() noexcept;
/** /**
* Move the value and the error to the provided variables. * Move the value and the error to the provided variables.
* *
@ -114,8 +99,8 @@ struct implementation_simdjson_result_base {
#endif // SIMDJSON_EXCEPTIONS #endif // SIMDJSON_EXCEPTIONS
T first; T first{};
error_code second; error_code second{UNINITIALIZED};
}; // struct implementation_simdjson_result_base }; // struct implementation_simdjson_result_base
} // namespace SIMDJSON_IMPLEMENTATION } // namespace SIMDJSON_IMPLEMENTATION

View File

@ -8,9 +8,6 @@ simdjson_really_inline document::document(ondemand::json_iterator &&_iter) noexc
logger::log_start_value(iter, "document"); logger::log_start_value(iter, "document");
} }
simdjson_really_inline void document::assert_at_start() const noexcept {
iter.assert_at_start();
}
simdjson_really_inline document document::start(json_iterator &&iter) noexcept { simdjson_really_inline document document::start(json_iterator &&iter) noexcept {
return document(std::forward<json_iterator>(iter)); return document(std::forward<json_iterator>(iter));
} }
@ -19,8 +16,11 @@ simdjson_really_inline value document::as_value() noexcept {
return as_value_iterator(); return as_value_iterator();
} }
simdjson_really_inline value_iterator document::as_value_iterator() noexcept { simdjson_really_inline value_iterator document::as_value_iterator() noexcept {
assert_at_start(); iter.assert_at_root();
return value_iterator(&iter, 1); return value_iterator(&iter, 1, iter.root_checkpoint());
}
simdjson_really_inline value_iterator document::as_non_root_value_iterator() noexcept {
return value_iterator(&iter, 1, iter.root_checkpoint());
} }
simdjson_really_inline simdjson_result<array> document::get_array() & noexcept { simdjson_really_inline simdjson_result<array> document::get_array() & noexcept {
@ -30,15 +30,12 @@ simdjson_really_inline simdjson_result<object> document::get_object() & noexcept
return as_value().get_object(); return as_value().get_object();
} }
simdjson_really_inline simdjson_result<uint64_t> document::get_uint64() noexcept { simdjson_really_inline simdjson_result<uint64_t> document::get_uint64() noexcept {
assert_at_start();
return as_value_iterator().require_root_uint64(); return as_value_iterator().require_root_uint64();
} }
simdjson_really_inline simdjson_result<int64_t> document::get_int64() noexcept { simdjson_really_inline simdjson_result<int64_t> document::get_int64() noexcept {
assert_at_start();
return as_value_iterator().require_root_int64(); return as_value_iterator().require_root_int64();
} }
simdjson_really_inline simdjson_result<double> document::get_double() noexcept { simdjson_really_inline simdjson_result<double> document::get_double() noexcept {
assert_at_start();
return as_value_iterator().require_root_double(); return as_value_iterator().require_root_double();
} }
simdjson_really_inline simdjson_result<std::string_view> document::get_string() & noexcept { simdjson_really_inline simdjson_result<std::string_view> document::get_string() & noexcept {
@ -48,11 +45,9 @@ simdjson_really_inline simdjson_result<raw_json_string> document::get_raw_json_s
return as_value().get_raw_json_string(); return as_value().get_raw_json_string();
} }
simdjson_really_inline simdjson_result<bool> document::get_bool() noexcept { simdjson_really_inline simdjson_result<bool> document::get_bool() noexcept {
assert_at_start();
return as_value_iterator().require_root_bool(); return as_value_iterator().require_root_bool();
} }
simdjson_really_inline bool document::is_null() noexcept { simdjson_really_inline bool document::is_null() noexcept {
assert_at_start();
return as_value_iterator().is_root_null(); return as_value_iterator().is_root_null();
} }
@ -95,10 +90,20 @@ simdjson_really_inline simdjson_result<array_iterator> document::end() & noexcep
return {}; return {};
} }
simdjson_really_inline simdjson_result<value> document::operator[](std::string_view key) & noexcept { simdjson_really_inline simdjson_result<value> document::operator[](std::string_view key) & noexcept {
if (iter.at_root()) {
return get_object()[key]; return get_object()[key];
} else {
// If we're not at the root, this is not the first key we've grabbed
return object::resume(as_non_root_value_iterator())[key];
}
} }
simdjson_really_inline simdjson_result<value> document::operator[](const char *key) & noexcept { simdjson_really_inline simdjson_result<value> document::operator[](const char *key) & noexcept {
if (iter.at_root()) {
return get_object()[key]; return get_object()[key];
} else {
// If we're not at the root, this is not the first key we've grabbed
return object::resume(as_non_root_value_iterator())[key];
}
} }
} // namespace ondemand } // namespace ondemand

View File

@ -20,17 +20,16 @@ class array_iterator;
*/ */
class document { class document {
public: public:
simdjson_really_inline document(document &&other) noexcept = default;
simdjson_really_inline document &operator=(document &&other) noexcept = default;
/** /**
* Create a new invalid document. * Create a new invalid document.
* *
* Exists so you can declare a variable and later assign to it before use. * Exists so you can declare a variable and later assign to it before use.
*/ */
simdjson_really_inline document() noexcept = default; simdjson_really_inline document() noexcept = default;
simdjson_really_inline document(const document &other) = delete; simdjson_really_inline document(const document &other) noexcept = delete;
simdjson_really_inline document &operator=(const document &other) = delete; 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;
/** /**
* Cast this JSON value to an array. * Cast this JSON value to an array.
@ -230,10 +229,9 @@ protected:
simdjson_really_inline value as_value() noexcept; simdjson_really_inline value as_value() noexcept;
simdjson_really_inline value_iterator as_value_iterator() noexcept; simdjson_really_inline value_iterator as_value_iterator() noexcept;
simdjson_really_inline value_iterator as_non_root_value_iterator() noexcept;
static simdjson_really_inline document start(ondemand::json_iterator &&iter) noexcept; static simdjson_really_inline document start(ondemand::json_iterator &&iter) noexcept;
simdjson_really_inline void assert_at_start() const noexcept;
// //
// Fields // Fields
// //
@ -261,10 +259,7 @@ struct simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document> : public SIM
public: public:
simdjson_really_inline simdjson_result(SIMDJSON_IMPLEMENTATION::ondemand::document &&value) noexcept; ///< @private simdjson_really_inline simdjson_result(SIMDJSON_IMPLEMENTATION::ondemand::document &&value) noexcept; ///< @private
simdjson_really_inline simdjson_result(error_code error) noexcept; ///< @private simdjson_really_inline simdjson_result(error_code error) noexcept; ///< @private
simdjson_really_inline simdjson_result() noexcept = default; simdjson_really_inline simdjson_result() noexcept = default;
simdjson_really_inline simdjson_result(simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document> &&a) noexcept = default;
simdjson_really_inline ~simdjson_result() noexcept = default; ///< @private
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array> get_array() & 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<SIMDJSON_IMPLEMENTATION::ondemand::object> get_object() & noexcept;

View File

@ -90,11 +90,15 @@ simdjson_warn_unused simdjson_really_inline error_code json_iterator::skip_child
return report_error(TAPE_ERROR, "not enough close braces"); return report_error(TAPE_ERROR, "not enough close braces");
} }
simdjson_really_inline bool json_iterator::at_start() const noexcept { simdjson_really_inline bool json_iterator::at_root() const noexcept {
return token.index == &parser->dom_parser.structural_indexes[0]; return token.checkpoint() == root_checkpoint();
} }
simdjson_really_inline void json_iterator::assert_at_start() const noexcept { simdjson_really_inline const uint32_t *json_iterator::root_checkpoint() const noexcept {
return parser->dom_parser.structural_indexes.get();
}
simdjson_really_inline void json_iterator::assert_at_root() const noexcept {
SIMDJSON_ASSUME( _depth == 1 ); SIMDJSON_ASSUME( _depth == 1 );
// Visual Studio Clang treats unique_ptr.get() as "side effecting." // Visual Studio Clang treats unique_ptr.get() as "side effecting."
#ifndef SIMDJSON_CLANG_VISUAL_STUDIO #ifndef SIMDJSON_CLANG_VISUAL_STUDIO

View File

@ -60,12 +60,17 @@ public:
/** /**
* Tell whether the iterator is still at the start * Tell whether the iterator is still at the start
*/ */
simdjson_really_inline bool at_start() const noexcept; simdjson_really_inline bool at_root() const noexcept;
/**
* Get the root value iterator
*/
simdjson_really_inline const uint32_t *root_checkpoint() const noexcept;
/** /**
* Assert if the iterator is not at the start * Assert if the iterator is not at the start
*/ */
simdjson_really_inline void assert_at_start() const noexcept; simdjson_really_inline void assert_at_root() const noexcept;
/** /**
* Tell whether the iterator is at the EOF mark * Tell whether the iterator is at the EOF mark
@ -184,8 +189,6 @@ public:
simdjson_really_inline simdjson_result(error_code error) noexcept; ///< @private simdjson_really_inline simdjson_result(error_code error) noexcept; ///< @private
simdjson_really_inline simdjson_result() noexcept = default; simdjson_really_inline simdjson_result() noexcept = default;
simdjson_really_inline simdjson_result(simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::json_iterator> &&a) noexcept = default;
simdjson_really_inline ~simdjson_result() noexcept = default; ///< @private
}; };
} // namespace simdjson } // namespace simdjson

View File

@ -43,18 +43,18 @@ namespace ondemand {
// In this state, iter.depth < depth, at_start == false, and error == SUCCESS. // In this state, iter.depth < depth, at_start == false, and error == SUCCESS.
// //
simdjson_warn_unused simdjson_really_inline error_code object::find_field_raw(const std::string_view key) noexcept {
return iter.find_field_raw(key);
}
simdjson_really_inline simdjson_result<value> object::operator[](const std::string_view key) & noexcept { simdjson_really_inline simdjson_result<value> object::operator[](const std::string_view key) & noexcept {
SIMDJSON_TRY( find_field_raw(key) ); bool has_value;
return value(iter.iter.child()); SIMDJSON_TRY( iter.find_field_raw(key).get(has_value) );
if (!has_value) { return NO_SUCH_FIELD; }
return value(iter.child());
} }
simdjson_really_inline simdjson_result<value> object::operator[](const std::string_view key) && noexcept { simdjson_really_inline simdjson_result<value> object::operator[](const std::string_view key) && noexcept {
SIMDJSON_TRY( find_field_raw(key) ); bool has_value;
return value(iter.iter.child()); SIMDJSON_TRY( iter.find_field_raw(key).get(has_value) );
if (!has_value) { return NO_SUCH_FIELD; }
return value(iter.child());
} }
simdjson_really_inline simdjson_result<object> object::start(value_iterator &iter) noexcept { simdjson_really_inline simdjson_result<object> object::start(value_iterator &iter) noexcept {
@ -71,6 +71,9 @@ simdjson_really_inline object object::started(value_iterator &iter) noexcept {
simdjson_unused bool has_value = iter.started_object(); simdjson_unused bool has_value = iter.started_object();
return iter; return iter;
} }
simdjson_really_inline object object::resume(const value_iterator &iter) noexcept {
return iter;
}
simdjson_really_inline object::object(const value_iterator &_iter) noexcept simdjson_really_inline object::object(const value_iterator &_iter) noexcept
: iter{_iter} : iter{_iter}
@ -78,7 +81,8 @@ simdjson_really_inline object::object(const value_iterator &_iter) noexcept
} }
simdjson_really_inline object_iterator object::begin() noexcept { simdjson_really_inline object_iterator object::begin() noexcept {
SIMDJSON_ASSUME( iter.at_start || iter.iter._json_iter->_depth < iter.iter._depth ); // Expanded version of SIMDJSON_ASSUME( iter.at_field_start() || !iter.is_open() )
SIMDJSON_ASSUME( (iter._json_iter->token.index == iter._start_index + 1) || (iter._json_iter->_depth < iter._depth) );
return iter; return iter;
} }
simdjson_really_inline object_iterator object::end() noexcept { simdjson_really_inline object_iterator object::end() noexcept {

View File

@ -49,11 +49,12 @@ protected:
static simdjson_really_inline simdjson_result<object> start(value_iterator &iter) noexcept; static simdjson_really_inline simdjson_result<object> start(value_iterator &iter) noexcept;
static simdjson_really_inline simdjson_result<object> try_start(value_iterator &iter) noexcept; static simdjson_really_inline simdjson_result<object> try_start(value_iterator &iter) noexcept;
static simdjson_really_inline object started(value_iterator &iter) noexcept; static simdjson_really_inline object started(value_iterator &iter) noexcept;
simdjson_really_inline object(const value_iterator &_iter) noexcept; static simdjson_really_inline object resume(const value_iterator &iter) noexcept;
simdjson_really_inline object(const value_iterator &iter) noexcept;
simdjson_warn_unused simdjson_really_inline error_code find_field_raw(const std::string_view key) noexcept; simdjson_warn_unused simdjson_really_inline error_code find_field_raw(const std::string_view key) noexcept;
object_iterator iter{}; value_iterator iter{};
friend class value; friend class value;
friend class document; friend class document;

View File

@ -7,8 +7,7 @@ namespace ondemand {
// //
simdjson_really_inline object_iterator::object_iterator(const value_iterator &_iter) noexcept simdjson_really_inline object_iterator::object_iterator(const value_iterator &_iter) noexcept
: iter{_iter}, : iter{_iter}
at_start{true}
{} {}
simdjson_really_inline simdjson_result<field> object_iterator::operator*() noexcept { simdjson_really_inline simdjson_result<field> object_iterator::operator*() noexcept {
@ -80,39 +79,6 @@ simdjson_really_inline object_iterator &object_iterator::operator++() noexcept {
// In this state, iter.depth < depth, at_start == false, and error == SUCCESS. // In this state, iter.depth < depth, at_start == false, and error == SUCCESS.
// //
simdjson_warn_unused simdjson_really_inline error_code object_iterator::find_field_raw(const std::string_view key) noexcept {
if (!iter.is_open()) { return NO_SUCH_FIELD; }
// Unless this is the first field, we need to advance past the , and check for }
error_code error;
bool has_value;
if (at_start) {
at_start = false;
has_value = true;
} else {
if ((error = iter.skip_child() )) { iter.abandon(); return error; }
if ((error = iter.has_next_field().get(has_value) )) { iter.abandon(); return error; }
}
while (has_value) {
// Get the key
raw_json_string actual_key;
if ((error = iter.field_key().get(actual_key) )) { iter.abandon(); return error; };
if ((error = iter.field_value() )) { iter.abandon(); return error; }
// Check if it matches
if (actual_key == key) {
logger::log_event(iter, "match", key, -2);
return SUCCESS;
}
logger::log_event(iter, "no match", key, -2);
SIMDJSON_TRY( iter.skip_child() ); // Skip the value entirely
if ((error = iter.has_next_field().get(has_value) )) { iter.abandon(); return error; }
}
// If the loop ended, we're out of fields to look at.
return NO_SUCH_FIELD;
}
} // namespace ondemand } // namespace ondemand
} // namespace SIMDJSON_IMPLEMENTATION } // namespace SIMDJSON_IMPLEMENTATION
} // namespace simdjson } // namespace simdjson

View File

@ -29,11 +29,6 @@ public:
// Checks for ']' and ',' // Checks for ']' and ','
simdjson_really_inline object_iterator &operator++() noexcept; simdjson_really_inline object_iterator &operator++() noexcept;
/**
* Find the field with the given key. May be used in place of ++.
*/
simdjson_warn_unused simdjson_really_inline error_code find_field_raw(const std::string_view key) noexcept;
private: private:
/** /**
* The underlying JSON iterator. * The underlying JSON iterator.
@ -42,15 +37,6 @@ private:
* is first used, and never changes afterwards. * is first used, and never changes afterwards.
*/ */
value_iterator iter{}; value_iterator iter{};
/**
* Whether we are at the start.
*
* PERF NOTE: this should be elided into inline control flow: it is only used for the first []
* or * call, and SSA optimizers commonly do first-iteration loop optimization.
*
* SAFETY: this is not safe; the object_iterator can be copied freely, so the state CAN be lost.
*/
bool at_start{};
simdjson_really_inline object_iterator(const value_iterator &iter) noexcept; simdjson_really_inline object_iterator(const value_iterator &iter) noexcept;
friend struct simdjson_result<object_iterator>; friend struct simdjson_result<object_iterator>;

View File

@ -130,10 +130,7 @@ struct simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::parser> : public SIMDJ
public: public:
simdjson_really_inline simdjson_result(SIMDJSON_IMPLEMENTATION::ondemand::parser &&value) noexcept; ///< @private simdjson_really_inline simdjson_result(SIMDJSON_IMPLEMENTATION::ondemand::parser &&value) noexcept; ///< @private
simdjson_really_inline simdjson_result(error_code error) noexcept; ///< @private simdjson_really_inline simdjson_result(error_code error) noexcept; ///< @private
simdjson_really_inline simdjson_result() noexcept = default; simdjson_really_inline simdjson_result() noexcept = default;
simdjson_really_inline simdjson_result(simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::parser> &&a) noexcept = default;
simdjson_really_inline ~simdjson_result() noexcept = default; ///< @private
}; };
} // namespace simdjson } // namespace simdjson

View File

@ -109,9 +109,7 @@ struct simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::raw_json_string> : pub
public: public:
simdjson_really_inline simdjson_result(SIMDJSON_IMPLEMENTATION::ondemand::raw_json_string &&value) noexcept; ///< @private simdjson_really_inline simdjson_result(SIMDJSON_IMPLEMENTATION::ondemand::raw_json_string &&value) noexcept; ///< @private
simdjson_really_inline simdjson_result(error_code error) noexcept; ///< @private simdjson_really_inline simdjson_result(error_code error) noexcept; ///< @private
simdjson_really_inline simdjson_result() noexcept = default; simdjson_really_inline simdjson_result() noexcept = default;
simdjson_really_inline simdjson_result(const simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::raw_json_string> &a) noexcept = default;
simdjson_really_inline ~simdjson_result() noexcept = default; ///< @private simdjson_really_inline ~simdjson_result() noexcept = default; ///< @private
simdjson_really_inline simdjson_result<const char *> raw() const noexcept; simdjson_really_inline simdjson_result<const char *> raw() const noexcept;

View File

@ -39,6 +39,10 @@ simdjson_really_inline bool token_iterator::operator<=(const token_iterator &oth
return index <= other.index; return index <= other.index;
} }
simdjson_really_inline const uint32_t *token_iterator::checkpoint() const noexcept {
return index;
}
} // namespace ondemand } // namespace ondemand
} // namespace SIMDJSON_IMPLEMENTATION } // namespace SIMDJSON_IMPLEMENTATION
} // namespace simdjson } // namespace simdjson

View File

@ -49,6 +49,11 @@ public:
*/ */
simdjson_really_inline const uint8_t *advance() noexcept; simdjson_really_inline const uint8_t *advance() noexcept;
/**
* Save the current index to be restored later.
*/
simdjson_really_inline const uint32_t *checkpoint() const noexcept;
// NOTE: we don't support a full C++ iterator interface, because we expect people to make // NOTE: we don't support a full C++ iterator interface, because we expect people to make
// different calls to advance the iterator based on *their own* state. // different calls to advance the iterator based on *their own* state.
@ -77,6 +82,8 @@ protected:
const uint32_t *index{}; const uint32_t *index{};
friend class json_iterator; friend class json_iterator;
friend class value_iterator;
friend class object;
friend simdjson_really_inline void logger::log_line(const json_iterator &iter, const char *title_prefix, const char *title, std::string_view detail, int delta, int depth_delta) noexcept; friend simdjson_really_inline void logger::log_line(const json_iterator &iter, const char *title_prefix, const char *title, std::string_view detail, int delta, int depth_delta) noexcept;
}; };
@ -91,9 +98,7 @@ struct simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::token_iterator> : publ
public: public:
simdjson_really_inline simdjson_result(SIMDJSON_IMPLEMENTATION::ondemand::token_iterator &&value) noexcept; ///< @private simdjson_really_inline simdjson_result(SIMDJSON_IMPLEMENTATION::ondemand::token_iterator &&value) noexcept; ///< @private
simdjson_really_inline simdjson_result(error_code error) noexcept; ///< @private simdjson_really_inline simdjson_result(error_code error) noexcept; ///< @private
simdjson_really_inline simdjson_result() noexcept = default; simdjson_really_inline simdjson_result() noexcept = default;
simdjson_really_inline simdjson_result(simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::token_iterator> &&a) noexcept = default;
simdjson_really_inline ~simdjson_result() noexcept = default; ///< @private simdjson_really_inline ~simdjson_result() noexcept = default; ///< @private
}; };

View File

@ -2,20 +2,21 @@ namespace simdjson {
namespace SIMDJSON_IMPLEMENTATION { namespace SIMDJSON_IMPLEMENTATION {
namespace ondemand { namespace ondemand {
simdjson_really_inline value_iterator::value_iterator(json_iterator *json_iter, depth_t depth) noexcept simdjson_really_inline value_iterator::value_iterator(json_iterator *json_iter, depth_t depth, const uint32_t *start_index) noexcept
: _json_iter{json_iter}, : _json_iter{json_iter},
_depth{depth} _depth{depth},
_start_index{start_index}
{ {
} }
simdjson_warn_unused simdjson_really_inline simdjson_result<bool> value_iterator::start_object() noexcept { simdjson_warn_unused simdjson_really_inline simdjson_result<bool> value_iterator::start_object() noexcept {
SIMDJSON_ASSUME( _json_iter->_depth == _depth && _depth > 0 ); assert_at_start();
if (*_json_iter->advance() != '{') { logger::log_error(*_json_iter, "Not an object"); return INCORRECT_TYPE; } if (*_json_iter->advance() != '{') { logger::log_error(*_json_iter, "Not an object"); return INCORRECT_TYPE; }
return started_object(); return started_object();
} }
simdjson_warn_unused simdjson_really_inline simdjson_result<bool> value_iterator::try_start_object() noexcept { simdjson_warn_unused simdjson_really_inline simdjson_result<bool> value_iterator::try_start_object() noexcept {
SIMDJSON_ASSUME( _json_iter->_depth == _depth && _depth > 0 ); assert_at_start();
if (*_json_iter->peek() != '{') { logger::log_error(*_json_iter, "Not an object"); return INCORRECT_TYPE; } if (*_json_iter->peek() != '{') { logger::log_error(*_json_iter, "Not an object"); return INCORRECT_TYPE; }
_json_iter->advance(); _json_iter->advance();
@ -23,8 +24,6 @@ simdjson_warn_unused simdjson_really_inline simdjson_result<bool> value_iterator
} }
simdjson_warn_unused simdjson_really_inline bool value_iterator::started_object() noexcept { simdjson_warn_unused simdjson_really_inline bool value_iterator::started_object() noexcept {
SIMDJSON_ASSUME( _json_iter->_depth == _depth && _depth > 0 );
if (*_json_iter->peek() == '}') { if (*_json_iter->peek() == '}') {
logger::log_value(*_json_iter, "empty object"); logger::log_value(*_json_iter, "empty object");
_json_iter->advance(); _json_iter->advance();
@ -37,7 +36,7 @@ simdjson_warn_unused simdjson_really_inline bool value_iterator::started_object(
} }
simdjson_warn_unused simdjson_really_inline simdjson_result<bool> value_iterator::has_next_field() noexcept { simdjson_warn_unused simdjson_really_inline simdjson_result<bool> value_iterator::has_next_field() noexcept {
SIMDJSON_ASSUME( _json_iter->_depth == _depth ); assert_at_next();
switch (*_json_iter->advance()) { switch (*_json_iter->advance()) {
case '}': case '}':
@ -52,36 +51,43 @@ simdjson_warn_unused simdjson_really_inline simdjson_result<bool> value_iterator
} }
} }
simdjson_warn_unused simdjson_really_inline simdjson_result<bool> value_iterator::find_field_raw(const char *key) noexcept { /**
// We assume we are sitting at a key: at "key": <value> * Find the field with the given key. May be used in place of ++.
SIMDJSON_ASSUME( _json_iter->_depth == _depth+1 ); */
simdjson_warn_unused simdjson_really_inline simdjson_result<bool> value_iterator::find_field_raw(const std::string_view key) noexcept {
if (!is_open()) { return false; }
bool has_next; // Unless this is the first field, we need to advance past the , and check for }
do { error_code error;
bool has_value;
if (at_first_field()) {
has_value = true;
} else {
if ((error = skip_child() )) { abandon(); return error; }
if ((error = has_next_field().get(has_value) )) { abandon(); return error; }
}
while (has_value) {
// Get the key // Get the key
raw_json_string actual_key; raw_json_string actual_key;
SIMDJSON_TRY( require_raw_json_string().get(actual_key) ); if ((error = field_key().get(actual_key) )) { abandon(); return error; };
if (*_json_iter->advance() != ':') { return _json_iter->report_error(TAPE_ERROR, "Missing colon in object field"); } if ((error = field_value() )) { abandon(); return error; }
// Check if the key matches, and return if so // Check if it matches
if (actual_key == key) { if (actual_key == key) {
logger::log_event(*_json_iter, "match", key); logger::log_event(*this, "match", key, -2);
return true; return true;
} }
logger::log_event(*this, "no match", key, -2);
SIMDJSON_TRY( skip_child() ); // Skip the value entirely
if ((error = has_next_field().get(has_value) )) { abandon(); return error; }
}
// Skip the value so we can look at the next key // If the loop ended, we're out of fields to look at.
logger::log_event(*_json_iter, "non-match", key);
SIMDJSON_TRY( skip_child() );
// Check whether the next token is , or }
SIMDJSON_TRY( has_next_field().get(has_next) );
} while (has_next);
logger::log_event(*_json_iter, "no matches", key);
return false; return false;
} }
simdjson_warn_unused simdjson_really_inline simdjson_result<raw_json_string> value_iterator::field_key() noexcept { simdjson_warn_unused simdjson_really_inline simdjson_result<raw_json_string> value_iterator::field_key() noexcept {
SIMDJSON_ASSUME( _json_iter->_depth == _depth+1 ); assert_at_child();
const uint8_t *key = _json_iter->advance(); const uint8_t *key = _json_iter->advance();
if (*(key++) != '"') { return _json_iter->report_error(TAPE_ERROR, "Object key is not a string"); } if (*(key++) != '"') { return _json_iter->report_error(TAPE_ERROR, "Object key is not a string"); }
@ -89,21 +95,21 @@ simdjson_warn_unused simdjson_really_inline simdjson_result<raw_json_string> val
} }
simdjson_warn_unused simdjson_really_inline error_code value_iterator::field_value() noexcept { simdjson_warn_unused simdjson_really_inline error_code value_iterator::field_value() noexcept {
SIMDJSON_ASSUME( _json_iter->_depth == _depth+1 ); assert_at_child();
if (*_json_iter->advance() != ':') { return _json_iter->report_error(TAPE_ERROR, "Missing colon in object field"); } if (*_json_iter->advance() != ':') { return _json_iter->report_error(TAPE_ERROR, "Missing colon in object field"); }
return SUCCESS; return SUCCESS;
} }
simdjson_warn_unused simdjson_really_inline simdjson_result<bool> value_iterator::start_array() noexcept { simdjson_warn_unused simdjson_really_inline simdjson_result<bool> value_iterator::start_array() noexcept {
SIMDJSON_ASSUME( _json_iter->_depth == _depth && _depth > 0); assert_at_start();
if (*_json_iter->advance() != '[') { logger::log_error(*_json_iter, "Not an array"); return INCORRECT_TYPE; } if (*_json_iter->advance() != '[') { logger::log_error(*_json_iter, "Not an array"); return INCORRECT_TYPE; }
return started_array(); return started_array();
} }
simdjson_warn_unused simdjson_really_inline simdjson_result<bool> value_iterator::try_start_array() noexcept { simdjson_warn_unused simdjson_really_inline simdjson_result<bool> value_iterator::try_start_array() noexcept {
SIMDJSON_ASSUME( _json_iter->_depth == _depth && _depth > 0); assert_at_start();
if (*_json_iter->peek() != '[') { logger::log_error(*_json_iter, "Not an array"); return INCORRECT_TYPE; } if (*_json_iter->peek() != '[') { logger::log_error(*_json_iter, "Not an array"); return INCORRECT_TYPE; }
_json_iter->advance(); _json_iter->advance();
@ -111,8 +117,6 @@ simdjson_warn_unused simdjson_really_inline simdjson_result<bool> value_iterator
} }
simdjson_warn_unused simdjson_really_inline bool value_iterator::started_array() noexcept { simdjson_warn_unused simdjson_really_inline bool value_iterator::started_array() noexcept {
SIMDJSON_ASSUME( _json_iter->_depth == _depth && _depth > 0 );
if (*_json_iter->peek() == ']') { if (*_json_iter->peek() == ']') {
logger::log_value(*_json_iter, "empty array"); logger::log_value(*_json_iter, "empty array");
_json_iter->advance(); _json_iter->advance();
@ -125,7 +129,7 @@ simdjson_warn_unused simdjson_really_inline bool value_iterator::started_array()
} }
simdjson_warn_unused simdjson_really_inline simdjson_result<bool> value_iterator::has_next_element() noexcept { simdjson_warn_unused simdjson_really_inline simdjson_result<bool> value_iterator::has_next_element() noexcept {
SIMDJSON_ASSUME( _json_iter->_depth == _depth ); assert_at_next();
switch (*_json_iter->advance()) { switch (*_json_iter->advance()) {
case ']': case ']':
@ -147,7 +151,7 @@ simdjson_warn_unused simdjson_really_inline simdjson_result<std::string_view> va
return require_raw_json_string().unescape(_json_iter->string_buf_loc()); return require_raw_json_string().unescape(_json_iter->string_buf_loc());
} }
simdjson_warn_unused simdjson_really_inline simdjson_result<raw_json_string> value_iterator::try_get_raw_json_string() noexcept { simdjson_warn_unused simdjson_really_inline simdjson_result<raw_json_string> value_iterator::try_get_raw_json_string() noexcept {
SIMDJSON_ASSUME( _json_iter->_depth == _depth && _depth > 0 ); assert_at_start();
logger::log_value(*_json_iter, "string", "", 0); logger::log_value(*_json_iter, "string", "", 0);
auto json = _json_iter->peek(); auto json = _json_iter->peek();
@ -157,7 +161,7 @@ simdjson_warn_unused simdjson_really_inline simdjson_result<raw_json_string> val
return raw_json_string(json+1); return raw_json_string(json+1);
} }
simdjson_warn_unused simdjson_really_inline simdjson_result<raw_json_string> value_iterator::require_raw_json_string() noexcept { simdjson_warn_unused simdjson_really_inline simdjson_result<raw_json_string> value_iterator::require_raw_json_string() noexcept {
SIMDJSON_ASSUME( _json_iter->_depth == _depth && _depth > 0 ); assert_at_start();
logger::log_value(*_json_iter, "string", "", 0); logger::log_value(*_json_iter, "string", "", 0);
auto json = _json_iter->advance(); auto json = _json_iter->advance();
@ -166,7 +170,7 @@ simdjson_warn_unused simdjson_really_inline simdjson_result<raw_json_string> val
return raw_json_string(json+1); return raw_json_string(json+1);
} }
simdjson_warn_unused simdjson_really_inline simdjson_result<uint64_t> value_iterator::try_get_uint64() noexcept { simdjson_warn_unused simdjson_really_inline simdjson_result<uint64_t> value_iterator::try_get_uint64() noexcept {
SIMDJSON_ASSUME( _json_iter->_depth == _depth && _depth > 1 ); assert_at_non_root_start();
logger::log_value(*_json_iter, "uint64", "", 0); logger::log_value(*_json_iter, "uint64", "", 0);
uint64_t result; uint64_t result;
@ -176,14 +180,14 @@ simdjson_warn_unused simdjson_really_inline simdjson_result<uint64_t> value_iter
return result; return result;
} }
simdjson_warn_unused simdjson_really_inline simdjson_result<uint64_t> value_iterator::require_uint64() noexcept { simdjson_warn_unused simdjson_really_inline simdjson_result<uint64_t> value_iterator::require_uint64() noexcept {
SIMDJSON_ASSUME( _json_iter->_depth == _depth && _depth > 1 ); assert_at_non_root_start();
logger::log_value(*_json_iter, "uint64", "", 0); logger::log_value(*_json_iter, "uint64", "", 0);
_json_iter->ascend_to(depth()-1); _json_iter->ascend_to(depth()-1);
return numberparsing::parse_unsigned(_json_iter->advance()); return numberparsing::parse_unsigned(_json_iter->advance());
} }
simdjson_warn_unused simdjson_really_inline simdjson_result<int64_t> value_iterator::try_get_int64() noexcept { simdjson_warn_unused simdjson_really_inline simdjson_result<int64_t> value_iterator::try_get_int64() noexcept {
SIMDJSON_ASSUME( _json_iter->_depth == _depth && _depth > 1 ); assert_at_non_root_start();
logger::log_value(*_json_iter, "int64", "", 0); logger::log_value(*_json_iter, "int64", "", 0);
int64_t result; int64_t result;
@ -193,14 +197,14 @@ simdjson_warn_unused simdjson_really_inline simdjson_result<int64_t> value_itera
return result; return result;
} }
simdjson_warn_unused simdjson_really_inline simdjson_result<int64_t> value_iterator::require_int64() noexcept { simdjson_warn_unused simdjson_really_inline simdjson_result<int64_t> value_iterator::require_int64() noexcept {
SIMDJSON_ASSUME( _json_iter->_depth == _depth && _depth > 1 ); assert_at_non_root_start();
logger::log_value(*_json_iter, "int64", "", 0); logger::log_value(*_json_iter, "int64", "", 0);
_json_iter->ascend_to(depth()-1); _json_iter->ascend_to(depth()-1);
return numberparsing::parse_integer(_json_iter->advance()); return numberparsing::parse_integer(_json_iter->advance());
} }
simdjson_warn_unused simdjson_really_inline simdjson_result<double> value_iterator::try_get_double() noexcept { simdjson_warn_unused simdjson_really_inline simdjson_result<double> value_iterator::try_get_double() noexcept {
SIMDJSON_ASSUME( _json_iter->_depth == _depth && _depth > 1 ); assert_at_non_root_start();
logger::log_value(*_json_iter, "double", "", 0); logger::log_value(*_json_iter, "double", "", 0);
double result; double result;
@ -210,7 +214,7 @@ simdjson_warn_unused simdjson_really_inline simdjson_result<double> value_iterat
return result; return result;
} }
simdjson_warn_unused simdjson_really_inline simdjson_result<double> value_iterator::require_double() noexcept { simdjson_warn_unused simdjson_really_inline simdjson_result<double> value_iterator::require_double() noexcept {
SIMDJSON_ASSUME( _json_iter->_depth == _depth && _depth > 1 ); assert_at_non_root_start();
logger::log_value(*_json_iter, "double", "", 0); logger::log_value(*_json_iter, "double", "", 0);
_json_iter->ascend_to(depth()-1); _json_iter->ascend_to(depth()-1);
@ -225,7 +229,7 @@ simdjson_warn_unused simdjson_really_inline simdjson_result<bool> value_iterator
return simdjson_result<bool>(!not_true); return simdjson_result<bool>(!not_true);
} }
simdjson_warn_unused simdjson_really_inline simdjson_result<bool> value_iterator::try_get_bool() noexcept { simdjson_warn_unused simdjson_really_inline simdjson_result<bool> value_iterator::try_get_bool() noexcept {
SIMDJSON_ASSUME( _json_iter->_depth == _depth && _depth > 1 ); assert_at_non_root_start();
bool result; bool result;
SIMDJSON_TRY( parse_bool(_json_iter->peek()).get(result) ); SIMDJSON_TRY( parse_bool(_json_iter->peek()).get(result) );
@ -234,7 +238,7 @@ simdjson_warn_unused simdjson_really_inline simdjson_result<bool> value_iterator
return result; return result;
} }
simdjson_warn_unused simdjson_really_inline simdjson_result<bool> value_iterator::require_bool() noexcept { simdjson_warn_unused simdjson_really_inline simdjson_result<bool> value_iterator::require_bool() noexcept {
SIMDJSON_ASSUME( _json_iter->_depth == _depth && _depth > 1 ); assert_at_non_root_start();
_json_iter->ascend_to(depth()-1); _json_iter->ascend_to(depth()-1);
return parse_bool(_json_iter->advance()); return parse_bool(_json_iter->advance());
@ -247,7 +251,7 @@ simdjson_really_inline bool value_iterator::is_null(const uint8_t *json) const n
return false; return false;
} }
simdjson_really_inline bool value_iterator::is_null() noexcept { simdjson_really_inline bool value_iterator::is_null() noexcept {
SIMDJSON_ASSUME( _json_iter->_depth == _depth && _depth > 1 ); assert_at_non_root_start();
if (is_null(_json_iter->peek())) { if (is_null(_json_iter->peek())) {
_json_iter->advance(); _json_iter->advance();
@ -257,7 +261,7 @@ simdjson_really_inline bool value_iterator::is_null() noexcept {
return false; return false;
} }
simdjson_really_inline bool value_iterator::require_null() noexcept { simdjson_really_inline bool value_iterator::require_null() noexcept {
SIMDJSON_ASSUME( _json_iter->_depth == _depth && _depth > 1 ); assert_at_non_root_start();
_json_iter->ascend_to(depth()-1); _json_iter->ascend_to(depth()-1);
return is_null(_json_iter->advance()); return is_null(_json_iter->advance());
@ -266,8 +270,6 @@ simdjson_really_inline bool value_iterator::require_null() noexcept {
constexpr const uint32_t MAX_INT_LENGTH = 1024; constexpr const uint32_t MAX_INT_LENGTH = 1024;
simdjson_warn_unused simdjson_really_inline simdjson_result<uint64_t> value_iterator::parse_root_uint64(const uint8_t *json, uint32_t max_len) const noexcept { simdjson_warn_unused simdjson_really_inline simdjson_result<uint64_t> value_iterator::parse_root_uint64(const uint8_t *json, uint32_t max_len) const noexcept {
SIMDJSON_ASSUME( _json_iter->_depth == _depth && _depth == 1 );
uint8_t tmpbuf[20+1]; // <20 digits> is the longest possible unsigned integer 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, "Root number more than 20 characters"); return NUMBER_ERROR; } if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf)) { logger::log_error(*_json_iter, "Root number more than 20 characters"); return NUMBER_ERROR; }
logger::log_value(*_json_iter, "uint64", "", 0); logger::log_value(*_json_iter, "uint64", "", 0);
@ -276,7 +278,7 @@ simdjson_warn_unused simdjson_really_inline simdjson_result<uint64_t> value_iter
return result; return result;
} }
simdjson_warn_unused simdjson_really_inline simdjson_result<uint64_t> value_iterator::try_get_root_uint64() noexcept { simdjson_warn_unused simdjson_really_inline simdjson_result<uint64_t> value_iterator::try_get_root_uint64() noexcept {
SIMDJSON_ASSUME( _json_iter->_depth == _depth && _depth == 1 ); assert_at_root();
uint64_t result; uint64_t result;
SIMDJSON_TRY( parse_root_uint64(_json_iter->peek(), _json_iter->peek_length()).get(result) ); SIMDJSON_TRY( parse_root_uint64(_json_iter->peek(), _json_iter->peek_length()).get(result) );
@ -284,14 +286,12 @@ simdjson_warn_unused simdjson_really_inline simdjson_result<uint64_t> value_iter
return result; return result;
} }
simdjson_warn_unused simdjson_really_inline simdjson_result<uint64_t> value_iterator::require_root_uint64() noexcept { simdjson_warn_unused simdjson_really_inline simdjson_result<uint64_t> value_iterator::require_root_uint64() noexcept {
SIMDJSON_ASSUME( _json_iter->_depth == _depth && _depth == 1 ); assert_at_root();
auto max_len = _json_iter->peek_length(); auto max_len = _json_iter->peek_length();
return parse_root_uint64(_json_iter->advance(), max_len); return parse_root_uint64(_json_iter->advance(), max_len);
} }
simdjson_warn_unused simdjson_really_inline simdjson_result<int64_t> value_iterator::parse_root_int64(const uint8_t *json, uint32_t max_len) const noexcept { simdjson_warn_unused simdjson_really_inline simdjson_result<int64_t> value_iterator::parse_root_int64(const uint8_t *json, uint32_t max_len) const noexcept {
SIMDJSON_ASSUME( _json_iter->_depth == _depth && _depth == 1 );
uint8_t tmpbuf[20+1]; // -<19 digits> is the longest possible integer 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, "Root number more than 20 characters"); return NUMBER_ERROR; } if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf)) { logger::log_error(*_json_iter, "Root number more than 20 characters"); return NUMBER_ERROR; }
logger::log_value(*_json_iter, "int64", "", 0); logger::log_value(*_json_iter, "int64", "", 0);
@ -300,7 +300,7 @@ simdjson_warn_unused simdjson_really_inline simdjson_result<int64_t> value_itera
return result; return result;
} }
simdjson_warn_unused simdjson_really_inline simdjson_result<int64_t> value_iterator::try_get_root_int64() noexcept { simdjson_warn_unused simdjson_really_inline simdjson_result<int64_t> value_iterator::try_get_root_int64() noexcept {
SIMDJSON_ASSUME( _json_iter->_depth == _depth && _depth == 1 ); assert_at_root();
int64_t result; int64_t result;
SIMDJSON_TRY( parse_root_int64(_json_iter->peek(), _json_iter->peek_length()).get(result) ); SIMDJSON_TRY( parse_root_int64(_json_iter->peek(), _json_iter->peek_length()).get(result) );
@ -308,14 +308,12 @@ simdjson_warn_unused simdjson_really_inline simdjson_result<int64_t> value_itera
return result; return result;
} }
simdjson_warn_unused simdjson_really_inline simdjson_result<int64_t> value_iterator::require_root_int64() noexcept { simdjson_warn_unused simdjson_really_inline simdjson_result<int64_t> value_iterator::require_root_int64() noexcept {
SIMDJSON_ASSUME( _json_iter->_depth == _depth && _depth == 1 ); assert_at_root();
auto max_len = _json_iter->peek_length(); auto max_len = _json_iter->peek_length();
return parse_root_int64(_json_iter->advance(), max_len); return parse_root_int64(_json_iter->advance(), max_len);
} }
simdjson_warn_unused simdjson_really_inline simdjson_result<double> value_iterator::parse_root_double(const uint8_t *json, uint32_t max_len) const noexcept { simdjson_warn_unused simdjson_really_inline simdjson_result<double> value_iterator::parse_root_double(const uint8_t *json, uint32_t max_len) const noexcept {
SIMDJSON_ASSUME( _json_iter->_depth == _depth && _depth == 1 );
// 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. // 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]; uint8_t tmpbuf[1074+8+1];
if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf)) { logger::log_error(*_json_iter, "Root number more than 1082 characters"); return NUMBER_ERROR; } if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf)) { logger::log_error(*_json_iter, "Root number more than 1082 characters"); return NUMBER_ERROR; }
@ -325,7 +323,7 @@ simdjson_warn_unused simdjson_really_inline simdjson_result<double> value_iterat
return result; return result;
} }
simdjson_warn_unused simdjson_really_inline simdjson_result<double> value_iterator::try_get_root_double() noexcept { simdjson_warn_unused simdjson_really_inline simdjson_result<double> value_iterator::try_get_root_double() noexcept {
SIMDJSON_ASSUME( _json_iter->_depth == _depth && _depth == 1 ); assert_at_root();
double result; double result;
SIMDJSON_TRY( parse_root_double(_json_iter->peek(), _json_iter->peek_length()).get(result) ); SIMDJSON_TRY( parse_root_double(_json_iter->peek(), _json_iter->peek_length()).get(result) );
@ -333,20 +331,18 @@ simdjson_warn_unused simdjson_really_inline simdjson_result<double> value_iterat
return result; return result;
} }
simdjson_warn_unused simdjson_really_inline simdjson_result<double> value_iterator::require_root_double() noexcept { simdjson_warn_unused simdjson_really_inline simdjson_result<double> value_iterator::require_root_double() noexcept {
SIMDJSON_ASSUME( _json_iter->_depth == _depth && _depth == 1 ); assert_at_root();
auto max_len = _json_iter->peek_length(); auto max_len = _json_iter->peek_length();
return parse_root_double(_json_iter->advance(), max_len); return parse_root_double(_json_iter->advance(), max_len);
} }
simdjson_warn_unused simdjson_really_inline simdjson_result<bool> value_iterator::parse_root_bool(const uint8_t *json, uint32_t max_len) const noexcept { simdjson_warn_unused simdjson_really_inline simdjson_result<bool> value_iterator::parse_root_bool(const uint8_t *json, uint32_t max_len) const noexcept {
SIMDJSON_ASSUME( _json_iter->_depth == _depth && _depth == 1 );
uint8_t tmpbuf[5+1]; uint8_t tmpbuf[5+1];
if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf)) { logger::log_error(*_json_iter, "Not a boolean"); return INCORRECT_TYPE; } if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf)) { logger::log_error(*_json_iter, "Not a boolean"); return INCORRECT_TYPE; }
return parse_bool(tmpbuf); return parse_bool(tmpbuf);
} }
simdjson_warn_unused simdjson_really_inline simdjson_result<bool> value_iterator::try_get_root_bool() noexcept { simdjson_warn_unused simdjson_really_inline simdjson_result<bool> value_iterator::try_get_root_bool() noexcept {
SIMDJSON_ASSUME( _json_iter->_depth == _depth && _depth == 1 ); assert_at_root();
bool result; bool result;
SIMDJSON_TRY( parse_root_bool(_json_iter->peek(), _json_iter->peek_length()).get(result) ); SIMDJSON_TRY( parse_root_bool(_json_iter->peek(), _json_iter->peek_length()).get(result) );
@ -354,44 +350,50 @@ simdjson_warn_unused simdjson_really_inline simdjson_result<bool> value_iterator
return result; return result;
} }
simdjson_warn_unused simdjson_really_inline simdjson_result<bool> value_iterator::require_root_bool() noexcept { simdjson_warn_unused simdjson_really_inline simdjson_result<bool> value_iterator::require_root_bool() noexcept {
SIMDJSON_ASSUME( _json_iter->_depth == _depth && _depth == 1 ); assert_at_root();
auto max_len = _json_iter->peek_length(); auto max_len = _json_iter->peek_length();
return parse_root_bool(_json_iter->advance(), max_len); return parse_root_bool(_json_iter->advance(), max_len);
} }
simdjson_really_inline bool value_iterator::is_root_null(const uint8_t *json, uint32_t max_len) const noexcept { simdjson_really_inline bool value_iterator::is_root_null(const uint8_t *json, uint32_t max_len) const noexcept {
SIMDJSON_ASSUME( _json_iter->_depth == _depth && _depth == 1 );
uint8_t tmpbuf[4+1]; uint8_t tmpbuf[4+1];
if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf)) { return false; } if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf)) { return false; }
return is_null(tmpbuf); return is_null(tmpbuf);
} }
simdjson_really_inline bool value_iterator::is_root_null() noexcept { simdjson_really_inline bool value_iterator::is_root_null() noexcept {
SIMDJSON_ASSUME( _json_iter->_depth == _depth && _depth == 1 ); assert_at_root();
if (!is_root_null(_json_iter->peek(), _json_iter->peek_length())) { return false; } if (!is_root_null(_json_iter->peek(), _json_iter->peek_length())) { return false; }
_json_iter->advance(); _json_iter->advance();
return true; return true;
} }
simdjson_really_inline bool value_iterator::require_root_null() noexcept { simdjson_really_inline bool value_iterator::require_root_null() noexcept {
SIMDJSON_ASSUME( _json_iter->_depth == _depth && _depth == 1 ); assert_at_root();
auto max_len = _json_iter->peek_length(); auto max_len = _json_iter->peek_length();
return is_root_null(_json_iter->advance(), max_len); return is_root_null(_json_iter->advance(), max_len);
} }
simdjson_warn_unused simdjson_really_inline error_code value_iterator::skip_child() noexcept { simdjson_warn_unused simdjson_really_inline error_code value_iterator::skip_child() noexcept {
SIMDJSON_ASSUME( _json_iter->token.index > _start_index );
SIMDJSON_ASSUME( _json_iter->_depth >= _depth );
return _json_iter->skip_child(depth()); return _json_iter->skip_child(depth());
} }
simdjson_really_inline value_iterator value_iterator::child() const noexcept { simdjson_really_inline value_iterator value_iterator::child() const noexcept {
SIMDJSON_ASSUME( _json_iter->_depth == _depth+1 ); assert_at_child();
return { _json_iter, depth()+1 }; return { _json_iter, depth()+1, _json_iter->token.checkpoint() };
} }
simdjson_really_inline bool value_iterator::is_open() const noexcept { simdjson_really_inline bool value_iterator::is_open() const noexcept {
return _json_iter->depth() >= depth(); return _json_iter->depth() >= depth();
} }
simdjson_really_inline bool value_iterator::at_first_field() const noexcept {
SIMDJSON_ASSUME( _json_iter->token.index > _start_index );
return _json_iter->token.index == _start_index + 1;
}
simdjson_really_inline void value_iterator::abandon() noexcept { simdjson_really_inline void value_iterator::abandon() noexcept {
_json_iter->abandon(); _json_iter->abandon();
} }
@ -413,6 +415,35 @@ simdjson_warn_unused simdjson_really_inline json_iterator &value_iterator::json_
return *_json_iter; return *_json_iter;
} }
simdjson_really_inline void value_iterator::assert_at_start() const noexcept {
SIMDJSON_ASSUME( _json_iter->token.index == _start_index );
SIMDJSON_ASSUME( _json_iter->_depth == _depth );
SIMDJSON_ASSUME( _depth > 0 );
}
simdjson_really_inline void value_iterator::assert_at_next() const noexcept {
SIMDJSON_ASSUME( _json_iter->token.index > _start_index );
SIMDJSON_ASSUME( _json_iter->_depth == _depth );
SIMDJSON_ASSUME( _depth > 0 );
}
simdjson_really_inline void value_iterator::assert_at_child() const noexcept {
SIMDJSON_ASSUME( _json_iter->token.index > _start_index );
SIMDJSON_ASSUME( _json_iter->_depth == _depth + 1 );
SIMDJSON_ASSUME( _depth > 0 );
}
simdjson_really_inline void value_iterator::assert_at_root() const noexcept {
assert_at_start();
SIMDJSON_ASSUME( _depth == 1 );
}
simdjson_really_inline void value_iterator::assert_at_non_root_start() const noexcept {
assert_at_start();
SIMDJSON_ASSUME( _depth > 1 );
}
} // namespace ondemand } // namespace ondemand
} // namespace SIMDJSON_IMPLEMENTATION } // namespace SIMDJSON_IMPLEMENTATION
} // namespace simdjson } // namespace simdjson

View File

@ -23,6 +23,12 @@ protected:
json_iterator *_json_iter{}; json_iterator *_json_iter{};
/** The depth of this value */ /** The depth of this value */
depth_t _depth{}; depth_t _depth{};
/**
* The starting token index for this value
*
* PERF NOTE: this is a safety check; we expect this to be elided in release builds.
*/
const uint32_t *_start_index{};
public: public:
simdjson_really_inline value_iterator() noexcept = default; simdjson_really_inline value_iterator() noexcept = default;
@ -49,6 +55,11 @@ public:
*/ */
simdjson_really_inline bool is_open() const noexcept; simdjson_really_inline bool is_open() const noexcept;
/**
* Tell whether the value is at an object's first field (just after the {).
*/
simdjson_really_inline bool at_first_field() const noexcept;
/** /**
* Abandon all iteration. * Abandon all iteration.
*/ */
@ -152,7 +163,7 @@ public:
* unescape it. This works well for typical ASCII and UTF-8 keys (almost all of them), but may * unescape it. This works well for typical ASCII and UTF-8 keys (almost all of them), but may
* fail to match some keys with escapes (\u, \n, etc.). * fail to match some keys with escapes (\u, \n, etc.).
*/ */
simdjson_warn_unused simdjson_really_inline simdjson_result<bool> find_field_raw(const char *key) noexcept; simdjson_warn_unused simdjson_really_inline simdjson_result<bool> find_field_raw(const std::string_view key) noexcept;
/** @} */ /** @} */
@ -246,7 +257,7 @@ public:
/** @} */ /** @} */
protected: protected:
simdjson_really_inline value_iterator(json_iterator *json_iter, depth_t depth) noexcept; simdjson_really_inline value_iterator(json_iterator *json_iter, depth_t depth, const uint32_t *start_index) noexcept;
simdjson_really_inline bool is_null(const uint8_t *json) const noexcept; simdjson_really_inline bool is_null(const uint8_t *json) const noexcept;
simdjson_really_inline simdjson_result<bool> parse_bool(const uint8_t *json) const noexcept; simdjson_really_inline simdjson_result<bool> parse_bool(const uint8_t *json) const noexcept;
simdjson_really_inline bool is_root_null(const uint8_t *json, uint32_t max_len) const noexcept; simdjson_really_inline bool is_root_null(const uint8_t *json, uint32_t max_len) const noexcept;
@ -255,6 +266,12 @@ protected:
simdjson_really_inline simdjson_result<int64_t> parse_root_int64(const uint8_t *json, uint32_t max_len) const noexcept; simdjson_really_inline simdjson_result<int64_t> parse_root_int64(const uint8_t *json, uint32_t max_len) const noexcept;
simdjson_really_inline simdjson_result<double> parse_root_double(const uint8_t *json, uint32_t max_len) const noexcept; simdjson_really_inline simdjson_result<double> parse_root_double(const uint8_t *json, uint32_t max_len) const noexcept;
simdjson_really_inline void assert_at_start() const noexcept;
simdjson_really_inline void assert_at_root() const noexcept;
simdjson_really_inline void assert_at_child() const noexcept;
simdjson_really_inline void assert_at_next() const noexcept;
simdjson_really_inline void assert_at_non_root_start() const noexcept;
friend class document; friend class document;
friend class object; friend class object;
friend class array; friend class array;

View File

@ -2,4 +2,6 @@
link_libraries(simdjson) link_libraries(simdjson)
include_directories(..) include_directories(..)
add_cpp_test(ondemand_basictests LABELS acceptance per_implementation) add_cpp_test(ondemand_basictests LABELS acceptance per_implementation)
if(HAVE_POSIX_FORK AND HAVE_POSIX_WAIT) # assert tests use fork and wait, which aren't on MSVC
add_cpp_test(ondemand_assert_out_of_order_values LABELS per_implementation explicitonly assert)
endif()

View File

@ -0,0 +1,56 @@
#include <iostream>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <sys/types.h>
#include "simdjson.h"
using namespace simdjson;
using namespace simdjson::builtin;
// This ensures the compiler can't rearrange them into the proper order (which causes it to work!)
simdjson_never_inline int check_point(simdjson_result<ondemand::value> xval, simdjson_result<ondemand::value> yval) {
// Verify the expected release behavior
error_code error;
uint64_t x = 0;
if ((error = xval.get(x))) { std::cerr << "error getting x: " << error << std::endl; }
else if (x != 2) { std::cerr << "expected x to (wrongly) be 2, was " << x << std::endl; }
uint64_t y = 0;
if ((error = yval.get(y))) { std::cerr << "error getting y: " << error << std::endl; }
else if (y != 3) { std::cerr << "expected y to (wrongly) be 3, was " << y << std::endl; }
return 0;
}
int test_check_point() {
auto json = R"(
{
"x": 1,
"y": 2 3
)"_padded;
ondemand::parser parser;
auto doc = parser.iterate(json);
return check_point(doc["x"], doc["y"]);
}
bool fork_failed_with_assert() {
int status = 0;
wait(&status);
return WIFSIGNALED(status);
}
int main(void) {
// To verify that the program asserts (which sends a signal), we fork a new process and use wait()
// to check the resulting error code. If it's a signal error code, we consider the
// test to have passed.
// From https://stackoverflow.com/a/33694733
pid_t pid = fork();
if (pid == -1) { std::cerr << "fork failed" << std::endl; return 1; }
if (pid) {
// Parent - wait child and interpret its result
return fork_failed_with_assert() ? 0 : 1;
} else {
test_check_point();
}
}

View File

@ -887,6 +887,116 @@ namespace dom_api_tests {
return true; return true;
})); }));
SUBTEST("simdjson_result<ondemand::document>", test_ondemand_doc(json, [&](auto doc_result) {
ASSERT_SUCCESS( doc_result["scalar_ignore"] );
std::cout << " - After ignoring empty scalar ..." << std::endl;
ASSERT_SUCCESS( doc_result["empty_array_ignore"] );
std::cout << " - After ignoring empty array ..." << std::endl;
ASSERT_SUCCESS( doc_result["empty_object_ignore"] );
std::cout << " - After ignoring empty doc_result ..." << std::endl;
// Break after using first value in child object
{
auto value = doc_result["object_break"];
for (auto [ child_field, error ] : value.get_object()) {
ASSERT_SUCCESS(error);
ASSERT_EQUAL(child_field.key(), "x");
uint64_t x;
ASSERT_SUCCESS( child_field.value().get(x) );
ASSERT_EQUAL(x, 3);
break; // Break after the first value
}
std::cout << " - After using first value in child object ..." << std::endl;
}
// Break without using first value in child object
{
auto value = doc_result["object_break_unused"];
for (auto [ child_field, error ] : value.get_object()) {
ASSERT_SUCCESS(error);
ASSERT_EQUAL(child_field.key(), "x");
break;
}
std::cout << " - After reaching (but not using) first value in child object ..." << std::endl;
}
// Only look up one field in child object
{
auto value = doc_result["object_index"];
uint64_t x;
ASSERT_SUCCESS( value["x"].get(x) );
ASSERT_EQUAL( x, 5 );
std::cout << " - After looking up one field in child object ..." << std::endl;
}
// Only look up one field in child object, but don't use it
{
auto value = doc_result["object_index_unused"];
ASSERT_SUCCESS( value["x"] );
std::cout << " - After looking up (but not using) one field in child object ..." << std::endl;
}
// Break after first value in child array
{
auto value = doc_result["array_break"];
for (auto child_value : value) {
uint64_t x;
ASSERT_SUCCESS( child_value.get(x) );
ASSERT_EQUAL( x, 7 );
break;
}
std::cout << " - After using first value in child array ..." << std::endl;
}
// Break without using first value in child array
{
auto value = doc_result["array_break_unused"];
for (auto child_value : value) {
ASSERT_SUCCESS(child_value);
break;
}
std::cout << " - After reaching (but not using) first value in child array ..." << std::endl;
}
// Break out of multiple child loops
{
auto value = doc_result["quadruple_nested_break"];
for (auto child1 : value.get_object()) {
for (auto child2 : child1.value().get_array()) {
for (auto child3 : child2.get_object()) {
for (auto child4 : child3.value().get_array()) {
uint64_t x;
ASSERT_SUCCESS( child4.get(x) );
ASSERT_EQUAL( x, 9 );
break;
}
break;
}
break;
}
break;
}
std::cout << " - After breaking out of quadruply-nested arrays and objects ..." << std::endl;
}
// Test the actual value
{
auto value = doc_result["actual_value"];
uint64_t actual_value;
ASSERT_SUCCESS( value.get(actual_value) );
ASSERT_EQUAL( actual_value, 10 );
}
return true;
}));
return true; return true;
} }
@ -1061,17 +1171,35 @@ namespace dom_api_tests {
return true; return true;
})); }));
SUBTEST("simdjson_result<ondemand::object>", test_ondemand_doc(json, [&](auto doc_result) { SUBTEST("simdjson_result<ondemand::object>", test_ondemand_doc(json, [&](auto doc_result) {
ASSERT_EQUAL( doc_result.get_object()["a"].get_uint64().first, 1 ); simdjson_result<ondemand::object> object;
object = doc_result.get_object();
ASSERT_EQUAL( object["a"].get_uint64().first, 1 );
ASSERT_EQUAL( object["b"].get_uint64().first, 2 );
ASSERT_EQUAL( object["c/d"].get_uint64().first, 3 );
ASSERT_ERROR( object["a"], NO_SUCH_FIELD );
ASSERT_ERROR( object["d"], NO_SUCH_FIELD );
return true; return true;
})); }));
SUBTEST("ondemand::document", test_ondemand_doc(json, [&](auto doc_result) { SUBTEST("ondemand::document", test_ondemand_doc(json, [&](auto doc_result) {
ondemand::document doc; ondemand::document doc;
ASSERT_SUCCESS( std::move(doc_result).get(doc) ); ASSERT_SUCCESS( std::move(doc_result).get(doc) );
ASSERT_EQUAL( doc["a"].get_uint64().first, 1 ); ASSERT_EQUAL( doc["a"].get_uint64().first, 1 );
ASSERT_EQUAL( doc["b"].get_uint64().first, 2 );
ASSERT_EQUAL( doc["c/d"].get_uint64().first, 3 );
ASSERT_ERROR( doc["a"], NO_SUCH_FIELD );
ASSERT_ERROR( doc["d"], NO_SUCH_FIELD );
return true; return true;
})); }));
SUBTEST("simdjson_result<ondemand::document>", test_ondemand_doc(json, [&](auto doc_result) { SUBTEST("simdjson_result<ondemand::document>", test_ondemand_doc(json, [&](auto doc_result) {
ASSERT_EQUAL( doc_result["a"].get_uint64().first, 1 ); ASSERT_EQUAL( doc_result["a"].get_uint64().first, 1 );
ASSERT_EQUAL( doc_result["b"].get_uint64().first, 2 );
ASSERT_EQUAL( doc_result["c/d"].get_uint64().first, 3 );
ASSERT_ERROR( doc_result["a"], NO_SUCH_FIELD );
ASSERT_ERROR( doc_result["d"], NO_SUCH_FIELD );
return true; return true;
})); }));
TEST_SUCCEED(); TEST_SUCCEED();