mirror of
https://github.com/simdjson/simdjson
synced 2026-06-08 17:27:07 +00:00
Compare commits
144 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 15e378af3c | |||
| fbc9b7e3fb | |||
| 1b5a9267d6 | |||
| e3c795072c | |||
| fb98cbdb3a | |||
| 21a2ccaeb8 | |||
| b98883b5ae | |||
| d39ef515a0 | |||
| 6cbb6ac89b | |||
| 5bbf124690 | |||
| f51a32ebcd | |||
| e9b943bf32 | |||
| e9f0f1bb9b | |||
| 7ef1ebd4fb | |||
| 8de540e267 | |||
| ebc51fbd1a | |||
| 84a31c1615 | |||
| f77ac963f4 | |||
| ae3d912f8d | |||
| abf3d7d440 | |||
| 3c313b8530 | |||
| f435fddda1 | |||
| 14d927128b | |||
| 48152a0326 | |||
| b5cf53232c | |||
| b3d0b732e6 | |||
| 3c29f40f2f | |||
| 4a89d79984 | |||
| 9cb639dcd7 | |||
| 4699dd0ce2 | |||
| cfd337bb50 | |||
| 9bef628982 | |||
| 59025bc8b1 | |||
| ffe96dde19 | |||
| f9664cf184 | |||
| 830323f383 | |||
| eb8e15d9c0 | |||
| 3571f3a8d0 | |||
| 4b13020d65 | |||
| 75c6c950e5 | |||
| 5ad7698af1 | |||
| f6f359d3eb | |||
| 185e157e0c | |||
| 3f3f6cde7c | |||
| 005054916d | |||
| 338224849d | |||
| ada52641b4 | |||
| ede9d57f22 | |||
| 7bf33f6c8a | |||
| d62b789cb3 | |||
| 33dbd44098 | |||
| e0dcf8adc9 | |||
| 34dcd33a88 | |||
| 17a1a8e187 | |||
| 77ad00b63c | |||
| 25e7f1765a | |||
| 8d01255ceb | |||
| 8ec016b093 | |||
| 9e726b9856 | |||
| 312f1f26d3 | |||
| ba50571d66 | |||
| 4a587cb898 | |||
| bdf9123c92 | |||
| 6e4c29b7c5 | |||
| ec0b48b772 | |||
| d65acbd47b | |||
| 75240ad8e1 | |||
| 3efb44dc0f | |||
| 5c5cd5b42d | |||
| 12a1b6db53 | |||
| 37e87f6f99 | |||
| cd13b02bf0 | |||
| 624174d916 | |||
| 8a247f1321 | |||
| 7aa35bffd3 | |||
| d6c910686b | |||
| 22cc523fd4 | |||
| 3177cd1b5d | |||
| 63d9ce3c58 | |||
| 8e8180560d | |||
| 1594af5d5d | |||
| b207338365 | |||
| 68be9c2170 | |||
| 5347771091 | |||
| 8bf8315651 | |||
| 269ae7ad6b | |||
| 2aa91f741f | |||
| 5430544bbb | |||
| 7b55f16682 | |||
| d8fec59e85 | |||
| 57b6034a0c | |||
| 7500d7bb4f | |||
| 82c9876aec | |||
| b9234be80f | |||
| 0a2563e13e | |||
| 727ec73c33 | |||
| 9a55a830ec | |||
| 8c89ae0cd9 | |||
| 8c71ca1b1d | |||
| c72b4bc0f4 | |||
| 8a26cb3c8e | |||
| bf2ba5c675 | |||
| f151300a76 | |||
| 9aa3563d99 | |||
| 9444c1a04f | |||
| 883901a81b | |||
| a2c96c9cca | |||
| c63da0ef2c | |||
| c61cefda85 | |||
| bffcbb444d | |||
| 0b2891aaab | |||
| 983fb41802 | |||
| 0d2455029d | |||
| e94f027310 | |||
| 2b766e4c09 | |||
| a5db75e1a6 | |||
| 4bd66cb891 | |||
| 960a7ebba1 | |||
| d520062f8e | |||
| db08d78ed0 | |||
| 46292b8d4b | |||
| 46241287c6 | |||
| 137cb14bcc | |||
| 5e6be3ed7a | |||
| c6ab52eebb | |||
| a1aab1fafe | |||
| b92cbbe280 | |||
| 6d2a09f8e5 | |||
| 00564bf7d5 | |||
| 5809e51ae4 | |||
| d27e7cce71 | |||
| f7dc03f93d | |||
| d4ac1b51d0 | |||
| 6a4222da71 | |||
| bba88eb5e5 | |||
| 16b3816455 | |||
| e5a408386b | |||
| e65f28e61a | |||
| fbb46b99e2 | |||
| 933c2ebeac | |||
| db3e813aa6 | |||
| 9c95a48fe6 | |||
| cb20f7e7df | |||
| 18b9168eec |
@@ -0,0 +1,12 @@
|
|||||||
|
# https://editorconfig.org/
|
||||||
|
root = true
|
||||||
|
# Conservatively avoid changing defaults for other file types, e.g. raw json files for test cases,
|
||||||
|
# Makefiles, etc.
|
||||||
|
[*.{cpp,h,md}]
|
||||||
|
charset = utf-8
|
||||||
|
end_of_line = lf
|
||||||
|
indent_size = 2
|
||||||
|
indent_style = space
|
||||||
|
insert_final_newline = true
|
||||||
|
tab_width = 2
|
||||||
|
trim_trailing_whitespace = true
|
||||||
@@ -78,6 +78,7 @@
|
|||||||
|
|
||||||
.gitattributes export-ignore
|
.gitattributes export-ignore
|
||||||
.gitignore export-ignore
|
.gitignore export-ignore
|
||||||
|
.editorconfig export-ignore
|
||||||
|
|
||||||
# Sources
|
# Sources
|
||||||
*.c text eol=lf diff=c
|
*.c text eol=lf diff=c
|
||||||
|
|||||||
@@ -12,24 +12,26 @@ 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: https://github.com/simdjson/simdjson/blob/master/doc/basics.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). If you wish to support features that are not part of RFC 8259, then you should not refer to your issue as a bug.
|
||||||
|
|
||||||
|
|
||||||
**Describe the bug**
|
**Describe the bug**
|
||||||
A clear and concise description of what the bug is.
|
A clear and concise description of what the bug is. A bug is a failure to build with normal compiler settings or a misbehaviour: when running the code, you get a result that differs from the expected result from our documentation.
|
||||||
|
|
||||||
A compiler or static-analyzer warning is not a bug.
|
A compiler or static-analyzer warning is not a bug. It is possible with tools such as Visual Studio to require that rarely enabled warnings are considered errors. Do not report such cases as bugs. We do accept pull requests if you want to silence warnings issued by code analyzers, however.
|
||||||
|
|
||||||
We are committed to providing good documentation. We accept the lack of documentation or a misleading documentation as a bug (a 'documentation bug').
|
We are committed to providing good documentation. We accept the lack of documentation or a misleading documentation as a bug (a 'documentation bug').
|
||||||
|
|
||||||
|
An unexpected poor software performance can be accepted as a bug (a 'performance bug').
|
||||||
|
|
||||||
We accept the identification of an issue by a sanitizer or some checker tool (e.g., valgrind) as a bug, but you must first ensure that it is not a false positive.
|
We accept the identification of an issue by a sanitizer or some checker tool (e.g., valgrind) as a bug, but you must first ensure that it is not a false positive.
|
||||||
|
|
||||||
We recommend that you run your tests using different optimization levels.
|
We recommend that you run your tests using different optimization levels. In particular, we recommend your run tests with the simdjson library and you code compiled in debug mode. The simdjson then sets the SIMDJSON_DEVELOPMENT_CHECKS macro to 1, and this triggers additional checks on your code and on the internals of the library. If possible, we recommend that you run tests with sanitizers (e.g., see [No more leaks with sanitize flags in gcc and clang](https://lemire.me/blog/2016/04/20/no-more-leaks-with-sanitize-flags-in-gcc-and-clang/)). You can compile the library with sanitizers for debugging purposes (e.g., set SIMDJSON_SANITIZE to ON using CMake), but you should also turn on sanitizers on your own code. You may also use tools like valgrind or the commercial equivalent.
|
||||||
|
|
||||||
Before reporting a bug, please ensure that you have read our documentation.
|
Before reporting a bug, please ensure that you have read our documentation.
|
||||||
|
|
||||||
**To Reproduce**
|
**To Reproduce**
|
||||||
Steps to reproduce the behaviour: provide a code sample if possible.
|
Steps to reproduce the behaviour: provide a code sample if possible. Please provide a complete test with data. Remember that a bug is either a failure to build or an unexpected result when running the code.
|
||||||
|
|
||||||
If we cannot reproduce the issue, then we cannot address it. Note that a stack trace from your own program is not enough. A sample of your source code is insufficient: please provide a complete test for us to reproduce the issue. Please reduce the issue: use as small and as simple an example of the bug as possible.
|
If we cannot reproduce the issue, then we cannot address it. Note that a stack trace from your own program is not enough. A sample of your source code is insufficient: please provide a complete test for us to reproduce the issue. Please reduce the issue: use as small and as simple an example of the bug as possible.
|
||||||
|
|
||||||
@@ -51,6 +53,6 @@ We support up-to-date 64-bit ARM and x64 FreeBSD, macOS, Windows and Linux syste
|
|||||||
|
|
||||||
**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
|
If you plan to contribute to simdjson, please read our guide:
|
||||||
* CONTRIBUTING guide: https://github.com/simdjson/simdjson/blob/master/CONTRIBUTING.md and 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
|
* HACKING guide: https://github.com/simdjson/simdjson/blob/master/HACKING.md
|
||||||
|
|||||||
@@ -0,0 +1,33 @@
|
|||||||
|
name: Debian
|
||||||
|
|
||||||
|
on: [push, pull_request]
|
||||||
|
|
||||||
|
defaults:
|
||||||
|
run:
|
||||||
|
shell: sh
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
pkg-config:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
container:
|
||||||
|
image: debian:testing
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: |
|
||||||
|
apt -y update
|
||||||
|
apt -y --no-install-recommends install g++ cmake make pkg-config
|
||||||
|
|
||||||
|
- name: Build and install
|
||||||
|
run: |
|
||||||
|
cmake -B build
|
||||||
|
cmake --build build
|
||||||
|
cmake --install build
|
||||||
|
|
||||||
|
- name: Test pkg-config
|
||||||
|
run: g++ examples/quickstart/quickstart.cpp $(pkg-config --cflags --libs simdjson)
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
name: Doxygen GitHub Pages
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
# Allows you to run this workflow manually from the Actions tab
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
pages: write
|
||||||
|
id-token: write
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
deploy:
|
||||||
|
environment:
|
||||||
|
name: github-pages
|
||||||
|
url: ${{ steps.deployment.outputs.page_url }}
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- name: Install Doxygen
|
||||||
|
run: sudo apt-get install doxygen graphviz -y
|
||||||
|
- run: mkdir docs
|
||||||
|
- name: Install theme
|
||||||
|
run: ./tools/prepare_doxygen.sh
|
||||||
|
- name: Generate Doxygen Documentation
|
||||||
|
run: doxygen
|
||||||
|
- name: Deploy to GitHub Pages
|
||||||
|
uses: peaceiris/actions-gh-pages@v3
|
||||||
|
with:
|
||||||
|
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
publish_dir: doc/api/html
|
||||||
@@ -24,7 +24,7 @@ jobs:
|
|||||||
implementations: haswell westmere fallback
|
implementations: haswell westmere fallback
|
||||||
UBSAN_OPTIONS: halt_on_error=1
|
UBSAN_OPTIONS: halt_on_error=1
|
||||||
MAXLEN: -max_len=4000
|
MAXLEN: -max_len=4000
|
||||||
CLANGVERSION: 11
|
CLANGVERSION: 15
|
||||||
# which optimization level to use for the sanitizer build (see build_fuzzer.variants.sh)
|
# which optimization level to use for the sanitizer build (see build_fuzzer.variants.sh)
|
||||||
OPTLEVEL: -O3
|
OPTLEVEL: -O3
|
||||||
|
|
||||||
@@ -32,7 +32,7 @@ jobs:
|
|||||||
- name: Install packages necessary for building
|
- name: Install packages necessary for building
|
||||||
run: |
|
run: |
|
||||||
sudo apt update
|
sudo apt update
|
||||||
sudo apt-get install --quiet ninja-build valgrind zip unzip
|
sudo apt-get install --quiet ninja-build valgrind zip unzip lsb-release wget software-properties-common gnupg
|
||||||
wget https://apt.llvm.org/llvm.sh
|
wget https://apt.llvm.org/llvm.sh
|
||||||
chmod +x llvm.sh
|
chmod +x llvm.sh
|
||||||
sudo ./llvm.sh $CLANGVERSION
|
sudo ./llvm.sh $CLANGVERSION
|
||||||
|
|||||||
@@ -1,34 +0,0 @@
|
|||||||
name: Macos (Xcode 11)
|
|
||||||
|
|
||||||
on: [push, pull_request]
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
macos-build:
|
|
||||||
if: >-
|
|
||||||
! contains(toJSON(github.event.commits.*.message), '[skip ci]') &&
|
|
||||||
! contains(toJSON(github.event.commits.*.message), '[skip github]')
|
|
||||||
runs-on: macos-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
- uses: actions/cache@v3
|
|
||||||
with:
|
|
||||||
path: dependencies/.cache
|
|
||||||
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
|
||||||
- name: Use cmake
|
|
||||||
run: |
|
|
||||||
xcversion select 11.7
|
|
||||||
mkdir builddebug &&
|
|
||||||
cd builddebug &&
|
|
||||||
cmake -DCMAKE_BUILD_TYPE=Debug -DSIMDJSON_GOOGLE_BENCHMARKS=OFF -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF .. &&
|
|
||||||
cmake --build . &&
|
|
||||||
ctest -j --output-on-failure -LE explicitonly &&
|
|
||||||
cd .. &&
|
|
||||||
mkdir build &&
|
|
||||||
cd build &&
|
|
||||||
cmake -DSIMDJSON_GOOGLE_BENCHMARKS=ON -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF -DCMAKE_INSTALL_PREFIX:PATH=destination .. &&
|
|
||||||
cmake --build . &&
|
|
||||||
ctest -j --output-on-failure -LE explicitonly &&
|
|
||||||
cmake --install . &&
|
|
||||||
echo -e '#include <simdjson.h>\nint main(int argc,char**argv) {simdjson::dom::parser parser;simdjson::dom::element tweets = parser.load(argv[1]); }' > tmp.cpp && c++ -Idestination/include -Ldestination/lib -std=c++17 -Wl,-rpath,destination/lib -o linkandrun tmp.cpp -lsimdjson && ./linkandrun jsonexamples/twitter.json &&
|
|
||||||
cd ../tests/installation_tests/find &&
|
|
||||||
mkdir build && cd build && cmake -DCMAKE_INSTALL_PREFIX:PATH=../../../build/destination .. && cmake --build .
|
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
name: Ubuntu s390x (GCC 11)
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- uses: uraimo/run-on-arch-action@v2
|
||||||
|
name: Test
|
||||||
|
id: runcmd
|
||||||
|
with:
|
||||||
|
arch: s390x
|
||||||
|
distro: ubuntu_latest
|
||||||
|
githubToken: ${{ github.token }}
|
||||||
|
install: |
|
||||||
|
apt-get update -q -y
|
||||||
|
apt-get install -y cmake make g++
|
||||||
|
run: |
|
||||||
|
cmake -DCMAKE_BUILD_TYPE=Release -B build
|
||||||
|
cmake --build build -j=2
|
||||||
|
ctest --output-on-failure --test-dir build
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
name: Performance check on Ubuntu 18.04 CI (GCC 7)
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- master
|
|
||||||
pull_request:
|
|
||||||
branches:
|
|
||||||
- master
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
ubuntu-build:
|
|
||||||
if: >-
|
|
||||||
! contains(toJSON(github.event.commits.*.message), '[skip ci]') &&
|
|
||||||
! contains(toJSON(github.event.commits.*.message), '[skip github]')
|
|
||||||
runs-on: ubuntu-18.04
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
- uses: actions/cache@v3
|
|
||||||
with:
|
|
||||||
path: dependencies/.cache
|
|
||||||
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
|
||||||
- name: Use cmake
|
|
||||||
run: |
|
|
||||||
mkdir build &&
|
|
||||||
cd build &&
|
|
||||||
cmake -DSIMDJSON_DEVELOPER_MODE=ON -DSIMDJSON_ENABLE_DOM_CHECKPERF=ON -DSIMDJSON_GOOGLE_BENCHMARKS=ON -DBUILD_SHARED_LIBS=OFF -DCMAKE_INSTALL_PREFIX:PATH=destination .. &&
|
|
||||||
cmake --build . --target checkperf &&
|
|
||||||
ctest --output-on-failure -R checkperf ubuntu18-checkperf.yml
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
name: Ubuntu 18.04 CI (GCC 7)
|
|
||||||
|
|
||||||
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-18.04
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
- uses: actions/cache@v3
|
|
||||||
with:
|
|
||||||
path: dependencies/.cache
|
|
||||||
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
|
||||||
- name: Use cmake
|
|
||||||
run: |
|
|
||||||
mkdir build &&
|
|
||||||
cd build &&
|
|
||||||
cmake -DSIMDJSON_DEVELOPER_MODE=ON -DSIMDJSON_GOOGLE_BENCHMARKS=ON -DBUILD_SHARED_LIBS=OFF -DCMAKE_INSTALL_PREFIX:PATH=destination .. &&
|
|
||||||
cmake --build . &&
|
|
||||||
ctest -j --output-on-failure -LE explicitonly &&
|
|
||||||
make install &&
|
|
||||||
echo -e '#include <simdjson.h>\nint main(int argc,char**argv) {simdjson::dom::parser parser;simdjson::dom::element tweets = parser.load(argv[1]); }' > tmp.cpp && c++ -Idestination/include -Ldestination/lib -std=c++17 -Wl,-rpath,destination/lib -o linkandrun tmp.cpp -lsimdjson && ./linkandrun jsonexamples/twitter.json
|
|
||||||
@@ -14,10 +14,17 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
path: dependencies/.cache
|
path: dependencies/.cache
|
||||||
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
||||||
- name: Use cmake
|
- name: Use cmake with address sanitizer
|
||||||
run: |
|
run: |
|
||||||
mkdir builddebug &&
|
mkdir builddebug &&
|
||||||
cd builddebug &&
|
cd builddebug &&
|
||||||
cmake -DSIMDJSON_SANITIZE=ON -DCMAKE_BUILD_TYPE=Debug -DSIMDJSON_GOOGLE_BENCHMARKS=OFF -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF .. &&
|
cmake -DSIMDJSON_SANITIZE=ON -DCMAKE_BUILD_TYPE=Debug -DSIMDJSON_GOOGLE_BENCHMARKS=OFF -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF .. &&
|
||||||
cmake --build . &&
|
cmake --build . &&
|
||||||
ctest -j --output-on-failure -LE explicitonly
|
ctest -j --output-on-failure -LE explicitonly
|
||||||
|
- name: Use cmake with undefined sanitizer
|
||||||
|
run: |
|
||||||
|
mkdir builddebugundefsani &&
|
||||||
|
cd builddebugundefsani &&
|
||||||
|
cmake -DSIMDJSON_SANITIZE_UNDEFINED=ON -DCMAKE_BUILD_TYPE=Debug -DSIMDJSON_GOOGLE_BENCHMARKS=OFF -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF .. &&
|
||||||
|
cmake --build . &&
|
||||||
|
ctest -j --output-on-failure -LE explicitonly
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
name: Ubuntu 18.04 CI (LLVM 7)
|
name: Ubuntu 22.04 CI (CLANG 14)
|
||||||
|
|
||||||
on: [push, pull_request]
|
on: [push, pull_request]
|
||||||
|
|
||||||
@@ -7,25 +7,19 @@ jobs:
|
|||||||
if: >-
|
if: >-
|
||||||
! contains(toJSON(github.event.commits.*.message), '[skip ci]') &&
|
! contains(toJSON(github.event.commits.*.message), '[skip ci]') &&
|
||||||
! contains(toJSON(github.event.commits.*.message), '[skip github]')
|
! contains(toJSON(github.event.commits.*.message), '[skip github]')
|
||||||
runs-on: ubuntu-18.04
|
runs-on: ubuntu-22.04
|
||||||
|
|
||||||
env:
|
|
||||||
CC: clang-7
|
|
||||||
CXX: clang++-7
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
- uses: actions/cache@v3
|
- uses: actions/cache@v3
|
||||||
with:
|
with:
|
||||||
path: dependencies/.cache
|
path: dependencies/.cache
|
||||||
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
||||||
- name: install clang 7
|
- name: Install clang++-14
|
||||||
run: |
|
run: sudo apt-get install -y clang++-14
|
||||||
sudo apt update
|
|
||||||
sudo apt install clang-7
|
|
||||||
- name: Use cmake
|
- name: Use cmake
|
||||||
run: |
|
run: |
|
||||||
mkdir build &&
|
mkdir build &&
|
||||||
cd build &&
|
cd build &&
|
||||||
cmake -DSIMDJSON_DEVELOPER_MODE=ON -DSIMDJSON_GOOGLE_BENCHMARKS=ON -DBUILD_SHARED_LIBS=OFF -DCMAKE_INSTALL_PREFIX:PATH=destination .. &&
|
CXX=clang++-14 cmake -DSIMDJSON_DEVELOPER_MODE=ON .. &&
|
||||||
cmake --build . &&
|
cmake --build . &&
|
||||||
ctest -j --output-on-failure -LE explicitonly
|
ctest -j --output-on-failure -LE explicitonly
|
||||||
+7
-8
@@ -1,25 +1,24 @@
|
|||||||
name: Ubuntu 18.04 CI (GCC 7) with Thread Sanitizer
|
name: Ubuntu 22.04 CI GCC 12 with GLIBCXX_ASSERTIONS
|
||||||
|
|
||||||
on: [push, pull_request]
|
on: [push, pull_request]
|
||||||
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
ubuntu-build:
|
ubuntu-build:
|
||||||
if: >-
|
if: >-
|
||||||
! contains(toJSON(github.event.commits.*.message), '[skip ci]') &&
|
! contains(toJSON(github.event.commits.*.message), '[skip ci]') &&
|
||||||
! contains(toJSON(github.event.commits.*.message), '[skip github]')
|
! contains(toJSON(github.event.commits.*.message), '[skip github]')
|
||||||
runs-on: ubuntu-18.04
|
runs-on: ubuntu-22.04
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
- uses: actions/cache@v3
|
- uses: actions/cache@v3
|
||||||
with:
|
with:
|
||||||
path: dependencies/.cache
|
path: dependencies/.cache
|
||||||
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
||||||
|
- name: Install gcc12
|
||||||
|
run: sudo apt-get install -y g++-12
|
||||||
- name: Use cmake
|
- name: Use cmake
|
||||||
run: |
|
run: |
|
||||||
mkdir build &&
|
mkdir build &&
|
||||||
cd build &&
|
cd build &&
|
||||||
cmake -DSIMDJSON_DEVELOPER_MODE=ON -DSIMDJSON_SANITIZE_THREADS=ON .. &&
|
CXX=g++-12 cmake -DCMAKE_BUILD_TYPE=Debug -DSIMDJSON_GLIBCXX_ASSERTIONS=ON -DSIMDJSON_GOOGLE_BENCHMARKS=OFF -DSIMDJSON_DEVELOPER_MODE=ON .. &&
|
||||||
cmake --build . --target document_stream_tests --target ondemand_document_stream_tests --target parse_many_test &&
|
cmake --build . &&
|
||||||
ctest --output-on-failure -R parse_many_test &&
|
ctest . -E avoid_
|
||||||
ctest --output-on-failure -R document_stream_tests
|
|
||||||
Vendored
+2
-1
@@ -96,6 +96,7 @@
|
|||||||
"future": "cpp",
|
"future": "cpp",
|
||||||
"queue": "cpp",
|
"queue": "cpp",
|
||||||
"shared_mutex": "cpp",
|
"shared_mutex": "cpp",
|
||||||
"ranges": "cpp"
|
"ranges": "cpp",
|
||||||
|
"span": "cpp"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+46
-8
@@ -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 2.2.1
|
VERSION 3.1.7
|
||||||
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 "13.0.0" CACHE STRING "simdjson library version")
|
set(SIMDJSON_LIB_VERSION "15.0.0" CACHE STRING "simdjson library version")
|
||||||
set(SIMDJSON_LIB_SOVERSION "13" CACHE STRING "simdjson library soversion")
|
set(SIMDJSON_LIB_SOVERSION "15" CACHE STRING "simdjson library soversion")
|
||||||
|
|
||||||
option(SIMDJSON_ENABLE_THREADS "Link with thread support" ON)
|
option(SIMDJSON_ENABLE_THREADS "Link with thread support" ON)
|
||||||
|
|
||||||
@@ -95,6 +95,21 @@ if(
|
|||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
# GCC and Clang have horrendous Debug builds when using SIMD.
|
||||||
|
# A common fix is to use '-Og' instead.
|
||||||
|
# bug https://gcc.gnu.org/bugzilla/show_bug.cgi?id=54412
|
||||||
|
if(
|
||||||
|
(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR
|
||||||
|
CMAKE_CXX_COMPILER_ID STREQUAL "Clang" OR
|
||||||
|
CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang")
|
||||||
|
)
|
||||||
|
message(STATUS "Adding -Og to compile flag")
|
||||||
|
simdjson_add_props(
|
||||||
|
target_compile_options PRIVATE
|
||||||
|
$<$<CONFIG:DEBUG>:-Og>
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
if(SIMDJSON_ENABLE_THREADS)
|
if(SIMDJSON_ENABLE_THREADS)
|
||||||
find_package(Threads REQUIRED)
|
find_package(Threads REQUIRED)
|
||||||
simdjson_add_props(target_link_libraries PUBLIC Threads::Threads)
|
simdjson_add_props(target_link_libraries PUBLIC Threads::Threads)
|
||||||
@@ -149,7 +164,25 @@ install(
|
|||||||
EXPORT simdjsonTargets
|
EXPORT simdjsonTargets
|
||||||
NAMESPACE simdjson::
|
NAMESPACE simdjson::
|
||||||
DESTINATION "${SIMDJSON_INSTALL_CMAKEDIR}"
|
DESTINATION "${SIMDJSON_INSTALL_CMAKEDIR}"
|
||||||
COMPONENT example_Development
|
COMPONENT simdjson_Development
|
||||||
|
)
|
||||||
|
|
||||||
|
# pkg-config
|
||||||
|
include(cmake/JoinPaths.cmake)
|
||||||
|
join_paths(PKGCONFIG_INCLUDEDIR "\${prefix}" "${CMAKE_INSTALL_INCLUDEDIR}")
|
||||||
|
join_paths(PKGCONFIG_LIBDIR "\${prefix}" "${CMAKE_INSTALL_LIBDIR}")
|
||||||
|
|
||||||
|
if(SIMDJSON_ENABLE_THREADS)
|
||||||
|
set(PKGCONFIG_CFLAGS "-DSIMDJSON_THREADS_ENABLED=1")
|
||||||
|
if(CMAKE_THREAD_LIBS_INIT)
|
||||||
|
set(PKGCONFIG_LIBS_PRIVATE "Libs.private: ${CMAKE_THREAD_LIBS_INIT}")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
configure_file("simdjson.pc.in" "simdjson.pc" @ONLY)
|
||||||
|
install(
|
||||||
|
FILES "${CMAKE_CURRENT_BINARY_DIR}/simdjson.pc"
|
||||||
|
DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig"
|
||||||
)
|
)
|
||||||
|
|
||||||
#
|
#
|
||||||
@@ -170,11 +203,14 @@ endif()
|
|||||||
|
|
||||||
# ---- Developer mode extras ----
|
# ---- Developer mode extras ----
|
||||||
|
|
||||||
|
if(is_top_project AND NOT SIMDJSON_DEVELOPER_MODE)
|
||||||
|
message(STATUS "Building only the library. Advanced users and contributors may want to turn SIMDJSON_DEVELOPER_MODE to ON, e.g., via -D SIMDJSON_DEVELOPER_MODE=ON.")
|
||||||
|
elseif(SIMDJSON_DEVELOPER_MODE AND NOT is_top_project)
|
||||||
|
message(AUTHOR_WARNING "Developer mode in simdjson is intended for the developers of simdjson")
|
||||||
|
endif()
|
||||||
|
|
||||||
if(NOT SIMDJSON_DEVELOPER_MODE)
|
if(NOT SIMDJSON_DEVELOPER_MODE)
|
||||||
message(STATUS "Building only the library. Advanced users may want to turn SIMDJSON_DEVELOPER_MODE to ON, e.g., via -D SIMDJSON_DEVELOPER_MODE=ON.")
|
|
||||||
return()
|
return()
|
||||||
elseif(NOT is_top_project)
|
|
||||||
message(AUTHOR_WARNING "Developer mode is intended for developers of simdjson")
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
simdjson_apply_props(simdjson-internal-flags)
|
simdjson_apply_props(simdjson-internal-flags)
|
||||||
@@ -215,7 +251,9 @@ add_subdirectory(singleheader)
|
|||||||
#
|
#
|
||||||
add_subdirectory(tests)
|
add_subdirectory(tests)
|
||||||
add_subdirectory(examples)
|
add_subdirectory(examples)
|
||||||
add_subdirectory(benchmark)
|
if(CMAKE_SIZEOF_VOID_P EQUAL 8) # we only include the benchmarks on 64-bit systems.
|
||||||
|
add_subdirectory(benchmark)
|
||||||
|
endif()
|
||||||
add_subdirectory(fuzz)
|
add_subdirectory(fuzz)
|
||||||
|
|
||||||
#
|
#
|
||||||
|
|||||||
+1
-1
@@ -54,7 +54,7 @@ Contributors are encouraged to :
|
|||||||
- Document their changes. Though we do not enforce a rule regarding code comments, we prefer that non-trivial algorithms and techniques be somewhat documented in the code.
|
- Document their changes. Though we do not enforce a rule regarding code comments, we prefer that non-trivial algorithms and techniques be somewhat documented in the code.
|
||||||
- Follow as much as possible the existing code style. We do not enforce a specific code style, but we prefer consistency.
|
- Follow as much as possible the existing code style. We do not enforce a specific code style, but we prefer consistency.
|
||||||
- Modify as few lines of code as possible when working on an issue. The more lines you modify, the harder it is for your fellow human beings to understand what is going on.
|
- Modify as few lines of code as possible when working on an issue. The more lines you modify, the harder it is for your fellow human beings to understand what is going on.
|
||||||
- Tools may report "problems" with the code, but we never delegate programming to tools: if there is a problem with the code, we need to understand it. Thus we will not "fix" code merely to please a static analyzer if we do not understand.
|
- Tools may report "problems" with the code, but we never delegate programming to tools: if there is a problem with the code, we need to understand it. Thus we will not "fix" code merely to please a static analyzer.
|
||||||
- Provide tests for any new feature. We will not merge a new feature without tests.
|
- Provide tests for any new feature. We will not merge a new feature without tests.
|
||||||
|
|
||||||
Pull Requests
|
Pull Requests
|
||||||
|
|||||||
@@ -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 = "2.2.1"
|
PROJECT_NUMBER = "3.1.7"
|
||||||
|
|
||||||
# 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
|
||||||
@@ -829,7 +829,7 @@ WARN_LOGFILE =
|
|||||||
# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
|
# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
|
||||||
# Note: If this tag is empty the current directory is searched.
|
# Note: If this tag is empty the current directory is searched.
|
||||||
|
|
||||||
INPUT = doc include
|
INPUT = doc include/simdjson include/simdjson/dom include/simdjson/generic
|
||||||
|
|
||||||
# This tag can be used to specify the character encoding of the source files
|
# This tag can be used to specify the character encoding of the source files
|
||||||
# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
|
# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
|
||||||
@@ -1246,7 +1246,10 @@ HTML_STYLESHEET =
|
|||||||
# list). For an example see the documentation.
|
# list). For an example see the documentation.
|
||||||
# This tag requires that the tag GENERATE_HTML is set to YES.
|
# This tag requires that the tag GENERATE_HTML is set to YES.
|
||||||
|
|
||||||
HTML_EXTRA_STYLESHEET =
|
|
||||||
|
HTML_EXTRA_STYLESHEET = theme/doxygen-awesome.css \
|
||||||
|
theme/doxygen-awesome-sidebar-only.css \
|
||||||
|
theme/doxygen-awesome-sidebar-only-darkmode-toggle.css
|
||||||
|
|
||||||
# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
|
# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
|
||||||
# other source files which should be copied to the HTML output directory. Note
|
# other source files which should be copied to the HTML output directory. Note
|
||||||
@@ -1256,7 +1259,10 @@ HTML_EXTRA_STYLESHEET =
|
|||||||
# files will be copied as-is; there are no commands or markers available.
|
# files will be copied as-is; there are no commands or markers available.
|
||||||
# This tag requires that the tag GENERATE_HTML is set to YES.
|
# This tag requires that the tag GENERATE_HTML is set to YES.
|
||||||
|
|
||||||
HTML_EXTRA_FILES =
|
HTML_EXTRA_FILES = theme/doxygen-awesome-darkmode-toggle.js \
|
||||||
|
theme/doxygen-awesome-interactive-toc.js \
|
||||||
|
theme/doxygen-awesome-fragment-copy-button.js \
|
||||||
|
theme/doxygen-awesome-paragraph-link.js
|
||||||
|
|
||||||
# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
|
# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
|
||||||
# will adjust the colors in the style sheet and background images according to
|
# will adjust the colors in the style sheet and background images according to
|
||||||
@@ -1543,7 +1549,7 @@ DISABLE_INDEX = NO
|
|||||||
# The default value is: NO.
|
# The default value is: NO.
|
||||||
# This tag requires that the tag GENERATE_HTML is set to YES.
|
# This tag requires that the tag GENERATE_HTML is set to YES.
|
||||||
|
|
||||||
GENERATE_TREEVIEW = NO
|
GENERATE_TREEVIEW = YES
|
||||||
|
|
||||||
# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that
|
# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that
|
||||||
# doxygen will group on one line in the generated HTML documentation.
|
# doxygen will group on one line in the generated HTML documentation.
|
||||||
|
|||||||
+18
-5
@@ -1,3 +1,4 @@
|
|||||||
|
|
||||||
Hacking simdjson
|
Hacking simdjson
|
||||||
================
|
================
|
||||||
|
|
||||||
@@ -6,6 +7,16 @@ Here is wisdom about how to build, test and run simdjson from within the reposit
|
|||||||
If you plan to contribute to simdjson, please read our [CONTRIBUTING](https://github.com/simdjson/simdjson/blob/master/CONTRIBUTING.md) guide.
|
If you plan to contribute to simdjson, please read our [CONTRIBUTING](https://github.com/simdjson/simdjson/blob/master/CONTRIBUTING.md) guide.
|
||||||
|
|
||||||
|
|
||||||
|
- [Design notes](#design-notes)
|
||||||
|
- [Developer mode](#developer-mode)
|
||||||
|
- [Directory Structure and Source](#directory-structure-and-source)
|
||||||
|
- [Runtime Dispatching](#runtime-dispatching)
|
||||||
|
- [Regenerating Single-Header Files](#regenerating-single-header-files)
|
||||||
|
- [Usage (CMake on 64-bit platforms like Linux, FreeBSD or macOS)](#usage-cmake-on-64-bit-platforms-like-linux-freebsd-or-macos)
|
||||||
|
- [Usage (CMake on 64-bit Windows using Visual Studio 2019)](#usage-cmake-on-64-bit-windows-using-visual-studio-2019)
|
||||||
|
- [Various References](#various-references)
|
||||||
|
|
||||||
|
|
||||||
Design notes
|
Design notes
|
||||||
------------------------------
|
------------------------------
|
||||||
|
|
||||||
@@ -82,7 +93,7 @@ Other important files and directories:
|
|||||||
* **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).
|
||||||
* **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, unnnecessary 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:
|
||||||
```bash
|
```bash
|
||||||
mkdir build
|
mkdir build
|
||||||
cd build
|
cd build
|
||||||
@@ -114,7 +125,7 @@ Other important files and directories:
|
|||||||
* `json2json mydoc.json` parses the document, constructs a model and then dumps back the result to standard output.
|
* `json2json mydoc.json` parses the document, constructs a model and then dumps back the result to standard output.
|
||||||
* `json2json -d mydoc.json` parses the document, constructs a model and then dumps model (as a tape) to standard output. The tape format is described in the accompanying file `tape.md`.
|
* `json2json -d mydoc.json` parses the document, constructs a model and then dumps model (as a tape) to standard output. The tape format is described in the accompanying file `tape.md`.
|
||||||
* `minify mydoc.json` minifies the JSON document, outputting the result to standard output. Minifying means to remove the unneeded white space characters.
|
* `minify mydoc.json` minifies the JSON document, outputting the result to standard output. Minifying means to remove the unneeded white space characters.
|
||||||
*`jsonpointer mydoc.json <jsonpath> <jsonpath> ... <jsonpath>` parses the document, constructs a model and then processes a series of [JSON Pointer paths](https://tools.ietf.org/html/rfc6901). The result is itself a JSON document.
|
* `jsonpointer mydoc.json <jsonpath> <jsonpath> ... <jsonpath>` parses the document, constructs a model and then processes a series of [JSON Pointer paths](https://tools.ietf.org/html/rfc6901). The result is itself a JSON document.
|
||||||
|
|
||||||
|
|
||||||
> **Don't modify the files in singleheader/ directly; these are automatically generated.**
|
> **Don't modify the files in singleheader/ directly; these are automatically generated.**
|
||||||
@@ -193,7 +204,7 @@ point it gets included (but only once per header). singleheader/simdjson.cpp is
|
|||||||
src/simdjson.cpp the same way, except files under generic/ may be included and copy/pasted multiple
|
src/simdjson.cpp the same way, except files under generic/ may be included and copy/pasted multiple
|
||||||
times.
|
times.
|
||||||
|
|
||||||
### Usage (CMake on 64-bit platforms like Linux, FreeBSD or macOS)
|
## Usage (CMake on 64-bit platforms like Linux, FreeBSD or macOS)
|
||||||
|
|
||||||
Requirements: In addition to git, we require a recent version of CMake as well as bash.
|
Requirements: In addition to git, we require a recent version of CMake as well as bash.
|
||||||
|
|
||||||
@@ -256,7 +267,9 @@ Note that the name of directory (`build`) is arbitrary, you can name it as you w
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
### Usage (CMake on 64-bit Windows using Visual Studio 2019)
|
## Usage (CMake on 64-bit Windows using Visual Studio 2019 or better)
|
||||||
|
|
||||||
|
Recent versions of Visual Studio support CMake natively, [please refer to the Visual Studio documentation](https://learn.microsoft.com/en-us/cpp/build/cmake-projects-in-visual-studio?view=msvc-170).
|
||||||
|
|
||||||
We assume you have a common 64-bit Windows PC with at least Visual Studio 2019.
|
We assume you have a common 64-bit Windows PC with at least Visual Studio 2019.
|
||||||
|
|
||||||
@@ -285,7 +298,7 @@ Furthermore, if you have installed LLVM clang on Windows, for example as a compo
|
|||||||
- `cmake --build . -config Release`
|
- `cmake --build . -config Release`
|
||||||
|
|
||||||
|
|
||||||
### Various References
|
## Various References
|
||||||
|
|
||||||
- [How to implement atoi using SIMD?](https://stackoverflow.com/questions/35127060/how-to-implement-atoi-using-simd)
|
- [How to implement atoi using SIMD?](https://stackoverflow.com/questions/35127060/how-to-implement-atoi-using-simd)
|
||||||
- [Parsing JSON is a Minefield 💣](http://seriot.ch/parsing_json.php)
|
- [Parsing JSON is a Minefield 💣](http://seriot.ch/parsing_json.php)
|
||||||
|
|||||||
@@ -186,7 +186,7 @@
|
|||||||
same "printed page" as the copyright notice for easier
|
same "printed page" as the copyright notice for easier
|
||||||
identification within third-party archives.
|
identification within third-party archives.
|
||||||
|
|
||||||
Copyright 2018-2019 The simdjson authors
|
Copyright 2018-2023 The simdjson authors
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
|
|
||||||
/badge.svg)
|
|
||||||
[/badge.svg)](https://simdjson.org/plots.html)
|
[/badge.svg)](https://simdjson.org/plots.html)
|
||||||

|

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

|

|
||||||
[![][license img]][license] [](https://simdjson.org/api/2.0.0/index.html)
|
[![][license img]][license]
|
||||||
|
|
||||||
|
[](https://simdjson.github.io/simdjson/)
|
||||||
|
|
||||||
simdjson : Parsing gigabytes of JSON per second
|
simdjson : Parsing gigabytes of JSON per second
|
||||||
===============================================
|
===============================================
|
||||||
@@ -116,7 +118,14 @@ Real-world usage
|
|||||||
- [Shopify HeapProfiler](https://github.com/Shopify/heap-profiler)
|
- [Shopify HeapProfiler](https://github.com/Shopify/heap-profiler)
|
||||||
- [StarRocks](https://github.com/StarRocks/starrocks)
|
- [StarRocks](https://github.com/StarRocks/starrocks)
|
||||||
- [Microsoft FishStore](https://github.com/microsoft/FishStore)
|
- [Microsoft FishStore](https://github.com/microsoft/FishStore)
|
||||||
|
- [Intel PCM](https://github.com/intel/pcm)
|
||||||
|
- [WatermelonDB](https://github.com/Nozbe/WatermelonDB)
|
||||||
|
- [Apache Doris](https://github.com/apache/doris)
|
||||||
|
- [Dgraph](https://github.com/dgraph-io/dgraph)
|
||||||
|
- [UJRPC](https://github.com/unum-cloud/ujrpc)
|
||||||
|
- [fastgltf](https://github.com/spnda/fastgltf)
|
||||||
|
- [Clang Build Analyzer](https://github.com/aras-p/ClangBuildAnalyzer)
|
||||||
|
- [vast](https://github.com/tenzir/vast)
|
||||||
|
|
||||||
If you are planning to use simdjson in a product, please work from one of our releases.
|
If you are planning to use simdjson in a product, please work from one of our releases.
|
||||||
|
|
||||||
@@ -139,9 +148,12 @@ We distinguish between "bindings" (which just wrap the C++ code) and a port to a
|
|||||||
- [simdjson-go](https://github.com/minio/simdjson-go): Go port using Golang assembly.
|
- [simdjson-go](https://github.com/minio/simdjson-go): Go port using Golang assembly.
|
||||||
- [rcppsimdjson](https://github.com/eddelbuettel/rcppsimdjson): R bindings.
|
- [rcppsimdjson](https://github.com/eddelbuettel/rcppsimdjson): R bindings.
|
||||||
- [simdjson_erlang](https://github.com/ChomperT/simdjson_erlang): erlang bindings.
|
- [simdjson_erlang](https://github.com/ChomperT/simdjson_erlang): erlang bindings.
|
||||||
|
- [simdjsone](https://github.com/saleyn/simdjsone): erlang bindings.
|
||||||
- [lua-simdjson](https://github.com/FourierTransformer/lua-simdjson): lua bindings.
|
- [lua-simdjson](https://github.com/FourierTransformer/lua-simdjson): lua bindings.
|
||||||
- [hermes-json](https://hackage.haskell.org/package/hermes-json): haskell bindings.
|
- [hermes-json](https://hackage.haskell.org/package/hermes-json): haskell bindings.
|
||||||
- [simdjzon](https://github.com/travisstaloch/simdjzon): zig port.
|
- [simdjzon](https://github.com/travisstaloch/simdjzon): zig port.
|
||||||
|
- [JSON-Simd](https://github.com/rawleyfowler/JSON-simd): Raku bindings.
|
||||||
|
- [JSON::SIMD](https://metacpan.org/pod/JSON::SIMD): Perl bindings; fully-featured JSON module that uses simdjson for decoding.
|
||||||
|
|
||||||
About simdjson
|
About simdjson
|
||||||
--------------
|
--------------
|
||||||
@@ -184,7 +196,7 @@ License
|
|||||||
|
|
||||||
This code is made available under the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0.html).
|
This code is made available under the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0.html).
|
||||||
|
|
||||||
Under Windows, we build some tools using the windows/dirent_portable.h file (which is outside our library code): it under the liberal (business-friendly) MIT license.
|
Under Windows, we build some tools using the windows/dirent_portable.h file (which is outside our library code): it is under the liberal (business-friendly) MIT license.
|
||||||
|
|
||||||
For compilers that do not support [C++17](https://en.wikipedia.org/wiki/C%2B%2B17), we bundle the string-view library which is published under the [Boost license](http://www.boost.org/LICENSE_1_0.txt). Like the Apache license, the Boost license is a permissive license allowing commercial redistribution.
|
For compilers that do not support [C++17](https://en.wikipedia.org/wiki/C%2B%2B17), we bundle the string-view library which is published under the [Boost license](http://www.boost.org/LICENSE_1_0.txt). Like the Apache license, the Boost license is a permissive license allowing commercial redistribution.
|
||||||
|
|
||||||
|
|||||||
-69
@@ -1,69 +0,0 @@
|
|||||||
# 0.5
|
|
||||||
|
|
||||||
## Highlights
|
|
||||||
|
|
||||||
Performance
|
|
||||||
* Faster and simpler UTF-8 validation with the lookup4 algorithm https://github.com/simdjson/simdjson/pull/993
|
|
||||||
* We improved the performance of simdjson under Visual Studio by about 25%. Users will still get better performance with clang-cl (+30%) but the gap has been reduced. https://github.com/simdjson/simdjson/pull/1031
|
|
||||||
|
|
||||||
Code usability
|
|
||||||
* In `parse_many`, when parsing streams of JSON documetns, we give to the users runtime control as to whether threads are used (via the parser.threaded attribute). https://github.com/simdjson/simdjson/issues/925
|
|
||||||
* Prefixed public macros to avoid name clashes with other libraries. https://github.com/simdjson/simdjson/issues/1035
|
|
||||||
* Better documentation regarding package managers (brew, MSYS2, conan, apt, vcpkg, FreeBSD package manager, etc.).
|
|
||||||
* Better documentation regarding CMake usage.
|
|
||||||
|
|
||||||
Standards
|
|
||||||
* We improved standard compliance with respect to both the JSON RFC 8259 and JSON Pointer RFC 6901. We added the at_pointer method to nodes for standard-compliant JSON Pointer queries. The legacy `at(std::string_view)` method remains but is deprecated since it is not standard-compliant as per RFC 6901.
|
|
||||||
* We removed computed GOTOs without sacrificing performance thus improving the C++ standard compliance (since computed GOTOs are compiler-specific extensions).
|
|
||||||
* Better support for C++20 https://github.com/simdjson/simdjson/pull/1050
|
|
||||||
|
|
||||||
# 0.4
|
|
||||||
|
|
||||||
## Highlights
|
|
||||||
|
|
||||||
- Test coverage has been greatly improved and we have resolved many static-analysis warnings on different systems.
|
|
||||||
- We added a fast (8GB/s) minifier that works directly on JSON strings.
|
|
||||||
- We added fast (10GB/s) UTF-8 validator that works directly on strings (any strings, including non-JSON).
|
|
||||||
- The array and object elements have a constant-time size() method.
|
|
||||||
- Performance improvements to the API (type(), get<>()).
|
|
||||||
- The parse_many function (ndjson) has been entirely reworked. It now uses a single secondary thread instead of several new threads.
|
|
||||||
- We have introduced a faster UTF-8 validation algorithm (lookup3) for all kernels (ARM, x64 SSE, x64 AVX).
|
|
||||||
- C++11 support for older compilers and systems.
|
|
||||||
- FreeBSD support (and tests).
|
|
||||||
- We support the clang front-end compiler (clangcl) under Visual Studio.
|
|
||||||
- It is now possible to target ARM platforms under Visual Studio.
|
|
||||||
- The simdjson library will never abort or print to standard output/error.
|
|
||||||
|
|
||||||
# 0.3
|
|
||||||
|
|
||||||
## Highlights
|
|
||||||
|
|
||||||
- **Multi-Document Parsing:** Read a bundle of JSON documents (ndjson) 2-4x faster than doing it
|
|
||||||
individually. [API docs](https://github.com/simdjson/simdjson/blob/master/doc/basics.md#newline-delimited-json-ndjson-and-json-lines) / [Design Details](https://github.com/simdjson/simdjson/blob/master/doc/parse_many.md)
|
|
||||||
- **Simplified API:** The API has been completely revamped for ease of use, including a new JSON
|
|
||||||
navigation API and fluent support for error code *and* exception styles of error handling with a
|
|
||||||
single API. [Docs](https://github.com/simdjson/simdjson/blob/master/doc/basics.md#the-basics-loading-and-parsing-json-documents)
|
|
||||||
- **Exact Float Parsing:** Now simdjson parses floats flawlessly *without* any performance loss,
|
|
||||||
thanks to [great work by @michaeleisel and @lemire](https://github.com/simdjson/simdjson/pull/558).
|
|
||||||
[Blog Post](https://lemire.me/blog/2020/03/10/fast-float-parsing-in-practice/)
|
|
||||||
- **Even Faster:** The fastest parser got faster! With a [shiny new UTF-8 validator](https://github.com/simdjson/simdjson/pull/387)
|
|
||||||
and meticulously refactored SIMD core, simdjson 0.3 is 15% faster than before, running at 2.5 GB/s
|
|
||||||
(where 0.2 ran at 2.2 GB/s).
|
|
||||||
|
|
||||||
## Minor Highlights
|
|
||||||
|
|
||||||
- Fallback implementation: simdjson now has a non-SIMD fallback implementation, and can run even on
|
|
||||||
very old 64-bit machines.
|
|
||||||
- Automatic allocation: as part of API simplification, the parser no longer has to be preallocated--
|
|
||||||
it will adjust automatically when it encounters larger files.
|
|
||||||
- Runtime selection API: We've exposed simdjson's runtime CPU detection and implementation selection
|
|
||||||
as an API, so you can tell what implementation we detected and test with other implementations.
|
|
||||||
- Error handling your way: Whether you use exceptions or check error codes, simdjson lets you handle
|
|
||||||
errors in your style. APIs that can fail return simdjson_result<T>, letting you check the error
|
|
||||||
code before using the result. But if you are more comfortable with exceptions, skip the error code
|
|
||||||
and cast straight to T, and exceptions will be thrown automatically if an error happens. Use the
|
|
||||||
same API either way!
|
|
||||||
- Error chaining: We also worked to keep non-exception error-handling short and sweet. Instead of
|
|
||||||
having to check the error code after every single operation, now you can *chain* JSON navigation
|
|
||||||
calls like looking up an object field or array element, or casting to a string, so that you only
|
|
||||||
have to check the error code once at the very end.
|
|
||||||
@@ -564,7 +564,7 @@ static void error_code_twitter_default_profile(State& state) noexcept {
|
|||||||
for (dom::element tweet : tweets) {
|
for (dom::element tweet : tweets) {
|
||||||
dom::object user;
|
dom::object user;
|
||||||
if ((error = tweet["user"].get(user))) { return; }
|
if ((error = tweet["user"].get(user))) { return; }
|
||||||
bool default_profile;
|
bool default_profile{};
|
||||||
if ((error = user["default_profile"].get(default_profile))) { return; }
|
if ((error = user["default_profile"].get(default_profile))) { return; }
|
||||||
if (default_profile) {
|
if (default_profile) {
|
||||||
std::string_view screen_name;
|
std::string_view screen_name;
|
||||||
@@ -656,6 +656,31 @@ static void error_code_twitter_image_sizes(State& state) noexcept {
|
|||||||
}
|
}
|
||||||
BENCHMARK(error_code_twitter_image_sizes);
|
BENCHMARK(error_code_twitter_image_sizes);
|
||||||
|
|
||||||
|
static void parse_surrogate_pairs(State& state) {
|
||||||
|
// NOTE: This mostly exists to show there's a tiny benefit to
|
||||||
|
// loading and comparing both bytes of "\\u" simultaneously.
|
||||||
|
// (which should also reduce the compiled code size).
|
||||||
|
// The repeated surrogate pairs make this easier to measure.
|
||||||
|
dom::parser parser;
|
||||||
|
const std::string_view data = "\"\\uD834\\uDD1E\\uD834\\uDD1E\\uD834\\uDD1E\\uD834\\uDD1E\\uD834\\uDD1E\\uD834\\uDD1E\\uD834\\uDD1E\\uD834\\uDD1E\\uD834\\uDD1E\\uD834\\uDD1E\"";
|
||||||
|
padded_string docdata{data};
|
||||||
|
// we do not want mem. alloc. in the loop.
|
||||||
|
auto error = parser.allocate(docdata.size());
|
||||||
|
if (error) {
|
||||||
|
cout << error << endl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (simdjson_unused auto _ : state) {
|
||||||
|
dom::element doc;
|
||||||
|
if ((error = parser.parse(docdata).get(doc))) {
|
||||||
|
cerr << "could not parse string" << error << endl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
BENCHMARK(parse_surrogate_pairs);
|
||||||
|
|
||||||
|
|
||||||
#ifndef SIMDJSON_DISABLE_DEPRECATED_API
|
#ifndef SIMDJSON_DISABLE_DEPRECATED_API
|
||||||
|
|
||||||
SIMDJSON_PUSH_DISABLE_WARNINGS
|
SIMDJSON_PUSH_DISABLE_WARNINGS
|
||||||
|
|||||||
+101
-59
@@ -25,74 +25,116 @@ SIMDJSON_PUSH_DISABLE_ALL_WARNINGS
|
|||||||
#include <benchmark/benchmark.h>
|
#include <benchmark/benchmark.h>
|
||||||
|
|
||||||
SIMDJSON_POP_DISABLE_WARNINGS
|
SIMDJSON_POP_DISABLE_WARNINGS
|
||||||
#include "json2msgpack/simdjson_dom.h"
|
|
||||||
#include "json2msgpack/simdjson_ondemand.h"
|
#include "json2msgpack/simdjson_ondemand.h"
|
||||||
#include "json2msgpack/rapidjson.h"
|
#include "json2msgpack/simdjson_dom.h"
|
||||||
#include "json2msgpack/yyjson.h"
|
#include "json2msgpack/yyjson.h"
|
||||||
|
#include "json2msgpack/rapidjson.h"
|
||||||
|
#if SIMDJSON_COMPETITION_ONDEMAND_SAJSON
|
||||||
#include "json2msgpack/sajson.h"
|
#include "json2msgpack/sajson.h"
|
||||||
|
#endif // SIMDJSON_COMPETITION_ONDEMAND_SAJSON
|
||||||
#include "json2msgpack/nlohmann_json.h"
|
#include "json2msgpack/nlohmann_json.h"
|
||||||
|
|
||||||
|
#include "partial_tweets/simdjson_ondemand.h"
|
||||||
|
#include "partial_tweets/simdjson_dom.h"
|
||||||
|
#include "partial_tweets/yyjson.h"
|
||||||
|
#if SIMDJSON_COMPETITION_ONDEMAND_SAJSON
|
||||||
|
#include "partial_tweets/sajson.h"
|
||||||
|
#endif // SIMDJSON_COMPETITION_ONDEMAND_SAJSON
|
||||||
|
#include "partial_tweets/rapidjson.h"
|
||||||
|
#if SIMDJSON_COMPETITION_SAX
|
||||||
|
#include "partial_tweets/rapidjson_sax.h"
|
||||||
|
#endif // SIMDJSON_COMPETITION_SAX
|
||||||
|
#include "partial_tweets/nlohmann_json.h"
|
||||||
|
#if SIMDJSON_COMPETITION_SAX
|
||||||
|
#include "partial_tweets/nlohmann_json_sax.h"
|
||||||
|
#endif // SIMDJSON_COMPETITION_SAX
|
||||||
|
|
||||||
|
|
||||||
|
#include "distinct_user_id/simdjson_ondemand.h"
|
||||||
|
#include "distinct_user_id/simdjson_ondemand_json_pointer.h"
|
||||||
|
#include "distinct_user_id/simdjson_dom.h"
|
||||||
|
#include "distinct_user_id/simdjson_dom_json_pointer.h"
|
||||||
|
#include "distinct_user_id/yyjson.h"
|
||||||
|
#if SIMDJSON_COMPETITION_ONDEMAND_SAJSON
|
||||||
|
#include "distinct_user_id/sajson.h"
|
||||||
|
#endif // SIMDJSON_COMPETITION_ONDEMAND_SAJSON
|
||||||
|
#include "distinct_user_id/rapidjson.h"
|
||||||
|
#if SIMDJSON_COMPETITION_SAX
|
||||||
|
#include "distinct_user_id/rapidjson_sax.h"
|
||||||
|
#endif // SIMDJSON_COMPETITION_SAX
|
||||||
|
#include "distinct_user_id/nlohmann_json.h"
|
||||||
|
#if SIMDJSON_COMPETITION_SAX
|
||||||
|
#include "distinct_user_id/nlohmann_json_sax.h"
|
||||||
|
#endif // SIMDJSON_COMPETITION_SAX
|
||||||
|
|
||||||
|
#include "find_tweet/simdjson_ondemand.h"
|
||||||
|
#include "find_tweet/simdjson_dom.h"
|
||||||
|
#include "find_tweet/yyjson.h"
|
||||||
|
#if SIMDJSON_COMPETITION_ONDEMAND_SAJSON
|
||||||
|
#include "find_tweet/sajson.h"
|
||||||
|
#endif // SIMDJSON_COMPETITION_ONDEMAND_SAJSON
|
||||||
|
#include "find_tweet/rapidjson.h"
|
||||||
|
#if SIMDJSON_COMPETITION_SAX
|
||||||
|
#include "find_tweet/rapidjson_sax.h"
|
||||||
|
#endif // SIMDJSON_COMPETITION_SAX
|
||||||
|
#include "find_tweet/nlohmann_json.h"
|
||||||
|
#if SIMDJSON_COMPETITION_SAX
|
||||||
|
#include "find_tweet/nlohmann_json_sax.h"
|
||||||
|
#endif // SIMDJSON_COMPETITION_SAX
|
||||||
|
|
||||||
|
#include "top_tweet/simdjson_ondemand.h"
|
||||||
|
#include "top_tweet/simdjson_dom.h"
|
||||||
|
#include "top_tweet/yyjson.h"
|
||||||
|
#if SIMDJSON_COMPETITION_ONDEMAND_SAJSON
|
||||||
|
#include "top_tweet/sajson.h"
|
||||||
|
#endif // SIMDJSON_COMPETITION_ONDEMAND_SAJSON
|
||||||
|
#include "top_tweet/rapidjson.h"
|
||||||
|
#if SIMDJSON_COMPETITION_SAX
|
||||||
|
#include "top_tweet/rapidjson_sax.h"
|
||||||
|
#endif // SIMDJSON_COMPETITION_SAX
|
||||||
|
#include "top_tweet/nlohmann_json.h"
|
||||||
|
#if SIMDJSON_COMPETITION_SAX
|
||||||
|
#include "top_tweet/nlohmann_json_sax.h"
|
||||||
|
#endif // SIMDJSON_COMPETITION_SAX
|
||||||
|
|
||||||
|
|
||||||
|
#include "kostya/simdjson_ondemand.h"
|
||||||
|
#include "kostya/simdjson_dom.h"
|
||||||
|
#include "kostya/yyjson.h"
|
||||||
|
#if SIMDJSON_COMPETITION_ONDEMAND_SAJSON
|
||||||
|
#include "kostya/sajson.h"
|
||||||
|
#endif // SIMDJSON_COMPETITION_ONDEMAND_SAJSON
|
||||||
|
#include "kostya/rapidjson.h"
|
||||||
|
#if SIMDJSON_COMPETITION_SAX
|
||||||
|
#include "kostya/rapidjson_sax.h"
|
||||||
|
#endif // SIMDJSON_COMPETITION_SAX
|
||||||
|
#include "kostya/nlohmann_json.h"
|
||||||
|
#if SIMDJSON_COMPETITION_SAX
|
||||||
|
#include "kostya/nlohmann_json_sax.h"
|
||||||
|
#endif // SIMDJSON_COMPETITION_SAX
|
||||||
|
|
||||||
|
#include "large_random/simdjson_ondemand.h"
|
||||||
|
#if SIMDJSON_COMPETITION_ONDEMAND_UNORDERED
|
||||||
|
#include "large_random/simdjson_ondemand_unordered.h"
|
||||||
|
#endif // SIMDJSON_COMPETITION_ONDEMAND_UNORDERED
|
||||||
|
#include "large_random/simdjson_dom.h"
|
||||||
|
#include "large_random/yyjson.h"
|
||||||
|
#if SIMDJSON_COMPETITION_ONDEMAND_SAJSON
|
||||||
|
#include "large_random/sajson.h"
|
||||||
|
#endif // SIMDJSON_COMPETITION_ONDEMAND_SAJSON
|
||||||
|
#include "large_random/rapidjson.h"
|
||||||
|
#if SIMDJSON_COMPETITION_SAX
|
||||||
|
#include "large_random/rapidjson_sax.h"
|
||||||
|
#endif // SIMDJSON_COMPETITION_SAX
|
||||||
|
#include "large_random/nlohmann_json.h"
|
||||||
|
#if SIMDJSON_COMPETITION_SAX
|
||||||
|
#include "large_random/nlohmann_json_sax.h"
|
||||||
|
#endif // SIMDJSON_COMPETITION_SAX
|
||||||
|
|
||||||
#include "amazon_cellphones/simdjson_dom.h"
|
#include "amazon_cellphones/simdjson_dom.h"
|
||||||
#include "amazon_cellphones/simdjson_ondemand.h"
|
#include "amazon_cellphones/simdjson_ondemand.h"
|
||||||
|
|
||||||
#include "large_amazon_cellphones/simdjson_dom.h"
|
#include "large_amazon_cellphones/simdjson_dom.h"
|
||||||
#include "large_amazon_cellphones/simdjson_ondemand.h"
|
#include "large_amazon_cellphones/simdjson_ondemand.h"
|
||||||
|
|
||||||
#include "partial_tweets/simdjson_dom.h"
|
|
||||||
#include "partial_tweets/simdjson_ondemand.h"
|
|
||||||
#include "partial_tweets/yyjson.h"
|
|
||||||
#include "partial_tweets/sajson.h"
|
|
||||||
#include "partial_tweets/rapidjson.h"
|
|
||||||
#include "partial_tweets/rapidjson_sax.h"
|
|
||||||
#include "partial_tweets/nlohmann_json.h"
|
|
||||||
#include "partial_tweets/nlohmann_json_sax.h"
|
|
||||||
|
|
||||||
#include "large_random/simdjson_dom.h"
|
|
||||||
#include "large_random/simdjson_ondemand.h"
|
|
||||||
#include "large_random/simdjson_ondemand_unordered.h"
|
|
||||||
#include "large_random/yyjson.h"
|
|
||||||
#include "large_random/sajson.h"
|
|
||||||
#include "large_random/rapidjson.h"
|
|
||||||
#include "large_random/rapidjson_sax.h"
|
|
||||||
#include "large_random/nlohmann_json.h"
|
|
||||||
#include "large_random/nlohmann_json_sax.h"
|
|
||||||
|
|
||||||
#include "kostya/simdjson_dom.h"
|
|
||||||
#include "kostya/simdjson_ondemand.h"
|
|
||||||
#include "kostya/yyjson.h"
|
|
||||||
#include "kostya/sajson.h"
|
|
||||||
#include "kostya/rapidjson.h"
|
|
||||||
#include "kostya/rapidjson_sax.h"
|
|
||||||
#include "kostya/nlohmann_json.h"
|
|
||||||
#include "kostya/nlohmann_json_sax.h"
|
|
||||||
|
|
||||||
#include "distinct_user_id/simdjson_dom.h"
|
|
||||||
#include "distinct_user_id/simdjson_dom_json_pointer.h"
|
|
||||||
#include "distinct_user_id/simdjson_ondemand.h"
|
|
||||||
#include "distinct_user_id/simdjson_ondemand_json_pointer.h"
|
|
||||||
#include "distinct_user_id/yyjson.h"
|
|
||||||
#include "distinct_user_id/sajson.h"
|
|
||||||
#include "distinct_user_id/rapidjson.h"
|
|
||||||
#include "distinct_user_id/rapidjson_sax.h"
|
|
||||||
#include "distinct_user_id/nlohmann_json.h"
|
|
||||||
#include "distinct_user_id/nlohmann_json_sax.h"
|
|
||||||
|
|
||||||
#include "find_tweet/simdjson_dom.h"
|
|
||||||
#include "find_tweet/simdjson_ondemand.h"
|
|
||||||
#include "find_tweet/yyjson.h"
|
|
||||||
#include "find_tweet/sajson.h"
|
|
||||||
#include "find_tweet/rapidjson.h"
|
|
||||||
#include "find_tweet/rapidjson_sax.h"
|
|
||||||
#include "find_tweet/nlohmann_json.h"
|
|
||||||
#include "find_tweet/nlohmann_json_sax.h"
|
|
||||||
|
|
||||||
#include "top_tweet/simdjson_dom.h"
|
|
||||||
#include "top_tweet/simdjson_ondemand.h"
|
|
||||||
#include "top_tweet/yyjson.h"
|
|
||||||
#include "top_tweet/sajson.h"
|
|
||||||
#include "top_tweet/rapidjson.h"
|
|
||||||
#include "top_tweet/rapidjson_sax.h"
|
|
||||||
#include "top_tweet/nlohmann_json.h"
|
|
||||||
#include "top_tweet/nlohmann_json_sax.h"
|
|
||||||
|
|
||||||
BENCHMARK_MAIN();
|
BENCHMARK_MAIN();
|
||||||
|
|||||||
@@ -46,13 +46,14 @@ struct rapidjson : rapidjson_base {
|
|||||||
};
|
};
|
||||||
BENCHMARK_TEMPLATE(distinct_user_id, rapidjson)->UseManualTime();
|
BENCHMARK_TEMPLATE(distinct_user_id, rapidjson)->UseManualTime();
|
||||||
|
|
||||||
|
#if SIMDJSON_COMPETITION_ONDEMAND_INSITU
|
||||||
struct rapidjson_insitu : rapidjson_base {
|
struct rapidjson_insitu : rapidjson_base {
|
||||||
bool run(simdjson::padded_string &json, std::vector<uint64_t> &result) {
|
bool run(simdjson::padded_string &json, std::vector<uint64_t> &result) {
|
||||||
return rapidjson_base::run(doc.ParseInsitu<kParseValidateEncodingFlag|kParseInsituFlag>(json.data()), result);
|
return rapidjson_base::run(doc.ParseInsitu<kParseValidateEncodingFlag|kParseInsituFlag>(json.data()), result);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
BENCHMARK_TEMPLATE(distinct_user_id, rapidjson_insitu)->UseManualTime();
|
BENCHMARK_TEMPLATE(distinct_user_id, rapidjson_insitu)->UseManualTime();
|
||||||
|
#endif // SIMDJSON_COMPETITION_ONDEMAND_INSITU
|
||||||
} // namespace partial_tweets
|
} // namespace partial_tweets
|
||||||
|
|
||||||
#endif // SIMDJSON_COMPETITION_RAPIDJSON
|
#endif // SIMDJSON_COMPETITION_RAPIDJSON
|
||||||
|
|||||||
@@ -49,13 +49,14 @@ struct yyjson : yyjson_base {
|
|||||||
};
|
};
|
||||||
BENCHMARK_TEMPLATE(distinct_user_id, yyjson)->UseManualTime();
|
BENCHMARK_TEMPLATE(distinct_user_id, yyjson)->UseManualTime();
|
||||||
|
|
||||||
|
#if SIMDJSON_COMPETITION_ONDEMAND_INSITU
|
||||||
struct yyjson_insitu : yyjson_base {
|
struct yyjson_insitu : yyjson_base {
|
||||||
bool run(simdjson::padded_string &json, std::vector<uint64_t> &result) {
|
bool run(simdjson::padded_string &json, std::vector<uint64_t> &result) {
|
||||||
return yyjson_base::run(yyjson_read_opts(json.data(), json.size(), YYJSON_READ_INSITU, 0, 0), result);
|
return yyjson_base::run(yyjson_read_opts(json.data(), json.size(), YYJSON_READ_INSITU, 0, 0), result);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
BENCHMARK_TEMPLATE(distinct_user_id, yyjson_insitu)->UseManualTime();
|
BENCHMARK_TEMPLATE(distinct_user_id, yyjson_insitu)->UseManualTime();
|
||||||
|
#endif // SIMDJSON_COMPETITION_ONDEMAND_INSITU
|
||||||
} // namespace distinct_user_id
|
} // namespace distinct_user_id
|
||||||
|
|
||||||
#endif // SIMDJSON_COMPETITION_YYJSON
|
#endif // SIMDJSON_COMPETITION_YYJSON
|
||||||
|
|||||||
@@ -134,7 +134,7 @@ struct event_collector {
|
|||||||
|
|
||||||
#if defined(__linux__)
|
#if defined(__linux__)
|
||||||
LinuxEvents<PERF_TYPE_HARDWARE> linux_events;
|
LinuxEvents<PERF_TYPE_HARDWARE> linux_events;
|
||||||
event_collector(bool quiet = false) : linux_events(vector<int>{
|
event_collector(simdjson_unused bool quiet = false) : linux_events(vector<int>{
|
||||||
#if SIMDJSON_SIMPLE_PERFORMANCE_COUNTERS
|
#if SIMDJSON_SIMPLE_PERFORMANCE_COUNTERS
|
||||||
PERF_COUNT_HW_CPU_CYCLES,
|
PERF_COUNT_HW_CPU_CYCLES,
|
||||||
PERF_COUNT_HW_INSTRUCTIONS,
|
PERF_COUNT_HW_INSTRUCTIONS,
|
||||||
@@ -145,7 +145,7 @@ struct event_collector {
|
|||||||
PERF_COUNT_HW_CACHE_REFERENCES,
|
PERF_COUNT_HW_CACHE_REFERENCES,
|
||||||
PERF_COUNT_HW_CACHE_MISSES
|
PERF_COUNT_HW_CACHE_MISSES
|
||||||
#endif
|
#endif
|
||||||
}, quiet) {}
|
}) {}
|
||||||
bool has_events() {
|
bool has_events() {
|
||||||
return linux_events.is_working();
|
return linux_events.is_working();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,13 +40,14 @@ struct rapidjson : rapidjson_base {
|
|||||||
};
|
};
|
||||||
BENCHMARK_TEMPLATE(find_tweet, rapidjson)->UseManualTime();
|
BENCHMARK_TEMPLATE(find_tweet, rapidjson)->UseManualTime();
|
||||||
|
|
||||||
|
#if SIMDJSON_COMPETITION_ONDEMAND_INSITU
|
||||||
struct rapidjson_insitu : rapidjson_base {
|
struct rapidjson_insitu : rapidjson_base {
|
||||||
bool run(simdjson::padded_string &json, uint64_t find_id, std::string_view &result) {
|
bool run(simdjson::padded_string &json, uint64_t find_id, std::string_view &result) {
|
||||||
return rapidjson_base::run(doc.ParseInsitu<kParseValidateEncodingFlag|kParseInsituFlag>(json.data()), find_id, result);
|
return rapidjson_base::run(doc.ParseInsitu<kParseValidateEncodingFlag|kParseInsituFlag>(json.data()), find_id, result);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
BENCHMARK_TEMPLATE(find_tweet, rapidjson_insitu)->UseManualTime();
|
BENCHMARK_TEMPLATE(find_tweet, rapidjson_insitu)->UseManualTime();
|
||||||
|
#endif // SIMDJSON_COMPETITION_ONDEMAND_INSITU
|
||||||
} // namespace find_tweet
|
} // namespace find_tweet
|
||||||
|
|
||||||
#endif // SIMDJSON_COMPETITION_RAPIDJSON
|
#endif // SIMDJSON_COMPETITION_RAPIDJSON
|
||||||
|
|||||||
@@ -40,14 +40,14 @@ struct yyjson : yyjson_base {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
BENCHMARK_TEMPLATE(find_tweet, yyjson)->UseManualTime();
|
BENCHMARK_TEMPLATE(find_tweet, yyjson)->UseManualTime();
|
||||||
|
#if SIMDJSON_COMPETITION_ONDEMAND_INSITU
|
||||||
struct yyjson_insitu : yyjson_base {
|
struct yyjson_insitu : yyjson_base {
|
||||||
bool run(simdjson::padded_string &json, uint64_t find_id, std::string_view &result) {
|
bool run(simdjson::padded_string &json, uint64_t find_id, std::string_view &result) {
|
||||||
return yyjson_base::run(yyjson_read_opts(json.data(), json.size(), YYJSON_READ_INSITU, 0, 0), find_id, result);
|
return yyjson_base::run(yyjson_read_opts(json.data(), json.size(), YYJSON_READ_INSITU, 0, 0), find_id, result);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
BENCHMARK_TEMPLATE(find_tweet, yyjson_insitu)->UseManualTime();
|
BENCHMARK_TEMPLATE(find_tweet, yyjson_insitu)->UseManualTime();
|
||||||
|
#endif // SIMDJSON_COMPETITION_ONDEMAND_INSITU
|
||||||
} // namespace find_tweet
|
} // namespace find_tweet
|
||||||
|
|
||||||
#endif // SIMDJSON_COMPETITION_YYJSON
|
#endif // SIMDJSON_COMPETITION_YYJSON
|
||||||
|
|||||||
@@ -122,19 +122,21 @@ struct rapidjson_base {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
using rapidjson_lossless = rapidjson_base<kParseValidateEncodingFlag|kParseFullPrecisionFlag>;
|
using rapidjson = rapidjson_base<kParseValidateEncodingFlag|kParseFullPrecisionFlag>;
|
||||||
|
|
||||||
BENCHMARK_TEMPLATE(json2msgpack, rapidjson_lossless)->UseManualTime();
|
|
||||||
|
|
||||||
|
|
||||||
using rapidjson = rapidjson_base<kParseValidateEncodingFlag>;
|
|
||||||
|
|
||||||
BENCHMARK_TEMPLATE(json2msgpack, rapidjson)->UseManualTime();
|
BENCHMARK_TEMPLATE(json2msgpack, rapidjson)->UseManualTime();
|
||||||
|
|
||||||
|
#if SIMDJSON_COMPETITION_ONDEMAND_APPROX
|
||||||
|
using rapidjson_approx = rapidjson_base<kParseValidateEncodingFlag>;
|
||||||
|
|
||||||
|
BENCHMARK_TEMPLATE(json2msgpack, rapidjson_approx)->UseManualTime();
|
||||||
|
#endif // SIMDJSON_COMPETITION_ONDEMAND_APPROX
|
||||||
|
|
||||||
|
#if SIMDJSON_COMPETITION_ONDEMAND_INSITU
|
||||||
using rapidjson_insitu = rapidjson_base<kParseValidateEncodingFlag|kParseInsituFlag>;
|
using rapidjson_insitu = rapidjson_base<kParseValidateEncodingFlag|kParseInsituFlag>;
|
||||||
|
|
||||||
BENCHMARK_TEMPLATE(json2msgpack, rapidjson_insitu)->UseManualTime();
|
BENCHMARK_TEMPLATE(json2msgpack, rapidjson_insitu)->UseManualTime();
|
||||||
|
#endif // SIMDJSON_COMPETITION_ONDEMAND_INSITU
|
||||||
} // namespace json2msgpack
|
} // namespace json2msgpack
|
||||||
|
|
||||||
#endif // SIMDJSON_COMPETITION_RAPIDJSON
|
#endif // SIMDJSON_COMPETITION_RAPIDJSON
|
||||||
|
|||||||
@@ -51,6 +51,7 @@ private:
|
|||||||
simdjson_inline void
|
simdjson_inline void
|
||||||
write_raw_string(simdjson::ondemand::raw_json_string rjs);
|
write_raw_string(simdjson::ondemand::raw_json_string rjs);
|
||||||
inline void recursive_processor(simdjson::ondemand::value element);
|
inline void recursive_processor(simdjson::ondemand::value element);
|
||||||
|
inline void recursive_processor_ref(simdjson::ondemand::value& element);
|
||||||
|
|
||||||
simdjson::ondemand::parser parser;
|
simdjson::ondemand::parser parser;
|
||||||
uint8_t *buff{};
|
uint8_t *buff{};
|
||||||
@@ -74,17 +75,33 @@ simdjson2msgpack::to_msgpack(const simdjson::padded_string &json,
|
|||||||
write_byte(0xc2 + doc.get_bool());
|
write_byte(0xc2 + doc.get_bool());
|
||||||
break;
|
break;
|
||||||
case simdjson::ondemand::json_type::null:
|
case simdjson::ondemand::json_type::null:
|
||||||
write_byte(0xc0);
|
// We check that the value is indeed null
|
||||||
|
// otherwise: an error is thrown.
|
||||||
|
if(doc.is_null()) {
|
||||||
|
write_byte(0xc0);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case simdjson::ondemand::json_type::array:
|
case simdjson::ondemand::json_type::array:
|
||||||
case simdjson::ondemand::json_type::object:
|
case simdjson::ondemand::json_type::object:
|
||||||
default:
|
default:
|
||||||
// impossible
|
// impossible
|
||||||
break;
|
SIMDJSON_UNREACHABLE();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
simdjson::ondemand::value val = doc;
|
simdjson::ondemand::value val = doc;
|
||||||
|
#define SIMDJSON_GCC_COMPILER ((__GNUC__) && !(__clang__) && !(__INTEL_COMPILER))
|
||||||
|
#if SIMDJSON_GCC_COMPILER
|
||||||
|
// the GCC compiler does well with by-value passing.
|
||||||
|
// GCC has superior recursive inlining:
|
||||||
|
// https://stackoverflow.com/questions/29186186/why-does-gcc-generate-a-faster-program-than-clang-in-this-recursive-fibonacci-co
|
||||||
|
// https://godbolt.org/z/TeK4doE51
|
||||||
recursive_processor(val);
|
recursive_processor(val);
|
||||||
|
#else
|
||||||
|
recursive_processor_ref(val);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
if (!doc.at_end()) {
|
||||||
|
throw "There are unexpectedly tokens after the end of the json in the json2msgpack sample data";
|
||||||
}
|
}
|
||||||
return std::string_view(reinterpret_cast<char *>(buf), size_t(buff - buf));
|
return std::string_view(reinterpret_cast<char *>(buf), size_t(buff - buf));
|
||||||
}
|
}
|
||||||
@@ -156,7 +173,58 @@ void simdjson2msgpack::recursive_processor(simdjson::ondemand::value element) {
|
|||||||
write_byte(0xc2 + element.get_bool());
|
write_byte(0xc2 + element.get_bool());
|
||||||
break;
|
break;
|
||||||
case simdjson::ondemand::json_type::null:
|
case simdjson::ondemand::json_type::null:
|
||||||
write_byte(0xc0);
|
// We check that the value is indeed null
|
||||||
|
// otherwise: an error is thrown.
|
||||||
|
if(element.is_null()) {
|
||||||
|
write_byte(0xc0);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
SIMDJSON_UNREACHABLE();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void simdjson2msgpack::recursive_processor_ref(simdjson::ondemand::value& element) {
|
||||||
|
switch (element.type()) {
|
||||||
|
case simdjson::ondemand::json_type::array: {
|
||||||
|
uint32_t counter = 0;
|
||||||
|
write_byte(0xdd);
|
||||||
|
uint8_t *location = skip_uint32();
|
||||||
|
for (auto child : element.get_array()) {
|
||||||
|
counter++;
|
||||||
|
simdjson::ondemand::value v = child.value();
|
||||||
|
recursive_processor_ref(v);
|
||||||
|
}
|
||||||
|
write_uint32_at(counter, location);
|
||||||
|
} break;
|
||||||
|
case simdjson::ondemand::json_type::object: {
|
||||||
|
uint32_t counter = 0;
|
||||||
|
write_byte(0xdf);
|
||||||
|
uint8_t *location = skip_uint32();
|
||||||
|
for (auto field : element.get_object()) {
|
||||||
|
counter++;
|
||||||
|
write_raw_string(field.key());
|
||||||
|
simdjson::ondemand::value v = field.value();
|
||||||
|
recursive_processor_ref(v);
|
||||||
|
}
|
||||||
|
write_uint32_at(counter, location);
|
||||||
|
} break;
|
||||||
|
case simdjson::ondemand::json_type::number:
|
||||||
|
write_double(element.get_double());
|
||||||
|
break;
|
||||||
|
case simdjson::ondemand::json_type::string:
|
||||||
|
write_raw_string(element.get_raw_json_string());
|
||||||
|
break;
|
||||||
|
case simdjson::ondemand::json_type::boolean:
|
||||||
|
write_byte(0xc2 + element.get_bool());
|
||||||
|
break;
|
||||||
|
case simdjson::ondemand::json_type::null:
|
||||||
|
// We check that the value is indeed null
|
||||||
|
// otherwise: an error is thrown.
|
||||||
|
if(element.is_null()) {
|
||||||
|
write_byte(0xc0);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
SIMDJSON_UNREACHABLE();
|
SIMDJSON_UNREACHABLE();
|
||||||
|
|||||||
@@ -106,6 +106,7 @@ struct yyjson : yyjson2msgpack {
|
|||||||
|
|
||||||
BENCHMARK_TEMPLATE(json2msgpack, yyjson)->UseManualTime();
|
BENCHMARK_TEMPLATE(json2msgpack, yyjson)->UseManualTime();
|
||||||
|
|
||||||
|
#if SIMDJSON_COMPETITION_ONDEMAND_INSITU
|
||||||
struct yyjson_insitu : yyjson2msgpack {
|
struct yyjson_insitu : yyjson2msgpack {
|
||||||
bool run(simdjson::padded_string &json, char *buffer,
|
bool run(simdjson::padded_string &json, char *buffer,
|
||||||
std::string_view &result) {
|
std::string_view &result) {
|
||||||
@@ -116,7 +117,7 @@ struct yyjson_insitu : yyjson2msgpack {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
BENCHMARK_TEMPLATE(json2msgpack, yyjson_insitu)->UseManualTime();
|
BENCHMARK_TEMPLATE(json2msgpack, yyjson_insitu)->UseManualTime();
|
||||||
|
#endif // SIMDJSON_COMPETITION_ONDEMAND_INSITU
|
||||||
} // namespace json2msgpack
|
} // namespace json2msgpack
|
||||||
|
|
||||||
#endif // SIMDJSON_COMPETITION_YYJSON
|
#endif // SIMDJSON_COMPETITION_YYJSON
|
||||||
@@ -34,28 +34,29 @@ struct rapidjson_base {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
#if SIMDJSON_COMPETITION_ONDEMAND_APPROX
|
||||||
struct rapidjson : rapidjson_base {
|
struct rapidjson_approx : rapidjson_base {
|
||||||
bool run(simdjson::padded_string &json, std::vector<point> &result) {
|
bool run(simdjson::padded_string &json, std::vector<point> &result) {
|
||||||
return rapidjson_base::run(doc.Parse<kParseValidateEncodingFlag>(json.data()), result);
|
return rapidjson_base::run(doc.Parse<kParseValidateEncodingFlag>(json.data()), result);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
BENCHMARK_TEMPLATE(kostya, rapidjson)->UseManualTime();
|
BENCHMARK_TEMPLATE(kostya, rapidjson_approx)->UseManualTime();
|
||||||
|
#endif // SIMDJSON_COMPETITION_ONDEMAND_APPROX
|
||||||
|
|
||||||
struct rapidjson_lossless : rapidjson_base {
|
struct rapidjson : rapidjson_base {
|
||||||
bool run(simdjson::padded_string &json, std::vector<point> &result) {
|
bool run(simdjson::padded_string &json, std::vector<point> &result) {
|
||||||
return rapidjson_base::run(doc.Parse<kParseValidateEncodingFlag | kParseFullPrecisionFlag>(json.data()), result);
|
return rapidjson_base::run(doc.Parse<kParseValidateEncodingFlag | kParseFullPrecisionFlag>(json.data()), result);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
BENCHMARK_TEMPLATE(kostya, rapidjson_lossless)->UseManualTime();
|
BENCHMARK_TEMPLATE(kostya, rapidjson)->UseManualTime();
|
||||||
|
#if SIMDJSON_COMPETITION_ONDEMAND_INSITU
|
||||||
struct rapidjson_insitu : rapidjson_base {
|
struct rapidjson_insitu : rapidjson_base {
|
||||||
bool run(simdjson::padded_string &json, std::vector<point> &result) {
|
bool run(simdjson::padded_string &json, std::vector<point> &result) {
|
||||||
return rapidjson_base::run(doc.ParseInsitu<kParseValidateEncodingFlag|kParseInsituFlag>(json.data()), result);
|
return rapidjson_base::run(doc.ParseInsitu<kParseValidateEncodingFlag|kParseInsituFlag>(json.data()), result);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
BENCHMARK_TEMPLATE(kostya, rapidjson_insitu)->UseManualTime();
|
BENCHMARK_TEMPLATE(kostya, rapidjson_insitu)->UseManualTime();
|
||||||
|
#endif // SIMDJSON_COMPETITION_ONDEMAND_INSITU
|
||||||
} // namespace kostya
|
} // namespace kostya
|
||||||
|
|
||||||
#endif // SIMDJSON_COMPETITION_RAPIDJSON
|
#endif // SIMDJSON_COMPETITION_RAPIDJSON
|
||||||
|
|||||||
@@ -53,14 +53,14 @@ struct yyjson : yyjson_base {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
BENCHMARK_TEMPLATE(kostya, yyjson)->UseManualTime();
|
BENCHMARK_TEMPLATE(kostya, yyjson)->UseManualTime();
|
||||||
|
#if SIMDJSON_COMPETITION_ONDEMAND_INSITU
|
||||||
struct yyjson_insitu : yyjson_base {
|
struct yyjson_insitu : yyjson_base {
|
||||||
bool run(simdjson::padded_string &json, std::vector<point> &result) {
|
bool run(simdjson::padded_string &json, std::vector<point> &result) {
|
||||||
return yyjson_base::run(yyjson_read_opts(json.data(), json.size(), YYJSON_READ_INSITU, 0, 0), result);
|
return yyjson_base::run(yyjson_read_opts(json.data(), json.size(), YYJSON_READ_INSITU, 0, 0), result);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
BENCHMARK_TEMPLATE(kostya, yyjson_insitu)->UseManualTime();
|
BENCHMARK_TEMPLATE(kostya, yyjson_insitu)->UseManualTime();
|
||||||
|
#endif // SIMDJSON_COMPETITION_ONDEMAND_INSITU
|
||||||
} // namespace kostya
|
} // namespace kostya
|
||||||
|
|
||||||
#endif // SIMDJSON_COMPETITION_YYJSON
|
#endif // SIMDJSON_COMPETITION_YYJSON
|
||||||
|
|||||||
@@ -31,28 +31,30 @@ struct rapidjson_base {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
#if SIMDJSON_COMPETITION_ONDEMAND_APPROX
|
||||||
struct rapidjson : rapidjson_base {
|
struct rapidjson_approx : rapidjson_base {
|
||||||
bool run(simdjson::padded_string &json, std::vector<point> &result) {
|
bool run(simdjson::padded_string &json, std::vector<point> &result) {
|
||||||
return rapidjson_base::run(doc.Parse<kParseValidateEncodingFlag>(json.data()), result);
|
return rapidjson_base::run(doc.Parse<kParseValidateEncodingFlag>(json.data()), result);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
BENCHMARK_TEMPLATE(large_random, rapidjson)->UseManualTime();
|
BENCHMARK_TEMPLATE(large_random, rapidjson_approx)->UseManualTime();
|
||||||
|
#endif // SIMDJSON_COMPETITION_ONDEMAND_APPROX
|
||||||
|
|
||||||
struct rapidjson_lossless : rapidjson_base {
|
struct rapidjson : rapidjson_base {
|
||||||
bool run(simdjson::padded_string &json, std::vector<point> &result) {
|
bool run(simdjson::padded_string &json, std::vector<point> &result) {
|
||||||
return rapidjson_base::run(doc.Parse<kParseValidateEncodingFlag | kParseFullPrecisionFlag>(json.data()), result);
|
return rapidjson_base::run(doc.Parse<kParseValidateEncodingFlag | kParseFullPrecisionFlag>(json.data()), result);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
BENCHMARK_TEMPLATE(large_random, rapidjson_lossless)->UseManualTime();
|
BENCHMARK_TEMPLATE(large_random, rapidjson)->UseManualTime();
|
||||||
|
|
||||||
|
#if SIMDJSON_COMPETITION_ONDEMAND_INSITU
|
||||||
struct rapidjson_insitu : rapidjson_base {
|
struct rapidjson_insitu : rapidjson_base {
|
||||||
bool run(simdjson::padded_string &json, std::vector<point> &result) {
|
bool run(simdjson::padded_string &json, std::vector<point> &result) {
|
||||||
return rapidjson_base::run(doc.ParseInsitu<kParseValidateEncodingFlag|kParseInsituFlag>(json.data()), result);
|
return rapidjson_base::run(doc.ParseInsitu<kParseValidateEncodingFlag|kParseInsituFlag>(json.data()), result);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
BENCHMARK_TEMPLATE(large_random, rapidjson_insitu)->UseManualTime();
|
BENCHMARK_TEMPLATE(large_random, rapidjson_insitu)->UseManualTime();
|
||||||
|
#endif // SIMDJSON_COMPETITION_ONDEMAND_INSITU
|
||||||
|
|
||||||
} // namespace large_random
|
} // namespace large_random
|
||||||
|
|
||||||
|
|||||||
@@ -51,14 +51,14 @@ struct yyjson : yyjson_base {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
BENCHMARK_TEMPLATE(large_random, yyjson)->UseManualTime();
|
BENCHMARK_TEMPLATE(large_random, yyjson)->UseManualTime();
|
||||||
|
#if SIMDJSON_COMPETITION_ONDEMAND_INSITU
|
||||||
struct yyjson_insitu : yyjson_base {
|
struct yyjson_insitu : yyjson_base {
|
||||||
bool run(simdjson::padded_string &json, std::vector<point> &result) {
|
bool run(simdjson::padded_string &json, std::vector<point> &result) {
|
||||||
return yyjson_base::run(yyjson_read_opts(json.data(), json.size(), YYJSON_READ_INSITU, 0, 0), result);
|
return yyjson_base::run(yyjson_read_opts(json.data(), json.size(), YYJSON_READ_INSITU, 0, 0), result);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
BENCHMARK_TEMPLATE(large_random, yyjson_insitu)->UseManualTime();
|
BENCHMARK_TEMPLATE(large_random, yyjson_insitu)->UseManualTime();
|
||||||
|
#endif // SIMDJSON_COMPETITION_ONDEMAND_INSITU
|
||||||
} // namespace large_random
|
} // namespace large_random
|
||||||
|
|
||||||
#endif // SIMDJSON_COMPETITION_YYJSON
|
#endif // SIMDJSON_COMPETITION_YYJSON
|
||||||
|
|||||||
@@ -1,22 +1,13 @@
|
|||||||
// https://github.com/WojciechMula/toys/blob/master/000helpers/linux-perf-events.h
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#ifdef __linux__
|
#ifdef __linux__
|
||||||
#ifdef __has_include
|
|
||||||
#if __has_include(<asm/unistd.h>)
|
|
||||||
#include <asm/unistd.h> // for __NR_perf_event_open
|
#include <asm/unistd.h> // for __NR_perf_event_open
|
||||||
#else
|
|
||||||
#warning "Header asm/unistd.h cannot be found though it is a linux system. Are linux headers missing?"
|
|
||||||
#endif
|
|
||||||
#else // no __has_include
|
|
||||||
// Please insure that linux headers have been installed.
|
|
||||||
#include <asm/unistd.h> // for __NR_perf_event_open
|
|
||||||
#endif
|
|
||||||
#include <linux/perf_event.h> // for perf event constants
|
#include <linux/perf_event.h> // for perf event constants
|
||||||
#include <sys/ioctl.h> // for ioctl
|
#include <sys/ioctl.h> // for ioctl
|
||||||
#include <unistd.h> // for syscall
|
#include <unistd.h> // for syscall
|
||||||
|
|
||||||
#include <cerrno> // for errno
|
#include <cerrno> // for errno
|
||||||
#include <cstring> // for std::memset
|
#include <cstring> // for memset
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
@@ -28,13 +19,11 @@ template <int TYPE = PERF_TYPE_HARDWARE> class LinuxEvents {
|
|||||||
perf_event_attr attribs{};
|
perf_event_attr attribs{};
|
||||||
size_t num_events{};
|
size_t num_events{};
|
||||||
std::vector<uint64_t> temp_result_vec{};
|
std::vector<uint64_t> temp_result_vec{};
|
||||||
std::vector<uint64_t> result{};
|
std::vector<uint64_t> ids{};
|
||||||
std::vector<int> fds{};
|
|
||||||
bool quiet;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit LinuxEvents(std::vector<int> config_vec, bool _quiet=false) : fd(0), working(true), quiet{_quiet} {
|
explicit LinuxEvents(std::vector<int> config_vec) : fd(0), working(true) {
|
||||||
std::memset(&attribs, 0, sizeof(attribs));
|
memset(&attribs, 0, sizeof(attribs));
|
||||||
attribs.type = TYPE;
|
attribs.type = TYPE;
|
||||||
attribs.size = sizeof(attribs);
|
attribs.size = sizeof(attribs);
|
||||||
attribs.disabled = 1;
|
attribs.disabled = 1;
|
||||||
@@ -49,7 +38,7 @@ public:
|
|||||||
|
|
||||||
int group = -1; // no group
|
int group = -1; // no group
|
||||||
num_events = config_vec.size();
|
num_events = config_vec.size();
|
||||||
result.resize(config_vec.size());
|
ids.resize(config_vec.size());
|
||||||
uint32_t i = 0;
|
uint32_t i = 0;
|
||||||
for (auto config : config_vec) {
|
for (auto config : config_vec) {
|
||||||
attribs.config = config;
|
attribs.config = config;
|
||||||
@@ -57,22 +46,17 @@ public:
|
|||||||
if (_fd == -1) {
|
if (_fd == -1) {
|
||||||
report_error("perf_event_open");
|
report_error("perf_event_open");
|
||||||
}
|
}
|
||||||
fd = _fd; // fd tracks the last _fd value.
|
ioctl(_fd, PERF_EVENT_IOC_ID, &ids[i++]);
|
||||||
fds.push_back(fd);
|
|
||||||
ioctl(fd, PERF_EVENT_IOC_ID, &result[i++]);
|
|
||||||
if (group == -1) {
|
if (group == -1) {
|
||||||
group = fd;
|
group = _fd;
|
||||||
|
fd = _fd;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
temp_result_vec.resize(num_events * 2 + 1);
|
temp_result_vec.resize(num_events * 2 + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
~LinuxEvents() {
|
~LinuxEvents() { if (fd != -1) { close(fd); } }
|
||||||
for (auto tfd : fds) {
|
|
||||||
if (tfd != -1) { close(tfd); }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void start() {
|
inline void start() {
|
||||||
if (fd != -1) {
|
if (fd != -1) {
|
||||||
@@ -97,10 +81,16 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// our actual results are in slots 1,3,5, ... of this structure
|
// our actual results are in slots 1,3,5, ... of this structure
|
||||||
// we really should be checking our result obtained earlier to be safe
|
|
||||||
for (uint32_t i = 1; i < temp_result_vec.size(); i += 2) {
|
for (uint32_t i = 1; i < temp_result_vec.size(); i += 2) {
|
||||||
results[i / 2] = temp_result_vec[i];
|
results[i / 2] = temp_result_vec[i];
|
||||||
}
|
}
|
||||||
|
for (uint32_t i = 2; i < temp_result_vec.size(); i += 2) {
|
||||||
|
if(ids[i/2-1] != temp_result_vec[i]) {
|
||||||
|
report_error("event mismatch");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_working() {
|
bool is_working() {
|
||||||
@@ -108,12 +98,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void report_error(const std::string &context) {
|
void report_error(const std::string &) {
|
||||||
if (!quiet) {
|
|
||||||
if (working) {
|
|
||||||
std::cerr << (context + ": " + std::string(strerror(errno))) << std::endl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
working = false;
|
working = false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -67,14 +67,14 @@ struct rapidjson : rapidjson_base {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
BENCHMARK_TEMPLATE(partial_tweets, rapidjson)->UseManualTime();
|
BENCHMARK_TEMPLATE(partial_tweets, rapidjson)->UseManualTime();
|
||||||
|
#if SIMDJSON_COMPETITION_ONDEMAND_INSITU
|
||||||
struct rapidjson_insitu : rapidjson_base {
|
struct rapidjson_insitu : rapidjson_base {
|
||||||
bool run(simdjson::padded_string &json, std::vector<tweet<std::string_view>> &result) {
|
bool run(simdjson::padded_string &json, std::vector<tweet<std::string_view>> &result) {
|
||||||
return rapidjson_base::run(doc.ParseInsitu<kParseValidateEncodingFlag|kParseInsituFlag>(json.data()), result);
|
return rapidjson_base::run(doc.ParseInsitu<kParseValidateEncodingFlag|kParseInsituFlag>(json.data()), result);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
BENCHMARK_TEMPLATE(partial_tweets, rapidjson_insitu)->UseManualTime();
|
BENCHMARK_TEMPLATE(partial_tweets, rapidjson_insitu)->UseManualTime();
|
||||||
|
#endif // SIMDJSON_COMPETITION_ONDEMAND_INSITU
|
||||||
} // namespace partial_tweets
|
} // namespace partial_tweets
|
||||||
|
|
||||||
#endif // SIMDJSON_COMPETITION_RAPIDJSON
|
#endif // SIMDJSON_COMPETITION_RAPIDJSON
|
||||||
|
|||||||
@@ -66,14 +66,14 @@ struct yyjson : yyjson_base {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
BENCHMARK_TEMPLATE(partial_tweets, yyjson)->UseManualTime();
|
BENCHMARK_TEMPLATE(partial_tweets, yyjson)->UseManualTime();
|
||||||
|
#if SIMDJSON_COMPETITION_ONDEMAND_INSITU
|
||||||
struct yyjson_insitu : yyjson_base {
|
struct yyjson_insitu : yyjson_base {
|
||||||
bool run(simdjson::padded_string &json, std::vector<tweet<std::string_view>> &result) {
|
bool run(simdjson::padded_string &json, std::vector<tweet<std::string_view>> &result) {
|
||||||
return yyjson_base::run(yyjson_read_opts(json.data(), json.size(), YYJSON_READ_INSITU, 0, 0), result);
|
return yyjson_base::run(yyjson_read_opts(json.data(), json.size(), YYJSON_READ_INSITU, 0, 0), result);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
BENCHMARK_TEMPLATE(partial_tweets, yyjson_insitu)->UseManualTime();
|
BENCHMARK_TEMPLATE(partial_tweets, yyjson_insitu)->UseManualTime();
|
||||||
|
#endif // SIMDJSON_COMPETITION_ONDEMAND_INSITU
|
||||||
} // namespace partial_tweets
|
} // namespace partial_tweets
|
||||||
|
|
||||||
#endif // SIMDJSON_COMPETITION_YYJSON
|
#endif // SIMDJSON_COMPETITION_YYJSON
|
||||||
|
|||||||
@@ -56,14 +56,14 @@ struct rapidjson : rapidjson_base {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
BENCHMARK_TEMPLATE(top_tweet, rapidjson)->UseManualTime();
|
BENCHMARK_TEMPLATE(top_tweet, rapidjson)->UseManualTime();
|
||||||
|
#if SIMDJSON_COMPETITION_ONDEMAND_INSITU
|
||||||
struct rapidjson_insitu : rapidjson_base {
|
struct rapidjson_insitu : rapidjson_base {
|
||||||
bool run(simdjson::padded_string &json, int64_t max_retweet_count, top_tweet_result<StringType> &result) {
|
bool run(simdjson::padded_string &json, int64_t max_retweet_count, top_tweet_result<StringType> &result) {
|
||||||
return rapidjson_base::run(doc.ParseInsitu<kParseValidateEncodingFlag|kParseInsituFlag>(json.data()), max_retweet_count, result);
|
return rapidjson_base::run(doc.ParseInsitu<kParseValidateEncodingFlag|kParseInsituFlag>(json.data()), max_retweet_count, result);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
BENCHMARK_TEMPLATE(top_tweet, rapidjson_insitu)->UseManualTime();
|
BENCHMARK_TEMPLATE(top_tweet, rapidjson_insitu)->UseManualTime();
|
||||||
|
#endif // SIMDJSON_COMPETITION_ONDEMAND_INSITU
|
||||||
} // namespace top_tweet
|
} // namespace top_tweet
|
||||||
|
|
||||||
#endif // SIMDJSON_COMPETITION_RAPIDJSON
|
#endif // SIMDJSON_COMPETITION_RAPIDJSON
|
||||||
|
|||||||
@@ -55,14 +55,14 @@ struct yyjson : yyjson_base {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
BENCHMARK_TEMPLATE(top_tweet, yyjson)->UseManualTime();
|
BENCHMARK_TEMPLATE(top_tweet, yyjson)->UseManualTime();
|
||||||
|
#if SIMDJSON_COMPETITION_ONDEMAND_INSITU
|
||||||
struct yyjson_insitu : yyjson_base {
|
struct yyjson_insitu : yyjson_base {
|
||||||
bool run(simdjson::padded_string &json, int64_t max_retweet_count, top_tweet_result<StringType> &result) {
|
bool run(simdjson::padded_string &json, int64_t max_retweet_count, top_tweet_result<StringType> &result) {
|
||||||
return yyjson_base::run(yyjson_read_opts(json.data(), json.size(), YYJSON_READ_INSITU, 0, 0), max_retweet_count, result);
|
return yyjson_base::run(yyjson_read_opts(json.data(), json.size(), YYJSON_READ_INSITU, 0, 0), max_retweet_count, result);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
BENCHMARK_TEMPLATE(top_tweet, yyjson_insitu)->UseManualTime();
|
BENCHMARK_TEMPLATE(top_tweet, yyjson_insitu)->UseManualTime();
|
||||||
|
#endif // SIMDJSON_COMPETITION_ONDEMAND_INSITU
|
||||||
} // namespace top_tweet
|
} // namespace top_tweet
|
||||||
|
|
||||||
#endif // SIMDJSON_COMPETITION_YYJSON
|
#endif // SIMDJSON_COMPETITION_YYJSON
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
# This module provides function for joining paths
|
||||||
|
# known from most languages
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: (MIT OR CC0-1.0)
|
||||||
|
# Copyright 2020 Jan Tojnar
|
||||||
|
# https://github.com/jtojnar/cmake-snips
|
||||||
|
#
|
||||||
|
# Modelled after Python’s os.path.join
|
||||||
|
# https://docs.python.org/3.7/library/os.path.html#os.path.join
|
||||||
|
# Windows not supported
|
||||||
|
function(join_paths joined_path first_path_segment)
|
||||||
|
set(temp_path "${first_path_segment}")
|
||||||
|
foreach(current_segment IN LISTS ARGN)
|
||||||
|
if(NOT ("${current_segment}" STREQUAL ""))
|
||||||
|
if(IS_ABSOLUTE "${current_segment}")
|
||||||
|
set(temp_path "${current_segment}")
|
||||||
|
else()
|
||||||
|
set(temp_path "${temp_path}/${current_segment}")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
endforeach()
|
||||||
|
set(${joined_path} "${temp_path}" PARENT_SCOPE)
|
||||||
|
endfunction()
|
||||||
@@ -50,6 +50,23 @@ undefined behavior.")
|
|||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
option(SIMDJSON_SANITIZE_MEMORY "Sanitize memory" OFF)
|
||||||
|
|
||||||
|
|
||||||
|
if(SIMDJSON_SANITIZE_MEMORY)
|
||||||
|
message(STATUS "Setting the memory sanitizer.")
|
||||||
|
add_compile_options(
|
||||||
|
-fsanitize=memory -fno-sanitize-recover=all
|
||||||
|
)
|
||||||
|
link_libraries(
|
||||||
|
-fsanitize=memory -fno-sanitize-recover=all
|
||||||
|
)
|
||||||
|
# Ubuntu bug for GCC 5.0+ (safe for all versions)
|
||||||
|
if(CMAKE_COMPILER_IS_GNUCC)
|
||||||
|
link_libraries(-fuse-ld=gold)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
if(SIMDJSON_SANITIZE_THREADS)
|
if(SIMDJSON_SANITIZE_THREADS)
|
||||||
message(STATUS "Setting both the thread sanitizer \
|
message(STATUS "Setting both the thread sanitizer \
|
||||||
and the undefined-behavior sanitizer.")
|
and the undefined-behavior sanitizer.")
|
||||||
@@ -73,6 +90,8 @@ if(NOT is_multi_config AND NOT CMAKE_BUILD_TYPE)
|
|||||||
if(SIMDJSON_SANITIZE OR SIMDJSON_SANITIZE_UNDEFINED)
|
if(SIMDJSON_SANITIZE OR SIMDJSON_SANITIZE_UNDEFINED)
|
||||||
message(STATUS "No build type selected and you have enabled the sanitizer, \
|
message(STATUS "No build type selected and you have enabled the sanitizer, \
|
||||||
default to Debug. Consider setting CMAKE_BUILD_TYPE.")
|
default to Debug. Consider setting CMAKE_BUILD_TYPE.")
|
||||||
|
message(STATUS "Setting debug optimization flag to -O1 to help sanitizer.")
|
||||||
|
set(CMAKE_CXX_FLAGS_DEBUG "-O1" CACHE STRING "" FORCE)
|
||||||
set(CMAKE_BUILD_TYPE Debug CACHE STRING "Choose the type of build." FORCE)
|
set(CMAKE_BUILD_TYPE Debug CACHE STRING "Choose the type of build." FORCE)
|
||||||
else()
|
else()
|
||||||
message(STATUS "No build type selected, default to Release")
|
message(STATUS "No build type selected, default to Release")
|
||||||
@@ -144,6 +163,11 @@ else()
|
|||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
option(SIMDJSON_GLIBCXX_ASSERTIONS "Set _GLIBCXX_ASSERTIONS" OFF)
|
||||||
|
if (SIMDJSON_GLIBCXX_ASSERTIONS)
|
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D_GLIBCXX_ASSERTIONS")
|
||||||
|
endif()
|
||||||
|
|
||||||
#
|
#
|
||||||
# Other optional flags
|
# Other optional flags
|
||||||
#
|
#
|
||||||
@@ -187,6 +211,18 @@ else()
|
|||||||
message(STATUS "AVX-512 instructions are not allowed.")
|
message(STATUS "AVX-512 instructions are not allowed.")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
option(
|
||||||
|
SIMDJSON_SKIPUTF8VALIDATION
|
||||||
|
"SKIP UTF8 VALIDATION."
|
||||||
|
OFF
|
||||||
|
)
|
||||||
|
if(SIMDJSON_SKIPUTF8VALIDATION)
|
||||||
|
add_compile_definitions(SIMDJSON_UTF8VALIDATION=0)
|
||||||
|
message(STATUS "SKIP UTF8 VALIDATION")
|
||||||
|
else()
|
||||||
|
add_compile_definitions(SIMDJSON_UTF8VALIDATION=1)
|
||||||
|
endif()
|
||||||
|
|
||||||
include(CheckSymbolExists)
|
include(CheckSymbolExists)
|
||||||
check_symbol_exists(fork unistd.h HAVE_POSIX_FORK)
|
check_symbol_exists(fork unistd.h HAVE_POSIX_FORK)
|
||||||
check_symbol_exists(wait sys/wait.h HAVE_POSIX_WAIT)
|
check_symbol_exists(wait sys/wait.h HAVE_POSIX_WAIT)
|
||||||
|
|||||||
Vendored
+11
-3
@@ -15,7 +15,7 @@ if(SIMDJSON_GOOGLE_BENCHMARKS)
|
|||||||
set_off(BENCHMARK_ENABLE_INSTALL)
|
set_off(BENCHMARK_ENABLE_INSTALL)
|
||||||
set_off(BENCHMARK_ENABLE_WERROR)
|
set_off(BENCHMARK_ENABLE_WERROR)
|
||||||
|
|
||||||
import_dependency(google_benchmarks google/benchmark f91b6b4)
|
import_dependency(google_benchmarks google/benchmark v1.7.1)
|
||||||
add_dependency(google_benchmarks)
|
add_dependency(google_benchmarks)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
@@ -91,9 +91,17 @@ int main() {}
|
|||||||
target_include_directories(jsoncpp SYSTEM PUBLIC "${jsoncpp_SOURCE_DIR}")
|
target_include_directories(jsoncpp SYSTEM PUBLIC "${jsoncpp_SOURCE_DIR}")
|
||||||
target_compile_definitions(jsoncpp INTERFACE SIMDJSON_COMPETITION_JSONCPP)
|
target_compile_definitions(jsoncpp INTERFACE SIMDJSON_COMPETITION_JSONCPP)
|
||||||
|
|
||||||
import_dependency(rapidjson Tencent/rapidjson b32cd94)
|
import_dependency(rapidjson Tencent/rapidjson f54b0e4)
|
||||||
add_library(rapidjson INTERFACE)
|
add_library(rapidjson INTERFACE)
|
||||||
target_compile_definitions(rapidjson INTERFACE RAPIDJSON_HAS_STDSTRING)
|
target_compile_definitions(rapidjson INTERFACE RAPIDJSON_HAS_STDSTRING)
|
||||||
|
include (TestBigEndian)
|
||||||
|
TEST_BIG_ENDIAN(IS_BIG_ENDIAN)
|
||||||
|
if(IS_BIG_ENDIAN)
|
||||||
|
target_compile_definitions(rapidjson INTERFACE RAPIDJSON_ENDIAN=1)
|
||||||
|
else()
|
||||||
|
target_compile_definitions(rapidjson INTERFACE RAPIDJSON_ENDIAN=0)
|
||||||
|
endif()
|
||||||
|
target_compile_definitions(rapidjson INTERFACE RAPIDJSON_HAS_STDSTRING)
|
||||||
target_include_directories(rapidjson SYSTEM INTERFACE
|
target_include_directories(rapidjson SYSTEM INTERFACE
|
||||||
"${rapidjson_SOURCE_DIR}/include")
|
"${rapidjson_SOURCE_DIR}/include")
|
||||||
target_compile_definitions(rapidjson INTERFACE SIMDJSON_COMPETITION_RAPIDJSON)
|
target_compile_definitions(rapidjson INTERFACE SIMDJSON_COMPETITION_RAPIDJSON)
|
||||||
@@ -114,7 +122,7 @@ int main() {}
|
|||||||
"${ujson4c_SOURCE_DIR}/3rdparty")
|
"${ujson4c_SOURCE_DIR}/3rdparty")
|
||||||
target_compile_definitions(ujson4c INTERFACE SIMDJSON_COMPETITION_UJSON4C)
|
target_compile_definitions(ujson4c INTERFACE SIMDJSON_COMPETITION_UJSON4C)
|
||||||
|
|
||||||
import_dependency(yyjson ibireme/yyjson aa33ec5)
|
import_dependency(yyjson ibireme/yyjson c385651)
|
||||||
add_library(yyjson STATIC "${yyjson_SOURCE_DIR}/src/yyjson.c")
|
add_library(yyjson STATIC "${yyjson_SOURCE_DIR}/src/yyjson.c")
|
||||||
target_include_directories(yyjson SYSTEM PUBLIC "${yyjson_SOURCE_DIR}/src")
|
target_include_directories(yyjson SYSTEM PUBLIC "${yyjson_SOURCE_DIR}/src")
|
||||||
target_compile_definitions(yyjson INTERFACE SIMDJSON_COMPETITION_YYJSON)
|
target_compile_definitions(yyjson INTERFACE SIMDJSON_COMPETITION_YYJSON)
|
||||||
|
|||||||
Vendored
+1
-1
@@ -40,7 +40,7 @@ macro(add_dependency NAME)
|
|||||||
message(FATAL_ERROR "Missing ${NAME}_SOURCE_DIR variable")
|
message(FATAL_ERROR "Missing ${NAME}_SOURCE_DIR variable")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
add_subdirectory("${${NAME}_SOURCE_DIR}" "${PROJECT_BINARY_DIR}/_deps/${NAME}")
|
add_subdirectory("${${NAME}_SOURCE_DIR}" "${PROJECT_BINARY_DIR}/_deps/${NAME}" EXCLUDE_FROM_ALL)
|
||||||
endmacro()
|
endmacro()
|
||||||
|
|
||||||
function(set_off NAME)
|
function(set_off NAME)
|
||||||
|
|||||||
+385
-25
@@ -12,7 +12,7 @@ An overview of what you need to know to use simdjson, with examples.
|
|||||||
- [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)
|
||||||
- [C++11 Support and string_view](#c11-support-and-string_view)
|
- [string_view](#string_view)
|
||||||
- [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)
|
||||||
- [Minifying JSON strings without parsing](#minifying-json-strings-without-parsing)
|
- [Minifying JSON strings without parsing](#minifying-json-strings-without-parsing)
|
||||||
@@ -23,6 +23,7 @@ An overview of what you need to know to use simdjson, with examples.
|
|||||||
- [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)
|
||||||
- [Rewinding](#rewinding)
|
- [Rewinding](#rewinding)
|
||||||
- [Direct Access to the Raw String](#direct-access-to-the-raw-string)
|
- [Direct Access to the Raw String](#direct-access-to-the-raw-string)
|
||||||
- [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)
|
||||||
@@ -32,16 +33,20 @@ An overview of what you need to know to use simdjson, with examples.
|
|||||||
- [Thread Safety](#thread-safety)
|
- [Thread Safety](#thread-safety)
|
||||||
- [Standard Compliance](#standard-compliance)
|
- [Standard Compliance](#standard-compliance)
|
||||||
- [Backwards Compatibility](#backwards-compatibility)
|
- [Backwards Compatibility](#backwards-compatibility)
|
||||||
|
- [Examples](#examples)
|
||||||
|
- [Performance Tips](#performance-tips)
|
||||||
|
|
||||||
|
|
||||||
Requirements
|
Requirements
|
||||||
------------------
|
------------------
|
||||||
|
|
||||||
- A recent compiler (LLVM clang 6 or better, GNU GCC 7.4 or better, Xcode 11 or better) on a 64-bit (PPC, ARM or x64 Intel/AMD) POSIX systems such as macOS, freeBSD or Linux. We require that the compiler supports the C++11 standard or better.
|
- A recent compiler (LLVM clang 6 or better, GNU GCC 7.4 or better, Xcode 11 or better) on a 64-bit (PPC, ARM or x64 Intel/AMD) POSIX systems such as macOS, freeBSD or Linux. We require that the compiler supports the C++11 standard or better.
|
||||||
- Visual Studio 2017 or better under 64-bit Windows. Users should target a 64-bit build (x64) instead of a 32-bit build (x86). We support the LLVM clang compiler under Visual Studio (clangcl) as well as as the regular Visual Studio compiler. We also support MinGW 64-bit under Windows.
|
- Visual Studio 2017 or better under 64-bit Windows. Users should target a 64-bit build (x64 or ARM64) instead of a 32-bit build (x86). We support the LLVM clang compiler under Visual Studio (clangcl) as well as as the regular Visual Studio compiler. We also support MinGW 64-bit under Windows.
|
||||||
|
|
||||||
|
|
||||||
Support for AVX-512 require a processor with AVX512-VBMI2 support (Ice Lake 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).
|
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.
|
||||||
|
|
||||||
|
We test the library on a big-endian system (IBM s390x with Linux) .
|
||||||
|
|
||||||
Including simdjson
|
Including simdjson
|
||||||
------------------
|
------------------
|
||||||
@@ -61,7 +66,7 @@ c++ myproject.cpp simdjson.cpp
|
|||||||
```
|
```
|
||||||
|
|
||||||
Note:
|
Note:
|
||||||
- Users on macOS and other platforms where default compilers do not provide C++11 compliant by default should request it with the appropriate flag (e.g., `c++ -std=c++17 myproject.cpp simdjson.cpp`).
|
- Users on macOS and other platforms 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`).
|
- The library relies on [runtime CPU detection](implementation-selection.md): avoid specifying an architecture at compile time (e.g., `-march-native`).
|
||||||
|
|
||||||
Using simdjson with package managers
|
Using simdjson with package managers
|
||||||
@@ -99,7 +104,7 @@ We recommend CMake version 3.15 or better.
|
|||||||
|
|
||||||
See [our CMake demonstration](https://github.com/simdjson/cmake_demo_single_file). It works under Linux, FreeBSD, macOS and Windows (including Visual Studio).
|
See [our CMake demonstration](https://github.com/simdjson/cmake_demo_single_file). It works under Linux, FreeBSD, macOS and Windows (including Visual Studio).
|
||||||
|
|
||||||
The CMake build in simdjson can be taylored with a few variables. You can see the available variables and their default values by entering the `cmake -LA` command.
|
The CMake build in simdjson can be tailored with a few variables. You can see the available variables and their default values by entering the `cmake -LA` command.
|
||||||
|
|
||||||
|
|
||||||
Versions
|
Versions
|
||||||
@@ -140,6 +145,12 @@ As required by the standard, your JSON document should be in a Unicode (UTF-8) s
|
|||||||
string, from the beginning to the end, needs to be valid: we do not attempt to tolerate bad
|
string, from the beginning to the end, needs to be valid: we do not attempt to tolerate bad
|
||||||
inputs before or after a document.
|
inputs before or after a document.
|
||||||
|
|
||||||
|
For efficiency reasons, simdjson requires a string with a few bytes (`simdjson::SIMDJSON_PADDING`)
|
||||||
|
at the end, these bytes may be read but their content does not affect the parsing. In practice,
|
||||||
|
it means that the JSON inputs should be stored in a memory region with `simdjson::SIMDJSON_PADDING`
|
||||||
|
extra bytes at the end. You do not have to set these bytes to specific values though you may
|
||||||
|
want to if you want to avoid runtime warnings with some sanitizers.
|
||||||
|
|
||||||
The simdjson library offers a tree-like [API](https://en.wikipedia.org/wiki/API), which you can
|
The simdjson library offers a tree-like [API](https://en.wikipedia.org/wiki/API), which you can
|
||||||
access by creating a `ondemand::parser` and calling the `iterate()` method. The iterate method
|
access by creating a `ondemand::parser` and calling the `iterate()` method. The iterate method
|
||||||
quickly indexes the input string and may detect some errors. The following example illustrates
|
quickly indexes the input string and may detect some errors. The following example illustrates
|
||||||
@@ -151,8 +162,7 @@ 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
|
||||||
```
|
```
|
||||||
|
|
||||||
You can also create a padded string---for efficiency reasons, simdjson requires a string
|
You can also create a padded string---and call `iterate()`:
|
||||||
with a few bytes (`simdjson::SIMDJSON_PADDING`) at the end---and calling `iterate()`:
|
|
||||||
|
|
||||||
```c++
|
```c++
|
||||||
ondemand::parser parser;
|
ondemand::parser parser;
|
||||||
@@ -172,6 +182,21 @@ ondemand::document doc = parser.iterate(json, strlen(json), sizeof(json));
|
|||||||
The simdjson library will also accept `std::string` instances, as long as the `capacity()` of
|
The simdjson library will also accept `std::string` instances, as long as the `capacity()` of
|
||||||
the string exceeds the `size()` by at least `SIMDJSON_PADDING`. You can increase the `capacity()` with the `reserve()` function of your strings.
|
the string exceeds the `size()` by at least `SIMDJSON_PADDING`. You can increase the `capacity()` with the `reserve()` function of your strings.
|
||||||
|
|
||||||
|
You can copy your data directly on a `simdjson::padded_string` as follows:
|
||||||
|
|
||||||
|
```c++
|
||||||
|
const char * data = "my data"; // 7 bytes
|
||||||
|
simdjson::padded_string my_padded_data(data, 7); // copies to a padded buffer
|
||||||
|
```
|
||||||
|
|
||||||
|
Or as follows...
|
||||||
|
|
||||||
|
```c++
|
||||||
|
std::string data = "my data";
|
||||||
|
simdjson::padded_string my_padded_data(data); // copies to a padded buffer
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
We recommend against creating many `std::string` or many `std::padding_string` instances in your application to store your JSON data.
|
We recommend against creating many `std::string` or many `std::padding_string` instances in your application to store your JSON data.
|
||||||
Consider reusing the same buffers and limiting memory allocations.
|
Consider reusing the same buffers and limiting memory allocations.
|
||||||
|
|
||||||
@@ -206,7 +231,9 @@ For best performance, a `parser` instance should be reused over several files: o
|
|||||||
needlessly reallocate memory, an expensive process. It is also possible to avoid entirely memory
|
needlessly reallocate memory, an expensive process. It is also possible to avoid entirely memory
|
||||||
allocations during parsing when using simdjson. [See our performance notes for details](performance.md).
|
allocations during parsing when using simdjson. [See our performance notes for details](performance.md).
|
||||||
|
|
||||||
C++11 Support and string_view
|
If you need to have several documents active at once, you should have several parser instances.
|
||||||
|
|
||||||
|
string_view
|
||||||
-------------
|
-------------
|
||||||
|
|
||||||
The simdjson library builds on compilers supporting the [C++11 standard](https://en.wikipedia.org/wiki/C%2B%2B11).
|
The simdjson library builds on compilers supporting the [C++11 standard](https://en.wikipedia.org/wiki/C%2B%2B11).
|
||||||
@@ -285,6 +312,11 @@ We invite you to keep the following rules in mind:
|
|||||||
2. Because On Demand is really just an iterator, you must fully consume the current object or array before accessing a sibling object or array.
|
2. Because On Demand is really just an iterator, you must fully consume the current object or array before accessing a sibling object or array.
|
||||||
3. Values can only be consumed once, you should get the values and store them if you plan to need them multiple times. You are expected to access the keys of an object just once. You are expected to go through the values of an array just once.
|
3. Values can only be consumed once, you should get the values and store them if you plan to need them multiple times. You are expected to access the keys of an object just once. You are expected to go through the values of an array just once.
|
||||||
|
|
||||||
|
The simdjson library makes generous use of `std::string_view` instances. If you are unfamiliar
|
||||||
|
with `std::string_view` in C++, make sure to [read the section on std::string_view](#string_view).
|
||||||
|
They behave much like an immutable `std::string` but they require no memory allocation. You can
|
||||||
|
create a `std::string` instance from an `std::string_view` when you need it.
|
||||||
|
|
||||||
The following specific instructions indicate how to use the JSON when exceptions are enabled, but simdjson has full, idiomatic
|
The following specific instructions indicate how to use the JSON when exceptions are enabled, but simdjson has full, idiomatic
|
||||||
support for users who avoid exceptions. See [the simdjson error handling documentation](basics.md#error-handling) for more.
|
support for users who avoid exceptions. See [the simdjson error handling documentation](basics.md#error-handling) for more.
|
||||||
|
|
||||||
@@ -296,8 +328,19 @@ support for users who avoid exceptions. See [the simdjson error handling documen
|
|||||||
`double(element)`. This works for `std::string_view`, double, uint64_t, int64_t, bool,
|
`double(element)`. This works for `std::string_view`, double, uint64_t, int64_t, bool,
|
||||||
ondemand::object and ondemand::array. We also have explicit methods such as `get_string()`, `get_double()`,
|
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. An exception is 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 is thrown if
|
||||||
the cast is not possible.
|
the cast is not possible. Importantly, when getting an ondemand::object or ondemand::array instance, its content is
|
||||||
|
not validated: you are only guaranteed that the corresponding initial character (`{` or `[`) is present. Thus,
|
||||||
|
for example, you could have an ondemand::object instance pointing at the invalid JSON `{ "this is not a valid object" }`: the validation occurs as you access the content.
|
||||||
|
The `get_string()` returns a valid UTF-8 string, after
|
||||||
|
unescaping characters as needed: unmatched surrogate pairs are treated as an error unless you
|
||||||
|
pass `true` (`get_string(true)`) as a parameter to get replacement characters where errors
|
||||||
|
occur. If you somehow need to access non-UTF-8 strings in a lossless manner
|
||||||
|
(e.g., if you strings contain unpaired surrogates), you may use the `get_wobbly_string()` function to get a string in the [WTF-8 format](https://simonsapin.github.io/wtf-8).
|
||||||
|
When calling `get_uint64()` and `get_int64()`, if the number does not fit in a corresponding
|
||||||
|
64-bit integer type, it is also considered an error. When parsing numbers or other scalar values, the library checks
|
||||||
|
that the value is followed by an expected character, thus you *may* get a number parsing error when accessing the digits
|
||||||
|
as an integer in the following strings: `{"number":12332a`, `{"number":12332\0`, `{"number":12332` (the digits appear at the end). We always abide by the [RFC 8259](https://www.tbray.org/ongoing/When/201x/2017/12/14/rfc8259.html) JSON specification so that, for example, numbers prefixed by the `+` sign are in error.
|
||||||
|
|
||||||
> IMPORTANT NOTE: values can only be parsed once. Since documents are *iterators*, once you have
|
> IMPORTANT NOTE: values can only be parsed once. Since documents are *iterators*, once you have
|
||||||
> parsed a value (such as by casting to double), you cannot get at it again. It is an error to call
|
> parsed a value (such as by casting to double), you cannot get at it again. It is an error to call
|
||||||
@@ -429,11 +472,12 @@ support for users who avoid exceptions. See [the simdjson error handling documen
|
|||||||
```
|
```
|
||||||
This examples also show how we can string several operations and only check for the error once, a strategy we call *error chaining*.
|
This examples also show how we can string several operations and only check for the error once, a strategy we call *error chaining*.
|
||||||
Though error chaining makes the code very compact, it also makes error reporting less precise: in this instance, you may get the
|
Though error chaining makes the code very compact, it also makes error reporting less precise: in this instance, you may get the
|
||||||
same error whether the field "str", "123" or "abc" is missing. If you need to break down error handling per operation, avoid error chaining.
|
same error whether the field "str", "123" or "abc" is missing. If you need to break down error handling per operation, avoid error chaining. Furthermore, you should be mindful that chaining that harm performance by encouraging redundancies: writing both `doc["str"]["123"]["abc"].get(value)` and `doc["str"]["123"]["zyw"].get(value)` in the same program may force multiple accesses to the same keys (`"str"` and `"123"`).
|
||||||
* **Counting elements in arrays:** Sometimes it is useful to scan an array to determine its length prior to parsing it.
|
* **Counting elements in arrays:** Sometimes it is useful to scan an array to determine its length prior to parsing it.
|
||||||
For this purpose, `array` instances have a `count_elements` method. Users should be
|
For this purpose, `array` instances have a `count_elements` method. Users should be
|
||||||
aware that the `count_elements` method can be costly since it requires scanning the
|
aware that the `count_elements` method can be costly since it requires scanning the
|
||||||
whole array. You may use it as follows if your document is itself an array:
|
whole array. You should only call `count_elements` as a last resort as it may
|
||||||
|
require scanning the document twice or more. You may use it as follows if your document is itself an array:
|
||||||
|
|
||||||
```C++
|
```C++
|
||||||
auto cars_json = R"( [ 40.1, 39.9, 37.7, 40.4 ] )"_padded;
|
auto cars_json = R"( [ 40.1, 39.9, 37.7, 40.4 ] )"_padded;
|
||||||
@@ -453,14 +497,15 @@ support for users who avoid exceptions. See [the simdjson error handling documen
|
|||||||
size_t count = test_array.count_elements(); // requires simdjson 1.0 or better
|
size_t count = test_array.count_elements(); // requires simdjson 1.0 or better
|
||||||
std::cout << "Number of elements: " << count << std::endl;
|
std::cout << "Number of elements: " << count << std::endl;
|
||||||
for(ondemand::object elem: test_array) {
|
for(ondemand::object elem: test_array) {
|
||||||
std::cout << simdjson::to_string(elem);
|
std::cout << simdjson::to_json_string(elem);
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
* **Counting fields in objects:** Other times, it is useful to scan an object to determine the number of fields prior to
|
* **Counting fields in objects:** Other times, it is useful to scan an object to determine the number of fields prior to
|
||||||
parsing it.
|
parsing it.
|
||||||
For this purpose, `object` instances have a `count_fields` method. Again, users should be
|
For this purpose, `object` instances have a `count_fields` method. Again, users should be
|
||||||
aware that the `count_fields` method can be costly since it requires scanning the
|
aware that the `count_fields` method can be costly since it requires scanning the
|
||||||
whole objects. You may use it as follows if your document is itself an object:
|
whole objects. You should only call `count_fields` as a last resort as it may
|
||||||
|
require scanning the document twice or more. You may use it as follows if your document is itself an object:
|
||||||
|
|
||||||
```C++
|
```C++
|
||||||
ondemand::parser parser;
|
ondemand::parser parser;
|
||||||
@@ -480,8 +525,20 @@ support for users who avoid exceptions. See [the simdjson error handling documen
|
|||||||
std::cout << "Number of fields: " << count << std::endl; // Prints "Number of fields: 2"
|
std::cout << "Number of fields: " << count << std::endl; // Prints "Number of fields: 2"
|
||||||
```
|
```
|
||||||
* **Tree Walking and JSON Element Types:** Sometimes you don't necessarily have a document
|
* **Tree Walking and JSON Element Types:** Sometimes you don't necessarily have a document
|
||||||
with a known type, and are trying to generically inspect or walk over JSON elements. To do that, you can use iterators and the `type()` method. You can also represent arbitrary JSON values with
|
with a known type, and are trying to generically inspect or walk over JSON elements.
|
||||||
`ondemand::value` instances: it can represent anything except a scalar document (lone number, string, null or Boolean). You can check for scalar documents with the method `scalar()`. You may also access [raw strings](#raw-strings).
|
You can also represent arbitrary JSON values with
|
||||||
|
`ondemand::value` instances: it can represent anything except a scalar document (lone number, string, null or Boolean). You can check for scalar documents with the method `scalar()`.
|
||||||
|
You can query the type of a document or a value with the `type()` method.
|
||||||
|
The `type()` method does not consume or validate documents and values, but it tells you whether they are
|
||||||
|
- arrays (`json_type::array`),
|
||||||
|
- objects (`json_type::object`)
|
||||||
|
- numbers (`json_type::number`),
|
||||||
|
- strings (`json_type::string`),
|
||||||
|
- Booleans (`json_type::boolean`),
|
||||||
|
- null (`json_type::null`).
|
||||||
|
|
||||||
|
You must still validate and consume the values (e.g., call `is_null()`) after calling `type()`.
|
||||||
|
You may also access [raw strings](#raw-strings).
|
||||||
For example, the following is a quick and dirty recursive function that verbosely prints the JSON document as JSON. This example also illustrates lifecycle requirements: the `document` instance holds the iterator. The document must remain in scope while you are accessing instances of `value`, `object` and `array`.
|
For example, the following is a quick and dirty recursive function that verbosely prints the JSON document as JSON. This example also illustrates lifecycle requirements: the `document` instance holds the iterator. The document must remain in scope while you are accessing instances of `value`, `object` and `array`.
|
||||||
```c++
|
```c++
|
||||||
void recursive_print_json(ondemand::value element) {
|
void recursive_print_json(ondemand::value element) {
|
||||||
@@ -530,7 +587,11 @@ support for users who avoid exceptions. See [the simdjson error handling documen
|
|||||||
cout << element.get_bool();
|
cout << element.get_bool();
|
||||||
break;
|
break;
|
||||||
case ondemand::json_type::null:
|
case ondemand::json_type::null:
|
||||||
cout << "null";
|
// We check that the value is indeed null
|
||||||
|
// otherwise: an error is thrown.
|
||||||
|
if(element.is_null()) {
|
||||||
|
cout << "null";
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -595,6 +656,41 @@ for (ondemand::object car : parser.iterate(cars_json)) {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
The previous example had an array of objects, but we can use essentially the same
|
||||||
|
approach with an object of objects.
|
||||||
|
|
||||||
|
```c++
|
||||||
|
ondemand::parser parser;
|
||||||
|
auto cars_json = R"( {
|
||||||
|
"identifier1":{ "make": "Toyota", "model": "Camry", "year": 2018, "tire_pressure": [ 40.1, 39.9, 37.7, 40.4 ] },
|
||||||
|
"identifier2":{ "make": "Kia", "model": "Soul", "year": 2012, "tire_pressure": [ 30.1, 31.0, 28.6, 28.7 ] },
|
||||||
|
"identifier3":{ "make": "Toyota", "model": "Tercel", "year": 1999, "tire_pressure": [ 29.8, 30.0, 30.2, 30.5 ] }
|
||||||
|
} )"_padded;
|
||||||
|
// Iterating through an array of objects
|
||||||
|
ondemand::document doc = parser.iterate(cars_json);
|
||||||
|
for (ondemand::field key_car : doc.get_object()) {
|
||||||
|
// If I need a string_view and/or, I can use key_car.unescaped_key() instead, but
|
||||||
|
// key_car.key() will be more performant otherwise.
|
||||||
|
cout << "identifier : " << key_car.key() << std::endl;
|
||||||
|
// I can now access the subobject:
|
||||||
|
ondemand::object car = key_car.value();
|
||||||
|
// Accessing a field by name
|
||||||
|
cout << "Make/Model: " << std::string_view(car["make"]) << "/" << std::string_view(car["model"]) << endl;
|
||||||
|
|
||||||
|
// Casting a JSON element to an integer
|
||||||
|
uint64_t year = car["year"];
|
||||||
|
cout << "- This car is " << 2020 - year << "years old." << endl;
|
||||||
|
|
||||||
|
// Iterating through an array of floats
|
||||||
|
double total_tire_pressure = 0;
|
||||||
|
for (double tire_pressure : car["tire_pressure"]) {
|
||||||
|
total_tire_pressure += tire_pressure;
|
||||||
|
}
|
||||||
|
cout << "- Average tire pressure: " << (total_tire_pressure / 4) << endl;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
The following example illustrates how you may also iterate through object values, effectively visiting all key-value pairs in the object.
|
The following example illustrates how you may also iterate through object values, effectively visiting all key-value pairs in the object.
|
||||||
|
|
||||||
```C++
|
```C++
|
||||||
@@ -929,11 +1025,11 @@ bool parse() {
|
|||||||
// Iterating through an array of objects
|
// Iterating through an array of objects
|
||||||
auto error = parser.iterate(cars_json).get(doc);
|
auto error = parser.iterate(cars_json).get(doc);
|
||||||
if(error) { std::cerr << error << std::endl; return false; }
|
if(error) { std::cerr << error << std::endl; return false; }
|
||||||
ondemand::array cars;
|
ondemand::array cars; // invalid until the get() succeeds
|
||||||
error = doc.get_array().get(cars);
|
error = doc.get_array().get(cars);
|
||||||
|
|
||||||
for (auto car_value : cars) {
|
for (auto car_value : cars) {
|
||||||
ondemand::object car;
|
ondemand::object car; // invalid until the get() succeeds
|
||||||
error = car_value.get_object().get(car);
|
error = car_value.get_object().get(car);
|
||||||
if(error) { std::cerr << error << std::endl; return false; }
|
if(error) { std::cerr << error << std::endl; return false; }
|
||||||
|
|
||||||
@@ -948,7 +1044,7 @@ bool parse() {
|
|||||||
cout << "Make/Model: " << make << "/" << model << endl;
|
cout << "Make/Model: " << make << "/" << model << endl;
|
||||||
|
|
||||||
// Casting a JSON element to an integer
|
// Casting a JSON element to an integer
|
||||||
uint64_t year;
|
uint64_t year{};
|
||||||
error = car["year"].get(year);
|
error = car["year"].get(year);
|
||||||
if(error) { std::cerr << error << std::endl; return false; }
|
if(error) { std::cerr << error << std::endl; return false; }
|
||||||
cout << "- This car is " << 2020 - year << " years old." << endl;
|
cout << "- This car is " << 2020 - year << " years old." << endl;
|
||||||
@@ -970,6 +1066,19 @@ bool parse() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
For safety, you should only use our ondemand instances (e.g., `ondemand::object`)
|
||||||
|
after you have initialized them and checked that there is no error:
|
||||||
|
|
||||||
|
```c++
|
||||||
|
ondemand::object car; // invalid until the get() succeeds
|
||||||
|
// the `car` instance should not use used before it is initialized
|
||||||
|
error = car_value.get_object().get(car);
|
||||||
|
if(error) {
|
||||||
|
// the `car` instance should not use used
|
||||||
|
} else {
|
||||||
|
// the `car` instance can be safely used
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
The following examples illustrates how to iterate through the content of an object without
|
The following examples illustrates how to iterate through the content of an object without
|
||||||
having to handle exceptions.
|
having to handle exceptions.
|
||||||
@@ -979,10 +1088,12 @@ having to handle exceptions.
|
|||||||
ondemand::document doc;
|
ondemand::document doc;
|
||||||
auto error = parser.iterate(json).get(doc);
|
auto error = parser.iterate(json).get(doc);
|
||||||
if(error) { return false; }
|
if(error) { return false; }
|
||||||
ondemand::object object;
|
ondemand::object object; // invalid until the get() succeeds
|
||||||
error = doc.get_object().get(object);
|
error = doc.get_object().get(object);
|
||||||
if(error) { return false; }
|
if(error) { return false; }
|
||||||
for(auto field : object) {
|
for(auto field : object) {
|
||||||
|
// We could replace 'field.key() with field.unescaped_key(),
|
||||||
|
// and ondemand::raw_json_string by std::string_view.
|
||||||
ondemand::raw_json_string keyv;
|
ondemand::raw_json_string keyv;
|
||||||
error = field.key().get(keyv);
|
error = field.key().get(keyv);
|
||||||
if(error) { return false; }
|
if(error) { return false; }
|
||||||
@@ -1008,7 +1119,7 @@ target_compile_definitions(simdjson PUBLIC SIMDJSON_EXCEPTIONS=OFF)
|
|||||||
Users more comfortable with an exception flow may choose to directly cast the `simdjson_result<T>` to the desired type:
|
Users more comfortable with an exception flow may choose to directly cast the `simdjson_result<T>` to the desired type:
|
||||||
|
|
||||||
```c++
|
```c++
|
||||||
simdjson::ondemande::document doc = parser.iterate(json); // Throws an exception if there was an error!
|
simdjson::ondemand::document doc = parser.iterate(json); // Throws an exception if there was an error!
|
||||||
```
|
```
|
||||||
|
|
||||||
When used this way, a `simdjson_error` exception will be thrown if an error occurs, preventing the
|
When used this way, a `simdjson_error` exception will be thrown if an error occurs, preventing the
|
||||||
@@ -1034,7 +1145,7 @@ int main(void) {
|
|||||||
### Current location in document
|
### Current location in document
|
||||||
|
|
||||||
Sometimes, it might be helpful to know the current location in the document during iteration. This is especially useful when encountering errors. The `current_location()` method on a
|
Sometimes, it might be helpful to know the current location in the document during iteration. This is especially useful when encountering errors. The `current_location()` method on a
|
||||||
`document` instances makes it easy to identify common JSON errors. Users can call the `current_location()` method on a validdocument instance to retrieve a `const char *` pointer to the current location in the document. This method also works even after an error has invalidated the document and the parser (e.g. `TAPE_ERROR`, `INCOMPLETE_ARRAY_OR_OBJECT`).
|
`document` instances makes it easy to identify common JSON errors. Users can call the `current_location()` method on a valid document instance to retrieve a `const char *` pointer to the current location in the document. This method also works even after an error has invalidated the document and the parser (e.g. `TAPE_ERROR`, `INCOMPLETE_ARRAY_OR_OBJECT`).
|
||||||
When the input was a `padding_string` or another null-terminated source, then you may
|
When the input was a `padding_string` or another null-terminated source, then you may
|
||||||
use the `const char *` pointer as a C string. As an example, consider the following
|
use the `const char *` pointer as a C string. As an example, consider the following
|
||||||
example where we used the exception-free simdjson interface:
|
example where we used the exception-free simdjson interface:
|
||||||
@@ -1047,6 +1158,12 @@ int64_t i;
|
|||||||
auto error = doc["integer"].get_int64().get(i); // Expect to get integer from "integer" key, but get TAPE_ERROR
|
auto error = doc["integer"].get_int64().get(i); // Expect to get integer from "integer" key, but get TAPE_ERROR
|
||||||
if (error) {
|
if (error) {
|
||||||
std::cout << error << std::endl; // Prints TAPE_ERROR error message
|
std::cout << error << std::endl; // Prints TAPE_ERROR error message
|
||||||
|
// Recover a pointer to the location of the first error:
|
||||||
|
const char * ptr;
|
||||||
|
doc.current_location().get(ptr);
|
||||||
|
// ptr points at 'false, "integer": -343} " which is the location of the error
|
||||||
|
//
|
||||||
|
// Because we pad simdjson::padded_string instances with null characters, you may also do the following:
|
||||||
std::cout<< doc.current_location() << std::endl; // Prints "false, "integer": -343} " (location of TAPE_ERROR)
|
std::cout<< doc.current_location() << std::endl; // Prints "false, "integer": -343} " (location of TAPE_ERROR)
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@@ -1095,6 +1212,9 @@ for (auto val : doc) {
|
|||||||
std::cout << doc.current_location() << std::endl; // Throws OUT_OF_BOUNDS
|
std::cout << doc.current_location() << std::endl; // Throws OUT_OF_BOUNDS
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Conversely, if `doc.current_location().error() == simdjson::SUCCESS`,
|
||||||
|
then the document has more content.
|
||||||
|
|
||||||
Finally, the `current_location()` method may also be used even when no exceptions/errors
|
Finally, the `current_location()` method may also be used even when no exceptions/errors
|
||||||
are thrown. This can be helpful for users that want to know the current state of iteration during parsing. For example:
|
are thrown. This can be helpful for users that want to know the current state of iteration during parsing. For example:
|
||||||
|
|
||||||
@@ -1103,7 +1223,7 @@ auto json = R"( [[1,2,3], -23.4, {"key": "value"}, true] )"_padded;
|
|||||||
ondemand::parser parser;
|
ondemand::parser parser;
|
||||||
auto doc = parser.iterate(json);
|
auto doc = parser.iterate(json);
|
||||||
for (auto val : doc) {
|
for (auto val : doc) {
|
||||||
ondemand::object obj;
|
ondemand::object obj; // invalid until the get() succeeds
|
||||||
auto error = val.get_object().get(obj); // Only get objects
|
auto error = val.get_object().get(obj); // Only get objects
|
||||||
if (!error) {
|
if (!error) {
|
||||||
std::cout << doc.current_location() << std::endl; // Prints ""key": "value"}, true] "
|
std::cout << doc.current_location() << std::endl; // Prints ""key": "value"}, true] "
|
||||||
@@ -1120,6 +1240,32 @@ contains control characters that must be escaped and UNCLOSED_STRING if there
|
|||||||
is an unclosed string in the document. We do not provide location information for these
|
is an unclosed string in the document. We do not provide location information for these
|
||||||
errors.
|
errors.
|
||||||
|
|
||||||
|
### Checking for trailing content
|
||||||
|
|
||||||
|
The parser validates all parsed content, but your code may exhaust the content while
|
||||||
|
not having processed the entire document. Thus, as a final optional step, you may
|
||||||
|
call `at_end()` on the document instance. If it returns `false`, then you may
|
||||||
|
conclude that you have trailing content and that your document is not valid JSON.
|
||||||
|
You may then use `doc.current_location()` to obtain a pointer to the start of the trailing
|
||||||
|
content.
|
||||||
|
|
||||||
|
```C++
|
||||||
|
auto json = R"([1, 2] foo ])"_padded;
|
||||||
|
ondemand::parser parser;
|
||||||
|
ondemand::document doc = parser.iterate(json);
|
||||||
|
ondemand::array array = doc.get_array();
|
||||||
|
for (uint64_t values : array) {
|
||||||
|
std::cout << values << std::endl;
|
||||||
|
}
|
||||||
|
if(!doc.at_end()) {
|
||||||
|
// In this instance, we will be left pointing at 'foo' since we have consumed the array [1,2].
|
||||||
|
std::cerr << "trailing content at byte index " << doc.current_location() - json.data() << std::endl;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
The `at_end()` method is equivalent to `doc.current_location().error() == simdjson::SUCCESS` but
|
||||||
|
more convenient.
|
||||||
|
|
||||||
Rewinding
|
Rewinding
|
||||||
----------
|
----------
|
||||||
|
|
||||||
@@ -1381,6 +1527,8 @@ if (error) {
|
|||||||
It is also important to note that when dealing an invalid number inside a string, simdjson will report a `NUMBER_ERROR` error if the string begins with a number whereas simdjson
|
It is also important to note that when dealing an invalid number inside a string, simdjson will report a `NUMBER_ERROR` error if the string begins with a number whereas simdjson
|
||||||
will report a `INCORRECT_TYPE` error otherwise.
|
will report a `INCORRECT_TYPE` error otherwise.
|
||||||
|
|
||||||
|
The `*_in_string` methods can also be called on a single document instance:
|
||||||
|
e.g., when your document consist solely of a quoted number.
|
||||||
|
|
||||||
Dynamic Number Types
|
Dynamic Number Types
|
||||||
------------------------------
|
------------------------------
|
||||||
@@ -1516,7 +1664,7 @@ Standard Compliance
|
|||||||
|
|
||||||
The simdjson library is fully compliant with the [RFC 8259](https://www.tbray.org/ongoing/When/201x/2017/12/14/rfc8259.html) JSON specification.
|
The simdjson library is fully compliant with the [RFC 8259](https://www.tbray.org/ongoing/When/201x/2017/12/14/rfc8259.html) JSON specification.
|
||||||
|
|
||||||
- The only insignificant whitespace characters allowed are the space, the horizontal tab, the line feed and the carriage return. In particular, a JSON document may not contain an unespaced null character.
|
- The only insignificant whitespace characters allowed are the space, the horizontal tab, the line feed and the carriage return. In particular, a JSON document may not contain an unescaped null character.
|
||||||
- A single string or a single number is considered to be a valid JSON document.
|
- A single string or a single number is considered to be a valid JSON document.
|
||||||
- We fully validate the numbers according to the JSON specification. For example, the string `01` is not valid JSON document since the specification states that *leading zeros are not allowed*.
|
- We fully validate the numbers according to the JSON specification. For example, the string `01` is not valid JSON document since the specification states that *leading zeros are not allowed*.
|
||||||
- The specification allows implementations to set limits on the range and precision of numbers accepted. We support 64-bit floating-point numbers as well as integer values.
|
- The specification allows implementations to set limits on the range and precision of numbers accepted. We support 64-bit floating-point numbers as well as integer values.
|
||||||
@@ -1535,3 +1683,215 @@ Backwards Compatibility
|
|||||||
The only header file supported by simdjson is `simdjson.h`. Older versions of simdjson published a
|
The only header file supported by simdjson is `simdjson.h`. Older versions of simdjson published a
|
||||||
number of other include files such as `document.h` or `ParsedJson.h` alongside `simdjson.h`; these headers
|
number of other include files such as `document.h` or `ParsedJson.h` alongside `simdjson.h`; these headers
|
||||||
may be moved or removed in future versions.
|
may be moved or removed in future versions.
|
||||||
|
|
||||||
|
Examples
|
||||||
|
--------
|
||||||
|
|
||||||
|
Some users like to have example. The following code samples illustrate how to process specific JSON inputs.
|
||||||
|
For simplicity, we do not include full error support: this code would throw exceptions on error.
|
||||||
|
|
||||||
|
|
||||||
|
* Example 1: ZuluBBox
|
||||||
|
|
||||||
|
```C++
|
||||||
|
struct ZuluBBox {
|
||||||
|
double xmin;
|
||||||
|
double ymin;
|
||||||
|
double width;
|
||||||
|
double height;
|
||||||
|
|
||||||
|
void print() {
|
||||||
|
std::cout << xmin << ", " << ymin << ", " << width << ", " << height
|
||||||
|
<< std::endl;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
bool example() {
|
||||||
|
|
||||||
|
auto json = R"+( {
|
||||||
|
"ZuluROI": {
|
||||||
|
"ZuluBBox": {
|
||||||
|
"xmin": 0,
|
||||||
|
"ymin": 0,
|
||||||
|
"width": 1,
|
||||||
|
"height": 1
|
||||||
|
},
|
||||||
|
"SubObjects": [
|
||||||
|
{
|
||||||
|
"ZuluDetection": {
|
||||||
|
"label": "car",
|
||||||
|
"class_id": 3,
|
||||||
|
"confidence": 0.7587034106254578,
|
||||||
|
"ZuluBBox": {
|
||||||
|
"xmin": 0.3843536376953125,
|
||||||
|
"ymin": 0.4532909393310547,
|
||||||
|
"width": 0.09115534275770187,
|
||||||
|
"height": 0.04127710685133934
|
||||||
|
},
|
||||||
|
"SubObjects": []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ZuluDetection": {
|
||||||
|
"label": "car",
|
||||||
|
"class_id": 3,
|
||||||
|
"confidence": 0.6718865633010864,
|
||||||
|
"ZuluBBox": {
|
||||||
|
"xmin": 0.7500002980232239,
|
||||||
|
"ymin": 0.5212296843528748,
|
||||||
|
"width": 0.07592231780290604,
|
||||||
|
"height": 0.038947589695453644
|
||||||
|
},
|
||||||
|
"SubObjects": []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ZuluDetection": {
|
||||||
|
"label": "car",
|
||||||
|
"class_id": 3,
|
||||||
|
"confidence": 0.5806200504302979,
|
||||||
|
"ZuluBBox": {
|
||||||
|
"xmin": 0.9025363922119141,
|
||||||
|
"ymin": 0.5925348401069641,
|
||||||
|
"width": 0.05478987470269203,
|
||||||
|
"height": 0.046337299048900604
|
||||||
|
},
|
||||||
|
"SubObjects": []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"timestamp (ms)": 1677085594421,
|
||||||
|
"buffer_offset": 35673
|
||||||
|
} )+"_padded;
|
||||||
|
ondemand::parser parser;
|
||||||
|
ondemand::document doc = parser.iterate(json);
|
||||||
|
ondemand::object root_object = doc.get_object();
|
||||||
|
ondemand::object roi_object = root_object["ZuluROI"];
|
||||||
|
|
||||||
|
ondemand::object box_roi_object = roi_object["ZuluBBox"];
|
||||||
|
ZuluBBox box = {
|
||||||
|
double(box_roi_object["xmin"]), double(box_roi_object["ymin"]),
|
||||||
|
double(box_roi_object["width"]), double(box_roi_object["height"])};
|
||||||
|
box.print();
|
||||||
|
|
||||||
|
for (ondemand::object value : roi_object["SubObjects"]) {
|
||||||
|
ondemand::object detect = value["ZuluDetection"];
|
||||||
|
std::cout << detect["label"].get_string() << std::endl;
|
||||||
|
std::cout << detect["class_id"].get_uint64() << std::endl;
|
||||||
|
std::cout << detect["confidence"].get_double() << std::endl;
|
||||||
|
|
||||||
|
ondemand::object vbox_roi_object = detect["ZuluBBox"];
|
||||||
|
ZuluBBox vbox = {
|
||||||
|
double(vbox_roi_object["xmin"]), double(vbox_roi_object["ymin"]),
|
||||||
|
double(vbox_roi_object["width"]), double(vbox_roi_object["height"])};
|
||||||
|
vbox.print();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << root_object["timestamp (ms)"].get_uint64() << std::endl;
|
||||||
|
std::cout << root_object["buffer_offset"].get_uint64() << std::endl;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
* Example 2: Demos
|
||||||
|
|
||||||
|
```C++
|
||||||
|
bool example() {
|
||||||
|
auto json = R"+( {
|
||||||
|
"5f08a730b280e54fd1e75a7046b93fdc": {
|
||||||
|
"file": "/DEMOS/0-9/10_Orbyte.sid",
|
||||||
|
"len": [
|
||||||
|
"1:17"
|
||||||
|
],
|
||||||
|
"loud": [
|
||||||
|
"-22.8"
|
||||||
|
],
|
||||||
|
"name": "10 Orbyte",
|
||||||
|
"author": "Michael Becker (Premium)",
|
||||||
|
"release": "2014 Tristar & Red Sector Inc.",
|
||||||
|
"bits": 20
|
||||||
|
},
|
||||||
|
"2727236ead44a62f0c6e01f6dd4dc484": {
|
||||||
|
"file": "/DEMOS/0-9/12345.sid",
|
||||||
|
"len": [
|
||||||
|
"0:56"
|
||||||
|
],
|
||||||
|
"loud": [
|
||||||
|
"-33.3"
|
||||||
|
],
|
||||||
|
"name": "12345",
|
||||||
|
"author": "Beal",
|
||||||
|
"release": "1988 Beal",
|
||||||
|
"bits": 20
|
||||||
|
},
|
||||||
|
"7ea765fce6c0f92570b18adc7bf52f54": {
|
||||||
|
"file": "/DEMOS/0-9/128_Byte_Blues_BASIC.sid",
|
||||||
|
"len": [
|
||||||
|
"0:18"
|
||||||
|
],
|
||||||
|
"loud": [
|
||||||
|
"-27.1"
|
||||||
|
],
|
||||||
|
"name": "128 Byte Blues",
|
||||||
|
"author": "Leonard J. Paul (Freaky DNA)",
|
||||||
|
"release": "2005 Freaky DNA",
|
||||||
|
"bits": 62
|
||||||
|
}
|
||||||
|
} )+"_padded;
|
||||||
|
ondemand::parser parser;
|
||||||
|
ondemand::document doc = parser.iterate(json);
|
||||||
|
ondemand::object root_object = doc.get_object();
|
||||||
|
for(auto key_value : root_object) {
|
||||||
|
// could get std::string_view with 'unescaped_key()':
|
||||||
|
std::cout << "key: " << key_value.key() << std::endl;
|
||||||
|
ondemand::object obj = key_value.value();
|
||||||
|
|
||||||
|
std::cout << "file: " << std::string_view(obj["file"]) << std::endl;
|
||||||
|
|
||||||
|
std::cout << "len: ";
|
||||||
|
for(std::string_view values : obj["len"]) {
|
||||||
|
std::cout << values << std::endl;
|
||||||
|
}
|
||||||
|
std::cout << std::endl;
|
||||||
|
|
||||||
|
std::cout << "loud: ";
|
||||||
|
for(std::string_view values : obj["loud"]) {
|
||||||
|
std::cout << values << std::endl;
|
||||||
|
}
|
||||||
|
std::cout << std::endl;
|
||||||
|
|
||||||
|
std::cout << "name: " << std::string_view(obj["name"]) << std::endl;
|
||||||
|
std::cout << "author: " << std::string_view(obj["author"]) << std::endl;
|
||||||
|
std::cout << "release: " << std::string_view(obj["release"]) << std::endl;
|
||||||
|
std::cout << "bits: " << uint64_t(obj["bits"]) << std::endl;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
Performance Tips
|
||||||
|
--------
|
||||||
|
|
||||||
|
|
||||||
|
- The On Demand front-end works best when doing a single pass over the input: avoid calling `count_elements`, `rewind` 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).
|
||||||
|
- Given a field `field` in an object, calling `field.key()` is often faster than `field.unescaped_key()` so if you do not need an unescaped `std::string_view` instance, prefer `field.key()`.
|
||||||
|
- For release builds, we recommend setting `NDEBUG` pre-processor directive when compiling the `simdjson` library. Importantly, using the optimization flags `-O2` or `-O3` under GCC and LLVM clang does not set the `NDEBUG` directive, you must set it manually (e.g., `-DNDEBUG`).
|
||||||
|
- For long streams of JSON documents, consider [`iterate_many`](iterate_many.md) and [`parse_many`](parse_many.md) for better performance.
|
||||||
|
- If possible, refer to each object and array in your code once. For example, the following code repeatedly refers to the `"data"` key to create an object...
|
||||||
|
```C++
|
||||||
|
std::string_view make = o["data"]["make"];
|
||||||
|
std::string_view model = o["data"]["model"];
|
||||||
|
std::string_view year = o["data"]["year"];
|
||||||
|
```
|
||||||
|
We expect that it is more efficient to access the `"data"` key once:
|
||||||
|
```C++
|
||||||
|
simdjson::ondemand::object data = o["data"];
|
||||||
|
std::string_view model = data["model"];
|
||||||
|
std::string_view year = data["year"];
|
||||||
|
std::string_view rating = data["rating"];
|
||||||
|
```
|
||||||
|
- To better understand the operation of your On Demand parser, and whether it is performing as well as you think it should be, there is a logger feature built in to simdjson! To use it, define the pre-processor directive `SIMDJSON_VERBOSE_LOGGING` prior to including the `simdjson.h` header, which enables logging in simdjson. Run your code. It may generate a lot of logging output; adding printouts from your application that show each section may be helpful. The log’s output will show step-by-step information on state, buffer pointer position, depth, and key retrieval status.
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
We take our documentation seriously. Please start reading the documentation before you attempt to use simdjson. We hope you will enjoy reading us.
|
We take our documentation seriously. Please start reading the documentation before you attempt to use simdjson. We hope you will enjoy reading us.
|
||||||
|
|
||||||
* Basics: https://github.com/simdjson/simdjson/blob/master/doc/basics.md is an overview of how to use simdjson and its APIs.
|
* Basics: https://github.com/simdjson/simdjson/blob/master/doc/basics.md is an overview of how to use simdjson and its APIs.
|
||||||
* parse_many: https://github.com/simdjson/simdjson/blob/master/doc/parse_many.md describes an interface providing features to work with files or streams containing multiple small JSON documents. As fast and convenient as possible.
|
* iterate_many: https://github.com/simdjson/simdjson/blob/master/doc/iterate_many.md describes an interface providing features to work with files or streams containing multiple small JSON documents. As fast and convenient as possible.
|
||||||
* Performance: https://github.com/simdjson/simdjson/blob/master/doc/performance.md shows some more advanced scenarios and how to tune for them.
|
* Performance: https://github.com/simdjson/simdjson/blob/master/doc/performance.md shows some more advanced scenarios and how to tune for them.
|
||||||
|
|||||||
+34
-12
@@ -16,6 +16,7 @@ An overview of what you need to know to use simdjson, with examples.
|
|||||||
* [Server Loops: Long-Running Processes and Memory Capacity](#server-loops-long-running-processes-and-memory-capacity)
|
* [Server Loops: Long-Running Processes and Memory Capacity](#server-loops-long-running-processes-and-memory-capacity)
|
||||||
* [Best Use of the DOM API](#best-use-of-the-dom-api)
|
* [Best Use of the DOM API](#best-use-of-the-dom-api)
|
||||||
* [Padding and Temporary Copies](#padding-and-temporary-copies)
|
* [Padding and Temporary Copies](#padding-and-temporary-copies)
|
||||||
|
* [Performance Tips](#performance-tips)
|
||||||
|
|
||||||
DOM vs On Demand
|
DOM vs On Demand
|
||||||
----------------------------------------------
|
----------------------------------------------
|
||||||
@@ -44,10 +45,24 @@ dom::parser parser;
|
|||||||
dom::element doc = parser.parse("[1,2,3]"_padded); // parse a string, the _padded suffix creates a simdjson::padded_string instance
|
dom::element doc = parser.parse("[1,2,3]"_padded); // parse a string, the _padded suffix creates a simdjson::padded_string instance
|
||||||
```
|
```
|
||||||
|
|
||||||
|
You can copy your data directly on a `simdjson::padded_string` as follows:
|
||||||
|
|
||||||
|
```c++
|
||||||
|
const char * data = "my data"; // 7 bytes
|
||||||
|
simdjson::padded_string my_padded_data(data, 7); // copies to a padded buffer
|
||||||
|
```
|
||||||
|
|
||||||
|
Or as follows...
|
||||||
|
|
||||||
|
```c++
|
||||||
|
std::string data = "my data";
|
||||||
|
simdjson::padded_string my_padded_data(data); // copies to a padded buffer
|
||||||
|
```
|
||||||
|
|
||||||
The parsed document resulting from the `parser.load` and `parser.parse` calls depends on the `parser` instance. Thus the `parser` instance must remain in scope. Furthermore, you must have at most one parsed document in play per `parser` instance.
|
The parsed document resulting from the `parser.load` and `parser.parse` calls depends on the `parser` instance. Thus the `parser` instance must remain in scope. Furthermore, you must have at most one parsed document in play per `parser` instance.
|
||||||
You cannot copy a `parser` instance, you may only move it.
|
You cannot copy a `parser` instance, you may only move it.
|
||||||
|
|
||||||
If you need to keep a document around long term, you can keep or move the parser instance. Note that moving a parser instance, or keeping one in a movable data structure like vector or map, can cause any outstanding `element`, `object` or `array` instances to be invalidated. If you need to store a parser in a movable data structure, you should use a `std::unique_ptr` to avoid this invalidation(e.g., `std::unique_ptr<dom::parser> parser(new dom::parser{})`).
|
If you need to keep a document around long term, you can keep or move the parser instance. Note that moving a parser instance, or keeping one in a movable data structure like vector or map, can cause any outstanding `element`, `object` or `array` instances to be invalidated. The `element`, `object` or `array` instances are mere thin wrappers akin to an `std::vector<int>::iterator`: they are invalid when default constructed, they must be tied to a valid document instance. If you need to store a parser in a movable data structure, you should use a `std::unique_ptr` to avoid this invalidation(e.g., `std::unique_ptr<dom::parser> parser(new dom::parser{})`).
|
||||||
|
|
||||||
During the`load` or `parse` calls, neither the input file nor the input string are ever modified. After calling `load` or `parse`, the source (either a file or a string) can be safely discarded. All of the JSON data is stored in the `parser` instance. The parsed document is also immutable in simdjson: you do not modify it by accessing it.
|
During the`load` or `parse` calls, neither the input file nor the input string are ever modified. After calling `load` or `parse`, the source (either a file or a string) can be safely discarded. All of the JSON data is stored in the `parser` instance. The parsed document is also immutable in simdjson: you do not modify it by accessing it.
|
||||||
|
|
||||||
@@ -65,7 +80,7 @@ Once you have an element, you can navigate it with idiomatic C++ iterators, oper
|
|||||||
* **Extracting Values (with exceptions):** You can cast a JSON element to a native type: `double(element)` or
|
* **Extracting Values (with exceptions):** You can cast a JSON element to a native type: `double(element)` or
|
||||||
`double x = json_element`. This works for double, uint64_t, int64_t, bool,
|
`double x = json_element`. This works for double, uint64_t, int64_t, bool,
|
||||||
dom::object and dom::array. An exception (`simdjson::simdjson_error`) is thrown if the cast is not possible.
|
dom::object and dom::array. An exception (`simdjson::simdjson_error`) is thrown if the cast is not possible.
|
||||||
* **Extracting Values (without exceptions):** You can use a variant usage of `get()` with error codes to avoid exceptions. You first declare the variable of the appropriate type (`double`, `uint64_t`, `int64_t`, `bool`,
|
* **Extracting Values (without exceptions):** You can use a variant usage of `get()` with error codes to avoid exceptions. You first declare the variable of the appropriate type (`double`, `uint64_t`, `int64_t`, `bool`, `std::string_view`,
|
||||||
`dom::object` and `dom::array`) and pass it by reference to `get()` which gives you back an error code: e.g.,
|
`dom::object` and `dom::array`) and pass it by reference to `get()` which gives you back an error code: e.g.,
|
||||||
```c++
|
```c++
|
||||||
simdjson::error_code error;
|
simdjson::error_code error;
|
||||||
@@ -76,6 +91,7 @@ Once you have an element, you can navigate it with idiomatic C++ iterators, oper
|
|||||||
if (error) { std::cerr << error << std::endl; return EXIT_FAILURE; }
|
if (error) { std::cerr << error << std::endl; return EXIT_FAILURE; }
|
||||||
std::cout << "I parsed " << value << " from " << numberstring.data() << std::endl;
|
std::cout << "I parsed " << value << " from " << numberstring.data() << std::endl;
|
||||||
```
|
```
|
||||||
|
The strings contain unescaped valid UTF-8 strings: no unmatched surrogate is allowed.
|
||||||
* **Field Access:** To get the value of the "foo" field in an object, use `object["foo"]`.
|
* **Field Access:** To get the value of the "foo" field in an object, use `object["foo"]`.
|
||||||
* **Array Iteration:** To iterate through an array, use `for (auto value : array) { ... }`. If you
|
* **Array Iteration:** To iterate through an array, use `for (auto value : array) { ... }`. If you
|
||||||
know the type of the value, you can cast it right there, too! `for (double value : array) { ... }`
|
know the type of the value, you can cast it right there, too! `for (double value : array) { ... }`
|
||||||
@@ -88,7 +104,7 @@ Once you have an element, you can navigate it with idiomatic C++ iterators, oper
|
|||||||
* **Array and Object size** Given an array or an object, you can get its size (number of elements or keys)
|
* **Array and Object size** Given an array or an object, you can get its size (number of elements or keys)
|
||||||
with the `size()` method.
|
with the `size()` method.
|
||||||
* **Checking an Element Type:** You can check an element's type with `element.type()`. It
|
* **Checking an Element Type:** You can check an element's type with `element.type()`. It
|
||||||
returns an `element_type` with values such as `simdjson::dom::element_type::ARRAY`, `simdjson::dom::element_type::OBJECT`, `simdjson::dom::element_type::INT64`, `simdjson::dom::element_type::UINT64`,`simdjson::dom::element_type::DOUBLE`, `simdjson::dom::element_type::BOOL` or, `simdjson::dom::element_type::NULL_VALUE`.
|
returns an `element_type` with values such as `simdjson::dom::element_type::ARRAY`, `simdjson::dom::element_type::OBJECT`, `simdjson::dom::element_type::INT64`, `simdjson::dom::element_type::UINT64`,`simdjson::dom::element_type::DOUBLE`, `simdjson::dom::element_type::STRING`, `simdjson::dom::element_type::BOOL` or, `simdjson::dom::element_type::NULL_VALUE`.
|
||||||
* **Output to streams and strings:** Given a document or an element (or node) out of a JSON document, you can output a minified string version using the C++ stream idiom (`out << element`). You can also request the construction of a minified string version (`simdjson::minify(element)`). Numbers are serialized as 64-bit floating-point numbers (`double`).
|
* **Output to streams and strings:** Given a document or an element (or node) out of a JSON document, you can output a minified string version using the C++ stream idiom (`out << element`). You can also request the construction of a minified string version (`simdjson::minify(element)`). Numbers are serialized as 64-bit floating-point numbers (`double`).
|
||||||
|
|
||||||
### Examples
|
### Examples
|
||||||
@@ -167,7 +183,7 @@ While the simdjson library can be used in any project using C++ 11 and above, fi
|
|||||||
```c++
|
```c++
|
||||||
padded_string json = R"( { "foo": 1, "bar": 2 } )"_padded;
|
padded_string json = R"( { "foo": 1, "bar": 2 } )"_padded;
|
||||||
dom::parser parser;
|
dom::parser parser;
|
||||||
dom::object object;
|
dom::object object; // invalid until the get() succeeds
|
||||||
auto error = parser.parse(json).get(object);
|
auto error = parser.parse(json).get(object);
|
||||||
if (error) { cerr << error << endl; return; }
|
if (error) { cerr << error << endl; return; }
|
||||||
for (auto [key, value] : object) {
|
for (auto [key, value] : object) {
|
||||||
@@ -181,7 +197,7 @@ For comparison, here is the C++ 11 version of the same code:
|
|||||||
// C++ 11 version for comparison
|
// C++ 11 version for comparison
|
||||||
padded_string json = R"( { "foo": 1, "bar": 2 } )"_padded;
|
padded_string json = R"( { "foo": 1, "bar": 2 } )"_padded;
|
||||||
dom::parser parser;
|
dom::parser parser;
|
||||||
dom::object object;
|
dom::object object; // invalid until the get() succeeds
|
||||||
auto error = parser.parse(json).get(object);
|
auto error = parser.parse(json).get(object);
|
||||||
if (error) { cerr << error << endl; return; }
|
if (error) { cerr << error << endl; return; }
|
||||||
for (dom::key_value_pair field : object) {
|
for (dom::key_value_pair field : object) {
|
||||||
@@ -227,7 +243,7 @@ dom::parser parser;
|
|||||||
dom::element cars = parser.parse(cars_json);
|
dom::element cars = parser.parse(cars_json);
|
||||||
cout << cars.at_pointer("/0/tire_pressure/1") << endl; // Prints 39.9
|
cout << cars.at_pointer("/0/tire_pressure/1") << endl; // Prints 39.9
|
||||||
for (dom::element car_element : cars) {
|
for (dom::element car_element : cars) {
|
||||||
dom::object car;
|
dom::object car; // invalid until the get() succeeds
|
||||||
simdjson::error_code error;
|
simdjson::error_code error;
|
||||||
if ((error = car_element.get(car))) { std::cerr << error << std::endl; return; }
|
if ((error = car_element.get(car))) { std::cerr << error << std::endl; return; }
|
||||||
double x = car.at_pointer("/tire_pressure/1");
|
double x = car.at_pointer("/tire_pressure/1");
|
||||||
@@ -283,11 +299,11 @@ it selects the key "count" within that object.
|
|||||||
|
|
||||||
int main(void) {
|
int main(void) {
|
||||||
simdjson::dom::parser parser;
|
simdjson::dom::parser parser;
|
||||||
simdjson::dom::element tweets;
|
simdjson::dom::element tweets; // invalid until the get() succeeds
|
||||||
auto error = parser.load("twitter.json").get(tweets);
|
auto error = parser.load("twitter.json").get(tweets);
|
||||||
if (error) { std::cerr << error << std::endl; return EXIT_FAILURE; }
|
if (error) { std::cerr << error << std::endl; return EXIT_FAILURE; }
|
||||||
|
|
||||||
simdjson::dom::element res;
|
simdjson::dom::element res; // invalid until the get() succeeds
|
||||||
if ((error = tweets["search_metadata"]["count"].get(res))) {
|
if ((error = tweets["search_metadata"]["count"].get(res))) {
|
||||||
std::cerr << "could not access keys" << std::endl;
|
std::cerr << "could not access keys" << std::endl;
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
@@ -311,7 +327,7 @@ Observe how we use the `at` method when querying an index into an array, and not
|
|||||||
|
|
||||||
int main(void) {
|
int main(void) {
|
||||||
simdjson::dom::parser parser;
|
simdjson::dom::parser parser;
|
||||||
simdjson::dom::element tweets;
|
simdjson::dom::element tweets; // invalid until the get() succeeds
|
||||||
auto error = parser.load("twitter.json").get(tweets);
|
auto error = parser.load("twitter.json").get(tweets);
|
||||||
if(error) { std::cerr << error << std::endl; return EXIT_FAILURE; }
|
if(error) { std::cerr << error << std::endl; return EXIT_FAILURE; }
|
||||||
uint64_t identifier;
|
uint64_t identifier;
|
||||||
@@ -336,7 +352,7 @@ auto cars_json = R"( [
|
|||||||
{ "make": "Toyota", "model": "Tercel", "year": 1999, "tire_pressure": [ 29.8, 30.0, 30.2, 30.5 ] }
|
{ "make": "Toyota", "model": "Tercel", "year": 1999, "tire_pressure": [ 29.8, 30.0, 30.2, 30.5 ] }
|
||||||
] )"_padded;
|
] )"_padded;
|
||||||
dom::parser parser;
|
dom::parser parser;
|
||||||
dom::array cars;
|
dom::array cars; // invalid until the get() succeeds
|
||||||
auto error = parser.parse(cars_json).get(cars);
|
auto error = parser.parse(cars_json).get(cars);
|
||||||
if (error) { cerr << error << endl; exit(1); }
|
if (error) { cerr << error << endl; exit(1); }
|
||||||
|
|
||||||
@@ -382,7 +398,7 @@ auto abstract_json = R"( [
|
|||||||
{ "12545" : {"a":11.44, "b":12.78, "c": 11111111} }
|
{ "12545" : {"a":11.44, "b":12.78, "c": 11111111} }
|
||||||
] )"_padded;
|
] )"_padded;
|
||||||
dom::parser parser;
|
dom::parser parser;
|
||||||
dom::array array;
|
dom::array array; // invalid until after the next line
|
||||||
auto error = parser.parse(abstract_json).get(array);
|
auto error = parser.parse(abstract_json).get(array);
|
||||||
if (error) { cerr << error << endl; exit(1); }
|
if (error) { cerr << error << endl; exit(1); }
|
||||||
// Iterate through an array of objects
|
// Iterate through an array of objects
|
||||||
@@ -436,7 +452,7 @@ bool parse_double(const char *j, double &d) {
|
|||||||
|
|
||||||
bool parse_string(const char *j, std::string &s) {
|
bool parse_string(const char *j, std::string &s) {
|
||||||
std::string_view answer;
|
std::string_view answer;
|
||||||
auto error = parser.parse(j,strlen(j))
|
auto error = parser.parse(j, strlen(j))
|
||||||
.at(0)
|
.at(0)
|
||||||
.get(answer, error);
|
.get(answer, error);
|
||||||
if (error) { return false; }
|
if (error) { return false; }
|
||||||
@@ -643,3 +659,9 @@ simdjson::dom::element element = parser.parse(padded_json_copy.get(), json_len,
|
|||||||
````
|
````
|
||||||
|
|
||||||
Setting the `realloc_if_needed` parameter `false` in this manner may lead to better performance since copies are avoided, but it requires that the user takes more responsibilities: the simdjson library cannot verify that the input buffer was padded with SIMDJSON_PADDING extra bytes.
|
Setting the `realloc_if_needed` parameter `false` in this manner may lead to better performance since copies are avoided, but it requires that the user takes more responsibilities: the simdjson library cannot verify that the input buffer was padded with SIMDJSON_PADDING extra bytes.
|
||||||
|
|
||||||
|
Performance Tips
|
||||||
|
---------------------
|
||||||
|
|
||||||
|
- 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` directrive, 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.
|
||||||
|
|||||||
@@ -21,12 +21,13 @@ The current implementations are:
|
|||||||
* haswell: AVX2 (2013 Intel Haswell or later)
|
* haswell: AVX2 (2013 Intel Haswell or later)
|
||||||
* westmere: SSE4.2 (2010 Westmere or later).
|
* westmere: SSE4.2 (2010 Westmere or later).
|
||||||
* arm64: 64-bit ARMv8-A NEON
|
* arm64: 64-bit ARMv8-A NEON
|
||||||
* ppc64: 64-bit POWER8 and POWER9 with VSX and ALTIVEC extensions. Both big endian and little endian are implemented, depends on the compiler you are using.
|
* ppc64: 64-bit POWER8 and POWER9 with VSX and ALTIVEC extensions. Both big endian and little endian are implemented, depends on the compiler you are using. The library is tested on recent, little-endian, POWER systems.
|
||||||
* fallback: A generic implementation that runs on any 64-bit processor.
|
* fallback: A generic implementation that runs on any 64-bit processor.
|
||||||
|
|
||||||
In many cases, you don't know where your compiled binary is going to run, so simdjson automatically
|
In many cases, you don't know where your compiled binary is going to run, so simdjson automatically
|
||||||
compiles *all* the implementations into the executable. On Intel, it will include 3 implementations
|
compiles *all* the implementations into the executable. On Intel, it will include 4 implementations
|
||||||
(haswell, westmere and fallback), on ARM it will include 2 (arm64 and fallback), and on PPC it will include 2 (ppc64 and fallback).
|
(icelake, haswell, westmere and fallback), on ARM it will include 2 (arm64 and fallback), and on PPC
|
||||||
|
it will include 2 (ppc64 and fallback).
|
||||||
|
|
||||||
If you know more about where you're going to run and want to save the space, you can disable any of
|
If you know more about where you're going to run and want to save the space, you can disable any of
|
||||||
these implementations at compile time with `-DSIMDJSON_IMPLEMENTATION_X=0` (where X is ICELAKE, HASWELL,
|
these implementations at compile time with `-DSIMDJSON_IMPLEMENTATION_X=0` (where X is ICELAKE, HASWELL,
|
||||||
@@ -51,7 +52,7 @@ Inspecting the Detected Implementation
|
|||||||
You can check what implementation is running with `active_implementation`:
|
You can check what implementation is running with `active_implementation`:
|
||||||
|
|
||||||
```c++
|
```c++
|
||||||
cout << "simdjson v" << SIMDJSON_STRINGIFY(SIMDJSON_VERSION) << endl;
|
cout << "simdjson v" << SIMDJSON_VERSION << endl;
|
||||||
cout << "Detected the best implementation for your machine: " << simdjson::get_active_implementation()->name();
|
cout << "Detected the best implementation for your machine: " << simdjson::get_active_implementation()->name();
|
||||||
cout << "(" << simdjson::get_active_implementation()->description() << ")" << endl;
|
cout << "(" << simdjson::get_active_implementation()->description() << ")" << endl;
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -752,7 +752,7 @@ On relevant systems, the On Demand API provides some support for runtime dispatc
|
|||||||
|
|
||||||
Some users wish to run at the best possible speed. Under recent Intel and AMD processors, these users should take additional steps to verify that their code is well optimized.
|
Some users wish to run at the best possible speed. Under recent Intel and AMD processors, these users should take additional steps to verify that their code is well optimized.
|
||||||
|
|
||||||
Given that the On Demand API offer limited runtime dispatching, it matters that your code is compiled against a specific CPU target. You should verify that the code is compiled against the target you expect. Thankfully, the simdjson library will tell you exactly what it detects as an implementation: `haswell` (AVX2 x64 processors), `westmere` (SSE4 x64 processors), `arm64` (64-bit ARM), `ppc64` (64-bit POWER), `fallback` (others). Under x64 processors, many programmers will want to target `haswell` whereas under ARM, most programmers will want to target `arm64` (and it should do so automatically). The `fallback` is probably only good for testing purposes, not for deployment.
|
Given that the On Demand API offer limited runtime dispatching, it matters that your code is compiled against a specific CPU target. You should verify that the code is compiled against the target you expect. Thankfully, the simdjson library will tell you exactly what it detects as an implementation: `icelake` (AVX512 x64 processors), `haswell` (AVX2 x64 processors), `westmere` (SSE4 x64 processors), `arm64` (64-bit ARM), `ppc64` (64-bit POWER), `fallback` (others). Under x64 processors, many programmers will want to target `haswell` whereas under ARM, most programmers will want to target `arm64` (and it should do so automatically). The `fallback` is probably only good for testing purposes, not for deployment.
|
||||||
|
|
||||||
```C++
|
```C++
|
||||||
std::cout << simdjson::builtin_implementation()->name() << std::endl;
|
std::cout << simdjson::builtin_implementation()->name() << std::endl;
|
||||||
|
|||||||
+18
-4
@@ -3,7 +3,10 @@ Performance Notes
|
|||||||
|
|
||||||
simdjson strives to be at its fastest *without tuning*, and generally achieves this. However, there
|
simdjson strives to be at its fastest *without tuning*, and generally achieves this. However, there
|
||||||
are still some scenarios where tuning can enhance performance.
|
are still some scenarios where tuning can enhance performance.
|
||||||
|
Once your code is tested, we
|
||||||
|
further encourage you to define `NDEBUG` in your Release builds to disable additional runtime
|
||||||
|
testing and get the best performance.
|
||||||
|
* [NDEBUG directive](#ndebug-directive)
|
||||||
* [Reusing the parser for maximum efficiency](#reusing-the-parser-for-maximum-efficiency)
|
* [Reusing the parser for maximum efficiency](#reusing-the-parser-for-maximum-efficiency)
|
||||||
* [Reusing string buffers](#reusing-string-buffers)
|
* [Reusing string buffers](#reusing-string-buffers)
|
||||||
* [Server Loops: Long-Running Processes and Memory Capacity](#server-loops-long-running-processes-and-memory-capacity)
|
* [Server Loops: Long-Running Processes and Memory Capacity](#server-loops-long-running-processes-and-memory-capacity)
|
||||||
@@ -12,6 +15,18 @@ are still some scenarios where tuning can enhance performance.
|
|||||||
* [Visual Studio](#visual-studio)
|
* [Visual Studio](#visual-studio)
|
||||||
* [Power Usage and Downclocking](#power-usage-and-downclocking)
|
* [Power Usage and Downclocking](#power-usage-and-downclocking)
|
||||||
|
|
||||||
|
|
||||||
|
NDEBUG directive
|
||||||
|
-------------
|
||||||
|
|
||||||
|
In C/C++, the `NDEBUG` pre-processor directive is not set by default. When it is not set, the simdjson library does
|
||||||
|
many additional checks that may impact negatively the performance. We recommend that, once your code
|
||||||
|
is well tested, you define `NDEBUG` directive in your Release builds. The `NDEBUG` directive should be defined
|
||||||
|
prior to including the `simdjson.h` header.
|
||||||
|
|
||||||
|
The `NDEBUG` directive is generally independent from optimization flags. For example, setting `-O3` under
|
||||||
|
GCC does not set the `NDEBUG` directive.
|
||||||
|
|
||||||
Reusing the parser for maximum efficiency
|
Reusing the parser for maximum efficiency
|
||||||
-----------------------------------------
|
-----------------------------------------
|
||||||
|
|
||||||
@@ -138,7 +153,7 @@ few hundred megabytes per second if your JSON documents are densely packed with
|
|||||||
Visual Studio
|
Visual Studio
|
||||||
--------------
|
--------------
|
||||||
|
|
||||||
On Intel and AMD Windows platforms, Microsoft Visual Studio enables programmers to build either 32-bit (x86) or 64-bit (x64) binaries. We urge you to always use 64-bit mode. Visual Studio 2019 should default on 64-bit builds when you have a 64-bit version of Windows, which we recommend.
|
On Intel and AMD Windows platforms, Microsoft Visual Studio enables programmers to build either 32-bit (x86) or 64-bit (x64 or ARM64) binaries. We urge you to always use 64-bit mode. Visual Studio 2019 should default on 64-bit builds when you have a 64-bit version of Windows, which we recommend.
|
||||||
|
|
||||||
When compiling with Visual Studio, we recommend the flags `/Ob2 /O2` or better. We do not recommend that you compile simdjson with architecture-specific flags such as `arch:AVX2`. The simdjson library automatically selects the best execution kernel at runtime.
|
When compiling with Visual Studio, we recommend the flags `/Ob2 /O2` or better. We do not recommend that you compile simdjson with architecture-specific flags such as `arch:AVX2`. The simdjson library automatically selects the best execution kernel at runtime.
|
||||||
|
|
||||||
@@ -160,8 +175,7 @@ You should not expect the simdjson library to cause *downclocking* of your recen
|
|||||||
- [Whenever 512-bit AVX-512 instructions are used](https://lemire.me/blog/2018/09/07/avx-512-when-and-how-to-use-these-new-instructions/).
|
- [Whenever 512-bit AVX-512 instructions are used](https://lemire.me/blog/2018/09/07/avx-512-when-and-how-to-use-these-new-instructions/).
|
||||||
- Whenever heavy 256-bit or wider instructions are used. Heavy instructions are those involving floating point operations or integer multiplications (since these execute on the floating point unit).
|
- Whenever heavy 256-bit or wider instructions are used. Heavy instructions are those involving floating point operations or integer multiplications (since these execute on the floating point unit).
|
||||||
|
|
||||||
The simdjson library does not make use of heavy 256-bit instructions. We do use vectorized multiplications, but only using 128-bit registers. Thus there should be no downclocking due to simdjson on recent processors, except when AVX-512 is allowed and
|
The simdjson library does not generally make use of heavy 256-bit instructions. On AVX2 kernels, we use vectorized multiplications, but only using 128-bit registers. On recent processors (Ice Lake/Tiger Lake or better, AMD Zen 4 or better) [no frequency throttling is found](https://travisdowns.github.io/blog/2020/08/19/icl-avx512-freq.html) due to SIMD instructions: we are thus more aggressive with SIMD on these machines. If you can still concerned, you can easily disable AVX-512 with the CMake option `SIMDJSON_AVX512_ALLOWED` set to `OFF` (e.g., `cmake -D SIMDJSON_AVX512_ALLOWED=OFF -B build && cmake --build build`) or by setting
|
||||||
detected. However, we only allow AVX-512 on recent processors (Ice Lake/Tiger Lake or better) where [little to no frequency throttling is expected](https://travisdowns.github.io/blog/2020/08/19/icl-avx512-freq.html). If you can still concerned, you can easily disable AVX-512 with the CMake option `SIMDJSON_AVX512_ALLOWED` set to `OFF` (e.g., `cmake -D SIMDJSON_AVX512_ALLOWED=OFF -B build && cmake --build build`) or by setting
|
|
||||||
the macro `SIMDJSON_AVX512_ALLOWED` to `0` in C++ prior to importing the headers.
|
the macro `SIMDJSON_AVX512_ALLOWED` to `0` in C++ prior to importing the headers.
|
||||||
|
|
||||||
You may still be worried about which SIMD instruction set is used by simdjson. Thankfully, [you can always determine and change which architecture-specific implementation is used](implementation-selection.md) by simdjson. Thus even if your CPU supports AVX2, you do not need to use AVX2. You are in control.
|
You may still be worried about which SIMD instruction set is used by simdjson. Thankfully, [you can always determine and change which architecture-specific implementation is used](implementation-selection.md) by simdjson. Thus even if your CPU supports AVX2, you do not need to use AVX2. You are in control.
|
||||||
|
|||||||
@@ -9,6 +9,10 @@ namespace {
|
|||||||
// but the algorithms do not end up using the returned value.
|
// but the algorithms do not end up using the returned value.
|
||||||
// Sadly, sanitizers are not smart enough to figure it out.
|
// Sadly, sanitizers are not smart enough to figure it out.
|
||||||
SIMDJSON_NO_SANITIZE_UNDEFINED
|
SIMDJSON_NO_SANITIZE_UNDEFINED
|
||||||
|
// This function can be used safely even if not all bytes have been
|
||||||
|
// initialized.
|
||||||
|
// See issue https://github.com/simdjson/simdjson/issues/1965
|
||||||
|
SIMDJSON_NO_SANITIZE_MEMORY
|
||||||
simdjson_inline int trailing_zeroes(uint64_t input_num) {
|
simdjson_inline int trailing_zeroes(uint64_t input_num) {
|
||||||
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
|
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||||
unsigned long ret;
|
unsigned long ret;
|
||||||
|
|||||||
@@ -12,6 +12,9 @@ using namespace simdjson;
|
|||||||
using namespace simdjson::dom;
|
using namespace simdjson::dom;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
class implementation final : public simdjson::implementation {
|
class implementation final : public simdjson::implementation {
|
||||||
public:
|
public:
|
||||||
simdjson_inline implementation() : simdjson::implementation("arm64", "ARM NEON", internal::instruction_set::NEON) {}
|
simdjson_inline implementation() : simdjson::implementation("arm64", "ARM NEON", internal::instruction_set::NEON) {}
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ constexpr size_t DEFAULT_MAX_DEPTH = 1024;
|
|||||||
|
|
||||||
#define SIMDJSON_ISALIGNED_N(ptr, n) (((uintptr_t)(ptr) & ((n)-1)) == 0)
|
#define SIMDJSON_ISALIGNED_N(ptr, n) (((uintptr_t)(ptr) & ((n)-1)) == 0)
|
||||||
|
|
||||||
#if defined(SIMDJSON_REGULAR_VISUAL_STUDIO)
|
#if SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||||
|
|
||||||
#define simdjson_really_inline __forceinline
|
#define simdjson_really_inline __forceinline
|
||||||
#define simdjson_never_inline __declspec(noinline)
|
#define simdjson_never_inline __declspec(noinline)
|
||||||
@@ -155,7 +155,7 @@ constexpr size_t DEFAULT_MAX_DEPTH = 1024;
|
|||||||
|
|
||||||
#define SIMDJSON_PRAGMA(P) _Pragma(#P)
|
#define SIMDJSON_PRAGMA(P) _Pragma(#P)
|
||||||
#define SIMDJSON_DISABLE_GCC_WARNING(WARNING) SIMDJSON_PRAGMA(GCC diagnostic ignored #WARNING)
|
#define SIMDJSON_DISABLE_GCC_WARNING(WARNING) SIMDJSON_PRAGMA(GCC diagnostic ignored #WARNING)
|
||||||
#if defined(SIMDJSON_CLANG_VISUAL_STUDIO)
|
#if SIMDJSON_CLANG_VISUAL_STUDIO
|
||||||
#define SIMDJSON_DISABLE_UNDESIRED_WARNINGS SIMDJSON_DISABLE_GCC_WARNING(-Wmicrosoft-include)
|
#define SIMDJSON_DISABLE_UNDESIRED_WARNINGS SIMDJSON_DISABLE_GCC_WARNING(-Wmicrosoft-include)
|
||||||
#else
|
#else
|
||||||
#define SIMDJSON_DISABLE_UNDESIRED_WARNINGS
|
#define SIMDJSON_DISABLE_UNDESIRED_WARNINGS
|
||||||
@@ -180,7 +180,7 @@ constexpr size_t DEFAULT_MAX_DEPTH = 1024;
|
|||||||
#define simdjson_inline simdjson_really_inline
|
#define simdjson_inline simdjson_really_inline
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(SIMDJSON_VISUAL_STUDIO)
|
#if SIMDJSON_VISUAL_STUDIO
|
||||||
/**
|
/**
|
||||||
* Windows users need to do some extra work when building
|
* Windows users need to do some extra work when building
|
||||||
* or using a dynamic library (DLL). When building, we need
|
* or using a dynamic library (DLL). When building, we need
|
||||||
@@ -322,4 +322,15 @@ namespace std {
|
|||||||
# define simdjson_fallthrough do {} while (0) /* fallthrough */
|
# define simdjson_fallthrough do {} while (0) /* fallthrough */
|
||||||
#endif // simdjson_fallthrough
|
#endif // simdjson_fallthrough
|
||||||
|
|
||||||
|
|
||||||
|
#if SIMDJSON_DEVELOPMENT_CHECKS
|
||||||
|
#define SIMDJSON_DEVELOPMENT_ASSERT(expr) do { assert ((expr)); } while (0)
|
||||||
|
#else
|
||||||
|
#define SIMDJSON_DEVELOPMENT_ASSERT(expr) do { } while (0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef SIMDJSON_UTF8VALIDATION
|
||||||
|
#define SIMDJSON_UTF8VALIDATION 1
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif // SIMDJSON_COMMON_DEFS_H
|
#endif // SIMDJSON_COMMON_DEFS_H
|
||||||
|
|||||||
@@ -53,18 +53,23 @@ namespace dom {
|
|||||||
simdjson_inline array::array() noexcept : tape{} {}
|
simdjson_inline array::array() noexcept : tape{} {}
|
||||||
simdjson_inline array::array(const internal::tape_ref &_tape) noexcept : tape{_tape} {}
|
simdjson_inline array::array(const internal::tape_ref &_tape) noexcept : tape{_tape} {}
|
||||||
inline array::iterator array::begin() const noexcept {
|
inline array::iterator array::begin() const noexcept {
|
||||||
|
SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
|
||||||
return internal::tape_ref(tape.doc, tape.json_index + 1);
|
return internal::tape_ref(tape.doc, tape.json_index + 1);
|
||||||
}
|
}
|
||||||
inline array::iterator array::end() const noexcept {
|
inline array::iterator array::end() const noexcept {
|
||||||
|
SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
|
||||||
return internal::tape_ref(tape.doc, tape.after_element() - 1);
|
return internal::tape_ref(tape.doc, tape.after_element() - 1);
|
||||||
}
|
}
|
||||||
inline size_t array::size() const noexcept {
|
inline size_t array::size() const noexcept {
|
||||||
|
SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
|
||||||
return tape.scope_count();
|
return tape.scope_count();
|
||||||
}
|
}
|
||||||
inline size_t array::number_of_slots() const noexcept {
|
inline size_t array::number_of_slots() const noexcept {
|
||||||
|
SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
|
||||||
return tape.matching_brace_index() - tape.json_index;
|
return tape.matching_brace_index() - tape.json_index;
|
||||||
}
|
}
|
||||||
inline simdjson_result<element> array::at_pointer(std::string_view json_pointer) const noexcept {
|
inline simdjson_result<element> array::at_pointer(std::string_view json_pointer) const noexcept {
|
||||||
|
SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
|
||||||
if(json_pointer.empty()) { // an empty string means that we return the current node
|
if(json_pointer.empty()) { // an empty string means that we return the current node
|
||||||
return element(this->tape); // copy the current node
|
return element(this->tape); // copy the current node
|
||||||
} else if(json_pointer[0] != '/') { // otherwise there is an error
|
} else if(json_pointer[0] != '/') { // otherwise there is an error
|
||||||
@@ -105,6 +110,7 @@ inline simdjson_result<element> array::at_pointer(std::string_view json_pointer)
|
|||||||
}
|
}
|
||||||
|
|
||||||
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
|
||||||
size_t i=0;
|
size_t i=0;
|
||||||
for (auto element : *this) {
|
for (auto element : *this) {
|
||||||
if (i == index) { return element; }
|
if (i == index) { return element; }
|
||||||
|
|||||||
@@ -186,11 +186,13 @@ simdjson_inline element::element() noexcept : tape{} {}
|
|||||||
simdjson_inline element::element(const internal::tape_ref &_tape) noexcept : tape{_tape} { }
|
simdjson_inline element::element(const internal::tape_ref &_tape) noexcept : tape{_tape} { }
|
||||||
|
|
||||||
inline element_type element::type() const noexcept {
|
inline element_type element::type() const noexcept {
|
||||||
|
SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
|
||||||
auto tape_type = tape.tape_ref_type();
|
auto tape_type = tape.tape_ref_type();
|
||||||
return tape_type == internal::tape_type::FALSE_VALUE ? element_type::BOOL : static_cast<element_type>(tape_type);
|
return tape_type == internal::tape_type::FALSE_VALUE ? element_type::BOOL : static_cast<element_type>(tape_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline simdjson_result<bool> element::get_bool() const noexcept {
|
inline simdjson_result<bool> element::get_bool() const noexcept {
|
||||||
|
SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
|
||||||
if(tape.is_true()) {
|
if(tape.is_true()) {
|
||||||
return true;
|
return true;
|
||||||
} else if(tape.is_false()) {
|
} else if(tape.is_false()) {
|
||||||
@@ -199,6 +201,7 @@ inline simdjson_result<bool> element::get_bool() const noexcept {
|
|||||||
return INCORRECT_TYPE;
|
return INCORRECT_TYPE;
|
||||||
}
|
}
|
||||||
inline simdjson_result<const char *> element::get_c_str() const noexcept {
|
inline simdjson_result<const char *> element::get_c_str() const noexcept {
|
||||||
|
SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
|
||||||
switch (tape.tape_ref_type()) {
|
switch (tape.tape_ref_type()) {
|
||||||
case internal::tape_type::STRING: {
|
case internal::tape_type::STRING: {
|
||||||
return tape.get_c_str();
|
return tape.get_c_str();
|
||||||
@@ -208,6 +211,7 @@ inline simdjson_result<const char *> element::get_c_str() const noexcept {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
inline simdjson_result<size_t> element::get_string_length() const noexcept {
|
inline simdjson_result<size_t> element::get_string_length() const noexcept {
|
||||||
|
SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
|
||||||
switch (tape.tape_ref_type()) {
|
switch (tape.tape_ref_type()) {
|
||||||
case internal::tape_type::STRING: {
|
case internal::tape_type::STRING: {
|
||||||
return tape.get_string_length();
|
return tape.get_string_length();
|
||||||
@@ -217,6 +221,7 @@ inline simdjson_result<size_t> element::get_string_length() const noexcept {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
inline simdjson_result<std::string_view> element::get_string() const noexcept {
|
inline simdjson_result<std::string_view> element::get_string() const noexcept {
|
||||||
|
SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
|
||||||
switch (tape.tape_ref_type()) {
|
switch (tape.tape_ref_type()) {
|
||||||
case internal::tape_type::STRING:
|
case internal::tape_type::STRING:
|
||||||
return tape.get_string_view();
|
return tape.get_string_view();
|
||||||
@@ -225,6 +230,7 @@ inline simdjson_result<std::string_view> element::get_string() const noexcept {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
inline simdjson_result<uint64_t> element::get_uint64() const noexcept {
|
inline simdjson_result<uint64_t> element::get_uint64() const noexcept {
|
||||||
|
SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
|
||||||
if(simdjson_unlikely(!tape.is_uint64())) { // branch rarely taken
|
if(simdjson_unlikely(!tape.is_uint64())) { // branch rarely taken
|
||||||
if(tape.is_int64()) {
|
if(tape.is_int64()) {
|
||||||
int64_t result = tape.next_tape_value<int64_t>();
|
int64_t result = tape.next_tape_value<int64_t>();
|
||||||
@@ -238,6 +244,7 @@ inline simdjson_result<uint64_t> element::get_uint64() const noexcept {
|
|||||||
return tape.next_tape_value<int64_t>();
|
return tape.next_tape_value<int64_t>();
|
||||||
}
|
}
|
||||||
inline simdjson_result<int64_t> element::get_int64() const noexcept {
|
inline simdjson_result<int64_t> element::get_int64() const noexcept {
|
||||||
|
SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
|
||||||
if(simdjson_unlikely(!tape.is_int64())) { // branch rarely taken
|
if(simdjson_unlikely(!tape.is_int64())) { // branch rarely taken
|
||||||
if(tape.is_uint64()) {
|
if(tape.is_uint64()) {
|
||||||
uint64_t result = tape.next_tape_value<uint64_t>();
|
uint64_t result = tape.next_tape_value<uint64_t>();
|
||||||
@@ -252,6 +259,7 @@ inline simdjson_result<int64_t> element::get_int64() const noexcept {
|
|||||||
return tape.next_tape_value<int64_t>();
|
return tape.next_tape_value<int64_t>();
|
||||||
}
|
}
|
||||||
inline simdjson_result<double> element::get_double() const noexcept {
|
inline simdjson_result<double> element::get_double() const noexcept {
|
||||||
|
SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
|
||||||
// Performance considerations:
|
// Performance considerations:
|
||||||
// 1. Querying tape_ref_type() implies doing a shift, it is fast to just do a straight
|
// 1. Querying tape_ref_type() implies doing a shift, it is fast to just do a straight
|
||||||
// comparison.
|
// comparison.
|
||||||
@@ -273,6 +281,7 @@ inline simdjson_result<double> element::get_double() const noexcept {
|
|||||||
return tape.next_tape_value<double>();
|
return tape.next_tape_value<double>();
|
||||||
}
|
}
|
||||||
inline simdjson_result<array> element::get_array() const noexcept {
|
inline simdjson_result<array> element::get_array() const noexcept {
|
||||||
|
SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
|
||||||
switch (tape.tape_ref_type()) {
|
switch (tape.tape_ref_type()) {
|
||||||
case internal::tape_type::START_ARRAY:
|
case internal::tape_type::START_ARRAY:
|
||||||
return array(tape);
|
return array(tape);
|
||||||
@@ -281,6 +290,7 @@ inline simdjson_result<array> element::get_array() const noexcept {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
inline simdjson_result<object> element::get_object() const noexcept {
|
inline simdjson_result<object> element::get_object() const noexcept {
|
||||||
|
SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
|
||||||
switch (tape.tape_ref_type()) {
|
switch (tape.tape_ref_type()) {
|
||||||
case internal::tape_type::START_OBJECT:
|
case internal::tape_type::START_OBJECT:
|
||||||
return object(tape);
|
return object(tape);
|
||||||
@@ -360,6 +370,7 @@ inline simdjson_result<element> element::operator[](const char *key) const noexc
|
|||||||
}
|
}
|
||||||
|
|
||||||
inline simdjson_result<element> element::at_pointer(std::string_view json_pointer) const noexcept {
|
inline simdjson_result<element> element::at_pointer(std::string_view json_pointer) const noexcept {
|
||||||
|
SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
|
||||||
switch (tape.tape_ref_type()) {
|
switch (tape.tape_ref_type()) {
|
||||||
case internal::tape_type::START_OBJECT:
|
case internal::tape_type::START_OBJECT:
|
||||||
return object(tape).at_pointer(json_pointer);
|
return object(tape).at_pointer(json_pointer);
|
||||||
@@ -395,6 +406,7 @@ inline simdjson_result<element> element::at_key_case_insensitive(std::string_vie
|
|||||||
}
|
}
|
||||||
|
|
||||||
inline bool element::dump_raw_tape(std::ostream &out) const noexcept {
|
inline bool element::dump_raw_tape(std::ostream &out) const noexcept {
|
||||||
|
SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
|
||||||
return tape.doc->dump_raw_tape(out);
|
return tape.doc->dump_raw_tape(out);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -65,12 +65,15 @@ namespace dom {
|
|||||||
simdjson_inline object::object() noexcept : tape{} {}
|
simdjson_inline object::object() noexcept : tape{} {}
|
||||||
simdjson_inline object::object(const internal::tape_ref &_tape) noexcept : tape{_tape} { }
|
simdjson_inline object::object(const internal::tape_ref &_tape) noexcept : tape{_tape} { }
|
||||||
inline object::iterator object::begin() const noexcept {
|
inline object::iterator object::begin() const noexcept {
|
||||||
|
SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
|
||||||
return internal::tape_ref(tape.doc, tape.json_index + 1);
|
return internal::tape_ref(tape.doc, tape.json_index + 1);
|
||||||
}
|
}
|
||||||
inline object::iterator object::end() const noexcept {
|
inline object::iterator object::end() const noexcept {
|
||||||
|
SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
|
||||||
return internal::tape_ref(tape.doc, tape.after_element() - 1);
|
return internal::tape_ref(tape.doc, tape.after_element() - 1);
|
||||||
}
|
}
|
||||||
inline size_t object::size() const noexcept {
|
inline size_t object::size() const noexcept {
|
||||||
|
SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
|
||||||
return tape.scope_count();
|
return tape.scope_count();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -81,6 +84,7 @@ inline simdjson_result<element> object::operator[](const char *key) const noexce
|
|||||||
return at_key(key);
|
return at_key(key);
|
||||||
}
|
}
|
||||||
inline simdjson_result<element> object::at_pointer(std::string_view json_pointer) const noexcept {
|
inline simdjson_result<element> object::at_pointer(std::string_view json_pointer) const noexcept {
|
||||||
|
SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
|
||||||
if(json_pointer.empty()) { // an empty string means that we return the current node
|
if(json_pointer.empty()) { // an empty string means that we return the current node
|
||||||
return element(this->tape); // copy the current node
|
return element(this->tape); // copy the current node
|
||||||
} else if(json_pointer[0] != '/') { // otherwise there is an error
|
} else if(json_pointer[0] != '/') { // otherwise there is an error
|
||||||
|
|||||||
@@ -42,11 +42,17 @@ inline simdjson_result<size_t> parser::read_file(const std::string &path) noexce
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Get the file size
|
// Get the file size
|
||||||
if(std::fseek(fp, 0, SEEK_END) < 0) {
|
int ret;
|
||||||
|
#if SIMDJSON_VISUAL_STUDIO && !SIMDJSON_IS_32BITS
|
||||||
|
ret = _fseeki64(fp, 0, SEEK_END);
|
||||||
|
#else
|
||||||
|
ret = std::fseek(fp, 0, SEEK_END);
|
||||||
|
#endif // _WIN64
|
||||||
|
if(ret < 0) {
|
||||||
std::fclose(fp);
|
std::fclose(fp);
|
||||||
return IO_ERROR;
|
return IO_ERROR;
|
||||||
}
|
}
|
||||||
#if defined(SIMDJSON_VISUAL_STUDIO) && !SIMDJSON_IS_32BITS
|
#if SIMDJSON_VISUAL_STUDIO && !SIMDJSON_IS_32BITS
|
||||||
__int64 len = _ftelli64(fp);
|
__int64 len = _ftelli64(fp);
|
||||||
if(len == -1L) {
|
if(len == -1L) {
|
||||||
std::fclose(fp);
|
std::fclose(fp);
|
||||||
@@ -142,6 +148,9 @@ simdjson_inline simdjson_result<element> parser::parse(const std::string &s) & n
|
|||||||
simdjson_inline simdjson_result<element> parser::parse(const padded_string &s) & noexcept {
|
simdjson_inline simdjson_result<element> parser::parse(const padded_string &s) & noexcept {
|
||||||
return parse(s.data(), s.length(), false);
|
return parse(s.data(), s.length(), false);
|
||||||
}
|
}
|
||||||
|
simdjson_inline simdjson_result<element> parser::parse(const padded_string_view &v) & noexcept {
|
||||||
|
return parse(v.data(), v.length(), false);
|
||||||
|
}
|
||||||
|
|
||||||
inline simdjson_result<document_stream> parser::parse_many(const uint8_t *buf, size_t len, size_t batch_size) noexcept {
|
inline simdjson_result<document_stream> parser::parse_many(const uint8_t *buf, size_t len, size_t batch_size) noexcept {
|
||||||
if(batch_size < MINIMAL_BATCH_SIZE) { batch_size = MINIMAL_BATCH_SIZE; }
|
if(batch_size < MINIMAL_BATCH_SIZE) { batch_size = MINIMAL_BATCH_SIZE; }
|
||||||
@@ -217,7 +226,7 @@ inline error_code parser::ensure_capacity(document& target_document, size_t desi
|
|||||||
}
|
}
|
||||||
|
|
||||||
simdjson_inline void parser::set_max_capacity(size_t max_capacity) noexcept {
|
simdjson_inline void parser::set_max_capacity(size_t max_capacity) noexcept {
|
||||||
if(max_capacity < MINIMAL_DOCUMENT_CAPACITY) {
|
if(max_capacity > MINIMAL_DOCUMENT_CAPACITY) {
|
||||||
_max_capacity = max_capacity;
|
_max_capacity = max_capacity;
|
||||||
} else {
|
} else {
|
||||||
_max_capacity = MINIMAL_DOCUMENT_CAPACITY;
|
_max_capacity = MINIMAL_DOCUMENT_CAPACITY;
|
||||||
|
|||||||
@@ -145,7 +145,9 @@ public:
|
|||||||
* ### 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
|
||||||
* those bytes are initialized to, as long as they are allocated.
|
* those bytes are initialized to, as long as they are allocated. These bytes will be read: if you
|
||||||
|
* using a sanitizer that verifies that no uninitialized byte is read, then you should initialize the
|
||||||
|
* SIMDJSON_PADDING bytes to avoid runtime warnings.
|
||||||
*
|
*
|
||||||
* If realloc_if_needed is true (the default), it is assumed that the buffer does *not* have enough padding,
|
* If realloc_if_needed is true (the default), it is assumed that the buffer does *not* have enough padding,
|
||||||
* and it is copied into an enlarged temporary buffer before parsing. Thus the following is safe:
|
* and it is copied into an enlarged temporary buffer before parsing. Thus the following is safe:
|
||||||
@@ -199,6 +201,9 @@ public:
|
|||||||
/** @overload parse(const uint8_t *buf, size_t len, bool realloc_if_needed) */
|
/** @overload parse(const uint8_t *buf, size_t len, bool realloc_if_needed) */
|
||||||
simdjson_inline simdjson_result<element> parse(const padded_string &s) & noexcept;
|
simdjson_inline simdjson_result<element> parse(const padded_string &s) & noexcept;
|
||||||
simdjson_inline simdjson_result<element> parse(const padded_string &s) && =delete;
|
simdjson_inline simdjson_result<element> parse(const padded_string &s) && =delete;
|
||||||
|
/** @overload parse(const uint8_t *buf, size_t len, bool realloc_if_needed) */
|
||||||
|
simdjson_inline simdjson_result<element> parse(const padded_string_view &v) & noexcept;
|
||||||
|
simdjson_inline simdjson_result<element> parse(const padded_string_view &v) && =delete;
|
||||||
|
|
||||||
/** @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_inline simdjson_result<element> parse(const char *buf) noexcept = delete;
|
simdjson_inline simdjson_result<element> parse(const char *buf) noexcept = delete;
|
||||||
@@ -405,7 +410,9 @@ public:
|
|||||||
* ### 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
|
||||||
* those bytes are initialized to, as long as they are allocated.
|
* those bytes are initialized to, as long as they are allocated. These bytes will be read: if you
|
||||||
|
* using a sanitizer that verifies that no uninitialized byte is read, then you should initialize the
|
||||||
|
* SIMDJSON_PADDING bytes to avoid runtime warnings.
|
||||||
*
|
*
|
||||||
* ### Threads
|
* ### Threads
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ enum error_code {
|
|||||||
SUCCESS = 0, ///< No error
|
SUCCESS = 0, ///< No error
|
||||||
CAPACITY, ///< This parser can't support a document that big
|
CAPACITY, ///< This parser can't support a document that big
|
||||||
MEMALLOC, ///< Error allocating memory, most likely out of memory
|
MEMALLOC, ///< Error allocating memory, most likely out of memory
|
||||||
TAPE_ERROR, ///< Something went wrong while writing to the tape (stage 2), this is a generic error
|
TAPE_ERROR, ///< Something went wrong, this is a generic error
|
||||||
DEPTH_ERROR, ///< Your document exceeds the user-specified depth limitation
|
DEPTH_ERROR, ///< Your document exceeds the user-specified depth limitation
|
||||||
STRING_ERROR, ///< Problem while parsing a string
|
STRING_ERROR, ///< Problem while parsing a string
|
||||||
T_ATOM_ERROR, ///< Problem while parsing an atom starting with the letter 't'
|
T_ATOM_ERROR, ///< Problem while parsing an atom starting with the letter 't'
|
||||||
@@ -45,6 +45,7 @@ enum error_code {
|
|||||||
INCOMPLETE_ARRAY_OR_OBJECT, ///< The document ends early.
|
INCOMPLETE_ARRAY_OR_OBJECT, ///< The document ends early.
|
||||||
SCALAR_DOCUMENT_AS_VALUE, ///< A scalar document is treated as a value.
|
SCALAR_DOCUMENT_AS_VALUE, ///< A scalar document is treated as a value.
|
||||||
OUT_OF_BOUNDS, ///< Attempted to access location outside of document.
|
OUT_OF_BOUNDS, ///< Attempted to access location outside of document.
|
||||||
|
TRAILING_CONTENT, ///< Unexpected trailing content in the JSON input
|
||||||
NUM_ERROR_CODES
|
NUM_ERROR_CODES
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -11,6 +11,9 @@ using namespace simdjson;
|
|||||||
using namespace simdjson::dom;
|
using namespace simdjson::dom;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
class implementation final : public simdjson::implementation {
|
class implementation final : public simdjson::implementation {
|
||||||
public:
|
public:
|
||||||
simdjson_inline implementation() : simdjson::implementation(
|
simdjson_inline implementation() : simdjson::implementation(
|
||||||
|
|||||||
@@ -35,7 +35,8 @@ public:
|
|||||||
simdjson_warn_unused error_code stage1(const uint8_t *buf, size_t len, stage1_mode partial) noexcept final;
|
simdjson_warn_unused error_code stage1(const uint8_t *buf, size_t len, stage1_mode partial) noexcept final;
|
||||||
simdjson_warn_unused error_code stage2(dom::document &doc) noexcept final;
|
simdjson_warn_unused error_code stage2(dom::document &doc) noexcept final;
|
||||||
simdjson_warn_unused error_code stage2_next(dom::document &doc) noexcept final;
|
simdjson_warn_unused error_code stage2_next(dom::document &doc) noexcept final;
|
||||||
simdjson_warn_unused uint8_t *parse_string(const uint8_t *src, uint8_t *dst) const noexcept final;
|
simdjson_warn_unused uint8_t *parse_string(const uint8_t *src, uint8_t *dst, bool allow_replacement) const noexcept final;
|
||||||
|
simdjson_warn_unused uint8_t *parse_wobbly_string(const uint8_t *src, uint8_t *dst) const noexcept final;
|
||||||
inline simdjson_warn_unused error_code set_capacity(size_t capacity) noexcept final;
|
inline simdjson_warn_unused error_code set_capacity(size_t capacity) noexcept final;
|
||||||
inline simdjson_warn_unused error_code set_max_depth(size_t max_depth) noexcept final;
|
inline simdjson_warn_unused error_code set_max_depth(size_t max_depth) noexcept final;
|
||||||
private:
|
private:
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ simdjson_inline size_t codepoint_to_utf8(uint32_t cp, uint8_t *c) {
|
|||||||
return 0; // bad r
|
return 0; // bad r
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef SIMDJSON_IS_32BITS // _umul128 for x86, arm
|
#if SIMDJSON_IS_32BITS // _umul128 for x86, arm
|
||||||
// this is a slow emulation routine for 32-bit
|
// this is a slow emulation routine for 32-bit
|
||||||
//
|
//
|
||||||
static simdjson_inline uint64_t __emulu(uint32_t x, uint32_t y) {
|
static simdjson_inline uint64_t __emulu(uint32_t x, uint32_t y) {
|
||||||
@@ -94,7 +94,7 @@ using internal::value128;
|
|||||||
|
|
||||||
simdjson_inline value128 full_multiplication(uint64_t value1, uint64_t value2) {
|
simdjson_inline value128 full_multiplication(uint64_t value1, uint64_t value2) {
|
||||||
value128 answer;
|
value128 answer;
|
||||||
#if defined(SIMDJSON_REGULAR_VISUAL_STUDIO) || defined(SIMDJSON_IS_32BITS)
|
#if SIMDJSON_REGULAR_VISUAL_STUDIO || SIMDJSON_IS_32BITS
|
||||||
#ifdef _M_ARM64
|
#ifdef _M_ARM64
|
||||||
// ARM64 has native support for 64-bit multiplications, no need to emultate
|
// ARM64 has native support for 64-bit multiplications, no need to emultate
|
||||||
answer.high = __umulh(value1, value2);
|
answer.high = __umulh(value1, value2);
|
||||||
@@ -102,7 +102,7 @@ simdjson_inline value128 full_multiplication(uint64_t value1, uint64_t value2) {
|
|||||||
#else
|
#else
|
||||||
answer.low = _umul128(value1, value2, &answer.high); // _umul128 not available on ARM64
|
answer.low = _umul128(value1, value2, &answer.high); // _umul128 not available on ARM64
|
||||||
#endif // _M_ARM64
|
#endif // _M_ARM64
|
||||||
#else // defined(SIMDJSON_REGULAR_VISUAL_STUDIO) || defined(SIMDJSON_IS_32BITS)
|
#else // SIMDJSON_REGULAR_VISUAL_STUDIO || SIMDJSON_IS_32BITS
|
||||||
__uint128_t r = (static_cast<__uint128_t>(value1)) * value2;
|
__uint128_t r = (static_cast<__uint128_t>(value1)) * value2;
|
||||||
answer.low = uint64_t(r);
|
answer.low = uint64_t(r);
|
||||||
answer.high = uint64_t(r >> 64);
|
answer.high = uint64_t(r >> 64);
|
||||||
|
|||||||
@@ -112,7 +112,7 @@ simdjson_inline bool compute_float_64(int64_t power, uint64_t i, bool negative,
|
|||||||
// In the slow path, we need to adjust i so that it is > 1<<63 which is always
|
// In the slow path, we need to adjust i so that it is > 1<<63 which is always
|
||||||
// possible, except if i == 0, so we handle i == 0 separately.
|
// possible, except if i == 0, so we handle i == 0 separately.
|
||||||
if(i == 0) {
|
if(i == 0) {
|
||||||
d = 0.0;
|
d = negative ? -0.0 : 0.0;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -227,7 +227,7 @@ simdjson_inline bool compute_float_64(int64_t power, uint64_t i, bool negative,
|
|||||||
if (simdjson_unlikely(real_exponent <= 0)) { // we have a subnormal?
|
if (simdjson_unlikely(real_exponent <= 0)) { // we have a subnormal?
|
||||||
// Here have that real_exponent <= 0 so -real_exponent >= 0
|
// Here have that real_exponent <= 0 so -real_exponent >= 0
|
||||||
if(-real_exponent + 1 >= 64) { // if we have more than 64 bits below the minimum exponent, you have a zero for sure.
|
if(-real_exponent + 1 >= 64) { // if we have more than 64 bits below the minimum exponent, you have a zero for sure.
|
||||||
d = 0.0;
|
d = negative ? -0.0 : 0.0;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
// next line is safe because -real_exponent + 1 < 0
|
// next line is safe because -real_exponent + 1 < 0
|
||||||
@@ -497,7 +497,8 @@ simdjson_inline error_code write_float(const uint8_t *const src, bool negative,
|
|||||||
static_assert(simdjson::internal::smallest_power <= -342, "smallest_power is not small enough");
|
static_assert(simdjson::internal::smallest_power <= -342, "smallest_power is not small enough");
|
||||||
//
|
//
|
||||||
if((exponent < simdjson::internal::smallest_power) || (i == 0)) {
|
if((exponent < simdjson::internal::smallest_power) || (i == 0)) {
|
||||||
WRITE_DOUBLE(0, src, writer);
|
// E.g. Parse "-0.0e-999" into the same value as "-0.0". See https://en.wikipedia.org/wiki/Signed_zero
|
||||||
|
WRITE_DOUBLE(negative ? -0.0 : 0.0, src, writer);
|
||||||
return SUCCESS;
|
return SUCCESS;
|
||||||
} else { // (exponent > largest_power) and (i != 0)
|
} else { // (exponent > largest_power) and (i != 0)
|
||||||
// We have, for sure, an infinite value and simdjson refuses to parse infinite values.
|
// We have, for sure, an infinite value and simdjson refuses to parse infinite values.
|
||||||
@@ -549,7 +550,7 @@ simdjson_inline error_code parse_number(const uint8_t *const src, W &writer) {
|
|||||||
// Check for minus sign
|
// Check for minus sign
|
||||||
//
|
//
|
||||||
bool negative = (*src == '-');
|
bool negative = (*src == '-');
|
||||||
const uint8_t *p = src + negative;
|
const uint8_t *p = src + uint8_t(negative);
|
||||||
|
|
||||||
//
|
//
|
||||||
// Parse the integer part.
|
// Parse the integer part.
|
||||||
@@ -846,7 +847,7 @@ simdjson_unused simdjson_inline simdjson_result<int64_t> parse_integer(const uin
|
|||||||
// Check for minus sign
|
// Check for minus sign
|
||||||
//
|
//
|
||||||
bool negative = (*src == '-');
|
bool negative = (*src == '-');
|
||||||
const uint8_t *p = src + negative;
|
const uint8_t *p = src + uint8_t(negative);
|
||||||
|
|
||||||
//
|
//
|
||||||
// Parse the integer part.
|
// Parse the integer part.
|
||||||
@@ -890,7 +891,7 @@ simdjson_unused simdjson_inline simdjson_result<int64_t> parse_integer(const uin
|
|||||||
//
|
//
|
||||||
if(src == src_end) { return NUMBER_ERROR; }
|
if(src == src_end) { return NUMBER_ERROR; }
|
||||||
bool negative = (*src == '-');
|
bool negative = (*src == '-');
|
||||||
const uint8_t *p = src + negative;
|
const uint8_t *p = src + uint8_t(negative);
|
||||||
|
|
||||||
//
|
//
|
||||||
// Parse the integer part.
|
// Parse the integer part.
|
||||||
@@ -932,19 +933,19 @@ simdjson_unused simdjson_inline simdjson_result<int64_t> parse_integer_in_string
|
|||||||
// Check for minus sign
|
// Check for minus sign
|
||||||
//
|
//
|
||||||
bool negative = (*(src + 1) == '-');
|
bool negative = (*(src + 1) == '-');
|
||||||
const uint8_t *p = src + negative + 1;
|
src += uint8_t(negative) + 1;
|
||||||
|
|
||||||
//
|
//
|
||||||
// Parse the integer part.
|
// Parse the integer part.
|
||||||
//
|
//
|
||||||
// PERF NOTE: we don't use is_made_of_eight_digits_fast because large integers like 123456789 are rare
|
// PERF NOTE: we don't use is_made_of_eight_digits_fast because large integers like 123456789 are rare
|
||||||
const uint8_t *const start_digits = p;
|
const uint8_t *const start_digits = src;
|
||||||
uint64_t i = 0;
|
uint64_t i = 0;
|
||||||
while (parse_digit(*p, i)) { p++; }
|
while (parse_digit(*src, i)) { src++; }
|
||||||
|
|
||||||
// If there were no digits, or if the integer starts with 0 and has more than one digit, it's an error.
|
// If there were no digits, or if the integer starts with 0 and has more than one digit, it's an error.
|
||||||
// Optimization note: size_t is expected to be unsigned.
|
// Optimization note: size_t is expected to be unsigned.
|
||||||
size_t digit_count = size_t(p - start_digits);
|
size_t digit_count = size_t(src - start_digits);
|
||||||
// We go from
|
// We go from
|
||||||
// -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807
|
// -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807
|
||||||
// so we can never represent numbers that have more than 19 digits.
|
// so we can never represent numbers that have more than 19 digits.
|
||||||
@@ -956,11 +957,11 @@ simdjson_unused simdjson_inline simdjson_result<int64_t> parse_integer_in_string
|
|||||||
// Here digit_count > 0.
|
// Here digit_count > 0.
|
||||||
if (('0' == *start_digits) && (digit_count > 1)) { return NUMBER_ERROR; }
|
if (('0' == *start_digits) && (digit_count > 1)) { return NUMBER_ERROR; }
|
||||||
// We can do the following...
|
// We can do the following...
|
||||||
// if (!jsoncharutils::is_structural_or_whitespace(*p)) {
|
// if (!jsoncharutils::is_structural_or_whitespace(*src)) {
|
||||||
// return (*p == '.' || *p == 'e' || *p == 'E') ? INCORRECT_TYPE : NUMBER_ERROR;
|
// return (*src == '.' || *src == 'e' || *src == 'E') ? INCORRECT_TYPE : NUMBER_ERROR;
|
||||||
// }
|
// }
|
||||||
// as a single table lookup:
|
// as a single table lookup:
|
||||||
if(*p != '"') { return NUMBER_ERROR; }
|
if(*src != '"') { return NUMBER_ERROR; }
|
||||||
// Negative numbers have can go down to - INT64_MAX - 1 whereas positive numbers are limited to INT64_MAX.
|
// Negative numbers have can go down to - INT64_MAX - 1 whereas positive numbers are limited to INT64_MAX.
|
||||||
// Performance note: This check is only needed when digit_count == longest_digit_count but it is
|
// Performance note: This check is only needed when digit_count == longest_digit_count but it is
|
||||||
// so cheap that we might as well always make it.
|
// so cheap that we might as well always make it.
|
||||||
@@ -973,7 +974,7 @@ simdjson_unused simdjson_inline simdjson_result<double> parse_double(const uint8
|
|||||||
// Check for minus sign
|
// Check for minus sign
|
||||||
//
|
//
|
||||||
bool negative = (*src == '-');
|
bool negative = (*src == '-');
|
||||||
src += negative;
|
src += uint8_t(negative);
|
||||||
|
|
||||||
//
|
//
|
||||||
// Parse the integer part.
|
// Parse the integer part.
|
||||||
@@ -1040,7 +1041,7 @@ simdjson_unused simdjson_inline simdjson_result<double> parse_double(const uint8
|
|||||||
if (simdjson_likely(!overflow)) {
|
if (simdjson_likely(!overflow)) {
|
||||||
if (compute_float_64(exponent, i, negative, d)) { return d; }
|
if (compute_float_64(exponent, i, negative, d)) { return d; }
|
||||||
}
|
}
|
||||||
if (!parse_float_fallback(src-negative, &d)) {
|
if (!parse_float_fallback(src - uint8_t(negative), &d)) {
|
||||||
return NUMBER_ERROR;
|
return NUMBER_ERROR;
|
||||||
}
|
}
|
||||||
return d;
|
return d;
|
||||||
@@ -1052,7 +1053,7 @@ simdjson_unused simdjson_inline bool is_negative(const uint8_t * src) noexcept {
|
|||||||
|
|
||||||
simdjson_unused simdjson_inline simdjson_result<bool> is_integer(const uint8_t * src) noexcept {
|
simdjson_unused simdjson_inline simdjson_result<bool> is_integer(const uint8_t * src) noexcept {
|
||||||
bool negative = (*src == '-');
|
bool negative = (*src == '-');
|
||||||
src += negative;
|
src += uint8_t(negative);
|
||||||
const uint8_t *p = src;
|
const uint8_t *p = src;
|
||||||
while(static_cast<uint8_t>(*p - '0') <= 9) { p++; }
|
while(static_cast<uint8_t>(*p - '0') <= 9) { p++; }
|
||||||
if ( p == src ) { return NUMBER_ERROR; }
|
if ( p == src ) { return NUMBER_ERROR; }
|
||||||
@@ -1062,7 +1063,7 @@ simdjson_unused simdjson_inline simdjson_result<bool> is_integer(const uint8_t *
|
|||||||
|
|
||||||
simdjson_unused simdjson_inline simdjson_result<ondemand::number_type> get_number_type(const uint8_t * src) noexcept {
|
simdjson_unused simdjson_inline simdjson_result<ondemand::number_type> get_number_type(const uint8_t * src) noexcept {
|
||||||
bool negative = (*src == '-');
|
bool negative = (*src == '-');
|
||||||
src += negative;
|
src += uint8_t(negative);
|
||||||
const uint8_t *p = src;
|
const uint8_t *p = src;
|
||||||
while(static_cast<uint8_t>(*p - '0') <= 9) { p++; }
|
while(static_cast<uint8_t>(*p - '0') <= 9) { p++; }
|
||||||
if ( p == src ) { return NUMBER_ERROR; }
|
if ( p == src ) { return NUMBER_ERROR; }
|
||||||
@@ -1092,7 +1093,7 @@ simdjson_unused simdjson_inline simdjson_result<double> parse_double(const uint8
|
|||||||
// Check for minus sign
|
// Check for minus sign
|
||||||
//
|
//
|
||||||
bool negative = (*src == '-');
|
bool negative = (*src == '-');
|
||||||
src += negative;
|
src += uint8_t(negative);
|
||||||
|
|
||||||
//
|
//
|
||||||
// Parse the integer part.
|
// Parse the integer part.
|
||||||
@@ -1161,7 +1162,7 @@ simdjson_unused simdjson_inline simdjson_result<double> parse_double(const uint8
|
|||||||
if (simdjson_likely(!overflow)) {
|
if (simdjson_likely(!overflow)) {
|
||||||
if (compute_float_64(exponent, i, negative, d)) { return d; }
|
if (compute_float_64(exponent, i, negative, d)) { return d; }
|
||||||
}
|
}
|
||||||
if (!parse_float_fallback(src-negative, src_end, &d)) {
|
if (!parse_float_fallback(src - uint8_t(negative), src_end, &d)) {
|
||||||
return NUMBER_ERROR;
|
return NUMBER_ERROR;
|
||||||
}
|
}
|
||||||
return d;
|
return d;
|
||||||
@@ -1172,7 +1173,7 @@ simdjson_unused simdjson_inline simdjson_result<double> parse_double_in_string(c
|
|||||||
// Check for minus sign
|
// Check for minus sign
|
||||||
//
|
//
|
||||||
bool negative = (*(src + 1) == '-');
|
bool negative = (*(src + 1) == '-');
|
||||||
src += negative + 1;
|
src += uint8_t(negative) + 1;
|
||||||
|
|
||||||
//
|
//
|
||||||
// Parse the integer part.
|
// Parse the integer part.
|
||||||
@@ -1239,7 +1240,7 @@ simdjson_unused simdjson_inline simdjson_result<double> parse_double_in_string(c
|
|||||||
if (simdjson_likely(!overflow)) {
|
if (simdjson_likely(!overflow)) {
|
||||||
if (compute_float_64(exponent, i, negative, d)) { return d; }
|
if (compute_float_64(exponent, i, negative, d)) { return d; }
|
||||||
}
|
}
|
||||||
if (!parse_float_fallback(src-negative, &d)) {
|
if (!parse_float_fallback(src - uint8_t(negative), &d)) {
|
||||||
return NUMBER_ERROR;
|
return NUMBER_ERROR;
|
||||||
}
|
}
|
||||||
return d;
|
return d;
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ inline std::string document::to_debug_string() noexcept {
|
|||||||
return iter.to_string();
|
return iter.to_string();
|
||||||
}
|
}
|
||||||
|
|
||||||
inline simdjson_result<const char *> document::current_location() noexcept {
|
inline simdjson_result<const char *> document::current_location() const noexcept {
|
||||||
return iter.current_location();
|
return iter.current_location();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -28,6 +28,11 @@ inline int32_t document::current_depth() const noexcept {
|
|||||||
return iter.depth();
|
return iter.depth();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline bool document::at_end() const noexcept {
|
||||||
|
return iter.at_end();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
inline bool document::is_alive() noexcept {
|
inline bool document::is_alive() noexcept {
|
||||||
return iter.is_alive();
|
return iter.is_alive();
|
||||||
}
|
}
|
||||||
@@ -49,14 +54,24 @@ simdjson_inline simdjson_result<value> document::get_value() noexcept {
|
|||||||
// gets called.
|
// gets called.
|
||||||
iter.assert_at_document_depth();
|
iter.assert_at_document_depth();
|
||||||
switch (*iter.peek()) {
|
switch (*iter.peek()) {
|
||||||
case '[':
|
case '[': {
|
||||||
case '{':
|
// The following lines check that the document ends with ].
|
||||||
|
auto value_iterator = get_root_value_iterator();
|
||||||
|
auto error = value_iterator.check_root_array();
|
||||||
|
if(error) { return error; }
|
||||||
return value(get_root_value_iterator());
|
return value(get_root_value_iterator());
|
||||||
|
}
|
||||||
|
case '{': {
|
||||||
|
// The following lines would check that the document ends with }.
|
||||||
|
auto value_iterator = get_root_value_iterator();
|
||||||
|
auto error = value_iterator.check_root_object();
|
||||||
|
if(error) { return error; }
|
||||||
|
return value(get_root_value_iterator());
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
// Unfortunately, scalar documents are a special case in simdjson and they cannot
|
// Unfortunately, scalar documents are a special case in simdjson and they cannot
|
||||||
// be safely converted to value instances.
|
// be safely converted to value instances.
|
||||||
return SCALAR_DOCUMENT_AS_VALUE;
|
return SCALAR_DOCUMENT_AS_VALUE;
|
||||||
// return value(get_root_value_iterator());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
simdjson_inline simdjson_result<array> document::get_array() & noexcept {
|
simdjson_inline simdjson_result<array> document::get_array() & noexcept {
|
||||||
@@ -67,41 +82,53 @@ simdjson_inline simdjson_result<object> document::get_object() & noexcept {
|
|||||||
auto value = get_root_value_iterator();
|
auto value = get_root_value_iterator();
|
||||||
return object::start_root(value);
|
return object::start_root(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* We decided that calling 'get_double()' on the JSON document '1.233 blabla' should
|
||||||
|
* give an error, so we check for trailing content. We want to disallow trailing
|
||||||
|
* content.
|
||||||
|
* Thus, in several implementations below, we pass a 'true' parameter value to
|
||||||
|
* a get_root_value_iterator() method: this indicates that we disallow trailing content.
|
||||||
|
*/
|
||||||
|
|
||||||
simdjson_inline simdjson_result<uint64_t> document::get_uint64() noexcept {
|
simdjson_inline simdjson_result<uint64_t> document::get_uint64() noexcept {
|
||||||
return get_root_value_iterator().get_root_uint64();
|
return get_root_value_iterator().get_root_uint64(true);
|
||||||
}
|
}
|
||||||
simdjson_inline simdjson_result<uint64_t> document::get_uint64_in_string() noexcept {
|
simdjson_inline simdjson_result<uint64_t> document::get_uint64_in_string() noexcept {
|
||||||
return get_root_value_iterator().get_root_uint64_in_string();
|
return get_root_value_iterator().get_root_uint64_in_string(true);
|
||||||
}
|
}
|
||||||
simdjson_inline simdjson_result<int64_t> document::get_int64() noexcept {
|
simdjson_inline simdjson_result<int64_t> document::get_int64() noexcept {
|
||||||
return get_root_value_iterator().get_root_int64();
|
return get_root_value_iterator().get_root_int64(true);
|
||||||
}
|
}
|
||||||
simdjson_inline simdjson_result<int64_t> document::get_int64_in_string() noexcept {
|
simdjson_inline simdjson_result<int64_t> document::get_int64_in_string() noexcept {
|
||||||
return get_root_value_iterator().get_root_int64_in_string();
|
return get_root_value_iterator().get_root_int64_in_string(true);
|
||||||
}
|
}
|
||||||
simdjson_inline simdjson_result<double> document::get_double() noexcept {
|
simdjson_inline simdjson_result<double> document::get_double() noexcept {
|
||||||
return get_root_value_iterator().get_root_double();
|
return get_root_value_iterator().get_root_double(true);
|
||||||
}
|
}
|
||||||
simdjson_inline simdjson_result<double> document::get_double_in_string() noexcept {
|
simdjson_inline simdjson_result<double> document::get_double_in_string() noexcept {
|
||||||
return get_root_value_iterator().get_root_double_in_string();
|
return get_root_value_iterator().get_root_double_in_string(true);
|
||||||
}
|
}
|
||||||
simdjson_inline simdjson_result<std::string_view> document::get_string() noexcept {
|
simdjson_inline simdjson_result<std::string_view> document::get_string(bool allow_replacement) noexcept {
|
||||||
return get_root_value_iterator().get_root_string();
|
return get_root_value_iterator().get_root_string(true, allow_replacement);
|
||||||
|
}
|
||||||
|
simdjson_inline simdjson_result<std::string_view> document::get_wobbly_string() noexcept {
|
||||||
|
return get_root_value_iterator().get_root_wobbly_string(true);
|
||||||
}
|
}
|
||||||
simdjson_inline simdjson_result<raw_json_string> document::get_raw_json_string() noexcept {
|
simdjson_inline simdjson_result<raw_json_string> document::get_raw_json_string() noexcept {
|
||||||
return get_root_value_iterator().get_root_raw_json_string();
|
return get_root_value_iterator().get_root_raw_json_string(true);
|
||||||
}
|
}
|
||||||
simdjson_inline simdjson_result<bool> document::get_bool() noexcept {
|
simdjson_inline simdjson_result<bool> document::get_bool() noexcept {
|
||||||
return get_root_value_iterator().get_root_bool();
|
return get_root_value_iterator().get_root_bool(true);
|
||||||
}
|
}
|
||||||
simdjson_inline bool document::is_null() noexcept {
|
simdjson_inline simdjson_result<bool> document::is_null() noexcept {
|
||||||
return get_root_value_iterator().is_root_null();
|
return get_root_value_iterator().is_root_null(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<> simdjson_inline simdjson_result<array> document::get() & noexcept { return get_array(); }
|
template<> simdjson_inline simdjson_result<array> document::get() & noexcept { return get_array(); }
|
||||||
template<> simdjson_inline simdjson_result<object> document::get() & noexcept { return get_object(); }
|
template<> simdjson_inline simdjson_result<object> document::get() & noexcept { return get_object(); }
|
||||||
template<> simdjson_inline simdjson_result<raw_json_string> document::get() & noexcept { return get_raw_json_string(); }
|
template<> simdjson_inline simdjson_result<raw_json_string> document::get() & noexcept { return get_raw_json_string(); }
|
||||||
template<> simdjson_inline simdjson_result<std::string_view> document::get() & noexcept { return get_string(); }
|
template<> simdjson_inline simdjson_result<std::string_view> document::get() & noexcept { return get_string(false); }
|
||||||
template<> simdjson_inline simdjson_result<double> document::get() & noexcept { return get_double(); }
|
template<> simdjson_inline simdjson_result<double> document::get() & noexcept { return get_double(); }
|
||||||
template<> simdjson_inline simdjson_result<uint64_t> document::get() & noexcept { return get_uint64(); }
|
template<> simdjson_inline simdjson_result<uint64_t> document::get() & noexcept { return get_uint64(); }
|
||||||
template<> simdjson_inline simdjson_result<int64_t> document::get() & noexcept { return get_int64(); }
|
template<> simdjson_inline simdjson_result<int64_t> document::get() & noexcept { return get_int64(); }
|
||||||
@@ -109,7 +136,7 @@ template<> simdjson_inline simdjson_result<bool> document::get() & noexcept { re
|
|||||||
template<> simdjson_inline simdjson_result<value> document::get() & noexcept { return get_value(); }
|
template<> simdjson_inline simdjson_result<value> document::get() & noexcept { return get_value(); }
|
||||||
|
|
||||||
template<> simdjson_inline simdjson_result<raw_json_string> document::get() && noexcept { return get_raw_json_string(); }
|
template<> simdjson_inline simdjson_result<raw_json_string> document::get() && noexcept { return get_raw_json_string(); }
|
||||||
template<> simdjson_inline simdjson_result<std::string_view> document::get() && noexcept { return get_string(); }
|
template<> simdjson_inline simdjson_result<std::string_view> document::get() && noexcept { return get_string(false); }
|
||||||
template<> simdjson_inline simdjson_result<double> document::get() && noexcept { return std::forward<document>(*this).get_double(); }
|
template<> simdjson_inline simdjson_result<double> document::get() && noexcept { return std::forward<document>(*this).get_double(); }
|
||||||
template<> simdjson_inline simdjson_result<uint64_t> document::get() && noexcept { return std::forward<document>(*this).get_uint64(); }
|
template<> simdjson_inline simdjson_result<uint64_t> document::get() && noexcept { return std::forward<document>(*this).get_uint64(); }
|
||||||
template<> simdjson_inline simdjson_result<int64_t> document::get() && noexcept { return std::forward<document>(*this).get_int64(); }
|
template<> simdjson_inline simdjson_result<int64_t> document::get() && noexcept { return std::forward<document>(*this).get_int64(); }
|
||||||
@@ -129,7 +156,7 @@ simdjson_inline document::operator object() & noexcept(false) { return get_objec
|
|||||||
simdjson_inline document::operator uint64_t() noexcept(false) { return get_uint64(); }
|
simdjson_inline document::operator uint64_t() noexcept(false) { return get_uint64(); }
|
||||||
simdjson_inline document::operator int64_t() noexcept(false) { return get_int64(); }
|
simdjson_inline document::operator int64_t() noexcept(false) { return get_int64(); }
|
||||||
simdjson_inline document::operator double() noexcept(false) { return get_double(); }
|
simdjson_inline document::operator double() noexcept(false) { return get_double(); }
|
||||||
simdjson_inline document::operator std::string_view() noexcept(false) { return get_string(); }
|
simdjson_inline document::operator std::string_view() noexcept(false) { return get_string(false); }
|
||||||
simdjson_inline document::operator raw_json_string() noexcept(false) { return get_raw_json_string(); }
|
simdjson_inline document::operator raw_json_string() noexcept(false) { return get_raw_json_string(); }
|
||||||
simdjson_inline document::operator bool() noexcept(false) { return get_bool(); }
|
simdjson_inline document::operator bool() noexcept(false) { return get_bool(); }
|
||||||
simdjson_inline document::operator value() noexcept(false) { return get_value(); }
|
simdjson_inline document::operator value() noexcept(false) { return get_value(); }
|
||||||
@@ -139,20 +166,14 @@ simdjson_inline simdjson_result<size_t> document::count_elements() & noexcept {
|
|||||||
auto a = get_array();
|
auto a = get_array();
|
||||||
simdjson_result<size_t> answer = a.count_elements();
|
simdjson_result<size_t> answer = a.count_elements();
|
||||||
/* If there was an array, we are now left pointing at its first element. */
|
/* If there was an array, we are now left pointing at its first element. */
|
||||||
if(answer.error() == SUCCESS) {
|
if(answer.error() == SUCCESS) { rewind(); }
|
||||||
iter._depth = 1 ; /* undoing the increment so we go back at the doc depth.*/
|
|
||||||
iter.assert_at_document_depth();
|
|
||||||
}
|
|
||||||
return answer;
|
return answer;
|
||||||
}
|
}
|
||||||
simdjson_inline simdjson_result<size_t> document::count_fields() & noexcept {
|
simdjson_inline simdjson_result<size_t> document::count_fields() & noexcept {
|
||||||
auto a = get_object();
|
auto a = get_object();
|
||||||
simdjson_result<size_t> answer = a.count_fields();
|
simdjson_result<size_t> answer = a.count_fields();
|
||||||
/* If there was an array, we are now left pointing at its first element. */
|
/* If there was an object, we are now left pointing at its first element. */
|
||||||
if(answer.error() == SUCCESS) {
|
if(answer.error() == SUCCESS) { rewind(); }
|
||||||
iter._depth = 1 ; /* undoing the increment so we go back at the doc depth.*/
|
|
||||||
iter.assert_at_document_depth();
|
|
||||||
}
|
|
||||||
return answer;
|
return answer;
|
||||||
}
|
}
|
||||||
simdjson_inline simdjson_result<value> document::at(size_t index) & noexcept {
|
simdjson_inline simdjson_result<value> document::at(size_t index) & noexcept {
|
||||||
@@ -219,15 +240,15 @@ simdjson_inline bool document::is_negative() noexcept {
|
|||||||
}
|
}
|
||||||
|
|
||||||
simdjson_inline simdjson_result<bool> document::is_integer() noexcept {
|
simdjson_inline simdjson_result<bool> document::is_integer() noexcept {
|
||||||
return get_root_value_iterator().is_root_integer();
|
return get_root_value_iterator().is_root_integer(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
simdjson_inline simdjson_result<number_type> document::get_number_type() noexcept {
|
simdjson_inline simdjson_result<number_type> document::get_number_type() noexcept {
|
||||||
return get_root_value_iterator().get_root_number_type();
|
return get_root_value_iterator().get_root_number_type(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
simdjson_inline simdjson_result<number> document::get_number() noexcept {
|
simdjson_inline simdjson_result<number> document::get_number() noexcept {
|
||||||
return get_root_value_iterator().get_root_number();
|
return get_root_value_iterator().get_root_number(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -336,17 +357,33 @@ simdjson_inline simdjson_result<uint64_t> simdjson_result<SIMDJSON_IMPLEMENTATIO
|
|||||||
if (error()) { return error(); }
|
if (error()) { return error(); }
|
||||||
return first.get_uint64();
|
return first.get_uint64();
|
||||||
}
|
}
|
||||||
|
simdjson_inline simdjson_result<uint64_t> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document>::get_uint64_in_string() noexcept {
|
||||||
|
if (error()) { return error(); }
|
||||||
|
return first.get_uint64_in_string();
|
||||||
|
}
|
||||||
simdjson_inline simdjson_result<int64_t> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document>::get_int64() noexcept {
|
simdjson_inline simdjson_result<int64_t> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document>::get_int64() noexcept {
|
||||||
if (error()) { return error(); }
|
if (error()) { return error(); }
|
||||||
return first.get_int64();
|
return first.get_int64();
|
||||||
}
|
}
|
||||||
|
simdjson_inline simdjson_result<int64_t> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document>::get_int64_in_string() noexcept {
|
||||||
|
if (error()) { return error(); }
|
||||||
|
return first.get_int64_in_string();
|
||||||
|
}
|
||||||
simdjson_inline simdjson_result<double> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document>::get_double() noexcept {
|
simdjson_inline simdjson_result<double> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document>::get_double() noexcept {
|
||||||
if (error()) { return error(); }
|
if (error()) { return error(); }
|
||||||
return first.get_double();
|
return first.get_double();
|
||||||
}
|
}
|
||||||
simdjson_inline simdjson_result<std::string_view> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document>::get_string() noexcept {
|
simdjson_inline simdjson_result<double> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document>::get_double_in_string() noexcept {
|
||||||
if (error()) { return error(); }
|
if (error()) { return error(); }
|
||||||
return first.get_string();
|
return first.get_double_in_string();
|
||||||
|
}
|
||||||
|
simdjson_inline simdjson_result<std::string_view> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document>::get_string(bool allow_replacement) noexcept {
|
||||||
|
if (error()) { return error(); }
|
||||||
|
return first.get_string(allow_replacement);
|
||||||
|
}
|
||||||
|
simdjson_inline simdjson_result<std::string_view> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document>::get_wobbly_string() noexcept {
|
||||||
|
if (error()) { return error(); }
|
||||||
|
return first.get_wobbly_string();
|
||||||
}
|
}
|
||||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::raw_json_string> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document>::get_raw_json_string() noexcept {
|
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::raw_json_string> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document>::get_raw_json_string() noexcept {
|
||||||
if (error()) { return error(); }
|
if (error()) { return error(); }
|
||||||
@@ -360,7 +397,7 @@ simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> simdjs
|
|||||||
if (error()) { return error(); }
|
if (error()) { return error(); }
|
||||||
return first.get_value();
|
return first.get_value();
|
||||||
}
|
}
|
||||||
simdjson_inline bool simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document>::is_null() noexcept {
|
simdjson_inline simdjson_result<bool> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document>::is_null() noexcept {
|
||||||
if (error()) { return error(); }
|
if (error()) { return error(); }
|
||||||
return first.is_null();
|
return first.is_null();
|
||||||
}
|
}
|
||||||
@@ -475,6 +512,12 @@ simdjson_inline simdjson_result<const char *> simdjson_result<SIMDJSON_IMPLEMENT
|
|||||||
return first.current_location();
|
return first.current_location();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
simdjson_inline bool simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document>::at_end() const noexcept {
|
||||||
|
if (error()) { return error(); }
|
||||||
|
return first.at_end();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
simdjson_inline int32_t simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document>::current_depth() const noexcept {
|
simdjson_inline int32_t simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document>::current_depth() const noexcept {
|
||||||
if (error()) { return error(); }
|
if (error()) { return error(); }
|
||||||
return first.current_depth();
|
return first.current_depth();
|
||||||
@@ -503,24 +546,42 @@ simdjson_inline document_reference::document_reference(document &d) noexcept : d
|
|||||||
simdjson_inline void document_reference::rewind() noexcept { doc->rewind(); }
|
simdjson_inline void document_reference::rewind() noexcept { doc->rewind(); }
|
||||||
simdjson_inline simdjson_result<array> document_reference::get_array() & noexcept { return doc->get_array(); }
|
simdjson_inline simdjson_result<array> document_reference::get_array() & noexcept { return doc->get_array(); }
|
||||||
simdjson_inline simdjson_result<object> document_reference::get_object() & noexcept { return doc->get_object(); }
|
simdjson_inline simdjson_result<object> document_reference::get_object() & noexcept { return doc->get_object(); }
|
||||||
simdjson_inline simdjson_result<uint64_t> document_reference::get_uint64() noexcept { return doc->get_uint64(); }
|
/**
|
||||||
simdjson_inline simdjson_result<int64_t> document_reference::get_int64() noexcept { return doc->get_int64(); }
|
* The document_reference instances are used primarily/solely for streams of JSON
|
||||||
simdjson_inline simdjson_result<double> document_reference::get_double() noexcept { return doc->get_double(); }
|
* documents.
|
||||||
simdjson_inline simdjson_result<std::string_view> document_reference::get_string() noexcept { return doc->get_string(); }
|
* We decided that calling 'get_double()' on the JSON document '1.233 blabla' should
|
||||||
simdjson_inline simdjson_result<raw_json_string> document_reference::get_raw_json_string() noexcept { return doc->get_raw_json_string(); }
|
* give an error, so we check for trailing content.
|
||||||
simdjson_inline simdjson_result<bool> document_reference::get_bool() noexcept { return doc->get_bool(); }
|
*
|
||||||
|
* However, for streams of JSON documents, we want to be able to start from
|
||||||
|
* "321" "321" "321"
|
||||||
|
* and parse it successfully as a stream of JSON documents, calling get_uint64_in_string()
|
||||||
|
* successfully each time.
|
||||||
|
*
|
||||||
|
* To achieve this result, we pass a 'false' to a get_root_value_iterator() method:
|
||||||
|
* this indicates that we allow trailing content.
|
||||||
|
*/
|
||||||
|
simdjson_inline simdjson_result<uint64_t> document_reference::get_uint64() noexcept { return doc->get_root_value_iterator().get_root_uint64(false); }
|
||||||
|
simdjson_inline simdjson_result<uint64_t> document_reference::get_uint64_in_string() noexcept { return doc->get_root_value_iterator().get_root_uint64_in_string(false); }
|
||||||
|
simdjson_inline simdjson_result<int64_t> document_reference::get_int64() noexcept { return doc->get_root_value_iterator().get_root_int64(false); }
|
||||||
|
simdjson_inline simdjson_result<int64_t> document_reference::get_int64_in_string() noexcept { return doc->get_root_value_iterator().get_root_int64_in_string(false); }
|
||||||
|
simdjson_inline simdjson_result<double> document_reference::get_double() noexcept { return doc->get_root_value_iterator().get_root_double(false); }
|
||||||
|
simdjson_inline simdjson_result<double> document_reference::get_double_in_string() noexcept { return doc->get_root_value_iterator().get_root_double(false); }
|
||||||
|
simdjson_inline simdjson_result<std::string_view> document_reference::get_string(bool allow_replacement) noexcept { return doc->get_root_value_iterator().get_root_string(false, allow_replacement); }
|
||||||
|
simdjson_inline simdjson_result<std::string_view> document_reference::get_wobbly_string() noexcept { return doc->get_root_value_iterator().get_root_wobbly_string(false); }
|
||||||
|
simdjson_inline simdjson_result<raw_json_string> document_reference::get_raw_json_string() noexcept { return doc->get_root_value_iterator().get_root_raw_json_string(false); }
|
||||||
|
simdjson_inline simdjson_result<bool> document_reference::get_bool() noexcept { return doc->get_root_value_iterator().get_root_bool(false); }
|
||||||
simdjson_inline simdjson_result<value> document_reference::get_value() noexcept { return doc->get_value(); }
|
simdjson_inline simdjson_result<value> document_reference::get_value() noexcept { return doc->get_value(); }
|
||||||
simdjson_inline bool document_reference::is_null() noexcept { return doc->is_null(); }
|
simdjson_inline simdjson_result<bool> document_reference::is_null() noexcept { return doc->get_root_value_iterator().is_root_null(false); }
|
||||||
|
|
||||||
#if SIMDJSON_EXCEPTIONS
|
#if SIMDJSON_EXCEPTIONS
|
||||||
simdjson_inline document_reference::operator array() & noexcept(false) { return array(*doc); }
|
simdjson_inline document_reference::operator array() & noexcept(false) { return array(*doc); }
|
||||||
simdjson_inline document_reference::operator object() & noexcept(false) { return object(*doc); }
|
simdjson_inline document_reference::operator object() & noexcept(false) { return object(*doc); }
|
||||||
simdjson_inline document_reference::operator uint64_t() noexcept(false) { return uint64_t(*doc); }
|
simdjson_inline document_reference::operator uint64_t() noexcept(false) { return get_uint64(); }
|
||||||
simdjson_inline document_reference::operator int64_t() noexcept(false) { return int64_t(*doc); }
|
simdjson_inline document_reference::operator int64_t() noexcept(false) { return get_int64(); }
|
||||||
simdjson_inline document_reference::operator double() noexcept(false) { return double(*doc); }
|
simdjson_inline document_reference::operator double() noexcept(false) { return get_double(); }
|
||||||
simdjson_inline document_reference::operator std::string_view() noexcept(false) { return std::string_view(*doc); }
|
simdjson_inline document_reference::operator std::string_view() noexcept(false) { return std::string_view(*doc); }
|
||||||
simdjson_inline document_reference::operator raw_json_string() noexcept(false) { return raw_json_string(*doc); }
|
simdjson_inline document_reference::operator raw_json_string() noexcept(false) { return raw_json_string(*doc); }
|
||||||
simdjson_inline document_reference::operator bool() noexcept(false) { return bool(*doc); }
|
simdjson_inline document_reference::operator bool() noexcept(false) { return get_bool(); }
|
||||||
simdjson_inline document_reference::operator value() noexcept(false) { return value(*doc); }
|
simdjson_inline document_reference::operator value() noexcept(false) { return value(*doc); }
|
||||||
#endif
|
#endif
|
||||||
simdjson_inline simdjson_result<size_t> document_reference::count_elements() & noexcept { return doc->count_elements(); }
|
simdjson_inline simdjson_result<size_t> document_reference::count_elements() & noexcept { return doc->count_elements(); }
|
||||||
@@ -539,9 +600,9 @@ simdjson_inline simdjson_result<bool> document_reference::is_scalar() noexcept {
|
|||||||
simdjson_inline simdjson_result<const char *> document_reference::current_location() noexcept { return doc->current_location(); }
|
simdjson_inline simdjson_result<const char *> document_reference::current_location() noexcept { return doc->current_location(); }
|
||||||
simdjson_inline int32_t document_reference::current_depth() const noexcept { return doc->current_depth(); }
|
simdjson_inline int32_t document_reference::current_depth() const noexcept { return doc->current_depth(); }
|
||||||
simdjson_inline bool document_reference::is_negative() noexcept { return doc->is_negative(); }
|
simdjson_inline bool document_reference::is_negative() noexcept { return doc->is_negative(); }
|
||||||
simdjson_inline simdjson_result<bool> document_reference::is_integer() noexcept { return doc->is_integer(); }
|
simdjson_inline simdjson_result<bool> document_reference::is_integer() noexcept { return doc->get_root_value_iterator().is_root_integer(false); }
|
||||||
simdjson_inline simdjson_result<number_type> document_reference::get_number_type() noexcept { return doc->get_number_type(); }
|
simdjson_inline simdjson_result<number_type> document_reference::get_number_type() noexcept { return doc->get_root_value_iterator().get_root_number_type(false); }
|
||||||
simdjson_inline simdjson_result<number> document_reference::get_number() noexcept { return doc->get_number(); }
|
simdjson_inline simdjson_result<number> document_reference::get_number() noexcept { return doc->get_root_value_iterator().get_root_number(false); }
|
||||||
simdjson_inline simdjson_result<std::string_view> document_reference::raw_json_token() noexcept { return doc->raw_json_token(); }
|
simdjson_inline simdjson_result<std::string_view> document_reference::raw_json_token() noexcept { return doc->raw_json_token(); }
|
||||||
simdjson_inline simdjson_result<value> document_reference::at_pointer(std::string_view json_pointer) noexcept { return doc->at_pointer(json_pointer); }
|
simdjson_inline simdjson_result<value> document_reference::at_pointer(std::string_view json_pointer) noexcept { return doc->at_pointer(json_pointer); }
|
||||||
simdjson_inline simdjson_result<std::string_view> document_reference::raw_json() noexcept { return doc->raw_json();}
|
simdjson_inline simdjson_result<std::string_view> document_reference::raw_json() noexcept { return doc->raw_json();}
|
||||||
@@ -618,17 +679,33 @@ simdjson_inline simdjson_result<uint64_t> simdjson_result<SIMDJSON_IMPLEMENTATIO
|
|||||||
if (error()) { return error(); }
|
if (error()) { return error(); }
|
||||||
return first.get_uint64();
|
return first.get_uint64();
|
||||||
}
|
}
|
||||||
|
simdjson_inline simdjson_result<uint64_t> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document_reference>::get_uint64_in_string() noexcept {
|
||||||
|
if (error()) { return error(); }
|
||||||
|
return first.get_uint64_in_string();
|
||||||
|
}
|
||||||
simdjson_inline simdjson_result<int64_t> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document_reference>::get_int64() noexcept {
|
simdjson_inline simdjson_result<int64_t> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document_reference>::get_int64() noexcept {
|
||||||
if (error()) { return error(); }
|
if (error()) { return error(); }
|
||||||
return first.get_int64();
|
return first.get_int64();
|
||||||
}
|
}
|
||||||
|
simdjson_inline simdjson_result<int64_t> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document_reference>::get_int64_in_string() noexcept {
|
||||||
|
if (error()) { return error(); }
|
||||||
|
return first.get_int64_in_string();
|
||||||
|
}
|
||||||
simdjson_inline simdjson_result<double> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document_reference>::get_double() noexcept {
|
simdjson_inline simdjson_result<double> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document_reference>::get_double() noexcept {
|
||||||
if (error()) { return error(); }
|
if (error()) { return error(); }
|
||||||
return first.get_double();
|
return first.get_double();
|
||||||
}
|
}
|
||||||
simdjson_inline simdjson_result<std::string_view> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document_reference>::get_string() noexcept {
|
simdjson_inline simdjson_result<double> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document_reference>::get_double_in_string() noexcept {
|
||||||
if (error()) { return error(); }
|
if (error()) { return error(); }
|
||||||
return first.get_string();
|
return first.get_double_in_string();
|
||||||
|
}
|
||||||
|
simdjson_inline simdjson_result<std::string_view> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document_reference>::get_string(bool allow_replacement) noexcept {
|
||||||
|
if (error()) { return error(); }
|
||||||
|
return first.get_string(allow_replacement);
|
||||||
|
}
|
||||||
|
simdjson_inline simdjson_result<std::string_view> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document_reference>::get_wobbly_string() noexcept {
|
||||||
|
if (error()) { return error(); }
|
||||||
|
return first.get_wobbly_string();
|
||||||
}
|
}
|
||||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::raw_json_string> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document_reference>::get_raw_json_string() noexcept {
|
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::raw_json_string> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document_reference>::get_raw_json_string() noexcept {
|
||||||
if (error()) { return error(); }
|
if (error()) { return error(); }
|
||||||
@@ -642,7 +719,7 @@ simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> simdjs
|
|||||||
if (error()) { return error(); }
|
if (error()) { return error(); }
|
||||||
return first.get_value();
|
return first.get_value();
|
||||||
}
|
}
|
||||||
simdjson_inline bool simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document_reference>::is_null() noexcept {
|
simdjson_inline simdjson_result<bool> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document_reference>::is_null() noexcept {
|
||||||
if (error()) { return error(); }
|
if (error()) { return error(); }
|
||||||
return first.is_null();
|
return first.is_null();
|
||||||
}
|
}
|
||||||
@@ -654,7 +731,7 @@ simdjson_inline simdjson_result<bool> simdjson_result<SIMDJSON_IMPLEMENTATION::o
|
|||||||
if (error()) { return error(); }
|
if (error()) { return error(); }
|
||||||
return first.is_scalar();
|
return first.is_scalar();
|
||||||
}
|
}
|
||||||
simdjson_inline bool simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document_reference>::is_negative() noexcept {
|
simdjson_inline simdjson_result<bool> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document_reference>::is_negative() noexcept {
|
||||||
if (error()) { return error(); }
|
if (error()) { return error(); }
|
||||||
return first.is_negative();
|
return first.is_negative();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -96,11 +96,24 @@ public:
|
|||||||
*
|
*
|
||||||
* Important: Calling get_string() twice on the same document is an error.
|
* Important: Calling get_string() twice on the same document is an error.
|
||||||
*
|
*
|
||||||
|
* @param Whether to allow a replacement character for unmatched surrogate pairs.
|
||||||
* @returns An UTF-8 string. The string is stored in the parser and will be invalidated the next
|
* @returns An UTF-8 string. The string is stored in the parser and will be invalidated the next
|
||||||
* time it parses a document or when it is destroyed.
|
* time it parses a document or when it is destroyed.
|
||||||
* @returns INCORRECT_TYPE if the JSON value is not a string.
|
* @returns INCORRECT_TYPE if the JSON value is not a string.
|
||||||
*/
|
*/
|
||||||
simdjson_inline simdjson_result<std::string_view> get_string() noexcept;
|
simdjson_inline simdjson_result<std::string_view> get_string(bool allow_replacement = false) noexcept;
|
||||||
|
/**
|
||||||
|
* Cast this JSON value to a string.
|
||||||
|
*
|
||||||
|
* The string is not guaranteed to be valid UTF-8. See https://simonsapin.github.io/wtf-8/
|
||||||
|
*
|
||||||
|
* Important: Calling get_wobbly_string() twice on the same document is an error.
|
||||||
|
*
|
||||||
|
* @returns An UTF-8 string. The string is stored in the parser and will be invalidated the next
|
||||||
|
* time it parses a document or when it is destroyed.
|
||||||
|
* @returns INCORRECT_TYPE if the JSON value is not a string.
|
||||||
|
*/
|
||||||
|
simdjson_inline simdjson_result<std::string_view> get_wobbly_string() noexcept;
|
||||||
/**
|
/**
|
||||||
* Cast this JSON value to a raw_json_string.
|
* Cast this JSON value to a raw_json_string.
|
||||||
*
|
*
|
||||||
@@ -126,11 +139,14 @@ public:
|
|||||||
simdjson_inline simdjson_result<value> get_value() noexcept;
|
simdjson_inline simdjson_result<value> get_value() noexcept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks if this JSON value is null.
|
* Checks if this JSON value is null. If and only if the value is
|
||||||
|
* null, then it is consumed (we advance). If we find a token that
|
||||||
|
* begins with 'n' but is not 'null', then an error is returned.
|
||||||
*
|
*
|
||||||
* @returns Whether the value is null.
|
* @returns Whether the value is null.
|
||||||
|
* @returns INCORRECT_TYPE If the JSON value begins with 'n' and is not 'null'.
|
||||||
*/
|
*/
|
||||||
simdjson_inline bool is_null() noexcept;
|
simdjson_inline simdjson_result<bool> is_null() noexcept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get this value as the given type.
|
* Get this value as the given type.
|
||||||
@@ -363,7 +379,9 @@ public:
|
|||||||
simdjson_inline simdjson_result<value> operator[](const char *key) & noexcept;
|
simdjson_inline simdjson_result<value> operator[](const char *key) & noexcept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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.
|
||||||
*
|
*
|
||||||
* 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
|
||||||
@@ -493,7 +511,14 @@ public:
|
|||||||
/**
|
/**
|
||||||
* Returns the current location in the document if in bounds.
|
* Returns the current location in the document if in bounds.
|
||||||
*/
|
*/
|
||||||
inline simdjson_result<const char *> current_location() noexcept;
|
inline simdjson_result<const char *> current_location() const noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if this document has been fully parsed.
|
||||||
|
* If you have consumed the whole document and at_end() returns
|
||||||
|
* false, then there may be trailing content.
|
||||||
|
*/
|
||||||
|
inline bool at_end() const noexcept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the current depth in the document if in bounds.
|
* Returns the current depth in the document if in bounds.
|
||||||
@@ -572,6 +597,7 @@ protected:
|
|||||||
friend class field;
|
friend class field;
|
||||||
friend class token;
|
friend class token;
|
||||||
friend class document_stream;
|
friend class document_stream;
|
||||||
|
friend class document_reference;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -588,14 +614,18 @@ public:
|
|||||||
simdjson_inline simdjson_result<array> get_array() & noexcept;
|
simdjson_inline simdjson_result<array> get_array() & noexcept;
|
||||||
simdjson_inline simdjson_result<object> get_object() & noexcept;
|
simdjson_inline simdjson_result<object> get_object() & noexcept;
|
||||||
simdjson_inline simdjson_result<uint64_t> get_uint64() noexcept;
|
simdjson_inline simdjson_result<uint64_t> get_uint64() noexcept;
|
||||||
|
simdjson_inline simdjson_result<uint64_t> get_uint64_in_string() noexcept;
|
||||||
simdjson_inline simdjson_result<int64_t> get_int64() noexcept;
|
simdjson_inline simdjson_result<int64_t> get_int64() noexcept;
|
||||||
|
simdjson_inline simdjson_result<int64_t> get_int64_in_string() noexcept;
|
||||||
simdjson_inline simdjson_result<double> get_double() noexcept;
|
simdjson_inline simdjson_result<double> get_double() noexcept;
|
||||||
simdjson_inline simdjson_result<std::string_view> get_string() noexcept;
|
simdjson_inline simdjson_result<double> get_double_in_string() noexcept;
|
||||||
|
simdjson_inline simdjson_result<std::string_view> get_string(bool allow_replacement = false) noexcept;
|
||||||
|
simdjson_inline simdjson_result<std::string_view> get_wobbly_string() noexcept;
|
||||||
simdjson_inline simdjson_result<raw_json_string> get_raw_json_string() noexcept;
|
simdjson_inline simdjson_result<raw_json_string> get_raw_json_string() noexcept;
|
||||||
simdjson_inline simdjson_result<bool> get_bool() noexcept;
|
simdjson_inline simdjson_result<bool> get_bool() noexcept;
|
||||||
simdjson_inline simdjson_result<value> get_value() noexcept;
|
simdjson_inline simdjson_result<value> get_value() noexcept;
|
||||||
|
|
||||||
simdjson_inline bool is_null() noexcept;
|
simdjson_inline simdjson_result<bool> is_null() noexcept;
|
||||||
simdjson_inline simdjson_result<std::string_view> raw_json() noexcept;
|
simdjson_inline simdjson_result<std::string_view> raw_json() noexcept;
|
||||||
simdjson_inline operator document&() const noexcept;
|
simdjson_inline operator document&() const noexcept;
|
||||||
|
|
||||||
@@ -653,14 +683,17 @@ public:
|
|||||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array> get_array() & noexcept;
|
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array> get_array() & noexcept;
|
||||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object> get_object() & noexcept;
|
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object> get_object() & noexcept;
|
||||||
simdjson_inline simdjson_result<uint64_t> get_uint64() noexcept;
|
simdjson_inline simdjson_result<uint64_t> get_uint64() noexcept;
|
||||||
|
simdjson_inline simdjson_result<uint64_t> get_uint64_in_string() noexcept;
|
||||||
simdjson_inline simdjson_result<int64_t> get_int64() noexcept;
|
simdjson_inline simdjson_result<int64_t> get_int64() noexcept;
|
||||||
|
simdjson_inline simdjson_result<int64_t> get_int64_in_string() noexcept;
|
||||||
simdjson_inline simdjson_result<double> get_double() noexcept;
|
simdjson_inline simdjson_result<double> get_double() noexcept;
|
||||||
simdjson_inline simdjson_result<double> get_double_from_string() noexcept;
|
simdjson_inline simdjson_result<double> get_double_in_string() noexcept;
|
||||||
simdjson_inline simdjson_result<std::string_view> get_string() noexcept;
|
simdjson_inline simdjson_result<std::string_view> get_string(bool allow_replacement = false) noexcept;
|
||||||
|
simdjson_inline simdjson_result<std::string_view> get_wobbly_string() noexcept;
|
||||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::raw_json_string> get_raw_json_string() noexcept;
|
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::raw_json_string> get_raw_json_string() noexcept;
|
||||||
simdjson_inline simdjson_result<bool> get_bool() noexcept;
|
simdjson_inline simdjson_result<bool> get_bool() noexcept;
|
||||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> get_value() noexcept;
|
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> get_value() noexcept;
|
||||||
simdjson_inline bool is_null() noexcept;
|
simdjson_inline simdjson_result<bool> is_null() noexcept;
|
||||||
|
|
||||||
template<typename T> simdjson_inline simdjson_result<T> get() & noexcept;
|
template<typename T> simdjson_inline simdjson_result<T> get() & noexcept;
|
||||||
template<typename T> simdjson_inline simdjson_result<T> get() && noexcept;
|
template<typename T> simdjson_inline simdjson_result<T> get() && noexcept;
|
||||||
@@ -694,6 +727,7 @@ public:
|
|||||||
simdjson_inline simdjson_result<bool> is_scalar() noexcept;
|
simdjson_inline simdjson_result<bool> is_scalar() noexcept;
|
||||||
simdjson_inline simdjson_result<const char *> current_location() noexcept;
|
simdjson_inline simdjson_result<const char *> current_location() noexcept;
|
||||||
simdjson_inline int32_t current_depth() const noexcept;
|
simdjson_inline int32_t current_depth() const noexcept;
|
||||||
|
simdjson_inline bool at_end() const noexcept;
|
||||||
simdjson_inline bool is_negative() noexcept;
|
simdjson_inline bool is_negative() noexcept;
|
||||||
simdjson_inline simdjson_result<bool> is_integer() noexcept;
|
simdjson_inline simdjson_result<bool> is_integer() noexcept;
|
||||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::number_type> get_number_type() noexcept;
|
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::number_type> get_number_type() noexcept;
|
||||||
@@ -721,13 +755,17 @@ public:
|
|||||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array> get_array() & noexcept;
|
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array> get_array() & noexcept;
|
||||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object> get_object() & noexcept;
|
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object> get_object() & noexcept;
|
||||||
simdjson_inline simdjson_result<uint64_t> get_uint64() noexcept;
|
simdjson_inline simdjson_result<uint64_t> get_uint64() noexcept;
|
||||||
|
simdjson_inline simdjson_result<uint64_t> get_uint64_in_string() noexcept;
|
||||||
simdjson_inline simdjson_result<int64_t> get_int64() noexcept;
|
simdjson_inline simdjson_result<int64_t> get_int64() noexcept;
|
||||||
|
simdjson_inline simdjson_result<int64_t> get_int64_in_string() noexcept;
|
||||||
simdjson_inline simdjson_result<double> get_double() noexcept;
|
simdjson_inline simdjson_result<double> get_double() noexcept;
|
||||||
simdjson_inline simdjson_result<std::string_view> get_string() noexcept;
|
simdjson_inline simdjson_result<double> get_double_in_string() noexcept;
|
||||||
|
simdjson_inline simdjson_result<std::string_view> get_string(bool allow_replacement = false) noexcept;
|
||||||
|
simdjson_inline simdjson_result<std::string_view> get_wobbly_string() noexcept;
|
||||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::raw_json_string> get_raw_json_string() noexcept;
|
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::raw_json_string> get_raw_json_string() noexcept;
|
||||||
simdjson_inline simdjson_result<bool> get_bool() noexcept;
|
simdjson_inline simdjson_result<bool> get_bool() noexcept;
|
||||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> get_value() noexcept;
|
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> get_value() noexcept;
|
||||||
simdjson_inline bool is_null() noexcept;
|
simdjson_inline simdjson_result<bool> is_null() noexcept;
|
||||||
|
|
||||||
#if SIMDJSON_EXCEPTIONS
|
#if SIMDJSON_EXCEPTIONS
|
||||||
simdjson_inline operator SIMDJSON_IMPLEMENTATION::ondemand::array() & noexcept(false);
|
simdjson_inline operator SIMDJSON_IMPLEMENTATION::ondemand::array() & noexcept(false);
|
||||||
@@ -754,8 +792,8 @@ public:
|
|||||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::json_type> type() noexcept;
|
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::json_type> type() noexcept;
|
||||||
simdjson_inline simdjson_result<bool> is_scalar() noexcept;
|
simdjson_inline simdjson_result<bool> is_scalar() noexcept;
|
||||||
simdjson_inline simdjson_result<const char *> current_location() noexcept;
|
simdjson_inline simdjson_result<const char *> current_location() noexcept;
|
||||||
simdjson_inline int32_t current_depth() const noexcept;
|
simdjson_inline simdjson_result<int32_t> current_depth() const noexcept;
|
||||||
simdjson_inline bool is_negative() noexcept;
|
simdjson_inline simdjson_result<bool> is_negative() noexcept;
|
||||||
simdjson_inline simdjson_result<bool> is_integer() noexcept;
|
simdjson_inline simdjson_result<bool> is_integer() noexcept;
|
||||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::number_type> get_number_type() noexcept;
|
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::number_type> get_number_type() noexcept;
|
||||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::number> get_number() noexcept;
|
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::number> get_number() noexcept;
|
||||||
|
|||||||
@@ -21,9 +21,9 @@ simdjson_inline simdjson_result<field> field::start(const value_iterator &parent
|
|||||||
return field(key, parent_iter.child());
|
return field(key, parent_iter.child());
|
||||||
}
|
}
|
||||||
|
|
||||||
simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> field::unescaped_key() noexcept {
|
simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> field::unescaped_key(bool allow_replacement) noexcept {
|
||||||
SIMDJSON_ASSUME(first.buf != nullptr); // We would like to call .alive() but Visual Studio won't let us.
|
SIMDJSON_ASSUME(first.buf != nullptr); // We would like to call .alive() but Visual Studio won't let us.
|
||||||
simdjson_result<std::string_view> answer = first.unescape(second.iter.json_iter());
|
simdjson_result<std::string_view> answer = first.unescape(second.iter.json_iter(), allow_replacement);
|
||||||
first.consume();
|
first.consume();
|
||||||
return answer;
|
return answer;
|
||||||
}
|
}
|
||||||
@@ -66,9 +66,9 @@ simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::raw_json_stri
|
|||||||
if (error()) { return error(); }
|
if (error()) { return error(); }
|
||||||
return first.key();
|
return first.key();
|
||||||
}
|
}
|
||||||
simdjson_inline simdjson_result<std::string_view> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::field>::unescaped_key() noexcept {
|
simdjson_inline simdjson_result<std::string_view> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::field>::unescaped_key(bool allow_replacement) noexcept {
|
||||||
if (error()) { return error(); }
|
if (error()) { return error(); }
|
||||||
return first.unescaped_key();
|
return first.unescaped_key(allow_replacement);
|
||||||
}
|
}
|
||||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::field>::value() noexcept {
|
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::field>::value() noexcept {
|
||||||
if (error()) { return error(); }
|
if (error()) { return error(); }
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ public:
|
|||||||
* This consumes the key: once you have called unescaped_key(), you cannot
|
* This consumes the key: once you have called unescaped_key(), you cannot
|
||||||
* call it again nor can you call key().
|
* call it again nor can you call key().
|
||||||
*/
|
*/
|
||||||
simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> unescaped_key() noexcept;
|
simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> unescaped_key(bool allow_replacement) noexcept;
|
||||||
/**
|
/**
|
||||||
* Get the key as a raw_json_string. Can be used for direct comparison with
|
* Get the key as a raw_json_string. Can be used for direct comparison with
|
||||||
* an unescaped C string: e.g., key() == "test".
|
* an unescaped C string: e.g., key() == "test".
|
||||||
@@ -64,7 +64,7 @@ public:
|
|||||||
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;
|
||||||
|
|
||||||
simdjson_inline simdjson_result<std::string_view> unescaped_key() noexcept;
|
simdjson_inline simdjson_result<std::string_view> unescaped_key(bool allow_replacement = false) noexcept;
|
||||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::raw_json_string> key() noexcept;
|
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::raw_json_string> key() noexcept;
|
||||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> value() noexcept;
|
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> value() noexcept;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -154,6 +154,10 @@ simdjson_inline bool json_iterator::at_root() const noexcept {
|
|||||||
return position() == root_position();
|
return position() == root_position();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
simdjson_inline bool json_iterator::is_single_token() const noexcept {
|
||||||
|
return parser->implementation->n_structural_indexes == 1;
|
||||||
|
}
|
||||||
|
|
||||||
simdjson_inline bool json_iterator::streaming() const noexcept {
|
simdjson_inline bool json_iterator::streaming() const noexcept {
|
||||||
return _streaming;
|
return _streaming;
|
||||||
}
|
}
|
||||||
@@ -204,7 +208,7 @@ inline std::string json_iterator::to_string() const noexcept {
|
|||||||
+ std::string(" ]");
|
+ std::string(" ]");
|
||||||
}
|
}
|
||||||
|
|
||||||
inline simdjson_result<const char *> json_iterator::current_location() noexcept {
|
inline simdjson_result<const char *> json_iterator::current_location() const noexcept {
|
||||||
if (!is_alive()) { // Unrecoverable error
|
if (!is_alive()) { // Unrecoverable error
|
||||||
if (!at_root()) {
|
if (!at_root()) {
|
||||||
return reinterpret_cast<const char *>(token.peek(-1));
|
return reinterpret_cast<const char *>(token.peek(-1));
|
||||||
@@ -312,8 +316,12 @@ simdjson_inline token_position json_iterator::position() const noexcept {
|
|||||||
return token.position();
|
return token.position();
|
||||||
}
|
}
|
||||||
|
|
||||||
simdjson_inline simdjson_result<std::string_view> json_iterator::unescape(raw_json_string in) noexcept {
|
simdjson_inline simdjson_result<std::string_view> json_iterator::unescape(raw_json_string in, bool allow_replacement) noexcept {
|
||||||
return parser->unescape(in, _string_buf_loc);
|
return parser->unescape(in, _string_buf_loc, allow_replacement);
|
||||||
|
}
|
||||||
|
|
||||||
|
simdjson_inline simdjson_result<std::string_view> json_iterator::unescape_wobbly(raw_json_string in) noexcept {
|
||||||
|
return parser->unescape_wobbly(in, _string_buf_loc);
|
||||||
}
|
}
|
||||||
|
|
||||||
simdjson_inline void json_iterator::reenter_child(token_position position, depth_t child_depth) noexcept {
|
simdjson_inline void json_iterator::reenter_child(token_position position, depth_t child_depth) noexcept {
|
||||||
@@ -321,6 +329,7 @@ simdjson_inline void json_iterator::reenter_child(token_position position, depth
|
|||||||
SIMDJSON_ASSUME(_depth == child_depth - 1);
|
SIMDJSON_ASSUME(_depth == child_depth - 1);
|
||||||
#if SIMDJSON_DEVELOPMENT_CHECKS
|
#if SIMDJSON_DEVELOPMENT_CHECKS
|
||||||
#ifndef SIMDJSON_CLANG_VISUAL_STUDIO
|
#ifndef SIMDJSON_CLANG_VISUAL_STUDIO
|
||||||
|
SIMDJSON_ASSUME(size_t(child_depth) < parser->max_depth());
|
||||||
SIMDJSON_ASSUME(position >= parser->start_positions[child_depth]);
|
SIMDJSON_ASSUME(position >= parser->start_positions[child_depth]);
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
@@ -331,11 +340,13 @@ simdjson_inline void json_iterator::reenter_child(token_position position, depth
|
|||||||
#if SIMDJSON_DEVELOPMENT_CHECKS
|
#if SIMDJSON_DEVELOPMENT_CHECKS
|
||||||
|
|
||||||
simdjson_inline token_position json_iterator::start_position(depth_t depth) const noexcept {
|
simdjson_inline token_position json_iterator::start_position(depth_t depth) const noexcept {
|
||||||
return parser->start_positions[depth];
|
SIMDJSON_ASSUME(size_t(depth) < parser->max_depth());
|
||||||
|
return size_t(depth) < parser->max_depth() ? parser->start_positions[depth] : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
simdjson_inline void json_iterator::set_start_position(depth_t depth, token_position position) noexcept {
|
simdjson_inline void json_iterator::set_start_position(depth_t depth, token_position position) noexcept {
|
||||||
parser->start_positions[depth] = position;
|
SIMDJSON_ASSUME(size_t(depth) < parser->max_depth());
|
||||||
|
if(size_t(depth) < parser->max_depth()) { parser->start_positions[depth] = position; }
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -347,19 +358,16 @@ simdjson_inline error_code json_iterator::optional_error(error_code _error, cons
|
|||||||
return _error;
|
return _error;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<int N>
|
|
||||||
simdjson_warn_unused simdjson_inline bool json_iterator::copy_to_buffer(const uint8_t *json, uint32_t max_len, uint8_t (&tmpbuf)[N]) noexcept {
|
simdjson_warn_unused simdjson_inline bool json_iterator::copy_to_buffer(const uint8_t *json, uint32_t max_len, uint8_t *tmpbuf, size_t N) noexcept {
|
||||||
|
// This function is not expected to be called in performance-sensitive settings.
|
||||||
// Let us guard against silly cases:
|
// Let us guard against silly cases:
|
||||||
if((N < max_len) || (N == 0)) { return false; }
|
if((N < max_len) || (N == 0)) { return false; }
|
||||||
// Truncate whitespace to fit the buffer.
|
|
||||||
if (max_len > N-1) {
|
|
||||||
// if (jsoncharutils::is_not_structural_or_whitespace(json[N-1])) { return false; }
|
|
||||||
max_len = N-1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Copy to the buffer.
|
// Copy to the buffer.
|
||||||
std::memcpy(tmpbuf, json, max_len);
|
std::memcpy(tmpbuf, json, max_len);
|
||||||
tmpbuf[max_len] = ' ';
|
if(N > max_len) { // We pad whatever remains with ' '.
|
||||||
|
std::memset(tmpbuf + max_len, ' ', N - max_len);
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -117,6 +117,14 @@ public:
|
|||||||
*/
|
*/
|
||||||
simdjson_inline const uint8_t *return_current_and_advance() noexcept;
|
simdjson_inline const uint8_t *return_current_and_advance() noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if there is a single token in the index (i.e., it is
|
||||||
|
* a JSON with a scalar value such as a single number).
|
||||||
|
*
|
||||||
|
* @return whether there is a single token
|
||||||
|
*/
|
||||||
|
simdjson_inline bool is_single_token() const noexcept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Assert that there are at least the given number of tokens left.
|
* Assert that there are at least the given number of tokens left.
|
||||||
*
|
*
|
||||||
@@ -230,7 +238,12 @@ public:
|
|||||||
*/
|
*/
|
||||||
simdjson_inline error_code optional_error(error_code error, const char *message) noexcept;
|
simdjson_inline error_code optional_error(error_code error, const char *message) noexcept;
|
||||||
|
|
||||||
template<int N> simdjson_warn_unused simdjson_inline bool copy_to_buffer(const uint8_t *json, uint32_t max_len, uint8_t (&tmpbuf)[N]) noexcept;
|
/**
|
||||||
|
* Take an input in json containing max_len characters and attempt to copy it over to tmpbuf, a buffer with
|
||||||
|
* N bytes of capacity. It will return false if N is too small (smaller than max_len) of if it is zero.
|
||||||
|
* The buffer (tmpbuf) is padded with space characters.
|
||||||
|
*/
|
||||||
|
simdjson_warn_unused simdjson_inline bool copy_to_buffer(const uint8_t *json, uint32_t max_len, uint8_t *tmpbuf, size_t N) noexcept;
|
||||||
|
|
||||||
simdjson_inline token_position position() const noexcept;
|
simdjson_inline token_position position() const noexcept;
|
||||||
/**
|
/**
|
||||||
@@ -238,7 +251,8 @@ public:
|
|||||||
* Each raw_json_string should be unescaped once, or else the string buffer might
|
* Each raw_json_string should be unescaped once, or else the string buffer might
|
||||||
* overflow.
|
* overflow.
|
||||||
*/
|
*/
|
||||||
simdjson_inline simdjson_result<std::string_view> unescape(raw_json_string in) noexcept;
|
simdjson_inline simdjson_result<std::string_view> unescape(raw_json_string in, bool allow_replacement) noexcept;
|
||||||
|
simdjson_inline simdjson_result<std::string_view> unescape_wobbly(raw_json_string in) noexcept;
|
||||||
simdjson_inline void reenter_child(token_position position, depth_t child_depth) noexcept;
|
simdjson_inline void reenter_child(token_position position, depth_t child_depth) noexcept;
|
||||||
|
|
||||||
#if SIMDJSON_DEVELOPMENT_CHECKS
|
#if SIMDJSON_DEVELOPMENT_CHECKS
|
||||||
@@ -252,7 +266,7 @@ public:
|
|||||||
/**
|
/**
|
||||||
* Returns the current location in the document if in bounds.
|
* Returns the current location in the document if in bounds.
|
||||||
*/
|
*/
|
||||||
inline simdjson_result<const char *> current_location() noexcept;
|
inline simdjson_result<const char *> current_location() const noexcept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates this json iterator so that it is back at the beginning of the document,
|
* Updates this json iterator so that it is back at the beginning of the document,
|
||||||
|
|||||||
@@ -136,9 +136,15 @@ inline void log_line(const json_iterator &iter, token_position index, depth_t de
|
|||||||
{
|
{
|
||||||
// Print the current structural.
|
// Print the current structural.
|
||||||
printf("| ");
|
printf("| ");
|
||||||
auto current_structural = &buf[*index];
|
// Before we begin, the index might point right before the document.
|
||||||
for (int i=0;i<LOG_BUFFER_LEN;i++) {
|
// This could be unsafe, see https://github.com/simdjson/simdjson/discussions/1938
|
||||||
printf("%c", printable_char(current_structural[i]));
|
if(index < iter._root) {
|
||||||
|
printf("%*s", LOG_BUFFER_LEN, "");
|
||||||
|
} else {
|
||||||
|
auto current_structural = &buf[*index];
|
||||||
|
for (int i=0;i<LOG_BUFFER_LEN;i++) {
|
||||||
|
printf("%c", printable_char(current_structural[i]));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
printf(" ");
|
printf(" ");
|
||||||
}
|
}
|
||||||
@@ -152,8 +158,8 @@ inline void log_line(const json_iterator &iter, token_position index, depth_t de
|
|||||||
printf(" ");
|
printf(" ");
|
||||||
}
|
}
|
||||||
// printf("| %5u ", *(index+1));
|
// printf("| %5u ", *(index+1));
|
||||||
printf("| %5u ", depth);
|
printf("| %5i ", depth);
|
||||||
printf("| %.*s ", int(detail.size()), detail.data());
|
printf("| %6.*s ", int(detail.size()) , detail.data());
|
||||||
printf("|\n");
|
printf("|\n");
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -166,6 +166,9 @@ public:
|
|||||||
*
|
*
|
||||||
* To check that an object is empty, it is more performant to use
|
* To check that an object is empty, it is more performant to use
|
||||||
* the is_empty() method.
|
* the is_empty() method.
|
||||||
|
*
|
||||||
|
* Performance hint: You should only call count_fields() as a last
|
||||||
|
* resort as it may require scanning the document twice or more.
|
||||||
*/
|
*/
|
||||||
simdjson_inline simdjson_result<size_t> count_fields() & noexcept;
|
simdjson_inline simdjson_result<size_t> count_fields() & noexcept;
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -109,16 +109,23 @@ simdjson_inline size_t parser::max_depth() const noexcept {
|
|||||||
}
|
}
|
||||||
|
|
||||||
simdjson_inline void parser::set_max_capacity(size_t max_capacity) noexcept {
|
simdjson_inline void parser::set_max_capacity(size_t max_capacity) noexcept {
|
||||||
size_t MINIMAL_DOCUMENT_CAPACITY = 32;
|
if(max_capacity < dom::MINIMAL_DOCUMENT_CAPACITY) {
|
||||||
if(max_capacity < MINIMAL_DOCUMENT_CAPACITY) {
|
|
||||||
_max_capacity = max_capacity;
|
_max_capacity = max_capacity;
|
||||||
} else {
|
} else {
|
||||||
_max_capacity = MINIMAL_DOCUMENT_CAPACITY;
|
_max_capacity = dom::MINIMAL_DOCUMENT_CAPACITY;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> parser::unescape(raw_json_string in, uint8_t *&dst) const noexcept {
|
simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> parser::unescape(raw_json_string in, uint8_t *&dst, bool allow_replacement) const noexcept {
|
||||||
uint8_t *end = implementation->parse_string(in.buf, dst);
|
uint8_t *end = implementation->parse_string(in.buf, dst, allow_replacement);
|
||||||
|
if (!end) { return STRING_ERROR; }
|
||||||
|
std::string_view result(reinterpret_cast<const char *>(dst), end-dst);
|
||||||
|
dst = end;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> parser::unescape_wobbly(raw_json_string in, uint8_t *&dst) const noexcept {
|
||||||
|
uint8_t *end = implementation->parse_wobbly_string(in.buf, dst);
|
||||||
if (!end) { return STRING_ERROR; }
|
if (!end) { return STRING_ERROR; }
|
||||||
std::string_view result(reinterpret_cast<const char *>(dst), end-dst);
|
std::string_view result(reinterpret_cast<const char *>(dst), end-dst);
|
||||||
dst = end;
|
dst = end;
|
||||||
|
|||||||
@@ -78,7 +78,9 @@ public:
|
|||||||
* ### 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
|
||||||
* those bytes are initialized to, as long as they are allocated.
|
* those bytes are initialized to, as long as they are allocated. These bytes will be read: if you
|
||||||
|
* using a sanitizer that verifies that no uninitialized byte is read, then you should initialize the
|
||||||
|
* SIMDJSON_PADDING bytes to avoid runtime warnings.
|
||||||
*
|
*
|
||||||
* @param json The JSON to parse.
|
* @param json The JSON to parse.
|
||||||
* @param len The length of the JSON.
|
* @param len The length of the JSON.
|
||||||
@@ -134,7 +136,9 @@ public:
|
|||||||
* ### 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
|
||||||
* those bytes are initialized to, as long as they are allocated.
|
* those bytes are initialized to, as long as they are allocated. These bytes will be read: if you
|
||||||
|
* using a sanitizer that verifies that no uninitialized byte is read, then you should initialize the
|
||||||
|
* SIMDJSON_PADDING bytes to avoid runtime warnings.
|
||||||
*
|
*
|
||||||
* @param json The JSON to parse.
|
* @param json The JSON to parse.
|
||||||
*
|
*
|
||||||
@@ -188,7 +192,9 @@ public:
|
|||||||
* ### 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
|
||||||
* those bytes are initialized to, as long as they are allocated.
|
* those bytes are initialized to, as long as they are allocated. These bytes will be read: if you
|
||||||
|
* using a sanitizer that verifies that no uninitialized byte is read, then you should initialize the
|
||||||
|
* SIMDJSON_PADDING bytes to avoid runtime warnings.
|
||||||
*
|
*
|
||||||
* ### Threads
|
* ### Threads
|
||||||
*
|
*
|
||||||
@@ -230,13 +236,22 @@ public:
|
|||||||
/** The maximum capacity of this parser (the largest document it is allowed to process). */
|
/** The maximum capacity of this parser (the largest document it is allowed to process). */
|
||||||
simdjson_inline size_t max_capacity() const noexcept;
|
simdjson_inline size_t max_capacity() const noexcept;
|
||||||
simdjson_inline void set_max_capacity(size_t max_capacity) noexcept;
|
simdjson_inline void set_max_capacity(size_t max_capacity) noexcept;
|
||||||
/** The maximum depth of this parser (the most deeply nested objects and arrays it can process). */
|
/**
|
||||||
|
* The maximum depth of this parser (the most deeply nested objects and arrays it can process).
|
||||||
|
* This parameter is only relevant when the macro SIMDJSON_DEVELOPMENT_CHECKS is set to true.
|
||||||
|
* The document's instance current_depth() method should be used to monitor the parsing
|
||||||
|
* depth and limit it if desired.
|
||||||
|
*/
|
||||||
simdjson_inline size_t max_depth() const noexcept;
|
simdjson_inline size_t max_depth() const noexcept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Ensure this parser has enough memory to process JSON documents up to `capacity` bytes in length
|
* Ensure this parser has enough memory to process JSON documents up to `capacity` bytes in length
|
||||||
* and `max_depth` depth.
|
* and `max_depth` depth.
|
||||||
*
|
*
|
||||||
|
* The max_depth parameter is only relevant when the macro SIMDJSON_DEVELOPMENT_CHECKS is set to true.
|
||||||
|
* The document's instance current_depth() method should be used to monitor the parsing
|
||||||
|
* depth and limit it if desired.
|
||||||
|
*
|
||||||
* @param capacity The new capacity.
|
* @param capacity The new capacity.
|
||||||
* @param max_depth The new max_depth. Defaults to DEFAULT_MAX_DEPTH.
|
* @param max_depth The new max_depth. Defaults to DEFAULT_MAX_DEPTH.
|
||||||
* @return The error, if there is one.
|
* @return The error, if there is one.
|
||||||
@@ -254,6 +269,31 @@ public:
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Unescape this JSON string, replacing \\ with \, \n with newline, etc. to a user-provided buffer.
|
* Unescape this JSON string, replacing \\ with \, \n with newline, etc. to a user-provided buffer.
|
||||||
|
* The result must be valid UTF-8.
|
||||||
|
* The provided pointer is advanced to the end of the string by reference, and a string_view instance
|
||||||
|
* is returned. You can ensure that your buffer is large enough by allocating a block of memory at least
|
||||||
|
* as large as the input JSON plus SIMDJSON_PADDING and then unescape all strings to this one buffer.
|
||||||
|
*
|
||||||
|
* This unescape function is a low-level function. If you want a more user-friendly approach, you should
|
||||||
|
* avoid raw_json_string instances (e.g., by calling unescaped_key() instead of key() or get_string()
|
||||||
|
* instead of get_raw_json_string()).
|
||||||
|
*
|
||||||
|
* ## IMPORTANT: string_view lifetime
|
||||||
|
*
|
||||||
|
* The string_view is only valid as long as the bytes in dst.
|
||||||
|
*
|
||||||
|
* @param raw_json_string input
|
||||||
|
* @param dst A pointer to a buffer at least large enough to write this string as well as
|
||||||
|
* an additional SIMDJSON_PADDING bytes.
|
||||||
|
* @param allow_replacement Whether we allow a replacement if the input string contains unmatched surrogate pairs.
|
||||||
|
* @return A string_view pointing at the unescaped string in dst
|
||||||
|
* @error STRING_ERROR if escapes are incorrect.
|
||||||
|
*/
|
||||||
|
simdjson_inline simdjson_result<std::string_view> unescape(raw_json_string in, uint8_t *&dst, bool allow_replacement = false) const noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unescape this JSON string, replacing \\ with \, \n with newline, etc. to a user-provided buffer.
|
||||||
|
* The result may not be valid UTF-8. See https://simonsapin.github.io/wtf-8/
|
||||||
* The provided pointer is advanced to the end of the string by reference, and a string_view instance
|
* The provided pointer is advanced to the end of the string by reference, and a string_view instance
|
||||||
* is returned. You can ensure that your buffer is large enough by allocating a block of memory at least
|
* is returned. You can ensure that your buffer is large enough by allocating a block of memory at least
|
||||||
* as large as the input JSON plus SIMDJSON_PADDING and then unescape all strings to this one buffer.
|
* as large as the input JSON plus SIMDJSON_PADDING and then unescape all strings to this one buffer.
|
||||||
@@ -272,7 +312,8 @@ public:
|
|||||||
* @return A string_view pointing at the unescaped string in dst
|
* @return A string_view pointing at the unescaped string in dst
|
||||||
* @error STRING_ERROR if escapes are incorrect.
|
* @error STRING_ERROR if escapes are incorrect.
|
||||||
*/
|
*/
|
||||||
simdjson_inline simdjson_result<std::string_view> unescape(raw_json_string in, uint8_t *&dst) const noexcept;
|
simdjson_inline simdjson_result<std::string_view> unescape_wobbly(raw_json_string in, uint8_t *&dst) const noexcept;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/** @private [for benchmarking access] The implementation to use */
|
/** @private [for benchmarking access] The implementation to use */
|
||||||
std::unique_ptr<internal::dom_parser_implementation> implementation{};
|
std::unique_ptr<internal::dom_parser_implementation> implementation{};
|
||||||
|
|||||||
@@ -143,10 +143,13 @@ simdjson_unused simdjson_inline bool operator!=(std::string_view c, const raw_js
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> raw_json_string::unescape(json_iterator &iter) const noexcept {
|
simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> raw_json_string::unescape(json_iterator &iter, bool allow_replacement) const noexcept {
|
||||||
return iter.unescape(*this);
|
return iter.unescape(*this, allow_replacement);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> raw_json_string::unescape_wobbly(json_iterator &iter) const noexcept {
|
||||||
|
return iter.unescape_wobbly(*this);
|
||||||
|
}
|
||||||
|
|
||||||
simdjson_unused simdjson_inline std::ostream &operator<<(std::ostream &out, const raw_json_string &str) noexcept {
|
simdjson_unused simdjson_inline std::ostream &operator<<(std::ostream &out, const raw_json_string &str) noexcept {
|
||||||
bool in_escape = false;
|
bool in_escape = false;
|
||||||
@@ -177,9 +180,12 @@ 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 simdjson_warn_unused simdjson_result<std::string_view> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::raw_json_string>::unescape(SIMDJSON_IMPLEMENTATION::ondemand::json_iterator &iter) 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);
|
return first.unescape(iter, allow_replacement);
|
||||||
|
}
|
||||||
|
simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::raw_json_string>::unescape_wobbly(SIMDJSON_IMPLEMENTATION::ondemand::json_iterator &iter) const noexcept {
|
||||||
|
if (error()) { return error(); }
|
||||||
|
return first.unescape_wobbly(iter);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace simdjson
|
} // namespace simdjson
|
||||||
|
|||||||
@@ -139,6 +139,20 @@ private:
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Unescape this JSON string, replacing \\ with \, \n with newline, etc.
|
* Unescape this JSON string, replacing \\ with \, \n with newline, etc.
|
||||||
|
* The result will be a valid UTF-8.
|
||||||
|
*
|
||||||
|
* ## IMPORTANT: string_view lifetime
|
||||||
|
*
|
||||||
|
* The string_view is only valid until the next parse() call on the parser.
|
||||||
|
*
|
||||||
|
* @param iter A json_iterator, which contains a buffer where the string will be written.
|
||||||
|
* @param allow_replacement Whether we allow replacement of invalid surrogate pairs.
|
||||||
|
*/
|
||||||
|
simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> unescape(json_iterator &iter, bool allow_replacement) const noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unescape this JSON string, replacing \\ with \, \n with newline, etc.
|
||||||
|
* The result may not be a valid UTF-8. https://simonsapin.github.io/wtf-8/
|
||||||
*
|
*
|
||||||
* ## IMPORTANT: string_view lifetime
|
* ## IMPORTANT: string_view lifetime
|
||||||
*
|
*
|
||||||
@@ -146,8 +160,7 @@ private:
|
|||||||
*
|
*
|
||||||
* @param iter A json_iterator, which contains a buffer where the string will be written.
|
* @param iter A json_iterator, which contains a buffer where the string will be written.
|
||||||
*/
|
*/
|
||||||
simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> unescape(json_iterator &iter) const noexcept;
|
simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> unescape_wobbly(json_iterator &iter) const noexcept;
|
||||||
|
|
||||||
const uint8_t * buf{};
|
const uint8_t * buf{};
|
||||||
friend class object;
|
friend class object;
|
||||||
friend class field;
|
friend class field;
|
||||||
@@ -182,7 +195,8 @@ 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 simdjson_warn_unused simdjson_result<std::string_view> unescape(SIMDJSON_IMPLEMENTATION::ondemand::json_iterator &iter) 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;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace simdjson
|
} // namespace simdjson
|
||||||
|
|||||||
@@ -4,23 +4,27 @@
|
|||||||
namespace simdjson {
|
namespace simdjson {
|
||||||
/**
|
/**
|
||||||
* Create a string-view instance out of a document instance. The string-view instance
|
* Create a string-view instance out of a document instance. The string-view instance
|
||||||
* contains JSON text that is suitable to be parsed as JSON again.
|
* contains JSON text that is suitable to be parsed as JSON again. It does not
|
||||||
|
* validate the content.
|
||||||
*/
|
*/
|
||||||
inline simdjson_result<std::string_view> to_json_string(SIMDJSON_IMPLEMENTATION::ondemand::document& x) noexcept;
|
inline simdjson_result<std::string_view> to_json_string(SIMDJSON_IMPLEMENTATION::ondemand::document& x) noexcept;
|
||||||
/**
|
/**
|
||||||
* Create a string-view instance out of a value instance. The string-view instance
|
* Create a string-view instance out of a value instance. The string-view instance
|
||||||
* contains JSON text that is suitable to be parsed as JSON again. The value must
|
* contains JSON text that is suitable to be parsed as JSON again. The value must
|
||||||
* not have been accessed previously.
|
* not have been accessed previously. It does not
|
||||||
|
* validate the content.
|
||||||
*/
|
*/
|
||||||
inline simdjson_result<std::string_view> to_json_string(SIMDJSON_IMPLEMENTATION::ondemand::value& x) noexcept;
|
inline simdjson_result<std::string_view> to_json_string(SIMDJSON_IMPLEMENTATION::ondemand::value& x) noexcept;
|
||||||
/**
|
/**
|
||||||
* Create a string-view instance out of an object instance. The string-view instance
|
* Create a string-view instance out of an object instance. The string-view instance
|
||||||
* contains JSON text that is suitable to be parsed as JSON again.
|
* contains JSON text that is suitable to be parsed as JSON again. It does not
|
||||||
|
* validate the content.
|
||||||
*/
|
*/
|
||||||
inline simdjson_result<std::string_view> to_json_string(SIMDJSON_IMPLEMENTATION::ondemand::object& x) noexcept;
|
inline simdjson_result<std::string_view> to_json_string(SIMDJSON_IMPLEMENTATION::ondemand::object& x) noexcept;
|
||||||
/**
|
/**
|
||||||
* Create a string-view instance out of an array instance. The string-view instance
|
* Create a string-view instance out of an array instance. The string-view instance
|
||||||
* contains JSON text that is suitable to be parsed as JSON again.
|
* contains JSON text that is suitable to be parsed as JSON again. It does not
|
||||||
|
* validate the content.
|
||||||
*/
|
*/
|
||||||
inline simdjson_result<std::string_view> to_json_string(SIMDJSON_IMPLEMENTATION::ondemand::array& x) noexcept;
|
inline simdjson_result<std::string_view> to_json_string(SIMDJSON_IMPLEMENTATION::ondemand::array& x) noexcept;
|
||||||
inline simdjson_result<std::string_view> to_json_string(simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document> x);
|
inline simdjson_result<std::string_view> to_json_string(simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document> x);
|
||||||
@@ -39,7 +43,8 @@ inline simdjson_result<std::string_view> to_json_string(simdjson_result<SIMDJSON
|
|||||||
namespace simdjson { namespace SIMDJSON_IMPLEMENTATION { namespace ondemand {
|
namespace simdjson { namespace SIMDJSON_IMPLEMENTATION { namespace ondemand {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Print JSON to an output stream.
|
* Print JSON to an output stream. It does not
|
||||||
|
* validate the content.
|
||||||
*
|
*
|
||||||
* @param out The output stream.
|
* @param out The output stream.
|
||||||
* @param value The element.
|
* @param value The element.
|
||||||
@@ -50,7 +55,8 @@ inline std::ostream& operator<<(std::ostream& out, simdjson::SIMDJSON_IMPLEMENTA
|
|||||||
inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::SIMDJSON_IMPLEMENTATION::ondemand::value> x);
|
inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::SIMDJSON_IMPLEMENTATION::ondemand::value> x);
|
||||||
#endif
|
#endif
|
||||||
/**
|
/**
|
||||||
* Print JSON to an output stream.
|
* Print JSON to an output stream. It does not
|
||||||
|
* validate the content.
|
||||||
*
|
*
|
||||||
* @param out The output stream.
|
* @param out The output stream.
|
||||||
* @param value The array.
|
* @param value The array.
|
||||||
@@ -61,7 +67,8 @@ inline std::ostream& operator<<(std::ostream& out, simdjson::SIMDJSON_IMPLEMENTA
|
|||||||
inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::SIMDJSON_IMPLEMENTATION::ondemand::array> x);
|
inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::SIMDJSON_IMPLEMENTATION::ondemand::array> x);
|
||||||
#endif
|
#endif
|
||||||
/**
|
/**
|
||||||
* Print JSON to an output stream.
|
* Print JSON to an output stream. It does not
|
||||||
|
* validate the content.
|
||||||
*
|
*
|
||||||
* @param out The output stream.
|
* @param out The output stream.
|
||||||
* @param value The array.
|
* @param value The array.
|
||||||
@@ -76,7 +83,8 @@ inline std::ostream& operator<<(std::ostream& out, simdjson::SIMDJSON_IMPLEMENTA
|
|||||||
inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::SIMDJSON_IMPLEMENTATION::ondemand::document_reference>&& x);
|
inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::SIMDJSON_IMPLEMENTATION::ondemand::document_reference>&& x);
|
||||||
#endif
|
#endif
|
||||||
/**
|
/**
|
||||||
* Print JSON to an output stream.
|
* Print JSON to an output stream. It does not
|
||||||
|
* validate the content.
|
||||||
*
|
*
|
||||||
* @param out The output stream.
|
* @param out The output stream.
|
||||||
* @param value The object.
|
* @param value The object.
|
||||||
|
|||||||
@@ -30,8 +30,11 @@ simdjson_inline simdjson_result<object> value::start_or_resume_object() noexcept
|
|||||||
simdjson_inline simdjson_result<raw_json_string> value::get_raw_json_string() noexcept {
|
simdjson_inline simdjson_result<raw_json_string> value::get_raw_json_string() noexcept {
|
||||||
return iter.get_raw_json_string();
|
return iter.get_raw_json_string();
|
||||||
}
|
}
|
||||||
simdjson_inline simdjson_result<std::string_view> value::get_string() noexcept {
|
simdjson_inline simdjson_result<std::string_view> value::get_string(bool allow_replacement) noexcept {
|
||||||
return iter.get_string();
|
return iter.get_string(allow_replacement);
|
||||||
|
}
|
||||||
|
simdjson_inline simdjson_result<std::string_view> value::get_wobbly_string() noexcept {
|
||||||
|
return iter.get_wobbly_string();
|
||||||
}
|
}
|
||||||
simdjson_inline simdjson_result<double> value::get_double() noexcept {
|
simdjson_inline simdjson_result<double> value::get_double() noexcept {
|
||||||
return iter.get_double();
|
return iter.get_double();
|
||||||
@@ -54,14 +57,13 @@ simdjson_inline simdjson_result<int64_t> value::get_int64_in_string() noexcept {
|
|||||||
simdjson_inline simdjson_result<bool> value::get_bool() noexcept {
|
simdjson_inline simdjson_result<bool> value::get_bool() noexcept {
|
||||||
return iter.get_bool();
|
return iter.get_bool();
|
||||||
}
|
}
|
||||||
simdjson_inline bool value::is_null() noexcept {
|
simdjson_inline simdjson_result<bool> value::is_null() noexcept {
|
||||||
return iter.is_null();
|
return iter.is_null();
|
||||||
}
|
}
|
||||||
|
|
||||||
template<> simdjson_inline simdjson_result<array> value::get() noexcept { return get_array(); }
|
template<> simdjson_inline simdjson_result<array> value::get() noexcept { return get_array(); }
|
||||||
template<> simdjson_inline simdjson_result<object> value::get() noexcept { return get_object(); }
|
template<> simdjson_inline simdjson_result<object> value::get() noexcept { return get_object(); }
|
||||||
template<> simdjson_inline simdjson_result<raw_json_string> value::get() noexcept { return get_raw_json_string(); }
|
template<> simdjson_inline simdjson_result<raw_json_string> value::get() noexcept { return get_raw_json_string(); }
|
||||||
template<> simdjson_inline simdjson_result<std::string_view> value::get() noexcept { return get_string(); }
|
template<> simdjson_inline simdjson_result<std::string_view> value::get() noexcept { return get_string(false); }
|
||||||
template<> simdjson_inline simdjson_result<number> value::get() noexcept { return get_number(); }
|
template<> simdjson_inline simdjson_result<number> value::get() noexcept { return get_number(); }
|
||||||
template<> simdjson_inline simdjson_result<double> value::get() noexcept { return get_double(); }
|
template<> simdjson_inline simdjson_result<double> value::get() noexcept { return get_double(); }
|
||||||
template<> simdjson_inline simdjson_result<uint64_t> value::get() noexcept { return get_uint64(); }
|
template<> simdjson_inline simdjson_result<uint64_t> value::get() noexcept { return get_uint64(); }
|
||||||
@@ -89,7 +91,7 @@ simdjson_inline value::operator double() noexcept(false) {
|
|||||||
return get_double();
|
return get_double();
|
||||||
}
|
}
|
||||||
simdjson_inline value::operator std::string_view() noexcept(false) {
|
simdjson_inline value::operator std::string_view() noexcept(false) {
|
||||||
return get_string();
|
return get_string(false);
|
||||||
}
|
}
|
||||||
simdjson_inline value::operator raw_json_string() noexcept(false) {
|
simdjson_inline value::operator raw_json_string() noexcept(false) {
|
||||||
return get_raw_json_string();
|
return get_raw_json_string();
|
||||||
@@ -299,9 +301,13 @@ simdjson_inline simdjson_result<double> simdjson_result<SIMDJSON_IMPLEMENTATION:
|
|||||||
if (error()) { return error(); }
|
if (error()) { return error(); }
|
||||||
return first.get_double_in_string();
|
return first.get_double_in_string();
|
||||||
}
|
}
|
||||||
simdjson_inline simdjson_result<std::string_view> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>::get_string() noexcept {
|
simdjson_inline simdjson_result<std::string_view> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>::get_string(bool allow_replacement) noexcept {
|
||||||
if (error()) { return error(); }
|
if (error()) { return error(); }
|
||||||
return first.get_string();
|
return first.get_string(allow_replacement);
|
||||||
|
}
|
||||||
|
simdjson_inline simdjson_result<std::string_view> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>::get_wobbly_string() noexcept {
|
||||||
|
if (error()) { return error(); }
|
||||||
|
return first.get_wobbly_string();
|
||||||
}
|
}
|
||||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::raw_json_string> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>::get_raw_json_string() noexcept {
|
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::raw_json_string> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>::get_raw_json_string() noexcept {
|
||||||
if (error()) { return error(); }
|
if (error()) { return error(); }
|
||||||
@@ -311,8 +317,8 @@ simdjson_inline simdjson_result<bool> simdjson_result<SIMDJSON_IMPLEMENTATION::o
|
|||||||
if (error()) { return error(); }
|
if (error()) { return error(); }
|
||||||
return first.get_bool();
|
return first.get_bool();
|
||||||
}
|
}
|
||||||
simdjson_inline bool simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>::is_null() noexcept {
|
simdjson_inline simdjson_result<bool> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>::is_null() noexcept {
|
||||||
if (error()) { return false; }
|
if (error()) { return error(); }
|
||||||
return first.is_null();
|
return first.is_null();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -404,7 +410,7 @@ simdjson_inline simdjson_result<const char *> simdjson_result<SIMDJSON_IMPLEMENT
|
|||||||
return first.current_location();
|
return first.current_location();
|
||||||
}
|
}
|
||||||
|
|
||||||
simdjson_inline int32_t simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>::current_depth() const noexcept {
|
simdjson_inline simdjson_result<int32_t> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>::current_depth() const noexcept {
|
||||||
if (error()) { return error(); }
|
if (error()) { return error(); }
|
||||||
return first.current_depth();
|
return first.current_depth();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -129,8 +129,23 @@ public:
|
|||||||
* time it parses a document or when it is destroyed.
|
* time it parses a document or when it is destroyed.
|
||||||
* @returns INCORRECT_TYPE if the JSON value is not a string.
|
* @returns INCORRECT_TYPE if the JSON value is not a string.
|
||||||
*/
|
*/
|
||||||
simdjson_inline simdjson_result<std::string_view> get_string() noexcept;
|
simdjson_inline simdjson_result<std::string_view> get_string(bool allow_replacement = false) noexcept;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cast this JSON value to a "wobbly" string.
|
||||||
|
*
|
||||||
|
* The string is may not be a valid UTF-8 string.
|
||||||
|
* See https://simonsapin.github.io/wtf-8/
|
||||||
|
*
|
||||||
|
* Important: a value should be consumed once. Calling get_wobbly_string() twice on the same value
|
||||||
|
* is an error.
|
||||||
|
*
|
||||||
|
* @returns An UTF-8 string. The string is stored in the parser and will be invalidated the next
|
||||||
|
* time it parses a document or when it is destroyed.
|
||||||
|
* @returns INCORRECT_TYPE if the JSON value is not a string.
|
||||||
|
*/
|
||||||
|
simdjson_inline simdjson_result<std::string_view> get_wobbly_string() noexcept;
|
||||||
/**
|
/**
|
||||||
* Cast this JSON value to a raw_json_string.
|
* Cast this JSON value to a raw_json_string.
|
||||||
*
|
*
|
||||||
@@ -150,11 +165,14 @@ public:
|
|||||||
simdjson_inline simdjson_result<bool> get_bool() noexcept;
|
simdjson_inline simdjson_result<bool> get_bool() noexcept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks if this JSON value is null.
|
* Checks if this JSON value is null. If and only if the value is
|
||||||
|
* null, then it is consumed (we advance). If we find a token that
|
||||||
|
* begins with 'n' but is not 'null', then an error is returned.
|
||||||
*
|
*
|
||||||
* @returns Whether the value is null.
|
* @returns Whether the value is null.
|
||||||
|
* @returns INCORRECT_TYPE If the JSON value begins with 'n' and is not 'null'.
|
||||||
*/
|
*/
|
||||||
simdjson_inline bool is_null() noexcept;
|
simdjson_inline simdjson_result<bool> is_null() noexcept;
|
||||||
|
|
||||||
#if SIMDJSON_EXCEPTIONS
|
#if SIMDJSON_EXCEPTIONS
|
||||||
/**
|
/**
|
||||||
@@ -246,6 +264,9 @@ public:
|
|||||||
* beginning as if it had never been accessed. If the JSON is malformed (e.g.,
|
* beginning as if it had never been accessed. If the JSON is malformed (e.g.,
|
||||||
* there is a missing comma), then an error is returned and it is no longer
|
* there is a missing comma), then an error is returned and it is no longer
|
||||||
* safe to continue.
|
* safe to continue.
|
||||||
|
*
|
||||||
|
* Performance hint: You should only call count_elements() as a last
|
||||||
|
* resort as it may require scanning the document twice or more.
|
||||||
*/
|
*/
|
||||||
simdjson_inline simdjson_result<size_t> count_elements() & noexcept;
|
simdjson_inline simdjson_result<size_t> count_elements() & noexcept;
|
||||||
/**
|
/**
|
||||||
@@ -261,6 +282,9 @@ public:
|
|||||||
*
|
*
|
||||||
* To check that an object is empty, it is more performant to use
|
* To check that an object is empty, it is more performant to use
|
||||||
* the is_empty() method on the object instance.
|
* the is_empty() method on the object instance.
|
||||||
|
*
|
||||||
|
* Performance hint: You should only call count_fields() as a last
|
||||||
|
* resort as it may require scanning the document twice or more.
|
||||||
*/
|
*/
|
||||||
simdjson_inline simdjson_result<size_t> count_fields() & noexcept;
|
simdjson_inline simdjson_result<size_t> count_fields() & noexcept;
|
||||||
/**
|
/**
|
||||||
@@ -328,7 +352,9 @@ public:
|
|||||||
simdjson_inline simdjson_result<value> operator[](const char *key) noexcept;
|
simdjson_inline simdjson_result<value> operator[](const char *key) noexcept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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.
|
||||||
*
|
*
|
||||||
* 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
|
||||||
@@ -574,10 +600,11 @@ public:
|
|||||||
simdjson_inline simdjson_result<int64_t> get_int64_in_string() noexcept;
|
simdjson_inline simdjson_result<int64_t> get_int64_in_string() noexcept;
|
||||||
simdjson_inline simdjson_result<double> get_double() noexcept;
|
simdjson_inline simdjson_result<double> get_double() noexcept;
|
||||||
simdjson_inline simdjson_result<double> get_double_in_string() noexcept;
|
simdjson_inline simdjson_result<double> get_double_in_string() noexcept;
|
||||||
simdjson_inline simdjson_result<std::string_view> get_string() noexcept;
|
simdjson_inline simdjson_result<std::string_view> get_string(bool allow_replacement = false) noexcept;
|
||||||
|
simdjson_inline simdjson_result<std::string_view> get_wobbly_string() noexcept;
|
||||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::raw_json_string> get_raw_json_string() noexcept;
|
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::raw_json_string> get_raw_json_string() noexcept;
|
||||||
simdjson_inline simdjson_result<bool> get_bool() noexcept;
|
simdjson_inline simdjson_result<bool> get_bool() noexcept;
|
||||||
simdjson_inline bool is_null() noexcept;
|
simdjson_inline simdjson_result<bool> is_null() noexcept;
|
||||||
|
|
||||||
template<typename T> simdjson_inline simdjson_result<T> get() noexcept;
|
template<typename T> simdjson_inline simdjson_result<T> get() noexcept;
|
||||||
|
|
||||||
@@ -670,7 +697,7 @@ public:
|
|||||||
/** @copydoc simdjson_inline simdjson_result<const char *> current_location() noexcept */
|
/** @copydoc simdjson_inline simdjson_result<const char *> current_location() noexcept */
|
||||||
simdjson_inline simdjson_result<const char *> current_location() noexcept;
|
simdjson_inline simdjson_result<const char *> current_location() noexcept;
|
||||||
/** @copydoc simdjson_inline int32_t current_depth() const noexcept */
|
/** @copydoc simdjson_inline int32_t current_depth() const noexcept */
|
||||||
simdjson_inline int32_t current_depth() const noexcept;
|
simdjson_inline simdjson_result<int32_t> current_depth() const 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_pointer(std::string_view json_pointer) noexcept;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -34,12 +34,17 @@ simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::start
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::started_root_object() noexcept {
|
simdjson_warn_unused simdjson_inline error_code value_iterator::check_root_object() noexcept {
|
||||||
// When in streaming mode, we cannot expect peek_last() to be the last structural element of the
|
// When in streaming mode, we cannot expect peek_last() to be the last structural element of the
|
||||||
// current document. It only works in the normal mode where we have indexed a single document.
|
// current document. It only works in the normal mode where we have indexed a single document.
|
||||||
// Note that adding a check for 'streaming' is not expensive since we only have at most
|
// Note that adding a check for 'streaming' is not expensive since we only have at most
|
||||||
// one root element.
|
// one root element.
|
||||||
if ( ! _json_iter->streaming() ) {
|
if ( ! _json_iter->streaming() ) {
|
||||||
|
// The following lines do not fully protect against garbage content within the
|
||||||
|
// object: e.g., `{"a":2} foo }`. Users concerned with garbage content should
|
||||||
|
// call `at_end()` on the document instance at the end of the processing to
|
||||||
|
// ensure that the processing has finished at the end.
|
||||||
|
//
|
||||||
if (*_json_iter->peek_last() != '}') {
|
if (*_json_iter->peek_last() != '}') {
|
||||||
_json_iter->abandon();
|
_json_iter->abandon();
|
||||||
return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "missing } at end");
|
return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "missing } at end");
|
||||||
@@ -56,6 +61,12 @@ simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::start
|
|||||||
return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "the document is unbalanced");
|
return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "the document is unbalanced");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::started_root_object() noexcept {
|
||||||
|
auto error = check_root_object();
|
||||||
|
if(error) { return error; }
|
||||||
return started_object();
|
return started_object();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -419,12 +430,17 @@ simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::start
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::started_root_array() noexcept {
|
simdjson_warn_unused simdjson_inline error_code value_iterator::check_root_array() noexcept {
|
||||||
// When in streaming mode, we cannot expect peek_last() to be the last structural element of the
|
// When in streaming mode, we cannot expect peek_last() to be the last structural element of the
|
||||||
// current document. It only works in the normal mode where we have indexed a single document.
|
// current document. It only works in the normal mode where we have indexed a single document.
|
||||||
// Note that adding a check for 'streaming' is not expensive since we only have at most
|
// Note that adding a check for 'streaming' is not expensive since we only have at most
|
||||||
// one root element.
|
// one root element.
|
||||||
if ( ! _json_iter->streaming() ) {
|
if ( ! _json_iter->streaming() ) {
|
||||||
|
// The following lines do not fully protect against garbage content within the
|
||||||
|
// array: e.g., `[1, 2] foo]`. Users concerned with garbage content should
|
||||||
|
// also call `at_end()` on the document instance at the end of the processing to
|
||||||
|
// ensure that the processing has finished at the end.
|
||||||
|
//
|
||||||
if (*_json_iter->peek_last() != ']') {
|
if (*_json_iter->peek_last() != ']') {
|
||||||
_json_iter->abandon();
|
_json_iter->abandon();
|
||||||
return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "missing ] at end");
|
return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "missing ] at end");
|
||||||
@@ -441,6 +457,12 @@ simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::start
|
|||||||
return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "the document is unbalanced");
|
return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "the document is unbalanced");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::started_root_array() noexcept {
|
||||||
|
auto error = check_root_array();
|
||||||
|
if (error) { return error; }
|
||||||
return started_array();
|
return started_array();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -468,12 +490,18 @@ simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::parse
|
|||||||
if (error) { return incorrect_type_error("Not a boolean"); }
|
if (error) { return incorrect_type_error("Not a boolean"); }
|
||||||
return simdjson_result<bool>(!not_true);
|
return simdjson_result<bool>(!not_true);
|
||||||
}
|
}
|
||||||
simdjson_inline bool value_iterator::parse_null(const uint8_t *json) const noexcept {
|
simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::parse_null(const uint8_t *json) const noexcept {
|
||||||
return !atomparsing::str4ncmp(json, "null") && jsoncharutils::is_structural_or_whitespace(json[4]);
|
bool is_null_string = !atomparsing::str4ncmp(json, "null") && jsoncharutils::is_structural_or_whitespace(json[4]);
|
||||||
|
// if we start with 'n', we must be a null
|
||||||
|
if(!is_null_string && json[0]=='n') { return incorrect_type_error("Not a null but starts with n"); }
|
||||||
|
return is_null_string;
|
||||||
}
|
}
|
||||||
|
|
||||||
simdjson_warn_unused simdjson_inline simdjson_result<std::string_view> value_iterator::get_string() noexcept {
|
simdjson_warn_unused simdjson_inline simdjson_result<std::string_view> value_iterator::get_string(bool allow_replacement) noexcept {
|
||||||
return get_raw_json_string().unescape(json_iter());
|
return get_raw_json_string().unescape(json_iter(), allow_replacement);
|
||||||
|
}
|
||||||
|
simdjson_warn_unused simdjson_inline simdjson_result<std::string_view> value_iterator::get_wobbly_string() noexcept {
|
||||||
|
return get_raw_json_string().unescape_wobbly(json_iter());
|
||||||
}
|
}
|
||||||
simdjson_warn_unused simdjson_inline simdjson_result<raw_json_string> value_iterator::get_raw_json_string() noexcept {
|
simdjson_warn_unused simdjson_inline simdjson_result<raw_json_string> value_iterator::get_raw_json_string() noexcept {
|
||||||
auto json = peek_scalar("string");
|
auto json = peek_scalar("string");
|
||||||
@@ -516,10 +544,11 @@ simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::get_b
|
|||||||
if(result.error() == SUCCESS) { advance_non_root_scalar("bool"); }
|
if(result.error() == SUCCESS) { advance_non_root_scalar("bool"); }
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
simdjson_inline bool value_iterator::is_null() noexcept {
|
simdjson_inline simdjson_result<bool> value_iterator::is_null() noexcept {
|
||||||
auto result = parse_null(peek_non_root_scalar("null"));
|
bool is_null_value;
|
||||||
if(result) { advance_non_root_scalar("null"); }
|
SIMDJSON_TRY(parse_null(peek_non_root_scalar("null")).get(is_null_value));
|
||||||
return result;
|
if(is_null_value) { advance_non_root_scalar("null"); }
|
||||||
|
return is_null_value;
|
||||||
}
|
}
|
||||||
simdjson_inline bool value_iterator::is_negative() noexcept {
|
simdjson_inline bool value_iterator::is_negative() noexcept {
|
||||||
return numberparsing::is_negative(peek_non_root_scalar("numbersign"));
|
return numberparsing::is_negative(peek_non_root_scalar("numbersign"));
|
||||||
@@ -540,149 +569,187 @@ simdjson_inline simdjson_result<number> value_iterator::get_number() noexcept {
|
|||||||
return num;
|
return num;
|
||||||
}
|
}
|
||||||
|
|
||||||
simdjson_inline simdjson_result<bool> value_iterator::is_root_integer() noexcept {
|
simdjson_inline simdjson_result<bool> value_iterator::is_root_integer(bool check_trailing) noexcept {
|
||||||
auto max_len = peek_start_length();
|
auto max_len = peek_start_length();
|
||||||
auto json = peek_root_scalar("is_root_integer");
|
auto json = peek_root_scalar("is_root_integer");
|
||||||
uint8_t tmpbuf[20+1]; // <20 digits> is the longest possible unsigned integer
|
uint8_t tmpbuf[20+1]; // <20 digits> is the longest possible unsigned integer
|
||||||
if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf)) {
|
if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 20+1)) {
|
||||||
return false; // if there are more than 20 characters, it cannot be represented as an integer.
|
return false; // if there are more than 20 characters, it cannot be represented as an integer.
|
||||||
}
|
}
|
||||||
return numberparsing::is_integer(tmpbuf);
|
auto answer = numberparsing::is_integer(tmpbuf);
|
||||||
|
// If the parsing was a success, we must still check that it is
|
||||||
|
// a single scalar. Note that we parse first because of cases like '[]' where
|
||||||
|
// getting TRAILING_CONTENT is wrong.
|
||||||
|
if(check_trailing && (answer.error() == SUCCESS) && (!_json_iter->is_single_token())) { return TRAILING_CONTENT; }
|
||||||
|
return answer;
|
||||||
}
|
}
|
||||||
|
|
||||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::number_type> value_iterator::get_root_number_type() noexcept {
|
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::number_type> value_iterator::get_root_number_type(bool check_trailing) noexcept {
|
||||||
auto max_len = peek_start_length();
|
auto max_len = peek_start_length();
|
||||||
auto json = peek_root_scalar("number");
|
auto json = peek_root_scalar("number");
|
||||||
// Per https://www.exploringbinary.com/maximum-number-of-decimal-digits-in-binary-floating-point-numbers/,
|
// Per https://www.exploringbinary.com/maximum-number-of-decimal-digits-in-binary-floating-point-numbers/,
|
||||||
// 1074 is the maximum number of significant fractional digits. Add 8 more digits for the biggest
|
// 1074 is the maximum number of significant fractional digits. Add 8 more digits for the biggest
|
||||||
// number: -0.<fraction>e-308.
|
// number: -0.<fraction>e-308.
|
||||||
uint8_t tmpbuf[1074+8+1];
|
uint8_t tmpbuf[1074+8+1];
|
||||||
if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf)) {
|
if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 1074+8+1)) {
|
||||||
logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 1082 characters");
|
logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 1082 characters");
|
||||||
return NUMBER_ERROR;
|
return NUMBER_ERROR;
|
||||||
}
|
}
|
||||||
return numberparsing::get_number_type(tmpbuf);
|
auto answer = numberparsing::get_number_type(tmpbuf);
|
||||||
|
if (check_trailing && (answer.error() == SUCCESS) && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
|
||||||
|
return answer;
|
||||||
}
|
}
|
||||||
simdjson_inline simdjson_result<number> value_iterator::get_root_number() noexcept {
|
simdjson_inline simdjson_result<number> value_iterator::get_root_number(bool check_trailing) noexcept {
|
||||||
auto max_len = peek_start_length();
|
auto max_len = peek_start_length();
|
||||||
auto json = peek_root_scalar("number");
|
auto json = peek_root_scalar("number");
|
||||||
// Per https://www.exploringbinary.com/maximum-number-of-decimal-digits-in-binary-floating-point-numbers/,
|
// Per https://www.exploringbinary.com/maximum-number-of-decimal-digits-in-binary-floating-point-numbers/,
|
||||||
// 1074 is the maximum number of significant fractional digits. Add 8 more digits for the biggest
|
// 1074 is the maximum number of significant fractional digits. Add 8 more digits for the biggest
|
||||||
// number: -0.<fraction>e-308.
|
// number: -0.<fraction>e-308.
|
||||||
uint8_t tmpbuf[1074+8+1];
|
uint8_t tmpbuf[1074+8+1];
|
||||||
if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf)) {
|
if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 1074+8+1)) {
|
||||||
logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 1082 characters");
|
logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 1082 characters");
|
||||||
return NUMBER_ERROR;
|
return NUMBER_ERROR;
|
||||||
}
|
}
|
||||||
number num;
|
number num;
|
||||||
error_code error = numberparsing::parse_number(tmpbuf, num);
|
error_code error = numberparsing::parse_number(tmpbuf, num);
|
||||||
if(error) { return error; }
|
if(error) { return error; }
|
||||||
|
if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
|
||||||
advance_root_scalar("number");
|
advance_root_scalar("number");
|
||||||
return num;
|
return num;
|
||||||
}
|
}
|
||||||
|
simdjson_warn_unused simdjson_inline simdjson_result<std::string_view> value_iterator::get_root_string(bool check_trailing, bool allow_replacement) noexcept {
|
||||||
simdjson_warn_unused simdjson_inline simdjson_result<std::string_view> value_iterator::get_root_string() noexcept {
|
return get_root_raw_json_string(check_trailing).unescape(json_iter(), allow_replacement);
|
||||||
return get_string();
|
|
||||||
}
|
}
|
||||||
simdjson_warn_unused simdjson_inline simdjson_result<raw_json_string> value_iterator::get_root_raw_json_string() noexcept {
|
simdjson_warn_unused simdjson_inline simdjson_result<std::string_view> value_iterator::get_root_wobbly_string(bool check_trailing) noexcept {
|
||||||
return get_raw_json_string();
|
return get_root_raw_json_string(check_trailing).unescape_wobbly(json_iter());
|
||||||
}
|
}
|
||||||
simdjson_warn_unused simdjson_inline simdjson_result<uint64_t> value_iterator::get_root_uint64() noexcept {
|
simdjson_warn_unused simdjson_inline simdjson_result<raw_json_string> value_iterator::get_root_raw_json_string(bool check_trailing) noexcept {
|
||||||
|
auto json = peek_scalar("string");
|
||||||
|
if (*json != '"') { return incorrect_type_error("Not a string"); }
|
||||||
|
if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
|
||||||
|
advance_scalar("string");
|
||||||
|
return raw_json_string(json+1);
|
||||||
|
}
|
||||||
|
simdjson_warn_unused simdjson_inline simdjson_result<uint64_t> value_iterator::get_root_uint64(bool check_trailing) noexcept {
|
||||||
auto max_len = peek_start_length();
|
auto max_len = peek_start_length();
|
||||||
auto json = peek_root_scalar("uint64");
|
auto json = peek_root_scalar("uint64");
|
||||||
uint8_t tmpbuf[20+1]; // <20 digits> is the longest possible unsigned integer
|
uint8_t tmpbuf[20+1]; // <20 digits> is the longest possible unsigned integer
|
||||||
if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf)) {
|
if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 20+1)) {
|
||||||
logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 20 characters");
|
logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 20 characters");
|
||||||
return NUMBER_ERROR;
|
return NUMBER_ERROR;
|
||||||
}
|
}
|
||||||
auto result = numberparsing::parse_unsigned(tmpbuf);
|
auto result = numberparsing::parse_unsigned(tmpbuf);
|
||||||
if(result.error() == SUCCESS) { advance_root_scalar("uint64"); }
|
if(result.error() == SUCCESS) {
|
||||||
|
if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
|
||||||
|
advance_root_scalar("uint64");
|
||||||
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
simdjson_warn_unused simdjson_inline simdjson_result<uint64_t> value_iterator::get_root_uint64_in_string() noexcept {
|
simdjson_warn_unused simdjson_inline simdjson_result<uint64_t> value_iterator::get_root_uint64_in_string(bool check_trailing) noexcept {
|
||||||
auto max_len = peek_start_length();
|
auto max_len = peek_start_length();
|
||||||
auto json = peek_root_scalar("uint64");
|
auto json = peek_root_scalar("uint64");
|
||||||
uint8_t tmpbuf[20+1]; // <20 digits> is the longest possible unsigned integer
|
uint8_t tmpbuf[20+1]; // <20 digits> is the longest possible unsigned integer
|
||||||
if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf)) {
|
if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 20+1)) {
|
||||||
logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 20 characters");
|
logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 20 characters");
|
||||||
return NUMBER_ERROR;
|
return NUMBER_ERROR;
|
||||||
}
|
}
|
||||||
auto result = numberparsing::parse_unsigned_in_string(tmpbuf);
|
auto result = numberparsing::parse_unsigned_in_string(tmpbuf);
|
||||||
if(result.error() == SUCCESS) { advance_root_scalar("uint64"); }
|
if(result.error() == SUCCESS) {
|
||||||
|
if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
|
||||||
|
advance_root_scalar("uint64");
|
||||||
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
simdjson_warn_unused simdjson_inline simdjson_result<int64_t> value_iterator::get_root_int64() noexcept {
|
simdjson_warn_unused simdjson_inline simdjson_result<int64_t> value_iterator::get_root_int64(bool check_trailing) noexcept {
|
||||||
auto max_len = peek_start_length();
|
auto max_len = peek_start_length();
|
||||||
auto json = peek_root_scalar("int64");
|
auto json = peek_root_scalar("int64");
|
||||||
uint8_t tmpbuf[20+1]; // -<19 digits> is the longest possible integer
|
uint8_t tmpbuf[20+1]; // -<19 digits> is the longest possible integer
|
||||||
if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf)) {
|
if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 20+1)) {
|
||||||
logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 20 characters");
|
logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 20 characters");
|
||||||
return NUMBER_ERROR;
|
return NUMBER_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto result = numberparsing::parse_integer(tmpbuf);
|
auto result = numberparsing::parse_integer(tmpbuf);
|
||||||
if(result.error() == SUCCESS) { advance_root_scalar("int64"); }
|
if(result.error() == SUCCESS) {
|
||||||
|
if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
|
||||||
|
advance_root_scalar("int64");
|
||||||
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
simdjson_warn_unused simdjson_inline simdjson_result<int64_t> value_iterator::get_root_int64_in_string() noexcept {
|
simdjson_warn_unused simdjson_inline simdjson_result<int64_t> value_iterator::get_root_int64_in_string(bool check_trailing) noexcept {
|
||||||
auto max_len = peek_start_length();
|
auto max_len = peek_start_length();
|
||||||
auto json = peek_root_scalar("int64");
|
auto json = peek_root_scalar("int64");
|
||||||
uint8_t tmpbuf[20+1]; // -<19 digits> is the longest possible integer
|
uint8_t tmpbuf[20+1]; // -<19 digits> is the longest possible integer
|
||||||
if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf)) {
|
if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 20+1)) {
|
||||||
logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 20 characters");
|
logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 20 characters");
|
||||||
return NUMBER_ERROR;
|
return NUMBER_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto result = numberparsing::parse_integer_in_string(tmpbuf);
|
auto result = numberparsing::parse_integer_in_string(tmpbuf);
|
||||||
if(result.error() == SUCCESS) { advance_root_scalar("int64"); }
|
if(result.error() == SUCCESS) {
|
||||||
|
if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
|
||||||
|
advance_root_scalar("int64");
|
||||||
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
simdjson_warn_unused simdjson_inline simdjson_result<double> value_iterator::get_root_double() noexcept {
|
simdjson_warn_unused simdjson_inline simdjson_result<double> value_iterator::get_root_double(bool check_trailing) noexcept {
|
||||||
auto max_len = peek_start_length();
|
auto max_len = peek_start_length();
|
||||||
auto json = peek_root_scalar("double");
|
auto json = peek_root_scalar("double");
|
||||||
// Per https://www.exploringbinary.com/maximum-number-of-decimal-digits-in-binary-floating-point-numbers/,
|
// Per https://www.exploringbinary.com/maximum-number-of-decimal-digits-in-binary-floating-point-numbers/,
|
||||||
// 1074 is the maximum number of significant fractional digits. Add 8 more digits for the biggest
|
// 1074 is the maximum number of significant fractional digits. Add 8 more digits for the biggest
|
||||||
// number: -0.<fraction>e-308.
|
// number: -0.<fraction>e-308.
|
||||||
uint8_t tmpbuf[1074+8+1];
|
uint8_t tmpbuf[1074+8+1];
|
||||||
if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf)) {
|
if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 1074+8+1)) {
|
||||||
logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 1082 characters");
|
logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 1082 characters");
|
||||||
return NUMBER_ERROR;
|
return NUMBER_ERROR;
|
||||||
}
|
}
|
||||||
auto result = numberparsing::parse_double(tmpbuf);
|
auto result = numberparsing::parse_double(tmpbuf);
|
||||||
if(result.error() == SUCCESS) { advance_root_scalar("double"); }
|
if(result.error() == SUCCESS) {
|
||||||
|
if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
|
||||||
|
advance_root_scalar("double");
|
||||||
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
simdjson_warn_unused simdjson_inline simdjson_result<double> value_iterator::get_root_double_in_string() noexcept {
|
simdjson_warn_unused simdjson_inline simdjson_result<double> value_iterator::get_root_double_in_string(bool check_trailing) noexcept {
|
||||||
auto max_len = peek_start_length();
|
auto max_len = peek_start_length();
|
||||||
auto json = peek_root_scalar("double");
|
auto json = peek_root_scalar("double");
|
||||||
// Per https://www.exploringbinary.com/maximum-number-of-decimal-digits-in-binary-floating-point-numbers/,
|
// Per https://www.exploringbinary.com/maximum-number-of-decimal-digits-in-binary-floating-point-numbers/,
|
||||||
// 1074 is the maximum number of significant fractional digits. Add 8 more digits for the biggest
|
// 1074 is the maximum number of significant fractional digits. Add 8 more digits for the biggest
|
||||||
// number: -0.<fraction>e-308.
|
// number: -0.<fraction>e-308.
|
||||||
uint8_t tmpbuf[1074+8+1];
|
uint8_t tmpbuf[1074+8+1];
|
||||||
if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf)) {
|
if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 1074+8+1)) {
|
||||||
logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 1082 characters");
|
logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 1082 characters");
|
||||||
return NUMBER_ERROR;
|
return NUMBER_ERROR;
|
||||||
}
|
}
|
||||||
auto result = numberparsing::parse_double_in_string(tmpbuf);
|
auto result = numberparsing::parse_double_in_string(tmpbuf);
|
||||||
if(result.error() == SUCCESS) { advance_root_scalar("double"); }
|
if(result.error() == SUCCESS) {
|
||||||
|
if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
|
||||||
|
advance_root_scalar("double");
|
||||||
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::get_root_bool() noexcept {
|
simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::get_root_bool(bool check_trailing) noexcept {
|
||||||
auto max_len = peek_start_length();
|
auto max_len = peek_start_length();
|
||||||
auto json = peek_root_scalar("bool");
|
auto json = peek_root_scalar("bool");
|
||||||
uint8_t tmpbuf[5+1];
|
uint8_t tmpbuf[5+1];
|
||||||
if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf)) { return incorrect_type_error("Not a boolean"); }
|
if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 5+1)) { return incorrect_type_error("Not a boolean"); }
|
||||||
auto result = parse_bool(tmpbuf);
|
auto result = parse_bool(tmpbuf);
|
||||||
if(result.error() == SUCCESS) { advance_root_scalar("bool"); }
|
if(result.error() == SUCCESS) {
|
||||||
|
if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
|
||||||
|
advance_root_scalar("bool");
|
||||||
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
simdjson_inline bool value_iterator::is_root_null() noexcept {
|
simdjson_inline simdjson_result<bool> value_iterator::is_root_null(bool check_trailing) noexcept {
|
||||||
auto max_len = peek_start_length();
|
auto max_len = peek_start_length();
|
||||||
auto json = peek_root_scalar("null");
|
auto json = peek_root_scalar("null");
|
||||||
bool result = (max_len >= 4 && !atomparsing::str4ncmp(json, "null") &&
|
bool result = (max_len >= 4 && !atomparsing::str4ncmp(json, "null") &&
|
||||||
(max_len == 4 || jsoncharutils::is_structural_or_whitespace(json[5])));
|
(max_len == 4 || jsoncharutils::is_structural_or_whitespace(json[4])));
|
||||||
if(result) { advance_root_scalar("null"); }
|
if(result) { // we have something that looks like a null.
|
||||||
|
if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
|
||||||
|
advance_root_scalar("null");
|
||||||
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -109,7 +109,14 @@ public:
|
|||||||
* @error TAPE_ERROR if there is no matching } at end of document
|
* @error TAPE_ERROR if there is no matching } at end of document
|
||||||
*/
|
*/
|
||||||
simdjson_warn_unused simdjson_inline simdjson_result<bool> start_root_object() noexcept;
|
simdjson_warn_unused simdjson_inline simdjson_result<bool> start_root_object() noexcept;
|
||||||
|
/**
|
||||||
|
* Checks whether an object could be started from the root. May be called by start_root_object.
|
||||||
|
*
|
||||||
|
* @returns SUCCESS if it is possible to safely start an object from the root (document level).
|
||||||
|
* @error INCORRECT_TYPE if there is no opening {
|
||||||
|
* @error TAPE_ERROR if there is no matching } at end of document
|
||||||
|
*/
|
||||||
|
simdjson_warn_unused simdjson_inline error_code check_root_object() noexcept;
|
||||||
/**
|
/**
|
||||||
* Start an object iteration after the user has already checked and moved past the {.
|
* Start an object iteration after the user has already checked and moved past the {.
|
||||||
*
|
*
|
||||||
@@ -234,7 +241,14 @@ public:
|
|||||||
* @error TAPE_ERROR if there is no matching ] at end of document
|
* @error TAPE_ERROR if there is no matching ] at end of document
|
||||||
*/
|
*/
|
||||||
simdjson_warn_unused simdjson_inline simdjson_result<bool> start_root_array() noexcept;
|
simdjson_warn_unused simdjson_inline simdjson_result<bool> start_root_array() noexcept;
|
||||||
|
/**
|
||||||
|
* Checks whether an array could be started from the root. May be called by start_root_array.
|
||||||
|
*
|
||||||
|
* @returns SUCCESS if it is possible to safely start an array from the root (document level).
|
||||||
|
* @error INCORRECT_TYPE If there is no [.
|
||||||
|
* @error TAPE_ERROR if there is no matching ] at end of document
|
||||||
|
*/
|
||||||
|
simdjson_warn_unused simdjson_inline error_code check_root_array() noexcept;
|
||||||
/**
|
/**
|
||||||
* Start an array iteration, after the user has already checked and moved past the [.
|
* Start an array iteration, after the user has already checked and moved past the [.
|
||||||
*
|
*
|
||||||
@@ -280,7 +294,8 @@ public:
|
|||||||
* @{
|
* @{
|
||||||
*/
|
*/
|
||||||
|
|
||||||
simdjson_warn_unused simdjson_inline simdjson_result<std::string_view> get_string() noexcept;
|
simdjson_warn_unused simdjson_inline simdjson_result<std::string_view> get_string(bool allow_replacement) noexcept;
|
||||||
|
simdjson_warn_unused simdjson_inline simdjson_result<std::string_view> get_wobbly_string() noexcept;
|
||||||
simdjson_warn_unused simdjson_inline simdjson_result<raw_json_string> get_raw_json_string() noexcept;
|
simdjson_warn_unused simdjson_inline simdjson_result<raw_json_string> get_raw_json_string() noexcept;
|
||||||
simdjson_warn_unused simdjson_inline simdjson_result<uint64_t> get_uint64() noexcept;
|
simdjson_warn_unused simdjson_inline simdjson_result<uint64_t> get_uint64() noexcept;
|
||||||
simdjson_warn_unused simdjson_inline simdjson_result<uint64_t> get_uint64_in_string() noexcept;
|
simdjson_warn_unused simdjson_inline simdjson_result<uint64_t> get_uint64_in_string() noexcept;
|
||||||
@@ -289,26 +304,27 @@ public:
|
|||||||
simdjson_warn_unused simdjson_inline simdjson_result<double> get_double() noexcept;
|
simdjson_warn_unused simdjson_inline simdjson_result<double> get_double() noexcept;
|
||||||
simdjson_warn_unused simdjson_inline simdjson_result<double> get_double_in_string() noexcept;
|
simdjson_warn_unused simdjson_inline simdjson_result<double> get_double_in_string() noexcept;
|
||||||
simdjson_warn_unused simdjson_inline simdjson_result<bool> get_bool() noexcept;
|
simdjson_warn_unused simdjson_inline simdjson_result<bool> get_bool() noexcept;
|
||||||
simdjson_inline bool is_null() noexcept;
|
simdjson_warn_unused simdjson_inline simdjson_result<bool> is_null() noexcept;
|
||||||
simdjson_warn_unused simdjson_inline bool is_negative() noexcept;
|
simdjson_warn_unused simdjson_inline bool is_negative() noexcept;
|
||||||
simdjson_warn_unused simdjson_inline simdjson_result<bool> is_integer() noexcept;
|
simdjson_warn_unused simdjson_inline simdjson_result<bool> is_integer() noexcept;
|
||||||
simdjson_warn_unused simdjson_inline simdjson_result<number_type> get_number_type() noexcept;
|
simdjson_warn_unused simdjson_inline simdjson_result<number_type> get_number_type() noexcept;
|
||||||
simdjson_warn_unused simdjson_inline simdjson_result<number> get_number() noexcept;
|
simdjson_warn_unused simdjson_inline simdjson_result<number> get_number() noexcept;
|
||||||
|
|
||||||
simdjson_warn_unused simdjson_inline simdjson_result<std::string_view> get_root_string() noexcept;
|
simdjson_warn_unused simdjson_inline simdjson_result<std::string_view> get_root_string(bool check_trailing, bool allow_replacement) noexcept;
|
||||||
simdjson_warn_unused simdjson_inline simdjson_result<raw_json_string> get_root_raw_json_string() noexcept;
|
simdjson_warn_unused simdjson_inline simdjson_result<std::string_view> get_root_wobbly_string(bool check_trailing) noexcept;
|
||||||
simdjson_warn_unused simdjson_inline simdjson_result<uint64_t> get_root_uint64() noexcept;
|
simdjson_warn_unused simdjson_inline simdjson_result<raw_json_string> get_root_raw_json_string(bool check_trailing) noexcept;
|
||||||
simdjson_warn_unused simdjson_inline simdjson_result<uint64_t> get_root_uint64_in_string() noexcept;
|
simdjson_warn_unused simdjson_inline simdjson_result<uint64_t> get_root_uint64(bool check_trailing) noexcept;
|
||||||
simdjson_warn_unused simdjson_inline simdjson_result<int64_t> get_root_int64() noexcept;
|
simdjson_warn_unused simdjson_inline simdjson_result<uint64_t> get_root_uint64_in_string(bool check_trailing) noexcept;
|
||||||
simdjson_warn_unused simdjson_inline simdjson_result<int64_t> get_root_int64_in_string() noexcept;
|
simdjson_warn_unused simdjson_inline simdjson_result<int64_t> get_root_int64(bool check_trailing) noexcept;
|
||||||
simdjson_warn_unused simdjson_inline simdjson_result<double> get_root_double() noexcept;
|
simdjson_warn_unused simdjson_inline simdjson_result<int64_t> get_root_int64_in_string(bool check_trailing) noexcept;
|
||||||
simdjson_warn_unused simdjson_inline simdjson_result<double> get_root_double_in_string() noexcept;
|
simdjson_warn_unused simdjson_inline simdjson_result<double> get_root_double(bool check_trailing) noexcept;
|
||||||
simdjson_warn_unused simdjson_inline simdjson_result<bool> get_root_bool() noexcept;
|
simdjson_warn_unused simdjson_inline simdjson_result<double> get_root_double_in_string(bool check_trailing) noexcept;
|
||||||
|
simdjson_warn_unused simdjson_inline simdjson_result<bool> get_root_bool(bool check_trailing) noexcept;
|
||||||
simdjson_warn_unused simdjson_inline bool is_root_negative() noexcept;
|
simdjson_warn_unused simdjson_inline bool is_root_negative() noexcept;
|
||||||
simdjson_warn_unused simdjson_inline simdjson_result<bool> is_root_integer() noexcept;
|
simdjson_warn_unused simdjson_inline simdjson_result<bool> is_root_integer(bool check_trailing) noexcept;
|
||||||
simdjson_warn_unused simdjson_inline simdjson_result<number_type> get_root_number_type() noexcept;
|
simdjson_warn_unused simdjson_inline simdjson_result<number_type> get_root_number_type(bool check_trailing) noexcept;
|
||||||
simdjson_warn_unused simdjson_inline simdjson_result<number> get_root_number() noexcept;
|
simdjson_warn_unused simdjson_inline simdjson_result<number> get_root_number(bool check_trailing) noexcept;
|
||||||
simdjson_inline bool is_root_null() noexcept;
|
simdjson_warn_unused simdjson_inline simdjson_result<bool> is_root_null(bool check_trailing) noexcept;
|
||||||
|
|
||||||
simdjson_inline error_code error() const noexcept;
|
simdjson_inline error_code error() const noexcept;
|
||||||
simdjson_inline uint8_t *&string_buf_loc() noexcept;
|
simdjson_inline uint8_t *&string_buf_loc() noexcept;
|
||||||
@@ -350,7 +366,7 @@ protected:
|
|||||||
inline std::string to_string() const noexcept;
|
inline std::string to_string() const noexcept;
|
||||||
simdjson_inline value_iterator(json_iterator *json_iter, depth_t depth, token_position start_index) noexcept;
|
simdjson_inline value_iterator(json_iterator *json_iter, depth_t depth, token_position start_index) noexcept;
|
||||||
|
|
||||||
simdjson_inline bool parse_null(const uint8_t *json) const noexcept;
|
simdjson_inline simdjson_result<bool> parse_null(const uint8_t *json) const noexcept;
|
||||||
simdjson_inline simdjson_result<bool> parse_bool(const uint8_t *json) const noexcept;
|
simdjson_inline simdjson_result<bool> parse_bool(const uint8_t *json) const noexcept;
|
||||||
simdjson_inline const uint8_t *peek_start() const noexcept;
|
simdjson_inline const uint8_t *peek_start() const noexcept;
|
||||||
simdjson_inline uint32_t peek_start_length() const noexcept;
|
simdjson_inline uint32_t peek_start_length() const noexcept;
|
||||||
|
|||||||
@@ -9,8 +9,12 @@ namespace {
|
|||||||
// but the algorithms do not end up using the returned value.
|
// but the algorithms do not end up using the returned value.
|
||||||
// Sadly, sanitizers are not smart enough to figure it out.
|
// Sadly, sanitizers are not smart enough to figure it out.
|
||||||
SIMDJSON_NO_SANITIZE_UNDEFINED
|
SIMDJSON_NO_SANITIZE_UNDEFINED
|
||||||
|
// This function can be used safely even if not all bytes have been
|
||||||
|
// initialized.
|
||||||
|
// See issue https://github.com/simdjson/simdjson/issues/1965
|
||||||
|
SIMDJSON_NO_SANITIZE_MEMORY
|
||||||
simdjson_inline int trailing_zeroes(uint64_t input_num) {
|
simdjson_inline int trailing_zeroes(uint64_t input_num) {
|
||||||
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
|
#if SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||||
return (int)_tzcnt_u64(input_num);
|
return (int)_tzcnt_u64(input_num);
|
||||||
#else // SIMDJSON_REGULAR_VISUAL_STUDIO
|
#else // SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||||
////////
|
////////
|
||||||
@@ -32,7 +36,7 @@ simdjson_inline int leading_zeroes(uint64_t input_num) {
|
|||||||
return int(_lzcnt_u64(input_num));
|
return int(_lzcnt_u64(input_num));
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
|
#if SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||||
simdjson_inline unsigned __int64 count_ones(uint64_t input_num) {
|
simdjson_inline unsigned __int64 count_ones(uint64_t input_num) {
|
||||||
// note: we do not support legacy 32-bit Windows
|
// note: we do not support legacy 32-bit Windows
|
||||||
return __popcnt64(input_num);// Visual Studio wants two underscores
|
return __popcnt64(input_num);// Visual Studio wants two underscores
|
||||||
@@ -45,7 +49,7 @@ simdjson_inline long long int count_ones(uint64_t input_num) {
|
|||||||
|
|
||||||
simdjson_inline bool add_overflow(uint64_t value1, uint64_t value2,
|
simdjson_inline bool add_overflow(uint64_t value1, uint64_t value2,
|
||||||
uint64_t *result) {
|
uint64_t *result) {
|
||||||
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
|
#if SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||||
return _addcarry_u64(0, value1, value2,
|
return _addcarry_u64(0, value1, value2,
|
||||||
reinterpret_cast<unsigned __int64 *>(result));
|
reinterpret_cast<unsigned __int64 *>(result));
|
||||||
#else
|
#else
|
||||||
|
|||||||
@@ -9,6 +9,9 @@ namespace haswell {
|
|||||||
|
|
||||||
using namespace simdjson;
|
using namespace simdjson;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
class implementation final : public simdjson::implementation {
|
class implementation final : public simdjson::implementation {
|
||||||
public:
|
public:
|
||||||
simdjson_inline implementation() : simdjson::implementation(
|
simdjson_inline implementation() : simdjson::implementation(
|
||||||
|
|||||||
@@ -3,14 +3,14 @@
|
|||||||
|
|
||||||
#include "simdjson/base.h"
|
#include "simdjson/base.h"
|
||||||
|
|
||||||
#ifdef SIMDJSON_VISUAL_STUDIO
|
#if SIMDJSON_VISUAL_STUDIO
|
||||||
// under clang within visual studio, this will include <x86intrin.h>
|
// under clang within visual studio, this will include <x86intrin.h>
|
||||||
#include <intrin.h> // visual studio or clang
|
#include <intrin.h> // visual studio or clang
|
||||||
#else
|
#else
|
||||||
#include <x86intrin.h> // elsewhere
|
#include <x86intrin.h> // elsewhere
|
||||||
#endif // SIMDJSON_VISUAL_STUDIO
|
#endif // SIMDJSON_VISUAL_STUDIO
|
||||||
|
|
||||||
#ifdef SIMDJSON_CLANG_VISUAL_STUDIO
|
#if SIMDJSON_CLANG_VISUAL_STUDIO
|
||||||
/**
|
/**
|
||||||
* You are not supposed, normally, to include these
|
* You are not supposed, normally, to include these
|
||||||
* headers directly. Instead you should either include intrin.h
|
* headers directly. Instead you should either include intrin.h
|
||||||
|
|||||||
@@ -9,8 +9,12 @@ namespace {
|
|||||||
// but the algorithms do not end up using the returned value.
|
// but the algorithms do not end up using the returned value.
|
||||||
// Sadly, sanitizers are not smart enough to figure it out.
|
// Sadly, sanitizers are not smart enough to figure it out.
|
||||||
SIMDJSON_NO_SANITIZE_UNDEFINED
|
SIMDJSON_NO_SANITIZE_UNDEFINED
|
||||||
|
// This function can be used safely even if not all bytes have been
|
||||||
|
// initialized.
|
||||||
|
// See issue https://github.com/simdjson/simdjson/issues/1965
|
||||||
|
SIMDJSON_NO_SANITIZE_MEMORY
|
||||||
simdjson_inline int trailing_zeroes(uint64_t input_num) {
|
simdjson_inline int trailing_zeroes(uint64_t input_num) {
|
||||||
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
|
#if SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||||
return (int)_tzcnt_u64(input_num);
|
return (int)_tzcnt_u64(input_num);
|
||||||
#else // SIMDJSON_REGULAR_VISUAL_STUDIO
|
#else // SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||||
////////
|
////////
|
||||||
@@ -32,7 +36,7 @@ simdjson_inline int leading_zeroes(uint64_t input_num) {
|
|||||||
return int(_lzcnt_u64(input_num));
|
return int(_lzcnt_u64(input_num));
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
|
#if SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||||
simdjson_inline unsigned __int64 count_ones(uint64_t input_num) {
|
simdjson_inline unsigned __int64 count_ones(uint64_t input_num) {
|
||||||
// note: we do not support legacy 32-bit Windows
|
// note: we do not support legacy 32-bit Windows
|
||||||
return __popcnt64(input_num);// Visual Studio wants two underscores
|
return __popcnt64(input_num);// Visual Studio wants two underscores
|
||||||
@@ -45,7 +49,7 @@ simdjson_inline long long int count_ones(uint64_t input_num) {
|
|||||||
|
|
||||||
simdjson_inline bool add_overflow(uint64_t value1, uint64_t value2,
|
simdjson_inline bool add_overflow(uint64_t value1, uint64_t value2,
|
||||||
uint64_t *result) {
|
uint64_t *result) {
|
||||||
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
|
#if SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||||
return _addcarry_u64(0, value1, value2,
|
return _addcarry_u64(0, value1, value2,
|
||||||
reinterpret_cast<unsigned __int64 *>(result));
|
reinterpret_cast<unsigned __int64 *>(result));
|
||||||
#else
|
#else
|
||||||
|
|||||||
@@ -9,6 +9,9 @@ namespace icelake {
|
|||||||
|
|
||||||
using namespace simdjson;
|
using namespace simdjson;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
class implementation final : public simdjson::implementation {
|
class implementation final : public simdjson::implementation {
|
||||||
public:
|
public:
|
||||||
simdjson_inline implementation() : simdjson::implementation(
|
simdjson_inline implementation() : simdjson::implementation(
|
||||||
|
|||||||
@@ -3,14 +3,14 @@
|
|||||||
|
|
||||||
#include "simdjson/base.h"
|
#include "simdjson/base.h"
|
||||||
|
|
||||||
#ifdef SIMDJSON_VISUAL_STUDIO
|
#if SIMDJSON_VISUAL_STUDIO
|
||||||
// under clang within visual studio, this will include <x86intrin.h>
|
// under clang within visual studio, this will include <x86intrin.h>
|
||||||
#include <intrin.h> // visual studio or clang
|
#include <intrin.h> // visual studio or clang
|
||||||
#else
|
#else
|
||||||
#include <x86intrin.h> // elsewhere
|
#include <x86intrin.h> // elsewhere
|
||||||
#endif // SIMDJSON_VISUAL_STUDIO
|
#endif // SIMDJSON_VISUAL_STUDIO
|
||||||
|
|
||||||
#ifdef SIMDJSON_CLANG_VISUAL_STUDIO
|
#if SIMDJSON_CLANG_VISUAL_STUDIO
|
||||||
/**
|
/**
|
||||||
* You are not supposed, normally, to include these
|
* You are not supposed, normally, to include these
|
||||||
* headers directly. Instead you should either include intrin.h
|
* headers directly. Instead you should either include intrin.h
|
||||||
|
|||||||
@@ -79,13 +79,9 @@ namespace simd {
|
|||||||
|
|
||||||
template<int N=1>
|
template<int N=1>
|
||||||
simdjson_inline simd8<T> prev(const simd8<T> prev_chunk) const {
|
simdjson_inline simd8<T> prev(const simd8<T> prev_chunk) const {
|
||||||
#if SIMDJSON_GCC8
|
|
||||||
// workaround for compilers unable to figure out that 16 - N is a constant (GCC 8)
|
// workaround for compilers unable to figure out that 16 - N is a constant (GCC 8)
|
||||||
constexpr int shift = 16 - N;
|
constexpr int shift = 16 - N;
|
||||||
return _mm512_alignr_epi8(*this, _mm512_permutex2var_epi64(prev_chunk, _mm512_set_epi64(13, 12, 11, 10, 9, 8, 7, 6), *this), shift);
|
return _mm512_alignr_epi8(*this, _mm512_permutex2var_epi64(prev_chunk, _mm512_set_epi64(13, 12, 11, 10, 9, 8, 7, 6), *this), shift);
|
||||||
#else
|
|
||||||
return _mm512_alignr_epi8(*this, _mm512_permutex2var_epi64(prev_chunk, _mm512_set_epi64(13, 12, 11, 10, 9, 8, 7, 6), *this), 16 - N);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ public:
|
|||||||
* const implementation *impl = simdjson::get_active_implementation();
|
* const implementation *impl = simdjson::get_active_implementation();
|
||||||
* cout << "simdjson is optimized for " << impl->name() << "(" << impl->description() << ")" << endl;
|
* cout << "simdjson is optimized for " << impl->name() << "(" << impl->description() << ")" << endl;
|
||||||
*
|
*
|
||||||
* @return the name of the implementation, e.g. "haswell", "westmere", "arm64"
|
* @return the name of the implementation, e.g. "haswell", "westmere", "arm64".
|
||||||
*/
|
*/
|
||||||
virtual const std::string &name() const { return _name; }
|
virtual const std::string &name() const { return _name; }
|
||||||
|
|
||||||
@@ -67,7 +67,7 @@ public:
|
|||||||
* const implementation *impl = simdjson::get_active_implementation();
|
* const implementation *impl = simdjson::get_active_implementation();
|
||||||
* cout << "simdjson is optimized for " << impl->name() << "(" << impl->description() << ")" << endl;
|
* cout << "simdjson is optimized for " << impl->name() << "(" << impl->description() << ")" << endl;
|
||||||
*
|
*
|
||||||
* @return the name of the implementation, e.g. "haswell", "westmere", "arm64"
|
* @return the description of the implementation, e.g. "Intel/AMD AVX2", "Intel/AMD SSE4.2", "ARM NEON".
|
||||||
*/
|
*/
|
||||||
virtual const std::string &description() const { return _description; }
|
virtual const std::string &description() const { return _description; }
|
||||||
|
|
||||||
@@ -76,8 +76,7 @@ public:
|
|||||||
* and the current CPU match. This function may poll the current CPU/system
|
* and the current CPU match. This function may poll the current CPU/system
|
||||||
* and should therefore not be called too often if performance is a concern.
|
* and should therefore not be called too often if performance is a concern.
|
||||||
*
|
*
|
||||||
*
|
* @return true if the implementation can be safely used on the current system (determined at runtime).
|
||||||
* @return true if the implementation can be safely used on the current system (determined at runtime)
|
|
||||||
*/
|
*/
|
||||||
bool supported_by_runtime_system() const;
|
bool supported_by_runtime_system() const;
|
||||||
|
|
||||||
@@ -86,9 +85,9 @@ public:
|
|||||||
*
|
*
|
||||||
* The instruction sets this implementation is compiled against.
|
* The instruction sets this implementation is compiled against.
|
||||||
*
|
*
|
||||||
* @return a mask of all required `internal::instruction_set::` values
|
* @return a mask of all required `internal::instruction_set::` values.
|
||||||
*/
|
*/
|
||||||
virtual uint32_t required_instruction_sets() const { return _required_instruction_sets; };
|
virtual uint32_t required_instruction_sets() const { return _required_instruction_sets; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @private For internal implementation use
|
* @private For internal implementation use
|
||||||
@@ -99,7 +98,7 @@ public:
|
|||||||
* @param capacity The largest document that will be passed to the parser.
|
* @param capacity The largest document that will be passed to the parser.
|
||||||
* @param max_depth The maximum JSON object/array nesting this parser is expected to handle.
|
* @param max_depth The maximum JSON object/array nesting this parser is expected to handle.
|
||||||
* @param dst The place to put the resulting parser implementation.
|
* @param dst The place to put the resulting parser implementation.
|
||||||
* @return the name of the implementation, e.g. "haswell", "westmere", "arm64"
|
* @return the error code, or SUCCESS if there was no error.
|
||||||
*/
|
*/
|
||||||
virtual error_code create_dom_parser_implementation(
|
virtual error_code create_dom_parser_implementation(
|
||||||
size_t capacity,
|
size_t capacity,
|
||||||
|
|||||||
@@ -51,8 +51,13 @@
|
|||||||
// Default Haswell to on if this is x86-64. Even if we're not compiled for it, it could be selected
|
// Default Haswell to on if this is x86-64. Even if we're not compiled for it, it could be selected
|
||||||
// at runtime.
|
// at runtime.
|
||||||
#ifndef SIMDJSON_IMPLEMENTATION_HASWELL
|
#ifndef SIMDJSON_IMPLEMENTATION_HASWELL
|
||||||
|
#if SIMDJSON_CAN_ALWAYS_RUN_ICELAKE
|
||||||
|
// if icelake is always available, never enable haswell.
|
||||||
|
#define SIMDJSON_IMPLEMENTATION_HASWELL 0
|
||||||
|
#else
|
||||||
#define SIMDJSON_IMPLEMENTATION_HASWELL SIMDJSON_IS_X86_64
|
#define SIMDJSON_IMPLEMENTATION_HASWELL SIMDJSON_IS_X86_64
|
||||||
#endif
|
#endif
|
||||||
|
#endif
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
// To see why (__BMI__) && (__PCLMUL__) && (__LZCNT__) are not part of this next line, see
|
// To see why (__BMI__) && (__PCLMUL__) && (__LZCNT__) are not part of this next line, see
|
||||||
// https://github.com/simdjson/simdjson/issues/1247
|
// https://github.com/simdjson/simdjson/issues/1247
|
||||||
@@ -61,9 +66,14 @@
|
|||||||
#define SIMDJSON_CAN_ALWAYS_RUN_HASWELL ((SIMDJSON_IMPLEMENTATION_HASWELL) && (SIMDJSON_IS_X86_64) && (__AVX2__) && (__BMI__) && (__PCLMUL__) && (__LZCNT__))
|
#define SIMDJSON_CAN_ALWAYS_RUN_HASWELL ((SIMDJSON_IMPLEMENTATION_HASWELL) && (SIMDJSON_IS_X86_64) && (__AVX2__) && (__BMI__) && (__PCLMUL__) && (__LZCNT__))
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Default Westmere to on if this is x86-64. Note that the macro SIMDJSON_REQUIRES_HASWELL appears unused.
|
// Default Westmere to on if this is x86-64.
|
||||||
#ifndef SIMDJSON_IMPLEMENTATION_WESTMERE
|
#ifndef SIMDJSON_IMPLEMENTATION_WESTMERE
|
||||||
#define SIMDJSON_IMPLEMENTATION_WESTMERE (SIMDJSON_IS_X86_64 && !SIMDJSON_REQUIRES_HASWELL)
|
#if SIMDJSON_CAN_ALWAYS_RUN_ICELAKE || SIMDJSON_CAN_ALWAYS_RUN_HASWELL
|
||||||
|
// if icelake or haswell are always available, never enable westmere.
|
||||||
|
#define SIMDJSON_IMPLEMENTATION_WESTMERE 0
|
||||||
|
#else
|
||||||
|
#define SIMDJSON_IMPLEMENTATION_WESTMERE SIMDJSON_IS_X86_64
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
#define SIMDJSON_CAN_ALWAYS_RUN_WESTMERE (SIMDJSON_IMPLEMENTATION_WESTMERE && SIMDJSON_IS_X86_64 && __SSE4_2__ && __PCLMUL__)
|
#define SIMDJSON_CAN_ALWAYS_RUN_WESTMERE (SIMDJSON_IMPLEMENTATION_WESTMERE && SIMDJSON_IS_X86_64 && __SSE4_2__ && __PCLMUL__)
|
||||||
|
|
||||||
@@ -74,7 +84,12 @@
|
|||||||
|
|
||||||
// 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
|
||||||
#define SIMDJSON_IMPLEMENTATION_FALLBACK 1 // (!SIMDJSON_CAN_ALWAYS_RUN_ARM64 && !SIMDJSON_CAN_ALWAYS_RUN_HASWELL && !SIMDJSON_CAN_ALWAYS_RUN_WESTMERE && !SIMDJSON_CAN_ALWAYS_RUN_PPC64)
|
#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
|
||||||
|
// if anything at all except fallback can always run, then disable fallback.
|
||||||
|
#define SIMDJSON_IMPLEMENTATION_FALLBACK 0
|
||||||
|
#else
|
||||||
|
#define SIMDJSON_IMPLEMENTATION_FALLBACK 1
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
#define SIMDJSON_CAN_ALWAYS_RUN_FALLBACK SIMDJSON_IMPLEMENTATION_FALLBACK
|
#define SIMDJSON_CAN_ALWAYS_RUN_FALLBACK SIMDJSON_IMPLEMENTATION_FALLBACK
|
||||||
|
|
||||||
|
|||||||
@@ -114,9 +114,26 @@ public:
|
|||||||
*
|
*
|
||||||
* @param str pointer to the beginning of a valid UTF-8 JSON string, must end with an unescaped quote.
|
* @param str pointer to the beginning of a valid UTF-8 JSON string, must end with an unescaped quote.
|
||||||
* @param dst pointer to a destination buffer, it must point a region in memory of sufficient size.
|
* @param dst pointer to a destination buffer, it must point a region in memory of sufficient size.
|
||||||
|
* @param allow_replacement whether we allow a replacement character when the UTF-8 contains unmatched surrogate pairs.
|
||||||
* @return end of the of the written region (exclusive) or nullptr in case of error.
|
* @return end of the of the written region (exclusive) or nullptr in case of error.
|
||||||
*/
|
*/
|
||||||
simdjson_warn_unused virtual uint8_t *parse_string(const uint8_t *src, uint8_t *dst) const noexcept = 0;
|
simdjson_warn_unused virtual uint8_t *parse_string(const uint8_t *src, uint8_t *dst, bool allow_replacement) const noexcept = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unescape a NON-valid UTF-8 string from src to dst, stopping at a final unescaped quote. There
|
||||||
|
* must be an unescaped quote terminating the string. It returns the final output
|
||||||
|
* position as pointer. In case of error (e.g., the string has bad escaped codes),
|
||||||
|
* then null_nullptrptr is returned. It is assumed that the output buffer is large
|
||||||
|
* enough. E.g., if src points at 'joe"', then dst needs to have four free bytes +
|
||||||
|
* SIMDJSON_PADDING bytes.
|
||||||
|
*
|
||||||
|
* Overridden by each implementation.
|
||||||
|
*
|
||||||
|
* @param str pointer to the beginning of a possibly invalid UTF-8 JSON string, must end with an unescaped quote.
|
||||||
|
* @param dst pointer to a destination buffer, it must point a region in memory of sufficient size.
|
||||||
|
* @return end of the of the written region (exclusive) or nullptr in case of error.
|
||||||
|
*/
|
||||||
|
simdjson_warn_unused virtual uint8_t *parse_wobbly_string(const uint8_t *src, uint8_t *dst) const noexcept = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Change the capacity of this parser.
|
* Change the capacity of this parser.
|
||||||
|
|||||||
@@ -57,7 +57,6 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||||||
namespace simdjson {
|
namespace simdjson {
|
||||||
namespace internal {
|
namespace internal {
|
||||||
|
|
||||||
|
|
||||||
enum instruction_set {
|
enum instruction_set {
|
||||||
DEFAULT = 0x0,
|
DEFAULT = 0x0,
|
||||||
NEON = 0x1,
|
NEON = 0x1,
|
||||||
@@ -84,22 +83,12 @@ static inline uint32_t detect_supported_architectures() {
|
|||||||
return instruction_set::ALTIVEC;
|
return instruction_set::ALTIVEC;
|
||||||
}
|
}
|
||||||
|
|
||||||
#elif defined(__arm__) || defined(__aarch64__) // incl. armel, armhf, arm64
|
#elif defined(__aarch64__) || defined(_M_ARM64)
|
||||||
|
|
||||||
#if defined(__ARM_NEON)
|
|
||||||
|
|
||||||
static inline uint32_t detect_supported_architectures() {
|
static inline uint32_t detect_supported_architectures() {
|
||||||
return instruction_set::NEON;
|
return instruction_set::NEON;
|
||||||
}
|
}
|
||||||
|
|
||||||
#else // ARM without NEON
|
|
||||||
|
|
||||||
static inline uint32_t detect_supported_architectures() {
|
|
||||||
return instruction_set::DEFAULT;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#elif defined(__x86_64__) || defined(_M_AMD64) // x64
|
#elif defined(__x86_64__) || defined(_M_AMD64) // x64
|
||||||
|
|
||||||
|
|
||||||
@@ -115,9 +104,12 @@ constexpr uint32_t cpuid_avx512pf_bit = 1 << 26; ///< @private bit 26 of EBX
|
|||||||
constexpr uint32_t cpuid_avx512er_bit = 1 << 27; ///< @private bit 27 of EBX for EAX=0x7
|
constexpr uint32_t cpuid_avx512er_bit = 1 << 27; ///< @private bit 27 of EBX for EAX=0x7
|
||||||
constexpr uint32_t cpuid_avx512cd_bit = 1 << 28; ///< @private bit 28 of EBX for EAX=0x7
|
constexpr uint32_t cpuid_avx512cd_bit = 1 << 28; ///< @private bit 28 of EBX for EAX=0x7
|
||||||
constexpr uint32_t cpuid_avx512bw_bit = 1 << 30; ///< @private bit 30 of EBX for EAX=0x7
|
constexpr uint32_t cpuid_avx512bw_bit = 1 << 30; ///< @private bit 30 of EBX for EAX=0x7
|
||||||
constexpr uint32_t cpuid_avx512vl_bit = 1 << 31; ///< @private bit 31 of EBX for EAX=0x7
|
constexpr uint32_t cpuid_avx512vl_bit = 1U << 31; ///< @private bit 31 of EBX for EAX=0x7
|
||||||
constexpr uint32_t cpuid_avx512vbmi2_bit = 1 << 6; ///< @private bit 6 of ECX for EAX=0x7
|
constexpr uint32_t cpuid_avx512vbmi2_bit = 1 << 6; ///< @private bit 6 of ECX for EAX=0x7
|
||||||
|
constexpr uint64_t cpuid_avx256_saved = uint64_t(1) << 2; ///< @private bit 2 = AVX
|
||||||
|
constexpr uint64_t cpuid_avx512_saved = uint64_t(7) << 5; ///< @private bits 5,6,7 = opmask, ZMM_hi256, hi16_ZMM
|
||||||
constexpr uint32_t cpuid_sse42_bit = 1 << 20; ///< @private bit 20 of ECX for EAX=0x1
|
constexpr uint32_t cpuid_sse42_bit = 1 << 20; ///< @private bit 20 of ECX for EAX=0x1
|
||||||
|
constexpr uint32_t cpuid_osxsave = (uint32_t(1) << 26) | (uint32_t(1) << 27); ///< @private bits 26+27 of ECX for EAX=0x1
|
||||||
constexpr uint32_t cpuid_pclmulqdq_bit = 1 << 1; ///< @private bit 1 of ECX for EAX=0x1
|
constexpr uint32_t cpuid_pclmulqdq_bit = 1 << 1; ///< @private bit 1 of ECX for EAX=0x1
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -127,7 +119,7 @@ static inline void cpuid(uint32_t *eax, uint32_t *ebx, uint32_t *ecx,
|
|||||||
uint32_t *edx) {
|
uint32_t *edx) {
|
||||||
#if defined(_MSC_VER)
|
#if defined(_MSC_VER)
|
||||||
int cpu_info[4];
|
int cpu_info[4];
|
||||||
__cpuid(cpu_info, *eax);
|
__cpuidex(cpu_info, *eax, *ecx);
|
||||||
*eax = cpu_info[0];
|
*eax = cpu_info[0];
|
||||||
*ebx = cpu_info[1];
|
*ebx = cpu_info[1];
|
||||||
*ecx = cpu_info[2];
|
*ecx = cpu_info[2];
|
||||||
@@ -145,10 +137,48 @@ static inline void cpuid(uint32_t *eax, uint32_t *ebx, uint32_t *ecx,
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static inline uint64_t xgetbv() {
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
return _xgetbv(0);
|
||||||
|
#else
|
||||||
|
uint32_t xcr0_lo, xcr0_hi;
|
||||||
|
asm volatile("xgetbv\n\t" : "=a" (xcr0_lo), "=d" (xcr0_hi) : "c" (0));
|
||||||
|
return xcr0_lo | (uint64_t(xcr0_hi) << 32);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
static inline uint32_t detect_supported_architectures() {
|
static inline uint32_t detect_supported_architectures() {
|
||||||
uint32_t eax, ebx, ecx, edx;
|
uint32_t eax, ebx, ecx, edx;
|
||||||
uint32_t host_isa = 0x0;
|
uint32_t host_isa = 0x0;
|
||||||
|
|
||||||
|
// EBX for EAX=0x1
|
||||||
|
eax = 0x1;
|
||||||
|
ecx = 0x0;
|
||||||
|
cpuid(&eax, &ebx, &ecx, &edx);
|
||||||
|
|
||||||
|
if (ecx & cpuid_sse42_bit) {
|
||||||
|
host_isa |= instruction_set::SSE42;
|
||||||
|
} else {
|
||||||
|
return host_isa; // everything after is redundant
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ecx & cpuid_pclmulqdq_bit) {
|
||||||
|
host_isa |= instruction_set::PCLMULQDQ;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if ((ecx & cpuid_osxsave) != cpuid_osxsave) {
|
||||||
|
return host_isa;
|
||||||
|
}
|
||||||
|
|
||||||
|
// xgetbv for checking if the OS saves registers
|
||||||
|
uint64_t xcr0 = xgetbv();
|
||||||
|
|
||||||
|
if ((xcr0 & cpuid_avx256_saved) == 0) {
|
||||||
|
return host_isa;
|
||||||
|
}
|
||||||
|
|
||||||
// ECX for EAX=0x7
|
// ECX for EAX=0x7
|
||||||
eax = 0x7;
|
eax = 0x7;
|
||||||
ecx = 0x0;
|
ecx = 0x0;
|
||||||
@@ -164,6 +194,10 @@ static inline uint32_t detect_supported_architectures() {
|
|||||||
host_isa |= instruction_set::BMI2;
|
host_isa |= instruction_set::BMI2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!((xcr0 & cpuid_avx512_saved) == cpuid_avx512_saved)) {
|
||||||
|
return host_isa;
|
||||||
|
}
|
||||||
|
|
||||||
if (ebx & cpuid_avx512f_bit) {
|
if (ebx & cpuid_avx512f_bit) {
|
||||||
host_isa |= instruction_set::AVX512F;
|
host_isa |= instruction_set::AVX512F;
|
||||||
}
|
}
|
||||||
@@ -200,18 +234,6 @@ static inline uint32_t detect_supported_architectures() {
|
|||||||
host_isa |= instruction_set::AVX512VBMI2;
|
host_isa |= instruction_set::AVX512VBMI2;
|
||||||
}
|
}
|
||||||
|
|
||||||
// EBX for EAX=0x1
|
|
||||||
eax = 0x1;
|
|
||||||
cpuid(&eax, &ebx, &ecx, &edx);
|
|
||||||
|
|
||||||
if (ecx & cpuid_sse42_bit) {
|
|
||||||
host_isa |= instruction_set::SSE42;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ecx & cpuid_pclmulqdq_bit) {
|
|
||||||
host_isa |= instruction_set::PCLMULQDQ;
|
|
||||||
}
|
|
||||||
|
|
||||||
return host_isa;
|
return host_isa;
|
||||||
}
|
}
|
||||||
#else // fallback
|
#else // fallback
|
||||||
|
|||||||
@@ -17,7 +17,9 @@ simdjson_inline tape_ref::tape_ref(const dom::document *_doc, size_t _json_index
|
|||||||
simdjson_inline bool tape_ref::is_document_root() const noexcept {
|
simdjson_inline bool tape_ref::is_document_root() const noexcept {
|
||||||
return json_index == 1; // should we ever change the structure of the tape, this should get updated.
|
return json_index == 1; // should we ever change the structure of the tape, this should get updated.
|
||||||
}
|
}
|
||||||
|
simdjson_inline bool tape_ref::usable() const noexcept {
|
||||||
|
return doc != nullptr; // when the document pointer is null, this tape_ref is uninitialized (should not be accessed).
|
||||||
|
}
|
||||||
// Some value types have a specific on-tape word value. It can be faster
|
// Some value types have a specific on-tape word value. It can be faster
|
||||||
// to check the type by doing a word-to-word comparison instead of extracting the
|
// to check the type by doing a word-to-word comparison instead of extracting the
|
||||||
// most significant 8 bits.
|
// most significant 8 bits.
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ public:
|
|||||||
simdjson_inline const char * get_c_str() const noexcept;
|
simdjson_inline const char * get_c_str() const noexcept;
|
||||||
inline std::string_view get_string_view() const noexcept;
|
inline std::string_view get_string_view() const noexcept;
|
||||||
simdjson_inline bool is_document_root() const noexcept;
|
simdjson_inline bool is_document_root() const noexcept;
|
||||||
|
simdjson_inline bool usable() const noexcept;
|
||||||
|
|
||||||
/** The document this element references. */
|
/** The document this element references. */
|
||||||
const dom::document *doc;
|
const dom::document *doc;
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
#define NONSTD_SV_LITE_H_INCLUDED
|
#define NONSTD_SV_LITE_H_INCLUDED
|
||||||
|
|
||||||
#define string_view_lite_MAJOR 1
|
#define string_view_lite_MAJOR 1
|
||||||
#define string_view_lite_MINOR 6
|
#define string_view_lite_MINOR 7
|
||||||
#define string_view_lite_PATCH 0
|
#define string_view_lite_PATCH 0
|
||||||
|
|
||||||
#define string_view_lite_VERSION nssv_STRINGIFY(string_view_lite_MAJOR) "." nssv_STRINGIFY(string_view_lite_MINOR) "." nssv_STRINGIFY(string_view_lite_PATCH)
|
#define string_view_lite_VERSION nssv_STRINGIFY(string_view_lite_MAJOR) "." nssv_STRINGIFY(string_view_lite_MINOR) "." nssv_STRINGIFY(string_view_lite_PATCH)
|
||||||
@@ -72,7 +72,7 @@
|
|||||||
// Control presence of exception handling (try and auto discover):
|
// Control presence of exception handling (try and auto discover):
|
||||||
|
|
||||||
#ifndef nssv_CONFIG_NO_EXCEPTIONS
|
#ifndef nssv_CONFIG_NO_EXCEPTIONS
|
||||||
# if _MSC_VER
|
# if defined(_MSC_VER)
|
||||||
# include <cstddef> // for _HAS_EXCEPTIONS
|
# include <cstddef> // for _HAS_EXCEPTIONS
|
||||||
# endif
|
# endif
|
||||||
# if defined(__cpp_exceptions) || defined(__EXCEPTIONS) || (_HAS_EXCEPTIONS)
|
# if defined(__cpp_exceptions) || defined(__EXCEPTIONS) || (_HAS_EXCEPTIONS)
|
||||||
@@ -82,7 +82,7 @@
|
|||||||
# endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// C++ language version detection (C++20 is speculative):
|
// C++ language version detection (C++23 is speculative):
|
||||||
// Note: VC14.0/1900 (VS2015) lacks too much from C++14.
|
// Note: VC14.0/1900 (VS2015) lacks too much from C++14.
|
||||||
|
|
||||||
#ifndef nssv_CPLUSPLUS
|
#ifndef nssv_CPLUSPLUS
|
||||||
@@ -98,7 +98,8 @@
|
|||||||
#define nssv_CPP11_OR_GREATER_ ( nssv_CPLUSPLUS >= 201103L )
|
#define nssv_CPP11_OR_GREATER_ ( nssv_CPLUSPLUS >= 201103L )
|
||||||
#define nssv_CPP14_OR_GREATER ( nssv_CPLUSPLUS >= 201402L )
|
#define nssv_CPP14_OR_GREATER ( nssv_CPLUSPLUS >= 201402L )
|
||||||
#define nssv_CPP17_OR_GREATER ( nssv_CPLUSPLUS >= 201703L )
|
#define nssv_CPP17_OR_GREATER ( nssv_CPLUSPLUS >= 201703L )
|
||||||
#define nssv_CPP20_OR_GREATER ( nssv_CPLUSPLUS >= 202000L )
|
#define nssv_CPP20_OR_GREATER ( nssv_CPLUSPLUS >= 202002L )
|
||||||
|
#define nssv_CPP23_OR_GREATER ( nssv_CPLUSPLUS >= 202300L )
|
||||||
|
|
||||||
// use C++17 std::string_view if available and requested:
|
// use C++17 std::string_view if available and requested:
|
||||||
|
|
||||||
@@ -288,6 +289,8 @@ using std::operator<<;
|
|||||||
#define nssv_HAVE_CONSTEXPR_11 nssv_CPP11_140
|
#define nssv_HAVE_CONSTEXPR_11 nssv_CPP11_140
|
||||||
#define nssv_HAVE_EXPLICIT_CONVERSION nssv_CPP11_140
|
#define nssv_HAVE_EXPLICIT_CONVERSION nssv_CPP11_140
|
||||||
#define nssv_HAVE_INLINE_NAMESPACE nssv_CPP11_140
|
#define nssv_HAVE_INLINE_NAMESPACE nssv_CPP11_140
|
||||||
|
#define nssv_HAVE_IS_DEFAULT nssv_CPP11_140
|
||||||
|
#define nssv_HAVE_IS_DELETE nssv_CPP11_140
|
||||||
#define nssv_HAVE_NOEXCEPT nssv_CPP11_140
|
#define nssv_HAVE_NOEXCEPT nssv_CPP11_140
|
||||||
#define nssv_HAVE_NULLPTR nssv_CPP11_100
|
#define nssv_HAVE_NULLPTR nssv_CPP11_100
|
||||||
#define nssv_HAVE_REF_QUALIFIER nssv_CPP11_140
|
#define nssv_HAVE_REF_QUALIFIER nssv_CPP11_140
|
||||||
@@ -469,6 +472,17 @@ nssv_DISABLE_MSVC_WARNINGS( 4455 26481 26472 )
|
|||||||
|
|
||||||
namespace nonstd { namespace sv_lite {
|
namespace nonstd { namespace sv_lite {
|
||||||
|
|
||||||
|
//
|
||||||
|
// basic_string_view declaration:
|
||||||
|
//
|
||||||
|
|
||||||
|
template
|
||||||
|
<
|
||||||
|
class CharT,
|
||||||
|
class Traits = std::char_traits<CharT>
|
||||||
|
>
|
||||||
|
class basic_string_view;
|
||||||
|
|
||||||
namespace detail {
|
namespace detail {
|
||||||
|
|
||||||
// support constexpr comparison in C++14;
|
// support constexpr comparison in C++14;
|
||||||
@@ -536,14 +550,33 @@ inline nssv_constexpr14 std::size_t length( CharT * s )
|
|||||||
|
|
||||||
#endif // OPTIMIZE
|
#endif // OPTIMIZE
|
||||||
|
|
||||||
} // namespace detail
|
#if nssv_CPP11_OR_GREATER && ! nssv_CPP17_OR_GREATER
|
||||||
|
#if defined(__OPTIMIZE__)
|
||||||
|
|
||||||
template
|
// gcc, clang provide __OPTIMIZE__
|
||||||
<
|
// Expect tail call optimization to make search() non-recursive:
|
||||||
class CharT,
|
|
||||||
class Traits = std::char_traits<CharT>
|
template< class CharT, class Traits = std::char_traits<CharT> >
|
||||||
>
|
constexpr const CharT* search( basic_string_view<CharT, Traits> haystack, basic_string_view<CharT, Traits> needle )
|
||||||
class basic_string_view;
|
{
|
||||||
|
return haystack.starts_with( needle ) ? haystack.begin() :
|
||||||
|
haystack.empty() ? haystack.end() : search( haystack.substr(1), needle );
|
||||||
|
}
|
||||||
|
|
||||||
|
#else // OPTIMIZE
|
||||||
|
|
||||||
|
// non-recursive:
|
||||||
|
|
||||||
|
template< class CharT, class Traits = std::char_traits<CharT> >
|
||||||
|
constexpr const CharT* search( basic_string_view<CharT, Traits> haystack, basic_string_view<CharT, Traits> needle )
|
||||||
|
{
|
||||||
|
return std::search( haystack.begin(), haystack.end(), needle.begin(), needle.end() );
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // OPTIMIZE
|
||||||
|
#endif // nssv_CPP11_OR_GREATER && ! nssv_CPP17_OR_GREATER
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
//
|
//
|
||||||
// basic_string_view:
|
// basic_string_view:
|
||||||
@@ -570,7 +603,7 @@ public:
|
|||||||
typedef const_pointer iterator;
|
typedef const_pointer iterator;
|
||||||
typedef const_pointer const_iterator;
|
typedef const_pointer const_iterator;
|
||||||
typedef std::reverse_iterator< const_iterator > reverse_iterator;
|
typedef std::reverse_iterator< const_iterator > reverse_iterator;
|
||||||
typedef std::reverse_iterator< const_iterator > const_reverse_iterator;
|
typedef std::reverse_iterator< const_iterator > const_reverse_iterator;
|
||||||
|
|
||||||
typedef std::size_t size_type;
|
typedef std::size_t size_type;
|
||||||
typedef std::ptrdiff_t difference_type;
|
typedef std::ptrdiff_t difference_type;
|
||||||
@@ -607,6 +640,14 @@ public:
|
|||||||
#endif
|
#endif
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
#if nssv_HAVE_NULLPTR
|
||||||
|
# if nssv_HAVE_IS_DELETE
|
||||||
|
nssv_constexpr basic_string_view( std::nullptr_t ) nssv_noexcept = delete;
|
||||||
|
# else
|
||||||
|
private: nssv_constexpr basic_string_view( std::nullptr_t ) nssv_noexcept; public:
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
// Assignment:
|
// Assignment:
|
||||||
|
|
||||||
#if nssv_CPP11_OR_GREATER
|
#if nssv_CPP11_OR_GREATER
|
||||||
@@ -804,25 +845,30 @@ public:
|
|||||||
|
|
||||||
// find(), 4x:
|
// find(), 4x:
|
||||||
|
|
||||||
nssv_constexpr14 size_type find( basic_string_view v, size_type pos = 0 ) const nssv_noexcept // (1)
|
nssv_constexpr size_type find( basic_string_view v, size_type pos = 0 ) const nssv_noexcept // (1)
|
||||||
{
|
{
|
||||||
return assert( v.size() == 0 || v.data() != nssv_nullptr )
|
return assert( v.size() == 0 || v.data() != nssv_nullptr )
|
||||||
, pos >= size()
|
, pos >= size()
|
||||||
? npos
|
? npos : to_pos(
|
||||||
: to_pos( std::search( cbegin() + pos, cend(), v.cbegin(), v.cend(), Traits::eq ) );
|
#if nssv_CPP11_OR_GREATER && ! nssv_CPP17_OR_GREATER
|
||||||
|
detail::search( substr(pos), v )
|
||||||
|
#else
|
||||||
|
std::search( cbegin() + pos, cend(), v.cbegin(), v.cend(), Traits::eq )
|
||||||
|
#endif
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
nssv_constexpr14 size_type find( CharT c, size_type pos = 0 ) const nssv_noexcept // (2)
|
nssv_constexpr size_type find( CharT c, size_type pos = 0 ) const nssv_noexcept // (2)
|
||||||
{
|
{
|
||||||
return find( basic_string_view( &c, 1 ), pos );
|
return find( basic_string_view( &c, 1 ), pos );
|
||||||
}
|
}
|
||||||
|
|
||||||
nssv_constexpr14 size_type find( CharT const * s, size_type pos, size_type n ) const // (3)
|
nssv_constexpr size_type find( CharT const * s, size_type pos, size_type n ) const // (3)
|
||||||
{
|
{
|
||||||
return find( basic_string_view( s, n ), pos );
|
return find( basic_string_view( s, n ), pos );
|
||||||
}
|
}
|
||||||
|
|
||||||
nssv_constexpr14 size_type find( CharT const * s, size_type pos = 0 ) const // (4)
|
nssv_constexpr size_type find( CharT const * s, size_type pos = 0 ) const // (4)
|
||||||
{
|
{
|
||||||
return find( basic_string_view( s ), pos );
|
return find( basic_string_view( s ), pos );
|
||||||
}
|
}
|
||||||
@@ -1381,7 +1427,7 @@ Stream & write_to_stream( Stream & os, View const & sv )
|
|||||||
{
|
{
|
||||||
typename Stream::sentry sentry( os );
|
typename Stream::sentry sentry( os );
|
||||||
|
|
||||||
if ( !os )
|
if ( !sentry )
|
||||||
return os;
|
return os;
|
||||||
|
|
||||||
const std::streamsize length = static_cast<std::streamsize>( sv.length() );
|
const std::streamsize length = static_cast<std::streamsize>( sv.length() );
|
||||||
|
|||||||
@@ -35,9 +35,8 @@ inline char *allocate_padded_buffer(size_t length) noexcept {
|
|||||||
if (padded_buffer == nullptr) {
|
if (padded_buffer == nullptr) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
// We write zeroes in the padded region to avoid having uninitized
|
// We write nulls in the padded region to avoid having uninitialized
|
||||||
// garbage. If nothing else, garbage getting read might trigger a
|
// content which may trigger warning for some sanitizers
|
||||||
// warning in a memory checking.
|
|
||||||
std::memset(padded_buffer + length, 0, totalpaddedlength - length);
|
std::memset(padded_buffer + length, 0, totalpaddedlength - length);
|
||||||
return padded_buffer;
|
return padded_buffer;
|
||||||
} // allocate_padded_buffer()
|
} // allocate_padded_buffer()
|
||||||
@@ -45,7 +44,7 @@ inline char *allocate_padded_buffer(size_t length) noexcept {
|
|||||||
} // namespace internal
|
} // namespace internal
|
||||||
|
|
||||||
|
|
||||||
inline padded_string::padded_string() noexcept {}
|
inline padded_string::padded_string() noexcept = default;
|
||||||
inline padded_string::padded_string(size_t length) noexcept
|
inline padded_string::padded_string(size_t length) noexcept
|
||||||
: viable_size(length), data_ptr(internal::allocate_padded_buffer(length)) {
|
: viable_size(length), data_ptr(internal::allocate_padded_buffer(length)) {
|
||||||
}
|
}
|
||||||
@@ -67,7 +66,7 @@ inline padded_string::padded_string(std::string_view sv_) noexcept
|
|||||||
: viable_size(sv_.size()), data_ptr(internal::allocate_padded_buffer(sv_.size())) {
|
: viable_size(sv_.size()), data_ptr(internal::allocate_padded_buffer(sv_.size())) {
|
||||||
if(simdjson_unlikely(!data_ptr)) {
|
if(simdjson_unlikely(!data_ptr)) {
|
||||||
//allocation failed or zero size
|
//allocation failed or zero size
|
||||||
viable_size=0;
|
viable_size = 0;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (sv_.size()) {
|
if (sv_.size()) {
|
||||||
@@ -127,11 +126,17 @@ inline simdjson_result<padded_string> padded_string::load(std::string_view filen
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Get the file size
|
// Get the file size
|
||||||
if(std::fseek(fp, 0, SEEK_END) < 0) {
|
int ret;
|
||||||
|
#if SIMDJSON_VISUAL_STUDIO && !SIMDJSON_IS_32BITS
|
||||||
|
ret = _fseeki64(fp, 0, SEEK_END);
|
||||||
|
#else
|
||||||
|
ret = std::fseek(fp, 0, SEEK_END);
|
||||||
|
#endif // _WIN64
|
||||||
|
if(ret < 0) {
|
||||||
std::fclose(fp);
|
std::fclose(fp);
|
||||||
return IO_ERROR;
|
return IO_ERROR;
|
||||||
}
|
}
|
||||||
#if defined(SIMDJSON_VISUAL_STUDIO) && !SIMDJSON_IS_32BITS
|
#if SIMDJSON_VISUAL_STUDIO && !SIMDJSON_IS_32BITS
|
||||||
__int64 llen = _ftelli64(fp);
|
__int64 llen = _ftelli64(fp);
|
||||||
if(llen == -1L) {
|
if(llen == -1L) {
|
||||||
std::fclose(fp);
|
std::fclose(fp);
|
||||||
|
|||||||
@@ -32,7 +32,7 @@
|
|||||||
#endif // __clang__
|
#endif // __clang__
|
||||||
#endif // _MSC_VER
|
#endif // _MSC_VER
|
||||||
|
|
||||||
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
|
#if SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||||
// https://en.wikipedia.org/wiki/C_alternative_tokens
|
// https://en.wikipedia.org/wiki/C_alternative_tokens
|
||||||
// This header should have no effect, except maybe
|
// This header should have no effect, except maybe
|
||||||
// under Visual Studio.
|
// under Visual Studio.
|
||||||
@@ -59,8 +59,11 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif // defined(__x86_64__) || defined(_M_AMD64)
|
#endif // defined(__x86_64__) || defined(_M_AMD64)
|
||||||
|
#ifndef SIMDJSON_IS_32BITS
|
||||||
|
#define SIMDJSON_IS_32BITS 0
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef SIMDJSON_IS_32BITS
|
#if SIMDJSON_IS_32BITS
|
||||||
#ifndef SIMDJSON_NO_PORTABILITY_WARNING
|
#ifndef SIMDJSON_NO_PORTABILITY_WARNING
|
||||||
#pragma message("The simdjson library is designed \
|
#pragma message("The simdjson library is designed \
|
||||||
for 64-bit processors and it seems that you are not \
|
for 64-bit processors and it seems that you are not \
|
||||||
@@ -91,7 +94,7 @@ use a 64-bit target such as x64, 64-bit ARM or 64-bit PPC.")
|
|||||||
//
|
//
|
||||||
|
|
||||||
// We are going to use runtime dispatch.
|
// We are going to use runtime dispatch.
|
||||||
#ifdef SIMDJSON_IS_X86_64
|
#if SIMDJSON_IS_X86_64
|
||||||
#ifdef __clang__
|
#ifdef __clang__
|
||||||
// clang does not have GCC push pop
|
// clang does not have GCC push pop
|
||||||
// warning: clang attribute push can't be used within a namespace in clang up
|
// warning: clang attribute push can't be used within a namespace in clang up
|
||||||
@@ -145,7 +148,20 @@ use a 64-bit target such as x64, 64-bit ARM or 64-bit PPC.")
|
|||||||
#define SIMDJSON_NO_SANITIZE_UNDEFINED
|
#define SIMDJSON_NO_SANITIZE_UNDEFINED
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef SIMDJSON_VISUAL_STUDIO
|
|
||||||
|
#if defined(__clang__) || defined(__GNUC__)
|
||||||
|
#if defined(__has_feature)
|
||||||
|
# if __has_feature(memory_sanitizer)
|
||||||
|
#define SIMDJSON_NO_SANITIZE_MEMORY __attribute__((no_sanitize("memory")))
|
||||||
|
# endif // if __has_feature(memory_sanitizer)
|
||||||
|
#endif // defined(__has_feature)
|
||||||
|
#endif
|
||||||
|
// make sure it is defined as 'nothing' if it is unapplicable.
|
||||||
|
#ifndef SIMDJSON_NO_SANITIZE_MEMORY
|
||||||
|
#define SIMDJSON_NO_SANITIZE_MEMORY
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if SIMDJSON_VISUAL_STUDIO
|
||||||
// This is one case where we do not distinguish between
|
// This is one case where we do not distinguish between
|
||||||
// regular visual studio and clang under visual studio.
|
// regular visual studio and clang under visual studio.
|
||||||
// clang under Windows has _stricmp (like visual studio) but not strcasecmp (as clang normally has)
|
// clang under Windows has _stricmp (like visual studio) but not strcasecmp (as clang normally has)
|
||||||
@@ -161,7 +177,7 @@ use a 64-bit target such as x64, 64-bit ARM or 64-bit PPC.")
|
|||||||
|
|
||||||
#ifdef NDEBUG
|
#ifdef NDEBUG
|
||||||
|
|
||||||
#ifdef SIMDJSON_VISUAL_STUDIO
|
#if SIMDJSON_VISUAL_STUDIO
|
||||||
#define SIMDJSON_UNREACHABLE() __assume(0)
|
#define SIMDJSON_UNREACHABLE() __assume(0)
|
||||||
#define SIMDJSON_ASSUME(COND) __assume(COND)
|
#define SIMDJSON_ASSUME(COND) __assume(COND)
|
||||||
#else
|
#else
|
||||||
|
|||||||
@@ -9,8 +9,12 @@ namespace {
|
|||||||
// but the algorithms do not end up using the returned value.
|
// but the algorithms do not end up using the returned value.
|
||||||
// Sadly, sanitizers are not smart enough to figure it out.
|
// Sadly, sanitizers are not smart enough to figure it out.
|
||||||
SIMDJSON_NO_SANITIZE_UNDEFINED
|
SIMDJSON_NO_SANITIZE_UNDEFINED
|
||||||
|
// This function can be used safely even if not all bytes have been
|
||||||
|
// initialized.
|
||||||
|
// See issue https://github.com/simdjson/simdjson/issues/1965
|
||||||
|
SIMDJSON_NO_SANITIZE_MEMORY
|
||||||
simdjson_inline int trailing_zeroes(uint64_t input_num) {
|
simdjson_inline int trailing_zeroes(uint64_t input_num) {
|
||||||
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
|
#if SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||||
unsigned long ret;
|
unsigned long ret;
|
||||||
// Search the mask data from least significant bit (LSB)
|
// Search the mask data from least significant bit (LSB)
|
||||||
// to the most significant bit (MSB) for a set bit (1).
|
// to the most significant bit (MSB) for a set bit (1).
|
||||||
@@ -28,7 +32,7 @@ simdjson_inline uint64_t clear_lowest_bit(uint64_t input_num) {
|
|||||||
|
|
||||||
/* result might be undefined when input_num is zero */
|
/* result might be undefined when input_num is zero */
|
||||||
simdjson_inline int leading_zeroes(uint64_t input_num) {
|
simdjson_inline int leading_zeroes(uint64_t input_num) {
|
||||||
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
|
#if SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||||
unsigned long leading_zero = 0;
|
unsigned long leading_zero = 0;
|
||||||
// Search the mask data from most significant bit (MSB)
|
// Search the mask data from most significant bit (MSB)
|
||||||
// to least significant bit (LSB) for a set bit (1).
|
// to least significant bit (LSB) for a set bit (1).
|
||||||
@@ -41,7 +45,7 @@ simdjson_inline int leading_zeroes(uint64_t input_num) {
|
|||||||
#endif // SIMDJSON_REGULAR_VISUAL_STUDIO
|
#endif // SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
|
#if SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||||
simdjson_inline int count_ones(uint64_t input_num) {
|
simdjson_inline int count_ones(uint64_t input_num) {
|
||||||
// note: we do not support legacy 32-bit Windows
|
// note: we do not support legacy 32-bit Windows
|
||||||
return __popcnt64(input_num); // Visual Studio wants two underscores
|
return __popcnt64(input_num); // Visual Studio wants two underscores
|
||||||
@@ -54,7 +58,7 @@ simdjson_inline int count_ones(uint64_t input_num) {
|
|||||||
|
|
||||||
simdjson_inline bool add_overflow(uint64_t value1, uint64_t value2,
|
simdjson_inline bool add_overflow(uint64_t value1, uint64_t value2,
|
||||||
uint64_t *result) {
|
uint64_t *result) {
|
||||||
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
|
#if SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||||
*result = value1 + value2;
|
*result = value1 + value2;
|
||||||
return *result < value1;
|
return *result < value1;
|
||||||
#else
|
#else
|
||||||
|
|||||||
@@ -12,6 +12,9 @@ using namespace simdjson;
|
|||||||
using namespace simdjson::dom;
|
using namespace simdjson::dom;
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
class implementation final : public simdjson::implementation {
|
class implementation final : public simdjson::implementation {
|
||||||
public:
|
public:
|
||||||
simdjson_inline implementation()
|
simdjson_inline implementation()
|
||||||
|
|||||||
@@ -4,22 +4,22 @@
|
|||||||
#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 2.2.1
|
#define SIMDJSON_VERSION "3.1.7"
|
||||||
|
|
||||||
namespace simdjson {
|
namespace simdjson {
|
||||||
enum {
|
enum {
|
||||||
/**
|
/**
|
||||||
* The major version (MAJOR.minor.revision) of simdjson being used.
|
* The major version (MAJOR.minor.revision) of simdjson being used.
|
||||||
*/
|
*/
|
||||||
SIMDJSON_VERSION_MAJOR = 2,
|
SIMDJSON_VERSION_MAJOR = 3,
|
||||||
/**
|
/**
|
||||||
* The minor version (major.MINOR.revision) of simdjson being used.
|
* The minor version (major.MINOR.revision) of simdjson being used.
|
||||||
*/
|
*/
|
||||||
SIMDJSON_VERSION_MINOR = 2,
|
SIMDJSON_VERSION_MINOR = 1,
|
||||||
/**
|
/**
|
||||||
* The revision (major.minor.REVISION) of simdjson being used.
|
* The revision (major.minor.REVISION) of simdjson being used.
|
||||||
*/
|
*/
|
||||||
SIMDJSON_VERSION_REVISION = 1
|
SIMDJSON_VERSION_REVISION = 7
|
||||||
};
|
};
|
||||||
} // namespace simdjson
|
} // namespace simdjson
|
||||||
|
|
||||||
|
|||||||
@@ -9,8 +9,12 @@ namespace {
|
|||||||
// but the algorithms do not end up using the returned value.
|
// but the algorithms do not end up using the returned value.
|
||||||
// Sadly, sanitizers are not smart enough to figure it out.
|
// Sadly, sanitizers are not smart enough to figure it out.
|
||||||
SIMDJSON_NO_SANITIZE_UNDEFINED
|
SIMDJSON_NO_SANITIZE_UNDEFINED
|
||||||
|
// This function can be used safely even if not all bytes have been
|
||||||
|
// initialized.
|
||||||
|
// See issue https://github.com/simdjson/simdjson/issues/1965
|
||||||
|
SIMDJSON_NO_SANITIZE_MEMORY
|
||||||
simdjson_inline int trailing_zeroes(uint64_t input_num) {
|
simdjson_inline int trailing_zeroes(uint64_t input_num) {
|
||||||
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
|
#if SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||||
unsigned long ret;
|
unsigned long ret;
|
||||||
// Search the mask data from least significant bit (LSB)
|
// Search the mask data from least significant bit (LSB)
|
||||||
// to the most significant bit (MSB) for a set bit (1).
|
// to the most significant bit (MSB) for a set bit (1).
|
||||||
@@ -28,7 +32,7 @@ simdjson_inline uint64_t clear_lowest_bit(uint64_t input_num) {
|
|||||||
|
|
||||||
/* result might be undefined when input_num is zero */
|
/* result might be undefined when input_num is zero */
|
||||||
simdjson_inline int leading_zeroes(uint64_t input_num) {
|
simdjson_inline int leading_zeroes(uint64_t input_num) {
|
||||||
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
|
#if SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||||
unsigned long leading_zero = 0;
|
unsigned long leading_zero = 0;
|
||||||
// Search the mask data from most significant bit (MSB)
|
// Search the mask data from most significant bit (MSB)
|
||||||
// to least significant bit (LSB) for a set bit (1).
|
// to least significant bit (LSB) for a set bit (1).
|
||||||
@@ -41,7 +45,7 @@ simdjson_inline int leading_zeroes(uint64_t input_num) {
|
|||||||
#endif// SIMDJSON_REGULAR_VISUAL_STUDIO
|
#endif// SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
|
#if SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||||
simdjson_inline unsigned __int64 count_ones(uint64_t input_num) {
|
simdjson_inline unsigned __int64 count_ones(uint64_t input_num) {
|
||||||
// note: we do not support legacy 32-bit Windows
|
// note: we do not support legacy 32-bit Windows
|
||||||
return __popcnt64(input_num);// Visual Studio wants two underscores
|
return __popcnt64(input_num);// Visual Studio wants two underscores
|
||||||
@@ -54,7 +58,7 @@ simdjson_inline long long int count_ones(uint64_t input_num) {
|
|||||||
|
|
||||||
simdjson_inline bool add_overflow(uint64_t value1, uint64_t value2,
|
simdjson_inline bool add_overflow(uint64_t value1, uint64_t value2,
|
||||||
uint64_t *result) {
|
uint64_t *result) {
|
||||||
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
|
#if SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||||
return _addcarry_u64(0, value1, value2,
|
return _addcarry_u64(0, value1, value2,
|
||||||
reinterpret_cast<unsigned __int64 *>(result));
|
reinterpret_cast<unsigned __int64 *>(result));
|
||||||
#else
|
#else
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user