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:
commit
f785f76d98
|
@ -19,7 +19,7 @@ environment:
|
|||
- job_name: VS2017 (Static, No Threads)
|
||||
image: Visual Studio 2017
|
||||
CMAKE_ARGS: -A %Platform% -DSIMDJSON_BUILD_STATIC=ON -DSIMDJSON_ENABLE_THREADS=OFF
|
||||
CTEST_ARGS: -E checkperf
|
||||
CTEST_ARGS: -LE explicitonly
|
||||
- job_name: VS2019 (Win32)
|
||||
platform: Win32
|
||||
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
|
||||
image: Visual Studio 2015
|
||||
CMAKE_ARGS: -A %Platform% -DSIMDJSON_BUILD_STATIC=ON -DSIMDJSON_ENABLE_THREADS=OFF
|
||||
CTEST_ARGS: -E checkperf
|
||||
CTEST_ARGS: -LE explicitonly
|
||||
|
||||
build_script:
|
||||
- mkdir build
|
||||
|
|
|
@ -103,7 +103,14 @@ commands:
|
|||
cd build &&
|
||||
tools/json2json -h &&
|
||||
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:
|
||||
steps:
|
||||
|
@ -112,9 +119,9 @@ commands:
|
|||
cd build &&
|
||||
tools/json2json -h &&
|
||||
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=westmere ctest $CTEST_FLAGS -L per_implementation -E checkperf &&
|
||||
SIMDJSON_FORCE_IMPLEMENTATION=fallback 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 -LE explicitonly &&
|
||||
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.
|
||||
|
||||
|
||||
|
@ -144,6 +151,16 @@ jobs:
|
|||
executor: gcc10
|
||||
environment: { CMAKE_FLAGS: -DSIMDJSON_JUST_LIBRARY=ON }
|
||||
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:
|
||||
description: Build and run performance tests on GCC 10 and AVX 2 with a cmake static build, this test performance regression
|
||||
executor: gcc10
|
||||
|
@ -174,22 +191,22 @@ jobs:
|
|||
sanitize-gcc10:
|
||||
description: Build and run tests on GCC 10 and AVX 2 with a cmake sanitize build
|
||||
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 ]
|
||||
sanitize-clang10:
|
||||
description: Build and run tests on clang 10 and AVX 2 with a cmake sanitize build
|
||||
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 ]
|
||||
threadsanitize-gcc10:
|
||||
description: Build and run tests on GCC 10 and AVX 2 with a cmake sanitize build
|
||||
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 ]
|
||||
threadsanitize-clang10:
|
||||
description: Build and run tests on clang 10 and AVX 2 with a cmake sanitize build
|
||||
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 ]
|
||||
# dynamic
|
||||
dynamic-gcc10:
|
||||
|
@ -245,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: -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 ]
|
||||
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: -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 ]
|
||||
|
||||
workflows:
|
||||
|
@ -292,4 +309,8 @@ workflows:
|
|||
# testing "just the library"
|
||||
- justlib-gcc10
|
||||
|
||||
# testing asserts
|
||||
- assert-gcc10
|
||||
- assert-clang10
|
||||
|
||||
# TODO add windows: https://circleci.com/docs/2.0/configuration-reference/#windows
|
||||
|
|
|
@ -23,4 +23,4 @@ task:
|
|||
- make
|
||||
test_script:
|
||||
- cd build
|
||||
- ctest --output-on-failure -E checkperf
|
||||
- ctest --output-on-failure -LE explicitonly
|
||||
|
|
38
.drone.yml
38
.drone.yml
|
@ -9,7 +9,7 @@ steps:
|
|||
CXX: g++
|
||||
BUILD_FLAGS: -- -j
|
||||
CMAKE_FLAGS: -DSIMDJSON_BUILD_STATIC=ON
|
||||
CTEST_FLAGS: -j4 --output-on-failure -E checkperf
|
||||
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
|
||||
|
@ -30,7 +30,7 @@ steps:
|
|||
CXX: clang++-6.0
|
||||
BUILD_FLAGS: -- -j
|
||||
CMAKE_FLAGS: -DSIMDJSON_BUILD_STATIC=ON
|
||||
CTEST_FLAGS: -j4 --output-on-failure -E checkperf
|
||||
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
|
||||
|
@ -51,7 +51,7 @@ steps:
|
|||
CXX: g++
|
||||
BUILD_FLAGS: -- -j
|
||||
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:
|
||||
- echo "deb http://deb.debian.org/debian buster-backports main" >> /etc/apt/sources.list
|
||||
- apt-get update -qq
|
||||
|
@ -78,7 +78,7 @@ steps:
|
|||
CXX: clang++-6.0
|
||||
BUILD_FLAGS: -- -j
|
||||
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:
|
||||
- mkdir build
|
||||
- cd build
|
||||
|
@ -101,7 +101,7 @@ steps:
|
|||
CXX: g++
|
||||
BUILD_FLAGS: -- -j
|
||||
CMAKE_FLAGS: -DSIMDJSON_BUILD_STATIC=OFF
|
||||
CTEST_FLAGS: -j4 --output-on-failure -E checkperf
|
||||
CTEST_FLAGS: -j4 --output-on-failure -LE explicitonly
|
||||
commands:
|
||||
- echo "deb http://deb.debian.org/debian buster-backports main" >> /etc/apt/sources.list
|
||||
- apt-get update -qq
|
||||
|
@ -124,7 +124,7 @@ steps:
|
|||
CXX: clang++-9
|
||||
CMAKE_FLAGS: -DSIMDJSON_BUILD_STATIC=OFF
|
||||
BUILD_FLAGS: -- -j
|
||||
CTEST_FLAGS: -j4 --output-on-failure -E checkperf
|
||||
CTEST_FLAGS: -j4 --output-on-failure -LE explicitonly
|
||||
commands:
|
||||
- mkdir build
|
||||
- cd build
|
||||
|
@ -143,7 +143,7 @@ steps:
|
|||
CXX: g++
|
||||
BUILD_FLAGS: -- -j
|
||||
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:
|
||||
- echo "deb http://deb.debian.org/debian buster-backports main" >> /etc/apt/sources.list
|
||||
- apt-get update -qq
|
||||
|
@ -170,7 +170,7 @@ steps:
|
|||
CXX: clang++-9
|
||||
CMAKE_FLAGS: -DSIMDJSON_SANITIZE=ON -DSIMDJSON_IMPLEMENTATION=haswell;westmere;fallback
|
||||
BUILD_FLAGS: -- -j
|
||||
CTEST_FLAGS: -j4 --output-on-failure -E checkperf
|
||||
CTEST_FLAGS: -j4 --output-on-failure -LE explicitonly
|
||||
commands:
|
||||
- mkdir build
|
||||
- cd build
|
||||
|
@ -194,7 +194,7 @@ steps:
|
|||
CXX: clang++-11
|
||||
CMAKE_FLAGS: -GNinja
|
||||
BUILD_FLAGS:
|
||||
CTEST_FLAGS: -j4 --output-on-failure -E checkperf
|
||||
CTEST_FLAGS: -j4 --output-on-failure -LE explicitonly
|
||||
CXXFLAGS: -std=c++20 -stdlib=libc++
|
||||
commands:
|
||||
- mkdir build
|
||||
|
@ -214,7 +214,7 @@ steps:
|
|||
CXX: g++
|
||||
BUILD_FLAGS: -- -j
|
||||
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:
|
||||
- echo "deb http://deb.debian.org/debian buster-backports main" >> /etc/apt/sources.list
|
||||
- apt-get update -qq
|
||||
|
@ -239,7 +239,7 @@ steps:
|
|||
CXX: clang++-6.0
|
||||
CMAKE_FLAGS: -DSIMDJSON_BUILD_STATIC=OFF
|
||||
BUILD_FLAGS: -- -j
|
||||
CTEST_FLAGS: -j4 --output-on-failure -E checkperf
|
||||
CTEST_FLAGS: -j4 --output-on-failure -LE explicitonly
|
||||
commands:
|
||||
- apt-get -qq update
|
||||
- apt-get -t buster-backports install -y cmake
|
||||
|
@ -261,7 +261,7 @@ steps:
|
|||
CXX: g++
|
||||
BUILD_FLAGS: -- -j
|
||||
CMAKE_FLAGS: -DSIMDJSON_BUILD_STATIC=OFF
|
||||
CTEST_FLAGS: -j4 --output-on-failure -E checkperf
|
||||
CTEST_FLAGS: -j4 --output-on-failure -LE explicitonly
|
||||
commands:
|
||||
- echo "deb http://deb.debian.org/debian buster-backports main" >> /etc/apt/sources.list
|
||||
- apt-get update -qq
|
||||
|
@ -283,7 +283,7 @@ steps:
|
|||
CXX: clang++-6.0
|
||||
CMAKE_FLAGS: -DSIMDJSON_BUILD_STATIC=OFF
|
||||
BUILD_FLAGS: -- -j
|
||||
CTEST_FLAGS: -j4 --output-on-failure -E checkperf
|
||||
CTEST_FLAGS: -j4 --output-on-failure -LE explicitonly
|
||||
commands:
|
||||
- apt-get -qq update
|
||||
- apt-get -t buster-backports install -y cmake
|
||||
|
@ -303,7 +303,7 @@ steps:
|
|||
environment:
|
||||
BUILD_FLAGS: -- -j
|
||||
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
|
||||
CXX: g++
|
||||
commands:
|
||||
|
@ -331,7 +331,7 @@ steps:
|
|||
CXX: clang++-6.0
|
||||
CMAKE_FLAGS: -DSIMDJSON_SANITIZE=ON -DSIMDJSON_IMPLEMENTATION=arm64;fallback
|
||||
BUILD_FLAGS: -- -j
|
||||
CTEST_FLAGS: -j4 --output-on-failure -E checkperf
|
||||
CTEST_FLAGS: -j4 --output-on-failure -LE explicitonly
|
||||
commands:
|
||||
- apt-get -qq update
|
||||
- apt-get -t buster-backports install -y cmake
|
||||
|
@ -357,7 +357,7 @@ steps:
|
|||
CXX: clang++-9
|
||||
BUILD_FLAGS: -- -j 4
|
||||
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++
|
||||
commands:
|
||||
- mkdir build
|
||||
|
@ -378,7 +378,7 @@ steps:
|
|||
CXX: clang++-9
|
||||
BUILD_FLAGS: -- -j
|
||||
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++
|
||||
commands:
|
||||
- mkdir build
|
||||
|
@ -399,7 +399,7 @@ steps:
|
|||
CXX: clang++-7
|
||||
BUILD_FLAGS: -- -j
|
||||
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++
|
||||
commands:
|
||||
- mkdir build
|
||||
|
@ -419,7 +419,7 @@ steps:
|
|||
CXX: g++
|
||||
BUILD_FLAGS: -- -j
|
||||
CMAKE_FLAGS: -DSIMDJSON_EXCEPTIONS=OFF
|
||||
CTEST_FLAGS: -j4 --output-on-failure -E checkperf
|
||||
CTEST_FLAGS: -j4 --output-on-failure -LE explicitonly
|
||||
commands:
|
||||
- echo "deb http://deb.debian.org/debian buster-backports main" >> /etc/apt/sources.list
|
||||
- apt-get update -qq
|
||||
|
|
|
@ -34,4 +34,4 @@ jobs:
|
|||
./alpine.sh cmake --build build_for_alpine
|
||||
- name: test
|
||||
run: |
|
||||
./alpine.sh bash -c "cd build_for_alpine && ctest -E checkperf"
|
||||
./alpine.sh bash -c "cd build_for_alpine && ctest -LE explicitonly"
|
||||
|
|
|
@ -51,4 +51,4 @@ jobs:
|
|||
cd build
|
||||
cmake -DCMAKE_BUILD_TYPE=${{ matrix.type }} -DSIMDJSON_BUILD_STATIC=ON -DSIMDJSON_DO_NOT_USE_THREADS_NO_MATTER_WHAT=ON ..
|
||||
cmake --build . --verbose
|
||||
ctest -j4 --output-on-failure -E checkperf
|
||||
ctest -j4 --output-on-failure -LE explicitonly
|
||||
|
|
|
@ -23,6 +23,6 @@ jobs:
|
|||
cd build &&
|
||||
cmake -DSIMDJSON_GOOGLE_BENCHMARKS=ON -DSIMDJSON_BUILD_STATIC=ON -DCMAKE_INSTALL_PREFIX:PATH=destination .. &&
|
||||
cmake --build . &&
|
||||
ctest -j --output-on-failure -E checkperf &&
|
||||
ctest -j --output-on-failure -LE explicitonly &&
|
||||
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
|
||||
|
|
|
@ -23,6 +23,6 @@ jobs:
|
|||
cd build &&
|
||||
cmake -DSIMDJSON_GOOGLE_BENCHMARKS=ON -DSIMDJSON_BUILD_STATIC=ON -DCMAKE_INSTALL_PREFIX:PATH=destination .. &&
|
||||
cmake --build . &&
|
||||
ctest -j --output-on-failure -E checkperf &&
|
||||
ctest -j --output-on-failure -LE explicitonly &&
|
||||
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
|
||||
|
|
|
@ -31,6 +31,6 @@ jobs:
|
|||
buildWithCMakeArgs: --config Release
|
||||
|
||||
- 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"
|
||||
|
||||
|
|
|
@ -31,5 +31,5 @@ jobs:
|
|||
buildWithCMakeArgs: --config Release
|
||||
|
||||
- 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"
|
||||
|
|
|
@ -31,6 +31,6 @@ jobs:
|
|||
buildWithCMakeArgs: --config Release
|
||||
|
||||
- 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"
|
||||
|
||||
|
|
|
@ -176,7 +176,7 @@ install:
|
|||
- if [[ "${STATIC}" == "on" ]]; then
|
||||
export CMAKE_FLAGS="${CMAKE_FLAGS} -DSIMDJSON_BUILD_STATIC=ON";
|
||||
fi
|
||||
- export CTEST_FLAGS="-j4 --output-on-failure -E checkperf"
|
||||
- export CTEST_FLAGS="-j4 --output-on-failure -LE explicitonly"
|
||||
|
||||
script:
|
||||
- mkdir build
|
||||
|
|
|
@ -41,7 +41,7 @@
|
|||
#
|
||||
# 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.
|
||||
#
|
||||
|
|
|
@ -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 $<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 PROPERTY RUN_SERIAL TRUE)
|
||||
else()
|
||||
|
|
|
@ -72,24 +72,24 @@ set(THREADS_PREFER_PTHREAD_FLAG ON)
|
|||
|
||||
option(SIMDJSON_VISUAL_STUDIO_BUILD_WITH_DEBUG_INFO_FOR_PROFILING "Under Visual Studio, add Zi to the compile flag and DEBUG to the link file to add debugging information to the release build for easier profiling inside tools like VTune" OFF)
|
||||
if(MSVC)
|
||||
if("${MSVC_TOOLSET_VERSION}" STREQUAL "140")
|
||||
# Visual Studio 2015 issues warnings and we tolerate it, cmake -G"Visual Studio 14" ..
|
||||
target_compile_options(simdjson-internal-flags INTERFACE /W0 /sdl)
|
||||
else()
|
||||
# Recent version of Visual Studio expected (2017, 2019...). Prior versions are unsupported.
|
||||
target_compile_options(simdjson-internal-flags INTERFACE /WX /W3 /sdl /w34714) # https://docs.microsoft.com/en-us/cpp/error-messages/compiler-warnings/compiler-warning-level-4-c4714?view=vs-2019
|
||||
endif()
|
||||
if(SIMDJSON_VISUAL_STUDIO_BUILD_WITH_DEBUG_INFO_FOR_PROFILING)
|
||||
target_link_options(simdjson-flags INTERFACE /DEBUG )
|
||||
target_compile_options(simdjson-flags INTERFACE /Zi)
|
||||
endif()
|
||||
else()
|
||||
if("${MSVC_TOOLSET_VERSION}" STREQUAL "140")
|
||||
# Visual Studio 2015 issues warnings and we tolerate it, cmake -G"Visual Studio 14" ..
|
||||
target_compile_options(simdjson-internal-flags INTERFACE /W0 /sdl)
|
||||
else()
|
||||
# Recent version of Visual Studio expected (2017, 2019...). Prior versions are unsupported.
|
||||
target_compile_options(simdjson-internal-flags INTERFACE /WX /W3 /sdl /w34714) # https://docs.microsoft.com/en-us/cpp/error-messages/compiler-warnings/compiler-warning-level-4-c4714?view=vs-2019
|
||||
endif()
|
||||
if(SIMDJSON_VISUAL_STUDIO_BUILD_WITH_DEBUG_INFO_FOR_PROFILING)
|
||||
target_link_options(simdjson-flags INTERFACE /DEBUG )
|
||||
target_compile_options(simdjson-flags INTERFACE /Zi)
|
||||
endif(SIMDJSON_VISUAL_STUDIO_BUILD_WITH_DEBUG_INFO_FOR_PROFILING)
|
||||
else(MSVC)
|
||||
if(NOT WIN32)
|
||||
target_compile_options(simdjson-internal-flags INTERFACE -fPIC)
|
||||
endif()
|
||||
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)
|
||||
endif()
|
||||
endif(MSVC)
|
||||
|
||||
#
|
||||
# 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")
|
||||
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-internal-flags EXPORT simdjson-config)
|
||||
|
|
|
@ -5,13 +5,6 @@ namespace SIMDJSON_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>
|
||||
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),
|
||||
|
@ -70,9 +63,6 @@ simdjson_really_inline implementation_simdjson_result_base<T>::implementation_si
|
|||
template<typename T>
|
||||
simdjson_really_inline implementation_simdjson_result_base<T>::implementation_simdjson_result_base(T &&value) noexcept
|
||||
: 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
|
|
@ -30,7 +30,7 @@ struct implementation_simdjson_result_base {
|
|||
/**
|
||||
* 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.
|
||||
|
@ -47,21 +47,6 @@ struct implementation_simdjson_result_base {
|
|||
*/
|
||||
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.
|
||||
*
|
||||
|
@ -114,8 +99,8 @@ struct implementation_simdjson_result_base {
|
|||
|
||||
#endif // SIMDJSON_EXCEPTIONS
|
||||
|
||||
T first;
|
||||
error_code second;
|
||||
T first{};
|
||||
error_code second{UNINITIALIZED};
|
||||
}; // struct implementation_simdjson_result_base
|
||||
|
||||
} // namespace SIMDJSON_IMPLEMENTATION
|
||||
|
|
|
@ -8,9 +8,6 @@ simdjson_really_inline document::document(ondemand::json_iterator &&_iter) noexc
|
|||
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 {
|
||||
return document(std::forward<json_iterator>(iter));
|
||||
}
|
||||
|
@ -19,8 +16,11 @@ simdjson_really_inline value document::as_value() noexcept {
|
|||
return as_value_iterator();
|
||||
}
|
||||
simdjson_really_inline value_iterator document::as_value_iterator() noexcept {
|
||||
assert_at_start();
|
||||
return value_iterator(&iter, 1);
|
||||
iter.assert_at_root();
|
||||
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 {
|
||||
|
@ -30,15 +30,12 @@ simdjson_really_inline simdjson_result<object> document::get_object() & noexcept
|
|||
return as_value().get_object();
|
||||
}
|
||||
simdjson_really_inline simdjson_result<uint64_t> document::get_uint64() noexcept {
|
||||
assert_at_start();
|
||||
return as_value_iterator().require_root_uint64();
|
||||
}
|
||||
simdjson_really_inline simdjson_result<int64_t> document::get_int64() noexcept {
|
||||
assert_at_start();
|
||||
return as_value_iterator().require_root_int64();
|
||||
}
|
||||
simdjson_really_inline simdjson_result<double> document::get_double() noexcept {
|
||||
assert_at_start();
|
||||
return as_value_iterator().require_root_double();
|
||||
}
|
||||
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();
|
||||
}
|
||||
simdjson_really_inline simdjson_result<bool> document::get_bool() noexcept {
|
||||
assert_at_start();
|
||||
return as_value_iterator().require_root_bool();
|
||||
}
|
||||
simdjson_really_inline bool document::is_null() noexcept {
|
||||
assert_at_start();
|
||||
return as_value_iterator().is_root_null();
|
||||
}
|
||||
|
||||
|
@ -95,10 +90,20 @@ simdjson_really_inline simdjson_result<array_iterator> document::end() & noexcep
|
|||
return {};
|
||||
}
|
||||
simdjson_really_inline simdjson_result<value> document::operator[](std::string_view key) & noexcept {
|
||||
return get_object()[key];
|
||||
if (iter.at_root()) {
|
||||
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 {
|
||||
return get_object()[key];
|
||||
if (iter.at_root()) {
|
||||
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
|
||||
|
|
|
@ -20,17 +20,16 @@ class array_iterator;
|
|||
*/
|
||||
class document {
|
||||
public:
|
||||
simdjson_really_inline document(document &&other) noexcept = default;
|
||||
simdjson_really_inline document &operator=(document &&other) noexcept = default;
|
||||
|
||||
/**
|
||||
* Create a new invalid document.
|
||||
*
|
||||
* 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) = delete;
|
||||
simdjson_really_inline document &operator=(const document &other) = delete;
|
||||
simdjson_really_inline document(const document &other) noexcept = 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.
|
||||
|
@ -230,10 +229,9 @@ protected:
|
|||
|
||||
simdjson_really_inline value as_value() 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;
|
||||
|
||||
simdjson_really_inline void assert_at_start() const noexcept;
|
||||
|
||||
//
|
||||
// Fields
|
||||
//
|
||||
|
@ -261,10 +259,7 @@ struct simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document> : public SIM
|
|||
public:
|
||||
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() 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::object> get_object() & noexcept;
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
||||
simdjson_really_inline bool json_iterator::at_start() const noexcept {
|
||||
return token.index == &parser->dom_parser.structural_indexes[0];
|
||||
simdjson_really_inline bool json_iterator::at_root() const noexcept {
|
||||
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 );
|
||||
// Visual Studio Clang treats unique_ptr.get() as "side effecting."
|
||||
#ifndef SIMDJSON_CLANG_VISUAL_STUDIO
|
||||
|
|
|
@ -60,12 +60,17 @@ public:
|
|||
/**
|
||||
* 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
|
||||
*/
|
||||
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
|
||||
|
@ -184,8 +189,6 @@ public:
|
|||
simdjson_really_inline simdjson_result(error_code error) noexcept; ///< @private
|
||||
|
||||
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
|
||||
|
|
|
@ -43,18 +43,18 @@ namespace ondemand {
|
|||
// 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_TRY( find_field_raw(key) );
|
||||
return value(iter.iter.child());
|
||||
bool has_value;
|
||||
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_TRY( find_field_raw(key) );
|
||||
return value(iter.iter.child());
|
||||
bool has_value;
|
||||
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 {
|
||||
|
@ -71,6 +71,9 @@ simdjson_really_inline object object::started(value_iterator &iter) noexcept {
|
|||
simdjson_unused bool has_value = iter.started_object();
|
||||
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
|
||||
: 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_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;
|
||||
}
|
||||
simdjson_really_inline object_iterator object::end() noexcept {
|
||||
|
|
|
@ -49,11 +49,12 @@ protected:
|
|||
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 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;
|
||||
|
||||
object_iterator iter{};
|
||||
value_iterator iter{};
|
||||
|
||||
friend class value;
|
||||
friend class document;
|
||||
|
|
|
@ -7,8 +7,7 @@ namespace ondemand {
|
|||
//
|
||||
|
||||
simdjson_really_inline object_iterator::object_iterator(const value_iterator &_iter) noexcept
|
||||
: iter{_iter},
|
||||
at_start{true}
|
||||
: iter{_iter}
|
||||
{}
|
||||
|
||||
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.
|
||||
//
|
||||
|
||||
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 SIMDJSON_IMPLEMENTATION
|
||||
} // namespace simdjson
|
||||
|
|
|
@ -29,11 +29,6 @@ public:
|
|||
// Checks for ']' and ','
|
||||
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:
|
||||
/**
|
||||
* The underlying JSON iterator.
|
||||
|
@ -42,15 +37,6 @@ private:
|
|||
* is first used, and never changes afterwards.
|
||||
*/
|
||||
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;
|
||||
friend struct simdjson_result<object_iterator>;
|
||||
|
|
|
@ -130,10 +130,7 @@ struct simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::parser> : public SIMDJ
|
|||
public:
|
||||
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() 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
|
||||
|
|
|
@ -109,9 +109,7 @@ struct simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::raw_json_string> : pub
|
|||
public:
|
||||
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() 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<const char *> raw() const noexcept;
|
||||
|
|
|
@ -39,6 +39,10 @@ simdjson_really_inline bool token_iterator::operator<=(const token_iterator &oth
|
|||
return index <= other.index;
|
||||
}
|
||||
|
||||
simdjson_really_inline const uint32_t *token_iterator::checkpoint() const noexcept {
|
||||
return index;
|
||||
}
|
||||
|
||||
} // namespace ondemand
|
||||
} // namespace SIMDJSON_IMPLEMENTATION
|
||||
} // namespace simdjson
|
||||
|
|
|
@ -49,6 +49,11 @@ public:
|
|||
*/
|
||||
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
|
||||
// different calls to advance the iterator based on *their own* state.
|
||||
|
||||
|
@ -77,6 +82,8 @@ protected:
|
|||
const uint32_t *index{};
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
|
@ -91,9 +98,7 @@ struct simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::token_iterator> : publ
|
|||
public:
|
||||
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() 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
|
||||
};
|
||||
|
||||
|
|
|
@ -2,20 +2,21 @@ namespace simdjson {
|
|||
namespace SIMDJSON_IMPLEMENTATION {
|
||||
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},
|
||||
_depth{depth}
|
||||
_depth{depth},
|
||||
_start_index{start_index}
|
||||
{
|
||||
}
|
||||
|
||||
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; }
|
||||
return started_object();
|
||||
}
|
||||
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; }
|
||||
_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_ASSUME( _json_iter->_depth == _depth && _depth > 0 );
|
||||
|
||||
if (*_json_iter->peek() == '}') {
|
||||
logger::log_value(*_json_iter, "empty object");
|
||||
_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_ASSUME( _json_iter->_depth == _depth );
|
||||
assert_at_next();
|
||||
|
||||
switch (*_json_iter->advance()) {
|
||||
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>
|
||||
SIMDJSON_ASSUME( _json_iter->_depth == _depth+1 );
|
||||
/**
|
||||
* Find the field with the given key. May be used in place of ++.
|
||||
*/
|
||||
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;
|
||||
do {
|
||||
// Unless this is the first field, we need to advance past the , and check for }
|
||||
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
|
||||
raw_json_string actual_key;
|
||||
SIMDJSON_TRY( require_raw_json_string().get(actual_key) );
|
||||
if (*_json_iter->advance() != ':') { return _json_iter->report_error(TAPE_ERROR, "Missing colon in object field"); }
|
||||
if ((error = field_key().get(actual_key) )) { abandon(); return error; };
|
||||
if ((error = field_value() )) { abandon(); return error; }
|
||||
|
||||
// Check if the key matches, and return if so
|
||||
// Check if it matches
|
||||
if (actual_key == key) {
|
||||
logger::log_event(*_json_iter, "match", key);
|
||||
logger::log_event(*this, "match", key, -2);
|
||||
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
|
||||
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);
|
||||
// If the loop ended, we're out of fields to look at.
|
||||
return false;
|
||||
}
|
||||
|
||||
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();
|
||||
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_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"); }
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
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; }
|
||||
return started_array();
|
||||
}
|
||||
|
||||
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; }
|
||||
_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_ASSUME( _json_iter->_depth == _depth && _depth > 0 );
|
||||
|
||||
if (*_json_iter->peek() == ']') {
|
||||
logger::log_value(*_json_iter, "empty array");
|
||||
_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_ASSUME( _json_iter->_depth == _depth );
|
||||
assert_at_next();
|
||||
|
||||
switch (*_json_iter->advance()) {
|
||||
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());
|
||||
}
|
||||
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);
|
||||
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);
|
||||
}
|
||||
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);
|
||||
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);
|
||||
}
|
||||
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);
|
||||
uint64_t result;
|
||||
|
@ -176,14 +180,14 @@ simdjson_warn_unused simdjson_really_inline simdjson_result<uint64_t> value_iter
|
|||
return result;
|
||||
}
|
||||
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);
|
||||
_json_iter->ascend_to(depth()-1);
|
||||
return numberparsing::parse_unsigned(_json_iter->advance());
|
||||
}
|
||||
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);
|
||||
int64_t result;
|
||||
|
@ -193,14 +197,14 @@ simdjson_warn_unused simdjson_really_inline simdjson_result<int64_t> value_itera
|
|||
return result;
|
||||
}
|
||||
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);
|
||||
_json_iter->ascend_to(depth()-1);
|
||||
return numberparsing::parse_integer(_json_iter->advance());
|
||||
}
|
||||
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);
|
||||
double result;
|
||||
|
@ -210,7 +214,7 @@ simdjson_warn_unused simdjson_really_inline simdjson_result<double> value_iterat
|
|||
return result;
|
||||
}
|
||||
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);
|
||||
_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);
|
||||
}
|
||||
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;
|
||||
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;
|
||||
}
|
||||
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);
|
||||
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;
|
||||
}
|
||||
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())) {
|
||||
_json_iter->advance();
|
||||
|
@ -257,7 +261,7 @@ simdjson_really_inline bool value_iterator::is_null() noexcept {
|
|||
return false;
|
||||
}
|
||||
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);
|
||||
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;
|
||||
|
||||
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
|
||||
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);
|
||||
|
@ -276,7 +278,7 @@ simdjson_warn_unused simdjson_really_inline simdjson_result<uint64_t> value_iter
|
|||
return result;
|
||||
}
|
||||
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;
|
||||
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;
|
||||
}
|
||||
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();
|
||||
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_ASSUME( _json_iter->_depth == _depth && _depth == 1 );
|
||||
|
||||
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; }
|
||||
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;
|
||||
}
|
||||
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;
|
||||
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;
|
||||
}
|
||||
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();
|
||||
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_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.
|
||||
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; }
|
||||
|
@ -325,7 +323,7 @@ simdjson_warn_unused simdjson_really_inline simdjson_result<double> value_iterat
|
|||
return result;
|
||||
}
|
||||
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;
|
||||
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;
|
||||
}
|
||||
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();
|
||||
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_ASSUME( _json_iter->_depth == _depth && _depth == 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; }
|
||||
return parse_bool(tmpbuf);
|
||||
}
|
||||
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;
|
||||
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;
|
||||
}
|
||||
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();
|
||||
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_ASSUME( _json_iter->_depth == _depth && _depth == 1 );
|
||||
|
||||
uint8_t tmpbuf[4+1];
|
||||
if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf)) { return false; }
|
||||
return is_null(tmpbuf);
|
||||
}
|
||||
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; }
|
||||
_json_iter->advance();
|
||||
return true;
|
||||
}
|
||||
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();
|
||||
return is_root_null(_json_iter->advance(), max_len);
|
||||
}
|
||||
|
||||
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());
|
||||
}
|
||||
simdjson_really_inline value_iterator value_iterator::child() const noexcept {
|
||||
SIMDJSON_ASSUME( _json_iter->_depth == _depth+1 );
|
||||
return { _json_iter, depth()+1 };
|
||||
assert_at_child();
|
||||
return { _json_iter, depth()+1, _json_iter->token.checkpoint() };
|
||||
}
|
||||
|
||||
simdjson_really_inline bool value_iterator::is_open() const noexcept {
|
||||
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 {
|
||||
_json_iter->abandon();
|
||||
}
|
||||
|
@ -413,6 +415,35 @@ simdjson_warn_unused simdjson_really_inline json_iterator &value_iterator::json_
|
|||
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 SIMDJSON_IMPLEMENTATION
|
||||
} // namespace simdjson
|
||||
|
|
|
@ -23,6 +23,12 @@ protected:
|
|||
json_iterator *_json_iter{};
|
||||
/** The depth of this value */
|
||||
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:
|
||||
simdjson_really_inline value_iterator() noexcept = default;
|
||||
|
@ -49,6 +55,11 @@ public:
|
|||
*/
|
||||
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.
|
||||
*/
|
||||
|
@ -152,7 +163,7 @@ public:
|
|||
* 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.).
|
||||
*/
|
||||
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:
|
||||
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 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;
|
||||
|
@ -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<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 object;
|
||||
friend class array;
|
||||
|
|
|
@ -2,4 +2,6 @@
|
|||
link_libraries(simdjson)
|
||||
include_directories(..)
|
||||
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()
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -887,6 +887,116 @@ namespace dom_api_tests {
|
|||
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -1061,17 +1171,35 @@ namespace dom_api_tests {
|
|||
return true;
|
||||
}));
|
||||
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;
|
||||
}));
|
||||
SUBTEST("ondemand::document", test_ondemand_doc(json, [&](auto doc_result) {
|
||||
ondemand::document doc;
|
||||
ASSERT_SUCCESS( std::move(doc_result).get(doc) );
|
||||
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;
|
||||
}));
|
||||
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["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;
|
||||
}));
|
||||
TEST_SUCCEED();
|
||||
|
|
Loading…
Reference in New Issue