mirror of
https://github.com/simdjson/simdjson
synced 2026-06-08 17:27:07 +00:00
Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 7edd32dc6b | |||
| 91b74c593c | |||
| fa629bd783 | |||
| 7784aa86c2 | |||
| a47b64e0ff | |||
| d92bc82b37 | |||
| 5b02e117bb | |||
| ef6fc77861 |
@@ -1,8 +1,5 @@
|
||||
CompileFlags:
|
||||
CompilationDatabase: build
|
||||
Add:
|
||||
- -Werror -Wall -Wextra -Weffc++ -Wsign-compare -Wshadow -Wwrite-strings -Wpointer-arith -Winit-self -Wconversion -Wno-sign-conversion
|
||||
- -Wundefined-inline
|
||||
Diagnostics:
|
||||
Suppress:
|
||||
- misc-unused-alias-decls
|
||||
@@ -19,28 +16,10 @@ If:
|
||||
CompileFlags:
|
||||
Add:
|
||||
- -Wno-unneeded-internal-declaration
|
||||
- -Wno-undefined-inline # TODO fix and remove these violations
|
||||
- -Wno-undefined-internal # TODO fix and remove these violations
|
||||
- -Wno-unused-function
|
||||
- -Wno-unused-const-variable
|
||||
Diagnostics:
|
||||
Suppress:
|
||||
- pp_including_mainfile_in_preamble
|
||||
---
|
||||
# Amalgamated files that require or partly define an implementation
|
||||
If:
|
||||
PathMatch:
|
||||
- .*/(arm64|fallback|haswell|icelake|ppc64|westmere)/begin.h
|
||||
- .*/generic/.*
|
||||
Diagnostics:
|
||||
Suppress:
|
||||
- pragma_attribute_no_pop_eof
|
||||
---
|
||||
# clang has a bad time detecting the push/pop together in src/ for some reason
|
||||
If:
|
||||
PathMatch:
|
||||
- include/simdjson/.*/end.h
|
||||
- src/(arm64|fallback|haswell|icelake|ppc64|westmere).cpp
|
||||
Diagnostics:
|
||||
Suppress:
|
||||
- pragma_attribute_no_pop_eof
|
||||
- pragma_attribute_stack_mismatch
|
||||
|
||||
@@ -45,15 +45,11 @@ It is fine to report bugs against our main branch, but if that is what you are d
|
||||
|
||||
**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]
|
||||
- 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.
|
||||
|
||||
* We do not support unreleased or experimental compilers. If you encounter an issue with a
|
||||
pre-release version of a compiler, do not report it as a bug to simdjson. However, we always
|
||||
invite contributions either in the form an analysis or of a code contribution.
|
||||
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.
|
||||
|
||||
**Indicate whether you are willing or able to provide a bug fix as a pull request**
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ A clear and concise description of any alternative solutions or features you've
|
||||
**Additional context**
|
||||
Add any other context or screenshots about the feature request here.
|
||||
|
||||
**Are you willing to contribute code or documentation toward this new feature?**
|
||||
** Are you willing to contribute code or documentation toward this new feature? **
|
||||
If you plan to contribute to simdjson, please read our
|
||||
* CONTRIBUTING guide: https://github.com/simdjson/simdjson/blob/master/CONTRIBUTING.md and our
|
||||
* HACKING guide: https://github.com/simdjson/simdjson/blob/master/HACKING.md
|
||||
|
||||
@@ -9,7 +9,7 @@ jobs:
|
||||
! contains(toJSON(github.event.commits.*.message), '[skip github]')
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/cache@v3
|
||||
with:
|
||||
path: dependencies/.cache
|
||||
|
||||
@@ -16,7 +16,7 @@ jobs:
|
||||
image: debian:testing
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
|
||||
@@ -19,7 +19,7 @@ jobs:
|
||||
url: ${{ steps.deployment.outputs.page_url }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v3
|
||||
- name: Install Doxygen
|
||||
run: sudo apt-get install doxygen graphviz -y
|
||||
- run: mkdir docs
|
||||
|
||||
@@ -6,7 +6,7 @@ jobs:
|
||||
whitespace:
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v3
|
||||
- name: Remove whitespace and check the diff
|
||||
run: |
|
||||
set -eu
|
||||
|
||||
@@ -20,7 +20,7 @@ jobs:
|
||||
# fuzzers that change behaviour with SIMDJSON_FORCE_IMPLEMENTATION
|
||||
defaultimplfuzzers: atpointer dump dump_raw_tape element minify parser print_json
|
||||
# fuzzers that loop over the implementations themselves, or don't need to switch.
|
||||
implfuzzers: implementations minifyimpl ndjson ondemand padded utf8
|
||||
implfuzzers: implementations minifyimpl ndjson ondemand padded utf8 # TODO add singlestage
|
||||
implementations: haswell westmere fallback
|
||||
UBSAN_OPTIONS: halt_on_error=1
|
||||
MAXLEN: -max_len=4000
|
||||
@@ -34,11 +34,10 @@ jobs:
|
||||
sudo apt update
|
||||
sudo apt-get install --quiet ninja-build valgrind zip unzip lsb-release wget software-properties-common gnupg
|
||||
wget https://apt.llvm.org/llvm.sh
|
||||
sudo apt-get purge --auto-remove llvm python3-lldb-14 llvm-14
|
||||
chmod +x llvm.sh
|
||||
sudo ./llvm.sh $CLANGVERSION
|
||||
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- uses: actions/cache@v3
|
||||
with:
|
||||
|
||||
@@ -9,7 +9,7 @@ jobs:
|
||||
! contains(toJSON(github.event.commits.*.message), '[skip github]')
|
||||
runs-on: macos-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/cache@v3
|
||||
with:
|
||||
path: dependencies/.cache
|
||||
@@ -31,14 +31,3 @@ jobs:
|
||||
echo -e '#include <simdjson.h>\nint main(int argc,char**argv) {simdjson::dom::parser parser;simdjson::dom::element tweets = parser.load(argv[1]); }' > tmp.cpp && c++ -Idestination/include -Ldestination/lib -std=c++17 -Wl,-rpath,destination/lib -o linkandrun tmp.cpp -lsimdjson && ./linkandrun jsonexamples/twitter.json &&
|
||||
cd ../tests/installation_tests/find &&
|
||||
mkdir build && cd build && cmake -DCMAKE_INSTALL_PREFIX:PATH=../../../build/destination .. && cmake --build .
|
||||
- name: Use cmake (shared)
|
||||
run: |
|
||||
mkdir buildshared &&
|
||||
cd buildshared &&
|
||||
cmake -DSIMDJSON_GOOGLE_BENCHMARKS=ON -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=ON -DCMAKE_INSTALL_PREFIX:PATH=destination .. &&
|
||||
cmake --build . &&
|
||||
ctest --output-on-failure -LE explicitonly -j &&
|
||||
cmake --install . &&
|
||||
echo -e '#include <simdjson.h>\nint main(int argc,char**argv) {simdjson::dom::parser parser;simdjson::dom::element tweets = parser.load(argv[1]); }' > tmp.cpp && c++ -Idestination/include -Ldestination/lib -std=c++17 -Wl,-rpath,destination/lib -o linkandrun tmp.cpp -lsimdjson && ./linkandrun jsonexamples/twitter.json &&
|
||||
cd ../tests/installation_tests/find &&
|
||||
mkdir buildshared && cd buildshared && cmake -DCMAKE_INSTALL_PREFIX:PATH=../../../buildshared/destination .. && cmake --build .
|
||||
|
||||
@@ -24,7 +24,7 @@ jobs:
|
||||
CMAKE_GENERATOR: Ninja
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/cache@v3
|
||||
with:
|
||||
path: dependencies/.cache
|
||||
|
||||
@@ -26,7 +26,7 @@ jobs:
|
||||
CMAKE_GENERATOR: Ninja
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/cache@v3
|
||||
with:
|
||||
path: dependencies/.cache
|
||||
|
||||
@@ -15,7 +15,7 @@ jobs:
|
||||
runs-on: ubuntu-20.04
|
||||
name: Build on ubuntu-20.04 ppc64le
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v3
|
||||
- uses: uraimo/run-on-arch-action@v2.0.5
|
||||
name: Run commands
|
||||
id: runcmd
|
||||
|
||||
@@ -12,7 +12,7 @@ jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v3
|
||||
- uses: uraimo/run-on-arch-action@v2
|
||||
name: Test
|
||||
id: runcmd
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
name: Ubuntu riscv64 (GCC 11)
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: uraimo/run-on-arch-action@v2
|
||||
name: Test
|
||||
id: runcmd
|
||||
with:
|
||||
arch: riscv64
|
||||
distro: ubuntu_latest
|
||||
githubToken: ${{ github.token }}
|
||||
install: |
|
||||
apt-get update -q -y
|
||||
apt-get install -y cmake make g++
|
||||
run: |
|
||||
cmake -DCMAKE_BUILD_TYPE=Release -B build
|
||||
cmake --build build -j=2
|
||||
ctest --output-on-failure --test-dir build
|
||||
@@ -12,7 +12,7 @@ jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v3
|
||||
- uses: uraimo/run-on-arch-action@v2
|
||||
name: Test
|
||||
id: runcmd
|
||||
|
||||
@@ -15,7 +15,7 @@ jobs:
|
||||
! contains(toJSON(github.event.commits.*.message), '[skip github]')
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/cache@v3
|
||||
with:
|
||||
path: dependencies/.cache
|
||||
|
||||
@@ -12,7 +12,7 @@ jobs:
|
||||
CXX: g++-8
|
||||
CC: gcc-8
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/cache@v3
|
||||
with:
|
||||
path: dependencies/.cache
|
||||
|
||||
@@ -9,7 +9,7 @@ jobs:
|
||||
! contains(toJSON(github.event.commits.*.message), '[skip github]')
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/cache@v3
|
||||
with:
|
||||
path: dependencies/.cache
|
||||
|
||||
@@ -9,7 +9,7 @@ jobs:
|
||||
! contains(toJSON(github.event.commits.*.message), '[skip github]')
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/cache@v3
|
||||
with:
|
||||
path: dependencies/.cache
|
||||
|
||||
@@ -3,13 +3,13 @@ name: Ubuntu 20.04 CI (GCC 9) With Memory Sanitizer
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
ubuntu-build-address-sanitizier:
|
||||
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@v4
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/cache@v3
|
||||
with:
|
||||
path: dependencies/.cache
|
||||
@@ -21,17 +21,6 @@ jobs:
|
||||
cmake -DSIMDJSON_SANITIZE=ON -DCMAKE_BUILD_TYPE=Debug -DSIMDJSON_GOOGLE_BENCHMARKS=OFF -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF .. &&
|
||||
cmake --build . &&
|
||||
ctest --output-on-failure -LE explicitonly -j
|
||||
ubuntu-build-undefined-sanitizer:
|
||||
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@v4
|
||||
- uses: actions/cache@v3
|
||||
with:
|
||||
path: dependencies/.cache
|
||||
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
||||
- name: Use cmake with undefined sanitizer
|
||||
run: |
|
||||
mkdir builddebugundefsani &&
|
||||
|
||||
+3
-3
@@ -1,4 +1,4 @@
|
||||
name: Ubuntu 22.04 CI (GCC 11) with Thread Sanitizer
|
||||
name: Ubuntu 20.04 CI (GCC 9) with Thread Sanitizer
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
@@ -7,9 +7,9 @@ jobs:
|
||||
if: >-
|
||||
! contains(toJSON(github.event.commits.*.message), '[skip ci]') &&
|
||||
! contains(toJSON(github.event.commits.*.message), '[skip github]')
|
||||
runs-on: ubuntu-22.04
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/cache@v3
|
||||
with:
|
||||
path: dependencies/.cache
|
||||
@@ -9,25 +9,11 @@ jobs:
|
||||
! contains(toJSON(github.event.commits.*.message), '[skip github]')
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/cache@v3
|
||||
with:
|
||||
path: dependencies/.cache
|
||||
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
||||
- name: Use cmake to build just the library
|
||||
run: |
|
||||
mkdir buildjustlib &&
|
||||
cd buildjustlib &&
|
||||
cmake -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=OFF -DSIMDJSON_DEVELOPER_MODE=OFF -DCMAKE_INSTALL_PREFIX:PATH=destination .. &&
|
||||
cmake --build . &&
|
||||
cmake --install . &&
|
||||
echo -e '#include <simdjson.h>\nint main(int argc,char**argv) {simdjson::dom::parser parser;simdjson::dom::element tweets = parser.load(argv[1]); }' > tmp.cpp &&
|
||||
c++ -Idestination/include -Ldestination/lib -std=c++17 -Wl,-rpath,destination/lib -o linkandrun tmp.cpp -lsimdjson &&
|
||||
cd ../tests/installation_tests/find &&
|
||||
mkdir buildjustlib &&
|
||||
cd buildjustlib &&
|
||||
cmake -DCMAKE_INSTALL_PREFIX:PATH=../../../buildjustlib/destination .. &&
|
||||
cmake --build .
|
||||
- name: Use cmake
|
||||
run: |
|
||||
mkdir builddebug &&
|
||||
|
||||
@@ -9,11 +9,13 @@ jobs:
|
||||
! contains(toJSON(github.event.commits.*.message), '[skip github]')
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/cache@v3
|
||||
with:
|
||||
path: dependencies/.cache
|
||||
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
||||
- name: Install clang++-13
|
||||
run: sudo apt-get install -y clang++-13
|
||||
- name: Use cmake
|
||||
run: |
|
||||
mkdir build &&
|
||||
|
||||
@@ -9,11 +9,13 @@ jobs:
|
||||
! contains(toJSON(github.event.commits.*.message), '[skip github]')
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/cache@v3
|
||||
with:
|
||||
path: dependencies/.cache
|
||||
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
||||
- name: Install clang++-14
|
||||
run: sudo apt-get install -y clang++-14
|
||||
- name: Use cmake
|
||||
run: |
|
||||
mkdir build &&
|
||||
|
||||
@@ -9,7 +9,7 @@ jobs:
|
||||
! contains(toJSON(github.event.commits.*.message), '[skip github]')
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/cache@v3
|
||||
with:
|
||||
path: dependencies/.cache
|
||||
|
||||
@@ -9,11 +9,13 @@ jobs:
|
||||
! contains(toJSON(github.event.commits.*.message), '[skip github]')
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/cache@v3
|
||||
with:
|
||||
path: dependencies/.cache
|
||||
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
||||
- name: Install gcc12
|
||||
run: sudo apt-get install -y g++-12
|
||||
- name: Use cmake
|
||||
run: |
|
||||
mkdir build &&
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
name: Ubuntu 22.04 CI (GCC 13)
|
||||
|
||||
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-22.04
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/cache@v3
|
||||
with:
|
||||
path: dependencies/.cache
|
||||
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
||||
- name: Use cmake
|
||||
run: |
|
||||
mkdir build &&
|
||||
cd build &&
|
||||
CXX=g++-13 cmake -DSIMDJSON_DEVELOPER_MODE=ON .. &&
|
||||
cmake --build . &&
|
||||
ctest --output-on-failure -LE explicitonly -j
|
||||
@@ -8,7 +8,7 @@ jobs:
|
||||
! contains(toJSON(github.event.commits.*.message), '[skip github]')
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/cache@v3
|
||||
with:
|
||||
path: dependencies/.cache
|
||||
|
||||
@@ -9,25 +9,11 @@ jobs:
|
||||
! contains(toJSON(github.event.commits.*.message), '[skip github]')
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/cache@v3
|
||||
with:
|
||||
path: dependencies/.cache
|
||||
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
||||
- name: Use cmake to build just the library
|
||||
run: |
|
||||
mkdir buildjustlib &&
|
||||
cd buildjustlib &&
|
||||
cmake -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=OFF -DSIMDJSON_DEVELOPER_MODE=OFF -DCMAKE_INSTALL_PREFIX:PATH=destination .. &&
|
||||
cmake --build . &&
|
||||
cmake --install . &&
|
||||
echo -e '#include <simdjson.h>\nint main(int argc,char**argv) {simdjson::dom::parser parser;simdjson::dom::element tweets = parser.load(argv[1]); }' > tmp.cpp &&
|
||||
c++ -Idestination/include -Ldestination/lib -std=c++17 -Wl,-rpath,destination/lib -o linkandrun tmp.cpp -lsimdjson &&
|
||||
cd ../tests/installation_tests/find &&
|
||||
mkdir buildjustlib &&
|
||||
cd buildjustlib &&
|
||||
cmake -DCMAKE_INSTALL_PREFIX:PATH=../../../buildjustlib/destination .. &&
|
||||
cmake --build .
|
||||
- name: Use cmake
|
||||
run: |
|
||||
mkdir builddebug &&
|
||||
|
||||
@@ -14,7 +14,7 @@ jobs:
|
||||
- {arch: ARM64}
|
||||
steps:
|
||||
- name: checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v3
|
||||
- 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 &&
|
||||
|
||||
@@ -19,7 +19,7 @@ jobs:
|
||||
- {gen: Visual Studio 17 2022, arch: x64, shared: OFF}
|
||||
steps:
|
||||
- name: checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v3
|
||||
- name: Configure
|
||||
run: |
|
||||
cmake -DSIMDJSON_CXX_STANDARD=20 -G "${{matrix.gen}}" -A ${{matrix.arch}} -DSIMDJSON_DEVELOPER_MODE=ON -DSIMDJSON_COMPETITION=OFF -DBUILD_SHARED_LIBS=${{matrix.shared}} -B build
|
||||
|
||||
@@ -19,7 +19,7 @@ jobs:
|
||||
- {gen: Visual Studio 17 2022, arch: x64, shared: OFF}
|
||||
steps:
|
||||
- name: checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v3
|
||||
- name: Configure
|
||||
run: |
|
||||
cmake -G "${{matrix.gen}}" -A ${{matrix.arch}} -DSIMDJSON_DEVELOPER_MODE=ON -DSIMDJSON_COMPETITION=OFF -DBUILD_SHARED_LIBS=${{matrix.shared}} -B build
|
||||
|
||||
@@ -16,7 +16,7 @@ jobs:
|
||||
- {gen: Visual Studio 17 2022, arch: x64}
|
||||
steps:
|
||||
- name: checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v3
|
||||
- name: Configure
|
||||
run: |
|
||||
cmake -G "${{matrix.gen}}" -A ${{matrix.arch}} -T ClangCL -DSIMDJSON_DEVELOPER_MODE=ON -DSIMDJSON_COMPETITION=OFF -B build
|
||||
|
||||
@@ -7,7 +7,7 @@ jobs:
|
||||
name: windows-vs17
|
||||
runs-on: windows-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/cache@v3
|
||||
with:
|
||||
path: dependencies/.cache
|
||||
|
||||
Vendored
+1
-6
@@ -98,11 +98,6 @@
|
||||
"queue": "cpp",
|
||||
"shared_mutex": "cpp",
|
||||
"ranges": "cpp",
|
||||
"span": "cpp",
|
||||
"__verbose_abort": "cpp",
|
||||
"charconv": "cpp",
|
||||
"source_location": "cpp",
|
||||
"strstream": "cpp",
|
||||
"typeindex": "cpp"
|
||||
"span": "cpp"
|
||||
}
|
||||
}
|
||||
+5
-32
@@ -3,7 +3,7 @@ cmake_minimum_required(VERSION 3.14)
|
||||
project(
|
||||
simdjson
|
||||
# The version number is modified by tools/release.py
|
||||
VERSION 3.7.0
|
||||
VERSION 3.2.1
|
||||
DESCRIPTION "Parsing gigabytes of JSON per second"
|
||||
HOMEPAGE_URL "https://simdjson.org/"
|
||||
LANGUAGES CXX C
|
||||
@@ -20,10 +20,8 @@ string(
|
||||
# ---- Options, variables ----
|
||||
|
||||
# These version numbers are modified by tools/release.py
|
||||
set(SIMDJSON_LIB_VERSION "20.0.0" CACHE STRING "simdjson library version")
|
||||
set(SIMDJSON_LIB_SOVERSION "20" CACHE STRING "simdjson library soversion")
|
||||
|
||||
option(SIMDJSON_BUILD_STATIC_LIB "Build simdjson_static library along with simdjson" OFF)
|
||||
set(SIMDJSON_LIB_VERSION "16.0.0" CACHE STRING "simdjson library version")
|
||||
set(SIMDJSON_LIB_SOVERSION "16" CACHE STRING "simdjson library soversion")
|
||||
|
||||
option(SIMDJSON_ENABLE_THREADS "Link with thread support" ON)
|
||||
|
||||
@@ -58,17 +56,8 @@ include(cmake/developer-options.cmake)
|
||||
|
||||
# ---- simdjson library ----
|
||||
|
||||
set(SIMDJSON_SOURCES src/simdjson.cpp)
|
||||
|
||||
add_library(simdjson ${SIMDJSON_SOURCES})
|
||||
add_library(simdjson src/simdjson.cpp)
|
||||
add_library(simdjson::simdjson ALIAS simdjson)
|
||||
set(SIMDJSON_LIBRARIES simdjson)
|
||||
|
||||
if(SIMDJSON_BUILD_STATIC_LIB)
|
||||
add_library(simdjson_static STATIC ${SIMDJSON_SOURCES})
|
||||
add_library(simdjson::simdjson_static ALIAS simdjson_static)
|
||||
list(APPEND SIMDJSON_LIBRARIES simdjson_static)
|
||||
endif()
|
||||
|
||||
set_target_properties(
|
||||
simdjson PROPERTIES
|
||||
@@ -128,9 +117,6 @@ if(SIMDJSON_ENABLE_THREADS)
|
||||
endif()
|
||||
|
||||
simdjson_apply_props(simdjson)
|
||||
if(SIMDJSON_BUILD_STATIC_LIB)
|
||||
simdjson_apply_props(simdjson_static)
|
||||
endif()
|
||||
|
||||
# ---- Install rules ----
|
||||
|
||||
@@ -152,6 +138,7 @@ install(
|
||||
ARCHIVE COMPONENT simdjson_Development
|
||||
INCLUDES DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}"
|
||||
)
|
||||
|
||||
configure_file(cmake/simdjson-config.cmake.in simdjson-config.cmake @ONLY)
|
||||
|
||||
write_basic_package_version_file(
|
||||
@@ -180,20 +167,6 @@ install(
|
||||
COMPONENT simdjson_Development
|
||||
)
|
||||
|
||||
if(SIMDJSON_BUILD_STATIC_LIB)
|
||||
install(
|
||||
TARGETS simdjson_static
|
||||
EXPORT simdjson_staticTargets
|
||||
ARCHIVE COMPONENT simdjson_Development
|
||||
)
|
||||
install(
|
||||
EXPORT simdjson_staticTargets
|
||||
NAMESPACE simdjson::
|
||||
DESTINATION "${SIMDJSON_INSTALL_CMAKEDIR}"
|
||||
COMPONENT simdjson_Development
|
||||
)
|
||||
endif()
|
||||
|
||||
# pkg-config
|
||||
include(cmake/JoinPaths.cmake)
|
||||
join_paths(PKGCONFIG_INCLUDEDIR "\${prefix}" "${CMAKE_INSTALL_INCLUDEDIR}")
|
||||
|
||||
+1
-2
@@ -52,11 +52,10 @@ General Guidelines
|
||||
Contributors are encouraged to :
|
||||
|
||||
- Document their changes. Though we do not enforce a rule regarding code comments, we prefer that non-trivial algorithms and techniques be somewhat documented in the code.
|
||||
- Follow as much as possible the existing code style. We do not enforce a specific code style, but we prefer consistency. We avoid contractions (isn't, aren't) in the comments.
|
||||
- Follow as much as possible the existing code style. We do not enforce a specific code style, but we prefer consistency.
|
||||
- Modify as few lines of code as possible when working on an issue. The more lines you modify, the harder it is for your fellow human beings to understand what is going on.
|
||||
- Tools may report "problems" with the code, but we never delegate programming to tools: if there is a problem with the code, we need to understand it. Thus we will not "fix" code merely to please a static analyzer.
|
||||
- Provide tests for any new feature. We will not merge a new feature without tests.
|
||||
- Run before/after benchmarks so that we can appreciate the effect of the changes on the performance.
|
||||
|
||||
Pull Requests
|
||||
--------------
|
||||
|
||||
@@ -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 = "3.7.0"
|
||||
PROJECT_NUMBER = "3.2.1"
|
||||
|
||||
# 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
|
||||
|
||||
+3
-3
@@ -80,7 +80,7 @@ simdjson's source structure, from the top level, looks like this:
|
||||
* simdjson/internal/*.h: the `simdjson::internal` namespace. Private classes and functions used by the rest of simdjson.
|
||||
* simdjson/dom.h: the `simdjson::dom` namespace. Includes all public DOM classes.
|
||||
* simdjson/dom/*.h: Declarations/definitions for individual DOM classes.
|
||||
* simdjson/arm64|fallback|haswell|icelake|ppc64|westmere.h: `simdjson::<implementation>` namespace. Common implementation-specific tools like number and string parsing, as well as minification.
|
||||
* simdjson/arm64|fallback|haswell|icelake|ppc64|westmere.h: `simdjson::<implementation>` namesapce. Common implementation-specific tools like number and string parsing, as well as minification.
|
||||
* simdjson/arm64|fallback|haswell|icelake|ppc64|westmere/*.h: implementation-specific functions such as , etc.
|
||||
* simdjson/generic/*.h: the bulk of the actual code, written generically and compiled for each implementation, using functions defined in the implementation's .h files.
|
||||
* simdjson/generic/dependencies.h: dependencies on common, non-implementation-specific simdjson classes. This will be included before including amalgamated.h.
|
||||
@@ -304,7 +304,7 @@ Though having Visual Studio installed is necessary, one can build simdjson using
|
||||
- `mkdir build`
|
||||
- `cd build`
|
||||
- `cmake ..`
|
||||
- `cmake --build . --config Release`
|
||||
- `cmake --build . -config Release`
|
||||
|
||||
|
||||
Furthermore, if you have installed LLVM clang on Windows, for example as a component of Visual Studio 2019, you can configure and build simdjson using LLVM clang on Windows using cmake:
|
||||
@@ -313,7 +313,7 @@ Furthermore, if you have installed LLVM clang on Windows, for example as a compo
|
||||
- `mkdir build`
|
||||
- `cd build`
|
||||
- `cmake -T ClangCL ..`
|
||||
- `cmake --build . --config Release`
|
||||
- `cmake --build . -config Release`
|
||||
|
||||
|
||||
## Various References
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
|
||||
[/badge.svg)](https://simdjson.org/plots.html)
|
||||

|
||||
[](https://bugs.chromium.org/p/oss-fuzz/issues/list?sort=-opened&can=1&q=proj:simdjson)
|
||||

|
||||
[![][license img]][license]
|
||||
|
||||
[](https://simdjson.github.io/simdjson/)
|
||||
@@ -29,7 +31,6 @@ Table of Contents
|
||||
* [Real-world usage](#real-world-usage)
|
||||
* [Quick Start](#quick-start)
|
||||
* [Documentation](#documentation)
|
||||
* [Godbolt](#godbolt)
|
||||
* [Performance results](#performance-results)
|
||||
* [Bindings and Ports of simdjson](#bindings-and-ports-of-simdjson)
|
||||
* [About simdjson](#about-simdjson)
|
||||
@@ -41,10 +42,8 @@ Table of Contents
|
||||
Real-world usage
|
||||
----------------
|
||||
|
||||
- [Node.js](https://nodejs.org/)
|
||||
- [ClickHouse](https://github.com/ClickHouse/ClickHouse)
|
||||
- [Meta Velox](https://velox-lib.io)
|
||||
- [Google Pax](https://github.com/google/paxml)
|
||||
- [Facebook/Meta Velox](https://velox-lib.io)
|
||||
- [milvus](https://github.com/milvus-io/milvus)
|
||||
- [Clang Build Analyzer](https://github.com/aras-p/ClangBuildAnalyzer)
|
||||
- [Shopify HeapProfiler](https://github.com/Shopify/heap-profiler)
|
||||
@@ -69,9 +68,9 @@ The simdjson library is easily consumable with a single .h and .cpp file.
|
||||
|
||||
0. Prerequisites: `g++` (version 7 or better) or `clang++` (version 6 or better), and a 64-bit
|
||||
system with a command-line shell (e.g., Linux, macOS, freeBSD). We also support programming
|
||||
environments like Visual Studio and Xcode, but different steps are needed. Users of clang++ may need to specify the C++ version (e.g., `c++ -std=c++17`) since clang++ tends to default on C++98.
|
||||
environments like Visual Studio and Xcode, but different steps are needed.
|
||||
1. Pull [simdjson.h](singleheader/simdjson.h) and [simdjson.cpp](singleheader/simdjson.cpp) into a
|
||||
directory, along with the sample file [twitter.json](jsonexamples/twitter.json). You can download them with the `wget` utility:
|
||||
directory, along with the sample file [twitter.json](jsonexamples/twitter.json).
|
||||
|
||||
```
|
||||
wget https://raw.githubusercontent.com/simdjson/simdjson/master/singleheader/simdjson.h https://raw.githubusercontent.com/simdjson/simdjson/master/singleheader/simdjson.cpp https://raw.githubusercontent.com/simdjson/simdjson/master/jsonexamples/twitter.json
|
||||
@@ -96,7 +95,6 @@ int main(void) {
|
||||
100 results.
|
||||
```
|
||||
|
||||
|
||||
Documentation
|
||||
-------------
|
||||
|
||||
@@ -108,12 +106,11 @@ Usage documentation is available:
|
||||
how you can work with it.
|
||||
* [API](https://simdjson.github.io/simdjson/) contains the automatically generated API documentation.
|
||||
|
||||
Godbolt
|
||||
-------------
|
||||
|
||||
Some users may want to browse code along with the compiled assembly. You want to check out the following lists of examples:
|
||||
* [simdjson examples with errors handled through exceptions](https://godbolt.org/z/7G5qE4sr9)
|
||||
* [simdjson examples with errors without exceptions](https://godbolt.org/z/e9dWb9E4v)
|
||||
|
||||
* [simdjson examples with errors handled through exceptions](https://godbolt.org/z/98Kx9Kqjn)
|
||||
* [simdjson examples with errors without exceptions](https://godbolt.org/z/PKG7GdbPo)
|
||||
|
||||
Performance results
|
||||
-------------------
|
||||
@@ -168,7 +165,6 @@ We distinguish between "bindings" (which just wrap the C++ code) and a port to a
|
||||
- [simdjzon](https://github.com/travisstaloch/simdjzon): zig port.
|
||||
- [JSON-Simd](https://github.com/rawleyfowler/JSON-simd): Raku bindings.
|
||||
- [JSON::SIMD](https://metacpan.org/pod/JSON::SIMD): Perl bindings; fully-featured JSON module that uses simdjson for decoding.
|
||||
- [gemmaJSON](https://github.com/sainttttt/gemmaJSON): Nim JSON parser based on simdjson bindings.
|
||||
|
||||
About simdjson
|
||||
--------------
|
||||
@@ -177,11 +173,7 @@ The simdjson library takes advantage of modern microarchitectures, parallelizing
|
||||
instructions, reducing branch misprediction, and reducing data dependency to take advantage of each
|
||||
CPU's multiple execution cores.
|
||||
|
||||
Our default front-end is called On Demand, and we wrote a paper about it:
|
||||
|
||||
- John Keiser, Daniel Lemire, [On-Demand JSON: A Better Way to Parse Documents?](http://arxiv.org/abs/2312.17149), Software: Practice and Experience (to appear)
|
||||
|
||||
Some people [enjoy reading the first (2019) simdjson paper](https://arxiv.org/abs/1902.08318): A description of the design
|
||||
Some people [enjoy reading our paper](https://arxiv.org/abs/1902.08318): A description of the design
|
||||
and implementation of simdjson is in our research article:
|
||||
- Geoff Langdale, Daniel Lemire, [Parsing Gigabytes of JSON per Second](https://arxiv.org/abs/1902.08318), VLDB Journal 28 (6), 2019.
|
||||
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
# Security Policy
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
Please use the following contact information for reporting a vulnerability:
|
||||
|
||||
- [Daniel Lemire](https://github.com/lemire) - daniel@lemire.me
|
||||
@@ -26,9 +26,6 @@ if (TARGET benchmark::benchmark)
|
||||
if(TARGET nlohmann_json)
|
||||
target_link_libraries(bench_ondemand PRIVATE nlohmann_json)
|
||||
endif()
|
||||
if(TARGET boostjson)
|
||||
target_link_libraries(bench_ondemand PRIVATE boostjson)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
#pragma once
|
||||
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
|
||||
#include "amazon_cellphones.h"
|
||||
|
||||
namespace amazon_cellphones {
|
||||
|
||||
using namespace simdjson;
|
||||
|
||||
template<bool threaded>
|
||||
struct simdjson_singlestage {
|
||||
using StringType = std::string;
|
||||
|
||||
singlestage::parser parser{};
|
||||
|
||||
bool run(simdjson::padded_string &json, std::map<StringType, brand> &result) {
|
||||
#ifdef SIMDJSON_THREADS_ENABLED
|
||||
parser.threaded = threaded;
|
||||
#endif
|
||||
singlestage::document_stream stream = parser.iterate_many(json);
|
||||
singlestage::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_singlestage<UNTHREADED>)->UseManualTime();
|
||||
#ifdef SIMDJSON_THREADS_ENABLED
|
||||
BENCHMARK_TEMPLATE(amazon_cellphones, simdjson_singlestage<THREADED>)->UseManualTime();
|
||||
#endif
|
||||
|
||||
} // namespace amazon_cellphones
|
||||
|
||||
#endif // SIMDJSON_EXCEPTIONS
|
||||
File diff suppressed because it is too large
Load Diff
@@ -473,6 +473,28 @@ static void twitter_count(State& state) {
|
||||
}
|
||||
BENCHMARK(twitter_count);
|
||||
|
||||
#ifndef SIMDJSON_DISABLE_DEPRECATED_API
|
||||
SIMDJSON_PUSH_DISABLE_WARNINGS
|
||||
SIMDJSON_DISABLE_DEPRECATED_WARNING
|
||||
static void iterator_twitter_count(State& state) {
|
||||
// Prints the number of results in twitter.json
|
||||
padded_string json = padded_string::load(TWITTER_JSON);
|
||||
ParsedJson pj = build_parsed_json(json);
|
||||
for (simdjson_unused auto _ : state) {
|
||||
ParsedJson::Iterator iter(pj);
|
||||
// uint64_t result_count = doc["search_metadata"]["count"];
|
||||
if (!iter.move_to_key("search_metadata")) { return; }
|
||||
if (!iter.move_to_key("count")) { return; }
|
||||
if (!iter.is_integer()) { return; }
|
||||
int64_t result_count = iter.get_integer();
|
||||
|
||||
if (result_count != 100) { return; }
|
||||
}
|
||||
}
|
||||
BENCHMARK(iterator_twitter_count);
|
||||
SIMDJSON_POP_DISABLE_WARNINGS
|
||||
#endif // SIMDJSON_DISABLE_DEPRECATED_API
|
||||
|
||||
static void twitter_default_profile(State& state) {
|
||||
// Count unique users with a default profile.
|
||||
dom::parser parser;
|
||||
@@ -556,6 +578,54 @@ static void error_code_twitter_default_profile(State& state) noexcept {
|
||||
}
|
||||
BENCHMARK(error_code_twitter_default_profile);
|
||||
|
||||
#ifndef SIMDJSON_DISABLE_DEPRECATED_API
|
||||
|
||||
SIMDJSON_PUSH_DISABLE_WARNINGS
|
||||
SIMDJSON_DISABLE_DEPRECATED_WARNING
|
||||
|
||||
static void iterator_twitter_default_profile(State& state) {
|
||||
// Count unique users with a default profile.
|
||||
padded_string json;
|
||||
auto error = padded_string::load(TWITTER_JSON).get(json);
|
||||
if (error) { std::cerr << error << std::endl; return; }
|
||||
ParsedJson pj = build_parsed_json(json);
|
||||
for (simdjson_unused auto _ : state) {
|
||||
set<string_view> default_users;
|
||||
ParsedJson::Iterator iter(pj);
|
||||
|
||||
// for (dom::object tweet : doc["statuses"]) {
|
||||
if (!(iter.move_to_key("statuses") && iter.is_array())) { return; }
|
||||
if (iter.down()) { // first status
|
||||
do {
|
||||
|
||||
// dom::object user = tweet["user"];
|
||||
if (!(iter.move_to_key("user") && iter.is_object())) { return; }
|
||||
|
||||
// if (user["default_profile"]) {
|
||||
if (iter.move_to_key("default_profile")) {
|
||||
if (iter.is_true()) {
|
||||
if (!iter.up()) { return; } // back to user
|
||||
|
||||
// default_users.insert(user["screen_name"]);
|
||||
if (!(iter.move_to_key("screen_name") && iter.is_string())) { return; }
|
||||
default_users.emplace(iter.get_string(), iter.get_string_length());
|
||||
}
|
||||
if (!iter.up()) { return; } // back to user
|
||||
}
|
||||
|
||||
if (!iter.up()) { return; } // back to status
|
||||
|
||||
} while (iter.next()); // next status
|
||||
}
|
||||
|
||||
if (default_users.size() != 86) { return; }
|
||||
}
|
||||
}
|
||||
|
||||
SIMDJSON_POP_DISABLE_WARNINGS
|
||||
BENCHMARK(iterator_twitter_default_profile);
|
||||
#endif // SIMDJSON_DISABLE_DEPRECATED_API
|
||||
|
||||
static void error_code_twitter_image_sizes(State& state) noexcept {
|
||||
// Count unique image sizes
|
||||
dom::parser parser;
|
||||
@@ -610,4 +680,92 @@ static void parse_surrogate_pairs(State& state) {
|
||||
}
|
||||
BENCHMARK(parse_surrogate_pairs);
|
||||
|
||||
|
||||
#ifndef SIMDJSON_DISABLE_DEPRECATED_API
|
||||
|
||||
SIMDJSON_PUSH_DISABLE_WARNINGS
|
||||
SIMDJSON_DISABLE_DEPRECATED_WARNING
|
||||
static void iterator_twitter_image_sizes(State& state) {
|
||||
// Count unique image sizes
|
||||
padded_string json;
|
||||
auto error = padded_string::load(TWITTER_JSON).get(json);
|
||||
if (error) { std::cerr << error << std::endl; return; }
|
||||
ParsedJson pj = build_parsed_json(json);
|
||||
for (simdjson_unused auto _ : state) {
|
||||
set<tuple<uint64_t, uint64_t>> image_sizes;
|
||||
ParsedJson::Iterator iter(pj);
|
||||
|
||||
// for (dom::object tweet : doc["statuses"]) {
|
||||
if (!(iter.move_to_key("statuses") && iter.is_array())) { return; }
|
||||
if (iter.down()) { // first status
|
||||
do {
|
||||
|
||||
// dom::object media;
|
||||
// not_found = tweet["entities"]["media"].get(media);
|
||||
// if (!not_found) {
|
||||
if (iter.move_to_key("entities")) {
|
||||
if (!iter.is_object()) { return; }
|
||||
if (iter.move_to_key("media")) {
|
||||
if (!iter.is_array()) { return; }
|
||||
|
||||
// for (dom::object image : media) {
|
||||
if (iter.down()) { // first media
|
||||
do {
|
||||
|
||||
// for (auto [key, size] : dom::object(image["sizes"])) {
|
||||
if (!(iter.move_to_key("sizes") && iter.is_object())) { return; }
|
||||
if (iter.down()) { // first size
|
||||
do {
|
||||
iter.move_to_value();
|
||||
|
||||
// image_sizes.insert({ size["w"], size["h"] });
|
||||
if (!(iter.move_to_key("w")) && !iter.is_integer()) { return; }
|
||||
uint64_t width = iter.get_integer();
|
||||
if (!iter.up()) { return; } // back to size
|
||||
if (!(iter.move_to_key("h")) && !iter.is_integer()) { return; }
|
||||
uint64_t height = iter.get_integer();
|
||||
if (!iter.up()) { return; } // back to size
|
||||
image_sizes.emplace(width, height);
|
||||
|
||||
} while (iter.next()); // next size
|
||||
if (!iter.up()) { return; } // back to sizes
|
||||
}
|
||||
if (!iter.up()) { return; } // back to image
|
||||
} while (iter.next()); // next image
|
||||
if (!iter.up()) { return; } // back to media
|
||||
}
|
||||
if (!iter.up()) { return; } // back to entities
|
||||
}
|
||||
if (!iter.up()) { return; } // back to status
|
||||
}
|
||||
} while (iter.next()); // next status
|
||||
}
|
||||
|
||||
if (image_sizes.size() != 15) { return; };
|
||||
}
|
||||
}
|
||||
BENCHMARK(iterator_twitter_image_sizes);
|
||||
|
||||
#endif // SIMDJSON_DISABLE_DEPRECATED_API
|
||||
|
||||
#ifndef SIMDJSON_DISABLE_DEPRECATED_API
|
||||
static void print_json(State& state) noexcept {
|
||||
// Prints the number of results in twitter.json
|
||||
dom::parser parser;
|
||||
|
||||
padded_string json;
|
||||
auto error = padded_string::load(TWITTER_JSON).get(json);
|
||||
if (error) { std::cerr << error << std::endl; return; }
|
||||
|
||||
int code = json_parse(json, parser);
|
||||
if (code) { cerr << error_message(code) << endl; return; }
|
||||
for (simdjson_unused auto _ : state) {
|
||||
std::stringstream s;
|
||||
if (!parser.print_json(s)) { cerr << "print_json failed" << endl; return; }
|
||||
}
|
||||
}
|
||||
BENCHMARK(print_json);
|
||||
#endif // SIMDJSON_DISABLE_DEPRECATED_API
|
||||
SIMDJSON_POP_DISABLE_WARNINGS
|
||||
|
||||
BENCHMARK_MAIN();
|
||||
|
||||
@@ -21,15 +21,12 @@ SIMDJSON_PUSH_DISABLE_ALL_WARNINGS
|
||||
#include <nlohmann/json.hpp>
|
||||
#endif
|
||||
|
||||
#ifdef SIMDJSON_COMPETITION_BOOSTJSON
|
||||
#include <boost/json.hpp>
|
||||
#endif
|
||||
|
||||
// This has to be last, for reasons I don't yet understand
|
||||
#include <benchmark/benchmark.h>
|
||||
|
||||
SIMDJSON_POP_DISABLE_WARNINGS
|
||||
#include "json2msgpack/simdjson_ondemand.h"
|
||||
#include "json2msgpack/simdjson_singlestage.h"
|
||||
#include "json2msgpack/simdjson_dom.h"
|
||||
#include "json2msgpack/yyjson.h"
|
||||
#include "json2msgpack/rapidjson.h"
|
||||
@@ -37,9 +34,9 @@ SIMDJSON_POP_DISABLE_WARNINGS
|
||||
#include "json2msgpack/sajson.h"
|
||||
#endif // SIMDJSON_COMPETITION_ONDEMAND_SAJSON
|
||||
#include "json2msgpack/nlohmann_json.h"
|
||||
#include "json2msgpack/boostjson.h"
|
||||
|
||||
#include "partial_tweets/simdjson_ondemand.h"
|
||||
#include "partial_tweets/simdjson_singlestage.h"
|
||||
#include "partial_tweets/simdjson_dom.h"
|
||||
#include "partial_tweets/yyjson.h"
|
||||
#if SIMDJSON_COMPETITION_ONDEMAND_SAJSON
|
||||
@@ -53,11 +50,12 @@ SIMDJSON_POP_DISABLE_WARNINGS
|
||||
#if SIMDJSON_COMPETITION_SAX
|
||||
#include "partial_tweets/nlohmann_json_sax.h"
|
||||
#endif // SIMDJSON_COMPETITION_SAX
|
||||
#include "partial_tweets/boostjson.h"
|
||||
|
||||
|
||||
#include "distinct_user_id/simdjson_ondemand.h"
|
||||
#include "distinct_user_id/simdjson_ondemand_json_pointer.h"
|
||||
#include "distinct_user_id/simdjson_singlestage.h"
|
||||
#include "distinct_user_id/simdjson_singlestage_json_pointer.h"
|
||||
#include "distinct_user_id/simdjson_dom.h"
|
||||
#include "distinct_user_id/simdjson_dom_json_pointer.h"
|
||||
#include "distinct_user_id/yyjson.h"
|
||||
@@ -72,9 +70,9 @@ SIMDJSON_POP_DISABLE_WARNINGS
|
||||
#if SIMDJSON_COMPETITION_SAX
|
||||
#include "distinct_user_id/nlohmann_json_sax.h"
|
||||
#endif // SIMDJSON_COMPETITION_SAX
|
||||
#include "distinct_user_id/boostjson.h"
|
||||
|
||||
#include "find_tweet/simdjson_ondemand.h"
|
||||
#include "find_tweet/simdjson_singlestage.h"
|
||||
#include "find_tweet/simdjson_dom.h"
|
||||
#include "find_tweet/yyjson.h"
|
||||
#if SIMDJSON_COMPETITION_ONDEMAND_SAJSON
|
||||
@@ -88,9 +86,9 @@ SIMDJSON_POP_DISABLE_WARNINGS
|
||||
#if SIMDJSON_COMPETITION_SAX
|
||||
#include "find_tweet/nlohmann_json_sax.h"
|
||||
#endif // SIMDJSON_COMPETITION_SAX
|
||||
#include "find_tweet/boostjson.h"
|
||||
|
||||
#include "top_tweet/simdjson_ondemand.h"
|
||||
#include "top_tweet/simdjson_singlestage.h"
|
||||
#include "top_tweet/simdjson_dom.h"
|
||||
#include "top_tweet/yyjson.h"
|
||||
#if SIMDJSON_COMPETITION_ONDEMAND_SAJSON
|
||||
@@ -104,10 +102,10 @@ SIMDJSON_POP_DISABLE_WARNINGS
|
||||
#if SIMDJSON_COMPETITION_SAX
|
||||
#include "top_tweet/nlohmann_json_sax.h"
|
||||
#endif // SIMDJSON_COMPETITION_SAX
|
||||
#include "top_tweet/boostjson.h"
|
||||
|
||||
|
||||
#include "kostya/simdjson_ondemand.h"
|
||||
#include "kostya/simdjson_singlestage.h"
|
||||
#include "kostya/simdjson_dom.h"
|
||||
#include "kostya/yyjson.h"
|
||||
#if SIMDJSON_COMPETITION_ONDEMAND_SAJSON
|
||||
@@ -121,12 +119,15 @@ SIMDJSON_POP_DISABLE_WARNINGS
|
||||
#if SIMDJSON_COMPETITION_SAX
|
||||
#include "kostya/nlohmann_json_sax.h"
|
||||
#endif // SIMDJSON_COMPETITION_SAX
|
||||
#include "kostya/boostjson.h"
|
||||
|
||||
#include "large_random/simdjson_ondemand.h"
|
||||
#if SIMDJSON_COMPETITION_ONDEMAND_UNORDERED
|
||||
#include "large_random/simdjson_ondemand_unordered.h"
|
||||
#endif // SIMDJSON_COMPETITION_ONDEMAND_UNORDERED
|
||||
#include "large_random/simdjson_singlestage.h"
|
||||
#if SIMDJSON_COMPETITION_SINGLESTAGE_UNORDERED
|
||||
#include "large_random/simdjson_singlestage_unordered.h"
|
||||
#endif // SIMDJSON_COMPETITION_SINGLESTAGE_UNORDERED
|
||||
#include "large_random/simdjson_dom.h"
|
||||
#include "large_random/yyjson.h"
|
||||
#if SIMDJSON_COMPETITION_ONDEMAND_SAJSON
|
||||
@@ -140,12 +141,13 @@ SIMDJSON_POP_DISABLE_WARNINGS
|
||||
#if SIMDJSON_COMPETITION_SAX
|
||||
#include "large_random/nlohmann_json_sax.h"
|
||||
#endif // SIMDJSON_COMPETITION_SAX
|
||||
#include "large_random/boostjson.h"
|
||||
|
||||
#include "amazon_cellphones/simdjson_dom.h"
|
||||
#include "amazon_cellphones/simdjson_ondemand.h"
|
||||
#include "amazon_cellphones/simdjson_singlestage.h"
|
||||
|
||||
#include "large_amazon_cellphones/simdjson_dom.h"
|
||||
#include "large_amazon_cellphones/simdjson_ondemand.h"
|
||||
#include "large_amazon_cellphones/simdjson_singlestage.h"
|
||||
|
||||
BENCHMARK_MAIN();
|
||||
|
||||
@@ -169,6 +169,22 @@ BENCHMARK(parse_gsoc)->Repetitions(10)->ComputeStatistics("max", [](const std::v
|
||||
})->DisplayAggregatesOnly(true);
|
||||
|
||||
|
||||
|
||||
#ifndef SIMDJSON_DISABLE_DEPRECATED_API
|
||||
SIMDJSON_PUSH_DISABLE_WARNINGS
|
||||
SIMDJSON_DISABLE_DEPRECATED_WARNING
|
||||
static void json_parse(State& state) {
|
||||
ParsedJson pj;
|
||||
if (!pj.allocate_capacity(EMPTY_ARRAY.length())) { return; }
|
||||
for (simdjson_unused auto _ : state) {
|
||||
auto error = json_parse(EMPTY_ARRAY, pj);
|
||||
if (error) { return; }
|
||||
}
|
||||
}
|
||||
SIMDJSON_POP_DISABLE_WARNINGS
|
||||
BENCHMARK(json_parse);
|
||||
#endif // SIMDJSON_DISABLE_DEPRECATED_API
|
||||
|
||||
static void parser_parse_error_code(State& state) {
|
||||
dom::parser parser;
|
||||
if (parser.allocate(EMPTY_ARRAY.length())) { return; }
|
||||
@@ -197,6 +213,20 @@ BENCHMARK(parser_parse_exception);
|
||||
|
||||
#endif // SIMDJSON_EXCEPTIONS
|
||||
|
||||
#ifndef SIMDJSON_DISABLE_DEPRECATED_API
|
||||
SIMDJSON_PUSH_DISABLE_WARNINGS
|
||||
SIMDJSON_DISABLE_DEPRECATED_WARNING
|
||||
static void build_parsed_json(State& state) {
|
||||
for (simdjson_unused auto _ : state) {
|
||||
dom::parser parser = simdjson::build_parsed_json(EMPTY_ARRAY);
|
||||
if (!parser.valid) { return; }
|
||||
}
|
||||
}
|
||||
SIMDJSON_POP_DISABLE_WARNINGS
|
||||
|
||||
BENCHMARK(build_parsed_json);
|
||||
#endif
|
||||
|
||||
static void document_parse_error_code(State& state) {
|
||||
for (simdjson_unused auto _ : state) {
|
||||
dom::parser parser;
|
||||
|
||||
+9
-13
@@ -445,7 +445,7 @@ struct benchmarker {
|
||||
return 100.0 * a / b;
|
||||
}
|
||||
|
||||
void print(bool tabbed_output, bool stage1_only) const {
|
||||
void print(bool tabbed_output) const {
|
||||
if (tabbed_output) {
|
||||
char* filename_copy = reinterpret_cast<char*>(malloc(strlen(filename)+1));
|
||||
SIMDJSON_PUSH_DISABLE_WARNINGS
|
||||
@@ -503,21 +503,17 @@ struct benchmarker {
|
||||
stats->blocks_with_16_structurals_flipped, percent(stats->blocks_with_16_structurals_flipped, stats->blocks));
|
||||
}
|
||||
printf("\n");
|
||||
if(!stage1_only) {
|
||||
printf("All Stages (excluding allocation)\n");
|
||||
print_aggregate("| " , all_stages_without_allocation.best);
|
||||
// frequently, allocation is a tiny fraction of the running time so we omit it
|
||||
if(allocate_stage.best.elapsed_sec() > 0.01 * all_stages_without_allocation.best.elapsed_sec()) {
|
||||
printf("|- Allocation\n");
|
||||
print_aggregate("| ", allocate_stage.best);
|
||||
}
|
||||
printf("All Stages (excluding allocation)\n");
|
||||
print_aggregate("| " , all_stages_without_allocation.best);
|
||||
// frequently, allocation is a tiny fraction of the running time so we omit it
|
||||
if(allocate_stage.best.elapsed_sec() > 0.01 * all_stages_without_allocation.best.elapsed_sec()) {
|
||||
printf("|- Allocation\n");
|
||||
print_aggregate("| ", allocate_stage.best);
|
||||
}
|
||||
printf("|- Stage 1\n");
|
||||
print_aggregate("| ", stage1.best);
|
||||
if(!stage1_only) {
|
||||
printf("|- Stage 2\n");
|
||||
print_aggregate("| ", stage2.best);
|
||||
}
|
||||
printf("|- Stage 2\n");
|
||||
print_aggregate("| ", stage2.best);
|
||||
if (collector.has_events()) {
|
||||
double freq1 = (stage1.best.cycles() / stage1.best.elapsed_sec()) / 1000000000.0;
|
||||
double freq2 = (stage2.best.cycles() / stage2.best.elapsed_sec()) / 1000000000.0;
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef SIMDJSON_COMPETITION_BOOSTJSON
|
||||
|
||||
#include "distinct_user_id.h"
|
||||
|
||||
namespace distinct_user_id {
|
||||
|
||||
struct boostjson {
|
||||
bool run(simdjson::padded_string &json, std::vector<uint64_t> &result) {
|
||||
|
||||
auto root = boost::json::parse(json);
|
||||
for (const auto &tweet : root.at("statuses").as_array()) {
|
||||
result.push_back(tweet.at("user").at("id").to_number<uint64_t>());
|
||||
|
||||
if (tweet.as_object().if_contains("retweeted_status")) {
|
||||
result.push_back(tweet.at("retweeted_status").at("user").at("id").to_number<uint64_t>());
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
BENCHMARK_TEMPLATE(distinct_user_id, boostjson)->UseManualTime();
|
||||
|
||||
} // namespace distinct_user_id
|
||||
|
||||
#endif // SIMDJSON_COMPETITION_BOOSTJSON
|
||||
@@ -0,0 +1,37 @@
|
||||
#pragma once
|
||||
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
|
||||
#include "distinct_user_id.h"
|
||||
|
||||
namespace distinct_user_id {
|
||||
|
||||
using namespace simdjson;
|
||||
|
||||
struct simdjson_singlestage {
|
||||
singlestage::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 (singlestage::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.find_field("user").find_field("id"));
|
||||
// Not all tweets have a "retweeted_status", but when they do
|
||||
// we want to go and find the user within.
|
||||
auto retweet = tweet.find_field("retweeted_status");
|
||||
if (!retweet.error()) {
|
||||
result.push_back(retweet.find_field("user").find_field("id"));
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
BENCHMARK_TEMPLATE(distinct_user_id, simdjson_singlestage)->UseManualTime();
|
||||
|
||||
} // namespace distinct_user_id
|
||||
|
||||
#endif // SIMDJSON_EXCEPTIONS
|
||||
@@ -0,0 +1,37 @@
|
||||
#pragma once
|
||||
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
|
||||
#include "distinct_user_id.h"
|
||||
|
||||
namespace distinct_user_id {
|
||||
|
||||
using namespace simdjson;
|
||||
|
||||
struct simdjson_singlestage_json_pointer {
|
||||
singlestage::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 (singlestage::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_singlestage_json_pointer)->UseManualTime();
|
||||
|
||||
} // namespace distinct_user_id
|
||||
|
||||
#endif // SIMDJSON_EXCEPTIONS
|
||||
@@ -218,7 +218,7 @@ int main(int argc, char *argv[]) {
|
||||
if (!options.verbose) { progress.erase(); }
|
||||
|
||||
for (size_t i=0; i<options.files.size(); i++) {
|
||||
benchmarkers[i]->print(options.tabbed_output, options.stage1_only);
|
||||
benchmarkers[i]->print(options.tabbed_output);
|
||||
delete benchmarkers[i];
|
||||
}
|
||||
|
||||
|
||||
@@ -34,15 +34,11 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#ifdef __linux__
|
||||
#include "linux-perf-events.h"
|
||||
#ifdef __linux__
|
||||
#include <libgen.h>
|
||||
#endif
|
||||
|
||||
#if __APPLE__ && __aarch64__
|
||||
#include "apple/apple_arm_events.h"
|
||||
#endif
|
||||
|
||||
#include "simdjson.h"
|
||||
|
||||
using std::string;
|
||||
@@ -138,7 +134,7 @@ struct event_collector {
|
||||
|
||||
#if defined(__linux__)
|
||||
LinuxEvents<PERF_TYPE_HARDWARE> linux_events;
|
||||
event_collector() : linux_events(vector<int>{
|
||||
event_collector(simdjson_unused bool quiet = false) : linux_events(vector<int>{
|
||||
#if SIMDJSON_SIMPLE_PERFORMANCE_COUNTERS
|
||||
PERF_COUNT_HW_CPU_CYCLES,
|
||||
PERF_COUNT_HW_INSTRUCTIONS,
|
||||
@@ -153,17 +149,8 @@ struct event_collector {
|
||||
bool has_events() {
|
||||
return linux_events.is_working();
|
||||
}
|
||||
#elif __APPLE__ && __aarch64__
|
||||
AppleEvents apple_events;
|
||||
performance_counters diff;
|
||||
event_collector() : diff(0) {
|
||||
apple_events.setup_performance_counters();
|
||||
}
|
||||
bool has_events() {
|
||||
return apple_events.setup_performance_counters();
|
||||
}
|
||||
#else
|
||||
event_collector() {}
|
||||
event_collector(simdjson_unused bool _quiet = false) {}
|
||||
bool has_events() {
|
||||
return false;
|
||||
}
|
||||
@@ -172,8 +159,6 @@ struct event_collector {
|
||||
simdjson_inline void start() {
|
||||
#if defined(__linux)
|
||||
linux_events.start();
|
||||
#elif __APPLE__ && __aarch64__
|
||||
if(has_events()) { diff = apple_events.get_counters(); }
|
||||
#endif
|
||||
start_clock = steady_clock::now();
|
||||
}
|
||||
@@ -181,16 +166,6 @@ struct event_collector {
|
||||
time_point<steady_clock> end_clock = steady_clock::now();
|
||||
#if defined(__linux)
|
||||
linux_events.end(count.event_counts);
|
||||
#elif __APPLE__ && __aarch64__
|
||||
if(has_events()) {
|
||||
performance_counters end = apple_events.get_counters();
|
||||
diff = end - diff;
|
||||
}
|
||||
count.event_counts[0] = diff.cycles;
|
||||
count.event_counts[1] = diff.instructions;
|
||||
count.event_counts[2] = diff.missed_branches;
|
||||
count.event_counts[3] = 0;
|
||||
count.event_counts[4] = 0;
|
||||
#endif
|
||||
count.elapsed = end_clock - start_clock;
|
||||
return count;
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef SIMDJSON_COMPETITION_BOOSTJSON
|
||||
|
||||
#include "find_tweet.h"
|
||||
|
||||
namespace find_tweet {
|
||||
|
||||
struct boostjson {
|
||||
using StringType=std::string;
|
||||
|
||||
bool run(simdjson::padded_string &json, uint64_t find_id, std::string &result) {
|
||||
|
||||
auto root = boost::json::parse(json);
|
||||
for (const auto &tweet : root.at("statuses").as_array()) {
|
||||
if (tweet.at("id") == find_id) {
|
||||
result = tweet.at("text").as_string();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
BENCHMARK_TEMPLATE(find_tweet, boostjson)->UseManualTime();
|
||||
|
||||
} // namespace find_tweet
|
||||
|
||||
#endif // SIMDJSON_COMPETITION_BOOSTJSON
|
||||
@@ -0,0 +1,33 @@
|
||||
#pragma once
|
||||
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
|
||||
#include "find_tweet.h"
|
||||
|
||||
namespace find_tweet {
|
||||
|
||||
using namespace simdjson;
|
||||
|
||||
struct simdjson_singlestage {
|
||||
using StringType=std::string_view;
|
||||
|
||||
singlestage::parser parser{};
|
||||
|
||||
bool run(simdjson::padded_string &json, uint64_t find_id, std::string_view &result) {
|
||||
// Walk the document, parsing as we go
|
||||
auto doc = parser.iterate(json);
|
||||
for (auto tweet : doc.find_field("statuses")) {
|
||||
if (uint64_t(tweet.find_field("id")) == find_id) {
|
||||
result = tweet.find_field("text");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
BENCHMARK_TEMPLATE(find_tweet, simdjson_singlestage)->UseManualTime();
|
||||
|
||||
} // namespace find_tweet
|
||||
|
||||
#endif // SIMDJSON_EXCEPTIONS
|
||||
@@ -1,104 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef SIMDJSON_COMPETITION_BOOSTJSON
|
||||
|
||||
#include "json2msgpack.h"
|
||||
|
||||
namespace json2msgpack {
|
||||
|
||||
struct boostjson2msgpack {
|
||||
inline std::string_view to_msgpack(const boost::json::value &root, uint8_t *buf) {
|
||||
buff = buf;
|
||||
recursive_processor(root);
|
||||
return std::string_view(reinterpret_cast<char *>(buf), size_t(buff - buf));
|
||||
}
|
||||
|
||||
private:
|
||||
uint8_t *buff{};
|
||||
|
||||
inline void write_double(const double d) noexcept {
|
||||
*buff++ = 0xcb;
|
||||
::memcpy(buff, &d, sizeof(d));
|
||||
buff += sizeof(d);
|
||||
}
|
||||
|
||||
inline void write_byte(const uint8_t b) noexcept {
|
||||
*buff = b;
|
||||
buff++;
|
||||
}
|
||||
|
||||
inline void write_uint32(const uint32_t w) noexcept {
|
||||
::memcpy(buff, &w, sizeof(w));
|
||||
buff += sizeof(w);
|
||||
}
|
||||
|
||||
inline void write_string(const std::string & str) {
|
||||
write_byte(0xdb);
|
||||
write_uint32(uint32_t(str.size()));
|
||||
::memcpy(buff, str.data(), str.size());
|
||||
buff += str.size();
|
||||
}
|
||||
|
||||
inline void recursive_processor(const boost::json::value &element) {
|
||||
switch(element.kind()) {
|
||||
case boost::json::kind::array: {
|
||||
write_byte(0xdd);
|
||||
const auto &array = element.as_array();
|
||||
write_uint32(static_cast<uint32_t>(array.size()));
|
||||
for (const auto &child : array) {
|
||||
recursive_processor(child);
|
||||
}
|
||||
} break;
|
||||
|
||||
case boost::json::kind::object: {
|
||||
write_byte(0xdf);
|
||||
const auto &object = element.as_object();
|
||||
write_uint32(static_cast<uint32_t>(object.size()));
|
||||
for (const auto &child : object) {
|
||||
write_string(child.key_c_str());
|
||||
recursive_processor(child.value());
|
||||
}
|
||||
} break;
|
||||
|
||||
case boost::json::kind::int64:
|
||||
case boost::json::kind::uint64:
|
||||
case boost::json::kind::double_:
|
||||
write_double(element.to_number<double>());
|
||||
break;
|
||||
|
||||
case boost::json::kind::string:
|
||||
write_string(element.as_string().c_str());
|
||||
break;
|
||||
|
||||
case boost::json::kind::bool_:
|
||||
write_byte(0xc2 + element.as_bool());
|
||||
break;
|
||||
|
||||
case boost::json::kind::null:
|
||||
write_byte(0xc0);
|
||||
break;
|
||||
|
||||
default:
|
||||
printf("unexpected\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct boostjson {
|
||||
using StringType=std::string;
|
||||
|
||||
boostjson2msgpack parser{};
|
||||
|
||||
bool run(simdjson::padded_string &json, char *buffer, std::string_view &result) {
|
||||
auto root = boost::json::parse(json);
|
||||
result = parser.to_msgpack(root, reinterpret_cast<uint8_t *>(buffer));
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
BENCHMARK_TEMPLATE(json2msgpack, boostjson)->UseManualTime();
|
||||
|
||||
} // namespace json2msgpack
|
||||
|
||||
#endif // SIMDJSON_COMPETITION_BOOSTJSON
|
||||
@@ -8,7 +8,7 @@ namespace json2msgpack {
|
||||
using namespace simdjson;
|
||||
|
||||
/**
|
||||
* @brief The simdjson2msgpack struct is used to quickly convert
|
||||
* @brief The simdjsonondemand2msgpack struct is used to quickly convert
|
||||
* JSON strings to msgpack views. You must provide a pointer to
|
||||
* a large memory region where the msgpack gets written. The
|
||||
* buffer should be large enough to store the msgpack output (which
|
||||
@@ -17,7 +17,7 @@ using namespace simdjson;
|
||||
*
|
||||
* Recommended usage:
|
||||
*
|
||||
* simdjson2msgpack parser{};
|
||||
* simdjsonondemand2msgpack parser{};
|
||||
* simdjson::padded_string json = "[1,2]"_padded; // some JSON
|
||||
* uint8_t * buffer = new uint8_t[3*json.size() + simdjson::SIMDJSON_PADDING]; // large buffer
|
||||
*
|
||||
@@ -26,10 +26,10 @@ using namespace simdjson;
|
||||
* The result (msgpack) is a string view to a msgpack serialization of the input JSON,
|
||||
* it points inside the buffer you provided.
|
||||
*
|
||||
* You may reuse the simdjson2msgpack instance though you should use
|
||||
* You may reuse the simdjsonondemand2msgpack instance though you should use
|
||||
* one per thread.
|
||||
*/
|
||||
struct simdjson2msgpack {
|
||||
struct simdjsonondemand2msgpack {
|
||||
/**
|
||||
* @brief Converts the provided JSON into msgpack.
|
||||
*
|
||||
@@ -58,7 +58,7 @@ private:
|
||||
};
|
||||
|
||||
std::string_view
|
||||
simdjson2msgpack::to_msgpack(const simdjson::padded_string &json,
|
||||
simdjsonondemand2msgpack::to_msgpack(const simdjson::padded_string &json,
|
||||
uint8_t *buf) {
|
||||
buff = buf;
|
||||
ondemand::document doc = parser.iterate(json);
|
||||
@@ -106,33 +106,33 @@ simdjson2msgpack::to_msgpack(const simdjson::padded_string &json,
|
||||
return std::string_view(reinterpret_cast<char *>(buf), size_t(buff - buf));
|
||||
}
|
||||
|
||||
void simdjson2msgpack::write_double(const double d) noexcept {
|
||||
void simdjsonondemand2msgpack::write_double(const double d) noexcept {
|
||||
*buff++ = 0xcb;
|
||||
::memcpy(buff, &d, sizeof(d));
|
||||
buff += sizeof(d);
|
||||
}
|
||||
|
||||
void simdjson2msgpack::write_byte(const uint8_t b) noexcept {
|
||||
void simdjsonondemand2msgpack::write_byte(const uint8_t b) noexcept {
|
||||
*buff = b;
|
||||
buff++;
|
||||
}
|
||||
|
||||
void simdjson2msgpack::write_uint32(const uint32_t w) noexcept {
|
||||
void simdjsonondemand2msgpack::write_uint32(const uint32_t w) noexcept {
|
||||
::memcpy(buff, &w, sizeof(w));
|
||||
buff += sizeof(w);
|
||||
}
|
||||
|
||||
uint8_t *simdjson2msgpack::skip_uint32() noexcept {
|
||||
uint8_t *simdjsonondemand2msgpack::skip_uint32() noexcept {
|
||||
uint8_t *ret = buff;
|
||||
buff += sizeof(uint32_t);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void simdjson2msgpack::write_uint32_at(const uint32_t w, uint8_t *p) noexcept {
|
||||
void simdjsonondemand2msgpack::write_uint32_at(const uint32_t w, uint8_t *p) noexcept {
|
||||
::memcpy(p, &w, sizeof(w));
|
||||
}
|
||||
|
||||
void simdjson2msgpack::write_raw_string(
|
||||
void simdjsonondemand2msgpack::write_raw_string(
|
||||
simdjson::ondemand::raw_json_string in) {
|
||||
write_byte(0xdb);
|
||||
uint8_t *location = skip_uint32();
|
||||
@@ -140,7 +140,7 @@ void simdjson2msgpack::write_raw_string(
|
||||
write_uint32_at(uint32_t(v.size()), location);
|
||||
}
|
||||
|
||||
void simdjson2msgpack::recursive_processor(simdjson::ondemand::value element) {
|
||||
void simdjsonondemand2msgpack::recursive_processor(simdjson::ondemand::value element) {
|
||||
switch (element.type()) {
|
||||
case simdjson::ondemand::json_type::array: {
|
||||
uint32_t counter = 0;
|
||||
@@ -185,7 +185,7 @@ void simdjson2msgpack::recursive_processor(simdjson::ondemand::value element) {
|
||||
}
|
||||
|
||||
|
||||
void simdjson2msgpack::recursive_processor_ref(simdjson::ondemand::value& element) {
|
||||
void simdjsonondemand2msgpack::recursive_processor_ref(simdjson::ondemand::value& element) {
|
||||
switch (element.type()) {
|
||||
case simdjson::ondemand::json_type::array: {
|
||||
uint32_t counter = 0;
|
||||
@@ -234,7 +234,7 @@ void simdjson2msgpack::recursive_processor_ref(simdjson::ondemand::value& elemen
|
||||
struct simdjson_ondemand {
|
||||
using StringType = std::string_view;
|
||||
|
||||
simdjson2msgpack parser{};
|
||||
simdjsonondemand2msgpack parser{};
|
||||
|
||||
bool run(simdjson::padded_string &json, char *buffer,
|
||||
std::string_view &result) {
|
||||
|
||||
@@ -0,0 +1,250 @@
|
||||
#pragma once
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
|
||||
#include "json2msgpack.h"
|
||||
|
||||
namespace json2msgpack {
|
||||
|
||||
using namespace simdjson;
|
||||
|
||||
/**
|
||||
* @brief The simdjsonsinglestage2msgpack struct is used to quickly convert
|
||||
* JSON strings to msgpack views. You must provide a pointer to
|
||||
* a large memory region where the msgpack gets written. The
|
||||
* buffer should be large enough to store the msgpack output (which
|
||||
* can never be 3x larger than the input JSON) with an additional
|
||||
* simdjson::SIMDJSON_PADDING bytes.
|
||||
*
|
||||
* Recommended usage:
|
||||
*
|
||||
* simdjsonsinglestage2msgpack parser{};
|
||||
* simdjson::padded_string json = "[1,2]"_padded; // some JSON
|
||||
* uint8_t * buffer = new uint8_t[3*json.size() + simdjson::SIMDJSON_PADDING]; // large buffer
|
||||
*
|
||||
* std::string_view msgpack = parser.to_msgpack(json, buffer);
|
||||
*
|
||||
* The result (msgpack) is a string view to a msgpack serialization of the input JSON,
|
||||
* it points inside the buffer you provided.
|
||||
*
|
||||
* You may reuse the simdjsonsinglestage2msgpack instance though you should use
|
||||
* one per thread.
|
||||
*/
|
||||
struct simdjsonsinglestage2msgpack {
|
||||
/**
|
||||
* @brief Converts the provided JSON into msgpack.
|
||||
*
|
||||
* @param json JSON input
|
||||
* @param buf temporary buffer (must be large enough, with simdjson::SIMDJSON_PADDING bytes
|
||||
* of padding)
|
||||
* @return std::string_view msgpack output, writing to the temporary buffer
|
||||
*/
|
||||
inline std::string_view to_msgpack(const simdjson::padded_string &json,
|
||||
uint8_t *buf);
|
||||
|
||||
private:
|
||||
simdjson_inline void write_double(const double d) noexcept;
|
||||
simdjson_inline void write_byte(const uint8_t b) noexcept;
|
||||
simdjson_inline void write_uint32(const uint32_t w) noexcept;
|
||||
simdjson_inline uint8_t *skip_uint32() noexcept;
|
||||
simdjson_inline void write_uint32_at(const uint32_t w,
|
||||
uint8_t *p) noexcept;
|
||||
simdjson_inline void
|
||||
write_raw_string(simdjson::singlestage::raw_json_string rjs);
|
||||
inline void recursive_processor(simdjson::singlestage::value element);
|
||||
inline void recursive_processor_ref(simdjson::singlestage::value& element);
|
||||
|
||||
simdjson::singlestage::parser parser;
|
||||
uint8_t *buff{};
|
||||
};
|
||||
|
||||
std::string_view
|
||||
simdjsonsinglestage2msgpack::to_msgpack(const simdjson::padded_string &json,
|
||||
uint8_t *buf) {
|
||||
buff = buf;
|
||||
singlestage::document doc = parser.iterate(json);
|
||||
if (doc.is_scalar()) {
|
||||
// we have a special case where the JSON document is a single document...
|
||||
switch (doc.type()) {
|
||||
case simdjson::singlestage::json_type::number:
|
||||
write_double(doc.get_double());
|
||||
break;
|
||||
case simdjson::singlestage::json_type::string:
|
||||
write_raw_string(doc.get_raw_json_string());
|
||||
break;
|
||||
case simdjson::singlestage::json_type::boolean:
|
||||
write_byte(0xc2 + doc.get_bool());
|
||||
break;
|
||||
case simdjson::singlestage::json_type::null:
|
||||
// We check that the value is indeed null
|
||||
// otherwise: an error is thrown.
|
||||
if(doc.is_null()) {
|
||||
write_byte(0xc0);
|
||||
}
|
||||
break;
|
||||
case simdjson::singlestage::json_type::array:
|
||||
case simdjson::singlestage::json_type::object:
|
||||
default:
|
||||
// impossible
|
||||
SIMDJSON_UNREACHABLE();
|
||||
}
|
||||
} else {
|
||||
simdjson::singlestage::value val = doc;
|
||||
#define SIMDJSON_GCC_COMPILER ((__GNUC__) && !(__clang__) && !(__INTEL_COMPILER))
|
||||
#if SIMDJSON_GCC_COMPILER
|
||||
// the GCC compiler does well with by-value passing.
|
||||
// GCC has superior recursive inlining:
|
||||
// https://stackoverflow.com/questions/29186186/why-does-gcc-generate-a-faster-program-than-clang-in-this-recursive-fibonacci-co
|
||||
// https://godbolt.org/z/TeK4doE51
|
||||
recursive_processor(val);
|
||||
#else
|
||||
recursive_processor_ref(val);
|
||||
#endif
|
||||
}
|
||||
if (!doc.at_end()) {
|
||||
throw "There are unexpectedly tokens after the end of the json in the json2msgpack sample data";
|
||||
}
|
||||
return std::string_view(reinterpret_cast<char *>(buf), size_t(buff - buf));
|
||||
}
|
||||
|
||||
void simdjsonsinglestage2msgpack::write_double(const double d) noexcept {
|
||||
*buff++ = 0xcb;
|
||||
::memcpy(buff, &d, sizeof(d));
|
||||
buff += sizeof(d);
|
||||
}
|
||||
|
||||
void simdjsonsinglestage2msgpack::write_byte(const uint8_t b) noexcept {
|
||||
*buff = b;
|
||||
buff++;
|
||||
}
|
||||
|
||||
void simdjsonsinglestage2msgpack::write_uint32(const uint32_t w) noexcept {
|
||||
::memcpy(buff, &w, sizeof(w));
|
||||
buff += sizeof(w);
|
||||
}
|
||||
|
||||
uint8_t *simdjsonsinglestage2msgpack::skip_uint32() noexcept {
|
||||
uint8_t *ret = buff;
|
||||
buff += sizeof(uint32_t);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void simdjsonsinglestage2msgpack::write_uint32_at(const uint32_t w, uint8_t *p) noexcept {
|
||||
::memcpy(p, &w, sizeof(w));
|
||||
}
|
||||
|
||||
void simdjsonsinglestage2msgpack::write_raw_string(
|
||||
simdjson::singlestage::raw_json_string in) {
|
||||
write_byte(0xdb);
|
||||
uint8_t *location = skip_uint32();
|
||||
std::string_view v = parser.unescape(in, buff);
|
||||
write_uint32_at(uint32_t(v.size()), location);
|
||||
}
|
||||
|
||||
void simdjsonsinglestage2msgpack::recursive_processor(simdjson::singlestage::value element) {
|
||||
switch (element.type()) {
|
||||
case simdjson::singlestage::json_type::array: {
|
||||
uint32_t counter = 0;
|
||||
write_byte(0xdd);
|
||||
uint8_t *location = skip_uint32();
|
||||
for (auto child : element.get_array()) {
|
||||
counter++;
|
||||
recursive_processor(child.value());
|
||||
}
|
||||
write_uint32_at(counter, location);
|
||||
} break;
|
||||
case simdjson::singlestage::json_type::object: {
|
||||
uint32_t counter = 0;
|
||||
write_byte(0xdf);
|
||||
uint8_t *location = skip_uint32();
|
||||
for (auto field : element.get_object()) {
|
||||
counter++;
|
||||
write_raw_string(field.key());
|
||||
recursive_processor(field.value());
|
||||
}
|
||||
write_uint32_at(counter, location);
|
||||
} break;
|
||||
case simdjson::singlestage::json_type::number:
|
||||
write_double(element.get_double());
|
||||
break;
|
||||
case simdjson::singlestage::json_type::string:
|
||||
write_raw_string(element.get_raw_json_string());
|
||||
break;
|
||||
case simdjson::singlestage::json_type::boolean:
|
||||
write_byte(0xc2 + element.get_bool());
|
||||
break;
|
||||
case simdjson::singlestage::json_type::null:
|
||||
// We check that the value is indeed null
|
||||
// otherwise: an error is thrown.
|
||||
if(element.is_null()) {
|
||||
write_byte(0xc0);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
SIMDJSON_UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void simdjsonsinglestage2msgpack::recursive_processor_ref(simdjson::singlestage::value& element) {
|
||||
switch (element.type()) {
|
||||
case simdjson::singlestage::json_type::array: {
|
||||
uint32_t counter = 0;
|
||||
write_byte(0xdd);
|
||||
uint8_t *location = skip_uint32();
|
||||
for (auto child : element.get_array()) {
|
||||
counter++;
|
||||
simdjson::singlestage::value v = child.value();
|
||||
recursive_processor_ref(v);
|
||||
}
|
||||
write_uint32_at(counter, location);
|
||||
} break;
|
||||
case simdjson::singlestage::json_type::object: {
|
||||
uint32_t counter = 0;
|
||||
write_byte(0xdf);
|
||||
uint8_t *location = skip_uint32();
|
||||
for (auto field : element.get_object()) {
|
||||
counter++;
|
||||
write_raw_string(field.key());
|
||||
simdjson::singlestage::value v = field.value();
|
||||
recursive_processor_ref(v);
|
||||
}
|
||||
write_uint32_at(counter, location);
|
||||
} break;
|
||||
case simdjson::singlestage::json_type::number:
|
||||
write_double(element.get_double());
|
||||
break;
|
||||
case simdjson::singlestage::json_type::string:
|
||||
write_raw_string(element.get_raw_json_string());
|
||||
break;
|
||||
case simdjson::singlestage::json_type::boolean:
|
||||
write_byte(0xc2 + element.get_bool());
|
||||
break;
|
||||
case simdjson::singlestage::json_type::null:
|
||||
// We check that the value is indeed null
|
||||
// otherwise: an error is thrown.
|
||||
if(element.is_null()) {
|
||||
write_byte(0xc0);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
SIMDJSON_UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
struct simdjson_singlestage {
|
||||
using StringType = std::string_view;
|
||||
|
||||
simdjsonsinglestage2msgpack parser{};
|
||||
|
||||
bool run(simdjson::padded_string &json, char *buffer,
|
||||
std::string_view &result) {
|
||||
result = parser.to_msgpack(json, reinterpret_cast<uint8_t *>(buffer));
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
BENCHMARK_TEMPLATE(json2msgpack, simdjson_singlestage)->UseManualTime();
|
||||
|
||||
} // namespace json2msgpack
|
||||
|
||||
#endif // SIMDJSON_EXCEPTIONS
|
||||
@@ -24,7 +24,7 @@ struct file_runner : public runner_base<I> {
|
||||
|
||||
simdjson_warn_unused bool before_run(benchmark::State &state) {
|
||||
if (!runner_base<I>::after_run(state)) { return false; };
|
||||
// Copy the original JSON in case we did *in situ* last time
|
||||
// Copy the original json in case we did *in situ* last time
|
||||
std::memcpy(json.data(), original_json.data(), original_json.size());
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -13,13 +13,15 @@ void maybe_display_implementation() {
|
||||
std::cout << "simdjson::dom implementation: " << simdjson::get_active_implementation()->name() << std::endl;
|
||||
std::cout << "simdjson::ondemand implementation (stage 1): " << simdjson::get_active_implementation()->name() << std::endl;
|
||||
std::cout << "simdjson::ondemand implementation (stage 2): " << simdjson::builtin_implementation()->name() << std::endl;
|
||||
std::cout << "simdjson::singlestage implementation (stage 1): " << simdjson::get_active_implementation()->name() << std::endl;
|
||||
std::cout << "simdjson::singlestage implementation (stage 2): " << simdjson::builtin_implementation()->name() << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename B, typename R> static void run_json_benchmark(benchmark::State &state) {
|
||||
maybe_display_implementation();
|
||||
|
||||
event_collector collector;
|
||||
event_collector collector(true);
|
||||
event_aggregate events;
|
||||
|
||||
// Warmup and equality check (make sure the data is right!)
|
||||
|
||||
@@ -13,7 +13,7 @@ struct string_runner : public runner_base<I> {
|
||||
|
||||
simdjson_warn_unused bool before_run(benchmark::State &state) {
|
||||
if (!runner_base<I>::after_run(state)) { return false; };
|
||||
// Copy the original JSON in case we did *in situ*
|
||||
// Copy the original json in case we did *in situ*
|
||||
std::memcpy(json.data(), original_json.data(), original_json.size());
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef SIMDJSON_COMPETITION_BOOSTJSON
|
||||
|
||||
#include "kostya.h"
|
||||
|
||||
namespace kostya {
|
||||
|
||||
struct boostjson {
|
||||
static constexpr diff_flags DiffFlags = diff_flags::IMPRECISE_FLOATS;
|
||||
|
||||
bool run(simdjson::padded_string &json, std::vector<point> &result) {
|
||||
auto root = boost::json::parse(json);
|
||||
for (const auto &point : root.at("coordinates").as_array()) {
|
||||
result.emplace_back(json_benchmark::point{
|
||||
point.at("x").to_number<double>(),
|
||||
point.at("y").to_number<double>(),
|
||||
point.at("z").to_number<double>()
|
||||
});
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
BENCHMARK_TEMPLATE(kostya, boostjson)->UseManualTime();
|
||||
|
||||
} // namespace kostya
|
||||
|
||||
#endif // SIMDJSON_COMPETITION_BOOSTJSON
|
||||
@@ -0,0 +1,29 @@
|
||||
#pragma once
|
||||
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
|
||||
#include "kostya.h"
|
||||
|
||||
namespace kostya {
|
||||
|
||||
using namespace simdjson;
|
||||
|
||||
struct simdjson_singlestage {
|
||||
static constexpr diff_flags DiffFlags = diff_flags::NONE;
|
||||
|
||||
singlestage::parser parser{};
|
||||
|
||||
bool run(simdjson::padded_string &json, std::vector<point> &result) {
|
||||
auto doc = parser.iterate(json);
|
||||
for (singlestage::object point : doc.find_field("coordinates")) {
|
||||
result.emplace_back(json_benchmark::point{point.find_field("x"), point.find_field("y"), point.find_field("z")});
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
BENCHMARK_TEMPLATE(kostya, simdjson_singlestage)->UseManualTime();
|
||||
|
||||
} // namespace kostya
|
||||
|
||||
#endif // SIMDJSON_EXCEPTIONS
|
||||
@@ -0,0 +1,72 @@
|
||||
#pragma once
|
||||
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
|
||||
#include "large_amazon_cellphones.h"
|
||||
|
||||
namespace large_amazon_cellphones {
|
||||
|
||||
using namespace simdjson;
|
||||
|
||||
template<bool threaded>
|
||||
struct simdjson_singlestage {
|
||||
using StringType = std::string;
|
||||
|
||||
singlestage::parser parser{};
|
||||
|
||||
bool run(simdjson::padded_string &json, std::map<StringType, brand> &result) {
|
||||
#ifdef SIMDJSON_THREADS_ENABLED
|
||||
parser.threaded = threaded;
|
||||
#endif
|
||||
singlestage::document_stream stream = parser.iterate_many(json);
|
||||
singlestage::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_singlestage<UNTHREADED>)->UseManualTime();
|
||||
#ifdef SIMDJSON_THREADS_ENABLED
|
||||
BENCHMARK_TEMPLATE(large_amazon_cellphones, simdjson_singlestage<THREADED>)->UseManualTime();
|
||||
#endif
|
||||
|
||||
} // namespace amazon_cellphones
|
||||
|
||||
#endif // SIMDJSON_EXCEPTIONS
|
||||
@@ -1,29 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef SIMDJSON_COMPETITION_BOOSTJSON
|
||||
|
||||
#include "large_random.h"
|
||||
|
||||
namespace large_random {
|
||||
|
||||
struct boostjson {
|
||||
static constexpr diff_flags DiffFlags = diff_flags::IMPRECISE_FLOATS;
|
||||
|
||||
bool run(simdjson::padded_string &json, std::vector<point> &result) {
|
||||
auto root = boost::json::parse(json);
|
||||
for (const auto &point : root.as_array()) {
|
||||
result.emplace_back(json_benchmark::point{
|
||||
point.at("x").to_number<double>(),
|
||||
point.at("y").to_number<double>(),
|
||||
point.at("z").to_number<double>()
|
||||
});
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
BENCHMARK_TEMPLATE(large_random, boostjson)->UseManualTime();
|
||||
|
||||
} // namespace large_random
|
||||
|
||||
#endif // SIMDJSON_COMPETITION_BOOSTJSON
|
||||
@@ -0,0 +1,29 @@
|
||||
#pragma once
|
||||
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
|
||||
#include "large_random.h"
|
||||
|
||||
namespace large_random {
|
||||
|
||||
using namespace simdjson;
|
||||
|
||||
struct simdjson_singlestage {
|
||||
static constexpr diff_flags DiffFlags = diff_flags::NONE;
|
||||
|
||||
singlestage::parser parser{};
|
||||
|
||||
bool run(simdjson::padded_string &json, std::vector<point> &result) {
|
||||
auto doc = parser.iterate(json);
|
||||
for (singlestage::object coord : doc) {
|
||||
result.emplace_back(json_benchmark::point{coord.find_field("x"), coord.find_field("y"), coord.find_field("z")});
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
BENCHMARK_TEMPLATE(large_random, simdjson_singlestage)->UseManualTime();
|
||||
|
||||
} // namespace large_random
|
||||
|
||||
#endif // SIMDJSON_EXCEPTIONS
|
||||
@@ -0,0 +1,29 @@
|
||||
#pragma once
|
||||
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
|
||||
#include "large_random.h"
|
||||
|
||||
namespace large_random {
|
||||
|
||||
using namespace simdjson;
|
||||
|
||||
struct simdjson_singlestage_unordered {
|
||||
static constexpr diff_flags DiffFlags = diff_flags::NONE;
|
||||
|
||||
singlestage::parser parser{};
|
||||
|
||||
bool run(simdjson::padded_string &json, std::vector<point> &result) {
|
||||
auto doc = parser.iterate(json);
|
||||
for (singlestage::object coord : doc) {
|
||||
result.emplace_back(json_benchmark::point{coord["x"], coord["y"], coord["z"]});
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
BENCHMARK_TEMPLATE(large_random, simdjson_singlestage_unordered)->UseManualTime();
|
||||
|
||||
} // namespace large_random
|
||||
|
||||
#endif // SIMDJSON_EXCEPTIONS
|
||||
@@ -0,0 +1,37 @@
|
||||
#pragma once
|
||||
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
|
||||
#include "largerandom.h"
|
||||
|
||||
namespace largerandom {
|
||||
|
||||
using namespace simdjson;
|
||||
|
||||
class OnDemand {
|
||||
public:
|
||||
simdjson_inline bool Run(const padded_string &json);
|
||||
simdjson_inline const std::vector<my_point> &Result() { return container; }
|
||||
simdjson_inline size_t ItemCount() { return container.size(); }
|
||||
|
||||
private:
|
||||
singlestage::parser parser{};
|
||||
std::vector<my_point> container{};
|
||||
};
|
||||
|
||||
simdjson_inline bool OnDemand::Run(const padded_string &json) {
|
||||
container.clear();
|
||||
|
||||
auto doc = parser.iterate(json);
|
||||
for (singlestage::object coord : doc) {
|
||||
container.emplace_back(my_point{coord.find_field("x"), coord.find_field("y"), coord.find_field("z")});
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
BENCHMARK_TEMPLATE(LargeRandom, OnDemand);
|
||||
|
||||
} // namespace largerandom
|
||||
|
||||
#endif // SIMDJSON_EXCEPTIONS
|
||||
@@ -1,43 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef SIMDJSON_COMPETITION_BOOSTJSON
|
||||
|
||||
#include "partial_tweets.h"
|
||||
|
||||
namespace partial_tweets {
|
||||
|
||||
struct boostjson {
|
||||
using StringType=std::string;
|
||||
|
||||
bool run(simdjson::padded_string &json, std::vector<tweet<StringType>> &result) {
|
||||
|
||||
auto root = boost::json::parse(json);
|
||||
for (const auto &tweet : root.at("statuses").as_array()) {
|
||||
const auto &user = tweet.at("user");
|
||||
|
||||
auto in_reply_to_status_id = tweet.as_object().if_contains("in_reply_to_status_id")
|
||||
? tweet.at("in_reply_to_status_id") : boost::json::value();
|
||||
|
||||
result.emplace_back(partial_tweets::tweet<StringType>{
|
||||
tweet.at("created_at").as_string().c_str(),
|
||||
tweet.at("id").to_number<uint64_t>(),
|
||||
tweet.at("text").as_string().c_str(),
|
||||
in_reply_to_status_id.is_null() ? 0 : in_reply_to_status_id.to_number<uint64_t>(),
|
||||
{
|
||||
user.at("id").to_number<uint64_t>(),
|
||||
user.at("screen_name").as_string().c_str()
|
||||
},
|
||||
tweet.at("retweet_count").to_number<uint64_t>(),
|
||||
tweet.at("favorite_count").to_number<uint64_t>()
|
||||
});
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
BENCHMARK_TEMPLATE(partial_tweets, boostjson)->UseManualTime();
|
||||
|
||||
} // namespace partial_tweets
|
||||
|
||||
#endif // SIMDJSON_COMPETITION_BOOSTJSON
|
||||
@@ -0,0 +1,48 @@
|
||||
#pragma once
|
||||
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
|
||||
#include "partial_tweets.h"
|
||||
|
||||
namespace partial_tweets {
|
||||
|
||||
using namespace simdjson;
|
||||
|
||||
struct simdjson_singlestage {
|
||||
using StringType=std::string_view;
|
||||
|
||||
singlestage::parser parser{};
|
||||
|
||||
simdjson_inline uint64_t nullable_int(singlestage::value value) {
|
||||
if (value.is_null()) { return 0; }
|
||||
return value;
|
||||
}
|
||||
|
||||
simdjson_inline twitter_user<std::string_view> read_user(singlestage::object user) {
|
||||
return { user.find_field("id"), user.find_field("screen_name") };
|
||||
}
|
||||
|
||||
bool run(simdjson::padded_string &json, std::vector<tweet<std::string_view>> &result) {
|
||||
// Walk the document, parsing the tweets as we go
|
||||
auto doc = parser.iterate(json);
|
||||
for (singlestage::object tweet : doc.find_field("statuses")) {
|
||||
result.emplace_back(partial_tweets::tweet<std::string_view>{
|
||||
tweet.find_field("created_at"),
|
||||
tweet.find_field("id"),
|
||||
tweet.find_field("text"),
|
||||
nullable_int(tweet.find_field("in_reply_to_status_id")),
|
||||
read_user(tweet.find_field("user")),
|
||||
tweet.find_field("retweet_count"),
|
||||
tweet.find_field("favorite_count")
|
||||
});
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
BENCHMARK_TEMPLATE(partial_tweets, simdjson_singlestage)->UseManualTime();
|
||||
|
||||
} // namespace partial_tweets
|
||||
|
||||
#endif // SIMDJSON_EXCEPTIONS
|
||||
@@ -0,0 +1,63 @@
|
||||
#pragma once
|
||||
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
|
||||
#include "partial_tweets.h"
|
||||
|
||||
namespace partial_tweets {
|
||||
|
||||
using namespace simdjson;
|
||||
|
||||
|
||||
class SingleStage {
|
||||
public:
|
||||
SingleStage() {
|
||||
if(!displayed_implementation) {
|
||||
std::cout << "On Demand implementation: " << builtin_implementation()->name() << std::endl;
|
||||
displayed_implementation = true;
|
||||
}
|
||||
}
|
||||
simdjson_inline bool Run(const padded_string &json);
|
||||
simdjson_inline const std::vector<tweet> &Result() { return tweets; }
|
||||
simdjson_inline size_t ItemCount() { return tweets.size(); }
|
||||
|
||||
private:
|
||||
singlestage::parser parser{};
|
||||
std::vector<tweet> tweets{};
|
||||
|
||||
simdjson_inline uint64_t nullable_int(singlestage::value value) {
|
||||
if (value.is_null()) { return 0; }
|
||||
return value;
|
||||
}
|
||||
|
||||
simdjson_inline twitter_user read_user(singlestage::object user) {
|
||||
return { user.find_field("id"), user.find_field("screen_name") };
|
||||
}
|
||||
|
||||
static inline bool displayed_implementation = false;
|
||||
};
|
||||
|
||||
simdjson_inline bool SingleStage::Run(const padded_string &json) {
|
||||
tweets.clear();
|
||||
|
||||
// Walk the document, parsing the tweets as we go
|
||||
auto doc = parser.iterate(json);
|
||||
for (singlestage::object tweet : doc.find_field("statuses")) {
|
||||
tweets.emplace_back(partial_tweets::tweet{
|
||||
tweet.find_field("created_at"),
|
||||
tweet.find_field("id"),
|
||||
tweet.find_field("text"),
|
||||
nullable_int(tweet.find_field("in_reply_to_status_id")),
|
||||
read_user(tweet.find_field("user")),
|
||||
tweet.find_field("retweet_count"),
|
||||
tweet.find_field("favorite_count")
|
||||
});
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
BENCHMARK_TEMPLATE(PartialTweets, SingleStage);
|
||||
|
||||
} // namespace partial_tweets
|
||||
|
||||
#endif // SIMDJSON_EXCEPTIONS
|
||||
@@ -1,37 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#if SIMDJSON_COMPETITION_BOOSTJSON
|
||||
|
||||
#include "top_tweet.h"
|
||||
|
||||
namespace top_tweet {
|
||||
|
||||
using namespace simdjson;
|
||||
|
||||
struct boostjson {
|
||||
using StringType=std::string;
|
||||
|
||||
bool run(simdjson::padded_string &json, int64_t max_retweet_count, top_tweet_result<StringType> &result) {
|
||||
result.retweet_count = -1;
|
||||
boost::json::value top_tweet{};
|
||||
|
||||
auto root = boost::json::parse(json);
|
||||
for (const auto &tweet : root.at("statuses").as_array()) {
|
||||
int64_t retweet_count = tweet.at("retweet_count").as_int64();
|
||||
if (retweet_count <= max_retweet_count && retweet_count >= result.retweet_count) {
|
||||
result.retweet_count = retweet_count;
|
||||
top_tweet = tweet;
|
||||
}
|
||||
}
|
||||
|
||||
result.text = top_tweet.at("text").as_string();
|
||||
result.screen_name = top_tweet.at("user").at("screen_name").as_string();
|
||||
return result.retweet_count != -1;
|
||||
}
|
||||
};
|
||||
|
||||
BENCHMARK_TEMPLATE(top_tweet, boostjson)->UseManualTime();
|
||||
|
||||
} // namespace top_tweet
|
||||
|
||||
#endif // SIMDJSON_COMPETITION_BOOSTJSON
|
||||
@@ -0,0 +1,80 @@
|
||||
#pragma once
|
||||
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
|
||||
#include "top_tweet.h"
|
||||
|
||||
namespace top_tweet {
|
||||
|
||||
using namespace simdjson;
|
||||
|
||||
struct simdjson_singlestage {
|
||||
using StringType=std::string_view;
|
||||
|
||||
singlestage::parser parser{};
|
||||
|
||||
bool run(simdjson::padded_string &json, int64_t max_retweet_count, top_tweet_result<StringType> &result) {
|
||||
result.retweet_count = -1;
|
||||
// We save these DOM values for later so we don't have to parse them
|
||||
// into string_views until we're sure which ones we want to parse
|
||||
// NOTE: simdjson does not presently support reuse of objects or arrays--just scalars. This is
|
||||
// why we have to grab the text and screen_name fields instead of just saving the tweet object.
|
||||
singlestage::value screen_name, text;
|
||||
|
||||
auto doc = parser.iterate(json);
|
||||
for (auto tweet : doc["statuses"]) {
|
||||
// Since text, user.screen_name, and retweet_count generally appear in order, it's nearly free
|
||||
// for us to retrieve them here (and will cost a bit more if we do it in the if
|
||||
// statement).
|
||||
auto tweet_text = tweet["text"];
|
||||
auto tweet_screen_name = tweet["user"]["screen_name"];
|
||||
int64_t retweet_count = tweet["retweet_count"];
|
||||
if (retweet_count <= max_retweet_count && retweet_count >= result.retweet_count) {
|
||||
result.retweet_count = retweet_count;
|
||||
// TODO std::move should not be necessary
|
||||
text = std::move(tweet_text);
|
||||
screen_name = std::move(tweet_screen_name);
|
||||
}
|
||||
}
|
||||
|
||||
// Now that we know which was the most retweeted, parse the values in it
|
||||
result.screen_name = screen_name;
|
||||
result.text = text;
|
||||
return result.retweet_count != -1;
|
||||
}
|
||||
};
|
||||
|
||||
BENCHMARK_TEMPLATE(top_tweet, simdjson_singlestage)->UseManualTime();
|
||||
|
||||
struct simdjson_singlestage_forward_only {
|
||||
using StringType=std::string_view;
|
||||
|
||||
singlestage::parser parser{};
|
||||
|
||||
bool run(simdjson::padded_string &json, int64_t max_retweet_count, top_tweet_result<StringType> &result) {
|
||||
result.retweet_count = -1;
|
||||
|
||||
auto doc = parser.iterate(json);
|
||||
for (auto tweet : doc["statuses"]) {
|
||||
// Since text, user.screen_name, and retweet_count generally appear in order, it's nearly free
|
||||
// for us to retrieve them here (and will cost a bit more if we do it in the if
|
||||
// statement).
|
||||
auto tweet_text = tweet["text"];
|
||||
auto tweet_screen_name = tweet["user"]["screen_name"];
|
||||
int64_t retweet_count = tweet["retweet_count"];
|
||||
if (retweet_count <= max_retweet_count && retweet_count >= result.retweet_count) {
|
||||
result.retweet_count = retweet_count;
|
||||
result.text = tweet_text;
|
||||
result.screen_name = tweet_screen_name;
|
||||
}
|
||||
}
|
||||
|
||||
return result.retweet_count != -1;
|
||||
}
|
||||
};
|
||||
|
||||
BENCHMARK_TEMPLATE(top_tweet, simdjson_singlestage_forward_only)->UseManualTime();
|
||||
|
||||
} // namespace top_tweet
|
||||
|
||||
#endif // SIMDJSON_EXCEPTIONS
|
||||
@@ -114,14 +114,10 @@ set(SIMDJSON_CXX_STANDARD 17 CACHE STRING "the C++ standard to use for simdjson"
|
||||
set(CMAKE_CXX_STANDARD ${SIMDJSON_CXX_STANDARD})
|
||||
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)
|
||||
set(SIMDJSON_STRUCTURAL_INDEXER_STEP CACHE STRING "the SIMDJSON_STRUCTURAL_INDEXER_STEP variable")
|
||||
|
||||
if(SIMDJSON_STRUCTURAL_INDEXER_STEP)
|
||||
message(STATUS "Setting SIMDJSON_STRUCTURAL_INDEXER_STEP to ${SIMDJSON_STRUCTURAL_INDEXER_STEP}.")
|
||||
add_compile_definitions(SIMDJSON_STRUCTURAL_INDEXER_STEP=${SIMDJSON_STRUCTURAL_INDEXER_STEP})
|
||||
endif()
|
||||
# LTO seems to create all sorts of fun problems. Let us
|
||||
# disable temporarily.
|
||||
#include(CheckIPOSupported)
|
||||
|
||||
@@ -4,4 +4,3 @@ if("@SIMDJSON_ENABLE_THREADS@")
|
||||
endif()
|
||||
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/simdjsonTargets.cmake")
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/simdjson_staticTargets.cmake" OPTIONAL)
|
||||
|
||||
Vendored
+1
-5
@@ -104,11 +104,7 @@ int main() {}
|
||||
target_compile_definitions(rapidjson INTERFACE RAPIDJSON_HAS_STDSTRING)
|
||||
target_include_directories(rapidjson SYSTEM INTERFACE
|
||||
"${rapidjson_SOURCE_DIR}/include")
|
||||
if (CMAKE_COMPILER_IS_GNUCC AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 14)
|
||||
message(STATUS "Disabling rapidjson")
|
||||
else()
|
||||
target_compile_definitions(rapidjson INTERFACE SIMDJSON_COMPETITION_RAPIDJSON)
|
||||
endif()
|
||||
target_compile_definitions(rapidjson INTERFACE SIMDJSON_COMPETITION_RAPIDJSON)
|
||||
|
||||
import_dependency(sajson chadaustin/sajson 2dcfd35)
|
||||
add_library(sajson INTERFACE)
|
||||
|
||||
+55
-605
@@ -15,11 +15,9 @@ An overview of what you need to know to use simdjson, with examples.
|
||||
- [string_view](#string_view)
|
||||
- [Using the Parsed JSON](#using-the-parsed-json)
|
||||
- [Using the Parsed JSON: Additional examples](#using-the-parsed-json-additional-examples)
|
||||
- [Adding support for custom types](#adding-support-for-custom-types)
|
||||
- [Minifying JSON strings without parsing](#minifying-json-strings-without-parsing)
|
||||
- [UTF-8 validation (alone)](#utf-8-validation-alone)
|
||||
- [JSON Pointer](#json-pointer)
|
||||
- [JSONPath](#json-path)
|
||||
- [Error Handling](#error-handling)
|
||||
- [Error Handling Examples without Exceptions](#error-handling-examples-without-exceptions)
|
||||
- [Disabling Exceptions](#disabling-exceptions)
|
||||
@@ -30,15 +28,13 @@ An overview of what you need to know to use simdjson, with examples.
|
||||
- [Newline-Delimited JSON (ndjson) and JSON lines](#newline-delimited-json-ndjson-and-json-lines)
|
||||
- [Parsing Numbers Inside Strings](#parsing-numbers-inside-strings)
|
||||
- [Dynamic Number Types](#dynamic-number-types)
|
||||
- [Raw Strings From Keys](#raw-strings-from-keys)
|
||||
- [Raw Strings](#raw-strings)
|
||||
- [General Direct Access to the Raw JSON String](#general-direct-access-to-the-raw-json-string)
|
||||
- [Storing Directly into an Existing String Instance](#storing-directly-into-an-existing-string-instance)
|
||||
- [Thread Safety](#thread-safety)
|
||||
- [Standard Compliance](#standard-compliance)
|
||||
- [Backwards Compatibility](#backwards-compatibility)
|
||||
- [Examples](#examples)
|
||||
- [Performance Tips](#performance-tips)
|
||||
- [Further Reading](#further-reading)
|
||||
|
||||
|
||||
Requirements
|
||||
@@ -71,7 +67,7 @@ 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++11 myproject.cpp simdjson.cpp`).
|
||||
- The library relies on [runtime CPU detection](implementation-selection.md): avoid specifying an architecture at compile time (e.g., `-march-native`) if you want your binaries to run everywhere.
|
||||
- The library relies on [runtime CPU detection](implementation-selection.md): avoid specifying an architecture at compile time (e.g., `-march-native`).
|
||||
|
||||
Using simdjson with package managers
|
||||
------------------
|
||||
@@ -89,7 +85,7 @@ include(FetchContent)
|
||||
FetchContent_Declare(
|
||||
simdjson
|
||||
GIT_REPOSITORY https://github.com/simdjson/simdjson.git
|
||||
GIT_TAG tags/v3.6.0
|
||||
GIT_TAG tags/v0.9.6
|
||||
GIT_SHALLOW TRUE)
|
||||
|
||||
FetchContent_MakeAvailable(simdjson)
|
||||
@@ -183,8 +179,8 @@ strcpy(json, "[1]");
|
||||
ondemand::document doc = parser.iterate(json, strlen(json), sizeof(json));
|
||||
```
|
||||
|
||||
The simdjson library will also accept `std::string` instances. If the provided
|
||||
reference is non-const, it will allocate padding as needed.
|
||||
The simdjson library will also accept `std::string` instances, as long as the `capacity()` of
|
||||
the string exceeds the `size()` by at least `SIMDJSON_PADDING`. You can increase the `capacity()` with the `reserve()` function of your strings.
|
||||
|
||||
You can copy your data directly on a `simdjson::padded_string` as follows:
|
||||
|
||||
@@ -222,8 +218,7 @@ This means that while you iterate an array, or search for a field in an object,
|
||||
walking through the original JSON text, merrily reading commas and colons and brackets to make sure
|
||||
you get where you are going. This is the key to On Demand's performance: since it's just an iterator,
|
||||
it lets you parse values as you use them. And particularly, it lets you *skip* values you do not want
|
||||
to use. On Demand is also ideally suited when you want to capture part of the document without parsing it
|
||||
immediately (e.g., see [General Direct Access to the Raw JSON String](#general-direct-access-to-the-raw-json-string)).
|
||||
to use.
|
||||
|
||||
We refer to "On Demand" as a front-end component since it is an interface between the
|
||||
low-level parsing functions and the user. It hides much of the complexity of parsing JSON
|
||||
@@ -258,8 +253,7 @@ copy the data into their own favorite class instances (e.g., alternatives to `st
|
||||
|
||||
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 (see [General Direct Access to the Raw JSON String](#general-direct-access-to-the-raw-json-string)), or to a temporary string buffer inside
|
||||
our parser class instances that is valid until the parser object is destroyed or you use it to parse another document.
|
||||
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
|
||||
@@ -267,7 +261,6 @@ inside our parser instances: e.g., when we parse a new document. Thus a `std::st
|
||||
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).
|
||||
For convenience, we also allow [storing an escaped string directly into an existing string instance](#storing-directly-into-an-existing-string-instance).
|
||||
|
||||
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
|
||||
@@ -362,7 +355,7 @@ support for users who avoid exceptions. See [the simdjson error handling documen
|
||||
* **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. It may generate the error `simdjson::NO_SUCH_FIELD` if there is no such key in the object, it may throw an exception (see [Error Handling](#error-handling)). For efficiency reason, you should avoid looking up the same field repeatedly: e.g., do
|
||||
not do `object["foo"]` followed by `object["foo"]` with the same `object` instance. For best performance, you should try to query the keys in the same order they appear in the document. If you need several keys and you cannot predict the order they will appear in, it is recommended to iterate through all keys `for(auto field : object) {...}`. Keep in mind that On Demand does not buffer or save the result of the parsing: if you repeatedly access `object["foo"]`, then it must repeatedly seek the key and parse the content. The library does not provide a distinct function to check if a key is present, instead we recommend you attempt to access the key: e.g., by doing `ondemand::value val{}; if (!object["foo"].get(val)) {...}`, you have that `val` contains the requested value inside the if clause. It is your responsibility as a user to temporarily keep a reference to the value (`auto v = object["foo"]`), or to consume the content and store it in your own data structures. If you consume an
|
||||
not do `object["foo"]` followed by `object["foo"]` with the same `object` instance. Keep in mind that On Demand does not buffer or save the result of the parsing: if you repeatedly access `object["foo"]`, then it must repeatedly seek the key and parse the content. The library does not provide a distinct function to check if a key is present, instead we recommend you attempt to access the key: e.g., by doing `ondemand::value val{}; if(!object["foo"].get(val)) {...}`, you have that `val` contains the requested value inside the if clause. It is your responsibility as a user to temporarily keep a reference to the value (`auto v = object["foo"]`), or to consume the content and store it in your own data structures. If you consume an
|
||||
object twice: `std::string_view(object["foo"]` followed by `std::string_view(object["foo"]` then your code
|
||||
is in error. Furthermore, you can only consume one field at a time, on the same object. The
|
||||
value instance you get from `content["bids"]` becomes invalid when you call `content["asks"]`.
|
||||
@@ -377,11 +370,7 @@ support for users who avoid exceptions. See [the simdjson error handling documen
|
||||
> 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. The `unescaped_key` takes an optional Boolean value: passing it true will decode invalid
|
||||
> Unicode sequences with replacement, meaning that the decoding always succeeds but bogus Unicode
|
||||
> replacement characters are inserted. In general, you should expect a performance penalty
|
||||
> when using `unescaped_key()` compared to `key()` because of the string processing: the `key()`
|
||||
> function just points inside the source JSON document.
|
||||
> instance. You should expect a performance penalty when using `unescaped_key()`.
|
||||
>
|
||||
> ```c++
|
||||
> auto json = R"({"k\u0065y": 1})"_padded;
|
||||
@@ -392,7 +381,7 @@ support for users who avoid exceptions. See [the simdjson error handling documen
|
||||
> // 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()); }
|
||||
> if(keyv == "key") { std::cout << uint64_t(field.value()); }
|
||||
> }
|
||||
> ```
|
||||
>
|
||||
@@ -425,10 +414,8 @@ support for users who avoid exceptions. See [the simdjson error handling documen
|
||||
step through each value in the JSON array.
|
||||
|
||||
If you know the type of the value, you can cast it right there, too! `for (double value : array) { ... }`.
|
||||
|
||||
You may also use explicit iterators: `for(auto i = array.begin(); i != array.end(); i++) {}`. You can check that an array is empty with the condition `auto i = array.begin(); if (i == array.end()) {...}`.
|
||||
* **Object Iteration:** You can iterate through an object's fields, as well: `for (auto field : object) { ... }`. You may also use explicit iterators : `for(auto i = object.begin(); i != object.end(); i++) { auto field = *i; .... }`. You can check that an object is empty with the condition `auto i = object.begin(); if (i == object.end()) {...}`.
|
||||
- `field.unescaped_key()` will get you the unescaped key string. E.g., the JSON string `"\u00e1"` becomes the Unicode string `á`. Optionally, you pass `true` as a parameter to the `unescaped_key` method if you want invalid escape sequences to be replaced by a default replacement character (e.g., `\ud800\ud801\ud811`): otherwise bad escape sequences lead to an immediate error.
|
||||
* **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.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 by index. Instead,
|
||||
you should iterate through the array and keep an index yourself.
|
||||
@@ -458,7 +445,7 @@ support for users who avoid exceptions. See [the simdjson error handling documen
|
||||
> {
|
||||
> ondemand::parser parser;
|
||||
> for (ondemand::object car : parser.iterate(cars_json)) {
|
||||
> if (uint64_t(car["year"]) > 2000) {
|
||||
> if(uint64_t(car["year"]) > 2000) {
|
||||
> arrays.push_back(simdjson::to_json_string(car["tire_pressure"]));
|
||||
> }
|
||||
> }
|
||||
@@ -467,7 +454,7 @@ support for users who avoid exceptions. See [the simdjson error handling documen
|
||||
> std::ostringstream oss;
|
||||
> oss << "[";
|
||||
> for(size_t i = 0; i < arrays.size(); i++) {
|
||||
> if (i>0) { oss << ","; }
|
||||
> if(i>0) { oss << ","; }
|
||||
> oss << arrays[i];
|
||||
> }
|
||||
> oss << "]";
|
||||
@@ -548,7 +535,9 @@ support for users who avoid exceptions. See [the simdjson error handling documen
|
||||
* **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.
|
||||
You can also represent arbitrary JSON values with
|
||||
`ondemand::value` instances: it can represent anything except a scalar document (lone number, string, null or Boolean). You can check for scalar documents with the method `scalar()`. You can cast a document that is either an array or an object to an `ondemand::value` instance immediately after you create the document instance: you cannot create a `ondemand::value` instance from a document that has already been accessed as it would mean that you would have two instances of the object or array simultaneously (see [rewinding](#rewinding)). You can query the type of a document or a value with the `type()` method. The `type()` method does not consume or validate documents and values, but it tells you whether they are
|
||||
`ondemand::value` instances: it can represent anything except a scalar document (lone number, string, null or Boolean). You can check for scalar documents with the method `scalar()`.
|
||||
You can query the type of a document or a value with the `type()` method.
|
||||
The `type()` method does not consume or validate documents and values, but it tells you whether they are
|
||||
- arrays (`json_type::array`),
|
||||
- objects (`json_type::object`)
|
||||
- numbers (`json_type::number`),
|
||||
@@ -557,7 +546,7 @@ support for users who avoid exceptions. See [the simdjson error handling documen
|
||||
- null (`json_type::null`).
|
||||
|
||||
You must still validate and consume the values (e.g., call `is_null()`) after calling `type()`.
|
||||
You may also access [the raw JSON string](#general-direct-access-to-the-raw-json-string).
|
||||
You may also access [raw strings](#raw-strings).
|
||||
For example, the following is a quick and dirty recursive function that verbosely prints the JSON document as JSON. This example also illustrates lifecycle requirements: the `document` instance holds the iterator. The document must remain in scope while you are accessing instances of `value`, `object` and `array`.
|
||||
```c++
|
||||
void recursive_print_json(ondemand::value element) {
|
||||
@@ -608,7 +597,7 @@ support for users who avoid exceptions. See [the simdjson error handling documen
|
||||
case ondemand::json_type::null:
|
||||
// We check that the value is indeed null
|
||||
// otherwise: an error is thrown.
|
||||
if (element.is_null()) {
|
||||
if(element.is_null()) {
|
||||
cout << "null";
|
||||
}
|
||||
break;
|
||||
@@ -741,289 +730,6 @@ for (ondemand::object points : parser.iterate(points_json)) {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
Adding support for custom types
|
||||
----------------------
|
||||
|
||||
Suppose you have your own types, such as a `Car` struct:
|
||||
|
||||
```C++
|
||||
struct Car {
|
||||
std::string make;
|
||||
std::string model;
|
||||
int64_t year;
|
||||
std::vector<double> tire_pressure;
|
||||
};
|
||||
```
|
||||
|
||||
You might want to write code that automatically parses the JSON content to your custom
|
||||
type:
|
||||
|
||||
```C++
|
||||
padded_string json = R"( [ { "make": "Toyota", "model": "Camry", "year": 2018,
|
||||
"tire_pressure": [ 40.1, 39.9 ] },
|
||||
{ "make": "Kia", "model": "Soul", "year": 2012,
|
||||
"tire_pressure": [ 30.1, 31.0 ] },
|
||||
{ "make": "Toyota", "model": "Tercel", "year": 1999,
|
||||
"tire_pressure": [ 29.8, 30.0 ] }
|
||||
])"_padded;
|
||||
|
||||
|
||||
ondemand::parser parser;
|
||||
ondemand::document doc = parser.iterate(json);
|
||||
for (auto val : doc) {
|
||||
Car c(val);
|
||||
std::cout << c.make << std::endl;
|
||||
}
|
||||
```
|
||||
|
||||
We may do so by providing additional template definitions to the `ondemand::value` type.
|
||||
We may start by providing a definition for `std::vector<double>` as follows:
|
||||
|
||||
```c++
|
||||
template <>
|
||||
simdjson_inline simdjson_result<std::vector<double>>
|
||||
simdjson::ondemand::value::get() noexcept {
|
||||
ondemand::array array;
|
||||
auto error = get_array().get(array);
|
||||
if (error) { return error; }
|
||||
std::vector<double> vec;
|
||||
for (auto v : array) {
|
||||
double val;
|
||||
error = v.get_double().get(val);
|
||||
if (error) { return error; }
|
||||
vec.push_back(val);
|
||||
}
|
||||
return vec;
|
||||
}
|
||||
```
|
||||
|
||||
We may then provide support for our `Car`` struct:
|
||||
|
||||
```C++
|
||||
template <>
|
||||
simdjson_inline simdjson_result<Car> simdjson::ondemand::value::get() noexcept {
|
||||
ondemand::object obj;
|
||||
auto error = get_object().get(obj);
|
||||
if (error) { return error; }
|
||||
Car car;
|
||||
// Instead of repeatedly obj["something"], we iterate through the object which
|
||||
// we expect to be faster.
|
||||
for (auto field : obj) {
|
||||
raw_json_string key;
|
||||
error = field.key().get(key);
|
||||
if (error) { return error; }
|
||||
if (key == "make") {
|
||||
error = field.value().get_string(car.make);
|
||||
if (error) { return error; }
|
||||
} else if (key == "model") {
|
||||
error = field.value().get_string(car.model);
|
||||
if (error) { return error; }
|
||||
} else if (key == "year") {
|
||||
error = field.value().get_int64().get(car.year);
|
||||
if (error) { return error; }
|
||||
} else if (key == "tire_pressure") {
|
||||
error = field.value().get<std::vector<double>>().get(car.tire_pressure);
|
||||
if (auto error) { return error; }
|
||||
}
|
||||
}
|
||||
return car;
|
||||
}
|
||||
```
|
||||
|
||||
And that is all that is needed! The following code is a complete example:
|
||||
|
||||
```c++
|
||||
#include "simdjson.h"
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
using namespace simdjson;
|
||||
|
||||
/**
|
||||
* A custom type that we want to parse.
|
||||
*/
|
||||
struct Car {
|
||||
std::string make;
|
||||
std::string model;
|
||||
int64_t year;
|
||||
std::vector<double> tire_pressure;
|
||||
};
|
||||
|
||||
template <>
|
||||
simdjson_inline simdjson_result<std::vector<double>>
|
||||
simdjson::ondemand::value::get() noexcept {
|
||||
ondemand::array array;
|
||||
auto error = get_array().get(array);
|
||||
if (error) { return error; }
|
||||
std::vector<double> vec;
|
||||
for (auto v : array) {
|
||||
double val;
|
||||
error = v.get_double().get(val);
|
||||
if (error) { return error; }
|
||||
vec.push_back(val);
|
||||
}
|
||||
return vec;
|
||||
}
|
||||
|
||||
|
||||
template <>
|
||||
simdjson_inline simdjson_result<Car> simdjson::ondemand::value::get() noexcept {
|
||||
ondemand::object obj;
|
||||
auto error = get_object().get(obj);
|
||||
if (error) { return error; }
|
||||
Car car;
|
||||
// Instead of repeatedly obj["something"], we iterate through the object which
|
||||
// we expect to be faster.
|
||||
for (auto field : obj) {
|
||||
raw_json_string key;
|
||||
error = field.key().get(key);
|
||||
if (error) { return error; }
|
||||
if (key == "make") {
|
||||
error = field.value().get_string(car.make);
|
||||
if (error) { return error; }
|
||||
} else if (key == "model") {
|
||||
error = field.value().get_string(car.model);
|
||||
if (error) { return error; }
|
||||
} else if (key == "year") {
|
||||
error = field.value().get_int64().get(car.year);
|
||||
if (error) { return error; }
|
||||
} else if (key == "tire_pressure") {
|
||||
error = field.value().get<std::vector<double>>().get(car.tire_pressure);
|
||||
if (error) { return error; }
|
||||
}
|
||||
}
|
||||
return car;
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
padded_string json = R"( [ { "make": "Toyota", "model": "Camry", "year": 2018,
|
||||
"tire_pressure": [ 40.1, 39.9 ] },
|
||||
{ "make": "Kia", "model": "Soul", "year": 2012,
|
||||
"tire_pressure": [ 30.1, 31.0 ] },
|
||||
{ "make": "Toyota", "model": "Tercel", "year": 1999,
|
||||
"tire_pressure": [ 29.8, 30.0 ] }
|
||||
])"_padded;
|
||||
ondemand::parser parser;
|
||||
ondemand::document doc = parser.iterate(json);
|
||||
for (auto val : doc) {
|
||||
Car c(val);
|
||||
std::cout << c.make << std::endl;
|
||||
}
|
||||
direct();
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
```
|
||||
|
||||
Observe that we require an explicit cast (`Car c(val)` instead of `for (Car c : doc) {`): it is by design.
|
||||
|
||||
If you prefer to avoid exceptions, you may modify the `main` function as follows:
|
||||
|
||||
```c++
|
||||
int main(void) {
|
||||
padded_string json = R"( [ { "make": "Toyota", "model": "Camry", "year": 2018,
|
||||
"tire_pressure": [ 40.1, 39.9 ] },
|
||||
{ "make": "Kia", "model": "Soul", "year": 2012,
|
||||
"tire_pressure": [ 30.1, 31.0 ] },
|
||||
{ "make": "Toyota", "model": "Tercel", "year": 1999,
|
||||
"tire_pressure": [ 29.8, 30.0 ] }
|
||||
])"_padded;
|
||||
ondemand::parser parser;
|
||||
ondemand::document doc;
|
||||
auto error = parser.iterate(json).get(doc);
|
||||
if (error) { std::cerr << error << std::endl; return EXIT_FAILURE; }
|
||||
for (auto val : doc) {
|
||||
Car c;
|
||||
error = val.get<Car>().get(c);
|
||||
if (error) { std::cerr << error << std::endl; return EXIT_FAILURE; }
|
||||
std::cout << c.make << std::endl;
|
||||
}
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
```
|
||||
|
||||
Our example is limited to `ondemand::value` instances. If you wish to also be able to map
|
||||
directly the document instance itself to a custom type, you need to provide the definitions to
|
||||
the `ondemand::document` type. In this instance, we must replace the function with signature
|
||||
`simdjson_result<Car> simdjson::ondemand::value::get()` with a function having signature
|
||||
`simdjson_result<Car> simdjson::ondemand::document::get() &`. The following is a complete
|
||||
example:
|
||||
|
||||
```C++
|
||||
#include "simdjson.h"
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
using namespace simdjson;
|
||||
|
||||
/**
|
||||
* A custom type that we want to parse.
|
||||
*/
|
||||
struct Car {
|
||||
std::string make;
|
||||
std::string model;
|
||||
int64_t year;
|
||||
std::vector<double> tire_pressure;
|
||||
};
|
||||
|
||||
template <>
|
||||
simdjson_inline simdjson_result<std::vector<double>>
|
||||
simdjson::ondemand::value::get() noexcept {
|
||||
ondemand::array array;
|
||||
if (auto error = get_array().get(array); error) { return error; }
|
||||
std::vector<double> vec;
|
||||
for (auto v : array) {
|
||||
double val;
|
||||
if (auto error = v.get_double().get(val); error) { return error; }
|
||||
vec.push_back(val);
|
||||
}
|
||||
return vec;
|
||||
}
|
||||
|
||||
|
||||
template <>
|
||||
simdjson_inline simdjson_result<Car> simdjson::ondemand::document::get() & noexcept {
|
||||
ondemand::object obj;
|
||||
auto error = get_object().get(obj);
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
Car car;
|
||||
// Instead of repeatedly obj["something"], we iterate through the object which
|
||||
// we expect to be faster.
|
||||
for (auto field : obj) {
|
||||
raw_json_string key;
|
||||
error = field.key().get(key);
|
||||
if (error) { return error; }
|
||||
if (key == "make") {
|
||||
error = field.value().get_string(car.make);
|
||||
if (error) { return error; }
|
||||
} else if (key == "model") {
|
||||
error = field.value().get_string(car.model);
|
||||
if (error) { return error; }
|
||||
} else if (key == "year") {
|
||||
error = field.value().get_int64().get(car.year);
|
||||
if (error) { return error; }
|
||||
} else if (key == "tire_pressure") {
|
||||
error = field.value().get<std::vector<double>>().get(car.tire_pressure);
|
||||
if (error) { return error; }
|
||||
}
|
||||
}
|
||||
return car;
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
padded_string json = R"( { "make": "Toyota", "model": "Camry", "year": 2018,
|
||||
"tire_pressure": [ 40.1, 39.9 ] } )"_padded;
|
||||
ondemand::parser parser;
|
||||
ondemand::document doc = parser.iterate(json);
|
||||
Car c(doc);
|
||||
std::cout << c.make << std::endl;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
Minifying JSON strings without parsing
|
||||
----------------------
|
||||
|
||||
@@ -1081,10 +787,10 @@ auto cars = parser.iterate(cars_json);
|
||||
cout << cars.at_pointer("/0/tire_pressure/1") << endl; // Prints 39.9
|
||||
```
|
||||
|
||||
A JSON Pointer path is a sequence of segments each starting with the '/' character. Within arrays, a zero-based integer
|
||||
A JSON Path is a sequence of segments each starting with the '/' character. Within arrays, an integer
|
||||
index allows you to select the indexed node. Within objects, the string value of the key allows you to
|
||||
select the value. If your keys contain the characters '/' or '~', they must be escaped as '~1' and
|
||||
'~0' respectively. An empty JSON Pointer Path refers to the whole document.
|
||||
'~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.
|
||||
|
||||
@@ -1105,17 +811,6 @@ for (size_t i = 0; i < size; i++) {
|
||||
}
|
||||
```
|
||||
|
||||
In most instances, a JSON Pointer is an ASCII string and the keys in a JSON document
|
||||
are ASCII strings. We support UTF-8 in JSON Pointer, but key values are matched exactly, without unescaping or Unicode normalization. We do a byte-by-byte comparison. The e acute character is
|
||||
considered distinct from its escaped version `\u00E9`. E.g.,
|
||||
|
||||
```c++
|
||||
const padded_string json = "{\"\\u00E9\":123}"_padded;
|
||||
auto doc = parser.iterate(json);
|
||||
doc.at_pointer("/\\u00E9") == 123; // true
|
||||
doc.at_pointer((const char*)u8"/\u00E9") // returns an error (NO_SUCH_FIELD)
|
||||
```
|
||||
|
||||
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++
|
||||
@@ -1175,55 +870,9 @@ doc.rewind(); // Need to manually rewind to be able to use find_field properly f
|
||||
std::cout << doc.find_field("k0") << std::endl; // Prints 27
|
||||
```
|
||||
|
||||
When the JSON Pointer Path is the empty string (`""`) applied to a scalar document (lone string, number, Boolean or null), a SCALAR_DOCUMENT_AS_VALUE error is returned because scalar document cannot
|
||||
When the JSON path is the empty string (`""`) applied to a scalar document (lone string, number, Boolean or null), a SCALAR_DOCUMENT_AS_VALUE error is returned because scalar document cannot
|
||||
be represented as `value` instances. You can check that a document is a scalar with the method `scalar()`.
|
||||
|
||||
JSONPath
|
||||
------------
|
||||
|
||||
The simdjson library now supports a subset of [JSONPath](https://datatracker.ietf.org/doc/html/draft-normington-jsonpath-00) through the `at_path()` method, allowing you to reach further into the document in a single call. The subset of JSONPath that is implemented is the subset that is trivially convertible into the JSON Pointer format, using `.` to access a field and `[]` to access a specific index.
|
||||
|
||||
This implementation relies on `at_path()` converting its argument to JSON Pointer and then calling `at_pointer`, which makes use of [`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_path`.
|
||||
|
||||
Consider the following example:
|
||||
|
||||
```c++
|
||||
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;
|
||||
ondemand::parser parser;
|
||||
auto cars = parser.iterate(cars_json);
|
||||
cout << cars.at_path("[0].tire_pressure[1]") << endl; // Prints 39.9
|
||||
```
|
||||
|
||||
A call to `at_path(json_path)` can result in any of the errors that are returned by the `at_pointer` method and if the conversion of `json_path` to JSON Pointer fails, it will lead to an `simdjson::INVALID_JSON_POINTER`error.
|
||||
|
||||
```c++
|
||||
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;
|
||||
ondemand::parser parser;
|
||||
auto cars = parser.iterate(cars_json);
|
||||
ASSERT_ERROR(cars.at_path("[0].tire_presure[1").get(x), INVALID_JSON_POINTER); // Fails on conversion to JSON Pointer, since last square bracket was not properly closed.
|
||||
ASSERT_ERROR(cars.at_path("[0].incorrect_field[1]").get(x), NO_SUCH_FIELD); // Conversion to JSON Pointer succeeds, but fails on at_pointer() since the path is invalid.
|
||||
```
|
||||
|
||||
In most instances, a JSONPath is an ASCII string and the keys in a JSON document
|
||||
are ASCII strings. We support UTF-8 within a JSONPath expression, but key values are
|
||||
matched exactly, without unescaping or Unicode normalization. We do a byte-by-byte comparison.
|
||||
The e acute character is considered distinct from its escaped version `\u00E9`. E.g.,
|
||||
|
||||
```c++
|
||||
const padded_string json = "{\"\\u00E9\":123}"_padded;
|
||||
auto doc = parser.iterate(json);
|
||||
doc.at_path(".\\u00E9") == 123; // true
|
||||
doc.at_path((const char*)u8".\u00E9") // returns an error (NO_SUCH_FIELD)
|
||||
```
|
||||
|
||||
Error Handling
|
||||
--------------
|
||||
|
||||
@@ -1261,11 +910,11 @@ bool simple_error_example() {
|
||||
ondemand::parser parser;
|
||||
auto json = R"({"bad number":3.14.1 })"_padded;
|
||||
ondemand::document doc;
|
||||
if (parser.iterate(json).get(doc) != SUCCESS) { return false; }
|
||||
if( parser.iterate(json).get(doc) != SUCCESS ) { return false; }
|
||||
double x;
|
||||
auto error = doc["bad number"].get_double().get(x);
|
||||
// returns "simdjson::NUMBER_ERROR"
|
||||
if (error != SUCCESS) {
|
||||
if(error != SUCCESS) {
|
||||
std::cout << error << std::endl;
|
||||
return false;
|
||||
}
|
||||
@@ -1327,10 +976,10 @@ it selects the key `"count"` within that object.
|
||||
int main(void) {
|
||||
simdjson::ondemand::parser parser;
|
||||
auto error = padded_string::load("twitter.json").get(json);
|
||||
if (error) { std::cerr << error << std::endl; return EXIT_FAILURE; }
|
||||
if(error) { std::cerr << error << std::endl; return EXIT_FAILURE; }
|
||||
simdjson::ondemand::document tweets;
|
||||
error = parser.iterate(json).get(tweets);
|
||||
if (error) { std::cerr << error << std::endl; return EXIT_FAILURE; }
|
||||
if( error ) { std::cerr << error << std::endl; return EXIT_FAILURE; }
|
||||
simdjson::ondemand::value res;
|
||||
error = tweets["search_metadata"]["count"].get(res);
|
||||
if (error != SUCCESS) {
|
||||
@@ -1361,12 +1010,12 @@ int main(void) {
|
||||
simdjson::ondemand::document tweets;
|
||||
padded_string json;
|
||||
auto error = padded_string::load("twitter.json").get(json);
|
||||
if (error) { std::cerr << error << std::endl; return EXIT_FAILURE; }
|
||||
if(error) { std::cerr << error << std::endl; return EXIT_FAILURE; }
|
||||
error = parser.iterate(json).get(tweets);
|
||||
if (error) { std::cerr << error << std::endl; return EXIT_FAILURE; }
|
||||
if(error) { std::cerr << error << std::endl; return EXIT_FAILURE; }
|
||||
uint64_t identifier;
|
||||
error = tweets["statuses"].at(0)["id"].get(identifier);
|
||||
if (error) { std::cerr << error << std::endl; return EXIT_FAILURE; }
|
||||
if(error) { std::cerr << error << std::endl; return EXIT_FAILURE; }
|
||||
std::cout << identifier << std::endl;
|
||||
}
|
||||
```
|
||||
@@ -1390,40 +1039,40 @@ bool parse() {
|
||||
|
||||
// Iterating through an array of objects
|
||||
auto error = parser.iterate(cars_json).get(doc);
|
||||
if (error) { std::cerr << error << std::endl; return false; }
|
||||
if(error) { std::cerr << error << std::endl; return false; }
|
||||
ondemand::array cars; // invalid until the get() succeeds
|
||||
error = doc.get_array().get(cars);
|
||||
|
||||
for (auto car_value : cars) {
|
||||
ondemand::object car; // invalid until the get() succeeds
|
||||
error = car_value.get_object().get(car);
|
||||
if (error) { std::cerr << error << std::endl; return false; }
|
||||
if(error) { std::cerr << error << std::endl; return false; }
|
||||
|
||||
// Accessing a field by name
|
||||
std::string_view make;
|
||||
std::string_view model;
|
||||
error = car["make"].get(make);
|
||||
if (error) { std::cerr << error << std::endl; return false; }
|
||||
if(error) { std::cerr << error << std::endl; return false; }
|
||||
error = car["model"].get(model);
|
||||
if (error) { std::cerr << error << std::endl; return false; }
|
||||
if(error) { std::cerr << error << std::endl; return false; }
|
||||
|
||||
cout << "Make/Model: " << make << "/" << model << endl;
|
||||
|
||||
// Casting a JSON element to an integer
|
||||
uint64_t year{};
|
||||
error = car["year"].get(year);
|
||||
if (error) { std::cerr << error << std::endl; return false; }
|
||||
if(error) { std::cerr << error << std::endl; return false; }
|
||||
cout << "- This car is " << 2020 - year << " years old." << endl;
|
||||
|
||||
// Iterating through an array of floats
|
||||
double total_tire_pressure = 0;
|
||||
ondemand::array pressures;
|
||||
error = car["tire_pressure"].get_array().get(pressures);
|
||||
if (error) { std::cerr << error << std::endl; return false; }
|
||||
if(error) { std::cerr << error << std::endl; return false; }
|
||||
for (auto tire_pressure_value : pressures) {
|
||||
double tire_pressure;
|
||||
error = tire_pressure_value.get_double().get(tire_pressure);
|
||||
if (error) { std::cerr << error << std::endl; return false; }
|
||||
if(error) { std::cerr << error << std::endl; return false; }
|
||||
total_tire_pressure += tire_pressure;
|
||||
}
|
||||
cout << "- Average tire pressure: " << (total_tire_pressure / 4) << endl;
|
||||
@@ -1439,7 +1088,7 @@ after you have initialized them and checked that there is no error:
|
||||
ondemand::object car; // invalid until the get() succeeds
|
||||
// the `car` instance should not use used before it is initialized
|
||||
error = car_value.get_object().get(car);
|
||||
if (error) {
|
||||
if(error) {
|
||||
// the `car` instance should not use used
|
||||
} else {
|
||||
// the `car` instance can be safely used
|
||||
@@ -1453,20 +1102,20 @@ having to handle exceptions.
|
||||
ondemand::parser parser;
|
||||
ondemand::document doc;
|
||||
auto error = parser.iterate(json).get(doc);
|
||||
if (error) { return false; }
|
||||
if(error) { return false; }
|
||||
ondemand::object object; // invalid until the get() succeeds
|
||||
error = doc.get_object().get(object);
|
||||
if (error) { return false; }
|
||||
if(error) { return false; }
|
||||
for(auto field : object) {
|
||||
// We could replace 'field.key() with field.unescaped_key(),
|
||||
// and ondemand::raw_json_string by std::string_view.
|
||||
ondemand::raw_json_string keyv;
|
||||
error = field.key().get(keyv);
|
||||
if (error) { return false; }
|
||||
if (keyv == "key") {
|
||||
if(error) { return false; }
|
||||
if(keyv == "key") {
|
||||
uint64_t intvalue;
|
||||
error = field.value().get(intvalue);
|
||||
if (error) { return false; }
|
||||
if(error) { return false; }
|
||||
std::cout << intvalue;
|
||||
}
|
||||
}
|
||||
@@ -1645,7 +1294,7 @@ content.
|
||||
for (uint64_t values : array) {
|
||||
std::cout << values << std::endl;
|
||||
}
|
||||
if (!doc.at_end()) {
|
||||
if(!doc.at_end()) {
|
||||
// In this instance, we will be left pointing at 'foo' since we have consumed the array [1,2].
|
||||
std::cerr << "trailing content at byte index " << doc.current_location() - json.data() << std::endl;
|
||||
}
|
||||
@@ -1675,7 +1324,7 @@ before printout the data.
|
||||
|
||||
auto doc = parser.iterate(cars_json);
|
||||
for (simdjson_unused ondemand::object car : doc) {
|
||||
if (car["make"] == "Toyota") { count++; }
|
||||
if(car["make"] == "Toyota") { count++; }
|
||||
}
|
||||
std::cout << "We have " << count << " Toyota cars.\n";
|
||||
doc.rewind(); // requires simdjson 1.0 or better
|
||||
@@ -1743,18 +1392,18 @@ ondemand::parser parser;
|
||||
ondemand::document_stream stream;
|
||||
size_t counter{0};
|
||||
auto error = parser.iterate_many(json, 50).get(stream);
|
||||
if (error) { /* handle the error */ }
|
||||
if( error ) { /* handle the error */ }
|
||||
for (auto doc: stream) {
|
||||
if (counter < 6) {
|
||||
if(counter < 6) {
|
||||
int64_t val;
|
||||
error = doc.at_pointer("/4").get(val);
|
||||
if (error) { /* handle the error */ }
|
||||
if( error ) { /* handle the error */ }
|
||||
std::cout << "5 = " << val << std::endl;
|
||||
} else {
|
||||
ondemand::value val;
|
||||
error = doc.at_pointer("/4").get(val);
|
||||
// error == simdjson::CAPACITY
|
||||
if (error) {
|
||||
if(error) {
|
||||
std::cerr << error << std::endl;
|
||||
// We left 293 bytes unprocessed at the tail end of the input.
|
||||
std::cout << " unprocessed bytes at the end: " << stream.truncated_bytes() << std::endl;
|
||||
@@ -1959,7 +1608,7 @@ It will output:
|
||||
9999999999999999999 negative: 0 is_integer: 1 large 64-bit integer: 9999999999999999999 large 64-bit integer: 9999999999999999999
|
||||
```
|
||||
|
||||
Raw Strings From Keys
|
||||
Raw Strings
|
||||
-----------
|
||||
|
||||
It is sometimes useful to have access to a raw (unescaped) string: we make available a
|
||||
@@ -1995,27 +1644,12 @@ JSON string to a user-provided buffer:
|
||||
}
|
||||
```
|
||||
|
||||
Some users might prefer to have a direct access to an `std::string_view` instance
|
||||
pointing inside the source document. The `key_raw_json_token()` method serves this
|
||||
purpose. It provides a view on the key, including the starting quote character,
|
||||
and everything up to the next `:` character after the final quote character. E.g.,
|
||||
if the key is `"name"` then `key_raw_json_token()` returns an `std::string_view` which
|
||||
begins with `"name"` and may containing trailing white-space characters.
|
||||
```C++
|
||||
auto json = R"( {"name" : "Jack The Ripper \u0033"} )"_padded;
|
||||
ondemand::parser parser;
|
||||
ondemand::document doc = parser.iterate(json);
|
||||
for (auto key_value : doc.get_object()) {
|
||||
std::string_view keysv = key_value.key_raw_json_token(); // keysv is "\"name\" "
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
General Direct Access to the Raw JSON String
|
||||
--------------------------------
|
||||
If your value is a string, the `raw_json_string` you get with `get_raw_json_string()` gives you direct access to the unprocessed
|
||||
string. But the simdjson library allows you to have access to the raw underlying JSON
|
||||
more generally, not just for strings.
|
||||
If your value is a string, the `raw_json_string` gives you direct access to the unprocess
|
||||
string. The simdjson library allows you to have access to the raw underlying JSON
|
||||
more generally.
|
||||
|
||||
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
|
||||
@@ -2048,16 +1682,9 @@ string_view token = obj["value"].raw_json_token();
|
||||
|
||||
The `raw_json_token()` should be fast and free of allocation.
|
||||
|
||||
Given a quote-deliminated string, you find the string sequence inside the quote with a
|
||||
single line of code:
|
||||
|
||||
```C++
|
||||
std::string_view noquote(std::string_view v) { return {v.data()+1, v.find_last_of('"')-1}; }
|
||||
```
|
||||
|
||||
If your value is an array or an object, `raw_json_token()` returns effectively a single
|
||||
If you value is an array or an object, `raw_json_token()` returns effectively a single
|
||||
character (`[`) or (`}`) which is not very useful. For arrays and objects, we have another
|
||||
method called `raw_json()` which consumes (traverses) the array or the object.
|
||||
method called `raw_json()` which consumes (traverse) the array or the object.
|
||||
|
||||
```C++
|
||||
simdjson::ondemand::parser parser;
|
||||
@@ -2089,82 +1716,6 @@ obj.reset(); // revise the object
|
||||
uint64_t x = obj["value"]; // gives me 123
|
||||
```
|
||||
|
||||
You can use `raw_json()` with the values inside an array and object. When
|
||||
calling `raw_json()` on an untyped value, it acts as `raw_json()` when the
|
||||
value is an array or an object. Otherwise, it acts as `raw_json_token()`.
|
||||
It is useful if you do not care for the type of the value and just wants a
|
||||
string representation.
|
||||
|
||||
```C++
|
||||
auto json = R"( [1,2,"fds", {"a":1}, [1,344]] )"_padded;
|
||||
ondemand::parser parser;
|
||||
ondemand::document doc = parser.iterate(json);
|
||||
size_t counter = 0;
|
||||
for(auto array: doc) {
|
||||
std::string_view raw = array.raw_json();
|
||||
// will capture "1", "2", "\"fds\"", "{\"a\":1}", "[1,344]"
|
||||
}
|
||||
```
|
||||
|
||||
```C++
|
||||
auto json = R"( {"key1":1,"key2":2,"key3":"fds", "key4":{"a":1}, "key5":[1,344]} )"_padded;
|
||||
ondemand::parser parser;
|
||||
ondemand::document doc = parser.iterate(json);
|
||||
size_t counter = 0;
|
||||
for(auto key_value: doc.get_object()) {
|
||||
std::string_view raw = key_value.value().raw_json();
|
||||
// will capture "1", "2", "\"fds\"", "{\"a\":1}", "[1,344]"
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
Storing Directly into an Existing String Instance
|
||||
-----------------------------------------------------
|
||||
|
||||
The simdjson library favours the use of `std::string_view` instances because
|
||||
it tends to lead to better performance due to causing fewer memory allocations.
|
||||
However, they are cases where you need to store a string result in an `std::string``
|
||||
instance. You can do so with a templated version of the `to_string()` method which takes as
|
||||
a parameter a reference to an `std::string`.
|
||||
|
||||
```C++
|
||||
auto json = R"({
|
||||
"name": "Daniel",
|
||||
"age": 42
|
||||
})"_padded;
|
||||
ondemand::parser parser;
|
||||
ondemand::document doc = parser.iterate(json);
|
||||
std::string name;
|
||||
doc["name"].get_string(name);
|
||||
```
|
||||
|
||||
The same routine can be written without exceptions handling:
|
||||
|
||||
```C++
|
||||
std::string name;
|
||||
auto err = doc["name"].get_string(name);
|
||||
if (err) { /* handle error */ }
|
||||
```
|
||||
|
||||
The `std::string` instance, once created, is independent. Unlike our `std::string_view` instances,
|
||||
it does not point at data that is within our `parser` instance. The same caveat applies: you should
|
||||
only consume a JSON string once.
|
||||
|
||||
Because `get_string()` is a template that requires a type that can be assigned an `std::string`, you
|
||||
can use it with features such as `std::optional`:
|
||||
|
||||
```C++
|
||||
auto json = R"({ "foo1": "3.1416" } )"_padded;
|
||||
ondemand::parser parser;
|
||||
ondemand::document doc = parser.iterate(json);
|
||||
std::optional<std::string> value;
|
||||
if (doc["foo1"].get_string(value)) { /* error */ }
|
||||
// value was populated with "3.1416"
|
||||
```
|
||||
|
||||
You should be mindful of the trade-off: allocating multiple
|
||||
`std::string` instances can become expensive.
|
||||
|
||||
Thread Safety
|
||||
-------------
|
||||
|
||||
@@ -2393,101 +1944,6 @@ bool example() {
|
||||
}
|
||||
```
|
||||
|
||||
* Example 3: CRT
|
||||
|
||||
```C++
|
||||
|
||||
bool example() {
|
||||
padded_string padded_input_json = R"([
|
||||
{ "monitor": [
|
||||
{ "id": "monitor", "type": "toggle", "label": "monitor" },
|
||||
{ "id": "profile", "type": "selector", "label": "collection" },
|
||||
{ "id": "overlay", "type": "selector", "label": "overlay" },
|
||||
{ "id": "zoom", "type": "toggleSlider", "label": "zoom" }
|
||||
] },
|
||||
|
||||
{ "crt": [
|
||||
{ "id": "system", "type": "multi", "label": "system", "choices": "PAL, NTSC" },
|
||||
{ "type": "spacer" },
|
||||
{ "id": "brightness", "type": "slider", "icon": "brightness" },
|
||||
{ "id": "contrast", "type": "slider", "icon": "contrast" },
|
||||
{ "id": "saturation", "type": "slider", "icon": "saturation" },
|
||||
{ "type": "spacer" },
|
||||
{ "id": "overscan", "type": "toggleSlider", "label": "overscan" },
|
||||
{ "type": "spacer" },
|
||||
{ "id": "emulation", "type": "toggle", "label": "CRT emulation" },
|
||||
{ "type": "spacer" },
|
||||
{ "id": "curve", "type": "toggleSlider", "label": "curve" },
|
||||
{ "id": "bleed", "type": "toggleSlider", "label": "bleed" },
|
||||
{ "id": "vignette", "type": "toggleSlider", "label": "vignette" },
|
||||
{ "id": "scanlines", "type": "toggleSlider", "label": "scanlines" },
|
||||
{ "id": "gridlines", "type": "toggleSlider", "label": "gridlines" },
|
||||
{ "id": "glow", "type": "toggleSlider", "label": "glow" },
|
||||
{ "id": "flicker", "type": "toggleSlider", "label": "flicker" },
|
||||
{ "id": "noise", "type": "toggleSlider", "label": "noise" },
|
||||
{}
|
||||
] }
|
||||
])"_padded;
|
||||
auto parser = ondemand::parser{};
|
||||
auto doc = parser.iterate(padded_input_json);
|
||||
auto root_array = doc.get_array();
|
||||
// the root should be an object, not an array, but that's the JSON we are
|
||||
// given.
|
||||
for (ondemand::object node : root_array) {
|
||||
// We know that we are going to have just one element in the object.
|
||||
for (auto field : node) {
|
||||
std::cout << "\n\ntop level:" << field.key() << std::endl;
|
||||
// You can get a proper std::string_view for the key with:
|
||||
// std::string_view key = field.unescaped_key();
|
||||
// and second for-range loop to get child-elements here
|
||||
for (ondemand::object inner_object : field.value()) {
|
||||
auto i = inner_object.begin();
|
||||
if (i == inner_object.end()) {
|
||||
std::cout << "empty object" << std::endl;
|
||||
continue;
|
||||
} else {
|
||||
for (; i != inner_object.end(); ++i) {
|
||||
auto inner_field = *i;
|
||||
std::cout << '"' << inner_field.key()
|
||||
<< "\" : " << inner_field.value() << ", ";
|
||||
// You can get proper std::string_view for the key and value with:
|
||||
// std::string_view inner_key = field.unescaped_key();
|
||||
// std::string_view value_str = field.value();
|
||||
}
|
||||
}
|
||||
std::cout << std::endl;
|
||||
}
|
||||
// You can break here if you only want just the first element.
|
||||
// break;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
```
|
||||
|
||||
* Example 4: Passing an array to a function
|
||||
|
||||
```C++
|
||||
|
||||
#include "simdjson.h"
|
||||
#include <iostream>
|
||||
|
||||
// prints the content of the array as hexadecimal 64-bit integers
|
||||
void f(simdjson::ondemand::array v) {
|
||||
for(uint64_t val : v) {
|
||||
std::cout << "0x" << std::hex << val << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int main(void) {
|
||||
simdjson::padded_string json = R"( [ 897314173811950000, 3122321 ])"_padded;
|
||||
simdjson::ondemand::parser parser;
|
||||
simdjson::ondemand::document doc = parser.iterate(json);
|
||||
f(doc.get_array());
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
```
|
||||
|
||||
Performance Tips
|
||||
--------
|
||||
@@ -2513,10 +1969,4 @@ Performance Tips
|
||||
std::string_view year = data["year"];
|
||||
std::string_view rating = data["rating"];
|
||||
```
|
||||
- To better understand the operation of your On Demand parser, and whether it is performing as well as you think it should be, there is a logger feature built in to simdjson! To use it, define the pre-processor directive `SIMDJSON_VERBOSE_LOGGING` prior to including the `simdjson.h` header, which enables logging in simdjson. Run your code. It may generate a lot of logging output; adding printouts from your application that show each section may be helpful. The log's output will show step-by-step information on state, buffer pointer position, depth, and key retrieval status. Importantly, unless `SIMDJSON_VERBOSE_LOGGING` is defined, logging is entirely disabled and thus carries no overhead.
|
||||
|
||||
Further reading
|
||||
--------
|
||||
|
||||
|
||||
- John Keiser, Daniel Lemire, [On-Demand JSON: A Better Way to Parse Documents?](http://arxiv.org/abs/2312.17149), Software: Practice and Experience (to appear)
|
||||
- To better understand the operation of your On Demand parser, and whether it is performing as well as you think it should be, there is a logger feature built in to simdjson! To use it, define the pre-processor directive `SIMDJSON_VERBOSE_LOGGING` prior to including the `simdjson.h` header, which enables logging in simdjson. Run your code. It may generate a lot of logging output; adding printouts from your application that show each section may be helpful. The log's output will show step-by-step information on state, buffer pointer position, depth, and key retrieval status. Importantly, unless `SIMDJSON_VERBOSE_LOGGING` is defined, logging is entirely disabled and thus carries no overhead.
|
||||
+5
-5
@@ -223,13 +223,13 @@ dom::element cars = parser.parse(cars_json);
|
||||
cout << cars.at_pointer("/0/tire_pressure/1") << endl; // Prints 39.9
|
||||
```
|
||||
|
||||
A JSON Pointer expression is a sequence of segments each starting with the '/' character. Within arrays, an integer
|
||||
A JSON Path is a sequence of segments each starting with the '/' character. Within arrays, an integer
|
||||
index allows you to select the indexed node. Within objects, the string value of the key allows you to
|
||||
select the value. If your keys contain the characters '/' or '~', they must be escaped as '~1' and
|
||||
'~0' respectively. An empty JSON Pointer expression refers to the whole document.
|
||||
'~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 Pointer expression 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 current node were a whole JSON document.
|
||||
|
||||
Consider the following example:
|
||||
|
||||
@@ -329,10 +329,10 @@ int main(void) {
|
||||
simdjson::dom::parser parser;
|
||||
simdjson::dom::element tweets; // invalid until the get() succeeds
|
||||
auto error = parser.load("twitter.json").get(tweets);
|
||||
if (error) { std::cerr << error << std::endl; return EXIT_FAILURE; }
|
||||
if(error) { std::cerr << error << std::endl; return EXIT_FAILURE; }
|
||||
uint64_t identifier;
|
||||
error = tweets["statuses"].at(0)["id"].get(identifier);
|
||||
if (error) { std::cerr << error << std::endl; return EXIT_FAILURE; }
|
||||
if(error) { std::cerr << error << std::endl; return EXIT_FAILURE; }
|
||||
std::cout << identifier << std::endl;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -11,24 +11,22 @@ CPU Architecture-Specific Implementations
|
||||
Overview
|
||||
--------
|
||||
|
||||
|
||||
|
||||
The simdjson library takes advantage of SIMD instruction sets such as NEON, SSE and AVX to achieve
|
||||
much of its speed. Because these instruction sets work differently, simdjson has to compile a
|
||||
different version of the JSON parser for different CPU architectures, often with different
|
||||
algorithms to take better advantage of a given CPU!
|
||||
|
||||
The current implementations are:
|
||||
* icelake: AVX-512F, AVX-512_VBMI, AVX-512_VBMI2, AVX-512_DQ, AVX-512512_CD, AVX-512_BW, AVX-512_VL (2019 Intel Ice Lake, Intel Rocket Lake, Intel Sapphire Rapids, AMD Zen 4)
|
||||
* haswell: AVX2 (2013 Intel Haswell or later, all AMD Zen processors)
|
||||
* icelake: AVX-512F, AVX-512VBMI, etc.
|
||||
* haswell: AVX2 (2013 Intel Haswell or later)
|
||||
* westmere: SSE4.2 (2010 Westmere or later).
|
||||
* arm64: 64-bit ARMv8-A NEON
|
||||
* ppc64: 64-bit POWER8 and POWER9 with VSX and ALTIVEC extensions. Both big endian and little endian are implemented, depending on the compiler you are using. The library is tested on recent, little-endian, POWER systems.
|
||||
* ppc64: 64-bit POWER8 and POWER9 with VSX and ALTIVEC extensions. Both big endian and little endian are implemented, depends on the compiler you are using. The library is tested on recent, little-endian, POWER systems.
|
||||
* fallback: A generic implementation that runs on any 64-bit processor.
|
||||
|
||||
In many cases, you don't know where your compiled binary is going to run, so simdjson automatically
|
||||
compiles *all* the implementations into the executable. On Intel, it will include 4 implementations
|
||||
(icelake, haswell, westmere and fallback), on 64-bit ARM it will include just one since running dispatching is unnecessary, and on PPC
|
||||
(icelake, haswell, westmere and fallback), on ARM it will include 2 (arm64 and fallback), and on PPC
|
||||
it will include 2 (ppc64 and fallback).
|
||||
|
||||
If you know more about where you're going to run and want to save the space, you can disable any of
|
||||
@@ -77,7 +75,8 @@ And look them up by name:
|
||||
```c++
|
||||
cout << simdjson::get_available_implementations()["fallback"]->description() << endl;
|
||||
```
|
||||
When an implementation is not available, the bracket call `simdjson::get_available_implementations()[name]`
|
||||
Though the fallback implementation should always be available, others might be missing. When
|
||||
an implementation is not available, the bracket call `simdjson::get_available_implementations()[name]`
|
||||
will return the null pointer.
|
||||
|
||||
The available implementations have been compiled but may not necessarily be run safely on your system
|
||||
@@ -102,8 +101,8 @@ by comparing it with the null pointer.
|
||||
|
||||
```c++
|
||||
auto my_implementation = simdjson::get_available_implementations()["haswell"];
|
||||
if (! my_implementation) { exit(1); }
|
||||
if (! my_implementation->supported_by_runtime_system()) { exit(1); }
|
||||
if(! my_implementation) { exit(1); }
|
||||
if(! my_implementation->supported_by_runtime_system()) { exit(1); }
|
||||
simdjson::get_active_implementation() = my_implementation;
|
||||
```
|
||||
|
||||
@@ -114,7 +113,7 @@ You should call `supported_by_runtime_system()` to compare the processor's featu
|
||||
|
||||
```c++
|
||||
for (auto implementation : simdjson::get_available_implementations()) {
|
||||
if (implementation->supported_by_runtime_system()) {
|
||||
if(implementation->supported_by_runtime_system()) {
|
||||
cout << implementation->name() << ": " << implementation->description() << endl;
|
||||
}
|
||||
}
|
||||
|
||||
+4
-7
@@ -17,9 +17,6 @@ Contents
|
||||
|
||||
- [Motivations](#motivations)
|
||||
- [How it works](#how-it-works)
|
||||
- [Context](#context)
|
||||
- [Design](#design)
|
||||
- [Threads](#threads)
|
||||
- [Support](#support)
|
||||
- [API](#api)
|
||||
- [Use cases](#use-cases)
|
||||
@@ -196,12 +193,12 @@ Let us illustrate the idea with code:
|
||||
simdjson::ondemand::parser parser;
|
||||
simdjson::ondemand::document_stream stream;
|
||||
auto error = parser.iterate_many(json).get(stream);
|
||||
if (error) { /* do something */ }
|
||||
if( error ) { /* do something */ }
|
||||
auto i = stream.begin();
|
||||
size_t count{0};
|
||||
for(; i != stream.end(); ++i) {
|
||||
auto doc = *i;
|
||||
if (!i.error()) {
|
||||
if(!i.error()) {
|
||||
std::cout << "got full document at " << i.current_index() << std::endl;
|
||||
std::cout << i.source() << std::endl;
|
||||
count++;
|
||||
@@ -237,7 +234,7 @@ Consider the following example where a truncated document (`{"key":"intentionall
|
||||
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; }
|
||||
if(error) { std::cerr << error << std::endl; return; }
|
||||
for(auto i = stream.begin(); i != stream.end(); ++i) {
|
||||
std::cout << i.source() << std::endl;
|
||||
}
|
||||
@@ -269,7 +266,7 @@ Example:
|
||||
// we pass 'true' to the allow_comma parameter, the batch size will be set to at least
|
||||
// the document size.
|
||||
auto error = parser.iterate_many(json, 32, true).get(doc_stream);
|
||||
if (error) { std::cerr << error << std::endl; return; }
|
||||
if(error) { std::cerr << error << std::endl; return; }
|
||||
for (auto doc : doc_stream) {
|
||||
std::cout << doc.type() << std::endl;
|
||||
}
|
||||
|
||||
@@ -679,14 +679,14 @@ in production systems:
|
||||
ondemand::object c1 = parent["child1"];
|
||||
// c1 owns the focus
|
||||
//
|
||||
if (std::string_view(c1["name"]) != "John") { ... }
|
||||
if(std::string_view(c1["name"]) != "John") { ... }
|
||||
// c2 attempts to grab the focus from parent but fails
|
||||
ondemand::object c2 = parent["child2"];
|
||||
// c2 is now in an unsafe state and the following line would be unsafe
|
||||
// if (std::string_view(c2["name"]) != "Daniel") { return false; }
|
||||
// if(std::string_view(c2["name"]) != "Daniel") { return false; }
|
||||
```
|
||||
|
||||
A correct usage is given by the following example:
|
||||
A correct usage is given by the following example:
|
||||
|
||||
```C++
|
||||
ondemand::parser parser;
|
||||
@@ -697,7 +697,7 @@ A correct usage is given by the following example:
|
||||
{
|
||||
ondemand::object c1 = parent["child1"];
|
||||
// c1 grabbed the focus from parent
|
||||
if (std::string_view(c1["name"]) != "John") { return false; }
|
||||
if(std::string_view(c1["name"]) != "John") { return false; }
|
||||
}
|
||||
// c1 went out of scope, so its destructor was called and the focus
|
||||
// was handed back to parent.
|
||||
@@ -705,7 +705,7 @@ A correct usage is given by the following example:
|
||||
ondemand::object c2 = parent["child2"];
|
||||
// c2 grabbed the focus from parent
|
||||
// the following is safe:
|
||||
if (std::string_view(c2["name"]) != "Daniel") { return false; }
|
||||
if(std::string_view(c2["name"]) != "Daniel") { return false; }
|
||||
}
|
||||
```
|
||||
|
||||
@@ -779,4 +779,4 @@ Instead of specifying a specific microarchitecture, you can let your compiler do
|
||||
|
||||
Passing `-march=native` to the compiler may make On Demand faster by allowing it to use optimizations specific to your machine. You cannot do this, however, if you are compiling code that might be run on less advanced machines. That is, be mindful that when compiling with the `-march=native` flag, the resulting binary will run on the current system but may not run on other systems (e.g., on an old processor).
|
||||
|
||||
If you are compiling on an ARM or POWER system, you do not need to be concerned with CPU selection during compilation. The `-march=native` flag is useful for best performance on x64 (e.g., Intel) systems but it is generally unsupported on some platforms such as ARM (aarch64) or POWER.
|
||||
If you are compiling on an ARM or POWER system, you do not need to be concerned with CPU selection during compilation. The `-march=native` flag useful for best performance on x64 (e.g., Intel) systems but it is generally unsupported on some platforms such as ARM (aarch64) or POWER.
|
||||
|
||||
+3
-3
@@ -184,12 +184,12 @@ Let us illustrate the idea with code:
|
||||
simdjson::dom::parser parser;
|
||||
simdjson::dom::document_stream stream;
|
||||
auto error = parser.parse_many(json).get(stream);
|
||||
if (error) { /* do something */ }
|
||||
if( error ) { /* do something */ }
|
||||
auto i = stream.begin();
|
||||
size_t count{0};
|
||||
for(; i != stream.end(); ++i) {
|
||||
auto doc = *i;
|
||||
if (!doc.error()) {
|
||||
if(!doc.error()) {
|
||||
std::cout << "got full document at " << i.current_index() << std::endl;
|
||||
std::cout << i.source() << std::endl;
|
||||
count++;
|
||||
@@ -225,7 +225,7 @@ Consider the following example where a truncated document (`{"key":"intentionall
|
||||
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; }
|
||||
if(error) { std::cerr << error << std::endl; return; }
|
||||
for(auto doc : stream) {
|
||||
std::cout << doc << std::endl;
|
||||
}
|
||||
|
||||
+1
-1
@@ -159,7 +159,7 @@ When compiling with Visual Studio, we recommend the flags `/Ob2 /O2` or better.
|
||||
|
||||
Recent versions of Microsoft Visual Studio on Windows provides support for the LLVM Clang compiler. You only need to install the "Clang compiler" optional component (ClangCL). You may also get a copy of the 64-bit LLVM CLang compiler for [Windows directly from LLVM](https://releases.llvm.org/download.html). The simdjson library fully supports the LLVM Clang compiler under Windows. In fact, you may get better performance out of simdjson with the LLVM Clang compiler than with the regular Visual Studio compiler. Meanwhile the [LLVM CLang compiler is binary compatible with Visual Studio](https://clang.llvm.org/docs/MSVCCompatibility.html) which means that you can combine their binaries (executables and libraries).
|
||||
|
||||
Under Windows, we also support the GNU GCC compiler via MSYS2. The performance of 64-bit MSYS2 under Windows is excellent (on par with Linux).
|
||||
Under Windows, we also support the GNU GCC compiler via MSYS2. The performance of 64-bit MSYS2 under Windows excellent (on par with Linux).
|
||||
|
||||
|
||||
Power Usage and Downclocking
|
||||
|
||||
+1
-1
@@ -29,7 +29,7 @@ It is sometimes useful to start with an example. Consider the following JSON doc
|
||||
The following is a dump of the content of the tape, with the first number of each line representing the index of a tape element.
|
||||
|
||||
### The Tape
|
||||
| index | element (64-bit word) |
|
||||
| index | element (64 bit word) |
|
||||
| ----- | ------------------------------------------------------------------- |
|
||||
| 0 | r // pointing to 39 (right after last node) |
|
||||
| 1 | { // pointing to next tape location 38 (first node after the scope) |
|
||||
|
||||
@@ -35,4 +35,14 @@ IF(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
|
||||
add_quickstart_test(quickstart_ondemand_noexceptions quickstart_ondemand_noexceptions.cpp NO_EXCEPTIONS LABELS quickstart_ondemand acceptance)
|
||||
add_quickstart_test(quickstart_ondemand_noexceptions11 quickstart_ondemand_noexceptions.cpp NO_EXCEPTIONS CXX_STANDARD c++11 LABELS quickstart_ondemand)
|
||||
|
||||
# SingleStage Quick Start
|
||||
if (SIMDJSON_EXCEPTIONS)
|
||||
add_quickstart_test(quickstart_singlestage quickstart_singlestage.cpp LABELS quickstart_singlestage acceptance)
|
||||
add_quickstart_test(quickstart_singlestage11 quickstart_singlestage.cpp CXX_STANDARD c++11 LABELS quickstart_singlestage acceptance)
|
||||
add_quickstart_test(quickstart_singlestage14 quickstart_singlestage.cpp CXX_STANDARD c++14 LABELS quickstart_singlestage)
|
||||
endif()
|
||||
|
||||
add_quickstart_test(quickstart_singlestage_noexceptions quickstart_singlestage_noexceptions.cpp NO_EXCEPTIONS LABELS quickstart_singlestage acceptance)
|
||||
add_quickstart_test(quickstart_singlestage_noexceptions11 quickstart_singlestage_noexceptions.cpp NO_EXCEPTIONS CXX_STANDARD c++11 LABELS quickstart_singlestage)
|
||||
|
||||
endif()
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
#include <iostream>
|
||||
#include "simdjson.h"
|
||||
using namespace simdjson;
|
||||
int main(void) {
|
||||
ondemand::parser parser;
|
||||
padded_string json = padded_string::load("twitter.json");
|
||||
ondemand::document tweets = parser.iterate(json);
|
||||
std::cout << uint64_t(tweets["search_metadata"]["count"]) << " results." << std::endl;
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
#include <iostream>
|
||||
#include "simdjson.h"
|
||||
using namespace simdjson;
|
||||
int main(void) {
|
||||
padded_string json;
|
||||
auto error = padded_string::load("twitter.json").get(json);
|
||||
if (error) { std::cerr << error << std::endl; return EXIT_FAILURE; }
|
||||
|
||||
ondemand::parser parser;
|
||||
ondemand::document tweets;
|
||||
error = parser.iterate(json).get(tweets);
|
||||
if (error) { std::cerr << error << std::endl; return EXIT_FAILURE; }
|
||||
|
||||
uint64_t count;
|
||||
error = tweets["search_metadata"]["count"].get(count);
|
||||
if (error) { std::cerr << error << std::endl; return EXIT_FAILURE; }
|
||||
|
||||
std::cout << count << " results." << std::endl;
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
@@ -63,6 +63,7 @@ if(SIMDJSON_ENABLE_FUZZING)
|
||||
implement_fuzzer(fuzz_minifyimpl) # minify *without* parsing, plus compare implementations
|
||||
implement_fuzzer(fuzz_ndjson) # the ndjson api
|
||||
implement_fuzzer(fuzz_ondemand)
|
||||
# implement_fuzzer(fuzz_singlestage) # TODO why no worky
|
||||
implement_fuzzer(fuzz_padded)
|
||||
implement_fuzzer(fuzz_parser)
|
||||
implement_fuzzer(fuzz_print_json)
|
||||
|
||||
@@ -78,7 +78,7 @@ fi
|
||||
# Different levels may uncover different types of bugs, see this interesting
|
||||
# thread: https://github.com/google/oss-fuzz/issues/2295#issuecomment-481493392
|
||||
# Oss-fuzz uses -O1 so it may be relevant to use something else than that,
|
||||
# to do something oss-fuzz does not do.
|
||||
# to do something oss-fuzz doesn't.
|
||||
variant=sanitizers-O3
|
||||
|
||||
if [ ! -d build-$variant ] ; then
|
||||
|
||||
@@ -7,11 +7,11 @@
|
||||
|
||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
|
||||
|
||||
// Split data into two strings, JSON Pointer and the document string.
|
||||
// Split data into two strings, json pointer and the document string.
|
||||
// Might end up with none, either or both being empty, important for
|
||||
// covering edge cases such as
|
||||
// https://github.com/simdjson/simdjson/issues/1142 Inputs missing the
|
||||
// separator line will get an empty JSON Pointer but the all the input put in
|
||||
// separator line will get an empty json pointer but the all the input put in
|
||||
// the document string. This means test data from other fuzzers that take json
|
||||
// input works for this fuzzer as well.
|
||||
FuzzData fd(Data, Size);
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
#include "FuzzUtils.h"
|
||||
#include "simdjson.h"
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
|
||||
FuzzData fd(Data, Size);
|
||||
const int action = fd.getInt<0, 12>();
|
||||
|
||||
// split the remainder of the document into strings
|
||||
auto strings = fd.splitIntoStrings();
|
||||
while (strings.size() < 1) {
|
||||
strings.emplace_back();
|
||||
}
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
try {
|
||||
#endif
|
||||
simdjson::singlestage::parser parser;
|
||||
simdjson::padded_string padded(strings[0]);
|
||||
auto doc = parser.iterate(padded);
|
||||
if (doc.error()) {
|
||||
return 0;
|
||||
}
|
||||
for (auto item : doc) {
|
||||
switch (action) {
|
||||
case 0: {
|
||||
simdjson_unused auto x = item.get_string();
|
||||
} break;
|
||||
case 1: {
|
||||
simdjson_unused auto x = item.get_bool();
|
||||
} break;
|
||||
case 2: {
|
||||
simdjson_unused auto x = item.get_array();
|
||||
} break;
|
||||
case 3: {
|
||||
simdjson_unused auto x = item.get_int64();
|
||||
} break;
|
||||
case 4: {
|
||||
simdjson_unused auto x = item.get_double();
|
||||
} break;
|
||||
case 5: {
|
||||
simdjson_unused auto x = item.get_object();
|
||||
} break;
|
||||
case 6: {
|
||||
simdjson_unused auto x = item.get_uint64();
|
||||
} break;
|
||||
case 7: {
|
||||
simdjson_unused auto x = item.get_raw_json_string();
|
||||
} break;
|
||||
case 8: {
|
||||
simdjson_unused auto x = item.is_null();
|
||||
} break;
|
||||
case 9: {
|
||||
simdjson_unused auto x = item.begin();
|
||||
} break;
|
||||
case 10: {
|
||||
simdjson_unused auto x = item.end();
|
||||
} break;
|
||||
case 11: {
|
||||
for (auto e : item) {
|
||||
simdjson_unused auto x = e.is_null();
|
||||
}
|
||||
} break;
|
||||
default:;
|
||||
}
|
||||
}
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
} catch (...) {
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -53,5 +53,6 @@
|
||||
|
||||
#include "simdjson/dom.h"
|
||||
#include "simdjson/ondemand.h"
|
||||
#include "simdjson/singlestage.h"
|
||||
|
||||
#endif // SIMDJSON_H
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
#ifndef SIMDJSON_ARM64_BASE_H
|
||||
#define SIMDJSON_ARM64_BASE_H
|
||||
|
||||
#ifndef SIMDJSON_CONDITIONAL_INCLUDE
|
||||
#ifndef SIMDJSON_AMALGAMATED
|
||||
#include "simdjson/base.h"
|
||||
#endif // SIMDJSON_CONDITIONAL_INCLUDE
|
||||
#endif // SIMDJSON_AMALGAMATED
|
||||
|
||||
namespace simdjson {
|
||||
/**
|
||||
@@ -23,4 +23,11 @@ template <typename T> struct simd8x64;
|
||||
} // namespace arm64
|
||||
} // namespace simdjson
|
||||
|
||||
#ifndef SIMDJSON_AMALGAMATED
|
||||
// If we're editing one of the files in this directory, begin the implementation!
|
||||
#ifndef SIMDJSON_IMPLEMENTATION
|
||||
#include "simdjson/arm64/begin.h"
|
||||
#endif
|
||||
#endif // SIMDJSON_AMALGAMATED
|
||||
|
||||
#endif // SIMDJSON_ARM64_BASE_H
|
||||
|
||||
@@ -6,5 +6,3 @@
|
||||
#include "simdjson/arm64/numberparsing_defs.h"
|
||||
#include "simdjson/arm64/simd.h"
|
||||
#include "simdjson/arm64/stringparsing_defs.h"
|
||||
|
||||
#define SIMDJSON_SKIP_BACKSLASH_SHORT_CIRCUIT 1
|
||||
@@ -1,13 +1,11 @@
|
||||
#ifndef SIMDJSON_ARM64_BITMANIPULATION_H
|
||||
#define SIMDJSON_ARM64_BITMANIPULATION_H
|
||||
|
||||
#ifndef SIMDJSON_CONDITIONAL_INCLUDE
|
||||
#include "simdjson/arm64/base.h"
|
||||
#include "simdjson/arm64/intrinsics.h"
|
||||
#endif // SIMDJSON_CONDITIONAL_INCLUDE
|
||||
|
||||
namespace simdjson {
|
||||
namespace arm64 {
|
||||
namespace SIMDJSON_IMPLEMENTATION {
|
||||
namespace {
|
||||
|
||||
// We sometimes call trailing_zero on inputs that are zero,
|
||||
@@ -100,7 +98,7 @@ simdjson_inline bool add_overflow(uint64_t value1, uint64_t value2, uint64_t *re
|
||||
}
|
||||
|
||||
} // unnamed namespace
|
||||
} // namespace arm64
|
||||
} // namespace SIMDJSON_IMPLEMENTATION
|
||||
} // namespace simdjson
|
||||
|
||||
#endif // SIMDJSON_ARM64_BITMANIPULATION_H
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
#ifndef SIMDJSON_ARM64_BITMASK_H
|
||||
#define SIMDJSON_ARM64_BITMASK_H
|
||||
|
||||
#ifndef SIMDJSON_CONDITIONAL_INCLUDE
|
||||
#include "simdjson/arm64/base.h"
|
||||
#endif // SIMDJSON_CONDITIONAL_INCLUDE
|
||||
|
||||
namespace simdjson {
|
||||
namespace arm64 {
|
||||
namespace SIMDJSON_IMPLEMENTATION {
|
||||
namespace {
|
||||
|
||||
//
|
||||
|
||||
@@ -1,6 +1 @@
|
||||
#ifndef SIMDJSON_CONDITIONAL_INCLUDE
|
||||
#include "simdjson/arm64/base.h"
|
||||
#endif // SIMDJSON_CONDITIONAL_INCLUDE
|
||||
|
||||
#undef SIMDJSON_SKIP_BACKSLASH_SHORT_CIRCUIT
|
||||
#undef SIMDJSON_IMPLEMENTATION
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
#ifndef SIMDJSON_ARM64_IMPLEMENTATION_H
|
||||
#define SIMDJSON_ARM64_IMPLEMENTATION_H
|
||||
|
||||
#ifndef SIMDJSON_CONDITIONAL_INCLUDE
|
||||
#include "simdjson/base.h"
|
||||
#ifndef SIMDJSON_AMALGAMATED
|
||||
#include "simdjson/implementation.h"
|
||||
#include "simdjson/internal/instruction_set.h"
|
||||
#endif // SIMDJSON_CONDITIONAL_INCLUDE
|
||||
#endif // SIMDJSON_AMALGAMATED
|
||||
|
||||
namespace simdjson {
|
||||
namespace arm64 {
|
||||
|
||||
@@ -1,14 +1,12 @@
|
||||
#ifndef SIMDJSON_ARM64_INTRINSICS_H
|
||||
#define SIMDJSON_ARM64_INTRINSICS_H
|
||||
|
||||
#ifndef SIMDJSON_CONDITIONAL_INCLUDE
|
||||
#include "simdjson/arm64/base.h"
|
||||
#endif // SIMDJSON_CONDITIONAL_INCLUDE
|
||||
|
||||
// This should be the correct header whether
|
||||
// you use visual studio or other compilers.
|
||||
#include <arm_neon.h>
|
||||
|
||||
#include "simdjson/arm64/base.h"
|
||||
|
||||
static_assert(sizeof(uint8x16_t) <= simdjson::SIMDJSON_PADDING, "insufficient padding for arm64");
|
||||
|
||||
#endif // SIMDJSON_ARM64_INTRINSICS_H
|
||||
|
||||
@@ -1,21 +1,22 @@
|
||||
#ifndef SIMDJSON_ARM64_NUMBERPARSING_DEFS_H
|
||||
#define SIMDJSON_ARM64_NUMBERPARSING_DEFS_H
|
||||
|
||||
#ifndef SIMDJSON_CONDITIONAL_INCLUDE
|
||||
#include "simdjson/arm64/base.h"
|
||||
#include "simdjson/arm64/intrinsics.h"
|
||||
#include "simdjson/internal/numberparsing_tables.h"
|
||||
#endif // SIMDJSON_CONDITIONAL_INCLUDE
|
||||
|
||||
#include <cstring>
|
||||
|
||||
#if _M_ARM64
|
||||
// __umulh requires intrin.h
|
||||
#include <intrin.h>
|
||||
#endif // _M_ARM64
|
||||
|
||||
#include <cstring>
|
||||
|
||||
#ifndef SIMDJSON_AMALGAMATED
|
||||
#include "simdjson/internal/numberparsing_tables.h"
|
||||
#endif // SIMDJSON_AMALGAMATED
|
||||
|
||||
namespace simdjson {
|
||||
namespace arm64 {
|
||||
namespace SIMDJSON_IMPLEMENTATION {
|
||||
namespace numberparsing {
|
||||
|
||||
// we don't have SSE, so let us use a scalar function
|
||||
@@ -48,7 +49,7 @@ simdjson_inline internal::value128 full_multiplication(uint64_t value1, uint64_t
|
||||
}
|
||||
|
||||
} // namespace numberparsing
|
||||
} // namespace arm64
|
||||
} // namespace SIMDJSON_IMPLEMENTATION
|
||||
} // namespace simdjson
|
||||
|
||||
#define SIMDJSON_SWAR_NUMBER_PARSING 1
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user