mirror of
https://github.com/simdjson/simdjson
synced 2026-06-08 17:27:07 +00:00
Compare commits
110 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 8149284602 | |||
| 0e28a8312d | |||
| 04ab4bb4d9 | |||
| 3960880a0d | |||
| e0f906da79 | |||
| 6a054395a6 | |||
| eac04c7324 | |||
| 319b10acad | |||
| d2d15255bc | |||
| 5b7acd2aa7 | |||
| 61ef447595 | |||
| b524e29576 | |||
| a7b7bc2b69 | |||
| 76dd137c87 | |||
| 52b2414281 | |||
| 5d762fb67f | |||
| 9dc70e8d9c | |||
| 589ef23b56 | |||
| 4b1148384e | |||
| 32afd34a90 | |||
| 70674d2dbd | |||
| f594a49a4b | |||
| 54cbebfd29 | |||
| c6e43a631c | |||
| a8635c9b89 | |||
| 075bfb173b | |||
| a88ad515c2 | |||
| 78b4c0aa6e | |||
| 14ec0ca8f4 | |||
| 8dabd02c3a | |||
| c9692005fd | |||
| 2e0a9397c9 | |||
| f7922075c3 | |||
| b2e20e04c9 | |||
| adc9d18efd | |||
| bf849e3619 | |||
| c09e8dc225 | |||
| 5bf585ef02 | |||
| caff09cafc | |||
| f043db4dca | |||
| e3bd0828d1 | |||
| 9408298e0e | |||
| 573bbac2d2 | |||
| ac78c625df | |||
| 390a66c6e8 | |||
| 210e0a56a1 | |||
| 084f662f32 | |||
| c878ff2500 | |||
| 06afe9ecb3 | |||
| e658502adb | |||
| 6e7d415040 | |||
| 2ccd5b9c97 | |||
| 1cdcbf79b3 | |||
| 7013ed98cc | |||
| b383c717d7 | |||
| b8743bced0 | |||
| ae9ba2bed2 | |||
| 939844d79f | |||
| 4f4e81668e | |||
| bb54946b78 | |||
| 4dec6ed5a7 | |||
| 1dfd48195d | |||
| 23afc6b695 | |||
| e3cac71afe | |||
| cbe562c1d5 | |||
| 30437d0ff6 | |||
| 1e97af7dfb | |||
| 80bc9e5051 | |||
| a74e87df17 | |||
| 3274299647 | |||
| 22ca25faa6 | |||
| 37399fd41b | |||
| a170145d5b | |||
| 7d1d635883 | |||
| ddfa8ae928 | |||
| 25dfb078c7 | |||
| 9f0710e3ad | |||
| 19b9cd9b05 | |||
| 7540248396 | |||
| ab09e96de9 | |||
| 66252e4925 | |||
| 944778c186 | |||
| 62868a2f53 | |||
| 3c446c551b | |||
| efe3d4b7d7 | |||
| 28db262b47 | |||
| bf076bfb5f | |||
| 7bf1ecff9e | |||
| e25a40facf | |||
| a442842f0d | |||
| 421ed4f390 | |||
| 7dff5fa37c | |||
| 9a0527c380 | |||
| b160cf0610 | |||
| 553ee69b7c | |||
| bf70cd0ebf | |||
| cf0551edf5 | |||
| ddb094d550 | |||
| 975fdda03c | |||
| c5c43e9c7f | |||
| 031ee32969 | |||
| b613326d69 | |||
| 53dad74d8e | |||
| e4da19f5cf | |||
| 342b58986a | |||
| 7edc475886 | |||
| d2f8e84fc1 | |||
| 08000518cb | |||
| 90040d96a5 | |||
| 2934892c0b |
@@ -0,0 +1,46 @@
|
||||
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
|
||||
- misc-unused-using-decls
|
||||
- misc-definitions-in-headers # TODO fix and remove these violations
|
||||
---
|
||||
If:
|
||||
PathMatch:
|
||||
- include/.*
|
||||
- src/.*
|
||||
PathExclude:
|
||||
- include/simdjson.h
|
||||
- src/simdjson.cpp
|
||||
CompileFlags:
|
||||
Add:
|
||||
- -Wno-unneeded-internal-declaration
|
||||
- -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
|
||||
@@ -49,7 +49,7 @@ It is fine to report bugs against our main branch, but if that is what you are d
|
||||
- Version [e.g. 22]
|
||||
- Optimization setting (e.g., -O3)
|
||||
|
||||
We support up-to-date 64-bit ARM and x64 FreeBSD, macOS, Windows and Linux systems. Please ensure that your configuration is supported before labelling the issue as a bug. In particular, we do not support legacy 32-bit systems.
|
||||
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.
|
||||
|
||||
**Indicate whether you are willing or able to provide a bug fix as a pull request**
|
||||
|
||||
|
||||
@@ -31,4 +31,4 @@ jobs:
|
||||
./alpine.sh cmake --build build_for_alpine
|
||||
- name: test
|
||||
run: |
|
||||
./alpine.sh bash -c "cd build_for_alpine && ctest -LE explicitonly"
|
||||
./alpine.sh bash -c "cd build_for_alpine && ctest -LE explicitonly --output-on-failure"
|
||||
|
||||
@@ -34,6 +34,7 @@ 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
|
||||
|
||||
@@ -124,7 +125,7 @@ jobs:
|
||||
done
|
||||
|
||||
- name: Save the corpus as a github artifact
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: corpus
|
||||
path: corpus.tar
|
||||
@@ -147,7 +148,7 @@ jobs:
|
||||
run: tar cf valgrind.tar valgrind-*.txt
|
||||
|
||||
- name: Save valgrind output as a github artifact
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v3
|
||||
if: always()
|
||||
with:
|
||||
name: valgrindresults
|
||||
@@ -155,7 +156,7 @@ jobs:
|
||||
if-no-files-found: ignore
|
||||
|
||||
- name: Archive any crashes as an artifact
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v3
|
||||
if: always()
|
||||
with:
|
||||
name: crashes
|
||||
|
||||
@@ -20,13 +20,13 @@ jobs:
|
||||
cd builddebug &&
|
||||
cmake -DCMAKE_BUILD_TYPE=Debug -DSIMDJSON_GOOGLE_BENCHMARKS=OFF -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF .. &&
|
||||
cmake --build . &&
|
||||
ctest -j --output-on-failure -LE explicitonly &&
|
||||
ctest --output-on-failure -LE explicitonly -j &&
|
||||
cd .. &&
|
||||
mkdir build &&
|
||||
cd build &&
|
||||
cmake -DSIMDJSON_GOOGLE_BENCHMARKS=ON -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF -DCMAKE_INSTALL_PREFIX:PATH=destination .. &&
|
||||
cmake --build . &&
|
||||
ctest -j --output-on-failure -LE explicitonly &&
|
||||
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 &&
|
||||
|
||||
@@ -15,7 +15,7 @@ jobs:
|
||||
runs-on: ubuntu-20.04
|
||||
name: Build on ubuntu-20.04 ppc64le
|
||||
steps:
|
||||
- uses: actions/checkout@v2.1.0
|
||||
- uses: actions/checkout@v3
|
||||
- uses: uraimo/run-on-arch-action@v2.0.5
|
||||
name: Run commands
|
||||
id: runcmd
|
||||
|
||||
@@ -25,13 +25,13 @@ jobs:
|
||||
cd builddebug &&
|
||||
cmake -DCMAKE_BUILD_TYPE=Debug -DSIMDJSON_GOOGLE_BENCHMARKS=OFF -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF .. &&
|
||||
cmake --build . &&
|
||||
ctest -j --output-on-failure -LE explicitonly &&
|
||||
ctest --output-on-failure -LE explicitonly -j &&
|
||||
cd .. &&
|
||||
mkdir build &&
|
||||
cd build &&
|
||||
cmake -DSIMDJSON_GOOGLE_BENCHMARKS=ON -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF -DCMAKE_INSTALL_PREFIX:PATH=destination .. &&
|
||||
cmake --build . &&
|
||||
ctest -j --output-on-failure -LE explicitonly &&
|
||||
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 &&
|
||||
|
||||
@@ -20,13 +20,13 @@ jobs:
|
||||
cd builddebug &&
|
||||
cmake -DCMAKE_BUILD_TYPE=Debug -DSIMDJSON_GOOGLE_BENCHMARKS=OFF -DSIMDJSON_DEVELOPER_MODE=ON -DSIMDJSON_EXCEPTIONS=OFF -DBUILD_SHARED_LIBS=OFF .. &&
|
||||
cmake --build . &&
|
||||
ctest -j --output-on-failure -LE explicitonly &&
|
||||
ctest --output-on-failure -LE explicitonly -j &&
|
||||
cd .. &&
|
||||
mkdir build &&
|
||||
cd build &&
|
||||
cmake -DSIMDJSON_DEVELOPER_MODE=ON -DSIMDJSON_GOOGLE_BENCHMARKS=ON -DSIMDJSON_GOOGLE_BENCHMARKS=ON -DSIMDJSON_EXCEPTIONS=OFF -DBUILD_SHARED_LIBS=OFF -DCMAKE_INSTALL_PREFIX:PATH=destination .. &&
|
||||
cmake --build . &&
|
||||
ctest -j --output-on-failure -LE explicitonly &&
|
||||
ctest --output-on-failure -LE explicitonly -j &&
|
||||
make 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 &&
|
||||
mkdir testfindpackage &&
|
||||
|
||||
@@ -20,13 +20,13 @@ jobs:
|
||||
cd builddebug &&
|
||||
cmake -DCMAKE_BUILD_TYPE=Debug -DSIMDJSON_GOOGLE_BENCHMARKS=OFF -DSIMDJSON_ENABLE_THREADS=OFF -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF .. &&
|
||||
cmake --build . &&
|
||||
ctest -j --output-on-failure -LE explicitonly &&
|
||||
ctest --output-on-failure -LE explicitonly -j &&
|
||||
cd .. &&
|
||||
mkdir build &&
|
||||
cd build &&
|
||||
cmake -DSIMDJSON_DEVELOPER_MODE=ON -DSIMDJSON_GOOGLE_BENCHMARKS=ON -DSIMDJSON_ENABLE_THREADS=OFF -DBUILD_SHARED_LIBS=OFF -DCMAKE_INSTALL_PREFIX:PATH=destination .. &&
|
||||
cmake --build . &&
|
||||
ctest -j --output-on-failure -LE explicitonly &&
|
||||
ctest --output-on-failure -LE explicitonly -j &&
|
||||
make 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 &&
|
||||
mkdir testfindpackage &&
|
||||
|
||||
@@ -3,7 +3,7 @@ name: Ubuntu 20.04 CI (GCC 9) With Memory Sanitizer
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
ubuntu-build:
|
||||
ubuntu-build-address-sanitizier:
|
||||
if: >-
|
||||
! contains(toJSON(github.event.commits.*.message), '[skip ci]') &&
|
||||
! contains(toJSON(github.event.commits.*.message), '[skip github]')
|
||||
@@ -20,11 +20,23 @@ jobs:
|
||||
cd builddebug &&
|
||||
cmake -DSIMDJSON_SANITIZE=ON -DCMAKE_BUILD_TYPE=Debug -DSIMDJSON_GOOGLE_BENCHMARKS=OFF -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF .. &&
|
||||
cmake --build . &&
|
||||
ctest -j --output-on-failure -LE explicitonly
|
||||
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@v3
|
||||
- uses: actions/cache@v3
|
||||
with:
|
||||
path: dependencies/.cache
|
||||
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
||||
ctest --output-on-failure -LE explicitonly -j
|
||||
- name: Use cmake with undefined sanitizer
|
||||
run: |
|
||||
mkdir builddebugundefsani &&
|
||||
cd builddebugundefsani &&
|
||||
cmake -DSIMDJSON_SANITIZE_UNDEFINED=ON -DCMAKE_BUILD_TYPE=Debug -DSIMDJSON_GOOGLE_BENCHMARKS=OFF -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF .. &&
|
||||
cmake --build . &&
|
||||
ctest -j --output-on-failure -LE explicitonly
|
||||
ctest --output-on-failure -LE explicitonly -j
|
||||
|
||||
@@ -14,19 +14,33 @@ jobs:
|
||||
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 &&
|
||||
cd builddebug &&
|
||||
cmake -DCMAKE_BUILD_TYPE=Debug -DSIMDJSON_GOOGLE_BENCHMARKS=OFF -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF .. &&
|
||||
cmake --build . &&
|
||||
ctest -j --output-on-failure -LE explicitonly &&
|
||||
ctest --output-on-failure -LE explicitonly -j &&
|
||||
cd .. &&
|
||||
mkdir build &&
|
||||
cd build &&
|
||||
cmake -DSIMDJSON_GOOGLE_BENCHMARKS=ON -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF -DCMAKE_INSTALL_PREFIX:PATH=destination .. &&
|
||||
cmake --build . &&
|
||||
ctest -j --output-on-failure -LE explicitonly &&
|
||||
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 &&
|
||||
|
||||
@@ -14,12 +14,10 @@ jobs:
|
||||
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 &&
|
||||
cd build &&
|
||||
CXX=clang++-13 cmake -DSIMDJSON_DEVELOPER_MODE=ON .. &&
|
||||
cmake --build . &&
|
||||
ctest -j --output-on-failure -LE explicitonly
|
||||
ctest --output-on-failure -LE explicitonly -j
|
||||
@@ -14,12 +14,10 @@ jobs:
|
||||
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 &&
|
||||
cd build &&
|
||||
CXX=clang++-14 cmake -DSIMDJSON_DEVELOPER_MODE=ON .. &&
|
||||
cmake --build . &&
|
||||
ctest -j --output-on-failure -LE explicitonly
|
||||
ctest --output-on-failure -LE explicitonly -j
|
||||
|
||||
@@ -9,8 +9,8 @@ jobs:
|
||||
! contains(toJSON(github.event.commits.*.message), '[skip github]')
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/cache@v2
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/cache@v3
|
||||
with:
|
||||
path: dependencies/.cache
|
||||
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
||||
@@ -20,13 +20,13 @@ jobs:
|
||||
cd builddebug &&
|
||||
CXX=g++-12 cmake -DSIMDJSON_CXX_STANDARD=20 -DCMAKE_BUILD_TYPE=Debug -DSIMDJSON_GOOGLE_BENCHMARKS=OFF -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF .. &&
|
||||
cmake --build . &&
|
||||
ctest -j --output-on-failure -LE explicitonly &&
|
||||
ctest --output-on-failure -LE explicitonly -j &&
|
||||
cd .. &&
|
||||
mkdir build &&
|
||||
cd build &&
|
||||
CXX=g++-12 cmake -DSIMDJSON_CXX_STANDARD=20 -DSIMDJSON_GOOGLE_BENCHMARKS=ON -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF -DCMAKE_INSTALL_PREFIX:PATH=destination .. &&
|
||||
cmake --build . &&
|
||||
ctest -j --output-on-failure -LE explicitonly &&
|
||||
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 &&
|
||||
|
||||
@@ -22,4 +22,4 @@ jobs:
|
||||
cd build &&
|
||||
CXX=g++-12 cmake -DSIMDJSON_DEVELOPER_MODE=ON .. &&
|
||||
cmake --build . &&
|
||||
ctest -j --output-on-failure -LE explicitonly
|
||||
ctest --output-on-failure -LE explicitonly -j
|
||||
+2
-2
@@ -1,4 +1,4 @@
|
||||
name: Ubuntu 20.04 CI (GCC 9) with Thread Sanitizer
|
||||
name: Ubuntu 22.04 CI (GCC 11) with Thread Sanitizer
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
@@ -7,7 +7,7 @@ jobs:
|
||||
if: >-
|
||||
! contains(toJSON(github.event.commits.*.message), '[skip ci]') &&
|
||||
! contains(toJSON(github.event.commits.*.message), '[skip github]')
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/cache@v3
|
||||
@@ -14,19 +14,33 @@ jobs:
|
||||
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 &&
|
||||
cd builddebug &&
|
||||
cmake -DCMAKE_BUILD_TYPE=Debug -DSIMDJSON_GOOGLE_BENCHMARKS=OFF -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF .. &&
|
||||
cmake --build . &&
|
||||
ctest -j --output-on-failure -LE explicitonly &&
|
||||
ctest --output-on-failure -LE explicitonly -j &&
|
||||
cd .. &&
|
||||
mkdir build &&
|
||||
cd build &&
|
||||
cmake -DSIMDJSON_GOOGLE_BENCHMARKS=ON -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF -DCMAKE_INSTALL_PREFIX:PATH=destination .. &&
|
||||
cmake --build . &&
|
||||
ctest -j --output-on-failure -LE explicitonly &&
|
||||
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 &&
|
||||
|
||||
@@ -19,7 +19,7 @@ jobs:
|
||||
- {gen: Visual Studio 17 2022, arch: x64, shared: OFF}
|
||||
steps:
|
||||
- name: checkout
|
||||
uses: actions/checkout@v2
|
||||
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
|
||||
|
||||
@@ -104,3 +104,6 @@ objs
|
||||
!.vscode/tasks.json
|
||||
!.vscode/launch.json
|
||||
!.vscode/extensions.json
|
||||
|
||||
# clangd
|
||||
.cache
|
||||
Vendored
+8
-3
@@ -4,10 +4,15 @@
|
||||
|
||||
// List of extensions which should be recommended for users of this workspace.
|
||||
"recommendations": [
|
||||
// Syntax
|
||||
"ms-vscode.cpptools",
|
||||
"ms-vscode.cmake-tools",
|
||||
// C++
|
||||
"llvm-vs-code-extensions.vscode-clangd",
|
||||
"xaver.clang-format",
|
||||
// Python
|
||||
"ms-python.python",
|
||||
// .github/*
|
||||
"github.vscode-github-actions",
|
||||
// cmake
|
||||
"ms-vscode.cmake-tools",
|
||||
"twxs.cmake"
|
||||
],
|
||||
// List of extensions recommended by VS Code that should not be recommended for users of this workspace.
|
||||
|
||||
Vendored
+1
@@ -5,6 +5,7 @@
|
||||
],
|
||||
"files.trimTrailingWhitespace": true,
|
||||
"files.associations": {
|
||||
".clangd": "yaml",
|
||||
"array": "cpp",
|
||||
"iterator": "cpp",
|
||||
"chrono": "cpp",
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@ cmake_minimum_required(VERSION 3.14)
|
||||
project(
|
||||
simdjson
|
||||
# The version number is modified by tools/release.py
|
||||
VERSION 3.2.0
|
||||
VERSION 3.2.3
|
||||
DESCRIPTION "Parsing gigabytes of JSON per second"
|
||||
HOMEPAGE_URL "https://simdjson.org/"
|
||||
LANGUAGES CXX C
|
||||
|
||||
@@ -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.2.0"
|
||||
PROJECT_NUMBER = "3.2.3"
|
||||
|
||||
# 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
|
||||
|
||||
+35
-17
@@ -6,16 +6,26 @@ Here is wisdom about how to build, test and run simdjson from within the reposit
|
||||
|
||||
If you plan to contribute to simdjson, please read our [CONTRIBUTING](https://github.com/simdjson/simdjson/blob/master/CONTRIBUTING.md) guide.
|
||||
|
||||
|
||||
- [Hacking simdjson](#hacking-simdjson)
|
||||
- [Build Quickstart](#build-quickstart)
|
||||
- [Design notes](#design-notes)
|
||||
- [Developer mode](#developer-mode)
|
||||
- [Directory Structure and Source](#directory-structure-and-source)
|
||||
- [Runtime Dispatching](#runtime-dispatching)
|
||||
- [Regenerating Single-Header Files](#regenerating-single-header-files)
|
||||
- [Usage (CMake on 64-bit platforms like Linux, FreeBSD or macOS)](#usage-cmake-on-64-bit-platforms-like-linux-freebsd-or-macos)
|
||||
- [Usage (CMake on 64-bit Windows using Visual Studio 2019)](#usage-cmake-on-64-bit-windows-using-visual-studio-2019)
|
||||
- [Usage (CMake on 64-bit Windows using Visual Studio 2019 or better)](#usage-cmake-on-64-bit-windows-using-visual-studio-2019-or-better)
|
||||
- [Various References](#various-references)
|
||||
|
||||
Build Quickstart
|
||||
------------------------------
|
||||
|
||||
```bash
|
||||
mkdir build
|
||||
cd build
|
||||
cmake -D SIMDJSON_DEVELOPER_MODE=ON ..
|
||||
cmake --build .
|
||||
```
|
||||
|
||||
Design notes
|
||||
------------------------------
|
||||
@@ -63,26 +73,34 @@ simdjson's source structure, from the top level, looks like this:
|
||||
|
||||
* **CMakeLists.txt:** The main build system.
|
||||
* **include:** User-facing declarations and inline definitions (most user-facing functions are inlined).
|
||||
* simdjson.h: A "main include" that includes files from include/simdjson/. This is equivalent to
|
||||
* simdjson.h: the `simdjson` namespace. A "main include" that includes files from include/simdjson/. This is equivalent to
|
||||
the distributed simdjson.h.
|
||||
* simdjson/*.h: Declarations for public simdjson classes and functions.
|
||||
* simdjson/*-inl.h: Definitions for public simdjson classes and functions.
|
||||
* simdjson/*.h: Declarations for public simdjson classes and functions.
|
||||
* simdjson/*-inl.h: Definitions for public simdjson classes and functions.
|
||||
* 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>` 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.
|
||||
* simdjson/generic/amalgamated.h: all generic ondemand classes for an implementation.
|
||||
* simdjson/ondemand.h: the `simdjson::ondemand` namespace. Includes all public ondemand classes.
|
||||
* simdjson/builtin.h: the `simdjson::builtin` namespace. Aliased to the most universal implementation available.
|
||||
* simdjson/builtin/ondemand.h: the `simdjson::builtin::ondemand` namespace.
|
||||
* simdjson/arm64|fallback|haswell|icelake|ppc64|westmere/ondemand.h: the `simdjson::<implementation>::ondemand` namespace. on demand compiled for the specific implementation.
|
||||
* simdjson/generic/ondemand/*.h: individual on demand classes, generically written.
|
||||
* simdjson/generic/ondemand/dependencies.h: dependencies on common, non-implementation-specific simdjson classes. This will be included before including amalgamated.h.
|
||||
* simdjson/generic/ondemand/amalgamated.h: all generic ondemand classes for an implementation.
|
||||
* **src:** The source files for non-inlined functionality (e.g. the architecture-specific parser
|
||||
implementations).
|
||||
* simdjson.cpp: A "main source" that includes all implementation files from src/. This is
|
||||
equivalent to the distributed simdjson.cpp.
|
||||
* arm64/|fallback/|haswell/|ppc64/|westmere/: Architecture-specific implementations. All functions are
|
||||
Each architecture defines its own namespace, e.g. simdjson::haswell.
|
||||
* generic/: Generic implementations of the simdjson parser. These files may be included and
|
||||
compiled multiple times, from whichever architectures use them. They assume they are already
|
||||
enclosed in a namespace, e.g.:
|
||||
```c++
|
||||
namespace simdjson {
|
||||
namespace haswell {
|
||||
#include "generic/stage1/json_structural_indexer.h"
|
||||
}
|
||||
}
|
||||
```
|
||||
* *.cpp: other misc. implementations, such as `simdjson::implementation` and the minifier.
|
||||
* arm64|fallback|haswell|icelake|ppc64|westmere.cpp: Architecture-specific parser implementations.
|
||||
* generic/*.h: `simdjson::<implementation>` namespace. Generic implementation of the parser, particularly the `dom_parser_implementation`.
|
||||
* generic/stage1/*.h: `simdjson::<implementation>::stage1` namespace. Generic implementation of the simd-heavy tokenizer/indexer pass of the simdjson parser. Used for the On Demand interface
|
||||
* generic/stage2/*.h: `simdjson::<implementation>::stage2` namespace. Generic implementation of the tape creator, which consumes the index from stage 1 and actually parses numbers and string and such. Used for the DOM interface.
|
||||
|
||||
Other important files and directories:
|
||||
* **.drone.yml:** Definitions for Drone CI.
|
||||
|
||||
@@ -57,6 +57,7 @@ Real-world usage
|
||||
- [fastgltf](https://github.com/spnda/fastgltf)
|
||||
- [vast](https://github.com/tenzir/vast)
|
||||
- [ada-url](https://github.com/ada-url/ada)
|
||||
- [fastgron](https://github.com/adamritter/fastgron)
|
||||
|
||||
If you are planning to use simdjson in a product, please work from one of our releases.
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
+13
-9
@@ -445,7 +445,7 @@ struct benchmarker {
|
||||
return 100.0 * a / b;
|
||||
}
|
||||
|
||||
void print(bool tabbed_output) const {
|
||||
void print(bool tabbed_output, bool stage1_only) const {
|
||||
if (tabbed_output) {
|
||||
char* filename_copy = reinterpret_cast<char*>(malloc(strlen(filename)+1));
|
||||
SIMDJSON_PUSH_DISABLE_WARNINGS
|
||||
@@ -503,17 +503,21 @@ struct benchmarker {
|
||||
stats->blocks_with_16_structurals_flipped, percent(stats->blocks_with_16_structurals_flipped, stats->blocks));
|
||||
}
|
||||
printf("\n");
|
||||
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);
|
||||
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("|- Stage 1\n");
|
||||
print_aggregate("| ", stage1.best);
|
||||
printf("|- Stage 2\n");
|
||||
print_aggregate("| ", stage2.best);
|
||||
if(!stage1_only) {
|
||||
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;
|
||||
|
||||
@@ -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);
|
||||
benchmarkers[i]->print(options.tabbed_output, options.stage1_only);
|
||||
delete benchmarkers[i];
|
||||
}
|
||||
|
||||
|
||||
@@ -34,11 +34,15 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "linux-perf-events.h"
|
||||
#ifdef __linux__
|
||||
#include "linux-perf-events.h"
|
||||
#include <libgen.h>
|
||||
#endif
|
||||
|
||||
#if __APPLE__ && __aarch64__
|
||||
#include "apple/apple_arm_events.h"
|
||||
#endif
|
||||
|
||||
#include "simdjson.h"
|
||||
|
||||
using std::string;
|
||||
@@ -134,7 +138,7 @@ struct event_collector {
|
||||
|
||||
#if defined(__linux__)
|
||||
LinuxEvents<PERF_TYPE_HARDWARE> linux_events;
|
||||
event_collector(simdjson_unused bool quiet = false) : linux_events(vector<int>{
|
||||
event_collector() : linux_events(vector<int>{
|
||||
#if SIMDJSON_SIMPLE_PERFORMANCE_COUNTERS
|
||||
PERF_COUNT_HW_CPU_CYCLES,
|
||||
PERF_COUNT_HW_INSTRUCTIONS,
|
||||
@@ -149,8 +153,17 @@ 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(simdjson_unused bool _quiet = false) {}
|
||||
event_collector() {}
|
||||
bool has_events() {
|
||||
return false;
|
||||
}
|
||||
@@ -159,6 +172,8 @@ 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();
|
||||
}
|
||||
@@ -166,6 +181,16 @@ 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;
|
||||
|
||||
@@ -15,7 +15,7 @@ struct simdjsondom2msgpack {
|
||||
* @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, writting to the temporary buffer
|
||||
* @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);
|
||||
|
||||
@@ -36,7 +36,7 @@ struct simdjson2msgpack {
|
||||
* @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, writting to the temporary buffer
|
||||
* @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);
|
||||
|
||||
@@ -19,7 +19,7 @@ void maybe_display_implementation() {
|
||||
template<typename B, typename R> static void run_json_benchmark(benchmark::State &state) {
|
||||
maybe_display_implementation();
|
||||
|
||||
event_collector collector(true);
|
||||
event_collector collector;
|
||||
event_aggregate events;
|
||||
|
||||
// Warmup and equality check (make sure the data is right!)
|
||||
|
||||
@@ -117,7 +117,12 @@ 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)
|
||||
|
||||
+16
-8
@@ -335,8 +335,8 @@ support for users who avoid exceptions. See [the simdjson error handling documen
|
||||
`double(element)`. This works for `std::string_view`, double, uint64_t, int64_t, bool,
|
||||
ondemand::object and ondemand::array. We also have explicit methods such as `get_string()`, `get_double()`,
|
||||
`get_uint64()`, `get_int64()`, `get_bool()`, `get_object()` and `get_array()`. After a cast or an explicit method,
|
||||
the number, string or boolean will be parsed, or the initial `{` or `[` will be verified for ondemand::object and ondemand::array. An exception is thrown if
|
||||
the cast is not possible. Importantly, when getting an ondemand::object or ondemand::array instance, its content is
|
||||
the number, string or boolean will be parsed, or the initial `{` or `[` will be verified for `ondemand::object` and `ondemand::array`. An exception may be thrown if
|
||||
the cast is not possible: there error code is `simdjson::INCORRECT_TYPE` (see [Error Handling](#error-handling)). Importantly, when getting an ondemand::object or ondemand::array instance, its content is
|
||||
not validated: you are only guaranteed that the corresponding initial character (`{` or `[`) is present. Thus,
|
||||
for example, you could have an ondemand::object instance pointing at the invalid JSON `{ "this is not a valid object" }`: the validation occurs as you access the content.
|
||||
The `get_string()` returns a valid UTF-8 string, after
|
||||
@@ -354,8 +354,8 @@ support for users who avoid exceptions. See [the simdjson error handling documen
|
||||
> `get_string()` twice on an object (or to cast an object twice to `std::string_view`).
|
||||
* **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. 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. 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 responsability 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
|
||||
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. 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"]`.
|
||||
@@ -887,10 +887,17 @@ auto error = parser.iterate(json).get(doc);
|
||||
if (error) { cerr << error << endl; exit(1); }
|
||||
```
|
||||
|
||||
When there is no error, the error code simdjson::SUCCESS is returned: it evaluates as false as a Boolean.
|
||||
When there is no error, the error code `simdjson::SUCCESS`is returned: it evaluates as false as a Boolean.
|
||||
We have several error codes to indicate errors, they all evaluate to true as a Boolean: your software should not generally not depend on exact
|
||||
error codes. We may change the error codes in future releases and the exact error codes could vary depending on your system.
|
||||
|
||||
Some errors are recoverable:
|
||||
|
||||
* You may get the error `simdjson::INCORRECT_TYPE` after trying to convert a value to an incorrect type: e.g., you expected a number and try to convert the value to a number, but it is an array.
|
||||
* You may query a key from an object, but the key is missing in which case you get the error `simdjson::NO_SUCH_FIELD`: e.g., you call `obj["myname"]` and the object does not have a key `"myname"`.
|
||||
|
||||
Other errors (e.g., `simdjson::INCOMPLETE_ARRAY_OR_OBJECT`) may indicate a fatal error and often follow from the fact that the document is not valid JSON. In which case, it is no longer possible to continue accessing the document: calling the method `is_alive()` on the document instance returns false. All following accesses will keep returning the same fatal error (e.g., `simdjson::INCOMPLETE_ARRAY_OR_OBJECT`).
|
||||
|
||||
When you use the code without exceptions, it is your responsibility to check for error before using the
|
||||
result: if there is an error, the result value will not be valid and using it will caused undefined behavior. Most compilers should be able to help you if you activate the right
|
||||
set of warnings: they can identify variables that are written to but never otherwise accessed.
|
||||
@@ -1422,10 +1429,9 @@ This parser can't support a document that big
|
||||
|
||||
If your documents are large (e.g., larger than a megabyte), then the `iterate_many` function is maybe ill-suited. It is really meant to support reading efficiently streams of relatively small documents (e.g., a few kilobytes each). If you have larger documents, you should use other functions like `iterate`.
|
||||
|
||||
We also provide some support for comma-separated documents and other advanced features.
|
||||
See [iterate_many.md](iterate_many.md) for detailed information and design.
|
||||
|
||||
|
||||
|
||||
Parsing Numbers Inside Strings
|
||||
------------------------------
|
||||
|
||||
@@ -1948,6 +1954,8 @@ Performance Tips
|
||||
- Given a field `field` in an object, calling `field.key()` is often faster than `field.unescaped_key()` so if you do not need an unescaped `std::string_view` instance, prefer `field.key()`.
|
||||
- For release builds, we recommend setting `NDEBUG` pre-processor directive when compiling the `simdjson` library. Importantly, using the optimization flags `-O2` or `-O3` under GCC and LLVM clang does not set the `NDEBUG` directive, you must set it manually (e.g., `-DNDEBUG`).
|
||||
- For long streams of JSON documents, consider [`iterate_many`](iterate_many.md) and [`parse_many`](parse_many.md) for better performance.
|
||||
- Never seek to access a field twice (e.g., o["data"] and later again o["data"]). Instead capture once an ondemand::value and reuse it.
|
||||
- If you must access several different keys in an object, it might be preferable to iterate through all the fields in the object instead, and branch on the field keys.
|
||||
- If possible, refer to each object and array in your code once. For example, the following code repeatedly refers to the `"data"` key to create an object...
|
||||
```C++
|
||||
std::string_view make = o["data"]["make"];
|
||||
@@ -1961,4 +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. The log level is set to `INFO` by default, but can be modified with the environment variable `SIMDJSON_LOG_LEVEL`. Setting the environment variable `SIMDJSON_LOG_LEVEL` to `ERROR` will log only errors.
|
||||
- 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.
|
||||
+1
-1
@@ -105,7 +105,7 @@ Once you have an element, you can navigate it with idiomatic C++ iterators, oper
|
||||
with the `size()` method.
|
||||
* **Checking an Element Type:** You can check an element's type with `element.type()`. It
|
||||
returns an `element_type` with values such as `simdjson::dom::element_type::ARRAY`, `simdjson::dom::element_type::OBJECT`, `simdjson::dom::element_type::INT64`, `simdjson::dom::element_type::UINT64`,`simdjson::dom::element_type::DOUBLE`, `simdjson::dom::element_type::STRING`, `simdjson::dom::element_type::BOOL` or, `simdjson::dom::element_type::NULL_VALUE`.
|
||||
* **Output to streams and strings:** Given a document or an element (or node) out of a JSON document, you can output a minified string version using the C++ stream idiom (`out << element`). You can also request the construction of a minified string version (`simdjson::minify(element)`). Numbers are serialized as 64-bit floating-point numbers (`double`).
|
||||
* **Output to streams and strings:** Given a document or an element (or node) out of a JSON document, you can output a minified string version using the C++ stream idiom (`out << element`). You can also request the construction of a minified string version (`simdjson::minify(element)`) or a prettified string version (`simdjson::prettify(element)`). Numbers are serialized as 64-bit floating-point numbers (`double`).
|
||||
|
||||
### Examples
|
||||
|
||||
|
||||
+48
-2
@@ -17,6 +17,9 @@ Contents
|
||||
|
||||
- [Motivations](#motivations)
|
||||
- [How it works](#how-it-works)
|
||||
- [Context](#context)
|
||||
- [Design](#design)
|
||||
- [Threads](#threads)
|
||||
- [Support](#support)
|
||||
- [API](#api)
|
||||
- [Use cases](#use-cases)
|
||||
@@ -129,6 +132,18 @@ Some official formats **(non-exhaustive list)**:
|
||||
API
|
||||
---
|
||||
|
||||
Example:
|
||||
|
||||
```c++
|
||||
auto json = R"({ "foo": 1 } { "foo": 2 } { "foo": 3 } )"_padded;
|
||||
ondemand::parser parser;
|
||||
ondemand::document_stream docs = parser.iterate_many(json);
|
||||
for (auto doc : docs) {
|
||||
std::cout << doc["foo"] << std::endl;
|
||||
}
|
||||
// Prints 1 2 3
|
||||
```
|
||||
|
||||
See [basics.md](basics.md#newline-delimited-json-ndjson-and-json-lines) for an overview of the API.
|
||||
|
||||
## Use cases
|
||||
@@ -238,7 +253,38 @@ This will print:
|
||||
|
||||
Importantly, you should only call `truncated_bytes()` after iterating through all of the documents since the stream cannot tell whether there are truncated documents at the very end when it may not have accessed that part of the data yet.
|
||||
|
||||
Comma separated documents
|
||||
Comma-separated documents
|
||||
-----------
|
||||
|
||||
`iterate_many` also takes in an option to allow parsing of comma separated documents. In this mode, the entire buffer is processed in 1 batch and batch size will be increased to be as large as the JSON passed. Therefore, the capacity of the parser has to be sufficient to support the batch size set.
|
||||
We also support comma-separated documents, but with some performance limitations. The `iterate_many` function takes in an option to allow parsing of comma separated documents (which defaults on false). In this mode, the entire buffer is processed in one batch. Therefore, the total size of the document should not exceed the maximal capacity of the parser (4 GB). This mode also effectively disallow multithreading. It is therefore mostly suitable for not "very large" inputs. In this mode, the batch_size parameter
|
||||
is effectively ignored, as it is set to at least the document size.
|
||||
|
||||
Example:
|
||||
|
||||
```C++
|
||||
auto json = R"( 1, 2, 3, 4, "a", "b", "c", {"hello": "world"} , [1, 2, 3])"_padded;
|
||||
ondemand::parser parser;
|
||||
ondemand::document_stream doc_stream;
|
||||
// We pass '32' as the batch size, but it is a bogus parameter because, since
|
||||
// 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; }
|
||||
for (auto doc : doc_stream) {
|
||||
std::cout << doc.type() << std::endl;
|
||||
}
|
||||
```
|
||||
|
||||
This will print:
|
||||
|
||||
```
|
||||
number
|
||||
number
|
||||
number
|
||||
number
|
||||
string
|
||||
string
|
||||
string
|
||||
object
|
||||
array
|
||||
```
|
||||
|
||||
+17
-1
@@ -34,8 +34,24 @@
|
||||
}
|
||||
*/
|
||||
|
||||
#include "simdjson/common_defs.h"
|
||||
|
||||
// This provides the public API for simdjson.
|
||||
// DOM and ondemand are amalgamated separately, in simdjson.h
|
||||
#include "simdjson/simdjson_version.h"
|
||||
|
||||
#include "simdjson/base.h"
|
||||
|
||||
#include "simdjson/error.h"
|
||||
#include "simdjson/error-inl.h"
|
||||
#include "simdjson/implementation.h"
|
||||
#include "simdjson/minify.h"
|
||||
#include "simdjson/padded_string.h"
|
||||
#include "simdjson/padded_string-inl.h"
|
||||
#include "simdjson/padded_string_view.h"
|
||||
#include "simdjson/padded_string_view-inl.h"
|
||||
|
||||
#include "simdjson/dom.h"
|
||||
#include "simdjson/builtin.h"
|
||||
#include "simdjson/ondemand.h"
|
||||
|
||||
#endif // SIMDJSON_H
|
||||
|
||||
@@ -1,34 +1,9 @@
|
||||
#ifndef SIMDJSON_ARM64_H
|
||||
#define SIMDJSON_ARM64_H
|
||||
|
||||
#include "simdjson/implementation-base.h"
|
||||
|
||||
#if SIMDJSON_IMPLEMENTATION_ARM64
|
||||
|
||||
namespace simdjson {
|
||||
/**
|
||||
* Implementation for NEON (ARMv8).
|
||||
*/
|
||||
namespace arm64 {
|
||||
} // namespace arm64
|
||||
} // namespace simdjson
|
||||
|
||||
#include "simdjson/arm64/implementation.h"
|
||||
|
||||
#include "simdjson/arm64/begin.h"
|
||||
|
||||
// Declarations
|
||||
#include "simdjson/generic/dom_parser_implementation.h"
|
||||
#include "simdjson/arm64/intrinsics.h"
|
||||
#include "simdjson/arm64/bitmanipulation.h"
|
||||
#include "simdjson/arm64/bitmask.h"
|
||||
#include "simdjson/arm64/simd.h"
|
||||
#include "simdjson/generic/jsoncharutils.h"
|
||||
#include "simdjson/generic/atomparsing.h"
|
||||
#include "simdjson/arm64/stringparsing.h"
|
||||
#include "simdjson/arm64/numberparsing.h"
|
||||
#include "simdjson/generic/amalgamated.h"
|
||||
#include "simdjson/generic/lookup_table.h"
|
||||
#include "simdjson/arm64/end.h"
|
||||
|
||||
#endif // SIMDJSON_IMPLEMENTATION_ARM64
|
||||
|
||||
#endif // SIMDJSON_ARM64_H
|
||||
#endif // SIMDJSON_ARM64_H
|
||||
@@ -0,0 +1,28 @@
|
||||
#ifndef SIMDJSON_ARM64_BASE_H
|
||||
#define SIMDJSON_ARM64_BASE_H
|
||||
|
||||
#ifndef SIMDJSON_CONDITIONAL_INCLUDE
|
||||
#include "simdjson/base.h"
|
||||
#endif // SIMDJSON_CONDITIONAL_INCLUDE
|
||||
|
||||
namespace simdjson {
|
||||
/**
|
||||
* Implementation for NEON (ARMv8).
|
||||
*/
|
||||
namespace arm64 {
|
||||
|
||||
class implementation;
|
||||
|
||||
namespace simd {
|
||||
|
||||
template <typename T> struct simd8;
|
||||
template <> struct simd8<bool>;
|
||||
template <> struct simd8<uint8_t>;
|
||||
template <typename T> struct simd8x64;
|
||||
|
||||
} // namespace simd
|
||||
|
||||
} // namespace arm64
|
||||
} // namespace simdjson
|
||||
|
||||
#endif // SIMDJSON_ARM64_BASE_H
|
||||
@@ -1 +1,10 @@
|
||||
#define SIMDJSON_IMPLEMENTATION arm64
|
||||
#include "simdjson/arm64/base.h"
|
||||
#include "simdjson/arm64/intrinsics.h"
|
||||
#include "simdjson/arm64/bitmask.h"
|
||||
#include "simdjson/arm64/bitmask.h"
|
||||
#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,101 +0,0 @@
|
||||
#ifndef SIMDJSON_ARM64_BITMANIPULATION_H
|
||||
#define SIMDJSON_ARM64_BITMANIPULATION_H
|
||||
|
||||
namespace simdjson {
|
||||
namespace SIMDJSON_IMPLEMENTATION {
|
||||
namespace {
|
||||
|
||||
// We sometimes call trailing_zero on inputs that are zero,
|
||||
// but the algorithms do not end up using the returned value.
|
||||
// Sadly, sanitizers are not smart enough to figure it out.
|
||||
SIMDJSON_NO_SANITIZE_UNDEFINED
|
||||
// This function can be used safely even if not all bytes have been
|
||||
// initialized.
|
||||
// See issue https://github.com/simdjson/simdjson/issues/1965
|
||||
SIMDJSON_NO_SANITIZE_MEMORY
|
||||
simdjson_inline int trailing_zeroes(uint64_t input_num) {
|
||||
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||
unsigned long ret;
|
||||
// Search the mask data from least significant bit (LSB)
|
||||
// to the most significant bit (MSB) for a set bit (1).
|
||||
_BitScanForward64(&ret, input_num);
|
||||
return (int)ret;
|
||||
#else // SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||
return __builtin_ctzll(input_num);
|
||||
#endif // SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||
}
|
||||
|
||||
/* result might be undefined when input_num is zero */
|
||||
simdjson_inline uint64_t clear_lowest_bit(uint64_t input_num) {
|
||||
return input_num & (input_num-1);
|
||||
}
|
||||
|
||||
/* result might be undefined when input_num is zero */
|
||||
simdjson_inline int leading_zeroes(uint64_t input_num) {
|
||||
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||
unsigned long leading_zero = 0;
|
||||
// Search the mask data from most significant bit (MSB)
|
||||
// to least significant bit (LSB) for a set bit (1).
|
||||
if (_BitScanReverse64(&leading_zero, input_num))
|
||||
return (int)(63 - leading_zero);
|
||||
else
|
||||
return 64;
|
||||
#else
|
||||
return __builtin_clzll(input_num);
|
||||
#endif// SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||
}
|
||||
|
||||
/* result might be undefined when input_num is zero */
|
||||
simdjson_inline int count_ones(uint64_t input_num) {
|
||||
return vaddv_u8(vcnt_u8(vcreate_u8(input_num)));
|
||||
}
|
||||
|
||||
|
||||
#if defined(__GNUC__) // catches clang and gcc
|
||||
/**
|
||||
* ARM has a fast 64-bit "bit reversal function" that is handy. However,
|
||||
* it is not generally available as an intrinsic function under Visual
|
||||
* Studio (though this might be changing). Even under clang/gcc, we
|
||||
* apparently need to invoke inline assembly.
|
||||
*/
|
||||
/*
|
||||
* We use SIMDJSON_PREFER_REVERSE_BITS as a hint that algorithms that
|
||||
* work well with bit reversal may use it.
|
||||
*/
|
||||
#define SIMDJSON_PREFER_REVERSE_BITS 1
|
||||
|
||||
/* reverse the bits */
|
||||
simdjson_inline uint64_t reverse_bits(uint64_t input_num) {
|
||||
uint64_t rev_bits;
|
||||
__asm("rbit %0, %1" : "=r"(rev_bits) : "r"(input_num));
|
||||
return rev_bits;
|
||||
}
|
||||
|
||||
/**
|
||||
* Flips bit at index 63 - lz. Thus if you have 'leading_zeroes' leading zeroes,
|
||||
* then this will set to zero the leading bit. It is possible for leading_zeroes to be
|
||||
* greating or equal to 63 in which case we trigger undefined behavior, but the output
|
||||
* of such undefined behavior is never used.
|
||||
**/
|
||||
SIMDJSON_NO_SANITIZE_UNDEFINED
|
||||
simdjson_inline uint64_t zero_leading_bit(uint64_t rev_bits, int leading_zeroes) {
|
||||
return rev_bits ^ (uint64_t(0x8000000000000000) >> leading_zeroes);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
simdjson_inline bool add_overflow(uint64_t value1, uint64_t value2, uint64_t *result) {
|
||||
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||
*result = value1 + value2;
|
||||
return *result < value1;
|
||||
#else
|
||||
return __builtin_uaddll_overflow(value1, value2,
|
||||
reinterpret_cast<unsigned long long *>(result));
|
||||
#endif
|
||||
}
|
||||
|
||||
} // unnamed namespace
|
||||
} // namespace SIMDJSON_IMPLEMENTATION
|
||||
} // namespace simdjson
|
||||
|
||||
#endif // SIMDJSON_ARM64_BITMANIPULATION_H
|
||||
@@ -1,9 +1,131 @@
|
||||
#ifndef SIMDJSON_ARM64_BITMASK_H
|
||||
#define SIMDJSON_ARM64_BITMASK_H
|
||||
|
||||
#ifndef SIMDJSON_CONDITIONAL_INCLUDE
|
||||
#include "simdjson/arm64/base.h"
|
||||
#include "simdjson/arm64/intrinsics.h"
|
||||
#endif // SIMDJSON_CONDITIONAL_INCLUDE
|
||||
|
||||
namespace simdjson {
|
||||
namespace SIMDJSON_IMPLEMENTATION {
|
||||
namespace {
|
||||
namespace arm64 {
|
||||
namespace bitmask {
|
||||
|
||||
// We sometimes call trailing_zero on inputs that are zero,
|
||||
// but the algorithms do not end up using the returned value.
|
||||
// Sadly, sanitizers are not smart enough to figure it out.
|
||||
SIMDJSON_NO_SANITIZE_UNDEFINED
|
||||
// This function can be used safely even if not all bytes have been
|
||||
// initialized.
|
||||
// See issue https://github.com/simdjson/simdjson/issues/1965
|
||||
SIMDJSON_NO_SANITIZE_MEMORY
|
||||
simdjson_inline int trailing_zeroes(uint64_t input_num) {
|
||||
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||
unsigned long ret;
|
||||
// Search the mask data from least significant bit (LSB)
|
||||
// to the most significant bit (MSB) for a set bit (1).
|
||||
_BitScanForward64(&ret, input_num);
|
||||
return (int)ret;
|
||||
#else // SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||
return __builtin_ctzll(input_num);
|
||||
#endif // SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||
}
|
||||
|
||||
/* result might be undefined when input_num is zero */
|
||||
simdjson_inline uint64_t clear_lowest_bit(uint64_t input_num) {
|
||||
return input_num & (input_num-1);
|
||||
}
|
||||
|
||||
/* result might be undefined when input_num is zero */
|
||||
simdjson_inline int leading_zeroes(uint64_t input_num) {
|
||||
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||
unsigned long leading_zero = 0;
|
||||
// Search the mask data from most significant bit (MSB)
|
||||
// to least significant bit (LSB) for a set bit (1).
|
||||
if (_BitScanReverse64(&leading_zero, input_num))
|
||||
return (int)(63 - leading_zero);
|
||||
else
|
||||
return 64;
|
||||
#else
|
||||
return __builtin_clzll(input_num);
|
||||
#endif// SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||
}
|
||||
|
||||
/* result might be undefined when input_num is zero */
|
||||
simdjson_inline int count_ones(uint64_t input_num) {
|
||||
return vaddv_u8(vcnt_u8(vcreate_u8(input_num)));
|
||||
}
|
||||
|
||||
|
||||
#if defined(__GNUC__) // catches clang and gcc
|
||||
/**
|
||||
* ARM has a fast 64-bit "bit reversal function" that is handy. However,
|
||||
* it is not generally available as an intrinsic function under Visual
|
||||
* Studio (though this might be changing). Even under clang/gcc, we
|
||||
* apparently need to invoke inline assembly.
|
||||
*/
|
||||
/*
|
||||
* We use SIMDJSON_PREFER_REVERSE_BITS as a hint that algorithms that
|
||||
* work well with bit reversal may use it.
|
||||
*/
|
||||
#define SIMDJSON_PREFER_REVERSE_BITS 1
|
||||
|
||||
/* reverse the bits */
|
||||
simdjson_inline uint64_t reverse_bits(uint64_t input_num) {
|
||||
uint64_t rev_bits;
|
||||
__asm("rbit %0, %1" : "=r"(rev_bits) : "r"(input_num));
|
||||
return rev_bits;
|
||||
}
|
||||
|
||||
/**
|
||||
* Flips bit at index 63 - lz. Thus if you have 'leading_zeroes' leading zeroes,
|
||||
* then this will set to zero the leading bit. It is possible for leading_zeroes to be
|
||||
* greating or equal to 63 in which case we trigger undefined behavior, but the output
|
||||
* of such undefined behavior is never used.
|
||||
**/
|
||||
SIMDJSON_NO_SANITIZE_UNDEFINED
|
||||
simdjson_inline uint64_t zero_leading_bit(uint64_t rev_bits, int leading_zeroes) {
|
||||
return rev_bits ^ (uint64_t(0x8000000000000000) >> leading_zeroes);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
simdjson_inline uint64_t add_carry_out(uint64_t value1, uint64_t value2, bool &carry_out) {
|
||||
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||
uint64_t result = value1 + value2;
|
||||
carry_out = result < value1;
|
||||
return result;
|
||||
#else
|
||||
unsigned long long result;
|
||||
carry_out = __builtin_uaddll_overflow(value1, value2, &result);
|
||||
return result;
|
||||
#endif
|
||||
}
|
||||
|
||||
simdjson_inline uint64_t subtract_borrow(uint64_t value1, uint64_t value2, bool &borrow) {
|
||||
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||
value2 += borrow;
|
||||
uint64_t result = value1 - value2;
|
||||
borrow = value1 > value2;
|
||||
return result;
|
||||
#else
|
||||
unsigned long long result;
|
||||
bool borrow1 = __builtin_usubll_overflow(value1, value2, &result);
|
||||
borrow = borrow1 | __builtin_usubll_overflow(result, borrow, &result);
|
||||
return result;
|
||||
#endif
|
||||
}
|
||||
|
||||
simdjson_inline uint64_t subtract_borrow_out(uint64_t value1, uint64_t value2, bool &borrow_out) {
|
||||
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||
uint64_t result = value1 - value2;
|
||||
borrow_out = result > value1;
|
||||
return result;
|
||||
#else
|
||||
unsigned long long result;
|
||||
borrow_out = __builtin_usubll_overflow(value1, value2, &result);
|
||||
return result;
|
||||
#endif
|
||||
}
|
||||
|
||||
//
|
||||
// Perform a "cumulative bitwise xor," flipping bits each time a 1 is encountered.
|
||||
|
||||
@@ -1 +1,6 @@
|
||||
#ifndef SIMDJSON_CONDITIONAL_INCLUDE
|
||||
#include "simdjson/arm64/base.h"
|
||||
#endif // SIMDJSON_CONDITIONAL_INCLUDE
|
||||
|
||||
#undef SIMDJSON_SKIP_BACKSLASH_SHORT_CIRCUIT
|
||||
#undef SIMDJSON_IMPLEMENTATION
|
||||
|
||||
@@ -1,17 +1,15 @@
|
||||
#ifndef SIMDJSON_ARM64_IMPLEMENTATION_H
|
||||
#define SIMDJSON_ARM64_IMPLEMENTATION_H
|
||||
|
||||
#ifndef SIMDJSON_CONDITIONAL_INCLUDE
|
||||
#include "simdjson/base.h"
|
||||
#include "simdjson/internal/isadetection.h"
|
||||
#include "simdjson/implementation.h"
|
||||
#include "simdjson/internal/instruction_set.h"
|
||||
#endif // SIMDJSON_CONDITIONAL_INCLUDE
|
||||
|
||||
namespace simdjson {
|
||||
namespace arm64 {
|
||||
|
||||
namespace {
|
||||
using namespace simdjson;
|
||||
using namespace simdjson::dom;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
#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>
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
#ifndef SIMDJSON_ARM64_NUMBERPARSING_H
|
||||
#define SIMDJSON_ARM64_NUMBERPARSING_H
|
||||
|
||||
namespace simdjson {
|
||||
namespace SIMDJSON_IMPLEMENTATION {
|
||||
namespace {
|
||||
|
||||
// we don't have SSE, so let us use a scalar function
|
||||
// credit: https://johnnylee-sde.github.io/Fast-numeric-string-to-int/
|
||||
static simdjson_inline uint32_t parse_eight_digits_unrolled(const uint8_t *chars) {
|
||||
uint64_t val;
|
||||
std::memcpy(&val, chars, sizeof(uint64_t));
|
||||
val = (val & 0x0F0F0F0F0F0F0F0F) * 2561 >> 8;
|
||||
val = (val & 0x00FF00FF00FF00FF) * 6553601 >> 16;
|
||||
return uint32_t((val & 0x0000FFFF0000FFFF) * 42949672960001 >> 32);
|
||||
}
|
||||
|
||||
} // unnamed namespace
|
||||
} // namespace SIMDJSON_IMPLEMENTATION
|
||||
} // namespace simdjson
|
||||
|
||||
#define SIMDJSON_SWAR_NUMBER_PARSING 1
|
||||
|
||||
#include "simdjson/generic/numberparsing.h"
|
||||
|
||||
#endif // SIMDJSON_ARM64_NUMBERPARSING_H
|
||||
@@ -0,0 +1,56 @@
|
||||
#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
|
||||
|
||||
namespace simdjson {
|
||||
namespace arm64 {
|
||||
namespace numberparsing {
|
||||
|
||||
// we don't have SSE, so let us use a scalar function
|
||||
// credit: https://johnnylee-sde.github.io/Fast-numeric-string-to-int/
|
||||
/** @private */
|
||||
static simdjson_inline uint32_t parse_eight_digits_unrolled(const uint8_t *chars) {
|
||||
uint64_t val;
|
||||
std::memcpy(&val, chars, sizeof(uint64_t));
|
||||
val = (val & 0x0F0F0F0F0F0F0F0F) * 2561 >> 8;
|
||||
val = (val & 0x00FF00FF00FF00FF) * 6553601 >> 16;
|
||||
return uint32_t((val & 0x0000FFFF0000FFFF) * 42949672960001 >> 32);
|
||||
}
|
||||
|
||||
simdjson_inline internal::value128 full_multiplication(uint64_t value1, uint64_t value2) {
|
||||
internal::value128 answer;
|
||||
#if SIMDJSON_REGULAR_VISUAL_STUDIO || SIMDJSON_IS_32BITS
|
||||
#ifdef _M_ARM64
|
||||
// ARM64 has native support for 64-bit multiplications, no need to emultate
|
||||
answer.high = __umulh(value1, value2);
|
||||
answer.low = value1 * value2;
|
||||
#else
|
||||
answer.low = _umul128(value1, value2, &answer.high); // _umul128 not available on ARM64
|
||||
#endif // _M_ARM64
|
||||
#else // SIMDJSON_REGULAR_VISUAL_STUDIO || SIMDJSON_IS_32BITS
|
||||
__uint128_t r = (static_cast<__uint128_t>(value1)) * value2;
|
||||
answer.low = uint64_t(r);
|
||||
answer.high = uint64_t(r >> 64);
|
||||
#endif
|
||||
return answer;
|
||||
}
|
||||
|
||||
} // namespace numberparsing
|
||||
} // namespace arm64
|
||||
} // namespace simdjson
|
||||
|
||||
#define SIMDJSON_SWAR_NUMBER_PARSING 1
|
||||
|
||||
#endif // SIMDJSON_ARM64_NUMBERPARSING_DEFS_H
|
||||
@@ -0,0 +1,8 @@
|
||||
#ifndef SIMDJSON_ARM64_ONDEMAND_H
|
||||
#define SIMDJSON_ARM64_ONDEMAND_H
|
||||
|
||||
#include "simdjson/arm64/begin.h"
|
||||
#include "simdjson/generic/ondemand/amalgamated.h"
|
||||
#include "simdjson/arm64/end.h"
|
||||
|
||||
#endif // SIMDJSON_ARM64_ONDEMAND_H
|
||||
+209
-55
@@ -1,15 +1,14 @@
|
||||
#ifndef SIMDJSON_ARM64_SIMD_H
|
||||
#define SIMDJSON_ARM64_SIMD_H
|
||||
|
||||
#include "simdjson/base.h"
|
||||
#ifndef SIMDJSON_CONDITIONAL_INCLUDE
|
||||
#include "simdjson/arm64/base.h"
|
||||
#include "simdjson/arm64/bitmask.h"
|
||||
#include "simdjson/internal/simdprune_tables.h"
|
||||
#include "simdjson/arm64/bitmanipulation.h"
|
||||
#include <type_traits>
|
||||
|
||||
#endif // SIMDJSON_CONDITIONAL_INCLUDE
|
||||
|
||||
namespace simdjson {
|
||||
namespace SIMDJSON_IMPLEMENTATION {
|
||||
namespace {
|
||||
namespace arm64 {
|
||||
namespace simd {
|
||||
|
||||
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||
@@ -28,7 +27,7 @@ namespace {
|
||||
* You should not use this function except for compile-time constants:
|
||||
* it is not efficient.
|
||||
*/
|
||||
simdjson_inline uint8x16_t make_uint8x16_t(uint8_t x1, uint8_t x2, uint8_t x3, uint8_t x4,
|
||||
simdjson_inline simd_t make_uint8x16_t(uint8_t x1, uint8_t x2, uint8_t x3, uint8_t x4,
|
||||
uint8_t x5, uint8_t x6, uint8_t x7, uint8_t x8,
|
||||
uint8_t x9, uint8_t x10, uint8_t x11, uint8_t x12,
|
||||
uint8_t x13, uint8_t x14, uint8_t x15, uint8_t x16) {
|
||||
@@ -36,7 +35,7 @@ simdjson_inline uint8x16_t make_uint8x16_t(uint8_t x1, uint8_t x2, uint8_t x3,
|
||||
// uint8_t array[16] = {x1, x2, x3, x4, x5, x6, x7, x8,
|
||||
// x9, x10,x11,x12,x13,x14,x15,x16};
|
||||
// return vld1q_u8(array);
|
||||
uint8x16_t x{};
|
||||
simd_t x{};
|
||||
// incredibly, Visual Studio does not allow x[0] = x1
|
||||
x = vsetq_lane_u8(x1, x, 0);
|
||||
x = vsetq_lane_u8(x2, x, 1);
|
||||
@@ -109,18 +108,28 @@ simdjson_inline int8x16_t make_int8x16_t(int8_t x1, int8_t x2, int8_t x3, int
|
||||
template<typename T>
|
||||
struct simd8;
|
||||
|
||||
#if !SIMDJSON_IS_ARM && !defined(SIMDJSON_CONDITIONAL_INCLUDE)
|
||||
// Make errors a bit more manageable when editing on non-ARM
|
||||
struct uint8x16_t { uint8_t x[16]; };
|
||||
#endif
|
||||
|
||||
//
|
||||
// Base class of simd8<uint8_t> and simd8<bool>, both of which use uint8x16_t internally.
|
||||
//
|
||||
template<typename T, typename Mask=simd8<bool>>
|
||||
struct base_u8 {
|
||||
uint8x16_t value;
|
||||
static const int SIZE = sizeof(value);
|
||||
/** The actual underlying system SIMD type. */
|
||||
using simd_t = uint8x16_t;
|
||||
static constexpr const int LANES = sizeof(simd_t);
|
||||
using bitmask_t = uint16_t;
|
||||
static_assert(sizeof(bitmask_t)*8 == LANES, "Bitmask type's bits must equal the simd type's bytes");
|
||||
|
||||
simd_t value;
|
||||
|
||||
// Conversion from/to SIMD register
|
||||
simdjson_inline base_u8(const uint8x16_t _value) : value(_value) {}
|
||||
simdjson_inline operator const uint8x16_t&() const { return this->value; }
|
||||
simdjson_inline operator uint8x16_t&() { return this->value; }
|
||||
simdjson_inline base_u8(const simd_t _value) : value(_value) {}
|
||||
simdjson_inline operator const simd_t&() const { return this->value; }
|
||||
simdjson_inline operator simd_t&() { return this->value; }
|
||||
|
||||
// Bit operations
|
||||
simdjson_inline simd8<T> operator|(const simd8<T> other) const { return vorrq_u8(*this, other); }
|
||||
@@ -132,7 +141,8 @@ simdjson_inline int8x16_t make_int8x16_t(int8_t x1, int8_t x2, int8_t x3, int
|
||||
simdjson_inline simd8<T>& operator&=(const simd8<T> other) { auto this_cast = static_cast<simd8<T>*>(this); *this_cast = *this_cast & other; return *this_cast; }
|
||||
simdjson_inline simd8<T>& operator^=(const simd8<T> other) { auto this_cast = static_cast<simd8<T>*>(this); *this_cast = *this_cast ^ other; return *this_cast; }
|
||||
|
||||
friend simdjson_inline Mask operator==(const simd8<T> lhs, const simd8<T> rhs) { return vceqq_u8(lhs, rhs); }
|
||||
simdjson_inline Mask eq(const simd8<T> rhs) const { return vceqq_u8(*this, rhs); }
|
||||
friend simdjson_inline Mask operator==(const simd8<T> lhs, const simd8<T> rhs) { return lhs.eq(rhs); }
|
||||
|
||||
template<int N=1>
|
||||
simdjson_inline simd8<T> prev(const simd8<T> prev_chunk) const {
|
||||
@@ -148,7 +158,7 @@ simdjson_inline int8x16_t make_int8x16_t(int8_t x1, int8_t x2, int8_t x3, int
|
||||
|
||||
static simdjson_inline simd8<bool> splat(bool _value) { return vmovq_n_u8(uint8_t(-(!!_value))); }
|
||||
|
||||
simdjson_inline simd8(const uint8x16_t _value) : base_u8<bool>(_value) {}
|
||||
simdjson_inline simd8(const simd_t _value) : base_u8<bool>(_value) {}
|
||||
// False constructor
|
||||
simdjson_inline simd8() : simd8(vdupq_n_u8(0)) {}
|
||||
// Splat constructor
|
||||
@@ -158,14 +168,14 @@ simdjson_inline int8x16_t make_int8x16_t(int8_t x1, int8_t x2, int8_t x3, int
|
||||
// purposes (cutting it down to uint16_t costs performance in some compilers).
|
||||
simdjson_inline uint32_t to_bitmask() const {
|
||||
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||
const uint8x16_t bit_mask = make_uint8x16_t(0x01, 0x02, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80,
|
||||
const simd_t bit_mask = make_simd_t(0x01, 0x02, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80,
|
||||
0x01, 0x02, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80);
|
||||
#else
|
||||
const uint8x16_t bit_mask = {0x01, 0x02, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80,
|
||||
const simd_t bit_mask = {0x01, 0x02, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80,
|
||||
0x01, 0x02, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80};
|
||||
#endif
|
||||
auto minput = *this & bit_mask;
|
||||
uint8x16_t tmp = vpaddq_u8(minput, minput);
|
||||
simd_t tmp = vpaddq_u8(minput, minput);
|
||||
tmp = vpaddq_u8(tmp, tmp);
|
||||
tmp = vpaddq_u8(tmp, tmp);
|
||||
return vgetq_lane_u16(vreinterpretq_u16_u8(tmp), 0);
|
||||
@@ -176,11 +186,14 @@ simdjson_inline int8x16_t make_int8x16_t(int8_t x1, int8_t x2, int8_t x3, int
|
||||
// Unsigned bytes
|
||||
template<>
|
||||
struct simd8<uint8_t>: base_u8<uint8_t> {
|
||||
static simdjson_inline uint8x16_t splat(uint8_t _value) { return vmovq_n_u8(_value); }
|
||||
static simdjson_inline uint8x16_t zero() { return vdupq_n_u8(0); }
|
||||
static simdjson_inline uint8x16_t load(const uint8_t* values) { return vld1q_u8(values); }
|
||||
using typename base_u8<uint8_t>::simd_t;
|
||||
using base_u8<uint8_t>::LANES;
|
||||
|
||||
simdjson_inline simd8(const uint8x16_t _value) : base_u8<uint8_t>(_value) {}
|
||||
static simdjson_inline simd_t splat(uint8_t _value) { return vmovq_n_u8(_value); }
|
||||
static simdjson_inline simd_t zero() { return vdupq_n_u8(0); }
|
||||
static simdjson_inline simd_t load(const uint8_t* values) { return vld1q_u8(values); }
|
||||
|
||||
simdjson_inline simd8(const simd_t _value) : base_u8<uint8_t>(_value) {}
|
||||
// Zero constructor
|
||||
simdjson_inline simd8() : simd8(zero()) {}
|
||||
// Array constructor
|
||||
@@ -200,7 +213,7 @@ simdjson_inline int8x16_t make_int8x16_t(int8_t x1, int8_t x2, int8_t x3, int
|
||||
simdjson_inline simd8(
|
||||
uint8_t v0, uint8_t v1, uint8_t v2, uint8_t v3, uint8_t v4, uint8_t v5, uint8_t v6, uint8_t v7,
|
||||
uint8_t v8, uint8_t v9, uint8_t v10, uint8_t v11, uint8_t v12, uint8_t v13, uint8_t v14, uint8_t v15
|
||||
) : simd8(uint8x16_t{
|
||||
) : simd8(simd_t{
|
||||
v0, v1, v2, v3, v4, v5, v6, v7,
|
||||
v8, v9, v10,v11,v12,v13,v14,v15
|
||||
}) {}
|
||||
@@ -254,15 +267,20 @@ simdjson_inline int8x16_t make_int8x16_t(int8_t x1, int8_t x2, int8_t x3, int
|
||||
simdjson_inline simd8<uint8_t> shl() const { return vshlq_n_u8(*this, N); }
|
||||
|
||||
// Perform a lookup assuming the value is between 0 and 16 (undefined behavior for out of range values)
|
||||
template<typename L>
|
||||
simdjson_inline simd8<L> lookup_16(simd8<L> lookup_table) const {
|
||||
simdjson_inline simd8<uint8_t> lookup_16(simd8<uint8_t> lookup_table) const {
|
||||
return lookup_table.apply_lookup_16_to(*this);
|
||||
}
|
||||
|
||||
// Perform a lookup based on the lower 4 bits of each lane. (Platform-dependent behavior for
|
||||
// non-ASCII values--may look up the lower 4 bits on some platforms, and return 0 on others.)
|
||||
simdjson_inline simd8<uint8_t> lookup_low_nibble_ascii(simd8<uint8_t> lookup_table) const {
|
||||
return lookup_table.apply_lookup_16_to(*this & 0b10001111);
|
||||
}
|
||||
|
||||
|
||||
// Copies to 'output" all bytes corresponding to a 0 in the mask (interpreted as a bitset).
|
||||
// Passing a 0 value for mask would be equivalent to writing out every byte to output.
|
||||
// Only the first 16 - count_ones(mask) bytes of the result are significant but 16 bytes
|
||||
// Only the first 16 - bitmask::count_ones(mask) bytes of the result are significant but 16 bytes
|
||||
// get written.
|
||||
// Design consideration: it seems like a function with the
|
||||
// signature simd8<L> compress(uint16_t mask) would be
|
||||
@@ -280,16 +298,16 @@ simdjson_inline int8x16_t make_int8x16_t(int8_t x1, int8_t x2, int8_t x3, int
|
||||
// thintable_epi8[mask2] into a 128-bit register, using only
|
||||
// two instructions on most compilers.
|
||||
uint64x2_t shufmask64 = {thintable_epi8[mask1], thintable_epi8[mask2]};
|
||||
uint8x16_t shufmask = vreinterpretq_u8_u64(shufmask64);
|
||||
simd_t shufmask = vreinterpretq_u8_u64(shufmask64);
|
||||
// we increment by 0x08 the second half of the mask
|
||||
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||
uint8x16_t inc = make_uint8x16_t(0, 0, 0, 0, 0, 0, 0, 0, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08);
|
||||
simd_t inc = make_uint8x16_t(0, 0, 0, 0, 0, 0, 0, 0, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08);
|
||||
#else
|
||||
uint8x16_t inc = {0, 0, 0, 0, 0, 0, 0, 0, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08};
|
||||
simd_t inc = {0, 0, 0, 0, 0, 0, 0, 0, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08};
|
||||
#endif
|
||||
shufmask = vaddq_u8(shufmask, inc);
|
||||
// this is the version "nearly pruned"
|
||||
uint8x16_t pruned = vqtbl1q_u8(*this, shufmask);
|
||||
simd_t pruned = vqtbl1q_u8(*this, shufmask);
|
||||
// we still need to put the two halves together.
|
||||
// we compute the popcount of the first half:
|
||||
int pop1 = BitsSetTable256mul2[mask1];
|
||||
@@ -297,8 +315,8 @@ simdjson_inline int8x16_t make_int8x16_t(int8_t x1, int8_t x2, int8_t x3, int
|
||||
// only the first pop1 bytes from the first 8 bytes, and then
|
||||
// it fills in with the bytes from the second 8 bytes + some filling
|
||||
// at the end.
|
||||
uint8x16_t compactmask = vld1q_u8(reinterpret_cast<const uint8_t *>(pshufb_combine_table + pop1 * 8));
|
||||
uint8x16_t answer = vqtbl1q_u8(pruned, compactmask);
|
||||
simd_t compactmask = vld1q_u8(reinterpret_cast<const uint8_t *>(pshufb_combine_table + pop1 * 8));
|
||||
simd_t answer = vqtbl1q_u8(pruned, compactmask);
|
||||
vst1q_u8(reinterpret_cast<uint8_t*>(output), answer);
|
||||
}
|
||||
|
||||
@@ -323,20 +341,6 @@ simdjson_inline int8x16_t make_int8x16_t(int8_t x1, int8_t x2, int8_t x3, int
|
||||
vst1_u8((uint8_t*)output2, vqtbl1_u8(*this, compactmask2));
|
||||
}
|
||||
|
||||
template<typename L>
|
||||
simdjson_inline simd8<L> lookup_16(
|
||||
L replace0, L replace1, L replace2, L replace3,
|
||||
L replace4, L replace5, L replace6, L replace7,
|
||||
L replace8, L replace9, L replace10, L replace11,
|
||||
L replace12, L replace13, L replace14, L replace15) const {
|
||||
return lookup_16(simd8<L>::repeat_16(
|
||||
replace0, replace1, replace2, replace3,
|
||||
replace4, replace5, replace6, replace7,
|
||||
replace8, replace9, replace10, replace11,
|
||||
replace12, replace13, replace14, replace15
|
||||
));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
simdjson_inline simd8<uint8_t> apply_lookup_16_to(const simd8<T> original) {
|
||||
return vqtbl1q_u8(*this, simd8<uint8_t>(original));
|
||||
@@ -401,7 +405,7 @@ simdjson_inline int8x16_t make_int8x16_t(int8_t x1, int8_t x2, int8_t x3, int
|
||||
// In theory, we could check this occurrence with std::same_as and std::enabled_if but it is C++14
|
||||
// and relatively ugly and hard to read.
|
||||
#ifndef SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||
simdjson_inline explicit simd8(const uint8x16_t other): simd8(vreinterpretq_s8_u8(other)) {}
|
||||
simdjson_inline explicit simd8(const simd_t other): simd8(vreinterpretq_s8_u8(other)) {}
|
||||
#endif
|
||||
simdjson_inline explicit operator simd8<uint8_t>() const { return vreinterpretq_u8_s8(this->value); }
|
||||
|
||||
@@ -424,10 +428,13 @@ simdjson_inline int8x16_t make_int8x16_t(int8_t x1, int8_t x2, int8_t x3, int
|
||||
}
|
||||
|
||||
// Perform a lookup assuming no value is larger than 16
|
||||
template<typename L>
|
||||
simdjson_inline simd8<L> lookup_16(simd8<L> lookup_table) const {
|
||||
simdjson_inline simd8<int8_t> lookup_16(simd8<int8_t> lookup_table) const {
|
||||
return lookup_table.apply_lookup_16_to(*this);
|
||||
}
|
||||
// Perform a lookup based on the lower 4 bits of each lane, returning 0 for values with a high bit of 1.
|
||||
simdjson_inline simd8<int8_t> lookup_low_nibble_ascii(simd8<int8_t> lookup_table) const {
|
||||
return lookup_table.apply_lookup_16_to(*this & 0b10001111);
|
||||
}
|
||||
template<typename L>
|
||||
simdjson_inline simd8<L> lookup_16(
|
||||
L replace0, L replace1, L replace2, L replace3,
|
||||
@@ -460,6 +467,8 @@ simdjson_inline int8x16_t make_int8x16_t(int8_t x1, int8_t x2, int8_t x3, int
|
||||
|
||||
simdjson_inline simd8x64(const simd8<T> chunk0, const simd8<T> chunk1, const simd8<T> chunk2, const simd8<T> chunk3) : chunks{chunk0, chunk1, chunk2, chunk3} {}
|
||||
simdjson_inline simd8x64(const T ptr[64]) : chunks{simd8<T>::load(ptr), simd8<T>::load(ptr+16), simd8<T>::load(ptr+32), simd8<T>::load(ptr+48)} {}
|
||||
simdjson_inline simd8x64(simd8x64<T>&& o) noexcept = default;
|
||||
simdjson_inline simd8x64<T>& operator=(simd8x64<T>&& other) noexcept = default;
|
||||
|
||||
simdjson_inline void store(T ptr[64]) const {
|
||||
this->chunks[0].store(ptr+sizeof(simd8<T>)*0);
|
||||
@@ -486,19 +495,19 @@ simdjson_inline int8x16_t make_int8x16_t(int8_t x1, int8_t x2, int8_t x3, int
|
||||
|
||||
simdjson_inline uint64_t to_bitmask() const {
|
||||
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||
const uint8x16_t bit_mask = make_uint8x16_t(
|
||||
const simd_t bit_mask = make_uint8x16_t(
|
||||
0x01, 0x02, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80,
|
||||
0x01, 0x02, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80
|
||||
);
|
||||
#else
|
||||
const uint8x16_t bit_mask = {
|
||||
const simd_t bit_mask = {
|
||||
0x01, 0x02, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80,
|
||||
0x01, 0x02, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80
|
||||
};
|
||||
#endif
|
||||
// Add each of the elements next to each other, successively, to stuff each 8 byte mask into one.
|
||||
uint8x16_t sum0 = vpaddq_u8(this->chunks[0] & bit_mask, this->chunks[1] & bit_mask);
|
||||
uint8x16_t sum1 = vpaddq_u8(this->chunks[2] & bit_mask, this->chunks[3] & bit_mask);
|
||||
simd_t sum0 = vpaddq_u8(this->chunks[0] & bit_mask, this->chunks[1] & bit_mask);
|
||||
simd_t sum1 = vpaddq_u8(this->chunks[2] & bit_mask, this->chunks[3] & bit_mask);
|
||||
sum0 = vpaddq_u8(sum0, sum1);
|
||||
sum0 = vpaddq_u8(sum0, sum0);
|
||||
return vgetq_lane_u64(vreinterpretq_u64_u8(sum0), 0);
|
||||
@@ -514,6 +523,24 @@ simdjson_inline int8x16_t make_int8x16_t(int8_t x1, int8_t x2, int8_t x3, int
|
||||
).to_bitmask();
|
||||
}
|
||||
|
||||
simdjson_inline simd8x64<T> lookup_16(const simd8<T>& lookup_table) const {
|
||||
return {
|
||||
this->chunks[0].lookup_16(lookup_table),
|
||||
this->chunks[1].lookup_16(lookup_table),
|
||||
this->chunks[2].lookup_16(lookup_table),
|
||||
this->chunks[3].lookup_16(lookup_table)
|
||||
};
|
||||
}
|
||||
|
||||
simdjson_inline simd8x64<T> lookup_low_nibble_ascii(const simd8<T>& lookup_table) const {
|
||||
return {
|
||||
this->chunks[0].lookup_low_nibble_ascii(lookup_table),
|
||||
this->chunks[1].lookup_low_nibble_ascii(lookup_table),
|
||||
this->chunks[2].lookup_low_nibble_ascii(lookup_table),
|
||||
this->chunks[3].lookup_low_nibble_ascii(lookup_table)
|
||||
};
|
||||
}
|
||||
|
||||
simdjson_inline uint64_t lteq(const T m) const {
|
||||
const simd8<T> mask = simd8<T>::splat(m);
|
||||
return simd8x64<bool>(
|
||||
@@ -523,11 +550,138 @@ simdjson_inline int8x16_t make_int8x16_t(int8_t x1, int8_t x2, int8_t x3, int
|
||||
this->chunks[3] <= mask
|
||||
).to_bitmask();
|
||||
}
|
||||
|
||||
simdjson_inline simd8x64<T> operator&(const simd8x64<T>& other) const {
|
||||
return {
|
||||
this->chunks[0] & other.chunks[0],
|
||||
this->chunks[1] & other.chunks[1],
|
||||
this->chunks[2] & other.chunks[2],
|
||||
this->chunks[3] & other.chunks[3]
|
||||
};
|
||||
}
|
||||
|
||||
simdjson_inline simd8x64<T> operator&(const simd8<T>& other) const {
|
||||
return {
|
||||
this->chunks[0] & other,
|
||||
this->chunks[1] & other,
|
||||
this->chunks[2] & other,
|
||||
this->chunks[3] & other
|
||||
};
|
||||
}
|
||||
|
||||
simdjson_inline simd8x64<T> operator|(const simd8x64<T>& other) const {
|
||||
return {
|
||||
this->chunks[0] | other.chunks[0],
|
||||
this->chunks[1] | other.chunks[1],
|
||||
this->chunks[2] | other.chunks[2],
|
||||
this->chunks[3] | other.chunks[3]
|
||||
};
|
||||
}
|
||||
|
||||
simdjson_inline simd8x64<T> operator|(const simd8<T>& other) const {
|
||||
return {
|
||||
this->chunks[0] | other,
|
||||
this->chunks[1] | other,
|
||||
this->chunks[2] | other,
|
||||
this->chunks[3] | other
|
||||
};
|
||||
}
|
||||
|
||||
simdjson_inline simd8x64<T> operator^(const simd8x64<T>& other) const {
|
||||
return {
|
||||
this->chunks[0] ^ other.chunks[0],
|
||||
this->chunks[1] ^ other.chunks[1],
|
||||
this->chunks[2] ^ other.chunks[2],
|
||||
this->chunks[3] ^ other.chunks[3]
|
||||
};
|
||||
}
|
||||
|
||||
simdjson_inline simd8x64<T> operator^(const simd8<T>& other) const {
|
||||
return {
|
||||
this->chunks[0] ^ other,
|
||||
this->chunks[1] ^ other,
|
||||
this->chunks[2] ^ other,
|
||||
this->chunks[3] ^ other
|
||||
};
|
||||
}
|
||||
|
||||
simdjson_inline simd8x64<T> bit_andnot(const simd8x64<T>& other) const {
|
||||
return {
|
||||
this->chunks[0].bit_andnot(other.chunks[0]),
|
||||
this->chunks[1].bit_andnot(other.chunks[1]),
|
||||
this->chunks[2].bit_andnot(other.chunks[2]),
|
||||
this->chunks[3].bit_andnot(other.chunks[3])
|
||||
};
|
||||
}
|
||||
|
||||
simdjson_inline simd8x64<T> bit_andnot(const simd8<T>& other) const {
|
||||
return {
|
||||
this->chunks[0].bit_andnot(other),
|
||||
this->chunks[1].bit_andnot(other),
|
||||
this->chunks[2].bit_andnot(other),
|
||||
this->chunks[3].bit_andnot(other)
|
||||
};
|
||||
}
|
||||
|
||||
template <int N>
|
||||
simdjson_inline simd8x64<T> shr() const noexcept {
|
||||
return {
|
||||
this->chunks[0].template shr<N>(),
|
||||
this->chunks[1].template shr<N>(),
|
||||
this->chunks[2].template shr<N>(),
|
||||
this->chunks[3].template shr<N>()
|
||||
};
|
||||
}
|
||||
|
||||
template <int N>
|
||||
simdjson_inline simd8x64<T> shl() const noexcept {
|
||||
return {
|
||||
this->chunks[0].template shl<N>(),
|
||||
this->chunks[1].template shl<N>(),
|
||||
this->chunks[2].template shl<N>(),
|
||||
this->chunks[3].template shl<N>()
|
||||
};
|
||||
}
|
||||
|
||||
simdjson_inline simd8x64<bool> any_bits_set(const simd8<T>& bits) const {
|
||||
return {
|
||||
this->chunks[0].any_bits_set(bits),
|
||||
this->chunks[1].any_bits_set(bits),
|
||||
this->chunks[2].any_bits_set(bits),
|
||||
this->chunks[3].any_bits_set(bits)
|
||||
};
|
||||
}
|
||||
|
||||
simdjson_inline simd8x64<bool> any_bits_set(const simd8x64<T>& bits) const {
|
||||
return {
|
||||
this->chunks[0].any_bits_set(bits.chunks[0]),
|
||||
this->chunks[1].any_bits_set(bits.chunks[1]),
|
||||
this->chunks[2].any_bits_set(bits.chunks[2]),
|
||||
this->chunks[3].any_bits_set(bits.chunks[3])
|
||||
};
|
||||
}
|
||||
|
||||
simdjson_inline simd8x64<bool> no_bits_set(const simd8<T>& bits) const {
|
||||
return {
|
||||
this->chunks[0].no_bits_set(bits),
|
||||
this->chunks[1].no_bits_set(bits),
|
||||
this->chunks[2].no_bits_set(bits),
|
||||
this->chunks[3].no_bits_set(bits)
|
||||
};
|
||||
}
|
||||
|
||||
simdjson_inline simd8x64<bool> no_bits_set(const simd8x64<T>& bits) const {
|
||||
return {
|
||||
this->chunks[0].no_bits_set(bits.chunks[0]),
|
||||
this->chunks[1].no_bits_set(bits.chunks[1]),
|
||||
this->chunks[2].no_bits_set(bits.chunks[2]),
|
||||
this->chunks[3].no_bits_set(bits.chunks[3])
|
||||
};
|
||||
}
|
||||
}; // struct simd8x64<T>
|
||||
|
||||
} // namespace simd
|
||||
} // unnamed namespace
|
||||
} // namespace SIMDJSON_IMPLEMENTATION
|
||||
} // namespace arm64
|
||||
} // namespace simdjson
|
||||
|
||||
#endif // SIMDJSON_ARM64_SIMD_H
|
||||
|
||||
+11
-9
@@ -1,12 +1,14 @@
|
||||
#ifndef SIMDJSON_ARM64_STRINGPARSING_H
|
||||
#define SIMDJSON_ARM64_STRINGPARSING_H
|
||||
#ifndef SIMDJSON_ARM64_STRINGPARSING_DEFS_H
|
||||
#define SIMDJSON_ARM64_STRINGPARSING_DEFS_H
|
||||
|
||||
#include "simdjson/base.h"
|
||||
#ifndef SIMDJSON_CONDITIONAL_INCLUDE
|
||||
#include "simdjson/arm64/base.h"
|
||||
#include "simdjson/arm64/simd.h"
|
||||
#include "simdjson/arm64/bitmanipulation.h"
|
||||
#include "simdjson/arm64/bitmask.h"
|
||||
#endif // SIMDJSON_CONDITIONAL_INCLUDE
|
||||
|
||||
namespace simdjson {
|
||||
namespace SIMDJSON_IMPLEMENTATION {
|
||||
namespace arm64 {
|
||||
namespace {
|
||||
|
||||
using namespace simd;
|
||||
@@ -19,8 +21,8 @@ public:
|
||||
|
||||
simdjson_inline bool has_quote_first() { return ((bs_bits - 1) & quote_bits) != 0; }
|
||||
simdjson_inline bool has_backslash() { return bs_bits != 0; }
|
||||
simdjson_inline int quote_index() { return trailing_zeroes(quote_bits); }
|
||||
simdjson_inline int backslash_index() { return trailing_zeroes(bs_bits); }
|
||||
simdjson_inline int quote_index() { return bitmask::trailing_zeroes(quote_bits); }
|
||||
simdjson_inline int backslash_index() { return bitmask::trailing_zeroes(bs_bits); }
|
||||
|
||||
uint32_t bs_bits;
|
||||
uint32_t quote_bits;
|
||||
@@ -45,7 +47,7 @@ simdjson_inline backslash_and_quote backslash_and_quote::copy_and_find(const uin
|
||||
}
|
||||
|
||||
} // unnamed namespace
|
||||
} // namespace SIMDJSON_IMPLEMENTATION
|
||||
} // namespace arm64
|
||||
} // namespace simdjson
|
||||
|
||||
#endif // SIMDJSON_ARM64_STRINGPARSING_H
|
||||
#endif // SIMDJSON_ARM64_STRINGPARSING_DEFS_H
|
||||
+50
-16
@@ -1,26 +1,60 @@
|
||||
/**
|
||||
* @file Base declarations for all simdjson headers
|
||||
* @private
|
||||
*/
|
||||
#ifndef SIMDJSON_BASE_H
|
||||
#define SIMDJSON_BASE_H
|
||||
|
||||
#include "simdjson/compiler_check.h"
|
||||
#include "simdjson/common_defs.h"
|
||||
#include "simdjson/compiler_check.h"
|
||||
#include "simdjson/error.h"
|
||||
#include "simdjson/portability.h"
|
||||
|
||||
SIMDJSON_PUSH_DISABLE_WARNINGS
|
||||
SIMDJSON_DISABLE_UNDESIRED_WARNINGS
|
||||
/**
|
||||
* @brief The top level simdjson namespace, containing everything the library provides.
|
||||
*/
|
||||
namespace simdjson {
|
||||
|
||||
// Public API
|
||||
#include "simdjson/simdjson_version.h"
|
||||
#include "simdjson/error.h"
|
||||
#include "simdjson/minify.h"
|
||||
#include "simdjson/padded_string.h"
|
||||
#include "simdjson/padded_string_view.h"
|
||||
#include "simdjson/implementation.h"
|
||||
SIMDJSON_PUSH_DISABLE_UNUSED_WARNINGS
|
||||
|
||||
// Inline functions
|
||||
#include "simdjson/error-inl.h"
|
||||
#include "simdjson/padded_string-inl.h"
|
||||
#include "simdjson/padded_string_view-inl.h"
|
||||
/** The maximum document size supported by simdjson. */
|
||||
constexpr size_t SIMDJSON_MAXSIZE_BYTES = 0xFFFFFFFF;
|
||||
|
||||
SIMDJSON_POP_DISABLE_WARNINGS
|
||||
/**
|
||||
* The amount of padding needed in a buffer to parse JSON.
|
||||
*
|
||||
* The input buf should be readable up to buf + SIMDJSON_PADDING
|
||||
* this is a stopgap; there should be a better description of the
|
||||
* main loop and its behavior that abstracts over this
|
||||
* See https://github.com/simdjson/simdjson/issues/174
|
||||
*/
|
||||
constexpr size_t SIMDJSON_PADDING = 64;
|
||||
|
||||
#endif // SIMDJSON_BASE_H
|
||||
/**
|
||||
* By default, simdjson supports this many nested objects and arrays.
|
||||
*
|
||||
* This is the default for parser::max_depth().
|
||||
*/
|
||||
constexpr size_t DEFAULT_MAX_DEPTH = 1024;
|
||||
|
||||
SIMDJSON_POP_DISABLE_UNUSED_WARNINGS
|
||||
|
||||
class implementation;
|
||||
struct padded_string;
|
||||
class padded_string_view;
|
||||
enum class stage1_mode;
|
||||
|
||||
namespace internal {
|
||||
|
||||
template<typename T>
|
||||
class atomic_ptr;
|
||||
class dom_parser_implementation;
|
||||
class escape_json_string;
|
||||
class tape_ref;
|
||||
struct value128;
|
||||
enum class tape_type;
|
||||
|
||||
} // namespace internal
|
||||
} // namespace simdjson
|
||||
|
||||
#endif // SIMDJSON_BASE_H
|
||||
|
||||
+20
-55
@@ -1,64 +1,29 @@
|
||||
#ifndef SIMDJSON_BUILTIN_H
|
||||
#define SIMDJSON_BUILTIN_H
|
||||
|
||||
#include "simdjson/implementations.h"
|
||||
#include "simdjson/builtin/base.h"
|
||||
#include "simdjson/builtin/implementation.h"
|
||||
|
||||
// Determine the best builtin implementation
|
||||
#ifndef SIMDJSON_BUILTIN_IMPLEMENTATION
|
||||
#if SIMDJSON_CAN_ALWAYS_RUN_ICELAKE
|
||||
#define SIMDJSON_BUILTIN_IMPLEMENTATION icelake
|
||||
#elif SIMDJSON_CAN_ALWAYS_RUN_HASWELL
|
||||
#define SIMDJSON_BUILTIN_IMPLEMENTATION haswell
|
||||
#elif SIMDJSON_CAN_ALWAYS_RUN_WESTMERE
|
||||
#define SIMDJSON_BUILTIN_IMPLEMENTATION westmere
|
||||
#elif SIMDJSON_CAN_ALWAYS_RUN_ARM64
|
||||
#define SIMDJSON_BUILTIN_IMPLEMENTATION arm64
|
||||
#elif SIMDJSON_CAN_ALWAYS_RUN_PPC64
|
||||
#define SIMDJSON_BUILTIN_IMPLEMENTATION ppc64
|
||||
#elif SIMDJSON_CAN_ALWAYS_RUN_FALLBACK
|
||||
#define SIMDJSON_BUILTIN_IMPLEMENTATION fallback
|
||||
#include "simdjson/generic/dependencies.h"
|
||||
|
||||
#define SIMDJSON_CONDITIONAL_INCLUDE
|
||||
|
||||
#if SIMDJSON_BUILTIN_IMPLEMENTATION_IS(arm64)
|
||||
#include "simdjson/arm64.h"
|
||||
#elif SIMDJSON_BUILTIN_IMPLEMENTATION_IS(fallback)
|
||||
#include "simdjson/fallback.h"
|
||||
#elif SIMDJSON_BUILTIN_IMPLEMENTATION_IS(haswell)
|
||||
#include "simdjson/haswell.h"
|
||||
#elif SIMDJSON_BUILTIN_IMPLEMENTATION_IS(icelake)
|
||||
#include "simdjson/icelake.h"
|
||||
#elif SIMDJSON_BUILTIN_IMPLEMENTATION_IS(ppc64)
|
||||
#include "simdjson/ppc64.h"
|
||||
#elif SIMDJSON_BUILTIN_IMPLEMENTATION_IS(westmere)
|
||||
#include "simdjson/westmere.h"
|
||||
#else
|
||||
#error "All possible implementations (including fallback) have been disabled! simdjson will not run."
|
||||
#error Unknown SIMDJSON_BUILTIN_IMPLEMENTATION
|
||||
#endif
|
||||
#endif // SIMDJSON_BUILTIN_IMPLEMENTATION
|
||||
|
||||
#define SIMDJSON_IMPLEMENTATION SIMDJSON_BUILTIN_IMPLEMENTATION
|
||||
|
||||
// ondemand is only compiled as part of the builtin implementation at present
|
||||
|
||||
// Interface declarations
|
||||
#include "simdjson/generic/implementation_simdjson_result_base.h"
|
||||
#include "simdjson/generic/ondemand.h"
|
||||
|
||||
// Inline definitions
|
||||
#include "simdjson/generic/implementation_simdjson_result_base-inl.h"
|
||||
#include "simdjson/generic/ondemand-inl.h"
|
||||
|
||||
#undef SIMDJSON_IMPLEMENTATION
|
||||
|
||||
namespace simdjson {
|
||||
/**
|
||||
* Represents the best statically linked simdjson implementation that can be used by the compiling
|
||||
* program.
|
||||
*
|
||||
* Detects what options the program is compiled against, and picks the minimum implementation that
|
||||
* will work on any computer that can run the program. For example, if you compile with g++
|
||||
* -march=westmere, it will pick the westmere implementation. The haswell implementation will
|
||||
* still be available, and can be selected at runtime, but the builtin implementation (and any
|
||||
* code that uses it) will use westmere.
|
||||
*/
|
||||
namespace builtin = SIMDJSON_BUILTIN_IMPLEMENTATION;
|
||||
/**
|
||||
* @copydoc simdjson::SIMDJSON_BUILTIN_IMPLEMENTATION::ondemand
|
||||
*/
|
||||
namespace ondemand = SIMDJSON_BUILTIN_IMPLEMENTATION::ondemand;
|
||||
/**
|
||||
* Function which returns a pointer to an implementation matching the "builtin" implementation.
|
||||
* The builtin implementation is the best statically linked simdjson implementation that can be used by the compiling
|
||||
* program. If you compile with g++ -march=haswell, this will return the haswell implementation.
|
||||
* It is handy to be able to check what builtin was used: builtin_implementation()->name().
|
||||
*/
|
||||
const implementation * builtin_implementation();
|
||||
} // namespace simdjson
|
||||
#undef SIMDJSON_CONDITIONAL_INCLUDE
|
||||
|
||||
#endif // SIMDJSON_BUILTIN_H
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
#ifndef SIMDJSON_BUILTIN_BASE_H
|
||||
#define SIMDJSON_BUILTIN_BASE_H
|
||||
|
||||
#include "simdjson/base.h"
|
||||
#include "simdjson/implementation_detection.h"
|
||||
|
||||
namespace simdjson {
|
||||
#if SIMDJSON_BUILTIN_IMPLEMENTATION_IS(arm64)
|
||||
namespace arm64 {}
|
||||
#elif SIMDJSON_BUILTIN_IMPLEMENTATION_IS(fallback)
|
||||
namespace fallback {}
|
||||
#elif SIMDJSON_BUILTIN_IMPLEMENTATION_IS(haswell)
|
||||
namespace haswell {}
|
||||
#elif SIMDJSON_BUILTIN_IMPLEMENTATION_IS(icelake)
|
||||
namespace icelake {}
|
||||
#elif SIMDJSON_BUILTIN_IMPLEMENTATION_IS(ppc64)
|
||||
namespace ppc64 {}
|
||||
#elif SIMDJSON_BUILTIN_IMPLEMENTATION_IS(westmere)
|
||||
namespace westmere {}
|
||||
#else
|
||||
#error Unknown SIMDJSON_BUILTIN_IMPLEMENTATION
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Represents the best statically linked simdjson implementation that can be used by the compiling
|
||||
* program.
|
||||
*
|
||||
* Detects what options the program is compiled against, and picks the minimum implementation that
|
||||
* will work on any computer that can run the program. For example, if you compile with g++
|
||||
* -march=westmere, it will pick the westmere implementation. The haswell implementation will
|
||||
* still be available, and can be selected at runtime, but the builtin implementation (and any
|
||||
* code that uses it) will use westmere.
|
||||
*/
|
||||
namespace builtin = SIMDJSON_BUILTIN_IMPLEMENTATION;
|
||||
} // namespace simdjson
|
||||
|
||||
#endif // SIMDJSON_BUILTIN_BASE_H
|
||||
@@ -0,0 +1,38 @@
|
||||
#ifndef SIMDJSON_BUILTIN_IMPLEMENTATION_H
|
||||
#define SIMDJSON_BUILTIN_IMPLEMENTATION_H
|
||||
|
||||
#include "simdjson/builtin/base.h"
|
||||
|
||||
#include "simdjson/generic/dependencies.h"
|
||||
|
||||
#define SIMDJSON_CONDITIONAL_INCLUDE
|
||||
|
||||
#if SIMDJSON_BUILTIN_IMPLEMENTATION_IS(arm64)
|
||||
#include "simdjson/arm64/implementation.h"
|
||||
#elif SIMDJSON_BUILTIN_IMPLEMENTATION_IS(fallback)
|
||||
#include "simdjson/fallback/implementation.h"
|
||||
#elif SIMDJSON_BUILTIN_IMPLEMENTATION_IS(haswell)
|
||||
#include "simdjson/haswell/implementation.h"
|
||||
#elif SIMDJSON_BUILTIN_IMPLEMENTATION_IS(icelake)
|
||||
#include "simdjson/icelake/implementation.h"
|
||||
#elif SIMDJSON_BUILTIN_IMPLEMENTATION_IS(ppc64)
|
||||
#include "simdjson/ppc64/implementation.h"
|
||||
#elif SIMDJSON_BUILTIN_IMPLEMENTATION_IS(westmere)
|
||||
#include "simdjson/westmere/implementation.h"
|
||||
#else
|
||||
#error Unknown SIMDJSON_BUILTIN_IMPLEMENTATION
|
||||
#endif
|
||||
|
||||
#undef SIMDJSON_CONDITIONAL_INCLUDE
|
||||
|
||||
namespace simdjson {
|
||||
/**
|
||||
* Function which returns a pointer to an implementation matching the "builtin" implementation.
|
||||
* The builtin implementation is the best statically linked simdjson implementation that can be used by the compiling
|
||||
* program. If you compile with g++ -march=haswell, this will return the haswell implementation.
|
||||
* It is handy to be able to check what builtin was used: builtin_implementation()->name().
|
||||
*/
|
||||
const implementation * builtin_implementation();
|
||||
} // namespace simdjson
|
||||
|
||||
#endif // SIMDJSON_BUILTIN_IMPLEMENTATION_H
|
||||
@@ -0,0 +1,36 @@
|
||||
#ifndef SIMDJSON_BUILTIN_ONDEMAND_H
|
||||
#define SIMDJSON_BUILTIN_ONDEMAND_H
|
||||
|
||||
#include "simdjson/builtin.h"
|
||||
#include "simdjson/builtin/base.h"
|
||||
|
||||
#include "simdjson/generic/ondemand/dependencies.h"
|
||||
|
||||
#define SIMDJSON_CONDITIONAL_INCLUDE
|
||||
|
||||
#if SIMDJSON_BUILTIN_IMPLEMENTATION_IS(arm64)
|
||||
#include "simdjson/arm64/ondemand.h"
|
||||
#elif SIMDJSON_BUILTIN_IMPLEMENTATION_IS(fallback)
|
||||
#include "simdjson/fallback/ondemand.h"
|
||||
#elif SIMDJSON_BUILTIN_IMPLEMENTATION_IS(haswell)
|
||||
#include "simdjson/haswell/ondemand.h"
|
||||
#elif SIMDJSON_BUILTIN_IMPLEMENTATION_IS(icelake)
|
||||
#include "simdjson/icelake/ondemand.h"
|
||||
#elif SIMDJSON_BUILTIN_IMPLEMENTATION_IS(ppc64)
|
||||
#include "simdjson/ppc64/ondemand.h"
|
||||
#elif SIMDJSON_BUILTIN_IMPLEMENTATION_IS(westmere)
|
||||
#include "simdjson/westmere/ondemand.h"
|
||||
#else
|
||||
#error Unknown SIMDJSON_BUILTIN_IMPLEMENTATION
|
||||
#endif
|
||||
|
||||
#undef SIMDJSON_CONDITIONAL_INCLUDE
|
||||
|
||||
namespace simdjson {
|
||||
/**
|
||||
* @copydoc simdjson::SIMDJSON_BUILTIN_IMPLEMENTATION::ondemand
|
||||
*/
|
||||
namespace ondemand = SIMDJSON_BUILTIN_IMPLEMENTATION::ondemand;
|
||||
} // namespace simdjson
|
||||
|
||||
#endif // SIMDJSON_BUILTIN_ONDEMAND_H
|
||||
@@ -2,10 +2,10 @@
|
||||
#define SIMDJSON_COMMON_DEFS_H
|
||||
|
||||
#include <cassert>
|
||||
#include "simdjson/compiler_check.h"
|
||||
#include "simdjson/portability.h"
|
||||
|
||||
namespace simdjson {
|
||||
|
||||
namespace internal {
|
||||
/**
|
||||
* @private
|
||||
@@ -20,7 +20,6 @@ char *to_chars(char *first, const char *last, double value);
|
||||
*/
|
||||
double from_chars(const char *first) noexcept;
|
||||
double from_chars(const char *first, const char* end) noexcept;
|
||||
|
||||
}
|
||||
|
||||
#ifndef SIMDJSON_EXCEPTIONS
|
||||
@@ -31,26 +30,6 @@ double from_chars(const char *first, const char* end) noexcept;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/** The maximum document size supported by simdjson. */
|
||||
constexpr size_t SIMDJSON_MAXSIZE_BYTES = 0xFFFFFFFF;
|
||||
|
||||
/**
|
||||
* The amount of padding needed in a buffer to parse JSON.
|
||||
*
|
||||
* The input buf should be readable up to buf + SIMDJSON_PADDING
|
||||
* this is a stopgap; there should be a better description of the
|
||||
* main loop and its behavior that abstracts over this
|
||||
* See https://github.com/simdjson/simdjson/issues/174
|
||||
*/
|
||||
constexpr size_t SIMDJSON_PADDING = 64;
|
||||
|
||||
/**
|
||||
* By default, simdjson supports this many nested objects and arrays.
|
||||
*
|
||||
* This is the default for parser::max_depth().
|
||||
*/
|
||||
constexpr size_t DEFAULT_MAX_DEPTH = 1024;
|
||||
|
||||
} // namespace simdjson
|
||||
|
||||
#if defined(__GNUC__)
|
||||
@@ -105,6 +84,9 @@ constexpr size_t DEFAULT_MAX_DEPTH = 1024;
|
||||
#define SIMDJSON_DISABLE_STRICT_OVERFLOW_WARNING
|
||||
#define SIMDJSON_POP_DISABLE_WARNINGS __pragma(warning( pop ))
|
||||
|
||||
#define SIMDJSON_PUSH_DISABLE_UNUSED_WARNINGS
|
||||
#define SIMDJSON_POP_DISABLE_UNUSED_WARNINGS
|
||||
|
||||
#else // SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||
|
||||
#define simdjson_really_inline inline __attribute__((always_inline))
|
||||
@@ -150,7 +132,8 @@ constexpr size_t DEFAULT_MAX_DEPTH = 1024;
|
||||
SIMDJSON_DISABLE_GCC_WARNING(-Wshadow) \
|
||||
SIMDJSON_DISABLE_GCC_WARNING(-Wunused-parameter) \
|
||||
SIMDJSON_DISABLE_GCC_WARNING(-Wunused-variable) \
|
||||
SIMDJSON_DISABLE_GCC_WARNING(-Wmaybe-uninitialized)
|
||||
SIMDJSON_DISABLE_GCC_WARNING(-Wmaybe-uninitialized) \
|
||||
SIMDJSON_DISABLE_GCC_WARNING(-Wformat-security)
|
||||
#endif // __clang__
|
||||
|
||||
#define SIMDJSON_PRAGMA(P) _Pragma(#P)
|
||||
@@ -164,6 +147,10 @@ constexpr size_t DEFAULT_MAX_DEPTH = 1024;
|
||||
#define SIMDJSON_DISABLE_STRICT_OVERFLOW_WARNING SIMDJSON_DISABLE_GCC_WARNING(-Wstrict-overflow)
|
||||
#define SIMDJSON_POP_DISABLE_WARNINGS _Pragma("GCC diagnostic pop")
|
||||
|
||||
#define SIMDJSON_PUSH_DISABLE_UNUSED_WARNINGS SIMDJSON_PUSH_DISABLE_WARNINGS \
|
||||
SIMDJSON_DISABLE_GCC_WARNING(-Wunused)
|
||||
#define SIMDJSON_POP_DISABLE_UNUSED_WARNINGS SIMDJSON_POP_DISABLE_WARNINGS
|
||||
|
||||
|
||||
|
||||
#endif // MSC_VER
|
||||
@@ -180,6 +167,41 @@ constexpr size_t DEFAULT_MAX_DEPTH = 1024;
|
||||
#define simdjson_inline simdjson_really_inline
|
||||
#endif
|
||||
|
||||
#ifndef simdjson_constexpr
|
||||
#if __cpp_constexpr
|
||||
#define simdjson_constexpr constexpr simdjson_inline
|
||||
#else
|
||||
#define simdjson_constexpr simdjson_inline
|
||||
#endif
|
||||
#endif
|
||||
// simdjson_constexpr
|
||||
|
||||
#ifndef simdjson_consteval
|
||||
#if __cpp_consteval
|
||||
#define simdjson_consteval consteval simdjson_inline
|
||||
#else
|
||||
#define simdjson_consteval simdjson_constexpr
|
||||
#endif
|
||||
#endif // simdjson_consteval
|
||||
|
||||
#ifndef simdjson_constinit
|
||||
#if __cpp_constinit
|
||||
#define simdjson_constinit constinit
|
||||
#elif __cpp_consteval
|
||||
#define simdjson_constinit consteval
|
||||
#else
|
||||
#define simdjson_constinit constexpr
|
||||
#endif
|
||||
#endif // simdjson_constinit
|
||||
|
||||
#ifndef simdjson_if_constexpr
|
||||
#if SIMDJSON_CPLUSPLUS17
|
||||
#define simdjson_if_constexpr constexpr
|
||||
#else
|
||||
#define simdjson_if_constexpr
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if SIMDJSON_VISUAL_STUDIO
|
||||
/**
|
||||
* Windows users need to do some extra work when building
|
||||
@@ -322,7 +344,6 @@ namespace std {
|
||||
# define simdjson_fallthrough do {} while (0) /* fallthrough */
|
||||
#endif // simdjson_fallthrough
|
||||
|
||||
|
||||
#if SIMDJSON_DEVELOPMENT_CHECKS
|
||||
#define SIMDJSON_DEVELOPMENT_ASSERT(expr) do { assert ((expr)); } while (0)
|
||||
#else
|
||||
@@ -333,4 +354,25 @@ namespace std {
|
||||
#define SIMDJSON_UTF8VALIDATION 1
|
||||
#endif
|
||||
|
||||
#ifdef __has_include
|
||||
// How do we detect that a compiler supports vbmi2?
|
||||
// For sure if the following header is found, we are ok?
|
||||
#if __has_include(<avx512vbmi2intrin.h>)
|
||||
#define SIMDJSON_COMPILER_SUPPORTS_VBMI2 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#if _MSC_VER >= 1920
|
||||
// Visual Studio 2019 and up support VBMI2 under x64 even if the header
|
||||
// avx512vbmi2intrin.h is not found.
|
||||
#define SIMDJSON_COMPILER_SUPPORTS_VBMI2 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// By default, we allow AVX512.
|
||||
#ifndef SIMDJSON_AVX512_ALLOWED
|
||||
#define SIMDJSON_AVX512_ALLOWED 1
|
||||
#endif
|
||||
|
||||
#endif // SIMDJSON_COMMON_DEFS_H
|
||||
|
||||
@@ -32,4 +32,12 @@
|
||||
#error simdjson requires a compiler compliant with the C++11 standard
|
||||
#endif
|
||||
|
||||
#ifndef SIMDJSON_IF_CONSTEXPR
|
||||
#if SIMDJSON_CPLUSPLUS17
|
||||
#define SIMDJSON_IF_CONSTEXPR if constexpr
|
||||
#else
|
||||
#define SIMDJSON_IF_CONSTEXPR if
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif // SIMDJSON_COMPILER_CHECK_H
|
||||
|
||||
@@ -1,11 +1,7 @@
|
||||
#ifndef SIMDJSON_DOM_H
|
||||
#define SIMDJSON_DOM_H
|
||||
|
||||
#include "simdjson/base.h"
|
||||
|
||||
SIMDJSON_PUSH_DISABLE_WARNINGS
|
||||
SIMDJSON_DISABLE_UNDESIRED_WARNINGS
|
||||
|
||||
#include "simdjson/dom/base.h"
|
||||
#include "simdjson/dom/array.h"
|
||||
#include "simdjson/dom/document_stream.h"
|
||||
#include "simdjson/dom/document.h"
|
||||
@@ -30,6 +26,4 @@ SIMDJSON_DISABLE_UNDESIRED_WARNINGS
|
||||
#include "simdjson/internal/tape_ref-inl.h"
|
||||
#include "simdjson/dom/serialization-inl.h"
|
||||
|
||||
SIMDJSON_POP_DISABLE_WARNINGS
|
||||
|
||||
#endif // SIMDJSON_DOM_H
|
||||
|
||||
@@ -1,11 +1,15 @@
|
||||
#ifndef SIMDJSON_INLINE_ARRAY_H
|
||||
#define SIMDJSON_INLINE_ARRAY_H
|
||||
#ifndef SIMDJSON_ARRAY_INL_H
|
||||
#define SIMDJSON_ARRAY_INL_H
|
||||
|
||||
// Inline implementations go in here.
|
||||
#include <utility>
|
||||
|
||||
#include "simdjson/dom/base.h"
|
||||
#include "simdjson/dom/array.h"
|
||||
#include "simdjson/dom/element.h"
|
||||
#include <utility>
|
||||
#include "simdjson/error-inl.h"
|
||||
#include "simdjson/internal/tape_ref-inl.h"
|
||||
|
||||
#include <limits>
|
||||
|
||||
namespace simdjson {
|
||||
|
||||
@@ -170,4 +174,4 @@ static_assert(std::ranges::sized_range<simdjson::simdjson_result<simdjson::dom::
|
||||
#endif // SIMDJSON_EXCEPTIONS
|
||||
#endif // defined(__cpp_lib_ranges)
|
||||
|
||||
#endif // SIMDJSON_INLINE_ARRAY_H
|
||||
#endif // SIMDJSON_ARRAY_INL_H
|
||||
|
||||
@@ -1,21 +1,12 @@
|
||||
#ifndef SIMDJSON_DOM_ARRAY_H
|
||||
#define SIMDJSON_DOM_ARRAY_H
|
||||
|
||||
#include "simdjson/common_defs.h"
|
||||
#include "simdjson/error.h"
|
||||
#include "simdjson/dom/base.h"
|
||||
#include "simdjson/internal/tape_ref.h"
|
||||
|
||||
namespace simdjson {
|
||||
|
||||
namespace internal {
|
||||
template<typename T>
|
||||
class string_builder;
|
||||
}
|
||||
namespace dom {
|
||||
|
||||
class document;
|
||||
class element;
|
||||
|
||||
/**
|
||||
* JSON array.
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
#ifndef SIMDJSON_DOM_BASE_H
|
||||
#define SIMDJSON_DOM_BASE_H
|
||||
|
||||
#include "simdjson/base.h"
|
||||
|
||||
namespace simdjson {
|
||||
|
||||
/**
|
||||
* @brief A DOM API on top of the simdjson parser.
|
||||
*/
|
||||
namespace dom {
|
||||
|
||||
/** The default batch size for parser.parse_many() and parser.load_many() */
|
||||
static constexpr size_t DEFAULT_BATCH_SIZE = 1000000;
|
||||
/**
|
||||
* Some adversary might try to set the batch size to 0 or 1, which might cause problems.
|
||||
* We set a minimum of 32B since anything else is highly likely to be an error. In practice,
|
||||
* most users will want a much larger batch size.
|
||||
*
|
||||
* All non-negative MINIMAL_BATCH_SIZE values should be 'safe' except that, obviously, no JSON
|
||||
* document can ever span 0 or 1 byte and that very large values would create memory allocation issues.
|
||||
*/
|
||||
static constexpr size_t MINIMAL_BATCH_SIZE = 32;
|
||||
|
||||
/**
|
||||
* It is wasteful to allocate memory for tiny documents (e.g., 4 bytes).
|
||||
*/
|
||||
static constexpr size_t MINIMAL_DOCUMENT_CAPACITY = 32;
|
||||
|
||||
class array;
|
||||
class document;
|
||||
class document_stream;
|
||||
class element;
|
||||
class key_value_pair;
|
||||
class object;
|
||||
class parser;
|
||||
|
||||
#ifdef SIMDJSON_THREADS_ENABLED
|
||||
struct stage1_worker;
|
||||
#endif // SIMDJSON_THREADS_ENABLED
|
||||
|
||||
} // namespace dom
|
||||
|
||||
namespace internal {
|
||||
|
||||
template<typename T>
|
||||
class string_builder;
|
||||
class tape_ref;
|
||||
|
||||
} // namespace internal
|
||||
|
||||
} // namespace simdjson
|
||||
|
||||
#endif // SIMDJSON_DOM_BASE_H
|
||||
@@ -1,13 +1,14 @@
|
||||
#ifndef SIMDJSON_INLINE_DOCUMENT_H
|
||||
#define SIMDJSON_INLINE_DOCUMENT_H
|
||||
#ifndef SIMDJSON_DOCUMENT_INL_H
|
||||
#define SIMDJSON_DOCUMENT_INL_H
|
||||
|
||||
// Inline implementations go in here.
|
||||
|
||||
#include "simdjson/dom/base.h"
|
||||
#include "simdjson/dom/document.h"
|
||||
#include "simdjson/dom/element.h"
|
||||
#include "simdjson/internal/tape_ref.h"
|
||||
#include "simdjson/dom/element-inl.h"
|
||||
#include "simdjson/internal/tape_ref-inl.h"
|
||||
#include "simdjson/internal/jsonformatutils.h"
|
||||
#include <ostream>
|
||||
|
||||
#include <cstring>
|
||||
|
||||
namespace simdjson {
|
||||
@@ -155,4 +156,4 @@ inline bool document::dump_raw_tape(std::ostream &os) const noexcept {
|
||||
} // namespace dom
|
||||
} // namespace simdjson
|
||||
|
||||
#endif // SIMDJSON_INLINE_DOCUMENT_H
|
||||
#endif // SIMDJSON_DOCUMENT_INL_H
|
||||
|
||||
@@ -1,15 +1,13 @@
|
||||
#ifndef SIMDJSON_DOM_DOCUMENT_H
|
||||
#define SIMDJSON_DOM_DOCUMENT_H
|
||||
|
||||
#include "simdjson/common_defs.h"
|
||||
#include "simdjson/dom/base.h"
|
||||
|
||||
#include <memory>
|
||||
#include <ostream>
|
||||
|
||||
namespace simdjson {
|
||||
namespace dom {
|
||||
|
||||
class element;
|
||||
|
||||
/**
|
||||
* A parsed JSON document.
|
||||
*
|
||||
|
||||
@@ -1,14 +1,18 @@
|
||||
#ifndef SIMDJSON_INLINE_DOCUMENT_STREAM_H
|
||||
#define SIMDJSON_INLINE_DOCUMENT_STREAM_H
|
||||
#ifndef SIMDJSON_DOCUMENT_STREAM_INL_H
|
||||
#define SIMDJSON_DOCUMENT_STREAM_INL_H
|
||||
|
||||
#include "simdjson/dom/base.h"
|
||||
#include "simdjson/dom/document_stream.h"
|
||||
#include <algorithm>
|
||||
#include <limits>
|
||||
#include <stdexcept>
|
||||
#include "simdjson/dom/element-inl.h"
|
||||
#include "simdjson/dom/parser-inl.h"
|
||||
#include "simdjson/error-inl.h"
|
||||
#include "simdjson/internal/dom_parser_implementation.h"
|
||||
|
||||
namespace simdjson {
|
||||
namespace dom {
|
||||
|
||||
#ifdef SIMDJSON_THREADS_ENABLED
|
||||
|
||||
inline void stage1_worker::finish() {
|
||||
// After calling "run" someone would call finish() to wait
|
||||
// for the end of the processing.
|
||||
@@ -337,4 +341,4 @@ simdjson_inline dom::document_stream::iterator simdjson_result<dom::document_str
|
||||
#endif // SIMDJSON_EXCEPTIONS
|
||||
|
||||
} // namespace simdjson
|
||||
#endif // SIMDJSON_INLINE_DOCUMENT_STREAM_H
|
||||
#endif // SIMDJSON_DOCUMENT_STREAM_INL_H
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
#ifndef SIMDJSON_DOCUMENT_STREAM_H
|
||||
#define SIMDJSON_DOCUMENT_STREAM_H
|
||||
|
||||
#include "simdjson/common_defs.h"
|
||||
#include "simdjson/dom/base.h"
|
||||
#include "simdjson/dom/parser.h"
|
||||
#include "simdjson/error.h"
|
||||
|
||||
#ifdef SIMDJSON_THREADS_ENABLED
|
||||
#include <thread>
|
||||
#include <mutex>
|
||||
@@ -13,7 +13,6 @@
|
||||
namespace simdjson {
|
||||
namespace dom {
|
||||
|
||||
|
||||
#ifdef SIMDJSON_THREADS_ENABLED
|
||||
/** @private Custom worker class **/
|
||||
struct stage1_worker {
|
||||
|
||||
@@ -1,11 +1,17 @@
|
||||
#ifndef SIMDJSON_INLINE_ELEMENT_H
|
||||
#define SIMDJSON_INLINE_ELEMENT_H
|
||||
#ifndef SIMDJSON_ELEMENT_INL_H
|
||||
#define SIMDJSON_ELEMENT_INL_H
|
||||
|
||||
#include "simdjson/dom/array.h"
|
||||
#include "simdjson/dom/base.h"
|
||||
#include "simdjson/dom/element.h"
|
||||
#include "simdjson/dom/document.h"
|
||||
#include "simdjson/dom/object.h"
|
||||
#include <cstring>
|
||||
#include <utility>
|
||||
#include "simdjson/internal/tape_type.h"
|
||||
|
||||
#include "simdjson/dom/object-inl.h"
|
||||
#include "simdjson/error-inl.h"
|
||||
|
||||
#include <ostream>
|
||||
#include <limits>
|
||||
|
||||
namespace simdjson {
|
||||
|
||||
@@ -438,4 +444,4 @@ inline std::ostream& operator<<(std::ostream& out, element_type type) {
|
||||
|
||||
} // namespace simdjson
|
||||
|
||||
#endif // SIMDJSON_INLINE_ELEMENT_H
|
||||
#endif // SIMDJSON_ELEMENT_INL_H
|
||||
|
||||
@@ -1,20 +1,11 @@
|
||||
#ifndef SIMDJSON_DOM_ELEMENT_H
|
||||
#define SIMDJSON_DOM_ELEMENT_H
|
||||
|
||||
#include "simdjson/common_defs.h"
|
||||
#include "simdjson/error.h"
|
||||
#include "simdjson/internal/tape_ref.h"
|
||||
#include <ostream>
|
||||
#include "simdjson/dom/base.h"
|
||||
#include "simdjson/dom/array.h"
|
||||
|
||||
namespace simdjson {
|
||||
namespace internal {
|
||||
template<typename T>
|
||||
class string_builder;
|
||||
}
|
||||
namespace dom {
|
||||
class array;
|
||||
class document;
|
||||
class object;
|
||||
|
||||
/**
|
||||
* The actual concrete type of a JSON element
|
||||
@@ -537,7 +528,6 @@ public:
|
||||
#endif // SIMDJSON_EXCEPTIONS
|
||||
};
|
||||
|
||||
|
||||
} // namespace simdjson
|
||||
|
||||
#endif // SIMDJSON_DOM_DOCUMENT_H
|
||||
|
||||
@@ -3,9 +3,11 @@
|
||||
#ifndef SIMDJSON_DOM_JSONPARSER_H
|
||||
#define SIMDJSON_DOM_JSONPARSER_H
|
||||
|
||||
#include "simdjson/dom/document.h"
|
||||
#include "simdjson/dom/parsedjson.h"
|
||||
#include "simdjson/jsonioutil.h"
|
||||
#include "simdjson/dom/base.h"
|
||||
#include "simdjson/dom/parser.h"
|
||||
#include "simdjson/dom/element.h"
|
||||
|
||||
#include "simdjson/dom/parser-inl.h"
|
||||
|
||||
namespace simdjson {
|
||||
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
#ifndef SIMDJSON_INLINE_OBJECT_H
|
||||
#define SIMDJSON_INLINE_OBJECT_H
|
||||
#ifndef SIMDJSON_OBJECT_INL_H
|
||||
#define SIMDJSON_OBJECT_INL_H
|
||||
|
||||
#include "simdjson/dom/element.h"
|
||||
#include "simdjson/dom/base.h"
|
||||
#include "simdjson/dom/object.h"
|
||||
#include "simdjson/portability.h"
|
||||
#include "simdjson/dom/document.h"
|
||||
|
||||
#include "simdjson/dom/element-inl.h"
|
||||
#include "simdjson/error-inl.h"
|
||||
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
|
||||
namespace simdjson {
|
||||
|
||||
@@ -253,4 +256,4 @@ static_assert(std::ranges::sized_range<simdjson::simdjson_result<simdjson::dom::
|
||||
#endif // SIMDJSON_EXCEPTIONS
|
||||
#endif // defined(__cpp_lib_ranges)
|
||||
|
||||
#endif // SIMDJSON_INLINE_OBJECT_H
|
||||
#endif // SIMDJSON_OBJECT_INL_H
|
||||
|
||||
@@ -1,21 +1,13 @@
|
||||
#ifndef SIMDJSON_DOM_OBJECT_H
|
||||
#define SIMDJSON_DOM_OBJECT_H
|
||||
|
||||
#include "simdjson/common_defs.h"
|
||||
#include "simdjson/error.h"
|
||||
#include "simdjson/dom/base.h"
|
||||
#include "simdjson/dom/element.h"
|
||||
#include "simdjson/internal/tape_ref.h"
|
||||
|
||||
namespace simdjson {
|
||||
namespace internal {
|
||||
template<typename T>
|
||||
class string_builder;
|
||||
}
|
||||
namespace dom {
|
||||
|
||||
class document;
|
||||
class element;
|
||||
class key_value_pair;
|
||||
|
||||
/**
|
||||
* JSON object.
|
||||
*/
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
#ifndef SIMDJSON_DOM_PARSEDJSON_H
|
||||
#define SIMDJSON_DOM_PARSEDJSON_H
|
||||
|
||||
#include "simdjson/dom/document.h"
|
||||
#include "simdjson/dom/base.h"
|
||||
|
||||
namespace simdjson {
|
||||
|
||||
|
||||
@@ -1,9 +1,17 @@
|
||||
#ifndef SIMDJSON_INLINE_PARSEDJSON_ITERATOR_H
|
||||
#define SIMDJSON_INLINE_PARSEDJSON_ITERATOR_H
|
||||
#ifndef SIMDJSON_PARSEDJSON_ITERATOR_INL_H
|
||||
#define SIMDJSON_PARSEDJSON_ITERATOR_INL_H
|
||||
|
||||
#include "simdjson/dom/base.h"
|
||||
#include "simdjson/dom/parsedjson_iterator.h"
|
||||
#include "simdjson/portability.h"
|
||||
#include "simdjson/internal/jsonformatutils.h"
|
||||
|
||||
#include "simdjson/dom/parser-inl.h"
|
||||
#include "simdjson/internal/tape_ref-inl.h"
|
||||
|
||||
#include <cstring>
|
||||
#include <iterator>
|
||||
#include <limits>
|
||||
#include <ostream>
|
||||
|
||||
#ifndef SIMDJSON_DISABLE_DEPRECATED_API
|
||||
|
||||
@@ -197,6 +205,12 @@ void dom::parser::Iterator::to_start_scope() {
|
||||
current_type = uint8_t(current_val >> 56);
|
||||
}
|
||||
|
||||
inline void dom::parser::Iterator::rewind() {
|
||||
while (up())
|
||||
;
|
||||
}
|
||||
|
||||
|
||||
bool dom::parser::Iterator::next() {
|
||||
size_t npos;
|
||||
if ((current_type == '[') || (current_type == '{')) {
|
||||
@@ -365,6 +379,48 @@ bool dom::parser::Iterator::move_to(const char *pointer,
|
||||
return found;
|
||||
}
|
||||
|
||||
inline bool dom::parser::Iterator::move_to(const std::string &pointer) {
|
||||
return move_to(pointer.c_str(), uint32_t(pointer.length()));
|
||||
}
|
||||
|
||||
inline int64_t dom::parser::Iterator::get_integer() const {
|
||||
if (location + 1 >= tape_length) {
|
||||
return 0; // default value in case of error
|
||||
}
|
||||
return static_cast<int64_t>(doc.tape[location + 1]);
|
||||
}
|
||||
|
||||
inline uint64_t dom::parser::Iterator::get_unsigned_integer() const {
|
||||
if (location + 1 >= tape_length) {
|
||||
return 0; // default value in case of error
|
||||
}
|
||||
return doc.tape[location + 1];
|
||||
}
|
||||
|
||||
inline const char * dom::parser::Iterator::get_string() const {
|
||||
return reinterpret_cast<const char *>(
|
||||
doc.string_buf.get() + (current_val & internal::JSON_VALUE_MASK) + sizeof(uint32_t));
|
||||
}
|
||||
|
||||
inline uint32_t dom::parser::Iterator::get_string_length() const {
|
||||
uint32_t answer;
|
||||
std::memcpy(&answer,
|
||||
reinterpret_cast<const char *>(doc.string_buf.get() +
|
||||
(current_val & internal::JSON_VALUE_MASK)),
|
||||
sizeof(uint32_t));
|
||||
return answer;
|
||||
}
|
||||
|
||||
inline double dom::parser::Iterator::get_double() const {
|
||||
if (location + 1 >= tape_length) {
|
||||
return std::numeric_limits<double>::quiet_NaN(); // default value in
|
||||
// case of error
|
||||
}
|
||||
double answer;
|
||||
std::memcpy(&answer, &doc.tape[location + 1], sizeof(answer));
|
||||
return answer;
|
||||
}
|
||||
|
||||
bool dom::parser::Iterator::relative_move_to(const char *pointer,
|
||||
uint32_t length) {
|
||||
if (length == 0) {
|
||||
@@ -486,4 +542,4 @@ SIMDJSON_POP_DISABLE_WARNINGS
|
||||
#endif // SIMDJSON_DISABLE_DEPRECATED_API
|
||||
|
||||
|
||||
#endif // SIMDJSON_INLINE_PARSEDJSON_ITERATOR_H
|
||||
#endif // SIMDJSON_PARSEDJSON_ITERATOR_INL_H
|
||||
|
||||
@@ -3,16 +3,8 @@
|
||||
#ifndef SIMDJSON_DOM_PARSEDJSON_ITERATOR_H
|
||||
#define SIMDJSON_DOM_PARSEDJSON_ITERATOR_H
|
||||
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <ostream>
|
||||
#include <iterator>
|
||||
#include <limits>
|
||||
#include <stdexcept>
|
||||
|
||||
#include "simdjson/dom/document.h"
|
||||
#include "simdjson/dom/parsedjson.h"
|
||||
#include "simdjson/internal/jsonformatutils.h"
|
||||
#include "simdjson/dom/base.h"
|
||||
#include "simdjson/dom/parser.h"
|
||||
|
||||
#ifndef SIMDJSON_DISABLE_DEPRECATED_API
|
||||
|
||||
@@ -52,51 +44,23 @@ public:
|
||||
}
|
||||
|
||||
// get the int64_t value at this node; valid only if get_type is "l"
|
||||
inline int64_t get_integer() const {
|
||||
if (location + 1 >= tape_length) {
|
||||
return 0; // default value in case of error
|
||||
}
|
||||
return static_cast<int64_t>(doc.tape[location + 1]);
|
||||
}
|
||||
inline int64_t get_integer() const;
|
||||
|
||||
// get the value as uint64; valid only if if get_type is "u"
|
||||
inline uint64_t get_unsigned_integer() const {
|
||||
if (location + 1 >= tape_length) {
|
||||
return 0; // default value in case of error
|
||||
}
|
||||
return doc.tape[location + 1];
|
||||
}
|
||||
inline uint64_t get_unsigned_integer() const;
|
||||
|
||||
// get the string value at this node (NULL ended); valid only if get_type is "
|
||||
// note that tabs, and line endings are escaped in the returned value (see
|
||||
// print_with_escapes) return value is valid UTF-8, it may contain NULL chars
|
||||
// within the string: get_string_length determines the true string length.
|
||||
inline const char *get_string() const {
|
||||
return reinterpret_cast<const char *>(
|
||||
doc.string_buf.get() + (current_val & internal::JSON_VALUE_MASK) + sizeof(uint32_t));
|
||||
}
|
||||
inline const char *get_string() const;
|
||||
|
||||
// return the length of the string in bytes
|
||||
inline uint32_t get_string_length() const {
|
||||
uint32_t answer;
|
||||
std::memcpy(&answer,
|
||||
reinterpret_cast<const char *>(doc.string_buf.get() +
|
||||
(current_val & internal::JSON_VALUE_MASK)),
|
||||
sizeof(uint32_t));
|
||||
return answer;
|
||||
}
|
||||
inline uint32_t get_string_length() const;
|
||||
|
||||
// get the double value at this node; valid only if
|
||||
// get_type() is "d"
|
||||
inline double get_double() const {
|
||||
if (location + 1 >= tape_length) {
|
||||
return std::numeric_limits<double>::quiet_NaN(); // default value in
|
||||
// case of error
|
||||
}
|
||||
double answer;
|
||||
std::memcpy(&answer, &doc.tape[location + 1], sizeof(answer));
|
||||
return answer;
|
||||
}
|
||||
inline double get_double() const;
|
||||
|
||||
inline bool is_object_or_array() const { return is_object() || is_array(); }
|
||||
|
||||
@@ -190,9 +154,7 @@ public:
|
||||
// "If a referenced member name is not unique in an object, the member that
|
||||
// is referenced is undefined, and evaluation fails". Here we just return
|
||||
// the first corresponding value.
|
||||
inline bool move_to(const std::string &pointer) {
|
||||
return move_to(pointer.c_str(), uint32_t(pointer.length()));
|
||||
}
|
||||
inline bool move_to(const std::string &pointer);
|
||||
|
||||
private:
|
||||
// Almost the same as move_to(), except it searches from the current
|
||||
@@ -240,10 +202,7 @@ public:
|
||||
// a scope is a series of nodes at the same level
|
||||
inline void to_start_scope();
|
||||
|
||||
inline void rewind() {
|
||||
while (up())
|
||||
;
|
||||
}
|
||||
inline void rewind();
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,12 +1,16 @@
|
||||
#ifndef SIMDJSON_INLINE_PARSER_H
|
||||
#define SIMDJSON_INLINE_PARSER_H
|
||||
#ifndef SIMDJSON_PARSER_INL_H
|
||||
#define SIMDJSON_PARSER_INL_H
|
||||
|
||||
#include "simdjson/dom/base.h"
|
||||
#include "simdjson/dom/document_stream.h"
|
||||
#include "simdjson/dom/parser.h"
|
||||
#include "simdjson/implementation.h"
|
||||
#include "simdjson/internal/jsonformatutils.h"
|
||||
#include "simdjson/portability.h"
|
||||
#include <cstdio>
|
||||
#include "simdjson/internal/dom_parser_implementation.h"
|
||||
|
||||
#include "simdjson/error-inl.h"
|
||||
#include "simdjson/padded_string-inl.h"
|
||||
#include "simdjson/dom/document_stream-inl.h"
|
||||
#include "simdjson/dom/element-inl.h"
|
||||
|
||||
#include <climits>
|
||||
|
||||
namespace simdjson {
|
||||
@@ -236,4 +240,4 @@ simdjson_inline void parser::set_max_capacity(size_t max_capacity) noexcept {
|
||||
} // namespace dom
|
||||
} // namespace simdjson
|
||||
|
||||
#endif // SIMDJSON_INLINE_PARSER_H
|
||||
#endif // SIMDJSON_PARSER_INL_H
|
||||
|
||||
@@ -1,41 +1,13 @@
|
||||
#ifndef SIMDJSON_DOM_PARSER_H
|
||||
#define SIMDJSON_DOM_PARSER_H
|
||||
|
||||
#include "simdjson/common_defs.h"
|
||||
#include "simdjson/dom/base.h"
|
||||
#include "simdjson/dom/document.h"
|
||||
#include "simdjson/error.h"
|
||||
#include "simdjson/internal/dom_parser_implementation.h"
|
||||
#include "simdjson/internal/tape_ref.h"
|
||||
#include "simdjson/padded_string.h"
|
||||
#include "simdjson/portability.h"
|
||||
#include <memory>
|
||||
#include <ostream>
|
||||
#include <string>
|
||||
|
||||
namespace simdjson {
|
||||
|
||||
namespace dom {
|
||||
|
||||
class document_stream;
|
||||
class element;
|
||||
|
||||
/** The default batch size for parser.parse_many() and parser.load_many() */
|
||||
static constexpr size_t DEFAULT_BATCH_SIZE = 1000000;
|
||||
/**
|
||||
* Some adversary might try to set the batch size to 0 or 1, which might cause problems.
|
||||
* We set a minimum of 32B since anything else is highly likely to be an error. In practice,
|
||||
* most users will want a much larger batch size.
|
||||
*
|
||||
* All non-negative MINIMAL_BATCH_SIZE values should be 'safe' except that, obviously, no JSON
|
||||
* document can ever span 0 or 1 byte and that very large values would create memory allocation issues.
|
||||
*/
|
||||
static constexpr size_t MINIMAL_BATCH_SIZE = 32;
|
||||
|
||||
/**
|
||||
* It is wasteful to allocate memory for tiny documents (e.g., 4 bytes).
|
||||
*/
|
||||
static constexpr size_t MINIMAL_DOCUMENT_CAPACITY = 32;
|
||||
|
||||
/**
|
||||
* A persistent document parser.
|
||||
*
|
||||
|
||||
@@ -2,10 +2,16 @@
|
||||
#ifndef SIMDJSON_SERIALIZATION_INL_H
|
||||
#define SIMDJSON_SERIALIZATION_INL_H
|
||||
|
||||
#include "simdjson/dom/base.h"
|
||||
#include "simdjson/dom/serialization.h"
|
||||
#include "simdjson/dom/parser.h"
|
||||
#include "simdjson/internal/tape_type.h"
|
||||
|
||||
#include <cinttypes>
|
||||
#include <type_traits>
|
||||
#include "simdjson/dom/array-inl.h"
|
||||
#include "simdjson/dom/object-inl.h"
|
||||
#include "simdjson/internal/tape_ref-inl.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
namespace simdjson {
|
||||
namespace dom {
|
||||
@@ -17,12 +23,46 @@ inline bool parser::print_json(std::ostream &os) const noexcept {
|
||||
os << answer;
|
||||
return true;
|
||||
}
|
||||
|
||||
inline std::ostream& operator<<(std::ostream& out, simdjson::dom::element value) {
|
||||
simdjson::internal::string_builder<> sb;
|
||||
sb.append(value);
|
||||
return (out << sb.str());
|
||||
}
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::dom::element> x) {
|
||||
if (x.error()) { throw simdjson::simdjson_error(x.error()); }
|
||||
return (out << x.value());
|
||||
}
|
||||
#endif
|
||||
inline std::ostream& operator<<(std::ostream& out, simdjson::dom::array value) {
|
||||
simdjson::internal::string_builder<> sb;
|
||||
sb.append(value);
|
||||
return (out << sb.str());
|
||||
}
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::dom::array> x) {
|
||||
if (x.error()) { throw simdjson::simdjson_error(x.error()); }
|
||||
return (out << x.value());
|
||||
}
|
||||
#endif
|
||||
inline std::ostream& operator<<(std::ostream& out, simdjson::dom::object value) {
|
||||
simdjson::internal::string_builder<> sb;
|
||||
sb.append(value);
|
||||
return (out << sb.str());
|
||||
}
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::dom::object> x) {
|
||||
if (x.error()) { throw simdjson::simdjson_error(x.error()); }
|
||||
return (out << x.value());
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace dom
|
||||
|
||||
/***
|
||||
* Number utility functions
|
||||
**/
|
||||
|
||||
|
||||
namespace {
|
||||
/**@private
|
||||
* Escape sequence like \b or \u0001
|
||||
@@ -41,7 +81,7 @@ struct escape_sequence {
|
||||
* adds the to_chars functions which would do as well, but
|
||||
* we want to support C++11.
|
||||
*/
|
||||
char *fast_itoa(char *output, int64_t value) noexcept {
|
||||
static char *fast_itoa(char *output, int64_t value) noexcept {
|
||||
// This is a standard implementation of itoa.
|
||||
char buffer[20];
|
||||
uint64_t value_positive;
|
||||
@@ -83,7 +123,7 @@ char *fast_itoa(char *output, int64_t value) noexcept {
|
||||
* adds the to_chars functions which would do as well, but
|
||||
* we want to support C++11.
|
||||
*/
|
||||
char *fast_itoa(char *output, uint64_t value) noexcept {
|
||||
static char *fast_itoa(char *output, uint64_t value) noexcept {
|
||||
// This is a standard implementation of itoa.
|
||||
char buffer[20];
|
||||
const char *const end_buffer = buffer + 20;
|
||||
@@ -100,6 +140,8 @@ char *fast_itoa(char *output, uint64_t value) noexcept {
|
||||
std::memcpy(output, write_pointer, len);
|
||||
return output + len;
|
||||
}
|
||||
|
||||
|
||||
} // anonymous namespace
|
||||
namespace internal {
|
||||
|
||||
@@ -107,19 +149,22 @@ namespace internal {
|
||||
* Minifier/formatter code.
|
||||
**/
|
||||
|
||||
simdjson_inline void mini_formatter::number(uint64_t x) {
|
||||
template<class formatter>
|
||||
simdjson_inline void base_formatter<formatter>::number(uint64_t x) {
|
||||
char number_buffer[24];
|
||||
char *newp = fast_itoa(number_buffer, x);
|
||||
buffer.insert(buffer.end(), number_buffer, newp);
|
||||
}
|
||||
|
||||
simdjson_inline void mini_formatter::number(int64_t x) {
|
||||
template<class formatter>
|
||||
simdjson_inline void base_formatter<formatter>::number(int64_t x) {
|
||||
char number_buffer[24];
|
||||
char *newp = fast_itoa(number_buffer, x);
|
||||
buffer.insert(buffer.end(), number_buffer, newp);
|
||||
}
|
||||
|
||||
simdjson_inline void mini_formatter::number(double x) {
|
||||
template<class formatter>
|
||||
simdjson_inline void base_formatter<formatter>::number(double x) {
|
||||
char number_buffer[24];
|
||||
// Currently, passing the nullptr to the second argument is
|
||||
// safe because our implementation does not check the second
|
||||
@@ -128,31 +173,51 @@ simdjson_inline void mini_formatter::number(double x) {
|
||||
buffer.insert(buffer.end(), number_buffer, newp);
|
||||
}
|
||||
|
||||
simdjson_inline void mini_formatter::start_array() { one_char('['); }
|
||||
simdjson_inline void mini_formatter::end_array() { one_char(']'); }
|
||||
simdjson_inline void mini_formatter::start_object() { one_char('{'); }
|
||||
simdjson_inline void mini_formatter::end_object() { one_char('}'); }
|
||||
simdjson_inline void mini_formatter::comma() { one_char(','); }
|
||||
template<class formatter>
|
||||
simdjson_inline void base_formatter<formatter>::start_array() { one_char('['); }
|
||||
|
||||
|
||||
simdjson_inline void mini_formatter::true_atom() {
|
||||
template<class formatter>
|
||||
simdjson_inline void base_formatter<formatter>::end_array() { one_char(']'); }
|
||||
|
||||
template<class formatter>
|
||||
simdjson_inline void base_formatter<formatter>::start_object() { one_char('{'); }
|
||||
|
||||
template<class formatter>
|
||||
simdjson_inline void base_formatter<formatter>::end_object() { one_char('}'); }
|
||||
|
||||
template<class formatter>
|
||||
simdjson_inline void base_formatter<formatter>::comma() { one_char(','); }
|
||||
|
||||
template<class formatter>
|
||||
simdjson_inline void base_formatter<formatter>::true_atom() {
|
||||
const char * s = "true";
|
||||
buffer.insert(buffer.end(), s, s + 4);
|
||||
}
|
||||
simdjson_inline void mini_formatter::false_atom() {
|
||||
|
||||
template<class formatter>
|
||||
simdjson_inline void base_formatter<formatter>::false_atom() {
|
||||
const char * s = "false";
|
||||
buffer.insert(buffer.end(), s, s + 5);
|
||||
}
|
||||
simdjson_inline void mini_formatter::null_atom() {
|
||||
|
||||
template<class formatter>
|
||||
simdjson_inline void base_formatter<formatter>::null_atom() {
|
||||
const char * s = "null";
|
||||
buffer.insert(buffer.end(), s, s + 4);
|
||||
}
|
||||
simdjson_inline void mini_formatter::one_char(char c) { buffer.push_back(c); }
|
||||
simdjson_inline void mini_formatter::key(std::string_view unescaped) {
|
||||
|
||||
template<class formatter>
|
||||
simdjson_inline void base_formatter<formatter>::one_char(char c) { buffer.push_back(c); }
|
||||
|
||||
template<class formatter>
|
||||
simdjson_inline void base_formatter<formatter>::key(std::string_view unescaped) {
|
||||
string(unescaped);
|
||||
one_char(':');
|
||||
}
|
||||
simdjson_inline void mini_formatter::string(std::string_view unescaped) {
|
||||
|
||||
template<class formatter>
|
||||
simdjson_inline void base_formatter<formatter>::string(std::string_view unescaped) {
|
||||
one_char('\"');
|
||||
size_t i = 0;
|
||||
// Fast path for the case where we have no control character, no ", and no backslash.
|
||||
@@ -231,14 +296,46 @@ simdjson_inline void mini_formatter::string(std::string_view unescaped) {
|
||||
one_char('\"');
|
||||
}
|
||||
|
||||
inline void mini_formatter::clear() {
|
||||
|
||||
template<class formatter>
|
||||
inline void base_formatter<formatter>::clear() {
|
||||
buffer.clear();
|
||||
}
|
||||
|
||||
simdjson_inline std::string_view mini_formatter::str() const {
|
||||
template<class formatter>
|
||||
simdjson_inline std::string_view base_formatter<formatter>::str() const {
|
||||
return std::string_view(buffer.data(), buffer.size());
|
||||
}
|
||||
|
||||
simdjson_inline void mini_formatter::print_newline() {
|
||||
return;
|
||||
}
|
||||
|
||||
simdjson_inline void mini_formatter::print_indents(size_t depth) {
|
||||
(void)depth;
|
||||
return;
|
||||
}
|
||||
|
||||
simdjson_inline void mini_formatter::print_space() {
|
||||
return;
|
||||
}
|
||||
|
||||
simdjson_inline void pretty_formatter::print_newline() {
|
||||
one_char('\n');
|
||||
}
|
||||
|
||||
simdjson_inline void pretty_formatter::print_indents(size_t depth) {
|
||||
if(this->indent_step <= 0) {
|
||||
return;
|
||||
}
|
||||
for(size_t i = 0; i < this->indent_step * depth; i++) {
|
||||
one_char(' ');
|
||||
}
|
||||
}
|
||||
|
||||
simdjson_inline void pretty_formatter::print_space() {
|
||||
one_char(' ');
|
||||
}
|
||||
|
||||
/***
|
||||
* String building code.
|
||||
@@ -258,11 +355,16 @@ inline void string_builder<serializer>::append(simdjson::dom::element value) {
|
||||
// print commas after each value
|
||||
if (after_value) {
|
||||
format.comma();
|
||||
format.print_newline();
|
||||
}
|
||||
|
||||
format.print_indents(depth);
|
||||
|
||||
// If we are in an object, print the next key and :, and skip to the next
|
||||
// value.
|
||||
if (is_object[depth]) {
|
||||
format.key(iter.get_string_view());
|
||||
format.print_space();
|
||||
iter.json_index++;
|
||||
}
|
||||
switch (iter.tape_ref_type()) {
|
||||
@@ -291,6 +393,7 @@ inline void string_builder<serializer>::append(simdjson::dom::element value) {
|
||||
|
||||
is_object[depth] = false;
|
||||
after_value = false;
|
||||
format.print_newline();
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -318,6 +421,7 @@ inline void string_builder<serializer>::append(simdjson::dom::element value) {
|
||||
|
||||
is_object[depth] = true;
|
||||
after_value = false;
|
||||
format.print_newline();
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -362,17 +466,21 @@ inline void string_builder<serializer>::append(simdjson::dom::element value) {
|
||||
// Handle multiple ends in a row
|
||||
while (depth != 0 && (iter.tape_ref_type() == tape_type::END_ARRAY ||
|
||||
iter.tape_ref_type() == tape_type::END_OBJECT)) {
|
||||
format.print_newline();
|
||||
depth--;
|
||||
format.print_indents(depth);
|
||||
if (iter.tape_ref_type() == tape_type::END_ARRAY) {
|
||||
format.end_array();
|
||||
} else {
|
||||
format.end_object();
|
||||
}
|
||||
depth--;
|
||||
iter.json_index++;
|
||||
}
|
||||
|
||||
// Stop when we're at depth 0
|
||||
} while (depth != 0);
|
||||
|
||||
format.print_newline();
|
||||
}
|
||||
|
||||
template <class serializer>
|
||||
|
||||
@@ -1,13 +1,10 @@
|
||||
#ifndef SIMDJSON_SERIALIZATION_H
|
||||
#define SIMDJSON_SERIALIZATION_H
|
||||
|
||||
#include "simdjson/common_defs.h"
|
||||
#include "simdjson/dom/document.h"
|
||||
#include "simdjson/error.h"
|
||||
#include "simdjson/internal/dom_parser_implementation.h"
|
||||
#include "simdjson/internal/tape_ref.h"
|
||||
#include "simdjson/padded_string.h"
|
||||
#include "simdjson/portability.h"
|
||||
#include "simdjson/dom/base.h"
|
||||
#include "simdjson/dom/element.h"
|
||||
#include "simdjson/dom/object.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace simdjson {
|
||||
@@ -19,7 +16,90 @@ namespace simdjson {
|
||||
*/
|
||||
namespace internal {
|
||||
|
||||
class mini_formatter;
|
||||
template<class formatter>
|
||||
class base_formatter {
|
||||
public:
|
||||
/** Add a comma **/
|
||||
simdjson_inline void comma();
|
||||
/** Start an array, prints [ **/
|
||||
simdjson_inline void start_array();
|
||||
/** End an array, prints ] **/
|
||||
simdjson_inline void end_array();
|
||||
/** Start an array, prints { **/
|
||||
simdjson_inline void start_object();
|
||||
/** Start an array, prints } **/
|
||||
simdjson_inline void end_object();
|
||||
/** Prints a true **/
|
||||
simdjson_inline void true_atom();
|
||||
/** Prints a false **/
|
||||
simdjson_inline void false_atom();
|
||||
/** Prints a null **/
|
||||
simdjson_inline void null_atom();
|
||||
/** Prints a number **/
|
||||
simdjson_inline void number(int64_t x);
|
||||
/** Prints a number **/
|
||||
simdjson_inline void number(uint64_t x);
|
||||
/** Prints a number **/
|
||||
simdjson_inline void number(double x);
|
||||
/** Prints a key (string + colon) **/
|
||||
simdjson_inline void key(std::string_view unescaped);
|
||||
/** Prints a string. The string is escaped as needed. **/
|
||||
simdjson_inline void string(std::string_view unescaped);
|
||||
/** Clears out the content. **/
|
||||
simdjson_inline void clear();
|
||||
/**
|
||||
* Get access to the buffer, it is owned by the instance, but
|
||||
* the user can make a copy.
|
||||
**/
|
||||
simdjson_inline std::string_view str() const;
|
||||
|
||||
/** Prints one character **/
|
||||
simdjson_inline void one_char(char c);
|
||||
|
||||
simdjson_inline void call_print_newline() {
|
||||
this->print_newline();
|
||||
}
|
||||
|
||||
simdjson_inline void call_print_indents(size_t depth) {
|
||||
this->print_indents(depth);
|
||||
}
|
||||
|
||||
simdjson_inline void call_print_space() {
|
||||
this->print_space();
|
||||
}
|
||||
|
||||
protected:
|
||||
// implementation details (subject to change)
|
||||
/** Backing buffer **/
|
||||
std::vector<char> buffer{}; // not ideal!
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @private This is the class that we expect to use with the string_builder
|
||||
* template. It tries to produce a compact version of the JSON element
|
||||
* as quickly as possible.
|
||||
*/
|
||||
class mini_formatter : public base_formatter<mini_formatter> {
|
||||
public:
|
||||
simdjson_inline void print_newline();
|
||||
|
||||
simdjson_inline void print_indents(size_t depth);
|
||||
|
||||
simdjson_inline void print_space();
|
||||
};
|
||||
|
||||
class pretty_formatter : public base_formatter<pretty_formatter> {
|
||||
public:
|
||||
simdjson_inline void print_newline();
|
||||
|
||||
simdjson_inline void print_indents(size_t depth);
|
||||
|
||||
simdjson_inline void print_space();
|
||||
|
||||
protected:
|
||||
int indent_step = 4;
|
||||
};
|
||||
|
||||
/**
|
||||
* @private The string_builder template allows us to construct
|
||||
@@ -55,56 +135,6 @@ private:
|
||||
formatter format{};
|
||||
};
|
||||
|
||||
/**
|
||||
* @private This is the class that we expect to use with the string_builder
|
||||
* template. It tries to produce a compact version of the JSON element
|
||||
* as quickly as possible.
|
||||
*/
|
||||
class mini_formatter {
|
||||
public:
|
||||
mini_formatter() = default;
|
||||
/** Add a comma **/
|
||||
simdjson_inline void comma();
|
||||
/** Start an array, prints [ **/
|
||||
simdjson_inline void start_array();
|
||||
/** End an array, prints ] **/
|
||||
simdjson_inline void end_array();
|
||||
/** Start an array, prints { **/
|
||||
simdjson_inline void start_object();
|
||||
/** Start an array, prints } **/
|
||||
simdjson_inline void end_object();
|
||||
/** Prints a true **/
|
||||
simdjson_inline void true_atom();
|
||||
/** Prints a false **/
|
||||
simdjson_inline void false_atom();
|
||||
/** Prints a null **/
|
||||
simdjson_inline void null_atom();
|
||||
/** Prints a number **/
|
||||
simdjson_inline void number(int64_t x);
|
||||
/** Prints a number **/
|
||||
simdjson_inline void number(uint64_t x);
|
||||
/** Prints a number **/
|
||||
simdjson_inline void number(double x);
|
||||
/** Prints a key (string + colon) **/
|
||||
simdjson_inline void key(std::string_view unescaped);
|
||||
/** Prints a string. The string is escaped as needed. **/
|
||||
simdjson_inline void string(std::string_view unescaped);
|
||||
/** Clears out the content. **/
|
||||
simdjson_inline void clear();
|
||||
/**
|
||||
* Get access to the buffer, it is owned by the instance, but
|
||||
* the user can make a copy.
|
||||
**/
|
||||
simdjson_inline std::string_view str() const;
|
||||
|
||||
private:
|
||||
// implementation details (subject to change)
|
||||
/** Prints one character **/
|
||||
simdjson_inline void one_char(char c);
|
||||
/** Backing buffer **/
|
||||
std::vector<char> buffer{}; // not ideal!
|
||||
};
|
||||
|
||||
} // internal
|
||||
|
||||
namespace dom {
|
||||
@@ -116,16 +146,9 @@ namespace dom {
|
||||
* @param value The element.
|
||||
* @throw if there is an error with the underlying output stream. simdjson itself will not throw.
|
||||
*/
|
||||
inline std::ostream& operator<<(std::ostream& out, simdjson::dom::element value) {
|
||||
simdjson::internal::string_builder<> sb;
|
||||
sb.append(value);
|
||||
return (out << sb.str());
|
||||
}
|
||||
inline std::ostream& operator<<(std::ostream& out, simdjson::dom::element value);
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::dom::element> x) {
|
||||
if (x.error()) { throw simdjson::simdjson_error(x.error()); }
|
||||
return (out << x.value());
|
||||
}
|
||||
inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::dom::element> x);
|
||||
#endif
|
||||
/**
|
||||
* Print JSON to an output stream.
|
||||
@@ -134,16 +157,9 @@ inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<sim
|
||||
* @param value The array.
|
||||
* @throw if there is an error with the underlying output stream. simdjson itself will not throw.
|
||||
*/
|
||||
inline std::ostream& operator<<(std::ostream& out, simdjson::dom::array value) {
|
||||
simdjson::internal::string_builder<> sb;
|
||||
sb.append(value);
|
||||
return (out << sb.str());
|
||||
}
|
||||
inline std::ostream& operator<<(std::ostream& out, simdjson::dom::array value);
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::dom::array> x) {
|
||||
if (x.error()) { throw simdjson::simdjson_error(x.error()); }
|
||||
return (out << x.value());
|
||||
}
|
||||
inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::dom::array> x);
|
||||
#endif
|
||||
/**
|
||||
* Print JSON to an output stream.
|
||||
@@ -152,16 +168,9 @@ inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<sim
|
||||
* @param value The object.
|
||||
* @throw if there is an error with the underlying output stream. simdjson itself will not throw.
|
||||
*/
|
||||
inline std::ostream& operator<<(std::ostream& out, simdjson::dom::object value) {
|
||||
simdjson::internal::string_builder<> sb;
|
||||
sb.append(value);
|
||||
return (out << sb.str());
|
||||
}
|
||||
inline std::ostream& operator<<(std::ostream& out, simdjson::dom::object value);
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::dom::object> x) {
|
||||
if (x.error()) { throw simdjson::simdjson_error(x.error()); }
|
||||
return (out << x.value());
|
||||
}
|
||||
inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::dom::object> x);
|
||||
#endif
|
||||
} // namespace dom
|
||||
|
||||
@@ -212,6 +221,38 @@ std::string minify(simdjson_result<T> x) {
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Prettifies a JSON element or document, printing the valid JSON with indentation.
|
||||
*
|
||||
* dom::parser parser;
|
||||
* element doc = parser.parse(" [ 1 , 2 , 3 ] "_padded);
|
||||
*
|
||||
* // Prints:
|
||||
* // {
|
||||
* // [
|
||||
* // 1,
|
||||
* // 2,
|
||||
* // 3
|
||||
* // ]
|
||||
* // }
|
||||
* cout << prettify(doc) << endl;
|
||||
*
|
||||
*/
|
||||
template <class T>
|
||||
std::string prettify(T x) {
|
||||
simdjson::internal::string_builder<simdjson::internal::pretty_formatter> sb;
|
||||
sb.append(x);
|
||||
std::string_view answer = sb.str();
|
||||
return std::string(answer.data(), answer.size());
|
||||
}
|
||||
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
template <class T>
|
||||
std::string prettify(simdjson_result<T> x) {
|
||||
if (x.error()) { throw simdjson_error(x.error()); }
|
||||
return to_string(x.value());
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace simdjson
|
||||
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
#ifndef SIMDJSON_INLINE_ERROR_H
|
||||
#define SIMDJSON_INLINE_ERROR_H
|
||||
#ifndef SIMDJSON_ERROR_INL_H
|
||||
#define SIMDJSON_ERROR_INL_H
|
||||
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include "simdjson/error.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
namespace simdjson {
|
||||
namespace internal {
|
||||
// We store the error code so we can validate the error message is associated with the right code
|
||||
@@ -182,4 +181,4 @@ simdjson_inline simdjson_result<T>::simdjson_result() noexcept
|
||||
|
||||
} // namespace simdjson
|
||||
|
||||
#endif // SIMDJSON_INLINE_ERROR_H
|
||||
#endif // SIMDJSON_ERROR_INL_H
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
#ifndef SIMDJSON_ERROR_H
|
||||
#define SIMDJSON_ERROR_H
|
||||
|
||||
#include "simdjson/common_defs.h"
|
||||
#include "simdjson/base.h"
|
||||
|
||||
#include <string>
|
||||
#include <ostream>
|
||||
|
||||
namespace simdjson {
|
||||
|
||||
|
||||
@@ -1,30 +1,8 @@
|
||||
#ifndef SIMDJSON_FALLBACK_H
|
||||
#define SIMDJSON_FALLBACK_H
|
||||
|
||||
#include "simdjson/implementation-base.h"
|
||||
|
||||
#if SIMDJSON_IMPLEMENTATION_FALLBACK
|
||||
|
||||
namespace simdjson {
|
||||
/**
|
||||
* Fallback implementation (runs on any machine).
|
||||
*/
|
||||
namespace fallback {
|
||||
} // namespace fallback
|
||||
} // namespace simdjson
|
||||
|
||||
#include "simdjson/fallback/implementation.h"
|
||||
|
||||
#include "simdjson/fallback/begin.h"
|
||||
|
||||
// Declarations
|
||||
#include "simdjson/generic/dom_parser_implementation.h"
|
||||
#include "simdjson/fallback/bitmanipulation.h"
|
||||
#include "simdjson/generic/jsoncharutils.h"
|
||||
#include "simdjson/generic/atomparsing.h"
|
||||
#include "simdjson/fallback/stringparsing.h"
|
||||
#include "simdjson/fallback/numberparsing.h"
|
||||
#include "simdjson/generic/amalgamated.h"
|
||||
#include "simdjson/fallback/end.h"
|
||||
|
||||
#endif // SIMDJSON_IMPLEMENTATION_FALLBACK
|
||||
#endif // SIMDJSON_FALLBACK_H
|
||||
#endif // SIMDJSON_FALLBACK_H
|
||||
@@ -0,0 +1,19 @@
|
||||
#ifndef SIMDJSON_FALLBACK_BASE_H
|
||||
#define SIMDJSON_FALLBACK_BASE_H
|
||||
|
||||
#ifndef SIMDJSON_CONDITIONAL_INCLUDE
|
||||
#include "simdjson/base.h"
|
||||
#endif // SIMDJSON_CONDITIONAL_INCLUDE
|
||||
|
||||
namespace simdjson {
|
||||
/**
|
||||
* Fallback implementation (runs on any machine).
|
||||
*/
|
||||
namespace fallback {
|
||||
|
||||
class implementation;
|
||||
|
||||
} // namespace fallback
|
||||
} // namespace simdjson
|
||||
|
||||
#endif // SIMDJSON_FALLBACK_BASE_H
|
||||
@@ -1 +1,5 @@
|
||||
#define SIMDJSON_IMPLEMENTATION fallback
|
||||
#include "simdjson/fallback/base.h"
|
||||
#include "simdjson/fallback/bitmask.h"
|
||||
#include "simdjson/fallback/stringparsing_defs.h"
|
||||
#include "simdjson/fallback/numberparsing_defs.h"
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
#ifndef SIMDJSON_FALLBACK_BITMANIPULATION_H
|
||||
#define SIMDJSON_FALLBACK_BITMANIPULATION_H
|
||||
#ifndef SIMDJSON_FALLBACK_BITMASK_H
|
||||
#define SIMDJSON_FALLBACK_BITMASK_H
|
||||
|
||||
#include "simdjson/base.h"
|
||||
#include <limits>
|
||||
#ifndef SIMDJSON_CONDITIONAL_INCLUDE
|
||||
#include "simdjson/fallback/base.h"
|
||||
#endif // SIMDJSON_CONDITIONAL_INCLUDE
|
||||
|
||||
namespace simdjson {
|
||||
namespace SIMDJSON_IMPLEMENTATION {
|
||||
namespace {
|
||||
namespace fallback {
|
||||
namespace bitmask {
|
||||
|
||||
#if defined(_MSC_VER) && !defined(_M_ARM64) && !defined(_M_X64)
|
||||
static inline unsigned char _BitScanForward64(unsigned long* ret, uint64_t x) {
|
||||
@@ -41,7 +42,7 @@ simdjson_inline int leading_zeroes(uint64_t input_num) {
|
||||
}
|
||||
|
||||
} // unnamed namespace
|
||||
} // namespace SIMDJSON_IMPLEMENTATION
|
||||
} // namespace fallback
|
||||
} // namespace simdjson
|
||||
|
||||
#endif // SIMDJSON_FALLBACK_BITMANIPULATION_H
|
||||
@@ -1 +1,5 @@
|
||||
#ifndef SIMDJSON_CONDITIONAL_INCLUDE
|
||||
#include "simdjson/fallback/base.h"
|
||||
#endif // SIMDJSON_CONDITIONAL_INCLUDE
|
||||
|
||||
#undef SIMDJSON_IMPLEMENTATION
|
||||
|
||||
@@ -1,16 +1,14 @@
|
||||
#ifndef SIMDJSON_FALLBACK_IMPLEMENTATION_H
|
||||
#define SIMDJSON_FALLBACK_IMPLEMENTATION_H
|
||||
|
||||
#ifndef SIMDJSON_CONDITIONAL_INCLUDE
|
||||
#include "simdjson/fallback/base.h"
|
||||
#include "simdjson/implementation.h"
|
||||
#endif // SIMDJSON_CONDITIONAL_INCLUDE
|
||||
|
||||
namespace simdjson {
|
||||
namespace fallback {
|
||||
|
||||
namespace {
|
||||
using namespace simdjson;
|
||||
using namespace simdjson::dom;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
@@ -24,7 +22,7 @@ public:
|
||||
simdjson_warn_unused error_code create_dom_parser_implementation(
|
||||
size_t capacity,
|
||||
size_t max_length,
|
||||
std::unique_ptr<internal::dom_parser_implementation>& dst
|
||||
std::unique_ptr<simdjson::internal::dom_parser_implementation>& dst
|
||||
) const noexcept final;
|
||||
simdjson_warn_unused error_code minify(const uint8_t *buf, size_t len, uint8_t *dst, size_t &dst_len) const noexcept final;
|
||||
simdjson_warn_unused bool validate_utf8(const char *buf, size_t len) const noexcept final;
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
#ifndef SIMDJSON_FALLBACK_NUMBERPARSING_H
|
||||
#define SIMDJSON_FALLBACK_NUMBERPARSING_H
|
||||
|
||||
#ifdef JSON_TEST_NUMBERS // for unit testing
|
||||
void found_invalid_number(const uint8_t *buf);
|
||||
void found_integer(int64_t result, const uint8_t *buf);
|
||||
void found_unsigned_integer(uint64_t result, const uint8_t *buf);
|
||||
void found_float(double result, const uint8_t *buf);
|
||||
#endif
|
||||
|
||||
namespace simdjson {
|
||||
namespace SIMDJSON_IMPLEMENTATION {
|
||||
namespace {
|
||||
// credit: https://johnnylee-sde.github.io/Fast-numeric-string-to-int/
|
||||
static simdjson_inline uint32_t parse_eight_digits_unrolled(const char *chars) {
|
||||
uint64_t val;
|
||||
memcpy(&val, chars, sizeof(uint64_t));
|
||||
val = (val & 0x0F0F0F0F0F0F0F0F) * 2561 >> 8;
|
||||
val = (val & 0x00FF00FF00FF00FF) * 6553601 >> 16;
|
||||
return uint32_t((val & 0x0000FFFF0000FFFF) * 42949672960001 >> 32);
|
||||
}
|
||||
static simdjson_inline uint32_t parse_eight_digits_unrolled(const uint8_t *chars) {
|
||||
return parse_eight_digits_unrolled(reinterpret_cast<const char *>(chars));
|
||||
}
|
||||
|
||||
} // unnamed namespace
|
||||
} // namespace SIMDJSON_IMPLEMENTATION
|
||||
} // namespace simdjson
|
||||
|
||||
#define SIMDJSON_SWAR_NUMBER_PARSING 1
|
||||
|
||||
#include "simdjson/generic/numberparsing.h"
|
||||
|
||||
#endif // SIMDJSON_FALLBACK_NUMBERPARSING_H
|
||||
@@ -0,0 +1,80 @@
|
||||
#ifndef SIMDJSON_FALLBACK_NUMBERPARSING_DEFS_H
|
||||
#define SIMDJSON_FALLBACK_NUMBERPARSING_DEFS_H
|
||||
|
||||
#ifndef SIMDJSON_CONDITIONAL_INCLUDE
|
||||
#include "simdjson/fallback/base.h"
|
||||
#include "simdjson/internal/numberparsing_tables.h"
|
||||
#endif // SIMDJSON_CONDITIONAL_INCLUDE
|
||||
|
||||
#include <cstring>
|
||||
|
||||
#ifdef JSON_TEST_NUMBERS // for unit testing
|
||||
void found_invalid_number(const uint8_t *buf);
|
||||
void found_integer(int64_t result, const uint8_t *buf);
|
||||
void found_unsigned_integer(uint64_t result, const uint8_t *buf);
|
||||
void found_float(double result, const uint8_t *buf);
|
||||
#endif
|
||||
|
||||
namespace simdjson {
|
||||
namespace fallback {
|
||||
namespace numberparsing {
|
||||
|
||||
// credit: https://johnnylee-sde.github.io/Fast-numeric-string-to-int/
|
||||
/** @private */
|
||||
static simdjson_inline uint32_t parse_eight_digits_unrolled(const char *chars) {
|
||||
uint64_t val;
|
||||
memcpy(&val, chars, sizeof(uint64_t));
|
||||
val = (val & 0x0F0F0F0F0F0F0F0F) * 2561 >> 8;
|
||||
val = (val & 0x00FF00FF00FF00FF) * 6553601 >> 16;
|
||||
return uint32_t((val & 0x0000FFFF0000FFFF) * 42949672960001 >> 32);
|
||||
}
|
||||
|
||||
/** @private */
|
||||
static simdjson_inline uint32_t parse_eight_digits_unrolled(const uint8_t *chars) {
|
||||
return parse_eight_digits_unrolled(reinterpret_cast<const char *>(chars));
|
||||
}
|
||||
|
||||
#if SIMDJSON_IS_32BITS // _umul128 for x86, arm
|
||||
// this is a slow emulation routine for 32-bit
|
||||
//
|
||||
static simdjson_inline uint64_t __emulu(uint32_t x, uint32_t y) {
|
||||
return x * (uint64_t)y;
|
||||
}
|
||||
static simdjson_inline uint64_t _umul128(uint64_t ab, uint64_t cd, uint64_t *hi) {
|
||||
uint64_t ad = __emulu((uint32_t)(ab >> 32), (uint32_t)cd);
|
||||
uint64_t bd = __emulu((uint32_t)ab, (uint32_t)cd);
|
||||
uint64_t adbc = ad + __emulu((uint32_t)ab, (uint32_t)(cd >> 32));
|
||||
uint64_t adbc_carry = !!(adbc < ad);
|
||||
uint64_t lo = bd + (adbc << 32);
|
||||
*hi = __emulu((uint32_t)(ab >> 32), (uint32_t)(cd >> 32)) + (adbc >> 32) +
|
||||
(adbc_carry << 32) + !!(lo < bd);
|
||||
return lo;
|
||||
}
|
||||
#endif
|
||||
|
||||
/** @private */
|
||||
simdjson_inline internal::value128 full_multiplication(uint64_t value1, uint64_t value2) {
|
||||
internal::value128 answer;
|
||||
#if SIMDJSON_REGULAR_VISUAL_STUDIO || SIMDJSON_IS_32BITS
|
||||
#ifdef _M_ARM64
|
||||
// ARM64 has native support for 64-bit multiplications, no need to emultate
|
||||
answer.high = __umulh(value1, value2);
|
||||
answer.low = value1 * value2;
|
||||
#else
|
||||
answer.low = _umul128(value1, value2, &answer.high); // _umul128 not available on ARM64
|
||||
#endif // _M_ARM64
|
||||
#else // SIMDJSON_REGULAR_VISUAL_STUDIO || SIMDJSON_IS_32BITS
|
||||
__uint128_t r = (static_cast<__uint128_t>(value1)) * value2;
|
||||
answer.low = uint64_t(r);
|
||||
answer.high = uint64_t(r >> 64);
|
||||
#endif
|
||||
return answer;
|
||||
}
|
||||
|
||||
} // namespace numberparsing
|
||||
} // namespace fallback
|
||||
} // namespace simdjson
|
||||
|
||||
#define SIMDJSON_SWAR_NUMBER_PARSING 1
|
||||
|
||||
#endif // SIMDJSON_FALLBACK_NUMBERPARSING_DEFS_H
|
||||
@@ -0,0 +1,8 @@
|
||||
#ifndef SIMDJSON_FALLBACK_ONDEMAND_H
|
||||
#define SIMDJSON_FALLBACK_ONDEMAND_H
|
||||
|
||||
#include "simdjson/fallback/begin.h"
|
||||
#include "simdjson/generic/ondemand/amalgamated.h"
|
||||
#include "simdjson/fallback/end.h"
|
||||
|
||||
#endif // SIMDJSON_FALLBACK_ONDEMAND_H
|
||||
+8
-6
@@ -1,10 +1,12 @@
|
||||
#ifndef SIMDJSON_FALLBACK_STRINGPARSING_H
|
||||
#define SIMDJSON_FALLBACK_STRINGPARSING_H
|
||||
#ifndef SIMDJSON_FALLBACK_STRINGPARSING_DEFS_H
|
||||
#define SIMDJSON_FALLBACK_STRINGPARSING_DEFS_H
|
||||
|
||||
#include "simdjson/base.h"
|
||||
#ifndef SIMDJSON_CONDITIONAL_INCLUDE
|
||||
#include "simdjson/fallback/base.h"
|
||||
#endif // SIMDJSON_CONDITIONAL_INCLUDE
|
||||
|
||||
namespace simdjson {
|
||||
namespace SIMDJSON_IMPLEMENTATION {
|
||||
namespace fallback {
|
||||
namespace {
|
||||
|
||||
// Holds backslashes and quotes locations.
|
||||
@@ -28,7 +30,7 @@ simdjson_inline backslash_and_quote backslash_and_quote::copy_and_find(const uin
|
||||
}
|
||||
|
||||
} // unnamed namespace
|
||||
} // namespace SIMDJSON_IMPLEMENTATION
|
||||
} // namespace fallback
|
||||
} // namespace simdjson
|
||||
|
||||
#endif // SIMDJSON_FALLBACK_STRINGPARSING_H
|
||||
#endif // SIMDJSON_FALLBACK_STRINGPARSING_DEFS_H
|
||||
@@ -0,0 +1,12 @@
|
||||
#if defined(SIMDJSON_CONDITIONAL_INCLUDE) && !defined(SIMDJSON_GENERIC_DEPENDENCIES_H)
|
||||
#error simdjson/generic/dependencies.h must be included before simdjson/generic/amalgamated.h!
|
||||
#endif
|
||||
|
||||
#include "simdjson/generic/base.h"
|
||||
#include "simdjson/generic/jsoncharutils.h"
|
||||
#include "simdjson/generic/atomparsing.h"
|
||||
#include "simdjson/generic/dom_parser_implementation.h"
|
||||
#include "simdjson/generic/implementation_simdjson_result_base.h"
|
||||
#include "simdjson/generic/numberparsing.h"
|
||||
|
||||
#include "simdjson/generic/implementation_simdjson_result_base-inl.h"
|
||||
@@ -1,3 +1,13 @@
|
||||
#ifndef SIMDJSON_GENERIC_ATOMPARSING_H
|
||||
|
||||
#ifndef SIMDJSON_CONDITIONAL_INCLUDE
|
||||
#define SIMDJSON_GENERIC_ATOMPARSING_H
|
||||
#include "simdjson/generic/base.h"
|
||||
#include "simdjson/generic/jsoncharutils.h"
|
||||
#endif // SIMDJSON_CONDITIONAL_INCLUDE
|
||||
|
||||
#include <cstring>
|
||||
|
||||
namespace simdjson {
|
||||
namespace SIMDJSON_IMPLEMENTATION {
|
||||
namespace {
|
||||
@@ -63,3 +73,5 @@ simdjson_inline bool is_valid_null_atom(const uint8_t *src, size_t len) {
|
||||
} // unnamed namespace
|
||||
} // namespace SIMDJSON_IMPLEMENTATION
|
||||
} // namespace simdjson
|
||||
|
||||
#endif // SIMDJSON_GENERIC_ATOMPARSING_H
|
||||
@@ -0,0 +1,46 @@
|
||||
#ifndef SIMDJSON_GENERIC_BASE_H
|
||||
|
||||
#ifndef SIMDJSON_CONDITIONAL_INCLUDE
|
||||
#define SIMDJSON_GENERIC_BASE_H
|
||||
#include "simdjson/base.h"
|
||||
// If we haven't got an implementation yet, we're in the editor, editing a generic file! Just
|
||||
// use the most advanced one we can so the most possible stuff can be tested.
|
||||
#ifndef SIMDJSON_IMPLEMENTATION
|
||||
#include "simdjson/implementation_detection.h"
|
||||
#if SIMDJSON_IMPLEMENTATION_ICELAKE
|
||||
#include "simdjson/icelake/begin.h"
|
||||
#elif SIMDJSON_IMPLEMENTATION_HASWELL
|
||||
#include "simdjson/haswell/begin.h"
|
||||
#elif SIMDJSON_IMPLEMENTATION_WESTMERE
|
||||
#include "simdjson/westmere/begin.h"
|
||||
#elif SIMDJSON_IMPLEMENTATION_ARM64
|
||||
#include "simdjson/arm64/begin.h"
|
||||
#elif SIMDJSON_IMPLEMENTATION_PPC64
|
||||
#include "simdjson/ppc64/begin.h"
|
||||
#elif SIMDJSON_IMPLEMENTATION_FALLBACK
|
||||
#include "simdjson/fallback/begin.h"
|
||||
#else
|
||||
#error "All possible implementations (including fallback) have been disabled! simdjson will not run."
|
||||
#endif
|
||||
#endif // SIMDJSON_IMPLEMENTATION
|
||||
#endif // SIMDJSON_CONDITIONAL_INCLUDE
|
||||
|
||||
namespace simdjson {
|
||||
namespace SIMDJSON_IMPLEMENTATION {
|
||||
|
||||
struct open_container;
|
||||
class dom_parser_implementation;
|
||||
|
||||
/**
|
||||
* The type of a JSON number
|
||||
*/
|
||||
enum class number_type {
|
||||
floating_point_number=1, /// a binary64 number
|
||||
signed_integer, /// a signed integer that fits in a 64-bit word using two's complement
|
||||
unsigned_integer /// a positive integer larger or equal to 1<<63
|
||||
};
|
||||
|
||||
} // namespace SIMDJSON_IMPLEMENTATION
|
||||
} // namespace simdjson
|
||||
|
||||
#endif // SIMDJSON_GENERIC_BASE_H
|
||||
@@ -0,0 +1,20 @@
|
||||
#ifdef SIMDJSON_CONDITIONAL_INCLUDE
|
||||
#error simdjson/generic/dependencies.h must be included before defining SIMDJSON_CONDITIONAL_INCLUDE!
|
||||
#endif
|
||||
|
||||
#ifndef SIMDJSON_GENERIC_DEPENDENCIES_H
|
||||
#define SIMDJSON_GENERIC_DEPENDENCIES_H
|
||||
|
||||
// Internal headers needed for generics.
|
||||
// All includes referencing simdjson headers *not* under simdjson/generic must be here!
|
||||
// Otherwise, amalgamation will fail.
|
||||
#include "simdjson/base.h"
|
||||
#include "simdjson/implementation.h"
|
||||
#include "simdjson/implementation_detection.h"
|
||||
#include "simdjson/internal/instruction_set.h"
|
||||
#include "simdjson/internal/dom_parser_implementation.h"
|
||||
#include "simdjson/internal/jsoncharutils_tables.h"
|
||||
#include "simdjson/internal/numberparsing_tables.h"
|
||||
#include "simdjson/internal/simdprune_tables.h"
|
||||
|
||||
#endif // SIMDJSON_GENERIC_DEPENDENCIES_H
|
||||
@@ -1,5 +1,10 @@
|
||||
#include "simdjson/base.h"
|
||||
#include "simdjson/internal/isadetection.h"
|
||||
#ifndef SIMDJSON_GENERIC_DOM_PARSER_IMPLEMENTATION_H
|
||||
|
||||
#ifndef SIMDJSON_CONDITIONAL_INCLUDE
|
||||
#define SIMDJSON_GENERIC_DOM_PARSER_IMPLEMENTATION_H
|
||||
#include "simdjson/generic/base.h"
|
||||
#include "simdjson/internal/dom_parser_implementation.h"
|
||||
#endif // SIMDJSON_CONDITIONAL_INCLUDE
|
||||
|
||||
namespace simdjson {
|
||||
namespace SIMDJSON_IMPLEMENTATION {
|
||||
@@ -80,3 +85,5 @@ inline simdjson_warn_unused error_code dom_parser_implementation::set_max_depth(
|
||||
|
||||
} // namespace SIMDJSON_IMPLEMENTATION
|
||||
} // namespace simdjson
|
||||
|
||||
#endif // SIMDJSON_GENERIC_DOM_PARSER_IMPLEMENTATION_H
|
||||
@@ -1,3 +1,11 @@
|
||||
#ifndef SIMDJSON_GENERIC_IMPLEMENTATION_SIMDJSON_RESULT_BASE_INL_H
|
||||
|
||||
#ifndef SIMDJSON_CONDITIONAL_INCLUDE
|
||||
#define SIMDJSON_GENERIC_IMPLEMENTATION_SIMDJSON_RESULT_BASE_INL_H
|
||||
#include "simdjson/generic/base.h"
|
||||
#include "simdjson/generic/implementation_simdjson_result_base.h"
|
||||
#endif // SIMDJSON_CONDITIONAL_INCLUDE
|
||||
|
||||
namespace simdjson {
|
||||
namespace SIMDJSON_IMPLEMENTATION {
|
||||
|
||||
@@ -78,3 +86,5 @@ simdjson_inline implementation_simdjson_result_base<T>::implementation_simdjson_
|
||||
|
||||
} // namespace SIMDJSON_IMPLEMENTATION
|
||||
} // namespace simdjson
|
||||
|
||||
#endif // SIMDJSON_GENERIC_IMPLEMENTATION_SIMDJSON_RESULT_BASE_INL_H
|
||||
@@ -1,3 +1,10 @@
|
||||
#ifndef SIMDJSON_GENERIC_IMPLEMENTATION_SIMDJSON_RESULT_BASE_H
|
||||
|
||||
#ifndef SIMDJSON_CONDITIONAL_INCLUDE
|
||||
#define SIMDJSON_GENERIC_IMPLEMENTATION_SIMDJSON_RESULT_BASE_H
|
||||
#include "simdjson/generic/base.h"
|
||||
#endif // SIMDJSON_CONDITIONAL_INCLUDE
|
||||
|
||||
namespace simdjson {
|
||||
namespace SIMDJSON_IMPLEMENTATION {
|
||||
|
||||
@@ -123,3 +130,5 @@ protected:
|
||||
|
||||
} // namespace SIMDJSON_IMPLEMENTATION
|
||||
} // namespace simdjson
|
||||
|
||||
#endif // SIMDJSON_GENERIC_IMPLEMENTATION_SIMDJSON_RESULT_BASE_H
|
||||
@@ -1,5 +1,11 @@
|
||||
#ifndef SIMDJSON_GENERIC_JSONCHARUTILS_H
|
||||
|
||||
#ifndef SIMDJSON_CONDITIONAL_INCLUDE
|
||||
#define SIMDJSON_GENERIC_JSONCHARUTILS_H
|
||||
#include "simdjson/generic/base.h"
|
||||
#include "simdjson/internal/jsoncharutils_tables.h"
|
||||
#include "simdjson/internal/numberparsing_tables.h"
|
||||
#endif // SIMDJSON_CONDITIONAL_INCLUDE
|
||||
|
||||
namespace simdjson {
|
||||
namespace SIMDJSON_IMPLEMENTATION {
|
||||
@@ -90,27 +96,9 @@ static simdjson_inline uint64_t _umul128(uint64_t ab, uint64_t cd, uint64_t *hi)
|
||||
}
|
||||
#endif
|
||||
|
||||
using internal::value128;
|
||||
|
||||
simdjson_inline value128 full_multiplication(uint64_t value1, uint64_t value2) {
|
||||
value128 answer;
|
||||
#if SIMDJSON_REGULAR_VISUAL_STUDIO || SIMDJSON_IS_32BITS
|
||||
#ifdef _M_ARM64
|
||||
// ARM64 has native support for 64-bit multiplications, no need to emultate
|
||||
answer.high = __umulh(value1, value2);
|
||||
answer.low = value1 * value2;
|
||||
#else
|
||||
answer.low = _umul128(value1, value2, &answer.high); // _umul128 not available on ARM64
|
||||
#endif // _M_ARM64
|
||||
#else // SIMDJSON_REGULAR_VISUAL_STUDIO || SIMDJSON_IS_32BITS
|
||||
__uint128_t r = (static_cast<__uint128_t>(value1)) * value2;
|
||||
answer.low = uint64_t(r);
|
||||
answer.high = uint64_t(r >> 64);
|
||||
#endif
|
||||
return answer;
|
||||
}
|
||||
|
||||
} // namespace jsoncharutils
|
||||
} // unnamed namespace
|
||||
} // namespace SIMDJSON_IMPLEMENTATION
|
||||
} // namespace simdjson
|
||||
|
||||
#endif // SIMDJSON_GENERIC_JSONCHARUTILS_H
|
||||
@@ -0,0 +1,303 @@
|
||||
#ifndef SIMDJSON_GENERIC_SIMD_LOOKUP_TABLE_H
|
||||
|
||||
#ifndef SIMDJSON_CONDITIONAL_INCLUDE
|
||||
#define SIMDJSON_GENERIC_SIMD_LOOKUP_TABLE_H
|
||||
#include "simdjson/generic/base.h"
|
||||
#endif // SIMDJSON_CONDITIONAL_INCLUDE
|
||||
|
||||
namespace simdjson {
|
||||
namespace SIMDJSON_IMPLEMENTATION {
|
||||
namespace simd {
|
||||
|
||||
template <typename T = uint8_t>
|
||||
struct simd8_buffer {
|
||||
T buf[simd8<T>::LANES] = {0};
|
||||
simdjson_consteval T& operator[](size_t i) noexcept { return buf[i]; }
|
||||
simdjson_consteval T operator[](size_t i) const noexcept { return buf[i]; }
|
||||
simdjson_inline operator simd8<T>() const noexcept { return buf; }
|
||||
};
|
||||
|
||||
|
||||
struct nibble_range;
|
||||
|
||||
struct byte_range {
|
||||
struct _exclusive{};
|
||||
static simdjson_constinit _exclusive exclusive{};
|
||||
|
||||
simdjson_consteval byte_range(uint8_t start, uint16_t end, const _exclusive&) noexcept : _start{start}, _end{end} {
|
||||
SIMDJSON_ASSUME(start < end && end <= 256);
|
||||
}
|
||||
simdjson_consteval byte_range(uint8_t first, uint8_t last) noexcept : byte_range(first, static_cast<uint16_t>(last+1), exclusive) {}
|
||||
simdjson_consteval byte_range(uint8_t first) noexcept : byte_range(first, first) {}
|
||||
|
||||
simdjson_consteval size_t size() const noexcept { return static_cast<size_t>(_end - _start); }
|
||||
simdjson_consteval byte_range operator|(const byte_range& other) const noexcept {
|
||||
SIMDJSON_ASSUME((_end + 1 >= other._start) || (other._end + 1 >= _start));
|
||||
return {std::min(_start, other._start), std::max(_end, other._end), exclusive};
|
||||
}
|
||||
|
||||
simdjson_consteval bool includes(uint8_t byte) const noexcept { return _start <= byte && byte < _end; }
|
||||
|
||||
struct nibble_iter {
|
||||
int nibble;
|
||||
const int last_nibble;
|
||||
simdjson_consteval nibble_iter& operator++() noexcept {
|
||||
if (nibble == last_nibble) {
|
||||
nibble = -1;
|
||||
} else {
|
||||
++nibble;
|
||||
nibble %= 16;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
simdjson_consteval nibble_iter operator++(int) noexcept { auto copy = *this; ++*this; return copy; }
|
||||
simdjson_consteval bool operator==(const nibble_iter& other) const noexcept { return nibble == other.nibble; }
|
||||
simdjson_consteval bool operator!=(const nibble_iter& other) const noexcept { return nibble != other.nibble; }
|
||||
simdjson_consteval uint8_t operator*() const noexcept { return static_cast<uint8_t>(nibble); }
|
||||
simdjson_consteval nibble_iter begin() const noexcept { return *this; }
|
||||
simdjson_consteval nibble_iter end() const noexcept { return {-1, last_nibble}; }
|
||||
};
|
||||
|
||||
simdjson_consteval nibble_iter nibble(int shift) const noexcept {
|
||||
SIMDJSON_ASSUME(_start < _end);
|
||||
auto first_nibble = _start >> shift;
|
||||
auto last_nibble = (_end-1) >> shift;
|
||||
if ((last_nibble - first_nibble) >= 16) { return {0x00, 0x0F}; }
|
||||
return {static_cast<uint8_t>(first_nibble & 0x0F), static_cast<uint8_t>(last_nibble & 0x0F)};
|
||||
}
|
||||
|
||||
struct _iter {
|
||||
uint16_t value;
|
||||
simdjson_consteval _iter& operator++() noexcept { ++value; return *this; }
|
||||
simdjson_consteval _iter operator++(int) noexcept { auto copy = *this; ++*this; return copy; }
|
||||
simdjson_consteval bool operator==(const _iter& other) const noexcept { return value == other.value; }
|
||||
simdjson_consteval bool operator!=(const _iter& other) const noexcept { return value != other.value; }
|
||||
simdjson_consteval uint8_t operator*() const noexcept { return static_cast<uint8_t>(value); }
|
||||
};
|
||||
|
||||
simdjson_consteval _iter begin() const noexcept { return _iter{_start}; }
|
||||
simdjson_consteval _iter end() const noexcept { return _iter{_end}; }
|
||||
|
||||
uint8_t _start;
|
||||
const uint16_t _end;
|
||||
};
|
||||
|
||||
namespace {
|
||||
|
||||
struct _lookup_entry_range;
|
||||
|
||||
struct _lookup_entry : byte_range {
|
||||
const uint8_t value;
|
||||
|
||||
simdjson_consteval _lookup_entry(const byte_range& bytes, uint8_t value) noexcept
|
||||
: byte_range{bytes}, value{value} {}
|
||||
};
|
||||
|
||||
simdjson_consteval simd8_buffer<uint8_t> _make_nibble_lookup_table(
|
||||
std::initializer_list<_lookup_entry> entries, int shift) noexcept {
|
||||
// Make the buffer
|
||||
simd8_buffer<uint8_t> buf;
|
||||
for (auto entry : entries) {
|
||||
for (auto key : entry.nibble(shift)) {
|
||||
// Repeat the value over and over for longer simd types.
|
||||
for (uint8_t k = key; k < sizeof(buf); k += 16) { buf[k] |= entry.value; }
|
||||
}
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
} // unnamed namespace
|
||||
|
||||
/**
|
||||
* Byte lookup table where the key is the high 4 bits of the input, and the value is an
|
||||
* arbitrary byte.
|
||||
*
|
||||
* - Unmatched values yield 0.
|
||||
* - Multiple keys may yield the same value.
|
||||
* - Multiple bytes with the same high 4 bits may NOT yield different values.
|
||||
*
|
||||
* ```
|
||||
* enum ops_t : uint8_t {
|
||||
* COMMA = 1,
|
||||
* COLON = 2,
|
||||
* BRACKET = 3,
|
||||
* CURLY = 4
|
||||
* };
|
||||
* static constinit const high_nibble_lookup OPS(
|
||||
* {',', COMMA},
|
||||
* {':', COLON},
|
||||
* {'[', BRACKET},
|
||||
* {']', BRACKET},
|
||||
* {'{', CURLY},
|
||||
* {'}', CURLY}
|
||||
* );
|
||||
* simd8<uint8_t> lookup_ops(simd8<uint8_t>& operators) { return OPS[operators]; }
|
||||
* ```
|
||||
*/
|
||||
struct high_nibble_lookup {
|
||||
const simd8_buffer<uint8_t> table;
|
||||
|
||||
/**
|
||||
* Construct a nibble lookup table from the high bits of the input to the output.
|
||||
*
|
||||
* @param entries A list of {key, value} pairs (e.g. {'a', 10}).
|
||||
* @error asserts if multiple keys have the same high 4 bits but different values.
|
||||
*/
|
||||
simdjson_consteval high_nibble_lookup(std::initializer_list<_lookup_entry> entries) noexcept
|
||||
: table{_make_nibble_lookup_table(entries, 4)} {}
|
||||
simdjson_consteval high_nibble_lookup(const simd8_buffer<uint8_t>& table) noexcept : table(table) {}
|
||||
|
||||
/** Look up the value corresponding the higher 4 bits of each input byte, and return it. */
|
||||
simdjson_inline simd8<uint8_t> operator[](const simd8<uint8_t>& keys) const noexcept { return lookup(keys); }
|
||||
/** Look up the value corresponding the higher 4 bits of each input byte, and return it. */
|
||||
simdjson_inline simd8<uint8_t> lookup(const simd8<uint8_t>& keys) const noexcept { return lookup_low(keys.shr<4>()); }
|
||||
/**
|
||||
* Look up the value in the table assuming the high 4 key bits are stored in the lower 4 bits.
|
||||
* @pre all indexes be less than 16.
|
||||
*/
|
||||
simdjson_inline simd8<uint8_t> lookup_low(const simd8<uint8_t>& shifted_keys) const noexcept {
|
||||
return shifted_keys.lookup_16(table);
|
||||
}
|
||||
|
||||
/**
|
||||
* Look up the value in the table assuming the high 4 key bits are stored in the lower 4 bits.
|
||||
* @pre all indexes be less than 16.
|
||||
*/
|
||||
simdjson_inline simd8x64<uint8_t> lookup_low(const simd8x64<uint8_t>& shifted_keys) const noexcept {
|
||||
return shifted_keys.lookup_16(table);
|
||||
}
|
||||
/** Look up the value corresponding the higher 4 bits of each input byte, and return it. */
|
||||
simdjson_inline simd8x64<uint8_t> lookup(const simd8x64<uint8_t>& keys) const noexcept { return lookup_low(keys.shr<4>()); }
|
||||
/** Look up the value corresponding the higher 4 bits of each input byte, and return it. */
|
||||
simdjson_inline simd8x64<uint8_t> operator[](const simd8x64<uint8_t>& keys) const noexcept { return lookup(keys); }
|
||||
|
||||
simdjson_consteval uint8_t operator[](uint8_t key) const noexcept { return lookup(key); }
|
||||
simdjson_consteval uint8_t lookup(uint8_t key) const noexcept { return table[key >> 4]; }
|
||||
};
|
||||
|
||||
/**
|
||||
* Byte lookup table where the key is the low 4 bits of the input, and the value is an
|
||||
* arbitrary byte.
|
||||
*
|
||||
* - Unmatched values yield 0.
|
||||
* - Multiple keys may yield the same value.
|
||||
* - Multiple bytes with the same low 4 bits may NOT yield different values.
|
||||
*
|
||||
* ```
|
||||
* enum ops_t : uint8_t {
|
||||
* COMMA = 1,
|
||||
* COLON = 2,
|
||||
* BRACKET = 3,
|
||||
* CURLY = 4
|
||||
* };
|
||||
* static constinit const high_nibble_lookup OPS(
|
||||
* {',', COMMA},
|
||||
* {':', COLON},
|
||||
* {'[', BRACKET},
|
||||
* {']', BRACKET},
|
||||
* {'{', CURLY},
|
||||
* {'}', CURLY}
|
||||
* );
|
||||
* simd8<uint8_t> lookup_ops(simd8<uint8_t>& operators) { return OPS[operators]; }
|
||||
* ```
|
||||
*/
|
||||
struct low_nibble_lookup {
|
||||
const simd8_buffer<uint8_t> table;
|
||||
|
||||
/**
|
||||
* Construct a nibble lookup table from the low bits of the input to the output.
|
||||
*
|
||||
* @param entries A list of {key, value} pairs (e.g. {'a', 0}).
|
||||
* @error asserts if multiple keys have the same low 4 bits but different values.
|
||||
*/
|
||||
simdjson_consteval low_nibble_lookup(std::initializer_list<_lookup_entry> entries) noexcept
|
||||
: table{_make_nibble_lookup_table(entries, 0)} {}
|
||||
simdjson_consteval low_nibble_lookup(const simd8_buffer<uint8_t>& table) noexcept : table(table) {}
|
||||
|
||||
/** Look up the value corresponding the lower 4 bits of each input byte, and return it. */
|
||||
simdjson_inline simd8<uint8_t> operator[](const simd8<uint8_t>& keys) const noexcept { return lookup(keys); }
|
||||
/** Look up the value corresponding the lower 4 bits of each input byte, and return it. */
|
||||
simdjson_inline simd8<uint8_t> lookup(const simd8<uint8_t>& keys) const noexcept {
|
||||
return keys.lookup_low_nibble_ascii(table);
|
||||
}
|
||||
/**
|
||||
* Look up the value in the table. Behavior is system-dependent for indexes greater than 16.
|
||||
*
|
||||
* - On some platforms like arm64, indexes greater than 16 will not match anything in the table.
|
||||
* - On platforms like Intel, index bits 4-6 will be ignored, but if the high bit is set, it
|
||||
* will not match anything in the table. greater than 16 will be ignored, *except* if the high bit is 1,
|
||||
*/
|
||||
simdjson_inline simd8<uint8_t> lookup_unsafe(const simd8<uint8_t>& keys) const noexcept {
|
||||
return keys.lookup_16(table);
|
||||
}
|
||||
|
||||
/** Look up the value corresponding the lower 4 bits of each input byte, and return it. */
|
||||
simdjson_inline simd8x64<uint8_t> operator[](const simd8x64<uint8_t>& keys) const noexcept { return lookup(keys); }
|
||||
/** Look up the value corresponding the lower 4 bits of each input byte, and return it. */
|
||||
simdjson_inline simd8x64<uint8_t> lookup(const simd8x64<uint8_t>& keys) const noexcept {
|
||||
return keys.lookup_low_nibble_ascii(table);
|
||||
}
|
||||
/**
|
||||
* Look up the value in the table. Behavior is system-dependent for indexes greater than 16.
|
||||
*
|
||||
* - On some platforms like arm64, indexes greater than 16 will not match anything in the table.
|
||||
* - On platforms like Intel, index bits 4-6 will be ignored, but if the high bit is set, it
|
||||
* will not match anything in the table. greater than 16 will be ignored, *except* if the high bit is 1,
|
||||
*/
|
||||
simdjson_inline simd8x64<uint8_t> lookup_unsafe(const simd8x64<uint8_t>& low_keys) const noexcept {
|
||||
return low_keys.lookup_16(table);
|
||||
}
|
||||
|
||||
simdjson_consteval uint8_t operator[](uint8_t key) const noexcept { return lookup(key); }
|
||||
simdjson_consteval uint8_t lookup(uint8_t key) const noexcept { return table[key & 0x0F]; }
|
||||
};
|
||||
|
||||
/**
|
||||
* Classifies bytes by looking up their lower 4 bits, then their high 4 bits, and &'ing the
|
||||
* results together.
|
||||
*
|
||||
* Pass the bytes you want to match, and the classifications you want for them.
|
||||
*/
|
||||
struct byte_classifier {
|
||||
const low_nibble_lookup low;
|
||||
const high_nibble_lookup high;
|
||||
simdjson_consteval byte_classifier(std::initializer_list<_lookup_entry> entries)
|
||||
: low{entries}, high{entries} {}
|
||||
|
||||
simdjson_inline simd8<uint8_t> classify(const simd8<uint8_t>& bytes) const noexcept {
|
||||
return low.lookup(bytes) & high.lookup(bytes);
|
||||
}
|
||||
simdjson_inline simd8x64<uint8_t> classify(const simd8x64<uint8_t>& bytes) const noexcept {
|
||||
auto low_lookup = low.lookup(bytes); // 3 (+simd:N)
|
||||
auto high_lookup = high.lookup(bytes); // 6 (+simd:2N)
|
||||
return low_lookup & high_lookup; // 3 (+simd:N)
|
||||
// critical path: 9 (+simd:4N)
|
||||
}
|
||||
simdjson_consteval uint8_t classify(uint8_t byte) const noexcept {
|
||||
return low.lookup(byte) & high.lookup(byte);
|
||||
}
|
||||
|
||||
simdjson_inline simd8<uint8_t> operator[](const simd8<uint8_t>& bytes) const noexcept { return classify(bytes); }
|
||||
simdjson_inline simd8x64<uint8_t> operator[](const simd8x64<uint8_t>& bytes) const noexcept { return classify(bytes); }
|
||||
simdjson_consteval uint8_t operator[](uint8_t byte) const noexcept { return classify(byte); }
|
||||
|
||||
simdjson_inline bool matches_correctly(std::initializer_list<_lookup_entry> entries) const noexcept {
|
||||
uint8_t expected_output[256] = {};
|
||||
for (auto entry : entries) {
|
||||
for (uint8_t byte : entry) {
|
||||
expected_output[byte] |= entry.value;
|
||||
}
|
||||
}
|
||||
for (uint8_t byte = 0; byte <= 0xFF; byte++) {
|
||||
if (expected_output[byte] != classify(byte)) { return false; }
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
} // namespace simd
|
||||
} // namespace SIMDJSON_IMPLEMENTATION
|
||||
} // namespace simdjson
|
||||
|
||||
#endif // SIMDJSON_GENERIC_SIMD_LOOKUP_TABLE_H
|
||||
@@ -1,26 +1,20 @@
|
||||
#ifndef SIMDJSON_GENERIC_NUMBERPARSING_H
|
||||
|
||||
#ifndef SIMDJSON_CONDITIONAL_INCLUDE
|
||||
#define SIMDJSON_GENERIC_NUMBERPARSING_H
|
||||
#include "simdjson/generic/base.h"
|
||||
#include "simdjson/generic/jsoncharutils.h"
|
||||
#include "simdjson/internal/numberparsing_tables.h"
|
||||
#endif // SIMDJSON_CONDITIONAL_INCLUDE
|
||||
|
||||
#include <limits>
|
||||
#include <ostream>
|
||||
#include <cstring>
|
||||
|
||||
namespace simdjson {
|
||||
namespace SIMDJSON_IMPLEMENTATION {
|
||||
|
||||
namespace ondemand {
|
||||
/**
|
||||
* The type of a JSON number
|
||||
*/
|
||||
enum class number_type {
|
||||
floating_point_number=1, /// a binary64 number
|
||||
signed_integer, /// a signed integer that fits in a 64-bit word using two's complement
|
||||
unsigned_integer /// a positive integer larger or equal to 1<<63
|
||||
};
|
||||
}
|
||||
|
||||
namespace {
|
||||
/// @private
|
||||
namespace numberparsing {
|
||||
|
||||
|
||||
|
||||
#ifdef JSON_TEST_NUMBERS
|
||||
#define INVALID_NUMBER(SRC) (found_invalid_number((SRC)), NUMBER_ERROR)
|
||||
#define WRITE_INTEGER(VALUE, SRC, WRITER) (found_integer((VALUE), (SRC)), (WRITER).append_s64((VALUE)))
|
||||
@@ -34,6 +28,7 @@ namespace numberparsing {
|
||||
#endif
|
||||
|
||||
namespace {
|
||||
|
||||
// Convert a mantissa, an exponent and a sign bit into an ieee64 double.
|
||||
// The real_exponent needs to be in [0, 2046] (technically real_exponent = 2047 would be acceptable).
|
||||
// The mantissa should be in [0,1<<53). The bit at index (1ULL << 52) while be zeroed.
|
||||
@@ -45,7 +40,7 @@ simdjson_inline double to_double(uint64_t mantissa, uint64_t real_exponent, bool
|
||||
std::memcpy(&d, &mantissa, sizeof(d));
|
||||
return d;
|
||||
}
|
||||
}
|
||||
|
||||
// Attempts to compute i * 10^(power) exactly; and if "negative" is
|
||||
// true, negate the result.
|
||||
// This function will only work in some cases, when it does not work, success is
|
||||
@@ -62,10 +57,11 @@ simdjson_inline bool compute_float_64(int64_t power, uint64_t i, bool negative,
|
||||
#endif
|
||||
#if (FLT_EVAL_METHOD != 1) && (FLT_EVAL_METHOD != 0)
|
||||
// We cannot be certain that x/y is rounded to nearest.
|
||||
if (0 <= power && power <= 22 && i <= 9007199254740991) {
|
||||
if (0 <= power && power <= 22 && i <= 9007199254740991)
|
||||
#else
|
||||
if (-22 <= power && power <= 22 && i <= 9007199254740991) {
|
||||
if (-22 <= power && power <= 22 && i <= 9007199254740991)
|
||||
#endif
|
||||
{
|
||||
// convert the integer into a double. This is lossless since
|
||||
// 0 <= i <= 2^53 - 1.
|
||||
d = double(i);
|
||||
@@ -147,7 +143,7 @@ simdjson_inline bool compute_float_64(int64_t power, uint64_t i, bool negative,
|
||||
|
||||
|
||||
// We want the most significant bit of i to be 1. Shift if needed.
|
||||
int lz = leading_zeroes(i);
|
||||
int lz = bitmask::leading_zeroes(i);
|
||||
i <<= lz;
|
||||
|
||||
|
||||
@@ -169,7 +165,7 @@ simdjson_inline bool compute_float_64(int64_t power, uint64_t i, bool negative,
|
||||
// with a returned value of type value128 with a "low component" corresponding to the
|
||||
// 64-bit least significant bits of the product and with a "high component" corresponding
|
||||
// to the 64-bit most significant bits of the product.
|
||||
simdjson::internal::value128 firstproduct = jsoncharutils::full_multiplication(i, simdjson::internal::power_of_five_128[index]);
|
||||
simdjson::internal::value128 firstproduct = full_multiplication(i, simdjson::internal::power_of_five_128[index]);
|
||||
// Both i and power_of_five_128[index] have their most significant bit set to 1 which
|
||||
// implies that the either the most or the second most significant bit of the product
|
||||
// is 1. We pack values in this manner for efficiency reasons: it maximizes the use
|
||||
@@ -203,7 +199,7 @@ simdjson_inline bool compute_float_64(int64_t power, uint64_t i, bool negative,
|
||||
// with a returned value of type value128 with a "low component" corresponding to the
|
||||
// 64-bit least significant bits of the product and with a "high component" corresponding
|
||||
// to the 64-bit most significant bits of the product.
|
||||
simdjson::internal::value128 secondproduct = jsoncharutils::full_multiplication(i, simdjson::internal::power_of_five_128[index + 1]);
|
||||
simdjson::internal::value128 secondproduct = full_multiplication(i, simdjson::internal::power_of_five_128[index + 1]);
|
||||
firstproduct.low += secondproduct.high;
|
||||
if(secondproduct.high > firstproduct.low) { firstproduct.high++; }
|
||||
// At this point, we might need to add at most one to firstproduct, but this
|
||||
@@ -317,6 +313,7 @@ static bool parse_float_fallback(const uint8_t *ptr, double *outDouble) {
|
||||
// to handle that max may be a macro on windows).
|
||||
return !(*outDouble > (std::numeric_limits<double>::max)() || *outDouble < std::numeric_limits<double>::lowest());
|
||||
}
|
||||
|
||||
static bool parse_float_fallback(const uint8_t *ptr, const uint8_t *end_ptr, double *outDouble) {
|
||||
*outDouble = simdjson::internal::from_chars(reinterpret_cast<const char *>(ptr), reinterpret_cast<const char *>(end_ptr));
|
||||
// We do not accept infinite values.
|
||||
@@ -350,16 +347,6 @@ simdjson_inline bool is_made_of_eight_digits_fast(const uint8_t *chars) {
|
||||
0x3333333333333333);
|
||||
}
|
||||
|
||||
template<typename W>
|
||||
error_code slow_float_parsing(simdjson_unused const uint8_t * src, W writer) {
|
||||
double d;
|
||||
if (parse_float_fallback(src, &d)) {
|
||||
writer.append_double(d);
|
||||
return SUCCESS;
|
||||
}
|
||||
return INVALID_NUMBER(src);
|
||||
}
|
||||
|
||||
template<typename I>
|
||||
SIMDJSON_NO_SANITIZE_UNDEFINED // We deliberately allow overflow here and check later
|
||||
simdjson_inline bool parse_digit(const uint8_t c, I &i) {
|
||||
@@ -372,7 +359,7 @@ simdjson_inline bool parse_digit(const uint8_t c, I &i) {
|
||||
return true;
|
||||
}
|
||||
|
||||
simdjson_inline error_code parse_decimal(simdjson_unused const uint8_t *const src, const uint8_t *&p, uint64_t &i, int64_t &exponent) {
|
||||
simdjson_inline error_code parse_decimal_after_separator(simdjson_unused const uint8_t *const src, const uint8_t *&p, uint64_t &i, int64_t &exponent) {
|
||||
// we continue with the fiction that we have an integer. If the
|
||||
// floating point number is representable as x * 10^z for some integer
|
||||
// z that fits in 53 bits, then we will be able to convert back the
|
||||
@@ -460,6 +447,20 @@ simdjson_inline size_t significant_digits(const uint8_t * start_digits, size_t d
|
||||
return digit_count - size_t(start - start_digits);
|
||||
}
|
||||
|
||||
} // unnamed namespace
|
||||
|
||||
/** @private */
|
||||
template<typename W>
|
||||
error_code slow_float_parsing(simdjson_unused const uint8_t * src, W writer) {
|
||||
double d;
|
||||
if (parse_float_fallback(src, &d)) {
|
||||
writer.append_double(d);
|
||||
return SUCCESS;
|
||||
}
|
||||
return INVALID_NUMBER(src);
|
||||
}
|
||||
|
||||
/** @private */
|
||||
template<typename W>
|
||||
simdjson_inline error_code write_float(const uint8_t *const src, bool negative, uint64_t i, const uint8_t * start_digits, size_t digit_count, int64_t exponent, W &writer) {
|
||||
// If we frequently had to deal with long strings of digits,
|
||||
@@ -531,7 +532,7 @@ simdjson_unused simdjson_inline simdjson_result<int64_t> parse_integer_in_string
|
||||
simdjson_unused simdjson_inline simdjson_result<double> parse_double_in_string(const uint8_t * const src) noexcept { return 0; }
|
||||
simdjson_unused simdjson_inline bool is_negative(const uint8_t * src) noexcept { return false; }
|
||||
simdjson_unused simdjson_inline simdjson_result<bool> is_integer(const uint8_t * src) noexcept { return false; }
|
||||
simdjson_unused simdjson_inline simdjson_result<ondemand::number_type> get_number_type(const uint8_t * src) noexcept { return ondemand::number_type::signed_integer; }
|
||||
simdjson_unused simdjson_inline simdjson_result<number_type> get_number_type(const uint8_t * src) noexcept { return number_type::signed_integer; }
|
||||
#else
|
||||
|
||||
// parse the number at src
|
||||
@@ -573,7 +574,7 @@ simdjson_inline error_code parse_number(const uint8_t *const src, W &writer) {
|
||||
if ('.' == *p) {
|
||||
is_float = true;
|
||||
++p;
|
||||
SIMDJSON_TRY( parse_decimal(src, p, i, exponent) );
|
||||
SIMDJSON_TRY( parse_decimal_after_separator(src, p, i, exponent) );
|
||||
digit_count = int(p - start_digits); // used later to guard against overflows
|
||||
}
|
||||
if (('e' == *p) || ('E' == *p)) {
|
||||
@@ -1061,7 +1062,7 @@ simdjson_unused simdjson_inline simdjson_result<bool> is_integer(const uint8_t *
|
||||
return false;
|
||||
}
|
||||
|
||||
simdjson_unused simdjson_inline simdjson_result<ondemand::number_type> get_number_type(const uint8_t * src) noexcept {
|
||||
simdjson_unused simdjson_inline simdjson_result<number_type> get_number_type(const uint8_t * src) noexcept {
|
||||
bool negative = (*src == '-');
|
||||
src += uint8_t(negative);
|
||||
const uint8_t *p = src;
|
||||
@@ -1070,20 +1071,20 @@ simdjson_unused simdjson_inline simdjson_result<ondemand::number_type> get_numbe
|
||||
if (jsoncharutils::is_structural_or_whitespace(*p)) {
|
||||
// We have an integer.
|
||||
// If the number is negative and valid, it must be a signed integer.
|
||||
if(negative) { return ondemand::number_type::signed_integer; }
|
||||
if(negative) { return number_type::signed_integer; }
|
||||
// We want values larger or equal to 9223372036854775808 to be unsigned
|
||||
// integers, and the other values to be signed integers.
|
||||
int digit_count = int(p - src);
|
||||
if(digit_count >= 19) {
|
||||
const uint8_t * smaller_big_integer = reinterpret_cast<const uint8_t *>("9223372036854775808");
|
||||
if((digit_count >= 20) || (memcmp(src, smaller_big_integer, 19) >= 0)) {
|
||||
return ondemand::number_type::unsigned_integer;
|
||||
return number_type::unsigned_integer;
|
||||
}
|
||||
}
|
||||
return ondemand::number_type::signed_integer;
|
||||
return number_type::signed_integer;
|
||||
}
|
||||
// Hopefully, we have 'e' or 'E' or '.'.
|
||||
return ondemand::number_type::floating_point_number;
|
||||
return number_type::floating_point_number;
|
||||
}
|
||||
|
||||
// Never read at src_end or beyond
|
||||
@@ -1245,10 +1246,23 @@ simdjson_unused simdjson_inline simdjson_result<double> parse_double_in_string(c
|
||||
}
|
||||
return d;
|
||||
}
|
||||
} //namespace {}
|
||||
|
||||
} // unnamed namespace
|
||||
#endif // SIMDJSON_SKIPNUMBERPARSING
|
||||
|
||||
} // namespace numberparsing
|
||||
} // unnamed namespace
|
||||
|
||||
inline std::ostream& operator<<(std::ostream& out, number_type type) noexcept {
|
||||
switch (type) {
|
||||
case number_type::signed_integer: out << "integer in [-9223372036854775808,9223372036854775808)"; break;
|
||||
case number_type::unsigned_integer: out << "unsigned integer in [9223372036854775808,18446744073709551616)"; break;
|
||||
case number_type::floating_point_number: out << "floating-point number (binary64)"; break;
|
||||
default: SIMDJSON_UNREACHABLE();
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
} // namespace SIMDJSON_IMPLEMENTATION
|
||||
} // namespace simdjson
|
||||
|
||||
#endif // SIMDJSON_GENERIC_NUMBERPARSING_H
|
||||
@@ -1,16 +0,0 @@
|
||||
#include "simdjson/generic/ondemand/json_type-inl.h"
|
||||
#include "simdjson/generic/ondemand/logger-inl.h"
|
||||
#include "simdjson/generic/ondemand/raw_json_string-inl.h"
|
||||
#include "simdjson/generic/ondemand/token_iterator-inl.h"
|
||||
#include "simdjson/generic/ondemand/json_iterator-inl.h"
|
||||
#include "simdjson/generic/ondemand/value_iterator-inl.h"
|
||||
#include "simdjson/generic/ondemand/array_iterator-inl.h"
|
||||
#include "simdjson/generic/ondemand/object_iterator-inl.h"
|
||||
#include "simdjson/generic/ondemand/array-inl.h"
|
||||
#include "simdjson/generic/ondemand/document-inl.h"
|
||||
#include "simdjson/generic/ondemand/value-inl.h"
|
||||
#include "simdjson/generic/ondemand/field-inl.h"
|
||||
#include "simdjson/generic/ondemand/object-inl.h"
|
||||
#include "simdjson/generic/ondemand/parser-inl.h"
|
||||
#include "simdjson/generic/ondemand/document_stream-inl.h"
|
||||
#include "simdjson/generic/ondemand/serialization-inl.h"
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user