mirror of
https://github.com/simdjson/simdjson
synced 2026-06-08 17:27:07 +00:00
Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 6a37fc1871 | |||
| c6c29c2827 | |||
| 941e903f28 |
+6
-6
@@ -15,29 +15,29 @@ environment:
|
||||
- job_name: VS2019
|
||||
CMAKE_ARGS: -A %Platform%
|
||||
- job_name: VS2019ARM
|
||||
CMAKE_ARGS: -A ARM64 -DSIMDJSON_DEVELOPER_MODE=ON -DCMAKE_CROSSCOMPILING=1 -D SIMDJSON_GOOGLE_BENCHMARKS=OFF # Does Google Benchmark builds under VS ARM?
|
||||
CMAKE_ARGS: -A ARM64 -DCMAKE_CROSSCOMPILING=1 -D SIMDJSON_GOOGLE_BENCHMARKS=OFF # Does Google Benchmark builds under VS ARM?
|
||||
- job_name: VS2017 (Static, No Threads)
|
||||
image: Visual Studio 2017
|
||||
CMAKE_ARGS: -A %Platform% -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF -DSIMDJSON_ENABLE_THREADS=OFF
|
||||
CMAKE_ARGS: -A %Platform% -DSIMDJSON_BUILD_STATIC=ON -DSIMDJSON_ENABLE_THREADS=OFF
|
||||
CTEST_ARGS: -LE explicitonly
|
||||
- job_name: VS2019 (Win32)
|
||||
platform: Win32
|
||||
CMAKE_ARGS: -A %Platform% -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=ON -DSIMDJSON_ENABLE_THREADS=ON # This should be the default. Testing anyway.
|
||||
CMAKE_ARGS: -A %Platform% -DSIMDJSON_BUILD_STATIC=OFF -DSIMDJSON_ENABLE_THREADS=ON # This should be the default. Testing anyway.
|
||||
CTEST_ARGS: -LE explicitonly
|
||||
- job_name: VS2019 (Win32, No Exceptions)
|
||||
platform: Win32
|
||||
CMAKE_ARGS: -A %Platform% -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=ON -DSIMDJSON_ENABLE_THREADS=ON -DSIMDJSON_EXCEPTIONS=OFF
|
||||
CMAKE_ARGS: -A %Platform% -DSIMDJSON_BUILD_STATIC=OFF -DSIMDJSON_ENABLE_THREADS=ON -DSIMDJSON_EXCEPTIONS=OFF
|
||||
CTEST_ARGS: -LE explicitonly
|
||||
- job_name: VS2015
|
||||
image: Visual Studio 2015
|
||||
CMAKE_ARGS: -A %Platform% -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF -DSIMDJSON_ENABLE_THREADS=OFF
|
||||
CMAKE_ARGS: -A %Platform% -DSIMDJSON_BUILD_STATIC=ON -DSIMDJSON_ENABLE_THREADS=OFF
|
||||
CTEST_ARGS: -LE explicitonly
|
||||
|
||||
build_script:
|
||||
- mkdir build
|
||||
- cd build
|
||||
- cmake --version
|
||||
- cmake %CMAKE_ARGS% ..
|
||||
- cmake %CMAKE_ARGS% --parallel ..
|
||||
- cmake -LH ..
|
||||
- cmake --build . --config %Configuration% --verbose --parallel
|
||||
|
||||
|
||||
+27
-35
@@ -1,7 +1,7 @@
|
||||
version: 2.1
|
||||
|
||||
|
||||
# We constantly run out of memory so please do not use parallelism (-j, -j4).
|
||||
# We constantly run out of memory so please do not use parallelism (-j, -j4).
|
||||
|
||||
# Reusable image / compiler definitions
|
||||
executors:
|
||||
@@ -11,7 +11,7 @@ executors:
|
||||
environment:
|
||||
CXX: g++-8
|
||||
CC: gcc-8
|
||||
CMAKE_BUILD_FLAGS:
|
||||
BUILD_FLAGS:
|
||||
CTEST_FLAGS: --output-on-failure
|
||||
|
||||
gcc9:
|
||||
@@ -20,7 +20,7 @@ executors:
|
||||
environment:
|
||||
CXX: g++-9
|
||||
CC: gcc-9
|
||||
CMAKE_BUILD_FLAGS:
|
||||
BUILD_FLAGS:
|
||||
CTEST_FLAGS: --output-on-failure
|
||||
|
||||
gcc10:
|
||||
@@ -29,7 +29,7 @@ executors:
|
||||
environment:
|
||||
CXX: g++-10
|
||||
CC: gcc-10
|
||||
CMAKE_BUILD_FLAGS:
|
||||
BUILD_FLAGS:
|
||||
CTEST_FLAGS: --output-on-failure
|
||||
|
||||
clang10:
|
||||
@@ -38,7 +38,7 @@ executors:
|
||||
environment:
|
||||
CXX: clang++-10
|
||||
CC: clang-10
|
||||
CMAKE_BUILD_FLAGS:
|
||||
BUILD_FLAGS:
|
||||
CTEST_FLAGS: --output-on-failure
|
||||
|
||||
clang9:
|
||||
@@ -47,8 +47,8 @@ executors:
|
||||
environment:
|
||||
CXX: clang++-9
|
||||
CC: clang-9
|
||||
CMAKE_BUILD_FLAGS:
|
||||
CTEST_FLAGS: --output-on-failure
|
||||
BUILD_FLAGS:
|
||||
CTEST_FLAGS: --output-on-failure
|
||||
|
||||
clang6:
|
||||
docker:
|
||||
@@ -56,7 +56,7 @@ executors:
|
||||
environment:
|
||||
CXX: clang++-6.0
|
||||
CC: clang-6.0
|
||||
CMAKE_BUILD_FLAGS:
|
||||
BUILD_FLAGS:
|
||||
CTEST_FLAGS: --output-on-failure
|
||||
|
||||
# Reusable test commands (and initializer for clang 6)
|
||||
@@ -88,13 +88,13 @@ commands:
|
||||
steps:
|
||||
- cmake_prep
|
||||
- dependency_restore
|
||||
- run: cmake -DSIMDJSON_DEVELOPER_MODE=ON $CMAKE_FLAGS -DCMAKE_INSTALL_PREFIX:PATH=destination -B build .
|
||||
- run: cmake $CMAKE_FLAGS -DCMAKE_INSTALL_PREFIX:PATH=destination -B build .
|
||||
- dependency_cache # dependencies are produced in the configure step
|
||||
|
||||
cmake_build:
|
||||
steps:
|
||||
- cmake_build_cache
|
||||
- run: cmake --build build
|
||||
- run: cmake --build build
|
||||
|
||||
cmake_test:
|
||||
steps:
|
||||
@@ -129,8 +129,8 @@ commands:
|
||||
steps:
|
||||
- cmake_build_cache
|
||||
- run: |
|
||||
cmake -DSIMDJSON_ENABLE_DOM_CHECKPERF=ON --build build --target checkperf &&
|
||||
cd build &&
|
||||
cmake --build build --target checkperf &&
|
||||
cd build &&
|
||||
ctest --output-on-failure -R checkperf
|
||||
|
||||
# we not only want cmake to build and run tests, but we want also a successful installation from which we can build, link and run programs
|
||||
@@ -164,68 +164,60 @@ jobs:
|
||||
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
|
||||
environment: { CMAKE_FLAGS: -DSIMDJSON_GOOGLE_BENCHMARKS=OFF -DBUILD_SHARED_LIBS=OFF }
|
||||
environment: { CMAKE_FLAGS: -DSIMDJSON_GOOGLE_BENCHMARKS=OFF -DSIMDJSON_BUILD_STATIC=ON }
|
||||
steps: [ cmake_perftest ]
|
||||
gcc10:
|
||||
description: Build and run tests on GCC 10 and AVX 2 with a cmake static build
|
||||
executor: gcc10
|
||||
environment: { CMAKE_FLAGS: -DSIMDJSON_GOOGLE_BENCHMARKS=ON -DBUILD_SHARED_LIBS=OFF }
|
||||
environment: { CMAKE_FLAGS: -DSIMDJSON_GOOGLE_BENCHMARKS=ON -DSIMDJSON_BUILD_STATIC=ON }
|
||||
steps: [ cmake_test, cmake_install_test, cmake_installed_test_cxx20 ]
|
||||
clang6:
|
||||
description: Build and run tests on clang 6 and AVX 2 with a cmake static build
|
||||
executor: clang6
|
||||
environment: { CMAKE_FLAGS: -DSIMDJSON_GOOGLE_BENCHMARKS=ON -DBUILD_SHARED_LIBS=OFF }
|
||||
environment: { CMAKE_FLAGS: -DSIMDJSON_GOOGLE_BENCHMARKS=ON -DSIMDJSON_BUILD_STATIC=ON }
|
||||
steps: [ cmake_test, cmake_install_test ]
|
||||
clang10:
|
||||
description: Build and run tests on clang 10 and AVX 2 with a cmake static build
|
||||
executor: clang10
|
||||
environment: { CMAKE_FLAGS: -DSIMDJSON_GOOGLE_BENCHMARKS=ON -DBUILD_SHARED_LIBS=OFF }
|
||||
environment: { CMAKE_FLAGS: -DSIMDJSON_GOOGLE_BENCHMARKS=ON -DSIMDJSON_BUILD_STATIC=ON }
|
||||
steps: [ cmake_test, cmake_install_test, cmake_installed_test_cxx20 ]
|
||||
# libcpp
|
||||
libcpp-clang10:
|
||||
description: Build and run tests on clang 10 and AVX 2 with a cmake static build and libc++
|
||||
executor: clang10
|
||||
environment: { CMAKE_FLAGS: -DSIMDJSON_USE_LIBCPP=ON -DBUILD_SHARED_LIBS=OFF }
|
||||
environment: { CMAKE_FLAGS: -DSIMDJSON_USE_LIBCPP=ON -DSIMDJSON_BUILD_STATIC=ON }
|
||||
steps: [ cmake_test, cmake_install_test, cmake_installed_test_cxx20 ]
|
||||
# sanitize
|
||||
sanitize-gcc10:
|
||||
description: Build and run tests on GCC 10 and AVX 2 with a cmake sanitize build
|
||||
executor: gcc10
|
||||
environment: { CMAKE_FLAGS: -DCMAKE_BUILD_TYPE=Debug -DBUILD_SHARED_LIBS=ON -DSIMDJSON_SANITIZE=ON, CTEST_FLAGS: --output-on-failure -LE explicitonly }
|
||||
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: -DBUILD_SHARED_LIBS=ON -DSIMDJSON_NO_FORCE_INLINING=ON -DSIMDJSON_SANITIZE=ON, CTEST_FLAGS: --output-on-failure -LE explicitonly }
|
||||
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: -DBUILD_SHARED_LIBS=ON -DSIMDJSON_SANITIZE_THREADS=ON, CTEST_FLAGS: --output-on-failure -LE explicitonly }
|
||||
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: -DBUILD_SHARED_LIBS=ON -DSIMDJSON_NO_FORCE_INLINING=ON -DSIMDJSON_SANITIZE_THREADS=ON, CTEST_FLAGS: --output-on-failure -LE explicitonly }
|
||||
steps: [ cmake_test ]
|
||||
nocheckeof-clang10:
|
||||
description: Validate that when __SIMDJSON_CHECK_EOF=0, everything still succeeds
|
||||
environment:
|
||||
CXXFLAGS: -D__SIMDJSON_CHECK_EOF=0
|
||||
CMAKE_BUILD_FLAGS: --target ondemand_tests
|
||||
CTEST_FLAGS: --output-on-failure -R ondemand_
|
||||
executor: clang10
|
||||
environment: { CMAKE_FLAGS: -DSIMDJSON_BUILD_STATIC=OFF -DSIMDJSON_SANITIZE_THREADS=ON, CTEST_FLAGS: --output-on-failure -LE explicitonly }
|
||||
steps: [ cmake_test ]
|
||||
# dynamic
|
||||
dynamic-gcc10:
|
||||
description: Build and run tests on GCC 10 and AVX 2 with a cmake dynamic build
|
||||
executor: gcc10
|
||||
environment: { CMAKE_FLAGS: -DBUILD_SHARED_LIBS=ON }
|
||||
environment: { CMAKE_FLAGS: -DSIMDJSON_BUILD_STATIC=OFF }
|
||||
steps: [ cmake_test, cmake_install_test ]
|
||||
dynamic-clang10:
|
||||
description: Build and run tests on clang 10 and AVX 2 with a cmake dynamic build
|
||||
executor: clang10
|
||||
environment: { CMAKE_FLAGS: -DBUILD_SHARED_LIBS=ON }
|
||||
environment: { CMAKE_FLAGS: -DSIMDJSON_BUILD_STATIC=OFF }
|
||||
steps: [ cmake_test, cmake_install_test ]
|
||||
|
||||
# unthreaded
|
||||
@@ -270,12 +262,12 @@ jobs:
|
||||
sanitize-haswell-gcc10:
|
||||
description: Build and run tests on GCC 10 and AVX 2 with a cmake sanitize build
|
||||
executor: gcc10
|
||||
environment: { CXXFLAGS: -march=haswell, CMAKE_FLAGS: -DCMAKE_BUILD_TYPE=Debug -DBUILD_SHARED_LIBS=ON -DSIMDJSON_SANITIZE=ON, CTEST_FLAGS: --output-on-failure -LE explicitonly }
|
||||
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: -DBUILD_SHARED_LIBS=ON -DSIMDJSON_NO_FORCE_INLINING=ON -DSIMDJSON_SANITIZE=ON, CTEST_FLAGS: --output-on-failure -LE explicitonly }
|
||||
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,7 +284,7 @@ workflows:
|
||||
- libcpp-clang10
|
||||
|
||||
# full single-implementation tests
|
||||
# - sanitize-gcc10 # gcc10 + sanitize uses a lot of memory?
|
||||
- sanitize-gcc10
|
||||
- sanitize-clang10
|
||||
- threadsanitize-gcc10
|
||||
- threadsanitize-clang10
|
||||
@@ -311,7 +303,7 @@ workflows:
|
||||
|
||||
|
||||
# sanitized single-implementation tests
|
||||
# - sanitize-haswell-gcc10 # gcc10 + sanitize uses a lot of memory?
|
||||
- sanitize-haswell-gcc10
|
||||
- sanitize-haswell-clang10
|
||||
|
||||
# testing "just the library"
|
||||
|
||||
+2
-2
@@ -19,8 +19,8 @@ task:
|
||||
build_script:
|
||||
- mkdir build
|
||||
- cd build
|
||||
- cmake -DSIMDJSON_BASH=OFF -DSIMDJSON_DEVELOPER_MODE=ON -DSIMDJSON_GIT=OFF ..
|
||||
- cmake --build .
|
||||
- cmake -DSIMDJSON_BASH=OFF -DSIMDJSON_GIT=OFF ..
|
||||
- make
|
||||
test_script:
|
||||
- cd build
|
||||
- ctest --output-on-failure -LE explicitonly
|
||||
|
||||
+25
-25
@@ -8,8 +8,8 @@ steps:
|
||||
CC: gcc
|
||||
CXX: g++
|
||||
BUILD_FLAGS: -- -j
|
||||
CMAKE_FLAGS: -DBUILD_SHARED_LIBS=OFF -DSIMDJSON_DEVELOPER_MODE=ON
|
||||
CTEST_FLAGS: -j4 --output-on-failure -LE explicitonly
|
||||
CMAKE_FLAGS: -DSIMDJSON_BUILD_STATIC=ON
|
||||
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
|
||||
@@ -17,7 +17,7 @@ steps:
|
||||
- cd build
|
||||
- cmake $CMAKE_FLAGS ..
|
||||
- cmake --build . $BUILD_FLAGS
|
||||
- ctest $CTEST_FLAGS
|
||||
- ctest $CTEST_FLAGS
|
||||
---
|
||||
kind: pipeline
|
||||
name: i386-clang # we do not support 32-bit systems, but we run tests
|
||||
@@ -29,8 +29,8 @@ steps:
|
||||
CC: clang-6.0
|
||||
CXX: clang++-6.0
|
||||
BUILD_FLAGS: -- -j
|
||||
CMAKE_FLAGS: -DBUILD_SHARED_LIBS=OFF -DSIMDJSON_DEVELOPER_MODE=ON
|
||||
CTEST_FLAGS: -j4 --output-on-failure -LE explicitonly
|
||||
CMAKE_FLAGS: -DSIMDJSON_BUILD_STATIC=ON
|
||||
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
|
||||
@@ -38,7 +38,7 @@ steps:
|
||||
- cd build
|
||||
- cmake $CMAKE_FLAGS ..
|
||||
- cmake --build . $BUILD_FLAGS
|
||||
- ctest $CTEST_FLAGS
|
||||
- ctest $CTEST_FLAGS
|
||||
---
|
||||
kind: pipeline
|
||||
name: gcc9
|
||||
@@ -50,7 +50,7 @@ steps:
|
||||
CC: gcc
|
||||
CXX: g++
|
||||
BUILD_FLAGS: -- -j
|
||||
CMAKE_FLAGS: -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF -DSIMDJSON_IMPLEMENTATION=haswell;westmere;fallback
|
||||
CMAKE_FLAGS: -DSIMDJSON_BUILD_STATIC=ON -DSIMDJSON_IMPLEMENTATION=haswell;westmere;fallback
|
||||
CTEST_FLAGS: -j4 --output-on-failure -LE explicitonly
|
||||
commands:
|
||||
- echo "deb http://deb.debian.org/debian buster-backports main" >> /etc/apt/sources.list
|
||||
@@ -77,7 +77,7 @@ steps:
|
||||
CC: clang-6.0
|
||||
CXX: clang++-6.0
|
||||
BUILD_FLAGS: -- -j
|
||||
CMAKE_FLAGS: -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF -DSIMDJSON_IMPLEMENTATION=haswell;westmere;fallback
|
||||
CMAKE_FLAGS: -DSIMDJSON_BUILD_STATIC=ON -DSIMDJSON_IMPLEMENTATION=haswell;westmere;fallback
|
||||
CTEST_FLAGS: -j4 --output-on-failure -LE explicitonly
|
||||
commands:
|
||||
- mkdir build
|
||||
@@ -100,7 +100,7 @@ steps:
|
||||
CC: gcc
|
||||
CXX: g++
|
||||
BUILD_FLAGS: -- -j
|
||||
CMAKE_FLAGS: -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=ON
|
||||
CMAKE_FLAGS: -DSIMDJSON_BUILD_STATIC=OFF
|
||||
CTEST_FLAGS: -j4 --output-on-failure -LE explicitonly
|
||||
commands:
|
||||
- echo "deb http://deb.debian.org/debian buster-backports main" >> /etc/apt/sources.list
|
||||
@@ -122,7 +122,7 @@ steps:
|
||||
environment:
|
||||
CC: clang-9
|
||||
CXX: clang++-9
|
||||
CMAKE_FLAGS: -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=ON
|
||||
CMAKE_FLAGS: -DSIMDJSON_BUILD_STATIC=OFF
|
||||
BUILD_FLAGS: -- -j
|
||||
CTEST_FLAGS: -j4 --output-on-failure -LE explicitonly
|
||||
commands:
|
||||
@@ -142,7 +142,7 @@ steps:
|
||||
CC: gcc
|
||||
CXX: g++
|
||||
BUILD_FLAGS: -- -j
|
||||
CMAKE_FLAGS: -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF -DSIMDJSON_IMPLEMENTATION=haswell;westmere;fallback
|
||||
CMAKE_FLAGS: -DSIMDJSON_BUILD_STATIC=ON -DSIMDJSON_IMPLEMENTATION=haswell;westmere;fallback
|
||||
CTEST_FLAGS: -j4 --output-on-failure -LE explicitonly
|
||||
commands:
|
||||
- echo "deb http://deb.debian.org/debian buster-backports main" >> /etc/apt/sources.list
|
||||
@@ -168,7 +168,7 @@ steps:
|
||||
environment:
|
||||
CC: clang-9
|
||||
CXX: clang++-9
|
||||
CMAKE_FLAGS: -DSIMDJSON_DEVELOPER_MODE=ON -DSIMDJSON_NO_FORCE_INLINING=ON -DSIMDJSON_SANITIZE=ON -DSIMDJSON_IMPLEMENTATION=haswell;westmere;fallback
|
||||
CMAKE_FLAGS: -DSIMDJSON_SANITIZE=ON -DSIMDJSON_IMPLEMENTATION=haswell;westmere;fallback
|
||||
BUILD_FLAGS: -- -j
|
||||
CTEST_FLAGS: -j4 --output-on-failure -LE explicitonly
|
||||
commands:
|
||||
@@ -192,7 +192,7 @@ steps:
|
||||
environment:
|
||||
CC: clang-11
|
||||
CXX: clang++-11
|
||||
CMAKE_FLAGS: -DSIMDJSON_DEVELOPER_MODE=ON -GNinja
|
||||
CMAKE_FLAGS: -GNinja
|
||||
BUILD_FLAGS:
|
||||
CTEST_FLAGS: -j4 --output-on-failure -LE explicitonly
|
||||
CXXFLAGS: -std=c++20 -stdlib=libc++
|
||||
@@ -213,7 +213,7 @@ steps:
|
||||
CC: gcc
|
||||
CXX: g++
|
||||
BUILD_FLAGS: -- -j
|
||||
CMAKE_FLAGS: -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF -DSIMDJSON_IMPLEMENTATION=arm64;fallback
|
||||
CMAKE_FLAGS: -DSIMDJSON_BUILD_STATIC=ON -DSIMDJSON_IMPLEMENTATION=arm64;fallback
|
||||
CTEST_FLAGS: -j4 --output-on-failure -LE explicitonly
|
||||
commands:
|
||||
- echo "deb http://deb.debian.org/debian buster-backports main" >> /etc/apt/sources.list
|
||||
@@ -237,7 +237,7 @@ steps:
|
||||
environment:
|
||||
CC: clang-6.0
|
||||
CXX: clang++-6.0
|
||||
CMAKE_FLAGS: -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=ON
|
||||
CMAKE_FLAGS: -DSIMDJSON_BUILD_STATIC=OFF
|
||||
BUILD_FLAGS: -- -j
|
||||
CTEST_FLAGS: -j4 --output-on-failure -LE explicitonly
|
||||
commands:
|
||||
@@ -260,7 +260,7 @@ steps:
|
||||
CC: gcc
|
||||
CXX: g++
|
||||
BUILD_FLAGS: -- -j
|
||||
CMAKE_FLAGS: -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=ON
|
||||
CMAKE_FLAGS: -DSIMDJSON_BUILD_STATIC=OFF
|
||||
CTEST_FLAGS: -j4 --output-on-failure -LE explicitonly
|
||||
commands:
|
||||
- echo "deb http://deb.debian.org/debian buster-backports main" >> /etc/apt/sources.list
|
||||
@@ -281,7 +281,7 @@ steps:
|
||||
environment:
|
||||
CC: clang-6.0
|
||||
CXX: clang++-6.0
|
||||
CMAKE_FLAGS: -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=ON
|
||||
CMAKE_FLAGS: -DSIMDJSON_BUILD_STATIC=OFF
|
||||
BUILD_FLAGS: -- -j
|
||||
CTEST_FLAGS: -j4 --output-on-failure -LE explicitonly
|
||||
commands:
|
||||
@@ -302,7 +302,7 @@ steps:
|
||||
image: gcc:8
|
||||
environment:
|
||||
BUILD_FLAGS: -- -j
|
||||
CMAKE_FLAGS: -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF -DSIMDJSON_IMPLEMENTATION=arm64;fallback
|
||||
CMAKE_FLAGS: -DSIMDJSON_BUILD_STATIC=ON -DSIMDJSON_IMPLEMENTATION=arm64;fallback
|
||||
CTEST_FLAGS: -j4 --output-on-failure -LE explicitonly
|
||||
CC: gcc
|
||||
CXX: g++
|
||||
@@ -329,7 +329,7 @@ steps:
|
||||
environment:
|
||||
CC: clang-6.0
|
||||
CXX: clang++-6.0
|
||||
CMAKE_FLAGS: -DSIMDJSON_DEVELOPER_MODE=ON -DSIMDJSON_NO_FORCE_INLINING=ON -DSIMDJSON_SANITIZE=ON -DSIMDJSON_IMPLEMENTATION=arm64;fallback
|
||||
CMAKE_FLAGS: -DSIMDJSON_SANITIZE=ON -DSIMDJSON_IMPLEMENTATION=arm64;fallback
|
||||
BUILD_FLAGS: -- -j
|
||||
CTEST_FLAGS: -j4 --output-on-failure -LE explicitonly
|
||||
commands:
|
||||
@@ -356,7 +356,7 @@ steps:
|
||||
CC: clang-9
|
||||
CXX: clang++-9
|
||||
BUILD_FLAGS: -- -j 4
|
||||
CMAKE_FLAGS: -DSIMDJSON_DEVELOPER_MODE=ON -GNinja -DBUILD_SHARED_LIBS=OFF
|
||||
CMAKE_FLAGS: -GNinja -DSIMDJSON_BUILD_STATIC=ON
|
||||
CTEST_FLAGS: -j4 --output-on-failure -LE explicitonly
|
||||
CXXFLAGS: -stdlib=libc++
|
||||
commands:
|
||||
@@ -377,7 +377,7 @@ steps:
|
||||
CC: clang-9
|
||||
CXX: clang++-9
|
||||
BUILD_FLAGS: -- -j
|
||||
CMAKE_FLAGS: -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF
|
||||
CMAKE_FLAGS: -DSIMDJSON_BUILD_STATIC=ON
|
||||
CTEST_FLAGS: -j4 --output-on-failure -LE explicitonly
|
||||
CXXFLAGS: -stdlib=libc++
|
||||
commands:
|
||||
@@ -398,7 +398,7 @@ steps:
|
||||
CC: clang-7
|
||||
CXX: clang++-7
|
||||
BUILD_FLAGS: -- -j
|
||||
CMAKE_FLAGS: -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF
|
||||
CMAKE_FLAGS: -DSIMDJSON_BUILD_STATIC=ON
|
||||
CTEST_FLAGS: -j4 --output-on-failure -LE explicitonly
|
||||
CXXFLAGS: -stdlib=libc++
|
||||
commands:
|
||||
@@ -418,7 +418,7 @@ steps:
|
||||
CC: gcc
|
||||
CXX: g++
|
||||
BUILD_FLAGS: -- -j
|
||||
CMAKE_FLAGS: -DSIMDJSON_DEVELOPER_MODE=ON -DSIMDJSON_EXCEPTIONS=OFF
|
||||
CMAKE_FLAGS: -DSIMDJSON_EXCEPTIONS=OFF
|
||||
CTEST_FLAGS: -j4 --output-on-failure -LE explicitonly
|
||||
commands:
|
||||
- echo "deb http://deb.debian.org/debian buster-backports main" >> /etc/apt/sources.list
|
||||
@@ -444,8 +444,8 @@ steps:
|
||||
commands:
|
||||
- apt-get -qq update
|
||||
- apt-get install -q -y clang cmake git wget zip ninja-build
|
||||
- wget -O corpus.tar.gz https://readonly:readonly@www.pauldreik.se/fuzzdata/index.php?project=simdjson
|
||||
- tar xf corpus.tar.gz && rm corpus.tar.gz
|
||||
- wget --quiet https://dl.bintray.com/pauldreik/simdjson-fuzz-corpus/corpus/corpus.tar
|
||||
- tar xf corpus.tar && rm corpus.tar
|
||||
- fuzz/build_like_ossfuzz.sh
|
||||
- mkdir -p common_out
|
||||
- for fuzzer in build/fuzz/fuzz_* ; do echo $fuzzer;$fuzzer common_out out/* -max_total_time=40; done
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@
|
||||
* text=auto
|
||||
|
||||
# we don't want json files to be modified for this project
|
||||
*.json binary diff=astextplain
|
||||
*.json binary
|
||||
|
||||
|
||||
# Common settings that generally should always be used with your language specific settings
|
||||
|
||||
@@ -18,34 +18,19 @@ Before submitting an issue, please ensure that you have read the documentation:
|
||||
**Describe the bug**
|
||||
A clear and concise description of what the bug is.
|
||||
|
||||
A compiler or static-analyzer warning is not a bug.
|
||||
|
||||
We are committed to providing good documentation. We accept the lack of documentation or a misleading documentation as a bug (a 'documentation bug').
|
||||
|
||||
We accept the identification of an issue by a sanitizer or some checker tool (e.g., valgrind) as a bug, but you must first ensure that it is not a false positive.
|
||||
|
||||
We recommend that you run your tests using different optimization levels.
|
||||
|
||||
Before reporting a bug, please ensure that you have read our documentation.
|
||||
Note that a compiler warning is not a bug.
|
||||
|
||||
**To Reproduce**
|
||||
Steps to reproduce the behaviour: provide a code sample if possible.
|
||||
|
||||
If we cannot reproduce the issue, then we cannot address it. Note that a stack trace from your own program is not enough. A sample of your source code is insufficient: please provide a complete test for us to reproduce the issue. Please reduce the issue: use as small and as simple an example of the bug as possible.
|
||||
If we cannot reproduce the issue, then we cannot address it.
|
||||
|
||||
It should be possible to trigger the bug by using solely simdjson with our default build setup. If you can only observe the bug within some specific context, with some other software, please reduce the issue first.
|
||||
Note that a stack trace from your own program is not enough.
|
||||
|
||||
**simjson release**
|
||||
|
||||
Unless you plan to contribute to simdjson, you should only work from releases. Please be mindful that our main branch may have additional features, bugs and documentation items.
|
||||
|
||||
It is fine to report bugs against our main branch, but if that is what you are doing, please be explicit.
|
||||
|
||||
**Configuration (please complete the following information if relevant)**
|
||||
**Configuration (please complete the following information if relevant):**
|
||||
- OS: [e.g. Ubuntu 16.04.6 LTS]
|
||||
- Compiler [e.g. Apple clang version 11.0.3 (clang-1103.0.32.59) x86_64-apple-darwin19.4.0]
|
||||
- Version [e.g. 22]
|
||||
- Optimization setting (e.g., -O3)
|
||||
|
||||
We support up-to-date 64-bit ARM and x64 FreeBSD, macOS, Windows and Linux systems. Please ensure that your configuration is supported before labelling the issue as a bug. In particular, we do not support legacy 32-bit systems.
|
||||
|
||||
|
||||
@@ -1,6 +1,12 @@
|
||||
name: Alpine Linux
|
||||
|
||||
on: [push, pull_request]
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
|
||||
jobs:
|
||||
ubuntu-build:
|
||||
@@ -25,7 +31,7 @@ jobs:
|
||||
./alpine.sh apk add build-base cmake g++ linux-headers git bash
|
||||
- name: cmake
|
||||
run: |
|
||||
./alpine.sh cmake -DSIMDJSON_DEVELOPER_MODE=ON -B build_for_alpine
|
||||
./alpine.sh cmake -B build_for_alpine
|
||||
- name: build
|
||||
run: |
|
||||
./alpine.sh cmake --build build_for_alpine
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
name: Detect trailing whitespace
|
||||
|
||||
on: [push, pull_request]
|
||||
on:
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
|
||||
jobs:
|
||||
whitespace:
|
||||
|
||||
@@ -44,18 +44,6 @@ jobs:
|
||||
path: dependencies/.cache
|
||||
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
||||
|
||||
- uses: actions/cache@v2
|
||||
id: cache-corpus
|
||||
with:
|
||||
path: out/
|
||||
key: corpus-${{ github.run_id }}
|
||||
restore-keys: corpus-
|
||||
|
||||
- name: show statistics for the cached corpus
|
||||
run: |
|
||||
echo number of files in github action corpus cache:
|
||||
find out -type f |wc -l
|
||||
|
||||
- name: Create and prepare the initial seed corpus
|
||||
run: |
|
||||
fuzz/build_corpus.sh
|
||||
@@ -63,6 +51,12 @@ jobs:
|
||||
mkdir seedcorpus
|
||||
unzip -q -d seedcorpus seed_corpus.zip
|
||||
|
||||
- name: Download the corpus from the last run
|
||||
run: |
|
||||
wget --quiet https://dl.bintray.com/pauldreik/simdjson-fuzz-corpus/corpus/corpus.tar
|
||||
tar xf corpus.tar
|
||||
rm corpus.tar
|
||||
|
||||
- name: List clang versions
|
||||
run: |
|
||||
ls /usr/bin/clang*
|
||||
@@ -76,7 +70,7 @@ jobs:
|
||||
run: |
|
||||
set -eux
|
||||
for fuzzer in $defaultimplfuzzers $implfuzzers; do
|
||||
mkdir -p out/$fuzzer # in case this is a new fuzzer, or the github action cached corpus is broken
|
||||
mkdir -p out/$fuzzer # in case this is a new fuzzer, or corpus.tar is broken
|
||||
# get input from everyone else (corpus cross pollination)
|
||||
others=$(find out -type d -not -name $fuzzer -not -name out -not -name cmin)
|
||||
build-fast/fuzz/fuzz_$fuzzer out/$fuzzer $others seedcorpus -max_total_time=30 $MAXLEN
|
||||
@@ -129,11 +123,6 @@ jobs:
|
||||
name: corpus
|
||||
path: corpus.tar
|
||||
|
||||
- name: Store the corpus externally
|
||||
run: |
|
||||
gzip --keep corpus.tar
|
||||
curl -F"filedata=@corpus.tar.gz" https://simdjson:${{ secrets.fuzzdatapassword }}@www.pauldreik.se/fuzzdata/index.php
|
||||
|
||||
# This takes a subset of the minimized corpus and run it through valgrind. It is slow,
|
||||
# therefore take a "random" subset. The random selection is accomplished by sorting on filenames,
|
||||
# which are hashes of the content.
|
||||
@@ -154,6 +143,15 @@ jobs:
|
||||
path: valgrind.tar
|
||||
if-no-files-found: ignore
|
||||
|
||||
- name: Upload the corpus and results to bintray if we are on master
|
||||
if: ${{ github.event_name == 'schedule' }}
|
||||
run: |
|
||||
echo uploading each artifact twice, otherwise it will not be published
|
||||
curl -T corpus.tar -upauldreik:${{ secrets.bintrayApiKey }} https://api.bintray.com/content/pauldreik/simdjson-fuzz-corpus/corpus/0/corpus/corpus.tar";publish=1;override=1"
|
||||
curl -T corpus.tar -upauldreik:${{ secrets.bintrayApiKey }} https://api.bintray.com/content/pauldreik/simdjson-fuzz-corpus/corpus/0/corpus/corpus.tar";publish=1;override=1"
|
||||
curl -T valgrind.tar -upauldreik:${{ secrets.bintrayApiKey }} https://api.bintray.com/content/pauldreik/simdjson-fuzz-corpus/corpus/0/corpus/valgrind.tar";publish=1;override=1"
|
||||
curl -T valgrind.tar -upauldreik:${{ secrets.bintrayApiKey }} https://api.bintray.com/content/pauldreik/simdjson-fuzz-corpus/corpus/0/corpus/valgrind.tar";publish=1;override=1"
|
||||
|
||||
- name: Archive any crashes as an artifact
|
||||
uses: actions/upload-artifact@v2
|
||||
if: always()
|
||||
|
||||
@@ -1,7 +1,12 @@
|
||||
name: MinGW32-CI
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
|
||||
# Important: scoop will either install 32-bit GCC or 64-bit GCC, not both.
|
||||
|
||||
@@ -17,7 +22,7 @@ jobs:
|
||||
runs-on: windows-2016
|
||||
|
||||
env:
|
||||
CMAKE_GENERATOR: Ninja # This is critical, try ' cmake -GNinja-DBUILD_SHARED_LIBS=OFF .. ' if using the command line
|
||||
CMAKE_GENERATOR: Ninja # This is critical, try ' cmake -GNinja-DSIMDJSON_BUILD_STATIC=ON .. ' if using the command line
|
||||
CC: gcc
|
||||
CXX: g++
|
||||
|
||||
@@ -42,7 +47,7 @@ jobs:
|
||||
run: |
|
||||
Invoke-Expression (New-Object System.Net.WebClient).DownloadString('https://get.scoop.sh')
|
||||
scoop install sudo --global
|
||||
sudo scoop install git --global
|
||||
sudo scoop install git --global
|
||||
sudo scoop install ninja --global
|
||||
sudo scoop install cmake --global
|
||||
sudo scoop install gcc --arch 32bit --global
|
||||
@@ -58,6 +63,6 @@ jobs:
|
||||
git --version
|
||||
mkdir build32
|
||||
cd build32
|
||||
cmake -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF -DSIMDJSON_COMPETITION=OFF -DSIMDJSON_GOOGLE_BENCHMARKS=OFF -DSIMDJSON_ENABLE_THREADS=OFF ..
|
||||
cmake -DSIMDJSON_BUILD_STATIC=ON -DSIMDJSON_COMPETITION=OFF -DSIMDJSON_GOOGLE_BENCHMARKS=OFF -DSIMDJSON_ENABLE_THREADS=OFF ..
|
||||
cmake --build . --target acceptance_tests --verbose
|
||||
ctest -L acceptance --output-on-failure
|
||||
|
||||
@@ -1,7 +1,12 @@
|
||||
name: MinGW64-CI
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
|
||||
# Important: scoop will either install 32-bit GCC or 64-bit GCC, not both.
|
||||
|
||||
@@ -17,7 +22,7 @@ jobs:
|
||||
runs-on: windows-2016
|
||||
|
||||
env:
|
||||
CMAKE_GENERATOR: Ninja # This is critical, try ' cmake -GNinja-DBUILD_SHARED_LIBS=OFF .. ' if using the command line
|
||||
CMAKE_GENERATOR: Ninja # This is critical, try ' cmake -GNinja-DSIMDJSON_BUILD_STATIC=ON .. ' if using the command line
|
||||
CC: gcc
|
||||
CXX: g++
|
||||
|
||||
@@ -58,12 +63,12 @@ jobs:
|
||||
git --version
|
||||
mkdir build64
|
||||
cd build64
|
||||
cmake -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF -DSIMDJSON_COMPETITION=OFF -DSIMDJSON_GOOGLE_BENCHMARKS=OFF -DSIMDJSON_ENABLE_THREADS=OFF ..
|
||||
cmake -DSIMDJSON_BUILD_STATIC=ON -DSIMDJSON_COMPETITION=OFF -DSIMDJSON_GOOGLE_BENCHMARKS=OFF -DSIMDJSON_ENABLE_THREADS=OFF ..
|
||||
cmake --build . --target acceptance_tests --verbose
|
||||
ctest -L acceptance --output-on-failure
|
||||
cd ..
|
||||
mkdir build64debug
|
||||
cd build64debug
|
||||
cmake -DSIMDJSON_DEVELOPER_MODE=ON -DCMAKE_BUILD_TYPE=Debug -DBUILD_SHARED_LIBS=OFF -DSIMDJSON_COMPETITION=OFF -DSIMDJSON_GOOGLE_BENCHMARKS=OFF -DSIMDJSON_ENABLE_THREADS=OFF ..
|
||||
cmake -DCMAKE_BUILD_TYPE=Debug -DSIMDJSON_BUILD_STATIC=ON -DSIMDJSON_COMPETITION=OFF -DSIMDJSON_GOOGLE_BENCHMARKS=OFF -DSIMDJSON_ENABLE_THREADS=OFF ..
|
||||
cmake --build . --target acceptance_tests --verbose
|
||||
ctest -L acceptance --output-on-failure
|
||||
|
||||
@@ -1,7 +1,12 @@
|
||||
name: MSYS2-CLANG-CI
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
|
||||
jobs:
|
||||
windows-mingw:
|
||||
@@ -15,16 +20,16 @@ jobs:
|
||||
matrix:
|
||||
include:
|
||||
- msystem: "MINGW64"
|
||||
install: mingw-w64-x86_64-libxml2 mingw-w64-x86_64-cmake mingw-w64-x86_64-ninja mingw-w64-x86_64-clang
|
||||
install: mingw-w64-x86_64-cmake mingw-w64-x86_64-ninja mingw-w64-x86_64-clang
|
||||
type: Release
|
||||
- msystem: "MINGW32"
|
||||
install: mingw-w64-i686-libxml2 mingw-w64-i686-cmake mingw-w64-i686-ninja mingw-w64-i686-clang
|
||||
install: mingw-w64-i686-cmake mingw-w64-i686-ninja mingw-w64-i686-clang
|
||||
type: Release
|
||||
- msystem: "MINGW64"
|
||||
install: mingw-w64-x86_64-libxml2 mingw-w64-x86_64-cmake mingw-w64-x86_64-ninja mingw-w64-x86_64-clang
|
||||
install: mingw-w64-x86_64-cmake mingw-w64-x86_64-ninja mingw-w64-x86_64-clang
|
||||
type: Debug
|
||||
- msystem: "MINGW32"
|
||||
install: mingw-w64-i686-libxml2 mingw-w64-i686-cmake mingw-w64-i686-ninja mingw-w64-i686-clang
|
||||
install: mingw-w64-i686-cmake mingw-w64-i686-ninja mingw-w64-i686-clang
|
||||
type: Debug
|
||||
env:
|
||||
CMAKE_GENERATOR: Ninja
|
||||
@@ -44,6 +49,6 @@ jobs:
|
||||
run: |
|
||||
mkdir build
|
||||
cd build
|
||||
cmake -DSIMDJSON_DEVELOPER_MODE=ON -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_BUILD_TYPE=${{ matrix.type }} -DSIMDJSON_BUILD_STATIC=ON -DSIMDJSON_DO_NOT_USE_THREADS_NO_MATTER_WHAT=ON ..
|
||||
cmake -DCMAKE_CXX_COMPILER=clang++ -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 -LE explicitonly
|
||||
|
||||
@@ -1,6 +1,12 @@
|
||||
name: MSYS2-CI
|
||||
|
||||
on: [push, pull_request]
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
|
||||
jobs:
|
||||
windows-mingw:
|
||||
@@ -46,6 +52,6 @@ jobs:
|
||||
run: |
|
||||
mkdir build
|
||||
cd build
|
||||
cmake -DSIMDJSON_DEVELOPER_MODE=ON -DCMAKE_BUILD_TYPE=${{ matrix.type }} -DBUILD_SHARED_LIBS=OFF -DSIMDJSON_DO_NOT_USE_THREADS_NO_MATTER_WHAT=ON ..
|
||||
cmake -DCMAKE_BUILD_TYPE=${{ matrix.type }} -DSIMDJSON_BUILD_STATIC=ON -DSIMDJSON_DO_NOT_USE_THREADS_NO_MATTER_WHAT=ON ..
|
||||
cmake --build . --verbose
|
||||
ctest -j4 --output-on-failure -LE explicitonly
|
||||
|
||||
@@ -32,19 +32,13 @@ jobs:
|
||||
run: |
|
||||
export CLANGSUFFIX="-7"
|
||||
apt-get -qq update
|
||||
apt-get install -q -y clang-7 libfuzzer-7-dev git wget zip ninja-build gnupg software-properties-common
|
||||
wget -q -O - "https://raw.githubusercontent.com/simdjson/debian-ppa/master/key.gpg" | apt-key add -
|
||||
apt-add-repository "deb https://raw.githubusercontent.com/simdjson/debian-ppa/master simdjson main"
|
||||
apt-get -qq update
|
||||
apt-get purge cmake cmake-data
|
||||
apt-get -t simdjson -y install cmake
|
||||
apt-get install -q -y clang-7 libfuzzer-7-dev cmake git wget zip ninja-build
|
||||
mkdir -p build ; cd build
|
||||
cmake .. -GNinja \
|
||||
-DCMAKE_CXX_COMPILER=clang++$CLANGSUFFIX \
|
||||
-DCMAKE_C_COMPILER=clang$CLANGSUFFIX \
|
||||
-DBUILD_SHARED_LIBS=OFF \
|
||||
-DSIMDJSON_DEVELOPER_MODE=ON \
|
||||
-DSIMDJSON_ENABLE_FUZZING=On \
|
||||
-DSIMDJSON_BUILD_STATIC=Off \
|
||||
-DENABLE_FUZZING=On \
|
||||
-DSIMDJSON_COMPETITION=OFF \
|
||||
-DSIMDJSON_GOOGLE_BENCHMARKS=OFF \
|
||||
-DSIMDJSON_DISABLE_DEPRECATED_API=On \
|
||||
@@ -56,8 +50,8 @@ jobs:
|
||||
cd ..
|
||||
builddir=build
|
||||
cmake --build $builddir
|
||||
wget -O corpus.tar.gz https://readonly:readonly@www.pauldreik.se/fuzzdata/index.php?project=simdjson
|
||||
tar xf corpus.tar.gz
|
||||
wget --quiet https://dl.bintray.com/pauldreik/simdjson-fuzz-corpus/corpus/corpus.tar
|
||||
tar xf corpus.tar && rm corpus.tar
|
||||
fuzzernames=$(cmake --build $builddir --target print_all_fuzzernames |tail -n1)
|
||||
for fuzzer in $fuzzernames ; do
|
||||
exe=$builddir/fuzz/$fuzzer
|
||||
|
||||
@@ -24,6 +24,6 @@ jobs:
|
||||
run: |
|
||||
mkdir build &&
|
||||
cd build &&
|
||||
cmake -DSIMDJSON_DEVELOPER_MODE=ON -DSIMDJSON_ENABLE_DOM_CHECKPERF=ON -DSIMDJSON_GOOGLE_BENCHMARKS=ON -DBUILD_SHARED_LIBS=OFF -DCMAKE_INSTALL_PREFIX:PATH=destination .. &&
|
||||
cmake -DSIMDJSON_GOOGLE_BENCHMARKS=ON -DSIMDJSON_BUILD_STATIC=ON -DCMAKE_INSTALL_PREFIX:PATH=destination .. &&
|
||||
cmake --build . --target checkperf &&
|
||||
ctest --output-on-failure -R checkperf ubuntu18-checkperf.yml
|
||||
|
||||
@@ -1,7 +1,12 @@
|
||||
name: Ubuntu 18.04 CI (GCC 7) with Thread Sanitizer
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
|
||||
jobs:
|
||||
ubuntu-build:
|
||||
@@ -19,7 +24,7 @@ jobs:
|
||||
run: |
|
||||
mkdir build &&
|
||||
cd build &&
|
||||
cmake -DSIMDJSON_DEVELOPER_MODE=ON -DSIMDJSON_SANITIZE_THREADS=ON .. &&
|
||||
cmake --build . --target document_stream_tests --target ondemand_document_stream_tests --target parse_many_test &&
|
||||
cmake -DSIMDJSON_SANITIZE_THREADS=ON .. &&
|
||||
cmake --build . --target document_stream_tests --target parse_many_test &&
|
||||
ctest --output-on-failure -R parse_many_test &&
|
||||
ctest --output-on-failure -R document_stream_tests
|
||||
@@ -1,6 +1,12 @@
|
||||
name: Ubuntu 18.04 CI (GCC 7)
|
||||
|
||||
on: [push, pull_request]
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
|
||||
jobs:
|
||||
ubuntu-build:
|
||||
@@ -18,7 +24,7 @@ jobs:
|
||||
run: |
|
||||
mkdir build &&
|
||||
cd build &&
|
||||
cmake -DSIMDJSON_DEVELOPER_MODE=ON -DSIMDJSON_GOOGLE_BENCHMARKS=ON -DBUILD_SHARED_LIBS=OFF -DCMAKE_INSTALL_PREFIX:PATH=destination .. &&
|
||||
cmake -DSIMDJSON_GOOGLE_BENCHMARKS=ON -DSIMDJSON_BUILD_STATIC=ON -DCMAKE_INSTALL_PREFIX:PATH=destination .. &&
|
||||
cmake --build . &&
|
||||
ctest -j --output-on-failure -LE explicitonly &&
|
||||
make install &&
|
||||
|
||||
@@ -24,6 +24,6 @@ jobs:
|
||||
run: |
|
||||
mkdir build &&
|
||||
cd build &&
|
||||
cmake -DSIMDJSON_DEVELOPER_MODE=ON -DSIMDJSON_ENABLE_DOM_CHECKPERF=ON -DCMAKE_CXX_FLAGS="-Werror=old-style-cast -pedantic -Wpedantic" -DSIMDJSON_GOOGLE_BENCHMARKS=ON -DBUILD_SHARED_LIBS=OFF -DCMAKE_INSTALL_PREFIX:PATH=destination .. &&
|
||||
cmake -DCMAKE_CXX_FLAGS="-Werror=old-style-cast -pedantic -Wpedantic" -DSIMDJSON_GOOGLE_BENCHMARKS=ON -DSIMDJSON_BUILD_STATIC=ON -DCMAKE_INSTALL_PREFIX:PATH=destination .. &&
|
||||
cmake --build . --target checkperf &&
|
||||
ctest --output-on-failure -R checkperf
|
||||
|
||||
@@ -1,6 +1,12 @@
|
||||
name: Ubuntu 20.04 CI (GCC 9) without exceptions
|
||||
|
||||
on: [push, pull_request]
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
|
||||
jobs:
|
||||
ubuntu-build:
|
||||
@@ -16,15 +22,9 @@ jobs:
|
||||
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
||||
- name: Use cmake
|
||||
run: |
|
||||
mkdir builddebug &&
|
||||
cd builddebug &&
|
||||
cmake -DCMAKE_BUILD_TYPE=Debug -DSIMDJSON_GOOGLE_BENCHMARKS=OFF -DSIMDJSON_DEVELOPER_MODE=ON -DSIMDJSON_EXCEPTIONS=OFF -DBUILD_SHARED_LIBS=OFF .. &&
|
||||
cmake --build . &&
|
||||
ctest -j --output-on-failure -LE explicitonly &&
|
||||
cd .. &&
|
||||
mkdir build &&
|
||||
cd build &&
|
||||
cmake -DSIMDJSON_DEVELOPER_MODE=ON -DSIMDJSON_GOOGLE_BENCHMARKS=ON -DSIMDJSON_GOOGLE_BENCHMARKS=ON -DSIMDJSON_EXCEPTIONS=OFF -DBUILD_SHARED_LIBS=OFF -DCMAKE_INSTALL_PREFIX:PATH=destination .. &&
|
||||
cmake -DSIMDJSON_GOOGLE_BENCHMARKS=ON -DSIMDJSON_GOOGLE_BENCHMARKS=ON -DSIMDJSON_EXCEPTIONS=OFF -DSIMDJSON_BUILD_STATIC=ON -DCMAKE_INSTALL_PREFIX:PATH=destination .. &&
|
||||
cmake --build . &&
|
||||
ctest -j --output-on-failure -LE explicitonly &&
|
||||
make install &&
|
||||
|
||||
@@ -1,6 +1,12 @@
|
||||
name: Ubuntu 20.04 CI (GCC 9) Without Threads
|
||||
name: Ubuntu 20.04 CI (GCC 9) without threads
|
||||
|
||||
on: [push, pull_request]
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
|
||||
jobs:
|
||||
ubuntu-build:
|
||||
@@ -16,15 +22,9 @@ jobs:
|
||||
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
||||
- name: Use cmake
|
||||
run: |
|
||||
mkdir builddebug &&
|
||||
cd builddebug &&
|
||||
cmake -DCMAKE_BUILD_TYPE=Debug -DSIMDJSON_GOOGLE_BENCHMARKS=OFF -DSIMDJSON_ENABLE_THREADS=OFF -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF .. &&
|
||||
cmake --build . &&
|
||||
ctest -j --output-on-failure -LE explicitonly &&
|
||||
cd .. &&
|
||||
mkdir build &&
|
||||
cd build &&
|
||||
cmake -DSIMDJSON_DEVELOPER_MODE=ON -DSIMDJSON_GOOGLE_BENCHMARKS=ON -DSIMDJSON_ENABLE_THREADS=OFF -DBUILD_SHARED_LIBS=OFF -DCMAKE_INSTALL_PREFIX:PATH=destination .. &&
|
||||
cmake -DSIMDJSON_GOOGLE_BENCHMARKS=ON -DSIMDJSON_ENABLE_THREADS=OFF -DSIMDJSON_BUILD_STATIC=ON -DCMAKE_INSTALL_PREFIX:PATH=destination .. &&
|
||||
cmake --build . &&
|
||||
ctest -j --output-on-failure -LE explicitonly &&
|
||||
make install &&
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
name: Ubuntu 20.04 CI (GCC 9) With Memory Sanitizer
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
ubuntu-build:
|
||||
if: >-
|
||||
! contains(toJSON(github.event.commits.*.message), '[skip ci]') &&
|
||||
! contains(toJSON(github.event.commits.*.message), '[skip github]')
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/cache@v2
|
||||
with:
|
||||
path: dependencies/.cache
|
||||
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
||||
- name: Use cmake
|
||||
run: |
|
||||
mkdir builddebug &&
|
||||
cd builddebug &&
|
||||
cmake -DSIMDJSON_SANITIZE=ON -DCMAKE_BUILD_TYPE=Debug -DSIMDJSON_GOOGLE_BENCHMARKS=OFF -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF .. &&
|
||||
cmake --build . &&
|
||||
ctest -j --output-on-failure -LE explicitonly
|
||||
@@ -1,6 +1,12 @@
|
||||
name: Ubuntu 20.04 CI (GCC 9) with Thread Sanitizer
|
||||
|
||||
on: [push, pull_request]
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
|
||||
jobs:
|
||||
ubuntu-build:
|
||||
@@ -18,7 +24,7 @@ jobs:
|
||||
run: |
|
||||
mkdir build &&
|
||||
cd build &&
|
||||
cmake -DSIMDJSON_DEVELOPER_MODE=ON -DSIMDJSON_SANITIZE_THREADS=ON .. &&
|
||||
cmake --build . --target document_stream_tests --target ondemand_document_stream_tests --target parse_many_test &&
|
||||
cmake -DSIMDJSON_SANITIZE_THREADS=ON .. &&
|
||||
cmake --build . --target document_stream_tests --target parse_many_test &&
|
||||
ctest --output-on-failure -R parse_many_test &&
|
||||
ctest --output-on-failure -R document_stream_tests
|
||||
@@ -1,6 +1,12 @@
|
||||
name: Ubuntu 20.04 CI (GCC 9)
|
||||
|
||||
on: [push, pull_request]
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
|
||||
jobs:
|
||||
ubuntu-build:
|
||||
@@ -16,15 +22,9 @@ jobs:
|
||||
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
||||
- name: Use cmake
|
||||
run: |
|
||||
mkdir builddebug &&
|
||||
cd builddebug &&
|
||||
cmake -DCMAKE_BUILD_TYPE=Debug -DSIMDJSON_GOOGLE_BENCHMARKS=OFF -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF .. &&
|
||||
cmake --build . &&
|
||||
ctest -j --output-on-failure -LE explicitonly &&
|
||||
cd .. &&
|
||||
mkdir build &&
|
||||
cd build &&
|
||||
cmake -DSIMDJSON_GOOGLE_BENCHMARKS=ON -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF -DCMAKE_INSTALL_PREFIX:PATH=destination .. &&
|
||||
cmake -DSIMDJSON_GOOGLE_BENCHMARKS=ON -DSIMDJSON_BUILD_STATIC=ON -DCMAKE_INSTALL_PREFIX:PATH=destination .. &&
|
||||
cmake --build . &&
|
||||
ctest -j --output-on-failure -LE explicitonly &&
|
||||
cmake --install . &&
|
||||
|
||||
@@ -1,6 +1,12 @@
|
||||
name: VS15-CI
|
||||
|
||||
on: [push, pull_request]
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
|
||||
jobs:
|
||||
ci:
|
||||
@@ -22,19 +28,15 @@ jobs:
|
||||
uses: actions/checkout@v2
|
||||
- name: Configure
|
||||
run: |
|
||||
cmake -G "${{matrix.gen}}" -A ${{matrix.arch}} -DSIMDJSON_COMPETITION=OFF -DSIMDJSON_DEVELOPER_MODE=ON -DSIMDJSON_BUILD_STATIC=${{matrix.static}} -B build
|
||||
cmake -G "${{matrix.gen}}" -A ${{matrix.arch}} -DSIMDJSON_COMPETITION=OFF -DSIMDJSON_BUILD_STATIC=${{matrix.static}} -B build
|
||||
- name: Build Debug
|
||||
run: cmake --build build --config Debug --verbose
|
||||
- name: Build Release
|
||||
run: cmake --build build --config Release --verbose
|
||||
- name: Run Release tests
|
||||
- name: Run tests
|
||||
run: |
|
||||
cd build
|
||||
ctest -C Release -LE explicitonly --output-on-failure
|
||||
- name: Run Debug tests
|
||||
run: |
|
||||
cd build
|
||||
ctest -C Debug -LE explicitonly --output-on-failure
|
||||
- name: Install
|
||||
run: |
|
||||
cmake --install build --config Release
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
name: VS16-ARM-CI
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
ci:
|
||||
name: windows-vs16
|
||||
runs-on: windows-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- {arch: ARM}
|
||||
- {arch: ARM64}
|
||||
steps:
|
||||
- name: checkout
|
||||
uses: actions/checkout@v2
|
||||
- name: Use cmake
|
||||
run: |
|
||||
cmake -A ${{ matrix.arch }} -DCMAKE_CROSSCOMPILING=1 -DSIMDJSON_DEVELOPER_MODE=ON -D SIMDJSON_GOOGLE_BENCHMARKS=OFF -DSIMDJSON_EXCEPTIONS=OFF -B build &&
|
||||
cmake --build build --verbose
|
||||
@@ -1,6 +1,12 @@
|
||||
name: VS16-CI
|
||||
|
||||
on: [push, pull_request]
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
|
||||
jobs:
|
||||
ci:
|
||||
@@ -22,19 +28,15 @@ jobs:
|
||||
uses: actions/checkout@v2
|
||||
- name: Configure
|
||||
run: |
|
||||
cmake -G "${{matrix.gen}}" -A ${{matrix.arch}} -DSIMDJSON_DEVELOPER_MODE=ON -DSIMDJSON_COMPETITION=OFF -DSIMDJSON_BUILD_STATIC=${{matrix.static}} -B build
|
||||
cmake -G "${{matrix.gen}}" -A ${{matrix.arch}} -DSIMDJSON_COMPETITION=OFF -DSIMDJSON_BUILD_STATIC=${{matrix.static}} -B build
|
||||
- name: Build Debug
|
||||
run: cmake --build build --config Debug --verbose
|
||||
- name: Build Release
|
||||
run: cmake --build build --config Release --verbose
|
||||
- name: Run Release tests
|
||||
- name: Run tests
|
||||
run: |
|
||||
cd build
|
||||
ctest -C Release -LE explicitonly --output-on-failure
|
||||
- name: Run Debug tests
|
||||
run: |
|
||||
cd build
|
||||
ctest -C Debug -LE explicitonly --output-on-failure
|
||||
- name: Install
|
||||
run: |
|
||||
cmake --install build --config Release
|
||||
|
||||
@@ -1,6 +1,12 @@
|
||||
name: VS16-CLANG-CI
|
||||
|
||||
on: [push, pull_request]
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
|
||||
jobs:
|
||||
ci:
|
||||
@@ -23,9 +29,9 @@ jobs:
|
||||
buildDirectory: "${{ github.workspace }}/../../_temp/windows"
|
||||
cmakeBuildType: Release
|
||||
buildWithCMake: true
|
||||
cmakeAppendedArgs: -T ClangCL -DSIMDJSON_COMPETITION=OFF -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF
|
||||
cmakeAppendedArgs: -T ClangCL -DSIMDJSON_COMPETITION=OFF -DSIMDJSON_BUILD_STATIC=ON
|
||||
buildWithCMakeArgs: --config Release
|
||||
|
||||
|
||||
- name: 'Run CTest'
|
||||
run: ctest -C Release -LE explicitonly --output-on-failure
|
||||
working-directory: "${{ github.workspace }}/../../_temp/windows"
|
||||
@@ -1,6 +1,12 @@
|
||||
name: VS16-Ninja-CI
|
||||
|
||||
on: [push, pull_request]
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
|
||||
jobs:
|
||||
ci:
|
||||
@@ -23,7 +29,7 @@ jobs:
|
||||
buildDirectory: "${{ github.workspace }}/../../_temp/windows"
|
||||
cmakeBuildType: Release
|
||||
buildWithCMake: true
|
||||
cmakeAppendedArgs: -G Ninja -DSIMDJSON_COMPETITION=OFF -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF
|
||||
cmakeAppendedArgs: -G Ninja -DSIMDJSON_COMPETITION=OFF -DSIMDJSON_BUILD_STATIC=ON
|
||||
buildWithCMakeArgs: --config Release
|
||||
- name: 'Run CTest'
|
||||
run: ctest -C Release -LE explicitonly --output-on-failure
|
||||
|
||||
@@ -1,6 +1,12 @@
|
||||
name: VS16-NoExcept-CI
|
||||
|
||||
on: [push, pull_request]
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
|
||||
jobs:
|
||||
ci:
|
||||
@@ -21,7 +27,7 @@ jobs:
|
||||
cmakeBuildType: Release
|
||||
buildWithCMake: true
|
||||
cmakeGenerator: VS16Win64
|
||||
cmakeAppendedArgs: -DSIMDJSON_COMPETITION=OFF -DSIMDJSON_DEVELOPER_MODE=ON -DSIMDJSON_EXCEPTIONS=OFF
|
||||
cmakeAppendedArgs: -DSIMDJSON_COMPETITION=OFF -DSIMDJSON_EXCEPTIONS=OFF
|
||||
buildWithCMakeArgs: --config Release
|
||||
|
||||
- name: 'Run CTest'
|
||||
|
||||
@@ -97,10 +97,3 @@ objs
|
||||
# Generated docs
|
||||
/doc/api
|
||||
*.orig
|
||||
|
||||
# VSCode workspace files
|
||||
.vscode/*
|
||||
!.vscode/settings.json
|
||||
!.vscode/tasks.json
|
||||
!.vscode/launch.json
|
||||
!.vscode/extensions.json
|
||||
|
||||
+27
-29
@@ -48,18 +48,17 @@ matrix:
|
||||
- COMPILER="CC=gcc-10 && CXX=g++-10"
|
||||
compiler: gcc-10
|
||||
|
||||
# The sanitizer runs fail systematically
|
||||
# - os: linux
|
||||
# addons:
|
||||
# apt:
|
||||
# sources:
|
||||
# - ubuntu-toolchain-r-test
|
||||
# packages:
|
||||
# - g++-10
|
||||
# env:
|
||||
# - COMPILER="CC=gcc-10 && CXX=g++-10"
|
||||
# - SANITIZE="on"
|
||||
# compiler: gcc-10-sanitize
|
||||
- os: linux
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
packages:
|
||||
- g++-10
|
||||
env:
|
||||
- COMPILER="CC=gcc-10 && CXX=g++-10"
|
||||
- SANITIZE="on"
|
||||
compiler: gcc-10-sanitize
|
||||
|
||||
- os: linux
|
||||
addons:
|
||||
@@ -144,20 +143,19 @@ matrix:
|
||||
- STATIC="on"
|
||||
compiler: clang-10-static
|
||||
|
||||
# The clang sanitizer runs fail frequently at setup time
|
||||
# - os: linux
|
||||
# addons:
|
||||
# apt:
|
||||
# packages:
|
||||
# - clang-10
|
||||
# sources:
|
||||
# - ubuntu-toolchain-r-test
|
||||
# - sourceline: 'deb http://apt.llvm.org/bionic/ llvm-toolchain-bionic-10 main'
|
||||
# key_url: 'https://apt.llvm.org/llvm-snapshot.gpg.key'
|
||||
# env:
|
||||
# - COMPILER="CC=clang-10 && CXX=clang++-10"
|
||||
# - SANITIZE="on"
|
||||
# compiler: clang-10-sanitize
|
||||
- os: linux
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- clang-10
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
- sourceline: 'deb http://apt.llvm.org/bionic/ llvm-toolchain-bionic-10 main'
|
||||
key_url: 'https://apt.llvm.org/llvm-snapshot.gpg.key'
|
||||
env:
|
||||
- COMPILER="CC=clang-10 && CXX=clang++-10"
|
||||
- SANITIZE="on"
|
||||
compiler: clang-10-sanitize
|
||||
|
||||
before_install:
|
||||
- eval "${COMPILER}"
|
||||
@@ -172,18 +170,18 @@ install:
|
||||
- export CMAKE_C_FLAGS="${CMAKE_CXX_FLAGS}"
|
||||
- export CMAKE_FLAGS="-DCMAKE_CXX_FLAGS=${CMAKE_CXX_FLAGS} -DCMAKE_C_FLAGS=${CMAKE_C_FLAGS} -DSIMDJSON_IMPLEMENTATION=ppc64;fallback";
|
||||
- if [[ "${SANITIZE}" == "on" ]]; then
|
||||
export CMAKE_FLAGS="${CMAKE_FLAGS} -DSIMDJSON_NO_FORCE_INLINING=ON -DSIMDJSON_SANITIZE=ON";
|
||||
export CMAKE_FLAGS="${CMAKE_FLAGS} -DSIMDJSON_SANITIZE=ON";
|
||||
export ASAN_OPTIONS="detect_leaks=0";
|
||||
fi
|
||||
- if [[ "${STATIC}" == "on" ]]; then
|
||||
export CMAKE_FLAGS="${CMAKE_FLAGS} -DBUILD_SHARED_LIBS=OFF";
|
||||
export CMAKE_FLAGS="${CMAKE_FLAGS} -DSIMDJSON_BUILD_STATIC=ON";
|
||||
fi
|
||||
- export CTEST_FLAGS="-j4 --output-on-failure -LE explicitonly"
|
||||
|
||||
script:
|
||||
- mkdir build
|
||||
- cd build
|
||||
- cmake -DSIMDJSON_DEVELOPER_MODE=ON $CMAKE_FLAGS ..
|
||||
- cmake $CMAKE_FLAGS ..
|
||||
- cmake --build . -- -j2
|
||||
- SIMDJSON_FORCE_IMPLEMENTATION=ppc64 ctest $CTEST_FLAGS -L per_implementation
|
||||
- SIMDJSON_FORCE_IMPLEMENTATION=fallback ctest $CTEST_FLAGS -L per_implementation
|
||||
|
||||
Vendored
-17
@@ -1,17 +0,0 @@
|
||||
{
|
||||
// See https://go.microsoft.com/fwlink/?LinkId=827846 to learn about workspace recommendations.
|
||||
// Extension identifier format: ${publisher}.${name}. Example: vscode.csharp
|
||||
|
||||
// List of extensions which should be recommended for users of this workspace.
|
||||
"recommendations": [
|
||||
// Syntax
|
||||
"ms-vscode.cpptools",
|
||||
"ms-vscode.cmake-tools",
|
||||
"ms-python.python",
|
||||
"twxs.cmake"
|
||||
],
|
||||
// List of extensions recommended by VS Code that should not be recommended for users of this workspace.
|
||||
"unwantedRecommendations": [
|
||||
|
||||
]
|
||||
}
|
||||
Vendored
-90
@@ -1,90 +0,0 @@
|
||||
{
|
||||
"editor.rulers": [
|
||||
{"column": 95 },
|
||||
{"column": 120 }
|
||||
],
|
||||
"files.trimTrailingWhitespace": true,
|
||||
"files.associations": {
|
||||
"array": "cpp",
|
||||
"iterator": "cpp",
|
||||
"chrono": "cpp",
|
||||
"optional": "cpp",
|
||||
"__locale": "cpp",
|
||||
"__tuple": "cpp",
|
||||
"__bit_reference": "cpp",
|
||||
"__config": "cpp",
|
||||
"__debug": "cpp",
|
||||
"__errc": "cpp",
|
||||
"__functional_base": "cpp",
|
||||
"__hash_table": "cpp",
|
||||
"__mutex_base": "cpp",
|
||||
"__node_handle": "cpp",
|
||||
"__nullptr": "cpp",
|
||||
"__split_buffer": "cpp",
|
||||
"__string": "cpp",
|
||||
"__threading_support": "cpp",
|
||||
"__tree": "cpp",
|
||||
"algorithm": "cpp",
|
||||
"atomic": "cpp",
|
||||
"bit": "cpp",
|
||||
"bitset": "cpp",
|
||||
"cctype": "cpp",
|
||||
"cinttypes": "cpp",
|
||||
"clocale": "cpp",
|
||||
"cmath": "cpp",
|
||||
"codecvt": "cpp",
|
||||
"complex": "cpp",
|
||||
"condition_variable": "cpp",
|
||||
"cstdarg": "cpp",
|
||||
"cstddef": "cpp",
|
||||
"cstdint": "cpp",
|
||||
"cstdio": "cpp",
|
||||
"cstdlib": "cpp",
|
||||
"cstring": "cpp",
|
||||
"ctime": "cpp",
|
||||
"cwchar": "cpp",
|
||||
"cwctype": "cpp",
|
||||
"deque": "cpp",
|
||||
"exception": "cpp",
|
||||
"forward_list": "cpp",
|
||||
"fstream": "cpp",
|
||||
"functional": "cpp",
|
||||
"initializer_list": "cpp",
|
||||
"iomanip": "cpp",
|
||||
"ios": "cpp",
|
||||
"iosfwd": "cpp",
|
||||
"iostream": "cpp",
|
||||
"istream": "cpp",
|
||||
"limits": "cpp",
|
||||
"list": "cpp",
|
||||
"locale": "cpp",
|
||||
"map": "cpp",
|
||||
"memory": "cpp",
|
||||
"mutex": "cpp",
|
||||
"new": "cpp",
|
||||
"numeric": "cpp",
|
||||
"ostream": "cpp",
|
||||
"random": "cpp",
|
||||
"ratio": "cpp",
|
||||
"regex": "cpp",
|
||||
"set": "cpp",
|
||||
"sstream": "cpp",
|
||||
"stack": "cpp",
|
||||
"stdexcept": "cpp",
|
||||
"streambuf": "cpp",
|
||||
"string": "cpp",
|
||||
"string_view": "cpp",
|
||||
"system_error": "cpp",
|
||||
"thread": "cpp",
|
||||
"tuple": "cpp",
|
||||
"type_traits": "cpp",
|
||||
"typeinfo": "cpp",
|
||||
"unordered_map": "cpp",
|
||||
"unordered_set": "cpp",
|
||||
"utility": "cpp",
|
||||
"valarray": "cpp",
|
||||
"vector": "cpp",
|
||||
"*.ipp": "cpp",
|
||||
"filesystem": "cpp"
|
||||
}
|
||||
}
|
||||
+83
-269
@@ -1,230 +1,74 @@
|
||||
cmake_minimum_required(VERSION 3.14)
|
||||
|
||||
project(
|
||||
simdjson
|
||||
# The version number is modified by tools/release.py
|
||||
VERSION 0.9.1
|
||||
DESCRIPTION "Parsing gigabytes of JSON per second"
|
||||
HOMEPAGE_URL "https://simdjson.org/"
|
||||
LANGUAGES CXX C
|
||||
cmake_minimum_required(VERSION 3.13)
|
||||
# CMP0025: Compiler id for Apple Clang is now AppleClang.
|
||||
# https://cmake.org/cmake/help/v3.17/policy/CMP0025.html
|
||||
cmake_policy(SET CMP0025 NEW)
|
||||
project(simdjson
|
||||
DESCRIPTION "Parsing gigabytes of JSON per second"
|
||||
LANGUAGES CXX C
|
||||
)
|
||||
|
||||
set(SIMDJSON_GITHUB_REPOSITORY "https://github.com/simdjson/simdjson")
|
||||
|
||||
string(
|
||||
COMPARE EQUAL
|
||||
"${CMAKE_SOURCE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}"
|
||||
is_top_project
|
||||
)
|
||||
|
||||
# ---- Options, variables ----
|
||||
|
||||
# These version numbers are modified by tools/release.py
|
||||
set(PROJECT_VERSION_MAJOR 0)
|
||||
set(PROJECT_VERSION_MINOR 9)
|
||||
set(PROJECT_VERSION_PATCH 2)
|
||||
set(SIMDJSON_SEMANTIC_VERSION "0.9.2" CACHE STRING "simdjson semantic version")
|
||||
set(SIMDJSON_LIB_VERSION "8.0.0" CACHE STRING "simdjson library version")
|
||||
set(SIMDJSON_LIB_SOVERSION "8" CACHE STRING "simdjson library soversion")
|
||||
set(SIMDJSON_GITHUB_REPOSITORY https://github.com/simdjson/simdjson)
|
||||
|
||||
include(GNUInstallDirs)
|
||||
include(cmake/simdjson-flags.cmake)
|
||||
include(cmake/simdjson-user-cmakecache.cmake)
|
||||
|
||||
|
||||
|
||||
if(SIMDJSON_JUST_LIBRARY)
|
||||
message( STATUS "Building just the library, omitting all tests, tools and benchmarks." )
|
||||
else(SIMDJSON_JUST_LIBRARY)
|
||||
# Setup tests
|
||||
enable_testing()
|
||||
add_subdirectory(jsonchecker)
|
||||
add_subdirectory(jsonexamples)
|
||||
add_library(test-data INTERFACE)
|
||||
target_link_libraries(test-data INTERFACE jsonchecker-data jsonchecker-minefield-data jsonexamples-data)
|
||||
endif(SIMDJSON_JUST_LIBRARY)
|
||||
|
||||
# Create the top level simdjson library (must be done at this level to use both src/ and include/
|
||||
# directories) and tools
|
||||
#
|
||||
add_subdirectory(include)
|
||||
add_subdirectory(src)
|
||||
add_subdirectory(windows)
|
||||
if(NOT(SIMDJSON_JUST_LIBRARY))
|
||||
add_subdirectory(dependencies) ## This needs to be before tools because of cxxopts
|
||||
add_subdirectory(tools) ## This needs to be before tests because of cxxopts
|
||||
add_subdirectory(singleheader)
|
||||
endif()
|
||||
install(FILES singleheader/simdjson.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
|
||||
|
||||
option(SIMDJSON_ENABLE_THREADS "Link with thread support" ON)
|
||||
|
||||
include(cmake/simdjson-props.cmake)
|
||||
include(cmake/implementation-flags.cmake)
|
||||
include(cmake/exception-flags.cmake)
|
||||
|
||||
option(SIMDJSON_DISABLE_DEPRECATED_API "Disables deprecated APIs" OFF)
|
||||
if(SIMDJSON_DISABLE_DEPRECATED_API)
|
||||
simdjson_add_props(
|
||||
target_compile_definitions PUBLIC
|
||||
SIMDJSON_DISABLE_DEPRECATED_API=1
|
||||
)
|
||||
endif()
|
||||
|
||||
option(SIMDJSON_DEVELOPMENT_CHECKS "Enable development-time aids, such as \
|
||||
checks for incorrect API usage. Enabled by default in DEBUG." OFF)
|
||||
if(SIMDJSON_DEVELOPMENT_CHECKS)
|
||||
simdjson_add_props(
|
||||
target_compile_definitions PUBLIC
|
||||
SIMDJSON_DEVELOPMENT_CHECKS
|
||||
)
|
||||
endif()
|
||||
|
||||
if(is_top_project)
|
||||
option(SIMDJSON_DEVELOPER_MODE "Enable targets for developing simdjson" OFF)
|
||||
option(BUILD_SHARED_LIBS "Build simdjson as a shared library" OFF)
|
||||
|
||||
if("$ENV{CI}")
|
||||
set(SIMDJSON_DEVELOPER_MODE ON CACHE INTERNAL "")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
include(cmake/handle-deprecations.cmake)
|
||||
|
||||
if(SIMDJSON_DEVELOPER_MODE)
|
||||
include(cmake/developer-options.cmake)
|
||||
else()
|
||||
message(STATUS "Building only the library. Advanced users may want to turn SIMDJSON_DEVELOPER_MODE to ON, e.g., via -D SIMDJSON_DEVELOPER_MODE=ON.")
|
||||
endif()
|
||||
|
||||
# ---- simdjson library ----
|
||||
|
||||
add_library(simdjson src/simdjson.cpp)
|
||||
add_library(simdjson::simdjson ALIAS simdjson)
|
||||
|
||||
set_target_properties(
|
||||
simdjson PROPERTIES
|
||||
VERSION "${SIMDJSON_LIB_VERSION}"
|
||||
SOVERSION "${SIMDJSON_LIB_SOVERSION}"
|
||||
# FIXME: symbols should be hidden by default
|
||||
WINDOWS_EXPORT_ALL_SYMBOLS YES
|
||||
)
|
||||
|
||||
# FIXME: Use proper CMake integration for exports
|
||||
if(MSVC AND BUILD_SHARED_LIBS)
|
||||
target_compile_definitions(
|
||||
simdjson
|
||||
PRIVATE SIMDJSON_BUILDING_WINDOWS_DYNAMIC_LIBRARY=1
|
||||
INTERFACE SIMDJSON_USING_WINDOWS_DYNAMIC_LIBRARY=1
|
||||
)
|
||||
endif()
|
||||
|
||||
simdjson_add_props(
|
||||
target_include_directories
|
||||
PUBLIC "$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>"
|
||||
PRIVATE "$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/src>"
|
||||
)
|
||||
|
||||
simdjson_add_props(target_compile_features PUBLIC cxx_std_11)
|
||||
|
||||
# workaround for GNU GCC poor AVX load/store code generation
|
||||
if(
|
||||
CMAKE_CXX_COMPILER_ID STREQUAL "GNU"
|
||||
AND CMAKE_SYSTEM_PROCESSOR MATCHES "^(i.86|x86(_64)?)$"
|
||||
)
|
||||
simdjson_add_props(
|
||||
target_compile_options PRIVATE
|
||||
-mno-avx256-split-unaligned-load -mno-avx256-split-unaligned-store
|
||||
)
|
||||
endif()
|
||||
|
||||
if(SIMDJSON_ENABLE_THREADS)
|
||||
find_package(Threads REQUIRED)
|
||||
simdjson_add_props(target_link_libraries PUBLIC Threads::Threads)
|
||||
simdjson_add_props(target_compile_definitions PUBLIC SIMDJSON_THREADS_ENABLED=1)
|
||||
endif()
|
||||
|
||||
simdjson_apply_props(simdjson)
|
||||
|
||||
# ---- Install rules ----
|
||||
|
||||
include(CMakePackageConfigHelpers)
|
||||
include(GNUInstallDirs)
|
||||
|
||||
install(
|
||||
FILES singleheader/simdjson.h
|
||||
DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}"
|
||||
COMPONENT simdjson_Development
|
||||
)
|
||||
|
||||
install(
|
||||
TARGETS simdjson
|
||||
EXPORT simdjsonTargets
|
||||
RUNTIME COMPONENT simdjson_Runtime
|
||||
LIBRARY COMPONENT simdjson_Runtime
|
||||
NAMELINK_COMPONENT simdjson_Development
|
||||
ARCHIVE COMPONENT simdjson_Development
|
||||
INCLUDES DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}"
|
||||
)
|
||||
|
||||
configure_file(cmake/simdjson-config.cmake.in simdjson-config.cmake @ONLY)
|
||||
|
||||
configure_package_config_file("${PROJECT_SOURCE_DIR}/cmake/simdjson-config.cmake.in"
|
||||
"${PROJECT_BINARY_DIR}/simdjson-config.cmake"
|
||||
INSTALL_DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/simdjson"
|
||||
NO_SET_AND_CHECK_MACRO
|
||||
NO_CHECK_REQUIRED_COMPONENTS_MACRO)
|
||||
write_basic_package_version_file(
|
||||
simdjson-config-version.cmake
|
||||
COMPATIBILITY SameMinorVersion
|
||||
)
|
||||
|
||||
set(
|
||||
SIMDJSON_INSTALL_CMAKEDIR "${CMAKE_INSTALL_LIBDIR}/cmake/simdjson"
|
||||
CACHE STRING "CMake package config location relative to the install prefix"
|
||||
)
|
||||
mark_as_advanced(SIMDJSON_INSTALL_CMAKEDIR)
|
||||
|
||||
install(
|
||||
FILES
|
||||
"${PROJECT_BINARY_DIR}/simdjson-config.cmake"
|
||||
"${PROJECT_BINARY_DIR}/simdjson-config-version.cmake"
|
||||
DESTINATION "${SIMDJSON_INSTALL_CMAKEDIR}"
|
||||
COMPONENT simdjson_Development
|
||||
)
|
||||
|
||||
install(
|
||||
EXPORT simdjsonTargets
|
||||
NAMESPACE simdjson::
|
||||
DESTINATION "${SIMDJSON_INSTALL_CMAKEDIR}"
|
||||
COMPONENT example_Development
|
||||
)
|
||||
|
||||
#
|
||||
# CPack
|
||||
#
|
||||
if(is_top_project)
|
||||
set(CPACK_PACKAGE_VENDOR "Daniel Lemire")
|
||||
set(CPACK_PACKAGE_CONTACT "lemire@gmail.com")
|
||||
set(CPACK_RESOURCE_FILE_LICENSE "${PROJECT_SOURCE_DIR}/LICENSE")
|
||||
set(CPACK_RESOURCE_FILE_README "${PROJECT_SOURCE_DIR}/README.md")
|
||||
|
||||
set(CPACK_RPM_PACKAGE_LICENSE "${PROJECT_SOURCE_DIR}/LICENSE")
|
||||
|
||||
set(CPACK_SOURCE_GENERATOR "TGZ;ZIP")
|
||||
|
||||
include(CPack)
|
||||
endif()
|
||||
|
||||
# ---- Developer mode extras ----
|
||||
|
||||
if(NOT SIMDJSON_DEVELOPER_MODE)
|
||||
return()
|
||||
elseif(NOT is_top_project)
|
||||
message(AUTHOR_WARNING "Developer mode is intended for developers of simdjson")
|
||||
endif()
|
||||
|
||||
simdjson_apply_props(simdjson-internal-flags)
|
||||
|
||||
set(
|
||||
SIMDJSON_USER_CMAKECACHE
|
||||
"${CMAKE_BINARY_DIR}/.simdjson-user-CMakeCache.txt"
|
||||
)
|
||||
add_custom_target(
|
||||
simdjson-user-cmakecache
|
||||
COMMAND "${CMAKE_COMMAND}"
|
||||
-D "BINARY_DIR=${CMAKE_BINARY_DIR}"
|
||||
-D "USER_CMAKECACHE=${SIMDJSON_USER_CMAKECACHE}"
|
||||
-P "${PROJECT_SOURCE_DIR}/cmake/simdjson-user-cmakecache.cmake"
|
||||
VERBATIM
|
||||
)
|
||||
|
||||
# Setup tests
|
||||
enable_testing()
|
||||
# So we can build just tests with "make all_tests"
|
||||
add_custom_target(all_tests)
|
||||
|
||||
add_subdirectory(windows)
|
||||
add_subdirectory(dependencies) ## This needs to be before tools because of cxxopts
|
||||
add_subdirectory(tools) ## This needs to be before tests because of cxxopts
|
||||
|
||||
# Data: jsonexamples is left with only the bare essential.
|
||||
# most of the data has been moved to https://github.com/simdjson/simdjson-data
|
||||
add_subdirectory(jsonexamples)
|
||||
|
||||
|
||||
add_subdirectory(singleheader)
|
||||
|
||||
|
||||
"${PROJECT_BINARY_DIR}/simdjson-config-version.cmake"
|
||||
VERSION ${SIMDJSON_SEMANTIC_VERSION}
|
||||
COMPATIBILITY SameMinorVersion)
|
||||
install(FILES "${PROJECT_BINARY_DIR}/simdjson-config.cmake"
|
||||
"${PROJECT_BINARY_DIR}/simdjson-config-version.cmake"
|
||||
DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/simdjson")
|
||||
|
||||
#
|
||||
# Compile tools / tests / benchmarks
|
||||
#
|
||||
add_subdirectory(tests)
|
||||
add_subdirectory(examples)
|
||||
add_subdirectory(benchmark)
|
||||
add_subdirectory(fuzz)
|
||||
if(NOT(SIMDJSON_JUST_LIBRARY))
|
||||
add_subdirectory(tests)
|
||||
add_subdirectory(examples)
|
||||
add_subdirectory(benchmark)
|
||||
add_subdirectory(fuzz)
|
||||
endif()
|
||||
|
||||
#
|
||||
# Source files should be just ASCII
|
||||
@@ -232,59 +76,29 @@ add_subdirectory(fuzz)
|
||||
find_program(FIND find)
|
||||
find_program(FILE file)
|
||||
find_program(GREP grep)
|
||||
if(FIND AND FILE AND GREP)
|
||||
add_test(
|
||||
NAME just_ascii
|
||||
COMMAND sh -c "\
|
||||
${FIND} include src windows tools singleheader tests examples benchmark \
|
||||
-path benchmark/checkperf-reference -prune -name '*.h' -o -name '*.cpp' \
|
||||
-type f -exec ${FILE} '{}' \; | ${GREP} -qv ASCII || exit 0 && exit 1"
|
||||
WORKING_DIRECTORY "${PROJECT_SOURCE_DIR}"
|
||||
)
|
||||
if((FIND) AND (FILE) AND (GREP))
|
||||
add_test(
|
||||
NAME "just_ascii"
|
||||
COMMAND sh -c "${FIND} include src windows tools singleheader tests examples benchmark -path benchmark/checkperf-reference -prune -name '*.h' -o -name '*.cpp' -type f -exec ${FILE} '{}' \; |${GREP} -v ASCII || exit 0 && exit 1"
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
)
|
||||
endif()
|
||||
|
||||
##
|
||||
## In systems like R, libraries must not use stderr or abort to be acceptable.
|
||||
## Thus we make it a hard rule that one is not allowed to call abort or stderr.
|
||||
## The sanitized builds are allowed to abort.
|
||||
##
|
||||
if(NOT SIMDJSON_SANITIZE)
|
||||
find_program(GREP grep)
|
||||
find_program(NM nm)
|
||||
if((NOT GREP) OR (NOT NM))
|
||||
message("grep and nm are unavailable on this system.")
|
||||
else()
|
||||
add_test(
|
||||
NAME "avoid_abort"
|
||||
# Under FreeBSD, the __cxa_guard_abort symbol may appear but it is fine.
|
||||
# So we want to look for <space><possibly _>abort as a test.
|
||||
COMMAND sh -c "${NM} $<TARGET_FILE_NAME:simdjson> | ${GREP} ' _*abort' || exit 0 && exit 1"
|
||||
WORKING_DIRECTORY ${PROJECT_BINARY_DIR}
|
||||
)
|
||||
add_test(
|
||||
NAME "avoid_cout"
|
||||
COMMAND sh -c "${NM} $<TARGET_FILE_NAME:simdjson> | ${GREP} ' _*cout' || exit 0 && exit 1"
|
||||
WORKING_DIRECTORY ${PROJECT_BINARY_DIR}
|
||||
)
|
||||
add_test(
|
||||
NAME "avoid_cerr"
|
||||
COMMAND sh -c "${NM} $<TARGET_FILE_NAME:simdjson> | ${GREP} ' _*cerr' || exit 0 && exit 1"
|
||||
WORKING_DIRECTORY ${PROJECT_BINARY_DIR}
|
||||
)
|
||||
add_test(
|
||||
NAME "avoid_printf"
|
||||
COMMAND sh -c "${NM} $<TARGET_FILE_NAME:simdjson> | ${GREP} ' _*printf' || exit 0 && exit 1"
|
||||
WORKING_DIRECTORY ${PROJECT_BINARY_DIR}
|
||||
)
|
||||
add_test(
|
||||
NAME "avoid_stdout"
|
||||
COMMAND sh -c "${NM} $<TARGET_FILE_NAME:simdjson> | ${GREP} stdout || exit 0 && exit 1"
|
||||
WORKING_DIRECTORY ${PROJECT_BINARY_DIR}
|
||||
)
|
||||
add_test(
|
||||
NAME "avoid_stderr"
|
||||
COMMAND sh -c "${NM} $<TARGET_FILE_NAME:simdjson> | ${GREP} stderr || exit 0 && exit 1"
|
||||
WORKING_DIRECTORY ${PROJECT_BINARY_DIR}
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
#
|
||||
# CPack
|
||||
#
|
||||
set(CPACK_PACKAGE_VENDOR "Daniel Lemire")
|
||||
set(CPACK_PACKAGE_CONTACT "lemire@gmail.com")
|
||||
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Parsing gigabytes of JSON per second")
|
||||
set(CPACK_PACKAGE_VERSION_MAJOR ${PROJECT_VERSION_MAJOR})
|
||||
set(CPACK_PACKAGE_VERSION_MINOR ${PROJECT_VERSION_MINOR})
|
||||
set(CPACK_PACKAGE_VERSION_PATCH ${PROJECT_VERSION_PATCH})
|
||||
set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE")
|
||||
set(CPACK_RESOURCE_FILE_README "${CMAKE_CURRENT_SOURCE_DIR}/README.md")
|
||||
|
||||
set(CPACK_RPM_PACKAGE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE")
|
||||
|
||||
set(CPACK_SOURCE_GENERATOR "TGZ;ZIP")
|
||||
|
||||
include(CPack)
|
||||
|
||||
+1
-1
@@ -69,7 +69,7 @@ Pull requests are always invited. However, we ask that you follow these guidelin
|
||||
3. Other types of changes must be clearly motivated. We openly discourage changes with no identifiable benefits.
|
||||
- Changes should be focused and minimal. You should change as few lines of code as possible. Please do not reformat or touch files needlessly.
|
||||
- New features must be accompanied of new tests, in general.
|
||||
- Your code should pass our continuous-integration tests. It is your responsibility to ensure that your proposal pass the tests. We do not merge pull requests that would break our build.
|
||||
- Your code should pass our continuous-integration tests. It is your responsability to ensure that your proposal pass the tests. We do not merge pull requests that would break our build.
|
||||
- An exception to this would be changes to non-code files, such as documentation and assets, or trivial changes to code, such as comments, where it is encouraged to explicitly ask for skipping a CI run using the `[skip ci]` prefix in your Pull Request title **and** in the first line of the most recent commit in a push. Example for such a commit: `[skip ci] Fixed typo in power_of_ten's docs`
|
||||
This benefits the project in such a way that the CI pipeline is not burdened by running jobs on changes that don't change any behavior in the code, which reduces wait times for other Pull Requests that do change behavior and require testing.
|
||||
|
||||
|
||||
@@ -36,6 +36,5 @@ Nong Li
|
||||
Furkan Taşkale
|
||||
Brendan Knapp
|
||||
Danila Kutenin
|
||||
Pavel Pavlov
|
||||
# if you have contributed to the project and your name does not
|
||||
# appear in this list, please let us know!
|
||||
|
||||
+88
@@ -0,0 +1,88 @@
|
||||
###
|
||||
#
|
||||
# Though simdjson requires only commonly available compilers and tools, it can
|
||||
# be convenient to build it and test it inside a docker container: it makes it
|
||||
# possible to test and benchmark simdjson under even relatively out-of-date
|
||||
# Linux servers. It should also work under macOS and Windows, though not
|
||||
# at native speeds, maybe.
|
||||
#
|
||||
# Assuming that you have a working docker server, this file
|
||||
# allows you to build, test and benchmark simdjson.
|
||||
#
|
||||
# We build the library and associated files in the dockerbuild subdirectory.
|
||||
# It may be necessary to delete it before creating the image:
|
||||
#
|
||||
# rm -r -f dockerbuild
|
||||
#
|
||||
# The need to delete the directory has nothing to do with docker per se: it is
|
||||
# simply cleaner in CMake to start from a fresh directory. This is important: if you
|
||||
# reuse the same directory with different configurations, you may get broken builds.
|
||||
#
|
||||
#
|
||||
# Then you can build the image as follows:
|
||||
#
|
||||
# docker build -t simdjson --build-arg USER_ID=$(id -u) --build-arg GROUP_ID=$(id -g) .
|
||||
#
|
||||
# Please note that the image does not contain a copy of the code. However, the image will contain the
|
||||
# the compiler and the build system. This means that if you change the source code, after you have built
|
||||
# the image, you won't need to rebuild the image. In fact, unless you want to try a different compiler, you
|
||||
# do not need to ever rebuild the image, even if you do a lot of work on the source code.
|
||||
#
|
||||
# We specify the users to avoid having files owned by a privileged user (root) in our directory. Some
|
||||
# people like to run their machine as the "root" user. We do not think it is cool.
|
||||
#
|
||||
# Then you need to build the project:
|
||||
#
|
||||
# docker run -v $(pwd):/project:Z simdjson
|
||||
#
|
||||
# Should you change a source file, you may need to call this command again. Because the output
|
||||
# files are persistent between calls to this command (they reside in the dockerbuild directory),
|
||||
# this command can be fast.
|
||||
#
|
||||
# Next you can test it as follows:
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
# Building all of simdjson takes a long time. Instead, you can build just one target:
|
||||
#
|
||||
# docker run -it -v $(pwd):/project:Z simdjson sh -c "[ -d dockerbuild ] || mkdir dockerbuild && cd dockerbuild && cmake .. && cmake --build . --target parse"
|
||||
#
|
||||
# Note that it is safe to remove dockerbuild before call the previous command, as the repository gets rebuild. It is also possible, by changing the command, to use a different directory name.
|
||||
#
|
||||
# You can run performance tests:
|
||||
#
|
||||
# docker run -it --privileged -v $(pwd):/project:Z simdjson sh -c "cd dockerbuild && for i in ../jsonexamples/*.json; do echo \$i; ./benchmark/parse \$i; done"
|
||||
#
|
||||
# The "--privileged" is recommended so you can get performance counters under Linux.
|
||||
#
|
||||
# You can also grab a fresh copy of simdjson and rebuild it, to make comparisons:
|
||||
#
|
||||
# docker run -it -v $(pwd):/project:Z simdjson sh -c "git clone https://github.com/simdjson/simdjson.git && cd simdjson && mkdir build && cd build && cmake .. && cmake --build . --target parse "
|
||||
#
|
||||
# Then you can run comparisons:
|
||||
#
|
||||
# docker run -it --privileged -v $(pwd):/project:Z simdjson sh -c "for i in jsonexamples/*.json; do echo \$i; dockerbuild/benchmark/parse \$i| grep GB| head -n 1; simdjson/build/benchmark/parse \$i | grep GB |head -n 1; done"
|
||||
#
|
||||
####
|
||||
FROM ubuntu:20.10
|
||||
################
|
||||
# We would prefer to use the conan io images but they do not support 64-bit ARM? The small gcc images appear to
|
||||
# be broken on ARM.
|
||||
# Furthermore, we would not expect users to frequently rebuild the container, so using ubuntu is probably fine.
|
||||
###############
|
||||
ARG USER_ID
|
||||
ARG GROUP_ID
|
||||
RUN apt-get update -qq
|
||||
RUN DEBIAN_FRONTEND="noninteractive" apt-get -y install tzdata
|
||||
RUN apt-get install -y cmake g++ git
|
||||
RUN mkdir project
|
||||
|
||||
RUN addgroup --gid $GROUP_ID user; exit 0
|
||||
RUN adduser --disabled-password --gecos '' --uid $USER_ID --gid $GROUP_ID user; exit 0
|
||||
USER user
|
||||
RUN gcc --version
|
||||
WORKDIR /project
|
||||
|
||||
CMD ["sh","-c","[ -d dockerbuild ] || mkdir dockerbuild && cd dockerbuild && cmake .. && cmake --build . "]
|
||||
@@ -38,7 +38,7 @@ PROJECT_NAME = simdjson
|
||||
# could be handy for archiving the generated documentation or if some version
|
||||
# control system is used.
|
||||
|
||||
PROJECT_NUMBER = "0.9.1"
|
||||
PROJECT_NUMBER = "0.9.2"
|
||||
|
||||
# Using the PROJECT_BRIEF tag one can provide an optional one line description
|
||||
# for a project that appears at the top of each page and should give viewer a
|
||||
|
||||
+15
-27
@@ -32,18 +32,6 @@ Stage 1 also does unicode validation.
|
||||
|
||||
Stage 2 handles all of the rest: number parsings, recognizing atoms like true, false, null, and so forth.
|
||||
|
||||
Developer mode
|
||||
--------------
|
||||
|
||||
Build system targets that are only useful for developers of the simdjson
|
||||
library are behind the `SIMDJSON_DEVELOPER_MODE` option. Enabling this option
|
||||
makes tests, examples, benchmarks and other developer targets available. Not
|
||||
enabling this option means that you are a consumer of simdjson and thus you
|
||||
only get the library targets and options.
|
||||
|
||||
Developer mode is forced to be on when the `CI` environment variable is set to
|
||||
a value that CMake recognizes as "on", which is set to `true` in all of the CI
|
||||
workflows used by simdjson.
|
||||
|
||||
Directory Structure and Source
|
||||
------------------------------
|
||||
@@ -86,19 +74,19 @@ Other important files and directories:
|
||||
```bash
|
||||
mkdir build
|
||||
cd build
|
||||
cmake -D SIMDJSON_DEVELOPER_MODE=ON ..
|
||||
cmake ..
|
||||
cmake --build . --config Release
|
||||
benchmark/dom/parse ../jsonexamples/twitter.json
|
||||
benchmark/parse ../jsonexamples/twitter.json
|
||||
```
|
||||
The last line becomes `./benchmark/Release/parse.exe ../jsonexample/twitter.json` under Windows. You may also use Google Benchmark:
|
||||
```bash
|
||||
mkdir build
|
||||
cd build
|
||||
cmake -D SIMDJSON_DEVELOPER_MODE=ON ..
|
||||
cmake ..
|
||||
cmake --build . --target bench_parse_call --config Release
|
||||
./benchmark/bench_parse_call
|
||||
```
|
||||
The last line becomes `./benchmark/Release/bench_parse_call.exe` under Windows. Under Windows, you can also build with the clang compiler by adding `-T ClangCL` to the call to `cmake ..`: `cmake -T ClangCL ..`.
|
||||
The last line becomes `./benchmark/Release/bench_parse_call.exe` under Windows. Under Windows, you can also build with the clang compiler by adding `-T ClangCL` to the call to `cmake ..`: `cmake .. - TClangCL`.
|
||||
* **fuzz:** The source for fuzz testing. This lets us explore important edge and middle cases
|
||||
* **fuzz:** The source for fuzz testing. This lets us explore important edge and middle cases
|
||||
automatically, and is run in CI.
|
||||
@@ -159,7 +147,7 @@ processor.
|
||||
|
||||
At this point, we are require to use one of two main strategies.
|
||||
|
||||
1. On POSIX systems, the main compilers (LLVM clang, GNU gcc) allow us to use any intrinsic function after including the header, but they fail to inline the resulting instruction if the target processor does not support them. Because we compile for a generic processor, we would not be able to use most intrinsic functions. Thankfully, more recent versions of these compilers allow us to flag a region of code with a specific target, so that we can compile only some of the code with support for advanced instructions. Thus in our C++, one might notice macros like `TARGET_HASWELL`. It is then our responsibility, at runtime, to only run the regions of code (that we call kernels) matching the properties of the runtime processor. The benefit of this approach is that the compiler not only let us use intrinsic functions, but it can also optimize the rest of the code in the kernel with advanced instructions we enabled.
|
||||
1. On POSIX systems, the main compilers (LLVM clang, GNU gcc) allow us to use any intrinsic function after including the header, but they fail to inline the resulting instruction if the target processor does not support them. Because we compile for a generic processor, we would not be able to use most intrinsic functions. Thankfully, more recent versions of these compilers allow us to flag a region of code with a specific target, so that we can compile only some of the code with support for advanced instructions. Thus in our C++, one might notice macros like `TARGET_HASWELL`. It is then our responsability, at runtime, to only run the regions of code (that we call kernels) matching the properties of the runtime processor. The benefit of this approach is that the compiler not only let us use intrinsic functions, but it can also optimize the rest of the code in the kernel with advanced instructions we enabled.
|
||||
|
||||
2. Under Visual Studio, the problem is somewhat simpler. Visual Studio will not only provide the intrinsic functions, but it will also allow us to use them. They will compile just fine. It is at runtime that they may cause a crash. So we do not need to mark regions of code for compilation toward advanced processors (e.g., with `TARGET_HASWELL` macros). The downside of the Visual Studio approach is that the compiler is not allowed to use advanced instructions others than those we specify. In principle, this means that Visual Studio has weaker optimization opportunities.
|
||||
|
||||
@@ -180,7 +168,7 @@ systematically regenerated on releases. To ensure you have the latest code, you
|
||||
```bash
|
||||
mkdir build
|
||||
cd build
|
||||
cmake -D SIMDJSON_DEVELOPER_MODE=ON ..
|
||||
cmake ..
|
||||
cmake --build . # needed, because currently dependencies do not work fully for the amalgamate target
|
||||
cmake --build . --target amalgamate
|
||||
```
|
||||
@@ -221,31 +209,31 @@ Building: While in the project repository, do the following:
|
||||
```
|
||||
mkdir build
|
||||
cd build
|
||||
cmake -D SIMDJSON_DEVELOPER_MODE=ON ..
|
||||
cmake ..
|
||||
cmake --build .
|
||||
ctest
|
||||
```
|
||||
|
||||
CMake will build a library. By default, it builds a static library (e.g., libsimdjson.a on Linux).
|
||||
CMake will build a library. By default, it builds a shared library (e.g., libsimdjson.so on Linux).
|
||||
|
||||
You can build a shared library:
|
||||
You can build a static library:
|
||||
|
||||
```
|
||||
mkdir buildshared
|
||||
cd buildshared
|
||||
cmake -D BUILD_SHARED_LIBS=ON -D SIMDJSON_DEVELOPER_MODE=ON ..
|
||||
mkdir buildstatic
|
||||
cd buildstatic
|
||||
cmake -DSIMDJSON_BUILD_STATIC=ON ..
|
||||
cmake --build .
|
||||
ctest
|
||||
```
|
||||
|
||||
In some cases, you may want to specify your compiler, especially if the default compiler on your system is too old. You need to tell cmake which compiler you wish to use by setting the CC and CXX variables. Under bash, you can do so with commands such as `export CC=gcc-7` and `export CXX=g++-7`. You can also do it as part of the `cmake` command: `cmake -DCMAKE_CXX_COMPILER=g++ ..`. You may proceed as follows:
|
||||
In some cases, you may want to specify your compiler, especially if the default compiler on your system is too old. You need to tell cmake which compiler you wish to use by setting the CC and CXX variables. Under bash, you can do so with commands such as `export CC=gcc-7` and `export CXX=g++-7`. You can also do it as part of the `cmake` command: `cmake .. -DCMAKE_CXX_COMPILER=g++`. You may proceed as follows:
|
||||
|
||||
```
|
||||
brew install gcc@8
|
||||
mkdir build
|
||||
cd build
|
||||
export CXX=g++-8 CC=gcc-8
|
||||
cmake -D SIMDJSON_DEVELOPER_MODE=ON ..
|
||||
cmake ..
|
||||
cmake --build .
|
||||
ctest
|
||||
```
|
||||
@@ -281,7 +269,7 @@ Furthermore, if you have installed LLVM clang on Windows, for example as a compo
|
||||
|
||||
- `mkdir build`
|
||||
- `cd build`
|
||||
- `cmake -T ClangCL ..`
|
||||
- `cmake .. -T ClangCL`
|
||||
- `cmake --build . -config Release`
|
||||
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
|
||||
[](https://bugs.chromium.org/p/oss-fuzz/issues/list?sort=-opened&q=proj%3Asimdjson&can=2)
|
||||
/badge.svg)
|
||||
[/badge.svg)](https://simdjson.org/plots.html)
|
||||

|
||||
@@ -27,6 +27,7 @@ Table of Contents
|
||||
-----------------
|
||||
|
||||
* [Quick Start](#quick-start)
|
||||
* [On Demand](#on-demand)
|
||||
* [Documentation](#documentation)
|
||||
* [Performance results](#performance-results)
|
||||
* [Real-world usage](#real-world-usage)
|
||||
@@ -136,7 +137,6 @@ We distinguish between "bindings" (which just wrap the C++ code) and a port to a
|
||||
- [simdjson-go](https://github.com/minio/simdjson-go): Go port using Golang assembly.
|
||||
- [rcppsimdjson](https://github.com/eddelbuettel/rcppsimdjson): R bindings.
|
||||
- [simdjson_erlang](https://github.com/ChomperT/simdjson_erlang): erlang bindings.
|
||||
- [lua-simdjson](https://github.com/FourierTransformer/lua-simdjson): lua bindings.
|
||||
|
||||
|
||||
About simdjson
|
||||
@@ -152,7 +152,7 @@ and implementation of simdjson is in our research article:
|
||||
|
||||
We have an in-depth paper focused on the UTF-8 validation:
|
||||
|
||||
- John Keiser, Daniel Lemire, [Validating UTF-8 In Less Than One Instruction Per Byte](https://arxiv.org/abs/2010.03090), Software: Practice & Experience 51 (5), 2021.
|
||||
- John Keiser, Daniel Lemire, [Validating UTF-8 In Less Than One Instruction Per Byte](https://arxiv.org/abs/2010.03090), Software: Practice & Experience (to appear)
|
||||
|
||||
We also have an informal [blog post providing some background and context](https://branchfree.org/2019/02/25/paper-parsing-gigabytes-of-json-per-second/).
|
||||
|
||||
@@ -182,8 +182,4 @@ This code is made available under the [Apache License 2.0](https://www.apache.or
|
||||
|
||||
Under Windows, we build some tools using the windows/dirent_portable.h file (which is outside our library code): it under the liberal (business-friendly) MIT license.
|
||||
|
||||
For compilers that do not support [C++17](https://en.wikipedia.org/wiki/C%2B%2B17), we bundle the string-view library which is published under the [Boost license](http://www.boost.org/LICENSE_1_0.txt). Like the Apache license, the Boost license is a permissive license allowing commercial redistribution.
|
||||
|
||||
For efficient number serialization, we bundle Florian Loitsch's implementation of the Grisu2 algorithm for binary to decimal floating-point numbers. The implementation was slightly modified by JSON for Modern C++ library. Both Florian Loitsch's implementation and JSON for Modern C++ are provided under the MIT license.
|
||||
|
||||
For runtime dispatching, we use some code from the PyTorch project licensed under 3-clause BSD.
|
||||
For compilers that do not support [C++17](https://en.wikipedia.org/wiki/C%2B%2B17), we bundle the string-view library which is published under the Boost license (http://www.boost.org/LICENSE_1_0.txt). Like the Apache license, the Boost license is a permissive license allowing commercial redistribution.
|
||||
|
||||
@@ -1,12 +1,20 @@
|
||||
add_subdirectory(dom)
|
||||
|
||||
|
||||
include_directories( . linux )
|
||||
link_libraries(simdjson-windows-headers test-data)
|
||||
link_libraries(simdjson)
|
||||
link_libraries(simdjson simdjson-flags)
|
||||
|
||||
add_executable(benchfeatures benchfeatures.cpp)
|
||||
add_executable(get_corpus_benchmark get_corpus_benchmark.cpp)
|
||||
add_executable(perfdiff perfdiff.cpp)
|
||||
add_executable(parse parse.cpp)
|
||||
add_executable(parse_stream parse_stream.cpp)
|
||||
add_executable(statisticalmodel statisticalmodel.cpp)
|
||||
|
||||
add_executable(parse_noutf8validation parse.cpp)
|
||||
target_compile_definitions(parse_noutf8validation PRIVATE SIMDJSON_SKIPUTF8VALIDATION)
|
||||
add_executable(parse_nonumberparsing parse.cpp)
|
||||
target_compile_definitions(parse_nonumberparsing PRIVATE SIMDJSON_SKIPNUMBERPARSING)
|
||||
add_executable(parse_nostringparsing parse.cpp)
|
||||
target_compile_definitions(parse_nostringparsing PRIVATE SIMDJSON_SKIPSTRINGPARSING)
|
||||
|
||||
if (TARGET benchmark::benchmark)
|
||||
link_libraries(benchmark::benchmark)
|
||||
@@ -29,3 +37,5 @@ if (TARGET benchmark::benchmark)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# deliberately disabling.
|
||||
# include(checkperf.cmake)
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
# From the ROOT, run:
|
||||
# docker build -t simdjsonbench -f benchmark/Dockerfile . && docker run --privileged -t simdjsonbench
|
||||
FROM gcc:8.3
|
||||
|
||||
# # Build latest
|
||||
# ENV latest_release=v0.2.1
|
||||
# WORKDIR /usr/src/$latest_release/
|
||||
# RUN git clone --depth 1 https://github.com/lemire/simdjson/ -b $latest_release .
|
||||
# RUN make parse
|
||||
|
||||
# # Build master
|
||||
# WORKDIR /usr/src/master/
|
||||
# RUN git clone --depth 1 https://github.com/lemire/simdjson/ .
|
||||
# RUN make parse
|
||||
|
||||
# Build the current source
|
||||
COPY . /usr/src/current/
|
||||
WORKDIR /usr/src/current/
|
||||
RUN make checkperf
|
||||
@@ -1,68 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "json_benchmark/file_runner.h"
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
namespace amazon_cellphones {
|
||||
|
||||
using namespace json_benchmark;
|
||||
|
||||
struct brand {
|
||||
double cumulative_rating;
|
||||
uint64_t reviews_count;
|
||||
simdjson_really_inline bool operator==(const brand &other) const {
|
||||
return cumulative_rating == other.cumulative_rating &&
|
||||
reviews_count == other.reviews_count;
|
||||
}
|
||||
simdjson_really_inline bool operator!=(const brand &other) const { return !(*this == other); }
|
||||
};
|
||||
|
||||
simdjson_unused static std::ostream &operator<<(std::ostream &o, const brand &b) {
|
||||
o << "cumulative_rating: " << b.cumulative_rating << std::endl;
|
||||
o << "reviews_count: " << b.reviews_count << std::endl;
|
||||
return o;
|
||||
}
|
||||
|
||||
template<typename StringType>
|
||||
simdjson_unused static std::ostream &operator<<(std::ostream &o, const std::pair<const StringType, brand> &p) {
|
||||
o << "brand: " << p.first << std::endl;
|
||||
o << p.second;
|
||||
return o;
|
||||
}
|
||||
|
||||
template<typename I>
|
||||
struct runner : public file_runner<I> {
|
||||
std::map<typename I::StringType, brand> result{};
|
||||
|
||||
bool setup(benchmark::State &state) {
|
||||
return this->load_json(state, AMAZON_CELLPHONES_NDJSON);
|
||||
}
|
||||
|
||||
bool before_run(benchmark::State &state) {
|
||||
if (!file_runner<I>::before_run(state)) { return false; }
|
||||
result.clear();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool run(benchmark::State &) {
|
||||
return this->implementation.run(this->json, result);
|
||||
}
|
||||
|
||||
template<typename R>
|
||||
bool diff(benchmark::State &state, runner<R> &reference) {
|
||||
return diff_results(state, result, reference.result, diff_flags::NONE);
|
||||
}
|
||||
|
||||
size_t items_per_iteration() {
|
||||
return result.size();
|
||||
}
|
||||
};
|
||||
|
||||
struct simdjson_dom;
|
||||
|
||||
template<typename I> simdjson_really_inline static void amazon_cellphones(benchmark::State &state) {
|
||||
run_json_benchmark<runner<I>, runner<simdjson_dom>>(state);
|
||||
}
|
||||
|
||||
} // namespace amazon_cellphones
|
||||
@@ -1,44 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
|
||||
#include "amazon_cellphones.h"
|
||||
|
||||
namespace amazon_cellphones {
|
||||
|
||||
using namespace simdjson;
|
||||
|
||||
struct simdjson_dom {
|
||||
using StringType = std::string;
|
||||
|
||||
dom::parser parser{};
|
||||
|
||||
bool run(simdjson::padded_string &json, std::map<StringType, brand> &result) {
|
||||
auto stream = parser.parse_many(json);
|
||||
auto i = stream.begin();
|
||||
++i; // Skip first line
|
||||
for (;i != stream.end(); ++i) {
|
||||
auto doc = *i;
|
||||
StringType copy(std::string_view(doc.at(1)));
|
||||
auto x = result.find(copy);
|
||||
if (x == result.end()) { // If key not found, add new key
|
||||
result.emplace(copy, amazon_cellphones::brand{
|
||||
double(doc.at(5)) * uint64_t(doc.at(7)),
|
||||
uint64_t(doc.at(7))
|
||||
});
|
||||
} else { // Otherwise, update key data
|
||||
x->second.cumulative_rating += double(doc.at(5)) * uint64_t(doc.at(7));
|
||||
x->second.reviews_count += uint64_t(doc.at(7));
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
BENCHMARK_TEMPLATE(amazon_cellphones, simdjson_dom)->UseManualTime();
|
||||
|
||||
} // namespace amazon_cellphones
|
||||
|
||||
#endif // SIMDJSON_EXCEPTIONS
|
||||
@@ -1,65 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
|
||||
#include "amazon_cellphones.h"
|
||||
|
||||
namespace amazon_cellphones {
|
||||
|
||||
using namespace simdjson;
|
||||
|
||||
struct simdjson_ondemand {
|
||||
using StringType = std::string;
|
||||
|
||||
ondemand::parser parser{};
|
||||
|
||||
bool run(simdjson::padded_string &json, std::map<StringType, brand> &result) {
|
||||
ondemand::document_stream stream = parser.iterate_many(json);
|
||||
ondemand::document_stream::iterator i = stream.begin();
|
||||
++i; // Skip first line
|
||||
for (;i != stream.end(); ++i) {
|
||||
auto & doc = *i;
|
||||
size_t index{0};
|
||||
StringType copy;
|
||||
double rating;
|
||||
uint64_t reviews;
|
||||
for ( auto value : doc ) {
|
||||
switch (index)
|
||||
{
|
||||
case 1:
|
||||
copy = StringType(std::string_view(value));
|
||||
break;
|
||||
case 5:
|
||||
rating = double(value);
|
||||
break;
|
||||
case 7:
|
||||
reviews = uint64_t(value);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
index++;
|
||||
}
|
||||
|
||||
auto x = result.find(copy);
|
||||
if (x == result.end()) { // If key not found, add new key
|
||||
result.emplace(copy, amazon_cellphones::brand{
|
||||
rating * reviews,
|
||||
reviews
|
||||
});
|
||||
} else { // Otherwise, update key data
|
||||
x->second.cumulative_rating += rating * reviews;
|
||||
x->second.reviews_count += reviews;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
BENCHMARK_TEMPLATE(amazon_cellphones, simdjson_ondemand)->UseManualTime();
|
||||
|
||||
} // namespace amazon_cellphones
|
||||
|
||||
#endif // SIMDJSON_EXCEPTIONS
|
||||
@@ -26,20 +26,12 @@ SIMDJSON_PUSH_DISABLE_ALL_WARNINGS
|
||||
|
||||
SIMDJSON_POP_DISABLE_WARNINGS
|
||||
|
||||
#include "amazon_cellphones/simdjson_dom.h"
|
||||
#include "amazon_cellphones/simdjson_ondemand.h"
|
||||
|
||||
#include "large_amazon_cellphones/simdjson_dom.h"
|
||||
#include "large_amazon_cellphones/simdjson_ondemand.h"
|
||||
|
||||
#include "partial_tweets/simdjson_dom.h"
|
||||
#include "partial_tweets/simdjson_ondemand.h"
|
||||
#include "partial_tweets/yyjson.h"
|
||||
#include "partial_tweets/sajson.h"
|
||||
#include "partial_tweets/rapidjson.h"
|
||||
#include "partial_tweets/rapidjson_sax.h"
|
||||
#include "partial_tweets/nlohmann_json.h"
|
||||
#include "partial_tweets/nlohmann_json_sax.h"
|
||||
|
||||
#include "large_random/simdjson_dom.h"
|
||||
#include "large_random/simdjson_ondemand.h"
|
||||
@@ -47,46 +39,34 @@ SIMDJSON_POP_DISABLE_WARNINGS
|
||||
#include "large_random/yyjson.h"
|
||||
#include "large_random/sajson.h"
|
||||
#include "large_random/rapidjson.h"
|
||||
#include "large_random/rapidjson_sax.h"
|
||||
#include "large_random/nlohmann_json.h"
|
||||
#include "large_random/nlohmann_json_sax.h"
|
||||
|
||||
#include "kostya/simdjson_dom.h"
|
||||
#include "kostya/simdjson_ondemand.h"
|
||||
#include "kostya/yyjson.h"
|
||||
#include "kostya/sajson.h"
|
||||
#include "kostya/rapidjson.h"
|
||||
#include "kostya/rapidjson_sax.h"
|
||||
#include "kostya/nlohmann_json.h"
|
||||
#include "kostya/nlohmann_json_sax.h"
|
||||
|
||||
#include "distinct_user_id/simdjson_dom.h"
|
||||
#include "distinct_user_id/simdjson_dom_json_pointer.h"
|
||||
#include "distinct_user_id/simdjson_ondemand.h"
|
||||
#include "distinct_user_id/simdjson_ondemand_json_pointer.h"
|
||||
#include "distinct_user_id/yyjson.h"
|
||||
#include "distinct_user_id/sajson.h"
|
||||
#include "distinct_user_id/rapidjson.h"
|
||||
#include "distinct_user_id/rapidjson_sax.h"
|
||||
#include "distinct_user_id/nlohmann_json.h"
|
||||
#include "distinct_user_id/nlohmann_json_sax.h"
|
||||
|
||||
#include "find_tweet/simdjson_dom.h"
|
||||
#include "find_tweet/simdjson_ondemand.h"
|
||||
#include "find_tweet/yyjson.h"
|
||||
#include "find_tweet/sajson.h"
|
||||
#include "find_tweet/rapidjson.h"
|
||||
#include "find_tweet/rapidjson_sax.h"
|
||||
#include "find_tweet/nlohmann_json.h"
|
||||
#include "find_tweet/nlohmann_json_sax.h"
|
||||
|
||||
#include "top_tweet/simdjson_dom.h"
|
||||
#include "top_tweet/simdjson_ondemand.h"
|
||||
#include "top_tweet/yyjson.h"
|
||||
#include "top_tweet/sajson.h"
|
||||
#include "top_tweet/rapidjson.h"
|
||||
#include "top_tweet/rapidjson_sax.h"
|
||||
#include "top_tweet/nlohmann_json.h"
|
||||
#include "top_tweet/nlohmann_json_sax.h"
|
||||
|
||||
BENCHMARK_MAIN();
|
||||
|
||||
@@ -10,64 +10,6 @@ const char *GSOC_JSON = SIMDJSON_BENCHMARK_DATA_DIR "gsoc-2018.json";
|
||||
|
||||
|
||||
|
||||
|
||||
static void fast_minify_twitter(State& state) {
|
||||
dom::parser parser;
|
||||
padded_string docdata;
|
||||
auto error = padded_string::load(TWITTER_JSON).get(docdata);
|
||||
if(error) {
|
||||
cerr << "could not parse twitter.json" << error << endl;
|
||||
return;
|
||||
}
|
||||
std::unique_ptr<char[]> buffer{new char[docdata.size()]};
|
||||
|
||||
size_t bytes = 0;
|
||||
for (simdjson_unused auto _ : state) {
|
||||
size_t new_length{}; // It will receive the minified length.
|
||||
auto error = simdjson::minify(docdata.data(), docdata.size(), buffer.get(), new_length);
|
||||
bytes += docdata.size();
|
||||
benchmark::DoNotOptimize(error);
|
||||
}
|
||||
// Gigabyte: https://en.wikipedia.org/wiki/Gigabyte
|
||||
state.counters["Gigabytes"] = benchmark::Counter(
|
||||
double(bytes), benchmark::Counter::kIsRate,
|
||||
benchmark::Counter::OneK::kIs1000); // For GiB : kIs1024
|
||||
state.counters["docs"] = Counter(double(state.iterations()), benchmark::Counter::kIsRate);
|
||||
}
|
||||
BENCHMARK(fast_minify_twitter)->Repetitions(10)->ComputeStatistics("max", [](const std::vector<double>& v) -> double {
|
||||
return *(std::max_element(std::begin(v), std::end(v)));
|
||||
})->DisplayAggregatesOnly(true);
|
||||
|
||||
|
||||
|
||||
|
||||
static void fast_minify_gsoc(State& state) {
|
||||
dom::parser parser;
|
||||
padded_string docdata;
|
||||
auto error = padded_string::load(GSOC_JSON).get(docdata);
|
||||
if(error) {
|
||||
cerr << "could not parse gsoc-2018.json" << error << endl;
|
||||
return;
|
||||
}
|
||||
std::unique_ptr<char[]> buffer{new char[docdata.size()]};
|
||||
|
||||
size_t bytes = 0;
|
||||
for (simdjson_unused auto _ : state) {
|
||||
size_t new_length{}; // It will receive the minified length.
|
||||
auto error = simdjson::minify(docdata.data(), docdata.size(), buffer.get(), new_length);
|
||||
bytes += docdata.size();
|
||||
benchmark::DoNotOptimize(error);
|
||||
}
|
||||
// Gigabyte: https://en.wikipedia.org/wiki/Gigabyte
|
||||
state.counters["Gigabytes"] = benchmark::Counter(
|
||||
double(bytes), benchmark::Counter::kIsRate,
|
||||
benchmark::Counter::OneK::kIs1000); // For GiB : kIs1024
|
||||
state.counters["docs"] = Counter(double(state.iterations()), benchmark::Counter::kIsRate);
|
||||
}
|
||||
BENCHMARK(fast_minify_gsoc)->Repetitions(10)->ComputeStatistics("max", [](const std::vector<double>& v) -> double {
|
||||
return *(std::max_element(std::begin(v), std::end(v)));
|
||||
})->DisplayAggregatesOnly(true);
|
||||
|
||||
static void unicode_validate_twitter(State& state) {
|
||||
dom::parser parser;
|
||||
padded_string docdata;
|
||||
|
||||
@@ -331,7 +331,7 @@ struct benchmarker {
|
||||
|
||||
// Stage 1 (find structurals)
|
||||
collector.start();
|
||||
error = parser.implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.size(), stage1_mode::regular);
|
||||
error = parser.implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.size(), false);
|
||||
event_count stage1_count = collector.end();
|
||||
stage1 << stage1_count;
|
||||
if (error) {
|
||||
|
||||
@@ -5,12 +5,9 @@
|
||||
# checkperf-repo: initialize and sync reference repository (first time only)
|
||||
# TEST checkperf: runs the actual checkperf test
|
||||
|
||||
option(SIMDJSON_ENABLE_DOM_CHECKPERF "Enable DOM performance comparison with main branch" OFF)
|
||||
|
||||
|
||||
# Clone the repository if it's not there
|
||||
find_package(Git QUIET)
|
||||
if (SIMDJSON_ENABLE_DOM_CHECKPERF AND Git_FOUND AND (GIT_VERSION_STRING VERSION_GREATER "2.1.4") AND (NOT CMAKE_GENERATOR MATCHES Ninja) AND (NOT MSVC) ) # We use "-C" which requires a recent git
|
||||
if (Git_FOUND AND (GIT_VERSION_STRING VERSION_GREATER "2.1.4") AND (NOT CMAKE_GENERATOR MATCHES Ninja) AND (NOT MSVC) ) # We use "-C" which requires a recent git
|
||||
message(STATUS "Git is available and it is recent. We are enabling checkperf targets.")
|
||||
# sync_git_repository(myrepo ...) creates two targets:
|
||||
# myrepo - if the repo does not exist, creates and syncs it against the origin branch
|
||||
@@ -64,13 +61,7 @@ if (SIMDJSON_ENABLE_DOM_CHECKPERF AND Git_FOUND AND (GIT_VERSION_STRING VERSION_
|
||||
OUTPUT ${SIMDJSON_CHECKPERF_DIR}/build/cmake_install.cmake # We make many things but this seems the most cross-platform one we can depend on
|
||||
COMMAND
|
||||
${CMAKE_COMMAND} -E env CXX=${CMAKE_CXX_COMPILER} CC=${CMAKE_C_COMPILER}
|
||||
${CMAKE_COMMAND}
|
||||
-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}
|
||||
-DSIMDJSON_GOOGLE_BENCHMARKS=OFF
|
||||
-DSIMDJSON_COMPETITION=OFF
|
||||
-DSIMDJSON_DEVELOPER_MODE=YES
|
||||
-G ${CMAKE_GENERATOR}
|
||||
..
|
||||
${CMAKE_COMMAND} -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} -DSIMDJSON_GOOGLE_BENCHMARKS=OFF -DSIMDJSON_COMPETITION=OFF -G ${CMAKE_GENERATOR} ..
|
||||
WORKING_DIRECTORY ${SIMDJSON_CHECKPERF_DIR}/build
|
||||
DEPENDS ${SIMDJSON_CHECKPERF_DIR}/build/CMakeCache.txt
|
||||
)
|
||||
@@ -79,7 +70,7 @@ if (SIMDJSON_ENABLE_DOM_CHECKPERF AND Git_FOUND AND (GIT_VERSION_STRING VERSION_
|
||||
if (CMAKE_CONFIGURATION_TYPES)
|
||||
set(CHECKPERF_PARSE ${SIMDJSON_CHECKPERF_DIR}/build/benchmark/$<CONFIGURATION>/parse)
|
||||
else()
|
||||
set(CHECKPERF_PARSE ${SIMDJSON_CHECKPERF_DIR}/build/benchmark/dom/parse)
|
||||
set(CHECKPERF_PARSE ${SIMDJSON_CHECKPERF_DIR}/build/benchmark/parse)
|
||||
endif()
|
||||
add_custom_target(
|
||||
checkperf-parse ALL # TODO is ALL necessary?
|
||||
@@ -101,8 +92,6 @@ if (SIMDJSON_ENABLE_DOM_CHECKPERF AND Git_FOUND AND (GIT_VERSION_STRING VERSION_
|
||||
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)
|
||||
add_dependencies(per_implementation_tests checkperf)
|
||||
add_dependencies(explicitonly_tests checkperf)
|
||||
else()
|
||||
if (CMAKE_GENERATOR MATCHES Ninja)
|
||||
message(STATUS "We disable the checkperf targets under Ninja.")
|
||||
@@ -1,59 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef SIMDJSON_COMPETITION_NLOHMANN_JSON
|
||||
|
||||
#include "distinct_user_id.h"
|
||||
|
||||
namespace distinct_user_id {
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
struct nlohmann_json_sax {
|
||||
struct Handler : json::json_sax_t
|
||||
{
|
||||
std::vector<uint64_t>& result;
|
||||
bool user = false;
|
||||
bool user_id = false;
|
||||
Handler(std::vector<uint64_t> &r) : result(r) { }
|
||||
|
||||
bool key(string_t& val) override {
|
||||
// Assume that valid user/id pairs appear only once in main array of user objects
|
||||
if (user) { // If already found user object, find id key
|
||||
if (val.compare("id") == 0) { user_id = true; }
|
||||
}
|
||||
else if (val.compare("user") == 0) { user = true; } // Otherwise, find user object
|
||||
return true;
|
||||
}
|
||||
bool number_unsigned(number_unsigned_t val) override {
|
||||
if (user_id) {
|
||||
result.emplace_back(val);
|
||||
user = false;
|
||||
user_id = false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
// Irrelevant events
|
||||
bool null() override { return true; }
|
||||
bool boolean(bool val) override { return true; }
|
||||
bool number_float(number_float_t val, const string_t& s) override { return true; }
|
||||
bool number_integer(number_integer_t val) override { return true; }
|
||||
bool string(string_t& val) override { return true; }
|
||||
bool start_object(std::size_t elements) override { return true; }
|
||||
bool end_object() override { return true; }
|
||||
bool start_array(std::size_t elements) override { return true; }
|
||||
bool end_array() override { return true; }
|
||||
bool binary(json::binary_t& val) override { return true; }
|
||||
bool parse_error(std::size_t position, const std::string& last_token, const json::exception& ex) override { return false; }
|
||||
}; // Handler
|
||||
|
||||
bool run(simdjson::padded_string &json, std::vector<uint64_t> &result) {
|
||||
Handler handler(result);
|
||||
json::sax_parse(json.data(), &handler);
|
||||
|
||||
return true;
|
||||
}
|
||||
}; // nlohmann_json_sax
|
||||
BENCHMARK_TEMPLATE(distinct_user_id, nlohmann_json_sax)->UseManualTime();
|
||||
} // namespace distinct_user_id
|
||||
|
||||
#endif // SIMDJSON_COMPETITION_NLOHMANN_JSON
|
||||
@@ -1,61 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef SIMDJSON_COMPETITION_RAPIDJSON
|
||||
|
||||
#include "distinct_user_id.h"
|
||||
#include <string.h>
|
||||
namespace distinct_user_id {
|
||||
|
||||
using namespace rapidjson;
|
||||
|
||||
struct rapidjson_sax {
|
||||
struct Handler {
|
||||
std::vector<uint64_t>& result;
|
||||
bool user = false;
|
||||
bool user_id = false;
|
||||
Handler(std::vector<uint64_t> &r) : result(r) { }
|
||||
|
||||
bool Key(const char* key, SizeType length, bool copy) {
|
||||
// Assume that valid user/id pairs appear only once in main array of user objects
|
||||
if (user) { // If already found user object, find id key
|
||||
if ((length == 2) && memcmp(key,"id",2) == 0) { user_id = true; }
|
||||
}
|
||||
else if ((length == 4) && memcmp(key,"user",4) == 0) { user = true; } // Otherwise, find user object
|
||||
return true;
|
||||
}
|
||||
bool Uint(unsigned i) { // id values are treated as Uint (not Uint64) by the reader
|
||||
if (user_id) { // Getting id if previous key was "id" for a user
|
||||
result.emplace_back(i);
|
||||
user_id = false;
|
||||
user = false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
// Irrelevant events
|
||||
bool Null() { return true; }
|
||||
bool Bool(bool b) { return true; }
|
||||
bool Double(double d) { return true; }
|
||||
bool Int(int i) { return true; }
|
||||
bool Int64(int64_t i) { return true; }
|
||||
bool Uint64(uint64_t i) { return true; }
|
||||
bool RawNumber(const char* str, SizeType length, bool copy) { return true; }
|
||||
bool String(const char* str, SizeType length, bool copy) { return true; }
|
||||
bool StartObject() { return true; }
|
||||
bool EndObject(SizeType memberCount) { return true; }
|
||||
bool StartArray() { return true; }
|
||||
bool EndArray(SizeType elementCount) { return true; }
|
||||
}; // handler
|
||||
|
||||
bool run(simdjson::padded_string &json, std::vector<uint64_t> &result) {
|
||||
Reader reader;
|
||||
Handler handler(result);
|
||||
InsituStringStream ss(json.data());
|
||||
reader.Parse<kParseInsituFlag | kParseValidateEncodingFlag | kParseFullPrecisionFlag>(ss,handler);
|
||||
return true;
|
||||
}
|
||||
|
||||
}; // rapid_jason_sax
|
||||
BENCHMARK_TEMPLATE(distinct_user_id, rapidjson_sax)->UseManualTime();
|
||||
} // namespace distinct_user_id
|
||||
|
||||
#endif // SIMDJSON_COMPETITION_RAPIDJSON
|
||||
@@ -1,36 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
|
||||
#include "distinct_user_id.h"
|
||||
|
||||
namespace distinct_user_id {
|
||||
|
||||
using namespace simdjson;
|
||||
|
||||
struct simdjson_dom_json_pointer {
|
||||
dom::parser parser{};
|
||||
|
||||
bool run(simdjson::padded_string &json, std::vector<uint64_t> &result) {
|
||||
// Walk the document, parsing as we go
|
||||
auto doc = parser.parse(json);
|
||||
for (dom::object tweet : doc["statuses"]) {
|
||||
// We believe that all statuses have a matching
|
||||
// user, and we are willing to throw when they do not.
|
||||
result.push_back(tweet.at_pointer("/user/id"));
|
||||
// Not all tweets have a "retweeted_status", but when they do
|
||||
// we want to go and find the user within.
|
||||
auto retweet_id = tweet.at_pointer("/retweeted_status/user/id");
|
||||
if (retweet_id.error() != NO_SUCH_FIELD) {
|
||||
result.push_back(retweet_id);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
BENCHMARK_TEMPLATE(distinct_user_id, simdjson_dom_json_pointer)->UseManualTime();
|
||||
|
||||
} // namespace distinct_user_id
|
||||
|
||||
#endif // SIMDJSON_EXCEPTIONS
|
||||
@@ -1,37 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
|
||||
#include "distinct_user_id.h"
|
||||
|
||||
namespace distinct_user_id {
|
||||
|
||||
using namespace simdjson;
|
||||
|
||||
struct simdjson_ondemand_json_pointer {
|
||||
ondemand::parser parser{};
|
||||
|
||||
bool run(simdjson::padded_string &json, std::vector<uint64_t> &result) {
|
||||
// Walk the document, parsing as we go
|
||||
auto doc = parser.iterate(json);
|
||||
for (ondemand::object tweet : doc.find_field("statuses")) {
|
||||
// We believe that all statuses have a matching
|
||||
// user, and we are willing to throw when they do not.
|
||||
result.push_back(tweet.at_pointer("/user/id"));
|
||||
// Not all tweets have a "retweeted_status", but when they do
|
||||
// we want to go and find the user within.
|
||||
auto retweet_id = tweet.at_pointer("/retweeted_status/user/id");
|
||||
if (retweet_id.error() != NO_SUCH_FIELD) {
|
||||
result.push_back(retweet_id);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
BENCHMARK_TEMPLATE(distinct_user_id, simdjson_ondemand_json_pointer)->UseManualTime();
|
||||
|
||||
} // namespace distinct_user_id
|
||||
|
||||
#endif // SIMDJSON_EXCEPTIONS
|
||||
@@ -1,16 +0,0 @@
|
||||
include_directories( .. ../linux )
|
||||
link_libraries(simdjson-windows-headers test-data)
|
||||
link_libraries(simdjson)
|
||||
|
||||
add_executable(perfdiff perfdiff.cpp)
|
||||
add_executable(parse parse.cpp)
|
||||
add_executable(parse_stream parse_stream.cpp)
|
||||
add_executable(statisticalmodel statisticalmodel.cpp)
|
||||
|
||||
add_executable(parse_noutf8validation parse.cpp)
|
||||
target_compile_definitions(parse_noutf8validation PRIVATE SIMDJSON_SKIPUTF8VALIDATION)
|
||||
add_executable(parse_nonumberparsing parse.cpp)
|
||||
target_compile_definitions(parse_nonumberparsing PRIVATE SIMDJSON_SKIPNUMBERPARSING)
|
||||
add_executable(parse_nostringparsing parse.cpp)
|
||||
target_compile_definitions(parse_nostringparsing PRIVATE SIMDJSON_SKIPSTRINGPARSING)
|
||||
include(checkperf.cmake)
|
||||
@@ -1,68 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef SIMDJSON_COMPETITION_NLOHMANN_JSON
|
||||
|
||||
#include "find_tweet.h"
|
||||
|
||||
namespace find_tweet {
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
struct nlohmann_json_sax {
|
||||
using StringType=std::string;
|
||||
|
||||
struct Handler : json::json_sax_t
|
||||
{
|
||||
bool text_key = false;
|
||||
bool id_key = false;
|
||||
bool found_id = false;
|
||||
uint64_t find_id;
|
||||
std::string &result;
|
||||
|
||||
Handler(std::string &r,uint64_t id): result(r), find_id(id) { }
|
||||
|
||||
// We assume id is found before text
|
||||
bool key(string_t& val) override {
|
||||
if (found_id) { // If have found id, find text key
|
||||
if (val.compare("text") == 0) { text_key = true; }
|
||||
}
|
||||
else if (val.compare("id") == 0) { id_key = true; } // Otherwise, find id key
|
||||
return true;
|
||||
}
|
||||
bool number_unsigned(number_unsigned_t val) override {
|
||||
if (id_key && (val == find_id)) { // If id key, check if id value matches find_id
|
||||
found_id = true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool string(string_t& val) override {
|
||||
if (text_key) {
|
||||
result = val;
|
||||
return false; // End parsing
|
||||
}
|
||||
return true;
|
||||
}
|
||||
// Irrelevant events
|
||||
bool null() override { return true; }
|
||||
bool boolean(bool val) override { return true; }
|
||||
bool number_float(number_float_t val, const string_t& s) override { return true; }
|
||||
bool number_integer(number_integer_t val) override { return true; }
|
||||
bool start_object(std::size_t elements) override { return true; }
|
||||
bool end_object() override { return true; }
|
||||
bool start_array(std::size_t elements) override { return true; }
|
||||
bool end_array() override { return true; }
|
||||
bool binary(json::binary_t& val) override { return true; }
|
||||
bool parse_error(std::size_t position, const std::string& last_token, const json::exception& ex) override { return false; }
|
||||
}; // Handler
|
||||
|
||||
bool run(simdjson::padded_string &json, uint64_t find_id, std::string &result) {
|
||||
Handler handler(result,find_id);
|
||||
json::sax_parse(json.data(), &handler);
|
||||
|
||||
return true;
|
||||
}
|
||||
}; // nlohmann_json_sax
|
||||
BENCHMARK_TEMPLATE(find_tweet, nlohmann_json_sax)->UseManualTime();
|
||||
} // namespace find_tweet
|
||||
|
||||
#endif // SIMDJSON_COMPETITION_NLOHMANN_JSON
|
||||
@@ -47,6 +47,6 @@ struct rapidjson_insitu : rapidjson_base {
|
||||
};
|
||||
BENCHMARK_TEMPLATE(find_tweet, rapidjson_insitu)->UseManualTime();
|
||||
|
||||
} // namespace find_tweet
|
||||
} // namespace partial_tweets
|
||||
|
||||
#endif // SIMDJSON_COMPETITION_RAPIDJSON
|
||||
|
||||
@@ -1,70 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef SIMDJSON_COMPETITION_RAPIDJSON
|
||||
|
||||
#include "find_tweet.h"
|
||||
#include <string.h>
|
||||
|
||||
namespace find_tweet {
|
||||
|
||||
using namespace rapidjson;
|
||||
|
||||
struct rapidjson_sax {
|
||||
using StringType=std::string_view;
|
||||
|
||||
struct Handler {
|
||||
bool text_key = false;
|
||||
bool id_key = false;
|
||||
bool found_id = false;
|
||||
uint64_t find_id;
|
||||
std::string_view &result;
|
||||
|
||||
Handler(std::string_view &r,uint64_t id): result(r), find_id(id) { }
|
||||
|
||||
// We assume id is found before text
|
||||
bool Key(const char* key, SizeType length, bool copy) {
|
||||
if (found_id) { // If have found id, find text key
|
||||
if ((length == 4) && (memcmp(key,"text",4) == 0)) { text_key = true; }
|
||||
}
|
||||
else if ((length == 2) && (memcmp(key,"id",2) == 0)) { id_key = true; } // Otherwise, find id key
|
||||
return true;
|
||||
}
|
||||
bool Uint64(uint64_t i) {
|
||||
if (id_key && (i == find_id)) { // If id key, check if id value matches find_id
|
||||
found_id = true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool String(const char* str, SizeType length, bool copy) {
|
||||
if (text_key) {
|
||||
result = {str,length};
|
||||
return false; // End parsing
|
||||
}
|
||||
return true;
|
||||
}
|
||||
// Irrelevant events
|
||||
bool Null() { return true; }
|
||||
bool Bool(bool b) { return true; }
|
||||
bool Double(double d) { return true; }
|
||||
bool Int(int i) { return true; }
|
||||
bool Int64(int64_t i) { return true; }
|
||||
bool Uint(unsigned i) { return true; }
|
||||
bool RawNumber(const char* str, SizeType length, bool copy) { return true; }
|
||||
bool StartObject() { return true; }
|
||||
bool EndObject(SizeType memberCount) { return true; }
|
||||
bool StartArray() { return true; }
|
||||
bool EndArray(SizeType elementCount) { return true; }
|
||||
}; // handler
|
||||
|
||||
bool run(simdjson::padded_string &json, uint64_t find_id, std::string_view &result) {
|
||||
Reader reader;
|
||||
Handler handler(result,find_id);
|
||||
InsituStringStream ss(json.data());
|
||||
reader.Parse<kParseInsituFlag | kParseValidateEncodingFlag | kParseFullPrecisionFlag>(ss,handler);
|
||||
return true;
|
||||
}
|
||||
}; // rapidjson_sax
|
||||
BENCHMARK_TEMPLATE(find_tweet, rapidjson_sax)->UseManualTime();
|
||||
} // namespace find_tweet
|
||||
|
||||
#endif // SIMDJSON_COMPETITION_RAPIDJSON
|
||||
@@ -4,6 +4,5 @@ namespace json_benchmark {
|
||||
|
||||
static constexpr const char *TWITTER_JSON = SIMDJSON_BENCHMARK_DATA_DIR "twitter.json";
|
||||
static constexpr const char *NUMBERS_JSON = SIMDJSON_BENCHMARK_DATA_DIR "numbers.json";
|
||||
static constexpr const char *AMAZON_CELLPHONES_NDJSON = SIMDJSON_BENCHMARK_DATA_DIR "amazon_cellphones.ndjson";
|
||||
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <sstream>
|
||||
#include <limits>
|
||||
|
||||
@@ -53,56 +52,6 @@ struct result_differ<std::vector<T>, std::vector<U>> {
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T, typename U, typename StringType>
|
||||
struct result_differ<std::map<StringType,T>, std::map<StringType,U>> {
|
||||
static bool diff(benchmark::State &state, const std::map<StringType,T> &result, const std::map<StringType,U> &reference, diff_flags flags) {
|
||||
auto result_iter = result.begin();
|
||||
auto reference_iter = reference.begin();
|
||||
while (result_iter != result.end() && reference_iter != reference.end()) {
|
||||
if (!diff_results(state, *result_iter, *reference_iter, flags)) { return false; }
|
||||
result_iter++;
|
||||
reference_iter++;
|
||||
}
|
||||
if (result_iter != result.end()) {
|
||||
std::stringstream str;
|
||||
str << "extra results (got " << result.size() << ", expected " << reference.size() << "): first extra element: " << *result_iter;
|
||||
state.SkipWithError(str.str().data());
|
||||
return false;
|
||||
} else if (reference_iter != reference.end()) {
|
||||
std::stringstream str;
|
||||
str << "missing results (got " << result.size() << ", expected " << reference.size() << "): first missing element: " << *reference_iter;
|
||||
state.SkipWithError(str.str().data());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T, typename U>
|
||||
struct result_differ<std::map<std::string_view,T>, std::vector<std::string_view,U>> {
|
||||
static bool diff(benchmark::State &state, const std::map<std::string_view,T> &result, const std::map<std::string_view,U> &reference, diff_flags flags) {
|
||||
auto result_iter = result.begin();
|
||||
auto reference_iter = reference.begin();
|
||||
while (result_iter != result.end() && reference_iter != reference.end()) {
|
||||
if (!diff_results(state, *result_iter, *reference_iter, flags)) { return false; }
|
||||
result_iter++;
|
||||
reference_iter++;
|
||||
}
|
||||
if (result_iter != result.end()) {
|
||||
std::stringstream str;
|
||||
str << "extra results (got " << result.size() << ", expected " << reference.size() << "): first extra element: " << *result_iter;
|
||||
state.SkipWithError(str.str().data());
|
||||
return false;
|
||||
} else if (reference_iter != reference.end()) {
|
||||
std::stringstream str;
|
||||
str << "missing results (got " << result.size() << ", expected " << reference.size() << "): first missing element: " << *reference_iter;
|
||||
state.SkipWithError(str.str().data());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct result_differ<double, double> {
|
||||
static bool diff(benchmark::State &state, const double &result, const double &reference, diff_flags flags) {
|
||||
|
||||
@@ -1,74 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef SIMDJSON_COMPETITION_NLOHMANN_JSON
|
||||
|
||||
#include "kostya.h"
|
||||
|
||||
namespace kostya {
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
struct nlohmann_json_sax {
|
||||
static constexpr diff_flags DiffFlags = diff_flags::NONE;
|
||||
|
||||
struct Handler : json::json_sax_t
|
||||
{
|
||||
size_t k{0};
|
||||
double buffer[3];
|
||||
std::vector<point>& result;
|
||||
|
||||
Handler(std::vector<point>& r) : result(r) { }
|
||||
|
||||
bool key(string_t& val) override {
|
||||
switch(val[0]) {
|
||||
case 'x':
|
||||
k = 0;
|
||||
break;
|
||||
case 'y':
|
||||
k = 1;
|
||||
break;
|
||||
case 'z':
|
||||
k = 2;
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool number_float(number_float_t val, const string_t& s) override {
|
||||
buffer[k] = val;
|
||||
if (k == 2) {
|
||||
result.emplace_back(json_benchmark::point{buffer[0],buffer[1],buffer[2]});
|
||||
k = 0;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool number_unsigned(number_unsigned_t val) override { // Need this event because coordinate value can be equal to 1
|
||||
buffer[k] = val;
|
||||
if (k == 2) {
|
||||
result.emplace_back(json_benchmark::point{buffer[0],buffer[1],buffer[2]});
|
||||
k = 0;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
// Irrelevant events
|
||||
bool null() override { return true; }
|
||||
bool boolean(bool val) override { return true; }
|
||||
bool number_integer(number_integer_t val) override { return true; }
|
||||
bool string(string_t& val) override { return true; }
|
||||
bool start_object(std::size_t elements) override { return true; }
|
||||
bool end_object() override { return true; }
|
||||
bool start_array(std::size_t elements) override { return true; }
|
||||
bool end_array() override { return true; }
|
||||
bool binary(json::binary_t& val) override { return true; }
|
||||
bool parse_error(std::size_t position, const std::string& last_token, const json::exception& ex) override { return false; }
|
||||
}; // Handler
|
||||
|
||||
bool run(simdjson::padded_string &json, std::vector<point> &result) {
|
||||
Handler handler(result);
|
||||
json::sax_parse(json.data(), &handler);
|
||||
return true;
|
||||
}
|
||||
}; // nlohmann_json_sax
|
||||
BENCHMARK_TEMPLATE(kostya, nlohmann_json_sax)->UseManualTime();
|
||||
} // namespace kostya
|
||||
|
||||
#endif // SIMDJSON_COMPETITION_NLOHMANN_JSON
|
||||
@@ -1,70 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef SIMDJSON_COMPETITION_RAPIDJSON
|
||||
|
||||
#include "kostya.h"
|
||||
|
||||
namespace kostya {
|
||||
|
||||
using namespace rapidjson;
|
||||
|
||||
struct rapidjson_sax {
|
||||
static constexpr diff_flags DiffFlags = diff_flags::NONE;
|
||||
|
||||
struct Handler {
|
||||
size_t k{0};
|
||||
double buffer[3];
|
||||
std::vector<point>& result;
|
||||
|
||||
Handler(std::vector<point> &r) : result(r) { }
|
||||
|
||||
bool Key(const char* key, SizeType length, bool copy) {
|
||||
switch(key[0]) {
|
||||
case 'x':
|
||||
k = 0;
|
||||
break;
|
||||
case 'y':
|
||||
k = 1;
|
||||
break;
|
||||
case 'z':
|
||||
k = 2;
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool Double(double d) {
|
||||
buffer[k] = d;
|
||||
if (k == 2) {
|
||||
result.emplace_back(json_benchmark::point{buffer[0],buffer[1],buffer[2]});
|
||||
k = 0;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool Uint(unsigned i) { return Double(i); } // Need this event because coordinate value can be equal to 1
|
||||
// Irrelevant events
|
||||
bool Null() { return true; }
|
||||
bool Bool(bool b) { return true; }
|
||||
bool Int(int i) { return true; }
|
||||
bool Int64(int64_t i) { return true; }
|
||||
bool Uint64(uint64_t i) { return true; }
|
||||
bool RawNumber(const char* str, SizeType length, bool copy) { return true; }
|
||||
bool String(const char* str, SizeType length, bool copy) { return true; }
|
||||
bool StartObject() { return true; }
|
||||
bool EndObject(SizeType memberCount) { return true; }
|
||||
bool StartArray() { return true; }
|
||||
bool EndArray(SizeType elementCount) { return true; }
|
||||
}; // handler
|
||||
|
||||
bool run(simdjson::padded_string &json, std::vector<point> &result) {
|
||||
Reader reader;
|
||||
Handler handler(result);
|
||||
InsituStringStream ss(json.data());
|
||||
reader.Parse<kParseInsituFlag | kParseValidateEncodingFlag | kParseFullPrecisionFlag>(ss,handler);
|
||||
return true;
|
||||
}
|
||||
|
||||
}; // rapid_jason_sax
|
||||
BENCHMARK_TEMPLATE(kostya, rapidjson_sax)->UseManualTime();
|
||||
} // namespace kostya
|
||||
|
||||
#endif // SIMDJSON_COMPETITION_RAPIDJSON
|
||||
@@ -1,91 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "json_benchmark/string_runner.h"
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
namespace large_amazon_cellphones {
|
||||
|
||||
static const simdjson::padded_string &get_built_json();
|
||||
|
||||
using namespace json_benchmark;
|
||||
|
||||
struct brand {
|
||||
double cumulative_rating;
|
||||
uint64_t reviews_count;
|
||||
simdjson_really_inline bool operator==(const brand &other) const {
|
||||
return cumulative_rating == other.cumulative_rating &&
|
||||
reviews_count == other.reviews_count;
|
||||
}
|
||||
simdjson_really_inline bool operator!=(const brand &other) const { return !(*this == other); }
|
||||
};
|
||||
|
||||
simdjson_unused static std::ostream &operator<<(std::ostream &o, const brand &b) {
|
||||
o << "cumulative_rating: " << b.cumulative_rating << std::endl;
|
||||
o << "reviews_count: " << b.reviews_count << std::endl;
|
||||
return o;
|
||||
}
|
||||
|
||||
template<typename StringType>
|
||||
simdjson_unused static std::ostream &operator<<(std::ostream &o, const std::pair<const StringType, brand> &p) {
|
||||
o << "brand: " << p.first << std::endl;
|
||||
o << p.second;
|
||||
return o;
|
||||
}
|
||||
|
||||
template<typename I>
|
||||
struct runner : public string_runner<I> {
|
||||
std::map<typename I::StringType, brand> result{};
|
||||
|
||||
runner() : string_runner<I>(get_built_json()) {}
|
||||
|
||||
bool before_run(benchmark::State &state) {
|
||||
if (!string_runner<I>::before_run(state)) { return false; }
|
||||
result.clear();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool run(benchmark::State &) {
|
||||
return this->implementation.run(this->json, result);
|
||||
}
|
||||
|
||||
template<typename R>
|
||||
bool diff(benchmark::State &state, runner<R> &reference) {
|
||||
return diff_results(state, result, reference.result, diff_flags::NONE);
|
||||
}
|
||||
|
||||
size_t items_per_iteration() {
|
||||
return result.size();
|
||||
}
|
||||
};
|
||||
|
||||
static std::string build_json(size_t N) {
|
||||
std::ifstream in(AMAZON_CELLPHONES_NDJSON);
|
||||
std::string answer((std::istreambuf_iterator<char>(in)), std::istreambuf_iterator<char>());
|
||||
// Find position of first line to exclude it in further copies
|
||||
size_t first_line = answer.find('\n');
|
||||
std::string copy(answer,first_line + 1);
|
||||
size_t count{1};
|
||||
|
||||
while (answer.size() < N) {
|
||||
answer.append(copy);
|
||||
count++;
|
||||
}
|
||||
|
||||
std::cout << "Creating a source file spanning " << (answer.size() + 512) / (1024*1024) << " MB (" << count << " copies of original file)" << std::endl;
|
||||
return answer;
|
||||
}
|
||||
|
||||
static const simdjson::padded_string &get_built_json() {
|
||||
static simdjson::padded_string json = build_json(10*1024*1024);
|
||||
return json;
|
||||
}
|
||||
|
||||
|
||||
struct simdjson_dom;
|
||||
|
||||
template<typename I> simdjson_really_inline static void large_amazon_cellphones(benchmark::State &state) {
|
||||
run_json_benchmark<runner<I>, runner<simdjson_dom>>(state);
|
||||
}
|
||||
|
||||
} // namespace large_amazon_cellphones
|
||||
@@ -1,45 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
|
||||
#include "large_amazon_cellphones.h"
|
||||
#include <algorithm>
|
||||
|
||||
namespace large_amazon_cellphones {
|
||||
|
||||
using namespace simdjson;
|
||||
|
||||
struct simdjson_dom {
|
||||
using StringType = std::string;
|
||||
|
||||
dom::parser parser{};
|
||||
|
||||
bool run(simdjson::padded_string &json, std::map<StringType, brand> &result) {
|
||||
auto stream = parser.parse_many(json);
|
||||
auto i = stream.begin();
|
||||
++i; // Skip first line
|
||||
for (;i != stream.end(); ++i) {
|
||||
auto doc = *i;
|
||||
StringType copy(std::string_view(doc.at(1)));
|
||||
auto x = result.find(copy);
|
||||
if (x == result.end()) { // If key not found, add new key
|
||||
result.emplace(copy, large_amazon_cellphones::brand{
|
||||
double(doc.at(5)) * uint64_t(doc.at(7)),
|
||||
uint64_t(doc.at(7))
|
||||
});
|
||||
} else { // Otherwise, update key data
|
||||
x->second.cumulative_rating += double(doc.at(5)) * uint64_t(doc.at(7));
|
||||
x->second.reviews_count += uint64_t(doc.at(7));
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
BENCHMARK_TEMPLATE(large_amazon_cellphones, simdjson_dom)->UseManualTime();
|
||||
|
||||
} // namespace large_amazon_cellphones
|
||||
|
||||
#endif // SIMDJSON_EXCEPTIONS
|
||||
@@ -1,65 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
|
||||
#include "large_amazon_cellphones.h"
|
||||
|
||||
namespace large_amazon_cellphones {
|
||||
|
||||
using namespace simdjson;
|
||||
|
||||
struct simdjson_ondemand {
|
||||
using StringType = std::string;
|
||||
|
||||
ondemand::parser parser{};
|
||||
|
||||
bool run(simdjson::padded_string &json, std::map<StringType, brand> &result) {
|
||||
ondemand::document_stream stream = parser.iterate_many(json);
|
||||
ondemand::document_stream::iterator i = stream.begin();
|
||||
++i; // Skip first line
|
||||
for (;i != stream.end(); ++i) {
|
||||
auto & doc = *i;
|
||||
size_t index{0};
|
||||
StringType copy;
|
||||
double rating;
|
||||
uint64_t reviews;
|
||||
for ( auto value : doc ) {
|
||||
switch (index)
|
||||
{
|
||||
case 1:
|
||||
copy = StringType(std::string_view(value));
|
||||
break;
|
||||
case 5:
|
||||
rating = double(value);
|
||||
break;
|
||||
case 7:
|
||||
reviews = uint64_t(value);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
index++;
|
||||
}
|
||||
|
||||
auto x = result.find(copy);
|
||||
if (x == result.end()) { // If key not found, add new key
|
||||
result.emplace(copy, large_amazon_cellphones::brand{
|
||||
rating * reviews,
|
||||
reviews
|
||||
});
|
||||
} else { // Otherwise, update key data
|
||||
x->second.cumulative_rating += rating * reviews;
|
||||
x->second.reviews_count += reviews;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
BENCHMARK_TEMPLATE(large_amazon_cellphones, simdjson_ondemand)->UseManualTime();
|
||||
|
||||
} // namespace amazon_cellphones
|
||||
|
||||
#endif // SIMDJSON_EXCEPTIONS
|
||||
@@ -1,73 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef SIMDJSON_COMPETITION_NLOHMANN_JSON
|
||||
|
||||
#include "large_random.h"
|
||||
|
||||
namespace large_random {
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
struct nlohmann_json_sax {
|
||||
static constexpr diff_flags DiffFlags = diff_flags::NONE;
|
||||
|
||||
struct Handler : json::json_sax_t
|
||||
{
|
||||
size_t k{0};
|
||||
double buffer[3];
|
||||
std::vector<point>& result;
|
||||
|
||||
Handler(std::vector<point> &r) : result(r) { }
|
||||
|
||||
bool key(string_t& val) override {
|
||||
switch(val[0]) {
|
||||
case 'x':
|
||||
k = 0;
|
||||
break;
|
||||
case 'y':
|
||||
k = 1;
|
||||
break;
|
||||
case 'z':
|
||||
k = 2;
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool number_unsigned(number_unsigned_t val) override {
|
||||
buffer[k] = val;
|
||||
if (k == 2) {
|
||||
result.emplace_back(json_benchmark::point{buffer[0],buffer[1],buffer[2]});
|
||||
k = 0;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool number_float(number_float_t val, const string_t& s) override {
|
||||
buffer[k] = val;
|
||||
if (k == 2) {
|
||||
result.emplace_back(json_benchmark::point{buffer[0],buffer[1],buffer[2]});
|
||||
k = 0;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
// Irrelevant events
|
||||
bool null() override { return true; }
|
||||
bool boolean(bool val) override { return true; }
|
||||
bool number_integer(number_integer_t val) override { return true; }
|
||||
bool string(string_t& val) override { return true; }
|
||||
bool start_object(std::size_t elements) override { return true; }
|
||||
bool end_object() override { return true; }
|
||||
bool start_array(std::size_t elements) override { return true; }
|
||||
bool end_array() override { return true; }
|
||||
bool binary(json::binary_t& val) override { return true; }
|
||||
bool parse_error(std::size_t position, const std::string& last_token, const json::exception& ex) override { return false; }
|
||||
}; // Handler
|
||||
|
||||
bool run(simdjson::padded_string &json, std::vector<point> &result) {
|
||||
Handler handler(result);
|
||||
json::sax_parse(json.data(), &handler);
|
||||
return true;
|
||||
}
|
||||
}; // nlohmann_json_sax
|
||||
BENCHMARK_TEMPLATE(large_random, nlohmann_json_sax)->UseManualTime();
|
||||
} // namespace large_random
|
||||
#endif // SIMDJSON_COMPETITION_NLOHMANN_JSON
|
||||
@@ -1,69 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef SIMDJSON_COMPETITION_RAPIDJSON
|
||||
|
||||
#include "large_random.h"
|
||||
|
||||
namespace large_random {
|
||||
|
||||
using namespace rapidjson;
|
||||
|
||||
struct rapidjson_sax {
|
||||
static constexpr diff_flags DiffFlags = diff_flags::NONE;
|
||||
|
||||
struct Handler {
|
||||
size_t k{0};
|
||||
double buffer[3];
|
||||
std::vector<point>& result;
|
||||
|
||||
Handler(std::vector<point> &r) : result(r) { }
|
||||
|
||||
bool Key(const char* key, SizeType length, bool copy) {
|
||||
switch(key[0]) {
|
||||
case 'x':
|
||||
k = 0;
|
||||
break;
|
||||
case 'y':
|
||||
k = 1;
|
||||
break;
|
||||
case 'z':
|
||||
k = 2;
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool Double(double d) {
|
||||
buffer[k] = d;
|
||||
if (k == 2) {
|
||||
result.emplace_back(json_benchmark::point{buffer[0],buffer[1],buffer[2]});
|
||||
k = 0;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool Uint(unsigned i) { return Double(i); } // Need this event because coordinate value can be equal to 1
|
||||
// Irrelevant events
|
||||
bool Null() { return true; }
|
||||
bool Bool(bool b) { return true; }
|
||||
bool Int(int i) { return true; }
|
||||
bool Int64(int64_t i) { return true; }
|
||||
bool Uint64(uint64_t i) { return true; }
|
||||
bool RawNumber(const char* str, SizeType length, bool copy) { return true; }
|
||||
bool String(const char* str, SizeType length, bool copy) { return true; }
|
||||
bool StartObject() { return true; }
|
||||
bool EndObject(SizeType memberCount) { return true; }
|
||||
bool StartArray() { return true; }
|
||||
bool EndArray(SizeType elementCount) { return true; }
|
||||
}; // handler
|
||||
|
||||
bool run(simdjson::padded_string &json, std::vector<point> &result) {
|
||||
Reader reader;
|
||||
Handler handler(result);
|
||||
InsituStringStream ss(json.data());
|
||||
reader.Parse<kParseInsituFlag | kParseValidateEncodingFlag | kParseFullPrecisionFlag>(ss,handler);
|
||||
return true;
|
||||
}
|
||||
}; // rapid_jason_sax
|
||||
BENCHMARK_TEMPLATE(large_random, rapidjson_sax)->UseManualTime();
|
||||
} // namespace large_random
|
||||
|
||||
#endif // SIMDJSON_COMPETITION_RAPIDJSON
|
||||
@@ -29,7 +29,6 @@ template <int TYPE = PERF_TYPE_HARDWARE> class LinuxEvents {
|
||||
size_t num_events{};
|
||||
std::vector<uint64_t> temp_result_vec{};
|
||||
std::vector<uint64_t> result{};
|
||||
std::vector<int> fds{};
|
||||
bool quiet;
|
||||
|
||||
public:
|
||||
@@ -53,12 +52,10 @@ public:
|
||||
uint32_t i = 0;
|
||||
for (auto config : config_vec) {
|
||||
attribs.config = config;
|
||||
int _fd = static_cast<int>(syscall(__NR_perf_event_open, &attribs, pid, cpu, group, flags));
|
||||
if (_fd == -1) {
|
||||
fd = static_cast<int>(syscall(__NR_perf_event_open, &attribs, pid, cpu, group, flags));
|
||||
if (fd == -1) {
|
||||
report_error("perf_event_open");
|
||||
}
|
||||
fd = _fd; // fd tracks the last _fd value.
|
||||
fds.push_back(fd);
|
||||
ioctl(fd, PERF_EVENT_IOC_ID, &result[i++]);
|
||||
if (group == -1) {
|
||||
group = fd;
|
||||
@@ -68,11 +65,7 @@ public:
|
||||
temp_result_vec.resize(num_events * 2 + 1);
|
||||
}
|
||||
|
||||
~LinuxEvents() {
|
||||
for (auto tfd : fds) {
|
||||
if (tfd != -1) { close(tfd); }
|
||||
}
|
||||
}
|
||||
~LinuxEvents() { if (fd != -1) { close(fd); } }
|
||||
|
||||
inline void start() {
|
||||
if (fd != -1) {
|
||||
|
||||
@@ -1,159 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef SIMDJSON_COMPETITION_NLOHMANN_JSON
|
||||
|
||||
#include "partial_tweets.h"
|
||||
|
||||
namespace partial_tweets {
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
struct nlohmann_json_sax {
|
||||
using StringType=std::string;
|
||||
|
||||
struct Handler : json::json_sax_t
|
||||
{
|
||||
// 8 keys to parse for each tweet (in order of appearance): "created_at", "id", "text", "in_reply_status_id", "id"(user),
|
||||
// "screen_name"(user), "retweet_count" and "favorite_count".
|
||||
// Assume that the first valid key encountered will be the correct key to parse.
|
||||
// Assume that each tweet/retweet start with a key "metadata" and has a key "retweeted" towards the end
|
||||
// The previous assumption will be used to check for the beginning of a new tweet and the end of a retweet
|
||||
enum state { // Bitset to store state of search
|
||||
key_date = (1<<0),
|
||||
key_id = (1<<1),
|
||||
key_text = (1<<2),
|
||||
key_reply = (1<<3),
|
||||
key_userid = (1<<4),
|
||||
key_screenname = (1<<5),
|
||||
key_rt = (1<<6),
|
||||
key_fav = (1<<7),
|
||||
found_date = (1<<8),
|
||||
found_id = (1<<9),
|
||||
found_text = (1<<10),
|
||||
found_reply = (1<<11),
|
||||
found_userid = (1<<12),
|
||||
found_screenname = (1<<13),
|
||||
found_rt = (1<<14),
|
||||
found_fav = (1<<15)
|
||||
};
|
||||
int values = state::key_date;
|
||||
bool userobject_id = false; // If in a user object (to find user.id)
|
||||
bool userobject_screen_name = false; // If in a user object (to find user.screen_name)
|
||||
bool inretweet = false; // If in a retweet (all keys irrelevant in retweet object)
|
||||
// Fields to store partial tweet info
|
||||
uint64_t user_id;
|
||||
uint64_t id;
|
||||
uint64_t rt;
|
||||
uint64_t fav;
|
||||
uint64_t reply_status;
|
||||
string_t screen_name;
|
||||
string_t date;
|
||||
string_t text;
|
||||
std::vector<tweet<std::string>>& result;
|
||||
|
||||
Handler(std::vector<tweet<std::string>> &r) : result(r) { }
|
||||
|
||||
bool key(string_t& val) override {
|
||||
if (!inretweet) { // If not in a retweet object, find relevant keys
|
||||
if (val.compare("retweeted_status") == 0) { inretweet = true; } // Check if entering retweet
|
||||
else if (val.compare("metadata") == 0) { values = 0; } // Reset
|
||||
// Check if key has been found and if key matches a valid key
|
||||
else if (!(values & found_date) && (val.compare("created_at") == 0)) { values |= (key_date); }
|
||||
// Must also check if not in a user object
|
||||
else if (!(values & found_id) && !userobject_id && (val.compare("id") == 0)) { values |= (key_id); }
|
||||
else if (!(values & found_text) && (val.compare("text") == 0)) { values |= (key_text); }
|
||||
else if (!(values & found_reply) && (val.compare("in_reply_to_status_id") == 0)) { values |= (key_reply); }
|
||||
// Check if entering user object
|
||||
else if ((val.compare("user") == 0)) { userobject_id = userobject_screen_name = true; }
|
||||
// Must also check if in a user object
|
||||
else if (!(values & found_userid) && userobject_id && (val.compare("id") == 0)) { values |= (key_userid); }
|
||||
// Must also check if in a user object
|
||||
else if (!(values & found_screenname) && userobject_screen_name && (val.compare("screen_name") == 0)) { values |= (key_screenname); }
|
||||
else if (!(values & found_rt) && (val.compare("retweet_count") == 0)) { values |= (key_rt); }
|
||||
else if (!(values & found_fav) && (val.compare("favorite_count") == 0)) { values |= (key_fav); }
|
||||
}
|
||||
else if (val.compare("retweeted") == 0) { inretweet = false; } // Check if end of retweet
|
||||
return true;
|
||||
}
|
||||
bool number_unsigned(number_unsigned_t val) override {
|
||||
if (values & key_id && !(values & found_id)) { // id
|
||||
id = val;
|
||||
values &= ~(key_id);
|
||||
values |= (found_id);
|
||||
}
|
||||
else if (values & key_reply && !(values & found_reply)) { // in_reply_status_id
|
||||
reply_status = val;
|
||||
values &= ~(key_reply);
|
||||
values |= (found_reply);
|
||||
}
|
||||
else if (values & key_userid && !(values & found_userid)) { // user.id
|
||||
user_id = val;
|
||||
userobject_id = false;
|
||||
values &= ~(key_userid);
|
||||
values |= (found_userid);
|
||||
}
|
||||
else if (values & key_rt && !(values & found_rt)) { // retweet_count
|
||||
rt = val;
|
||||
values &= ~(key_rt);
|
||||
values |= (found_rt);
|
||||
}
|
||||
else if (values & key_fav && !(values & found_fav)) { // favorite_count
|
||||
fav = val;
|
||||
values &= ~(key_fav);
|
||||
values |= (found_fav);
|
||||
// Assume that this is last key required, so add the partial_tweet to result
|
||||
result.emplace_back(partial_tweets::tweet<std::string>{
|
||||
date,id,text,reply_status,{user_id,screen_name},rt,fav});
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool string(string_t& val) override {
|
||||
if (values & key_date && !(values & found_date)) { // created_at
|
||||
date = val;
|
||||
values &= ~(key_date);
|
||||
values |= (found_date);
|
||||
}
|
||||
else if (values & key_text && !(values & found_text)) { // text
|
||||
text = val;
|
||||
values &= ~(key_text);
|
||||
values |= (found_text);
|
||||
}
|
||||
else if (values & key_screenname && !(values & found_screenname)) { // user.screen_name
|
||||
screen_name = val;
|
||||
userobject_screen_name = false;
|
||||
values &= ~(key_screenname);
|
||||
values |= (found_screenname);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool null() override {
|
||||
if (values & key_reply && !(values & found_reply)) { // in_reply_status (null case)
|
||||
reply_status = 0;
|
||||
values &= ~(key_reply);
|
||||
values |= (found_reply);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
// Irrelevant events
|
||||
bool boolean(bool val) override { return true; }
|
||||
bool number_float(number_float_t val, const string_t& s) override { return true; }
|
||||
bool number_integer(number_integer_t val) override { return true; }
|
||||
bool start_object(std::size_t elements) override { return true; }
|
||||
bool end_object() override { return true; }
|
||||
bool start_array(std::size_t elements) override { return true; }
|
||||
bool end_array() override { return true; }
|
||||
bool binary(json::binary_t& val) override { return true; }
|
||||
bool parse_error(std::size_t position, const std::string& last_token, const json::exception& ex) override { return false; }
|
||||
}; // Handler
|
||||
|
||||
bool run(simdjson::padded_string &json, std::vector<tweet<std::string>> &result) {
|
||||
Handler handler(result);
|
||||
json::sax_parse(json.data(), &handler);
|
||||
|
||||
return true;
|
||||
}
|
||||
}; // nlohmann_json_sax
|
||||
BENCHMARK_TEMPLATE(partial_tweets, nlohmann_json_sax)->UseManualTime();
|
||||
} // namespace partial_tweets
|
||||
|
||||
#endif // SIMDJSON_COMPETITION_NLOHMANN_JSON
|
||||
@@ -1,165 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef SIMDJSON_COMPETITION_RAPIDJSON
|
||||
|
||||
#include "partial_tweets.h"
|
||||
#include <string.h>
|
||||
#include <fstream>
|
||||
|
||||
namespace partial_tweets {
|
||||
|
||||
using namespace rapidjson;
|
||||
|
||||
struct rapidjson_sax {
|
||||
using StringType=std::string_view;
|
||||
|
||||
// 8 keys to parse for each tweet (in order of appearance): "created_at", "id", "text", "in_reply_status_id", "id"(user),
|
||||
// "screen_name"(user), "retweet_count" and "favorite_count".
|
||||
// Assume that the first valid key encountered will be the correct key to parse.
|
||||
// Assume that each tweet/retweet start with a key "metadata" and has a key "retweeted" towards the end
|
||||
// The previous assumption will be used to check for the beginning of a new tweet and the end of a retweet
|
||||
struct Handler {
|
||||
enum state { // Bitset to store state of search
|
||||
key_date = (1<<0),
|
||||
key_id = (1<<1),
|
||||
key_text = (1<<2),
|
||||
key_reply = (1<<3),
|
||||
key_userid = (1<<4),
|
||||
key_screenname = (1<<5),
|
||||
key_rt = (1<<6),
|
||||
key_fav = (1<<7),
|
||||
found_date = (1<<8),
|
||||
found_id = (1<<9),
|
||||
found_text = (1<<10),
|
||||
found_reply = (1<<11),
|
||||
found_userid = (1<<12),
|
||||
found_screenname = (1<<13),
|
||||
found_rt = (1<<14),
|
||||
found_fav = (1<<15)
|
||||
};
|
||||
int values = state::key_date;
|
||||
bool userobject_id = false; // If in a user object (to find user.id)
|
||||
bool userobject_screen_name = false; // If in a user object (to find user.screen_name)
|
||||
bool inretweet = false; // If in a retweet (all keys irrelevant in retweet object)
|
||||
// Fields to store partial tweet info
|
||||
uint64_t user_id;
|
||||
uint64_t id;
|
||||
uint64_t rt;
|
||||
uint64_t fav;
|
||||
uint64_t reply_status;
|
||||
std::string_view screen_name;
|
||||
std::string_view date;
|
||||
std::string_view text;
|
||||
std::vector<tweet<std::string_view>>& result;
|
||||
|
||||
Handler(std::vector<tweet<std::string_view>> &r) : result(r) { }
|
||||
|
||||
bool Key(const char* key, SizeType length, bool copy) {
|
||||
if (!inretweet) { // If not in a retweet object, find relevant keys
|
||||
if ((length == 16) && (memcmp(key,"retweeted_status",16) == 0)) { inretweet = true; } // Check if entering retweet
|
||||
else if ((length == 8) && (memcmp(key,"metadata",8) == 0)) { values = 0; } // Reset
|
||||
// Check if key has been found and if key matches a valid key
|
||||
else if (!(values & found_date) && (length == 10) && (memcmp(key,"created_at",10) == 0)) { values |= (key_date); }
|
||||
// Must also check if not in a user object
|
||||
else if (!(values & found_id) && !userobject_id && (length == 2) && (memcmp(key,"id",2) == 0)) { values |= (key_id); }
|
||||
else if (!(values & found_text) && (length == 4) && (memcmp(key,"text",4) == 0)) { values |= (key_text); }
|
||||
else if (!(values & found_reply) && (length == 21) && (memcmp(key,"in_reply_to_status_id",21) == 0)) { values |= (key_reply); }
|
||||
// Check if entering user object
|
||||
else if ((length == 4) && (memcmp(key,"user",4) == 0)) { userobject_id = userobject_screen_name = true; }
|
||||
// Must also check if in a user object
|
||||
else if (!(values & found_userid) && userobject_id && (length == 2) && (memcmp(key,"id",2) == 0)) { values |= (key_userid); }
|
||||
// Must also check if in a user object
|
||||
else if (!(values & found_screenname) && userobject_screen_name && (length == 11) && (memcmp(key,"screen_name",11) == 0)) { values |= (key_screenname); }
|
||||
else if (!(values & found_rt) && (length == 13) && (memcmp(key,"retweet_count",13) == 0)) { values |= (key_rt); }
|
||||
else if (!(values & found_fav) && (length == 14) && (memcmp(key,"favorite_count",14) == 0)) { values |= (key_fav); }
|
||||
}
|
||||
else if ((length == 9) && (memcmp(key,"retweeted",9) == 0)) { inretweet = false; } // Check if end of retweet
|
||||
return true;
|
||||
}
|
||||
bool Uint(unsigned i) {
|
||||
if (values & key_userid && !(values & found_userid)) { // user.id
|
||||
user_id = i;
|
||||
userobject_id = false;
|
||||
values &= ~(key_userid);
|
||||
values |= (found_userid);
|
||||
}
|
||||
else if (values & key_rt && !(values & found_rt)) { // retweet_count
|
||||
rt = i;
|
||||
values &= ~(key_rt);
|
||||
values |= (found_rt);
|
||||
}
|
||||
else if (values & key_fav && !(values & found_fav)) { // favorite_count
|
||||
fav = i;
|
||||
values &= ~(key_fav);
|
||||
values |= (found_fav);
|
||||
// Assume that this is last key required, so add the partial_tweet to result
|
||||
result.emplace_back(partial_tweets::tweet<std::string_view>{
|
||||
date,id,text,reply_status,{user_id,screen_name},rt,fav});
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool Uint64(uint64_t i) {
|
||||
if (values & key_id && !(values & found_id)) { // id
|
||||
id = i;
|
||||
values &= ~(key_id);
|
||||
values |= (found_id);
|
||||
}
|
||||
else if (values & key_reply && !(values & found_reply)) { // in_reply_status_id
|
||||
reply_status = i;
|
||||
values &= ~(key_reply);
|
||||
values |= (found_reply);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool String(const char* str, SizeType length, bool copy) {
|
||||
if (values & key_date && !(values & found_date)) { // created_at
|
||||
date = {str,length};
|
||||
values &= ~(key_date);
|
||||
values |= (found_date);
|
||||
}
|
||||
else if (values & key_text && !(values & found_text)) { // text
|
||||
text = {str,length};
|
||||
values &= ~(key_text);
|
||||
values |= (found_text);
|
||||
}
|
||||
else if (values & key_screenname && !(values & found_screenname)) { // user.screen_name
|
||||
screen_name = {str,length};
|
||||
userobject_screen_name = false;
|
||||
values &= ~(key_screenname);
|
||||
values |= (found_screenname);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool Null() {
|
||||
if (values & key_reply && !(values & found_reply)) { // in_reply_status (null case)
|
||||
reply_status = 0;
|
||||
values &= ~(key_reply);
|
||||
values |= (found_reply);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
// Irrelevant events
|
||||
bool Bool(bool b) { return true; }
|
||||
bool Double(double d) { return true; }
|
||||
bool Int(int i) { return true; }
|
||||
bool Int64(int64_t i) { return true; }
|
||||
bool RawNumber(const char* str, SizeType length, bool copy) { return true; }
|
||||
bool StartObject() { return true; }
|
||||
bool EndObject(SizeType memberCount) { return true; }
|
||||
bool StartArray() { return true; }
|
||||
bool EndArray(SizeType elementCount) { return true; }
|
||||
}; // handler
|
||||
|
||||
bool run(simdjson::padded_string &json, std::vector<tweet<std::string_view>> &result) {
|
||||
Reader reader;
|
||||
Handler handler(result);
|
||||
InsituStringStream ss(json.data());
|
||||
reader.Parse<kParseInsituFlag | kParseValidateEncodingFlag | kParseFullPrecisionFlag>(ss,handler);
|
||||
return true;
|
||||
}
|
||||
|
||||
}; // rapid_jason_sax
|
||||
BENCHMARK_TEMPLATE(partial_tweets, rapidjson_sax)->UseManualTime();
|
||||
} // namespace partial_tweets
|
||||
|
||||
#endif // SIMDJSON_COMPETITION_RAPIDJSON
|
||||
@@ -183,7 +183,7 @@ int main(int argc, char *argv[]) {
|
||||
for (uint32_t i = 0; i < iterations; i++) {
|
||||
unified.start();
|
||||
// The default template is simdjson::architecture::NATIVE.
|
||||
bool isok = (parser.implementation->stage1((const uint8_t *)p.data(), p.size(), simdjson::stage1_mode::regular) == simdjson::SUCCESS);
|
||||
bool isok = (parser.implementation->stage1((const uint8_t *)p.data(), p.size(), false) == simdjson::SUCCESS);
|
||||
unified.end(results);
|
||||
|
||||
cy1 += results[0];
|
||||
@@ -1,99 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef SIMDJSON_COMPETITION_NLOHMANN_JSON
|
||||
|
||||
#include "top_tweet.h"
|
||||
|
||||
namespace top_tweet {
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
struct nlohmann_json_sax {
|
||||
using StringType=std::string;
|
||||
|
||||
struct Handler : json::json_sax_t
|
||||
{
|
||||
// Assume every tweet/retweet starts with "metadata" key and ends with "retweeted" key. Ignore everything in a retweet.
|
||||
// Assume that the first valid key encountered outside a retweet is the correct key.
|
||||
enum state { // Bitset to store state of search
|
||||
key_text = (1<<0),
|
||||
key_screen_name = (1<<1),
|
||||
key_rt = (1<<2),
|
||||
found_text = (1<<3),
|
||||
found_screen_name = (1<<4),
|
||||
found_rt = (1<<5)
|
||||
};
|
||||
int values = state::key_text;
|
||||
bool userobject = false; // If in a user object
|
||||
bool inretweet = false;
|
||||
int64_t max_rt;
|
||||
int rt;
|
||||
string_t screen_name;
|
||||
string_t text;
|
||||
top_tweet_result<StringType>& result;
|
||||
|
||||
Handler(top_tweet_result<StringType> &r,int64_t m) : result(r), max_rt(m) { }
|
||||
|
||||
bool key(string_t& val) override {
|
||||
if (!inretweet) { // If not in a retweet object, find relevant keys
|
||||
if (val.compare("retweeted_status") == 0) { inretweet = true; } // Check if entering retweet
|
||||
else if (val.compare("metadata") == 0) { values = 0; } // Reset
|
||||
else if (!(values & found_text) && (val.compare("text") == 0)) { values |= (key_text); }
|
||||
else if ((val.compare("user") == 0)) { userobject = true; }
|
||||
else if (!(values & found_screen_name) && userobject && (val.compare("screen_name") == 0)) { values |= (key_screen_name); }
|
||||
else if (!(values & found_rt) && (val.compare("retweet_count") == 0)) { values |= (key_rt); }
|
||||
}
|
||||
else if (val.compare("retweeted") == 0) { inretweet = false; } // Check if end of retweet
|
||||
return true;
|
||||
}
|
||||
bool number_unsigned(number_unsigned_t val) override {
|
||||
if (values & key_rt && !(values & found_rt)) { // retweet_count
|
||||
rt = val;
|
||||
values &= ~(key_rt);
|
||||
values |= (found_rt);
|
||||
if (rt <= max_rt && rt >= result.retweet_count) { // Check if current tweet has more retweet than previous top tweet
|
||||
result.retweet_count = rt;
|
||||
result.text = text;
|
||||
result.screen_name = screen_name;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool string(string_t& val) override {
|
||||
if (values & key_text && !(values & found_text)) { // text
|
||||
text = val;
|
||||
values &= ~(key_text);
|
||||
values |= (found_text);
|
||||
}
|
||||
else if (values & key_screen_name && !(values & found_screen_name)) { // user.screen_name
|
||||
screen_name = val;
|
||||
userobject = false;
|
||||
values &= ~(key_screen_name);
|
||||
values |= (found_screen_name);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
// Irrelevant events
|
||||
bool null() override { return true; }
|
||||
bool boolean(bool val) override { return true; }
|
||||
bool number_float(number_float_t val, const string_t& s) override { return true; }
|
||||
bool number_integer(number_integer_t val) override { return true; }
|
||||
bool start_object(std::size_t elements) override { return true; }
|
||||
bool end_object() override { return true; }
|
||||
bool start_array(std::size_t elements) override { return true; }
|
||||
bool end_array() override { return true; }
|
||||
bool binary(json::binary_t& val) override { return true; }
|
||||
bool parse_error(std::size_t position, const std::string& last_token, const json::exception& ex) override { return false; }
|
||||
}; // Handler
|
||||
|
||||
bool run(simdjson::padded_string &json, int64_t max_retweet_count, top_tweet_result<StringType> &result) {
|
||||
result.retweet_count = -1;
|
||||
Handler handler(result,max_retweet_count);
|
||||
json::sax_parse(json.data(), &handler);
|
||||
return true;
|
||||
}
|
||||
}; // nlohmann_json_sax
|
||||
BENCHMARK_TEMPLATE(top_tweet, nlohmann_json_sax)->UseManualTime();
|
||||
} // namespace top_tweet
|
||||
|
||||
#endif // SIMDJSON_COMPETITION_NLOHMANN_JSON
|
||||
@@ -64,6 +64,6 @@ struct rapidjson_insitu : rapidjson_base {
|
||||
};
|
||||
BENCHMARK_TEMPLATE(top_tweet, rapidjson_insitu)->UseManualTime();
|
||||
|
||||
} // namespace top_tweet
|
||||
} // namespace partial_tweets
|
||||
|
||||
#endif // SIMDJSON_COMPETITION_RAPIDJSON
|
||||
|
||||
@@ -1,101 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef SIMDJSON_COMPETITION_RAPIDJSON
|
||||
|
||||
#include "top_tweet.h"
|
||||
#include <string.h>
|
||||
|
||||
namespace top_tweet {
|
||||
|
||||
using namespace rapidjson;
|
||||
|
||||
struct rapidjson_sax {
|
||||
using StringType=std::string_view;
|
||||
struct Handler {
|
||||
// Assume every tweet/retweet starts with "metadata" key and ends with "retweeted" key. Ignore everything in a retweet.
|
||||
// Assume that the first valid key encountered outside a retweet is the correct key.
|
||||
enum state { // Bit set to keep track of state of search for keys
|
||||
key_text = (1<<0),
|
||||
key_screen_name = (1<<1),
|
||||
key_rt = (1<<2),
|
||||
found_text = (1<<3),
|
||||
found_screen_name = (1<<4),
|
||||
found_rt = (1<<5)
|
||||
};
|
||||
int values = state::key_text;
|
||||
int rt;
|
||||
StringType text;
|
||||
StringType screen_name;
|
||||
bool inretweet = false;
|
||||
bool userobject = false;
|
||||
top_tweet_result<StringType>& result;
|
||||
int64_t max_rt;
|
||||
|
||||
Handler(top_tweet_result<StringType> &r,int64_t m) : result(r), max_rt(m) { }
|
||||
|
||||
bool Key(const char* key, SizeType length, bool copy) {
|
||||
if (!inretweet) {
|
||||
if ((length == 16) && (memcmp(key,"retweeted_status",16) == 0)) { inretweet = true; } // Check if entering retweet
|
||||
else if ((length == 8) && (memcmp(key,"metadata",8) == 0)) { values = 0; } // Reset
|
||||
else if (!(values & found_text) && (length == 4) && (memcmp(key,"text",4) == 0)) { values |= (key_text); }
|
||||
else if ((length == 4) && (memcmp(key,"user",4) == 0)) { userobject = true; }
|
||||
else if (!(values & found_screen_name) && userobject && (length == 11) && memcmp(key,"screen_name",11) == 0) { values |= (key_screen_name); }
|
||||
else if (!(values & found_rt) && (length == 13) && (memcmp(key,"retweet_count",13) == 0)) { values |= (key_rt); }
|
||||
}
|
||||
else if ((length == 9) && (memcmp(key,"retweeted",9) == 0)) { inretweet = false; } // Check if end of retweet
|
||||
return true;
|
||||
}
|
||||
bool String(const char* str, SizeType length, bool copy) {
|
||||
if (values & key_text && !(values & found_text)) { // text
|
||||
text = {str,length};
|
||||
values &= ~(key_text);
|
||||
values |= (found_text);
|
||||
}
|
||||
else if (values & key_screen_name && !(values & found_screen_name)) { // user.screen_name
|
||||
screen_name = {str,length};
|
||||
values &= ~(key_screen_name);
|
||||
values |= (found_screen_name);
|
||||
userobject = false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool Uint(unsigned i) {
|
||||
if (values & key_rt && !(values & found_rt)) { // retweet_count
|
||||
rt = i;
|
||||
values &= ~(key_rt);
|
||||
values |= (found_rt);
|
||||
if (rt <= max_rt && rt >= result.retweet_count) { // Check if current tweet has more retweet than previous top tweet
|
||||
result.retweet_count = rt;
|
||||
result.text = text;
|
||||
result.screen_name = screen_name;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
// Irrelevant events
|
||||
bool Null() { return true; }
|
||||
bool Bool(bool b) { return true; }
|
||||
bool Double(double d) { return true; }
|
||||
bool Int(int i) { return true; }
|
||||
bool Int64(int64_t i) { return true; }
|
||||
bool Uint64(uint64_t i) { return true; }
|
||||
bool RawNumber(const char* str, SizeType length, bool copy) { return true; }
|
||||
bool StartObject() { return true; }
|
||||
bool EndObject(SizeType memberCount) { return true; }
|
||||
bool StartArray() { return true; }
|
||||
bool EndArray(SizeType elementCount) { return true; }
|
||||
}; // handler
|
||||
|
||||
bool run(simdjson::padded_string &json, int64_t max_retweet_count, top_tweet_result<StringType> &result) {
|
||||
result.retweet_count = -1;
|
||||
Reader reader;
|
||||
Handler handler(result,max_retweet_count);
|
||||
InsituStringStream ss(json.data());
|
||||
reader.Parse<kParseInsituFlag | kParseValidateEncodingFlag | kParseFullPrecisionFlag>(ss,handler);
|
||||
return true;
|
||||
}
|
||||
}; // rapidjson_sax
|
||||
BENCHMARK_TEMPLATE(top_tweet, rapidjson_sax)->UseManualTime();
|
||||
} // namespace top_tweet
|
||||
|
||||
#endif // SIMDJSON_COMPETITION_RAPIDJSON
|
||||
@@ -1,187 +0,0 @@
|
||||
#
|
||||
# Flags used by exes and by the simdjson library (project-wide flags)
|
||||
#
|
||||
add_library(simdjson-internal-flags INTERFACE)
|
||||
|
||||
option(SIMDJSON_NO_FORCE_INLINING "Do not attempt to force function inlining" OFF)
|
||||
if(SIMDJSON_NO_FORCE_INLINING)
|
||||
add_compile_definitions(SIMDJSON_NO_FORCE_INLINING=1)
|
||||
endif()
|
||||
|
||||
option(SIMDJSON_CHECK_EOF "Check for the end of the input buffer (to avoid buffer overflows). We expect this setting to be ON except for performance testing." ON)
|
||||
if(SIMDJSON_CHECK_EOF)
|
||||
add_compile_definitions(SIMDJSON_CHECK_EOF=1)
|
||||
else()
|
||||
add_compile_definitions(SIMDJSON_CHECK_EOF=0)
|
||||
endif()
|
||||
|
||||
|
||||
option(SIMDJSON_SANITIZE_UNDEFINED "Sanitize undefined behavior" OFF)
|
||||
if(SIMDJSON_SANITIZE_UNDEFINED)
|
||||
add_compile_options(-fsanitize=undefined -fno-sanitize-recover=all)
|
||||
add_link_options(-fsanitize=undefined -fno-sanitize-recover=all)
|
||||
endif()
|
||||
|
||||
option(SIMDJSON_SANITIZE "Sanitize addresses" OFF)
|
||||
if(SIMDJSON_SANITIZE)
|
||||
if(CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang")
|
||||
message(STATUS "The address sanitizer under Apple's clang appears to be \
|
||||
incompatible with the undefined-behavior sanitizer.")
|
||||
message(STATUS "You may set SIMDJSON_SANITIZE_UNDEFINED to sanitize \
|
||||
undefined behavior.")
|
||||
add_compile_options(
|
||||
-fsanitize=address -fno-omit-frame-pointer -fno-sanitize-recover=all
|
||||
)
|
||||
add_compile_definitions(ASAN_OPTIONS=detect_leaks=1)
|
||||
link_libraries(
|
||||
-fsanitize=address -fno-omit-frame-pointer -fno-sanitize-recover=all
|
||||
)
|
||||
else()
|
||||
message(
|
||||
STATUS
|
||||
"Setting both the address sanitizer and the undefined sanitizer."
|
||||
)
|
||||
add_compile_options(
|
||||
-fsanitize=address -fno-omit-frame-pointer
|
||||
-fsanitize=undefined -fno-sanitize-recover=all
|
||||
)
|
||||
link_libraries(
|
||||
-fsanitize=address -fno-omit-frame-pointer
|
||||
-fsanitize=undefined -fno-sanitize-recover=all
|
||||
)
|
||||
endif()
|
||||
|
||||
# Ubuntu bug for GCC 5.0+ (safe for all versions)
|
||||
if(CMAKE_COMPILER_IS_GNUCC)
|
||||
link_libraries(-fuse-ld=gold)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(SIMDJSON_SANITIZE_THREADS)
|
||||
message(STATUS "Setting both the thread sanitizer \
|
||||
and the undefined-behavior sanitizer.")
|
||||
add_compile_options(
|
||||
-fsanitize=thread -fsanitize=undefined -fno-sanitize-recover=all
|
||||
)
|
||||
link_libraries(
|
||||
-fsanitize=thread -fsanitize=undefined -fno-sanitize-recover=all
|
||||
)
|
||||
|
||||
# Ubuntu bug for GCC 5.0+ (safe for all versions)
|
||||
if(CMAKE_COMPILER_IS_GNUCC)
|
||||
link_libraries(-fuse-ld=gold)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
get_cmake_property(is_multi_config GENERATOR_IS_MULTI_CONFIG)
|
||||
if(NOT is_multi_config AND NOT CMAKE_BUILD_TYPE)
|
||||
# Deliberately not including SIMDJSON_SANITIZE_THREADS since thread behavior
|
||||
# depends on the build type.
|
||||
if(SIMDJSON_SANITIZE OR SIMDJSON_SANITIZE_UNDEFINED)
|
||||
message(STATUS "No build type selected and you have enabled the sanitizer, \
|
||||
default to Debug. Consider setting CMAKE_BUILD_TYPE.")
|
||||
set(CMAKE_BUILD_TYPE Debug CACHE STRING "Choose the type of build." FORCE)
|
||||
else()
|
||||
message(STATUS "No build type selected, default to Release")
|
||||
set(CMAKE_BUILD_TYPE Release CACHE STRING "Choose the type of build." FORCE)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(NOT MSVC)
|
||||
option(SIMDJSON_USE_LIBCPP "Use the libc++ library" OFF)
|
||||
endif()
|
||||
|
||||
if(MSVC AND BUILD_SHARED_LIBS)
|
||||
# This will require special handling.
|
||||
set(SIMDJSON_WINDOWS_DLL TRUE)
|
||||
endif()
|
||||
|
||||
# We compile tools, tests, etc. with C++ 17. Override yourself if you need on a
|
||||
# target.
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
set(CMAKE_CXX_EXTENSIONS OFF)
|
||||
set(CMAKE_MACOSX_RPATH OFF)
|
||||
set(CMAKE_THREAD_PREFER_PTHREAD ON)
|
||||
set(THREADS_PREFER_PTHREAD_FLAG ON)
|
||||
|
||||
# LTO seems to create all sorts of fun problems. Let us
|
||||
# disable temporarily.
|
||||
#include(CheckIPOSupported)
|
||||
#check_ipo_supported(RESULT ltoresult)
|
||||
#if(ltoresult)
|
||||
# set(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE)
|
||||
#endif()
|
||||
|
||||
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 STRLESS "142")
|
||||
set(SIMDJSON_LEGACY_VISUAL_STUDIO TRUE)
|
||||
message (STATUS "A legacy Visual Studio version was detected. \
|
||||
We recommend Visual Studio 2019 or better on a 64-bit system.")
|
||||
endif()
|
||||
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.
|
||||
# https://docs.microsoft.com/en-us/cpp/error-messages/compiler-warnings/compiler-warning-level-4-c4714?view=vs-2019
|
||||
target_compile_options(simdjson-internal-flags INTERFACE /WX /W3 /sdl /w34714)
|
||||
if(MSVC_VERSION GREATER 1910)
|
||||
target_compile_options(simdjson-internal-flags INTERFACE /permissive-)
|
||||
endif()
|
||||
endif()
|
||||
if(SIMDJSON_VISUAL_STUDIO_BUILD_WITH_DEBUG_INFO_FOR_PROFILING)
|
||||
add_link_options(/DEBUG)
|
||||
add_compile_options(/Zi)
|
||||
endif()
|
||||
else()
|
||||
if(NOT WIN32)
|
||||
target_compile_options(simdjson-internal-flags INTERFACE -fPIC)
|
||||
endif()
|
||||
target_compile_options(
|
||||
simdjson-internal-flags INTERFACE
|
||||
-Werror -Wall -Wextra -Weffc++ -Wsign-compare -Wshadow -Wwrite-strings
|
||||
-Wpointer-arith -Winit-self -Wconversion -Wno-sign-conversion
|
||||
)
|
||||
endif()
|
||||
|
||||
#
|
||||
# Other optional flags
|
||||
#
|
||||
option(SIMDJSON_BASH "Allow usage of bash within CMake" ON)
|
||||
|
||||
option(
|
||||
SIMDJSON_VERBOSE_LOGGING
|
||||
"Enable verbose logging for internal simdjson library development."
|
||||
OFF
|
||||
)
|
||||
if(SIMDJSON_VERBOSE_LOGGING)
|
||||
add_compile_definitions(SIMDJSON_VERBOSE_LOGGING=1
|
||||
)
|
||||
endif()
|
||||
|
||||
if(SIMDJSON_USE_LIBCPP)
|
||||
link_libraries(-stdlib=libc++ -lc++abi)
|
||||
# instead of the above line, we could have used
|
||||
# set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -stdlib=libc++
|
||||
# -lc++abi")
|
||||
# The next line is needed empirically.
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++")
|
||||
# we update CMAKE_SHARED_LINKER_FLAGS, this gets updated later as well
|
||||
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -lc++abi")
|
||||
endif()
|
||||
|
||||
# prevent shared libraries from depending on Intel provided libraries
|
||||
if(CMAKE_C_COMPILER_ID MATCHES "Intel")
|
||||
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)
|
||||
@@ -1,28 +0,0 @@
|
||||
option(SIMDJSON_EXCEPTIONS "Enable simdjson's exception-throwing interface" ON)
|
||||
if(NOT SIMDJSON_EXCEPTIONS)
|
||||
message(STATUS "simdjson exception interface turned off. \
|
||||
Code that does not check error codes will not compile.")
|
||||
simdjson_add_props(target_compile_definitions PUBLIC SIMDJSON_EXCEPTIONS=0)
|
||||
if(MSVC)
|
||||
if(NOT is_top_project)
|
||||
message(AUTHOR_WARNING "Turning SIMDJSON_EXCEPTIONS off requires \
|
||||
editing CMAKE_CXX_FLAGS")
|
||||
endif()
|
||||
|
||||
# CMake currently /EHsc as a default flag in CMAKE_CXX_FLAGS on MSVC.
|
||||
# Replacing this with a more general abstraction is a WIP
|
||||
# (see https://gitlab.kitware.com/cmake/cmake/-/issues/20610)
|
||||
# /EHs enables standard C++ stack unwinding when catching exceptions
|
||||
# (non-structured exception handling)
|
||||
# /EHc used in conjection with /EHs indicates that extern "C" functions
|
||||
# never throw (terminate-on-throw)
|
||||
# Here, we disable both with the - argument negation operator
|
||||
string(REPLACE "/EHsc" "/EHs-c-" CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS})
|
||||
|
||||
# Because we cannot change the flag above on an individual target (yet), the
|
||||
# definition below must similarly be added globally
|
||||
add_definitions(-D_HAS_EXCEPTIONS=0)
|
||||
elseif(CMAKE_COMPILER_IS_GNUCC)
|
||||
simdjson_add_props(target_link_libraries PRIVATE -fno-exceptions)
|
||||
endif()
|
||||
endif()
|
||||
@@ -1,23 +0,0 @@
|
||||
if(DEFINED SIMDJSON_BUILD_STATIC)
|
||||
message(DEPRECATION "SIMDJSON_BUILD_STATIC is deprecated, setting \
|
||||
BUILD_SHARED_LIBS with its value and unsetting it")
|
||||
set(shared ON)
|
||||
if(SIMDJSON_BUILD_STATIC)
|
||||
set(shared OFF)
|
||||
endif()
|
||||
|
||||
set(BUILD_SHARED_LIBS "${shared}" CACHE BOOL "" FORCE)
|
||||
unset(SIMDJSON_BUILD_STATIC CACHE)
|
||||
endif()
|
||||
|
||||
if(DEFINED SIMDJSON_JUST_LIBRARY)
|
||||
message(DEPRECATION "SIMDJSON_JUST_LIBRARY is deprecated, setting \
|
||||
SIMDJSON_DEVELOPER_MODE with its value and unsetting it")
|
||||
set(dev_mode ON)
|
||||
if(SIMDJSON_JUST_LIBRARY)
|
||||
set(dev_mode OFF)
|
||||
endif()
|
||||
|
||||
set(SIMDJSON_DEVELOPER_MODE "${dev_mode}" CACHE BOOL "" FORCE)
|
||||
unset(SIMDJSON_JUST_LIBRARY CACHE)
|
||||
endif()
|
||||
@@ -1,106 +0,0 @@
|
||||
#
|
||||
# Implementation selection
|
||||
#
|
||||
set(SIMDJSON_ALL_IMPLEMENTATIONS fallback westmere haswell arm64 ppc64)
|
||||
|
||||
set(
|
||||
SIMDJSON_IMPLEMENTATION ""
|
||||
CACHE STRING "\
|
||||
Semicolon-separated list of implementations to include \
|
||||
(${SIMDJSON_ALL_IMPLEMENTATIONS}). If this is not set, any implementations \
|
||||
that are supported at compile time and may be selected at runtime will be \
|
||||
included."
|
||||
)
|
||||
set(
|
||||
SIMDJSON_EXCLUDE_IMPLEMENTATION ""
|
||||
CACHE STRING "\
|
||||
Semicolon-separated list of implementations to exclude \
|
||||
(haswell/westmere/arm64/ppc64/fallback). By default, excludes any \
|
||||
implementations that are unsupported at compile time or cannot be selected at \
|
||||
runtime."
|
||||
)
|
||||
|
||||
foreach(var IN ITEMS IMPLEMENTATION EXCLUDE_IMPLEMENTATION)
|
||||
set(var "SIMDJSON_${var}")
|
||||
foreach(impl IN LISTS "${var}")
|
||||
if(NOT impl IN_LIST SIMDJSON_ALL_IMPLEMENTATIONS)
|
||||
message(ERROR "\
|
||||
Implementation ${impl} found in ${var} not supported by simdjson. \
|
||||
Possible implementations: ${SIMDJSON_ALL_IMPLEMENTATIONS}")
|
||||
endif()
|
||||
endforeach()
|
||||
endforeach()
|
||||
|
||||
macro(flag_action action var val)
|
||||
message(STATUS "${action} implementation ${impl} due to ${var}=${${var}}")
|
||||
simdjson_add_props(
|
||||
target_compile_definitions PUBLIC
|
||||
"SIMDJSON_IMPLEMENTATION_${impl_upper}=${val}"
|
||||
)
|
||||
endmacro()
|
||||
|
||||
foreach(impl IN LISTS SIMDJSON_ALL_IMPLEMENTATIONS)
|
||||
string(TOUPPER "${impl}" impl_upper)
|
||||
if(impl IN_LIST SIMDJSON_EXCLUDE_IMPLEMENTATION)
|
||||
flag_action(Excluding SIMDJSON_EXCLUDE_IMPLEMENTATION 0)
|
||||
elseif(impl IN_LIST SIMDJSON_IMPLEMENTATION)
|
||||
flag_action(Including SIMDJSON_IMPLEMENTATION 1)
|
||||
elseif(SIMDJSON_IMPLEMENTATION)
|
||||
flag_action(Excluding SIMDJSON_IMPLEMENTATION 0)
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
# TODO make it so this generates the necessary compiler flags to select the
|
||||
# given impl as the builtin automatically!
|
||||
set(
|
||||
SIMDJSON_BUILTIN_IMPLEMENTATION ""
|
||||
CACHE STRING "\
|
||||
Select the implementation that will be used for user code. Defaults to the \
|
||||
most universal implementation in SIMDJSON_IMPLEMENTATION (in the order \
|
||||
${SIMDJSON_ALL_IMPLEMENTATIONS}) if specified; otherwise, by default the \
|
||||
compiler will pick the best implementation that can always be selected given \
|
||||
the compiler flags."
|
||||
)
|
||||
if(NOT SIMDJSON_BUILTIN_IMPLEMENTATION STREQUAL "")
|
||||
simdjson_add_props(
|
||||
target_compile_definitions PUBLIC
|
||||
"SIMDJSON_BUILTIN_IMPLEMENTATION=${SIMDJSON_BUILTIN_IMPLEMENTATION}"
|
||||
)
|
||||
else()
|
||||
# Pick the most universal implementation out of the selected implementations
|
||||
# (if any)
|
||||
foreach(impl IN LISTS SIMDJSON_ALL_IMPLEMENTATIONS)
|
||||
if(
|
||||
impl IN_LIST SIMDJSON_IMPLEMENTATION
|
||||
AND NOT impl IN_LIST SIMDJSON_EXCLUDE_IMPLEMENTATION
|
||||
)
|
||||
message(STATUS "\
|
||||
Selected implementation ${impl} as builtin implementation based on \
|
||||
${SIMDJSON_IMPLEMENTATION}")
|
||||
simdjson_add_props(
|
||||
target_compile_definitions PUBLIC
|
||||
"SIMDJSON_BUILTIN_IMPLEMENTATION=${impl}"
|
||||
)
|
||||
break()
|
||||
endif()
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
foreach(impl IN LISTS SIMDJSON_ALL_IMPLEMENTATIONS)
|
||||
string(TOUPPER "${impl}" impl_upper)
|
||||
option(
|
||||
"SIMDJSON_IMPLEMENTATION_${impl_upper}"
|
||||
"Include the ${impl} implementation"
|
||||
ON
|
||||
)
|
||||
mark_as_advanced("SIMDJSON_IMPLEMENTATION_${impl_upper}")
|
||||
if(NOT "${SIMDJSON_IMPLEMENTATION_${impl_upper}}")
|
||||
message(DEPRECATION "\
|
||||
SIMDJSON_IMPLEMENTATION_${impl_upper} is deprecated. \
|
||||
Use SIMDJSON_IMPLEMENTATION=-${impl} instead")
|
||||
simdjson_add_props(
|
||||
target_compile_definitions PUBLIC
|
||||
"SIMDJSON_IMPLEMENTATION_${impl_upper}=0"
|
||||
)
|
||||
endif()
|
||||
endforeach()
|
||||
@@ -1,6 +1,9 @@
|
||||
include(CMakeFindDependencyMacro)
|
||||
if("@SIMDJSON_ENABLE_THREADS@")
|
||||
find_dependency(Threads)
|
||||
endif()
|
||||
@PACKAGE_INIT@
|
||||
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/simdjsonTargets.cmake")
|
||||
include(CMakeFindDependencyMacro)
|
||||
if(@SIMDJSON_ENABLE_THREADS@)
|
||||
set(CMAKE_THREAD_PREFER_PTHREAD TRUE)
|
||||
find_dependency(Threads)
|
||||
endif()
|
||||
# Import targets.
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@-targets.cmake")
|
||||
|
||||
@@ -0,0 +1,275 @@
|
||||
|
||||
if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
|
||||
message (STATUS "The simdjson repository appears to be standalone.")
|
||||
option(SIMDJSON_JUST_LIBRARY "Build just the library, omit tests, tools and benchmarks" OFF)
|
||||
message (STATUS "By default, we attempt to build everything.")
|
||||
else()
|
||||
message (STATUS "The simdjson repository appears to be used as a subdirectory.")
|
||||
option(SIMDJSON_JUST_LIBRARY "Build just the library, omit tests, tools and benchmarks" ON)
|
||||
message (STATUS "By default, we just build the library.")
|
||||
endif()
|
||||
|
||||
#
|
||||
# Flags used by exes and by the simdjson library (project-wide flags)
|
||||
#
|
||||
add_library(simdjson-flags INTERFACE)
|
||||
add_library(simdjson-internal-flags INTERFACE)
|
||||
target_link_libraries(simdjson-internal-flags INTERFACE simdjson-flags)
|
||||
|
||||
option(SIMDJSON_SANITIZE_UNDEFINED "Sanitize undefined behavior" OFF)
|
||||
if(SIMDJSON_SANITIZE_UNDEFINED)
|
||||
target_compile_options(simdjson-flags INTERFACE -fsanitize=undefined -fno-sanitize-recover=all)
|
||||
target_link_libraries(simdjson-flags INTERFACE -fsanitize=undefined -fno-sanitize-recover=all)
|
||||
endif()
|
||||
|
||||
option(SIMDJSON_SANITIZE "Sanitize addresses" OFF)
|
||||
if(SIMDJSON_SANITIZE)
|
||||
if(CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang")
|
||||
message(STATUS "The address sanitizer under Apple's clang appears to be incompatible with the undefined-behavior sanitizer.")
|
||||
message(STATUS "You may set SIMDJSON_SANITIZE_UNDEFINED to sanitize undefined behavior.")
|
||||
target_compile_options(simdjson-flags INTERFACE -fsanitize=address -fno-omit-frame-pointer -fno-sanitize-recover=all)
|
||||
target_compile_definitions(simdjson-flags INTERFACE ASAN_OPTIONS=detect_leaks=1)
|
||||
target_link_libraries(simdjson-flags INTERFACE -fsanitize=address -fno-omit-frame-pointer -fno-sanitize-recover=all)
|
||||
else()
|
||||
message(STATUS "Setting both the address sanitizer and the undefined sanitizer.")
|
||||
target_compile_options(simdjson-flags INTERFACE -fsanitize=address -fno-omit-frame-pointer -fsanitize=undefined -fno-sanitize-recover=all)
|
||||
target_link_libraries(simdjson-flags INTERFACE -fsanitize=address -fno-omit-frame-pointer -fsanitize=undefined -fno-sanitize-recover=all)
|
||||
endif()
|
||||
# Ubuntu bug for GCC 5.0+ (safe for all versions)
|
||||
if (CMAKE_COMPILER_IS_GNUCC)
|
||||
target_link_libraries(simdjson-flags INTERFACE -fuse-ld=gold)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
|
||||
if(SIMDJSON_SANITIZE_THREADS)
|
||||
message(STATUS "Setting both the thread sanitizer and the undefined-behavior sanitizer.")
|
||||
target_compile_options(simdjson-flags INTERFACE -fsanitize=thread -fsanitize=undefined -fno-sanitize-recover=all)
|
||||
target_link_libraries(simdjson-flags INTERFACE -fsanitize=thread -fsanitize=undefined -fno-sanitize-recover=all)
|
||||
|
||||
# Ubuntu bug for GCC 5.0+ (safe for all versions)
|
||||
if (CMAKE_COMPILER_IS_GNUCC)
|
||||
target_link_libraries(simdjson-flags INTERFACE -fuse-ld=gold)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (NOT CMAKE_BUILD_TYPE)
|
||||
# Deliberately not including SIMDJSON_SANITIZE_THREADS since thread behavior depends on the build type.
|
||||
if(SIMDJSON_SANITIZE OR SIMDJSON_SANITIZE_UNDEFINED)
|
||||
message(STATUS "No build type selected and you have enabled the sanitizer, default to Debug. Consider setting CMAKE_BUILD_TYPE.")
|
||||
set(CMAKE_BUILD_TYPE Debug CACHE STRING "Choose the type of build." FORCE)
|
||||
else()
|
||||
message(STATUS "No build type selected, default to Release")
|
||||
set(CMAKE_BUILD_TYPE Release CACHE STRING "Choose the type of build." FORCE)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(MSVC)
|
||||
option(SIMDJSON_BUILD_STATIC "Build a static library" ON) # turning it on disables the production of a dynamic library
|
||||
else()
|
||||
option(SIMDJSON_BUILD_STATIC "Build a static library" OFF) # turning it on disables the production of a dynamic library
|
||||
option(SIMDJSON_USE_LIBCPP "Use the libc++ library" OFF)
|
||||
endif()
|
||||
|
||||
if(MSVC AND NOT(SIMDJSON_BUILD_STATIC))
|
||||
# This will require special handling.
|
||||
set(SIMDJSON_WINDOWS_DLL TRUE)
|
||||
endif()
|
||||
|
||||
set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/tools/cmake")
|
||||
|
||||
# We compile tools, tests, etc. with C++ 17. Override yourself if you need on a target.
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
set(CMAKE_CXX_EXTENSIONS OFF)
|
||||
set(CMAKE_MACOSX_RPATH OFF)
|
||||
set(CMAKE_THREAD_PREFER_PTHREAD ON)
|
||||
set(THREADS_PREFER_PTHREAD_FLAG ON)
|
||||
|
||||
# LTO seems to create all sorts of fun problems. Let us
|
||||
# disable temporarily.
|
||||
#include(CheckIPOSupported)
|
||||
#check_ipo_supported(RESULT ltoresult)
|
||||
#if(ltoresult)
|
||||
# set(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE)
|
||||
#endif()
|
||||
|
||||
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}" STRLESS "142")
|
||||
set(SIMDJSON_LEGACY_VISUAL_STUDIO TRUE)
|
||||
message (STATUS "A legacy Visual Studio version was detected. We recommend Visual Studio 2019 or better on a 64-bit system.")
|
||||
endif()
|
||||
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(MSVC)
|
||||
|
||||
|
||||
# workaround for GNU GCC poor AVX load/store code generation
|
||||
if ((CMAKE_CXX_COMPILER_ID STREQUAL "GNU") AND (CMAKE_SYSTEM_PROCESSOR MATCHES "^(i.86|x86(_64)?)$"))
|
||||
target_compile_options(simdjson-flags INTERFACE -mno-avx256-split-unaligned-load -mno-avx256-split-unaligned-store)
|
||||
endif()
|
||||
|
||||
#
|
||||
# Optional flags
|
||||
#
|
||||
|
||||
#
|
||||
# Implementation selection
|
||||
#
|
||||
set(SIMDJSON_ALL_IMPLEMENTATIONS "fallback;westmere;haswell;arm64;ppc64")
|
||||
|
||||
set(SIMDJSON_IMPLEMENTATION "" CACHE STRING "Semicolon-separated list of implementations to include (${SIMDJSON_ALL_IMPLEMENTATIONS}). If this is not set, any implementations that are supported at compile time and may be selected at runtime will be included.")
|
||||
foreach(implementation ${SIMDJSON_IMPLEMENTATION})
|
||||
if(NOT (implementation IN_LIST SIMDJSON_ALL_IMPLEMENTATIONS))
|
||||
message(ERROR "Implementation ${implementation} not supported by simdjson. Possible implementations: ${SIMDJSON_ALL_IMPLEMENTATIONS}")
|
||||
endif()
|
||||
endforeach(implementation)
|
||||
|
||||
set(SIMDJSON_EXCLUDE_IMPLEMENTATION "" CACHE STRING "Semicolon-separated list of implementations to exclude (haswell/westmere/arm64/ppc64/fallback). By default, excludes any implementations that are unsupported at compile time or cannot be selected at runtime.")
|
||||
foreach(implementation ${SIMDJSON_EXCLUDE_IMPLEMENTATION})
|
||||
if(NOT (implementation IN_LIST SIMDJSON_ALL_IMPLEMENTATIONS))
|
||||
message(ERROR "Implementation ${implementation} not supported by simdjson. Possible implementations: ${SIMDJSON_ALL_IMPLEMENTATIONS}")
|
||||
endif()
|
||||
endforeach(implementation)
|
||||
|
||||
foreach(implementation ${SIMDJSON_ALL_IMPLEMENTATIONS})
|
||||
string(TOUPPER ${implementation} implementation_upper)
|
||||
if(implementation IN_LIST SIMDJSON_EXCLUDE_IMPLEMENTATION)
|
||||
message(STATUS "Excluding implementation ${implementation} due to SIMDJSON_EXCLUDE_IMPLEMENTATION=${SIMDJSON_EXCLUDE_IMPLEMENTATION}")
|
||||
target_compile_definitions(simdjson-flags INTERFACE "SIMDJSON_IMPLEMENTATION_${implementation_upper}=0")
|
||||
elseif(implementation IN_LIST SIMDJSON_IMPLEMENTATION)
|
||||
message(STATUS "Including implementation ${implementation} due to SIMDJSON_IMPLEMENTATION=${SIMDJSON_IMPLEMENTATION}")
|
||||
target_compile_definitions(simdjson-flags INTERFACE "SIMDJSON_IMPLEMENTATION_${implementation_upper}=1")
|
||||
elseif(SIMDJSON_IMPLEMENTATION)
|
||||
message(STATUS "Excluding implementation ${implementation} due to SIMDJSON_IMPLEMENTATION=${SIMDJSON_IMPLEMENTATION}")
|
||||
target_compile_definitions(simdjson-flags INTERFACE "SIMDJSON_IMPLEMENTATION_${implementation_upper}=0")
|
||||
endif()
|
||||
endforeach(implementation)
|
||||
|
||||
# TODO make it so this generates the necessary compiler flags to select the given implementation as the builtin automatically!
|
||||
option(SIMDJSON_BUILTIN_IMPLEMENTATION "Select the implementation that will be used for user code. Defaults to the most universal implementation in SIMDJSON_IMPLEMENTATION (in the order ${SIMDJSON_ALL_IMPLEMENTATIONS}) if specified; otherwise, by default the compiler will pick the best implementation that can always be selected given the compiler flags." "")
|
||||
if(SIMDJSON_BUILTIN_IMPLEMENTATION)
|
||||
target_compile_definitions(simdjson-flags INTERFACE "SIMDJSON_BUILTIN_IMPLEMENTATION=${SIMDJSON_BUILTIN_IMPLEMENTATION}")
|
||||
else()
|
||||
# Pick the most universal implementation out of the selected implementations (if any)
|
||||
foreach(implementation ${SIMDJSON_ALL_IMPLEMENTATIONS})
|
||||
if(implementation IN_LIST SIMDJSON_IMPLEMENTATION AND NOT (implementation IN_LIST SIMDJSON_EXCLUDE_IMPLEMENTATION))
|
||||
message(STATUS "Selected implementation ${implementation} as builtin implementation based on ${SIMDJSON_IMPLEMENTATION}.")
|
||||
target_compile_definitions(simdjson-flags INTERFACE "SIMDJSON_BUILTIN_IMPLEMENTATION=${implementation}")
|
||||
break()
|
||||
endif()
|
||||
endforeach(implementation)
|
||||
endif(SIMDJSON_BUILTIN_IMPLEMENTATION)
|
||||
|
||||
option(SIMDJSON_IMPLEMENTATION_HASWELL "Include the haswell implementation" ON)
|
||||
if(NOT SIMDJSON_IMPLEMENTATION_HASWELL)
|
||||
message(DEPRECATION "SIMDJSON_IMPLEMENTATION_HASWELL is deprecated. Use SIMDJSON_IMPLEMENTATION=-haswell instead.")
|
||||
target_compile_definitions(simdjson-flags INTERFACE SIMDJSON_IMPLEMENTATION_HASWELL=0)
|
||||
endif()
|
||||
option(SIMDJSON_IMPLEMENTATION_WESTMERE "Include the westmere implementation" ON)
|
||||
if(NOT SIMDJSON_IMPLEMENTATION_WESTMERE)
|
||||
message(DEPRECATION "SIMDJSON_IMPLEMENTATION_WESTMERE is deprecated. SIMDJSON_IMPLEMENTATION=-westmere instead.")
|
||||
target_compile_definitions(simdjson-flags INTERFACE SIMDJSON_IMPLEMENTATION_WESTMERE=0)
|
||||
endif()
|
||||
option(SIMDJSON_IMPLEMENTATION_ARM64 "Include the arm64 implementation" ON)
|
||||
if(NOT SIMDJSON_IMPLEMENTATION_ARM64)
|
||||
message(DEPRECATION "SIMDJSON_IMPLEMENTATION_ARM64 is deprecated. Use SIMDJSON_IMPLEMENTATION=-arm64 instead.")
|
||||
target_compile_definitions(simdjson-flags INTERFACE SIMDJSON_IMPLEMENTATION_ARM64=0)
|
||||
endif()
|
||||
option(SIMDJSON_IMPLEMENTATION_PPC64 "Include the arm64 implementation" ON)
|
||||
if(NOT SIMDJSON_IMPLEMENTATION_PPC64)
|
||||
message(DEPRECATION "SIMDJSON_IMPLEMENTATION_PPC64 is deprecated. Use SIMDJSON_IMPLEMENTATION=-ppc64 instead.")
|
||||
target_compile_definitions(simdjson-flags INTERFACE SIMDJSON_IMPLEMENTATION_PPC64=0)
|
||||
endif()
|
||||
option(SIMDJSON_IMPLEMENTATION_FALLBACK "Include the fallback implementation" ON)
|
||||
if(NOT SIMDJSON_IMPLEMENTATION_FALLBACK)
|
||||
message(DEPRECATION "SIMDJSON_IMPLEMENTATION_FALLBACK is deprecated. Use SIMDJSON_IMPLEMENTATION=-fallback instead.")
|
||||
target_compile_definitions(simdjson-flags INTERFACE SIMDJSON_IMPLEMENTATION_FALLBACK=0)
|
||||
endif()
|
||||
|
||||
#
|
||||
# Other optional flags
|
||||
#
|
||||
option(SIMDJSON_DEVELOPMENT_CHECKS "Enable development-time aids, such as checks for incorrect API usage. Enabled by default in DEBUG." OFF)
|
||||
if(SIMDJSON_DEVELOPMENT_CHECKS)
|
||||
target_compile_definitions(simdjson-flags INTERFACE SIMDJSON_DEVELOPMENT_CHECKS)
|
||||
endif()
|
||||
|
||||
option(SIMDJSON_BASH "Allow usage of bash within CMake" ON)
|
||||
|
||||
option(SIMDJSON_EXCEPTIONS "Enable simdjson's exception-throwing interface" ON)
|
||||
if(NOT SIMDJSON_EXCEPTIONS)
|
||||
message(STATUS "simdjson exception interface turned off. Code that does not check error codes will not compile.")
|
||||
target_compile_definitions(simdjson-flags INTERFACE SIMDJSON_EXCEPTIONS=0)
|
||||
if(MSVC)
|
||||
# CMake currently /EHsc as a default flag in CMAKE_CXX_FLAGS on MSVC. Replacing this with a more general abstraction is a WIP (see https://gitlab.kitware.com/cmake/cmake/-/issues/20610)
|
||||
# /EHs enables standard C++ stack unwinding when catching exceptions (non-structured exception handling)
|
||||
# /EHc used in conjection with /EHs indicates that extern "C" functions never throw (terminate-on-throw)
|
||||
# Here, we disable both with the - argument negation operator
|
||||
string(REPLACE "/EHsc" "/EHs-c-" CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS})
|
||||
|
||||
# Because we cannot change the flag above on an invidual target (yet), the definition below must similarly be added globally
|
||||
add_definitions(-D_HAS_EXCEPTIONS=0)
|
||||
elseif (CMAKE_COMPILER_IS_GNUCC)
|
||||
target_link_libraries(simdjson-flags INTERFACE -fno-exceptions)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
option(SIMDJSON_ENABLE_THREADS "Link with thread support" ON)
|
||||
if(SIMDJSON_ENABLE_THREADS)
|
||||
set(CMAKE_THREAD_PREFER_PTHREAD TRUE)
|
||||
set(THREADS_PREFER_PTHREAD_FLAG TRUE)
|
||||
find_package(Threads REQUIRED)
|
||||
target_link_libraries(simdjson-flags INTERFACE Threads::Threads)
|
||||
target_compile_definitions(simdjson-flags INTERFACE SIMDJSON_THREADS_ENABLED=1) # This will be set in the code automatically.
|
||||
endif()
|
||||
|
||||
option(SIMDJSON_VERBOSE_LOGGING, "Enable verbose logging for internal simdjson library development." OFF)
|
||||
if (SIMDJSON_VERBOSE_LOGGING)
|
||||
target_compile_definitions(simdjson-flags INTERFACE SIMDJSON_VERBOSE_LOGGING=1)
|
||||
endif()
|
||||
|
||||
option(SIMDJSON_DISABLE_DEPRECATED_API "Disables deprecated APIs" Off)
|
||||
if (SIMDJSON_DISABLE_DEPRECATED_API)
|
||||
target_compile_definitions(simdjson-flags INTERFACE SIMDJSON_DISABLE_DEPRECATED_API=1)
|
||||
endif()
|
||||
|
||||
if(SIMDJSON_USE_LIBCPP)
|
||||
target_link_libraries(simdjson-flags INTERFACE -stdlib=libc++ -lc++abi)
|
||||
# instead of the above line, we could have used
|
||||
# set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -stdlib=libc++ -lc++abi")
|
||||
# The next line is needed empirically.
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++")
|
||||
# we update CMAKE_SHARED_LINKER_FLAGS, this gets updated later as well
|
||||
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -lc++abi")
|
||||
endif(SIMDJSON_USE_LIBCPP)
|
||||
|
||||
# prevent shared libraries from depending on Intel provided libraries
|
||||
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)
|
||||
|
||||
# I do not think we want to export our internal flags!
|
||||
# install(TARGETS simdjson-internal-flags EXPORT simdjson-config)
|
||||
@@ -1,48 +0,0 @@
|
||||
#
|
||||
# Accumulate flags
|
||||
#
|
||||
set(simdjson_props_script "${PROJECT_BINARY_DIR}/simdjson-props.cmake")
|
||||
set(simdjson_props_content "")
|
||||
set(simdjson_props_flushed NO)
|
||||
|
||||
function(simdjson_add_props command)
|
||||
set(args "")
|
||||
math(EXPR limit "${ARGC} - 1")
|
||||
foreach(i RANGE 1 "${limit}")
|
||||
set(value "${ARGV${i}}")
|
||||
if(value MATCHES "^(PRIVATE|PUBLIC)$")
|
||||
string(TOLOWER "${value}" value)
|
||||
set(value "\${${value}}")
|
||||
else()
|
||||
set(value "[==[${value}]==]")
|
||||
endif()
|
||||
string(APPEND args " ${value}")
|
||||
endforeach()
|
||||
|
||||
set(simdjson_props_flushed NO PARENT_SCOPE)
|
||||
set(
|
||||
simdjson_props_content
|
||||
"${simdjson_props_content}${command}(\"\${target}\"${args})\n"
|
||||
PARENT_SCOPE
|
||||
)
|
||||
endfunction()
|
||||
|
||||
macro(simdjson_flush_props)
|
||||
if(NOT simdjson_props_flushed)
|
||||
set(simdjson_props_flushed YES PARENT_SCOPE)
|
||||
file(WRITE "${simdjson_props_script}" "${simdjson_props_content}")
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
function(simdjson_apply_props target)
|
||||
set(private PRIVATE)
|
||||
set(public PUBLIC)
|
||||
get_target_property(TYPE "${target}" TYPE)
|
||||
if(TYPE STREQUAL "INTERFACE_LIBRARY")
|
||||
set(private INTERFACE)
|
||||
set(public INTERFACE)
|
||||
endif()
|
||||
|
||||
simdjson_flush_props()
|
||||
include("${simdjson_props_script}")
|
||||
endfunction()
|
||||
@@ -1,19 +1,24 @@
|
||||
#
|
||||
# ${USER_CMAKECACHE} contains the *user-specified* simdjson options so you can
|
||||
# call cmake on another branch or repository with the same options.
|
||||
# ${SIMDJSON_USER_CMAKECACHE} contains the *user-specified* simdjson options so you can call cmake on
|
||||
# another branch or repository with the same options.
|
||||
#
|
||||
|
||||
file(READ "${BINARY_DIR}/CMakeCache.txt" cache)
|
||||
# Escape semicolons, so the lines can be safely iterated in CMake
|
||||
string(REPLACE ";" "\\;" cache "${cache}")
|
||||
# Turn the contents into a list
|
||||
string(REPLACE "\n" ";" cache "${cache}")
|
||||
|
||||
message(STATUS "${USER_CMAKECACHE}")
|
||||
|
||||
file(REMOVE "${USER_CMAKECACHE}")
|
||||
foreach(line IN LISTS cache)
|
||||
if(line MATCHES "^SIMDJSON_" AND NOT line MATCHES "^SIMDJSON_LIB_")
|
||||
file(APPEND "${USER_CMAKECACHE}" "${line}\n")
|
||||
endif()
|
||||
endforeach()
|
||||
# Not supported on Windows at present, because the only thing that uses it is checkperf, which we
|
||||
# don't run on Windows.
|
||||
#
|
||||
set(SIMDJSON_USER_CMAKECACHE ${CMAKE_CURRENT_BINARY_DIR}/.simdjson-user-CMakeCache.txt)
|
||||
if (MSVC)
|
||||
add_custom_command(
|
||||
OUTPUT ${SIMDJSON_USER_CMAKECACHE}
|
||||
COMMAND findstr SIMDJSON_ ${PROJECT_BINARY_DIR}/CMakeCache.txt > ${SIMDJSON_USER_CMAKECACHE}.tmp
|
||||
COMMAND findstr /v SIMDJSON_LIB_ ${SIMDJSON_USER_CMAKECACHE}.tmp > ${SIMDJSON_USER_CMAKECACHE}
|
||||
VERBATIM # Makes it not do weird escaping with the command
|
||||
)
|
||||
else()
|
||||
add_custom_command(
|
||||
OUTPUT ${SIMDJSON_USER_CMAKECACHE}
|
||||
COMMAND grep SIMDJSON_ ${PROJECT_BINARY_DIR}/CMakeCache.txt > ${SIMDJSON_USER_CMAKECACHE}.tmp
|
||||
COMMAND grep -v SIMDJSON_LIB_ ${SIMDJSON_USER_CMAKECACHE}.tmp > ${SIMDJSON_USER_CMAKECACHE}
|
||||
VERBATIM # Makes it not do weird escaping with the command
|
||||
)
|
||||
endif()
|
||||
add_custom_target(simdjson-user-cmakecache DEPENDS ${SIMDJSON_USER_CMAKECACHE})
|
||||
|
||||
Vendored
-4
@@ -18,10 +18,6 @@ if(SIMDJSON_GOOGLE_BENCHMARKS)
|
||||
add_dependency(google_benchmarks)
|
||||
endif()
|
||||
|
||||
# The bulk of our benchmarking and testing data has been moved simdjson/simdjson-data
|
||||
import_dependency(simdjson-data simdjson/simdjson-data a5b13babe65c1bba7186b41b43d4cbdc20a5c470)
|
||||
add_dependency(simdjson-data)
|
||||
|
||||
# This prevents variables declared with set() from unnecessarily escaping and
|
||||
# should not be called more than once
|
||||
function(competition_scope_)
|
||||
|
||||
+175
-365
@@ -7,11 +7,10 @@ An overview of what you need to know to use simdjson, with examples.
|
||||
* [Including simdjson](#including-simdjson)
|
||||
* [Using simdjson with package managers](#using-simdjson-with-package-managers)
|
||||
* [Using simdjson as a CMake dependency](#using-simdjson-as-a-cmake-dependency)
|
||||
* [Versions](#versions)
|
||||
* [The Basics: Loading and Parsing JSON Documents](#the-basics-loading-and-parsing-json-documents)
|
||||
* [Documents Are Iterators](#documents-are-iterators)
|
||||
* [C++11 Support and string_view](#c11-support-and-string_view)
|
||||
* [Using the Parsed JSON](#using-the-parsed-json)
|
||||
* [C++11 Support and string_view](#c11-support-and-string_view)
|
||||
* [C++17 Support](#c17-support)
|
||||
* [Minifying JSON strings without parsing](#minifying-json-strings-without-parsing)
|
||||
* [UTF-8 validation (alone)](#utf-8-validation-alone)
|
||||
@@ -19,8 +18,7 @@ An overview of what you need to know to use simdjson, with examples.
|
||||
* [Error Handling](#error-handling)
|
||||
* [Error Handling Example](#error-handling-example)
|
||||
* [Exceptions](#exceptions)
|
||||
* [Rewinding](#rewinding)
|
||||
* [Direct Access to the Raw String](#direct-access-to-the-raw-string)
|
||||
* [Tree Walking and JSON Element Types](#tree-walking-and-json-element-types)
|
||||
* [Newline-Delimited JSON (ndjson) and JSON lines](#newline-delimited-json-ndjson-and-json-lines)
|
||||
* [Thread Safety](#thread-safety)
|
||||
* [Standard Compliance](#standard-compliance)
|
||||
@@ -50,17 +48,17 @@ c++ myproject.cpp simdjson.cpp
|
||||
```
|
||||
|
||||
Note:
|
||||
- Users on macOS and other platforms where default compilers do not provide C++11 compliant by default should request it with the appropriate flag (e.g., `c++ -std=c++17 myproject.cpp simdjson.cpp`).
|
||||
- Users on macOS and other platforms were default compilers do not provide C++11 compliant by default should request it with the appropriate flag (e.g., `c++ -std=c++17 myproject.cpp simdjson.cpp`).
|
||||
|
||||
Using simdjson with package managers
|
||||
------------------
|
||||
|
||||
You can install the simdjson library on your system or in your project using multiple package managers such as MSYS2, the conan package manager, vcpkg, brew, the apt package manager (debian-based Linux systems), the FreeBSD package manager (FreeBSD), and so on. [Visit our wiki for more details](https://github.com/simdjson/simdjson/wiki/Installing-simdjson-with-a-package-manager).
|
||||
You can install the simdjson library on your system or in your project using multiple package managers such as MSYS2, the conan package manager, vcpkg, brew, the apt package manager (debian-based Linux systems), the FreeBSD package manager (FreeBSD), and so on. [Visit our wiki for more details](https://github.com/simdjson/simdjson/wiki/Installing-simdjson-with-a-package-manager).
|
||||
|
||||
Using simdjson as a CMake dependency
|
||||
------------------
|
||||
|
||||
You can include the simdjson library as a CMake dependency by including the following lines in your `CMakeLists.txt`:
|
||||
You can include the simdjson as a CMake dependency by including the following lines in your `CMakeLists.txt`:
|
||||
|
||||
```cmake
|
||||
include(FetchContent)
|
||||
@@ -68,15 +66,15 @@ include(FetchContent)
|
||||
FetchContent_Declare(
|
||||
simdjson
|
||||
GIT_REPOSITORY https://github.com/simdjson/simdjson.git
|
||||
GIT_TAG tags/v0.9.6
|
||||
GIT_TAG v0.9.0
|
||||
GIT_SHALLOW TRUE)
|
||||
|
||||
FetchContent_MakeAvailable(simdjson)
|
||||
```
|
||||
|
||||
You should provide `GIT_TAG` with the release you need. If you omit `GIT_TAG ...`, you will work from the main branch of simdjson: we recommend that if you are working on production code, you always work from a release.
|
||||
You should replace `GIT_TAG v0.9.0` by the version you need. If you omit `GIT_TAG v0.9.0`, you will work from the main branch of simdjson: we recommend that if you are working on production code,
|
||||
|
||||
Elsewhere in your project, you can declare dependencies on simdjson with lines such as these:
|
||||
Elsewhere in your project, you can declare dependencies on simdjson with lines such as these:
|
||||
|
||||
```cmake
|
||||
add_executable(myprogram myprogram.cpp)
|
||||
@@ -87,39 +85,11 @@ We recommend CMake version 3.15 or better.
|
||||
|
||||
See [our CMake demonstration](https://github.com/simdjson/cmake_demo_single_file). It works under Linux, FreeBSD, macOS and Windows (including Visual Studio).
|
||||
|
||||
|
||||
|
||||
The CMake build in simdjson can be taylored with a few variables. You can see the available variables and their default values by entering the `cmake -LA` command.
|
||||
|
||||
|
||||
Versions
|
||||
------------------
|
||||
|
||||
Users are discouraged from building production code from the
|
||||
project's main branch. The main branch is used for development:
|
||||
it may contain new features but also additional bugs.
|
||||
|
||||
Users should pick a release. They should also access the
|
||||
documentation matching the release that they have chosen.
|
||||
Note that new features may be added over time.
|
||||
|
||||
Our releases are tagged using semantic versioning: the tags
|
||||
are made of three numbers prefixed by the letter `v` and separated by periods.
|
||||
|
||||
You can always find the latest release at the following hyperlink:
|
||||
|
||||
https://github.com/simdjson/simdjson/releases/latest/
|
||||
|
||||
The archive you download at this location contains its own corresponding
|
||||
documentation.
|
||||
|
||||
You can also choose to browse a specific version
|
||||
of the documentation and the code using GitHub,
|
||||
by appending the version number to the hyperlink, like so:
|
||||
|
||||
https://github.com/simdjson/simdjson/blob/vx.y.z/doc/basics.md
|
||||
|
||||
where `x.y.z` should correspond to the version number you have
|
||||
chosen.
|
||||
|
||||
The Basics: Loading and Parsing JSON Documents
|
||||
----------------------------------------------
|
||||
|
||||
@@ -132,22 +102,25 @@ auto json = padded_string::load("twitter.json");
|
||||
ondemand::document doc = parser.iterate(json); // position a pointer at the beginning of the JSON data
|
||||
```
|
||||
|
||||
Or by creating a string and calling `iterate()`:
|
||||
Or by creating a padded string (for efficiency reasons, simdjson requires a string with
|
||||
SIMDJSON_PADDING bytes at the end) and calling `iterate()`:
|
||||
|
||||
```c++
|
||||
ondemand::parser parser;
|
||||
std::string json = "[1,2,3]";
|
||||
auto json = "[1,2,3]"_padded; // The _padded suffix creates a simdjson::padded_string instance
|
||||
ondemand::document doc = parser.iterate(json); // parse a string
|
||||
```
|
||||
|
||||
If you have a buffer of your own pass it in:
|
||||
If you have a buffer of your own with enough padding already (SIMDJSON_PADDING extra bytes allocated), you can use `padded_string_view` to pass it in:
|
||||
|
||||
```c++
|
||||
ondemand::parser parser;
|
||||
const char * json = "[1]";
|
||||
ondemand::document doc = parser.iterate(json, strlen(json));
|
||||
char json[3+SIMDJSON_PADDING];
|
||||
strcpy(json, "[1]");
|
||||
ondemand::document doc = parser.iterate(json, strlen(json), sizeof(json));
|
||||
```
|
||||
|
||||
We recommend against creating many `std::string` or many `std::padding_string` instances in your application to store your JSON data.
|
||||
Consider reusing the same buffers and limiting memory allocations.
|
||||
|
||||
Documents Are Iterators
|
||||
@@ -174,41 +147,6 @@ For best performance, a `parser` instance should be reused over several files: o
|
||||
needlessly reallocate memory, an expensive process. It is also possible to avoid entirely memory
|
||||
allocations during parsing when using simdjson. [See our performance notes for details](performance.md).
|
||||
|
||||
|
||||
|
||||
C++11 Support and string_view
|
||||
-------------
|
||||
|
||||
The simdjson library builds on compilers supporting the [C++11 standard](https://en.wikipedia.org/wiki/C%2B%2B11). It is also a strict requirement: we have no plan to support older C++ compilers.
|
||||
|
||||
We represent parsed strings in simdjson using the `std::string_view` class. It avoids
|
||||
the need to copy the data, as would be necessary with the `std::string` class. It also
|
||||
avoids the pitfalls of null-terminated C strings. It makes it easier for our users to
|
||||
copy the data into their own favorite class instances (e.g., alternatives to `std::string`).
|
||||
|
||||
A `std::string_view` instance is effectively just a pointer to a region in memory representing
|
||||
a string. In simdjson, we return `std::string_view` instances that either point within the
|
||||
input string you parsed, or to a temporary string buffer inside our parser class instances.
|
||||
When using `std::string_view` instances, it is your responsibility to ensure that
|
||||
`std::string_view` instance does not outlive the pointed-to memory (e.g., either the input
|
||||
buffer or the parser instance). Furthermore, some operations reset the string buffer
|
||||
inside our parser instances: e.g., when we parse a new document. Thus a `std::string_view` instance
|
||||
is often best viewed as a temporary string value that is tied to the document you are parsing.
|
||||
At the cost of some memory allocation, you may convert your `std::string_view` instances for long-term storage into `std::string` instances:
|
||||
`std::string mycopy(view)` (C++17) or `std::string mycopy(view.begin(), view.end())` (prior to C++17).
|
||||
|
||||
|
||||
The `std::string_view` class has become standard as part of C++17 but it is not always available
|
||||
on compilers which only supports C++11. When we detect that `string_view` is natively
|
||||
available, we define the macro `SIMDJSON_HAS_STRING_VIEW`.
|
||||
|
||||
When we detect that it is unavailable,
|
||||
we use [string-view-lite](https://github.com/martinmoene/string-view-lite) as a
|
||||
substitute. In such cases, we use the type alias `using string_view = nonstd::string_view;` to
|
||||
offer the same API, irrespective of the compiler and standard library. The macro
|
||||
`SIMDJSON_HAS_STRING_VIEW` will be *undefined* to indicate that we emulate `string_view`.
|
||||
|
||||
|
||||
Using the Parsed JSON
|
||||
---------------------
|
||||
|
||||
@@ -216,10 +154,6 @@ Once you have a document, you can navigate it with idiomatic C++ iterators, oper
|
||||
The following show how to use the JSON when exceptions are enabled, but simdjson has full, idiomatic
|
||||
support for users who avoid exceptions. See [the simdjson error handling documentation](basics.md#error-handling) for more.
|
||||
|
||||
* **Validate What You Use:** When calling `iterate`, the document is quickly indexed. If it is
|
||||
not a valid UTF-8 string or if there is an unclosed string, an error may be reported right away.
|
||||
However, it is not fully validated. On Demand only fully validates the values you use and the
|
||||
structure leading to it.
|
||||
* **Extracting Values:** You can cast a JSON element to a native type:
|
||||
`double(element)` or `double x = json_element`. This works for double, uint64_t, int64_t, bool,
|
||||
ondemand::object and ondemand::array. At this point, the number, string or boolean will be parsed,
|
||||
@@ -228,32 +162,15 @@ support for users who avoid exceptions. See [the simdjson error handling documen
|
||||
> IMPORTANT NOTE: values can only be parsed once. Since documents are *iterators*, once you have
|
||||
> parsed a value (such as by casting to double), you cannot get at it again.
|
||||
* **Field Access:** To get the value of the "foo" field in an object, use `object["foo"]`. This will
|
||||
scan through the object looking for the field with the matching string, doing a character-by-character
|
||||
comparison.
|
||||
scan through the object looking for the field with the matching string.
|
||||
|
||||
> NOTE: JSON allows you to escape characters in keys. E.g., the key `"date"` may be written as
|
||||
> `"\u0064\u0061\u0074\u0065"`. By default, simdjson does *not* unescape keys when matching by default.
|
||||
> Thus if you search for the key `"date"` and the JSON document uses `"\u0064\u0061\u0074\u0065"`
|
||||
> as a key, it will not be recognized. This is not generally a problem. Nevertheless, if you do need
|
||||
> to support escaped keys, the method `unescaped_key()` provides the desired unescaped keys by
|
||||
> parsing and writing out the unescaped keys to a string buffer and returning a `std::string_view`
|
||||
> instance. You should expect a performance penalty when using `unescaped_key()`.
|
||||
> ```c++
|
||||
> std::string json = R"({"k\u0065y": 1})";
|
||||
> ondemand::parser parser;
|
||||
> auto doc = parser.iterate(json);
|
||||
> ondemand::object object = doc.get_object();
|
||||
> for(auto field : object) {
|
||||
> // parses and writes out the key, after unescaping it,
|
||||
> // to a string buffer. It causes a performance penalty.
|
||||
> std::string_view keyv = field.unescaped_key();
|
||||
> if(keyv == "key") { std::cout << uint64_t(field.value()); }
|
||||
> }
|
||||
> ```
|
||||
> NOTE: simdjson does *not* unescape keys when matching. This is not generally a problem for
|
||||
> applications with well-defined key names (which generally do not use escapes). If you do need this
|
||||
> support, it's best to iterate through the object fields to find the field you are looking for.
|
||||
>
|
||||
> By default, field lookup is order-insensitive, so you can look up values in any order. However,
|
||||
> we still encourage you to look up fields in the order you expect them in the JSON, as it is still
|
||||
> faster.
|
||||
> much faster.
|
||||
>
|
||||
> If you want to enforce finding fields in order, you can use `object.find_field("foo")` instead.
|
||||
> This will only look forward, and will fail to find fields in the wrong order: for example, this
|
||||
@@ -261,7 +178,7 @@ support for users who avoid exceptions. See [the simdjson error handling documen
|
||||
>
|
||||
> ```c++
|
||||
> ondemand::parser parser;
|
||||
> std::string json = R"( { "x": 1, "y": 2 } )";
|
||||
> auto json = R"( { "x": 1, "y": 2 } )"_padded;
|
||||
> auto doc = parser.iterate(json);
|
||||
> double y = doc.find_field("y"); // The cursor is now after the 2 (at })
|
||||
> double x = doc.find_field("x"); // This fails, because there are no more fields after "y"
|
||||
@@ -271,7 +188,7 @@ support for users who avoid exceptions. See [the simdjson error handling documen
|
||||
>
|
||||
> ```c++
|
||||
> ondemand::parser parser;
|
||||
> std::string json = R"( { "x": 1, "y": 2 } )";
|
||||
> auto json = R"( { "x": 1, "y": 2 } )"_padded;
|
||||
> auto doc = parser.iterate(json);
|
||||
> double y = doc["y"]; // The cursor is now after the 2 (at })
|
||||
> double x = doc["x"]; // Success: [] loops back around to find "x"
|
||||
@@ -281,53 +198,10 @@ support for users who avoid exceptions. See [the simdjson error handling documen
|
||||
|
||||
If you know the type of the value, you can cast it right there, too! `for (double value : array) { ... }`.
|
||||
* **Object Iteration:** You can iterate through an object's fields, as well: `for (auto field : object) { ... }`
|
||||
- `field.unescaped_key()` will get you the unescaped key string.
|
||||
- `field.unescaped_key()` will get you the key string.
|
||||
- `field.value()` will get you the value, which you can then use all these other methods on.
|
||||
* **Array Index:** Because it is forward-only, you cannot look up an array element by index. Instead,
|
||||
you will need to iterate through the array and keep an index yourself.
|
||||
* **Output to strings (simdjson 1.0 or better):** Given a document, a value, an array or an object in a JSON document, you can output a JSON string version suitable to be parsed again as JSON content: `simdjson::to_json_string(element)`. A call to `to_json_string` consumes fully the element: if you apply it on a document, the JSON pointer is advanced to the end of the document. The `simdjson::to_json_string` does not allocate memory. The `to_json_string` function should not be confused with retrieving the value of a string instance which are escaped and represented using a lightweight `std::string_view` instance pointing at an internal string buffer inside the parser instance. To illustrate, the first of the following two code segments will print the unescaped string `"test"` complete with the quote whereas the second one will print the escaped content of the string (without the quotes).
|
||||
> ```C++
|
||||
> // serialize a JSON to an escaped std::string instance so that it can be parsed again as JSON
|
||||
> std::string silly_json = R"( { "test": "result" } )";
|
||||
> ondemand::document doc = parser.iterate(silly_json);
|
||||
> std::cout << simdjson::to_json_string(doc["test"]) << std::endl; // Requires simdjson 1.0 or better
|
||||
>````
|
||||
> ```C++
|
||||
> // retrieves an unescaped string value as a string_view instance
|
||||
> std::string silly_json = R"( { "test": "result" } )";
|
||||
> ondemand::document doc = parser.iterate(silly_json);
|
||||
> std::cout << std::string_view(doc["test"]) << std::endl;
|
||||
>````
|
||||
You can use `to_json_string` to efficiently extract components of a JSON document to reconstruct a new JSON document, as in the following example:
|
||||
> ```C++
|
||||
> std::string cars_json = R"( [
|
||||
> { "make": "Toyota", "model": "Camry", "year": 2018, "tire_pressure": [ 40.1, 39.9, 37.7, 40.4 ] },
|
||||
> { "make": "Kia", "model": "Soul", "year": 2012, "tire_pressure": [ 30.1, 31.0, 28.6, 28.7 ] },
|
||||
> { "make": "Toyota", "model": "Tercel", "year": 1999, "tire_pressure": [ 29.8, 30.0, 30.2, 30.5 ] }
|
||||
> ] )";
|
||||
> std::vector<std::string_view> arrays;
|
||||
> // We are going to collect string_view instances which point inside the `cars_json` string
|
||||
> // and are therefore valid as long as `cars_json` remains in scope.
|
||||
> {
|
||||
> ondemand::parser parser;
|
||||
> for (ondemand::object car : parser.iterate(cars_json)) {
|
||||
> if(uint64_t(car["year"]) > 2000) {
|
||||
> arrays.push_back(simdjson::to_json_string(car["tire_pressure"]));
|
||||
> }
|
||||
> }
|
||||
> }
|
||||
> // We can now convert to a JSON string:
|
||||
> std::ostringstream oss;
|
||||
> oss << "[";
|
||||
> for(size_t i = 0; i < arrays.size(); i++) {
|
||||
> if(i>0) { oss << ","; }
|
||||
> oss << arrays[i];
|
||||
> }
|
||||
> oss << "]";
|
||||
> auto json_string = oss.str();
|
||||
> // json_string == "[[ 40.1, 39.9, 37.7, 40.4 ],[ 30.1, 31.0, 28.6, 28.7 ]]"
|
||||
>````
|
||||
|
||||
|
||||
### Examples
|
||||
|
||||
@@ -335,11 +209,11 @@ The following code illustrates many of the above concepts:
|
||||
|
||||
```c++
|
||||
ondemand::parser parser;
|
||||
std::string cars_json = R"( [
|
||||
auto cars_json = R"( [
|
||||
{ "make": "Toyota", "model": "Camry", "year": 2018, "tire_pressure": [ 40.1, 39.9, 37.7, 40.4 ] },
|
||||
{ "make": "Kia", "model": "Soul", "year": 2012, "tire_pressure": [ 30.1, 31.0, 28.6, 28.7 ] },
|
||||
{ "make": "Toyota", "model": "Tercel", "year": 1999, "tire_pressure": [ 29.8, 30.0, 30.2, 30.5 ] }
|
||||
] )";
|
||||
] )"_padded;
|
||||
|
||||
// Iterating through an array of objects
|
||||
for (ondemand::object car : parser.iterate(cars_json)) {
|
||||
@@ -363,10 +237,10 @@ Here is a different example illustrating the same ideas:
|
||||
|
||||
```C++
|
||||
ondemand::parser parser;
|
||||
std::string points_json = R"( [
|
||||
auto points_json = R"( [
|
||||
{ "12345" : {"x":12.34, "y":56.78, "z": 9998877} },
|
||||
{ "12545" : {"x":11.44, "y":12.78, "z": 11111111} }
|
||||
] )";
|
||||
] )"_padded;
|
||||
|
||||
// Parse and iterate through an array of objects
|
||||
for (ondemand::object points : parser.iterate(points_json)) {
|
||||
@@ -382,9 +256,9 @@ for (ondemand::object points : parser.iterate(points_json)) {
|
||||
And another one:
|
||||
|
||||
```C++
|
||||
std::string abstract_json = R"(
|
||||
auto abstract_json = R"(
|
||||
{ "str" : { "123" : {"abc" : 3.14 } } }
|
||||
)";
|
||||
)"_padded;
|
||||
ondemand::parser parser;
|
||||
auto doc = parser.iterate(abstract_json);
|
||||
cout << doc["str"]["123"]["abc"].get_double() << endl; // Prints 3.14
|
||||
@@ -396,9 +270,9 @@ cout << doc["str"]["123"]["abc"].get_double() << endl; // Prints 3.14
|
||||
to `get()` which gives you back an error code: e.g.,
|
||||
|
||||
```c++
|
||||
std::string abstract_json = R"(
|
||||
auto abstract_json = R"(
|
||||
{ "str" : { "123" : {"abc" : 3.14 } } }
|
||||
)";
|
||||
)"_padded;
|
||||
ondemand::parser parser;
|
||||
|
||||
double value;
|
||||
@@ -408,33 +282,7 @@ cout << doc["str"]["123"]["abc"].get_double() << endl; // Prints 3.14
|
||||
cout << value << endl; // Prints 3.14
|
||||
```
|
||||
|
||||
Sometimes it is useful to scan an array to determine its length prior to parsing it.
|
||||
For this purpose, `array` instances have a `count_elements` method. Users should be
|
||||
aware that the `count_elements` method can be costly since it requires scanning the
|
||||
whole array. You may use it as follows if your document is itself an array:
|
||||
|
||||
```C++
|
||||
std::string cars_json = R"( [ 40.1, 39.9, 37.7, 40.4 ] )";
|
||||
auto doc = parser.iterate(cars_json);
|
||||
size_t count = doc.count_elements(); // requires simdjson 1.0 or better
|
||||
std::vector<double> values(count);
|
||||
size_t index = 0;
|
||||
for(double x : doc) { values[index++] = x; }
|
||||
```
|
||||
|
||||
If you access an array inside a document, you can use the `count_elements` method as follow.
|
||||
You should not let the array instance go out of scope before consuming it after calling the `count_elements` method:
|
||||
``` C++
|
||||
ondemand::parser parser;
|
||||
std::string cars_json = R"( { "test":[ { "val1":1, "val2":2 }, { "val1":1, "val2":2 } ] } )";
|
||||
auto doc = parser.iterate(cars_json);
|
||||
auto test_array = doc.find_field("test").get_array();
|
||||
size_t count = test_array.count_elements(); // requires simdjson 1.0 or better
|
||||
std::cout << "Number of elements: " << count << std::endl;
|
||||
for(ondemand::object elem: test_array) {
|
||||
std::cout << simdjson::to_string(elem);
|
||||
}
|
||||
```
|
||||
|
||||
Tree Walking and JSON Element Types: Sometimes you don't necessarily have a document with a known type, and are trying to generically inspect or walk over JSON elements. To do that, you can use iterators and the type() method. For example, here's a quick and dirty recursive function that verbosely prints the JSON document as JSON:
|
||||
|
||||
@@ -467,9 +315,9 @@ void recursive_print_json(T&& element) {
|
||||
if (add_comma) {
|
||||
cout << ",";
|
||||
}
|
||||
// key() returns the key as it appears in the raw
|
||||
// JSON document, if we want the unescaped key,
|
||||
// we should do field.unescaped_key().
|
||||
// key() returns the unescaped key, if we
|
||||
// want the escaped key, we should do
|
||||
// field.unescaped_key().
|
||||
cout << "\"" << field.key() << "\": ";
|
||||
recursive_print_json(field.value());
|
||||
add_comma = true;
|
||||
@@ -502,13 +350,33 @@ void basics_treewalk() {
|
||||
```
|
||||
|
||||
|
||||
C++11 Support and string_view
|
||||
-------------
|
||||
|
||||
The simdjson library builds on compilers supporting the [C++11 standard](https://en.wikipedia.org/wiki/C%2B%2B11). It is also a strict requirement: we have no plan to support older C++ compilers.
|
||||
|
||||
We represent parsed strings in simdjson using the `std::string_view` class. It avoids
|
||||
the need to copy the data, as would be necessary with the `std::string` class. It also
|
||||
avoids the pitfalls of null-terminated C strings.
|
||||
|
||||
The `std::string_view` class has become standard as part of C++17 but it is not always available
|
||||
on compilers which only supports C++11. When we detect that `string_view` is natively
|
||||
available, we define the macro `SIMDJSON_HAS_STRING_VIEW`.
|
||||
|
||||
When we detect that it is unavailable,
|
||||
we use [string-view-lite](https://github.com/martinmoene/string-view-lite) as a
|
||||
substitute. In such cases, we use the type alias `using string_view = nonstd::string_view;` to
|
||||
offer the same API, irrespective of the compiler and standard library. The macro
|
||||
`SIMDJSON_HAS_STRING_VIEW` will be *undefined* to indicate that we emulate `string_view`.
|
||||
|
||||
|
||||
C++17 Support
|
||||
-------------
|
||||
|
||||
While the simdjson library can be used in any project using C++ 11 and above, field iteration has special support C++ 17's destructuring syntax. For example:
|
||||
|
||||
```c++
|
||||
std::string json = R"( { "foo": 1, "bar": 2 } )";
|
||||
padded_string json = R"( { "foo": 1, "bar": 2 } )"_padded;
|
||||
dom::parser parser;
|
||||
dom::object object;
|
||||
auto error = parser.parse(json).get(object);
|
||||
@@ -522,7 +390,7 @@ For comparison, here is the C++ 11 version of the same code:
|
||||
|
||||
```c++
|
||||
// C++ 11 version for comparison
|
||||
std::string json = R"( { "foo": 1, "bar": 2 } )";
|
||||
padded_string json = R"( { "foo": 1, "bar": 2 } )"_padded;
|
||||
dom::parser parser;
|
||||
dom::object object;
|
||||
auto error = parser.parse(json).get(object);
|
||||
@@ -570,20 +438,17 @@ Your input string does not need any padding. Any string will do. The `validate_u
|
||||
JSON Pointer
|
||||
------------
|
||||
|
||||
The simdjson library also supports [JSON pointer](https://tools.ietf.org/html/rfc6901) through the `at_pointer()` method, letting you reach further down into the document in a single call. JSON pointer is supported by both the [DOM approach](https://github.com/simdjson/simdjson/blob/master/doc/dom.md#json-pointer) as well as the On Demand approach.
|
||||
|
||||
**Note:** The On Demand implementation of JSON pointer relies on `find_field` which implies that it does not unescape keys when matching.
|
||||
|
||||
Consider the following example:
|
||||
The simdjson library also supports [JSON pointer](https://tools.ietf.org/html/rfc6901) through the
|
||||
`at_pointer()` method, letting you reach further down into the document in a single call:
|
||||
|
||||
```c++
|
||||
std::string cars_json = R"( [
|
||||
auto cars_json = R"( [
|
||||
{ "make": "Toyota", "model": "Camry", "year": 2018, "tire_pressure": [ 40.1, 39.9, 37.7, 40.4 ] },
|
||||
{ "make": "Kia", "model": "Soul", "year": 2012, "tire_pressure": [ 30.1, 31.0, 28.6, 28.7 ] },
|
||||
{ "make": "Toyota", "model": "Tercel", "year": 1999, "tire_pressure": [ 29.8, 30.0, 30.2, 30.5 ] }
|
||||
] )";
|
||||
ondemand::parser parser;
|
||||
auto cars = parser.iterate(cars_json);
|
||||
] )"_padded;
|
||||
dom::parser parser;
|
||||
dom::element cars = parser.parse(cars_json);
|
||||
cout << cars.at_pointer("/0/tire_pressure/1") << endl; // Prints 39.9
|
||||
```
|
||||
|
||||
@@ -592,91 +457,29 @@ index allows you to select the indexed node. Within objects, the string value of
|
||||
select the value. If your keys contain the characters '/' or '~', they must be escaped as '~1' and
|
||||
'~0' respectively. An empty JSON Path refers to the whole document.
|
||||
|
||||
For multiple JSON pointer queries on a document, one can call `at_pointer` multiple times.
|
||||
We also extend the JSON Pointer support to include *relative* paths.
|
||||
You can apply a JSON path to any node and the path gets interpreted relatively, as if the currrent node were a whole JSON document.
|
||||
|
||||
Consider the following example:
|
||||
|
||||
```c++
|
||||
std::string cars_json = R"( [
|
||||
auto cars_json = R"( [
|
||||
{ "make": "Toyota", "model": "Camry", "year": 2018, "tire_pressure": [ 40.1, 39.9, 37.7, 40.4 ] },
|
||||
{ "make": "Kia", "model": "Soul", "year": 2012, "tire_pressure": [ 30.1, 31.0, 28.6, 28.7 ] },
|
||||
{ "make": "Toyota", "model": "Tercel", "year": 1999, "tire_pressure": [ 29.8, 30.0, 30.2, 30.5 ] }
|
||||
] )";
|
||||
ondemand::parser parser;
|
||||
auto cars = parser.iterate(cars_json);
|
||||
size_t size = cars.count_elements();
|
||||
|
||||
for (size_t i = 0; i < size; i++) {
|
||||
std::string json_pointer = "/" + std::to_string(i) + "/tire_pressure/1";
|
||||
double x = cars.at_pointer(json_pointer);
|
||||
std::cout << x << std::endl; // Prints 39.9, 31 and 30
|
||||
] )"_padded;
|
||||
dom::parser parser;
|
||||
dom::element cars = parser.parse(cars_json);
|
||||
cout << cars.at_pointer("/0/tire_pressure/1") << endl; // Prints 39.9
|
||||
for (dom::element car_element : cars) {
|
||||
dom::object car;
|
||||
simdjson::error_code error;
|
||||
if ((error = car_element.get(car))) { std::cerr << error << std::endl; return; }
|
||||
double x = car.at_pointer("/tire_pressure/1");
|
||||
cout << x << endl; // Prints 39.9, 31 and 30
|
||||
}
|
||||
```
|
||||
|
||||
Note that `at_pointer` calls [`rewind`](#rewind) to reset the parser at the beginning of the document. Hence, it invalidates all previously parsed values, objects and arrays: make sure to consume the values between each call to `at_pointer`. Consider the following example where one wants to store each object from the JSON into a vector of `struct car_type`:
|
||||
|
||||
```c++
|
||||
struct car_type {
|
||||
std::string make;
|
||||
std::string model;
|
||||
uint64_t year;
|
||||
std::vector<double> tire_pressure;
|
||||
car_type(std::string_view _make, std::string_view _model, uint64_t _year,
|
||||
std::vector<double>&& _tire_pressure) :
|
||||
make{_make}, model{_model}, year(_year), tire_pressure(_tire_pressure) {}
|
||||
};
|
||||
|
||||
std::string cars_json = R"( [
|
||||
{ "make": "Toyota", "model": "Camry", "year": 2018, "tire_pressure": [ 40.1, 39.9, 37.7, 40.4 ] },
|
||||
{ "make": "Kia", "model": "Soul", "year": 2012, "tire_pressure": [ 30.1, 31.0, 28.6, 28.7 ] },
|
||||
{ "make": "Toyota", "model": "Tercel", "year": 1999, "tire_pressure": [ 29.8, 30.0, 30.2, 30.5 ] }
|
||||
] )";
|
||||
|
||||
ondemand::parser parser;
|
||||
ondemand::document cars;
|
||||
std::vector<double> measured;
|
||||
parser.iterate(cars_json).get(cars);
|
||||
std::vector<car_type> content;
|
||||
for (int i = 0; i < 3; i++) {
|
||||
ondemand::object obj;
|
||||
std::string json_pointer = "/" + std::to_string(i);
|
||||
// Each successive at_pointer call invalidates
|
||||
// previously parsed values, strings, objects and array.
|
||||
cars.at_pointer(json_pointer).get(obj);
|
||||
// We materialize the object.
|
||||
std::string_view make;
|
||||
ASSERT_SUCCESS(obj["make"].get(make));
|
||||
std::string_view model;
|
||||
ASSERT_SUCCESS(obj["model"].get(model));
|
||||
uint64_t year;
|
||||
ASSERT_SUCCESS(obj["year"].get(year));
|
||||
// We materialize the array.
|
||||
ondemand::array arr;
|
||||
ASSERT_SUCCESS(obj["tire_pressure"].get(arr));
|
||||
std::vector<double> values;
|
||||
for(auto x : arr) {
|
||||
double value_double;
|
||||
ASSERT_SUCCESS(x.get(value_double));
|
||||
values.push_back(value_double);
|
||||
}
|
||||
content.emplace_back(make, model, year, std::move(values));
|
||||
}
|
||||
```
|
||||
|
||||
Furthermore, `at_pointer` calls `rewind` at the beginning of the call (i.e. the document is not reset after `at_pointer`). Consider the following example,
|
||||
|
||||
```c++
|
||||
std::string json = R"( {
|
||||
"k0": 27,
|
||||
"k1": [13,26],
|
||||
"k2": true
|
||||
} )";
|
||||
ondemand::parser parser;
|
||||
auto doc = parser.iterate(json);
|
||||
std::cout << doc.at_pointer("/k1/1") << std::endl; // Prints 26
|
||||
std::cout << doc.at_pointer("/k2") << std::endl; // Prints true
|
||||
doc.rewind(); // Need to manually rewind to be able to use find_field properly from start of document
|
||||
std::cout << doc.find_field("k0") << std::endl; // Prints 27
|
||||
```
|
||||
|
||||
|
||||
|
||||
Error Handling
|
||||
@@ -763,11 +566,11 @@ int main(void) {
|
||||
This is how the example in "Using the Parsed JSON" could be written using only error code checking:
|
||||
|
||||
```c++
|
||||
std::string cars_json = R"( [
|
||||
auto cars_json = R"( [
|
||||
{ "make": "Toyota", "model": "Camry", "year": 2018, "tire_pressure": [ 40.1, 39.9, 37.7, 40.4 ] },
|
||||
{ "make": "Kia", "model": "Soul", "year": 2012, "tire_pressure": [ 30.1, 31.0, 28.6, 28.7 ] },
|
||||
{ "make": "Toyota", "model": "Tercel", "year": 1999, "tire_pressure": [ 29.8, 30.0, 30.2, 30.5 ] }
|
||||
] )";
|
||||
] )"_padded;
|
||||
dom::parser parser;
|
||||
dom::array cars;
|
||||
auto error = parser.parse(cars_json).get(cars);
|
||||
@@ -810,10 +613,10 @@ for (dom::element car_element : cars) {
|
||||
Here is another example:
|
||||
|
||||
```C++
|
||||
std::string abstract_json = R"( [
|
||||
auto abstract_json = R"( [
|
||||
{ "12345" : {"a":12.34, "b":56.78, "c": 9998877} },
|
||||
{ "12545" : {"a":11.44, "b":12.78, "c": 11111111} }
|
||||
] )";
|
||||
] )"_padded;
|
||||
dom::parser parser;
|
||||
dom::array array;
|
||||
auto error = parser.parse(abstract_json).get(array);
|
||||
@@ -843,8 +646,8 @@ for (dom::element elem : array) {
|
||||
And another one:
|
||||
|
||||
```C++
|
||||
std::string abstract_json = R"(
|
||||
{ "str" : { "123" : {"abc" : 3.14 } } } )";
|
||||
auto abstract_json = R"(
|
||||
{ "str" : { "123" : {"abc" : 3.14 } } } )"_padded;
|
||||
dom::parser parser;
|
||||
double v;
|
||||
auto error = parser.parse(abstract_json)["str"]["123"]["abc"].get(v);
|
||||
@@ -910,74 +713,60 @@ int main(void) {
|
||||
```
|
||||
|
||||
|
||||
Rewinding
|
||||
----------
|
||||
Tree Walking and JSON Element Types
|
||||
-----------------------------------
|
||||
|
||||
In some instances, you may need to go through a document more than once. For that purpose, you may
|
||||
call the `rewind()` method on the document instance. It allows you to restart processing from the
|
||||
beginning without rescanning all of the input data again. It invalidates all values, objects and arrays
|
||||
that you have created so far (including unescaped strings).
|
||||
Sometimes you don't necessarily have a document with a known type, and are trying to generically
|
||||
inspect or walk over JSON elements. To do that, you can use iterators and the type() method. For
|
||||
example, here's a quick and dirty recursive function that verbosely prints the JSON document as JSON
|
||||
(* ignoring nuances like trailing commas and escaping strings, for brevity's sake):
|
||||
|
||||
In the following example, we print on the screen the number of cars in the JSON input file
|
||||
before printout the data.
|
||||
|
||||
```C++
|
||||
ondemand::parser parser;
|
||||
std::string cars_json = R"( [
|
||||
{ "make": "Toyota", "model": "Camry", "year": 2018, "tire_pressure": [ 40.1, 39.9, 37.7, 40.4 ] },
|
||||
{ "make": "Kia", "model": "Soul", "year": 2012, "tire_pressure": [ 30.1, 31.0, 28.6, 28.7 ] },
|
||||
{ "make": "Toyota", "model": "Tercel", "year": 1999, "tire_pressure": [ 29.8, 30.0, 30.2, 30.5 ] }
|
||||
] )";
|
||||
|
||||
auto doc = parser.iterate(cars_json);
|
||||
for (simdjson_unused ondemand::object car : doc) {
|
||||
if(car["make"] == "Toyota") { count++; }
|
||||
}
|
||||
std::cout << "We have " << count << " Toyota cars.\n";
|
||||
doc.rewind(); // requires simdjson 1.0 or better
|
||||
for (ondemand::object car : doc) {
|
||||
cout << "Make/Model: " << std::string_view(car["make"]) << "/" << std::string_view(car["model"]) << endl;
|
||||
```c++
|
||||
void print_json(dom::element element) {
|
||||
switch (element.type()) {
|
||||
case dom::element_type::ARRAY:
|
||||
cout << "[";
|
||||
for (dom::element child : dom::array(element)) {
|
||||
print_json(child);
|
||||
cout << ",";
|
||||
}
|
||||
cout << "]";
|
||||
break;
|
||||
case dom::element_type::OBJECT:
|
||||
cout << "{";
|
||||
for (dom::key_value_pair field : dom::object(element)) {
|
||||
cout << "\"" << field.key << "\": ";
|
||||
print_json(field.value);
|
||||
}
|
||||
cout << "}";
|
||||
break;
|
||||
case dom::element_type::INT64:
|
||||
cout << int64_t(element) << endl;
|
||||
break;
|
||||
case dom::element_type::UINT64:
|
||||
cout << uint64_t(element) << endl;
|
||||
break;
|
||||
case dom::element_type::DOUBLE:
|
||||
cout << double(element) << endl;
|
||||
break;
|
||||
case dom::element_type::STRING:
|
||||
cout << std::string_view(element) << endl;
|
||||
break;
|
||||
case dom::element_type::BOOL:
|
||||
cout << bool(element) << endl;
|
||||
break;
|
||||
case dom::element_type::NULL_VALUE:
|
||||
cout << "null" << endl;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void basics_treewalk_1() {
|
||||
dom::parser parser;
|
||||
print_json(parser.load("twitter.json"));
|
||||
}
|
||||
```
|
||||
|
||||
Performance note: the On Demand front-end does not materialize the parsed numbers and other values. If you are accessing everything twice, you may need to parse them twice. Thus the rewind functionality is best suited for cases where the first pass only scans the structure of the document.
|
||||
|
||||
Direct Access to the Raw String
|
||||
--------------------------------
|
||||
|
||||
The simdjson library makes explicit assumptions about types. For examples, numbers
|
||||
must be integers (up to 64-bit integers) or binary64 floating-point numbers. Some users
|
||||
have different needs. For example, some users might want to support big integers.
|
||||
The library makes this possible by providing a `raw_json_token` method which returns
|
||||
a `std::string_view` instance containing the value as a string which you may then
|
||||
parse as you see fit.
|
||||
|
||||
```C++
|
||||
simdjson::ondemand::parser parser;
|
||||
std::string docdata = R"({"value":12321323213213213213213213213211223})";
|
||||
simdjson::ondemand::document doc = parser.iterate(docdata);
|
||||
simdjson::ondemand::object obj = doc.get_object();
|
||||
std::string_view token = obj["value"].raw_json_token();
|
||||
// token has value 12321323213213213213213213213211223, it points inside the input string
|
||||
```
|
||||
|
||||
The `raw_json_token` method even works when the JSON value is a string. In such cases, it
|
||||
will return the complete string with the quotes and with eventual escaped sequences as in the
|
||||
source document.
|
||||
|
||||
```C++
|
||||
simdjson::ondemand::parser parser;
|
||||
std::string docdata = R"({"value":"12321323213213213213213213213211223"})";
|
||||
simdjson::ondemand::document doc = parser.iterate(docdata);
|
||||
simdjson::ondemand::object obj = doc.get_object();
|
||||
string_view token = obj["value"].raw_json_token();
|
||||
// token has value "12321323213213213213213213213211223", it points inside the input string
|
||||
```
|
||||
|
||||
The `raw_json_token()` should be fast and free of allocation.
|
||||
|
||||
|
||||
|
||||
Newline-Delimited JSON (ndjson) and JSON lines
|
||||
----------------------------------------------
|
||||
|
||||
@@ -987,38 +776,60 @@ format. If your JSON documents all contain arrays or objects, we even support di
|
||||
concatenation without whitespace. The concatenated file has no size restrictions (including larger
|
||||
than 4GB), though each individual document must be no larger than 4 GB.
|
||||
|
||||
Here is a simple example:
|
||||
Here is a simple example, given `x.json` with this content:
|
||||
|
||||
```json
|
||||
{ "foo": 1 }
|
||||
{ "foo": 2 }
|
||||
{ "foo": 3 }
|
||||
```
|
||||
|
||||
```c++
|
||||
std::string json = R"({ "foo": 1 } { "foo": 2 } { "foo": 3 } )";
|
||||
ondemand::parser parser;
|
||||
ondemand::document_stream docs = parser.iterate_many(json);
|
||||
for (auto & doc : docs) {
|
||||
std::cout << doc["foo"] << std::endl;
|
||||
dom::parser parser;
|
||||
dom::document_stream docs = parser.load_many("x.json");
|
||||
for (dom::element doc : docs) {
|
||||
cout << doc["foo"] << endl;
|
||||
}
|
||||
// Prints 1 2 3
|
||||
```
|
||||
|
||||
It is important to note that the iteration returns a `document` reference, and hence why the `&` is needed.
|
||||
|
||||
Unlike `parser.iterate`, `parser.iterate_many` may parse "on demand" (lazily). That is, no parsing may have been done before you enter the loop
|
||||
`for (auto & doc : docs) {` and you should expect the parser to only ever fully parse one JSON document at a time.
|
||||
|
||||
As with `parser.iterate`, when calling `parser.iterate_many(string)`, no copy is made of the provided string input. The provided memory buffer may be accessed each time a JSON document is parsed. Calling `parser.iterate_many(string)` on a temporary string buffer (e.g., `docs = parser.parse_many("[1,2,3]")`) is unsafe (and will not compile) because the `document_stream` instance needs access to the buffer to return the JSON documents.
|
||||
In-memory ndjson strings can be parsed as well, with `parser.parse_many(string)`:
|
||||
|
||||
|
||||
The `iterate_many` function can also take an optional parameter `size_t batch_size` which defines the window processing size. It is set by default to a large value (`1000000` corresponding to 1 MB). None of your JSON documents should exceed this window size, or else you will get the error `simdjson::CAPACITY`. You cannot set this window size larger than 4 GB: you will get the error `simdjson::CAPACITY`. The smaller the window size is, the less memory the function will use. Setting the window size too small (e.g., less than 100 kB) may also impact performance negatively. Leaving it to 1 MB is expected to be a good choice, unless you have some larger documents.
|
||||
```c++
|
||||
dom::parser parser;
|
||||
auto json = R"({ "foo": 1 }
|
||||
{ "foo": 2 }
|
||||
{ "foo": 3 })"_padded;
|
||||
dom::document_stream docs = parser.parse_many(json);
|
||||
for (dom::element doc : docs) {
|
||||
cout << doc["foo"] << endl;
|
||||
}
|
||||
// Prints 1 2 3
|
||||
```
|
||||
|
||||
If your individual documents within the stream of documents are large (e.g., larger than a megabyte per individual document), then the `iterate_many` function is maybe ill-suited. It is really meant to support reading efficiently streams of relatively small documents (e.g., a few kilobytes each). If you have larger documents, you should use other functions like `iterate`.
|
||||
|
||||
See [iterate_many.md](iterate_many.md) for detailed information and design.
|
||||
Unlike `parser.parse`, both `parser.load_many(filename)` and `parser.parse_many(string)` may parse
|
||||
"on demand" (lazily). That is, no parsing may have been done before you enter the loop
|
||||
`for (dom::element doc : docs) {` and you should expect the parser to only ever fully parse one JSON
|
||||
document at a time.
|
||||
|
||||
1. When calling `parser.load_many(filename)`, the file's content is loaded up in a memory buffer owned by the `parser`'s instance. Thus the file can be safely deleted after calling `parser.load_many(filename)` as the parser instance owns all of the data.
|
||||
2. When calling `parser.parse_many(string)`, no copy is made of the provided string input. The provided memory buffer may be accessed each time a JSON document is parsed. Calling `parser.parse_many(string)` on a temporary string buffer (e.g., `docs = parser.parse_many("[1,2,3]"_padded)`) is unsafe (and will not compile) because the `document_stream` instance needs access to the buffer to return the JSON documents. In constrast, calling `doc = parser.parse("[1,2,3]"_padded)` is safe because `parser.parse` eagerly parses the input.
|
||||
|
||||
|
||||
Both `load_many` and `parse_many` take an optional parameter `size_t batch_size` which defines the window processing size. It is set by default to a large value (`1000000` corresponding to 1 MB). None of your JSON documents should exceed this window size, or else you will get the error `simdjson::CAPACITY`. You cannot set this window size larger than 4 GB: you will get the error `simdjson::CAPACITY`. The smaller the window size is, the less memory the function will use. Setting the window size too small (e.g., less than 100 kB) may also impact performance negatively. Leaving it to 1 MB is expected to be a good choice, unless you have some larger documents.
|
||||
|
||||
If your documents are large (e.g., larger than a megabyte), then the `load_many` and `parse_many` functions are maybe ill-suited. They are really meant to support reading efficiently streams of relatively small documents (e.g., a few kilobytes each). If you have larger documents, you should use other functions like `parse`.
|
||||
|
||||
See [parse_many.md](parse_many.md) for detailed information and design.
|
||||
|
||||
Thread Safety
|
||||
-------------
|
||||
|
||||
We built simdjson with thread safety in mind.
|
||||
|
||||
The simdjson library is single-threaded except for [`iterate_many`](iterate_many.md) and [`parse_many`](parse_many.md) which may use secondary threads under their control when the library is compiled with thread support.
|
||||
The simdjson library is single-threaded except for [`parse_many`](parse_many.md) which may use secondary threads under its control when the library is compiled with thread support.
|
||||
|
||||
|
||||
We recommend using one `dom::parser` object per thread in which case the library is thread-safe.
|
||||
@@ -1028,7 +839,6 @@ The parsed results (`dom::document`, `dom::element`, `array`, `object`) depend o
|
||||
The CPU detection, which runs the first time parsing is attempted and switches to the fastest
|
||||
parser for your CPU, is transparent and thread-safe.
|
||||
|
||||
In a threaded environment, stack space is often limited. Running code like simdjson in debug mode may require hundreds of kilobytes of stack memory. Thus stack overflows are a possibility. We recommend you turn on optimization when working in an environment where stack space is limited. If you must run your code in debug mode, we recommend you configure your system to have more stack space. We discourage you from running production code based on a debug build.
|
||||
|
||||
Standard Compliance
|
||||
--------------------
|
||||
@@ -1039,8 +849,8 @@ The simdjson library is fully compliant with the [RFC 8259](https://www.tbray.o
|
||||
- A single string or a single number is considered to be a valid JSON document.
|
||||
- We fully validate the numbers according to the JSON specification. For example, the string `01` is not valid JSON document since the specification states that *leading zeros are not allowed*.
|
||||
- The specification allows implementations to set limits on the range and precision of numbers accepted. We support 64-bit floating-point numbers as well as integer values.
|
||||
- We parse integers and floating-point numbers as separate types which allows us to support all signed (two's complement) 64-bit integers, like a Java `long` or a C/C++ `long long` and all 64-bit unsigned integers. When we cannot represent exactly an integer as a signed or unsigned 64-bit value, we reject the JSON document.
|
||||
- We support the full range of 64-bit floating-point numbers (binary64). The values range from `std::numeric_limits<double>::lowest()` to `std::numeric_limits<double>::max()`, so from -1.7976e308 all the way to 1.7975e308. Extreme values (less or equal to -1e308, greater or equal to 1e308) are rejected: we refuse to parse the input document. Numbers are parsed with a perfect accuracy (ULP 0): the nearest floating-point value is chosen, rounding to even when needed. If you serialized your floating-point numbers with 17 significant digits in a standard compliant manner, the simdjson library is guaranteed to recover the same numbers, exactly.
|
||||
- We parse integers and floating-point numbers as separate types which allows us to support all signed (two complement's) 64-bit integers, like a Java `long` or a C/C++ `long long` and all 64-bit unsigned integers. When we cannot represent exactly an integer as a signed or unsigned 64-bit value, we reject the JSON document.
|
||||
- We support the full range of 64-bit floating-point numbers (binary64). The values range from `std::numeric_limits<double>::lowest()` to `std::numeric_limits<double>::max()`, so from -1.7976e308 all the way to 1.7975e308. Extreme values (less or equal to -1e308, greater or equal to 1e308) are rejected: we refuse to parse the input document. Numbers are parsed with with a perfect accuracy (ULP 0): the nearest floating-point value is chosen, rounding to even when needed. If you serialized your floating-point numbers with 17 significant digits in a standard compliant manner, the simdjson library is guaranteed to recovere the example same numbers, exactly.
|
||||
- The specification states that JSON text exchanged between systems that are not part of a closed ecosystem MUST be encoded using UTF-8. The simdjson library does full UTF-8 validation as part of the parsing. The specification states that implementations MUST NOT add a byte order mark: the simdjson library rejects documents starting with a byte order mark.
|
||||
- The simdjson library validates string content for unescaped characters. Unescaped line breaks and tabs in strings are not allowed.
|
||||
- The simdjson library accepts objects with repeated keys: all of the name/value pairs, including duplicates, are reported. We do not enforce key uniqueness.
|
||||
|
||||
+53
-28
@@ -15,6 +15,7 @@ An overview of what you need to know to use simdjson, with examples.
|
||||
* [Reusing the parser for maximum efficiency](#reusing-the-parser-for-maximum-efficiency)
|
||||
* [Server Loops: Long-Running Processes and Memory Capacity](#server-loops-long-running-processes-and-memory-capacity)
|
||||
* [Best Use of the DOM API](#best-use-of-the-dom-api)
|
||||
* [Padding and Temporary Copies](#padding-and-temporary-copies)
|
||||
|
||||
DOM vs On Demand
|
||||
----------------------------------------------
|
||||
@@ -35,11 +36,12 @@ dom::parser parser;
|
||||
dom::element doc = parser.load(filename); // load and parse a file
|
||||
```
|
||||
|
||||
Or by creating a string and calling `parse()`:
|
||||
Or by creating a padded string (for efficiency reasons, simdjson requires a string with
|
||||
SIMDJSON_PADDING bytes at the end) and calling `parse()`:
|
||||
|
||||
```c++
|
||||
dom::parser parser;
|
||||
dom::element doc = parser.parse(std::string("[1,2,3]")); // parse a string
|
||||
dom::element doc = parser.parse("[1,2,3]"_padded); // parse a string, the _padded suffix creates a simdjson::padded_string instance
|
||||
```
|
||||
|
||||
The parsed document resulting from the `parser.load` and `parser.parse` calls depends on the `parser` instance. Thus the `parser` instance must remain in scope. Furthermore, you must have at most one parsed document in play per `parser` instance.
|
||||
@@ -52,7 +54,8 @@ During the`load` or `parse` calls, neither the input file nor the input string a
|
||||
For best performance, a `parser` instance should be reused over several files: otherwise you will needlessly reallocate memory, an expensive process. It is also possible to avoid entirely memory allocations during parsing when using simdjson. [See our performance notes for details](performance.md).
|
||||
|
||||
If you need a lower-level interface, you may call the function `parser.parse(const char * p, size_t l)` on a pointer `p` while specifying the
|
||||
length of your input `l` in bytes.
|
||||
length of your input `l` in bytes. To see how to get the very best performance from a low-level approach, you way want to read our [performance notes](https://github.com/simdjson/simdjson/blob/master/doc/performance.md#padding-and-temporary-copies) on this topic (see the Padding and Temporary Copies section).
|
||||
|
||||
|
||||
Using the Parsed JSON
|
||||
---------------------
|
||||
@@ -66,7 +69,7 @@ Once you have an element, you can navigate it with idiomatic C++ iterators, oper
|
||||
`dom::object` and `dom::array`) and pass it by reference to `get()` which gives you back an error code: e.g.,
|
||||
```c++
|
||||
simdjson::error_code error;
|
||||
std::string numberstring = "1.2"; // our JSON input ("1.2")
|
||||
simdjson::padded_string numberstring = "1.2"_padded; // our JSON input ("1.2")
|
||||
simdjson::dom::parser parser;
|
||||
double value; // variable where we store the value to be parsed
|
||||
error = parser.parse(numberstring).get(value);
|
||||
@@ -86,18 +89,18 @@ Once you have an element, you can navigate it with idiomatic C++ iterators, oper
|
||||
with the `size()` method.
|
||||
* **Checking an Element Type:** You can check an element's type with `element.type()`. It
|
||||
returns an `element_type` with values such as `simdjson::dom::element_type::ARRAY`, `simdjson::dom::element_type::OBJECT`, `simdjson::dom::element_type::INT64`, `simdjson::dom::element_type::UINT64`,`simdjson::dom::element_type::DOUBLE`, `simdjson::dom::element_type::BOOL` or, `simdjson::dom::element_type::NULL_VALUE`.
|
||||
* **Output to streams and strings:** Given a document or an element (or node) out of a JSON document, you can output a minified string version using the C++ stream idiom (`out << element`). You can also request the construction of a minified string version (`simdjson::minify(element)`). Numbers are serialized as 64-bit floating-point numbers (`double`).
|
||||
* **Output to streams and strings:** Given a document or an element (or node) out of a JSON document, you can output a minified string version using the C++ stream idiom (`out << element`). You can also request the construction of a minified string version (`simdjson::minify(element)`).
|
||||
|
||||
### Examples
|
||||
|
||||
The following code illustrates all of the above:
|
||||
|
||||
```c++
|
||||
std::string cars_json = R"( [
|
||||
auto cars_json = R"( [
|
||||
{ "make": "Toyota", "model": "Camry", "year": 2018, "tire_pressure": [ 40.1, 39.9, 37.7, 40.4 ] },
|
||||
{ "make": "Kia", "model": "Soul", "year": 2012, "tire_pressure": [ 30.1, 31.0, 28.6, 28.7 ] },
|
||||
{ "make": "Toyota", "model": "Tercel", "year": 1999, "tire_pressure": [ 29.8, 30.0, 30.2, 30.5 ] }
|
||||
] )";
|
||||
] )"_padded;
|
||||
dom::parser parser;
|
||||
|
||||
// Iterating through an array of objects
|
||||
@@ -126,10 +129,10 @@ for (dom::object car : parser.parse(cars_json)) {
|
||||
Here is a different example illustrating the same ideas:
|
||||
|
||||
```C++
|
||||
std::string abstract_json = R"( [
|
||||
auto abstract_json = R"( [
|
||||
{ "12345" : {"a":12.34, "b":56.78, "c": 9998877} },
|
||||
{ "12545" : {"a":11.44, "b":12.78, "c": 11111111} }
|
||||
] )";
|
||||
] )"_padded;
|
||||
dom::parser parser;
|
||||
|
||||
// Parse and iterate through an array of objects
|
||||
@@ -148,8 +151,8 @@ And another one:
|
||||
|
||||
|
||||
```C++
|
||||
std::string abstract_json = R"(
|
||||
{ "str" : { "123" : {"abc" : 3.14 } } } )";
|
||||
auto abstract_json = R"(
|
||||
{ "str" : { "123" : {"abc" : 3.14 } } } )"_padded;
|
||||
dom::parser parser;
|
||||
double v = parser.parse(abstract_json)["str"]["123"]["abc"];
|
||||
cout << "number: " << v << endl;
|
||||
@@ -162,7 +165,7 @@ C++17 Support
|
||||
While the simdjson library can be used in any project using C++ 11 and above, field iteration has special support C++ 17's destructuring syntax. For example:
|
||||
|
||||
```c++
|
||||
std::string json = R"( { "foo": 1, "bar": 2 } )";
|
||||
padded_string json = R"( { "foo": 1, "bar": 2 } )"_padded;
|
||||
dom::parser parser;
|
||||
dom::object object;
|
||||
auto error = parser.parse(json).get(object);
|
||||
@@ -176,7 +179,7 @@ For comparison, here is the C++ 11 version of the same code:
|
||||
|
||||
```c++
|
||||
// C++ 11 version for comparison
|
||||
std::string json = R"( { "foo": 1, "bar": 2 } )";
|
||||
padded_string json = R"( { "foo": 1, "bar": 2 } )"_padded;
|
||||
dom::parser parser;
|
||||
dom::object object;
|
||||
auto error = parser.parse(json).get(object);
|
||||
@@ -194,11 +197,11 @@ The simdjson library also supports [JSON pointer](https://tools.ietf.org/html/rf
|
||||
`at_pointer()` method, letting you reach further down into the document in a single call:
|
||||
|
||||
```c++
|
||||
std::string cars_json = R"( [
|
||||
auto cars_json = R"( [
|
||||
{ "make": "Toyota", "model": "Camry", "year": 2018, "tire_pressure": [ 40.1, 39.9, 37.7, 40.4 ] },
|
||||
{ "make": "Kia", "model": "Soul", "year": 2012, "tire_pressure": [ 30.1, 31.0, 28.6, 28.7 ] },
|
||||
{ "make": "Toyota", "model": "Tercel", "year": 1999, "tire_pressure": [ 29.8, 30.0, 30.2, 30.5 ] }
|
||||
] )";
|
||||
] )"_padded;
|
||||
dom::parser parser;
|
||||
dom::element cars = parser.parse(cars_json);
|
||||
cout << cars.at_pointer("/0/tire_pressure/1") << endl; // Prints 39.9
|
||||
@@ -210,16 +213,16 @@ select the value. If your keys contain the characters '/' or '~', they must be e
|
||||
'~0' respectively. An empty JSON Path refers to the whole document.
|
||||
|
||||
We also extend the JSON Pointer support to include *relative* paths.
|
||||
You can apply a JSON path to any node and the path gets interpreted relatively, as if the current node were a whole JSON document.
|
||||
You can apply a JSON path to any node and the path gets interpreted relatively, as if the currrent node were a whole JSON document.
|
||||
|
||||
Consider the following example:
|
||||
|
||||
```c++
|
||||
std::string cars_json = R"( [
|
||||
auto cars_json = R"( [
|
||||
{ "make": "Toyota", "model": "Camry", "year": 2018, "tire_pressure": [ 40.1, 39.9, 37.7, 40.4 ] },
|
||||
{ "make": "Kia", "model": "Soul", "year": 2012, "tire_pressure": [ 30.1, 31.0, 28.6, 28.7 ] },
|
||||
{ "make": "Toyota", "model": "Tercel", "year": 1999, "tire_pressure": [ 29.8, 30.0, 30.2, 30.5 ] }
|
||||
] )";
|
||||
] )"_padded;
|
||||
dom::parser parser;
|
||||
dom::element cars = parser.parse(cars_json);
|
||||
cout << cars.at_pointer("/0/tire_pressure/1") << endl; // Prints 39.9
|
||||
@@ -318,11 +321,11 @@ int main(void) {
|
||||
This is how the example in "Using the Parsed JSON" could be written using only error code checking:
|
||||
|
||||
```c++
|
||||
std::string cars_json = R"( [
|
||||
auto cars_json = R"( [
|
||||
{ "make": "Toyota", "model": "Camry", "year": 2018, "tire_pressure": [ 40.1, 39.9, 37.7, 40.4 ] },
|
||||
{ "make": "Kia", "model": "Soul", "year": 2012, "tire_pressure": [ 30.1, 31.0, 28.6, 28.7 ] },
|
||||
{ "make": "Toyota", "model": "Tercel", "year": 1999, "tire_pressure": [ 29.8, 30.0, 30.2, 30.5 ] }
|
||||
] )";
|
||||
] )"_padded;
|
||||
dom::parser parser;
|
||||
dom::array cars;
|
||||
auto error = parser.parse(cars_json).get(cars);
|
||||
@@ -365,10 +368,10 @@ for (dom::element car_element : cars) {
|
||||
Here is another example:
|
||||
|
||||
```C++
|
||||
std::string abstract_json = R"( [
|
||||
auto abstract_json = R"( [
|
||||
{ "12345" : {"a":12.34, "b":56.78, "c": 9998877} },
|
||||
{ "12545" : {"a":11.44, "b":12.78, "c": 11111111} }
|
||||
] )";
|
||||
] )"_padded;
|
||||
dom::parser parser;
|
||||
dom::array array;
|
||||
auto error = parser.parse(abstract_json).get(array);
|
||||
@@ -398,8 +401,8 @@ for (dom::element elem : array) {
|
||||
And another one:
|
||||
|
||||
```C++
|
||||
std::string abstract_json = R"(
|
||||
{ "str" : { "123" : {"abc" : 3.14 } } } )";
|
||||
auto abstract_json = R"(
|
||||
{ "str" : { "123" : {"abc" : 3.14 } } } )"_padded;
|
||||
dom::parser parser;
|
||||
double v;
|
||||
auto error = parser.parse(abstract_json)["str"]["123"]["abc"].get(v);
|
||||
@@ -533,16 +536,15 @@ you can parse terabytes of JSON data without doing any new allocation.
|
||||
dom::parser parser;
|
||||
|
||||
// This initializes buffers and a document big enough to handle this JSON.
|
||||
dom::element doc = parser.parse(std::string("[ true, false ]"));
|
||||
// std::string("[ true, false ]") may be replaced by "[ true, false ]"s
|
||||
dom::element doc = parser.parse("[ true, false ]"_padded);
|
||||
cout << doc << endl;
|
||||
|
||||
// This reuses the existing buffers, and reuses and *overwrites* the old document
|
||||
doc = parser.parse(std::string("[1, 2, 3]"));
|
||||
doc = parser.parse("[1, 2, 3]"_padded);
|
||||
cout << doc << endl;
|
||||
|
||||
// This also reuses the existing buffers, and reuses and *overwrites* the old document
|
||||
dom::element doc2 = parser.parse(std::string("true"));
|
||||
dom::element doc2 = parser.parse("true"_padded);
|
||||
// Even if you keep the old reference around, doc and doc2 refer to the same document.
|
||||
cout << doc << endl;
|
||||
cout << doc2 << endl;
|
||||
@@ -608,3 +610,26 @@ Best Use of the DOM API
|
||||
-------------------------
|
||||
|
||||
The simdjson API provides access to the JSON DOM (document-object-model) content as a tree of `dom::element` instances, each representing an object, an array or an atomic type (null, true, false, number). These `dom::element` instances are lightweight objects (e.g., spanning 16 bytes) and it might be advantageous to pass them by value, as opposed to passing them by reference or by pointer.
|
||||
|
||||
Padding and Temporary Copies
|
||||
--------------
|
||||
|
||||
The simdjson function `parser.parse` reads data from a padded buffer, containing SIMDJSON_PADDING extra bytes added at the end.
|
||||
If you are passing a `padded_string` to `parser.parse` or loading the JSON directly from
|
||||
disk (`parser.load`), padding is automatically handled.
|
||||
When calling `parser.parse` on a pointer (e.g., `parser.parse(my_char_pointer, my_length_in_bytes)`) a temporary copy is made by default with adequate padding and you, again, do not need to be concerned with padding.
|
||||
|
||||
Some users may not be able use our `padded_string` class or to load the data directly from disk (`parser.load`). They may need to pass data pointers to the library. If these users wish to avoid temporary copies and corresponding temporary memory allocations, they may want to call `parser.parse` with the `realloc_if_needed` parameter set to false (e.g., `parser.parse(my_char_pointer, my_length_in_bytes, false)`). In such cases, they need to ensure that there are at least SIMDJSON_PADDING extra bytes at the end that can be safely accessed and read. They do not need to initialize the padded bytes to any value in particular. The following example is safe:
|
||||
|
||||
|
||||
```C++
|
||||
const char *json = R"({"key":"value"})";
|
||||
const size_t json_len = std::strlen(json);
|
||||
std::unique_ptr<char[]> padded_json_copy{new char[json_len + SIMDJSON_PADDING]};
|
||||
memcpy(padded_json_copy.get(), json, json_len);
|
||||
memset(padded_json_copy.get() + json_len, 0, SIMDJSON_PADDING);
|
||||
simdjson::dom::parser parser;
|
||||
simdjson::dom::element element = parser.parse(padded_json_copy.get(), json_len, false);
|
||||
````
|
||||
|
||||
Setting the `realloc_if_needed` parameter `false` in this manner may lead to better performance since copies are avoided, but it requires that the user takes more responsibilities: the simdjson library cannot verify that the input buffer was padded with SIMDJSON_PADDING extra bytes.
|
||||
@@ -1,229 +0,0 @@
|
||||
iterate_many
|
||||
==========
|
||||
|
||||
An interface providing features to work with files or streams containing multiple small JSON documents.
|
||||
As fast and convenient as possible.
|
||||
|
||||
Contents
|
||||
--------
|
||||
|
||||
- [Motivations](#motivations)
|
||||
- [How it works](#how-it-works)
|
||||
- [Support](#support)
|
||||
- [API](#api)
|
||||
- [Use cases](#use-cases)
|
||||
- [Tracking your position](#tracking-your-position)
|
||||
- [Incomplete streams](#incomplete-streams)
|
||||
|
||||
Motivation
|
||||
-----------
|
||||
|
||||
The main motivation for this piece of software is to achieve maximum speed and offer a
|
||||
better quality of life in parsing files containing multiple small JSON documents.
|
||||
|
||||
The JavaScript Object Notation (JSON) [RFC7159](https://tools.ietf.org/html/rfc7159) is a handy
|
||||
serialization format. However, when serializing a large sequence of
|
||||
values as an array, or a possibly indeterminate-length or never-
|
||||
ending sequence of values, JSON may be inconvenient.
|
||||
|
||||
Consider a sequence of one million values, each possibly one kilobyte
|
||||
when encoded -- roughly one gigabyte. It is often desirable to process such a dataset incrementally
|
||||
without having to first read all of it before beginning to produce results.
|
||||
|
||||
|
||||
How it works
|
||||
------------
|
||||
|
||||
### Context
|
||||
|
||||
Before parsing anything, simdjson first preprocesses the JSON text by identifying all structural indexes
|
||||
(i.e. the starting position of any JSON value, as well as any important operators like `,`, `:`, `]` or
|
||||
`}`) and validating UTF8. This stage is referred to stage 1. However, during this process, simdjson has
|
||||
no knowledge of whether parsed a valid document, multiple documents, or even if the document is complete.
|
||||
Then, to iterate through the JSON text during parsing, we use what we call a JSON iterator that will navigate
|
||||
through the text using these structural indexes. This JSON iterator is not visible though, but it is the
|
||||
key component to make parsing work.
|
||||
|
||||
Prior to iterate_many, most people who had to parse a multiline JSON file would proceed by reading the
|
||||
file line by line, using a utility function like `std::getline` or equivalent, and would then use
|
||||
the `parse` on each of those lines. From a performance point of view, this process is highly
|
||||
inefficient, in that it requires a lot of unnecessary memory allocation and makes use of the
|
||||
`getline` function, which is fundamentally slow, slower than the act of parsing with simdjson
|
||||
[(more on this here)](https://lemire.me/blog/2019/06/18/how-fast-is-getline-in-c/).
|
||||
|
||||
Unlike the popular parser RapidJson, our DOM does not require the buffer once the parsing job is
|
||||
completed, the DOM and the buffer are completely independent. The drawback of this architecture is
|
||||
that we need to allocate some additional memory to store our ParsedJson data, for every document
|
||||
inside a given file. Memory allocation can be slow and become a bottleneck, therefore, we want to
|
||||
minimize it as much as possible.
|
||||
|
||||
### Design
|
||||
|
||||
To achieve a minimum amount of allocations, we opted for a design where we create only one
|
||||
parser object and therefore allocate its memory once, and then recycle it for every document in a
|
||||
given file. But, knowing that they often have largely varying size, we need to make sure that we
|
||||
allocate enough memory so that all the documents can fit. This value is what we call the batch size.
|
||||
As of right now, we need to manually specify a value for this batch size, it has to be at least as
|
||||
big as the biggest document in your file, but not too big so that it submerges the cached memory.
|
||||
The bigger the batch size, the fewer we need to make allocations. We found that 1MB is somewhat a
|
||||
sweet spot.
|
||||
|
||||
1. When the user calls `iterate_many`, we return a `document_stream` which the user can iterate over
|
||||
to receive parsed documents.
|
||||
2. We call stage 1 on the first batch_size bytes of JSON in the buffer, detecting structural
|
||||
indexes for all documents in that batch.
|
||||
3. The `document_stream` owns a `document` instance that keeps track of the current document position
|
||||
in the stream using a JSON iterator. To obtain a valid document, the `document_stream` returns a
|
||||
**reference** to its document instance.
|
||||
4. Each time the user calls `++` to read the next document, the JSON iterator moves to the start the
|
||||
next document.
|
||||
5. When we reach the end of the batch, we call stage 1 on the next batch, starting from the end of
|
||||
the last document, and go to step 3.
|
||||
|
||||
### Threads
|
||||
|
||||
But how can we make use of threads if they are available? We found a pretty cool algorithm that allows
|
||||
us to quickly identify the position of the last JSON document in a given batch. Knowing exactly where
|
||||
the end of the last document in the batch is, we can safely parse through the last document without any
|
||||
worries that it might be incomplete. Therefore, we can run stage 1 on the next batch concurrently while
|
||||
parsing the documents in the current batch. Running stage 1 in a different thread can, in best cases,
|
||||
remove almost entirely its cost and replaces it by the overhead of a thread, which is orders of magnitude
|
||||
cheaper. Ain't that awesome!
|
||||
|
||||
Thread support is only active if thread supported is detected in which case the macro
|
||||
SIMDJSON_THREADS_ENABLED is set. Otherwise the library runs in single-thread mode.
|
||||
|
||||
A `document_stream` instance uses at most two threads: there is a main thread and a worker thread.
|
||||
|
||||
Support
|
||||
-------
|
||||
|
||||
Since we want to offer flexibility and not restrict ourselves to a specific file
|
||||
format, we support any file that contains any amount of valid JSON document, **separated by one
|
||||
or more character that is considered whitespace** by the JSON spec. Anything that is
|
||||
not whitespace will be parsed as a JSON document and could lead to failure.
|
||||
|
||||
Whitespace Characters:
|
||||
- **Space**
|
||||
- **Linefeed**
|
||||
- **Carriage return**
|
||||
- **Horizontal tab**
|
||||
- **Nothing**
|
||||
|
||||
Some official formats **(non-exhaustive list)**:
|
||||
- [Newline-Delimited JSON (NDJSON)](http://ndjson.org/)
|
||||
- [JSON lines (JSONL)](http://jsonlines.org/)
|
||||
- [Record separator-delimited JSON (RFC 7464)](https://tools.ietf.org/html/rfc7464) <- Not supported by JsonStream!
|
||||
- [More on Wikipedia...](https://en.wikipedia.org/wiki/JSON_streaming)
|
||||
|
||||
API
|
||||
---
|
||||
|
||||
See [basics.md](basics.md#newline-delimited-json-ndjson-and-json-lines) for an overview of the API.
|
||||
|
||||
## Use cases
|
||||
|
||||
From [jsonlines.org](http://jsonlines.org/examples/):
|
||||
|
||||
- **Better than CSV**
|
||||
```json
|
||||
["Name", "Session", "Score", "Completed"]
|
||||
["Gilbert", "2013", 24, true]
|
||||
["Alexa", "2013", 29, true]
|
||||
["May", "2012B", 14, false]
|
||||
["Deloise", "2012A", 19, true]
|
||||
```
|
||||
CSV seems so easy that many programmers have written code to generate it themselves, and almost every implementation is
|
||||
different. Handling broken CSV files is a common and frustrating task. CSV has no standard encoding, no standard column
|
||||
separator and multiple character escaping standards. String is the only type supported for cell values, so some programs
|
||||
attempt to guess the correct types.
|
||||
|
||||
JSON Lines handles tabular data cleanly and without ambiguity. Cells may use the standard JSON types.
|
||||
|
||||
The biggest missing piece is an import/export filter for popular spreadsheet programs so that non-programmers can use
|
||||
this format.
|
||||
|
||||
- **Easy Nested Data**
|
||||
```json
|
||||
{"name": "Gilbert", "wins": [["straight", "7♣"], ["one pair", "10♥"]]}
|
||||
{"name": "Alexa", "wins": [["two pair", "4♠"], ["two pair", "9♠"]]}
|
||||
{"name": "May", "wins": []}
|
||||
{"name": "Deloise", "wins": [["three of a kind", "5♣"]]}
|
||||
```
|
||||
JSON Lines' biggest strength is in handling lots of similar nested data structures. One .jsonl file is easier to
|
||||
work with than a directory full of XML files.
|
||||
|
||||
|
||||
Tracking your position
|
||||
-----------
|
||||
|
||||
Some users would like to know where the document they parsed is in the input array of bytes.
|
||||
It is possible to do so by accessing directly the iterator and calling its `current_index()`
|
||||
method which reports the location (in bytes) of the current document in the input stream.
|
||||
You may also call the `source()` method to get a `std::string_view` instance on the document
|
||||
and `error()` to check if there were any error.
|
||||
|
||||
Let us illustrate the idea with code:
|
||||
|
||||
|
||||
```C++
|
||||
std::string json = R"([1,2,3] {"1":1,"2":3,"4":4} [1,2,3] )";
|
||||
simdjson::ondemand::parser parser;
|
||||
simdjson::ondemand::document_stream stream;
|
||||
auto error = parser.iterate_many(json).get(stream);
|
||||
if( error ) { /* do something */ }
|
||||
auto i = stream.begin();
|
||||
size_t count{0};
|
||||
for(; i != stream.end(); ++i) {
|
||||
auto & doc = *i;
|
||||
if(!i.error()) {
|
||||
std::cout << "got full document at " << i.current_index() << std::endl;
|
||||
std::cout << i.source() << std::endl;
|
||||
count++;
|
||||
} else {
|
||||
std::cout << "got broken document at " << i.current_index() << std::endl;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
This code will print:
|
||||
```
|
||||
got full document at 0
|
||||
[1,2,3]
|
||||
got full document at 9
|
||||
{"1":1,"2":3,"4":4}
|
||||
got full document at 29
|
||||
[1,2,3]
|
||||
```
|
||||
|
||||
|
||||
Incomplete streams
|
||||
-----------
|
||||
|
||||
Some users may need to work with truncated streams. The simdjson may truncate documents at the very end of the stream that cannot possibly be valid JSON (e.g., they contain unclosed strings, unmatched brackets, unmatched braces). After iterating through the stream, you may query the `truncated_bytes()` method which tells you how many bytes were truncated. If the stream is made of full (whole) documents, then you should expect `truncated_bytes()` to return zero.
|
||||
|
||||
|
||||
Consider the following example where a truncated document (`{"key":"intentionally unclosed string `) containing 39 bytes has been left within the stream. In such cases, the first two whole documents are parsed and returned, and the `truncated_bytes()` method returns 39.
|
||||
|
||||
```C++
|
||||
std::string json = R"([1,2,3] {"1":1,"2":3,"4":4} {"key":"intentionally unclosed string )";
|
||||
simdjson::ondemand::parser parser;
|
||||
simdjson::ondemand::document_stream stream;
|
||||
auto error = parser.iterate_many(json,json.size()).get(stream);
|
||||
if(error) { std::cerr << error << std::endl; return; }
|
||||
for(auto i = stream.begin(); i != stream.end(); ++i) {
|
||||
std::cout << i.source() << std::endl;
|
||||
}
|
||||
std::cout << stream.truncated_bytes() << " bytes "<< std::endl; // returns 39 bytes
|
||||
```
|
||||
|
||||
This will print:
|
||||
```
|
||||
[1,2,3]
|
||||
{"1":1,"2":3,"4":4}
|
||||
39 bytes
|
||||
```
|
||||
|
||||
Importantly, you should only call `truncated_bytes()` after iterating through all of the documents since the stream cannot tell whether there are truncated documents at the very end when it may not have accessed that part of the data yet.
|
||||
+1
-37
@@ -636,7 +636,7 @@ direct raw ASCII comparisons: `key().raw()` provides direct access to the unesca
|
||||
You can compare `key()` with unescaped C strings (e.g., `key()=="test"`). It is expected
|
||||
that the provided string is a valid JSON string. Importantly,
|
||||
the C string must not contain an unescaped quote character (`"`). For speed, the comparison is done byte-by-byte
|
||||
without handling the escaped characters.
|
||||
without handling the escaped caracters.
|
||||
If you occasionally need to access and store the
|
||||
unescaped key values, you may use the `unescaped_key()` method. Once you have called `unescaped_key()` method,
|
||||
neither the `key()` nor the `unescaped_key()` methods should be called: the current field instance
|
||||
@@ -709,42 +709,6 @@ in production systems:
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### Long-Running Processes and Memory Capacity
|
||||
|
||||
The On Demand approach also automatically expands its memory capacity when larger documents are parsed. However, for longer processes where very large files are processed (such as server loops), this capacity is not resized down. Similarly to the DOM-based approach (see [here](https://github.com/simdjson/simdjson/blob/master/doc/dom.md#server-loops-long-running-processes-and-memory-capacity)]), On Demand also lets you adjust the maximal capacity that the parser can process:
|
||||
|
||||
* You can set an upper bound (*max_capacity*) when construction the parser:
|
||||
```C++
|
||||
ondemand::parser parser(1000*1000); // Never grows past documents > 1 MB
|
||||
auto doc = parser.iterate(json);
|
||||
for (web_request request : listen()) {
|
||||
padded_string json;
|
||||
padded_string json = padded_string::load(request.body);
|
||||
auto error = parser.iterate(json);
|
||||
// If the document was above our limit, emit 413 = payload too large
|
||||
if (error == CAPACITY) { request.respond(413); continue; }
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
The capacity will grow as the parser encounters larger documents up to 1 MB.
|
||||
|
||||
* You can also allocate a *fixed capacity* that will never grow:
|
||||
```C++
|
||||
ondemand::parser parser(1000*1000);
|
||||
parser.allocate(1000*1000) // Fix the capacity to 1 MB
|
||||
auto doc = parser.iterate(json);
|
||||
for (web_request request : listen()) {
|
||||
padded_string json;
|
||||
padded_string json = padded_string::load(request.body);
|
||||
auto error = parser.iterate(json);
|
||||
// If the document was above our limit, emit 413 = payload too large
|
||||
if (error == CAPACITY) { request.respond(413); continue; }
|
||||
// ...
|
||||
}
|
||||
```
|
||||
You can also manually set the maximal capacity using the method `set_max_capacity()`.
|
||||
### Benefits of the On Demand Approach
|
||||
|
||||
We expect that the On Demand approach has many of the performance benefits of the schema-based approach, while providing a flexibility that is similar to that of the DOM-based approach.
|
||||
|
||||
+18
-31
@@ -168,63 +168,50 @@ Tracking your position
|
||||
Some users would like to know where the document they parsed is in the input array of bytes.
|
||||
It is possible to do so by accessing directly the iterator and calling its `current_index()`
|
||||
method which reports the location (in bytes) of the current document in the input stream.
|
||||
You may also call the `source()` method to get a `std::string_view` instance on the document.
|
||||
|
||||
Let us illustrate the idea with code:
|
||||
|
||||
|
||||
```C++
|
||||
std::string json = R"([1,2,3] {"1":1,"2":3,"4":4} [1,2,3] )";
|
||||
auto json = R"([1,2,3] {"1":1,"2":3,"4":4} [1,2,3] )"_padded;
|
||||
simdjson::dom::parser parser;
|
||||
simdjson::dom::document_stream stream;
|
||||
auto error = parser.parse_many(json).get(stream);
|
||||
if( error ) { /* do something */ }
|
||||
ASSERT_SUCCESS( parser.parse_many(json).get(stream) );
|
||||
auto i = stream.begin();
|
||||
size_t count{0};
|
||||
for(; i != stream.end(); ++i) {
|
||||
auto doc = *i;
|
||||
if(!doc.error()) {
|
||||
std::cout << "got full document at " << i.current_index() << std::endl;
|
||||
std::cout << i.source() << std::endl;
|
||||
count++;
|
||||
} else {
|
||||
std::cout << "got broken document at " << i.current_index() << std::endl;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
size_t index = i.current_index();
|
||||
if(index != 38) {
|
||||
std::cerr << "Expected to stop after the three full documents " << std::endl;
|
||||
std::cerr << "index = " << index << std::endl;
|
||||
return false;
|
||||
}
|
||||
```
|
||||
|
||||
This code will print:
|
||||
```
|
||||
got full document at 0
|
||||
[1,2,3]
|
||||
got full document at 9
|
||||
{"1":1,"2":3,"4":4}
|
||||
got full document at 29
|
||||
[1,2,3]
|
||||
```
|
||||
|
||||
The last call to `i.current_index()` return the byte index 38, which is just beyond
|
||||
the last document.
|
||||
|
||||
Incomplete streams
|
||||
-----------
|
||||
|
||||
Some users may need to work with truncated streams. The simdjson may truncate documents at the very end of the stream that cannot possibly be valid JSON (e.g., they contain unclosed strings, unmatched brackets, unmatched braces). After iterating through the stream, you may query the `truncated_bytes()` method which tells you how many bytes were truncated. If the stream is made of full (whole) documents, then you should expect `truncated_bytes()` to return zero.
|
||||
Some users may need to work with truncated streams while tracking their location in the stream.
|
||||
The same code, with the `current_index()` will work. However, the last block (by default 1MB)
|
||||
terminates with an unclosed string, then no JSON document within this last block will validate.
|
||||
In particular, it means that if your input string is `[1,2,3] {"1":1,"2":3,"4":4} [1,2` then
|
||||
no JSON document will be successfully parsed. The error `simdjson::UNCLOSED_STRING` will be
|
||||
given (even with the first JSON document). It is then your responsability to terminate the input
|
||||
maybe by appending the missing data at the end of the truncated string, or by copying the truncated
|
||||
data before the continuing input.
|
||||
|
||||
|
||||
Consider the following example where a truncated document (`{"key":"intentionally unclosed string `) containing 39 bytes has been left within the stream. In such cases, the first two whole documents are parsed and returned, and the `truncated_bytes()` method returns 39.
|
||||
|
||||
```C++
|
||||
std::string json = R"([1,2,3] {"1":1,"2":3,"4":4} {"key":"intentionally unclosed string )";
|
||||
simdjson::dom::parser parser;
|
||||
simdjson::dom::document_stream stream;
|
||||
auto error = parser.parse_many(json,json.size()).get(stream);
|
||||
if(error) { std::cerr << error << std::endl; return; }
|
||||
for(auto doc : stream) {
|
||||
std::cout << doc << std::endl;
|
||||
}
|
||||
std::cout << stream.truncated_bytes() << " bytes "<< std::endl; // returns 39 bytes
|
||||
```
|
||||
|
||||
|
||||
Importantly, you should only call `truncated_bytes()` after iterating through all of the documents since the stream cannot tell whether there are truncated documents at the very end when it may not have accessed that part of the data yet.
|
||||
+9
-3
@@ -24,14 +24,14 @@ you can parse terabytes of JSON data without doing any new allocation.
|
||||
ondemand::parser parser;
|
||||
|
||||
// This initializes buffers big enough to handle this JSON.
|
||||
std::string json = "[ true, false ]";
|
||||
auto json = "[ true, false ]"_padded;
|
||||
auto doc = parser.iterate(json);
|
||||
for(bool i : doc.get_array()) {
|
||||
cout << i << endl;
|
||||
}
|
||||
|
||||
// This reuses the existing buffers
|
||||
std::string number_json = "[1, 2, 3]";
|
||||
auto number_json = "[1, 2, 3]"_padded;
|
||||
doc = parser.iterate(number_json);
|
||||
for(int64_t i : doc.get_array()) {
|
||||
cout << i << endl;
|
||||
@@ -45,9 +45,15 @@ Reusing string buffers
|
||||
We recommend against creating many `std::string` or `simdjson::padded_string` instances to store the JSON content in your application. [Creating many non-trivial objects is convenient but often surprisingly slow](https://lemire.me/blog/2020/08/08/performance-tip-constructing-many-non-trivial-objects-is-slow/). Instead, as much as possible, you should allocate (once or a few times) reusable memory buffers where you write your JSON content. If you have a buffer `json_str` (of type `char*`) allocated for `capacity` bytes and you store a JSON document spanning `length` bytes, you can pass it to simdjson as follows:
|
||||
|
||||
```c++
|
||||
auto doc = parser.iterate(json_str, length));
|
||||
auto doc = parser.iterate(padded_string_view(json_str, length, capacity));
|
||||
```
|
||||
|
||||
or simply
|
||||
|
||||
|
||||
```c++
|
||||
auto doc = parser.iterate(json_str, length, capacity);
|
||||
```
|
||||
|
||||
|
||||
Large files and huge page support
|
||||
|
||||
+7
-6
@@ -1,11 +1,11 @@
|
||||
if(NOT SIMDJSON_LEGACY_VISUAL_STUDIO AND NOT SIMDJSON_WINDOWS_DLL)
|
||||
option(SIMDJSON_ENABLE_FUZZING "enable building the fuzzers" ON)
|
||||
option(ENABLE_FUZZING "enable building the fuzzers" ON)
|
||||
else()
|
||||
option(SIMDJSON_ENABLE_FUZZING "enable building the fuzzers" OFF)
|
||||
option(ENABLE_FUZZING "enable building the fuzzers" OFF)
|
||||
endif()
|
||||
|
||||
|
||||
if(SIMDJSON_ENABLE_FUZZING)
|
||||
if(ENABLE_FUZZING)
|
||||
|
||||
# First attempt at a fuzzer, using libFuzzer.
|
||||
#
|
||||
@@ -17,7 +17,7 @@ if(SIMDJSON_ENABLE_FUZZING)
|
||||
# export CFLAGS="-fsanitize=fuzzer-no-link,address,undefined"
|
||||
# export CXX=clang++
|
||||
# export CC=clang++
|
||||
# cmake .. -GNinja -DCMAKE_BUILD_TYPE=Debug -DSIMDJSON_ENABLE_FUZZING=On -DSIMDJSON_FUZZ_LINKMAIN=Off -DSIMDJSON_FUZZ_LDFLAGS=-fsanitize=fuzzer
|
||||
# cmake .. -GNinja -DCMAKE_BUILD_TYPE=Debug -DENABLE_FUZZING=On -DSIMDJSON_FUZZ_LINKMAIN=Off -DSIMDJSON_FUZZ_LDFLAGS=-fsanitize=fuzzer
|
||||
# ninja
|
||||
|
||||
# settings this links in a main. useful for reproducing,
|
||||
@@ -25,7 +25,7 @@ if(SIMDJSON_ENABLE_FUZZING)
|
||||
# (note that libFuzzer can also reproduce, just pass it the files)
|
||||
#
|
||||
# Using this by default, means the fuzzers will be built as a part of the normal
|
||||
# workflow, meaning they won't bitrot and will participate in refactoring etc.
|
||||
# workflow, meaning they wont bitrot and will participate in refactoring etc.
|
||||
#
|
||||
option(SIMDJSON_FUZZ_LINKMAIN "links a main into fuzz targets for building reproducers" On)
|
||||
|
||||
@@ -35,10 +35,11 @@ if(SIMDJSON_ENABLE_FUZZING)
|
||||
|
||||
# Fuzzer build flags and libraries
|
||||
add_library(simdjson-fuzzer INTERFACE)
|
||||
target_link_libraries(simdjson-fuzzer INTERFACE simdjson)
|
||||
if (SIMDJSON_FUZZ_LINKMAIN)
|
||||
target_link_libraries(simdjson-fuzzer INTERFACE simdjson-source)
|
||||
target_sources(simdjson-fuzzer INTERFACE $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>/main.cpp)
|
||||
else ()
|
||||
target_link_libraries(simdjson-fuzzer INTERFACE simdjson)
|
||||
target_link_libraries(simdjson-fuzzer INTERFACE ${SIMDJSON_FUZZ_LDFLAGS})
|
||||
endif ()
|
||||
target_link_libraries(simdjson-fuzzer INTERFACE simdjson-internal-flags)
|
||||
|
||||
+2
-5
@@ -45,9 +45,6 @@ The corpus will grow over time and easy to find bugs will be detected already du
|
||||
## Fuzzing as a CI job - arm64
|
||||
There is also a job running the fuzzers on arm64 (see .drone.yml) to make sure also the arm specific parts are fuzzed. This does not update the corpus, it just reuses what the x64 job finds.
|
||||
|
||||
## Fuzzing as a CI job - power
|
||||
There is a fuzzing job similar to the arm64 one. It takes the corpus from the x64 fuzzer as a starting point and fuzzes it for a short while. See the "short fuzz on the power arch" github action job.
|
||||
|
||||
## Fuzzing on oss-fuzz
|
||||
The simdjson library is continuously fuzzed on [oss-fuzz](https://github.com/google/oss-fuzz). In case a bug is found, the offending input is minimized and tested for reproducibility. A report with the details is automatically filed, and the contact persons at simdjson are notified via email. An issue is opened at the oss-fuzz bugtracker with restricted view access. When the bug is fixed, the issue is automatically closed.
|
||||
|
||||
@@ -67,7 +64,7 @@ As little code as possible is kept at oss-fuzz since it is inconvenient to chang
|
||||
|
||||
## Corpus
|
||||
|
||||
The simdjson library does not benefit from a corpus as much as other projects, because the library is very fast and explores the input space very well. With that said, it is still beneficial to have one. The CI job stores the corpus on a remote server between runs, and is available at [www.pauldreik.se](https://readonly:readonly@www.pauldreik.se/fuzzdata/index.php?project=simdjson).
|
||||
The simdjson library does not benefit from a corpus as much as other projects, because the library is very fast and explores the input space very well. With that said, it is still beneficial to have one. The CI job stores the corpus on bintray between runs, and is available at [bintray](https://dl.bintray.com/pauldreik/simdjson-fuzz-corpus/corpus/corpus.tar).
|
||||
|
||||
One can also grab the corpus as an artifact from the github actions job. Pick a run, then go to artifacts and download.
|
||||
|
||||
@@ -100,4 +97,4 @@ build-sanitizers-O0/fuzz/fuzz_ndjson minimized_crash -cleanse_crash=1 -exact_art
|
||||
|
||||
# use/share cleansed_crash
|
||||
|
||||
```
|
||||
```
|
||||
@@ -48,7 +48,7 @@ if [ -e $testfuzzer ] ; then rm $testfuzzer; fi
|
||||
|
||||
# common options
|
||||
CXX_CLAGS_COMMON=-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
|
||||
COMMON="-GNinja -DCMAKE_CXX_COMPILER=clang++$CLANGSUFFIX -DCMAKE_C_COMPILER=clang$CLANGSUFFIX -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=ON -DSIMDJSON_ENABLE_FUZZING=On -DSIMDJSON_COMPETITION=OFF -DSIMDJSON_GOOGLE_BENCHMARKS=OFF -DSIMDJSON_DISABLE_DEPRECATED_API=On -DSIMDJSON_FUZZ_LDFLAGS=$SIMDJSON_FUZZ_LDFLAGS"
|
||||
COMMON="-GNinja -DCMAKE_CXX_COMPILER=clang++$CLANGSUFFIX -DCMAKE_C_COMPILER=clang$CLANGSUFFIX -DSIMDJSON_BUILD_STATIC=Off -DENABLE_FUZZING=On -DSIMDJSON_COMPETITION=OFF -DSIMDJSON_GOOGLE_BENCHMARKS=OFF -DSIMDJSON_DISABLE_DEPRECATED_API=On -DSIMDJSON_FUZZ_LDFLAGS=$SIMDJSON_FUZZ_LDFLAGS"
|
||||
|
||||
# A replay build, as plain as it gets. For use with valgrind/gdb.
|
||||
variant=replay
|
||||
|
||||
@@ -23,9 +23,8 @@ if [ ! -d $bdir ] ; then
|
||||
cmake .. \
|
||||
-GNinja \
|
||||
-DCMAKE_BUILD_TYPE=Debug \
|
||||
-DSIMDJSON_DEVELOPER_MODE=ON \
|
||||
-DBUILD_SHARED_LIBS=OFF \
|
||||
-DSIMDJSON_ENABLE_FUZZING=On \
|
||||
-DSIMDJSON_BUILD_STATIC=On \
|
||||
-DENABLE_FUZZING=On \
|
||||
-DSIMDJSON_DISABLE_DEPRECATED_API=On \
|
||||
-DSIMDJSON_FUZZ_LINKMAIN=On
|
||||
ninja all_fuzzers
|
||||
|
||||
+2
-3
@@ -26,9 +26,8 @@ cd build
|
||||
cmake .. \
|
||||
-GNinja \
|
||||
-DCMAKE_BUILD_TYPE=Debug \
|
||||
-DSIMDJSON_DEVELOPER_MODE=ON \
|
||||
-DBUILD_SHARED_LIBS=OFF \
|
||||
-DSIMDJSON_ENABLE_FUZZING=On \
|
||||
-DSIMDJSON_BUILD_STATIC=On \
|
||||
-DENABLE_FUZZING=On \
|
||||
-DSIMDJSON_COMPETITION=Off \
|
||||
-DSIMDJSON_FUZZ_LINKMAIN=Off \
|
||||
-DSIMDJSON_GOOGLE_BENCHMARKS=Off \
|
||||
|
||||
+2
-4
@@ -23,10 +23,8 @@ done
|
||||
|
||||
#download the corpus if it does not already exist
|
||||
if [ ! -d out ] ; then
|
||||
# ideally, we would download the github artifact but that requires being logged in which can not
|
||||
# easily be fixed from this shell script.
|
||||
echo "NOTE! please go to the artifacts page on https://github.com/simdjson/simdjson/actions/workflows/fuzzers.yml and download the latest corpus.tar.zip artifact manually to speed up fuzzing"
|
||||
sleep 5s
|
||||
wget --quiet https://dl.bintray.com/pauldreik/simdjson-fuzz-corpus/corpus/corpus.tar
|
||||
tar xf corpus.tar && rm corpus.tar
|
||||
fi
|
||||
|
||||
# By default, use the debug friendly variant since this script is intended
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
#
|
||||
# Provides the simdjson headers.
|
||||
#
|
||||
# target_link_libraries(my-project simdjson-headers) grants the headers. It does not provide the
|
||||
# source, libraries or any compiler flags.
|
||||
#
|
||||
add_library(simdjson-headers INTERFACE)
|
||||
target_compile_features(simdjson-headers INTERFACE cxx_std_11) # headers require at least C++11
|
||||
target_include_directories(simdjson-headers INTERFACE
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
|
||||
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCDIR}>)
|
||||
|
||||
install(TARGETS simdjson-headers EXPORT simdjson-config INCLUDES DESTINATION include)
|
||||
+1
-1
@@ -4,7 +4,7 @@
|
||||
/**
|
||||
* @mainpage
|
||||
*
|
||||
* Check the [README.md](https://github.com/simdjson/simdjson/blob/master/README.md#simdjson--parsing-gigabytes-of-json-per-second).
|
||||
* Check the [README.md](https://github.com/lemire/simdjson/blob/master/README.md#simdjson--parsing-gigabytes-of-json-per-second).
|
||||
*
|
||||
* Sample code. See https://github.com/simdjson/simdjson/blob/master/doc/basics.md for more examples.
|
||||
|
||||
|
||||
@@ -46,40 +46,6 @@ simdjson_really_inline int count_ones(uint64_t input_num) {
|
||||
return vaddv_u8(vcnt_u8(vcreate_u8(input_num)));
|
||||
}
|
||||
|
||||
|
||||
#if defined(__GNUC__) // catches clang and gcc
|
||||
/**
|
||||
* ARM has a fast 64-bit "bit reversal function" that is handy. However,
|
||||
* it is not generally available as an intrinsic function under Visual
|
||||
* Studio (though this might be changing). Even under clang/gcc, we
|
||||
* apparently need to invoke inline assembly.
|
||||
*/
|
||||
/*
|
||||
* We use SIMDJSON_PREFER_REVERSE_BITS as a hint that algorithms that
|
||||
* work well with bit reversal may use it.
|
||||
*/
|
||||
#define SIMDJSON_PREFER_REVERSE_BITS 1
|
||||
|
||||
/* reverse the bits */
|
||||
simdjson_really_inline uint64_t reverse_bits(uint64_t input_num) {
|
||||
uint64_t rev_bits;
|
||||
__asm("rbit %0, %1" : "=r"(rev_bits) : "r"(input_num));
|
||||
return rev_bits;
|
||||
}
|
||||
|
||||
/**
|
||||
* Flips bit at index 63 - lz. Thus if you have 'leading_zeroes' leading zeroes,
|
||||
* then this will set to zero the leading bit. It is possible for leading_zeroes to be
|
||||
* greating or equal to 63 in which case we trigger undefined behavior, but the output
|
||||
* of such undefined behavior is never used.
|
||||
**/
|
||||
NO_SANITIZE_UNDEFINED
|
||||
simdjson_really_inline uint64_t zero_leading_bit(uint64_t rev_bits, int leading_zeroes) {
|
||||
return rev_bits ^ (uint64_t(0x8000000000000000) >> leading_zeroes);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
simdjson_really_inline bool add_overflow(uint64_t value1, uint64_t value2, uint64_t *result) {
|
||||
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||
*result = value1 + value2;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user