Compare commits

..

6 Commits

Author SHA1 Message Date
Daniel Lemire 45182ec11b Tagging the version. 2021-05-27 16:21:00 -04:00
Daniel Lemire a0c020d46d Patching. 2021-05-27 16:20:07 -04:00
Daniel Lemire 076f41ae4b Patch release candidate. 2021-05-15 15:45:02 -04:00
Daniel Lemire 6a37fc1871 Disabling perf testing on version 0.9 2021-05-14 09:22:48 -04:00
Daniel Lemire c6c29c2827 Better definition for fallthrough. 2021-03-31 14:38:52 -04:00
Daniel Lemire 941e903f28 Prerelease commit. 2021-03-31 13:48:43 -04:00
2169 changed files with 310380 additions and 15690 deletions
+6 -6
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
+4 -19
View File
@@ -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.
+8 -2
View File
@@ -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:
+16 -18
View File
@@ -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()
+10 -5
View File
@@ -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
+10 -5
View File
@@ -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
+12 -7
View File
@@ -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
+8 -2
View File
@@ -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
+5 -11
View File
@@ -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
+1 -1
View File
@@ -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
+9 -4
View File
@@ -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
+8 -2
View File
@@ -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 &&
+1 -1
View File
@@ -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
+8 -8
View File
@@ -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 &&
+9 -9
View File
@@ -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 &&
-23
View File
@@ -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
+9 -3
View File
@@ -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
+8 -8
View File
@@ -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 . &&
+9 -7
View File
@@ -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
-21
View File
@@ -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
+9 -7
View File
@@ -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
+9 -3
View File
@@ -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"
+8 -2
View File
@@ -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
+8 -2
View File
@@ -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'
-7
View File
@@ -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
View File
@@ -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
-17
View File
@@ -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": [
]
}
-90
View File
@@ -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
View File
@@ -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 5)
set(SIMDJSON_SEMANTIC_VERSION "0.9.5" 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
View File
@@ -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.
-1
View File
@@ -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
View File
@@ -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 . "]
+1 -1
View File
@@ -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.5"
# 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
View File
@@ -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`
+4 -8
View File
@@ -1,4 +1,4 @@
[![Fuzzing Status](https://oss-fuzz-build-logs.storage.googleapis.com/badges/simdjson.svg)](https://bugs.chromium.org/p/oss-fuzz/issues/list?sort=-opened&q=proj%3Asimdjson&can=2)
![Ubuntu 18.04 CI](https://github.com/simdjson/simdjson/workflows/Ubuntu%2018.04%20CI%20(GCC%207)/badge.svg)
[![Ubuntu 20.04 CI](https://github.com/simdjson/simdjson/workflows/Ubuntu%2020.04%20CI%20(GCC%209)/badge.svg)](https://simdjson.org/plots.html)
![VS16-CI](https://github.com/simdjson/simdjson/workflows/VS16-CI/badge.svg)
@@ -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.
+14 -4
View File
@@ -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)
+19
View File
@@ -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
-20
View File
@@ -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();
-58
View File
@@ -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;
+1 -1
View File
@@ -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
-16
View File
@@ -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)
-68
View File
@@ -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
+1 -1
View File
@@ -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
-70
View File
@@ -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
-1
View File
@@ -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";
}
-51
View File
@@ -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) {
-74
View File
@@ -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
-70
View File
@@ -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
-69
View File
@@ -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
+3 -10
View File
@@ -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
-165
View File
@@ -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];
-99
View File
@@ -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
+1 -1
View File
@@ -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
-101
View File
@@ -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
-187
View File
@@ -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)
-28
View File
@@ -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()
-23
View File
@@ -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()
-106
View File
@@ -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()
+8 -5
View File
@@ -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")
+275
View File
@@ -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)
-48
View File
@@ -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()
+22 -17
View File
@@ -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})
-4
View File
@@ -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
View File
@@ -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
View File
@@ -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.
-229
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
```
```
+1 -1
View File
@@ -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
+2 -3
View File
@@ -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
View File
@@ -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
View File
@@ -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
+13
View File
@@ -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
View File
@@ -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.
-34
View File
@@ -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