mirror of
https://github.com/simdjson/simdjson
synced 2026-06-08 17:27:07 +00:00
Compare commits
92 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 11d9dbb7b7 | |||
| 896fb5d6a5 | |||
| e3d3b4b5a4 | |||
| 08e5943efc | |||
| 8aae14931d | |||
| 7068894be3 | |||
| ef3d1ac25f | |||
| 9292480a9b | |||
| 611ea97dbd | |||
| f249e7e128 | |||
| 44fddaa807 | |||
| be16e1ae04 | |||
| 124a33c160 | |||
| a0b870e9c2 | |||
| 68699eb73c | |||
| 06453f1637 | |||
| eb828d97ba | |||
| 00f84fb448 | |||
| 5bf0954c6e | |||
| 3056d54fa3 | |||
| 241b9f6ea7 | |||
| 015daad6a9 | |||
| fc3b7766c0 | |||
| b5c78288e5 | |||
| bd86bb0cfb | |||
| 4840a0347c | |||
| 7f68baec1e | |||
| e2ea5fb8de | |||
| 7dfd165ecd | |||
| 4dfa0a2407 | |||
| e252a21f65 | |||
| 89f2b634df | |||
| addca203d5 | |||
| 1825d7e88c | |||
| f87d6af3e9 | |||
| 8fff57578c | |||
| 056d66926a | |||
| b434a50681 | |||
| e8ff2fa692 | |||
| 1ebf115b2b | |||
| 172fbe785d | |||
| a10f096af2 | |||
| a85e474360 | |||
| 05752d6c6f | |||
| fb9a689dff | |||
| 472f818fe5 | |||
| 5c9c133632 | |||
| faf921bc7e | |||
| 626eedc3d8 | |||
| 294aa64f94 | |||
| 397b40e574 | |||
| fdc93528d1 | |||
| 3e00a431a0 | |||
| d3626c6a37 | |||
| 686a1869c8 | |||
| 4c0f86db44 | |||
| 6c4c934457 | |||
| fcae795042 | |||
| b7c51156b9 | |||
| 662e3d96c7 | |||
| 64009f7063 | |||
| 74fb3ecac7 | |||
| 26abf1d180 | |||
| e878dc6be3 | |||
| efa03f5733 | |||
| 8519623257 | |||
| 484a092c31 | |||
| 8bb520adbf | |||
| ec8e6a6758 | |||
| 769528b6c0 | |||
| 9fbc577be7 | |||
| a7c95e9cc8 | |||
| 248d4eb2aa | |||
| 559493e2bf | |||
| 75acae5c46 | |||
| bd761ef573 | |||
| 76ed73f07f | |||
| 1b59b38de8 | |||
| 4794b5d936 | |||
| 114f14924c | |||
| e94825c9a8 | |||
| 333fd72f98 | |||
| dd4d02617f | |||
| e28d63334e | |||
| d43fb6ff84 | |||
| 5eec29a6db | |||
| 228501f786 | |||
| 9d9f2427c5 | |||
| 8d53840253 | |||
| 0a82fb110f | |||
| 11f273c580 | |||
| 31662531ac |
@@ -9,7 +9,8 @@ assignees: ''
|
|||||||
|
|
||||||
Before submitting an issue, please ensure that you have read the documentation:
|
Before submitting an issue, please ensure that you have read the documentation:
|
||||||
|
|
||||||
* Basics is an overview of how to use simdjson and its APIs: https://github.com/simdjson/simdjson/blob/master/doc/basics.md
|
* Basics is an overview of how to use simdjson and its APIs to parse JSON: https://github.com/simdjson/simdjson/blob/master/doc/basics.md
|
||||||
|
* Builder is an overview of how to use simdjson to generate JSON: https://github.com/simdjson/simdjson/blob/master/doc/builder.md
|
||||||
* Performance shows some more advanced scenarios and how to tune for them: https://github.com/simdjson/simdjson/blob/master/doc/performance.md
|
* Performance shows some more advanced scenarios and how to tune for them: https://github.com/simdjson/simdjson/blob/master/doc/performance.md
|
||||||
* Contributing: https://github.com/simdjson/simdjson/blob/master/CONTRIBUTING.md
|
* Contributing: https://github.com/simdjson/simdjson/blob/master/CONTRIBUTING.md
|
||||||
* We follow the [JSON specification as described by RFC 8259](https://www.rfc-editor.org/rfc/rfc8259.txt) (T. Bray, 2017). If you wish to support features that are not part of RFC 8259, then you should not refer to your issue as a bug.
|
* We follow the [JSON specification as described by RFC 8259](https://www.rfc-editor.org/rfc/rfc8259.txt) (T. Bray, 2017). If you wish to support features that are not part of RFC 8259, then you should not refer to your issue as a bug.
|
||||||
@@ -55,6 +56,8 @@ We support up-to-date 64-bit ARM and x64 FreeBSD, macOS, Windows and Linux syste
|
|||||||
pre-release version of a compiler, do not report it as a bug to simdjson. However, we always
|
pre-release version of a compiler, do not report it as a bug to simdjson. However, we always
|
||||||
invite contributions either in the form an analysis or of a code contribution.
|
invite contributions either in the form an analysis or of a code contribution.
|
||||||
|
|
||||||
|
Under Windows, we support Visual Studio (both with LLVM and without). We do not support MinGW and other alternate compiler systems. Windows users should be aware that there [is a long-running bug with GCC under Windows](https://gcc.gnu.org/bugzilla/show_bug.cgi?id=54412).
|
||||||
|
|
||||||
**Indicate whether you are willing or able to provide a bug fix as a pull request**
|
**Indicate whether you are willing or able to provide a bug fix as a pull request**
|
||||||
|
|
||||||
If you plan to contribute to simdjson, please read our guide:
|
If you plan to contribute to simdjson, please read our guide:
|
||||||
|
|||||||
@@ -9,7 +9,8 @@ assignees: ''
|
|||||||
|
|
||||||
Before submitting an issue, please ensure that you have read the documentation:
|
Before submitting an issue, please ensure that you have read the documentation:
|
||||||
|
|
||||||
* Basics is an overview of how to use simdjson and its APIs: https://github.com/simdjson/simdjson/blob/master/doc/basics.md
|
* Basics is an overview of how to use simdjson and its APIs to parse JSON: https://github.com/simdjson/simdjson/blob/master/doc/basics.md
|
||||||
|
* Builder is an overview of how to use simdjson to generate JSON: https://github.com/simdjson/simdjson/blob/master/doc/builder.md
|
||||||
* Performance shows some more advanced scenarios and how to tune for them: https://github.com/simdjson/simdjson/blob/master/doc/performance.md
|
* Performance shows some more advanced scenarios and how to tune for them: https://github.com/simdjson/simdjson/blob/master/doc/performance.md
|
||||||
* Contributing: https://github.com/simdjson/simdjson/blob/master/CONTRIBUTING.md
|
* Contributing: https://github.com/simdjson/simdjson/blob/master/CONTRIBUTING.md
|
||||||
* We follow the [JSON specification as described by RFC 8259](https://www.rfc-editor.org/rfc/rfc8259.txt) (T. Bray, 2017).
|
* We follow the [JSON specification as described by RFC 8259](https://www.rfc-editor.org/rfc/rfc8259.txt) (T. Bray, 2017).
|
||||||
|
|||||||
@@ -9,7 +9,8 @@ assignees: ''
|
|||||||
|
|
||||||
Before submitting an issue, please ensure that you have read the documentation:
|
Before submitting an issue, please ensure that you have read the documentation:
|
||||||
|
|
||||||
* Basics is an overview of how to use simdjson and its APIs: https://github.com/simdjson/simdjson/blob/master/doc/basics.md
|
* Basics is an overview of how to use simdjson and its APIs to parse JSON: https://github.com/simdjson/simdjson/blob/master/doc/basics.md
|
||||||
|
* Builder is an overview of how to use simdjson to generate JSON: https://github.com/simdjson/simdjson/blob/master/doc/builder.md
|
||||||
* Performance shows some more advanced scenarios and how to tune for them: https://github.com/simdjson/simdjson/blob/master/doc/performance.md
|
* Performance shows some more advanced scenarios and how to tune for them: https://github.com/simdjson/simdjson/blob/master/doc/performance.md
|
||||||
* Contributing: https://github.com/simdjson/simdjson/blob/master/CONTRIBUTING.md
|
* Contributing: https://github.com/simdjson/simdjson/blob/master/CONTRIBUTING.md
|
||||||
* We follow the [JSON specification as described by RFC 8259](https://www.rfc-editor.org/rfc/rfc8259.txt) (T. Bray, 2017).
|
* We follow the [JSON specification as described by RFC 8259](https://www.rfc-editor.org/rfc/rfc8259.txt) (T. Bray, 2017).
|
||||||
|
|||||||
@@ -1,8 +1,53 @@
|
|||||||
|
Short title (summary):
|
||||||
|
|
||||||
|
Description
|
||||||
|
- What did you change and why? (1-3 sentences)
|
||||||
|
- Issue reproduced / related issue: link the issue if relevant (e.g. #123)
|
||||||
|
|
||||||
|
Type of change
|
||||||
|
- [ ] Bug fix
|
||||||
|
- [ ] New feature
|
||||||
|
- [ ] Refactor / cleanup
|
||||||
|
- [ ] Documentation / tests
|
||||||
|
- [ ] Other (please describe):
|
||||||
|
|
||||||
|
How to verify / test
|
||||||
|
- Add additional tests to verify bugs or new features.
|
||||||
|
- If you claim performance gains, you should provide benchmark numbers using high quality benchmarking code.
|
||||||
|
|
||||||
|
|
||||||
Our tests check whether you have introduced trailing white space. If such a test fails, please check the "artifacts button" above, which if you click it gives a link to a downloadable file to help you identify the issue. You can also run scripts/remove_trailing_whitespace.sh locally if you have a bash shell and the sed command available on your system.
|
Please read before contributing:
|
||||||
|
- CONTRIBUTING: https://github.com/simdjson/simdjson/blob/master/CONTRIBUTING.md
|
||||||
|
- HACKING: https://github.com/simdjson/simdjson/blob/master/HACKING.md
|
||||||
|
|
||||||
If you plan to contribute to simdjson, please read our
|
|
||||||
|
|
||||||
CONTRIBUTING guide: https://github.com/simdjson/simdjson/blob/master/CONTRIBUTING.md and our
|
|
||||||
HACKING guide: https://github.com/simdjson/simdjson/blob/master/HACKING.md
|
If you can, we recommend running our tests with the sanitizers turned on.
|
||||||
|
For non-Visual Studio users, it is as easy as doing:
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cmake -B build -D SIMDJSON_SANITIZE=ON -D SIMDJSON_DEVELOPER_MODE=ON
|
||||||
|
cmake --build build
|
||||||
|
ctest --test-dir build
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
Our CI checks, among other things, for trailing whitespace. If a test fails for that reason,
|
||||||
|
use the "artifacts" button to download the artifact and inspect the problematic lines,
|
||||||
|
or run `scripts/remove_trailing_whitespace.sh` locally if you have a bash shell and `sed`.
|
||||||
|
|
||||||
|
|
||||||
|
Checklist before submitting
|
||||||
|
- [ ] I added/updated tests covering my change (if applicable)
|
||||||
|
- [ ] Code builds locally and passes my check
|
||||||
|
- [ ] Documentation / README updated if needed
|
||||||
|
- [ ] Commits are atomic and messages are clear
|
||||||
|
- [ ] I linked the related issue (if applicable)
|
||||||
|
|
||||||
|
Final notes
|
||||||
|
- For large PRs, prefer smaller incremental PRs or request staged review.
|
||||||
|
|
||||||
|
Thanks for the contribution!
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,29 @@
|
|||||||
|
name: Ubuntu rvv VLEN=1024 (clang 18)
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-24.04
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- name: Install packages
|
||||||
|
run: |
|
||||||
|
sudo apt-get update -q -y
|
||||||
|
sudo apt-get install -y cmake make g++-riscv64-linux-gnu qemu-user-static clang-18
|
||||||
|
- name: Build
|
||||||
|
run: |
|
||||||
|
CXX=clang++-18 CXXFLAGS="--target=riscv64-linux-gnu -march=rv64gcv_zvbb" \
|
||||||
|
cmake --toolchain=cmake/toolchains-ci/riscv64-linux-gnu.cmake -DCMAKE_BUILD_TYPE=Release -B build
|
||||||
|
cmake --build build/ -j$(nproc)
|
||||||
|
- name: Test VLEN=1024
|
||||||
|
run: |
|
||||||
|
export QEMU_LD_PREFIX="/usr/riscv64-linux-gnu"
|
||||||
|
export QEMU_CPU="rv64,v=on,zvbb=on,vlen=1024,rvv_ta_all_1s=on,rvv_ma_all_1s=on"
|
||||||
|
ctest --timeout 1800 --output-on-failure --test-dir build -j $(nproc)
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
name: Ubuntu rvv VLEN=128 (clang 17)
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-24.04
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- name: Install packages
|
||||||
|
run: |
|
||||||
|
sudo apt-get update -q -y
|
||||||
|
sudo apt-get install -y cmake make g++-riscv64-linux-gnu qemu-user-static clang-17
|
||||||
|
- name: Build
|
||||||
|
run: |
|
||||||
|
CXX=clang++-17 CXXFLAGS="--target=riscv64-linux-gnu -march=rv64gcv" \
|
||||||
|
cmake --toolchain=cmake/toolchains-ci/riscv64-linux-gnu.cmake -DCMAKE_BUILD_TYPE=Release -B build
|
||||||
|
cmake --build build/ -j$(nproc)
|
||||||
|
- name: Test VLEN=128
|
||||||
|
run: |
|
||||||
|
export QEMU_LD_PREFIX="/usr/riscv64-linux-gnu"
|
||||||
|
export QEMU_CPU="rv64,v=on,vlen=128,rvv_ta_all_1s=on,rvv_ma_all_1s=on"
|
||||||
|
ctest --timeout 1800 --output-on-failure --test-dir build -j $(nproc)
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
name: Ubuntu rvv VLEN=256 (gcc 14)
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-24.04
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- name: Install packages
|
||||||
|
run: |
|
||||||
|
sudo apt-get update -q -y
|
||||||
|
sudo apt-get install -y cmake make g++-14-riscv64-linux-gnu qemu-user-static
|
||||||
|
- name: Build
|
||||||
|
run: |
|
||||||
|
CXX=riscv64-linux-gnu-g++-14 CXXFLAGS=-march=rv64gcv \
|
||||||
|
cmake --toolchain=cmake/toolchains-ci/riscv64-linux-gnu.cmake -DCMAKE_BUILD_TYPE=Release -B build
|
||||||
|
cmake --build build/ -j$(nproc)
|
||||||
|
- name: Test VLEN=256
|
||||||
|
run: |
|
||||||
|
export QEMU_LD_PREFIX="/usr/riscv64-linux-gnu"
|
||||||
|
export QEMU_CPU="rv64,v=on,zvbb=on,vlen=256,rvv_ta_all_1s=on,rvv_ma_all_1s=on"
|
||||||
|
ctest --timeout 1800 --output-on-failure --test-dir build -j $(nproc)
|
||||||
@@ -14,20 +14,52 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
path: dependencies/.cache
|
path: dependencies/.cache
|
||||||
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
||||||
- name: Use cmake
|
|
||||||
|
- name: Configure Debug Build
|
||||||
run: |
|
run: |
|
||||||
mkdir 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 -B builddebug
|
||||||
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 .. &&
|
- name: Compile Debug Build
|
||||||
cmake --build . &&
|
run: |
|
||||||
ctest --output-on-failure -LE explicitonly -j &&
|
cmake --build builddebug
|
||||||
cd .. &&
|
|
||||||
mkdir build &&
|
- name: Test Debug Build
|
||||||
cd build &&
|
run: |
|
||||||
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 .. &&
|
ctest --output-on-failure -LE explicitonly -j --test-dir builddebug
|
||||||
cmake --build . &&
|
|
||||||
ctest --output-on-failure -LE explicitonly -j &&
|
- name: Configure Release Build
|
||||||
cmake --install . &&
|
run: |
|
||||||
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 &&
|
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 -B build
|
||||||
cd ../tests/installation_tests/find &&
|
|
||||||
mkdir build && cd build && cmake -DCMAKE_INSTALL_PREFIX:PATH=../../../build/destination .. && cmake --build .
|
- name: Compile Release Build
|
||||||
|
run: |
|
||||||
|
cmake --build build
|
||||||
|
|
||||||
|
- name: Test Release Build
|
||||||
|
run: |
|
||||||
|
ctest --output-on-failure -LE explicitonly -j --test-dir build
|
||||||
|
|
||||||
|
- name: Install Release Build
|
||||||
|
run: |
|
||||||
|
cmake --install build
|
||||||
|
|
||||||
|
- name: Generate Example Code
|
||||||
|
run: |
|
||||||
|
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
|
||||||
|
|
||||||
|
- name: Compile Example Code
|
||||||
|
run: |
|
||||||
|
c++ -Idestination/include -Ldestination/lib -std=c++17 -Wl,-rpath,destination/lib -o linkandrun tmp.cpp -lsimdjson
|
||||||
|
|
||||||
|
- name: Run Example Code
|
||||||
|
run: |
|
||||||
|
./linkandrun jsonexamples/twitter.json
|
||||||
|
|
||||||
|
- name: Configure Find Tests
|
||||||
|
run: |
|
||||||
|
cd tests/installation_tests/find && \
|
||||||
|
cmake -DCMAKE_INSTALL_PREFIX:PATH=../../../destination -B build
|
||||||
|
|
||||||
|
- name: Compile Find Tests
|
||||||
|
run: |
|
||||||
|
cd tests/installation_tests/find && cmake --build build
|
||||||
|
|||||||
@@ -0,0 +1,22 @@
|
|||||||
|
name: Ubuntu 24.04 CI (CXX 20, noexcept)
|
||||||
|
|
||||||
|
on: [push, pull_request]
|
||||||
|
jobs:
|
||||||
|
ubuntu-build:
|
||||||
|
if: >-
|
||||||
|
! contains(toJSON(github.event.commits.*.message), '[skip ci]') &&
|
||||||
|
! contains(toJSON(github.event.commits.*.message), '[skip github]')
|
||||||
|
runs-on: ubuntu-24.04
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
cxx: [g++-13, clang++-16]
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
|
||||||
|
- name: Prepare
|
||||||
|
run: cmake -DSIMDJSON_CXX_STANDARD=20 -DSIMDJSON_EXCEPTIONS=OFF -DSIMDJSON_DEVELOPER_MODE=ON -B build
|
||||||
|
env:
|
||||||
|
CXX: ${{matrix.cxx}}
|
||||||
|
- name: Build
|
||||||
|
run: cmake --build build -j=2
|
||||||
|
- name: Test
|
||||||
|
run: ctest --output-on-failure --test-dir build
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
name: VS17-CI-SANITIZE
|
||||||
|
|
||||||
|
on: [push, pull_request]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
ci:
|
||||||
|
if: >-
|
||||||
|
! contains(toJSON(github.event.commits.*.message), '[skip ci]') &&
|
||||||
|
! contains(toJSON(github.event.commits.*.message), '[skip github]')
|
||||||
|
name: windows-vs17
|
||||||
|
runs-on: windows-latest
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
include:
|
||||||
|
- {gen: Visual Studio 17 2022, arch: x64, shared: OFF, build_type: Debug}
|
||||||
|
- {gen: Visual Studio 17 2022, arch: x64, shared: OFF, build_type: Release}
|
||||||
|
- {gen: Visual Studio 17 2022, arch: x64, shared: OFF, build_type: RelWithDebInfo}
|
||||||
|
steps:
|
||||||
|
- name: checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
- name: Configure
|
||||||
|
run: |
|
||||||
|
cmake -G "${{matrix.gen}}" -A ${{matrix.arch}} -DSANITIZE=ON -DSIMDJSON_DEVELOPER_MODE=ON -DSIMDJSON_COMPETITION=OFF -DBUILD_SHARED_LIBS=${{matrix.shared}} -B build
|
||||||
|
- name: Build
|
||||||
|
run: cmake --build build --config ${{matrix.build_type}} --verbose
|
||||||
|
- name: Run tests
|
||||||
|
run: |
|
||||||
|
cd build
|
||||||
|
ctest -C ${{matrix.build_type}} -LE explicitonly --output-on-failure
|
||||||
@@ -88,6 +88,7 @@ objs
|
|||||||
# Build outputs
|
# Build outputs
|
||||||
/build*/
|
/build*/
|
||||||
/visual_studio/
|
/visual_studio/
|
||||||
|
/originbuild/
|
||||||
|
|
||||||
# Fuzzer outputs generated by instructions in fuzz/Fuzzing.md
|
# Fuzzer outputs generated by instructions in fuzz/Fuzzing.md
|
||||||
/corpus.zip
|
/corpus.zip
|
||||||
|
|||||||
Vendored
+3
@@ -3,6 +3,9 @@
|
|||||||
{"column": 95 },
|
{"column": 95 },
|
||||||
{"column": 120 }
|
{"column": 120 }
|
||||||
],
|
],
|
||||||
|
"cmake.configureArgs": [
|
||||||
|
"-DSIMDJSON_DEVELOPER_MODE=ON"
|
||||||
|
],
|
||||||
"files.trimTrailingWhitespace": true,
|
"files.trimTrailingWhitespace": true,
|
||||||
"files.associations": {
|
"files.associations": {
|
||||||
".clangd": "yaml",
|
".clangd": "yaml",
|
||||||
|
|||||||
+3
-3
@@ -3,7 +3,7 @@ cmake_minimum_required(VERSION 3.14)
|
|||||||
project(
|
project(
|
||||||
simdjson
|
simdjson
|
||||||
# The version number is modified by tools/release.py
|
# The version number is modified by tools/release.py
|
||||||
VERSION 4.0.0
|
VERSION 4.0.2
|
||||||
DESCRIPTION "Parsing gigabytes of JSON per second"
|
DESCRIPTION "Parsing gigabytes of JSON per second"
|
||||||
HOMEPAGE_URL "https://simdjson.org/"
|
HOMEPAGE_URL "https://simdjson.org/"
|
||||||
LANGUAGES CXX C
|
LANGUAGES CXX C
|
||||||
@@ -20,8 +20,8 @@ string(
|
|||||||
# ---- Options, variables ----
|
# ---- Options, variables ----
|
||||||
|
|
||||||
# These version numbers are modified by tools/release.py
|
# These version numbers are modified by tools/release.py
|
||||||
set(SIMDJSON_LIB_VERSION "28.0.0" CACHE STRING "simdjson library version")
|
set(SIMDJSON_LIB_VERSION "27.0.0" CACHE STRING "simdjson library version")
|
||||||
set(SIMDJSON_LIB_SOVERSION "28" CACHE STRING "simdjson library soversion")
|
set(SIMDJSON_LIB_SOVERSION "27" CACHE STRING "simdjson library soversion")
|
||||||
|
|
||||||
option(SIMDJSON_BUILD_STATIC_LIB "Build simdjson_static library along with simdjson (only makes sense if BUILD_SHARED_LIBS=ON)" OFF)
|
option(SIMDJSON_BUILD_STATIC_LIB "Build simdjson_static library along with simdjson (only makes sense if BUILD_SHARED_LIBS=ON)" OFF)
|
||||||
if(SIMDJSON_BUILD_STATIC_LIB AND NOT BUILD_SHARED_LIBS)
|
if(SIMDJSON_BUILD_STATIC_LIB AND NOT BUILD_SHARED_LIBS)
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ PROJECT_NAME = simdjson
|
|||||||
# could be handy for archiving the generated documentation or if some version
|
# could be handy for archiving the generated documentation or if some version
|
||||||
# control system is used.
|
# control system is used.
|
||||||
|
|
||||||
PROJECT_NUMBER = "4.0.0"
|
PROJECT_NUMBER = "4.0.2"
|
||||||
|
|
||||||
# Using the PROJECT_BRIEF tag one can provide an optional one line description
|
# 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
|
# for a project that appears at the top of each page and should give viewer a
|
||||||
|
|||||||
+46
-8
@@ -20,13 +20,54 @@ If you plan to contribute to simdjson, please read our [CONTRIBUTING](https://gi
|
|||||||
Build Quickstart
|
Build Quickstart
|
||||||
------------------------------
|
------------------------------
|
||||||
|
|
||||||
|
For non-Windows system,
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
mkdir build
|
cmake -B -D SIMDJSON_DEVELOPER_MODE=ON ..
|
||||||
cd build
|
cmake --build build
|
||||||
cmake -D SIMDJSON_DEVELOPER_MODE=ON ..
|
ctest --test-dir build
|
||||||
cmake --build .
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
It is similar for Visual Studio users, please see the CMake or Visual Studio documentation.
|
||||||
|
|
||||||
|
By default the library is built in Release mode.
|
||||||
|
|
||||||
|
|
||||||
|
Assertions and development checks
|
||||||
|
------------------------------
|
||||||
|
|
||||||
|
We do not use conventional `assert` in simdjson. Instead we use the macro
|
||||||
|
`SIMDJSON_ASSUME`:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
SIMDJSON_ASSUME(something_that_is_true());
|
||||||
|
```
|
||||||
|
|
||||||
|
Sometimes, you need to do a bit more work that a simple check.
|
||||||
|
The `SIMDJSON_DEVELOPMENT_CHECKS` macro is true only in Debug mode unless manually set.
|
||||||
|
It is acceptable to add checks that you would not do in Release mode as long as
|
||||||
|
they are guarded:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
#if SIMDJSON_DEVELOPMENT_CHECKS
|
||||||
|
// do sanity checks here
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
Working with sanitizers
|
||||||
|
------------------------------
|
||||||
|
|
||||||
|
The simdjson library must be memory-safe. We cannot allow buffer overruns.
|
||||||
|
During development, if you system supports it, we recommend configuring
|
||||||
|
the project with `-D SIMDJSON_SANITIZE=ON`.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cmake -B -D SIMDJSON_SANITIZE=ON -D SIMDJSON_DEVELOPER_MODE=ON ..
|
||||||
|
cmake --build build
|
||||||
|
ctest --test-dir build
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
Design notes
|
Design notes
|
||||||
------------------------------
|
------------------------------
|
||||||
|
|
||||||
@@ -103,12 +144,9 @@ simdjson's source structure, from the top level, looks like this:
|
|||||||
* 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.
|
* 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:
|
Other important files and directories:
|
||||||
* **.drone.yml:** Definitions for Drone CI.
|
|
||||||
* **.appveyor.yml:** Definitions for Appveyor CI (Windows).
|
|
||||||
* **.circleci:** Definitions for Circle CI.
|
|
||||||
* **.github/workflows:** Definitions for GitHub Actions (CI).
|
* **.github/workflows:** Definitions for GitHub Actions (CI).
|
||||||
* **singleheader:** Contains generated `simdjson.h` and `simdjson.cpp` that we release. The files `singleheader/simdjson.h` and `singleheader/simdjson.cpp` should never be edited by hand.
|
* **singleheader:** Contains generated `simdjson.h` and `simdjson.cpp` that we release. The files `singleheader/simdjson.h` and `singleheader/simdjson.cpp` should never be edited by hand.
|
||||||
* **singleheader/amalgamate.py:** Generates `singleheader/simdjson.h` and `singleheader/simdjson.cpp` for release (python script).
|
* **singleheader/amalgamate.py:** Generates `singleheader/simdjson.h` and `singleheader/simdjson.cpp` for release (python script). If you add a new implementation (e.g., rvv), you need to edit this file (IMPLEMENTATIONS).
|
||||||
* **benchmark:** This is where we do benchmarking. Benchmarking is core to every change we make; the
|
* **benchmark:** This is where we do benchmarking. Benchmarking is core to every change we make; the
|
||||||
cardinal rule is don't regress performance without knowing exactly why, and what you're trading
|
cardinal rule is don't regress performance without knowing exactly why, and what you're trading
|
||||||
for it. Many of our benchmarks are microbenchmarks. We are effectively doing controlled scientific experiments for the purpose of understanding what affects our performance. So we simplify as much as possible. We try to avoid irrelevant factors such as page faults, interrupts, unnecessary system calls. We recommend checking the performance as follows:
|
for it. Many of our benchmarks are microbenchmarks. We are effectively doing controlled scientific experiments for the purpose of understanding what affects our performance. So we simplify as much as possible. We try to avoid irrelevant factors such as page faults, interrupts, unnecessary system calls. We recommend checking the performance as follows:
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
|
|
||||||
[](https://bugs.chromium.org/p/oss-fuzz/issues/list?sort=-opened&can=1&q=proj:simdjson)
|
|
||||||
[![][license img]][license] [![][licensemit img]][licensemit]
|
[![][license img]][license] [![][licensemit img]][licensemit]
|
||||||
|
|
||||||
|
|
||||||
@@ -121,6 +119,7 @@ Godbolt
|
|||||||
Some users may want to browse code along with the compiled assembly. You want to check out the following lists of examples:
|
Some users may want to browse code along with the compiled assembly. You want to check out the following lists of examples:
|
||||||
* [simdjson examples with errors handled through exceptions](https://godbolt.org/z/7G5qE4sr9)
|
* [simdjson examples with errors handled through exceptions](https://godbolt.org/z/7G5qE4sr9)
|
||||||
* [simdjson examples with errors without exceptions](https://godbolt.org/z/e9dWb9E4v)
|
* [simdjson examples with errors without exceptions](https://godbolt.org/z/e9dWb9E4v)
|
||||||
|
* [C++26 reflection example](https://godbolt.org/z/xK5TGKdPb)
|
||||||
|
|
||||||
Performance results
|
Performance results
|
||||||
-------------------
|
-------------------
|
||||||
|
|||||||
@@ -35,6 +35,16 @@ if (TARGET benchmark::benchmark)
|
|||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|
||||||
|
include(CheckCXXCompilerFlag)
|
||||||
|
check_cxx_compiler_flag("-std=c++20" SIMDJSON_COMPILER_SUPPORTS_CXX20)
|
||||||
if(SIMDJSON_STATIC_REFLECTION)
|
if(SIMDJSON_STATIC_REFLECTION)
|
||||||
add_subdirectory(static_reflect)
|
add_subdirectory(static_reflect)
|
||||||
|
else()
|
||||||
|
if(SIMDJSON_EXCEPTIONS AND SIMDJSON_COMPILER_SUPPORTS_CXX20)
|
||||||
|
add_subdirectory(from)
|
||||||
|
add_subdirectory(car_builder)
|
||||||
|
endif()
|
||||||
endif(SIMDJSON_STATIC_REFLECTION)
|
endif(SIMDJSON_STATIC_REFLECTION)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
# Executable
|
||||||
|
add_executable(benchmark_car_builder benchmark_car_builder.cpp)
|
||||||
|
|
||||||
|
# Compile for C++20.
|
||||||
|
target_compile_features(benchmark_car_builder PRIVATE cxx_std_20)
|
||||||
|
|
||||||
|
# Check if -march=native is supported
|
||||||
|
include(CheckCXXCompilerFlag)
|
||||||
|
check_cxx_compiler_flag("-march=native" SIMDJSON_SUPPORTS_MARCH_NATIVE)
|
||||||
|
if(SIMDJSON_SUPPORTS_MARCH_NATIVE)
|
||||||
|
target_compile_options(benchmark_car_builder PRIVATE -march=native)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
target_include_directories(benchmark_car_builder PRIVATE ${CMAKE_CURRENT_LIST_DIR}/..)
|
||||||
@@ -0,0 +1,127 @@
|
|||||||
|
#include "event_counter.h"
|
||||||
|
#include <random>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <simdjson.h>
|
||||||
|
|
||||||
|
event_collector collector;
|
||||||
|
|
||||||
|
struct Car {
|
||||||
|
std::string make;
|
||||||
|
std::string model;
|
||||||
|
int64_t year; // We deliberately do not include the tire pressure.
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<Car> generate_random_cars(size_t count) {
|
||||||
|
static const std::vector<std::string> makes = {"Toyota", "Honda", "Ford",
|
||||||
|
"BMW", "Mazda"};
|
||||||
|
static const std::vector<std::string> models = {"Camry", "Civic", "Focus",
|
||||||
|
"320i", "3"};
|
||||||
|
static thread_local std::mt19937 rng{std::random_device{}()};
|
||||||
|
std::uniform_int_distribution<int> make_dist(0, makes.size() - 1);
|
||||||
|
std::uniform_int_distribution<int> model_dist(0, models.size() - 1);
|
||||||
|
std::uniform_int_distribution<int64_t> year_dist(2000, 2025);
|
||||||
|
std::uniform_real_distribution<double> pressure_dist(30.0, 45.0);
|
||||||
|
|
||||||
|
std::vector<Car> cars;
|
||||||
|
cars.reserve(count);
|
||||||
|
for (size_t i = 0; i < count; ++i) {
|
||||||
|
Car car;
|
||||||
|
car.make = makes[make_dist(rng)];
|
||||||
|
car.model = models[model_dist(rng)];
|
||||||
|
car.year = year_dist(rng);
|
||||||
|
cars.push_back(std::move(car));
|
||||||
|
}
|
||||||
|
return cars;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string_view serialize(simdjson::builder::string_builder &sb,
|
||||||
|
const std::vector<Car> &cars) {
|
||||||
|
sb.clear();
|
||||||
|
sb.start_array();
|
||||||
|
for (const auto &car : cars) {
|
||||||
|
sb.start_object();
|
||||||
|
sb.append_key_value("make", car.make);
|
||||||
|
sb.append_comma();
|
||||||
|
sb.append_key_value("model", car.model);
|
||||||
|
sb.append_comma();
|
||||||
|
sb.append_key_value("year", car.year);
|
||||||
|
sb.end_object();
|
||||||
|
}
|
||||||
|
sb.end_array();
|
||||||
|
std::string_view result;
|
||||||
|
if (sb.view().get(result)) {
|
||||||
|
return ""; // unexpected (error)
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
double pretty_print(const std::string &name, size_t num_chars,
|
||||||
|
std::pair<event_aggregate, size_t> result) {
|
||||||
|
const auto &agg = result.first;
|
||||||
|
size_t N = result.second;
|
||||||
|
num_chars *= N;
|
||||||
|
printf("%-40s : %8.2f ns %8.2f GB/s", name.c_str(),
|
||||||
|
agg.elapsed_ns() / num_chars, num_chars / agg.elapsed_ns());
|
||||||
|
if (collector.has_events()) {
|
||||||
|
printf(" %8.2f GHz %8.2f cycles/char %8.2f ins./char %8.2f i/c",
|
||||||
|
agg.cycles() / agg.elapsed_ns(), agg.cycles() / num_chars,
|
||||||
|
agg.instructions() / num_chars, agg.instructions() / agg.cycles());
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
return num_chars / agg.elapsed_ns();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class function_type>
|
||||||
|
std::pair<event_aggregate, size_t>
|
||||||
|
bench(const function_type &&function, size_t min_repeat = 100,
|
||||||
|
size_t min_time_ns = 40'000'000, size_t max_repeat = 10000000) {
|
||||||
|
size_t N = min_repeat;
|
||||||
|
if (N == 0) {
|
||||||
|
N = 1;
|
||||||
|
}
|
||||||
|
event_aggregate warm_aggregate{};
|
||||||
|
for (size_t i = 0; i < N; i++) {
|
||||||
|
std::atomic_thread_fence(std::memory_order_acquire);
|
||||||
|
collector.start();
|
||||||
|
function();
|
||||||
|
std::atomic_thread_fence(std::memory_order_release);
|
||||||
|
event_count allocate_count = collector.end();
|
||||||
|
warm_aggregate << allocate_count;
|
||||||
|
if ((i + 1 == N) && (warm_aggregate.total_elapsed_ns() < min_time_ns) &&
|
||||||
|
(N < max_repeat)) {
|
||||||
|
N *= 10;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
event_aggregate aggregate{};
|
||||||
|
for (size_t i = 0; i < 10; i++) {
|
||||||
|
std::atomic_thread_fence(std::memory_order_acquire);
|
||||||
|
collector.start();
|
||||||
|
for (size_t i = 0; i < N; i++) {
|
||||||
|
function();
|
||||||
|
}
|
||||||
|
std::atomic_thread_fence(std::memory_order_release);
|
||||||
|
event_count allocate_count = collector.end();
|
||||||
|
aggregate << allocate_count;
|
||||||
|
}
|
||||||
|
return {aggregate, N};
|
||||||
|
}
|
||||||
|
|
||||||
|
void run_benchmarks() {
|
||||||
|
std::vector<Car> source = generate_random_cars(100000);
|
||||||
|
simdjson::builder::string_builder sb;
|
||||||
|
size_t volume = serialize(sb, source).size();
|
||||||
|
|
||||||
|
pretty_print("string_builder", volume, bench([&source, &sb]() -> size_t {
|
||||||
|
return serialize(sb, source).size();
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
for (size_t trial = 0; trial < 3; trial++) {
|
||||||
|
printf("Trial %zu:\n", trial + 1);
|
||||||
|
run_benchmarks();
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
||||||
@@ -25,12 +25,11 @@ int main(int argc, char *argv[]) {
|
|||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
const char *filename = argv[1];
|
const char *filename = argv[1];
|
||||||
auto v = simdjson::padded_string::load(filename);
|
simdjson::padded_string p;
|
||||||
if (v.error()) {
|
if (simdjson::padded_string::load(filename).get(p)) {
|
||||||
std::cerr << "Could not load the file " << filename << std::endl;
|
std::cerr << "Could not load the file " << filename << std::endl;
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
const simdjson::padded_string& p = v.value_unsafe();
|
|
||||||
if (test_baseline) {
|
if (test_baseline) {
|
||||||
std::wclog << "Baseline: Getline + normal parse... " << std::endl;
|
std::wclog << "Baseline: Getline + normal parse... " << std::endl;
|
||||||
std::cout << "Gigabytes/second\t"
|
std::cout << "Gigabytes/second\t"
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
# Executable
|
||||||
|
add_executable(from_benchmark from_benchmark.cpp)
|
||||||
|
|
||||||
|
# Compile for C++20.
|
||||||
|
if(CMAKE_CXX_STANDARD LESS 20)
|
||||||
|
target_compile_features(from_benchmark PRIVATE cxx_std_20)
|
||||||
|
endif()
|
||||||
|
# Check if -march=native is supported
|
||||||
|
include(CheckCXXCompilerFlag)
|
||||||
|
check_cxx_compiler_flag("-march=native" SIMDJSON_SUPPORTS_MARCH_NATIVE)
|
||||||
|
if(SIMDJSON_SUPPORTS_MARCH_NATIVE)
|
||||||
|
target_compile_options(from_benchmark PRIVATE -march=native)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
target_include_directories(from_benchmark PRIVATE ${CMAKE_CURRENT_LIST_DIR}/..)
|
||||||
@@ -0,0 +1,77 @@
|
|||||||
|
#ifndef BENCHMARK_HELPERS_H
|
||||||
|
#define BENCHMARK_HELPERS_H
|
||||||
|
|
||||||
|
#include "event_counter.h"
|
||||||
|
#include <atomic>
|
||||||
|
|
||||||
|
event_collector collector;
|
||||||
|
|
||||||
|
template <class function_type>
|
||||||
|
std::pair<event_aggregate, size_t>
|
||||||
|
bench(const function_type &&function, size_t min_repeat = 10,
|
||||||
|
size_t min_time_ns = 40'000'000, size_t max_repeat = 10000000) {
|
||||||
|
size_t N = min_repeat;
|
||||||
|
if (N == 0) {
|
||||||
|
N = 1;
|
||||||
|
}
|
||||||
|
event_aggregate warm_aggregate{};
|
||||||
|
for (size_t i = 0; i < N; i++) {
|
||||||
|
std::atomic_thread_fence(std::memory_order_acquire);
|
||||||
|
collector.start();
|
||||||
|
function();
|
||||||
|
std::atomic_thread_fence(std::memory_order_release);
|
||||||
|
event_count allocate_count = collector.end();
|
||||||
|
warm_aggregate << allocate_count;
|
||||||
|
if ((i + 1 == N) && (warm_aggregate.total_elapsed_ns() < min_time_ns) &&
|
||||||
|
(N < max_repeat)) {
|
||||||
|
N *= 10;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
event_aggregate aggregate{};
|
||||||
|
for (size_t i = 0; i < 10; i++) {
|
||||||
|
std::atomic_thread_fence(std::memory_order_acquire);
|
||||||
|
collector.start();
|
||||||
|
for (size_t i = 0; i < N; i++) {
|
||||||
|
function();
|
||||||
|
}
|
||||||
|
std::atomic_thread_fence(std::memory_order_release);
|
||||||
|
event_count allocate_count = collector.end();
|
||||||
|
aggregate << allocate_count;
|
||||||
|
}
|
||||||
|
return {aggregate, N};
|
||||||
|
}
|
||||||
|
|
||||||
|
double pretty_print(const std::string &name, size_t num_chars,
|
||||||
|
std::pair<event_aggregate, size_t> result) {
|
||||||
|
const auto &agg = result.first;
|
||||||
|
size_t N = result.second;
|
||||||
|
num_chars *= N;
|
||||||
|
printf("%-40s : %8.2f ns %8.2f GB/s", name.c_str(),
|
||||||
|
agg.elapsed_ns() / num_chars, num_chars / agg.elapsed_ns());
|
||||||
|
if (collector.has_events()) {
|
||||||
|
printf(" %8.2f GHz %8.2f cycles/char %8.2f ins./char %8.2f i/c",
|
||||||
|
agg.cycles() / agg.elapsed_ns(), agg.cycles() / num_chars,
|
||||||
|
agg.instructions() / num_chars, agg.instructions() / agg.cycles());
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
return num_chars / agg.elapsed_ns();
|
||||||
|
}
|
||||||
|
|
||||||
|
double pretty_print_array(const std::string &name, size_t num_chars, size_t num_elements,
|
||||||
|
std::pair<event_aggregate, size_t> result) {
|
||||||
|
const auto &agg = result.first;
|
||||||
|
size_t N = result.second;
|
||||||
|
num_chars *= N;
|
||||||
|
printf("%-40s : %8.2f ns/char %8.2f ns/value %8.2f GB/s", name.c_str(),
|
||||||
|
agg.elapsed_ns() / num_chars, agg.elapsed_ns() / num_elements, num_chars / agg.elapsed_ns());
|
||||||
|
if (collector.has_events()) {
|
||||||
|
printf(" %8.2f GHz %8.2f cycles/char %8.2f ins./char %8.2f ins./value %8.2f i/c",
|
||||||
|
agg.cycles() / agg.elapsed_ns(), agg.cycles() / num_chars,
|
||||||
|
agg.instructions() / num_chars, agg.instructions() / num_elements, agg.instructions() / agg.cycles());
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
return num_chars / agg.elapsed_ns();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,146 @@
|
|||||||
|
#ifndef CAR_HELPERS_H
|
||||||
|
#define CAR_HELPERS_H
|
||||||
|
|
||||||
|
#include <iomanip>
|
||||||
|
#include <random>
|
||||||
|
#include <sstream>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <simdjson.h>
|
||||||
|
|
||||||
|
struct Car {
|
||||||
|
std::string make;
|
||||||
|
std::string model;
|
||||||
|
int64_t year; // We deliberately do not include the tire pressure.
|
||||||
|
};
|
||||||
|
|
||||||
|
using namespace simdjson;
|
||||||
|
|
||||||
|
std::string random_car_json() {
|
||||||
|
static const std::vector<std::string> makes = {"Toyota", "Honda", "Ford",
|
||||||
|
"BMW", "Mazda"};
|
||||||
|
static const std::vector<std::string> models = {"Camry", "Civic", "Focus",
|
||||||
|
"320i", "3"};
|
||||||
|
static thread_local std::mt19937 rng{std::random_device{}()};
|
||||||
|
std::uniform_int_distribution<int> make_dist(0, makes.size() - 1);
|
||||||
|
std::uniform_int_distribution<int> model_dist(0, models.size() - 1);
|
||||||
|
std::uniform_int_distribution<int> year_dist(2000, 2025);
|
||||||
|
std::uniform_real_distribution<double> pressure_dist(30.0, 45.0);
|
||||||
|
|
||||||
|
std::ostringstream oss;
|
||||||
|
oss << R"({ "make": ")" << makes[make_dist(rng)] << R"(", "model": ")"
|
||||||
|
<< models[model_dist(rng)] << R"(", "year": )" << year_dist(rng)
|
||||||
|
<< R"(, "tire_pressure": [ )" << std::fixed << std::setprecision(1)
|
||||||
|
<< pressure_dist(rng) << ", " << pressure_dist(rng) << R"( ] })";
|
||||||
|
return oss.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string generate_car_json_stream(size_t N) {
|
||||||
|
std::ostringstream oss;
|
||||||
|
for (size_t i = 0; i < N; ++i) {
|
||||||
|
oss << random_car_json();
|
||||||
|
oss << "\n";
|
||||||
|
}
|
||||||
|
return oss.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string generate_car_json_array(size_t N) {
|
||||||
|
std::ostringstream oss;
|
||||||
|
oss << "[\n";
|
||||||
|
for (size_t i = 0; i < N; ++i) {
|
||||||
|
oss << random_car_json();
|
||||||
|
if (i < N - 1) {
|
||||||
|
oss << ",";
|
||||||
|
}
|
||||||
|
oss << "\n";
|
||||||
|
}
|
||||||
|
oss << "]";
|
||||||
|
return oss.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
// We want to maximize C++ portability, but this is not needed with static
|
||||||
|
// reflection (C++26).
|
||||||
|
template <>
|
||||||
|
simdjson_inline simdjson_result<Car>
|
||||||
|
simdjson::ondemand::document::get() & noexcept {
|
||||||
|
ondemand::object obj;
|
||||||
|
auto error = get_object().get(obj);
|
||||||
|
if (error) {
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
Car car;
|
||||||
|
if ((error = obj["make"].get_string(car.make))) {
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
if ((error = obj["model"].get_string(car.model))) {
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
if ((error = obj["year"].get_int64().get(car.year))) {
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
return car;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
simdjson_inline simdjson_result<Car> simdjson::ondemand::value::get() noexcept {
|
||||||
|
ondemand::object obj;
|
||||||
|
auto error = get_object().get(obj);
|
||||||
|
if (error) {
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
Car car;
|
||||||
|
if ((error = obj["make"].get_string(car.make))) {
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
if ((error = obj["model"].get_string(car.model))) {
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
if ((error = obj["year"].get_int64().get(car.year))) {
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
return car;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
simdjson_inline simdjson_result<Car>
|
||||||
|
simdjson::ondemand::document_reference::get() & noexcept {
|
||||||
|
ondemand::object obj;
|
||||||
|
auto error = get_object().get(obj);
|
||||||
|
if (error) {
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
Car car;
|
||||||
|
if ((error = obj["make"].get_string(car.make))) {
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
if ((error = obj["model"].get_string(car.model))) {
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
if ((error = obj["year"].get_int64().get(car.year))) {
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
return car;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
simdjson_inline simdjson_result<Car>
|
||||||
|
simdjson::ondemand::document_reference::get() && noexcept {
|
||||||
|
ondemand::object obj;
|
||||||
|
auto error = get_object().get(obj);
|
||||||
|
if (error) {
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
Car car;
|
||||||
|
if ((error = obj["make"].get_string(car.make))) {
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
if ((error = obj["model"].get_string(car.model))) {
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
if ((error = obj["year"].get_int64().get(car.year))) {
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
return car;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,132 @@
|
|||||||
|
// We are going to assume C++20.
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <cstdio>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <simdjson.h>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "benchmark_helpers.h"
|
||||||
|
#include "car_helpers.h"
|
||||||
|
|
||||||
|
using namespace simdjson;
|
||||||
|
|
||||||
|
void run_benchmarks() {
|
||||||
|
printf("Running benchmarks on tiny input...\n");
|
||||||
|
simdjson::padded_string json =
|
||||||
|
R"({ "make": "Toyota", "model": "Camry", "year": 2018, "tire_pressure": [ 40.1, 39.9 ] })"_padded;
|
||||||
|
volatile size_t dummy = 0;
|
||||||
|
ondemand::parser parser;
|
||||||
|
|
||||||
|
// Classic On-Demand
|
||||||
|
pretty_print("simdjson classic", json.size(),
|
||||||
|
bench([&json, &dummy, &parser]() {
|
||||||
|
ondemand::document doc = parser.iterate(json);
|
||||||
|
Car car = doc.get<Car>();
|
||||||
|
dummy = dummy + car.year;
|
||||||
|
}));
|
||||||
|
|
||||||
|
// Benchmark simdjson::from() without parser
|
||||||
|
pretty_print("simdjson::from<Car>() (no parser)", json.size(),
|
||||||
|
bench([&json, &dummy]() {
|
||||||
|
Car car = simdjson::from(json);
|
||||||
|
dummy = dummy + car.year;
|
||||||
|
}));
|
||||||
|
|
||||||
|
// Benchmark simdjson::from() with parser
|
||||||
|
pretty_print("simdjson::from<Car>() (with parser)", json.size(),
|
||||||
|
bench([&json, &dummy, &parser]() {
|
||||||
|
Car car = simdjson::from(parser, json);
|
||||||
|
dummy = dummy + car.year;
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
void run_array_benchmarks() {
|
||||||
|
printf("Running benchmarks on large array...\n");
|
||||||
|
size_t N = 1'000'000;
|
||||||
|
simdjson::padded_string json = generate_car_json_array(N);
|
||||||
|
volatile size_t dummy = 0;
|
||||||
|
ondemand::parser parser;
|
||||||
|
|
||||||
|
// Classic On-Demand
|
||||||
|
pretty_print_array("simdjson classic", json.size(), N,
|
||||||
|
bench([&json, &dummy, &parser]() {
|
||||||
|
dummy = 0;
|
||||||
|
ondemand::document doc = parser.iterate(json);
|
||||||
|
ondemand::array array = doc.get_array();
|
||||||
|
for (auto value : array) {
|
||||||
|
Car car = value.get<Car>();
|
||||||
|
dummy = dummy + car.year;
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
// from with array
|
||||||
|
pretty_print_array("simdjson::from(json).array()", json.size(), N,
|
||||||
|
bench([&json, &dummy, &parser]() {
|
||||||
|
dummy = 0;
|
||||||
|
|
||||||
|
for (auto value : simdjson::from(json).array()) {
|
||||||
|
Car car = value.get<Car>();
|
||||||
|
dummy = dummy + car.year;
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
#if SIMDJSON_SUPPORTS_RANGES_FROM
|
||||||
|
// Benchmark simdjson::from() without parser (EXPERIMENTAL)
|
||||||
|
pretty_print_array("simdjson::from<Car>() (experimental, no parser)",
|
||||||
|
json.size(), N, bench([&json, &dummy]() {
|
||||||
|
dummy = 0;
|
||||||
|
for (Car car :
|
||||||
|
simdjson::from(json) | simdjson::as<Car>()) {
|
||||||
|
dummy = dummy + car.year;
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
// Benchmark simdjson::from() with parser (EXPERIMENTAL)
|
||||||
|
pretty_print_array("simdjson::from<Car>() (experimental, with parser)",
|
||||||
|
json.size(), N, bench([&json, &dummy, &parser]() {
|
||||||
|
dummy = 0;
|
||||||
|
for (Car car : simdjson::from(parser, json) |
|
||||||
|
simdjson::as<Car>()) {
|
||||||
|
dummy = dummy + car.year;
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
#endif // SIMDJSON_SUPPORTS_RANGES_FROM
|
||||||
|
}
|
||||||
|
|
||||||
|
void run_stream_benchmarks() {
|
||||||
|
printf("Running stream benchmarks...\n");
|
||||||
|
simdjson::padded_string json = generate_car_json_stream(1'000'000);
|
||||||
|
volatile size_t dummy = 0;
|
||||||
|
ondemand::parser parser;
|
||||||
|
|
||||||
|
// Classic On-Demand
|
||||||
|
pretty_print("simdjson classic", json.size(),
|
||||||
|
bench([&json, &dummy, &parser]() {
|
||||||
|
ondemand::document_stream stream = parser.iterate_many(json);
|
||||||
|
for (auto doc : stream) {
|
||||||
|
Car car = doc.get<Car>();
|
||||||
|
dummy = dummy + car.year;
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
// from_many
|
||||||
|
pretty_print("simdjson with thread local", json.size(),
|
||||||
|
bench([&json, &dummy, &parser]() {
|
||||||
|
ondemand::document_stream stream =
|
||||||
|
ondemand::parser::get_parser().iterate_many(json);
|
||||||
|
for (auto doc : stream) {
|
||||||
|
Car car = doc.get<Car>();
|
||||||
|
dummy = dummy + car.year;
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
for (size_t trial = 0; trial < 3; trial++) {
|
||||||
|
printf("Trial %zu:\n", trial + 1);
|
||||||
|
run_array_benchmarks();
|
||||||
|
run_stream_benchmarks();
|
||||||
|
run_benchmarks();
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
||||||
@@ -9,7 +9,11 @@ simdjson_never_inline
|
|||||||
double bench(std::string filename, simdjson::padded_string& p) {
|
double bench(std::string filename, simdjson::padded_string& p) {
|
||||||
std::chrono::time_point<std::chrono::steady_clock> start_clock =
|
std::chrono::time_point<std::chrono::steady_clock> start_clock =
|
||||||
std::chrono::steady_clock::now();
|
std::chrono::steady_clock::now();
|
||||||
simdjson::padded_string::load(filename).value_unsafe().swap(p);
|
auto error = simdjson::padded_string::load(filename).get(p);
|
||||||
|
if(error) {
|
||||||
|
std::cerr << simdjson::error_message(error) << std::endl;
|
||||||
|
std::abort();
|
||||||
|
}
|
||||||
std::chrono::time_point<std::chrono::steady_clock> end_clock =
|
std::chrono::time_point<std::chrono::steady_clock> end_clock =
|
||||||
std::chrono::steady_clock::now();
|
std::chrono::steady_clock::now();
|
||||||
std::chrono::duration<double> elapsed = end_clock - start_clock;
|
std::chrono::duration<double> elapsed = end_clock - start_clock;
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
add_library(simdjson-internal-flags INTERFACE)
|
add_library(simdjson-internal-flags INTERFACE)
|
||||||
if(NOT DEFINED CMAKE_POSITION_INDEPENDENT_CODE)
|
if(NOT DEFINED CMAKE_POSITION_INDEPENDENT_CODE)
|
||||||
# We default to ON for all targets, so that we can use the library in shared libraries.
|
# We default to ON for all targets, so that we can use the library in shared libraries.
|
||||||
set_target_properties(simdjson-internal-flags PROPERTIES POSITION_INDEPENDENT_CODE ON)
|
set_target_properties(simdjson-internal-flags PROPERTIES INTERFACE_POSITION_INDEPENDENT_CODE ON)
|
||||||
endif(NOT DEFINED CMAKE_POSITION_INDEPENDENT_CODE)
|
endif(NOT DEFINED CMAKE_POSITION_INDEPENDENT_CODE)
|
||||||
|
|
||||||
option(SIMDJSON_CHECK_EOF "Check for the end of the input buffer. The setting is unnecessary since we require padding of the inputs. You should expect tests to fail with this option turned on." OFF)
|
option(SIMDJSON_CHECK_EOF "Check for the end of the input buffer. The setting is unnecessary since we require padding of the inputs. You should expect tests to fail with this option turned on." OFF)
|
||||||
@@ -32,6 +32,9 @@ undefined behavior.")
|
|||||||
link_libraries(
|
link_libraries(
|
||||||
-fsanitize=address -fno-omit-frame-pointer -fno-sanitize-recover=all
|
-fsanitize=address -fno-omit-frame-pointer -fno-sanitize-recover=all
|
||||||
)
|
)
|
||||||
|
elseif (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
|
||||||
|
add_compile_options(-fsanitize=address)
|
||||||
|
link_libraries(-fsanitize=address)
|
||||||
else()
|
else()
|
||||||
message(
|
message(
|
||||||
STATUS
|
STATUS
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
#
|
#
|
||||||
# Implementation selection
|
# Implementation selection
|
||||||
#
|
#
|
||||||
set(SIMDJSON_ALL_IMPLEMENTATIONS fallback westmere haswell icelake arm64 ppc64)
|
set(SIMDJSON_ALL_IMPLEMENTATIONS fallback westmere haswell icelake arm64 ppc64 rvv)
|
||||||
|
|
||||||
set(
|
set(
|
||||||
SIMDJSON_IMPLEMENTATION ""
|
SIMDJSON_IMPLEMENTATION ""
|
||||||
@@ -15,7 +15,7 @@ set(
|
|||||||
SIMDJSON_EXCLUDE_IMPLEMENTATION ""
|
SIMDJSON_EXCLUDE_IMPLEMENTATION ""
|
||||||
CACHE STRING "\
|
CACHE STRING "\
|
||||||
Semicolon-separated list of implementations to exclude \
|
Semicolon-separated list of implementations to exclude \
|
||||||
(icelake/haswell/westmere/arm64/ppc64/fallback). By default, excludes any \
|
(icelake/haswell/westmere/arm64/ppc64/rvv/fallback). By default, excludes any \
|
||||||
implementations that are unsupported at compile time or cannot be selected at \
|
implementations that are unsupported at compile time or cannot be selected at \
|
||||||
runtime."
|
runtime."
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
set(CMAKE_SYSTEM_NAME Linux)
|
||||||
|
set(CMAKE_SYSTEM_PROCESSOR riscv64)
|
||||||
|
|
||||||
|
set(CMAKE_CROSSCOMPILING_EMULATOR "qemu-riscv64-static")
|
||||||
+254
-67
@@ -5,47 +5,47 @@ An overview of what you need to know to use simdjson to parse JSON documents, wi
|
|||||||
[Our documentation regarding the generation (serialization) of JSON documents is in a
|
[Our documentation regarding the generation (serialization) of JSON documents is in a
|
||||||
separate document](https://github.com/simdjson/simdjson/blob/master/doc/builder.md).
|
separate document](https://github.com/simdjson/simdjson/blob/master/doc/builder.md).
|
||||||
|
|
||||||
- [The Basics](#the-basics)
|
- [Requirements](#requirements)
|
||||||
* [Requirements](#requirements)
|
- [Including simdjson](#including-simdjson)
|
||||||
* [Including simdjson](#including-simdjson)
|
- [Using simdjson with package managers](#using-simdjson-with-package-managers)
|
||||||
* [Using simdjson with package managers](#using-simdjson-with-package-managers)
|
- [Using simdjson as a CMake dependency](#using-simdjson-as-a-cmake-dependency)
|
||||||
* [Using simdjson as a CMake dependency](#using-simdjson-as-a-cmake-dependency)
|
- [Versions](#versions)
|
||||||
* [Versions](#versions)
|
- [The basics: loading and parsing JSON documents](#the-basics-loading-and-parsing-json-documents)
|
||||||
* [The basics: loading and parsing JSON documents](#the-basics--loading-and-parsing-json-documents)
|
- [Documents are iterators](#documents-are-iterators)
|
||||||
* [Documents are iterators](#documents-are-iterators)
|
* [Parser, document and JSON scope](#parser-document-and-json-scope)
|
||||||
+ [Parser, document and JSON scope](#parser--document-and-json-scope)
|
- [string_view](#string_view)
|
||||||
* [string_view](#string-view)
|
- [Avoiding pitfalls: enable development checks](#avoiding-pitfalls-enable-development-checks)
|
||||||
* [Avoiding pitfalls: enable development checks](#avoiding-pitfalls--enable-development-checks)
|
- [Using the parsed JSON](#using-the-parsed-json)
|
||||||
* [Using the parsed JSON](#using-the-parsed-json)
|
* [Using the parsed JSON: additional examples](#using-the-parsed-json-additional-examples)
|
||||||
+ [Using the parsed JSON: additional examples](#using-the-parsed-json--additional-examples)
|
- [Adding support for custom types](#adding-support-for-custom-types)
|
||||||
* [Adding support for custom types](#adding-support-for-custom-types)
|
* [1. Specialize `simdjson::ondemand::value::get` to get custom types (pre-C++20)](#1-specialize-simdjsonondemandvalueget-to-get-custom-types-pre-c20)
|
||||||
+ [1. Specialize `simdjson::ondemand::value::get` to get custom types (pre-C++20)](#1-specialize--simdjson--ondemand--value--get--to-get-custom-types--pre-c--20-)
|
* [2. Use `tag_invoke` for custom types (C++20)](#2-use-tag_invoke-for-custom-types-c20)
|
||||||
+ [2. Use `tag_invoke` for custom types (C++20)](#2-use--tag-invoke--for-custom-types--c--20-)
|
* [3. Using static reflection (C++26)](#3-using-static-reflection-c26)
|
||||||
+ [3. Using static reflection (C++26)](#3-using-static-reflection--c--26-)
|
* [The simdjson::from shortcut (experimental, C++20)](#the-simdjsonfrom-shortcut-experimental-c20)
|
||||||
* [Minifying JSON strings without parsing](#minifying-json-strings-without-parsing)
|
- [Minifying JSON strings without parsing](#minifying-json-strings-without-parsing)
|
||||||
* [UTF-8 validation (alone)](#utf-8-validation--alone-)
|
- [UTF-8 validation (alone)](#utf-8-validation-alone)
|
||||||
* [JSON Pointer](#json-pointer)
|
- [JSON Pointer](#json-pointer)
|
||||||
* [JSONPath](#jsonpath)
|
- [JSONPath](#jsonpath)
|
||||||
* [Error handling](#error-handling)
|
- [Error handling](#error-handling)
|
||||||
+ [Error handling examples without exceptions](#error-handling-examples-without-exceptions)
|
* [Error handling examples without exceptions](#error-handling-examples-without-exceptions)
|
||||||
+ [Disabling exceptions](#disabling-exceptions)
|
* [Disabling exceptions](#disabling-exceptions)
|
||||||
+ [Exceptions](#exceptions)
|
* [Exceptions](#exceptions)
|
||||||
+ [Current location in document](#current-location-in-document)
|
* [Current location in document](#current-location-in-document)
|
||||||
+ [Checking for trailing content](#checking-for-trailing-content)
|
* [Checking for trailing content](#checking-for-trailing-content)
|
||||||
* [Rewinding](#rewinding)
|
- [Rewinding](#rewinding)
|
||||||
* [Newline-Delimited JSON (ndjson) and JSON lines](#newline-delimited-json--ndjson--and-json-lines)
|
- [Newline-Delimited JSON (ndjson) and JSON lines](#newline-delimited-json-ndjson-and-json-lines)
|
||||||
* [Parsing numbers inside strings](#parsing-numbers-inside-strings)
|
- [Parsing numbers inside strings](#parsing-numbers-inside-strings)
|
||||||
* [Dynamic Number Types](#dynamic-number-types)
|
- [Dynamic Number Types](#dynamic-number-types)
|
||||||
* [Raw strings from keys](#raw-strings-from-keys)
|
- [Raw strings from keys](#raw-strings-from-keys)
|
||||||
* [General direct access to the raw JSON string](#general-direct-access-to-the-raw-json-string)
|
- [General direct access to the raw JSON string](#general-direct-access-to-the-raw-json-string)
|
||||||
* [Storing directly into an existing string instance](#storing-directly-into-an-existing-string-instance)
|
* [Raw JSON string for objects and arrays](#raw-json-string-for-objects-and-arrays)
|
||||||
* [Thread safety](#thread-safety)
|
- [Storing directly into an existing string instance](#storing-directly-into-an-existing-string-instance)
|
||||||
* [Standard compliance](#standard-compliance)
|
- [Thread safety](#thread-safety)
|
||||||
* [Backwards compatibility](#backwards-compatibility)
|
- [Standard compliance](#standard-compliance)
|
||||||
* [Examples](#examples)
|
- [Backwards compatibility](#backwards-compatibility)
|
||||||
* [Performance tips](#performance-tips)
|
- [Examples](#examples)
|
||||||
* [Further reading](#further-reading)
|
- [Performance tips](#performance-tips)
|
||||||
|
- [Further reading](#further-reading)
|
||||||
|
|
||||||
Requirements
|
Requirements
|
||||||
------------------
|
------------------
|
||||||
@@ -54,7 +54,7 @@ The simdjson library is widely deployed in popular systems such as the Node.js r
|
|||||||
environment.
|
environment.
|
||||||
|
|
||||||
- A recent compiler (LLVM clang 6 or better, GNU GCC 7.4 or better, Xcode 11 or better) on POSIX systems such as macOS, FreeBSD or Linux. We require that the compiler supports the C++11 standard or better. We test the library on a big-endian system (IBM s390x with Linux).
|
- A recent compiler (LLVM clang 6 or better, GNU GCC 7.4 or better, Xcode 11 or better) on POSIX systems such as macOS, FreeBSD or Linux. We require that the compiler supports the C++11 standard or better. We test the library on a big-endian system (IBM s390x with Linux).
|
||||||
- Visual Studio 2017 or better. We support the LLVM clang compiler under Visual Studio (clang-cl) as well as as the regular Visual Studio compiler. For better release performance (both compile time and execution time), we recommend Visual Studio users adopt LLVM (clang-cl). We also support MinGW 64-bit under Windows.
|
- Visual Studio 2017 or better. We support the LLVM clang compiler under Visual Studio (clang-cl) as well as the regular Visual Studio compiler. For better release performance (both compile time and execution time), we recommend Visual Studio users adopt LLVM (clang-cl). We discourage using GCC under Windows: there [is a long-running bug with GCC under Windows](https://gcc.gnu.org/bugzilla/show_bug.cgi?id=54412).
|
||||||
|
|
||||||
Support for AVX-512 require a processor with AVX512-VBMI2 support (Ice Lake or better, AMD Zen 4 or better) under a 64-bit system and a recent compiler (LLVM clang 6 or better, GCC 8 or better, Visual Studio 2019 or better). You need a correspondingly recent assembler such as gas (2.30+) or nasm (2.14+): recent compilers usually come with recent assemblers. If you mix a recent compiler with an incompatible/old assembler (e.g., when using a recent compiler with an old Linux distribution), you may get errors at build time because the compiler produces instructions that the assembler does not recognize: you should update your assembler to match your compiler (e.g., upgrade binutils to version 2.30 or better under Linux) or use an older compiler matching the capabilities of your assembler.
|
Support for AVX-512 require a processor with AVX512-VBMI2 support (Ice Lake or better, AMD Zen 4 or better) under a 64-bit system and a recent compiler (LLVM clang 6 or better, GCC 8 or better, Visual Studio 2019 or better). You need a correspondingly recent assembler such as gas (2.30+) or nasm (2.14+): recent compilers usually come with recent assemblers. If you mix a recent compiler with an incompatible/old assembler (e.g., when using a recent compiler with an old Linux distribution), you may get errors at build time because the compiler produces instructions that the assembler does not recognize: you should update your assembler to match your compiler (e.g., upgrade binutils to version 2.30 or better under Linux) or use an older compiler matching the capabilities of your assembler.
|
||||||
|
|
||||||
@@ -78,14 +78,14 @@ c++ myproject.cpp simdjson.cpp
|
|||||||
```
|
```
|
||||||
|
|
||||||
Note:
|
Note:
|
||||||
- We recommend that you use simdjson by copying the single-header `simdjson.h` file along with the source file `simdjson.cpp` directly in your project, as they are part of [every release](https://github.com/simdjson/simdjson/releases) as assets. In this manner, you only have to compile `simdjson.cpp` as any other source file: it works well in every development environment. However, you may also use simdjson as a git submodule ([example](https://github.com/simdjson/cmakedemo)), using FetchContent ([example](https://github.com/simdjson/cmake_demo_single_file)), with ExternalProject_Add ([example](https://github.com/simdjson/cmakedemo_externalproject)) or with CPM ([example](https://github.com/cpm-cmake/CPM.cmake/tree/master/examples/simdjson)).
|
- We recommend that you use simdjson by copying the single-header `simdjson.h` file along with the source file `simdjson.cpp` directly into your project, as they are part of [every release](https://github.com/simdjson/simdjson/releases) as assets. In this manner, you only have to compile `simdjson.cpp` as any other source file: it works well in every development environment. However, you may also use simdjson as a git submodule ([example](https://github.com/simdjson/cmakedemo)), using FetchContent ([example](https://github.com/simdjson/cmake_demo_single_file)), with ExternalProject_Add ([example](https://github.com/simdjson/cmakedemo_externalproject)) or with CPM ([example](https://github.com/cpm-cmake/CPM.cmake/tree/master/examples/simdjson)).
|
||||||
- Users on macOS and other platforms where default compilers do not provide C++11 compliant by default should request it with the appropriate flag (e.g., `c++ -std=c++11 myproject.cpp simdjson.cpp`).
|
- Users on macOS and other platforms where default compilers do not provide C++11 compliant by default should request it with the appropriate flag (e.g., `c++ -std=c++11 myproject.cpp simdjson.cpp`).
|
||||||
- The library relies on [runtime CPU detection](implementation-selection.md): avoid specifying an architecture at compile time (e.g., `-march-native`) if you want your binaries to run everywhere.
|
- The library relies on [runtime CPU detection](implementation-selection.md): avoid specifying an architecture at compile time (e.g., `-march-native`) if you want your binaries to run everywhere.
|
||||||
|
|
||||||
Using simdjson with package managers
|
Using simdjson with package managers
|
||||||
------------------
|
------------------
|
||||||
|
|
||||||
You can install the simdjson library on your system or in your project using multiple package managers such as MSYS2, the conan package manager, vcpkg, brew, the apt package manager (debian-based Linux systems), the FreeBSD package manager (FreeBSD), and so on. E.g., [we provide an complete example with vcpkg](https://github.com/simdjson/simdjson-vcpkg) that works under Windows. [Visit our wiki for more details](https://github.com/simdjson/simdjson/wiki/Installing-simdjson-with-a-package-manager).
|
You can install the simdjson library on your system or in your project using multiple package managers such as MSYS2, the conan package manager, vcpkg, brew, the apt package manager (debian-based Linux systems), the FreeBSD package manager (FreeBSD), and so on. E.g., [we provide a complete example with vcpkg](https://github.com/simdjson/simdjson-vcpkg) that works under Windows. [Visit our wiki for more details](https://github.com/simdjson/simdjson/wiki/Installing-simdjson-with-a-package-manager).
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -180,6 +180,18 @@ auto json = padded_string::load("twitter.json"); // load JSON file 'twitter.json
|
|||||||
ondemand::document doc = parser.iterate(json); // position a pointer at the beginning of the JSON data
|
ondemand::document doc = parser.iterate(json); // position a pointer at the beginning of the JSON data
|
||||||
```
|
```
|
||||||
|
|
||||||
|
If you prefer not to create your own `ondemand::parser` instance, you can access
|
||||||
|
a thread-local version by calling `ondemand::parser.get_parser()`.
|
||||||
|
|
||||||
|
|
||||||
|
```c++
|
||||||
|
ondemand::document doc = ondemand::parser.get_parser().iterate(json);
|
||||||
|
```
|
||||||
|
|
||||||
|
However, you should be careful because a parser instance can only be used for one
|
||||||
|
document at a time, thus it is only applicable when you are only parsing one
|
||||||
|
document per thread at any one time.
|
||||||
|
|
||||||
You can also create a padded string---and call `iterate()`:
|
You can also create a padded string---and call `iterate()`:
|
||||||
|
|
||||||
```c++
|
```c++
|
||||||
@@ -239,7 +251,6 @@ Consider reusing the same buffers and limiting memory allocations.
|
|||||||
|
|
||||||
By default, the simdjson library throws exceptions (`simdjson_error`) on errors. We omit `try`-`catch` clauses from our illustrating examples: if you omit `try`-`catch` in your code, an uncaught exception will halt your program. It is also possible to use simdjson without generating exceptions, and you may even build the library without exception support at all. See [Error handling](#error-handling) for details.
|
By default, the simdjson library throws exceptions (`simdjson_error`) on errors. We omit `try`-`catch` clauses from our illustrating examples: if you omit `try`-`catch` in your code, an uncaught exception will halt your program. It is also possible to use simdjson without generating exceptions, and you may even build the library without exception support at all. See [Error handling](#error-handling) for details.
|
||||||
|
|
||||||
|
|
||||||
Some users may want to browse code along with the compiled assembly. You want to check out the following lists of examples:
|
Some users may want to browse code along with the compiled assembly. You want to check out the following lists of examples:
|
||||||
|
|
||||||
* [simdjson examples with errors handled through exceptions](https://godbolt.org/z/98Kx9Kqjn)
|
* [simdjson examples with errors handled through exceptions](https://godbolt.org/z/98Kx9Kqjn)
|
||||||
@@ -309,7 +320,7 @@ At the cost of some memory allocation, you may convert your `std::string_view` i
|
|||||||
For convenience, we also allow [storing an escaped string directly into an existing string instance](#storing-directly-into-an-existing-string-instance).
|
For convenience, we also allow [storing an escaped string directly into an existing string instance](#storing-directly-into-an-existing-string-instance).
|
||||||
|
|
||||||
The `std::string_view` class has become standard as part of C++17 but it is not always available
|
The `std::string_view` class has become standard as part of C++17 but it is not always available
|
||||||
on compilers which only supports C++11. When we detect that `string_view` is natively
|
on compilers that only supports C++11. When we detect that `string_view` is natively
|
||||||
available, we define the macro `SIMDJSON_HAS_STRING_VIEW`.
|
available, we define the macro `SIMDJSON_HAS_STRING_VIEW`.
|
||||||
|
|
||||||
When we detect that it is unavailable,
|
When we detect that it is unavailable,
|
||||||
@@ -332,7 +343,7 @@ We recommend that you first compile and run your code in debug mode:
|
|||||||
|
|
||||||
The simdjson code will set `SIMDJSON_DEVELOPMENT_CHECKS=1` in debug mode. Because
|
The simdjson code will set `SIMDJSON_DEVELOPMENT_CHECKS=1` in debug mode. Because
|
||||||
the C++ standard does not provide a direct way of checking for a debug build, and
|
the C++ standard does not provide a direct way of checking for a debug build, and
|
||||||
because you may want the checks while building with otimizations, you can set
|
because you may want the checks while building with optimizations, you can set
|
||||||
the macro `SIMDJSON_DEVELOPMENT_CHECKS` to 1 prior to including
|
the macro `SIMDJSON_DEVELOPMENT_CHECKS` to 1 prior to including
|
||||||
the `simdjson.h` header to enable these additional checks: just make sure you remove the
|
the `simdjson.h` header to enable these additional checks: just make sure you remove the
|
||||||
definition once your code has been tested. When `SIMDJSON_DEVELOPMENT_CHECKS` is set to 1, the
|
definition once your code has been tested. When `SIMDJSON_DEVELOPMENT_CHECKS` is set to 1, the
|
||||||
@@ -360,9 +371,8 @@ and arrays (`simdjson::ondemand::array`).
|
|||||||
We also have a generic ephemeral type (`simdjson::ondemand::value`) which represents a potential
|
We also have a generic ephemeral type (`simdjson::ondemand::value`) which represents a potential
|
||||||
array or object, or scalar type (`double`, `uint64_t`, `int64_t`, `bool`, `null`, string) inside
|
array or object, or scalar type (`double`, `uint64_t`, `int64_t`, `bool`, `null`, string) inside
|
||||||
an array or an object. Both generic types (`simdjson::ondemand::document` and
|
an array or an object. Both generic types (`simdjson::ondemand::document` and
|
||||||
`simdjson::ondemand::value`) have a `type()` method returning a `json_type` value describing the
|
`simdjson::ondemand::value`) have a `type()` method returning a `json_type` value describing indicating the type (`json_type::array`, `json_type::object`, `json_type::number`, `json_type::string`,
|
||||||
value (`json_type::array`, `json_type::object`, `json_type::number`, `json_type::string`,
|
`json_type::boolean`, `json_type::null`, and `json_type::unknown` for unrecognized types). The `type()` method does not consume nor validate the value: e.g., you must still call `is_null()` to check that the value is a `null` even if `json_type::null` is returned. Starting with simdjson 4.0, we return `json_type::unknown` for bad tokens such as the `NaN` token in `{"key":NaN}`. A `json_type::unknown` type value indicates an error in the JSON document but you might still be able to proceed, see [General direct access to the raw JSON string](#general-direct-access-to-the-raw-json-string). A generic value (`simdjson::ondemand::value`)
|
||||||
`json_type::boolean`, `json_type::null`). A generic value (`simdjson::ondemand::value`)
|
|
||||||
is only valid temporarily, as soon as you access other values, other keys in objects, etc.
|
is only valid temporarily, as soon as you access other values, other keys in objects, etc.
|
||||||
it becomes invalid: you should therefore consume the value immediately by converting it to a
|
it becomes invalid: you should therefore consume the value immediately by converting it to a
|
||||||
scalar type, an array or an object.
|
scalar type, an array or an object.
|
||||||
@@ -395,7 +405,7 @@ support for users who avoid exceptions. See [the simdjson error handling documen
|
|||||||
ondemand::object and ondemand::array. We also have explicit methods such as `get_string()`, `get_double()`,
|
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,
|
`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 may be thrown if
|
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
|
the cast is not possible: the 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,
|
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.
|
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
|
The `get_string()` returns a valid UTF-8 string, after
|
||||||
@@ -442,7 +452,7 @@ support for users who avoid exceptions. See [the simdjson error handling documen
|
|||||||
* **Field Access:** To get the value of the "foo" field in an object, use `object["foo"]`. This will
|
* **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
|
scan through the object looking for the field with the matching string, doing a character-by-character
|
||||||
comparison. It may generate the error `simdjson::NO_SUCH_FIELD` if there is no such key in the object, it may throw an exception (see [Error handling](#error-handling)). For efficiency reason, you should avoid looking up the same field repeatedly: e.g., do
|
comparison. It may generate the error `simdjson::NO_SUCH_FIELD` if there is no such key in the object, it may throw an exception (see [Error handling](#error-handling)). For efficiency reason, you should avoid looking up the same field repeatedly: e.g., do
|
||||||
not do `object["foo"]` followed by `object["foo"]` with the same `object` instance. For best performance, you should try to query the keys in the same order they appear in the document. If you need several keys and you cannot predict the order they will appear in, it is recommended to iterate through all keys `for(auto field : object) {...}`. Generally, you should not mix and match iterating through an object (`for(auto field : object) {...}`) and key accesses (`object["foo"]`): if you need to iterate through an object after a key access, you need to call `reset()` on the object. Whenever you call `reset()`, you need to keep in mind that though you can iterate over the array repeatedly, values should be consumedonly once (e.g., repeatedly calling `unescaped_key()` on the same key is forbidden). Keep in mind that On-Demand does not buffer or save the result of the parsing: if you repeatedly access `object["foo"]`, then it must repeatedly seek the key and parse the content. The library does not provide a distinct function to check if a key is present, instead we recommend you attempt to access the key: e.g., by doing `ondemand::value val{}; if (!object["foo"].get(val)) {...}`, you have that `val` contains the requested value inside the if clause. It is your responsibility as a user to temporarily keep a reference to the value (`auto v = object["foo"]`), or to consume the content and store it in your own data structures. If you consume an
|
not do `object["foo"]` followed by `object["foo"]` with the same `object` instance. Generally, you should not mix and match iterating through an object (`for(auto field : object) {...}`) and key accesses (`object["foo"]`): if you need to iterate through an object after a key access, you need to call `reset()` on the object. Whenever you call `reset()`, you need to keep in mind that though you can iterate over the array repeatedly, values should be consumedonly once (e.g., repeatedly calling `unescaped_key()` on the same key is forbidden). 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
|
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
|
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"]`.
|
value instance you get from `content["bids"]` becomes invalid when you call `content["asks"]`.
|
||||||
@@ -505,7 +515,7 @@ support for users who avoid exceptions. See [the simdjson error handling documen
|
|||||||
> double y = doc["y"]; // The cursor is now after the 2 (at })
|
> double y = doc["y"]; // The cursor is now after the 2 (at })
|
||||||
> double x = doc["x"]; // Success: [] loops back around to find "x"
|
> double x = doc["x"]; // Success: [] loops back around to find "x"
|
||||||
> ```
|
> ```
|
||||||
* **Output to strings:** Given a document, a value, an array or an object in a JSON document, you can output a JSON string version suitable to be parsed again as JSON content: `simdjson::to_json_string(element)`. A call to `to_json_string` consumes fully the element: if you apply it on a document, the JSON pointer is advanced to the end of the document. The `simdjson::to_json_string` does not allocate memory. The `to_json_string` function should not be confused with retrieving the value of a string instance which are escaped and represented using a lightweight `std::string_view` instance pointing at an internal string buffer inside the parser instance. To illustrate, the first of the following two code segments will print the unescaped string `"test"` complete with the quote whereas the second one will print the escaped content of the string (without the quotes).
|
* **Output to strings:** Given a document, a value, an array or an object in a JSON document, you can output a JSON string version suitable to be parsed again as JSON content: `simdjson::to_json_string(element)`. A call to `to_json_string` consumes fully the element: if you apply it on a document, the internal pointer is advanced to the end of the document. The `simdjson::to_json_string` does not allocate memory. The `to_json_string` function should not be confused with retrieving the value of a string instance which are escaped and represented using a lightweight `std::string_view` instance pointing at an internal string buffer inside the parser instance. To illustrate, the first of the following two code segments will print the unescaped string `"test"` complete with the quote whereas the second one will print the escaped content of the string (without the quotes).
|
||||||
> ```C++
|
> ```C++
|
||||||
> // serialize a JSON to an escaped std::string instance so that it can be parsed again as JSON
|
> // serialize a JSON to an escaped std::string instance so that it can be parsed again as JSON
|
||||||
> auto silly_json = R"( { "test": "result" } )"_padded;
|
> auto silly_json = R"( { "test": "result" } )"_padded;
|
||||||
@@ -688,6 +698,9 @@ support for users who avoid exceptions. See [the simdjson error handling documen
|
|||||||
cout << "null";
|
cout << "null";
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case ondemand::json_type::unknown:
|
||||||
|
cout << "unknown"; // indicates an error
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void basics_treewalk() {
|
void basics_treewalk() {
|
||||||
@@ -871,13 +884,13 @@ type:
|
|||||||
|
|
||||||
We may do so by providing additional template definitions to the `ondemand::value` type.
|
We may do so by providing additional template definitions to the `ondemand::value` type.
|
||||||
We may start by providing a definition for `std::vector<double>` as follows. Observe
|
We may start by providing a definition for `std::vector<double>` as follows. Observe
|
||||||
how we guard the code with `#if !SIMDJSON_SUPPORTS_DESERIALIZATION`: that is because the necessary code
|
how we guard the code with `#if !SIMDJSON_SUPPORTS_CONCEPTS`: that is because the necessary code
|
||||||
is automatically provided by simdjson if C++20 (and concepts) are available.
|
is automatically provided by simdjson if C++20 (and concepts) are available.
|
||||||
See [Use `tag_invoke` for custom types](#2-use-tag_invoke-for-custom-types-c20) if you have
|
See [Use `tag_invoke` for custom types](#2-use-tag_invoke-for-custom-types-c20) if you have
|
||||||
C++20 support.
|
C++20 support.
|
||||||
|
|
||||||
```c++
|
```c++
|
||||||
#if !SIMDJSON_SUPPORTS_DESERIALIZATION
|
#if !SIMDJSON_SUPPORTS_CONCEPTS
|
||||||
// The code is unnecessary with C++20:
|
// The code is unnecessary with C++20:
|
||||||
template <>
|
template <>
|
||||||
simdjson_inline simdjson_result<std::vector<double>>
|
simdjson_inline simdjson_result<std::vector<double>>
|
||||||
@@ -933,7 +946,7 @@ struct Car {
|
|||||||
std::vector<double> tire_pressure;
|
std::vector<double> tire_pressure;
|
||||||
};
|
};
|
||||||
|
|
||||||
#if !SIMDJSON_SUPPORTS_DESERIALIZATION
|
#if !SIMDJSON_SUPPORTS_CONCEPTS
|
||||||
// This code is not necessary if you have a C++20 compliant system:
|
// This code is not necessary if you have a C++20 compliant system:
|
||||||
template <>
|
template <>
|
||||||
simdjson_inline simdjson_result<std::vector<double>>
|
simdjson_inline simdjson_result<std::vector<double>>
|
||||||
@@ -1034,7 +1047,7 @@ struct Car {
|
|||||||
std::vector<double> tire_pressure;
|
std::vector<double> tire_pressure;
|
||||||
};
|
};
|
||||||
|
|
||||||
#if !SIMDJSON_SUPPORTS_DESERIALIZATION
|
#if !SIMDJSON_SUPPORTS_CONCEPTS
|
||||||
// This code is not necessary if you have a C++20 compliant system:
|
// This code is not necessary if you have a C++20 compliant system:
|
||||||
template <>
|
template <>
|
||||||
simdjson_inline simdjson_result<std::vector<double>>
|
simdjson_inline simdjson_result<std::vector<double>>
|
||||||
@@ -1129,7 +1142,7 @@ The first argument is usually a tag type (often an empty struct) that uniquely i
|
|||||||
|
|
||||||
If your system supports C++20, we recommend that you adopt the `tag_invoke` approach
|
If your system supports C++20, we recommend that you adopt the `tag_invoke` approach
|
||||||
instead to deserialize custom types. It may prove to be considerably simpler. When
|
instead to deserialize custom types. It may prove to be considerably simpler. When
|
||||||
simdjson detects the necessary support, it sets the `SIMDJSON_SUPPORTS_DESERIALIZATION` macro
|
simdjson detects the necessary support, it sets the `SIMDJSON_SUPPORTS_CONCEPTS` macro
|
||||||
to 1, otherwise it is set to 0.
|
to 1, otherwise it is set to 0.
|
||||||
|
|
||||||
Consider a custom class `Car`:
|
Consider a custom class `Car`:
|
||||||
@@ -1346,6 +1359,9 @@ auto tag_invoke(deserialize_tag, simdjson_value &val, std::list<Car>& car) {
|
|||||||
With this code, deserializing an `std::list<Car>` instance would capture only the cars
|
With this code, deserializing an `std::list<Car>` instance would capture only the cars
|
||||||
that are not made by Toyota.
|
that are not made by Toyota.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### 3. Using static reflection (C++26)
|
### 3. Using static reflection (C++26)
|
||||||
|
|
||||||
If you have a C++26 compatible compiler, you can compile
|
If you have a C++26 compatible compiler, you can compile
|
||||||
@@ -1359,7 +1375,16 @@ your code with the `SIMDJSON_STATIC_REFLECTION` macro set:
|
|||||||
|
|
||||||
Then you can deserialize a type such as `Car` automatically:
|
Then you can deserialize a type such as `Car` automatically:
|
||||||
|
|
||||||
```cpp
|
|
||||||
|
|
||||||
|
```C++
|
||||||
|
struct Car {
|
||||||
|
std::string make;
|
||||||
|
std::string model;
|
||||||
|
int year;
|
||||||
|
std::vector<float> tire_pressure;
|
||||||
|
};
|
||||||
|
|
||||||
std::string json = R"( { "make": "Toyota", "model": "Camry", "year": 2018,
|
std::string json = R"( { "make": "Toyota", "model": "Camry", "year": 2018,
|
||||||
"tire_pressure": [ 40.1, 39.9 ] } )";
|
"tire_pressure": [ 40.1, 39.9 ] } )";
|
||||||
simdjson::ondemand::parser parser;
|
simdjson::ondemand::parser parser;
|
||||||
@@ -1367,10 +1392,110 @@ simdjson::ondemand::document doc = parser.iterate(simdjson::pad(json));
|
|||||||
Car c = doc.get<Car>();
|
Car c = doc.get<Car>();
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
We try to automate the parsing of any given structure or class
|
||||||
|
by looking at its non-static public members. At compile-time,
|
||||||
|
the library looks at a simple structre like `Car` and
|
||||||
|
maps it to parsing code. We call the default constructor,
|
||||||
|
and then assign values to the public members.
|
||||||
|
|
||||||
|
|
||||||
|
#### Special cases
|
||||||
|
|
||||||
|
However, there are instances where the construction cannot
|
||||||
|
be easily automated. Let us consider a class without any
|
||||||
|
public member.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
|
||||||
|
class MyDate {
|
||||||
|
public:
|
||||||
|
void assign(std::string_view str) {
|
||||||
|
date_str = str;
|
||||||
|
}
|
||||||
|
const std::string& to_string() const {
|
||||||
|
return date_str;
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
std::string date_str;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
This class has a default constructor, but it must be initialized
|
||||||
|
with the `assign` method. We need to help the library with
|
||||||
|
a `tag_invoke` function (just as in the C++20 case).
|
||||||
|
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
namespace simdjson {
|
||||||
|
template <typename simdjson_value>
|
||||||
|
auto tag_invoke(deserialize_tag, simdjson_value &val, MyDate& date) {
|
||||||
|
std::string_view str;
|
||||||
|
auto error = val.get_string().get(str);
|
||||||
|
if(error) { return error; }
|
||||||
|
date.assign(str);
|
||||||
|
return simdjson::SUCCESS;
|
||||||
|
}
|
||||||
|
} // namespace simdjson
|
||||||
|
```
|
||||||
|
|
||||||
|
Once this is done, we can now automatically parse a custom type
|
||||||
|
like `complicated_weather_data` containing `MyDate` values.
|
||||||
|
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
struct complicated_weather_data {
|
||||||
|
std::vector<MyDate> time;
|
||||||
|
std::vector<float> temperature;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
The code might as simple as the following.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
auto padded = R"({"time":["2023-03-15T12:00:00Z"],"temperature":[42]})"_padded;
|
||||||
|
simdjson::ondemand::parser parser;
|
||||||
|
simdjson::ondemand::document doc = parser.iterate(padded);
|
||||||
|
complicated_weather_data p = doc.get<>(complicated_weather_data);
|
||||||
|
```
|
||||||
|
|
||||||
|
Thus you can combine C++26 static reflection with custom deserialization
|
||||||
|
functions.
|
||||||
|
|
||||||
You can also automatically serialize the `Car` instance to a JSON string, see
|
You can also automatically serialize the `Car` instance to a JSON string, see
|
||||||
our [Builder documentation](builder.md).
|
our [Builder documentation](builder.md).
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### The simdjson::from shortcut (experimental, C++20)
|
||||||
|
|
||||||
|
|
||||||
|
For even more convenience, you can parse a JSON document directly to a supported
|
||||||
|
type without a document instance like so:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
Car car = simdjson::from(json);
|
||||||
|
```
|
||||||
|
|
||||||
|
You can also use the `simdjson::from` syntax to iterate over an array.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
for(auto val : simdjson::from(json).array()) {
|
||||||
|
Car c = val.get<Car>(); // ...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Standard STL types are supported:
|
||||||
|
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
std::map<std::string, std::string> obj =
|
||||||
|
simdjson::from(R"({"key": "value"})"_padded);
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
The `simdjson::from` construction is EXPERIMENTAL and subject to changes.
|
||||||
|
|
||||||
Minifying JSON strings without parsing
|
Minifying JSON strings without parsing
|
||||||
----------------------
|
----------------------
|
||||||
|
|
||||||
@@ -1412,9 +1537,9 @@ If you find yourself needing only fast Unicode functions, consider using the sim
|
|||||||
JSON Pointer
|
JSON Pointer
|
||||||
------------
|
------------
|
||||||
|
|
||||||
The simdjson library also supports [JSON pointer](https://tools.ietf.org/html/rfc6901) through the `at_pointer()` method, letting you reach further down into the document in a single call. JSON pointer is supported by both the [DOM approach](https://github.com/simdjson/simdjson/blob/master/doc/dom.md#json-pointer) as well as the On-Demand approach.
|
The simdjson library also supports [JSON pointer](https://tools.ietf.org/html/rfc6901) through the `at_pointer()` method, letting you reach further down into the document in a single call. JSON Pointer is supported by both the [DOM approach](https://github.com/simdjson/simdjson/blob/master/doc/dom.md#json-pointer) as well as the On-Demand approach.
|
||||||
|
|
||||||
**Note:** The On-Demand implementation of JSON pointer relies on `find_field` which implies that it does not unescape keys when matching.
|
**Note:** The On-Demand implementation of JSON Pointer relies on `find_field` which implies that it does not unescape keys when matching.
|
||||||
|
|
||||||
Consider the following example:
|
Consider the following example:
|
||||||
|
|
||||||
@@ -1434,7 +1559,7 @@ index allows you to select the indexed node. Within objects, the string value of
|
|||||||
select the value. If your keys contain the characters '/' or '~', they must be escaped as '~1' and
|
select the value. If your keys contain the characters '/' or '~', they must be escaped as '~1' and
|
||||||
'~0' respectively. An empty JSON Pointer Path refers to the whole document.
|
'~0' respectively. An empty JSON Pointer Path refers to the whole document.
|
||||||
|
|
||||||
For multiple JSON pointer queries on a document, one can call `at_pointer` multiple times.
|
For multiple JSON Pointer queries on a document, one can call `at_pointer` multiple times.
|
||||||
|
|
||||||
```c++
|
```c++
|
||||||
auto cars_json = R"( [
|
auto cars_json = R"( [
|
||||||
@@ -1589,7 +1714,7 @@ x = obj.at_path("$.d.foo2.a.2"); // 30
|
|||||||
Error handling
|
Error handling
|
||||||
--------------
|
--------------
|
||||||
|
|
||||||
Error handing with exception and a single try/catch clause makes the code simple, but it gives you little control over errors. For easier debugging or more robust error handling, you may want to consider our exception-free approach.
|
Error handling with exception and a single try/catch clause makes the code simple, but it gives you little control over errors. For easier debugging or more robust error handling, you may want to consider our exception-free approach.
|
||||||
|
|
||||||
The entire simdjson API is usable with and without exceptions. All simdjson APIs that can fail return `simdjson_result<T>`, which is a <value, error_code>
|
The entire simdjson API is usable with and without exceptions. All simdjson APIs that can fail return `simdjson_result<T>`, which is a <value, error_code>
|
||||||
pair. You can retrieve the value with .get() without generating an exception, like so:
|
pair. You can retrieve the value with .get() without generating an exception, like so:
|
||||||
@@ -2183,7 +2308,8 @@ The simdjson library supports parsing valid numbers inside strings which makes i
|
|||||||
three methods: `get_double_in_string`, `get_int64_in_string` and `get_uint64_in_string`. However, it is important to note that these methods are not substitute to the regular
|
three methods: `get_double_in_string`, `get_int64_in_string` and `get_uint64_in_string`. However, it is important to note that these methods are not substitute to the regular
|
||||||
`get_double`, `get_int64` and `get_uint64`. The usage of the `get_*_in_string` methods is solely to parse valid JSON numbers inside strings, and so we expect users to call these
|
`get_double`, `get_int64` and `get_uint64`. The usage of the `get_*_in_string` methods is solely to parse valid JSON numbers inside strings, and so we expect users to call these
|
||||||
methods appropriately. In particular, a valid JSON number has no leading and no trailing whitespaces, and the strings `"nan"`, `"1e"` and `"infinity"` will not be accepted as valid
|
methods appropriately. In particular, a valid JSON number has no leading and no trailing whitespaces, and the strings `"nan"`, `"1e"` and `"infinity"` will not be accepted as valid
|
||||||
numbers. As an example, suppose we have the following JSON text:
|
numbers (although you have access to the raw string with the `raw_json_token()` method, see [General direct access to the raw JSON string](#general-direct-access-to-the-raw-json-string)
|
||||||
|
). As an example, suppose we have the following JSON text:
|
||||||
|
|
||||||
```c++
|
```c++
|
||||||
auto json =
|
auto json =
|
||||||
@@ -2502,10 +2628,36 @@ The `raw_json_token()` should be fast and free of allocation.
|
|||||||
Given a quote-deliminated string, you find the string sequence inside the quote with a
|
Given a quote-deliminated string, you find the string sequence inside the quote with a
|
||||||
single line of code:
|
single line of code:
|
||||||
|
|
||||||
```C++
|
```cpp
|
||||||
std::string_view noquote(std::string_view v) { return {v.data()+1, v.find_last_of('"')-1}; }
|
std::string_view noquote(std::string_view v) { return {v.data()+1, v.find_last_of('"')-1}; }
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
The `raw_json_token()` method can enable you to provide fallbacks when parsing fails.
|
||||||
|
Consider the following example.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
padded_string json = "{\"key\": NaN}"_padded;
|
||||||
|
simdjson::ondemand::parser parser;
|
||||||
|
simdjson::ondemand::document doc = parser.iterate(json);
|
||||||
|
simdjson::ondemand::object object = doc.get_object();
|
||||||
|
simdjson::ondemand::value val = object["key"];
|
||||||
|
simdjson::ondemand::json_type type = val.type();
|
||||||
|
// type == simdjson::ondemand::json_type::unknown
|
||||||
|
try {
|
||||||
|
double num = val.get_double();
|
||||||
|
} catch (const simdjson::simdjson_error& e) {
|
||||||
|
// e == simdjson::error_code::INCORRECT_TYPE
|
||||||
|
std::string_view str = val.raw_json_token();
|
||||||
|
// str == "NaN"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
The NaN is not supported in JSON. However, in the On-Demand API, you can check
|
||||||
|
the string corresponding to the JSON token and determine how to handle it.
|
||||||
|
|
||||||
|
### Raw JSON string for objects and arrays
|
||||||
|
|
||||||
If your value is an array or an object, `raw_json_token()` returns effectively a single
|
If your value is an array or an object, `raw_json_token()` returns effectively a single
|
||||||
character (`[`) or (`}`) which is not very useful. For arrays and objects, we have another
|
character (`[`) or (`}`) which is not very useful. For arrays and objects, we have another
|
||||||
method called `raw_json()` which consumes (traverses) the array or the object.
|
method called `raw_json()` which consumes (traverses) the array or the object.
|
||||||
@@ -3024,10 +3176,45 @@ Performance tips
|
|||||||
- The On-Demand front-end works best when doing a single pass over the input: avoid calling `count_elements`, `rewind`, `reset` and similar methods.
|
- The On-Demand front-end works best when doing a single pass over the input: avoid calling `count_elements`, `rewind`, `reset` and similar methods.
|
||||||
- If you are familiar with assembly language, you may use the online tool godbolt to explore the compiled code. The following example may work: [https://godbolt.org/z/xE4GWs573](https://godbolt.org/z/xE4GWs573).
|
- If you are familiar with assembly language, you may use the online tool godbolt to explore the compiled code. The following example may work: [https://godbolt.org/z/xE4GWs573](https://godbolt.org/z/xE4GWs573).
|
||||||
- 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()`. Similarly, we expect `field.escaped_key()` to be faster than `field.unescaped_key()` even though both return a `std::string_view` instance.
|
- 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()`. Similarly, we expect `field.escaped_key()` to be faster than `field.unescaped_key()` even though both return a `std::string_view` instance.
|
||||||
- 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 release builds, we recommend setting the `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.
|
- 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.
|
- 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 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. Consider this example.
|
||||||
|
```cpp
|
||||||
|
|
||||||
|
auto json = R"({"price": 123.456789, "volume": 9999,
|
||||||
|
"timestamp": "2025-09-04T09:45:00Z",
|
||||||
|
"symbol": "XYZ", "currency": "USD", "change": 1.23,
|
||||||
|
"isActive": true})"_padded;
|
||||||
|
|
||||||
|
simdjson::ondemand::parser parser;
|
||||||
|
simdjson::ondemand::document doc = parser.iterate(json);
|
||||||
|
|
||||||
|
for(auto keyvalue : doc.get_object()) {
|
||||||
|
simdjson::ondemand::raw_json_string key = keyvalue.key();
|
||||||
|
switch(key[0]) {
|
||||||
|
case 'p': // price
|
||||||
|
if (key == "price") {
|
||||||
|
std::string_view price_str = keyvalue.value().raw_json();
|
||||||
|
std::cout << "Price: " << price_str << std::endl;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'v': // volume
|
||||||
|
if (key == "volume") {
|
||||||
|
std::string_view volume_str = keyvalue.value().raw_json();
|
||||||
|
std::cout << "Volume: " << volume_str << std::endl;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 't': // timestamp
|
||||||
|
if (key == "timestamp") {
|
||||||
|
std::string_view timestamp = keyvalue.value();
|
||||||
|
std::cout << "Timestamp: " << timestamp << std::endl;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
- 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...
|
- 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++
|
```C++
|
||||||
std::string_view make = o["data"]["make"];
|
std::string_view make = o["data"]["make"];
|
||||||
|
|||||||
+60
-6
@@ -46,7 +46,7 @@ After writting the content, if you have reasons to believe that the content migh
|
|||||||
- `validate_unicode()`: Checks if the content in the JSON buffer is valid UTF-8. Returns: true if the content is valid UTF-8, false otherwise.
|
- `validate_unicode()`: Checks if the content in the JSON buffer is valid UTF-8. Returns: true if the content is valid UTF-8, false otherwise.
|
||||||
|
|
||||||
You might need to do unicode validation if you have strings in your data structures containing
|
You might need to do unicode validation if you have strings in your data structures containing
|
||||||
malformed UTF-8.
|
malformed UTF-8. Note that we do not automatically call `validate_unicode()`.
|
||||||
|
|
||||||
Once you are satisfied, you can recover the string as follows:
|
Once you are satisfied, you can recover the string as follows:
|
||||||
|
|
||||||
@@ -54,7 +54,7 @@ Once you are satisfied, you can recover the string as follows:
|
|||||||
- `operator std::string_view()`: Converts the JSON buffer to an std::string_view. (Might throw if an error occurred.)
|
- `operator std::string_view()`: Converts the JSON buffer to an std::string_view. (Might throw if an error occurred.)
|
||||||
- `view()`: Returns a view of the written JSON buffer as a `simdjson_result<std::string_view>`.
|
- `view()`: Returns a view of the written JSON buffer as a `simdjson_result<std::string_view>`.
|
||||||
|
|
||||||
The later method (`view()`) is recommended.
|
The later method (`view()`) is recommended. For performance reasons, we expect you to explicitly call `validate_unicode()` as needed (e.g., prior to calling `view()`).
|
||||||
|
|
||||||
Example: string_builder
|
Example: string_builder
|
||||||
---------------------------
|
---------------------------
|
||||||
@@ -109,6 +109,9 @@ bool car_test() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
The `string_builder` constructor takes an optional parameter which specifies the initial
|
The `string_builder` constructor takes an optional parameter which specifies the initial
|
||||||
memory allocation in byte. If you know approximately the size of your JSON output, you can
|
memory allocation in byte. If you know approximately the size of your JSON output, you can
|
||||||
pass this value as a parameter (e.g., `simdjson::builder::string_builder sb{1233213}`).
|
pass this value as a parameter (e.g., `simdjson::builder::string_builder sb{1233213}`).
|
||||||
@@ -124,6 +127,57 @@ The `string_builder` might throw an exception in case of error when you cast it
|
|||||||
|
|
||||||
In all cases, the `std::string_view` instance depends the corresponding `string_builder` instance.
|
In all cases, the `std::string_view` instance depends the corresponding `string_builder` instance.
|
||||||
|
|
||||||
|
### C++20
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
If you have C++20, you can simplify the code, as the `std::vector<double>` is automatically
|
||||||
|
supported.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
Car c = {"Toyota", "Corolla", 2017, {30.0,30.2,30.513,30.79}};
|
||||||
|
simdjson::builder::string_builder sb;
|
||||||
|
sb.start_object();
|
||||||
|
sb.append_key_value("make", c.make);
|
||||||
|
sb.append_comma();
|
||||||
|
sb.append_key_value("model", c.model);
|
||||||
|
sb.append_comma();
|
||||||
|
sb.append_key_value("year", c.year);
|
||||||
|
sb.append_comma();
|
||||||
|
sb.append_key_value("tire_pressure", c.tire_pressure);
|
||||||
|
sb.end_object();
|
||||||
|
std::string_view p = sb.view();
|
||||||
|
```
|
||||||
|
|
||||||
|
With C++20, you can similarly handle standard containers transparently.
|
||||||
|
For example, you can serialize `std::map<std::string,T>` types.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
std::map<std::string,double> c = {{"key1", 1}, {"key2", 1}};
|
||||||
|
simdjson::builder::string_builder sb;
|
||||||
|
sb.append(c);
|
||||||
|
std::string_view p = sb.view();
|
||||||
|
```
|
||||||
|
|
||||||
|
You can also serialize `std::vector<T>` types.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
std::vector<std::vector<double>> c = {{1.0, 2.0}, {3.0, 4.0}};
|
||||||
|
simdjson::builder::string_builder sb;
|
||||||
|
sb.append(c);
|
||||||
|
std::string_view p = sb.view();
|
||||||
|
```
|
||||||
|
|
||||||
|
You can also skip the creation for the `string_builder` instance in such simple cases.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
std::vector<std::vector<double>> c = {{1.0, 2.0}, {3.0, 4.0}};
|
||||||
|
std::string json = simdjson::to_json(c);
|
||||||
|
```
|
||||||
|
|
||||||
|
We do recommend that you create and reuse the `string_builder` instance for performance
|
||||||
|
reasons.
|
||||||
|
|
||||||
C++26 static reflection
|
C++26 static reflection
|
||||||
------------------------
|
------------------------
|
||||||
|
|
||||||
@@ -165,7 +219,7 @@ automatically. In most cases, it should work automatically:
|
|||||||
|
|
||||||
In some instances, you might want to create a string directly from your own data type.
|
In some instances, you might want to create a string directly from your own data type.
|
||||||
You can create a string directly, without an explicit `string_builder` instance
|
You can create a string directly, without an explicit `string_builder` instance
|
||||||
with the `simdjson::builder::to_json_string` function.
|
with the `simdjson::to_json` template function.
|
||||||
(Under the hood a `string_builder` instance may still be created.)
|
(Under the hood a `string_builder` instance may still be created.)
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
@@ -178,12 +232,12 @@ with the `simdjson::builder::to_json_string` function.
|
|||||||
|
|
||||||
void f() {
|
void f() {
|
||||||
Car c = {"Toyota", "Corolla", 2017, {30.0,30.2,30.513,30.79}};
|
Car c = {"Toyota", "Corolla", 2017, {30.0,30.2,30.513,30.79}};
|
||||||
std::string json = simdjson::builder::to_json_string(c);
|
std::string json = simdjson::to_json(c);
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
If you know the output size, in bytes, of your JSON string, you may
|
If you know the output size, in bytes, of your JSON string, you may
|
||||||
pass it as a second parameter (e.g., `simdjson::builder::to_json_string(c, 31123)`).
|
pass it as a second parameter (e.g., `simdjson::to_json(c, 31123)`).
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -194,7 +248,7 @@ pattern:
|
|||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
std::string json;
|
std::string json;
|
||||||
if(simdjson::builder::to_json_string(c).get(json)) {
|
if(simdjson::to(c).get(json)) {
|
||||||
// there was an error
|
// there was an error
|
||||||
} else {
|
} else {
|
||||||
// json contain the serialized JSON
|
// json contain the serialized JSON
|
||||||
|
|||||||
+68
@@ -354,6 +354,74 @@ if(error) { /*won't happen*/ }
|
|||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## Using `at_path_with_wildcard` for JSONPath Queries
|
||||||
|
|
||||||
|
The `at_path_with_wildcard` function in simdjson extends the JSONPath querying capabilities by supporting wildcard expressions (`*`) in JSON paths. This allows users to retrieve multiple elements from a JSON document in a single query. For example, you can use `$.address.*` to fetch all fields within the `address` object or `$.phoneNumbers[*].numbers[*]` to retrieve all phone numbers across multiple objects in an array.
|
||||||
|
|
||||||
|
The `*` wildcard matches all elements at a specific level. For instance, `$.address.*` retrieves all key-value pairs in the `address` object, while `$.*.streetAddress` fetches all `streetAddress` fields across objects at the root level. You can combine wildcards with array indexing. For example, `$.phoneNumbers[*].numbers[1]` retrieves the second number from each `numbers` array in the `phoneNumbers` array. If no elements match the wildcard query, the function returns an empty result. For instance, querying `$.empty_object.*` or `$.empty_array.*` will yield an empty set.
|
||||||
|
|
||||||
|
### Example Usage
|
||||||
|
|
||||||
|
Here is an example demonstrating the use of `at_path_with_wildcard`:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
simdjson::padded_string json_string = R"(
|
||||||
|
{
|
||||||
|
"firstName": "John",
|
||||||
|
"lastName": "doe",
|
||||||
|
"age": 26,
|
||||||
|
"address": {
|
||||||
|
"streetAddress": "naist street",
|
||||||
|
"city": "Nara",
|
||||||
|
"postalCode": "630-0192"
|
||||||
|
},
|
||||||
|
"phoneNumbers": [
|
||||||
|
{
|
||||||
|
"type": "iPhone",
|
||||||
|
"numbers": ["0123-4567-8888", "0123-4567-8788"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "home",
|
||||||
|
"numbers": ["0123-4567-8910"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
})"_padded;
|
||||||
|
|
||||||
|
dom::parser parser;
|
||||||
|
dom::element parsed_json = parser.parse(json_string);
|
||||||
|
std::vector<dom::element> values;
|
||||||
|
|
||||||
|
// Fetch all fields in the address object
|
||||||
|
auto error = parsed_json.at_path_with_wildcard("$.address.*").get(values);
|
||||||
|
if(error) {
|
||||||
|
// do something
|
||||||
|
}
|
||||||
|
for (auto &value : values) {
|
||||||
|
std::string_view field;
|
||||||
|
error = value.get(field);
|
||||||
|
if(error) {
|
||||||
|
// do something
|
||||||
|
}
|
||||||
|
std::cout << field << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fetch all phone numbers
|
||||||
|
error = parsed_json.at_path_with_wildcard("$.phoneNumbers[*].numbers[*]").get(values);
|
||||||
|
if(error) {
|
||||||
|
// do something
|
||||||
|
}
|
||||||
|
for (auto &value : values) {
|
||||||
|
std::string_view number;
|
||||||
|
error = value.get(number);
|
||||||
|
if(error) {
|
||||||
|
// do something
|
||||||
|
}
|
||||||
|
std::cout << number << std::endl;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
This function is particularly useful for extracting data from complex JSON structures with nested arrays and objects. By leveraging wildcards, you can simplify your queries and reduce the need for multiple iterations.
|
||||||
|
|
||||||
Error Handling
|
Error Handling
|
||||||
--------------
|
--------------
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -309,7 +309,7 @@ The first argument is usually a tag type (often an empty struct) that uniquely i
|
|||||||
|
|
||||||
|
|
||||||
You can deserialize you own data structures conveniently if your system supports C++20.
|
You can deserialize you own data structures conveniently if your system supports C++20.
|
||||||
When it is the case, the macro `SIMDJSON_SUPPORTS_DESERIALIZATION` will be set to 1 by
|
When it is the case, the macro `SIMDJSON_SUPPORTS_CONCEPTS` will be set to 1 by
|
||||||
the simdjson library.
|
the simdjson library.
|
||||||
|
|
||||||
Consider a custom class `Car`:
|
Consider a custom class `Car`:
|
||||||
|
|||||||
@@ -173,8 +173,6 @@ Recent versions of Microsoft Visual Studio on Windows provides support for the L
|
|||||||
|
|
||||||
We recommend Visual Studio users prefer LLVM (clang-cl). It compiles to faster release binaries. Furthermore, it compilers faster in release mode.
|
We recommend Visual Studio users prefer LLVM (clang-cl). It compiles to faster release binaries. Furthermore, it compilers faster in release mode.
|
||||||
|
|
||||||
Under Windows, we also support the GNU GCC compiler via MSYS2. The performance of 64-bit MSYS2 under Windows is excellent (on par with Linux).
|
|
||||||
|
|
||||||
|
|
||||||
Power Usage and Downclocking
|
Power Usage and Downclocking
|
||||||
--------------
|
--------------
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
|
|||||||
auto error = parser.parse(str).get(elem);
|
auto error = parser.parse(str).get(elem);
|
||||||
if (error) { return 0; }
|
if (error) { return 0; }
|
||||||
|
|
||||||
std::string minified=simdjson::minify(elem);
|
std::string minified = simdjson::minify(elem);
|
||||||
(void)minified;
|
(void)minified;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -53,4 +53,6 @@
|
|||||||
|
|
||||||
#include "simdjson/dom.h"
|
#include "simdjson/dom.h"
|
||||||
#include "simdjson/ondemand.h"
|
#include "simdjson/ondemand.h"
|
||||||
|
#include "simdjson/convert.h"
|
||||||
|
#include "simdjson/convert-inl.h"
|
||||||
#endif // SIMDJSON_H
|
#endif // SIMDJSON_H
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
#include "simdjson/error.h"
|
#include "simdjson/error.h"
|
||||||
#include "simdjson/portability.h"
|
#include "simdjson/portability.h"
|
||||||
#include "simdjson/concepts.h"
|
#include "simdjson/concepts.h"
|
||||||
|
#include "simdjson/constevalutil.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief The top level simdjson namespace, containing everything the library provides.
|
* @brief The top level simdjson namespace, containing everything the library provides.
|
||||||
|
|||||||
@@ -24,6 +24,8 @@
|
|||||||
#include "simdjson/lsx.h"
|
#include "simdjson/lsx.h"
|
||||||
#elif SIMDJSON_BUILTIN_IMPLEMENTATION_IS(lasx)
|
#elif SIMDJSON_BUILTIN_IMPLEMENTATION_IS(lasx)
|
||||||
#include "simdjson/lasx.h"
|
#include "simdjson/lasx.h"
|
||||||
|
#elif SIMDJSON_BUILTIN_IMPLEMENTATION_IS(rvv)
|
||||||
|
#include "simdjson/rvv.h"
|
||||||
#else
|
#else
|
||||||
#error Unknown SIMDJSON_BUILTIN_IMPLEMENTATION
|
#error Unknown SIMDJSON_BUILTIN_IMPLEMENTATION
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -21,6 +21,8 @@ namespace simdjson {
|
|||||||
namespace lsx {}
|
namespace lsx {}
|
||||||
#elif SIMDJSON_BUILTIN_IMPLEMENTATION_IS(lasx)
|
#elif SIMDJSON_BUILTIN_IMPLEMENTATION_IS(lasx)
|
||||||
namespace lasx {}
|
namespace lasx {}
|
||||||
|
#elif SIMDJSON_BUILTIN_IMPLEMENTATION_IS(rvv)
|
||||||
|
namespace rvv {}
|
||||||
#else
|
#else
|
||||||
#error Unknown SIMDJSON_BUILTIN_IMPLEMENTATION
|
#error Unknown SIMDJSON_BUILTIN_IMPLEMENTATION
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -23,6 +23,8 @@
|
|||||||
#include "simdjson/lsx/implementation.h"
|
#include "simdjson/lsx/implementation.h"
|
||||||
#elif SIMDJSON_BUILTIN_IMPLEMENTATION_IS(lasx)
|
#elif SIMDJSON_BUILTIN_IMPLEMENTATION_IS(lasx)
|
||||||
#include "simdjson/lasx/implementation.h"
|
#include "simdjson/lasx/implementation.h"
|
||||||
|
#elif SIMDJSON_BUILTIN_IMPLEMENTATION_IS(rvv)
|
||||||
|
#include "simdjson/rvv/implementation.h"
|
||||||
#else
|
#else
|
||||||
#error Unknown SIMDJSON_BUILTIN_IMPLEMENTATION
|
#error Unknown SIMDJSON_BUILTIN_IMPLEMENTATION
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -24,6 +24,8 @@
|
|||||||
#include "simdjson/lsx/ondemand.h"
|
#include "simdjson/lsx/ondemand.h"
|
||||||
#elif SIMDJSON_BUILTIN_IMPLEMENTATION_IS(lasx)
|
#elif SIMDJSON_BUILTIN_IMPLEMENTATION_IS(lasx)
|
||||||
#include "simdjson/lasx/ondemand.h"
|
#include "simdjson/lasx/ondemand.h"
|
||||||
|
#elif SIMDJSON_BUILTIN_IMPLEMENTATION_IS(rvv)
|
||||||
|
#include "simdjson/rvv/ondemand.h"
|
||||||
#else
|
#else
|
||||||
#error Unknown SIMDJSON_BUILTIN_IMPLEMENTATION
|
#error Unknown SIMDJSON_BUILTIN_IMPLEMENTATION
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -199,17 +199,6 @@ double from_chars(const char *first, const char* end) noexcept;
|
|||||||
// We assume by default static linkage
|
// We assume by default static linkage
|
||||||
#define SIMDJSON_DLLIMPORTEXPORT
|
#define SIMDJSON_DLLIMPORTEXPORT
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
|
||||||
* Workaround for the vcpkg package manager. Only vcpkg should
|
|
||||||
* ever touch the next line. The SIMDJSON_USING_LIBRARY macro is otherwise unused.
|
|
||||||
*/
|
|
||||||
#if SIMDJSON_USING_LIBRARY
|
|
||||||
#define SIMDJSON_DLLIMPORTEXPORT __declspec(dllimport)
|
|
||||||
#endif
|
|
||||||
/**
|
|
||||||
* End of workaround for the vcpkg package manager.
|
|
||||||
*/
|
|
||||||
#else
|
#else
|
||||||
#define SIMDJSON_DLLIMPORTEXPORT
|
#define SIMDJSON_DLLIMPORTEXPORT
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -81,24 +81,38 @@
|
|||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(__cpp_lib_ranges) && __cpp_lib_ranges >= 201911L
|
||||||
|
#include <ranges>
|
||||||
|
#define SIMDJSON_SUPPORTS_RANGES 1
|
||||||
|
#else
|
||||||
|
#define SIMDJSON_SUPPORTS_RANGES 0
|
||||||
|
#endif
|
||||||
|
|
||||||
#if defined(__cpp_concepts) && !defined(SIMDJSON_CONCEPT_DISABLED)
|
#if defined(__cpp_concepts) && !defined(SIMDJSON_CONCEPT_DISABLED)
|
||||||
#if __cpp_concepts >= 201907L
|
#if __cpp_concepts >= 201907L
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
#define SIMDJSON_SUPPORTS_CONCEPTS 1
|
||||||
|
#else
|
||||||
|
#define SIMDJSON_SUPPORTS_CONCEPTS 0
|
||||||
|
#endif
|
||||||
|
#else // defined(__cpp_concepts) && !defined(SIMDJSON_CONCEPT_DISABLED)
|
||||||
|
#define SIMDJSON_SUPPORTS_CONCEPTS 0
|
||||||
|
#endif // defined(__cpp_concepts) && !defined(SIMDJSON_CONCEPT_DISABLED)
|
||||||
|
|
||||||
|
// copy SIMDJSON_SUPPORTS_CONCEPTS to SIMDJSON_SUPPORTS_DESERIALIZATION.
|
||||||
|
#if SIMDJSON_SUPPORTS_CONCEPTS
|
||||||
#define SIMDJSON_SUPPORTS_DESERIALIZATION 1
|
#define SIMDJSON_SUPPORTS_DESERIALIZATION 1
|
||||||
#else
|
#else
|
||||||
#define SIMDJSON_SUPPORTS_DESERIALIZATION 0
|
#define SIMDJSON_SUPPORTS_DESERIALIZATION 0
|
||||||
#endif
|
#endif
|
||||||
#else // defined(__cpp_concepts) && !defined(SIMDJSON_CONCEPT_DISABLED)
|
|
||||||
#define SIMDJSON_SUPPORTS_DESERIALIZATION 0
|
|
||||||
#endif // defined(__cpp_concepts) && !defined(SIMDJSON_CONCEPT_DISABLED)
|
|
||||||
|
|
||||||
#if !defined(SIMDJSON_CONSTEVAL)
|
#if !defined(SIMDJSON_CONSTEVAL)
|
||||||
#if defined(__cpp_consteval) && __cpp_consteval >= 201811L
|
#if defined(__cpp_consteval) && __cpp_consteval >= 201811L && defined(__cpp_lib_constexpr_string) && __cpp_lib_constexpr_string >= 201907L
|
||||||
#define SIMDJSON_CONSTEVAL 1
|
#define SIMDJSON_CONSTEVAL 1
|
||||||
#else
|
#else
|
||||||
#define SIMDJSON_CONSTEVAL 0
|
#define SIMDJSON_CONSTEVAL 0
|
||||||
#endif // defined(__cpp_consteval) && __cpp_consteval >= 201811L
|
#endif // defined(__cpp_consteval) && __cpp_consteval >= 201811L && defined(__cpp_lib_constexpr_string) && __cpp_lib_constexpr_string >= 201907L
|
||||||
#endif // !defined(SIMDJSON_CONSTEVAL)
|
#endif // !defined(SIMDJSON_CONSTEVAL)
|
||||||
|
|
||||||
#endif // SIMDJSON_COMPILER_CHECK_H
|
#endif // SIMDJSON_COMPILER_CHECK_H
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#ifndef SIMDJSON_CONCEPTS_H
|
#ifndef SIMDJSON_CONCEPTS_H
|
||||||
#define SIMDJSON_CONCEPTS_H
|
#define SIMDJSON_CONCEPTS_H
|
||||||
#if SIMDJSON_SUPPORTS_DESERIALIZATION
|
#if SIMDJSON_SUPPORTS_CONCEPTS
|
||||||
|
|
||||||
#include <concepts>
|
#include <concepts>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
@@ -32,7 +32,9 @@ SIMDJSON_IMPL_CONCEPT(op_append, operator+=)
|
|||||||
#undef SIMDJSON_IMPL_CONCEPT
|
#undef SIMDJSON_IMPL_CONCEPT
|
||||||
} // namespace details
|
} // namespace details
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
concept is_pair = requires { typename T::first_type; typename T::second_type; } &&
|
||||||
|
std::same_as<T, std::pair<typename T::first_type, typename T::second_type>>;
|
||||||
template <typename T>
|
template <typename T>
|
||||||
concept string_view_like = std::is_convertible_v<T, std::string_view> &&
|
concept string_view_like = std::is_convertible_v<T, std::string_view> &&
|
||||||
!std::is_convertible_v<T, const char*>;
|
!std::is_convertible_v<T, const char*>;
|
||||||
@@ -126,5 +128,5 @@ concept optional_type = requires(std::remove_cvref_t<T> obj) {
|
|||||||
|
|
||||||
} // namespace concepts
|
} // namespace concepts
|
||||||
} // namespace simdjson
|
} // namespace simdjson
|
||||||
#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
|
#endif // SIMDJSON_SUPPORTS_CONCEPTS
|
||||||
#endif // SIMDJSON_CONCEPTS_H
|
#endif // SIMDJSON_CONCEPTS_H
|
||||||
|
|||||||
@@ -0,0 +1,53 @@
|
|||||||
|
#ifndef SIMDJSON_CONSTEVALUTIL_H
|
||||||
|
#define SIMDJSON_CONSTEVALUTIL_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <string_view>
|
||||||
|
#include <array>
|
||||||
|
|
||||||
|
#if SIMDJSON_CONSTEVAL
|
||||||
|
namespace simdjson {
|
||||||
|
namespace constevalutil {
|
||||||
|
|
||||||
|
constexpr static std::array<uint8_t, 256> json_quotable_character = {
|
||||||
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||||
|
1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
|
||||||
|
constexpr static std::array<std::string_view, 32> control_chars = {
|
||||||
|
"\\u0000", "\\u0001", "\\u0002", "\\u0003", "\\u0004", "\\u0005", "\\u0006",
|
||||||
|
"\\u0007", "\\b", "\\t", "\\n", "\\u000b", "\\f", "\\r",
|
||||||
|
"\\u000e", "\\u000f", "\\u0010", "\\u0011", "\\u0012", "\\u0013", "\\u0014",
|
||||||
|
"\\u0015", "\\u0016", "\\u0017", "\\u0018", "\\u0019", "\\u001a", "\\u001b",
|
||||||
|
"\\u001c", "\\u001d", "\\u001e", "\\u001f"};
|
||||||
|
// unoptimized, meant for compile-time execution
|
||||||
|
consteval std::string consteval_to_quoted_escaped(std::string_view input) {
|
||||||
|
std::string out = "\"";
|
||||||
|
for (char c : input) {
|
||||||
|
if (json_quotable_character[uint8_t(c)]) {
|
||||||
|
if (c == '"') {
|
||||||
|
out.append("\\\"");
|
||||||
|
} else if (c == '\\') {
|
||||||
|
out.append("\\\\");
|
||||||
|
} else {
|
||||||
|
std::string_view v = control_chars[uint8_t(c)];
|
||||||
|
out.append(v);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
out.push_back(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out.push_back('"');
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
} // namespace constevalutil
|
||||||
|
} // namespace simdjson
|
||||||
|
#endif // SIMDJSON_CONSTEVAL
|
||||||
|
#endif // SIMDJSON_CONSTEVALUTIL_H
|
||||||
@@ -0,0 +1,123 @@
|
|||||||
|
|
||||||
|
#ifndef SIMDJSON_CONVERT_INL_H
|
||||||
|
#define SIMDJSON_CONVERT_INL_H
|
||||||
|
|
||||||
|
#include "simdjson/convert.h"
|
||||||
|
#if SIMDJSON_SUPPORTS_CONCEPTS
|
||||||
|
namespace simdjson {
|
||||||
|
namespace convert {
|
||||||
|
namespace internal {
|
||||||
|
// auto_parser method definitions
|
||||||
|
template <typename parser_type>
|
||||||
|
inline auto_parser<parser_type>::auto_parser(parser_type &&parser, ondemand::document &&doc) noexcept requires(!std::is_pointer_v<parser_type>)
|
||||||
|
: m_parser{std::move(parser)}, m_doc{std::move(doc)} {}
|
||||||
|
|
||||||
|
template <typename parser_type>
|
||||||
|
inline auto_parser<parser_type>::auto_parser(parser_type &&parser, padded_string_view const str) noexcept requires(!std::is_pointer_v<parser_type>)
|
||||||
|
: m_parser{std::move(parser)}, m_doc{}, m_error{SUCCESS} {
|
||||||
|
m_error = m_parser.iterate(str).get(m_doc);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename parser_type>
|
||||||
|
inline auto_parser<parser_type>::auto_parser(std::remove_pointer_t<parser_type> &parser, ondemand::document &&doc) noexcept requires(std::is_pointer_v<parser_type>)
|
||||||
|
: m_parser{&parser}, m_doc{std::move(doc)} {}
|
||||||
|
|
||||||
|
template <typename parser_type>
|
||||||
|
inline auto_parser<parser_type>::auto_parser(std::remove_pointer_t<parser_type> &parser, padded_string_view const str) noexcept requires(std::is_pointer_v<parser_type>)
|
||||||
|
: m_parser{&parser}, m_doc{}, m_error{SUCCESS} {
|
||||||
|
m_error = m_parser->iterate(str).get(m_doc);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename parser_type>
|
||||||
|
inline auto_parser<parser_type>::auto_parser(padded_string_view const str) noexcept requires(std::is_pointer_v<parser_type>)
|
||||||
|
: auto_parser{ondemand::parser::get_parser(), str} {}
|
||||||
|
|
||||||
|
template <typename parser_type>
|
||||||
|
inline auto_parser<parser_type>::auto_parser(parser_type parser, ondemand::document &&doc) noexcept requires(std::is_pointer_v<parser_type>)
|
||||||
|
: auto_parser{*parser, std::move(doc)} {}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
template <typename parser_type>
|
||||||
|
inline std::remove_pointer_t<parser_type> &auto_parser<parser_type>::parser() noexcept {
|
||||||
|
if constexpr (std::is_pointer_v<parser_type>) {
|
||||||
|
return *m_parser;
|
||||||
|
} else {
|
||||||
|
return m_parser;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename parser_type>
|
||||||
|
template <typename T>
|
||||||
|
inline simdjson_result<T> auto_parser<parser_type>::result() noexcept(is_nothrow_gettable<T>) {
|
||||||
|
if (m_error != SUCCESS) {
|
||||||
|
return m_error;
|
||||||
|
}
|
||||||
|
return m_doc.get<T>();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename parser_type>
|
||||||
|
inline simdjson_result<ondemand::array> auto_parser<parser_type>::array() noexcept {
|
||||||
|
return result<ondemand::array>();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename parser_type>
|
||||||
|
inline simdjson_result<ondemand::object> auto_parser<parser_type>::object() noexcept {
|
||||||
|
return result<ondemand::object>();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename parser_type>
|
||||||
|
inline simdjson_result<ondemand::number> auto_parser<parser_type>::number() noexcept {
|
||||||
|
return result<ondemand::number>();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename parser_type>
|
||||||
|
template <typename T>
|
||||||
|
inline auto_parser<parser_type>::operator simdjson_result<T>() noexcept(is_nothrow_gettable<T>) {
|
||||||
|
return result<T>();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename parser_type>
|
||||||
|
template <typename T>
|
||||||
|
inline auto_parser<parser_type>::operator T() noexcept(false) {
|
||||||
|
if (m_error != SUCCESS) {
|
||||||
|
throw simdjson_error(m_error);
|
||||||
|
}
|
||||||
|
return m_doc.get<T>();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename parser_type>
|
||||||
|
template <typename T>
|
||||||
|
inline std::optional<T> auto_parser<parser_type>::optional() noexcept(is_nothrow_gettable<T>) {
|
||||||
|
if (m_error != SUCCESS) {
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
T value;
|
||||||
|
if (m_doc.get<T>().get(value)) [[unlikely]] {
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
return {std::move(value)};
|
||||||
|
}
|
||||||
|
|
||||||
|
// to_adaptor method definitions
|
||||||
|
template <typename T>
|
||||||
|
inline T to_adaptor<T>::operator()(simdjson_result<ondemand::value> &val) const noexcept {
|
||||||
|
return val.get<T>();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
inline auto to_adaptor<T>::operator()(padded_string_view const str) const noexcept {
|
||||||
|
return auto_parser{str};
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
inline auto to_adaptor<T>::operator()(ondemand::parser &parser, padded_string_view const str) const noexcept {
|
||||||
|
return auto_parser<ondemand::parser *>{parser, str};
|
||||||
|
}
|
||||||
|
} // namespace internal
|
||||||
|
} // namespace convert
|
||||||
|
} // namespace simdjson
|
||||||
|
#endif // SIMDJSON_SUPPORTS_CONCEPTS
|
||||||
|
#endif // SIMDJSON_CONVERT_INL_H
|
||||||
@@ -0,0 +1,111 @@
|
|||||||
|
|
||||||
|
#ifndef SIMDJSON_CONVERT_H
|
||||||
|
#define SIMDJSON_CONVERT_H
|
||||||
|
|
||||||
|
#include "simdjson/ondemand.h"
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
|
#if SIMDJSON_SUPPORTS_CONCEPTS
|
||||||
|
|
||||||
|
|
||||||
|
namespace simdjson {
|
||||||
|
namespace convert {
|
||||||
|
namespace internal {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A utility class for automatically parsing JSON documents.
|
||||||
|
* This template is NOT part of our public API.
|
||||||
|
* It is subject to changes.
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
template <typename parser_type = ondemand::parser*>
|
||||||
|
struct auto_parser {
|
||||||
|
private:
|
||||||
|
parser_type m_parser;
|
||||||
|
ondemand::document m_doc;
|
||||||
|
error_code m_error{SUCCESS};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
static constexpr bool is_nothrow_gettable = requires(ondemand::document doc) {
|
||||||
|
{ doc.get<T>() } noexcept;
|
||||||
|
};
|
||||||
|
public:
|
||||||
|
explicit auto_parser(parser_type &&parser, ondemand::document &&doc) noexcept requires(!std::is_pointer_v<parser_type>);
|
||||||
|
explicit auto_parser(parser_type &&parser, padded_string_view const str) noexcept requires(!std::is_pointer_v<parser_type>);
|
||||||
|
explicit auto_parser(std::remove_pointer_t<parser_type> &parser, ondemand::document &&doc) noexcept requires(std::is_pointer_v<parser_type>);
|
||||||
|
explicit auto_parser(std::remove_pointer_t<parser_type> &parser, padded_string_view const str) noexcept requires(std::is_pointer_v<parser_type>);
|
||||||
|
explicit auto_parser(padded_string_view const str) noexcept requires(std::is_pointer_v<parser_type>);
|
||||||
|
explicit auto_parser(parser_type parser, ondemand::document &&doc) noexcept requires(std::is_pointer_v<parser_type>);
|
||||||
|
auto_parser(auto_parser const &) = delete;
|
||||||
|
auto_parser &operator=(auto_parser const &) = delete;
|
||||||
|
auto_parser(auto_parser &&) noexcept = default;
|
||||||
|
auto_parser &operator=(auto_parser &&) noexcept = default;
|
||||||
|
~auto_parser() = default;
|
||||||
|
|
||||||
|
simdjson_warn_unused std::remove_pointer_t<parser_type> &parser() noexcept;
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
simdjson_warn_unused simdjson_inline simdjson_result<T> result() noexcept(is_nothrow_gettable<T>);
|
||||||
|
|
||||||
|
simdjson_warn_unused simdjson_inline simdjson_result<ondemand::array> array() noexcept;
|
||||||
|
simdjson_warn_unused simdjson_inline simdjson_result<ondemand::object> object() noexcept;
|
||||||
|
simdjson_warn_unused simdjson_inline simdjson_result<ondemand::number> number() noexcept;
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
simdjson_warn_unused simdjson_inline explicit(false) operator simdjson_result<T>() noexcept(is_nothrow_gettable<T>);
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
simdjson_warn_unused simdjson_inline explicit(false) operator T() noexcept(false);
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
simdjson_warn_unused simdjson_inline std::optional<T> optional() noexcept(is_nothrow_gettable<T>);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A utility class for adapting values for the `auto_parser`.
|
||||||
|
* This template is not part of our public API. It is subject to changes.
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
template <typename T = void>
|
||||||
|
struct to_adaptor {
|
||||||
|
T operator()(simdjson_result<ondemand::value> &val) const noexcept;
|
||||||
|
auto operator()(padded_string_view const str) const noexcept;
|
||||||
|
auto operator()(ondemand::parser &parser, padded_string_view const str) const noexcept;
|
||||||
|
};
|
||||||
|
} // namespace internal
|
||||||
|
} // namespace convert
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The simdjson::from instance is EXPERIMENTAL AND SUBJECT TO CHANGES.
|
||||||
|
*
|
||||||
|
* The `from` instance is a utility adaptor for parsing JSON strings into objects.
|
||||||
|
* It provides a convenient way to convert JSON data into C++ objects using the `auto_parser`.
|
||||||
|
*
|
||||||
|
* Example usage:
|
||||||
|
*
|
||||||
|
* ```cpp
|
||||||
|
* std::map<std::string, std::string> obj =
|
||||||
|
* simdjson::from(R"({"key": "value"})"_padded);
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* This will parse the JSON string and return an object representation. By default, we
|
||||||
|
* use the simdjson::ondemand::parser::get_parser() instance. A parser instance should
|
||||||
|
* be used for just one document at a time.
|
||||||
|
*
|
||||||
|
* You can also pass you own parser instance:
|
||||||
|
* ```cpp
|
||||||
|
* simdjson::ondemand::parser parser;
|
||||||
|
* std::map<std::string, std::string> obj =
|
||||||
|
* simdjson::from(parser, R"({"key": "value"})"_padded);
|
||||||
|
* ```
|
||||||
|
* The parser instance can be reused.
|
||||||
|
*
|
||||||
|
* This functionality requires C++20 or better.
|
||||||
|
*/
|
||||||
|
static constexpr convert::internal::to_adaptor<> from{};
|
||||||
|
|
||||||
|
} // namespace simdjson
|
||||||
|
|
||||||
|
#endif // SIMDJSON_SUPPORTS_CONCEPTS
|
||||||
|
#endif // SIMDJSON_CONVERT_H
|
||||||
@@ -52,11 +52,22 @@ inline simdjson_result<dom::element> simdjson_result<dom::array>::at_pointer(std
|
|||||||
return at_pointer(json_pointer);
|
return at_pointer(json_pointer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline simdjson_result<std::vector<dom::element>> simdjson_result<dom::array>::at_path_with_wildcard(std::string_view json_path) const noexcept {
|
||||||
|
if (error()) {
|
||||||
|
return error();
|
||||||
|
}
|
||||||
|
return first.at_path_with_wildcard(json_path);
|
||||||
|
}
|
||||||
|
|
||||||
inline simdjson_result<dom::element> simdjson_result<dom::array>::at(size_t index) const noexcept {
|
inline simdjson_result<dom::element> simdjson_result<dom::array>::at(size_t index) const noexcept {
|
||||||
if (error()) { return error(); }
|
if (error()) { return error(); }
|
||||||
return first.at(index);
|
return first.at(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline std::vector<dom::element>& simdjson_result<dom::array>::get_values(std::vector<dom::element>& out) const noexcept {
|
||||||
|
return first.get_values(out);
|
||||||
|
}
|
||||||
|
|
||||||
namespace dom {
|
namespace dom {
|
||||||
|
|
||||||
//
|
//
|
||||||
@@ -127,6 +138,93 @@ inline simdjson_result<element> array::at_path(std::string_view json_path) const
|
|||||||
return at_pointer(json_pointer);
|
return at_pointer(json_pointer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline void array::process_json_path_of_child_elements(std::vector<element>::iterator& current, std::vector<element>::iterator& end, const std::string_view& path_suffix, std::vector<element>& accumulator) const noexcept {
|
||||||
|
if (current == end) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
simdjson_result<std::vector<element>> result;
|
||||||
|
|
||||||
|
|
||||||
|
for (auto it = current; it != end; ++it) {
|
||||||
|
std::vector<element> child_result;
|
||||||
|
auto error = it->at_path_with_wildcard(path_suffix).get(child_result);
|
||||||
|
if(error) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
accumulator.reserve(accumulator.size() + child_result.size());
|
||||||
|
accumulator.insert(accumulator.end(),
|
||||||
|
std::make_move_iterator(child_result.begin()),
|
||||||
|
std::make_move_iterator(child_result.end()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline simdjson_result<std::vector<element>> array::at_path_with_wildcard(std::string_view json_path) const noexcept {
|
||||||
|
SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
|
||||||
|
|
||||||
|
size_t i = 0;
|
||||||
|
// json_path.starts_with('$') requires C++20.
|
||||||
|
if (!json_path.empty() && json_path.front() == '$') {
|
||||||
|
i = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i >= json_path.size() || (json_path[i] != '.' && json_path[i] != '[')) {
|
||||||
|
return INVALID_JSON_POINTER;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (json_path.find("*") != std::string::npos) {
|
||||||
|
std::vector<element> child_values;
|
||||||
|
|
||||||
|
if (
|
||||||
|
(json_path.compare(i, 3, "[*]") == 0 && json_path.size() == i + 3) ||
|
||||||
|
(json_path.compare(i, 2,".*") == 0 && json_path.size() == i + 2)
|
||||||
|
) {
|
||||||
|
get_values(child_values);
|
||||||
|
return child_values;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::pair<std::string_view, std::string_view> key_and_json_path = get_next_key_and_json_path(json_path);
|
||||||
|
|
||||||
|
std::string_view key = key_and_json_path.first;
|
||||||
|
json_path = key_and_json_path.second;
|
||||||
|
|
||||||
|
if (key.size() > 0) {
|
||||||
|
if (key == "*") {
|
||||||
|
get_values(child_values);
|
||||||
|
} else {
|
||||||
|
element pointer_result;
|
||||||
|
std::string json_pointer = std::string("/") + std::string(key);
|
||||||
|
auto error = at_pointer(json_pointer).get(pointer_result);
|
||||||
|
|
||||||
|
if (!error) {
|
||||||
|
child_values.emplace_back(pointer_result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<element> result = {};
|
||||||
|
|
||||||
|
if (child_values.size() > 0) {
|
||||||
|
std::vector<element>::iterator child_values_begin = child_values.begin();
|
||||||
|
std::vector<element>::iterator child_values_end = child_values.end();
|
||||||
|
|
||||||
|
process_json_path_of_child_elements(child_values_begin, child_values_end, json_path, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
} else {
|
||||||
|
return INVALID_JSON_POINTER;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
element result;
|
||||||
|
auto error = at_path(json_path).get(result);
|
||||||
|
if (error) {
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::vector<element>{std::move(result)};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
inline simdjson_result<element> array::at(size_t index) const noexcept {
|
inline simdjson_result<element> array::at(size_t index) const noexcept {
|
||||||
SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
|
SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
|
||||||
size_t i=0;
|
size_t i=0;
|
||||||
@@ -137,6 +235,15 @@ inline simdjson_result<element> array::at(size_t index) const noexcept {
|
|||||||
return INDEX_OUT_OF_BOUNDS;
|
return INDEX_OUT_OF_BOUNDS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline std::vector<element>& array::get_values(std::vector<element>& out) const noexcept {
|
||||||
|
out.reserve(this->size());
|
||||||
|
for (auto element : *this) {
|
||||||
|
out.emplace_back(element);
|
||||||
|
}
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
inline array::operator element() const noexcept {
|
inline array::operator element() const noexcept {
|
||||||
return element(tape);
|
return element(tape);
|
||||||
}
|
}
|
||||||
@@ -183,13 +290,13 @@ inline bool array::iterator::operator>(const array::iterator& other) const noexc
|
|||||||
|
|
||||||
#include "simdjson/dom/element-inl.h"
|
#include "simdjson/dom/element-inl.h"
|
||||||
|
|
||||||
#if defined(__cpp_lib_ranges)
|
#if SIMDJSON_SUPPORTS_RANGES
|
||||||
static_assert(std::ranges::view<simdjson::dom::array>);
|
static_assert(std::ranges::view<simdjson::dom::array>);
|
||||||
static_assert(std::ranges::sized_range<simdjson::dom::array>);
|
static_assert(std::ranges::sized_range<simdjson::dom::array>);
|
||||||
#if SIMDJSON_EXCEPTIONS
|
#if SIMDJSON_EXCEPTIONS
|
||||||
static_assert(std::ranges::view<simdjson::simdjson_result<simdjson::dom::array>>);
|
static_assert(std::ranges::view<simdjson::simdjson_result<simdjson::dom::array>>);
|
||||||
static_assert(std::ranges::sized_range<simdjson::simdjson_result<simdjson::dom::array>>);
|
static_assert(std::ranges::sized_range<simdjson::simdjson_result<simdjson::dom::array>>);
|
||||||
#endif // SIMDJSON_EXCEPTIONS
|
#endif // SIMDJSON_EXCEPTIONS
|
||||||
#endif // defined(__cpp_lib_ranges)
|
#endif // SIMDJSON_SUPPORTS_RANGES
|
||||||
|
|
||||||
#endif // SIMDJSON_ARRAY_INL_H
|
#endif // SIMDJSON_ARRAY_INL_H
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
#ifndef SIMDJSON_DOM_ARRAY_H
|
#ifndef SIMDJSON_DOM_ARRAY_H
|
||||||
#define SIMDJSON_DOM_ARRAY_H
|
#define SIMDJSON_DOM_ARRAY_H
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include "simdjson/dom/base.h"
|
#include "simdjson/dom/base.h"
|
||||||
#include "simdjson/internal/tape_ref.h"
|
#include "simdjson/internal/tape_ref.h"
|
||||||
|
|
||||||
@@ -108,6 +110,17 @@ public:
|
|||||||
*/
|
*/
|
||||||
inline simdjson_result<element> at_pointer(std::string_view json_pointer) const noexcept;
|
inline simdjson_result<element> at_pointer(std::string_view json_pointer) const noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Recursive function which processes the json path of each child element
|
||||||
|
*/
|
||||||
|
inline void process_json_path_of_child_elements(std::vector<element>::iterator& current, std::vector<element>::iterator& end, const std::string_view& path_suffix, std::vector<element>& accumulator) const noexcept;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds support for JSONPath expression with wildcards '*'
|
||||||
|
*/
|
||||||
|
inline simdjson_result<std::vector<element>> at_path_with_wildcard(std::string_view json_path) const noexcept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value associated with the given JSONPath expression. We only support
|
* Get the value associated with the given JSONPath expression. We only support
|
||||||
* JSONPath queries that trivially convertible to JSON Pointer queries: key
|
* JSONPath queries that trivially convertible to JSON Pointer queries: key
|
||||||
@@ -141,6 +154,15 @@ public:
|
|||||||
*/
|
*/
|
||||||
inline simdjson_result<element> at(size_t index) const noexcept;
|
inline simdjson_result<element> at(size_t index) const noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the values of items in an array element
|
||||||
|
* This function has linear-time complexity: the values are checked one by one.
|
||||||
|
*
|
||||||
|
* @return The child elements of an array
|
||||||
|
*/
|
||||||
|
|
||||||
|
inline std::vector<element>& get_values(std::vector<element>& out) const noexcept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implicitly convert object to element
|
* Implicitly convert object to element
|
||||||
*/
|
*/
|
||||||
@@ -167,8 +189,11 @@ public:
|
|||||||
simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
|
simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
|
||||||
|
|
||||||
inline simdjson_result<dom::element> at_pointer(std::string_view json_pointer) const noexcept;
|
inline simdjson_result<dom::element> at_pointer(std::string_view json_pointer) const noexcept;
|
||||||
|
inline void process_json_path_of_child_elements(std::vector<dom::element>::iterator& current, std::vector<dom::element>::iterator& end, const std::string_view& path_suffix, std::vector<dom::element>& accumulator) const noexcept;
|
||||||
|
inline simdjson_result<std::vector<dom::element>> at_path_with_wildcard(std::string_view json_path) const noexcept;
|
||||||
inline simdjson_result<dom::element> at_path(std::string_view json_path) const noexcept;
|
inline simdjson_result<dom::element> at_path(std::string_view json_path) const noexcept;
|
||||||
inline simdjson_result<dom::element> at(size_t index) const noexcept;
|
inline simdjson_result<dom::element> at(size_t index) const noexcept;
|
||||||
|
inline std::vector<dom::element>& get_values(std::vector<dom::element>& out) const noexcept;
|
||||||
|
|
||||||
#if SIMDJSON_EXCEPTIONS
|
#if SIMDJSON_EXCEPTIONS
|
||||||
inline dom::array::iterator begin() const noexcept(false);
|
inline dom::array::iterator begin() const noexcept(false);
|
||||||
@@ -181,9 +206,7 @@ public:
|
|||||||
|
|
||||||
} // namespace simdjson
|
} // namespace simdjson
|
||||||
|
|
||||||
#if defined(__cpp_lib_ranges)
|
#if SIMDJSON_SUPPORTS_RANGES
|
||||||
#include <ranges>
|
|
||||||
|
|
||||||
namespace std {
|
namespace std {
|
||||||
namespace ranges {
|
namespace ranges {
|
||||||
template<>
|
template<>
|
||||||
@@ -194,6 +217,6 @@ inline constexpr bool enable_view<simdjson::simdjson_result<simdjson::dom::array
|
|||||||
#endif // SIMDJSON_EXCEPTIONS
|
#endif // SIMDJSON_EXCEPTIONS
|
||||||
} // namespace ranges
|
} // namespace ranges
|
||||||
} // namespace std
|
} // namespace std
|
||||||
#endif // defined(__cpp_lib_ranges)
|
#endif // SIMDJSON_SUPPORTS_RANGES
|
||||||
|
|
||||||
#endif // SIMDJSON_DOM_ARRAY_H
|
#endif // SIMDJSON_DOM_ARRAY_H
|
||||||
|
|||||||
@@ -128,6 +128,12 @@ simdjson_inline simdjson_result<dom::element> simdjson_result<dom::element>::at_
|
|||||||
if (json_pointer == "-1") { return INVALID_JSON_POINTER; }
|
if (json_pointer == "-1") { return INVALID_JSON_POINTER; }
|
||||||
return at_pointer(json_pointer);
|
return at_pointer(json_pointer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
simdjson_inline simdjson_result<std::vector<dom::element>> simdjson_result<dom::element>::at_path_with_wildcard(const std::string_view json_path) const noexcept {
|
||||||
|
if (error()) { return error(); }
|
||||||
|
return first.at_path_with_wildcard(json_path);
|
||||||
|
}
|
||||||
|
|
||||||
#ifndef SIMDJSON_DISABLE_DEPRECATED_API
|
#ifndef SIMDJSON_DISABLE_DEPRECATED_API
|
||||||
[[deprecated("For standard compliance, use at_pointer instead, and prefix your pointers with a slash '/', see RFC6901 ")]]
|
[[deprecated("For standard compliance, use at_pointer instead, and prefix your pointers with a slash '/', see RFC6901 ")]]
|
||||||
simdjson_inline simdjson_result<dom::element> simdjson_result<dom::element>::at(const std::string_view json_pointer) const noexcept {
|
simdjson_inline simdjson_result<dom::element> simdjson_result<dom::element>::at(const std::string_view json_pointer) const noexcept {
|
||||||
@@ -418,6 +424,20 @@ inline simdjson_result<element> element::at_pointer(std::string_view json_pointe
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline simdjson_result<std::vector<element>> element::at_path_with_wildcard(std::string_view json_path) const noexcept {
|
||||||
|
SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
|
||||||
|
|
||||||
|
switch (tape.tape_ref_type()) {
|
||||||
|
case internal::tape_type::START_OBJECT:
|
||||||
|
return object(tape).at_path_with_wildcard(json_path);
|
||||||
|
case internal::tape_type::START_ARRAY:
|
||||||
|
return array(tape).at_path_with_wildcard(json_path);
|
||||||
|
default:
|
||||||
|
return std::vector<element>{};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
inline simdjson_result<element> element::at_path(std::string_view json_path) const noexcept {
|
inline simdjson_result<element> element::at_path(std::string_view json_path) const noexcept {
|
||||||
auto json_pointer = json_path_to_pointer_conversion(json_path);
|
auto json_pointer = json_path_to_pointer_conversion(json_path);
|
||||||
if (json_pointer == "-1") { return INVALID_JSON_POINTER; }
|
if (json_pointer == "-1") { return INVALID_JSON_POINTER; }
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
#ifndef SIMDJSON_DOM_ELEMENT_H
|
#ifndef SIMDJSON_DOM_ELEMENT_H
|
||||||
#define SIMDJSON_DOM_ELEMENT_H
|
#define SIMDJSON_DOM_ELEMENT_H
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include "simdjson/dom/base.h"
|
#include "simdjson/dom/base.h"
|
||||||
#include "simdjson/dom/array.h"
|
#include "simdjson/dom/array.h"
|
||||||
|
|
||||||
@@ -399,6 +401,8 @@ public:
|
|||||||
*/
|
*/
|
||||||
inline simdjson_result<element> at_pointer(const std::string_view json_pointer) const noexcept;
|
inline simdjson_result<element> at_pointer(const std::string_view json_pointer) const noexcept;
|
||||||
|
|
||||||
|
inline simdjson_result<std::vector<element>> at_path_with_wildcard(const std::string_view json_path) const noexcept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value associated with the given JSONPath expression. We only support
|
* Get the value associated with the given JSONPath expression. We only support
|
||||||
* JSONPath queries that trivially convertible to JSON Pointer queries: key
|
* JSONPath queries that trivially convertible to JSON Pointer queries: key
|
||||||
@@ -544,6 +548,7 @@ public:
|
|||||||
simdjson_inline simdjson_result<dom::element> operator[](const char *key) const noexcept;
|
simdjson_inline simdjson_result<dom::element> operator[](const char *key) const noexcept;
|
||||||
simdjson_result<dom::element> operator[](int) const noexcept = delete;
|
simdjson_result<dom::element> operator[](int) const noexcept = delete;
|
||||||
simdjson_inline simdjson_result<dom::element> at_pointer(const std::string_view json_pointer) const noexcept;
|
simdjson_inline simdjson_result<dom::element> at_pointer(const std::string_view json_pointer) const noexcept;
|
||||||
|
simdjson_inline simdjson_result<std::vector<dom::element>> at_path_with_wildcard(const std::string_view json_path) const noexcept;
|
||||||
simdjson_inline simdjson_result<dom::element> at_path(const std::string_view json_path) const noexcept;
|
simdjson_inline simdjson_result<dom::element> at_path(const std::string_view json_path) const noexcept;
|
||||||
[[deprecated("For standard compliance, use at_pointer instead, and prefix your pointers with a slash '/', see RFC6901 ")]]
|
[[deprecated("For standard compliance, use at_pointer instead, and prefix your pointers with a slash '/', see RFC6901 ")]]
|
||||||
simdjson_inline simdjson_result<dom::element> at(const std::string_view json_pointer) const noexcept;
|
simdjson_inline simdjson_result<dom::element> at(const std::string_view json_pointer) const noexcept;
|
||||||
|
|||||||
@@ -40,10 +40,19 @@ inline simdjson_result<dom::element> simdjson_result<dom::object>::at_path(std::
|
|||||||
if (json_pointer == "-1") { return INVALID_JSON_POINTER; }
|
if (json_pointer == "-1") { return INVALID_JSON_POINTER; }
|
||||||
return at_pointer(json_pointer);
|
return at_pointer(json_pointer);
|
||||||
}
|
}
|
||||||
|
inline simdjson_result<std::vector<dom::element>> simdjson_result<dom::object>::at_path_with_wildcard(std::string_view json_path) const noexcept {
|
||||||
|
if (error()) {
|
||||||
|
return error();
|
||||||
|
}
|
||||||
|
return first.at_path_with_wildcard(json_path);
|
||||||
|
}
|
||||||
inline simdjson_result<dom::element> simdjson_result<dom::object>::at_key(std::string_view key) const noexcept {
|
inline simdjson_result<dom::element> simdjson_result<dom::object>::at_key(std::string_view key) const noexcept {
|
||||||
if (error()) { return error(); }
|
if (error()) { return error(); }
|
||||||
return first.at_key(key);
|
return first.at_key(key);
|
||||||
}
|
}
|
||||||
|
inline std::vector<dom::element>& simdjson_result<dom::object>::get_values(std::vector<dom::element>& out) const noexcept {
|
||||||
|
return first.get_values(out);
|
||||||
|
}
|
||||||
inline simdjson_result<dom::element> simdjson_result<dom::object>::at_key_case_insensitive(std::string_view key) const noexcept {
|
inline simdjson_result<dom::element> simdjson_result<dom::object>::at_key_case_insensitive(std::string_view key) const noexcept {
|
||||||
if (error()) { return error(); }
|
if (error()) { return error(); }
|
||||||
return first.at_key_case_insensitive(key);
|
return first.at_key_case_insensitive(key);
|
||||||
@@ -143,6 +152,97 @@ inline simdjson_result<element> object::at_path(std::string_view json_path) cons
|
|||||||
return at_pointer(json_pointer);
|
return at_pointer(json_pointer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline void object::process_json_path_of_child_elements(std::vector<element>::iterator& current, std::vector<element>::iterator& end, const std::string_view& path_suffix, std::vector<element>& accumulator) const noexcept {
|
||||||
|
if (current == end) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
simdjson_result<std::vector<element>> result;
|
||||||
|
|
||||||
|
for (auto it = current; it != end; ++it) {
|
||||||
|
std::vector<element> child_result;
|
||||||
|
auto error = it->at_path_with_wildcard(path_suffix).get(child_result);
|
||||||
|
if(error) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
accumulator.reserve(accumulator.size() + child_result.size());
|
||||||
|
accumulator.insert(accumulator.end(),
|
||||||
|
std::make_move_iterator(child_result.begin()),
|
||||||
|
std::make_move_iterator(child_result.end()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline simdjson_result<std::vector<element>> object::at_path_with_wildcard(std::string_view json_path) const noexcept {
|
||||||
|
SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
|
||||||
|
|
||||||
|
size_t i = 0;
|
||||||
|
if (json_path.empty()) {
|
||||||
|
return INVALID_JSON_POINTER;
|
||||||
|
}
|
||||||
|
// if JSONPath starts with $, skip it
|
||||||
|
// json_path.starts_with('$') requires C++20.
|
||||||
|
if (json_path.front() == '$') {
|
||||||
|
i = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i >= json_path.size() || (json_path[i] != '.' && json_path[i] != '[')) {
|
||||||
|
// expect json path to always start with $ but this isn't currently
|
||||||
|
// expected in jsonpathutil.h.
|
||||||
|
return INVALID_JSON_POINTER;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (json_path.find("*") != std::string::npos) {
|
||||||
|
|
||||||
|
std::vector<element> child_values;
|
||||||
|
|
||||||
|
if (
|
||||||
|
(json_path.compare(i, 3, "[*]") == 0 && json_path.size() == i + 3) ||
|
||||||
|
(json_path.compare(i, 2,".*") == 0 && json_path.size() == i + 2)
|
||||||
|
) {
|
||||||
|
get_values(child_values);
|
||||||
|
return child_values;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::pair<std::string_view, std::string_view> key_and_json_path = get_next_key_and_json_path(json_path);
|
||||||
|
|
||||||
|
std::string_view key = key_and_json_path.first;
|
||||||
|
json_path = key_and_json_path.second;
|
||||||
|
|
||||||
|
if (key.size() > 0) {
|
||||||
|
if (key == "*") {
|
||||||
|
get_values(child_values);
|
||||||
|
} else {
|
||||||
|
element pointer_result;
|
||||||
|
auto error = at_pointer(std::string("/") + std::string(key)).get(pointer_result);
|
||||||
|
|
||||||
|
if (!error) {
|
||||||
|
child_values.emplace_back(pointer_result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<element> result = {};
|
||||||
|
if (child_values.size() > 0) {
|
||||||
|
|
||||||
|
std::vector<element>::iterator child_values_begin = child_values.begin();
|
||||||
|
std::vector<element>::iterator child_values_end = child_values.end();
|
||||||
|
|
||||||
|
process_json_path_of_child_elements(child_values_begin, child_values_end, json_path, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
} else {
|
||||||
|
return INVALID_JSON_POINTER;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
element result;
|
||||||
|
auto error = this->at_path(json_path).get(result);
|
||||||
|
if (error) {
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
return std::vector<element>{std::move(result)};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
inline simdjson_result<element> object::at_key(std::string_view key) const noexcept {
|
inline simdjson_result<element> object::at_key(std::string_view key) const noexcept {
|
||||||
iterator end_field = end();
|
iterator end_field = end();
|
||||||
for (iterator field = begin(); field != end_field; ++field) {
|
for (iterator field = begin(); field != end_field; ++field) {
|
||||||
@@ -152,6 +252,18 @@ inline simdjson_result<element> object::at_key(std::string_view key) const noexc
|
|||||||
}
|
}
|
||||||
return NO_SUCH_FIELD;
|
return NO_SUCH_FIELD;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline std::vector<element>& object::get_values(std::vector<element>& out) const noexcept {
|
||||||
|
iterator end_field = end();
|
||||||
|
iterator begin_field = begin();
|
||||||
|
|
||||||
|
out.reserve(std::distance(begin_field, end_field));
|
||||||
|
for (iterator field = begin_field; field != end_field; ++field) {
|
||||||
|
out.emplace_back(field.value());
|
||||||
|
}
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
// In case you wonder why we need this, please see
|
// In case you wonder why we need this, please see
|
||||||
// https://github.com/simdjson/simdjson/issues/323
|
// https://github.com/simdjson/simdjson/issues/323
|
||||||
// People do seek keys in a case-insensitive manner.
|
// People do seek keys in a case-insensitive manner.
|
||||||
@@ -263,13 +375,13 @@ inline key_value_pair::key_value_pair(std::string_view _key, element _value) noe
|
|||||||
|
|
||||||
} // namespace simdjson
|
} // namespace simdjson
|
||||||
|
|
||||||
#if defined(__cpp_lib_ranges)
|
#if SIMDJSON_SUPPORTS_RANGES
|
||||||
static_assert(std::ranges::view<simdjson::dom::object>);
|
static_assert(std::ranges::view<simdjson::dom::object>);
|
||||||
static_assert(std::ranges::sized_range<simdjson::dom::object>);
|
static_assert(std::ranges::sized_range<simdjson::dom::object>);
|
||||||
#if SIMDJSON_EXCEPTIONS
|
#if SIMDJSON_EXCEPTIONS
|
||||||
static_assert(std::ranges::view<simdjson::simdjson_result<simdjson::dom::object>>);
|
static_assert(std::ranges::view<simdjson::simdjson_result<simdjson::dom::object>>);
|
||||||
static_assert(std::ranges::sized_range<simdjson::simdjson_result<simdjson::dom::object>>);
|
static_assert(std::ranges::sized_range<simdjson::simdjson_result<simdjson::dom::object>>);
|
||||||
#endif // SIMDJSON_EXCEPTIONS
|
#endif // SIMDJSON_EXCEPTIONS
|
||||||
#endif // defined(__cpp_lib_ranges)
|
#endif // SIMDJSON_SUPPORTS_RANGES
|
||||||
|
|
||||||
#endif // SIMDJSON_OBJECT_INL_H
|
#endif // SIMDJSON_OBJECT_INL_H
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
#ifndef SIMDJSON_DOM_OBJECT_H
|
#ifndef SIMDJSON_DOM_OBJECT_H
|
||||||
#define SIMDJSON_DOM_OBJECT_H
|
#define SIMDJSON_DOM_OBJECT_H
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include "simdjson/dom/base.h"
|
#include "simdjson/dom/base.h"
|
||||||
#include "simdjson/dom/element.h"
|
#include "simdjson/dom/element.h"
|
||||||
#include "simdjson/internal/tape_ref.h"
|
#include "simdjson/internal/tape_ref.h"
|
||||||
@@ -172,6 +174,16 @@ public:
|
|||||||
*/
|
*/
|
||||||
inline simdjson_result<element> at_pointer(std::string_view json_pointer) const noexcept;
|
inline simdjson_result<element> at_pointer(std::string_view json_pointer) const noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Recursive function which processes the json path of each child element
|
||||||
|
*/
|
||||||
|
inline void process_json_path_of_child_elements(std::vector<element>::iterator& current, std::vector<element>::iterator& end, const std::string_view& path_suffix, std::vector<element>& accumulator) const noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds support for JSONPath expression with wildcards '*'
|
||||||
|
*/
|
||||||
|
inline simdjson_result<std::vector<element>> at_path_with_wildcard(std::string_view json_path) const noexcept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value associated with the given JSONPath expression. We only support
|
* Get the value associated with the given JSONPath expression. We only support
|
||||||
* JSONPath queries that trivially convertible to JSON Pointer queries: key
|
* JSONPath queries that trivially convertible to JSON Pointer queries: key
|
||||||
@@ -203,6 +215,14 @@ public:
|
|||||||
*/
|
*/
|
||||||
inline simdjson_result<element> at_key(std::string_view key) const noexcept;
|
inline simdjson_result<element> at_key(std::string_view key) const noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the values associated with keys of an object
|
||||||
|
* This function has linear-time complexity: the keys are checked one by one.
|
||||||
|
*
|
||||||
|
* @return the values associated with each key of an object
|
||||||
|
*/
|
||||||
|
inline std::vector<element>& get_values(std::vector<element>& out) const noexcept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value associated with the given key in a case-insensitive manner.
|
* Get the value associated with the given key in a case-insensitive manner.
|
||||||
* It is only guaranteed to work over ASCII inputs.
|
* It is only guaranteed to work over ASCII inputs.
|
||||||
@@ -261,8 +281,11 @@ public:
|
|||||||
inline simdjson_result<dom::element> operator[](const char *key) const noexcept;
|
inline simdjson_result<dom::element> operator[](const char *key) const noexcept;
|
||||||
simdjson_result<dom::element> operator[](int) const noexcept = delete;
|
simdjson_result<dom::element> operator[](int) const noexcept = delete;
|
||||||
inline simdjson_result<dom::element> at_pointer(std::string_view json_pointer) const noexcept;
|
inline simdjson_result<dom::element> at_pointer(std::string_view json_pointer) const noexcept;
|
||||||
|
inline void process_json_path_of_child_elements(std::vector<dom::element>::iterator& current, std::vector<dom::element>::iterator& end, const std::string_view& path_suffix, std::vector<dom::element>& accumulator) const noexcept;
|
||||||
|
inline simdjson_result<std::vector<dom::element>> at_path_with_wildcard(std::string_view json_path_new) const noexcept;
|
||||||
inline simdjson_result<dom::element> at_path(std::string_view json_path) const noexcept;
|
inline simdjson_result<dom::element> at_path(std::string_view json_path) const noexcept;
|
||||||
inline simdjson_result<dom::element> at_key(std::string_view key) const noexcept;
|
inline simdjson_result<dom::element> at_key(std::string_view key) const noexcept;
|
||||||
|
inline std::vector<dom::element>& get_values(std::vector<dom::element>& out) const noexcept;
|
||||||
inline simdjson_result<dom::element> at_key_case_insensitive(std::string_view key) const noexcept;
|
inline simdjson_result<dom::element> at_key_case_insensitive(std::string_view key) const noexcept;
|
||||||
|
|
||||||
#if SIMDJSON_EXCEPTIONS
|
#if SIMDJSON_EXCEPTIONS
|
||||||
@@ -274,9 +297,7 @@ public:
|
|||||||
|
|
||||||
} // namespace simdjson
|
} // namespace simdjson
|
||||||
|
|
||||||
#if defined(__cpp_lib_ranges)
|
#if SIMDJSON_SUPPORTS_RANGES
|
||||||
#include <ranges>
|
|
||||||
|
|
||||||
namespace std {
|
namespace std {
|
||||||
namespace ranges {
|
namespace ranges {
|
||||||
template<>
|
template<>
|
||||||
@@ -287,6 +308,6 @@ inline constexpr bool enable_view<simdjson::simdjson_result<simdjson::dom::objec
|
|||||||
#endif // SIMDJSON_EXCEPTIONS
|
#endif // SIMDJSON_EXCEPTIONS
|
||||||
} // namespace ranges
|
} // namespace ranges
|
||||||
} // namespace std
|
} // namespace std
|
||||||
#endif // defined(__cpp_lib_ranges)
|
#endif // SIMDJSON_SUPPORTS_RANGES
|
||||||
|
|
||||||
#endif // SIMDJSON_DOM_OBJECT_H
|
#endif // SIMDJSON_DOM_OBJECT_H
|
||||||
|
|||||||
@@ -35,11 +35,11 @@ inline bool parser::dump_raw_tape(std::ostream &os) const noexcept {
|
|||||||
return valid ? doc.dump_raw_tape(os) : false;
|
return valid ? doc.dump_raw_tape(os) : false;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline simdjson_result<size_t> parser::read_file(const std::string &path) noexcept {
|
inline simdjson_result<size_t> parser::read_file(std::string_view path) noexcept {
|
||||||
// Open the file
|
// Open the file
|
||||||
SIMDJSON_PUSH_DISABLE_WARNINGS
|
SIMDJSON_PUSH_DISABLE_WARNINGS
|
||||||
SIMDJSON_DISABLE_DEPRECATED_WARNING // Disable CRT_SECURE warning on MSVC: manually verified this is safe
|
SIMDJSON_DISABLE_DEPRECATED_WARNING // Disable CRT_SECURE warning on MSVC: manually verified this is safe
|
||||||
std::FILE *fp = std::fopen(path.c_str(), "rb");
|
std::FILE *fp = std::fopen(path.data(), "rb");
|
||||||
SIMDJSON_POP_DISABLE_WARNINGS
|
SIMDJSON_POP_DISABLE_WARNINGS
|
||||||
|
|
||||||
if (fp == nullptr) {
|
if (fp == nullptr) {
|
||||||
@@ -91,18 +91,18 @@ inline simdjson_result<size_t> parser::read_file(const std::string &path) noexce
|
|||||||
return bytes_read;
|
return bytes_read;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline simdjson_result<element> parser::load(const std::string &path) & noexcept {
|
inline simdjson_result<element> parser::load(std::string_view path) & noexcept {
|
||||||
return load_into_document(doc, path);
|
return load_into_document(doc, path);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline simdjson_result<element> parser::load_into_document(document& provided_doc, const std::string &path) & noexcept {
|
inline simdjson_result<element> parser::load_into_document(document& provided_doc, std::string_view path) & noexcept {
|
||||||
size_t len;
|
size_t len;
|
||||||
auto _error = read_file(path).get(len);
|
auto _error = read_file(path).get(len);
|
||||||
if (_error) { return _error; }
|
if (_error) { return _error; }
|
||||||
return parse_into_document(provided_doc, loaded_bytes.get(), len, false);
|
return parse_into_document(provided_doc, loaded_bytes.get(), len, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline simdjson_result<document_stream> parser::load_many(const std::string &path, size_t batch_size) noexcept {
|
inline simdjson_result<document_stream> parser::load_many(std::string_view path, size_t batch_size) noexcept {
|
||||||
size_t len;
|
size_t len;
|
||||||
auto _error = read_file(path).get(len);
|
auto _error = read_file(path).get(len);
|
||||||
if (_error) { return _error; }
|
if (_error) { return _error; }
|
||||||
|
|||||||
@@ -102,8 +102,8 @@ public:
|
|||||||
* - other json errors if parsing fails. You should not rely on these errors to always the same for the
|
* - other json errors if parsing fails. You should not rely on these errors to always the same for the
|
||||||
* same document: they may vary under runtime dispatch (so they may vary depending on your system and hardware).
|
* same document: they may vary under runtime dispatch (so they may vary depending on your system and hardware).
|
||||||
*/
|
*/
|
||||||
inline simdjson_result<element> load(const std::string &path) & noexcept;
|
inline simdjson_result<element> load(std::string_view path) & noexcept;
|
||||||
inline simdjson_result<element> load(const std::string &path) && = delete ;
|
inline simdjson_result<element> load(std::string_view path) && = delete ;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Load a JSON document from a file into a provide document instance and return a temporary reference to it.
|
* Load a JSON document from a file into a provide document instance and return a temporary reference to it.
|
||||||
@@ -148,8 +148,8 @@ public:
|
|||||||
* - other json errors if parsing fails. You should not rely on these errors to always the same for the
|
* - other json errors if parsing fails. You should not rely on these errors to always the same for the
|
||||||
* same document: they may vary under runtime dispatch (so they may vary depending on your system and hardware).
|
* same document: they may vary under runtime dispatch (so they may vary depending on your system and hardware).
|
||||||
*/
|
*/
|
||||||
inline simdjson_result<element> load_into_document(document& doc, const std::string &path) & noexcept;
|
inline simdjson_result<element> load_into_document(document& doc, std::string_view path) & noexcept;
|
||||||
inline simdjson_result<element> load_into_document(document& doc, const std::string &path) && =delete;
|
inline simdjson_result<element> load_into_document(document& doc, std::string_view path) && =delete;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse a JSON document and return a temporary reference to it.
|
* Parse a JSON document and return a temporary reference to it.
|
||||||
@@ -386,7 +386,7 @@ public:
|
|||||||
* - other json errors if parsing fails. You should not rely on these errors to always the same for the
|
* - other json errors if parsing fails. You should not rely on these errors to always the same for the
|
||||||
* same document: they may vary under runtime dispatch (so they may vary depending on your system and hardware).
|
* same document: they may vary under runtime dispatch (so they may vary depending on your system and hardware).
|
||||||
*/
|
*/
|
||||||
inline simdjson_result<document_stream> load_many(const std::string &path, size_t batch_size = dom::DEFAULT_BATCH_SIZE) noexcept;
|
inline simdjson_result<document_stream> load_many(std::string_view path, size_t batch_size = dom::DEFAULT_BATCH_SIZE) noexcept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse a buffer containing many JSON documents.
|
* Parse a buffer containing many JSON documents.
|
||||||
@@ -657,7 +657,7 @@ private:
|
|||||||
inline error_code ensure_capacity(document& doc, size_t desired_capacity) noexcept;
|
inline error_code ensure_capacity(document& doc, size_t desired_capacity) noexcept;
|
||||||
|
|
||||||
/** Read the file into loaded_bytes */
|
/** Read the file into loaded_bytes */
|
||||||
inline simdjson_result<size_t> read_file(const std::string &path) noexcept;
|
inline simdjson_result<size_t> read_file(std::string_view path) noexcept;
|
||||||
|
|
||||||
friend class parser::Iterator;
|
friend class parser::Iterator;
|
||||||
friend class document_stream;
|
friend class document_stream;
|
||||||
|
|||||||
@@ -3,8 +3,8 @@
|
|||||||
#define SIMDJSON_SERIALIZATION_INL_H
|
#define SIMDJSON_SERIALIZATION_INL_H
|
||||||
|
|
||||||
#include "simdjson/dom/base.h"
|
#include "simdjson/dom/base.h"
|
||||||
#include "simdjson/dom/serialization.h"
|
|
||||||
#include "simdjson/dom/parser.h"
|
#include "simdjson/dom/parser.h"
|
||||||
|
#include "simdjson/dom/serialization.h"
|
||||||
#include "simdjson/internal/tape_type.h"
|
#include "simdjson/internal/tape_type.h"
|
||||||
|
|
||||||
#include "simdjson/dom/array-inl.h"
|
#include "simdjson/dom/array-inl.h"
|
||||||
@@ -16,7 +16,9 @@
|
|||||||
namespace simdjson {
|
namespace simdjson {
|
||||||
namespace dom {
|
namespace dom {
|
||||||
inline bool parser::print_json(std::ostream &os) const noexcept {
|
inline bool parser::print_json(std::ostream &os) const noexcept {
|
||||||
if (!valid) { return false; }
|
if (!valid) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
simdjson::internal::string_builder<> sb;
|
simdjson::internal::string_builder<> sb;
|
||||||
sb.append(doc.root());
|
sb.append(doc.root());
|
||||||
std::string_view answer = sb.str();
|
std::string_view answer = sb.str();
|
||||||
@@ -24,37 +26,51 @@ inline bool parser::print_json(std::ostream &os) const noexcept {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline std::ostream& operator<<(std::ostream& out, simdjson::dom::element value) {
|
inline std::ostream &operator<<(std::ostream &out,
|
||||||
simdjson::internal::string_builder<> sb;
|
simdjson::dom::element value) {
|
||||||
sb.append(value);
|
simdjson::internal::string_builder<> sb;
|
||||||
return (out << sb.str());
|
sb.append(value);
|
||||||
|
return (out << sb.str());
|
||||||
}
|
}
|
||||||
#if SIMDJSON_EXCEPTIONS
|
#if SIMDJSON_EXCEPTIONS
|
||||||
inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::dom::element> x) {
|
inline std::ostream &
|
||||||
if (x.error()) { throw simdjson::simdjson_error(x.error()); }
|
operator<<(std::ostream &out,
|
||||||
return (out << x.value());
|
simdjson::simdjson_result<simdjson::dom::element> x) {
|
||||||
|
if (x.error()) {
|
||||||
|
throw simdjson::simdjson_error(x.error());
|
||||||
|
}
|
||||||
|
return (out << x.value());
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
inline std::ostream& operator<<(std::ostream& out, simdjson::dom::array value) {
|
inline std::ostream &operator<<(std::ostream &out, simdjson::dom::array value) {
|
||||||
simdjson::internal::string_builder<> sb;
|
simdjson::internal::string_builder<> sb;
|
||||||
sb.append(value);
|
sb.append(value);
|
||||||
return (out << sb.str());
|
return (out << sb.str());
|
||||||
}
|
}
|
||||||
#if SIMDJSON_EXCEPTIONS
|
#if SIMDJSON_EXCEPTIONS
|
||||||
inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::dom::array> x) {
|
inline std::ostream &
|
||||||
if (x.error()) { throw simdjson::simdjson_error(x.error()); }
|
operator<<(std::ostream &out,
|
||||||
return (out << x.value());
|
simdjson::simdjson_result<simdjson::dom::array> x) {
|
||||||
|
if (x.error()) {
|
||||||
|
throw simdjson::simdjson_error(x.error());
|
||||||
|
}
|
||||||
|
return (out << x.value());
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
inline std::ostream& operator<<(std::ostream& out, simdjson::dom::object value) {
|
inline std::ostream &operator<<(std::ostream &out,
|
||||||
simdjson::internal::string_builder<> sb;
|
simdjson::dom::object value) {
|
||||||
sb.append(value);
|
simdjson::internal::string_builder<> sb;
|
||||||
return (out << sb.str());
|
sb.append(value);
|
||||||
|
return (out << sb.str());
|
||||||
}
|
}
|
||||||
#if SIMDJSON_EXCEPTIONS
|
#if SIMDJSON_EXCEPTIONS
|
||||||
inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::dom::object> x) {
|
inline std::ostream &
|
||||||
if (x.error()) { throw simdjson::simdjson_error(x.error()); }
|
operator<<(std::ostream &out,
|
||||||
return (out << x.value());
|
simdjson::simdjson_result<simdjson::dom::object> x) {
|
||||||
|
if (x.error()) {
|
||||||
|
throw simdjson::simdjson_error(x.error());
|
||||||
|
}
|
||||||
|
return (out << x.value());
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -69,8 +85,9 @@ namespace {
|
|||||||
* We expect that most compilers will use 8 bytes for this data structure.
|
* We expect that most compilers will use 8 bytes for this data structure.
|
||||||
**/
|
**/
|
||||||
struct escape_sequence {
|
struct escape_sequence {
|
||||||
uint8_t length;
|
uint8_t length;
|
||||||
const char string[7]; // technically, we only ever need 6 characters, we pad to 8
|
const char
|
||||||
|
string[7]; // technically, we only ever need 6 characters, we pad to 8
|
||||||
};
|
};
|
||||||
/**@private
|
/**@private
|
||||||
* This converts a signed integer into a character sequence.
|
* This converts a signed integer into a character sequence.
|
||||||
@@ -86,7 +103,7 @@ static char *fast_itoa(char *output, int64_t value) noexcept {
|
|||||||
char buffer[20];
|
char buffer[20];
|
||||||
uint64_t value_positive;
|
uint64_t value_positive;
|
||||||
// In general, negating a signed integer is unsafe.
|
// In general, negating a signed integer is unsafe.
|
||||||
if(value < 0) {
|
if (value < 0) {
|
||||||
*output++ = '-';
|
*output++ = '-';
|
||||||
// Doing value_positive = -value; while avoiding
|
// Doing value_positive = -value; while avoiding
|
||||||
// undefined behavior warnings.
|
// undefined behavior warnings.
|
||||||
@@ -105,7 +122,7 @@ static char *fast_itoa(char *output, int64_t value) noexcept {
|
|||||||
// A faster approach is possible if we expect large integers:
|
// A faster approach is possible if we expect large integers:
|
||||||
// unroll the loop (work in 100s, 1000s) and use some kind of
|
// unroll the loop (work in 100s, 1000s) and use some kind of
|
||||||
// memoization.
|
// memoization.
|
||||||
while(value_positive >= 10) {
|
while (value_positive >= 10) {
|
||||||
*write_pointer-- = char('0' + (value_positive % 10));
|
*write_pointer-- = char('0' + (value_positive % 10));
|
||||||
value_positive /= 10;
|
value_positive /= 10;
|
||||||
}
|
}
|
||||||
@@ -131,7 +148,7 @@ static char *fast_itoa(char *output, uint64_t value) noexcept {
|
|||||||
// A faster approach is possible if we expect large integers:
|
// A faster approach is possible if we expect large integers:
|
||||||
// unroll the loop (work in 100s, 1000s) and use some kind of
|
// unroll the loop (work in 100s, 1000s) and use some kind of
|
||||||
// memoization.
|
// memoization.
|
||||||
while(value >= 10) {
|
while (value >= 10) {
|
||||||
*write_pointer-- = char('0' + (value % 10));
|
*write_pointer-- = char('0' + (value % 10));
|
||||||
value /= 10;
|
value /= 10;
|
||||||
};
|
};
|
||||||
@@ -141,7 +158,6 @@ static char *fast_itoa(char *output, uint64_t value) noexcept {
|
|||||||
return output + len;
|
return output + len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
} // anonymous namespace
|
} // anonymous namespace
|
||||||
namespace internal {
|
namespace internal {
|
||||||
|
|
||||||
@@ -149,193 +165,208 @@ namespace internal {
|
|||||||
* Minifier/formatter code.
|
* Minifier/formatter code.
|
||||||
**/
|
**/
|
||||||
|
|
||||||
template<class formatter>
|
template <class formatter>
|
||||||
simdjson_inline void base_formatter<formatter>::number(uint64_t x) {
|
simdjson_inline void base_formatter<formatter>::number(uint64_t x) {
|
||||||
char number_buffer[24];
|
char number_buffer[24];
|
||||||
char *newp = fast_itoa(number_buffer, x);
|
char *newp = fast_itoa(number_buffer, x);
|
||||||
buffer.insert(buffer.end(), number_buffer, newp);
|
chars(number_buffer, newp);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class formatter>
|
template <class formatter>
|
||||||
simdjson_inline void base_formatter<formatter>::number(int64_t x) {
|
simdjson_inline void base_formatter<formatter>::number(int64_t x) {
|
||||||
char number_buffer[24];
|
char number_buffer[24];
|
||||||
char *newp = fast_itoa(number_buffer, x);
|
char *newp = fast_itoa(number_buffer, x);
|
||||||
buffer.insert(buffer.end(), number_buffer, newp);
|
chars(number_buffer, newp);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class formatter>
|
template <class formatter>
|
||||||
simdjson_inline void base_formatter<formatter>::number(double x) {
|
simdjson_inline void base_formatter<formatter>::number(double x) {
|
||||||
char number_buffer[24];
|
char number_buffer[24];
|
||||||
// Currently, passing the nullptr to the second argument is
|
// Currently, passing the nullptr to the second argument is
|
||||||
// safe because our implementation does not check the second
|
// safe because our implementation does not check the second
|
||||||
// argument.
|
// argument.
|
||||||
char *newp = internal::to_chars(number_buffer, nullptr, x);
|
char *newp = internal::to_chars(number_buffer, nullptr, x);
|
||||||
buffer.insert(buffer.end(), number_buffer, newp);
|
chars(number_buffer, newp);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class formatter>
|
template <class formatter>
|
||||||
simdjson_inline void base_formatter<formatter>::start_array() { one_char('['); }
|
simdjson_inline void base_formatter<formatter>::start_array() {
|
||||||
|
one_char('[');
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class formatter>
|
||||||
|
simdjson_inline void base_formatter<formatter>::end_array() {
|
||||||
|
one_char(']');
|
||||||
|
}
|
||||||
|
|
||||||
template<class formatter>
|
template <class formatter>
|
||||||
simdjson_inline void base_formatter<formatter>::end_array() { one_char(']'); }
|
simdjson_inline void base_formatter<formatter>::start_object() {
|
||||||
|
one_char('{');
|
||||||
|
}
|
||||||
|
|
||||||
template<class formatter>
|
template <class formatter>
|
||||||
simdjson_inline void base_formatter<formatter>::start_object() { one_char('{'); }
|
simdjson_inline void base_formatter<formatter>::end_object() {
|
||||||
|
one_char('}');
|
||||||
|
}
|
||||||
|
|
||||||
template<class formatter>
|
template <class formatter>
|
||||||
simdjson_inline void base_formatter<formatter>::end_object() { one_char('}'); }
|
simdjson_inline void base_formatter<formatter>::comma() {
|
||||||
|
one_char(',');
|
||||||
|
}
|
||||||
|
|
||||||
template<class formatter>
|
template <class formatter>
|
||||||
simdjson_inline void base_formatter<formatter>::comma() { one_char(','); }
|
|
||||||
|
|
||||||
template<class formatter>
|
|
||||||
simdjson_inline void base_formatter<formatter>::true_atom() {
|
simdjson_inline void base_formatter<formatter>::true_atom() {
|
||||||
const char * s = "true";
|
const char *s = "true";
|
||||||
buffer.insert(buffer.end(), s, s + 4);
|
chars(s, s + 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class formatter>
|
template <class formatter>
|
||||||
simdjson_inline void base_formatter<formatter>::false_atom() {
|
simdjson_inline void base_formatter<formatter>::false_atom() {
|
||||||
const char * s = "false";
|
const char *s = "false";
|
||||||
buffer.insert(buffer.end(), s, s + 5);
|
chars(s, s + 5);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class formatter>
|
template <class formatter>
|
||||||
simdjson_inline void base_formatter<formatter>::null_atom() {
|
simdjson_inline void base_formatter<formatter>::null_atom() {
|
||||||
const char * s = "null";
|
const char *s = "null";
|
||||||
buffer.insert(buffer.end(), s, s + 4);
|
chars(s, s + 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class formatter>
|
template <class formatter>
|
||||||
simdjson_inline void base_formatter<formatter>::one_char(char c) { buffer.push_back(c); }
|
simdjson_inline void base_formatter<formatter>::one_char(char c) {
|
||||||
|
buffer.push_back(c);
|
||||||
|
}
|
||||||
|
|
||||||
template<class formatter>
|
template <class formatter>
|
||||||
simdjson_inline void base_formatter<formatter>::key(std::string_view unescaped) {
|
simdjson_inline void base_formatter<formatter>::chars(const char *begin,
|
||||||
|
const char *end) {
|
||||||
|
buffer.append(begin, end);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class formatter>
|
||||||
|
simdjson_inline void
|
||||||
|
base_formatter<formatter>::key(std::string_view unescaped) {
|
||||||
string(unescaped);
|
string(unescaped);
|
||||||
one_char(':');
|
one_char(':');
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class formatter>
|
template <class formatter>
|
||||||
simdjson_inline void base_formatter<formatter>::string(std::string_view unescaped) {
|
simdjson_inline void
|
||||||
|
base_formatter<formatter>::string(std::string_view unescaped) {
|
||||||
one_char('\"');
|
one_char('\"');
|
||||||
size_t i = 0;
|
size_t i = 0;
|
||||||
// Fast path for the case where we have no control character, no ", and no backslash.
|
// Fast path for the case where we have no control character, no ", and no
|
||||||
// This should include most keys.
|
// backslash. This should include most keys.
|
||||||
//
|
//
|
||||||
// We would like to use 'bool' but some compilers take offense to bitwise operation
|
// We would like to use 'bool' but some compilers take offense to bitwise
|
||||||
// with bool types.
|
// operation with bool types.
|
||||||
constexpr static char needs_escaping[] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
constexpr static char needs_escaping[] = {
|
||||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0,
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
for(;i + 8 <= unescaped.length(); i += 8) {
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
|
||||||
|
for (; i + 8 <= unescaped.length(); i += 8) {
|
||||||
// Poor's man vectorization. This could get much faster if we used SIMD.
|
// Poor's man vectorization. This could get much faster if we used SIMD.
|
||||||
//
|
//
|
||||||
// It is not the case that replacing '|' with '||' would be neutral performance-wise.
|
// It is not the case that replacing '|' with '||' would be neutral
|
||||||
if(needs_escaping[uint8_t(unescaped[i])] | needs_escaping[uint8_t(unescaped[i+1])]
|
// performance-wise.
|
||||||
| needs_escaping[uint8_t(unescaped[i+2])] | needs_escaping[uint8_t(unescaped[i+3])]
|
if (needs_escaping[uint8_t(unescaped[i])] |
|
||||||
| needs_escaping[uint8_t(unescaped[i+4])] | needs_escaping[uint8_t(unescaped[i+5])]
|
needs_escaping[uint8_t(unescaped[i + 1])] |
|
||||||
| needs_escaping[uint8_t(unescaped[i+6])] | needs_escaping[uint8_t(unescaped[i+7])]
|
needs_escaping[uint8_t(unescaped[i + 2])] |
|
||||||
) { break; }
|
needs_escaping[uint8_t(unescaped[i + 3])] |
|
||||||
|
needs_escaping[uint8_t(unescaped[i + 4])] |
|
||||||
|
needs_escaping[uint8_t(unescaped[i + 5])] |
|
||||||
|
needs_escaping[uint8_t(unescaped[i + 6])] |
|
||||||
|
needs_escaping[uint8_t(unescaped[i + 7])]) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
for(;i < unescaped.length(); i++) {
|
for (; i < unescaped.length(); i++) {
|
||||||
if(needs_escaping[uint8_t(unescaped[i])]) { break; }
|
if (needs_escaping[uint8_t(unescaped[i])]) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// The following is also possible and omits a 256-byte table, but it is slower:
|
// The following is also possible and omits a 256-byte table, but it is
|
||||||
// for (; (i < unescaped.length()) && (uint8_t(unescaped[i]) > 0x1F)
|
// slower: for (; (i < unescaped.length()) && (uint8_t(unescaped[i]) > 0x1F)
|
||||||
// && (unescaped[i] != '\"') && (unescaped[i] != '\\'); i++) {}
|
// && (unescaped[i] != '\"') && (unescaped[i] != '\\'); i++) {}
|
||||||
|
|
||||||
// At least for long strings, the following should be fast. We could
|
// At least for long strings, the following should be fast. We could
|
||||||
// do better by integrating the checks and the insertion.
|
// do better by integrating the checks and the insertion.
|
||||||
buffer.insert(buffer.end(), unescaped.data(), unescaped.data() + i);
|
chars(unescaped.data(), unescaped.data() + i);
|
||||||
// We caught a control character if we enter this loop (slow).
|
// We caught a control character if we enter this loop (slow).
|
||||||
// Note that we are do not restart from the beginning, but rather we continue
|
// Note that we are do not restart from the beginning, but rather we continue
|
||||||
// from the point where we encountered something that requires escaping.
|
// from the point where we encountered something that requires escaping.
|
||||||
for (; i < unescaped.length(); i++) {
|
for (; i < unescaped.length(); i++) {
|
||||||
switch (unescaped[i]) {
|
switch (unescaped[i]) {
|
||||||
case '\"':
|
case '\"': {
|
||||||
{
|
const char *s = "\\\"";
|
||||||
const char * s = "\\\"";
|
chars(s, s + 2);
|
||||||
buffer.insert(buffer.end(), s, s + 2);
|
} break;
|
||||||
}
|
case '\\': {
|
||||||
break;
|
const char *s = "\\\\";
|
||||||
case '\\':
|
chars(s, s + 2);
|
||||||
{
|
} break;
|
||||||
const char * s = "\\\\";
|
|
||||||
buffer.insert(buffer.end(), s, s + 2);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
if (uint8_t(unescaped[i]) <= 0x1F) {
|
if (uint8_t(unescaped[i]) <= 0x1F) {
|
||||||
// If packed, this uses 8 * 32 bytes.
|
// If packed, this uses 8 * 32 bytes.
|
||||||
// Note that we expect most compilers to embed this code in the data
|
// Note that we expect most compilers to embed this code in the data
|
||||||
// section.
|
// section.
|
||||||
constexpr static escape_sequence escaped[32] = {
|
constexpr static escape_sequence escaped[32] = {
|
||||||
{6, "\\u0000"}, {6, "\\u0001"}, {6, "\\u0002"}, {6, "\\u0003"},
|
{6, "\\u0000"}, {6, "\\u0001"}, {6, "\\u0002"}, {6, "\\u0003"},
|
||||||
{6, "\\u0004"}, {6, "\\u0005"}, {6, "\\u0006"}, {6, "\\u0007"},
|
{6, "\\u0004"}, {6, "\\u0005"}, {6, "\\u0006"}, {6, "\\u0007"},
|
||||||
{2, "\\b"}, {2, "\\t"}, {2, "\\n"}, {6, "\\u000b"},
|
{2, "\\b"}, {2, "\\t"}, {2, "\\n"}, {6, "\\u000b"},
|
||||||
{2, "\\f"}, {2, "\\r"}, {6, "\\u000e"}, {6, "\\u000f"},
|
{2, "\\f"}, {2, "\\r"}, {6, "\\u000e"}, {6, "\\u000f"},
|
||||||
{6, "\\u0010"}, {6, "\\u0011"}, {6, "\\u0012"}, {6, "\\u0013"},
|
{6, "\\u0010"}, {6, "\\u0011"}, {6, "\\u0012"}, {6, "\\u0013"},
|
||||||
{6, "\\u0014"}, {6, "\\u0015"}, {6, "\\u0016"}, {6, "\\u0017"},
|
{6, "\\u0014"}, {6, "\\u0015"}, {6, "\\u0016"}, {6, "\\u0017"},
|
||||||
{6, "\\u0018"}, {6, "\\u0019"}, {6, "\\u001a"}, {6, "\\u001b"},
|
{6, "\\u0018"}, {6, "\\u0019"}, {6, "\\u001a"}, {6, "\\u001b"},
|
||||||
{6, "\\u001c"}, {6, "\\u001d"}, {6, "\\u001e"}, {6, "\\u001f"}};
|
{6, "\\u001c"}, {6, "\\u001d"}, {6, "\\u001e"}, {6, "\\u001f"}};
|
||||||
auto u = escaped[uint8_t(unescaped[i])];
|
auto u = escaped[uint8_t(unescaped[i])];
|
||||||
buffer.insert(buffer.end(), u.string, u.string + u.length);
|
chars(u.string, u.string + u.length);
|
||||||
} else {
|
} else {
|
||||||
one_char(unescaped[i]);
|
one_char(unescaped[i]);
|
||||||
}
|
}
|
||||||
} // switch
|
} // switch
|
||||||
} // for
|
} // for
|
||||||
one_char('\"');
|
one_char('\"');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <class formatter> inline void base_formatter<formatter>::clear() {
|
||||||
template<class formatter>
|
|
||||||
inline void base_formatter<formatter>::clear() {
|
|
||||||
buffer.clear();
|
buffer.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class formatter>
|
template <class formatter>
|
||||||
simdjson_inline std::string_view base_formatter<formatter>::str() const {
|
simdjson_inline std::string_view base_formatter<formatter>::str() const {
|
||||||
return std::string_view(buffer.data(), buffer.size());
|
return buffer.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
simdjson_inline void mini_formatter::print_newline() {
|
simdjson_inline void mini_formatter::print_newline() { return; }
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
simdjson_inline void mini_formatter::print_indents(size_t depth) {
|
simdjson_inline void mini_formatter::print_indents(size_t depth) {
|
||||||
(void)depth;
|
(void)depth;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
simdjson_inline void mini_formatter::print_space() {
|
simdjson_inline void mini_formatter::print_space() { return; }
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
simdjson_inline void pretty_formatter::print_newline() {
|
simdjson_inline void pretty_formatter::print_newline() { one_char('\n'); }
|
||||||
one_char('\n');
|
|
||||||
}
|
|
||||||
|
|
||||||
simdjson_inline void pretty_formatter::print_indents(size_t depth) {
|
simdjson_inline void pretty_formatter::print_indents(size_t depth) {
|
||||||
if(this->indent_step <= 0) {
|
if (this->indent_step <= 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
for(size_t i = 0; i < this->indent_step * depth; i++) {
|
for (size_t i = 0; i < this->indent_step * depth; i++) {
|
||||||
one_char(' ');
|
one_char(' ');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
simdjson_inline void pretty_formatter::print_space() {
|
simdjson_inline void pretty_formatter::print_space() { one_char(' '); }
|
||||||
one_char(' ');
|
|
||||||
}
|
|
||||||
|
|
||||||
/***
|
/***
|
||||||
* String building code.
|
* String building code.
|
||||||
@@ -514,7 +545,8 @@ inline void string_builder<serializer>::append(simdjson::dom::array value) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <class serializer>
|
template <class serializer>
|
||||||
simdjson_inline void string_builder<serializer>::append(simdjson::dom::key_value_pair kv) {
|
simdjson_inline void
|
||||||
|
string_builder<serializer>::append(simdjson::dom::key_value_pair kv) {
|
||||||
format.key(kv.key);
|
format.key(kv.key);
|
||||||
append(kv.value);
|
append(kv.value);
|
||||||
}
|
}
|
||||||
@@ -529,7 +561,6 @@ simdjson_inline std::string_view string_builder<serializer>::str() const {
|
|||||||
return format.str();
|
return format.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
} // namespace internal
|
} // namespace internal
|
||||||
} // namespace simdjson
|
} // namespace simdjson
|
||||||
|
|
||||||
|
|||||||
@@ -5,8 +5,6 @@
|
|||||||
#include "simdjson/dom/element.h"
|
#include "simdjson/dom/element.h"
|
||||||
#include "simdjson/dom/object.h"
|
#include "simdjson/dom/object.h"
|
||||||
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
namespace simdjson {
|
namespace simdjson {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -16,8 +14,7 @@ namespace simdjson {
|
|||||||
*/
|
*/
|
||||||
namespace internal {
|
namespace internal {
|
||||||
|
|
||||||
template<class formatter>
|
template <class formatter> class base_formatter {
|
||||||
class base_formatter {
|
|
||||||
public:
|
public:
|
||||||
/** Add a comma **/
|
/** Add a comma **/
|
||||||
simdjson_inline void comma();
|
simdjson_inline void comma();
|
||||||
@@ -56,24 +53,76 @@ public:
|
|||||||
/** Prints one character **/
|
/** Prints one character **/
|
||||||
simdjson_inline void one_char(char c);
|
simdjson_inline void one_char(char c);
|
||||||
|
|
||||||
|
/** Prints characters in [begin, end) verbatim. **/
|
||||||
|
simdjson_inline void chars(const char *begin, const char *end);
|
||||||
|
|
||||||
simdjson_inline void call_print_newline() {
|
simdjson_inline void call_print_newline() {
|
||||||
static_cast<formatter*>(this)->print_newline();
|
static_cast<formatter *>(this)->print_newline();
|
||||||
}
|
}
|
||||||
|
|
||||||
simdjson_inline void call_print_indents(size_t depth) {
|
simdjson_inline void call_print_indents(size_t depth) {
|
||||||
static_cast<formatter*>(this)->print_indents(depth);
|
static_cast<formatter *>(this)->print_indents(depth);
|
||||||
}
|
}
|
||||||
|
|
||||||
simdjson_inline void call_print_space() {
|
simdjson_inline void call_print_space() {
|
||||||
static_cast<formatter*>(this)->print_space();
|
static_cast<formatter *>(this)->print_space();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// implementation details (subject to change)
|
// implementation details (subject to change)
|
||||||
/** Backing buffer **/
|
/** Backing buffer **/
|
||||||
std::vector<char> buffer{}; // not ideal!
|
struct vector_with_small_buffer {
|
||||||
};
|
vector_with_small_buffer() = default;
|
||||||
|
~vector_with_small_buffer() { free_buffer(); }
|
||||||
|
|
||||||
|
vector_with_small_buffer(const vector_with_small_buffer &) = delete;
|
||||||
|
vector_with_small_buffer &
|
||||||
|
operator=(const vector_with_small_buffer &) = delete;
|
||||||
|
|
||||||
|
void clear() {
|
||||||
|
size = 0;
|
||||||
|
capacity = StaticCapacity;
|
||||||
|
free_buffer();
|
||||||
|
buffer = array;
|
||||||
|
}
|
||||||
|
|
||||||
|
simdjson_inline void push_back(char c) {
|
||||||
|
if (capacity < size + 1)
|
||||||
|
grow(capacity * 2);
|
||||||
|
buffer[size++] = c;
|
||||||
|
}
|
||||||
|
|
||||||
|
simdjson_inline void append(const char *begin, const char *end) {
|
||||||
|
const size_t new_size = size + (end - begin);
|
||||||
|
if (capacity < new_size)
|
||||||
|
// std::max(new_size, capacity * 2); is broken in tests on Windows
|
||||||
|
grow(new_size < capacity * 2 ? capacity * 2 : new_size);
|
||||||
|
std::copy(begin, end, buffer + size);
|
||||||
|
size = new_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string_view str() const { return std::string_view(buffer, size); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
void free_buffer() {
|
||||||
|
if (buffer != array)
|
||||||
|
delete[] buffer;
|
||||||
|
}
|
||||||
|
void grow(size_t new_capacity) {
|
||||||
|
auto new_buffer = new char[new_capacity];
|
||||||
|
std::copy(buffer, buffer + size, new_buffer);
|
||||||
|
free_buffer();
|
||||||
|
buffer = new_buffer;
|
||||||
|
capacity = new_capacity;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const size_t StaticCapacity = 64;
|
||||||
|
char array[StaticCapacity];
|
||||||
|
char *buffer = array;
|
||||||
|
size_t size = 0;
|
||||||
|
size_t capacity = StaticCapacity;
|
||||||
|
} buffer{};
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @private This is the class that we expect to use with the string_builder
|
* @private This is the class that we expect to use with the string_builder
|
||||||
@@ -111,8 +160,7 @@ protected:
|
|||||||
* This is not to be confused with the simdjson::builder::string_builder
|
* This is not to be confused with the simdjson::builder::string_builder
|
||||||
* which is a different class.
|
* which is a different class.
|
||||||
*/
|
*/
|
||||||
template <class formatter = mini_formatter>
|
template <class formatter = mini_formatter> class string_builder {
|
||||||
class string_builder {
|
|
||||||
public:
|
public:
|
||||||
/** Construct an initially empty builder, would print the empty string **/
|
/** Construct an initially empty builder, would print the empty string **/
|
||||||
string_builder() = default;
|
string_builder() = default;
|
||||||
@@ -134,11 +182,12 @@ public:
|
|||||||
simdjson_inline std::string_view str() const;
|
simdjson_inline std::string_view str() const;
|
||||||
/** Append a key_value_pair to the builder (to be printed) **/
|
/** Append a key_value_pair to the builder (to be printed) **/
|
||||||
simdjson_inline void append(simdjson::dom::key_value_pair value);
|
simdjson_inline void append(simdjson::dom::key_value_pair value);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
formatter format{};
|
formatter format{};
|
||||||
};
|
};
|
||||||
|
|
||||||
} // internal
|
} // namespace internal
|
||||||
|
|
||||||
namespace dom {
|
namespace dom {
|
||||||
|
|
||||||
@@ -147,33 +196,43 @@ namespace dom {
|
|||||||
*
|
*
|
||||||
* @param out The output stream.
|
* @param out The output stream.
|
||||||
* @param value The element.
|
* @param value The element.
|
||||||
* @throw if there is an error with the underlying output stream. simdjson itself will not throw.
|
* @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);
|
inline std::ostream &operator<<(std::ostream &out,
|
||||||
|
simdjson::dom::element value);
|
||||||
#if SIMDJSON_EXCEPTIONS
|
#if SIMDJSON_EXCEPTIONS
|
||||||
inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::dom::element> x);
|
inline std::ostream &
|
||||||
|
operator<<(std::ostream &out,
|
||||||
|
simdjson::simdjson_result<simdjson::dom::element> x);
|
||||||
#endif
|
#endif
|
||||||
/**
|
/**
|
||||||
* Print JSON to an output stream.
|
* Print JSON to an output stream.
|
||||||
*
|
*
|
||||||
* @param out The output stream.
|
* @param out The output stream.
|
||||||
* @param value The array.
|
* @param value The array.
|
||||||
* @throw if there is an error with the underlying output stream. simdjson itself will not throw.
|
* @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);
|
inline std::ostream &operator<<(std::ostream &out, simdjson::dom::array value);
|
||||||
#if SIMDJSON_EXCEPTIONS
|
#if SIMDJSON_EXCEPTIONS
|
||||||
inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::dom::array> x);
|
inline std::ostream &
|
||||||
|
operator<<(std::ostream &out,
|
||||||
|
simdjson::simdjson_result<simdjson::dom::array> x);
|
||||||
#endif
|
#endif
|
||||||
/**
|
/**
|
||||||
* Print JSON to an output stream.
|
* Print JSON to an output stream.
|
||||||
*
|
*
|
||||||
* @param out The output stream.
|
* @param out The output stream.
|
||||||
* @param value The object.
|
* @param value The object.
|
||||||
* @throw if there is an error with the underlying output stream. simdjson itself will not throw.
|
* @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);
|
inline std::ostream &operator<<(std::ostream &out, simdjson::dom::object value);
|
||||||
#if SIMDJSON_EXCEPTIONS
|
#if SIMDJSON_EXCEPTIONS
|
||||||
inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::dom::object> x);
|
inline std::ostream &
|
||||||
|
operator<<(std::ostream &out,
|
||||||
|
simdjson::simdjson_result<simdjson::dom::object> x);
|
||||||
#endif
|
#endif
|
||||||
} // namespace dom
|
} // namespace dom
|
||||||
|
|
||||||
@@ -185,47 +244,47 @@ inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<si
|
|||||||
* cout << to_string(doc) << endl; // prints [1,2,3]
|
* cout << to_string(doc) << endl; // prints [1,2,3]
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
template <class T>
|
template <class T> std::string to_string(T x) {
|
||||||
std::string to_string(T x) {
|
// in C++, to_string is standard:
|
||||||
// in C++, to_string is standard: http://www.cplusplus.com/reference/string/to_string/
|
// http://www.cplusplus.com/reference/string/to_string/ Currently minify and
|
||||||
// Currently minify and to_string are identical but in the future, they may
|
// to_string are identical but in the future, they may differ.
|
||||||
// differ.
|
simdjson::internal::string_builder<> sb;
|
||||||
simdjson::internal::string_builder<> sb;
|
sb.append(x);
|
||||||
sb.append(x);
|
std::string_view answer = sb.str();
|
||||||
std::string_view answer = sb.str();
|
return std::string(answer.data(), answer.size());
|
||||||
return std::string(answer.data(), answer.size());
|
|
||||||
}
|
}
|
||||||
#if SIMDJSON_EXCEPTIONS
|
#if SIMDJSON_EXCEPTIONS
|
||||||
template <class T>
|
template <class T> std::string to_string(simdjson_result<T> x) {
|
||||||
std::string to_string(simdjson_result<T> x) {
|
if (x.error()) {
|
||||||
if (x.error()) { throw simdjson_error(x.error()); }
|
throw simdjson_error(x.error());
|
||||||
return to_string(x.value());
|
}
|
||||||
|
return to_string(x.value());
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Minifies a JSON element or document, printing the smallest possible valid JSON.
|
* Minifies a JSON element or document, printing the smallest possible valid
|
||||||
|
* JSON.
|
||||||
*
|
*
|
||||||
* dom::parser parser;
|
* dom::parser parser;
|
||||||
* element doc = parser.parse(" [ 1 , 2 , 3 ] "_padded);
|
* element doc = parser.parse(" [ 1 , 2 , 3 ] "_padded);
|
||||||
* cout << minify(doc) << endl; // prints [1,2,3]
|
* cout << minify(doc) << endl; // prints [1,2,3]
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
template <class T>
|
template <class T> std::string minify(T x) { return to_string(x); }
|
||||||
std::string minify(T x) {
|
|
||||||
return to_string(x);
|
|
||||||
}
|
|
||||||
|
|
||||||
#if SIMDJSON_EXCEPTIONS
|
#if SIMDJSON_EXCEPTIONS
|
||||||
template <class T>
|
template <class T> std::string minify(simdjson_result<T> x) {
|
||||||
std::string minify(simdjson_result<T> x) {
|
if (x.error()) {
|
||||||
if (x.error()) { throw simdjson_error(x.error()); }
|
throw simdjson_error(x.error());
|
||||||
return to_string(x.value());
|
}
|
||||||
|
return to_string(x.value());
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Prettifies a JSON element or document, printing the valid JSON with indentation.
|
* Prettifies a JSON element or document, printing the valid JSON with
|
||||||
|
* indentation.
|
||||||
*
|
*
|
||||||
* dom::parser parser;
|
* dom::parser parser;
|
||||||
* element doc = parser.parse(" [ 1 , 2 , 3 ] "_padded);
|
* element doc = parser.parse(" [ 1 , 2 , 3 ] "_padded);
|
||||||
@@ -241,23 +300,22 @@ std::string minify(simdjson_result<T> x) {
|
|||||||
* cout << prettify(doc) << endl;
|
* cout << prettify(doc) << endl;
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
template <class T>
|
template <class T> std::string prettify(T x) {
|
||||||
std::string prettify(T x) {
|
simdjson::internal::string_builder<simdjson::internal::pretty_formatter> sb;
|
||||||
simdjson::internal::string_builder<simdjson::internal::pretty_formatter> sb;
|
sb.append(x);
|
||||||
sb.append(x);
|
std::string_view answer = sb.str();
|
||||||
std::string_view answer = sb.str();
|
return std::string(answer.data(), answer.size());
|
||||||
return std::string(answer.data(), answer.size());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if SIMDJSON_EXCEPTIONS
|
#if SIMDJSON_EXCEPTIONS
|
||||||
template <class T>
|
template <class T> std::string prettify(simdjson_result<T> x) {
|
||||||
std::string prettify(simdjson_result<T> x) {
|
if (x.error()) {
|
||||||
if (x.error()) { throw simdjson_error(x.error()); }
|
throw simdjson_error(x.error());
|
||||||
return to_string(x.value());
|
}
|
||||||
|
return to_string(x.value());
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
} // namespace simdjson
|
} // namespace simdjson
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -67,8 +67,38 @@ simdjson_inline error_code simdjson_result_base<T>::error() const noexcept {
|
|||||||
return this->second;
|
return this->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
simdjson_inline bool simdjson_result_base<T>::has_value() const noexcept {
|
||||||
|
return this->error() == SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
#if SIMDJSON_EXCEPTIONS
|
#if SIMDJSON_EXCEPTIONS
|
||||||
|
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
simdjson_inline T& simdjson_result_base<T>::operator*() & noexcept(false) {
|
||||||
|
return this->value();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
simdjson_inline T&& simdjson_result_base<T>::operator*() && noexcept(false) {
|
||||||
|
return std::forward<internal::simdjson_result_base<T>>(*this).value();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
simdjson_inline T* simdjson_result_base<T>::operator->() noexcept(false) {
|
||||||
|
if (this->error()) { throw simdjson_error(this->error()); }
|
||||||
|
return &this->first;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
simdjson_inline const T* simdjson_result_base<T>::operator->() const noexcept(false) {
|
||||||
|
if (this->error()) { throw simdjson_error(this->error()); }
|
||||||
|
return &this->first;
|
||||||
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
simdjson_inline T& simdjson_result_base<T>::value() & noexcept(false) {
|
simdjson_inline T& simdjson_result_base<T>::value() & noexcept(false) {
|
||||||
if (error()) { throw simdjson_error(error()); }
|
if (error()) { throw simdjson_error(error()); }
|
||||||
@@ -93,6 +123,7 @@ simdjson_inline simdjson_result_base<T>::operator T&&() && noexcept(false) {
|
|||||||
|
|
||||||
#endif // SIMDJSON_EXCEPTIONS
|
#endif // SIMDJSON_EXCEPTIONS
|
||||||
|
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
simdjson_inline const T& simdjson_result_base<T>::value_unsafe() const& noexcept {
|
simdjson_inline const T& simdjson_result_base<T>::value_unsafe() const& noexcept {
|
||||||
return this->first;
|
return this->first;
|
||||||
@@ -127,26 +158,10 @@ simdjson_inline void simdjson_result<T>::tie(T &value, error_code &error) && noe
|
|||||||
std::forward<internal::simdjson_result_base<T>>(*this).tie(value, error);
|
std::forward<internal::simdjson_result_base<T>>(*this).tie(value, error);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
simdjson_warn_unused simdjson_inline error_code simdjson_result<T>::get(T &value) && noexcept {
|
|
||||||
return std::forward<internal::simdjson_result_base<T>>(*this).get(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
simdjson_warn_unused simdjson_inline error_code
|
simdjson_warn_unused simdjson_inline error_code
|
||||||
simdjson_result<T>::get(std::string &value) && noexcept
|
simdjson_result<T>::get(T &value) && noexcept {
|
||||||
#if SIMDJSON_SUPPORTS_DESERIALIZATION
|
return std::forward<internal::simdjson_result_base<T>>(*this).get(value);
|
||||||
requires (!std::is_same_v<T, std::string>)
|
|
||||||
#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
|
|
||||||
{
|
|
||||||
// SFINAE : n'active que pour T = std::string_view
|
|
||||||
static_assert(std::is_same<T, std::string_view>::value, "simdjson_result<T>::get(std::string&) n'est disponible que pour T = std::string_view");
|
|
||||||
std::string_view v;
|
|
||||||
error_code error = std::forward<simdjson_result<T>>(*this).get(v);
|
|
||||||
if (!error) {
|
|
||||||
value.assign(v.data(), v.size());
|
|
||||||
}
|
|
||||||
return error;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
|
|||||||
@@ -108,6 +108,10 @@ namespace internal {
|
|||||||
/**
|
/**
|
||||||
* The result of a simdjson operation that could fail.
|
* The result of a simdjson operation that could fail.
|
||||||
*
|
*
|
||||||
|
* IMPORTANT: For the ondemand API, we use implementation_simdjson_result_base<T> as a base class
|
||||||
|
* to avoid some compilation issue. Thus, if you modify this class, please ensure that the ondemand
|
||||||
|
* implementation_simdjson_result_base<T> is also modified.
|
||||||
|
*
|
||||||
* Gives the option of reading error codes, or throwing an exception by casting to the desired result.
|
* Gives the option of reading error codes, or throwing an exception by casting to the desired result.
|
||||||
*
|
*
|
||||||
* This is a base class for implementations that want to add functions to the result type for
|
* This is a base class for implementations that want to add functions to the result type for
|
||||||
@@ -168,8 +172,27 @@ struct simdjson_result_base : protected std::pair<T, error_code> {
|
|||||||
*/
|
*/
|
||||||
simdjson_inline error_code error() const noexcept;
|
simdjson_inline error_code error() const noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether there is a value.
|
||||||
|
*/
|
||||||
|
simdjson_inline bool has_value() const noexcept;
|
||||||
#if SIMDJSON_EXCEPTIONS
|
#if SIMDJSON_EXCEPTIONS
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dereference operator to access the contained value.
|
||||||
|
*
|
||||||
|
* @throw simdjson_error if there was an error.
|
||||||
|
*/
|
||||||
|
simdjson_inline T& operator*() & noexcept(false);
|
||||||
|
simdjson_inline T&& operator*() && noexcept(false);
|
||||||
|
/**
|
||||||
|
* Arrow operator to access members of the contained value.
|
||||||
|
*
|
||||||
|
* @throw simdjson_error if there was an error.
|
||||||
|
*/
|
||||||
|
simdjson_inline T* operator->() noexcept(false);
|
||||||
|
simdjson_inline const T* operator->() const noexcept(false);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the result value.
|
* Get the result value.
|
||||||
*
|
*
|
||||||
@@ -203,12 +226,42 @@ struct simdjson_result_base : protected std::pair<T, error_code> {
|
|||||||
/**
|
/**
|
||||||
* Get the result value. This function is safe if and only
|
* Get the result value. This function is safe if and only
|
||||||
* the error() method returns a value that evaluates to false.
|
* the error() method returns a value that evaluates to false.
|
||||||
|
* We discourage the use of value_unsafe().
|
||||||
|
*
|
||||||
|
* The recommended pattern is:
|
||||||
|
*
|
||||||
|
* T value; // where T is the type
|
||||||
|
* auto error = result.get(value);
|
||||||
|
* if (error) {
|
||||||
|
* // handle error
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* Or you may call 'value()' which will raise an exception
|
||||||
|
* in case of error:
|
||||||
|
*
|
||||||
|
* T value = result.value();
|
||||||
*/
|
*/
|
||||||
simdjson_inline const T& value_unsafe() const& noexcept;
|
simdjson_inline const T& value_unsafe() const& noexcept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Take the result value (move it). This function is safe if and only
|
* Take the result value (move it). This function is safe if and only
|
||||||
* the error() method returns a value that evaluates to false.
|
* the error() method returns a value that evaluates to false.
|
||||||
|
* We discourage the use of value_unsafe().
|
||||||
|
*
|
||||||
|
* The recommended pattern is:
|
||||||
|
*
|
||||||
|
* T value; // where T is the type
|
||||||
|
* auto error = result.get(value);
|
||||||
|
* if (error) {
|
||||||
|
* // handle error, return, exit, abort
|
||||||
|
* } else {
|
||||||
|
* // use value here.
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* Or you may call 'value()' which will raise an exception
|
||||||
|
* in case of error:
|
||||||
|
*
|
||||||
|
* T value = result.value();
|
||||||
*/
|
*/
|
||||||
simdjson_inline T&& value_unsafe() && noexcept;
|
simdjson_inline T&& value_unsafe() && noexcept;
|
||||||
|
|
||||||
@@ -223,6 +276,7 @@ struct simdjson_result_base : protected std::pair<T, error_code> {
|
|||||||
*/
|
*/
|
||||||
template<typename T>
|
template<typename T>
|
||||||
struct simdjson_result : public internal::simdjson_result_base<T> {
|
struct simdjson_result : public internal::simdjson_result_base<T> {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @private Create a new empty result with error = UNINITIALIZED.
|
* @private Create a new empty result with error = UNINITIALIZED.
|
||||||
*/
|
*/
|
||||||
@@ -254,24 +308,33 @@ struct simdjson_result : public internal::simdjson_result_base<T> {
|
|||||||
* @param value The variable to assign the value to. May not be set if there is an error.
|
* @param value The variable to assign the value to. May not be set if there is an error.
|
||||||
*/
|
*/
|
||||||
simdjson_warn_unused simdjson_inline error_code get(T &value) && noexcept;
|
simdjson_warn_unused simdjson_inline error_code get(T &value) && noexcept;
|
||||||
//
|
|
||||||
/**
|
/**
|
||||||
* Copy the value to a provided std::string, only enabled for std::string_view.
|
* Copy the value to a provided std::string, only enabled for std::string_view.
|
||||||
*
|
*
|
||||||
* @param value The variable to assign the value to. May not be set if there is an error.
|
* @param value The variable to assign the value to. May not be set if there is an error.
|
||||||
*/
|
*/
|
||||||
simdjson_warn_unused simdjson_inline error_code get(std::string &value) && noexcept
|
template <typename U = T>
|
||||||
#if SIMDJSON_SUPPORTS_DESERIALIZATION
|
simdjson_warn_unused simdjson_inline error_code get(std::string &value) && noexcept {
|
||||||
requires (!std::is_same_v<T, std::string>)
|
static_assert(std::is_same<U, std::string_view>::value, "SFINAE");
|
||||||
#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
|
std::string_view v;
|
||||||
;
|
error_code error = std::forward<simdjson_result<T>>(*this).get(v);
|
||||||
|
if (!error) {
|
||||||
|
value.assign(v.data(), v.size());
|
||||||
|
}
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The error.
|
* The error.
|
||||||
*/
|
*/
|
||||||
simdjson_inline error_code error() const noexcept;
|
simdjson_inline error_code error() const noexcept;
|
||||||
|
|
||||||
#if SIMDJSON_EXCEPTIONS
|
|
||||||
|
|
||||||
|
|
||||||
|
#if SIMDJSON_EXCEPTIONS
|
||||||
|
using internal::simdjson_result_base<T>::operator*;
|
||||||
|
using internal::simdjson_result_base<T>::operator->;
|
||||||
/**
|
/**
|
||||||
* Get the result value.
|
* Get the result value.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -33,8 +33,37 @@ simdjson_inline error_code implementation_simdjson_result_base<T>::error() const
|
|||||||
return this->second;
|
return this->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
simdjson_inline bool implementation_simdjson_result_base<T>::has_value() const noexcept {
|
||||||
|
return this->error() == SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
#if SIMDJSON_EXCEPTIONS
|
#if SIMDJSON_EXCEPTIONS
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
simdjson_inline T& implementation_simdjson_result_base<T>::operator*() & noexcept(false) {
|
||||||
|
return this->value();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
simdjson_inline T&& implementation_simdjson_result_base<T>::operator*() && noexcept(false) {
|
||||||
|
return std::forward<implementation_simdjson_result_base<T>>(*this).value();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
simdjson_inline T* implementation_simdjson_result_base<T>::operator->() noexcept(false) {
|
||||||
|
if (this->error()) { throw simdjson_error(this->error()); }
|
||||||
|
return &this->first;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
simdjson_inline const T* implementation_simdjson_result_base<T>::operator->() const noexcept(false) {
|
||||||
|
if (this->error()) { throw simdjson_error(this->error()); }
|
||||||
|
return &this->first;
|
||||||
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
simdjson_inline T& implementation_simdjson_result_base<T>::value() & noexcept(false) {
|
simdjson_inline T& implementation_simdjson_result_base<T>::value() & noexcept(false) {
|
||||||
if (error()) { throw simdjson_error(error()); }
|
if (error()) { throw simdjson_error(error()); }
|
||||||
|
|||||||
@@ -74,6 +74,11 @@ struct implementation_simdjson_result_base {
|
|||||||
*/
|
*/
|
||||||
simdjson_inline error_code error() const noexcept;
|
simdjson_inline error_code error() const noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether there is a value.
|
||||||
|
*/
|
||||||
|
simdjson_inline bool has_value() const noexcept;
|
||||||
|
|
||||||
#if SIMDJSON_EXCEPTIONS
|
#if SIMDJSON_EXCEPTIONS
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -81,6 +86,16 @@ struct implementation_simdjson_result_base {
|
|||||||
*
|
*
|
||||||
* @throw simdjson_error if there was an error.
|
* @throw simdjson_error if there was an error.
|
||||||
*/
|
*/
|
||||||
|
simdjson_inline T& operator*() & noexcept(false);
|
||||||
|
simdjson_inline T&& operator*() && noexcept(false);
|
||||||
|
/**
|
||||||
|
* Arrow operator to access members of the contained value.
|
||||||
|
*
|
||||||
|
* @throw simdjson_error if there was an error.
|
||||||
|
*/
|
||||||
|
simdjson_inline T* operator->() noexcept(false);
|
||||||
|
simdjson_inline const T* operator->() const noexcept(false);
|
||||||
|
|
||||||
simdjson_inline T& value() & noexcept(false);
|
simdjson_inline T& value() & noexcept(false);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -122,6 +137,7 @@ struct implementation_simdjson_result_base {
|
|||||||
* the error() method returns a value that evaluates to false.
|
* the error() method returns a value that evaluates to false.
|
||||||
*/
|
*/
|
||||||
simdjson_inline T&& value_unsafe() && noexcept;
|
simdjson_inline T&& value_unsafe() && noexcept;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/** users should never directly access first and second. **/
|
/** users should never directly access first and second. **/
|
||||||
T first{}; /** Users should never directly access 'first'. **/
|
T first{}; /** Users should never directly access 'first'. **/
|
||||||
|
|||||||
@@ -132,7 +132,7 @@ public:
|
|||||||
*/
|
*/
|
||||||
simdjson_inline simdjson_result<value> at(size_t index) noexcept;
|
simdjson_inline simdjson_result<value> at(size_t index) noexcept;
|
||||||
|
|
||||||
#if SIMDJSON_SUPPORTS_DESERIALIZATION
|
#if SIMDJSON_SUPPORTS_CONCEPTS
|
||||||
/**
|
/**
|
||||||
* Get this array as the given type.
|
* Get this array as the given type.
|
||||||
*
|
*
|
||||||
@@ -161,7 +161,7 @@ public:
|
|||||||
SIMDJSON_TRY(get<T>(out));
|
SIMDJSON_TRY(get<T>(out));
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
|
#endif // SIMDJSON_SUPPORTS_CONCEPTS
|
||||||
protected:
|
protected:
|
||||||
/**
|
/**
|
||||||
* Go to the end of the array, no matter where you are right now.
|
* Go to the end of the array, no matter where you are right now.
|
||||||
@@ -240,7 +240,7 @@ public:
|
|||||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> at_pointer(std::string_view json_pointer) noexcept;
|
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> at_pointer(std::string_view json_pointer) noexcept;
|
||||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> at_path(std::string_view json_path) noexcept;
|
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> at_path(std::string_view json_path) noexcept;
|
||||||
simdjson_inline simdjson_result<std::string_view> raw_json() noexcept;
|
simdjson_inline simdjson_result<std::string_view> raw_json() noexcept;
|
||||||
#if SIMDJSON_SUPPORTS_DESERIALIZATION
|
#if SIMDJSON_SUPPORTS_CONCEPTS
|
||||||
// TODO: move this code into object-inl.h
|
// TODO: move this code into object-inl.h
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
@@ -261,7 +261,7 @@ public:
|
|||||||
}
|
}
|
||||||
return SUCCESS;
|
return SUCCESS;
|
||||||
}
|
}
|
||||||
#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
|
#endif // SIMDJSON_SUPPORTS_CONCEPTS
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace simdjson
|
} // namespace simdjson
|
||||||
|
|||||||
@@ -36,6 +36,9 @@ simdjson_inline array_iterator &array_iterator::operator++() noexcept {
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
simdjson_inline bool array_iterator::at_end() const noexcept {
|
||||||
|
return iter.at_end();
|
||||||
|
}
|
||||||
} // namespace ondemand
|
} // namespace ondemand
|
||||||
} // namespace SIMDJSON_IMPLEMENTATION
|
} // namespace SIMDJSON_IMPLEMENTATION
|
||||||
} // namespace simdjson
|
} // namespace simdjson
|
||||||
@@ -72,7 +75,9 @@ simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array_iterato
|
|||||||
++(first);
|
++(first);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
simdjson_inline bool simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array_iterator>::at_end() const noexcept {
|
||||||
|
return !first.iter.is_valid() || first.at_end();
|
||||||
|
}
|
||||||
} // namespace simdjson
|
} // namespace simdjson
|
||||||
|
|
||||||
#endif // SIMDJSON_GENERIC_ONDEMAND_ARRAY_ITERATOR_INL_H
|
#endif // SIMDJSON_GENERIC_ONDEMAND_ARRAY_ITERATOR_INL_H
|
||||||
@@ -34,7 +34,8 @@ public:
|
|||||||
*
|
*
|
||||||
* Part of the std::iterator interface.
|
* Part of the std::iterator interface.
|
||||||
*/
|
*/
|
||||||
simdjson_inline simdjson_result<value> operator*() noexcept; // MUST ONLY BE CALLED ONCE PER ITERATION.
|
simdjson_inline simdjson_result<value>
|
||||||
|
operator*() noexcept; // MUST ONLY BE CALLED ONCE PER ITERATION.
|
||||||
/**
|
/**
|
||||||
* Check if we are at the end of the JSON.
|
* Check if we are at the end of the JSON.
|
||||||
*
|
*
|
||||||
@@ -58,6 +59,11 @@ public:
|
|||||||
*/
|
*/
|
||||||
simdjson_inline array_iterator &operator++() noexcept;
|
simdjson_inline array_iterator &operator++() noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the array is at the end.
|
||||||
|
*/
|
||||||
|
simdjson_warn_unused simdjson_inline bool at_end() const noexcept;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
value_iterator iter{};
|
value_iterator iter{};
|
||||||
|
|
||||||
@@ -76,7 +82,6 @@ namespace simdjson {
|
|||||||
|
|
||||||
template<>
|
template<>
|
||||||
struct simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array_iterator> : public SIMDJSON_IMPLEMENTATION::implementation_simdjson_result_base<SIMDJSON_IMPLEMENTATION::ondemand::array_iterator> {
|
struct simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array_iterator> : public SIMDJSON_IMPLEMENTATION::implementation_simdjson_result_base<SIMDJSON_IMPLEMENTATION::ondemand::array_iterator> {
|
||||||
public:
|
|
||||||
simdjson_inline simdjson_result(SIMDJSON_IMPLEMENTATION::ondemand::array_iterator &&value) noexcept; ///< @private
|
simdjson_inline simdjson_result(SIMDJSON_IMPLEMENTATION::ondemand::array_iterator &&value) noexcept; ///< @private
|
||||||
simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
|
simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
|
||||||
simdjson_inline simdjson_result() noexcept = default;
|
simdjson_inline simdjson_result() noexcept = default;
|
||||||
@@ -89,6 +94,8 @@ public:
|
|||||||
simdjson_inline bool operator==(const simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array_iterator> &) const noexcept;
|
simdjson_inline bool operator==(const simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array_iterator> &) const noexcept;
|
||||||
simdjson_inline bool operator!=(const simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array_iterator> &) const noexcept;
|
simdjson_inline bool operator!=(const simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array_iterator> &) const noexcept;
|
||||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array_iterator> &operator++() noexcept;
|
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array_iterator> &operator++() noexcept;
|
||||||
|
|
||||||
|
simdjson_warn_unused simdjson_inline bool at_end() const noexcept;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace simdjson
|
} // namespace simdjson
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
#if SIMDJSON_SUPPORTS_DESERIALIZATION
|
#if SIMDJSON_SUPPORTS_CONCEPTS
|
||||||
|
|
||||||
#ifndef SIMDJSON_ONDEMAND_DESERIALIZE_H
|
#ifndef SIMDJSON_ONDEMAND_DESERIALIZE_H
|
||||||
#ifndef SIMDJSON_CONDITIONAL_INCLUDE
|
#ifndef SIMDJSON_CONDITIONAL_INCLUDE
|
||||||
@@ -97,35 +97,35 @@ inline constexpr struct deserialize_tag {
|
|||||||
// Customization Point for array
|
// Customization Point for array
|
||||||
template <typename T>
|
template <typename T>
|
||||||
requires custom_deserializable<T, value_type>
|
requires custom_deserializable<T, value_type>
|
||||||
[[nodiscard]] constexpr /* error_code */ auto operator()(array_type &object, T& output) const noexcept(nothrow_custom_deserializable<T, value_type>) {
|
simdjson_warn_unused constexpr /* error_code */ auto operator()(array_type &object, T& output) const noexcept(nothrow_custom_deserializable<T, value_type>) {
|
||||||
return tag_invoke(*this, object, output);
|
return tag_invoke(*this, object, output);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Customization Point for object
|
// Customization Point for object
|
||||||
template <typename T>
|
template <typename T>
|
||||||
requires custom_deserializable<T, value_type>
|
requires custom_deserializable<T, value_type>
|
||||||
[[nodiscard]] constexpr /* error_code */ auto operator()(object_type &object, T& output) const noexcept(nothrow_custom_deserializable<T, value_type>) {
|
simdjson_warn_unused constexpr /* error_code */ auto operator()(object_type &object, T& output) const noexcept(nothrow_custom_deserializable<T, value_type>) {
|
||||||
return tag_invoke(*this, object, output);
|
return tag_invoke(*this, object, output);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Customization Point for value
|
// Customization Point for value
|
||||||
template <typename T>
|
template <typename T>
|
||||||
requires custom_deserializable<T, value_type>
|
requires custom_deserializable<T, value_type>
|
||||||
[[nodiscard]] constexpr /* error_code */ auto operator()(value_type &object, T& output) const noexcept(nothrow_custom_deserializable<T, value_type>) {
|
simdjson_warn_unused constexpr /* error_code */ auto operator()(value_type &object, T& output) const noexcept(nothrow_custom_deserializable<T, value_type>) {
|
||||||
return tag_invoke(*this, object, output);
|
return tag_invoke(*this, object, output);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Customization Point for document
|
// Customization Point for document
|
||||||
template <typename T>
|
template <typename T>
|
||||||
requires custom_deserializable<T, document_type>
|
requires custom_deserializable<T, document_type>
|
||||||
[[nodiscard]] constexpr /* error_code */ auto operator()(document_type &object, T& output) const noexcept(nothrow_custom_deserializable<T, document_type>) {
|
simdjson_warn_unused constexpr /* error_code */ auto operator()(document_type &object, T& output) const noexcept(nothrow_custom_deserializable<T, document_type>) {
|
||||||
return tag_invoke(*this, object, output);
|
return tag_invoke(*this, object, output);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Customization Point for document reference
|
// Customization Point for document reference
|
||||||
template <typename T>
|
template <typename T>
|
||||||
requires custom_deserializable<T, document_reference_type>
|
requires custom_deserializable<T, document_reference_type>
|
||||||
[[nodiscard]] constexpr /* error_code */ auto operator()(document_reference_type &object, T& output) const noexcept(nothrow_custom_deserializable<T, document_reference_type>) {
|
simdjson_warn_unused constexpr /* error_code */ auto operator()(document_reference_type &object, T& output) const noexcept(nothrow_custom_deserializable<T, document_reference_type>) {
|
||||||
return tag_invoke(*this, object, output);
|
return tag_invoke(*this, object, output);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -135,5 +135,5 @@ inline constexpr struct deserialize_tag {
|
|||||||
} // namespace simdjson
|
} // namespace simdjson
|
||||||
|
|
||||||
#endif // SIMDJSON_ONDEMAND_DESERIALIZE_H
|
#endif // SIMDJSON_ONDEMAND_DESERIALIZE_H
|
||||||
#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
|
#endif // SIMDJSON_SUPPORTS_CONCEPTS
|
||||||
|
|
||||||
|
|||||||
@@ -183,7 +183,7 @@ public:
|
|||||||
*/
|
*/
|
||||||
template <typename T>
|
template <typename T>
|
||||||
simdjson_inline simdjson_result<T> get() &
|
simdjson_inline simdjson_result<T> get() &
|
||||||
#if SIMDJSON_SUPPORTS_DESERIALIZATION
|
#if SIMDJSON_SUPPORTS_CONCEPTS
|
||||||
noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document> : true)
|
noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document> : true)
|
||||||
#else
|
#else
|
||||||
noexcept
|
noexcept
|
||||||
@@ -206,7 +206,7 @@ public:
|
|||||||
*/
|
*/
|
||||||
template<typename T>
|
template<typename T>
|
||||||
simdjson_inline simdjson_result<T> get() &&
|
simdjson_inline simdjson_result<T> get() &&
|
||||||
#if SIMDJSON_SUPPORTS_DESERIALIZATION
|
#if SIMDJSON_SUPPORTS_CONCEPTS
|
||||||
noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document> : true)
|
noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document> : true)
|
||||||
#else
|
#else
|
||||||
noexcept
|
noexcept
|
||||||
@@ -229,13 +229,13 @@ public:
|
|||||||
*/
|
*/
|
||||||
template<typename T>
|
template<typename T>
|
||||||
simdjson_inline error_code get(T &out) &
|
simdjson_inline error_code get(T &out) &
|
||||||
#if SIMDJSON_SUPPORTS_DESERIALIZATION
|
#if SIMDJSON_SUPPORTS_CONCEPTS
|
||||||
noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document> : true)
|
noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document> : true)
|
||||||
#else
|
#else
|
||||||
noexcept
|
noexcept
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
#if SIMDJSON_SUPPORTS_DESERIALIZATION
|
#if SIMDJSON_SUPPORTS_CONCEPTS
|
||||||
if constexpr (custom_deserializable<T, document>) {
|
if constexpr (custom_deserializable<T, document>) {
|
||||||
return deserialize(*this, out);
|
return deserialize(*this, out);
|
||||||
} else {
|
} else {
|
||||||
@@ -247,7 +247,7 @@ public:
|
|||||||
static_cast<void>(out); // to get rid of unused errors
|
static_cast<void>(out); // to get rid of unused errors
|
||||||
return UNINITIALIZED;
|
return UNINITIALIZED;
|
||||||
}
|
}
|
||||||
#else // SIMDJSON_SUPPORTS_DESERIALIZATION
|
#else // SIMDJSON_SUPPORTS_CONCEPTS
|
||||||
// Unless the simdjson library or the user provides an inline implementation, calling this method should
|
// Unless the simdjson library or the user provides an inline implementation, calling this method should
|
||||||
// immediately fail.
|
// immediately fail.
|
||||||
static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. "
|
static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. "
|
||||||
@@ -257,7 +257,7 @@ public:
|
|||||||
" You may also add support for custom types, see our documentation.");
|
" You may also add support for custom types, see our documentation.");
|
||||||
static_cast<void>(out); // to get rid of unused errors
|
static_cast<void>(out); // to get rid of unused errors
|
||||||
return UNINITIALIZED;
|
return UNINITIALIZED;
|
||||||
#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
|
#endif // SIMDJSON_SUPPORTS_CONCEPTS
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @overload template<typename T> error_code get(T &out) & noexcept */
|
/** @overload template<typename T> error_code get(T &out) & noexcept */
|
||||||
@@ -481,11 +481,27 @@ public:
|
|||||||
* E.g., you must still call "is_null()" to check that a value is null even if
|
* E.g., you must still call "is_null()" to check that a value is null even if
|
||||||
* "type()" returns json_type::null.
|
* "type()" returns json_type::null.
|
||||||
*
|
*
|
||||||
|
* The answer can be one of
|
||||||
|
* simdjson::ondemand::json_type::object,
|
||||||
|
* simdjson::ondemand::json_type::array,
|
||||||
|
* simdjson::ondemand::json_type::string,
|
||||||
|
* simdjson::ondemand::json_type::number,
|
||||||
|
* simdjson::ondemand::json_type::boolean,
|
||||||
|
* simdjson::ondemand::json_type::null.
|
||||||
|
*
|
||||||
|
* Starting with simdjson 4.0, this function will return simdjson::ondemand::json_type::unknown
|
||||||
|
* given a bad token.
|
||||||
|
* This allows you to identify a case such as {"key": NaN} and identify the NaN value.
|
||||||
|
* The simdjson::ondemand::json_type::unknown value should only happen with non-valid JSON.
|
||||||
|
*
|
||||||
* NOTE: If you're only expecting a value to be one type (a typical case), it's generally
|
* NOTE: If you're only expecting a value to be one type (a typical case), it's generally
|
||||||
* better to just call .get_double, .get_string, etc. and check for INCORRECT_TYPE (or just
|
* better to just call .get_double, .get_string, etc. and check for INCORRECT_TYPE (or just
|
||||||
* let it throw an exception).
|
* let it throw an exception).
|
||||||
*
|
*
|
||||||
* @error TAPE_ERROR when the JSON value is a bad token like "}" "," or "alse".
|
* Prior to simdjson 4.0, this function would return an error given a bad token.
|
||||||
|
* Starting with simdjson 4.0, it will return simdjson::ondemand::json_type::unknown.
|
||||||
|
* This allows you to identify a case such as {"key": NaN} and identify the NaN value.
|
||||||
|
* The simdjson::ondemand::json_type::unknown value should only happen with non-valid JSON.
|
||||||
*/
|
*/
|
||||||
simdjson_inline simdjson_result<json_type> type() noexcept;
|
simdjson_inline simdjson_result<json_type> type() noexcept;
|
||||||
|
|
||||||
@@ -775,7 +791,7 @@ public:
|
|||||||
simdjson_inline simdjson_result<bool> is_null() noexcept;
|
simdjson_inline simdjson_result<bool> is_null() noexcept;
|
||||||
template <typename T>
|
template <typename T>
|
||||||
simdjson_inline simdjson_result<T> get() &
|
simdjson_inline simdjson_result<T> get() &
|
||||||
#if SIMDJSON_SUPPORTS_DESERIALIZATION
|
#if SIMDJSON_SUPPORTS_CONCEPTS
|
||||||
noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document> : true)
|
noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document> : true)
|
||||||
#else
|
#else
|
||||||
noexcept
|
noexcept
|
||||||
@@ -788,7 +804,7 @@ public:
|
|||||||
}
|
}
|
||||||
template<typename T>
|
template<typename T>
|
||||||
simdjson_inline simdjson_result<T> get() &&
|
simdjson_inline simdjson_result<T> get() &&
|
||||||
#if SIMDJSON_SUPPORTS_DESERIALIZATION
|
#if SIMDJSON_SUPPORTS_CONCEPTS
|
||||||
noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document> : true)
|
noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document> : true)
|
||||||
#else
|
#else
|
||||||
noexcept
|
noexcept
|
||||||
@@ -811,13 +827,13 @@ public:
|
|||||||
*/
|
*/
|
||||||
template<typename T>
|
template<typename T>
|
||||||
simdjson_inline error_code get(T &out) &
|
simdjson_inline error_code get(T &out) &
|
||||||
#if SIMDJSON_SUPPORTS_DESERIALIZATION
|
#if SIMDJSON_SUPPORTS_CONCEPTS
|
||||||
noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document_reference> : true)
|
noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document_reference> : true)
|
||||||
#else
|
#else
|
||||||
noexcept
|
noexcept
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
#if SIMDJSON_SUPPORTS_DESERIALIZATION
|
#if SIMDJSON_SUPPORTS_CONCEPTS
|
||||||
if constexpr (custom_deserializable<T, document_reference>) {
|
if constexpr (custom_deserializable<T, document_reference>) {
|
||||||
return deserialize(*this, out);
|
return deserialize(*this, out);
|
||||||
} else {
|
} else {
|
||||||
@@ -829,7 +845,7 @@ public:
|
|||||||
static_cast<void>(out); // to get rid of unused errors
|
static_cast<void>(out); // to get rid of unused errors
|
||||||
return UNINITIALIZED;
|
return UNINITIALIZED;
|
||||||
}
|
}
|
||||||
#else // SIMDJSON_SUPPORTS_DESERIALIZATION
|
#else // SIMDJSON_SUPPORTS_CONCEPTS
|
||||||
// Unless the simdjson library or the user provides an inline implementation, calling this method should
|
// Unless the simdjson library or the user provides an inline implementation, calling this method should
|
||||||
// immediately fail.
|
// immediately fail.
|
||||||
static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. "
|
static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. "
|
||||||
@@ -839,7 +855,7 @@ public:
|
|||||||
" You may also add support for custom types, see our documentation.");
|
" You may also add support for custom types, see our documentation.");
|
||||||
static_cast<void>(out); // to get rid of unused errors
|
static_cast<void>(out); // to get rid of unused errors
|
||||||
return UNINITIALIZED;
|
return UNINITIALIZED;
|
||||||
#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
|
#endif // SIMDJSON_SUPPORTS_CONCEPTS
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @overload template<typename T> error_code get(T &out) & noexcept */
|
/** @overload template<typename T> error_code get(T &out) & noexcept */
|
||||||
@@ -926,6 +942,9 @@ public:
|
|||||||
template<typename T> simdjson_inline error_code get(T &out) & noexcept;
|
template<typename T> simdjson_inline error_code get(T &out) & noexcept;
|
||||||
template<typename T> simdjson_inline error_code get(T &out) && noexcept;
|
template<typename T> simdjson_inline error_code get(T &out) && noexcept;
|
||||||
#if SIMDJSON_EXCEPTIONS
|
#if SIMDJSON_EXCEPTIONS
|
||||||
|
|
||||||
|
using SIMDJSON_IMPLEMENTATION::implementation_simdjson_result_base<SIMDJSON_IMPLEMENTATION::ondemand::document>::operator*;
|
||||||
|
using SIMDJSON_IMPLEMENTATION::implementation_simdjson_result_base<SIMDJSON_IMPLEMENTATION::ondemand::document>::operator->;
|
||||||
template <class T, typename std::enable_if<std::is_same<T, SIMDJSON_IMPLEMENTATION::ondemand::document>::value == false>::type>
|
template <class T, typename std::enable_if<std::is_same<T, SIMDJSON_IMPLEMENTATION::ondemand::document>::value == false>::type>
|
||||||
explicit simdjson_inline operator T() noexcept(false);
|
explicit simdjson_inline operator T() noexcept(false);
|
||||||
simdjson_inline operator SIMDJSON_IMPLEMENTATION::ondemand::array() & noexcept(false);
|
simdjson_inline operator SIMDJSON_IMPLEMENTATION::ondemand::array() & noexcept(false);
|
||||||
|
|||||||
@@ -182,10 +182,19 @@ simdjson_inline document_stream::iterator& document_stream::iterator::operator++
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
simdjson_inline bool document_stream::iterator::at_end() const noexcept {
|
||||||
|
return finished;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
simdjson_inline bool document_stream::iterator::operator!=(const document_stream::iterator &other) const noexcept {
|
simdjson_inline bool document_stream::iterator::operator!=(const document_stream::iterator &other) const noexcept {
|
||||||
return finished != other.finished;
|
return finished != other.finished;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
simdjson_inline bool document_stream::iterator::operator==(const document_stream::iterator &other) const noexcept {
|
||||||
|
return finished == other.finished;
|
||||||
|
}
|
||||||
|
|
||||||
simdjson_inline document_stream::iterator document_stream::begin() noexcept {
|
simdjson_inline document_stream::iterator document_stream::begin() noexcept {
|
||||||
start();
|
start();
|
||||||
// If there are no documents, we're finished.
|
// If there are no documents, we're finished.
|
||||||
|
|||||||
@@ -131,6 +131,7 @@ public:
|
|||||||
* Default constructor.
|
* Default constructor.
|
||||||
*/
|
*/
|
||||||
simdjson_inline iterator() noexcept;
|
simdjson_inline iterator() noexcept;
|
||||||
|
simdjson_inline iterator(const iterator &other) noexcept = default;
|
||||||
/**
|
/**
|
||||||
* Get the current document (or error).
|
* Get the current document (or error).
|
||||||
*/
|
*/
|
||||||
@@ -144,6 +145,7 @@ public:
|
|||||||
* @param other the end iterator to compare to.
|
* @param other the end iterator to compare to.
|
||||||
*/
|
*/
|
||||||
simdjson_inline bool operator!=(const iterator &other) const noexcept;
|
simdjson_inline bool operator!=(const iterator &other) const noexcept;
|
||||||
|
simdjson_inline bool operator==(const iterator &other) const noexcept;
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
*
|
*
|
||||||
@@ -187,6 +189,11 @@ public:
|
|||||||
*/
|
*/
|
||||||
inline error_code error() const noexcept;
|
inline error_code error() const noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether the iterator is at the end.
|
||||||
|
*/
|
||||||
|
inline bool at_end() const noexcept;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
simdjson_inline iterator(document_stream *s, bool finished) noexcept;
|
simdjson_inline iterator(document_stream *s, bool finished) noexcept;
|
||||||
/** The document_stream we're iterating through. */
|
/** The document_stream we're iterating through. */
|
||||||
@@ -198,6 +205,7 @@ public:
|
|||||||
friend class document_stream;
|
friend class document_stream;
|
||||||
friend class json_iterator;
|
friend class json_iterator;
|
||||||
};
|
};
|
||||||
|
using iterator = document_stream::iterator;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Start iterating the documents in the stream.
|
* Start iterating the documents in the stream.
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
|
|
||||||
#include <charconv>
|
#include <charconv>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <experimental/meta>
|
#include <meta>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
@@ -89,9 +89,6 @@ template<typename number_type,
|
|||||||
constexpr void atom(string_builder &b, const number_type t) {
|
constexpr void atom(string_builder &b, const number_type t) {
|
||||||
b.append(t);
|
b.append(t);
|
||||||
}
|
}
|
||||||
#if SIMDJSON_CONSTEVAL
|
|
||||||
consteval std::string consteval_to_quoted_escaped(std::string_view input);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
requires(std::is_class_v<T> && !container_but_not_string<T> &&
|
requires(std::is_class_v<T> && !container_but_not_string<T> &&
|
||||||
@@ -106,10 +103,10 @@ template <class T>
|
|||||||
constexpr void atom(string_builder &b, const T &t) {
|
constexpr void atom(string_builder &b, const T &t) {
|
||||||
int i = 0;
|
int i = 0;
|
||||||
b.append('{');
|
b.append('{');
|
||||||
[:expand(std::meta::nonstatic_data_members_of(^^T, std::meta::access_context::unchecked())):] >> [&]<auto dm>() {
|
template for (constexpr auto dm : std::define_static_array(std::meta::nonstatic_data_members_of(^^T, std::meta::access_context::unchecked()))) {
|
||||||
if (i != 0)
|
if (i != 0)
|
||||||
b.append(',');
|
b.append(',');
|
||||||
constexpr auto key = std::define_static_string(consteval_to_quoted_escaped(std::meta::identifier_of(dm)));
|
constexpr auto key = std::define_static_string(constevalutil::consteval_to_quoted_escaped(std::meta::identifier_of(dm)));
|
||||||
b.append_raw(key);
|
b.append_raw(key);
|
||||||
b.append(':');
|
b.append(':');
|
||||||
atom(b, t.[:dm:]);
|
atom(b, t.[:dm:]);
|
||||||
@@ -143,21 +140,16 @@ template <typename T>
|
|||||||
requires(std::is_enum_v<T>)
|
requires(std::is_enum_v<T>)
|
||||||
void atom(string_builder &b, const T &e) {
|
void atom(string_builder &b, const T &e) {
|
||||||
#if SIMDJSON_STATIC_REFLECTION
|
#if SIMDJSON_STATIC_REFLECTION
|
||||||
std::string_view result = "<unnamed>";
|
constexpr auto enumerators = std::define_static_array(std::meta::enumerators_of(^^T));
|
||||||
[:expand(std::meta::enumerators_of(^^T)):] >> [&]<auto enum_val>{
|
template for (constexpr auto enum_val : enumerators) {
|
||||||
|
constexpr auto enum_str = std::define_static_string(constevalutil::consteval_to_quoted_escaped(std::meta::identifier_of(enum_val)));
|
||||||
if (e == [:enum_val:]) {
|
if (e == [:enum_val:]) {
|
||||||
result = std::meta::identifier_of(enum_val);
|
b.append_raw(enum_str);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
// Fallback to integer if enum value not found
|
||||||
if (result != "<unnamed>") {
|
atom(b, static_cast<std::underlying_type_t<T>>(e));
|
||||||
b.append_raw("\"");
|
|
||||||
b.append_raw(result);
|
|
||||||
b.append_raw("\"");
|
|
||||||
} else {
|
|
||||||
// Fallback to integer if enum value not found
|
|
||||||
atom(b, static_cast<std::underlying_type_t<T>>(e));
|
|
||||||
}
|
|
||||||
#else
|
#else
|
||||||
// Fallback: serialize as integer if reflection not available
|
// Fallback: serialize as integer if reflection not available
|
||||||
atom(b, static_cast<std::underlying_type_t<T>>(e));
|
atom(b, static_cast<std::underlying_type_t<T>>(e));
|
||||||
@@ -241,10 +233,10 @@ template <class Z>
|
|||||||
void append(string_builder &b, const Z &z) {
|
void append(string_builder &b, const Z &z) {
|
||||||
int i = 0;
|
int i = 0;
|
||||||
b.append('{');
|
b.append('{');
|
||||||
[:expand(std::meta::nonstatic_data_members_of(^^Z, std::meta::access_context::unchecked())):] >> [&]<auto dm>() {
|
template for (constexpr auto dm : std::define_static_array(std::meta::nonstatic_data_members_of(^^Z, std::meta::access_context::unchecked()))) {
|
||||||
if (i != 0)
|
if (i != 0)
|
||||||
b.append(',');
|
b.append(',');
|
||||||
constexpr auto key = std::define_static_string(consteval_to_quoted_escaped(std::meta::identifier_of(dm)));
|
constexpr auto key = std::define_static_string(constevalutil::consteval_to_quoted_escaped(std::meta::identifier_of(dm)));
|
||||||
b.append_raw(key);
|
b.append_raw(key);
|
||||||
b.append(':');
|
b.append(':');
|
||||||
atom(b, z.[:dm:]);
|
atom(b, z.[:dm:]);
|
||||||
@@ -296,7 +288,13 @@ string_builder& operator<<(string_builder& b, const Z& z) {
|
|||||||
}
|
}
|
||||||
} // namespace builder
|
} // namespace builder
|
||||||
} // namespace SIMDJSON_IMPLEMENTATION
|
} // namespace SIMDJSON_IMPLEMENTATION
|
||||||
|
// Alias the function template to 'to' in the global namespace
|
||||||
|
template <class Z>
|
||||||
|
simdjson_result<std::string> to_json(const Z &z, size_t initial_capacity = 1024) {
|
||||||
|
return SIMDJSON_IMPLEMENTATION::builder::to_json_string(z, initial_capacity);
|
||||||
|
}
|
||||||
} // namespace simdjson
|
} // namespace simdjson
|
||||||
|
|
||||||
#endif // SIMDJSON_STATIC_REFLECTION
|
#endif // SIMDJSON_STATIC_REFLECTION
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -218,6 +218,8 @@ simdjson_inline void json_iterator::assert_valid_position(token_position positio
|
|||||||
#ifndef SIMDJSON_CLANG_VISUAL_STUDIO
|
#ifndef SIMDJSON_CLANG_VISUAL_STUDIO
|
||||||
SIMDJSON_ASSUME( position >= &parser->implementation->structural_indexes[0] );
|
SIMDJSON_ASSUME( position >= &parser->implementation->structural_indexes[0] );
|
||||||
SIMDJSON_ASSUME( position < &parser->implementation->structural_indexes[parser->implementation->n_structural_indexes] );
|
SIMDJSON_ASSUME( position < &parser->implementation->structural_indexes[parser->implementation->n_structural_indexes] );
|
||||||
|
#else
|
||||||
|
(void)position; // Suppress unused parameter warning
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -155,12 +155,17 @@ find_next_json_quotable_character(const std::string_view view,
|
|||||||
}
|
}
|
||||||
|
|
||||||
SIMDJSON_CONSTEXPR_LAMBDA static std::string_view control_chars[] = {
|
SIMDJSON_CONSTEXPR_LAMBDA static std::string_view control_chars[] = {
|
||||||
"\\x0000", "\\x0001", "\\x0002", "\\x0003", "\\x0004", "\\x0005", "\\x0006",
|
"\\u0000", "\\u0001", "\\u0002", "\\u0003", "\\u0004", "\\u0005", "\\u0006",
|
||||||
"\\x0007", "\\x0008", "\\t", "\\n", "\\x000b", "\\f", "\\r",
|
"\\u0007", "\\b", "\\t", "\\n", "\\u000b", "\\f", "\\r",
|
||||||
"\\x000e", "\\x000f", "\\x0010", "\\x0011", "\\x0012", "\\x0013", "\\x0014",
|
"\\u000e", "\\u000f", "\\u0010", "\\u0011", "\\u0012", "\\u0013", "\\u0014",
|
||||||
"\\x0015", "\\x0016", "\\x0017", "\\x0018", "\\x0019", "\\x001a", "\\x001b",
|
"\\u0015", "\\u0016", "\\u0017", "\\u0018", "\\u0019", "\\u001a", "\\u001b",
|
||||||
"\\x001c", "\\x001d", "\\x001e", "\\x001f"};
|
"\\u001c", "\\u001d", "\\u001e", "\\u001f"};
|
||||||
|
|
||||||
|
// All Unicode characters may be placed within the quotation marks, except for the
|
||||||
|
// characters that MUST be escaped: quotation mark, reverse solidus, and the control
|
||||||
|
// characters (U+0000 through U+001F).
|
||||||
|
// There are two-character sequence escape representations of some popular characters:
|
||||||
|
// \", \\, \b, \f, \n, \r, \t.
|
||||||
SIMDJSON_CONSTEXPR_LAMBDA void escape_json_char(char c, char *&out) {
|
SIMDJSON_CONSTEXPR_LAMBDA void escape_json_char(char c, char *&out) {
|
||||||
if (c == '"') {
|
if (c == '"') {
|
||||||
memcpy(out, "\\\"", 2);
|
memcpy(out, "\\\"", 2);
|
||||||
@@ -201,29 +206,6 @@ inline size_t write_string_escaped(const std::string_view input, char *out) {
|
|||||||
return out - initout;
|
return out - initout;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if SIMDJSON_CONSTEVAL
|
|
||||||
// unoptimized, meant for compile-time execution
|
|
||||||
consteval std::string consteval_to_quoted_escaped(std::string_view input) {
|
|
||||||
std::string out = "\"";
|
|
||||||
for (char c : input) {
|
|
||||||
if (json_quotable_character[uint8_t(c)]) {
|
|
||||||
if (c == '"') {
|
|
||||||
out.append("\\\"");
|
|
||||||
} else if (c == '\\') {
|
|
||||||
out.append("\\\\");
|
|
||||||
} else {
|
|
||||||
std::string_view v = control_chars[uint8_t(c)];
|
|
||||||
out.append(v);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
out.push_back(c);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
out.push_back('"');
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
#endif // SIMDJSON_CONSTEVAL
|
|
||||||
|
|
||||||
simdjson_inline string_builder::string_builder(size_t initial_capacity)
|
simdjson_inline string_builder::string_builder(size_t initial_capacity)
|
||||||
: buffer(new(std::nothrow) char[initial_capacity]), position(0),
|
: buffer(new(std::nothrow) char[initial_capacity]), position(0),
|
||||||
capacity(buffer.get() != nullptr ? initial_capacity : 0),
|
capacity(buffer.get() != nullptr ? initial_capacity : 0),
|
||||||
@@ -509,6 +491,70 @@ simdjson_inline void string_builder::append_raw(const char *str,
|
|||||||
position += len;
|
position += len;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#if SIMDJSON_SUPPORTS_CONCEPTS
|
||||||
|
// Support for optional types (std::optional, etc.)
|
||||||
|
template <concepts::optional_type T>
|
||||||
|
simdjson_inline void string_builder::append(const T &opt) {
|
||||||
|
if (opt) {
|
||||||
|
append(*opt);
|
||||||
|
} else {
|
||||||
|
append_null();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
template <typename T>
|
||||||
|
requires(std::is_convertible<T, std::string_view>::value ||
|
||||||
|
std::is_same<T, const char*>::value )
|
||||||
|
simdjson_inline void string_builder::append(const T &value) {
|
||||||
|
escape_and_append_with_quotes(value);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if SIMDJSON_SUPPORTS_RANGES && SIMDJSON_SUPPORTS_CONCEPTS
|
||||||
|
// Support for range-based appending (std::ranges::view, etc.)
|
||||||
|
template <std::ranges::range R>
|
||||||
|
requires (!std::is_convertible<R, std::string_view>::value)
|
||||||
|
simdjson_inline void string_builder::append(const R &range) noexcept {
|
||||||
|
auto it = std::ranges::begin(range);
|
||||||
|
auto end = std::ranges::end(range);
|
||||||
|
if constexpr (concepts::is_pair<typename R::value_type>) {
|
||||||
|
start_object();
|
||||||
|
|
||||||
|
if (it == end) {
|
||||||
|
end_object();
|
||||||
|
return; // Handle empty range
|
||||||
|
}
|
||||||
|
// Append first item without leading comma
|
||||||
|
append_key_value(it->first, it->second);
|
||||||
|
++it;
|
||||||
|
|
||||||
|
// Append remaining items with preceding commas
|
||||||
|
for (; it != end; ++it) {
|
||||||
|
append_comma();
|
||||||
|
append_key_value(it->first, it->second);
|
||||||
|
}
|
||||||
|
end_object();
|
||||||
|
} else {
|
||||||
|
start_array();
|
||||||
|
if (it == end) {
|
||||||
|
end_array();
|
||||||
|
return; // Handle empty range
|
||||||
|
}
|
||||||
|
|
||||||
|
// Append first item without leading comma
|
||||||
|
append(*it);
|
||||||
|
++it;
|
||||||
|
|
||||||
|
// Append remaining items with preceding commas
|
||||||
|
for (; it != end; ++it) {
|
||||||
|
append_comma();
|
||||||
|
append(*it);
|
||||||
|
}
|
||||||
|
end_array();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
#if SIMDJSON_EXCEPTIONS
|
#if SIMDJSON_EXCEPTIONS
|
||||||
simdjson_inline string_builder::operator std::string() const noexcept(false) {
|
simdjson_inline string_builder::operator std::string() const noexcept(false) {
|
||||||
@@ -584,13 +630,6 @@ simdjson_inline void string_builder::append_colon() noexcept {
|
|||||||
|
|
||||||
template<typename key_type, typename value_type>
|
template<typename key_type, typename value_type>
|
||||||
simdjson_inline void string_builder::append_key_value(key_type key, value_type value) noexcept {
|
simdjson_inline void string_builder::append_key_value(key_type key, value_type value) noexcept {
|
||||||
static_assert(
|
|
||||||
std::is_arithmetic<value_type>::value ||
|
|
||||||
std::is_same<value_type, char>::value ||
|
|
||||||
std::is_same<value_type, const char*>::value ||
|
|
||||||
std::is_convertible<value_type, std::string_view>::value ||
|
|
||||||
std::is_same<value_type, std::nullptr_t>::value,
|
|
||||||
"Unsupported value type");
|
|
||||||
static_assert(
|
static_assert(
|
||||||
std::is_same<key_type, const char*>::value ||
|
std::is_same<key_type, const char*>::value ||
|
||||||
std::is_convertible<key_type, std::string_view>::value,
|
std::is_convertible<key_type, std::string_view>::value,
|
||||||
|
|||||||
@@ -118,6 +118,23 @@ public:
|
|||||||
*/
|
*/
|
||||||
template<typename key_type, typename value_type>
|
template<typename key_type, typename value_type>
|
||||||
simdjson_inline void append_key_value(key_type key, value_type value) noexcept;
|
simdjson_inline void append_key_value(key_type key, value_type value) noexcept;
|
||||||
|
#if SIMDJSON_SUPPORTS_CONCEPTS
|
||||||
|
// Support for optional types (std::optional, etc.)
|
||||||
|
template <concepts::optional_type T>
|
||||||
|
simdjson_inline void append(const T &opt);
|
||||||
|
|
||||||
|
// Support for string-like types
|
||||||
|
template <typename T>
|
||||||
|
requires(std::is_convertible<T, std::string_view>::value ||
|
||||||
|
std::is_same<T, const char*>::value )
|
||||||
|
simdjson_inline void append(const T &value);
|
||||||
|
#endif
|
||||||
|
#if SIMDJSON_SUPPORTS_RANGES && SIMDJSON_SUPPORTS_CONCEPTS
|
||||||
|
// Support for range-based appending (std::ranges::view, etc.)
|
||||||
|
template <std::ranges::range R>
|
||||||
|
requires (!std::is_convertible<R, std::string_view>::value)
|
||||||
|
simdjson_inline void append(const R &range) noexcept;
|
||||||
|
#endif
|
||||||
/**
|
/**
|
||||||
* Append the std::string_view directly, without escaping.
|
* Append the std::string_view directly, without escaping.
|
||||||
* There is no UTF-8 validation.
|
* There is no UTF-8 validation.
|
||||||
@@ -210,6 +227,22 @@ private:
|
|||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#if !SIMDJSON_STATIC_REFLECTION
|
||||||
|
// fallback implementation until we have static reflection
|
||||||
|
template <class Z>
|
||||||
|
simdjson_result<std::string> to_json(const Z &z, size_t initial_capacity = 1024) {
|
||||||
|
simdjson::SIMDJSON_IMPLEMENTATION::builder::string_builder b(initial_capacity);
|
||||||
|
b.append(z);
|
||||||
|
std::string_view s;
|
||||||
|
auto e = b.view().get(s);
|
||||||
|
if(e) { return e; }
|
||||||
|
return std::string(s);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
} // namespace simdjson
|
} // namespace simdjson
|
||||||
|
|
||||||
#endif // SIMDJSON_GENERIC_STRING_BUILDER_H
|
#endif // SIMDJSON_GENERIC_STRING_BUILDER_H
|
||||||
@@ -15,6 +15,7 @@ namespace ondemand {
|
|||||||
* The type of a JSON value.
|
* The type of a JSON value.
|
||||||
*/
|
*/
|
||||||
enum class json_type {
|
enum class json_type {
|
||||||
|
unknown=0,
|
||||||
// Start at 1 to catch uninitialized / default values more easily
|
// Start at 1 to catch uninitialized / default values more easily
|
||||||
array=1, ///< A JSON array ( [ 1, 2, 3 ... ] )
|
array=1, ///< A JSON array ( [ 1, 2, 3 ... ] )
|
||||||
object, ///< A JSON object ( { "a": 1, "b" 2, ... } )
|
object, ///< A JSON object ( { "a": 1, "b" 2, ... } )
|
||||||
|
|||||||
@@ -202,7 +202,7 @@ public:
|
|||||||
*/
|
*/
|
||||||
simdjson_inline simdjson_result<std::string_view> raw_json() noexcept;
|
simdjson_inline simdjson_result<std::string_view> raw_json() noexcept;
|
||||||
|
|
||||||
#if SIMDJSON_SUPPORTS_DESERIALIZATION
|
#if SIMDJSON_SUPPORTS_CONCEPTS
|
||||||
/**
|
/**
|
||||||
* Get this object as the given type.
|
* Get this object as the given type.
|
||||||
*
|
*
|
||||||
@@ -231,7 +231,7 @@ public:
|
|||||||
SIMDJSON_TRY(get<T>(out));
|
SIMDJSON_TRY(get<T>(out));
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
|
#endif // SIMDJSON_SUPPORTS_CONCEPTS
|
||||||
protected:
|
protected:
|
||||||
/**
|
/**
|
||||||
* Go to the end of the object, no matter where you are right now.
|
* Go to the end of the object, no matter where you are right now.
|
||||||
@@ -279,7 +279,7 @@ public:
|
|||||||
inline simdjson_result<bool> is_empty() noexcept;
|
inline simdjson_result<bool> is_empty() noexcept;
|
||||||
inline simdjson_result<size_t> count_fields() & noexcept;
|
inline simdjson_result<size_t> count_fields() & noexcept;
|
||||||
inline simdjson_result<std::string_view> raw_json() noexcept;
|
inline simdjson_result<std::string_view> raw_json() noexcept;
|
||||||
#if SIMDJSON_SUPPORTS_DESERIALIZATION
|
#if SIMDJSON_SUPPORTS_CONCEPTS
|
||||||
// TODO: move this code into object-inl.h
|
// TODO: move this code into object-inl.h
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
@@ -300,7 +300,7 @@ public:
|
|||||||
}
|
}
|
||||||
return SUCCESS;
|
return SUCCESS;
|
||||||
}
|
}
|
||||||
#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
|
#endif // SIMDJSON_SUPPORTS_CONCEPTS
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace simdjson
|
} // namespace simdjson
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ simdjson_inline simdjson_warn_unused bool parser::string_buffer_overflow(const u
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(padded_string_view json) & noexcept {
|
simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(padded_string_view json) & noexcept {
|
||||||
if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
|
if (!json.has_sufficient_padding()) { return INSUFFICIENT_PADDING; }
|
||||||
|
|
||||||
json.remove_utf8_bom();
|
json.remove_utf8_bom();
|
||||||
|
|
||||||
@@ -65,7 +65,7 @@ simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(p
|
|||||||
|
|
||||||
#ifdef SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
|
#ifdef SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
|
||||||
simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate_allow_incomplete_json(padded_string_view json) & noexcept {
|
simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate_allow_incomplete_json(padded_string_view json) & noexcept {
|
||||||
if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
|
if (!json.has_sufficient_padding()) { return INSUFFICIENT_PADDING; }
|
||||||
|
|
||||||
json.remove_utf8_bom();
|
json.remove_utf8_bom();
|
||||||
|
|
||||||
@@ -97,10 +97,7 @@ simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(s
|
|||||||
}
|
}
|
||||||
|
|
||||||
simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(std::string &json) & noexcept {
|
simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(std::string &json) & noexcept {
|
||||||
if(json.capacity() - json.size() < SIMDJSON_PADDING) {
|
return iterate(pad_with_reserve(json));
|
||||||
json.reserve(json.size() + SIMDJSON_PADDING);
|
|
||||||
}
|
|
||||||
return iterate(padded_string_view(json));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const std::string &json) & noexcept {
|
simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const std::string &json) & noexcept {
|
||||||
@@ -122,7 +119,7 @@ simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(c
|
|||||||
}
|
}
|
||||||
|
|
||||||
simdjson_warn_unused simdjson_inline simdjson_result<json_iterator> parser::iterate_raw(padded_string_view json) & noexcept {
|
simdjson_warn_unused simdjson_inline simdjson_result<json_iterator> parser::iterate_raw(padded_string_view json) & noexcept {
|
||||||
if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
|
if (!json.has_sufficient_padding()) { return INSUFFICIENT_PADDING; }
|
||||||
|
|
||||||
json.remove_utf8_bom();
|
json.remove_utf8_bom();
|
||||||
|
|
||||||
@@ -137,6 +134,7 @@ simdjson_warn_unused simdjson_inline simdjson_result<json_iterator> parser::iter
|
|||||||
}
|
}
|
||||||
|
|
||||||
inline simdjson_result<document_stream> parser::iterate_many(const uint8_t *buf, size_t len, size_t batch_size, bool allow_comma_separated) noexcept {
|
inline simdjson_result<document_stream> parser::iterate_many(const uint8_t *buf, size_t len, size_t batch_size, bool allow_comma_separated) noexcept {
|
||||||
|
// Warning: no check is done on the buffer padding. We trust the user.
|
||||||
if(batch_size < MINIMAL_BATCH_SIZE) { batch_size = MINIMAL_BATCH_SIZE; }
|
if(batch_size < MINIMAL_BATCH_SIZE) { batch_size = MINIMAL_BATCH_SIZE; }
|
||||||
if((len >= 3) && (std::memcmp(buf, "\xEF\xBB\xBF", 3) == 0)) {
|
if((len >= 3) && (std::memcmp(buf, "\xEF\xBB\xBF", 3) == 0)) {
|
||||||
buf += 3;
|
buf += 3;
|
||||||
@@ -145,16 +143,24 @@ inline simdjson_result<document_stream> parser::iterate_many(const uint8_t *buf,
|
|||||||
if(allow_comma_separated && batch_size < len) { batch_size = len; }
|
if(allow_comma_separated && batch_size < len) { batch_size = len; }
|
||||||
return document_stream(*this, buf, len, batch_size, allow_comma_separated);
|
return document_stream(*this, buf, len, batch_size, allow_comma_separated);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline simdjson_result<document_stream> parser::iterate_many(const char *buf, size_t len, size_t batch_size, bool allow_comma_separated) noexcept {
|
inline simdjson_result<document_stream> parser::iterate_many(const char *buf, size_t len, size_t batch_size, bool allow_comma_separated) noexcept {
|
||||||
|
// Warning: no check is done on the buffer padding. We trust the user.
|
||||||
return iterate_many(reinterpret_cast<const uint8_t *>(buf), len, batch_size, allow_comma_separated);
|
return iterate_many(reinterpret_cast<const uint8_t *>(buf), len, batch_size, allow_comma_separated);
|
||||||
}
|
}
|
||||||
inline simdjson_result<document_stream> parser::iterate_many(const std::string &s, size_t batch_size, bool allow_comma_separated) noexcept {
|
inline simdjson_result<document_stream> parser::iterate_many(padded_string_view s, size_t batch_size, bool allow_comma_separated) noexcept {
|
||||||
|
if (!s.has_sufficient_padding()) { return INSUFFICIENT_PADDING; }
|
||||||
return iterate_many(s.data(), s.length(), batch_size, allow_comma_separated);
|
return iterate_many(s.data(), s.length(), batch_size, allow_comma_separated);
|
||||||
}
|
}
|
||||||
inline simdjson_result<document_stream> parser::iterate_many(const padded_string &s, size_t batch_size, bool allow_comma_separated) noexcept {
|
inline simdjson_result<document_stream> parser::iterate_many(const padded_string &s, size_t batch_size, bool allow_comma_separated) noexcept {
|
||||||
return iterate_many(s.data(), s.length(), batch_size, allow_comma_separated);
|
return iterate_many(padded_string_view(s), batch_size, allow_comma_separated);
|
||||||
|
}
|
||||||
|
inline simdjson_result<document_stream> parser::iterate_many(const std::string &s, size_t batch_size, bool allow_comma_separated) noexcept {
|
||||||
|
return iterate_many(padded_string_view(s), batch_size, allow_comma_separated);
|
||||||
|
}
|
||||||
|
inline simdjson_result<document_stream> parser::iterate_many(std::string &s, size_t batch_size, bool allow_comma_separated) noexcept {
|
||||||
|
return iterate_many(pad(s), batch_size, allow_comma_separated);
|
||||||
}
|
}
|
||||||
|
|
||||||
simdjson_pure simdjson_inline size_t parser::capacity() const noexcept {
|
simdjson_pure simdjson_inline size_t parser::capacity() const noexcept {
|
||||||
return _capacity;
|
return _capacity;
|
||||||
}
|
}
|
||||||
@@ -189,6 +195,34 @@ simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> parser::u
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
simdjson_inline simdjson_warn_unused ondemand::parser& parser::get_parser() {
|
||||||
|
return *parser::get_parser_instance();
|
||||||
|
}
|
||||||
|
|
||||||
|
simdjson_inline bool release_parser() {
|
||||||
|
auto &parser_instance = parser::get_threadlocal_parser_if_exists();
|
||||||
|
if (parser_instance) {
|
||||||
|
parser_instance.reset();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
simdjson_inline simdjson_warn_unused std::unique_ptr<ondemand::parser>& parser::get_parser_instance() {
|
||||||
|
std::unique_ptr<ondemand::parser>& parser_instance = get_threadlocal_parser_if_exists();
|
||||||
|
if (!parser_instance) {
|
||||||
|
parser_instance.reset(new ondemand::parser());
|
||||||
|
}
|
||||||
|
return parser_instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
simdjson_inline simdjson_warn_unused std::unique_ptr<ondemand::parser>& parser::get_threadlocal_parser_if_exists() {
|
||||||
|
// @the-moisrex points out that this could be implemented with std::optional (C++17).
|
||||||
|
thread_local std::unique_ptr<ondemand::parser> parser_instance = nullptr;
|
||||||
|
return parser_instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
} // namespace ondemand
|
} // namespace ondemand
|
||||||
} // namespace SIMDJSON_IMPLEMENTATION
|
} // namespace SIMDJSON_IMPLEMENTATION
|
||||||
} // namespace simdjson
|
} // namespace simdjson
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
#endif // SIMDJSON_CONDITIONAL_INCLUDE
|
#endif // SIMDJSON_CONDITIONAL_INCLUDE
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
namespace simdjson {
|
namespace simdjson {
|
||||||
namespace SIMDJSON_IMPLEMENTATION {
|
namespace SIMDJSON_IMPLEMENTATION {
|
||||||
@@ -125,7 +126,9 @@ public:
|
|||||||
simdjson_warn_unused simdjson_result<document> iterate(std::string_view json, size_t capacity) & noexcept;
|
simdjson_warn_unused simdjson_result<document> iterate(std::string_view json, size_t capacity) & noexcept;
|
||||||
/** @overload simdjson_result<document> iterate(padded_string_view json) & noexcept */
|
/** @overload simdjson_result<document> iterate(padded_string_view json) & noexcept */
|
||||||
simdjson_warn_unused simdjson_result<document> iterate(const std::string &json) & noexcept;
|
simdjson_warn_unused simdjson_result<document> iterate(const std::string &json) & noexcept;
|
||||||
/** @overload simdjson_result<document> iterate(padded_string_view json) & noexcept */
|
/** @overload simdjson_result<document> iterate(padded_string_view json) & noexcept
|
||||||
|
The string instance might be have its capacity extended. Note that this can still
|
||||||
|
result in AddressSanitizer: container-overflow in some cases. */
|
||||||
simdjson_warn_unused simdjson_result<document> iterate(std::string &json) & noexcept;
|
simdjson_warn_unused simdjson_result<document> iterate(std::string &json) & noexcept;
|
||||||
/** @overload simdjson_result<document> iterate(padded_string_view json) & noexcept */
|
/** @overload simdjson_result<document> iterate(padded_string_view json) & noexcept */
|
||||||
simdjson_warn_unused simdjson_result<document> iterate(const simdjson_result<padded_string> &json) & noexcept;
|
simdjson_warn_unused simdjson_result<document> iterate(const simdjson_result<padded_string> &json) & noexcept;
|
||||||
@@ -213,6 +216,11 @@ public:
|
|||||||
* Setting batch_size to excessively large or excessively small values may impact negatively the
|
* Setting batch_size to excessively large or excessively small values may impact negatively the
|
||||||
* performance.
|
* performance.
|
||||||
*
|
*
|
||||||
|
* ### Threads
|
||||||
|
*
|
||||||
|
* When compiled with SIMDJSON_THREADS_ENABLED, this method will use a single thread under the
|
||||||
|
* hood to do some lookahead.
|
||||||
|
*
|
||||||
* ### REQUIRED: Buffer Padding
|
* ### REQUIRED: Buffer Padding
|
||||||
*
|
*
|
||||||
* The buffer must have at least SIMDJSON_PADDING extra allocated bytes. It does not matter what
|
* The buffer must have at least SIMDJSON_PADDING extra allocated bytes. It does not matter what
|
||||||
@@ -220,10 +228,10 @@ public:
|
|||||||
* using a sanitizer that verifies that no uninitialized byte is read, then you should initialize the
|
* using a sanitizer that verifies that no uninitialized byte is read, then you should initialize the
|
||||||
* SIMDJSON_PADDING bytes to avoid runtime warnings.
|
* SIMDJSON_PADDING bytes to avoid runtime warnings.
|
||||||
*
|
*
|
||||||
* ### Threads
|
* This is checked automatically with all iterate_many function calls, except for the two
|
||||||
|
* that take pointers (const char* or const uint8_t*).
|
||||||
*
|
*
|
||||||
* When compiled with SIMDJSON_THREADS_ENABLED, this method will use a single thread under the
|
* ### Threads
|
||||||
* hood to do some lookahead.
|
|
||||||
*
|
*
|
||||||
* ### Parser Capacity
|
* ### Parser Capacity
|
||||||
*
|
*
|
||||||
@@ -249,14 +257,16 @@ public:
|
|||||||
*/
|
*/
|
||||||
inline simdjson_result<document_stream> iterate_many(const uint8_t *buf, size_t len, size_t batch_size = DEFAULT_BATCH_SIZE, bool allow_comma_separated = false) noexcept;
|
inline simdjson_result<document_stream> iterate_many(const uint8_t *buf, size_t len, size_t batch_size = DEFAULT_BATCH_SIZE, bool allow_comma_separated = false) noexcept;
|
||||||
/** @overload parse_many(const uint8_t *buf, size_t len, size_t batch_size) */
|
/** @overload parse_many(const uint8_t *buf, size_t len, size_t batch_size) */
|
||||||
|
inline simdjson_result<document_stream> iterate_many(padded_string_view json, size_t batch_size = DEFAULT_BATCH_SIZE, bool allow_comma_separated = false) noexcept;
|
||||||
|
/** @overload parse_many(const uint8_t *buf, size_t len, size_t batch_size) */
|
||||||
inline simdjson_result<document_stream> iterate_many(const char *buf, size_t len, size_t batch_size = DEFAULT_BATCH_SIZE, bool allow_comma_separated = false) noexcept;
|
inline simdjson_result<document_stream> iterate_many(const char *buf, size_t len, size_t batch_size = DEFAULT_BATCH_SIZE, bool allow_comma_separated = false) noexcept;
|
||||||
/** @overload parse_many(const uint8_t *buf, size_t len, size_t batch_size) */
|
/** @overload parse_many(const uint8_t *buf, size_t len, size_t batch_size) */
|
||||||
inline simdjson_result<document_stream> iterate_many(const std::string &s, size_t batch_size = DEFAULT_BATCH_SIZE, bool allow_comma_separated = false) noexcept;
|
inline simdjson_result<document_stream> iterate_many(const std::string &s, size_t batch_size = DEFAULT_BATCH_SIZE, bool allow_comma_separated = false) noexcept;
|
||||||
inline simdjson_result<document_stream> iterate_many(const std::string &&s, size_t batch_size, bool allow_comma_separated = false) = delete;// unsafe
|
/** @overload parse_many(const uint8_t *buf, size_t len, size_t batch_size)
|
||||||
|
the string might be automatically padded with up to SIMDJSON_PADDING whitespace characters */
|
||||||
|
inline simdjson_result<document_stream> iterate_many(std::string &s, size_t batch_size = DEFAULT_BATCH_SIZE, bool allow_comma_separated = false) noexcept;
|
||||||
/** @overload parse_many(const uint8_t *buf, size_t len, size_t batch_size) */
|
/** @overload parse_many(const uint8_t *buf, size_t len, size_t batch_size) */
|
||||||
inline simdjson_result<document_stream> iterate_many(const padded_string &s, size_t batch_size = DEFAULT_BATCH_SIZE, bool allow_comma_separated = false) noexcept;
|
inline simdjson_result<document_stream> iterate_many(const padded_string &s, size_t batch_size = DEFAULT_BATCH_SIZE, bool allow_comma_separated = false) noexcept;
|
||||||
inline simdjson_result<document_stream> iterate_many(const padded_string &&s, size_t batch_size, bool allow_comma_separated = false) = delete;// unsafe
|
|
||||||
|
|
||||||
/** @private We do not want to allow implicit conversion from C string to std::string. */
|
/** @private We do not want to allow implicit conversion from C string to std::string. */
|
||||||
simdjson_result<document_stream> iterate_many(const char *buf, size_t batch_size = DEFAULT_BATCH_SIZE) noexcept = delete;
|
simdjson_result<document_stream> iterate_many(const char *buf, size_t batch_size = DEFAULT_BATCH_SIZE) noexcept = delete;
|
||||||
|
|
||||||
@@ -358,13 +368,39 @@ public:
|
|||||||
bool string_buffer_overflow(const uint8_t *string_buf_loc) const noexcept;
|
bool string_buffer_overflow(const uint8_t *string_buf_loc) const noexcept;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a unique parser instance corresponding to the current thread.
|
||||||
|
* This instance can be safely used within the current thread, but it should
|
||||||
|
* not be passed to other threads.
|
||||||
|
*
|
||||||
|
* A parser should only be used for one document at a time.
|
||||||
|
*
|
||||||
|
* Our simdjson::from functions use this parser instance.
|
||||||
|
*
|
||||||
|
* You can free the related parser by calling release_parser().
|
||||||
|
*/
|
||||||
|
static simdjson_inline simdjson_warn_unused ondemand::parser& get_parser();
|
||||||
|
/**
|
||||||
|
* Release the parser instance initialized by get_parser() and all the
|
||||||
|
* associated resources (memory). Returns true if a parser instance
|
||||||
|
* was released.
|
||||||
|
*/
|
||||||
|
static simdjson_inline bool release_parser();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
friend bool release_parser();
|
||||||
|
friend ondemand::parser& get_parser();
|
||||||
|
/** Get the thread-local parser instance, allocates it if needed */
|
||||||
|
static simdjson_inline simdjson_warn_unused std::unique_ptr<ondemand::parser>& get_parser_instance();
|
||||||
|
/** Get the thread-local parser instance, it might be null */
|
||||||
|
static simdjson_inline simdjson_warn_unused std::unique_ptr<ondemand::parser>& get_threadlocal_parser_if_exists();
|
||||||
/** @private [for benchmarking access] The implementation to use */
|
/** @private [for benchmarking access] The implementation to use */
|
||||||
std::unique_ptr<simdjson::internal::dom_parser_implementation> implementation{};
|
std::unique_ptr<simdjson::internal::dom_parser_implementation> implementation{};
|
||||||
size_t _capacity{0};
|
size_t _capacity{0};
|
||||||
size_t _max_capacity;
|
size_t _max_capacity;
|
||||||
size_t _max_depth{DEFAULT_MAX_DEPTH};
|
size_t _max_depth{DEFAULT_MAX_DEPTH};
|
||||||
std::unique_ptr<uint8_t[]> string_buf{};
|
std::unique_ptr<uint8_t[]> string_buf{};
|
||||||
|
|
||||||
#if SIMDJSON_DEVELOPMENT_CHECKS
|
#if SIMDJSON_DEVELOPMENT_CHECKS
|
||||||
std::unique_ptr<token_position[]> start_positions{};
|
std::unique_ptr<token_position[]> start_positions{};
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -15,8 +15,13 @@ namespace ondemand {
|
|||||||
|
|
||||||
simdjson_inline raw_json_string::raw_json_string(const uint8_t * _buf) noexcept : buf{_buf} {}
|
simdjson_inline raw_json_string::raw_json_string(const uint8_t * _buf) noexcept : buf{_buf} {}
|
||||||
|
|
||||||
simdjson_inline const char * raw_json_string::raw() const noexcept { return reinterpret_cast<const char *>(buf); }
|
simdjson_inline const char * raw_json_string::raw() const noexcept {
|
||||||
|
return reinterpret_cast<const char *>(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
simdjson_inline char raw_json_string::operator[](size_t i) const noexcept {
|
||||||
|
return reinterpret_cast<const char *>(buf)[i];
|
||||||
|
}
|
||||||
|
|
||||||
simdjson_inline bool raw_json_string::is_free_from_unescaped_quote(std::string_view target) noexcept {
|
simdjson_inline bool raw_json_string::is_free_from_unescaped_quote(std::string_view target) noexcept {
|
||||||
size_t pos{0};
|
size_t pos{0};
|
||||||
@@ -193,6 +198,10 @@ simdjson_inline simdjson_result<const char *> simdjson_result<SIMDJSON_IMPLEMENT
|
|||||||
if (error()) { return error(); }
|
if (error()) { return error(); }
|
||||||
return first.raw();
|
return first.raw();
|
||||||
}
|
}
|
||||||
|
simdjson_inline char simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::raw_json_string>::operator[](size_t i) const noexcept {
|
||||||
|
if (error()) { return error(); }
|
||||||
|
return first[i];
|
||||||
|
}
|
||||||
simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::raw_json_string>::unescape(SIMDJSON_IMPLEMENTATION::ondemand::json_iterator &iter, bool allow_replacement) const noexcept {
|
simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::raw_json_string>::unescape(SIMDJSON_IMPLEMENTATION::ondemand::json_iterator &iter, bool allow_replacement) const noexcept {
|
||||||
if (error()) { return error(); }
|
if (error()) { return error(); }
|
||||||
return first.unescape(iter, allow_replacement);
|
return first.unescape(iter, allow_replacement);
|
||||||
|
|||||||
@@ -58,6 +58,12 @@ public:
|
|||||||
*/
|
*/
|
||||||
simdjson_inline const char * raw() const noexcept;
|
simdjson_inline const char * raw() const noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the character at index i. This is unchecked.
|
||||||
|
* [0] when the string is of length 0 returns the final quote (").
|
||||||
|
*/
|
||||||
|
simdjson_inline char operator[](size_t i) const noexcept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This compares the current instance to the std::string_view target: returns true if
|
* This compares the current instance to the std::string_view target: returns true if
|
||||||
* they are byte-by-byte equal (no escaping is done) on target.size() characters,
|
* they are byte-by-byte equal (no escaping is done) on target.size() characters,
|
||||||
@@ -197,10 +203,10 @@ public:
|
|||||||
simdjson_inline ~simdjson_result() noexcept = default; ///< @private
|
simdjson_inline ~simdjson_result() noexcept = default; ///< @private
|
||||||
|
|
||||||
simdjson_inline simdjson_result<const char *> raw() const noexcept;
|
simdjson_inline simdjson_result<const char *> raw() const noexcept;
|
||||||
|
simdjson_inline char operator[](size_t) const noexcept;
|
||||||
simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> unescape(SIMDJSON_IMPLEMENTATION::ondemand::json_iterator &iter, bool allow_replacement) const noexcept;
|
simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> unescape(SIMDJSON_IMPLEMENTATION::ondemand::json_iterator &iter, bool allow_replacement) const noexcept;
|
||||||
simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> unescape_wobbly(SIMDJSON_IMPLEMENTATION::ondemand::json_iterator &iter) const noexcept;
|
simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> unescape_wobbly(SIMDJSON_IMPLEMENTATION::ondemand::json_iterator &iter) const noexcept;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace simdjson
|
} // namespace simdjson
|
||||||
|
|
||||||
#endif // SIMDJSON_GENERIC_ONDEMAND_RAW_JSON_STRING_H
|
#endif // SIMDJSON_GENERIC_ONDEMAND_RAW_JSON_STRING_H
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
#if SIMDJSON_SUPPORTS_DESERIALIZATION
|
#if SIMDJSON_SUPPORTS_CONCEPTS
|
||||||
|
|
||||||
#ifndef SIMDJSON_ONDEMAND_DESERIALIZE_H
|
#ifndef SIMDJSON_ONDEMAND_DESERIALIZE_H
|
||||||
#ifndef SIMDJSON_CONDITIONAL_INCLUDE
|
#ifndef SIMDJSON_CONDITIONAL_INCLUDE
|
||||||
@@ -11,7 +11,7 @@
|
|||||||
#include <concepts>
|
#include <concepts>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
#if SIMDJSON_STATIC_REFLECTION
|
#if SIMDJSON_STATIC_REFLECTION
|
||||||
#include <experimental/meta>
|
#include <meta>
|
||||||
// #include <static_reflection> // for std::define_static_string - header not available yet
|
// #include <static_reflection> // for std::define_static_string - header not available yet
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -97,13 +97,12 @@ template <concepts::appendable_containers T, typename ValT>
|
|||||||
requires(!require_custom_serialization<T>)
|
requires(!require_custom_serialization<T>)
|
||||||
error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(false) {
|
error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(false) {
|
||||||
using value_type = typename std::remove_cvref_t<T>::value_type;
|
using value_type = typename std::remove_cvref_t<T>::value_type;
|
||||||
/*static_assert(
|
static_assert(
|
||||||
deserializable<value_type, ValT>,
|
deserializable<value_type, ValT>,
|
||||||
"The specified type inside the container must itself be deserializable");*/
|
"The specified type inside the container must itself be deserializable");
|
||||||
static_assert(
|
static_assert(
|
||||||
std::is_default_constructible_v<value_type>,
|
std::is_default_constructible_v<value_type>,
|
||||||
"The specified type inside the container must default constructible.");
|
"The specified type inside the container must default constructible.");
|
||||||
|
|
||||||
SIMDJSON_IMPLEMENTATION::ondemand::array arr;
|
SIMDJSON_IMPLEMENTATION::ondemand::array arr;
|
||||||
if constexpr (std::is_same_v<std::remove_cvref_t<ValT>, SIMDJSON_IMPLEMENTATION::ondemand::array>) {
|
if constexpr (std::is_same_v<std::remove_cvref_t<ValT>, SIMDJSON_IMPLEMENTATION::ondemand::array>) {
|
||||||
arr = val;
|
arr = val;
|
||||||
@@ -254,7 +253,9 @@ error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept(nothrow_deser
|
|||||||
using value_type = typename std::remove_cvref_t<T>::value_type;
|
using value_type = typename std::remove_cvref_t<T>::value_type;
|
||||||
|
|
||||||
// Check if the value is null
|
// Check if the value is null
|
||||||
if (val.is_null()) {
|
bool is_null_value;
|
||||||
|
SIMDJSON_TRY( val.is_null().get(is_null_value) );
|
||||||
|
if (is_null_value) {
|
||||||
out.reset(); // Set to nullopt
|
out.reset(); // Set to nullopt
|
||||||
return SUCCESS;
|
return SUCCESS;
|
||||||
}
|
}
|
||||||
@@ -276,32 +277,6 @@ constexpr bool user_defined_type = (std::is_class_v<T>
|
|||||||
!concepts::appendable_containers<T> && !require_custom_serialization<T>);
|
!concepts::appendable_containers<T> && !require_custom_serialization<T>);
|
||||||
|
|
||||||
|
|
||||||
// workaround from
|
|
||||||
// https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/p2996r10.html#back-and-forth
|
|
||||||
// for missing expansion statements
|
|
||||||
namespace __impl {
|
|
||||||
template<auto... vals>
|
|
||||||
struct replicator_type {
|
|
||||||
template<typename F>
|
|
||||||
constexpr void operator>>(F body) const {
|
|
||||||
(body.template operator()<vals>(), ...);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template<auto... vals>
|
|
||||||
replicator_type<vals...> replicator = {};
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename R>
|
|
||||||
consteval auto expand(R range) {
|
|
||||||
std::vector<std::meta::info> args;
|
|
||||||
for (auto r : range) {
|
|
||||||
args.push_back(reflect_constant(r));
|
|
||||||
}
|
|
||||||
return substitute(^^__impl::replicator, args);
|
|
||||||
}
|
|
||||||
// end of workaround
|
|
||||||
|
|
||||||
template <typename T, typename ValT>
|
template <typename T, typename ValT>
|
||||||
requires(user_defined_type<T> && std::is_class_v<T>)
|
requires(user_defined_type<T> && std::is_class_v<T>)
|
||||||
error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept {
|
error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept {
|
||||||
@@ -312,9 +287,8 @@ error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept {
|
|||||||
SIMDJSON_TRY(val.get_object().get(obj));
|
SIMDJSON_TRY(val.get_object().get(obj));
|
||||||
}
|
}
|
||||||
error_code e = simdjson::SUCCESS;
|
error_code e = simdjson::SUCCESS;
|
||||||
|
template for (constexpr auto mem : std::define_static_array(std::meta::nonstatic_data_members_of(^^T, std::meta::access_context::unchecked()))) {
|
||||||
[:expand(std::meta::nonstatic_data_members_of(^^T, std::meta::access_context::unchecked())):] >> [&]<auto mem>() {
|
if constexpr (!std::meta::is_const(mem) && std::meta::is_public(mem)) {
|
||||||
if constexpr (!std::meta::is_const(mem) && std::meta::is_public(mem)) {
|
|
||||||
constexpr std::string_view key = std::define_static_string(std::meta::identifier_of(mem));
|
constexpr std::string_view key = std::define_static_string(std::meta::identifier_of(mem));
|
||||||
// Note: removed static assert as optional types are now handled generically
|
// Note: removed static assert as optional types are now handled generically
|
||||||
// as long we are succesful or the field is not found, we continue
|
// as long we are succesful or the field is not found, we continue
|
||||||
@@ -333,16 +307,15 @@ error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept {
|
|||||||
#if SIMDJSON_STATIC_REFLECTION
|
#if SIMDJSON_STATIC_REFLECTION
|
||||||
std::string_view str;
|
std::string_view str;
|
||||||
SIMDJSON_TRY(val.get_string().get(str));
|
SIMDJSON_TRY(val.get_string().get(str));
|
||||||
|
constexpr auto enumerators = std::define_static_array(std::meta::enumerators_of(^^T));
|
||||||
bool found = false;
|
template for (constexpr auto enum_val : enumerators) {
|
||||||
[:expand(std::meta::enumerators_of(^^T)):] >> [&]<auto enum_val>{
|
if (str == std::meta::identifier_of(enum_val)) {
|
||||||
if (!found && str == std::meta::identifier_of(enum_val)) {
|
|
||||||
out = [:enum_val:];
|
out = [:enum_val:];
|
||||||
found = true;
|
return SUCCESS;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return found ? SUCCESS : INCORRECT_TYPE;
|
return INCORRECT_TYPE;
|
||||||
#else
|
#else
|
||||||
// Fallback: deserialize as integer if reflection not available
|
// Fallback: deserialize as integer if reflection not available
|
||||||
std::underlying_type_t<T> int_val;
|
std::underlying_type_t<T> int_val;
|
||||||
@@ -390,7 +363,9 @@ error_code tag_invoke(deserialize_tag, simdjson_value &val, std::shared_ptr<T> &
|
|||||||
// Unique pointers
|
// Unique pointers
|
||||||
////////////////////////////////////////
|
////////////////////////////////////////
|
||||||
error_code tag_invoke(deserialize_tag, auto &val, std::unique_ptr<bool> &out) noexcept {
|
error_code tag_invoke(deserialize_tag, auto &val, std::unique_ptr<bool> &out) noexcept {
|
||||||
if (val.is_null()) {
|
bool is_null_value;
|
||||||
|
SIMDJSON_TRY( val.is_null().get(is_null_value) );
|
||||||
|
if (is_null_value) {
|
||||||
out.reset();
|
out.reset();
|
||||||
return SUCCESS;
|
return SUCCESS;
|
||||||
}
|
}
|
||||||
@@ -403,7 +378,9 @@ error_code tag_invoke(deserialize_tag, auto &val, std::unique_ptr<bool> &out) no
|
|||||||
}
|
}
|
||||||
|
|
||||||
error_code tag_invoke(deserialize_tag, auto &val, std::unique_ptr<int64_t> &out) noexcept {
|
error_code tag_invoke(deserialize_tag, auto &val, std::unique_ptr<int64_t> &out) noexcept {
|
||||||
if (val.is_null()) {
|
bool is_null_value;
|
||||||
|
SIMDJSON_TRY( val.is_null().get(is_null_value) );
|
||||||
|
if (is_null_value) {
|
||||||
out.reset();
|
out.reset();
|
||||||
return SUCCESS;
|
return SUCCESS;
|
||||||
}
|
}
|
||||||
@@ -416,7 +393,9 @@ error_code tag_invoke(deserialize_tag, auto &val, std::unique_ptr<int64_t> &out)
|
|||||||
}
|
}
|
||||||
|
|
||||||
error_code tag_invoke(deserialize_tag, auto &val, std::unique_ptr<uint64_t> &out) noexcept {
|
error_code tag_invoke(deserialize_tag, auto &val, std::unique_ptr<uint64_t> &out) noexcept {
|
||||||
if (val.is_null()) {
|
bool is_null_value;
|
||||||
|
SIMDJSON_TRY( val.is_null().get(is_null_value) );
|
||||||
|
if (is_null_value) {
|
||||||
out.reset();
|
out.reset();
|
||||||
return SUCCESS;
|
return SUCCESS;
|
||||||
}
|
}
|
||||||
@@ -429,7 +408,9 @@ error_code tag_invoke(deserialize_tag, auto &val, std::unique_ptr<uint64_t> &out
|
|||||||
}
|
}
|
||||||
|
|
||||||
error_code tag_invoke(deserialize_tag, auto &val, std::unique_ptr<double> &out) noexcept {
|
error_code tag_invoke(deserialize_tag, auto &val, std::unique_ptr<double> &out) noexcept {
|
||||||
if (val.is_null()) {
|
bool is_null_value;
|
||||||
|
SIMDJSON_TRY( val.is_null().get(is_null_value) );
|
||||||
|
if (is_null_value) {
|
||||||
out.reset();
|
out.reset();
|
||||||
return SUCCESS;
|
return SUCCESS;
|
||||||
}
|
}
|
||||||
@@ -442,7 +423,9 @@ error_code tag_invoke(deserialize_tag, auto &val, std::unique_ptr<double> &out)
|
|||||||
}
|
}
|
||||||
|
|
||||||
error_code tag_invoke(deserialize_tag, auto &val, std::unique_ptr<std::string_view> &out) noexcept {
|
error_code tag_invoke(deserialize_tag, auto &val, std::unique_ptr<std::string_view> &out) noexcept {
|
||||||
if (val.is_null()) {
|
bool is_null_value;
|
||||||
|
SIMDJSON_TRY( val.is_null().get(is_null_value) );
|
||||||
|
if (is_null_value) {
|
||||||
out.reset();
|
out.reset();
|
||||||
return SUCCESS;
|
return SUCCESS;
|
||||||
}
|
}
|
||||||
@@ -459,7 +442,9 @@ error_code tag_invoke(deserialize_tag, auto &val, std::unique_ptr<std::string_vi
|
|||||||
// Shared pointers
|
// Shared pointers
|
||||||
////////////////////////////////////////
|
////////////////////////////////////////
|
||||||
error_code tag_invoke(deserialize_tag, auto &val, std::shared_ptr<bool> &out) noexcept {
|
error_code tag_invoke(deserialize_tag, auto &val, std::shared_ptr<bool> &out) noexcept {
|
||||||
if (val.is_null()) {
|
bool is_null_value;
|
||||||
|
SIMDJSON_TRY( val.is_null().get(is_null_value) );
|
||||||
|
if (is_null_value) {
|
||||||
out.reset();
|
out.reset();
|
||||||
return SUCCESS;
|
return SUCCESS;
|
||||||
}
|
}
|
||||||
@@ -472,7 +457,9 @@ error_code tag_invoke(deserialize_tag, auto &val, std::shared_ptr<bool> &out) no
|
|||||||
}
|
}
|
||||||
|
|
||||||
error_code tag_invoke(deserialize_tag, auto &val, std::shared_ptr<int64_t> &out) noexcept {
|
error_code tag_invoke(deserialize_tag, auto &val, std::shared_ptr<int64_t> &out) noexcept {
|
||||||
if (val.is_null()) {
|
bool is_null_value;
|
||||||
|
SIMDJSON_TRY( val.is_null().get(is_null_value) );
|
||||||
|
if (is_null_value) {
|
||||||
out.reset();
|
out.reset();
|
||||||
return SUCCESS;
|
return SUCCESS;
|
||||||
}
|
}
|
||||||
@@ -485,7 +472,9 @@ error_code tag_invoke(deserialize_tag, auto &val, std::shared_ptr<int64_t> &out)
|
|||||||
}
|
}
|
||||||
|
|
||||||
error_code tag_invoke(deserialize_tag, auto &val, std::shared_ptr<uint64_t> &out) noexcept {
|
error_code tag_invoke(deserialize_tag, auto &val, std::shared_ptr<uint64_t> &out) noexcept {
|
||||||
if (val.is_null()) {
|
bool is_null_value;
|
||||||
|
SIMDJSON_TRY( val.is_null().get(is_null_value) );
|
||||||
|
if (is_null_value) {
|
||||||
out.reset();
|
out.reset();
|
||||||
return SUCCESS;
|
return SUCCESS;
|
||||||
}
|
}
|
||||||
@@ -498,7 +487,9 @@ error_code tag_invoke(deserialize_tag, auto &val, std::shared_ptr<uint64_t> &out
|
|||||||
}
|
}
|
||||||
|
|
||||||
error_code tag_invoke(deserialize_tag, auto &val, std::shared_ptr<double> &out) noexcept {
|
error_code tag_invoke(deserialize_tag, auto &val, std::shared_ptr<double> &out) noexcept {
|
||||||
if (val.is_null()) {
|
bool is_null_value;
|
||||||
|
SIMDJSON_TRY( val.is_null().get(is_null_value) );
|
||||||
|
if (is_null_value) {
|
||||||
out.reset();
|
out.reset();
|
||||||
return SUCCESS;
|
return SUCCESS;
|
||||||
}
|
}
|
||||||
@@ -511,7 +502,9 @@ error_code tag_invoke(deserialize_tag, auto &val, std::shared_ptr<double> &out)
|
|||||||
}
|
}
|
||||||
|
|
||||||
error_code tag_invoke(deserialize_tag, auto &val, std::shared_ptr<std::string_view> &out) noexcept {
|
error_code tag_invoke(deserialize_tag, auto &val, std::shared_ptr<std::string_view> &out) noexcept {
|
||||||
if (val.is_null()) {
|
bool is_null_value;
|
||||||
|
SIMDJSON_TRY( val.is_null().get(is_null_value) );
|
||||||
|
if (is_null_value) {
|
||||||
out.reset();
|
out.reset();
|
||||||
return SUCCESS;
|
return SUCCESS;
|
||||||
}
|
}
|
||||||
@@ -533,7 +526,9 @@ error_code tag_invoke(deserialize_tag, auto &val, std::shared_ptr<std::string_vi
|
|||||||
////////////////////////////////////////
|
////////////////////////////////////////
|
||||||
error_code tag_invoke(deserialize_tag, auto &val, std::unique_ptr<std::string> &out) noexcept {
|
error_code tag_invoke(deserialize_tag, auto &val, std::unique_ptr<std::string> &out) noexcept {
|
||||||
// Check if the value is null
|
// Check if the value is null
|
||||||
if (val.is_null()) {
|
bool is_null_value;
|
||||||
|
SIMDJSON_TRY( val.is_null().get(is_null_value) );
|
||||||
|
if (is_null_value) {
|
||||||
out.reset(); // Set to nullptr
|
out.reset(); // Set to nullptr
|
||||||
return SUCCESS;
|
return SUCCESS;
|
||||||
}
|
}
|
||||||
@@ -549,7 +544,9 @@ error_code tag_invoke(deserialize_tag, auto &val, std::unique_ptr<std::string> &
|
|||||||
|
|
||||||
error_code tag_invoke(deserialize_tag, auto &val, std::shared_ptr<std::string> &out) noexcept {
|
error_code tag_invoke(deserialize_tag, auto &val, std::shared_ptr<std::string> &out) noexcept {
|
||||||
// Check if the value is null
|
// Check if the value is null
|
||||||
if (val.is_null()) {
|
bool is_null_value;
|
||||||
|
SIMDJSON_TRY( val.is_null().get(is_null_value) );
|
||||||
|
if (is_null_value) {
|
||||||
out.reset(); // Set to nullptr
|
out.reset(); // Set to nullptr
|
||||||
return SUCCESS;
|
return SUCCESS;
|
||||||
}
|
}
|
||||||
@@ -565,7 +562,9 @@ error_code tag_invoke(deserialize_tag, auto &val, std::shared_ptr<std::string> &
|
|||||||
|
|
||||||
error_code tag_invoke(deserialize_tag, auto &val, std::unique_ptr<int> &out) noexcept {
|
error_code tag_invoke(deserialize_tag, auto &val, std::unique_ptr<int> &out) noexcept {
|
||||||
// Check if the value is null
|
// Check if the value is null
|
||||||
if (val.is_null()) {
|
bool is_null_value;
|
||||||
|
SIMDJSON_TRY( val.is_null().get(is_null_value) );
|
||||||
|
if (is_null_value) {
|
||||||
out.reset(); // Set to nullptr
|
out.reset(); // Set to nullptr
|
||||||
return SUCCESS;
|
return SUCCESS;
|
||||||
}
|
}
|
||||||
@@ -582,4 +581,4 @@ error_code tag_invoke(deserialize_tag, auto &val, std::unique_ptr<int> &out) noe
|
|||||||
} // namespace simdjson
|
} // namespace simdjson
|
||||||
|
|
||||||
#endif // SIMDJSON_ONDEMAND_DESERIALIZE_H
|
#endif // SIMDJSON_ONDEMAND_DESERIALIZE_H
|
||||||
#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
|
#endif // SIMDJSON_SUPPORTS_CONCEPTS
|
||||||
|
|||||||
@@ -34,14 +34,14 @@ public:
|
|||||||
*
|
*
|
||||||
* You may use get_double(), get_bool(), get_uint64(), get_int64(),
|
* You may use get_double(), get_bool(), get_uint64(), get_int64(),
|
||||||
* get_object(), get_array(), get_raw_json_string(), or get_string() instead.
|
* get_object(), get_array(), get_raw_json_string(), or get_string() instead.
|
||||||
* When SIMDJSON_SUPPORTS_DESERIALIZATION is set, custom types are also supported.
|
* When SIMDJSON_SUPPORTS_CONCEPTS is set, custom types are also supported.
|
||||||
*
|
*
|
||||||
* @returns A value of the given type, parsed from the JSON.
|
* @returns A value of the given type, parsed from the JSON.
|
||||||
* @returns INCORRECT_TYPE If the JSON value is not the given type.
|
* @returns INCORRECT_TYPE If the JSON value is not the given type.
|
||||||
*/
|
*/
|
||||||
template <typename T>
|
template <typename T>
|
||||||
simdjson_inline simdjson_result<T> get()
|
simdjson_inline simdjson_result<T> get()
|
||||||
#if SIMDJSON_SUPPORTS_DESERIALIZATION
|
#if SIMDJSON_SUPPORTS_CONCEPTS
|
||||||
noexcept(custom_deserializable<T, value> ? nothrow_custom_deserializable<T, value> : true)
|
noexcept(custom_deserializable<T, value> ? nothrow_custom_deserializable<T, value> : true)
|
||||||
#else
|
#else
|
||||||
noexcept
|
noexcept
|
||||||
@@ -58,7 +58,7 @@ public:
|
|||||||
* Get this value as the given type.
|
* Get this value as the given type.
|
||||||
*
|
*
|
||||||
* Supported types: object, array, raw_json_string, string_view, uint64_t, int64_t, double, bool
|
* Supported types: object, array, raw_json_string, string_view, uint64_t, int64_t, double, bool
|
||||||
* If the macro SIMDJSON_SUPPORTS_DESERIALIZATION is set, then custom types are also supported.
|
* If the macro SIMDJSON_SUPPORTS_CONCEPTS is set, then custom types are also supported.
|
||||||
*
|
*
|
||||||
* @param out This is set to a value of the given type, parsed from the JSON. If there is an error, this may not be initialized.
|
* @param out This is set to a value of the given type, parsed from the JSON. If there is an error, this may not be initialized.
|
||||||
* @returns INCORRECT_TYPE If the JSON value is not an object.
|
* @returns INCORRECT_TYPE If the JSON value is not an object.
|
||||||
@@ -66,20 +66,22 @@ public:
|
|||||||
*/
|
*/
|
||||||
template <typename T>
|
template <typename T>
|
||||||
simdjson_inline error_code get(T &out)
|
simdjson_inline error_code get(T &out)
|
||||||
#if SIMDJSON_SUPPORTS_DESERIALIZATION
|
#if SIMDJSON_SUPPORTS_CONCEPTS
|
||||||
noexcept(custom_deserializable<T, value> ? nothrow_custom_deserializable<T, value> : true)
|
noexcept(custom_deserializable<T, value> ? nothrow_custom_deserializable<T, value> : true)
|
||||||
#else
|
#else
|
||||||
noexcept
|
noexcept
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
#if SIMDJSON_SUPPORTS_DESERIALIZATION
|
#if SIMDJSON_SUPPORTS_CONCEPTS
|
||||||
if constexpr (custom_deserializable<T, value>) {
|
if constexpr (custom_deserializable<T, value>) {
|
||||||
return deserialize(*this, out);
|
return deserialize(*this, out);
|
||||||
} else if constexpr (concepts::optional_type<T>) {
|
} else if constexpr (concepts::optional_type<T>) {
|
||||||
using value_type = typename std::remove_cvref_t<T>::value_type;
|
using value_type = typename std::remove_cvref_t<T>::value_type;
|
||||||
|
|
||||||
// Check if the value is null
|
// Check if the value is null
|
||||||
if (is_null()) {
|
bool is_null_value;
|
||||||
|
SIMDJSON_TRY( is_null().get(is_null_value) );
|
||||||
|
if (is_null_value) {
|
||||||
out.reset(); // Set to nullopt
|
out.reset(); // Set to nullopt
|
||||||
return SUCCESS;
|
return SUCCESS;
|
||||||
}
|
}
|
||||||
@@ -97,7 +99,7 @@ public:
|
|||||||
static_cast<void>(out); // to get rid of unused errors
|
static_cast<void>(out); // to get rid of unused errors
|
||||||
return UNINITIALIZED;
|
return UNINITIALIZED;
|
||||||
}
|
}
|
||||||
#else // SIMDJSON_SUPPORTS_DESERIALIZATION
|
#else // SIMDJSON_SUPPORTS_CONCEPTS
|
||||||
// Unless the simdjson library or the user provides an inline implementation, calling this method should
|
// Unless the simdjson library or the user provides an inline implementation, calling this method should
|
||||||
// immediately fail.
|
// immediately fail.
|
||||||
static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. "
|
static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. "
|
||||||
@@ -817,7 +819,22 @@ public:
|
|||||||
simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> operator[](int) noexcept = delete;
|
simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> operator[](int) noexcept = delete;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the type of this JSON value.
|
* Get the type of this JSON value. It does not validate or consume the value.
|
||||||
|
* E.g., you must still call "is_null()" to check that a value is null even if
|
||||||
|
* "type()" returns json_type::null.
|
||||||
|
*
|
||||||
|
* Given a valid JSON document, the answer can be one of
|
||||||
|
* simdjson::ondemand::json_type::object,
|
||||||
|
* simdjson::ondemand::json_type::array,
|
||||||
|
* simdjson::ondemand::json_type::string,
|
||||||
|
* simdjson::ondemand::json_type::number,
|
||||||
|
* simdjson::ondemand::json_type::boolean,
|
||||||
|
* simdjson::ondemand::json_type::null.
|
||||||
|
*
|
||||||
|
* Starting with simdjson 4.0, this function will return simdjson::ondemand::json_type::unknown
|
||||||
|
* given a bad token.
|
||||||
|
* This allows you to identify a case such as {"key": NaN} and identify the NaN value.
|
||||||
|
* The simdjson::ondemand::json_type::unknown value should only happen with non-valid JSON.
|
||||||
*
|
*
|
||||||
* NOTE: If you're only expecting a value to be one type (a typical case), it's generally
|
* NOTE: If you're only expecting a value to be one type (a typical case), it's generally
|
||||||
* better to just call .get_double, .get_string, etc. and check for INCORRECT_TYPE (or just
|
* better to just call .get_double, .get_string, etc. and check for INCORRECT_TYPE (or just
|
||||||
|
|||||||
@@ -1057,7 +1057,7 @@ simdjson_inline simdjson_result<json_type> value_iterator::type() const noexcept
|
|||||||
case '5': case '6': case '7': case '8': case '9':
|
case '5': case '6': case '7': case '8': case '9':
|
||||||
return json_type::number;
|
return json_type::number;
|
||||||
default:
|
default:
|
||||||
return TAPE_ERROR;
|
return json_type::unknown;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
#define SIMDJSON_IMPLEMENTATION_ID_westmere 6
|
#define SIMDJSON_IMPLEMENTATION_ID_westmere 6
|
||||||
#define SIMDJSON_IMPLEMENTATION_ID_lsx 7
|
#define SIMDJSON_IMPLEMENTATION_ID_lsx 7
|
||||||
#define SIMDJSON_IMPLEMENTATION_ID_lasx 8
|
#define SIMDJSON_IMPLEMENTATION_ID_lasx 8
|
||||||
|
#define SIMDJSON_IMPLEMENTATION_ID_rvv 9
|
||||||
|
|
||||||
#define SIMDJSON_IMPLEMENTATION_ID_FOR(IMPL) SIMDJSON_CAT(SIMDJSON_IMPLEMENTATION_ID_, IMPL)
|
#define SIMDJSON_IMPLEMENTATION_ID_FOR(IMPL) SIMDJSON_CAT(SIMDJSON_IMPLEMENTATION_ID_, IMPL)
|
||||||
#define SIMDJSON_IMPLEMENTATION_ID SIMDJSON_IMPLEMENTATION_ID_FOR(SIMDJSON_IMPLEMENTATION)
|
#define SIMDJSON_IMPLEMENTATION_ID SIMDJSON_IMPLEMENTATION_ID_FOR(SIMDJSON_IMPLEMENTATION)
|
||||||
@@ -23,6 +24,15 @@
|
|||||||
// in which we include them.
|
// in which we include them.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
#ifndef SIMDJSON_IMPLEMENTATION_RVV
|
||||||
|
#define SIMDJSON_IMPLEMENTATION_RVV (SIMDJSON_IS_RISCV64 && SIMDJSON_IS_RVV)
|
||||||
|
#endif
|
||||||
|
#if SIMDJSON_IMPLEMENTATION_RVV && SIMDJSON_IS_RISCV64 && SIMDJSON_IS_RVV
|
||||||
|
#define SIMDJSON_CAN_ALWAYS_RUN_RVV 1
|
||||||
|
#else
|
||||||
|
#define SIMDJSON_CAN_ALWAYS_RUN_RVV 0
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef SIMDJSON_IMPLEMENTATION_ARM64
|
#ifndef SIMDJSON_IMPLEMENTATION_ARM64
|
||||||
#define SIMDJSON_IMPLEMENTATION_ARM64 (SIMDJSON_IS_ARM64)
|
#define SIMDJSON_IMPLEMENTATION_ARM64 (SIMDJSON_IS_ARM64)
|
||||||
#endif
|
#endif
|
||||||
@@ -128,7 +138,7 @@
|
|||||||
|
|
||||||
// Default Fallback to on unless a builtin implementation has already been selected.
|
// Default Fallback to on unless a builtin implementation has already been selected.
|
||||||
#ifndef SIMDJSON_IMPLEMENTATION_FALLBACK
|
#ifndef SIMDJSON_IMPLEMENTATION_FALLBACK
|
||||||
#if SIMDJSON_CAN_ALWAYS_RUN_ARM64 || SIMDJSON_CAN_ALWAYS_RUN_ICELAKE || SIMDJSON_CAN_ALWAYS_RUN_HASWELL || SIMDJSON_CAN_ALWAYS_RUN_WESTMERE || SIMDJSON_CAN_ALWAYS_RUN_PPC64 || SIMDJSON_CAN_ALWAYS_RUN_LSX || SIMDJSON_CAN_ALWAYS_RUN_LASX
|
#if SIMDJSON_CAN_ALWAYS_RUN_ARM64 || SIMDJSON_CAN_ALWAYS_RUN_ICELAKE || SIMDJSON_CAN_ALWAYS_RUN_HASWELL || SIMDJSON_CAN_ALWAYS_RUN_WESTMERE || SIMDJSON_CAN_ALWAYS_RUN_PPC64 || SIMDJSON_CAN_ALWAYS_RUN_LSX || SIMDJSON_CAN_ALWAYS_RUN_LASX || SIMDJSON_CAN_ALWAYS_RUN_RVV
|
||||||
// if anything at all except fallback can always run, then disable fallback.
|
// if anything at all except fallback can always run, then disable fallback.
|
||||||
#define SIMDJSON_IMPLEMENTATION_FALLBACK 0
|
#define SIMDJSON_IMPLEMENTATION_FALLBACK 0
|
||||||
#else
|
#else
|
||||||
@@ -154,6 +164,8 @@
|
|||||||
#define SIMDJSON_BUILTIN_IMPLEMENTATION lsx
|
#define SIMDJSON_BUILTIN_IMPLEMENTATION lsx
|
||||||
#elif SIMDJSON_CAN_ALWAYS_RUN_LASX
|
#elif SIMDJSON_CAN_ALWAYS_RUN_LASX
|
||||||
#define SIMDJSON_BUILTIN_IMPLEMENTATION lasx
|
#define SIMDJSON_BUILTIN_IMPLEMENTATION lasx
|
||||||
|
#elif SIMDJSON_CAN_ALWAYS_RUN_RVV
|
||||||
|
#define SIMDJSON_BUILTIN_IMPLEMENTATION rvv
|
||||||
#elif SIMDJSON_CAN_ALWAYS_RUN_FALLBACK
|
#elif SIMDJSON_CAN_ALWAYS_RUN_FALLBACK
|
||||||
#define SIMDJSON_BUILTIN_IMPLEMENTATION fallback
|
#define SIMDJSON_BUILTIN_IMPLEMENTATION fallback
|
||||||
#else
|
#else
|
||||||
|
|||||||
@@ -4,6 +4,8 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include "simdjson/common_defs.h"
|
#include "simdjson/common_defs.h"
|
||||||
|
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
namespace simdjson {
|
namespace simdjson {
|
||||||
/**
|
/**
|
||||||
* Converts JSONPath to JSON Pointer.
|
* Converts JSONPath to JSON Pointer.
|
||||||
@@ -12,12 +14,12 @@ namespace simdjson {
|
|||||||
*/
|
*/
|
||||||
inline std::string json_path_to_pointer_conversion(std::string_view json_path) {
|
inline std::string json_path_to_pointer_conversion(std::string_view json_path) {
|
||||||
size_t i = 0;
|
size_t i = 0;
|
||||||
|
|
||||||
// if JSONPath starts with $, skip it
|
// if JSONPath starts with $, skip it
|
||||||
|
// json_path.starts_with('$') requires C++20.
|
||||||
if (!json_path.empty() && json_path.front() == '$') {
|
if (!json_path.empty() && json_path.front() == '$') {
|
||||||
i = 1;
|
i = 1;
|
||||||
}
|
}
|
||||||
if (json_path.empty() || (json_path[i] != '.' &&
|
if (i >= json_path.size() || (json_path[i] != '.' &&
|
||||||
json_path[i] != '[')) {
|
json_path[i] != '[')) {
|
||||||
return "-1"; // This is just a sentinel value, the caller should check for this and return an error.
|
return "-1"; // This is just a sentinel value, the caller should check for this and return an error.
|
||||||
}
|
}
|
||||||
@@ -60,5 +62,48 @@ inline std::string json_path_to_pointer_conversion(std::string_view json_path) {
|
|||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline std::pair<std::string_view, std::string_view> get_next_key_and_json_path(std::string_view& json_path) {
|
||||||
|
std::string_view key;
|
||||||
|
|
||||||
|
if (json_path.empty()) {
|
||||||
|
return {key, json_path};
|
||||||
|
}
|
||||||
|
size_t i = 0;
|
||||||
|
|
||||||
|
// if JSONPath starts with $, skip it
|
||||||
|
if (json_path.front() == '$') {
|
||||||
|
i = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (i < json_path.length() && json_path[i] == '.') {
|
||||||
|
i += 1;
|
||||||
|
size_t key_start = i;
|
||||||
|
|
||||||
|
while (i < json_path.length() && json_path[i] != '[' && json_path[i] != '.') {
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
|
||||||
|
key = json_path.substr(key_start, i - key_start);
|
||||||
|
} else if ((i+1 < json_path.size()) && json_path[i] == '[' && (json_path[i+1] == '\'' || json_path[i+1] == '"')) {
|
||||||
|
i += 2;
|
||||||
|
size_t key_start = i;
|
||||||
|
while (i < json_path.length() && json_path[i] != '\'' && json_path[i] != '"') {
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
|
||||||
|
key = json_path.substr(key_start, i - key_start);
|
||||||
|
|
||||||
|
i += 2;
|
||||||
|
} else if ((i+2 < json_path.size()) && json_path[i] == '[' && json_path[i+1] == '*' && json_path[i+2] == ']') { // i.e [*].additional_keys or [*]["additional_keys"]
|
||||||
|
key = "*";
|
||||||
|
i += 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return std::make_pair(key, json_path.substr(i));
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace simdjson
|
} // namespace simdjson
|
||||||
#endif // SIMDJSON_JSONPATHUTIL_H
|
#endif // SIMDJSON_JSONPATHUTIL_H
|
||||||
@@ -409,9 +409,9 @@ using std::operator<<;
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if nssv_HAVE_NODISCARD
|
#if nssv_HAVE_NODISCARD
|
||||||
# define nssv_nodiscard [[nodiscard]]
|
# define nssv_nodiscard simdjson_warn_unused
|
||||||
#else
|
#else
|
||||||
# define nssv_nodiscard /*[[nodiscard]]*/
|
# define nssv_nodiscard /*simdjson_warn_unused*/
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Additional includes:
|
// Additional includes:
|
||||||
|
|||||||
@@ -35,6 +35,22 @@ inline padded_string_view::padded_string_view(std::string_view s, size_t capacit
|
|||||||
if(_capacity < s.length()) { _capacity = s.length(); }
|
if(_capacity < s.length()) { _capacity = s.length(); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline bool padded_string_view::has_sufficient_padding() const noexcept {
|
||||||
|
if (padding() >= SIMDJSON_PADDING) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
size_t missing_padding = SIMDJSON_PADDING - padding();
|
||||||
|
if(length() < missing_padding) { return false; }
|
||||||
|
|
||||||
|
for (size_t i = length() - missing_padding; i < length(); i++) {
|
||||||
|
char c = data()[i];
|
||||||
|
if (c != ' ' && c != '\t' && c != '\n' && c != '\r') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
inline size_t padded_string_view::capacity() const noexcept { return _capacity; }
|
inline size_t padded_string_view::capacity() const noexcept { return _capacity; }
|
||||||
|
|
||||||
inline size_t padded_string_view::padding() const noexcept { return capacity() - length(); }
|
inline size_t padded_string_view::padding() const noexcept { return capacity() - length(); }
|
||||||
@@ -54,10 +70,33 @@ inline std::ostream& operator<<(std::ostream& out, simdjson_result<padded_string
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
inline padded_string_view pad(std::string& s) noexcept {
|
inline padded_string_view pad(std::string& s) noexcept {
|
||||||
const auto len = s.size();
|
size_t existing_padding = 0;
|
||||||
s.append(SIMDJSON_PADDING, ' ');
|
for (size_t i = s.size(); i > 0; i--) {
|
||||||
return padded_string_view(s.data(), len, s.size());
|
char c = s[i - 1];
|
||||||
|
if (c == ' ' || c == '\t' || c == '\n' || c == '\r') {
|
||||||
|
existing_padding++;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
size_t needed_padding = 0;
|
||||||
|
if (existing_padding < SIMDJSON_PADDING) {
|
||||||
|
needed_padding = SIMDJSON_PADDING - existing_padding;
|
||||||
|
s.append(needed_padding, ' ');
|
||||||
|
}
|
||||||
|
|
||||||
|
return padded_string_view(s.data(), s.size() - needed_padding, s.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline padded_string_view pad_with_reserve(std::string& s) noexcept {
|
||||||
|
if (s.capacity() - s.size() < SIMDJSON_PADDING) {
|
||||||
|
s.reserve(s.size() + SIMDJSON_PADDING );
|
||||||
|
}
|
||||||
|
return padded_string_view(s.data(), s.size(), s.capacity());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
} // namespace simdjson
|
} // namespace simdjson
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -58,6 +58,9 @@ public:
|
|||||||
/** The number of allocated bytes. */
|
/** The number of allocated bytes. */
|
||||||
inline size_t capacity() const noexcept;
|
inline size_t capacity() const noexcept;
|
||||||
|
|
||||||
|
/** check that the view has sufficient padding */
|
||||||
|
inline bool has_sufficient_padding() const noexcept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove the UTF-8 Byte Order Mark (BOM) if it exists.
|
* Remove the UTF-8 Byte Order Mark (BOM) if it exists.
|
||||||
*
|
*
|
||||||
@@ -84,14 +87,24 @@ inline std::ostream& operator<<(std::ostream& out, simdjson_result<padded_string
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a padded_string_view from a string. The string will be padded with SIMDJSON_PADDING
|
* Create a padded_string_view from a string. The string will be padded with up to SIMDJSON_PADDING
|
||||||
* space characters. The resulting padded_string_view will have a length equal to the original
|
* space characters. The resulting padded_string_view will have a length equal to the original
|
||||||
* string.
|
* string, except maybe for trailing white space characters.
|
||||||
*
|
*
|
||||||
* @param s The string.
|
* @param s The string.
|
||||||
* @return The padded string.
|
* @return The padded string.
|
||||||
*/
|
*/
|
||||||
inline padded_string_view pad(std::string& s) noexcept;
|
inline padded_string_view pad(std::string& s) noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a padded_string_view from a string. The capacity of the string will be padded with SIMDJSON_PADDING
|
||||||
|
* characters. The resulting padded_string_view will have a length equal to the original
|
||||||
|
* string.
|
||||||
|
*
|
||||||
|
* @param s The string.
|
||||||
|
* @return The padded string.
|
||||||
|
*/
|
||||||
|
inline padded_string_view pad_with_reserve(std::string& s) noexcept;
|
||||||
} // namespace simdjson
|
} // namespace simdjson
|
||||||
|
|
||||||
#endif // SIMDJSON_PADDED_STRING_VIEW_H
|
#endif // SIMDJSON_PADDED_STRING_VIEW_H
|
||||||
|
|||||||
@@ -45,6 +45,22 @@ using std::size_t;
|
|||||||
#define SIMDJSON_IS_ARM64 1
|
#define SIMDJSON_IS_ARM64 1
|
||||||
#elif defined(__riscv) && __riscv_xlen == 64
|
#elif defined(__riscv) && __riscv_xlen == 64
|
||||||
#define SIMDJSON_IS_RISCV64 1
|
#define SIMDJSON_IS_RISCV64 1
|
||||||
|
#if __riscv_v_intrinsic >= 11000
|
||||||
|
#define SIMDJSON_HAS_RVV_INTRINSICS 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define SIMDJSON_HAS_ZVBB_INTRINSICS \
|
||||||
|
0 // there is currently no way to detect this
|
||||||
|
|
||||||
|
#if SIMDJSON_HAS_RVV_INTRINSICS && __riscv_vector && \
|
||||||
|
__riscv_v_min_vlen >= 128 && __riscv_v_elen >= 64
|
||||||
|
// RISC-V V extension
|
||||||
|
#define SIMDJSON_IS_RVV 1
|
||||||
|
#if SIMDJSON_HAS_ZVBB_INTRINSICS && __riscv_zvbb >= 1000000
|
||||||
|
// RISC-V Vector Basic Bit-manipulation
|
||||||
|
#define SIMDJSON_IS_ZVBB 1
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
#elif defined(__loongarch_lp64)
|
#elif defined(__loongarch_lp64)
|
||||||
#define SIMDJSON_IS_LOONGARCH64 1
|
#define SIMDJSON_IS_LOONGARCH64 1
|
||||||
#elif defined(__PPC64__) || defined(_M_PPC64)
|
#elif defined(__PPC64__) || defined(_M_PPC64)
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
#ifndef SIMDJSON_RVV_H
|
||||||
|
#define SIMDJSON_RVV_H
|
||||||
|
|
||||||
|
#include "simdjson/rvv/begin.h"
|
||||||
|
#include "simdjson/generic/amalgamated.h"
|
||||||
|
#include "simdjson/rvv/end.h"
|
||||||
|
|
||||||
|
#endif // SIMDJSON_RVV_H
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
#ifndef SIMDJSON_RVV_BASE_H
|
||||||
|
#define SIMDJSON_RVV_BASE_H
|
||||||
|
|
||||||
|
#ifndef SIMDJSON_CONDITIONAL_INCLUDE
|
||||||
|
#include "simdjson/base.h"
|
||||||
|
#endif // SIMDJSON_CONDITIONAL_INCLUDE
|
||||||
|
namespace simdjson {
|
||||||
|
namespace rvv {
|
||||||
|
|
||||||
|
class implementation;
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
namespace simd {
|
||||||
|
template <typename T> struct simd8;
|
||||||
|
template <typename T> struct simd8x64;
|
||||||
|
} // namespace simd
|
||||||
|
} // unnamed namespace
|
||||||
|
} // namespace rvv
|
||||||
|
} // namespace simdjson
|
||||||
|
#endif // SIMDJSON_RVV_BASE_H
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
#define SIMDJSON_IMPLEMENTATION rvv
|
||||||
|
|
||||||
|
// include RVV intrinsics and definitions
|
||||||
|
#include <riscv_vector.h>
|
||||||
|
#include "simdjson/rvv/base.h"
|
||||||
|
#include "simdjson/rvv/intrinsics.h"
|
||||||
|
#include "simdjson/rvv/bitmanipulation.h"
|
||||||
|
#include "simdjson/rvv/bitmask.h"
|
||||||
|
#include "simdjson/rvv/numberparsing_defs.h"
|
||||||
|
#include "simdjson/rvv/simd.h"
|
||||||
|
#include "simdjson/rvv/stringparsing_defs.h"
|
||||||
|
|
||||||
|
#define SIMDJSON_SKIP_BACKSLASH_SHORT_CIRCUIT 1
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
#ifndef SIMDJSON_RVV_BITMANIPULATION_H
|
||||||
|
#define SIMDJSON_RVV_BITMANIPULATION_H
|
||||||
|
|
||||||
|
#ifndef SIMDJSON_CONDITIONAL_INCLUDE
|
||||||
|
#include "simdjson/rvv/base.h"
|
||||||
|
#endif // SIMDJSON_CONDITIONAL_INCLUDE
|
||||||
|
|
||||||
|
namespace simdjson {
|
||||||
|
namespace rvv {
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
/* result might be undefined when input_num is zero */
|
||||||
|
simdjson_inline int leading_zeroes(uint64_t input_num) {
|
||||||
|
#if defined(_MSC_VER) && !defined(__clang__)
|
||||||
|
unsigned long leading_zero = 0;
|
||||||
|
if (_BitScanReverse64(&leading_zero, input_num))
|
||||||
|
return (int)(63 - leading_zero);
|
||||||
|
else
|
||||||
|
return 64;
|
||||||
|
#else
|
||||||
|
return __builtin_clzll(input_num);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
simdjson_inline uint64_t clear_lowest_bit(uint64_t input_num) {
|
||||||
|
return input_num & (input_num - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
simdjson_inline int count_ones(uint64_t input_num) {
|
||||||
|
return __builtin_popcountll(input_num);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline simdjson::internal::value128 full_multiplication(uint64_t a, uint64_t b) {
|
||||||
|
#if __SIZEOF_INT128__
|
||||||
|
unsigned __int128 p = (unsigned __int128)a * b;
|
||||||
|
return { (uint64_t)p, (uint64_t)(p >> 64) };
|
||||||
|
#else
|
||||||
|
uint64_t lo = a * b;
|
||||||
|
uint64_t a0 = (uint32_t)a, a1 = a >> 32;
|
||||||
|
uint64_t b0 = (uint32_t)b, b1 = b >> 32;
|
||||||
|
uint64_t mid1 = a0 * b1;
|
||||||
|
uint64_t mid2 = a1 * b0;
|
||||||
|
uint64_t carry = ((mid1 & 0xFFFFFFFF) + (mid2 & 0xFFFFFFFF) + (lo >> 32)) >> 32;
|
||||||
|
uint64_t hi = a1 * b1 + (mid1 >> 32) + (mid2 >> 32) + carry;
|
||||||
|
return { lo, hi };
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
} // unnamed namespace
|
||||||
|
} // namespace rvv
|
||||||
|
} // namespace simdjson
|
||||||
|
|
||||||
|
#endif // SIMDJSON_RVV_BITMANIPULATION_H
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
#ifndef SIMDJSON_CONDITIONAL_INCLUDE
|
||||||
|
#include "simdjson/rvv/base.h"
|
||||||
|
#endif // SIMDJSON_CONDITIONAL_INCLUDE
|
||||||
|
|
||||||
|
#undef SIMDJSON_SKIP_BACKSLASH_SHORT_CIRCUIT
|
||||||
|
#undef SIMDJSON_IMPLEMENTATION
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
#ifndef SIMDJSON_RVV_IMPLEMENTATION_H
|
||||||
|
#define SIMDJSON_RVV_IMPLEMENTATION_H
|
||||||
|
|
||||||
|
#ifndef SIMDJSON_CONDITIONAL_INCLUDE
|
||||||
|
#define SIMDJSON_CONDITIONAL_INCLUDE
|
||||||
|
#include "simdjson/base.h"
|
||||||
|
#include "simdjson/implementation.h"
|
||||||
|
#include "simdjson/internal/instruction_set.h"
|
||||||
|
#endif // SIMDJSON_CONDITIONAL_INCLUDE
|
||||||
|
|
||||||
|
namespace simdjson {
|
||||||
|
namespace rvv {
|
||||||
|
|
||||||
|
class implementation final: public simdjson::implementation {
|
||||||
|
public:
|
||||||
|
simdjson_inline implementation() : simdjson::implementation("rvv", "RISC-V Vector Extension", 0) {}
|
||||||
|
simdjson_warn_unused error_code create_dom_parser_implementation(
|
||||||
|
size_t capacity,
|
||||||
|
size_t max_depth,
|
||||||
|
std::unique_ptr<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;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace rvv
|
||||||
|
} // namespace simdjson
|
||||||
|
|
||||||
|
#endif // SIMDJSON_RVV_IMPLEMENTATION_H
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
#ifndef SIMDJSON_RVV_INTRINSICS_H
|
||||||
|
#define SIMDJSON_RVV_INTRINSICS_H
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef SIMDJSON_CONDITIONAL_INCLUDE
|
||||||
|
#include "simdjson/rvv/base.h"
|
||||||
|
#endif // SIMDJSON_CONDITIONAL_INCLUDE
|
||||||
|
#endif // SIMDJSON_RVV_INTRINSICS_H
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
#ifndef SIMDJSON_RVV_ONDEMAND_H
|
||||||
|
#define SIMDJSON_RVV_ONDEMAND_H
|
||||||
|
|
||||||
|
#include "simdjson/rvv/begin.h"
|
||||||
|
#include "simdjson/generic/ondemand/amalgamated.h"
|
||||||
|
#include "simdjson/rvv/end.h"
|
||||||
|
|
||||||
|
#endif // SIMDJSON_RVV_ONDEMAND_H
|
||||||
|
|
||||||
@@ -0,0 +1,298 @@
|
|||||||
|
#ifndef SIMDJSON_RVV_SIMD_H
|
||||||
|
#define SIMDJSON_RVV_SIMD_H
|
||||||
|
|
||||||
|
#ifndef SIMDJSON_CONDITIONAL_INCLUDE
|
||||||
|
#include "simdjson/rvv/base.h"
|
||||||
|
#include "simdjson/rvv/intrinsics.h"
|
||||||
|
#include "simdjson/internal/simdprune_tables.h"
|
||||||
|
#endif // SIMDJSON_CONDITIONAL_INCLUDE
|
||||||
|
|
||||||
|
namespace simdjson {
|
||||||
|
namespace rvv {
|
||||||
|
namespace {
|
||||||
|
namespace simd {
|
||||||
|
|
||||||
|
// ---------- 128-bit fixed vectors ----------
|
||||||
|
using vuint8x16 = vuint8m1_t __attribute__((riscv_rvv_vector_bits(128)));
|
||||||
|
using vint8x16 = vint8m1_t __attribute__((riscv_rvv_vector_bits(128)));
|
||||||
|
using vbool8x16 = vbool8_t;
|
||||||
|
static constexpr size_t fixed_vl = 16;
|
||||||
|
|
||||||
|
// ---------- forward ----------
|
||||||
|
template<typename T> struct simd8;
|
||||||
|
template<typename T> struct simd8x64;
|
||||||
|
|
||||||
|
// ---------- base<Child> ----------
|
||||||
|
template<typename Child>
|
||||||
|
struct base {
|
||||||
|
vuint8x16 value{};
|
||||||
|
base() = default;
|
||||||
|
base(vuint8x16 v) : value(v) {}
|
||||||
|
operator vuint8x16() const { return value; }
|
||||||
|
operator vuint8x16&() { return value; }
|
||||||
|
|
||||||
|
simdjson_inline Child operator|(const Child o) const { return __riscv_vor_vv_u8m1(value, o, fixed_vl); }
|
||||||
|
simdjson_inline Child operator&(const Child o) const { return __riscv_vand_vv_u8m1(value, o, fixed_vl); }
|
||||||
|
simdjson_inline Child operator^(const Child o) const { return __riscv_vxor_vv_u8m1(value, o, fixed_vl); }
|
||||||
|
simdjson_inline Child bit_andnot(const Child o) const { return __riscv_vandn_vv_u8m1(value, o, fixed_vl); }
|
||||||
|
|
||||||
|
simdjson_inline Child& operator|=(const Child o) { auto* c = static_cast<Child*>(this); *c = *c | o; return *c; }
|
||||||
|
simdjson_inline Child& operator&=(const Child o) { auto* c = static_cast<Child*>(this); *c = *c & o; return *c; }
|
||||||
|
simdjson_inline Child& operator^=(const Child o) { auto* c = static_cast<Child*>(this); *c = *c ^ o; return *c; }
|
||||||
|
};
|
||||||
|
|
||||||
|
// ---------- base8<T,Mask> ----------
|
||||||
|
template<typename T, typename Mask = simd8<bool>>
|
||||||
|
struct base8 : base<simd8<T>> {
|
||||||
|
using base<simd8<T>>::value;
|
||||||
|
using bitmask_t = uint32_t;
|
||||||
|
base8() = default;
|
||||||
|
base8(vuint8x16 v) : base<simd8<T>>(v) {}
|
||||||
|
|
||||||
|
friend simdjson_inline Mask operator==(const simd8<T> a, const simd8<T> b) {
|
||||||
|
return simd8<bool>(__riscv_vmseq_vv_u8m1_b8(a, b, fixed_vl));
|
||||||
|
}
|
||||||
|
template<int N=1>
|
||||||
|
simdjson_inline simd8<T> prev(const simd8<T> prev_chunk) const {
|
||||||
|
return __riscv_vslideup_vx_u8m1(prev_chunk, value, fixed_vl - N, 2 * fixed_vl);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// ---------- simd8<bool> ----------
|
||||||
|
template<>
|
||||||
|
struct simd8<bool> : base8<bool> {
|
||||||
|
simd8() = default;
|
||||||
|
simd8(vuint8x16 v) : base8(v) {}
|
||||||
|
simd8(vbool8_t m) : base8(__riscv_vmerge_vvm_u8m1(
|
||||||
|
__riscv_vmv_v_x_u8m1(0, fixed_vl),
|
||||||
|
__riscv_vmv_v_x_u8m1(0xFFu, fixed_vl),
|
||||||
|
m, fixed_vl)) {}
|
||||||
|
|
||||||
|
static simdjson_inline simd8<bool> splat(bool b) {
|
||||||
|
return __riscv_vmv_v_x_u8m1(uint8_t(-b), fixed_vl);
|
||||||
|
}
|
||||||
|
simdjson_inline simd8(bool b) : simd8(splat(b)) {}
|
||||||
|
|
||||||
|
simdjson_inline int to_bitmask() const {
|
||||||
|
vuint8x16 bits = __riscv_vand_vx_u8m1(value, 0xFFu, fixed_vl);
|
||||||
|
vbool8x16 mask = __riscv_vmseq_vx_u8m1_b8(bits, 0xFFu, fixed_vl);
|
||||||
|
return __riscv_vcpop_m_b8(mask, fixed_vl);
|
||||||
|
}
|
||||||
|
simdjson_inline bool any_bits_set_anywhere() const {
|
||||||
|
return to_bitmask() != 0;
|
||||||
|
}
|
||||||
|
simdjson_inline simd8<bool> operator~() const { return *this ^ splat(true); }
|
||||||
|
};
|
||||||
|
|
||||||
|
// ---------- simd8<uint8_t> ----------
|
||||||
|
template<>
|
||||||
|
struct simd8<uint8_t> : base8<uint8_t> {
|
||||||
|
simd8() = default;
|
||||||
|
simd8(vuint8x16 v) : base8(v) {}
|
||||||
|
static simdjson_inline simd8<uint8_t> splat(uint8_t v) {
|
||||||
|
return __riscv_vmv_v_x_u8m1(v, fixed_vl);
|
||||||
|
}
|
||||||
|
static simdjson_inline simd8<uint8_t> zero() { return splat(0); }
|
||||||
|
static simdjson_inline simd8<uint8_t> load(const uint8_t* p) {
|
||||||
|
return __riscv_vle8_v_u8m1(p, fixed_vl);
|
||||||
|
}
|
||||||
|
simdjson_inline simd8(uint8_t v) : simd8(splat(v)) {}
|
||||||
|
simdjson_inline simd8(const uint8_t* p) : simd8(load(p)) {}
|
||||||
|
|
||||||
|
simdjson_inline void store(uint8_t* p) const {
|
||||||
|
__riscv_vse8_v_u8m1(p, value, fixed_vl);
|
||||||
|
}
|
||||||
|
|
||||||
|
simdjson_inline simd8<uint8_t> operator+(const simd8<uint8_t> o) const {
|
||||||
|
return __riscv_vadd_vv_u8m1(value, o, fixed_vl);
|
||||||
|
}
|
||||||
|
simdjson_inline simd8<uint8_t> operator-(const simd8<uint8_t> o) const {
|
||||||
|
return __riscv_vsub_vv_u8m1(value, o, fixed_vl);
|
||||||
|
}
|
||||||
|
simdjson_inline simd8<uint8_t>& operator+=(const simd8<uint8_t> o) {
|
||||||
|
*this = *this + o; return *this;
|
||||||
|
}
|
||||||
|
simdjson_inline simd8<uint8_t>& operator-=(const simd8<uint8_t> o) {
|
||||||
|
*this = *this - o; return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
simdjson_inline simd8<uint8_t> saturating_add(const simd8<uint8_t> o) const {
|
||||||
|
return __riscv_vsaddu_vv_u8m1(value, o, fixed_vl);
|
||||||
|
}
|
||||||
|
simdjson_inline simd8<uint8_t> saturating_sub(const simd8<uint8_t> o) const {
|
||||||
|
return __riscv_vssubu_vv_u8m1(value, o, fixed_vl);
|
||||||
|
}
|
||||||
|
simdjson_inline simd8<uint8_t> max_val(const simd8<uint8_t> o) const {
|
||||||
|
return __riscv_vmaxu_vv_u8m1(value, o, fixed_vl);
|
||||||
|
}
|
||||||
|
simdjson_inline simd8<uint8_t> min_val(const simd8<uint8_t> o) const {
|
||||||
|
return __riscv_vminu_vv_u8m1(value, o, fixed_vl);
|
||||||
|
}
|
||||||
|
simdjson_inline simd8<bool> operator>(const simd8<uint8_t> o) const {
|
||||||
|
return simd8<bool>(__riscv_vmsgtu_vv_u8m1_b8(value, o, fixed_vl));
|
||||||
|
}
|
||||||
|
simdjson_inline simd8<bool> operator<(const simd8<uint8_t> o) const {
|
||||||
|
return simd8<bool>(__riscv_vmsgtu_vv_u8m1_b8(o, value, fixed_vl));
|
||||||
|
}
|
||||||
|
simdjson_inline simd8<bool> operator<=(const simd8<uint8_t> o) const {
|
||||||
|
return simd8<bool>(__riscv_vmsleu_vv_u8m1_b8(value, o, fixed_vl));
|
||||||
|
}
|
||||||
|
simdjson_inline simd8<bool> operator>=(const simd8<uint8_t> o) const {
|
||||||
|
return simd8<bool>(__riscv_vmsleu_vv_u8m1_b8(o, value, fixed_vl));
|
||||||
|
}
|
||||||
|
template<int NS>
|
||||||
|
simdjson_inline simd8<uint8_t> shr() const {
|
||||||
|
return __riscv_vsrl_vx_u8m1(value, NS, fixed_vl);
|
||||||
|
}
|
||||||
|
template<int NS>
|
||||||
|
simdjson_inline simd8<uint8_t> shl() const {
|
||||||
|
return __riscv_vsll_vx_u8m1(value, NS, fixed_vl);
|
||||||
|
}
|
||||||
|
template <typename Ret>
|
||||||
|
simdjson_inline simd8<Ret> lookup_16(const Ret* table) const {
|
||||||
|
alignas(16) uint8_t idx[16];
|
||||||
|
store(idx);
|
||||||
|
alignas(16) Ret res[16];
|
||||||
|
for (int i = 0; i < 16; ++i) res[i] = table[idx[i]];
|
||||||
|
return simd8<Ret>::load(reinterpret_cast<const Ret*>(res));
|
||||||
|
}
|
||||||
|
simdjson_inline void compress(uint16_t mask, uint8_t* out) const {
|
||||||
|
alignas(16) uint8_t tmp[16];
|
||||||
|
store(tmp);
|
||||||
|
for (int i = 0, j = 0; i < 16; ++i)
|
||||||
|
if (mask & (1u << i)) out[j++] = tmp[i];
|
||||||
|
}
|
||||||
|
simdjson_inline uint64_t gt_bits(uint8_t max_value) const {
|
||||||
|
return (*this > splat(max_value)).to_bitmask();
|
||||||
|
}
|
||||||
|
simdjson_inline uint64_t gt_bits(const simd8<uint8_t>& max_vec) const {
|
||||||
|
return (*this > max_vec).to_bitmask();
|
||||||
|
}
|
||||||
|
simdjson_inline bool any_bits_set_anywhere() const {
|
||||||
|
return (*this > zero()).any_bits_set_anywhere();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// ---------- simd8<int8_t> ----------
|
||||||
|
template<>
|
||||||
|
struct simd8<int8_t> {
|
||||||
|
vint8x16 value{};
|
||||||
|
simd8() = default;
|
||||||
|
simd8(vint8x16 v) : value(v) {}
|
||||||
|
static simdjson_inline simd8<int8_t> splat(int8_t v) {
|
||||||
|
return __riscv_vmv_v_x_i8m1(v, fixed_vl);
|
||||||
|
}
|
||||||
|
static simdjson_inline simd8<int8_t> zero() { return splat(0); }
|
||||||
|
static simdjson_inline simd8<int8_t> load(const int8_t* p) {
|
||||||
|
return __riscv_vle8_v_i8m1(p, fixed_vl);
|
||||||
|
}
|
||||||
|
simdjson_inline simd8(int8_t v) : simd8(splat(v)) {}
|
||||||
|
simdjson_inline simd8(const int8_t* p) : simd8(load(p)) {}
|
||||||
|
|
||||||
|
simdjson_inline void store(int8_t* p) const {
|
||||||
|
__riscv_vse8_v_i8m1(p, value, fixed_vl);
|
||||||
|
}
|
||||||
|
simdjson_inline simd8<int8_t> operator+(const simd8<int8_t> o) const {
|
||||||
|
return __riscv_vadd_vv_i8m1(value, o.value, fixed_vl);
|
||||||
|
}
|
||||||
|
simdjson_inline simd8<int8_t> operator-(const simd8<int8_t> o) const {
|
||||||
|
return __riscv_vsub_vv_i8m1(value, o.value, fixed_vl);
|
||||||
|
}
|
||||||
|
simdjson_inline simd8<int8_t> max_val(const simd8<int8_t> o) const {
|
||||||
|
return __riscv_vmax_vv_i8m1(value, o.value, fixed_vl);
|
||||||
|
}
|
||||||
|
simdjson_inline simd8<int8_t> min_val(const simd8<int8_t> o) const {
|
||||||
|
return __riscv_vmin_vv_i8m1(value, o.value, fixed_vl);
|
||||||
|
}
|
||||||
|
simdjson_inline simd8<bool> operator>(const simd8<int8_t> o) const {
|
||||||
|
return simd8<bool>(__riscv_vmsgt_vv_i8m1_b8(value, o.value, fixed_vl));
|
||||||
|
}
|
||||||
|
simdjson_inline simd8<bool> operator<(const simd8<int8_t> o) const {
|
||||||
|
return simd8<bool>(__riscv_vmsgt_vv_i8m1_b8(o.value, value, fixed_vl));
|
||||||
|
}
|
||||||
|
simdjson_inline simd8<bool> operator==(const simd8<int8_t> o) const {
|
||||||
|
return simd8<bool>(__riscv_vmseq_vv_i8m1_b8(value, o.value, fixed_vl));
|
||||||
|
}
|
||||||
|
template<int N=1>
|
||||||
|
simdjson_inline simd8<int8_t> prev(const simd8<int8_t> prev_chunk) const {
|
||||||
|
return __riscv_vslideup_vx_i8m1(prev_chunk.value, value, fixed_vl - N, 2 * fixed_vl);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// ---------- simd8x64<T> ----------
|
||||||
|
template<typename T>
|
||||||
|
struct simd8x64 {
|
||||||
|
static constexpr int NUM_CHUNKS = 64 / sizeof(simd8<T>);
|
||||||
|
static_assert(NUM_CHUNKS == 4, "RVV kernel uses 4×128-bit chunks per 64-byte block.");
|
||||||
|
const simd8<T> chunks[4];
|
||||||
|
|
||||||
|
simd8x64(const simd8x64&) = delete;
|
||||||
|
simd8x64& operator=(const simd8x64&) = delete;
|
||||||
|
simd8x64() = delete;
|
||||||
|
|
||||||
|
simdjson_inline simd8x64(const simd8<T> c0, const simd8<T> c1,
|
||||||
|
const simd8<T> c2, const simd8<T> c3)
|
||||||
|
: chunks{c0, c1, c2, c3} {}
|
||||||
|
simdjson_inline simd8x64(const T* ptr)
|
||||||
|
: chunks{simd8<T>::load(ptr),
|
||||||
|
simd8<T>::load(ptr + 16),
|
||||||
|
simd8<T>::load(ptr + 32),
|
||||||
|
simd8<T>::load(ptr + 48)} {}
|
||||||
|
|
||||||
|
simdjson_inline void store(T* ptr) const {
|
||||||
|
chunks[0].store(ptr);
|
||||||
|
chunks[1].store(ptr + 16);
|
||||||
|
chunks[2].store(ptr + 32);
|
||||||
|
chunks[3].store(ptr + 48);
|
||||||
|
}
|
||||||
|
simdjson_inline simd8<T> reduce_or() const {
|
||||||
|
return (chunks[0] | chunks[1]) | (chunks[2] | chunks[3]);
|
||||||
|
}
|
||||||
|
simdjson_inline uint64_t to_bitmask() const {
|
||||||
|
uint16_t m0 = uint16_t(chunks[0].to_bitmask());
|
||||||
|
uint16_t m1 = uint16_t(chunks[1].to_bitmask());
|
||||||
|
uint16_t m2 = uint16_t(chunks[2].to_bitmask());
|
||||||
|
uint16_t m3 = uint16_t(chunks[3].to_bitmask());
|
||||||
|
return m0 | (uint64_t(m1) << 16) | (uint64_t(m2) << 32) | (uint64_t(m3) << 48);
|
||||||
|
}
|
||||||
|
simdjson_inline uint64_t eq(const T m) const {
|
||||||
|
simd8<T> spl = simd8<T>::splat(m);
|
||||||
|
return simd8x64<bool>(chunks[0] == spl,
|
||||||
|
chunks[1] == spl,
|
||||||
|
chunks[2] == spl,
|
||||||
|
chunks[3] == spl).to_bitmask();
|
||||||
|
}
|
||||||
|
simdjson_inline uint64_t lteq(const T m) const {
|
||||||
|
simd8<T> spl = simd8<T>::splat(m);
|
||||||
|
return simd8x64<bool>(chunks[0] <= spl,
|
||||||
|
chunks[1] <= spl,
|
||||||
|
chunks[2] <= spl,
|
||||||
|
chunks[3] <= spl).to_bitmask();
|
||||||
|
}
|
||||||
|
simdjson_inline uint64_t compress(uint64_t mask, T* out) const {
|
||||||
|
using internal::BitsSetTable256mul2;
|
||||||
|
uint32_t m0 = uint32_t(mask);
|
||||||
|
uint32_t m1 = uint32_t(mask >> 16);
|
||||||
|
uint32_t m2 = uint32_t(mask >> 32);
|
||||||
|
uint32_t m3 = uint32_t(mask >> 48);
|
||||||
|
|
||||||
|
int pop0 = BitsSetTable256mul2[uint8_t(m0)];
|
||||||
|
int pop1 = BitsSetTable256mul2[uint8_t(m1)];
|
||||||
|
int pop2 = BitsSetTable256mul2[uint8_t(m2)];
|
||||||
|
|
||||||
|
chunks[0].compress(uint16_t(m0), out);
|
||||||
|
chunks[1].compress(uint16_t(m1), out + 16 - pop0);
|
||||||
|
chunks[2].compress(uint16_t(m2), out + 32 - pop0 - pop1);
|
||||||
|
chunks[3].compress(uint16_t(m3), out + 48 - pop0 - pop1 - pop2);
|
||||||
|
return 64 - __builtin_popcountll(mask);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace simd
|
||||||
|
} // unnamed namespace
|
||||||
|
} // namespace rvv
|
||||||
|
} // namespace simdjson
|
||||||
|
|
||||||
|
|
||||||
|
#endif // SIMDJSON_RVV_SIMD_H
|
||||||
@@ -4,7 +4,7 @@
|
|||||||
#define SIMDJSON_SIMDJSON_VERSION_H
|
#define SIMDJSON_SIMDJSON_VERSION_H
|
||||||
|
|
||||||
/** The version of simdjson being used (major.minor.revision) */
|
/** The version of simdjson being used (major.minor.revision) */
|
||||||
#define SIMDJSON_VERSION "4.0.0"
|
#define SIMDJSON_VERSION "4.0.2"
|
||||||
|
|
||||||
namespace simdjson {
|
namespace simdjson {
|
||||||
enum {
|
enum {
|
||||||
@@ -19,7 +19,7 @@ enum {
|
|||||||
/**
|
/**
|
||||||
* The revision (major.minor.REVISION) of simdjson being used.
|
* The revision (major.minor.REVISION) of simdjson being used.
|
||||||
*/
|
*/
|
||||||
SIMDJSON_VERSION_REVISION = 0
|
SIMDJSON_VERSION_REVISION = 2
|
||||||
};
|
};
|
||||||
} // namespace simdjson
|
} // namespace simdjson
|
||||||
|
|
||||||
|
|||||||
+5
-1
@@ -8,7 +8,11 @@ RUN apt-get update && \
|
|||||||
apt-get install -y --no-install-recommends ca-certificates gnupg \
|
apt-get install -y --no-install-recommends ca-certificates gnupg \
|
||||||
build-essential cmake make python3 zlib1g wget subversion unzip ninja-build git linux-perf && \
|
build-essential cmake make python3 zlib1g wget subversion unzip ninja-build git linux-perf && \
|
||||||
rm -rf /var/lib/apt/lists/*
|
rm -rf /var/lib/apt/lists/*
|
||||||
RUN git clone --depth=1 --branch p2996 https://github.com/bloomberg/clang-p2996.git /tmp/clang-source
|
ARG CLANG_COMMIT=d77eff1cbd78fd065668acf93b1f5f400d39134d
|
||||||
|
RUN git clone --depth=1 https://github.com/bloomberg/clang-p2996.git /tmp/clang-source && \
|
||||||
|
cd /tmp/clang-source && \
|
||||||
|
git fetch origin $CLANG_COMMIT --depth=1 && \
|
||||||
|
git checkout $CLANG_COMMIT
|
||||||
RUN cmake -S /tmp/clang-source/llvm -B /tmp/clang-source/build-llvm -DCMAKE_BUILD_TYPE=Release \
|
RUN cmake -S /tmp/clang-source/llvm -B /tmp/clang-source/build-llvm -DCMAKE_BUILD_TYPE=Release \
|
||||||
-DLLVM_ENABLE_ASSERTIONS=ON \
|
-DLLVM_ENABLE_ASSERTIONS=ON \
|
||||||
-DLLVM_UNREACHABLE_OPTIMIZE=ON \
|
-DLLVM_UNREACHABLE_OPTIMIZE=ON \
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user