diff --git a/.appveyor.yml b/.appveyor.yml index b12050c33..59299e7d6 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -2,28 +2,33 @@ version: '{build}' branches: only: - master -image: - - Visual Studio 2017 clone_folder: c:\projects\simdjson - -platform: -- x64 - +platform: x64 +image: + - Visual Studio 2019 + - Visual Studio 2017 +configuration: Release environment: matrix: - - SIMDJSON_BUILD_STATIC: "OFF" - THREADS: "ON" - - SIMDJSON_BUILD_STATIC: "OFF" - THREADS: "OFF" - - SIMDJSON_BUILD_STATIC: "ON" - THREADS: "ON" -# - SIMDJSON_BUILD_STATIC: "ON" -# THREADS: "OFF" - + - SIMDJSON_BUILD_STATIC: ON + SIMDJSON_ENABLE_THREADS: OFF + - SIMDJSON_BUILD_STATIC: OFF + SIMDJSON_ENABLE_THREADS: ON + build_script: + - set - mkdir build - cd build - - ps: cmake -DSIMDJSON_BUILD_STATIC="$env:SIMDJSON_BUILD_STATIC" -DSIMDJSON_ENABLE_THREADS="$env:THREADS" -DCMAKE_BUILD_TYPE=Release -DCMAKE_GENERATOR_PLATFORM=x64 -DSIMDJSON_GOOGLE_BENCHMARKS=OFF .. - - cmake --build . - - ctest --verbose --output-on-failure + - cmake -DSIMDJSON_BUILD_STATIC=%SIMDJSON_BUILD_STATIC% -DSIMDJSON_ENABLE_THREADS=%SIMDJSON_ENABLE_THREADS% -DCMAKE_BUILD_TYPE=%Configuration% -DCMAKE_GENERATOR_PLATFORM=x64 -DSIMDJSON_GOOGLE_BENCHMARKS=OFF .. + - cmake --build . --config %Configuration% +test_script: + - ctest --verbose --output-on-failure -C %Configuration% + +matrix: + fast_finish: true + exclude: + # Don't build all variants on 2019, just running it to make sure readme_tests succeed + - image: Visual Studio 2019 + SIMDJSON_BUILD_STATIC: ON + SIMDJSON_ENABLE_THREADS: OFF diff --git a/.circleci/config.yml b/.circleci/config.yml index 2eed29a37..332f0a297 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -59,7 +59,7 @@ commands: - run: make all - run: make test - cmake_test: # this version builds, install, test and then verifyi from the installation + cmake_test: # this version builds, install, test and then verify from the installation steps: - run: apt-get update -qq - run: apt-get install -y cmake diff --git a/.gitignore b/.gitignore index 250dd4d66..5dfa3ec6d 100644 --- a/.gitignore +++ b/.gitignore @@ -121,15 +121,17 @@ objs /singleheader/demo /tests/basictests /tests/errortests -/tests/jsoncheck -/tests/pointercheck /tests/integer_tests +/tests/jsoncheck +/tests/numberparsingcheck +/tests/pointercheck /tests/parse_many_test /tests/readme_examples /tests/readme_examples11 /tests/readme_examples_noexceptions /tests/readme_examples_noexceptions11 /tests/staticchecks +/tests/stringparsingcheck /tools/json2json /tools/jsonstats /tools/minify diff --git a/CMakeLists.txt b/CMakeLists.txt index 1e25a3da3..b294297e8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,6 @@ cmake_minimum_required(VERSION 3.9) # CMP0069 NEW +message(STATUS "cmake version ${CMAKE_VERSION}") if (NOT CMAKE_BUILD_TYPE) message(STATUS "No build type selected, default to Release") set(CMAKE_BUILD_TYPE Release CACHE STRING "Choose the type of build." FORCE) @@ -24,7 +25,6 @@ set(CMAKE_MACOSX_RPATH OFF) set(CMAKE_THREAD_PREFER_PTHREAD ON) set(THREADS_PREFER_PTHREAD_FLAG ON) -set(SIMDJSON_LIB_NAME simdjson) set(PROJECT_VERSION_MAJOR 0) set(PROJECT_VERSION_MINOR 3) set(PROJECT_VERSION_PATCH 1) @@ -43,25 +43,28 @@ endif() option(SIMDJSON_SANITIZE "Sanitize addresses" OFF) option(SIMDJSON_GOOGLE_BENCHMARKS "compile the Google Benchmark benchmarks" OFF) option(SIMDJSON_ENABLE_THREADS "enable threaded operation" ON) -option(SIMDJSON_EXCEPTIONS "Enable simdjson's exception-throwing interface" ON) +option(SIMDJSON_NO_EXCEPTIONS "Disable simdjson's exception-throwing interface" OFF) set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/tools/cmake") -find_package(CTargets) find_package(Options) -# We used to have install(DIRECTORY include/${SIMDJSON_LIB_NAME} DESTINATION include) -# alone. -# However, this fails because we also need the root level simdjson.h file. -install(DIRECTORY include/${SIMDJSON_LIB_NAME} DESTINATION include) -install(FILES include/${SIMDJSON_LIB_NAME}.h DESTINATION include) -set (TEST_DATA_DIR "${CMAKE_CURRENT_SOURCE_DIR}/jsonchecker/") -set (BENCHMARK_DATA_DIR "${CMAKE_CURRENT_SOURCE_DIR}/jsonexamples/") -add_definitions(-DSIMDJSON_TEST_DATA_DIR="${TEST_DATA_DIR}") -add_definitions(-DSIMDJSON_BENCHMARK_DATA_DIR="${TEST_DATA_DIR}") -enable_testing() -include(include/CMakeLists.txt) +# +# Create the top level simdjson library (must be done at this level to use both src/ and include/ +# directories) +# +add_subdirectory(windows) +add_subdirectory(include) add_subdirectory(src) + +# +# Compile tools / tests / benchmarks +# +add_definitions(-DSIMDJSON_TEST_DATA_DIR="${CMAKE_CURRENT_SOURCE_DIR}/jsonchecker/") +add_definitions(-DSIMDJSON_BENCHMARK_DATA_DIR="${CMAKE_CURRENT_SOURCE_DIR}/jsonexamples/") + +enable_testing() + add_subdirectory(tools) add_subdirectory(tests) add_subdirectory(benchmark) diff --git a/benchmark/CMakeLists.txt b/benchmark/CMakeLists.txt index 3e4f95f9a..a9be18072 100644 --- a/benchmark/CMakeLists.txt +++ b/benchmark/CMakeLists.txt @@ -1,21 +1,14 @@ -target_include_directories(${SIMDJSON_LIB_NAME} - INTERFACE - $ - $ -) - -add_cpp_benchmark(parse) -add_cpp_benchmark(statisticalmodel) -add_cpp_benchmark(parse_stream) -add_cpp_benchmark(get_corpus_benchmark) +include_directories( . linux ) +link_libraries(simdjson) +add_executable(parse parse.cpp) +add_executable(statisticalmodel statisticalmodel.cpp) +add_executable(parse_stream parse_stream.cpp) +add_executable(get_corpus_benchmark get_corpus_benchmark.cpp) add_executable(perfdiff perfdiff.cpp) # Google Benchmarks if (SIMDJSON_GOOGLE_BENCHMARKS) - add_cpp_benchmark(bench_parse_call) - target_link_libraries(bench_parse_call benchmark::benchmark) - - add_cpp_benchmark(bench_dom_api) - target_link_libraries(bench_dom_api benchmark::benchmark) - target_compile_definitions(bench_dom_api PRIVATE JSON_TEST_PATH="${PROJECT_SOURCE_DIR}/jsonexamples/twitter.json") + link_libraries(benchmark::benchmark) + add_executable(bench_parse_call bench_parse_call.cpp) + add_executable(bench_dom_api bench_dom_api.cpp) endif() \ No newline at end of file diff --git a/benchmark/bench_dom_api.cpp b/benchmark/bench_dom_api.cpp index f9494fc51..297fdc093 100644 --- a/benchmark/bench_dom_api.cpp +++ b/benchmark/bench_dom_api.cpp @@ -6,18 +6,16 @@ using namespace simdjson; using namespace benchmark; using namespace std; -#ifndef JSON_TEST_PATH -#define JSON_TEST_PATH "jsonexamples/twitter.json" -#endif - const padded_string EMPTY_ARRAY("[]", 2); +const char *TWITTER_JSON = SIMDJSON_BENCHMARK_DATA_DIR ""; + #if SIMDJSON_EXCEPTIONS static void twitter_count(State& state) { // Prints the number of results in twitter.json dom::parser parser; - dom::element doc = parser.load(JSON_TEST_PATH); + dom::element doc = parser.load(TWITTER_JSON); for (auto _ : state) { uint64_t result_count = doc["search_metadata"]["count"]; if (result_count != 100) { return; } @@ -29,7 +27,7 @@ SIMDJSON_PUSH_DISABLE_WARNINGS SIMDJSON_DISABLE_DEPRECATED_WARNING static void iterator_twitter_count(State& state) { // Prints the number of results in twitter.json - padded_string json = padded_string::load(JSON_TEST_PATH); + padded_string json = padded_string::load(TWITTER_JSON); ParsedJson pj = build_parsed_json(json); for (auto _ : state) { ParsedJson::Iterator iter(pj); @@ -48,7 +46,7 @@ SIMDJSON_POP_DISABLE_WARNINGS static void twitter_default_profile(State& state) { // Count unique users with a default profile. dom::parser parser; - dom::element doc = parser.load(JSON_TEST_PATH); + dom::element doc = parser.load(TWITTER_JSON); for (auto _ : state) { set default_users; for (dom::object tweet : doc["statuses"].get()) { @@ -65,7 +63,7 @@ BENCHMARK(twitter_default_profile); static void twitter_image_sizes(State& state) { // Count unique image sizes dom::parser parser; - dom::element doc = parser.load(JSON_TEST_PATH); + dom::element doc = parser.load(TWITTER_JSON); for (auto _ : state) { set> image_sizes; for (dom::object tweet : doc["statuses"].get()) { @@ -88,7 +86,7 @@ BENCHMARK(twitter_image_sizes); static void error_code_twitter_count(State& state) noexcept { // Prints the number of results in twitter.json dom::parser parser; - dom::element doc = parser.load(JSON_TEST_PATH); + dom::element doc = parser.load(TWITTER_JSON); for (auto _ : state) { auto [value, error] = doc["search_metadata"]["count"].get(); if (error) { return; } @@ -100,7 +98,7 @@ BENCHMARK(error_code_twitter_count); static void error_code_twitter_default_profile(State& state) noexcept { // Count unique users with a default profile. dom::parser parser; - dom::element doc = parser.load(JSON_TEST_PATH); + dom::element doc = parser.load(TWITTER_JSON); for (auto _ : state) { set default_users; @@ -127,7 +125,7 @@ SIMDJSON_PUSH_DISABLE_WARNINGS SIMDJSON_DISABLE_DEPRECATED_WARNING static void iterator_twitter_default_profile(State& state) { // Count unique users with a default profile. - padded_string json = padded_string::load(JSON_TEST_PATH); + padded_string json = padded_string::load(TWITTER_JSON); ParsedJson pj = build_parsed_json(json); for (auto _ : state) { set default_users; @@ -167,7 +165,7 @@ BENCHMARK(iterator_twitter_default_profile); static void error_code_twitter_image_sizes(State& state) noexcept { // Count unique image sizes dom::parser parser; - dom::element doc = parser.load(JSON_TEST_PATH); + dom::element doc = parser.load(TWITTER_JSON); for (auto _ : state) { set> image_sizes; auto [statuses, error] = doc["statuses"].get(); @@ -196,7 +194,7 @@ SIMDJSON_PUSH_DISABLE_WARNINGS SIMDJSON_DISABLE_DEPRECATED_WARNING static void iterator_twitter_image_sizes(State& state) { // Count unique image sizes - padded_string json = padded_string::load(JSON_TEST_PATH); + padded_string json = padded_string::load(TWITTER_JSON); ParsedJson pj = build_parsed_json(json); for (auto _ : state) { set> image_sizes; @@ -254,7 +252,7 @@ BENCHMARK(iterator_twitter_image_sizes); static void print_json(State& state) noexcept { // Prints the number of results in twitter.json - padded_string json = get_corpus(JSON_TEST_PATH); + padded_string json = get_corpus(TWITTER_JSON); dom::parser parser; if (int error = json_parse(json, parser); error != SUCCESS) { cerr << error_message(error) << endl; return; } for (auto _ : state) { diff --git a/fuzz/CMakeLists.txt b/fuzz/CMakeLists.txt index d30c38a4c..1a31d3b38 100644 --- a/fuzz/CMakeLists.txt +++ b/fuzz/CMakeLists.txt @@ -44,7 +44,7 @@ macro(implement_fuzzer sourcefile) if (SIMDJSON_FUZZ_LINKMAIN) target_sources(${name} PRIVATE main.cpp) endif () - target_link_libraries(${name} PRIVATE ${SIMDJSON_LIB_NAME}) + target_link_libraries(${name} PRIVATE simdjson) if (SIMDJSON_FUZZ_LDFLAGS) target_link_libraries(${name} PRIVATE ${SIMDJSON_FUZZ_LDFLAGS}) endif () diff --git a/include/CMakeLists.txt b/include/CMakeLists.txt index 657a7052e..7e06d9821 100644 --- a/include/CMakeLists.txt +++ b/include/CMakeLists.txt @@ -1,25 +1,2 @@ -set(SIMDJSON_INCLUDE_DIR ${PROJECT_SOURCE_DIR}/include) -set(SIMDJSON_INCLUDE - ${SIMDJSON_INCLUDE_DIR}/simdjson.h - ${SIMDJSON_INCLUDE_DIR}/simdjson/common_defs.h - ${SIMDJSON_INCLUDE_DIR}/simdjson/compiler_check.h - ${SIMDJSON_INCLUDE_DIR}/simdjson/document_stream.h - ${SIMDJSON_INCLUDE_DIR}/simdjson/document.h - ${SIMDJSON_INCLUDE_DIR}/simdjson/error.h - ${SIMDJSON_INCLUDE_DIR}/simdjson/implementation.h - ${SIMDJSON_INCLUDE_DIR}/simdjson/inline/document_stream.h - ${SIMDJSON_INCLUDE_DIR}/simdjson/inline/document.h - ${SIMDJSON_INCLUDE_DIR}/simdjson/inline/error.h - ${SIMDJSON_INCLUDE_DIR}/simdjson/inline/padded_string.h - ${SIMDJSON_INCLUDE_DIR}/simdjson/inline/parsedjson_iterator.h - ${SIMDJSON_INCLUDE_DIR}/simdjson/internal/jsonformatutils.h - ${SIMDJSON_INCLUDE_DIR}/simdjson/jsonioutil.h - ${SIMDJSON_INCLUDE_DIR}/simdjson/jsonparser.h - ${SIMDJSON_INCLUDE_DIR}/simdjson/nonstd/string_view.hpp - ${SIMDJSON_INCLUDE_DIR}/simdjson/padded_string.h - ${SIMDJSON_INCLUDE_DIR}/simdjson/parsedjson.h - ${SIMDJSON_INCLUDE_DIR}/simdjson/parsedjson_iterator.h - ${SIMDJSON_INCLUDE_DIR}/simdjson/portability.h - ${SIMDJSON_INCLUDE_DIR}/simdjson/simdjson_version.h - ${SIMDJSON_INCLUDE_DIR}/simdjson/simdjson.h -) \ No newline at end of file +install(DIRECTORY simdjson DESTINATION include FILES_MATCHING PATTERN *.h) +install(FILES simdjson.h DESTINATION include) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 239091a04..70270fbea 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,132 +1,70 @@ -if(${CMAKE_C_COMPILER_ID} MATCHES "Intel") # icc / icpc - # prevent shared libraries from depending on Intel provided libraries - set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -static-intel") -endif() - include(GNUInstallDirs) -# we default on a shared library. if(SIMDJSON_BUILD_STATIC) - set(SIMDJSON_LIB_TYPE STATIC) MESSAGE( STATUS "Building a static library." ) + add_library(simdjson STATIC "") else() - MESSAGE( STATUS "Building a dynamic library (default)." ) - set(SIMDJSON_LIB_TYPE SHARED) + MESSAGE( STATUS "Building a dynamic library." ) + add_library(simdjson SHARED "") endif() -MESSAGE( STATUS "SIMDJSON_LIB_TYPE: " ${SIMDJSON_LIB_TYPE}) +target_sources(simdjson PRIVATE simdjson.cpp) +target_include_directories(simdjson PRIVATE .) +target_include_directories(simdjson PUBLIC $) -# Bring in include files -include(../include/CMakeLists.txt) +if(SIMDJSON_NO_EXCEPTIONS) + message(STATUS "simdjson exception interface turned off. Code that does not check error codes will not compile.") + target_compile_definitions(simdjson PUBLIC SIMDJSON_EXCEPTIONS=0) +endif() -set(SIMDJSON_SRC_DIR $) +if(${CMAKE_C_COMPILER_ID} MATCHES "Intel") # icc / icpc + # prevent shared libraries from depending on Intel provided libraries + target_link_options(simdjson PUBLIC "-static-intel") +endif() -set(SIMDJSON_SRC - simdjson.cpp -) +if(SIMDJSON_ENABLE_THREADS) + find_package(Threads REQUIRED) + target_link_libraries(simdjson PRIVATE Threads::Threads) +endif() -# Load headers and sources -set(SIMDJSON_SRC_HEADERS - error.cpp - implementation.cpp - isadetection.h - simdprune_tables.h - stage1_find_marks.cpp - stage2_build_tape.cpp - arm64/bitmanipulation.h - arm64/bitmask.h - arm64/implementation.h - arm64/intrinsics.h - arm64/numberparsing.h - arm64/simd.h - arm64/stage1_find_marks.h - arm64/stage2_build_tape.h - arm64/stringparsing.h - fallback/implementation.h - fallback/stage1_find_marks.h - fallback/stage2_build_tape.h - generic/atomparsing.h - generic/json_scanner.h - generic/json_string_scanner.h - generic/json_structural_indexer.h - generic/numberparsing.h - generic/stage2_build_tape.h - generic/stage2_streaming_build_tape.h - generic/stringparsing.h - generic/utf8_fastvalidate_algorithm.h - generic/utf8_lookup_algorithm.h - generic/utf8_lookup2_algorithm.h - generic/utf8_range_algorithm.h - generic/utf8_zwegner_algorithm.h - haswell/bitmanipulation.h - haswell/bitmask.h - haswell/implementation.h - haswell/intrinsics.h - haswell/numberparsing.h - haswell/simd.h - haswell/stage1_find_marks.h - haswell/stage2_build_tape.h - haswell/stringparsing.h - document_parser_callbacks.h - westmere/bitmanipulation.h - westmere/bitmask.h - westmere/implementation.h - westmere/intrinsics.h - westmere/numberparsing.h - westmere/simd.h - westmere/stage1_find_marks.h - westmere/stage2_build_tape.h - westmere/stringparsing.h -) -set_source_files_properties(${SIMDJSON_SRC_HEADERS} PROPERTIES HEADER_FILE_ONLY TRUE) +# For targets that want to include the source directly +add_library(simdjson-source INTERFACE) +target_include_directories(simdjson-source INTERFACE .) +target_include_directories(simdjson-source INTERFACE $) -add_library(${SIMDJSON_LIB_NAME} ${SIMDJSON_LIB_TYPE} ${SIMDJSON_SRC} ${SIMDJSON_INCLUDE} ${SIMDJSON_SRC_HEADERS}) +# Installation -target_include_directories(${SIMDJSON_LIB_NAME} - PUBLIC - $ - $ - $ -) - -install(TARGETS ${SIMDJSON_LIB_NAME} - EXPORT ${SIMDJSON_LIB_NAME}-config +install(TARGETS simdjson + EXPORT simdjson-config ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} ) -install(EXPORT ${SIMDJSON_LIB_NAME}-config - FILE ${SIMDJSON_LIB_NAME}-config.cmake - NAMESPACE ${SIMDJSON_LIB_NAME}:: - DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${SIMDJSON_LIB_NAME} +install(EXPORT simdjson-config + FILE simdjson-config.cmake + NAMESPACE simdjson:: + DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/simdjson ) if(NOT MSVC) ## We output the library at the root of the current directory where cmake is invoked ## This is handy but Visual Studio will happily ignore us -set_target_properties(${SIMDJSON_LIB_NAME} PROPERTIES - LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR} - VERSION ${SIMDJSON_LIB_VERSION} - SOVERSION ${SIMDJSON_LIB_SOVERSION}) +set_target_properties(simdjson PROPERTIES + LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) MESSAGE( STATUS "Library output directory (does not apply to Visual Studio): " ${CMAKE_BINARY_DIR}) endif() -if((SIMDJSON_LIB_TYPE STREQUAL "SHARED")) - target_compile_definitions(${SIMDJSON_LIB_NAME} INTERFACE SIMDJSON_USING_LIBRARY=1) +if(NOT SIMDJSON_BUILD_STATIC) + target_compile_definitions(simdjson INTERFACE SIMDJSON_USING_LIBRARY=1) endif() -if(MSVC AND (SIMDJSON_LIB_TYPE STREQUAL "SHARED")) +if(MSVC AND (NOT SIMDJSON_BUILD_STATIC)) if (CMAKE_VERSION VERSION_LESS 3.4) - MESSAGE( STATUS "To build a Windows DLL using Visual Studio, you may need cmake 3.4 or better." ) + MESSAGE( STATUS "To build a Windows DLL using Visual Studio, you may need cmake 3.4 or better." ) endif() MESSAGE( STATUS "Building a Windows DLL using Visual Studio, exporting all symbols automatically." ) - set_target_properties(${SIMDJSON_LIB_NAME} + set_target_properties(simdjson PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS 1) endif() -if(SIMDJSON_ENABLE_THREADS) - find_package(Threads REQUIRED) - target_link_libraries( ${SIMDJSON_LIB_NAME} Threads::Threads) -endif() - diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index fa2c524eb..2587d9af8 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1,31 +1,57 @@ -if(MSVC) - target_include_directories(${SIMDJSON_LIB_NAME} - INTERFACE $ - ) +# Helper so we don't have to repeat ourselves so much +function(add_cpp_test TEST_NAME TEST_FILE) + add_executable(${TEST_NAME} ${TEST_FILE}) + add_test(${TEST_NAME} ${TEST_NAME}) +endfunction(add_cpp_test) + +# Sets a target to only build when you run the test, and expect failure +function(add_compile_test TEST_NAME TEST_FILE EXPECT_SUCCESS) + add_executable(${TEST_NAME} ${TEST_FILE}) + set_target_properties(${TEST_NAME} PROPERTIES + EXCLUDE_FROM_ALL TRUE + EXCLUDE_FROM_DEFAULT_BUILD TRUE) + add_test(NAME ${TEST_NAME} + COMMAND ${CMAKE_COMMAND} --build . --target ${TEST_NAME} --config $ + WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) + if(NOT ${EXPECT_SUCCESS}) + set_tests_properties(${TEST_NAME} PROPERTIES WILL_FAIL TRUE) + endif() +endfunction(add_compile_test) + +# +# These test explicitly do #include "simdjson.cpp" +# +if (NOT MSVC) # Can't get simdjson-source to compile on Windows for some reason. + add_cpp_test(numberparsingcheck numberparsingcheck.cpp) + target_link_libraries(numberparsingcheck simdjson-source simdjson-windows-headers) + add_cpp_test(stringparsingcheck stringparsingcheck.cpp) + target_link_libraries(stringparsingcheck simdjson-source simdjson-windows-headers) endif() -add_cpp_test(basictests) -add_cpp_test(errortests) +# +# All remaining tests link with simdjson proper +# +link_libraries(simdjson) -## Next bit should not be needed! -#if(CMAKE_INTERPROCEDURAL_OPTIMIZATION) -# next line is a workaround for an odr-violation in basictests regarding the globals 0x432a40 and 0x52045c under clang -#set_tests_properties(basictests PROPERTIES -# ENVIRONMENT ASAN_OPTIONS="detect_odr_violation=0") -#endif() +# add_executable(allparserscheckfile allparserscheckfile.cpp) +add_cpp_test(basictests basictests.cpp) +add_cpp_test(errortests errortests.cpp) +add_cpp_test(integer_tests integer_tests.cpp) +add_cpp_test(jsoncheck jsoncheck.cpp) +target_link_libraries(jsoncheck simdjson-windows-headers) +add_cpp_test(parse_many_test parse_many_test.cpp) +target_link_libraries(parse_many_test simdjson-windows-headers) +add_cpp_test(pointercheck pointercheck.cpp) -add_cpp_test(jsoncheck) -add_cpp_test(parse_many_test) -add_cpp_test(pointercheck) -add_cpp_test(integer_tests) - -target_compile_definitions(basictests PRIVATE JSON_TEST_PATH="${PROJECT_SOURCE_DIR}/jsonexamples/twitter.json" NDJSON_TEST_PATH="${PROJECT_SOURCE_DIR}/jsonexamples/amazon_cellphones.ndjson") -target_compile_definitions(errortests PRIVATE JSON_TEST_PATH="${PROJECT_SOURCE_DIR}/jsonexamples/twitter.json") - -## This causes problems -# add_executable(singleheader ./singleheadertest.cpp ${PROJECT_SOURCE_DIR}/singleheader/simdjson.cpp) -# target_link_libraries(singleheader ${SIMDJSON_LIB_NAME}) -# add_test(singleheader singleheader) +# Compile-only tests +# Don't add the tests if we're on VS2017 or older; they don't succeed. +if(NOT (MSVC AND MSVC_VERSION LESS 1920)) + add_compile_test(readme_examples readme_examples.cpp TRUE) + # Test that readme_examples does NOT compile when SIMDJSON_EXCEPTIONS=0 (i.e. test that the define + # works even if exceptions are on) + add_compile_test(readme_examples_will_fail_with_exceptions_off readme_examples.cpp FALSE) + target_compile_definitions(readme_examples_will_fail_with_exceptions_off PRIVATE SIMDJSON_EXCEPTIONS=0) +endif() if(MSVC) add_custom_command(TARGET basictests POST_BUILD # Adds a post-build event @@ -36,3 +62,14 @@ if(MSVC) "$") # <--this is out-file path endif() +## Next bit should not be needed! +#if(CMAKE_INTERPROCEDURAL_OPTIMIZATION) +# next line is a workaround for an odr-violation in basictests regarding the globals 0x432a40 and 0x52045c under clang +#set_tests_properties(basictests PROPERTIES +# ENVIRONMENT ASAN_OPTIONS="detect_odr_violation=0") +#endif() + +## This causes problems +# add_executable(singleheader ./singleheadertest.cpp ${PROJECT_SOURCE_DIR}/singleheader/simdjson.cpp) +# target_link_libraries(singleheader simdjson) +# add_test(singleheader singleheader) diff --git a/tests/basictests.cpp b/tests/basictests.cpp index a8f218936..1fbf0e481 100644 --- a/tests/basictests.cpp +++ b/tests/basictests.cpp @@ -17,12 +17,11 @@ #include "simdjson.h" -#ifndef JSON_TEST_PATH -#define JSON_TEST_PATH "jsonexamples/twitter.json" -#endif -#ifndef NDJSON_TEST_PATH -#define NDJSON_TEST_PATH "jsonexamples/amazon_cellphones.ndjson" +#ifndef SIMDJSON_BENCHMARK_DATA_DIR +#define SIMDJSON_BENCHMARK_DATA_DIR "jsonexamples/" #endif +const char *TWITTER_JSON = SIMDJSON_BENCHMARK_DATA_DIR "twitter.json"; +const char *AMAZON_CELLPHONES_NDJSON = SIMDJSON_BENCHMARK_DATA_DIR "amazon_cellphones.ndjson"; #define ASSERT_EQUAL(ACTUAL, EXPECTED) if ((ACTUAL) != (EXPECTED)) { std::cerr << "Expected " << #ACTUAL << " to be " << (EXPECTED) << ", got " << (ACTUAL) << " instead!" << std::endl; return false; } #define ASSERT_TRUE(ACTUAL) ASSERT_EQUAL(ACTUAL, true) @@ -493,18 +492,18 @@ namespace parse_api_tests { // } bool parser_load() { - std::cout << "Running " << __func__ << std::endl; + std::cout << "Running " << __func__ << " on " << TWITTER_JSON << std::endl; dom::parser parser; - auto [doc, error] = parser.load(JSON_TEST_PATH); + auto [doc, error] = parser.load(TWITTER_JSON); if (error) { cerr << error << endl; return false; } if (!doc.is()) { cerr << "Document did not parse as an object" << endl; return false; } return true; } bool parser_load_many() { - std::cout << "Running " << __func__ << std::endl; + std::cout << "Running " << __func__ << " on " << AMAZON_CELLPHONES_NDJSON << std::endl; dom::parser parser; int count = 0; - for (auto [doc, error] : parser.load_many(NDJSON_TEST_PATH)) { + for (auto [doc, error] : parser.load_many(AMAZON_CELLPHONES_NDJSON)) { if (error) { cerr << error << endl; return false; } if (!doc.is()) { cerr << "Document did not parse as an array" << endl; return false; } count++; @@ -537,7 +536,7 @@ namespace parse_api_tests { bool parser_load_exception() { std::cout << "Running " << __func__ << std::endl; dom::parser parser; - const element doc = parser.load(JSON_TEST_PATH); + const element doc = parser.load(TWITTER_JSON); if (!doc.is()) { cerr << "Document did not parse as an object" << endl; return false; } return true; } @@ -545,7 +544,7 @@ namespace parse_api_tests { std::cout << "Running " << __func__ << std::endl; dom::parser parser; int count = 0; - for (const element doc : parser.load_many(NDJSON_TEST_PATH)) { + for (const element doc : parser.load_many(AMAZON_CELLPHONES_NDJSON)) { if (!doc.is()) { cerr << "Document did not parse as an array" << endl; return false; } count++; } @@ -869,7 +868,7 @@ namespace dom_api_tests { std::cout << "Running " << __func__ << std::endl; // Prints the number of results in twitter.json dom::parser parser; - auto [result_count, error] = parser.load(JSON_TEST_PATH)["search_metadata"]["count"].get(); + auto [result_count, error] = parser.load(TWITTER_JSON)["search_metadata"]["count"].get(); if (error) { cerr << "Error: " << error << endl; return false; } if (result_count != 100) { cerr << "Expected twitter.json[metadata_count][count] = 100, got " << result_count << endl; return false; } return true; @@ -880,7 +879,7 @@ namespace dom_api_tests { // Print users with a default profile. set default_users; dom::parser parser; - auto [tweets, error] = parser.load(JSON_TEST_PATH)["statuses"].get(); + auto [tweets, error] = parser.load(TWITTER_JSON)["statuses"].get(); if (error) { cerr << "Error: " << error << endl; return false; } for (auto tweet : tweets) { object user; @@ -905,7 +904,7 @@ namespace dom_api_tests { // Print image names and sizes set> image_sizes; dom::parser parser; - auto [tweets, error] = parser.load(JSON_TEST_PATH)["statuses"].get(); + auto [tweets, error] = parser.load(TWITTER_JSON)["statuses"].get(); if (error) { cerr << "Error: " << error << endl; return false; } for (auto tweet : tweets) { auto [media, not_found] = tweet["entities"]["media"].get(); @@ -1043,7 +1042,7 @@ namespace dom_api_tests { std::cout << "Running " << __func__ << std::endl; // Prints the number of results in twitter.json dom::parser parser; - element doc = parser.load(JSON_TEST_PATH); + element doc = parser.load(TWITTER_JSON); uint64_t result_count = doc["search_metadata"]["count"]; if (result_count != 100) { cerr << "Expected twitter.json[metadata_count][count] = 100, got " << result_count << endl; return false; } return true; @@ -1054,7 +1053,7 @@ namespace dom_api_tests { // Print users with a default profile. set default_users; dom::parser parser; - element doc = parser.load(JSON_TEST_PATH); + element doc = parser.load(TWITTER_JSON); for (object tweet : doc["statuses"].get()) { object user = tweet["user"]; if (user["default_profile"]) { @@ -1070,7 +1069,7 @@ namespace dom_api_tests { // Print image names and sizes set> image_sizes; dom::parser parser; - element doc = parser.load(JSON_TEST_PATH); + element doc = parser.load(TWITTER_JSON); for (object tweet : doc["statuses"].get()) { auto [media, not_found] = tweet["entities"]["media"]; if (!not_found) { diff --git a/tests/errortests.cpp b/tests/errortests.cpp index 74788b2bb..525e7b119 100644 --- a/tests/errortests.cpp +++ b/tests/errortests.cpp @@ -14,9 +14,10 @@ using namespace simdjson; using namespace std; -#ifndef JSON_TEST_PATH -#define JSON_TEST_PATH "jsonexamples/twitter.json" +#ifndef SIMDJSON_BENCHMARK_DATA_DIR +#define SIMDJSON_BENCHMARK_DATA_DIR "jsonexamples/" #endif +const char *TWITTER_JSON = SIMDJSON_BENCHMARK_DATA_DIR "twitter.json"; #define TEST_START() { cout << "Running " << __func__ << " ..." << endl; } #define ASSERT_ERROR(ACTUAL, EXPECTED) if ((ACTUAL) != (EXPECTED)) { cerr << "FAIL: Unexpected error \"" << (ACTUAL) << "\" (expected \"" << (EXPECTED) << "\")" << endl; return false; } @@ -27,14 +28,14 @@ namespace parser_load { bool parser_load_capacity() { TEST_START(); dom::parser parser(1); // 1 byte max capacity - auto [doc, error] = parser.load(JSON_TEST_PATH); + auto [doc, error] = parser.load(TWITTER_JSON); ASSERT_ERROR(error, CAPACITY); TEST_SUCCEED(); } bool parser_load_many_capacity() { TEST_START(); dom::parser parser(1); // 1 byte max capacity - for (auto [doc, error] : parser.load_many(JSON_TEST_PATH)) { + for (auto [doc, error] : parser.load_many(TWITTER_JSON)) { ASSERT_ERROR(error, CAPACITY); TEST_SUCCEED(); } diff --git a/tests/singleheadertest.cpp b/tests/singleheadertest.cpp index 07ee12fc3..b2d0051d8 100644 --- a/tests/singleheadertest.cpp +++ b/tests/singleheadertest.cpp @@ -5,7 +5,7 @@ using namespace simdjson; int main() { - const char *filename = JSON_TEST_PATH; + const char *filename = SIMDJSON_BENCHMARK_DATA_DIR "/twitter.json"; padded_string p = get_corpus(filename); dom::parser parser; auto [doc, error] = parser.parse(p); diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index f6eb247ed..b952a7f19 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -1,3 +1,6 @@ -add_cpp_tool(json2json) -add_cpp_tool(jsonstats) -add_cpp_tool(minify) +link_libraries(simdjson) +link_libraries(simdjson-windows-headers) + +add_executable(json2json json2json.cpp) +add_executable(jsonstats jsonstats.cpp) +add_executable(minify minify.cpp) diff --git a/tools/cmake/FindCTargets.cmake b/tools/cmake/FindCTargets.cmake deleted file mode 100644 index 3d7f569e7..000000000 --- a/tools/cmake/FindCTargets.cmake +++ /dev/null @@ -1,15 +0,0 @@ -function(add_cpp_test TEST_NAME) - add_executable(${TEST_NAME} ${TEST_NAME}.cpp) - target_link_libraries(${TEST_NAME} ${SIMDJSON_LIB_NAME}) - add_test(${TEST_NAME} ${TEST_NAME}) -endfunction(add_cpp_test) - -function(add_cpp_benchmark BENCH_NAME) - add_executable(${BENCH_NAME} ${BENCH_NAME}.cpp) - target_link_libraries(${BENCH_NAME} ${SIMDJSON_LIB_NAME}) -endfunction(add_cpp_benchmark) - -function(add_cpp_tool TOOL_NAME) - add_executable(${TOOL_NAME} ${TOOL_NAME}.cpp) - target_link_libraries(${TOOL_NAME} ${SIMDJSON_LIB_NAME}) -endfunction(add_cpp_tool) diff --git a/tools/cmake/FindOptions.cmake b/tools/cmake/FindOptions.cmake index b1ad85aaf..50e89692e 100644 --- a/tools/cmake/FindOptions.cmake +++ b/tools/cmake/FindOptions.cmake @@ -18,13 +18,6 @@ else () set (X64 FALSE) endif () -if(SIMDJSON_EXCEPTIONS) - set(OPT_FLAGS "${OPT_FLAGS} -DSIMDJSON_EXCEPTIONS=1") -else() - message(STATUS "simdjson exception interface turned off. Code that does not check error codes will not compile.") - set(OPT_FLAGS "${OPT_FLAGS} -DSIMDJSON_EXCEPTIONS=0") -endif() - if(MSVC) set(CXXSTD_FLAGS "/std:c++17") else() diff --git a/windows/CMakeLists.txt b/windows/CMakeLists.txt new file mode 100644 index 000000000..49f28664b --- /dev/null +++ b/windows/CMakeLists.txt @@ -0,0 +1,4 @@ +add_library(simdjson-windows-headers INTERFACE) +if(MSVC) + target_include_directories(simdjson-windows-headers INTERFACE .) +endif() \ No newline at end of file