diff --git a/.appveyor.yml b/.appveyor.yml index 3c0c97ec5..ec37094d3 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -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 diff --git a/.circleci/config.yml b/.circleci/config.yml index df78a9191..e103452e4 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -103,7 +103,15 @@ 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_test: + steps: + - run: | + cd build && + tools/json2json -h && + ctest $CTEST_FLAGS -L assert && + ctest $CTEST_FLAGS -LE acceptance -LE explicitonly cmake_test_all: steps: @@ -112,9 +120,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 +152,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 -DCXX_CMAKE_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 -DCXX_CMAKE_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 +192,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 +263,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 +310,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 diff --git a/.cirrus.yml b/.cirrus.yml index ddabd38b4..e6cff0c37 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -23,4 +23,4 @@ task: - make test_script: - cd build - - ctest --output-on-failure -E checkperf + - ctest --output-on-failure -LE explicitonly diff --git a/.drone.yml b/.drone.yml index e55b44f22..eafa52cbd 100644 --- a/.drone.yml +++ b/.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 diff --git a/.github/workflows/alpine.yml b/.github/workflows/alpine.yml index a24f7e10b..68840d571 100644 --- a/.github/workflows/alpine.yml +++ b/.github/workflows/alpine.yml @@ -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" diff --git a/.github/workflows/msys2.yml b/.github/workflows/msys2.yml index 0aec0754f..4050db4bc 100644 --- a/.github/workflows/msys2.yml +++ b/.github/workflows/msys2.yml @@ -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 diff --git a/.github/workflows/ubuntu18.yml b/.github/workflows/ubuntu18.yml index 9ce25cc87..f95b4d41c 100644 --- a/.github/workflows/ubuntu18.yml +++ b/.github/workflows/ubuntu18.yml @@ -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 \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 diff --git a/.github/workflows/ubuntu20.yml b/.github/workflows/ubuntu20.yml index e58c8af9c..402f63d2e 100644 --- a/.github/workflows/ubuntu20.yml +++ b/.github/workflows/ubuntu20.yml @@ -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 \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 diff --git a/.github/workflows/vs16-ci.yml b/.github/workflows/vs16-ci.yml index 99c375b0d..ff9cf8839 100644 --- a/.github/workflows/vs16-ci.yml +++ b/.github/workflows/vs16-ci.yml @@ -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" diff --git a/.github/workflows/vs16-clang-ci.yml b/.github/workflows/vs16-clang-ci.yml index a90cb46d4..87da0cacb 100644 --- a/.github/workflows/vs16-clang-ci.yml +++ b/.github/workflows/vs16-clang-ci.yml @@ -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" diff --git a/.github/workflows/vs16-ninja-ci.yml b/.github/workflows/vs16-ninja-ci.yml index 8abbdab89..ad7aa9d2f 100644 --- a/.github/workflows/vs16-ninja-ci.yml +++ b/.github/workflows/vs16-ninja-ci.yml @@ -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" diff --git a/.travis.yml b/.travis.yml index e3dad90dd..67add3a8a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -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 diff --git a/Dockerfile b/Dockerfile index 264c28f0f..363512d86 100644 --- a/Dockerfile +++ b/Dockerfile @@ -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. # diff --git a/benchmark/checkperf.cmake b/benchmark/checkperf.cmake index 02f8bf01c..bd4837747 100644 --- a/benchmark/checkperf.cmake +++ b/benchmark/checkperf.cmake @@ -89,7 +89,7 @@ if (Git_FOUND AND (GIT_VERSION_STRING VERSION_GREATER "2.1.4") AND (NOT CMAKE_G # COMMAND ECHO $ \"$ -t ${SIMDJSON_CHECKPERF_ARGS}\" \"${CHECKPERF_PARSE} -t ${SIMDJSON_CHECKPERF_ARGS}\" } COMMAND $ $ ${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() diff --git a/cmake/simdjson-flags.cmake b/cmake/simdjson-flags.cmake index 7ffb4a48e..a9c7ff7bc 100644 --- a/cmake/simdjson-flags.cmake +++ b/cmake/simdjson-flags.cmake @@ -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) diff --git a/include/simdjson/generic/implementation_simdjson_result_base.h b/include/simdjson/generic/implementation_simdjson_result_base.h index 9c7ac8ab7..67b89ff67 100644 --- a/include/simdjson/generic/implementation_simdjson_result_base.h +++ b/include/simdjson/generic/implementation_simdjson_result_base.h @@ -47,16 +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 &&value) noexcept = default; - - /** - * Copy a result. - */ - simdjson_really_inline implementation_simdjson_result_base(const implementation_simdjson_result_base &value) = default; - /** * Create a new empty result with error = UNINITIALIZED. */ diff --git a/include/simdjson/generic/ondemand/document-inl.h b/include/simdjson/generic/ondemand/document-inl.h index 4972123df..e9a66995a 100644 --- a/include/simdjson/generic/ondemand/document-inl.h +++ b/include/simdjson/generic/ondemand/document-inl.h @@ -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_root() const noexcept { - iter.assert_at_root(); -} simdjson_really_inline document document::start(json_iterator &&iter) noexcept { return document(std::forward(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_root(); - return value_iterator(&iter, 1, iter.token.checkpoint()); + 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 document::get_array() & noexcept { @@ -90,10 +90,20 @@ simdjson_really_inline simdjson_result document::end() & noexcep return {}; } simdjson_really_inline simdjson_result 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 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 diff --git a/include/simdjson/generic/ondemand/document.h b/include/simdjson/generic/ondemand/document.h index 44847c1a1..ec4455a5a 100644 --- a/include/simdjson/generic/ondemand/document.h +++ b/include/simdjson/generic/ondemand/document.h @@ -230,10 +230,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_root() const noexcept; - // // Fields // @@ -261,10 +260,7 @@ struct simdjson_result : 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 &&a) noexcept = default; - simdjson_really_inline ~simdjson_result() noexcept = default; ///< @private simdjson_really_inline simdjson_result get_array() & noexcept; simdjson_really_inline simdjson_result get_object() & noexcept; diff --git a/include/simdjson/generic/ondemand/json_iterator-inl.h b/include/simdjson/generic/ondemand/json_iterator-inl.h index 49bac01db..c61925e51 100644 --- a/include/simdjson/generic/ondemand/json_iterator-inl.h +++ b/include/simdjson/generic/ondemand/json_iterator-inl.h @@ -91,7 +91,11 @@ simdjson_warn_unused simdjson_really_inline error_code json_iterator::skip_child } simdjson_really_inline bool json_iterator::at_root() const noexcept { - return token.index == parser->dom_parser.structural_indexes.get(); + return token.checkpoint() == root_checkpoint(); +} + +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 { diff --git a/include/simdjson/generic/ondemand/json_iterator.h b/include/simdjson/generic/ondemand/json_iterator.h index 9be042676..8d4c4da35 100644 --- a/include/simdjson/generic/ondemand/json_iterator.h +++ b/include/simdjson/generic/ondemand/json_iterator.h @@ -62,6 +62,11 @@ public: */ 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 */ @@ -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 &&a) noexcept = default; - simdjson_really_inline ~simdjson_result() noexcept = default; ///< @private }; } // namespace simdjson diff --git a/include/simdjson/generic/ondemand/object-inl.h b/include/simdjson/generic/ondemand/object-inl.h index 94b08c541..e6a268969 100644 --- a/include/simdjson/generic/ondemand/object-inl.h +++ b/include/simdjson/generic/ondemand/object-inl.h @@ -71,9 +71,12 @@ 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, false }; +} -simdjson_really_inline object::object(const value_iterator &_iter) noexcept - : iter{_iter} +simdjson_really_inline object::object(const value_iterator &_iter, bool _at_start) noexcept + : iter{_iter, _at_start} { } diff --git a/include/simdjson/generic/ondemand/object.h b/include/simdjson/generic/ondemand/object.h index 8138e84c1..c685408d3 100644 --- a/include/simdjson/generic/ondemand/object.h +++ b/include/simdjson/generic/ondemand/object.h @@ -49,7 +49,8 @@ protected: static simdjson_really_inline simdjson_result start(value_iterator &iter) noexcept; static simdjson_really_inline simdjson_result 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, bool at_start = true) noexcept; simdjson_warn_unused simdjson_really_inline error_code find_field_raw(const std::string_view key) noexcept; diff --git a/include/simdjson/generic/ondemand/object_iterator-inl.h b/include/simdjson/generic/ondemand/object_iterator-inl.h index d1e725d03..6bca42369 100644 --- a/include/simdjson/generic/ondemand/object_iterator-inl.h +++ b/include/simdjson/generic/ondemand/object_iterator-inl.h @@ -6,9 +6,9 @@ namespace ondemand { // object_iterator // -simdjson_really_inline object_iterator::object_iterator(const value_iterator &_iter) noexcept +simdjson_really_inline object_iterator::object_iterator(const value_iterator &_iter, bool _at_start) noexcept : iter{_iter}, - at_start{true} + at_start{_at_start} {} simdjson_really_inline simdjson_result object_iterator::operator*() noexcept { diff --git a/include/simdjson/generic/ondemand/object_iterator.h b/include/simdjson/generic/ondemand/object_iterator.h index 20d90ceab..719e0ef9d 100644 --- a/include/simdjson/generic/ondemand/object_iterator.h +++ b/include/simdjson/generic/ondemand/object_iterator.h @@ -52,7 +52,7 @@ private: */ bool at_start{}; - simdjson_really_inline object_iterator(const value_iterator &iter) noexcept; + simdjson_really_inline object_iterator(const value_iterator &iter, bool at_start = true) noexcept; friend struct simdjson_result; friend class object; }; diff --git a/include/simdjson/generic/ondemand/parser.h b/include/simdjson/generic/ondemand/parser.h index 95470daa1..e9af08891 100644 --- a/include/simdjson/generic/ondemand/parser.h +++ b/include/simdjson/generic/ondemand/parser.h @@ -130,10 +130,7 @@ struct simdjson_result : 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 &&a) noexcept = default; - simdjson_really_inline ~simdjson_result() noexcept = default; ///< @private }; } // namespace simdjson diff --git a/include/simdjson/generic/ondemand/raw_json_string.h b/include/simdjson/generic/ondemand/raw_json_string.h index bfe0ec7e8..c553e642e 100644 --- a/include/simdjson/generic/ondemand/raw_json_string.h +++ b/include/simdjson/generic/ondemand/raw_json_string.h @@ -109,9 +109,7 @@ struct simdjson_result : 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 &a) noexcept = default; simdjson_really_inline ~simdjson_result() noexcept = default; ///< @private simdjson_really_inline simdjson_result raw() const noexcept; diff --git a/include/simdjson/generic/ondemand/token_iterator.h b/include/simdjson/generic/ondemand/token_iterator.h index 286d3d7d6..86e0fcdd7 100644 --- a/include/simdjson/generic/ondemand/token_iterator.h +++ b/include/simdjson/generic/ondemand/token_iterator.h @@ -97,9 +97,7 @@ struct simdjson_result : 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 &&a) noexcept = default; simdjson_really_inline ~simdjson_result() noexcept = default; ///< @private }; diff --git a/include/simdjson/generic/ondemand/value_iterator-inl.h b/include/simdjson/generic/ondemand/value_iterator-inl.h index 0c0258745..4e5cc52bb 100644 --- a/include/simdjson/generic/ondemand/value_iterator-inl.h +++ b/include/simdjson/generic/ondemand/value_iterator-inl.h @@ -80,7 +80,6 @@ simdjson_warn_unused simdjson_really_inline simdjson_result value_iterator } simdjson_warn_unused simdjson_really_inline simdjson_result value_iterator::field_key() noexcept { - logger::log_event(*this, "hi"); assert_at_child(); const uint8_t *key = _json_iter->advance(); diff --git a/include/simdjson/generic/ondemand/value_iterator.h b/include/simdjson/generic/ondemand/value_iterator.h index 066bfd877..5fac3a006 100644 --- a/include/simdjson/generic/ondemand/value_iterator.h +++ b/include/simdjson/generic/ondemand/value_iterator.h @@ -23,7 +23,11 @@ protected: json_iterator *_json_iter{}; /** The depth of this value */ depth_t _depth{}; - /** The starting token index for this value */ + /** + * 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: diff --git a/tests/ondemand/CMakeLists.txt b/tests/ondemand/CMakeLists.txt index 27167b94d..1cc501fba 100644 --- a/tests/ondemand/CMakeLists.txt +++ b/tests/ondemand/CMakeLists.txt @@ -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() diff --git a/tests/ondemand/ondemand_assert_out_of_order_values.cpp b/tests/ondemand/ondemand_assert_out_of_order_values.cpp new file mode 100644 index 000000000..9abac4c4f --- /dev/null +++ b/tests/ondemand/ondemand_assert_out_of_order_values.cpp @@ -0,0 +1,46 @@ +#include +#include +#include +#include +#include +#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 xval, simdjson_result 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 main(void) { + pid_t pid = fork(); + if (pid == -1) { std::cerr << "fork failed" << std::endl; return 1; } + if (pid) { + // Parent - wait child and interpret its result + int status = 0; + wait(&status); + if(!WIFSIGNALED(status)) { + std::cerr << "Expected program to abort, but it exited successfully with status " << status << std::endl; + return 1; + } + return 0; // Signal-terminated means success + } else { + auto json = R"( + { + "x": 1, + "y": 2 3 + )"_padded; + ondemand::parser parser; + auto doc = parser.iterate(json); + return check_point(doc["x"], doc["y"]); + } +} diff --git a/tests/ondemand/ondemand_basictests.cpp b/tests/ondemand/ondemand_basictests.cpp index 8634c067e..86ea4e5a2 100644 --- a/tests/ondemand/ondemand_basictests.cpp +++ b/tests/ondemand/ondemand_basictests.cpp @@ -887,6 +887,116 @@ namespace dom_api_tests { return true; })); + + SUBTEST("simdjson_result", 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", test_ondemand_doc(json, [&](auto doc_result) { - ASSERT_EQUAL( doc_result.get_object()["a"].get_uint64().first, 1 ); + simdjson_result 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", 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();