mirror of
https://github.com/simdjson/simdjson
synced 2026-06-08 17:27:07 +00:00
Compare commits
287 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 8149284602 | |||
| 0e28a8312d | |||
| 04ab4bb4d9 | |||
| 3960880a0d | |||
| e0f906da79 | |||
| 6a054395a6 | |||
| eac04c7324 | |||
| 319b10acad | |||
| d2d15255bc | |||
| 5b7acd2aa7 | |||
| 61ef447595 | |||
| b524e29576 | |||
| a7b7bc2b69 | |||
| 76dd137c87 | |||
| 52b2414281 | |||
| 5d762fb67f | |||
| 9dc70e8d9c | |||
| 589ef23b56 | |||
| 4b1148384e | |||
| 32afd34a90 | |||
| 70674d2dbd | |||
| f594a49a4b | |||
| 54cbebfd29 | |||
| c6e43a631c | |||
| a8635c9b89 | |||
| 075bfb173b | |||
| a88ad515c2 | |||
| 78b4c0aa6e | |||
| 14ec0ca8f4 | |||
| 8dabd02c3a | |||
| c9692005fd | |||
| 2e0a9397c9 | |||
| f7922075c3 | |||
| b2e20e04c9 | |||
| adc9d18efd | |||
| bf849e3619 | |||
| c09e8dc225 | |||
| 5bf585ef02 | |||
| caff09cafc | |||
| f043db4dca | |||
| e3bd0828d1 | |||
| 9408298e0e | |||
| 573bbac2d2 | |||
| ac78c625df | |||
| 390a66c6e8 | |||
| 210e0a56a1 | |||
| 084f662f32 | |||
| c878ff2500 | |||
| 06afe9ecb3 | |||
| e658502adb | |||
| 6e7d415040 | |||
| 2ccd5b9c97 | |||
| 1cdcbf79b3 | |||
| 7013ed98cc | |||
| b383c717d7 | |||
| b8743bced0 | |||
| ae9ba2bed2 | |||
| 939844d79f | |||
| 4f4e81668e | |||
| bb54946b78 | |||
| 4dec6ed5a7 | |||
| 1dfd48195d | |||
| 23afc6b695 | |||
| e3cac71afe | |||
| cbe562c1d5 | |||
| 30437d0ff6 | |||
| 1e97af7dfb | |||
| 80bc9e5051 | |||
| a74e87df17 | |||
| 3274299647 | |||
| 22ca25faa6 | |||
| 37399fd41b | |||
| a170145d5b | |||
| 7d1d635883 | |||
| ddfa8ae928 | |||
| 25dfb078c7 | |||
| 9f0710e3ad | |||
| 19b9cd9b05 | |||
| 7540248396 | |||
| ab09e96de9 | |||
| 66252e4925 | |||
| 944778c186 | |||
| 62868a2f53 | |||
| 3c446c551b | |||
| efe3d4b7d7 | |||
| 28db262b47 | |||
| bf076bfb5f | |||
| 7bf1ecff9e | |||
| e25a40facf | |||
| a442842f0d | |||
| 421ed4f390 | |||
| 7dff5fa37c | |||
| 9a0527c380 | |||
| b160cf0610 | |||
| 553ee69b7c | |||
| bf70cd0ebf | |||
| cf0551edf5 | |||
| ddb094d550 | |||
| 975fdda03c | |||
| c5c43e9c7f | |||
| 031ee32969 | |||
| b613326d69 | |||
| 53dad74d8e | |||
| e4da19f5cf | |||
| 342b58986a | |||
| 7edc475886 | |||
| d2f8e84fc1 | |||
| 08000518cb | |||
| 90040d96a5 | |||
| 2934892c0b | |||
| 92174c927d | |||
| b399c0165e | |||
| 445ae024ba | |||
| 65f9822542 | |||
| 74bb7b2533 | |||
| fd97288561 | |||
| 1da0d8ac65 | |||
| 85661a2901 | |||
| 3fcdb65d88 | |||
| 8b00d91a2c | |||
| 7db3f97ba8 | |||
| 412a8f7c4d | |||
| d4b31c9feb | |||
| ecdcf276b2 | |||
| 6d92563280 | |||
| 0998233d58 | |||
| cb735818ec | |||
| 41ee548e3f | |||
| e9d5d5088a | |||
| 78151e80e5 | |||
| 083a5d7351 | |||
| 25fcc8b432 | |||
| a9c120f779 | |||
| b1487e34c3 | |||
| 2a68a32012 | |||
| 21a2ccaeb8 | |||
| 6cbb6ac89b | |||
| 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 | |||
| 241ce7304c | |||
| 5dbe96da96 | |||
| 40b397a3d4 | |||
| 5510089d45 | |||
| 62a57907a7 | |||
| becbe99e81 | |||
| bd3d67e889 | |||
| a89d57d0d4 | |||
| e04d400c64 | |||
| 1075e8609c | |||
| 3fde8a4eac | |||
| 62bdb9a2f7 | |||
| 2fbacb0058 | |||
| 509066f06a | |||
| 070f0b26a3 | |||
| 1a195623a5 | |||
| 5f7a56e7f1 | |||
| 5e60f0482d |
@@ -0,0 +1,46 @@
|
|||||||
|
CompileFlags:
|
||||||
|
CompilationDatabase: build
|
||||||
|
Add:
|
||||||
|
- -Werror -Wall -Wextra -Weffc++ -Wsign-compare -Wshadow -Wwrite-strings -Wpointer-arith -Winit-self -Wconversion -Wno-sign-conversion
|
||||||
|
- -Wundefined-inline
|
||||||
|
Diagnostics:
|
||||||
|
Suppress:
|
||||||
|
- misc-unused-alias-decls
|
||||||
|
- misc-unused-using-decls
|
||||||
|
- misc-definitions-in-headers # TODO fix and remove these violations
|
||||||
|
---
|
||||||
|
If:
|
||||||
|
PathMatch:
|
||||||
|
- include/.*
|
||||||
|
- src/.*
|
||||||
|
PathExclude:
|
||||||
|
- include/simdjson.h
|
||||||
|
- src/simdjson.cpp
|
||||||
|
CompileFlags:
|
||||||
|
Add:
|
||||||
|
- -Wno-unneeded-internal-declaration
|
||||||
|
- -Wno-undefined-internal # TODO fix and remove these violations
|
||||||
|
- -Wno-unused-function
|
||||||
|
- -Wno-unused-const-variable
|
||||||
|
Diagnostics:
|
||||||
|
Suppress:
|
||||||
|
- pp_including_mainfile_in_preamble
|
||||||
|
---
|
||||||
|
# Amalgamated files that require or partly define an implementation
|
||||||
|
If:
|
||||||
|
PathMatch:
|
||||||
|
- .*/(arm64|fallback|haswell|icelake|ppc64|westmere)/begin.h
|
||||||
|
- .*/generic/.*
|
||||||
|
Diagnostics:
|
||||||
|
Suppress:
|
||||||
|
- pragma_attribute_no_pop_eof
|
||||||
|
---
|
||||||
|
# clang has a bad time detecting the push/pop together in src/ for some reason
|
||||||
|
If:
|
||||||
|
PathMatch:
|
||||||
|
- include/simdjson/.*/end.h
|
||||||
|
- src/(arm64|fallback|haswell|icelake|ppc64|westmere).cpp
|
||||||
|
Diagnostics:
|
||||||
|
Suppress:
|
||||||
|
- pragma_attribute_no_pop_eof
|
||||||
|
- pragma_attribute_stack_mismatch
|
||||||
@@ -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.
|
||||||
|
|
||||||
@@ -47,10 +49,10 @@ It is fine to report bugs against our main branch, but if that is what you are d
|
|||||||
- Version [e.g. 22]
|
- Version [e.g. 22]
|
||||||
- Optimization setting (e.g., -O3)
|
- Optimization setting (e.g., -O3)
|
||||||
|
|
||||||
We support up-to-date 64-bit ARM and x64 FreeBSD, macOS, Windows and Linux systems. Please ensure that your configuration is supported before labelling the issue as a bug. In particular, we do not support legacy 32-bit systems.
|
We support up-to-date 64-bit ARM and x64 FreeBSD, macOS, Windows and Linux systems. Please ensure that your configuration is supported before labelling the issue as a bug.
|
||||||
|
|
||||||
**Indicate whether you are willing or able to provide a bug fix as a pull request**
|
**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
|
||||||
|
|||||||
@@ -31,4 +31,4 @@ jobs:
|
|||||||
./alpine.sh cmake --build build_for_alpine
|
./alpine.sh cmake --build build_for_alpine
|
||||||
- name: test
|
- name: test
|
||||||
run: |
|
run: |
|
||||||
./alpine.sh bash -c "cd build_for_alpine && ctest -LE explicitonly"
|
./alpine.sh bash -c "cd build_for_alpine && ctest -LE explicitonly --output-on-failure"
|
||||||
|
|||||||
@@ -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,8 +32,9 @@ 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
|
||||||
|
sudo apt-get purge --auto-remove llvm python3-lldb-14 llvm-14
|
||||||
chmod +x llvm.sh
|
chmod +x llvm.sh
|
||||||
sudo ./llvm.sh $CLANGVERSION
|
sudo ./llvm.sh $CLANGVERSION
|
||||||
|
|
||||||
@@ -124,7 +125,7 @@ jobs:
|
|||||||
done
|
done
|
||||||
|
|
||||||
- name: Save the corpus as a github artifact
|
- name: Save the corpus as a github artifact
|
||||||
uses: actions/upload-artifact@v2
|
uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: corpus
|
name: corpus
|
||||||
path: corpus.tar
|
path: corpus.tar
|
||||||
@@ -147,7 +148,7 @@ jobs:
|
|||||||
run: tar cf valgrind.tar valgrind-*.txt
|
run: tar cf valgrind.tar valgrind-*.txt
|
||||||
|
|
||||||
- name: Save valgrind output as a github artifact
|
- name: Save valgrind output as a github artifact
|
||||||
uses: actions/upload-artifact@v2
|
uses: actions/upload-artifact@v3
|
||||||
if: always()
|
if: always()
|
||||||
with:
|
with:
|
||||||
name: valgrindresults
|
name: valgrindresults
|
||||||
@@ -155,7 +156,7 @@ jobs:
|
|||||||
if-no-files-found: ignore
|
if-no-files-found: ignore
|
||||||
|
|
||||||
- name: Archive any crashes as an artifact
|
- name: Archive any crashes as an artifact
|
||||||
uses: actions/upload-artifact@v2
|
uses: actions/upload-artifact@v3
|
||||||
if: always()
|
if: always()
|
||||||
with:
|
with:
|
||||||
name: crashes
|
name: crashes
|
||||||
|
|||||||
@@ -20,13 +20,13 @@ jobs:
|
|||||||
cd builddebug &&
|
cd builddebug &&
|
||||||
cmake -DCMAKE_BUILD_TYPE=Debug -DSIMDJSON_GOOGLE_BENCHMARKS=OFF -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF .. &&
|
cmake -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 --output-on-failure -LE explicitonly -j &&
|
||||||
cd .. &&
|
cd .. &&
|
||||||
mkdir build &&
|
mkdir build &&
|
||||||
cd build &&
|
cd build &&
|
||||||
cmake -DSIMDJSON_GOOGLE_BENCHMARKS=ON -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF -DCMAKE_INSTALL_PREFIX:PATH=destination .. &&
|
cmake -DSIMDJSON_GOOGLE_BENCHMARKS=ON -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF -DCMAKE_INSTALL_PREFIX:PATH=destination .. &&
|
||||||
cmake --build . &&
|
cmake --build . &&
|
||||||
ctest -j --output-on-failure -LE explicitonly &&
|
ctest --output-on-failure -LE explicitonly -j &&
|
||||||
cmake --install . &&
|
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 &&
|
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 &&
|
cd ../tests/installation_tests/find &&
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ jobs:
|
|||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-20.04
|
||||||
name: Build on ubuntu-20.04 ppc64le
|
name: Build on ubuntu-20.04 ppc64le
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2.1.0
|
- uses: actions/checkout@v3
|
||||||
- uses: uraimo/run-on-arch-action@v2.0.5
|
- uses: uraimo/run-on-arch-action@v2.0.5
|
||||||
name: Run commands
|
name: Run commands
|
||||||
id: runcmd
|
id: runcmd
|
||||||
|
|||||||
@@ -0,0 +1,29 @@
|
|||||||
|
name: Ubuntu ppc64le (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: ppc64le
|
||||||
|
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
|
||||||
@@ -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
|
|
||||||
@@ -25,13 +25,13 @@ jobs:
|
|||||||
cd builddebug &&
|
cd builddebug &&
|
||||||
cmake -DCMAKE_BUILD_TYPE=Debug -DSIMDJSON_GOOGLE_BENCHMARKS=OFF -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF .. &&
|
cmake -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 --output-on-failure -LE explicitonly -j &&
|
||||||
cd .. &&
|
cd .. &&
|
||||||
mkdir build &&
|
mkdir build &&
|
||||||
cd build &&
|
cd build &&
|
||||||
cmake -DSIMDJSON_GOOGLE_BENCHMARKS=ON -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF -DCMAKE_INSTALL_PREFIX:PATH=destination .. &&
|
cmake -DSIMDJSON_GOOGLE_BENCHMARKS=ON -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF -DCMAKE_INSTALL_PREFIX:PATH=destination .. &&
|
||||||
cmake --build . &&
|
cmake --build . &&
|
||||||
ctest -j --output-on-failure -LE explicitonly &&
|
ctest --output-on-failure -LE explicitonly -j &&
|
||||||
cmake --install . &&
|
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 &&
|
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 &&
|
cd ../tests/installation_tests/find &&
|
||||||
|
|||||||
@@ -20,13 +20,13 @@ jobs:
|
|||||||
cd builddebug &&
|
cd builddebug &&
|
||||||
cmake -DCMAKE_BUILD_TYPE=Debug -DSIMDJSON_GOOGLE_BENCHMARKS=OFF -DSIMDJSON_DEVELOPER_MODE=ON -DSIMDJSON_EXCEPTIONS=OFF -DBUILD_SHARED_LIBS=OFF .. &&
|
cmake -DCMAKE_BUILD_TYPE=Debug -DSIMDJSON_GOOGLE_BENCHMARKS=OFF -DSIMDJSON_DEVELOPER_MODE=ON -DSIMDJSON_EXCEPTIONS=OFF -DBUILD_SHARED_LIBS=OFF .. &&
|
||||||
cmake --build . &&
|
cmake --build . &&
|
||||||
ctest -j --output-on-failure -LE explicitonly &&
|
ctest --output-on-failure -LE explicitonly -j &&
|
||||||
cd .. &&
|
cd .. &&
|
||||||
mkdir build &&
|
mkdir build &&
|
||||||
cd build &&
|
cd build &&
|
||||||
cmake -DSIMDJSON_DEVELOPER_MODE=ON -DSIMDJSON_GOOGLE_BENCHMARKS=ON -DSIMDJSON_GOOGLE_BENCHMARKS=ON -DSIMDJSON_EXCEPTIONS=OFF -DBUILD_SHARED_LIBS=OFF -DCMAKE_INSTALL_PREFIX:PATH=destination .. &&
|
cmake -DSIMDJSON_DEVELOPER_MODE=ON -DSIMDJSON_GOOGLE_BENCHMARKS=ON -DSIMDJSON_GOOGLE_BENCHMARKS=ON -DSIMDJSON_EXCEPTIONS=OFF -DBUILD_SHARED_LIBS=OFF -DCMAKE_INSTALL_PREFIX:PATH=destination .. &&
|
||||||
cmake --build . &&
|
cmake --build . &&
|
||||||
ctest -j --output-on-failure -LE explicitonly &&
|
ctest --output-on-failure -LE explicitonly -j &&
|
||||||
make install &&
|
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 &&
|
echo -e '#include <simdjson.h>\nint main(int argc,char**argv) {simdjson::dom::parser parser;simdjson::dom::element tweets = parser.load(argv[1]); }' > tmp.cpp && c++ -Idestination/include -Ldestination/lib -std=c++17 -Wl,-rpath,destination/lib -o linkandrun tmp.cpp -lsimdjson && ./linkandrun jsonexamples/twitter.json &&
|
||||||
mkdir testfindpackage &&
|
mkdir testfindpackage &&
|
||||||
|
|||||||
@@ -20,13 +20,13 @@ jobs:
|
|||||||
cd builddebug &&
|
cd builddebug &&
|
||||||
cmake -DCMAKE_BUILD_TYPE=Debug -DSIMDJSON_GOOGLE_BENCHMARKS=OFF -DSIMDJSON_ENABLE_THREADS=OFF -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF .. &&
|
cmake -DCMAKE_BUILD_TYPE=Debug -DSIMDJSON_GOOGLE_BENCHMARKS=OFF -DSIMDJSON_ENABLE_THREADS=OFF -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF .. &&
|
||||||
cmake --build . &&
|
cmake --build . &&
|
||||||
ctest -j --output-on-failure -LE explicitonly &&
|
ctest --output-on-failure -LE explicitonly -j &&
|
||||||
cd .. &&
|
cd .. &&
|
||||||
mkdir build &&
|
mkdir build &&
|
||||||
cd build &&
|
cd build &&
|
||||||
cmake -DSIMDJSON_DEVELOPER_MODE=ON -DSIMDJSON_GOOGLE_BENCHMARKS=ON -DSIMDJSON_ENABLE_THREADS=OFF -DBUILD_SHARED_LIBS=OFF -DCMAKE_INSTALL_PREFIX:PATH=destination .. &&
|
cmake -DSIMDJSON_DEVELOPER_MODE=ON -DSIMDJSON_GOOGLE_BENCHMARKS=ON -DSIMDJSON_ENABLE_THREADS=OFF -DBUILD_SHARED_LIBS=OFF -DCMAKE_INSTALL_PREFIX:PATH=destination .. &&
|
||||||
cmake --build . &&
|
cmake --build . &&
|
||||||
ctest -j --output-on-failure -LE explicitonly &&
|
ctest --output-on-failure -LE explicitonly -j &&
|
||||||
make install &&
|
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 &&
|
echo -e '#include <simdjson.h>\nint main(int argc,char**argv) {simdjson::dom::parser parser;simdjson::dom::element tweets = parser.load(argv[1]); }' > tmp.cpp && c++ -Idestination/include -Ldestination/lib -std=c++17 -Wl,-rpath,destination/lib -o linkandrun tmp.cpp -lsimdjson && ./linkandrun jsonexamples/twitter.json &&
|
||||||
mkdir testfindpackage &&
|
mkdir testfindpackage &&
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ name: Ubuntu 20.04 CI (GCC 9) With Memory Sanitizer
|
|||||||
on: [push, pull_request]
|
on: [push, pull_request]
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
ubuntu-build:
|
ubuntu-build-address-sanitizier:
|
||||||
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]')
|
||||||
@@ -14,10 +14,29 @@ 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 --output-on-failure -LE explicitonly -j
|
||||||
|
ubuntu-build-undefined-sanitizer:
|
||||||
|
if: >-
|
||||||
|
! contains(toJSON(github.event.commits.*.message), '[skip ci]') &&
|
||||||
|
! contains(toJSON(github.event.commits.*.message), '[skip github]')
|
||||||
|
runs-on: ubuntu-20.04
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- uses: actions/cache@v3
|
||||||
|
with:
|
||||||
|
path: dependencies/.cache
|
||||||
|
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
||||||
|
ctest --output-on-failure -LE explicitonly -j
|
||||||
|
- name: Use cmake with undefined sanitizer
|
||||||
|
run: |
|
||||||
|
mkdir builddebugundefsani &&
|
||||||
|
cd builddebugundefsani &&
|
||||||
|
cmake -DSIMDJSON_SANITIZE_UNDEFINED=ON -DCMAKE_BUILD_TYPE=Debug -DSIMDJSON_GOOGLE_BENCHMARKS=OFF -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF .. &&
|
||||||
|
cmake --build . &&
|
||||||
|
ctest --output-on-failure -LE explicitonly -j
|
||||||
|
|||||||
@@ -14,19 +14,33 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
path: dependencies/.cache
|
path: dependencies/.cache
|
||||||
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
||||||
|
- name: Use cmake to build just the library
|
||||||
|
run: |
|
||||||
|
mkdir buildjustlib &&
|
||||||
|
cd buildjustlib &&
|
||||||
|
cmake -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=OFF -DSIMDJSON_DEVELOPER_MODE=OFF -DCMAKE_INSTALL_PREFIX:PATH=destination .. &&
|
||||||
|
cmake --build . &&
|
||||||
|
cmake --install . &&
|
||||||
|
echo -e '#include <simdjson.h>\nint main(int argc,char**argv) {simdjson::dom::parser parser;simdjson::dom::element tweets = parser.load(argv[1]); }' > tmp.cpp &&
|
||||||
|
c++ -Idestination/include -Ldestination/lib -std=c++17 -Wl,-rpath,destination/lib -o linkandrun tmp.cpp -lsimdjson &&
|
||||||
|
cd ../tests/installation_tests/find &&
|
||||||
|
mkdir buildjustlib &&
|
||||||
|
cd buildjustlib &&
|
||||||
|
cmake -DCMAKE_INSTALL_PREFIX:PATH=../../../buildjustlib/destination .. &&
|
||||||
|
cmake --build .
|
||||||
- name: Use cmake
|
- name: Use cmake
|
||||||
run: |
|
run: |
|
||||||
mkdir builddebug &&
|
mkdir builddebug &&
|
||||||
cd builddebug &&
|
cd builddebug &&
|
||||||
cmake -DCMAKE_BUILD_TYPE=Debug -DSIMDJSON_GOOGLE_BENCHMARKS=OFF -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF .. &&
|
cmake -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 --output-on-failure -LE explicitonly -j &&
|
||||||
cd .. &&
|
cd .. &&
|
||||||
mkdir build &&
|
mkdir build &&
|
||||||
cd build &&
|
cd build &&
|
||||||
cmake -DSIMDJSON_GOOGLE_BENCHMARKS=ON -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF -DCMAKE_INSTALL_PREFIX:PATH=destination .. &&
|
cmake -DSIMDJSON_GOOGLE_BENCHMARKS=ON -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF -DCMAKE_INSTALL_PREFIX:PATH=destination .. &&
|
||||||
cmake --build . &&
|
cmake --build . &&
|
||||||
ctest -j --output-on-failure -LE explicitonly &&
|
ctest --output-on-failure -LE explicitonly -j &&
|
||||||
cmake --install . &&
|
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 &&
|
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 &&
|
cd ../tests/installation_tests/find &&
|
||||||
|
|||||||
@@ -14,12 +14,10 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
path: dependencies/.cache
|
path: dependencies/.cache
|
||||||
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
||||||
- name: Install clang++-13
|
|
||||||
run: sudo apt-get install -y clang++-13
|
|
||||||
- name: Use cmake
|
- name: Use cmake
|
||||||
run: |
|
run: |
|
||||||
mkdir build &&
|
mkdir build &&
|
||||||
cd build &&
|
cd build &&
|
||||||
CXX=clang++-13 cmake -DSIMDJSON_DEVELOPER_MODE=ON .. &&
|
CXX=clang++-13 cmake -DSIMDJSON_DEVELOPER_MODE=ON .. &&
|
||||||
cmake --build . &&
|
cmake --build . &&
|
||||||
ctest -j --output-on-failure -LE explicitonly
|
ctest --output-on-failure -LE explicitonly -j
|
||||||
@@ -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,17 @@ 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
|
|
||||||
run: |
|
|
||||||
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 --output-on-failure -LE explicitonly -j
|
||||||
@@ -1,13 +1,13 @@
|
|||||||
name: Macos (Xcode 11)
|
name: Ubuntu 22.04 CI (GCC 12, CXX 20)
|
||||||
|
|
||||||
on: [push, pull_request]
|
on: [push, pull_request]
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
macos-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: macos-latest
|
runs-on: ubuntu-22.04
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
- uses: actions/cache@v3
|
- uses: actions/cache@v3
|
||||||
@@ -16,18 +16,17 @@ jobs:
|
|||||||
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
||||||
- name: Use cmake
|
- name: Use cmake
|
||||||
run: |
|
run: |
|
||||||
xcversion select 11.7
|
|
||||||
mkdir builddebug &&
|
mkdir builddebug &&
|
||||||
cd builddebug &&
|
cd builddebug &&
|
||||||
cmake -DCMAKE_BUILD_TYPE=Debug -DSIMDJSON_GOOGLE_BENCHMARKS=OFF -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF .. &&
|
CXX=g++-12 cmake -DSIMDJSON_CXX_STANDARD=20 -DCMAKE_BUILD_TYPE=Debug -DSIMDJSON_GOOGLE_BENCHMARKS=OFF -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF .. &&
|
||||||
cmake --build . &&
|
cmake --build . &&
|
||||||
ctest -j --output-on-failure -LE explicitonly &&
|
ctest --output-on-failure -LE explicitonly -j &&
|
||||||
cd .. &&
|
cd .. &&
|
||||||
mkdir build &&
|
mkdir build &&
|
||||||
cd build &&
|
cd build &&
|
||||||
cmake -DSIMDJSON_GOOGLE_BENCHMARKS=ON -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF -DCMAKE_INSTALL_PREFIX:PATH=destination .. &&
|
CXX=g++-12 cmake -DSIMDJSON_CXX_STANDARD=20 -DSIMDJSON_GOOGLE_BENCHMARKS=ON -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF -DCMAKE_INSTALL_PREFIX:PATH=destination .. &&
|
||||||
cmake --build . &&
|
cmake --build . &&
|
||||||
ctest -j --output-on-failure -LE explicitonly &&
|
ctest --output-on-failure -LE explicitonly -j &&
|
||||||
cmake --install . &&
|
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 &&
|
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 &&
|
cd ../tests/installation_tests/find &&
|
||||||
@@ -22,4 +22,4 @@ jobs:
|
|||||||
cd build &&
|
cd build &&
|
||||||
CXX=g++-12 cmake -DSIMDJSON_DEVELOPER_MODE=ON .. &&
|
CXX=g++-12 cmake -DSIMDJSON_DEVELOPER_MODE=ON .. &&
|
||||||
cmake --build . &&
|
cmake --build . &&
|
||||||
ctest -j --output-on-failure -LE explicitonly
|
ctest --output-on-failure -LE explicitonly -j
|
||||||
+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
|
|
||||||
+2
-2
@@ -1,4 +1,4 @@
|
|||||||
name: Ubuntu 20.04 CI (GCC 9) with Thread Sanitizer
|
name: Ubuntu 22.04 CI (GCC 11) with Thread Sanitizer
|
||||||
|
|
||||||
on: [push, pull_request]
|
on: [push, pull_request]
|
||||||
|
|
||||||
@@ -7,7 +7,7 @@ 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-20.04
|
runs-on: ubuntu-22.04
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
- uses: actions/cache@v3
|
- uses: actions/cache@v3
|
||||||
@@ -14,19 +14,33 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
path: dependencies/.cache
|
path: dependencies/.cache
|
||||||
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
||||||
|
- name: Use cmake to build just the library
|
||||||
|
run: |
|
||||||
|
mkdir buildjustlib &&
|
||||||
|
cd buildjustlib &&
|
||||||
|
cmake -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=OFF -DSIMDJSON_DEVELOPER_MODE=OFF -DCMAKE_INSTALL_PREFIX:PATH=destination .. &&
|
||||||
|
cmake --build . &&
|
||||||
|
cmake --install . &&
|
||||||
|
echo -e '#include <simdjson.h>\nint main(int argc,char**argv) {simdjson::dom::parser parser;simdjson::dom::element tweets = parser.load(argv[1]); }' > tmp.cpp &&
|
||||||
|
c++ -Idestination/include -Ldestination/lib -std=c++17 -Wl,-rpath,destination/lib -o linkandrun tmp.cpp -lsimdjson &&
|
||||||
|
cd ../tests/installation_tests/find &&
|
||||||
|
mkdir buildjustlib &&
|
||||||
|
cd buildjustlib &&
|
||||||
|
cmake -DCMAKE_INSTALL_PREFIX:PATH=../../../buildjustlib/destination .. &&
|
||||||
|
cmake --build .
|
||||||
- name: Use cmake
|
- name: Use cmake
|
||||||
run: |
|
run: |
|
||||||
mkdir builddebug &&
|
mkdir builddebug &&
|
||||||
cd builddebug &&
|
cd builddebug &&
|
||||||
cmake -DCMAKE_BUILD_TYPE=Debug -DSIMDJSON_GOOGLE_BENCHMARKS=OFF -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF .. &&
|
cmake -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 --output-on-failure -LE explicitonly -j &&
|
||||||
cd .. &&
|
cd .. &&
|
||||||
mkdir build &&
|
mkdir build &&
|
||||||
cd build &&
|
cd build &&
|
||||||
cmake -DSIMDJSON_GOOGLE_BENCHMARKS=ON -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF -DCMAKE_INSTALL_PREFIX:PATH=destination .. &&
|
cmake -DSIMDJSON_GOOGLE_BENCHMARKS=ON -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF -DCMAKE_INSTALL_PREFIX:PATH=destination .. &&
|
||||||
cmake --build . &&
|
cmake --build . &&
|
||||||
ctest -j --output-on-failure -LE explicitonly &&
|
ctest --output-on-failure -LE explicitonly -j &&
|
||||||
cmake --install . &&
|
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 &&
|
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 &&
|
cd ../tests/installation_tests/find &&
|
||||||
|
|||||||
@@ -0,0 +1,44 @@
|
|||||||
|
name: VS17-CI CXX20
|
||||||
|
|
||||||
|
on: [push, pull_request]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
ci:
|
||||||
|
if: >-
|
||||||
|
! contains(toJSON(github.event.commits.*.message), '[skip ci]') &&
|
||||||
|
! contains(toJSON(github.event.commits.*.message), '[skip github]')
|
||||||
|
name: windows-vs17
|
||||||
|
runs-on: windows-latest
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
include:
|
||||||
|
- {gen: Visual Studio 17 2022, arch: Win32, shared: ON}
|
||||||
|
- {gen: Visual Studio 17 2022, arch: Win32, shared: OFF}
|
||||||
|
- {gen: Visual Studio 17 2022, arch: x64, shared: ON}
|
||||||
|
- {gen: Visual Studio 17 2022, arch: x64, shared: OFF}
|
||||||
|
steps:
|
||||||
|
- name: checkout
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
- name: Configure
|
||||||
|
run: |
|
||||||
|
cmake -DSIMDJSON_CXX_STANDARD=20 -G "${{matrix.gen}}" -A ${{matrix.arch}} -DSIMDJSON_DEVELOPER_MODE=ON -DSIMDJSON_COMPETITION=OFF -DBUILD_SHARED_LIBS=${{matrix.shared}} -B build
|
||||||
|
- name: Build Debug
|
||||||
|
run: cmake --build build --config Debug --verbose
|
||||||
|
- name: Build Release
|
||||||
|
run: cmake --build build --config Release --verbose
|
||||||
|
- name: Run Release tests
|
||||||
|
run: |
|
||||||
|
cd build
|
||||||
|
ctest -C Release -LE explicitonly --output-on-failure
|
||||||
|
- name: Run Debug tests
|
||||||
|
run: |
|
||||||
|
cd build
|
||||||
|
ctest -C Debug -LE explicitonly --output-on-failure
|
||||||
|
- name: Install
|
||||||
|
run: |
|
||||||
|
cmake --install build --config Release
|
||||||
|
- name: Test Installation
|
||||||
|
run: |
|
||||||
|
cmake -G "${{matrix.gen}}" -A ${{matrix.arch}} -B build_install_test tests/installation_tests/find
|
||||||
|
cmake --build build_install_test --config Release
|
||||||
@@ -104,3 +104,6 @@ objs
|
|||||||
!.vscode/tasks.json
|
!.vscode/tasks.json
|
||||||
!.vscode/launch.json
|
!.vscode/launch.json
|
||||||
!.vscode/extensions.json
|
!.vscode/extensions.json
|
||||||
|
|
||||||
|
# clangd
|
||||||
|
.cache
|
||||||
Vendored
+8
-3
@@ -4,10 +4,15 @@
|
|||||||
|
|
||||||
// List of extensions which should be recommended for users of this workspace.
|
// List of extensions which should be recommended for users of this workspace.
|
||||||
"recommendations": [
|
"recommendations": [
|
||||||
// Syntax
|
// C++
|
||||||
"ms-vscode.cpptools",
|
"llvm-vs-code-extensions.vscode-clangd",
|
||||||
"ms-vscode.cmake-tools",
|
"xaver.clang-format",
|
||||||
|
// Python
|
||||||
"ms-python.python",
|
"ms-python.python",
|
||||||
|
// .github/*
|
||||||
|
"github.vscode-github-actions",
|
||||||
|
// cmake
|
||||||
|
"ms-vscode.cmake-tools",
|
||||||
"twxs.cmake"
|
"twxs.cmake"
|
||||||
],
|
],
|
||||||
// List of extensions recommended by VS Code that should not be recommended for users of this workspace.
|
// List of extensions recommended by VS Code that should not be recommended for users of this workspace.
|
||||||
|
|||||||
Vendored
+13
-1
@@ -5,6 +5,7 @@
|
|||||||
],
|
],
|
||||||
"files.trimTrailingWhitespace": true,
|
"files.trimTrailingWhitespace": true,
|
||||||
"files.associations": {
|
"files.associations": {
|
||||||
|
".clangd": "yaml",
|
||||||
"array": "cpp",
|
"array": "cpp",
|
||||||
"iterator": "cpp",
|
"iterator": "cpp",
|
||||||
"chrono": "cpp",
|
"chrono": "cpp",
|
||||||
@@ -86,6 +87,17 @@
|
|||||||
"vector": "cpp",
|
"vector": "cpp",
|
||||||
"*.ipp": "cpp",
|
"*.ipp": "cpp",
|
||||||
"__functional_base_03": "cpp",
|
"__functional_base_03": "cpp",
|
||||||
"filesystem": "cpp"
|
"filesystem": "cpp",
|
||||||
|
"*.inc": "cpp",
|
||||||
|
"compare": "cpp",
|
||||||
|
"concepts": "cpp",
|
||||||
|
"variant": "cpp",
|
||||||
|
"__bits": "cpp",
|
||||||
|
"csignal": "cpp",
|
||||||
|
"future": "cpp",
|
||||||
|
"queue": "cpp",
|
||||||
|
"shared_mutex": "cpp",
|
||||||
|
"ranges": "cpp",
|
||||||
|
"span": "cpp"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+45
-7
@@ -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.0.4
|
VERSION 3.2.3
|
||||||
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 "11.0.0" CACHE STRING "simdjson library version")
|
set(SIMDJSON_LIB_VERSION "16.0.0" CACHE STRING "simdjson library version")
|
||||||
set(SIMDJSON_LIB_SOVERSION "11" CACHE STRING "simdjson library soversion")
|
set(SIMDJSON_LIB_SOVERSION "16" 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)
|
||||||
|
if(CMAKE_SIZEOF_VOID_P EQUAL 8) # we only include the benchmarks on 64-bit systems.
|
||||||
add_subdirectory(benchmark)
|
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.0.4"
|
PROJECT_NUMBER = "3.2.3"
|
||||||
|
|
||||||
# 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.
|
||||||
|
|||||||
+48
-17
@@ -1,3 +1,4 @@
|
|||||||
|
|
||||||
Hacking simdjson
|
Hacking simdjson
|
||||||
================
|
================
|
||||||
|
|
||||||
@@ -5,6 +6,26 @@ Here is wisdom about how to build, test and run simdjson from within the reposit
|
|||||||
|
|
||||||
If you plan to contribute to simdjson, please read our [CONTRIBUTING](https://github.com/simdjson/simdjson/blob/master/CONTRIBUTING.md) guide.
|
If you plan to contribute to simdjson, please read our [CONTRIBUTING](https://github.com/simdjson/simdjson/blob/master/CONTRIBUTING.md) guide.
|
||||||
|
|
||||||
|
- [Hacking simdjson](#hacking-simdjson)
|
||||||
|
- [Build Quickstart](#build-quickstart)
|
||||||
|
- [Design notes](#design-notes)
|
||||||
|
- [Developer mode](#developer-mode)
|
||||||
|
- [Directory Structure and Source](#directory-structure-and-source)
|
||||||
|
- [Runtime Dispatching](#runtime-dispatching)
|
||||||
|
- [Regenerating Single-Header Files](#regenerating-single-header-files)
|
||||||
|
- [Usage (CMake on 64-bit platforms like Linux, FreeBSD or macOS)](#usage-cmake-on-64-bit-platforms-like-linux-freebsd-or-macos)
|
||||||
|
- [Usage (CMake on 64-bit Windows using Visual Studio 2019 or better)](#usage-cmake-on-64-bit-windows-using-visual-studio-2019-or-better)
|
||||||
|
- [Various References](#various-references)
|
||||||
|
|
||||||
|
Build Quickstart
|
||||||
|
------------------------------
|
||||||
|
|
||||||
|
```bash
|
||||||
|
mkdir build
|
||||||
|
cd build
|
||||||
|
cmake -D SIMDJSON_DEVELOPER_MODE=ON ..
|
||||||
|
cmake --build .
|
||||||
|
```
|
||||||
|
|
||||||
Design notes
|
Design notes
|
||||||
------------------------------
|
------------------------------
|
||||||
@@ -52,26 +73,34 @@ simdjson's source structure, from the top level, looks like this:
|
|||||||
|
|
||||||
* **CMakeLists.txt:** The main build system.
|
* **CMakeLists.txt:** The main build system.
|
||||||
* **include:** User-facing declarations and inline definitions (most user-facing functions are inlined).
|
* **include:** User-facing declarations and inline definitions (most user-facing functions are inlined).
|
||||||
* simdjson.h: A "main include" that includes files from include/simdjson/. This is equivalent to
|
* simdjson.h: the `simdjson` namespace. A "main include" that includes files from include/simdjson/. This is equivalent to
|
||||||
the distributed simdjson.h.
|
the distributed simdjson.h.
|
||||||
* simdjson/*.h: Declarations for public simdjson classes and functions.
|
* simdjson/*.h: Declarations for public simdjson classes and functions.
|
||||||
* simdjson/*-inl.h: Definitions for public simdjson classes and functions.
|
* simdjson/*-inl.h: Definitions for public simdjson classes and functions.
|
||||||
|
* simdjson/internal/*.h: the `simdjson::internal` namespace. Private classes and functions used by the rest of simdjson.
|
||||||
|
* simdjson/dom.h: the `simdjson::dom` namespace. Includes all public DOM classes.
|
||||||
|
* simdjson/dom/*.h: Declarations/definitions for individual DOM classes.
|
||||||
|
* simdjson/arm64|fallback|haswell|icelake|ppc64|westmere.h: `simdjson::<implementation>` namesapce. Common implementation-specific tools like number and string parsing, as well as minification.
|
||||||
|
* simdjson/arm64|fallback|haswell|icelake|ppc64|westmere/*.h: implementation-specific functions such as , etc.
|
||||||
|
* simdjson/generic/*.h: the bulk of the actual code, written generically and compiled for each implementation, using functions defined in the implementation's .h files.
|
||||||
|
* simdjson/generic/dependencies.h: dependencies on common, non-implementation-specific simdjson classes. This will be included before including amalgamated.h.
|
||||||
|
* simdjson/generic/amalgamated.h: all generic ondemand classes for an implementation.
|
||||||
|
* simdjson/ondemand.h: the `simdjson::ondemand` namespace. Includes all public ondemand classes.
|
||||||
|
* simdjson/builtin.h: the `simdjson::builtin` namespace. Aliased to the most universal implementation available.
|
||||||
|
* simdjson/builtin/ondemand.h: the `simdjson::builtin::ondemand` namespace.
|
||||||
|
* simdjson/arm64|fallback|haswell|icelake|ppc64|westmere/ondemand.h: the `simdjson::<implementation>::ondemand` namespace. on demand compiled for the specific implementation.
|
||||||
|
* simdjson/generic/ondemand/*.h: individual on demand classes, generically written.
|
||||||
|
* simdjson/generic/ondemand/dependencies.h: dependencies on common, non-implementation-specific simdjson classes. This will be included before including amalgamated.h.
|
||||||
|
* simdjson/generic/ondemand/amalgamated.h: all generic ondemand classes for an implementation.
|
||||||
* **src:** The source files for non-inlined functionality (e.g. the architecture-specific parser
|
* **src:** The source files for non-inlined functionality (e.g. the architecture-specific parser
|
||||||
implementations).
|
implementations).
|
||||||
* simdjson.cpp: A "main source" that includes all implementation files from src/. This is
|
* simdjson.cpp: A "main source" that includes all implementation files from src/. This is
|
||||||
equivalent to the distributed simdjson.cpp.
|
equivalent to the distributed simdjson.cpp.
|
||||||
* arm64/|fallback/|haswell/|ppc64/|westmere/: Architecture-specific implementations. All functions are
|
* *.cpp: other misc. implementations, such as `simdjson::implementation` and the minifier.
|
||||||
Each architecture defines its own namespace, e.g. simdjson::haswell.
|
* arm64|fallback|haswell|icelake|ppc64|westmere.cpp: Architecture-specific parser implementations.
|
||||||
* generic/: Generic implementations of the simdjson parser. These files may be included and
|
* generic/*.h: `simdjson::<implementation>` namespace. Generic implementation of the parser, particularly the `dom_parser_implementation`.
|
||||||
compiled multiple times, from whichever architectures use them. They assume they are already
|
* generic/stage1/*.h: `simdjson::<implementation>::stage1` namespace. Generic implementation of the simd-heavy tokenizer/indexer pass of the simdjson parser. Used for the On Demand interface
|
||||||
enclosed in a namespace, e.g.:
|
* generic/stage2/*.h: `simdjson::<implementation>::stage2` namespace. Generic implementation of the tape creator, which consumes the index from stage 1 and actually parses numbers and string and such. Used for the DOM interface.
|
||||||
```c++
|
|
||||||
namespace simdjson {
|
|
||||||
namespace haswell {
|
|
||||||
#include "generic/stage1/json_structural_indexer.h"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Other important files and directories:
|
Other important files and directories:
|
||||||
* **.drone.yml:** Definitions for Drone CI.
|
* **.drone.yml:** Definitions for Drone CI.
|
||||||
@@ -82,7 +111,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
|
||||||
@@ -193,7 +222,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 +285,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 +316,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
|
||||||
===============================================
|
===============================================
|
||||||
@@ -26,16 +28,39 @@ This library is part of the [Awesome Modern C++](https://awesomecpp.com) list.
|
|||||||
Table of Contents
|
Table of Contents
|
||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
|
* [Real-world usage](#real-world-usage)
|
||||||
* [Quick Start](#quick-start)
|
* [Quick Start](#quick-start)
|
||||||
* [Documentation](#documentation)
|
* [Documentation](#documentation)
|
||||||
* [Performance results](#performance-results)
|
* [Performance results](#performance-results)
|
||||||
* [Real-world usage](#real-world-usage)
|
|
||||||
* [Bindings and Ports of simdjson](#bindings-and-ports-of-simdjson)
|
* [Bindings and Ports of simdjson](#bindings-and-ports-of-simdjson)
|
||||||
* [About simdjson](#about-simdjson)
|
* [About simdjson](#about-simdjson)
|
||||||
* [Funding](#funding)
|
* [Funding](#funding)
|
||||||
* [Contributing to simdjson](#contributing-to-simdjson)
|
* [Contributing to simdjson](#contributing-to-simdjson)
|
||||||
* [License](#license)
|
* [License](#license)
|
||||||
|
|
||||||
|
|
||||||
|
Real-world usage
|
||||||
|
----------------
|
||||||
|
|
||||||
|
- [ClickHouse](https://github.com/ClickHouse/ClickHouse)
|
||||||
|
- [Facebook/Meta Velox](https://velox-lib.io)
|
||||||
|
- [milvus](https://github.com/milvus-io/milvus)
|
||||||
|
- [Clang Build Analyzer](https://github.com/aras-p/ClangBuildAnalyzer)
|
||||||
|
- [Shopify HeapProfiler](https://github.com/Shopify/heap-profiler)
|
||||||
|
- [StarRocks](https://github.com/StarRocks/starrocks)
|
||||||
|
- [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)
|
||||||
|
- [vast](https://github.com/tenzir/vast)
|
||||||
|
- [ada-url](https://github.com/ada-url/ada)
|
||||||
|
- [fastgron](https://github.com/adamritter/fastgron)
|
||||||
|
|
||||||
|
If you are planning to use simdjson in a product, please work from one of our releases.
|
||||||
|
|
||||||
Quick Start
|
Quick Start
|
||||||
-----------
|
-----------
|
||||||
|
|
||||||
@@ -62,10 +87,10 @@ int main(void) {
|
|||||||
ondemand::document tweets = parser.iterate(json);
|
ondemand::document tweets = parser.iterate(json);
|
||||||
std::cout << uint64_t(tweets["search_metadata"]["count"]) << " results." << std::endl;
|
std::cout << uint64_t(tweets["search_metadata"]["count"]) << " results." << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
```
|
```
|
||||||
3. `c++ -o quickstart quickstart.cpp simdjson.cpp`
|
3. `c++ -o quickstart quickstart.cpp simdjson.cpp`
|
||||||
4. `./quickstart`
|
4. `./quickstart`
|
||||||
|
|
||||||
```
|
```
|
||||||
100 results.
|
100 results.
|
||||||
```
|
```
|
||||||
@@ -79,7 +104,13 @@ Usage documentation is available:
|
|||||||
* [Performance](doc/performance.md) shows some more advanced scenarios and how to tune for them.
|
* [Performance](doc/performance.md) shows some more advanced scenarios and how to tune for them.
|
||||||
* [Implementation Selection](doc/implementation-selection.md) describes runtime CPU detection and
|
* [Implementation Selection](doc/implementation-selection.md) describes runtime CPU detection and
|
||||||
how you can work with it.
|
how you can work with it.
|
||||||
* [API](https://simdjson.org/api/1.0.0/annotated.html) contains the automatically generated API documentation.
|
* [API](https://simdjson.github.io/simdjson/) contains the automatically generated API documentation.
|
||||||
|
|
||||||
|
|
||||||
|
Some users may want to browse code along with the compiled assembly. You want to check out the following lists of examples:
|
||||||
|
|
||||||
|
* [simdjson examples with errors handled through exceptions](https://godbolt.org/z/98Kx9Kqjn)
|
||||||
|
* [simdjson examples with errors without exceptions](https://godbolt.org/z/PKG7GdbPo)
|
||||||
|
|
||||||
Performance results
|
Performance results
|
||||||
-------------------
|
-------------------
|
||||||
@@ -108,15 +139,6 @@ For NDJSON files, we can exceed 3 GB/s with [our multithreaded parsing function
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
Real-world usage
|
|
||||||
----------------
|
|
||||||
|
|
||||||
- [Microsoft FishStore](https://github.com/microsoft/FishStore)
|
|
||||||
- [Yandex ClickHouse](https://github.com/yandex/ClickHouse)
|
|
||||||
- [Clang Build Analyzer](https://github.com/aras-p/ClangBuildAnalyzer)
|
|
||||||
- [Shopify HeapProfiler](https://github.com/Shopify/heap-profiler)
|
|
||||||
|
|
||||||
If you are planning to use simdjson in a product, please work from one of our releases.
|
|
||||||
|
|
||||||
Bindings and Ports of simdjson
|
Bindings and Ports of simdjson
|
||||||
------------------------------
|
------------------------------
|
||||||
@@ -137,9 +159,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.
|
||||||
|
- [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
|
||||||
--------------
|
--------------
|
||||||
@@ -182,7 +207,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.
|
|
||||||
@@ -15,11 +15,11 @@ using namespace json_benchmark;
|
|||||||
struct brand {
|
struct brand {
|
||||||
double cumulative_rating;
|
double cumulative_rating;
|
||||||
uint64_t reviews_count;
|
uint64_t reviews_count;
|
||||||
simdjson_really_inline bool operator==(const brand &other) const {
|
simdjson_inline bool operator==(const brand &other) const {
|
||||||
return cumulative_rating == other.cumulative_rating &&
|
return cumulative_rating == other.cumulative_rating &&
|
||||||
reviews_count == other.reviews_count;
|
reviews_count == other.reviews_count;
|
||||||
}
|
}
|
||||||
simdjson_really_inline bool operator!=(const brand &other) const { return !(*this == other); }
|
simdjson_inline bool operator!=(const brand &other) const { return !(*this == other); }
|
||||||
};
|
};
|
||||||
|
|
||||||
simdjson_unused static std::ostream &operator<<(std::ostream &o, const brand &b) {
|
simdjson_unused static std::ostream &operator<<(std::ostream &o, const brand &b) {
|
||||||
@@ -66,7 +66,7 @@ struct runner : public file_runner<I> {
|
|||||||
template<bool threaded>
|
template<bool threaded>
|
||||||
struct simdjson_dom;
|
struct simdjson_dom;
|
||||||
|
|
||||||
template<typename I> simdjson_really_inline static void amazon_cellphones(benchmark::State &state) {
|
template<typename I> simdjson_inline static void amazon_cellphones(benchmark::State &state) {
|
||||||
run_json_benchmark<runner<I>, runner<simdjson_dom<UNTHREADED>>>(state);
|
run_json_benchmark<runner<I>, runner<simdjson_dom<UNTHREADED>>>(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -521,7 +521,7 @@ static void twitter_image_sizes(State& state) {
|
|||||||
set<tuple<uint64_t, uint64_t>> image_sizes;
|
set<tuple<uint64_t, uint64_t>> image_sizes;
|
||||||
for (dom::object tweet : doc["statuses"]) {
|
for (dom::object tweet : doc["statuses"]) {
|
||||||
dom::array media;
|
dom::array media;
|
||||||
if (not (error = tweet["entities"]["media"].get(media))) {
|
if (! (error = tweet["entities"]["media"].get(media))) {
|
||||||
for (dom::object image : media) {
|
for (dom::object image : media) {
|
||||||
for (auto size : image["sizes"].get_object()) {
|
for (auto size : image["sizes"].get_object()) {
|
||||||
image_sizes.emplace(size.value["w"], size.value["h"]);
|
image_sizes.emplace(size.value["w"], size.value["h"]);
|
||||||
@@ -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;
|
||||||
@@ -638,7 +638,7 @@ static void error_code_twitter_image_sizes(State& state) noexcept {
|
|||||||
if ((error = doc["statuses"].get(statuses))) { return; }
|
if ((error = doc["statuses"].get(statuses))) { return; }
|
||||||
for (dom::element tweet : statuses) {
|
for (dom::element tweet : statuses) {
|
||||||
dom::array images;
|
dom::array images;
|
||||||
if (not (error = tweet["entities"]["media"].get(images))) {
|
if (! (error = tweet["entities"]["media"].get(images))) {
|
||||||
for (dom::element image : images) {
|
for (dom::element image : images) {
|
||||||
dom::object sizes;
|
dom::object sizes;
|
||||||
if ((error = image["sizes"].get(sizes))) { return; }
|
if ((error = image["sizes"].get(sizes))) { return; }
|
||||||
@@ -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
|
||||||
|
|||||||
+105
-57
@@ -25,6 +25,111 @@ SIMDJSON_PUSH_DISABLE_ALL_WARNINGS
|
|||||||
#include <benchmark/benchmark.h>
|
#include <benchmark/benchmark.h>
|
||||||
|
|
||||||
SIMDJSON_POP_DISABLE_WARNINGS
|
SIMDJSON_POP_DISABLE_WARNINGS
|
||||||
|
#include "json2msgpack/simdjson_ondemand.h"
|
||||||
|
#include "json2msgpack/simdjson_dom.h"
|
||||||
|
#include "json2msgpack/yyjson.h"
|
||||||
|
#include "json2msgpack/rapidjson.h"
|
||||||
|
#if SIMDJSON_COMPETITION_ONDEMAND_SAJSON
|
||||||
|
#include "json2msgpack/sajson.h"
|
||||||
|
#endif // SIMDJSON_COMPETITION_ONDEMAND_SAJSON
|
||||||
|
#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"
|
||||||
@@ -32,61 +137,4 @@ SIMDJSON_POP_DISABLE_WARNINGS
|
|||||||
#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();
|
||||||
|
|||||||
@@ -164,7 +164,7 @@ struct feature_benchmarker {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
simdjson_really_inline void run_iterations(size_t iterations, bool stage1_only=false) {
|
simdjson_inline void run_iterations(size_t iterations, bool stage1_only=false) {
|
||||||
struct7.run_iterations(iterations, stage1_only);
|
struct7.run_iterations(iterations, stage1_only);
|
||||||
struct7_miss.run_iterations(iterations, stage1_only);
|
struct7_miss.run_iterations(iterations, stage1_only);
|
||||||
struct7_full.run_iterations(iterations, stage1_only);
|
struct7_full.run_iterations(iterations, stage1_only);
|
||||||
|
|||||||
@@ -308,7 +308,7 @@ struct benchmarker {
|
|||||||
return all_stages_without_allocation.iterations;
|
return all_stages_without_allocation.iterations;
|
||||||
}
|
}
|
||||||
|
|
||||||
simdjson_really_inline void run_iteration(bool stage1_only, bool hotbuffers=false) {
|
simdjson_inline void run_iteration(bool stage1_only, bool hotbuffers=false) {
|
||||||
// Allocate dom::parser
|
// Allocate dom::parser
|
||||||
collector.start();
|
collector.start();
|
||||||
dom::parser parser;
|
dom::parser parser;
|
||||||
@@ -384,7 +384,7 @@ struct benchmarker {
|
|||||||
loop << all_loop_count;
|
loop << all_loop_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
simdjson_really_inline void run_iterations(size_t iterations, bool stage1_only, bool hotbuffers=false) {
|
simdjson_inline void run_iterations(size_t iterations, bool stage1_only, bool hotbuffers=false) {
|
||||||
for (size_t i = 0; i<iterations; i++) {
|
for (size_t i = 0; i<iterations; i++) {
|
||||||
run_iteration(stage1_only, hotbuffers);
|
run_iteration(stage1_only, hotbuffers);
|
||||||
}
|
}
|
||||||
@@ -445,7 +445,7 @@ struct benchmarker {
|
|||||||
return 100.0 * a / b;
|
return 100.0 * a / b;
|
||||||
}
|
}
|
||||||
|
|
||||||
void print(bool tabbed_output) const {
|
void print(bool tabbed_output, bool stage1_only) const {
|
||||||
if (tabbed_output) {
|
if (tabbed_output) {
|
||||||
char* filename_copy = reinterpret_cast<char*>(malloc(strlen(filename)+1));
|
char* filename_copy = reinterpret_cast<char*>(malloc(strlen(filename)+1));
|
||||||
SIMDJSON_PUSH_DISABLE_WARNINGS
|
SIMDJSON_PUSH_DISABLE_WARNINGS
|
||||||
@@ -503,6 +503,7 @@ struct benchmarker {
|
|||||||
stats->blocks_with_16_structurals_flipped, percent(stats->blocks_with_16_structurals_flipped, stats->blocks));
|
stats->blocks_with_16_structurals_flipped, percent(stats->blocks_with_16_structurals_flipped, stats->blocks));
|
||||||
}
|
}
|
||||||
printf("\n");
|
printf("\n");
|
||||||
|
if(!stage1_only) {
|
||||||
printf("All Stages (excluding allocation)\n");
|
printf("All Stages (excluding allocation)\n");
|
||||||
print_aggregate("| " , all_stages_without_allocation.best);
|
print_aggregate("| " , all_stages_without_allocation.best);
|
||||||
// frequently, allocation is a tiny fraction of the running time so we omit it
|
// frequently, allocation is a tiny fraction of the running time so we omit it
|
||||||
@@ -510,17 +511,20 @@ struct benchmarker {
|
|||||||
printf("|- Allocation\n");
|
printf("|- Allocation\n");
|
||||||
print_aggregate("| ", allocate_stage.best);
|
print_aggregate("| ", allocate_stage.best);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
printf("|- Stage 1\n");
|
printf("|- Stage 1\n");
|
||||||
print_aggregate("| ", stage1.best);
|
print_aggregate("| ", stage1.best);
|
||||||
|
if(!stage1_only) {
|
||||||
printf("|- Stage 2\n");
|
printf("|- Stage 2\n");
|
||||||
print_aggregate("| ", stage2.best);
|
print_aggregate("| ", stage2.best);
|
||||||
|
}
|
||||||
if (collector.has_events()) {
|
if (collector.has_events()) {
|
||||||
double freq1 = (stage1.best.cycles() / stage1.best.elapsed_sec()) / 1000000000.0;
|
double freq1 = (stage1.best.cycles() / stage1.best.elapsed_sec()) / 1000000000.0;
|
||||||
double freq2 = (stage2.best.cycles() / stage2.best.elapsed_sec()) / 1000000000.0;
|
double freq2 = (stage2.best.cycles() / stage2.best.elapsed_sec()) / 1000000000.0;
|
||||||
double freqall = (all_stages_without_allocation.best.cycles() / all_stages_without_allocation.best.elapsed_sec()) / 1000000000.0;
|
double freqall = (all_stages_without_allocation.best.cycles() / all_stages_without_allocation.best.elapsed_sec()) / 1000000000.0;
|
||||||
double freqmin = min(freq1, freq2);
|
double freqmin = min(freq1, freq2);
|
||||||
double freqmax = max(freq1, freq2);
|
double freqmax = max(freq1, freq2);
|
||||||
if((freqall < 0.95 * freqmin) or (freqall > 1.05 * freqmax)) {
|
if((freqall < 0.95 * freqmin) || (freqall > 1.05 * freqmax)) {
|
||||||
printf("\nWarning: The processor frequency fluctuates in an expected way!!!\n"
|
printf("\nWarning: The processor frequency fluctuates in an expected way!!!\n"
|
||||||
"Range for stage 1 and stage 2 : [%.3f GHz, %.3f GHz], overall: %.3f GHz.\n",
|
"Range for stage 1 and stage 2 : [%.3f GHz, %.3f GHz], overall: %.3f GHz.\n",
|
||||||
freqmin, freqmax, freqall);
|
freqmin, freqmax, freqall);
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ struct runner : public file_runner<I> {
|
|||||||
|
|
||||||
struct simdjson_dom;
|
struct simdjson_dom;
|
||||||
|
|
||||||
template<typename I> simdjson_really_inline static void distinct_user_id(benchmark::State &state) {
|
template<typename I> simdjson_inline static void distinct_user_id(benchmark::State &state) {
|
||||||
run_json_benchmark<runner<I>, runner<simdjson_dom>>(state);
|
run_json_benchmark<runner<I>, runner<simdjson_dom>>(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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>(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
|
||||||
|
|||||||
@@ -9,12 +9,14 @@ namespace distinct_user_id {
|
|||||||
struct sajson {
|
struct sajson {
|
||||||
size_t ast_buffer_size{0};
|
size_t ast_buffer_size{0};
|
||||||
size_t *ast_buffer{nullptr};
|
size_t *ast_buffer{nullptr};
|
||||||
simdjson_really_inline std::string_view get_string_view(const ::sajson::value &obj, std::string_view key) {
|
~sajson() { free(ast_buffer); }
|
||||||
|
|
||||||
|
simdjson_inline std::string_view get_string_view(const ::sajson::value &obj, std::string_view key) {
|
||||||
auto val = obj.get_value_of_key({key.data(), key.length()});
|
auto val = obj.get_value_of_key({key.data(), key.length()});
|
||||||
if (val.get_type() != ::sajson::TYPE_STRING) { throw "field is not a string"; }
|
if (val.get_type() != ::sajson::TYPE_STRING) { throw "field is not a string"; }
|
||||||
return { val.as_cstring(), val.get_string_length() };
|
return { val.as_cstring(), val.get_string_length() };
|
||||||
}
|
}
|
||||||
simdjson_really_inline uint64_t get_str_uint64(const ::sajson::value &obj, std::string_view key) {
|
simdjson_inline uint64_t get_str_uint64(const ::sajson::value &obj, std::string_view key) {
|
||||||
// Since sajson only supports 53-bit numbers, and IDs in twitter.json can be > 53 bits, we read the corresponding id_str and parse that.
|
// Since sajson only supports 53-bit numbers, and IDs in twitter.json can be > 53 bits, we read the corresponding id_str and parse that.
|
||||||
auto val = obj.get_value_of_key({key.data(), key.length()});
|
auto val = obj.get_value_of_key({key.data(), key.length()});
|
||||||
if (val.get_type() != ::sajson::TYPE_STRING) { throw "field not a string"; }
|
if (val.get_type() != ::sajson::TYPE_STRING) { throw "field not a string"; }
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -218,7 +218,7 @@ int main(int argc, char *argv[]) {
|
|||||||
if (!options.verbose) { progress.erase(); }
|
if (!options.verbose) { progress.erase(); }
|
||||||
|
|
||||||
for (size_t i=0; i<options.files.size(); i++) {
|
for (size_t i=0; i<options.files.size(); i++) {
|
||||||
benchmarkers[i]->print(options.tabbed_output);
|
benchmarkers[i]->print(options.tabbed_output, options.stage1_only);
|
||||||
delete benchmarkers[i];
|
delete benchmarkers[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ using stat_t = struct stat_s;
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
simdjson_really_inline void simdjson_process_atom(stat_t &s,
|
simdjson_inline void simdjson_process_atom(stat_t &s,
|
||||||
simdjson::dom::element element) {
|
simdjson::dom::element element) {
|
||||||
if (element.is<int64_t>()) {
|
if (element.is<int64_t>()) {
|
||||||
s.integer_count++;
|
s.integer_count++;
|
||||||
|
|||||||
@@ -34,11 +34,15 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "linux-perf-events.h"
|
|
||||||
#ifdef __linux__
|
#ifdef __linux__
|
||||||
|
#include "linux-perf-events.h"
|
||||||
#include <libgen.h>
|
#include <libgen.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if __APPLE__ && __aarch64__
|
||||||
|
#include "apple/apple_arm_events.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "simdjson.h"
|
#include "simdjson.h"
|
||||||
|
|
||||||
using std::string;
|
using std::string;
|
||||||
@@ -134,7 +138,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() : 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,27 +149,48 @@ 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();
|
||||||
}
|
}
|
||||||
|
#elif __APPLE__ && __aarch64__
|
||||||
|
AppleEvents apple_events;
|
||||||
|
performance_counters diff;
|
||||||
|
event_collector() : diff(0) {
|
||||||
|
apple_events.setup_performance_counters();
|
||||||
|
}
|
||||||
|
bool has_events() {
|
||||||
|
return apple_events.setup_performance_counters();
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
event_collector(simdjson_unused bool _quiet = false) {}
|
event_collector() {}
|
||||||
bool has_events() {
|
bool has_events() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
simdjson_really_inline void start() {
|
simdjson_inline void start() {
|
||||||
#if defined(__linux)
|
#if defined(__linux)
|
||||||
linux_events.start();
|
linux_events.start();
|
||||||
|
#elif __APPLE__ && __aarch64__
|
||||||
|
if(has_events()) { diff = apple_events.get_counters(); }
|
||||||
#endif
|
#endif
|
||||||
start_clock = steady_clock::now();
|
start_clock = steady_clock::now();
|
||||||
}
|
}
|
||||||
simdjson_really_inline event_count& end() {
|
simdjson_inline event_count& end() {
|
||||||
time_point<steady_clock> end_clock = steady_clock::now();
|
time_point<steady_clock> end_clock = steady_clock::now();
|
||||||
#if defined(__linux)
|
#if defined(__linux)
|
||||||
linux_events.end(count.event_counts);
|
linux_events.end(count.event_counts);
|
||||||
|
#elif __APPLE__ && __aarch64__
|
||||||
|
if(has_events()) {
|
||||||
|
performance_counters end = apple_events.get_counters();
|
||||||
|
diff = end - diff;
|
||||||
|
}
|
||||||
|
count.event_counts[0] = diff.cycles;
|
||||||
|
count.event_counts[1] = diff.instructions;
|
||||||
|
count.event_counts[2] = diff.missed_branches;
|
||||||
|
count.event_counts[3] = 0;
|
||||||
|
count.event_counts[4] = 0;
|
||||||
#endif
|
#endif
|
||||||
count.elapsed = end_clock - start_clock;
|
count.elapsed = end_clock - start_clock;
|
||||||
return count;
|
return count;
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ struct runner : public file_runner<I> {
|
|||||||
|
|
||||||
struct simdjson_dom;
|
struct simdjson_dom;
|
||||||
|
|
||||||
template<typename I> simdjson_really_inline static void find_tweet(benchmark::State &state) {
|
template<typename I> simdjson_inline static void find_tweet(benchmark::State &state) {
|
||||||
run_json_benchmark<runner<I>, runner<simdjson_dom>>(state);
|
run_json_benchmark<runner<I>, runner<simdjson_dom>>(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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>(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
|
||||||
|
|||||||
@@ -11,12 +11,14 @@ struct sajson {
|
|||||||
|
|
||||||
size_t ast_buffer_size{0};
|
size_t ast_buffer_size{0};
|
||||||
size_t *ast_buffer{nullptr};
|
size_t *ast_buffer{nullptr};
|
||||||
simdjson_really_inline std::string_view get_string_view(const ::sajson::value &obj, std::string_view key) {
|
~sajson() { free(ast_buffer); }
|
||||||
|
|
||||||
|
simdjson_inline std::string_view get_string_view(const ::sajson::value &obj, std::string_view key) {
|
||||||
auto val = obj.get_value_of_key({key.data(), key.length()});
|
auto val = obj.get_value_of_key({key.data(), key.length()});
|
||||||
if (val.get_type() != ::sajson::TYPE_STRING) { throw "field is not a string"; }
|
if (val.get_type() != ::sajson::TYPE_STRING) { throw "field is not a string"; }
|
||||||
return { val.as_cstring(), val.get_string_length() };
|
return { val.as_cstring(), val.get_string_length() };
|
||||||
}
|
}
|
||||||
simdjson_really_inline uint64_t get_str_uint64(const ::sajson::value &obj, std::string_view key) {
|
simdjson_inline uint64_t get_str_uint64(const ::sajson::value &obj, std::string_view key) {
|
||||||
// Since sajson only supports 53-bit numbers, and IDs in twitter.json can be > 53 bits, we read the corresponding id_str and parse that.
|
// Since sajson only supports 53-bit numbers, and IDs in twitter.json can be > 53 bits, we read the corresponding id_str and parse that.
|
||||||
auto val = obj.get_value_of_key({key.data(), key.length()});
|
auto val = obj.get_value_of_key({key.data(), key.length()});
|
||||||
if (val.get_type() != ::sajson::TYPE_STRING) { throw "field not a string"; }
|
if (val.get_type() != ::sajson::TYPE_STRING) { throw "field not a string"; }
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -0,0 +1,48 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "json_benchmark/file_runner.h"
|
||||||
|
|
||||||
|
namespace json2msgpack {
|
||||||
|
|
||||||
|
using namespace json_benchmark;
|
||||||
|
|
||||||
|
template <typename I> struct runner : public file_runner<I> {
|
||||||
|
std::string_view result;
|
||||||
|
std::unique_ptr<char[]> buffer;
|
||||||
|
|
||||||
|
bool setup(benchmark::State &state) {
|
||||||
|
bool isok = this->load_json(state, TWITTER_JSON);
|
||||||
|
if (isok) {
|
||||||
|
// Let us allocate a sizeable buffer.
|
||||||
|
buffer = std::unique_ptr<char[]>(new char[this->json.size() * 4 + 1024]);
|
||||||
|
}
|
||||||
|
return isok;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool before_run(benchmark::State &state) {
|
||||||
|
if (!file_runner<I>::before_run(state)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// Clear the buffer.
|
||||||
|
::memset(buffer.get(), 0, this->json.size() * 4 + 1024);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool run(benchmark::State &) {
|
||||||
|
return this->implementation.run(this->json, buffer.get(), result);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename R>
|
||||||
|
bool diff(benchmark::State &state, runner<R> &reference) {
|
||||||
|
return diff_results(state, result.size(), reference.result.size(), diff_flags::NONE);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct simdjson_ondemand;
|
||||||
|
|
||||||
|
template <typename I>
|
||||||
|
simdjson_inline static void json2msgpack(benchmark::State &state) {
|
||||||
|
run_json_benchmark<runner<I>, runner<simdjson_ondemand>>(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace json2msgpack
|
||||||
@@ -0,0 +1,117 @@
|
|||||||
|
#pragma once
|
||||||
|
#ifdef SIMDJSON_COMPETITION_NLOHMANN_JSON
|
||||||
|
|
||||||
|
#include "json2msgpack.h"
|
||||||
|
|
||||||
|
namespace json2msgpack {
|
||||||
|
|
||||||
|
using namespace nlohmann;
|
||||||
|
|
||||||
|
struct nlohmann_json2msgpack {
|
||||||
|
inline std::string_view to_msgpack(const simdjson::padded_string &json,
|
||||||
|
uint8_t *buf);
|
||||||
|
|
||||||
|
private:
|
||||||
|
inline void write_double(const double d) noexcept;
|
||||||
|
inline void write_byte(const uint8_t b) noexcept;
|
||||||
|
inline void write_uint32(const uint32_t w) noexcept;
|
||||||
|
inline void write_string(const std::string& str);
|
||||||
|
inline void recursive_processor(basic_json<> element);
|
||||||
|
|
||||||
|
uint8_t *buff{};
|
||||||
|
};
|
||||||
|
|
||||||
|
std::string_view nlohmann_json2msgpack::to_msgpack(const simdjson::padded_string &json,
|
||||||
|
uint8_t *buf) {
|
||||||
|
buff = buf;
|
||||||
|
auto val = nlohmann::json::parse(json.data(), json.data() + json.size());
|
||||||
|
recursive_processor(val);
|
||||||
|
return std::string_view(reinterpret_cast<char *>(buf), size_t(buff - buf));
|
||||||
|
}
|
||||||
|
|
||||||
|
void nlohmann_json2msgpack::write_double(const double d) noexcept {
|
||||||
|
*buff++ = 0xcb;
|
||||||
|
::memcpy(buff, &d, sizeof(d));
|
||||||
|
buff += sizeof(d);
|
||||||
|
}
|
||||||
|
|
||||||
|
void nlohmann_json2msgpack::write_byte(const uint8_t b) noexcept {
|
||||||
|
*buff = b;
|
||||||
|
buff++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void nlohmann_json2msgpack::write_uint32(const uint32_t w) noexcept {
|
||||||
|
::memcpy(buff, &w, sizeof(w));
|
||||||
|
buff += sizeof(w);
|
||||||
|
}
|
||||||
|
|
||||||
|
void nlohmann_json2msgpack::write_string(const std::string & str) {
|
||||||
|
write_byte(0xdb);
|
||||||
|
write_uint32(uint32_t(str.size()));
|
||||||
|
::memcpy(buff, str.data(), str.size());
|
||||||
|
buff += str.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
void nlohmann_json2msgpack::recursive_processor(json element) {
|
||||||
|
switch (element.type()) {
|
||||||
|
case nlohmann::detail::value_t::array: {
|
||||||
|
uint32_t counter = 0;
|
||||||
|
write_byte(0xdd);
|
||||||
|
std::vector<json> array = element.get<std::vector<json>>();
|
||||||
|
write_uint32(uint32_t(array.size()));
|
||||||
|
for (auto child : array) {
|
||||||
|
recursive_processor(child);
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
case nlohmann::detail::value_t::object: {
|
||||||
|
write_byte(0xdf);
|
||||||
|
std::map<std::string,json> object = element.get<std::map<std::string,json>>();
|
||||||
|
write_uint32(uint32_t(object.size()));
|
||||||
|
for (auto field : object) {
|
||||||
|
write_string(field.first);
|
||||||
|
recursive_processor(field.second);
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case nlohmann::detail::value_t::number_integer:
|
||||||
|
case nlohmann::detail::value_t::number_unsigned:
|
||||||
|
case nlohmann::detail::value_t::number_float:
|
||||||
|
write_double(double(element));
|
||||||
|
break;
|
||||||
|
case nlohmann::detail::value_t::string:
|
||||||
|
write_string(std::string(element));
|
||||||
|
break;
|
||||||
|
case nlohmann::detail::value_t::boolean:
|
||||||
|
write_byte(0xc2 + bool(element));
|
||||||
|
break;
|
||||||
|
case nlohmann::detail::value_t::null:
|
||||||
|
write_byte(0xc0);
|
||||||
|
break;
|
||||||
|
case nlohmann::detail::value_t::discarded:
|
||||||
|
case nlohmann::detail::value_t::binary:
|
||||||
|
default:
|
||||||
|
printf("unexpected\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct nlohmann_json {
|
||||||
|
using StringType = std::string_view;
|
||||||
|
|
||||||
|
nlohmann_json2msgpack parser{};
|
||||||
|
|
||||||
|
bool run(simdjson::padded_string &json, char *buffer,
|
||||||
|
std::string_view &result) {
|
||||||
|
result = parser.to_msgpack(json, reinterpret_cast<uint8_t *>(buffer));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
BENCHMARK_TEMPLATE(json2msgpack, nlohmann_json)->UseManualTime();
|
||||||
|
|
||||||
|
} // namespace json2msgpack
|
||||||
|
|
||||||
|
#endif // SIMDJSON_COMPETITION_NLOHMANN_JSON
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,142 @@
|
|||||||
|
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#ifdef SIMDJSON_COMPETITION_RAPIDJSON
|
||||||
|
|
||||||
|
#include "json2msgpack.h"
|
||||||
|
|
||||||
|
namespace json2msgpack {
|
||||||
|
|
||||||
|
using namespace rapidjson;
|
||||||
|
|
||||||
|
template <int parseflag>
|
||||||
|
struct rapidjson2msgpack {
|
||||||
|
inline std::string_view to_msgpack(char *json, uint8_t *buf);
|
||||||
|
|
||||||
|
private:
|
||||||
|
inline void write_double(const double d) noexcept;
|
||||||
|
inline void write_byte(const uint8_t b) noexcept;
|
||||||
|
inline void write_uint32(const uint32_t w) noexcept;
|
||||||
|
inline void write_uint32_at(const uint32_t w, uint8_t *p) noexcept;
|
||||||
|
void write_string(const char * s, size_t length) noexcept;
|
||||||
|
inline void recursive_processor(Value &v);
|
||||||
|
|
||||||
|
uint8_t *buff{};
|
||||||
|
};
|
||||||
|
|
||||||
|
template <int parseflag>
|
||||||
|
std::string_view rapidjson2msgpack<parseflag>::to_msgpack(char *json, uint8_t *buf) {
|
||||||
|
buff = buf;
|
||||||
|
Document doc{};
|
||||||
|
if(parseflag & kParseInsituFlag) {
|
||||||
|
doc.ParseInsitu<parseflag>(json);
|
||||||
|
} else {
|
||||||
|
doc.Parse<parseflag>(json);
|
||||||
|
}
|
||||||
|
recursive_processor(doc);
|
||||||
|
return std::string_view(reinterpret_cast<char *>(buf), size_t(buff - buf));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <int parseflag>
|
||||||
|
void rapidjson2msgpack<parseflag>::write_double(const double d) noexcept {
|
||||||
|
*buff++ = 0xcb;
|
||||||
|
::memcpy(buff, &d, sizeof(d));
|
||||||
|
buff += sizeof(d);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <int parseflag>
|
||||||
|
void rapidjson2msgpack<parseflag>::write_byte(const uint8_t b) noexcept {
|
||||||
|
*buff = b;
|
||||||
|
buff++;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <int parseflag>
|
||||||
|
void rapidjson2msgpack<parseflag>::write_string(const char * c, size_t len) noexcept {
|
||||||
|
write_byte(0xdb);
|
||||||
|
write_uint32(uint32_t(len));
|
||||||
|
::memcpy(buff, c, len);
|
||||||
|
buff += len;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <int parseflag>
|
||||||
|
void rapidjson2msgpack<parseflag>::write_uint32(const uint32_t w) noexcept {
|
||||||
|
::memcpy(buff, &w, sizeof(w));
|
||||||
|
buff += sizeof(w);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <int parseflag>
|
||||||
|
void rapidjson2msgpack<parseflag>::write_uint32_at(const uint32_t w, uint8_t *p) noexcept {
|
||||||
|
::memcpy(p, &w, sizeof(w));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <int parseflag>
|
||||||
|
void rapidjson2msgpack<parseflag>::recursive_processor(Value &v) {
|
||||||
|
switch (v.GetType()) {
|
||||||
|
case kArrayType:
|
||||||
|
write_byte(0xdd);
|
||||||
|
write_uint32(v.Size());
|
||||||
|
for (Value::ValueIterator i = v.Begin(); i != v.End(); ++i) {
|
||||||
|
recursive_processor(*i);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case kObjectType:
|
||||||
|
write_byte(0xdf);
|
||||||
|
write_uint32(uint32_t(v.MemberEnd()-v.MemberBegin()));
|
||||||
|
for (Value::MemberIterator m = v.MemberBegin(); m != v.MemberEnd();
|
||||||
|
++m) {
|
||||||
|
write_string(m->name.GetString(), m->name.GetStringLength());
|
||||||
|
recursive_processor(m->value);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case kStringType:
|
||||||
|
write_string(v.GetString(), v.GetStringLength());
|
||||||
|
break;
|
||||||
|
case kNumberType:
|
||||||
|
write_double(v.GetDouble());
|
||||||
|
break;
|
||||||
|
case kFalseType:
|
||||||
|
write_byte(0xc2);
|
||||||
|
break;
|
||||||
|
case kTrueType:
|
||||||
|
write_byte(0xc3);
|
||||||
|
break;
|
||||||
|
case kNullType:
|
||||||
|
write_byte(0xc0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <int parseflag>
|
||||||
|
struct rapidjson_base {
|
||||||
|
using StringType = std::string_view;
|
||||||
|
|
||||||
|
rapidjson2msgpack<parseflag> parser{};
|
||||||
|
|
||||||
|
bool run(simdjson::padded_string &json, char *buffer,
|
||||||
|
std::string_view &result) {
|
||||||
|
result =
|
||||||
|
parser.to_msgpack(json.data(), reinterpret_cast<uint8_t *>(buffer));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
using rapidjson = rapidjson_base<kParseValidateEncodingFlag|kParseFullPrecisionFlag>;
|
||||||
|
|
||||||
|
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>;
|
||||||
|
|
||||||
|
BENCHMARK_TEMPLATE(json2msgpack, rapidjson_insitu)->UseManualTime();
|
||||||
|
#endif // SIMDJSON_COMPETITION_ONDEMAND_INSITU
|
||||||
|
} // namespace json2msgpack
|
||||||
|
|
||||||
|
#endif // SIMDJSON_COMPETITION_RAPIDJSON
|
||||||
@@ -0,0 +1,131 @@
|
|||||||
|
#pragma once
|
||||||
|
#ifdef SIMDJSON_COMPETITION_SAJSON
|
||||||
|
|
||||||
|
#include "json2msgpack.h"
|
||||||
|
|
||||||
|
namespace json2msgpack {
|
||||||
|
|
||||||
|
using namespace sajson;
|
||||||
|
|
||||||
|
|
||||||
|
struct sajson2msgpack {
|
||||||
|
inline std::string_view to_msgpack(char *json, size_t size, uint8_t *buf);
|
||||||
|
virtual ~sajson2msgpack() { free(ast_buffer); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
inline void write_double(const double d) noexcept;
|
||||||
|
inline void write_byte(const uint8_t b) noexcept;
|
||||||
|
inline void write_uint32(const uint32_t w) noexcept;
|
||||||
|
inline void write_string(const char * s, size_t length) noexcept;
|
||||||
|
inline void recursive_processor(const sajson::value &v);
|
||||||
|
|
||||||
|
uint8_t *buff{};
|
||||||
|
size_t ast_buffer_size{0};
|
||||||
|
size_t *ast_buffer{nullptr};
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
std::string_view sajson2msgpack::to_msgpack(char *json, size_t size, uint8_t *buf) {
|
||||||
|
buff = buf;
|
||||||
|
|
||||||
|
if (!ast_buffer) {
|
||||||
|
ast_buffer_size = size;
|
||||||
|
ast_buffer = (size_t *)std::malloc(ast_buffer_size * sizeof(size_t));
|
||||||
|
}
|
||||||
|
auto doc = parse(
|
||||||
|
bounded_allocation(ast_buffer, ast_buffer_size),
|
||||||
|
mutable_string_view(size, json)
|
||||||
|
);
|
||||||
|
|
||||||
|
auto root = doc.get_root();
|
||||||
|
recursive_processor(root);
|
||||||
|
return std::string_view(reinterpret_cast<char *>(buf), size_t(buff - buf));
|
||||||
|
}
|
||||||
|
|
||||||
|
void sajson2msgpack::write_string(const char * c, size_t len) noexcept {
|
||||||
|
write_byte(0xdb);
|
||||||
|
write_uint32(uint32_t(len));
|
||||||
|
::memcpy(buff, c, len);
|
||||||
|
buff += len;
|
||||||
|
}
|
||||||
|
|
||||||
|
void sajson2msgpack::write_double(const double d) noexcept {
|
||||||
|
*buff++ = 0xcb;
|
||||||
|
::memcpy(buff, &d, sizeof(d));
|
||||||
|
buff += sizeof(d);
|
||||||
|
}
|
||||||
|
|
||||||
|
void sajson2msgpack::write_byte(const uint8_t b) noexcept {
|
||||||
|
*buff = b;
|
||||||
|
buff++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void sajson2msgpack::write_uint32(const uint32_t w) noexcept {
|
||||||
|
::memcpy(buff, &w, sizeof(w));
|
||||||
|
buff += sizeof(w);
|
||||||
|
}
|
||||||
|
|
||||||
|
void sajson2msgpack::recursive_processor(const sajson::value &node) {
|
||||||
|
using namespace sajson;
|
||||||
|
switch (node.get_type()) {
|
||||||
|
case TYPE_NULL:
|
||||||
|
write_byte(0xc0);
|
||||||
|
break;
|
||||||
|
case TYPE_FALSE:
|
||||||
|
write_byte(0xc2);
|
||||||
|
break;
|
||||||
|
case TYPE_TRUE:
|
||||||
|
write_byte(0xc3);
|
||||||
|
break;
|
||||||
|
case TYPE_ARRAY: {
|
||||||
|
auto length = node.get_length();
|
||||||
|
write_byte(0xdf);
|
||||||
|
write_uint32(uint32_t(length));
|
||||||
|
for (size_t i = 0; i < length; ++i) {
|
||||||
|
recursive_processor(node.get_array_element(i));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case TYPE_OBJECT: {
|
||||||
|
auto length = node.get_length();
|
||||||
|
write_byte(0xdd);
|
||||||
|
write_uint32(uint32_t(length));
|
||||||
|
for (auto i = 0u; i < length; ++i) {
|
||||||
|
auto s = node.get_object_key(i);
|
||||||
|
write_string(s.data(), s.length());
|
||||||
|
recursive_processor(node.get_object_value(i));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case TYPE_STRING:
|
||||||
|
write_string(node.as_cstring(), node.get_string_length());
|
||||||
|
break;
|
||||||
|
case TYPE_DOUBLE:
|
||||||
|
case TYPE_INTEGER:
|
||||||
|
write_double(node.get_number_value());
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
assert(false && "unknown node type");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct sajson {
|
||||||
|
using StringType = std::string_view;
|
||||||
|
|
||||||
|
sajson2msgpack parser{};
|
||||||
|
|
||||||
|
bool run(simdjson::padded_string &json, char *buffer,
|
||||||
|
std::string_view &result) {
|
||||||
|
result =
|
||||||
|
parser.to_msgpack(json.data(), json.size(), reinterpret_cast<uint8_t *>(buffer));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
BENCHMARK_TEMPLATE(json2msgpack, sajson)->UseManualTime();
|
||||||
|
|
||||||
|
} // namespace json2msgpack
|
||||||
|
|
||||||
|
#endif // SIMDJSON_COMPETITION_SAJSON
|
||||||
@@ -0,0 +1,138 @@
|
|||||||
|
#pragma once
|
||||||
|
#if SIMDJSON_EXCEPTIONS
|
||||||
|
|
||||||
|
|
||||||
|
#include "json2msgpack.h"
|
||||||
|
|
||||||
|
namespace json2msgpack {
|
||||||
|
|
||||||
|
using namespace simdjson;
|
||||||
|
|
||||||
|
struct simdjsondom2msgpack {
|
||||||
|
/**
|
||||||
|
* @brief Converts the provided JSON into msgpack.
|
||||||
|
*
|
||||||
|
* @param json JSON input
|
||||||
|
* @param buf temporary buffer (must be large enough, with simdjson::SIMDJSON_PADDING bytes
|
||||||
|
* of padding)
|
||||||
|
* @return std::string_view msgpack output, writing to the temporary buffer
|
||||||
|
*/
|
||||||
|
inline std::string_view to_msgpack(const simdjson::padded_string &json,
|
||||||
|
uint8_t *buf);
|
||||||
|
|
||||||
|
private:
|
||||||
|
simdjson_really_inline void write_double(const double d) noexcept;
|
||||||
|
simdjson_really_inline void write_string(const std::string_view v) noexcept;
|
||||||
|
simdjson_really_inline void write_byte(const uint8_t b) noexcept;
|
||||||
|
simdjson_really_inline void write_uint32(const uint32_t w) noexcept;
|
||||||
|
simdjson_really_inline uint8_t *skip_uint32() noexcept;
|
||||||
|
simdjson_really_inline void write_uint32_at(const uint32_t w,
|
||||||
|
uint8_t *p) noexcept;
|
||||||
|
|
||||||
|
inline void recursive_processor(simdjson::dom::element element);
|
||||||
|
|
||||||
|
dom::parser parser;
|
||||||
|
uint8_t *buff{};
|
||||||
|
};
|
||||||
|
|
||||||
|
std::string_view
|
||||||
|
simdjsondom2msgpack::to_msgpack(const simdjson::padded_string &json,
|
||||||
|
uint8_t *buf) {
|
||||||
|
buff = buf;
|
||||||
|
|
||||||
|
recursive_processor(parser.parse(json));
|
||||||
|
return std::string_view(reinterpret_cast<char *>(buf), size_t(buff - buf));
|
||||||
|
}
|
||||||
|
void simdjsondom2msgpack::write_string(const std::string_view v) noexcept {
|
||||||
|
write_byte(0xdb);
|
||||||
|
write_uint32(uint32_t(v.size()));
|
||||||
|
::memcpy(buff, v.data(), v.size());
|
||||||
|
buff += v.size();
|
||||||
|
}
|
||||||
|
void simdjsondom2msgpack::write_double(const double d) noexcept {
|
||||||
|
*buff++ = 0xcb;
|
||||||
|
::memcpy(buff, &d, sizeof(d));
|
||||||
|
buff += sizeof(d);
|
||||||
|
}
|
||||||
|
|
||||||
|
void simdjsondom2msgpack::write_byte(const uint8_t b) noexcept {
|
||||||
|
*buff = b;
|
||||||
|
buff++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void simdjsondom2msgpack::write_uint32(const uint32_t w) noexcept {
|
||||||
|
::memcpy(buff, &w, sizeof(w));
|
||||||
|
buff += sizeof(w);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t *simdjsondom2msgpack::skip_uint32() noexcept {
|
||||||
|
uint8_t *ret = buff;
|
||||||
|
buff += sizeof(uint32_t);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void simdjsondom2msgpack::write_uint32_at(const uint32_t w, uint8_t *p) noexcept {
|
||||||
|
::memcpy(p, &w, sizeof(w));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void simdjsondom2msgpack::recursive_processor(simdjson::dom::element element) {
|
||||||
|
switch (element.type()) {
|
||||||
|
case dom::element_type::ARRAY: {
|
||||||
|
uint32_t counter = 0;
|
||||||
|
write_byte(0xdd);
|
||||||
|
uint8_t *location = skip_uint32();
|
||||||
|
for (auto child : dom::array(element)) {
|
||||||
|
counter++;
|
||||||
|
recursive_processor(child);
|
||||||
|
}
|
||||||
|
write_uint32_at(counter, location);}
|
||||||
|
break;
|
||||||
|
case dom::element_type::OBJECT:{
|
||||||
|
uint32_t counter = 0;
|
||||||
|
write_byte(0xdf);
|
||||||
|
uint8_t *location = skip_uint32();
|
||||||
|
for (dom::key_value_pair field : dom::object(element)) {
|
||||||
|
counter++;
|
||||||
|
write_string(field.key);
|
||||||
|
recursive_processor(field.value);
|
||||||
|
}
|
||||||
|
write_uint32_at(counter, location);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case dom::element_type::INT64:
|
||||||
|
case dom::element_type::UINT64:
|
||||||
|
case dom::element_type::DOUBLE:
|
||||||
|
write_double( double(element));
|
||||||
|
break;
|
||||||
|
case dom::element_type::STRING:
|
||||||
|
write_string(std::string_view(element));
|
||||||
|
break;
|
||||||
|
case dom::element_type::BOOL:
|
||||||
|
write_byte(0xc2 + bool(element));
|
||||||
|
break;
|
||||||
|
case dom::element_type::NULL_VALUE:
|
||||||
|
write_byte(0xc0);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct simdjson_dom {
|
||||||
|
using StringType = std::string_view;
|
||||||
|
|
||||||
|
simdjsondom2msgpack parser{};
|
||||||
|
|
||||||
|
bool run(simdjson::padded_string &json, char *buffer,
|
||||||
|
std::string_view &result) {
|
||||||
|
result = parser.to_msgpack(json, reinterpret_cast<uint8_t *>(buffer));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
BENCHMARK_TEMPLATE(json2msgpack, simdjson_dom)->UseManualTime();
|
||||||
|
|
||||||
|
} // namespace json2msgpack
|
||||||
|
|
||||||
|
#endif // SIMDJSON_EXCEPTIONS
|
||||||
@@ -0,0 +1,250 @@
|
|||||||
|
#pragma once
|
||||||
|
#if SIMDJSON_EXCEPTIONS
|
||||||
|
|
||||||
|
#include "json2msgpack.h"
|
||||||
|
|
||||||
|
namespace json2msgpack {
|
||||||
|
|
||||||
|
using namespace simdjson;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The simdjson2msgpack struct is used to quickly convert
|
||||||
|
* JSON strings to msgpack views. You must provide a pointer to
|
||||||
|
* a large memory region where the msgpack gets written. The
|
||||||
|
* buffer should be large enough to store the msgpack output (which
|
||||||
|
* can never be 3x larger than the input JSON) with an additional
|
||||||
|
* simdjson::SIMDJSON_PADDING bytes.
|
||||||
|
*
|
||||||
|
* Recommended usage:
|
||||||
|
*
|
||||||
|
* simdjson2msgpack parser{};
|
||||||
|
* simdjson::padded_string json = "[1,2]"_padded; // some JSON
|
||||||
|
* uint8_t * buffer = new uint8_t[3*json.size() + simdjson::SIMDJSON_PADDING]; // large buffer
|
||||||
|
*
|
||||||
|
* std::string_view msgpack = parser.to_msgpack(json, buffer);
|
||||||
|
*
|
||||||
|
* The result (msgpack) is a string view to a msgpack serialization of the input JSON,
|
||||||
|
* it points inside the buffer you provided.
|
||||||
|
*
|
||||||
|
* You may reuse the simdjson2msgpack instance though you should use
|
||||||
|
* one per thread.
|
||||||
|
*/
|
||||||
|
struct simdjson2msgpack {
|
||||||
|
/**
|
||||||
|
* @brief Converts the provided JSON into msgpack.
|
||||||
|
*
|
||||||
|
* @param json JSON input
|
||||||
|
* @param buf temporary buffer (must be large enough, with simdjson::SIMDJSON_PADDING bytes
|
||||||
|
* of padding)
|
||||||
|
* @return std::string_view msgpack output, writing to the temporary buffer
|
||||||
|
*/
|
||||||
|
inline std::string_view to_msgpack(const simdjson::padded_string &json,
|
||||||
|
uint8_t *buf);
|
||||||
|
|
||||||
|
private:
|
||||||
|
simdjson_inline void write_double(const double d) noexcept;
|
||||||
|
simdjson_inline void write_byte(const uint8_t b) noexcept;
|
||||||
|
simdjson_inline void write_uint32(const uint32_t w) noexcept;
|
||||||
|
simdjson_inline uint8_t *skip_uint32() noexcept;
|
||||||
|
simdjson_inline void write_uint32_at(const uint32_t w,
|
||||||
|
uint8_t *p) noexcept;
|
||||||
|
simdjson_inline void
|
||||||
|
write_raw_string(simdjson::ondemand::raw_json_string rjs);
|
||||||
|
inline void recursive_processor(simdjson::ondemand::value element);
|
||||||
|
inline void recursive_processor_ref(simdjson::ondemand::value& element);
|
||||||
|
|
||||||
|
simdjson::ondemand::parser parser;
|
||||||
|
uint8_t *buff{};
|
||||||
|
};
|
||||||
|
|
||||||
|
std::string_view
|
||||||
|
simdjson2msgpack::to_msgpack(const simdjson::padded_string &json,
|
||||||
|
uint8_t *buf) {
|
||||||
|
buff = buf;
|
||||||
|
ondemand::document doc = parser.iterate(json);
|
||||||
|
if (doc.is_scalar()) {
|
||||||
|
// we have a special case where the JSON document is a single document...
|
||||||
|
switch (doc.type()) {
|
||||||
|
case simdjson::ondemand::json_type::number:
|
||||||
|
write_double(doc.get_double());
|
||||||
|
break;
|
||||||
|
case simdjson::ondemand::json_type::string:
|
||||||
|
write_raw_string(doc.get_raw_json_string());
|
||||||
|
break;
|
||||||
|
case simdjson::ondemand::json_type::boolean:
|
||||||
|
write_byte(0xc2 + doc.get_bool());
|
||||||
|
break;
|
||||||
|
case simdjson::ondemand::json_type::null:
|
||||||
|
// We check that the value is indeed null
|
||||||
|
// otherwise: an error is thrown.
|
||||||
|
if(doc.is_null()) {
|
||||||
|
write_byte(0xc0);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case simdjson::ondemand::json_type::array:
|
||||||
|
case simdjson::ondemand::json_type::object:
|
||||||
|
default:
|
||||||
|
// impossible
|
||||||
|
SIMDJSON_UNREACHABLE();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
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);
|
||||||
|
#else
|
||||||
|
recursive_processor_ref(val);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
if (!doc.at_end()) {
|
||||||
|
throw "There are unexpectedly tokens after the end of the json in the json2msgpack sample data";
|
||||||
|
}
|
||||||
|
return std::string_view(reinterpret_cast<char *>(buf), size_t(buff - buf));
|
||||||
|
}
|
||||||
|
|
||||||
|
void simdjson2msgpack::write_double(const double d) noexcept {
|
||||||
|
*buff++ = 0xcb;
|
||||||
|
::memcpy(buff, &d, sizeof(d));
|
||||||
|
buff += sizeof(d);
|
||||||
|
}
|
||||||
|
|
||||||
|
void simdjson2msgpack::write_byte(const uint8_t b) noexcept {
|
||||||
|
*buff = b;
|
||||||
|
buff++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void simdjson2msgpack::write_uint32(const uint32_t w) noexcept {
|
||||||
|
::memcpy(buff, &w, sizeof(w));
|
||||||
|
buff += sizeof(w);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t *simdjson2msgpack::skip_uint32() noexcept {
|
||||||
|
uint8_t *ret = buff;
|
||||||
|
buff += sizeof(uint32_t);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void simdjson2msgpack::write_uint32_at(const uint32_t w, uint8_t *p) noexcept {
|
||||||
|
::memcpy(p, &w, sizeof(w));
|
||||||
|
}
|
||||||
|
|
||||||
|
void simdjson2msgpack::write_raw_string(
|
||||||
|
simdjson::ondemand::raw_json_string in) {
|
||||||
|
write_byte(0xdb);
|
||||||
|
uint8_t *location = skip_uint32();
|
||||||
|
std::string_view v = parser.unescape(in, buff);
|
||||||
|
write_uint32_at(uint32_t(v.size()), location);
|
||||||
|
}
|
||||||
|
|
||||||
|
void simdjson2msgpack::recursive_processor(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++;
|
||||||
|
recursive_processor(child.value());
|
||||||
|
}
|
||||||
|
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());
|
||||||
|
recursive_processor(field.value());
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
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;
|
||||||
|
default:
|
||||||
|
SIMDJSON_UNREACHABLE();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct simdjson_ondemand {
|
||||||
|
using StringType = std::string_view;
|
||||||
|
|
||||||
|
simdjson2msgpack parser{};
|
||||||
|
|
||||||
|
bool run(simdjson::padded_string &json, char *buffer,
|
||||||
|
std::string_view &result) {
|
||||||
|
result = parser.to_msgpack(json, reinterpret_cast<uint8_t *>(buffer));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
BENCHMARK_TEMPLATE(json2msgpack, simdjson_ondemand)->UseManualTime();
|
||||||
|
|
||||||
|
} // namespace json2msgpack
|
||||||
|
|
||||||
|
#endif // SIMDJSON_EXCEPTIONS
|
||||||
@@ -0,0 +1,123 @@
|
|||||||
|
#pragma once
|
||||||
|
#ifdef SIMDJSON_COMPETITION_YYJSON
|
||||||
|
|
||||||
|
#include "json2msgpack.h"
|
||||||
|
|
||||||
|
namespace json2msgpack {
|
||||||
|
|
||||||
|
struct yyjson2msgpack {
|
||||||
|
inline std::string_view to_msgpack(yyjson_doc *doc, uint8_t *buf);
|
||||||
|
|
||||||
|
private:
|
||||||
|
inline void write_double(const double d) noexcept;
|
||||||
|
inline void write_byte(const uint8_t b) noexcept;
|
||||||
|
inline void write_uint32(const uint32_t w) noexcept;
|
||||||
|
inline void write_string(const char *s, size_t length) noexcept;
|
||||||
|
inline void recursive_processor(yyjson_val *obj);
|
||||||
|
|
||||||
|
uint8_t *buff{};
|
||||||
|
};
|
||||||
|
|
||||||
|
std::string_view yyjson2msgpack::to_msgpack(yyjson_doc *doc, uint8_t *buf) {
|
||||||
|
buff = buf;
|
||||||
|
yyjson_val *root = yyjson_doc_get_root(doc);
|
||||||
|
recursive_processor(root);
|
||||||
|
return std::string_view(reinterpret_cast<char *>(buf), size_t(buff - buf));
|
||||||
|
}
|
||||||
|
|
||||||
|
void yyjson2msgpack::write_string(const char *c, size_t len) noexcept {
|
||||||
|
write_byte(0xdb);
|
||||||
|
write_uint32(uint32_t(len));
|
||||||
|
::memcpy(buff, c, len);
|
||||||
|
buff += len;
|
||||||
|
}
|
||||||
|
|
||||||
|
void yyjson2msgpack::write_double(const double d) noexcept {
|
||||||
|
*buff++ = 0xcb;
|
||||||
|
::memcpy(buff, &d, sizeof(d));
|
||||||
|
buff += sizeof(d);
|
||||||
|
}
|
||||||
|
|
||||||
|
void yyjson2msgpack::write_byte(const uint8_t b) noexcept {
|
||||||
|
*buff = b;
|
||||||
|
buff++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void yyjson2msgpack::write_uint32(const uint32_t w) noexcept {
|
||||||
|
::memcpy(buff, &w, sizeof(w));
|
||||||
|
buff += sizeof(w);
|
||||||
|
}
|
||||||
|
|
||||||
|
void yyjson2msgpack::recursive_processor(yyjson_val *obj) {
|
||||||
|
size_t idx, max;
|
||||||
|
yyjson_val *val;
|
||||||
|
yyjson_val *key;
|
||||||
|
switch (yyjson_get_type(obj)) {
|
||||||
|
case YYJSON_TYPE_STR:
|
||||||
|
write_string(yyjson_get_str(obj), yyjson_get_len(obj));
|
||||||
|
break;
|
||||||
|
case YYJSON_TYPE_ARR:
|
||||||
|
write_byte(0xdf);
|
||||||
|
write_uint32(uint32_t(yyjson_arr_size(obj)));
|
||||||
|
yyjson_arr_foreach(obj, idx, max, val) { recursive_processor(val); }
|
||||||
|
break;
|
||||||
|
case YYJSON_TYPE_OBJ:
|
||||||
|
write_byte(0xdd);
|
||||||
|
write_uint32(uint32_t(yyjson_obj_size(obj)));
|
||||||
|
yyjson_obj_foreach(obj, idx, max, key, val) {
|
||||||
|
write_string(yyjson_get_str(key), yyjson_get_len(key));
|
||||||
|
recursive_processor(val);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case YYJSON_TYPE_BOOL:
|
||||||
|
write_byte(0xc2 + yyjson_get_bool(obj));
|
||||||
|
break;
|
||||||
|
case YYJSON_TYPE_NULL:
|
||||||
|
write_byte(0xc0);
|
||||||
|
break;
|
||||||
|
case YYJSON_TYPE_NUM:
|
||||||
|
switch (yyjson_get_subtype(obj)) {
|
||||||
|
case YYJSON_SUBTYPE_UINT:
|
||||||
|
write_double(double(yyjson_get_uint(obj)));
|
||||||
|
break;
|
||||||
|
case YYJSON_SUBTYPE_SINT:
|
||||||
|
write_double(double(yyjson_get_sint(obj)));
|
||||||
|
break;
|
||||||
|
case YYJSON_SUBTYPE_REAL:
|
||||||
|
write_double(yyjson_get_real(obj));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
SIMDJSON_UNREACHABLE();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
SIMDJSON_UNREACHABLE();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct yyjson : yyjson2msgpack {
|
||||||
|
bool run(simdjson::padded_string &json, char *buffer,
|
||||||
|
std::string_view &result) {
|
||||||
|
yyjson_doc *doc = yyjson_read(json.data(), json.size(), 0);
|
||||||
|
result = to_msgpack(doc, reinterpret_cast<uint8_t*>(buffer));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
BENCHMARK_TEMPLATE(json2msgpack, yyjson)->UseManualTime();
|
||||||
|
|
||||||
|
#if SIMDJSON_COMPETITION_ONDEMAND_INSITU
|
||||||
|
struct yyjson_insitu : yyjson2msgpack {
|
||||||
|
bool run(simdjson::padded_string &json, char *buffer,
|
||||||
|
std::string_view &result) {
|
||||||
|
yyjson_doc *doc =
|
||||||
|
yyjson_read_opts(json.data(), json.size(), YYJSON_READ_INSITU, 0, 0);
|
||||||
|
result = to_msgpack(doc, reinterpret_cast<uint8_t*>(buffer));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
BENCHMARK_TEMPLATE(json2msgpack, yyjson_insitu)->UseManualTime();
|
||||||
|
#endif // SIMDJSON_COMPETITION_ONDEMAND_INSITU
|
||||||
|
} // namespace json2msgpack
|
||||||
|
|
||||||
|
#endif // SIMDJSON_COMPETITION_YYJSON
|
||||||
@@ -19,7 +19,7 @@ void maybe_display_implementation() {
|
|||||||
template<typename B, typename R> static void run_json_benchmark(benchmark::State &state) {
|
template<typename B, typename R> static void run_json_benchmark(benchmark::State &state) {
|
||||||
maybe_display_implementation();
|
maybe_display_implementation();
|
||||||
|
|
||||||
event_collector collector(true);
|
event_collector collector;
|
||||||
event_aggregate events;
|
event_aggregate events;
|
||||||
|
|
||||||
// Warmup and equality check (make sure the data is right!)
|
// Warmup and equality check (make sure the data is right!)
|
||||||
|
|||||||
@@ -79,7 +79,7 @@ static const simdjson::padded_string &get_built_json_array() {
|
|||||||
|
|
||||||
struct simdjson_dom;
|
struct simdjson_dom;
|
||||||
|
|
||||||
template<typename I> simdjson_really_inline static void kostya(benchmark::State &state) {
|
template<typename I> simdjson_inline static void kostya(benchmark::State &state) {
|
||||||
run_json_benchmark<runner<I>, runner<simdjson_dom>>(state);
|
run_json_benchmark<runner<I>, runner<simdjson_dom>>(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ struct nlohmann_json_sax {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
bool number_unsigned(number_unsigned_t val) override { // Need this event because coordinate value can be equal to 1
|
bool number_unsigned(number_unsigned_t val) override { // Need this event because coordinate value can be equal to 1
|
||||||
buffer[k] = val;
|
buffer[k] = double(val);
|
||||||
if (k == 2) {
|
if (k == 2) {
|
||||||
result.emplace_back(json_benchmark::point{buffer[0],buffer[1],buffer[2]});
|
result.emplace_back(json_benchmark::point{buffer[0],buffer[1],buffer[2]});
|
||||||
k = 0;
|
k = 0;
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ struct rapidjson_base {
|
|||||||
|
|
||||||
Document doc;
|
Document doc;
|
||||||
|
|
||||||
simdjson_really_inline double get_double(Value &object, std::string_view key) {
|
simdjson_inline double get_double(Value &object, std::string_view key) {
|
||||||
auto field = object.FindMember(key.data());
|
auto field = object.FindMember(key.data());
|
||||||
if (field == object.MemberEnd()) { throw "Missing double field"; }
|
if (field == object.MemberEnd()) { throw "Missing double field"; }
|
||||||
if (!field->value.IsNumber()) { throw "Field is not double"; }
|
if (!field->value.IsNumber()) { throw "Field is not double"; }
|
||||||
@@ -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>(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
|
||||||
|
|||||||
@@ -11,8 +11,9 @@ struct sajson {
|
|||||||
|
|
||||||
size_t ast_buffer_size{0};
|
size_t ast_buffer_size{0};
|
||||||
size_t *ast_buffer{nullptr};
|
size_t *ast_buffer{nullptr};
|
||||||
|
~sajson() { free(ast_buffer); }
|
||||||
|
|
||||||
simdjson_really_inline double get_double(const ::sajson::value &obj, std::string_view key) {
|
simdjson_inline double get_double(const ::sajson::value &obj, std::string_view key) {
|
||||||
using namespace sajson;
|
using namespace sajson;
|
||||||
|
|
||||||
auto val = obj.get_value_of_key({key.data(), key.length()});
|
auto val = obj.get_value_of_key({key.data(), key.length()});
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ namespace kostya {
|
|||||||
struct yyjson_base {
|
struct yyjson_base {
|
||||||
static constexpr diff_flags DiffFlags = diff_flags::NONE;
|
static constexpr diff_flags DiffFlags = diff_flags::NONE;
|
||||||
|
|
||||||
simdjson_really_inline double get_double(yyjson_val *obj, std::string_view key) {
|
simdjson_inline double get_double(yyjson_val *obj, std::string_view key) {
|
||||||
yyjson_val *val = yyjson_obj_getn(obj, key.data(), key.length());
|
yyjson_val *val = yyjson_obj_getn(obj, key.data(), key.length());
|
||||||
if (!val) { throw "missing point field!"; }
|
if (!val) { throw "missing point field!"; }
|
||||||
if (yyjson_get_type(val) != YYJSON_TYPE_NUM) { throw "Number is not a type!"; }
|
if (yyjson_get_type(val) != YYJSON_TYPE_NUM) { throw "Number is not a type!"; }
|
||||||
@@ -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
|
||||||
|
|||||||
@@ -16,11 +16,11 @@ using namespace json_benchmark;
|
|||||||
struct brand {
|
struct brand {
|
||||||
double cumulative_rating;
|
double cumulative_rating;
|
||||||
uint64_t reviews_count;
|
uint64_t reviews_count;
|
||||||
simdjson_really_inline bool operator==(const brand &other) const {
|
simdjson_inline bool operator==(const brand &other) const {
|
||||||
return cumulative_rating == other.cumulative_rating &&
|
return cumulative_rating == other.cumulative_rating &&
|
||||||
reviews_count == other.reviews_count;
|
reviews_count == other.reviews_count;
|
||||||
}
|
}
|
||||||
simdjson_really_inline bool operator!=(const brand &other) const { return !(*this == other); }
|
simdjson_inline bool operator!=(const brand &other) const { return !(*this == other); }
|
||||||
};
|
};
|
||||||
|
|
||||||
simdjson_unused static std::ostream &operator<<(std::ostream &o, const brand &b) {
|
simdjson_unused static std::ostream &operator<<(std::ostream &o, const brand &b) {
|
||||||
@@ -87,7 +87,7 @@ static const simdjson::padded_string &get_built_json() {
|
|||||||
template<bool threaded>
|
template<bool threaded>
|
||||||
struct simdjson_dom;
|
struct simdjson_dom;
|
||||||
|
|
||||||
template<typename I> simdjson_really_inline static void large_amazon_cellphones(benchmark::State &state) {
|
template<typename I> simdjson_inline static void large_amazon_cellphones(benchmark::State &state) {
|
||||||
run_json_benchmark<runner<I>, runner<simdjson_dom<UNTHREADED>>>(state);
|
run_json_benchmark<runner<I>, runner<simdjson_dom<UNTHREADED>>>(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ struct nlohmann_json_sax {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
bool number_unsigned(number_unsigned_t val) override {
|
bool number_unsigned(number_unsigned_t val) override {
|
||||||
buffer[k] = val;
|
buffer[k] = double(val);
|
||||||
if (k == 2) {
|
if (k == 2) {
|
||||||
result.emplace_back(json_benchmark::point{buffer[0],buffer[1],buffer[2]});
|
result.emplace_back(json_benchmark::point{buffer[0],buffer[1],buffer[2]});
|
||||||
k = 0;
|
k = 0;
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ struct rapidjson_base {
|
|||||||
|
|
||||||
Document doc;
|
Document doc;
|
||||||
|
|
||||||
simdjson_really_inline double get_double(Value &object, std::string_view key) {
|
simdjson_inline double get_double(Value &object, std::string_view key) {
|
||||||
auto field = object.FindMember(key.data());
|
auto field = object.FindMember(key.data());
|
||||||
if (field == object.MemberEnd()) { throw "Missing double field"; }
|
if (field == object.MemberEnd()) { throw "Missing double field"; }
|
||||||
if (!field->value.IsNumber()) { throw "Field is not double"; }
|
if (!field->value.IsNumber()) { throw "Field is not double"; }
|
||||||
@@ -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>(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
|
||||||
|
|
||||||
|
|||||||
@@ -11,8 +11,9 @@ struct sajson {
|
|||||||
|
|
||||||
size_t ast_buffer_size{0};
|
size_t ast_buffer_size{0};
|
||||||
size_t *ast_buffer{nullptr};
|
size_t *ast_buffer{nullptr};
|
||||||
|
~sajson() { free(ast_buffer); }
|
||||||
|
|
||||||
simdjson_really_inline double get_double(const ::sajson::value &obj, std::string_view key) {
|
simdjson_inline double get_double(const ::sajson::value &obj, std::string_view key) {
|
||||||
using namespace sajson;
|
using namespace sajson;
|
||||||
|
|
||||||
auto val = obj.get_value_of_key({key.data(), key.length()});
|
auto val = obj.get_value_of_key({key.data(), key.length()});
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ namespace large_random {
|
|||||||
struct yyjson_base {
|
struct yyjson_base {
|
||||||
static constexpr diff_flags DiffFlags = diff_flags::NONE;
|
static constexpr diff_flags DiffFlags = diff_flags::NONE;
|
||||||
|
|
||||||
simdjson_really_inline double get_double(yyjson_val *obj, std::string_view key) {
|
simdjson_inline double get_double(yyjson_val *obj, std::string_view key) {
|
||||||
yyjson_val *val = yyjson_obj_getn(obj, key.data(), key.length());
|
yyjson_val *val = yyjson_obj_getn(obj, key.data(), key.length());
|
||||||
if (!val) { throw "missing point field!"; }
|
if (!val) { throw "missing point field!"; }
|
||||||
if (yyjson_get_type(val) != YYJSON_TYPE_NUM) { throw "Number is not a type!"; }
|
if (yyjson_get_type(val) != YYJSON_TYPE_NUM) { throw "Number is not a type!"; }
|
||||||
@@ -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
|
||||||
|
|||||||
@@ -10,28 +10,28 @@ using namespace simdjson;
|
|||||||
|
|
||||||
class Iter {
|
class Iter {
|
||||||
public:
|
public:
|
||||||
simdjson_really_inline bool Run(const padded_string &json);
|
simdjson_inline bool Run(const padded_string &json);
|
||||||
|
|
||||||
simdjson_really_inline const std::vector<my_point> &Result() { return container; }
|
simdjson_inline const std::vector<my_point> &Result() { return container; }
|
||||||
simdjson_really_inline size_t ItemCount() { return container.size(); }
|
simdjson_inline size_t ItemCount() { return container.size(); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ondemand::parser parser{};
|
ondemand::parser parser{};
|
||||||
std::vector<my_point> container{};
|
std::vector<my_point> container{};
|
||||||
|
|
||||||
simdjson_really_inline double first_double(ondemand::json_iterator &iter) {
|
simdjson_inline double first_double(ondemand::json_iterator &iter) {
|
||||||
if (iter.start_object().error() || iter.field_key().error() || iter.field_value()) { throw "Invalid field"; }
|
if (iter.start_object().error() || iter.field_key().error() || iter.field_value()) { throw "Invalid field"; }
|
||||||
return iter.consume_double();
|
return iter.consume_double();
|
||||||
}
|
}
|
||||||
|
|
||||||
simdjson_really_inline double next_double(ondemand::json_iterator &iter) {
|
simdjson_inline double next_double(ondemand::json_iterator &iter) {
|
||||||
if (!iter.has_next_field() || iter.field_key().error() || iter.field_value()) { throw "Invalid field"; }
|
if (!iter.has_next_field() || iter.field_key().error() || iter.field_value()) { throw "Invalid field"; }
|
||||||
return iter.consume_double();
|
return iter.consume_double();
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
simdjson_really_inline bool Iter::Run(const padded_string &json) {
|
simdjson_inline bool Iter::Run(const padded_string &json) {
|
||||||
container.clear();
|
container.clear();
|
||||||
|
|
||||||
auto iter = parser.iterate_raw(json).value();
|
auto iter = parser.iterate_raw(json).value();
|
||||||
|
|||||||
@@ -10,16 +10,16 @@ using namespace simdjson;
|
|||||||
|
|
||||||
class OnDemand {
|
class OnDemand {
|
||||||
public:
|
public:
|
||||||
simdjson_really_inline bool Run(const padded_string &json);
|
simdjson_inline bool Run(const padded_string &json);
|
||||||
simdjson_really_inline const std::vector<my_point> &Result() { return container; }
|
simdjson_inline const std::vector<my_point> &Result() { return container; }
|
||||||
simdjson_really_inline size_t ItemCount() { return container.size(); }
|
simdjson_inline size_t ItemCount() { return container.size(); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ondemand::parser parser{};
|
ondemand::parser parser{};
|
||||||
std::vector<my_point> container{};
|
std::vector<my_point> container{};
|
||||||
};
|
};
|
||||||
|
|
||||||
simdjson_really_inline bool OnDemand::Run(const padded_string &json) {
|
simdjson_inline bool OnDemand::Run(const padded_string &json) {
|
||||||
container.clear();
|
container.clear();
|
||||||
|
|
||||||
auto doc = parser.iterate(json);
|
auto doc = parser.iterate(json);
|
||||||
|
|||||||
+16
-16
@@ -11,13 +11,13 @@ using namespace simdjson::builtin::stage2;
|
|||||||
|
|
||||||
class Sax {
|
class Sax {
|
||||||
public:
|
public:
|
||||||
simdjson_really_inline bool Run(const padded_string &json) noexcept;
|
simdjson_inline bool Run(const padded_string &json) noexcept;
|
||||||
|
|
||||||
simdjson_really_inline const std::vector<my_point> &Result() { return container; }
|
simdjson_inline const std::vector<my_point> &Result() { return container; }
|
||||||
simdjson_really_inline size_t ItemCount() { return container.size(); }
|
simdjson_inline size_t ItemCount() { return container.size(); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
simdjson_really_inline error_code RunNoExcept(const padded_string &json) noexcept;
|
simdjson_inline error_code RunNoExcept(const padded_string &json) noexcept;
|
||||||
error_code Allocate(size_t new_capacity);
|
error_code Allocate(size_t new_capacity);
|
||||||
std::unique_ptr<uint8_t[]> string_buf{};
|
std::unique_ptr<uint8_t[]> string_buf{};
|
||||||
size_t capacity{};
|
size_t capacity{};
|
||||||
@@ -34,21 +34,21 @@ public:
|
|||||||
|
|
||||||
explicit sax_point_reader_visitor(std::vector<my_point> &_points) : points(_points) {}
|
explicit sax_point_reader_visitor(std::vector<my_point> &_points) : points(_points) {}
|
||||||
|
|
||||||
simdjson_really_inline error_code visit_object_start(json_iterator &) {
|
simdjson_inline error_code visit_object_start(json_iterator &) {
|
||||||
idx = 0;
|
idx = 0;
|
||||||
return SUCCESS;
|
return SUCCESS;
|
||||||
}
|
}
|
||||||
simdjson_really_inline error_code visit_primitive(json_iterator &, const uint8_t *value) {
|
simdjson_inline error_code visit_primitive(json_iterator &, const uint8_t *value) {
|
||||||
if(idx == GOT_SOMETHING_ELSE) { return simdjson::SUCCESS; }
|
if(idx == GOT_SOMETHING_ELSE) { return simdjson::SUCCESS; }
|
||||||
return numberparsing::parse_double(value).get(buffer[idx]);
|
return numberparsing::parse_double(value).get(buffer[idx]);
|
||||||
}
|
}
|
||||||
simdjson_really_inline error_code visit_object_end(json_iterator &) {
|
simdjson_inline error_code visit_object_end(json_iterator &) {
|
||||||
points.emplace_back(my_point{buffer[0], buffer[1], buffer[2]});
|
points.emplace_back(my_point{buffer[0], buffer[1], buffer[2]});
|
||||||
return SUCCESS;
|
return SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
simdjson_really_inline error_code visit_document_start(json_iterator &) { return SUCCESS; }
|
simdjson_inline error_code visit_document_start(json_iterator &) { return SUCCESS; }
|
||||||
simdjson_really_inline error_code visit_key(json_iterator &, const uint8_t * key) {
|
simdjson_inline error_code visit_key(json_iterator &, const uint8_t * key) {
|
||||||
switch(key[1]) {
|
switch(key[1]) {
|
||||||
// Technically, we should check the other characters
|
// Technically, we should check the other characters
|
||||||
// in the key, but we are cheating to go as fast
|
// in the key, but we are cheating to go as fast
|
||||||
@@ -67,13 +67,13 @@ public:
|
|||||||
}
|
}
|
||||||
return SUCCESS;
|
return SUCCESS;
|
||||||
}
|
}
|
||||||
simdjson_really_inline error_code visit_array_start(json_iterator &) { return SUCCESS; }
|
simdjson_inline error_code visit_array_start(json_iterator &) { return SUCCESS; }
|
||||||
simdjson_really_inline error_code visit_array_end(json_iterator &) { return SUCCESS; }
|
simdjson_inline error_code visit_array_end(json_iterator &) { return SUCCESS; }
|
||||||
simdjson_really_inline error_code visit_document_end(json_iterator &) { return SUCCESS; }
|
simdjson_inline error_code visit_document_end(json_iterator &) { return SUCCESS; }
|
||||||
simdjson_really_inline error_code visit_empty_array(json_iterator &) { return SUCCESS; }
|
simdjson_inline error_code visit_empty_array(json_iterator &) { return SUCCESS; }
|
||||||
simdjson_really_inline error_code visit_empty_object(json_iterator &) { return SUCCESS; }
|
simdjson_inline error_code visit_empty_object(json_iterator &) { return SUCCESS; }
|
||||||
simdjson_really_inline error_code visit_root_primitive(json_iterator &, const uint8_t *) { return SUCCESS; }
|
simdjson_inline error_code visit_root_primitive(json_iterator &, const uint8_t *) { return SUCCESS; }
|
||||||
simdjson_really_inline error_code increment_count(json_iterator &) { return SUCCESS; }
|
simdjson_inline error_code increment_count(json_iterator &) { return SUCCESS; }
|
||||||
};
|
};
|
||||||
|
|
||||||
// NOTE: this assumes the dom_parser is already allocated
|
// NOTE: this assumes the dom_parser is already allocated
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ namespace partial_tweets {
|
|||||||
struct nlohmann_json {
|
struct nlohmann_json {
|
||||||
using StringType=std::string;
|
using StringType=std::string;
|
||||||
|
|
||||||
simdjson_really_inline uint64_t nullable_int(nlohmann::json value) {
|
simdjson_inline uint64_t nullable_int(nlohmann::json value) {
|
||||||
if (value.is_null()) { return 0; }
|
if (value.is_null()) { return 0; }
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,27 +17,27 @@ public:
|
|||||||
displayed_implementation = true;
|
displayed_implementation = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
simdjson_really_inline bool Run(const padded_string &json);
|
simdjson_inline bool Run(const padded_string &json);
|
||||||
simdjson_really_inline const std::vector<tweet> &Result() { return tweets; }
|
simdjson_inline const std::vector<tweet> &Result() { return tweets; }
|
||||||
simdjson_really_inline size_t ItemCount() { return tweets.size(); }
|
simdjson_inline size_t ItemCount() { return tweets.size(); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ondemand::parser parser{};
|
ondemand::parser parser{};
|
||||||
std::vector<tweet> tweets{};
|
std::vector<tweet> tweets{};
|
||||||
|
|
||||||
simdjson_really_inline uint64_t nullable_int(ondemand::value value) {
|
simdjson_inline uint64_t nullable_int(ondemand::value value) {
|
||||||
if (value.is_null()) { return 0; }
|
if (value.is_null()) { return 0; }
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
simdjson_really_inline twitter_user read_user(ondemand::object user) {
|
simdjson_inline twitter_user read_user(ondemand::object user) {
|
||||||
return { user.find_field("id"), user.find_field("screen_name") };
|
return { user.find_field("id"), user.find_field("screen_name") };
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool displayed_implementation = false;
|
static inline bool displayed_implementation = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
simdjson_really_inline bool OnDemand::Run(const padded_string &json) {
|
simdjson_inline bool OnDemand::Run(const padded_string &json) {
|
||||||
tweets.clear();
|
tweets.clear();
|
||||||
|
|
||||||
// Walk the document, parsing the tweets as we go
|
// Walk the document, parsing the tweets as we go
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ struct runner : public file_runner<I> {
|
|||||||
|
|
||||||
struct simdjson_dom;
|
struct simdjson_dom;
|
||||||
|
|
||||||
template<typename I> simdjson_really_inline static void partial_tweets(benchmark::State &state) {
|
template<typename I> simdjson_inline static void partial_tweets(benchmark::State &state) {
|
||||||
run_json_benchmark<runner<I>, runner<simdjson_dom>>(state);
|
run_json_benchmark<runner<I>, runner<simdjson_dom>>(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,27 +13,27 @@ struct rapidjson_base {
|
|||||||
|
|
||||||
Document doc{};
|
Document doc{};
|
||||||
|
|
||||||
simdjson_really_inline std::string_view get_string_view(Value &object, std::string_view key) {
|
simdjson_inline std::string_view get_string_view(Value &object, std::string_view key) {
|
||||||
// TODO use version that supports passing string length?
|
// TODO use version that supports passing string length?
|
||||||
auto field = object.FindMember(key.data());
|
auto field = object.FindMember(key.data());
|
||||||
if (field == object.MemberEnd()) { throw "Missing object field"; }
|
if (field == object.MemberEnd()) { throw "Missing object field"; }
|
||||||
if (!field->value.IsString()) { throw "Field is not a string"; }
|
if (!field->value.IsString()) { throw "Field is not a string"; }
|
||||||
return { field->value.GetString(), field->value.GetStringLength() };
|
return { field->value.GetString(), field->value.GetStringLength() };
|
||||||
}
|
}
|
||||||
simdjson_really_inline uint64_t get_uint64(Value &object, std::string_view key) {
|
simdjson_inline uint64_t get_uint64(Value &object, std::string_view key) {
|
||||||
auto field = object.FindMember(key.data());
|
auto field = object.FindMember(key.data());
|
||||||
if (field == object.MemberEnd()) { throw "Missing object field"; }
|
if (field == object.MemberEnd()) { throw "Missing object field"; }
|
||||||
if (!field->value.IsUint64()) { throw "Field is not uint64"; }
|
if (!field->value.IsUint64()) { throw "Field is not uint64"; }
|
||||||
return field->value.GetUint64();
|
return field->value.GetUint64();
|
||||||
}
|
}
|
||||||
simdjson_really_inline uint64_t get_nullable_uint64(Value &object, std::string_view key) {
|
simdjson_inline uint64_t get_nullable_uint64(Value &object, std::string_view key) {
|
||||||
auto field = object.FindMember(key.data());
|
auto field = object.FindMember(key.data());
|
||||||
if (field == object.MemberEnd()) { throw "Missing nullable uint64 field"; }
|
if (field == object.MemberEnd()) { throw "Missing nullable uint64 field"; }
|
||||||
if (field->value.IsNull()) { return 0; }
|
if (field->value.IsNull()) { return 0; }
|
||||||
if (!field->value.IsUint64()) { throw "Field is not nullable uint64"; }
|
if (!field->value.IsUint64()) { throw "Field is not nullable uint64"; }
|
||||||
return field->value.GetUint64();
|
return field->value.GetUint64();
|
||||||
}
|
}
|
||||||
simdjson_really_inline partial_tweets::twitter_user<std::string_view> get_user(Value &object, std::string_view key) {
|
simdjson_inline partial_tweets::twitter_user<std::string_view> get_user(Value &object, std::string_view key) {
|
||||||
auto field = object.FindMember(key.data());
|
auto field = object.FindMember(key.data());
|
||||||
if (field == object.MemberEnd()) { throw "Missing user field"; }
|
if (field == object.MemberEnd()) { throw "Missing user field"; }
|
||||||
if (!field->value.IsObject()) { throw "User field is not an object"; }
|
if (!field->value.IsObject()) { throw "User field is not an object"; }
|
||||||
@@ -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>(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
|
||||||
|
|||||||
@@ -11,12 +11,14 @@ struct sajson {
|
|||||||
|
|
||||||
size_t ast_buffer_size{0};
|
size_t ast_buffer_size{0};
|
||||||
size_t *ast_buffer{nullptr};
|
size_t *ast_buffer{nullptr};
|
||||||
simdjson_really_inline std::string_view get_string_view(const ::sajson::value &obj, std::string_view key) {
|
~sajson() { free(ast_buffer); }
|
||||||
|
|
||||||
|
simdjson_inline std::string_view get_string_view(const ::sajson::value &obj, std::string_view key) {
|
||||||
auto val = obj.get_value_of_key({key.data(), key.length()});
|
auto val = obj.get_value_of_key({key.data(), key.length()});
|
||||||
if (val.get_type() != ::sajson::TYPE_STRING) { throw "field is not a string"; }
|
if (val.get_type() != ::sajson::TYPE_STRING) { throw "field is not a string"; }
|
||||||
return { val.as_cstring(), val.get_string_length() };
|
return { val.as_cstring(), val.get_string_length() };
|
||||||
}
|
}
|
||||||
simdjson_really_inline uint64_t get_uint52(const ::sajson::value &obj, std::string_view key) {
|
simdjson_inline uint64_t get_uint52(const ::sajson::value &obj, std::string_view key) {
|
||||||
auto val = obj.get_value_of_key({key.data(), key.length()});
|
auto val = obj.get_value_of_key({key.data(), key.length()});
|
||||||
switch (val.get_type()) {
|
switch (val.get_type()) {
|
||||||
case ::sajson::TYPE_INTEGER: {
|
case ::sajson::TYPE_INTEGER: {
|
||||||
@@ -28,7 +30,7 @@ struct sajson {
|
|||||||
throw "field not integer";
|
throw "field not integer";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
simdjson_really_inline uint64_t get_str_uint64(const ::sajson::value &obj, std::string_view key) {
|
simdjson_inline uint64_t get_str_uint64(const ::sajson::value &obj, std::string_view key) {
|
||||||
// Since sajson only supports 53-bit numbers, and IDs in twitter.json can be > 53 bits, we read the corresponding id_str and parse that.
|
// Since sajson only supports 53-bit numbers, and IDs in twitter.json can be > 53 bits, we read the corresponding id_str and parse that.
|
||||||
auto val = obj.get_value_of_key({key.data(), key.length()});
|
auto val = obj.get_value_of_key({key.data(), key.length()});
|
||||||
if (val.get_type() != ::sajson::TYPE_STRING) { throw "field not a string"; }
|
if (val.get_type() != ::sajson::TYPE_STRING) { throw "field not a string"; }
|
||||||
@@ -38,7 +40,7 @@ struct sajson {
|
|||||||
if (endptr != &str[val.get_string_length()]) { throw "field is a string, but not an integer string"; }
|
if (endptr != &str[val.get_string_length()]) { throw "field is a string, but not an integer string"; }
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
simdjson_really_inline uint64_t get_nullable_str_uint64(const ::sajson::value &obj, std::string_view key) {
|
simdjson_inline uint64_t get_nullable_str_uint64(const ::sajson::value &obj, std::string_view key) {
|
||||||
auto val = obj.get_value_of_key({key.data(), key.length()});
|
auto val = obj.get_value_of_key({key.data(), key.length()});
|
||||||
if (val.get_type() == ::sajson::TYPE_NULL) { return 0; }
|
if (val.get_type() == ::sajson::TYPE_NULL) { return 0; }
|
||||||
if (val.get_type() != ::sajson::TYPE_STRING) { throw "field not a string"; }
|
if (val.get_type() != ::sajson::TYPE_STRING) { throw "field not a string"; }
|
||||||
@@ -48,7 +50,7 @@ struct sajson {
|
|||||||
if (endptr != &str[val.get_string_length()]) { throw "field is a string, but not an integer string"; }
|
if (endptr != &str[val.get_string_length()]) { throw "field is a string, but not an integer string"; }
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
simdjson_really_inline partial_tweets::twitter_user<std::string_view> get_user(const ::sajson::value &obj, std::string_view key) {
|
simdjson_inline partial_tweets::twitter_user<std::string_view> get_user(const ::sajson::value &obj, std::string_view key) {
|
||||||
auto user = obj.get_value_of_key({key.data(), key.length()});
|
auto user = obj.get_value_of_key({key.data(), key.length()});
|
||||||
if (user.get_type() != ::sajson::TYPE_OBJECT) { throw "user is not an object"; }
|
if (user.get_type() != ::sajson::TYPE_OBJECT) { throw "user is not an object"; }
|
||||||
return { get_str_uint64(user, "id_str"), get_string_view(user, "screen_name") };
|
return { get_str_uint64(user, "id_str"), get_string_view(user, "screen_name") };
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ struct simdjson_dom {
|
|||||||
|
|
||||||
dom::parser parser{};
|
dom::parser parser{};
|
||||||
|
|
||||||
simdjson_really_inline uint64_t nullable_int(dom::element element) {
|
simdjson_inline uint64_t nullable_int(dom::element element) {
|
||||||
if (element.is_null()) { return 0; }
|
if (element.is_null()) { return 0; }
|
||||||
return element;
|
return element;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,12 +13,12 @@ struct simdjson_ondemand {
|
|||||||
|
|
||||||
ondemand::parser parser{};
|
ondemand::parser parser{};
|
||||||
|
|
||||||
simdjson_really_inline uint64_t nullable_int(ondemand::value value) {
|
simdjson_inline uint64_t nullable_int(ondemand::value value) {
|
||||||
if (value.is_null()) { return 0; }
|
if (value.is_null()) { return 0; }
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
simdjson_really_inline twitter_user<std::string_view> read_user(ondemand::object user) {
|
simdjson_inline twitter_user<std::string_view> read_user(ondemand::object user) {
|
||||||
return { user.find_field("id"), user.find_field("screen_name") };
|
return { user.find_field("id"), user.find_field("screen_name") };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ struct tweet {
|
|||||||
uint64_t retweet_count{};
|
uint64_t retweet_count{};
|
||||||
uint64_t favorite_count{};
|
uint64_t favorite_count{};
|
||||||
template<typename OtherStringType>
|
template<typename OtherStringType>
|
||||||
simdjson_really_inline bool operator==(const tweet<OtherStringType> &other) const {
|
simdjson_inline bool operator==(const tweet<OtherStringType> &other) const {
|
||||||
return created_at == other.created_at &&
|
return created_at == other.created_at &&
|
||||||
id == other.id &&
|
id == other.id &&
|
||||||
result == other.result &&
|
result == other.result &&
|
||||||
@@ -42,7 +42,7 @@ struct tweet {
|
|||||||
favorite_count == other.favorite_count;
|
favorite_count == other.favorite_count;
|
||||||
}
|
}
|
||||||
template<typename OtherStringType>
|
template<typename OtherStringType>
|
||||||
simdjson_really_inline bool operator!=(const tweet<OtherStringType> &other) const { return !(*this == other); }
|
simdjson_inline bool operator!=(const tweet<OtherStringType> &other) const { return !(*this == other); }
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename StringType>
|
template<typename StringType>
|
||||||
|
|||||||
@@ -9,24 +9,24 @@ namespace partial_tweets {
|
|||||||
struct yyjson_base {
|
struct yyjson_base {
|
||||||
using StringType=std::string_view;
|
using StringType=std::string_view;
|
||||||
|
|
||||||
simdjson_really_inline std::string_view get_string_view(yyjson_val *obj, std::string_view key) {
|
simdjson_inline std::string_view get_string_view(yyjson_val *obj, std::string_view key) {
|
||||||
auto val = yyjson_obj_getn(obj, key.data(), key.length());
|
auto val = yyjson_obj_getn(obj, key.data(), key.length());
|
||||||
if (!yyjson_is_str(val)) { throw "field is not uint64 or null!"; }
|
if (!yyjson_is_str(val)) { throw "field is not uint64 or null!"; }
|
||||||
return { yyjson_get_str(val), yyjson_get_len(val) };
|
return { yyjson_get_str(val), yyjson_get_len(val) };
|
||||||
}
|
}
|
||||||
simdjson_really_inline uint64_t get_uint64(yyjson_val *obj, std::string_view key) {
|
simdjson_inline uint64_t get_uint64(yyjson_val *obj, std::string_view key) {
|
||||||
auto val = yyjson_obj_getn(obj, key.data(), key.length());
|
auto val = yyjson_obj_getn(obj, key.data(), key.length());
|
||||||
if (!yyjson_is_uint(val)) { throw "field is not uint64 or null!"; }
|
if (!yyjson_is_uint(val)) { throw "field is not uint64 or null!"; }
|
||||||
return yyjson_get_uint(val);
|
return yyjson_get_uint(val);
|
||||||
}
|
}
|
||||||
simdjson_really_inline uint64_t get_nullable_uint64(yyjson_val *obj, std::string_view key) {
|
simdjson_inline uint64_t get_nullable_uint64(yyjson_val *obj, std::string_view key) {
|
||||||
auto val = yyjson_obj_getn(obj, key.data(), key.length());
|
auto val = yyjson_obj_getn(obj, key.data(), key.length());
|
||||||
if (!yyjson_is_uint(val)) { }
|
if (!yyjson_is_uint(val)) { }
|
||||||
auto type = yyjson_get_type(val);
|
auto type = yyjson_get_type(val);
|
||||||
if (type != YYJSON_TYPE_NUM && type != YYJSON_TYPE_NULL ) { throw "field is not uint64 or null!"; }
|
if (type != YYJSON_TYPE_NUM && type != YYJSON_TYPE_NULL ) { throw "field is not uint64 or null!"; }
|
||||||
return yyjson_get_uint(val);
|
return yyjson_get_uint(val);
|
||||||
}
|
}
|
||||||
simdjson_really_inline partial_tweets::twitter_user<std::string_view> get_user(yyjson_val *obj, std::string_view key) {
|
simdjson_inline partial_tweets::twitter_user<std::string_view> get_user(yyjson_val *obj, std::string_view key) {
|
||||||
auto user = yyjson_obj_getn(obj, key.data(), key.length());
|
auto user = yyjson_obj_getn(obj, key.data(), key.length());
|
||||||
if (!yyjson_is_obj(user)) { throw "missing twitter user field!"; }
|
if (!yyjson_is_obj(user)) { throw "missing twitter user field!"; }
|
||||||
return { get_uint64(user, "id"), get_string_view(user, "screen_name") };
|
return { get_uint64(user, "id"), get_string_view(user, "screen_name") };
|
||||||
@@ -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
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ struct nlohmann_json_sax {
|
|||||||
}
|
}
|
||||||
bool number_unsigned(number_unsigned_t val) override {
|
bool number_unsigned(number_unsigned_t val) override {
|
||||||
if (values & key_rt && !(values & found_rt)) { // retweet_count
|
if (values & key_rt && !(values & found_rt)) { // retweet_count
|
||||||
rt = val;
|
rt = int(val);
|
||||||
values &= ~(key_rt);
|
values &= ~(key_rt);
|
||||||
values |= (found_rt);
|
values |= (found_rt);
|
||||||
if (rt <= max_rt && rt >= result.retweet_count) { // Check if current tweet has more retweet than previous top tweet
|
if (rt <= max_rt && rt >= result.retweet_count) { // Check if current tweet has more retweet than previous top tweet
|
||||||
|
|||||||
@@ -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>(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
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ struct sajson {
|
|||||||
|
|
||||||
size_t ast_buffer_size{0};
|
size_t ast_buffer_size{0};
|
||||||
size_t *ast_buffer{nullptr};
|
size_t *ast_buffer{nullptr};
|
||||||
|
~sajson() { free(ast_buffer); }
|
||||||
|
|
||||||
bool run(simdjson::padded_string &json, int32_t max_retweet_count, top_tweet_result<StringType> &result) {
|
bool run(simdjson::padded_string &json, int32_t max_retweet_count, top_tweet_result<StringType> &result) {
|
||||||
if (!ast_buffer) {
|
if (!ast_buffer) {
|
||||||
|
|||||||
@@ -13,13 +13,13 @@ struct top_tweet_result {
|
|||||||
StringType screen_name{};
|
StringType screen_name{};
|
||||||
StringType text{};
|
StringType text{};
|
||||||
template<typename OtherStringType>
|
template<typename OtherStringType>
|
||||||
simdjson_really_inline bool operator==(const top_tweet_result<OtherStringType> &other) const {
|
simdjson_inline bool operator==(const top_tweet_result<OtherStringType> &other) const {
|
||||||
return retweet_count == other.retweet_count &&
|
return retweet_count == other.retweet_count &&
|
||||||
screen_name == other.screen_name &&
|
screen_name == other.screen_name &&
|
||||||
text == other.text;
|
text == other.text;
|
||||||
}
|
}
|
||||||
template<typename OtherStringType>
|
template<typename OtherStringType>
|
||||||
simdjson_really_inline bool operator!=(const top_tweet_result<OtherStringType> &other) const { return !(*this == other); }
|
simdjson_inline bool operator!=(const top_tweet_result<OtherStringType> &other) const { return !(*this == other); }
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename StringType>
|
template<typename StringType>
|
||||||
@@ -60,7 +60,7 @@ struct runner : public file_runner<I> {
|
|||||||
|
|
||||||
struct simdjson_dom;
|
struct simdjson_dom;
|
||||||
|
|
||||||
template<typename I> simdjson_really_inline static void top_tweet(benchmark::State &state) {
|
template<typename I> simdjson_inline static void top_tweet(benchmark::State &state) {
|
||||||
json_benchmark::run_json_benchmark<runner<I>, runner<simdjson_dom>>(state);
|
json_benchmark::run_json_benchmark<runner<I>, runner<simdjson_dom>>(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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")
|
||||||
@@ -91,13 +110,19 @@ endif()
|
|||||||
|
|
||||||
# We compile tools, tests, etc. with C++ 17. Override yourself if you need on a
|
# We compile tools, tests, etc. with C++ 17. Override yourself if you need on a
|
||||||
# target.
|
# target.
|
||||||
set(CMAKE_CXX_STANDARD 17)
|
set(SIMDJSON_CXX_STANDARD 17 CACHE STRING "the C++ standard to use for simdjson")
|
||||||
|
set(CMAKE_CXX_STANDARD ${SIMDJSON_CXX_STANDARD})
|
||||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
set(CMAKE_CXX_EXTENSIONS OFF)
|
set(CMAKE_CXX_EXTENSIONS OFF)
|
||||||
set(CMAKE_MACOSX_RPATH OFF)
|
set(CMAKE_MACOSX_RPATH OFF)
|
||||||
set(CMAKE_THREAD_PREFER_PTHREAD ON)
|
set(CMAKE_THREAD_PREFER_PTHREAD ON)
|
||||||
set(THREADS_PREFER_PTHREAD_FLAG ON)
|
set(THREADS_PREFER_PTHREAD_FLAG ON)
|
||||||
|
set(SIMDJSON_STRUCTURAL_INDEXER_STEP CACHE STRING "the SIMDJSON_STRUCTURAL_INDEXER_STEP variable")
|
||||||
|
|
||||||
|
if(SIMDJSON_STRUCTURAL_INDEXER_STEP)
|
||||||
|
message(STATUS "Setting SIMDJSON_STRUCTURAL_INDEXER_STEP to ${SIMDJSON_STRUCTURAL_INDEXER_STEP}.")
|
||||||
|
add_compile_definitions(SIMDJSON_STRUCTURAL_INDEXER_STEP=${SIMDJSON_STRUCTURAL_INDEXER_STEP})
|
||||||
|
endif()
|
||||||
# LTO seems to create all sorts of fun problems. Let us
|
# LTO seems to create all sorts of fun problems. Let us
|
||||||
# disable temporarily.
|
# disable temporarily.
|
||||||
#include(CheckIPOSupported)
|
#include(CheckIPOSupported)
|
||||||
@@ -144,6 +169,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 +217,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
+13
-5
@@ -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()
|
||||||
|
|
||||||
@@ -70,11 +70,11 @@ int main() {}
|
|||||||
target_include_directories(jsmn SYSTEM PUBLIC "${jsmn_SOURCE_DIR}")
|
target_include_directories(jsmn SYSTEM PUBLIC "${jsmn_SOURCE_DIR}")
|
||||||
target_compile_definitions(jsmn INTERFACE SIMDJSON_COMPETITION_JSMN)
|
target_compile_definitions(jsmn INTERFACE SIMDJSON_COMPETITION_JSMN)
|
||||||
|
|
||||||
message(STATUS "Importing json (nlohmann/json@v3.9.1)")
|
message(STATUS "Importing json (nlohmann/json@v3.10.5)")
|
||||||
set(nlohmann_json_SOURCE_DIR "${dep_root}/json")
|
set(nlohmann_json_SOURCE_DIR "${dep_root}/json")
|
||||||
if(NOT EXISTS "${nlohmann_json_SOURCE_DIR}")
|
if(NOT EXISTS "${nlohmann_json_SOURCE_DIR}")
|
||||||
file(DOWNLOAD
|
file(DOWNLOAD
|
||||||
"https://github.com/nlohmann/json/releases/download/v3.9.1/json.hpp"
|
"https://github.com/nlohmann/json/releases/download/v3.10.5/json.hpp"
|
||||||
"${nlohmann_json_SOURCE_DIR}/nlohmann/json.hpp")
|
"${nlohmann_json_SOURCE_DIR}/nlohmann/json.hpp")
|
||||||
endif()
|
endif()
|
||||||
add_library(nlohmann_json INTERFACE)
|
add_library(nlohmann_json INTERFACE)
|
||||||
@@ -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)
|
||||||
|
|||||||
+188
-86
@@ -79,6 +79,150 @@ license you like.
|
|||||||
/// to prevent private header inclusion.
|
/// to prevent private header inclusion.
|
||||||
#define JSON_IS_AMALGAMATION
|
#define JSON_IS_AMALGAMATION
|
||||||
|
|
||||||
|
// //////////////////////////////////////////////////////////////////////
|
||||||
|
// Beginning of content of file: include/json/version.h
|
||||||
|
// //////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#ifndef JSON_VERSION_H_INCLUDED
|
||||||
|
#define JSON_VERSION_H_INCLUDED
|
||||||
|
|
||||||
|
// Note: version must be updated in three places when doing a release. This
|
||||||
|
// annoying process ensures that amalgamate, CMake, and meson all report the
|
||||||
|
// correct version.
|
||||||
|
// 1. /meson.build
|
||||||
|
// 2. /include/json/version.h
|
||||||
|
// 3. /CMakeLists.txt
|
||||||
|
// IMPORTANT: also update the SOVERSION!!
|
||||||
|
|
||||||
|
#define JSONCPP_VERSION_STRING "1.9.5"
|
||||||
|
#define JSONCPP_VERSION_MAJOR 1
|
||||||
|
#define JSONCPP_VERSION_MINOR 9
|
||||||
|
#define JSONCPP_VERSION_PATCH 5
|
||||||
|
#define JSONCPP_VERSION_QUALIFIER
|
||||||
|
#define JSONCPP_VERSION_HEXA \
|
||||||
|
((JSONCPP_VERSION_MAJOR << 24) | (JSONCPP_VERSION_MINOR << 16) | \
|
||||||
|
(JSONCPP_VERSION_PATCH << 8))
|
||||||
|
|
||||||
|
#ifdef JSONCPP_USING_SECURE_MEMORY
|
||||||
|
#undef JSONCPP_USING_SECURE_MEMORY
|
||||||
|
#endif
|
||||||
|
#define JSONCPP_USING_SECURE_MEMORY 0
|
||||||
|
// If non-zero, the library zeroes any memory that it has allocated before
|
||||||
|
// it frees its memory.
|
||||||
|
|
||||||
|
#endif // JSON_VERSION_H_INCLUDED
|
||||||
|
|
||||||
|
// //////////////////////////////////////////////////////////////////////
|
||||||
|
// End of content of file: include/json/version.h
|
||||||
|
// //////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// //////////////////////////////////////////////////////////////////////
|
||||||
|
// Beginning of content of file: include/json/allocator.h
|
||||||
|
// //////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors
|
||||||
|
// Distributed under MIT license, or public domain if desired and
|
||||||
|
// recognized in your jurisdiction.
|
||||||
|
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
|
||||||
|
|
||||||
|
#ifndef JSON_ALLOCATOR_H_INCLUDED
|
||||||
|
#define JSON_ALLOCATOR_H_INCLUDED
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#pragma pack(push, 8)
|
||||||
|
|
||||||
|
namespace Json {
|
||||||
|
template <typename T> class SecureAllocator {
|
||||||
|
public:
|
||||||
|
// Type definitions
|
||||||
|
using value_type = T;
|
||||||
|
using pointer = T*;
|
||||||
|
using const_pointer = const T*;
|
||||||
|
using reference = T&;
|
||||||
|
using const_reference = const T&;
|
||||||
|
using size_type = std::size_t;
|
||||||
|
using difference_type = std::ptrdiff_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allocate memory for N items using the standard allocator.
|
||||||
|
*/
|
||||||
|
pointer allocate(size_type n) {
|
||||||
|
// allocate using "global operator new"
|
||||||
|
return static_cast<pointer>(::operator new(n * sizeof(T)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Release memory which was allocated for N items at pointer P.
|
||||||
|
*
|
||||||
|
* The memory block is filled with zeroes before being released.
|
||||||
|
*/
|
||||||
|
void deallocate(pointer p, size_type n) {
|
||||||
|
// memset_s is used because memset may be optimized away by the compiler
|
||||||
|
memset_s(p, n * sizeof(T), 0, n * sizeof(T));
|
||||||
|
// free using "global operator delete"
|
||||||
|
::operator delete(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct an item in-place at pointer P.
|
||||||
|
*/
|
||||||
|
template <typename... Args> void construct(pointer p, Args&&... args) {
|
||||||
|
// construct using "placement new" and "perfect forwarding"
|
||||||
|
::new (static_cast<void*>(p)) T(std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_type max_size() const { return size_t(-1) / sizeof(T); }
|
||||||
|
|
||||||
|
pointer address(reference x) const { return std::addressof(x); }
|
||||||
|
|
||||||
|
const_pointer address(const_reference x) const { return std::addressof(x); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Destroy an item in-place at pointer P.
|
||||||
|
*/
|
||||||
|
void destroy(pointer p) {
|
||||||
|
// destroy using "explicit destructor"
|
||||||
|
p->~T();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Boilerplate
|
||||||
|
SecureAllocator() {}
|
||||||
|
template <typename U> SecureAllocator(const SecureAllocator<U>&) {}
|
||||||
|
template <typename U> struct rebind { using other = SecureAllocator<U>; };
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T, typename U>
|
||||||
|
bool operator==(const SecureAllocator<T>&, const SecureAllocator<U>&) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, typename U>
|
||||||
|
bool operator!=(const SecureAllocator<T>&, const SecureAllocator<U>&) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Json
|
||||||
|
|
||||||
|
#pragma pack(pop)
|
||||||
|
|
||||||
|
#endif // JSON_ALLOCATOR_H_INCLUDED
|
||||||
|
|
||||||
|
// //////////////////////////////////////////////////////////////////////
|
||||||
|
// End of content of file: include/json/allocator.h
|
||||||
|
// //////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// //////////////////////////////////////////////////////////////////////
|
// //////////////////////////////////////////////////////////////////////
|
||||||
// Beginning of content of file: include/json/config.h
|
// Beginning of content of file: include/json/config.h
|
||||||
// //////////////////////////////////////////////////////////////////////
|
// //////////////////////////////////////////////////////////////////////
|
||||||
@@ -99,47 +243,38 @@ license you like.
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
|
||||||
/// If defined, indicates that json library is embedded in CppTL library.
|
|
||||||
//# define JSON_IN_CPPTL 1
|
|
||||||
|
|
||||||
/// If defined, indicates that json may leverage CppTL library
|
|
||||||
//# define JSON_USE_CPPTL 1
|
|
||||||
/// If defined, indicates that cpptl vector based map should be used instead of
|
|
||||||
/// std::map
|
|
||||||
/// as Value container.
|
|
||||||
//# define JSON_USE_CPPTL_SMALLMAP 1
|
|
||||||
|
|
||||||
// If non-zero, the library uses exceptions to report bad input instead of C
|
// If non-zero, the library uses exceptions to report bad input instead of C
|
||||||
// assertion macros. The default is to use exceptions.
|
// assertion macros. The default is to use exceptions.
|
||||||
#ifndef JSON_USE_EXCEPTION
|
#ifndef JSON_USE_EXCEPTION
|
||||||
#define JSON_USE_EXCEPTION 1
|
#define JSON_USE_EXCEPTION 1
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Temporary, tracked for removal with issue #982.
|
||||||
|
#ifndef JSON_USE_NULLREF
|
||||||
|
#define JSON_USE_NULLREF 1
|
||||||
|
#endif
|
||||||
|
|
||||||
/// If defined, indicates that the source file is amalgamated
|
/// If defined, indicates that the source file is amalgamated
|
||||||
/// to prevent private header inclusion.
|
/// to prevent private header inclusion.
|
||||||
/// Remarks: it is automatically defined in the generated amalgamated header.
|
/// Remarks: it is automatically defined in the generated amalgamated header.
|
||||||
// #define JSON_IS_AMALGAMATION
|
// #define JSON_IS_AMALGAMATION
|
||||||
|
|
||||||
#ifdef JSON_IN_CPPTL
|
// Export macros for DLL visibility
|
||||||
#include <cpptl/config.h>
|
#if defined(JSON_DLL_BUILD)
|
||||||
#ifndef JSON_USE_CPPTL
|
|
||||||
#define JSON_USE_CPPTL 1
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef JSON_IN_CPPTL
|
|
||||||
#define JSON_API CPPTL_API
|
|
||||||
#elif defined(JSON_DLL_BUILD)
|
|
||||||
#if defined(_MSC_VER) || defined(__MINGW32__)
|
#if defined(_MSC_VER) || defined(__MINGW32__)
|
||||||
#define JSON_API __declspec(dllexport)
|
#define JSON_API __declspec(dllexport)
|
||||||
#define JSONCPP_DISABLE_DLL_INTERFACE_WARNING
|
#define JSONCPP_DISABLE_DLL_INTERFACE_WARNING
|
||||||
|
#elif defined(__GNUC__) || defined(__clang__)
|
||||||
|
#define JSON_API __attribute__((visibility("default")))
|
||||||
#endif // if defined(_MSC_VER)
|
#endif // if defined(_MSC_VER)
|
||||||
|
|
||||||
#elif defined(JSON_DLL)
|
#elif defined(JSON_DLL)
|
||||||
#if defined(_MSC_VER) || defined(__MINGW32__)
|
#if defined(_MSC_VER) || defined(__MINGW32__)
|
||||||
#define JSON_API __declspec(dllimport)
|
#define JSON_API __declspec(dllimport)
|
||||||
#define JSONCPP_DISABLE_DLL_INTERFACE_WARNING
|
#define JSONCPP_DISABLE_DLL_INTERFACE_WARNING
|
||||||
#endif // if defined(_MSC_VER)
|
#endif // if defined(_MSC_VER)
|
||||||
#endif // ifdef JSON_IN_CPPTL
|
#endif // ifdef JSON_DLL_BUILD
|
||||||
|
|
||||||
#if !defined(JSON_API)
|
#if !defined(JSON_API)
|
||||||
#define JSON_API
|
#define JSON_API
|
||||||
#endif
|
#endif
|
||||||
@@ -152,8 +287,8 @@ license you like.
|
|||||||
#if defined(_MSC_VER) && _MSC_VER < 1900
|
#if defined(_MSC_VER) && _MSC_VER < 1900
|
||||||
// As recommended at
|
// As recommended at
|
||||||
// https://stackoverflow.com/questions/2915672/snprintf-and-visual-studio-2010
|
// https://stackoverflow.com/questions/2915672/snprintf-and-visual-studio-2010
|
||||||
extern JSON_API int
|
extern JSON_API int msvc_pre1900_c99_snprintf(char* outBuf, size_t size,
|
||||||
msvc_pre1900_c99_snprintf(char* outBuf, size_t size, const char* format, ...);
|
const char* format, ...);
|
||||||
#define jsoncpp_snprintf msvc_pre1900_c99_snprintf
|
#define jsoncpp_snprintf msvc_pre1900_c99_snprintf
|
||||||
#else
|
#else
|
||||||
#define jsoncpp_snprintf std::snprintf
|
#define jsoncpp_snprintf std::snprintf
|
||||||
@@ -164,69 +299,30 @@ msvc_pre1900_c99_snprintf(char* outBuf, size_t size, const char* format, ...);
|
|||||||
// Storages, and 64 bits integer support is disabled.
|
// Storages, and 64 bits integer support is disabled.
|
||||||
// #define JSON_NO_INT64 1
|
// #define JSON_NO_INT64 1
|
||||||
|
|
||||||
#if defined(_MSC_VER) // MSVC
|
|
||||||
#define JSONCPP_DEPRECATED(message) __declspec(deprecated(message))
|
|
||||||
#endif // defined(_MSC_VER)
|
|
||||||
|
|
||||||
// JSONCPP_OVERRIDE is maintained for backwards compatibility of external tools.
|
// JSONCPP_OVERRIDE is maintained for backwards compatibility of external tools.
|
||||||
// C++11 should be used directly in JSONCPP.
|
// C++11 should be used directly in JSONCPP.
|
||||||
#define JSONCPP_OVERRIDE override
|
#define JSONCPP_OVERRIDE override
|
||||||
|
|
||||||
#if __cplusplus >= 201103L
|
|
||||||
#define JSONCPP_NOEXCEPT noexcept
|
|
||||||
#define JSONCPP_OP_EXPLICIT explicit
|
|
||||||
#elif defined(_MSC_VER) && _MSC_VER < 1900
|
|
||||||
#define JSONCPP_NOEXCEPT throw()
|
|
||||||
#define JSONCPP_OP_EXPLICIT explicit
|
|
||||||
#elif defined(_MSC_VER) && _MSC_VER >= 1900
|
|
||||||
#define JSONCPP_NOEXCEPT noexcept
|
|
||||||
#define JSONCPP_OP_EXPLICIT explicit
|
|
||||||
#else
|
|
||||||
#define JSONCPP_NOEXCEPT throw()
|
|
||||||
#define JSONCPP_OP_EXPLICIT
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef JSON_HAS_RVALUE_REFERENCES
|
|
||||||
|
|
||||||
#if defined(_MSC_VER)
|
|
||||||
#define JSON_HAS_RVALUE_REFERENCES 1
|
|
||||||
#endif // MSVC >= 2013
|
|
||||||
|
|
||||||
#ifdef __clang__
|
|
||||||
#if __has_feature(cxx_rvalue_references)
|
|
||||||
#define JSON_HAS_RVALUE_REFERENCES 1
|
|
||||||
#endif // has_feature
|
|
||||||
|
|
||||||
#elif defined __GNUC__ // not clang (gcc comes later since clang emulates gcc)
|
|
||||||
#if defined(__GXX_EXPERIMENTAL_CXX0X__) || (__cplusplus >= 201103L)
|
|
||||||
#define JSON_HAS_RVALUE_REFERENCES 1
|
|
||||||
#endif // GXX_EXPERIMENTAL
|
|
||||||
|
|
||||||
#endif // __clang__ || __GNUC__
|
|
||||||
|
|
||||||
#endif // not defined JSON_HAS_RVALUE_REFERENCES
|
|
||||||
|
|
||||||
#ifndef JSON_HAS_RVALUE_REFERENCES
|
|
||||||
#define JSON_HAS_RVALUE_REFERENCES 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef __clang__
|
#ifdef __clang__
|
||||||
#if __has_extension(attribute_deprecated_with_message)
|
#if __has_extension(attribute_deprecated_with_message)
|
||||||
#define JSONCPP_DEPRECATED(message) __attribute__((deprecated(message)))
|
#define JSONCPP_DEPRECATED(message) __attribute__((deprecated(message)))
|
||||||
#endif
|
#endif
|
||||||
#elif defined __GNUC__ // not clang (gcc comes later since clang emulates gcc)
|
#elif defined(__GNUC__) // not clang (gcc comes later since clang emulates gcc)
|
||||||
#if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5))
|
#if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5))
|
||||||
#define JSONCPP_DEPRECATED(message) __attribute__((deprecated(message)))
|
#define JSONCPP_DEPRECATED(message) __attribute__((deprecated(message)))
|
||||||
#elif (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1))
|
#elif (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1))
|
||||||
#define JSONCPP_DEPRECATED(message) __attribute__((__deprecated__))
|
#define JSONCPP_DEPRECATED(message) __attribute__((__deprecated__))
|
||||||
#endif // GNUC version
|
#endif // GNUC version
|
||||||
#endif // __clang__ || __GNUC__
|
#elif defined(_MSC_VER) // MSVC (after clang because clang on Windows emulates
|
||||||
|
// MSVC)
|
||||||
|
#define JSONCPP_DEPRECATED(message) __declspec(deprecated(message))
|
||||||
|
#endif // __clang__ || __GNUC__ || _MSC_VER
|
||||||
|
|
||||||
#if !defined(JSONCPP_DEPRECATED)
|
#if !defined(JSONCPP_DEPRECATED)
|
||||||
#define JSONCPP_DEPRECATED(message)
|
#define JSONCPP_DEPRECATED(message)
|
||||||
#endif // if !defined(JSONCPP_DEPRECATED)
|
#endif // if !defined(JSONCPP_DEPRECATED)
|
||||||
|
|
||||||
#if __GNUC__ >= 6
|
#if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ >= 6))
|
||||||
#define JSON_USE_INT64_DOUBLE_CONVERSION 1
|
#define JSON_USE_INT64_DOUBLE_CONVERSION 1
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -238,36 +334,36 @@ msvc_pre1900_c99_snprintf(char* outBuf, size_t size, const char* format, ...);
|
|||||||
#endif // if !defined(JSON_IS_AMALGAMATION)
|
#endif // if !defined(JSON_IS_AMALGAMATION)
|
||||||
|
|
||||||
namespace Json {
|
namespace Json {
|
||||||
typedef int Int;
|
using Int = int;
|
||||||
typedef unsigned int UInt;
|
using UInt = unsigned int;
|
||||||
#if defined(JSON_NO_INT64)
|
#if defined(JSON_NO_INT64)
|
||||||
typedef int LargestInt;
|
using LargestInt = int;
|
||||||
typedef unsigned int LargestUInt;
|
using LargestUInt = unsigned int;
|
||||||
#undef JSON_HAS_INT64
|
#undef JSON_HAS_INT64
|
||||||
#else // if defined(JSON_NO_INT64)
|
#else // if defined(JSON_NO_INT64)
|
||||||
// For Microsoft Visual use specific types as long long is not supported
|
// For Microsoft Visual use specific types as long long is not supported
|
||||||
#if defined(_MSC_VER) // Microsoft Visual Studio
|
#if defined(_MSC_VER) // Microsoft Visual Studio
|
||||||
typedef __int64 Int64;
|
using Int64 = __int64;
|
||||||
typedef unsigned __int64 UInt64;
|
using UInt64 = unsigned __int64;
|
||||||
#else // if defined(_MSC_VER) // Other platforms, use long long
|
#else // if defined(_MSC_VER) // Other platforms, use long long
|
||||||
typedef int64_t Int64;
|
using Int64 = int64_t;
|
||||||
typedef uint64_t UInt64;
|
using UInt64 = uint64_t;
|
||||||
#endif // if defined(_MSC_VER)
|
#endif // if defined(_MSC_VER)
|
||||||
typedef Int64 LargestInt;
|
using LargestInt = Int64;
|
||||||
typedef UInt64 LargestUInt;
|
using LargestUInt = UInt64;
|
||||||
#define JSON_HAS_INT64
|
#define JSON_HAS_INT64
|
||||||
#endif // if defined(JSON_NO_INT64)
|
#endif // if defined(JSON_NO_INT64)
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
using Allocator = typename std::conditional<JSONCPP_USING_SECURE_MEMORY,
|
using Allocator =
|
||||||
SecureAllocator<T>,
|
typename std::conditional<JSONCPP_USING_SECURE_MEMORY, SecureAllocator<T>,
|
||||||
std::allocator<T>>::type;
|
std::allocator<T>>::type;
|
||||||
using String = std::basic_string<char, std::char_traits<char>, Allocator<char>>;
|
using String = std::basic_string<char, std::char_traits<char>, Allocator<char>>;
|
||||||
using IStringStream = std::basic_istringstream<String::value_type,
|
using IStringStream =
|
||||||
String::traits_type,
|
std::basic_istringstream<String::value_type, String::traits_type,
|
||||||
String::allocator_type>;
|
String::allocator_type>;
|
||||||
using OStringStream = std::basic_ostringstream<String::value_type,
|
using OStringStream =
|
||||||
String::traits_type,
|
std::basic_ostringstream<String::value_type, String::traits_type,
|
||||||
String::allocator_type>;
|
String::allocator_type>;
|
||||||
using IStream = std::istream;
|
using IStream = std::istream;
|
||||||
using OStream = std::ostream;
|
using OStream = std::ostream;
|
||||||
@@ -310,17 +406,23 @@ using JSONCPP_OSTREAM = Json::OStream;
|
|||||||
namespace Json {
|
namespace Json {
|
||||||
|
|
||||||
// writer.h
|
// writer.h
|
||||||
|
class StreamWriter;
|
||||||
|
class StreamWriterBuilder;
|
||||||
|
class Writer;
|
||||||
class FastWriter;
|
class FastWriter;
|
||||||
class StyledWriter;
|
class StyledWriter;
|
||||||
|
class StyledStreamWriter;
|
||||||
|
|
||||||
// reader.h
|
// reader.h
|
||||||
class Reader;
|
class Reader;
|
||||||
|
class CharReader;
|
||||||
|
class CharReaderBuilder;
|
||||||
|
|
||||||
// features.h
|
// json_features.h
|
||||||
class Features;
|
class Features;
|
||||||
|
|
||||||
// value.h
|
// value.h
|
||||||
typedef unsigned int ArrayIndex;
|
using ArrayIndex = unsigned int;
|
||||||
class StaticString;
|
class StaticString;
|
||||||
class Path;
|
class Path;
|
||||||
class PathArgument;
|
class PathArgument;
|
||||||
|
|||||||
Vendored
+507
-527
File diff suppressed because it is too large
Load Diff
Vendored
+497
-593
File diff suppressed because it is too large
Load Diff
+589
-104
@@ -3,40 +3,50 @@ The Basics
|
|||||||
|
|
||||||
An overview of what you need to know to use simdjson, with examples.
|
An overview of what you need to know to use simdjson, with examples.
|
||||||
|
|
||||||
* [Requirements](#requirements)
|
- [The Basics](#the-basics)
|
||||||
* [Including simdjson](#including-simdjson)
|
- [Requirements](#requirements)
|
||||||
* [Using simdjson with package managers](#using-simdjson-with-package-managers)
|
- [Including simdjson](#including-simdjson)
|
||||||
* [Using simdjson as a CMake dependency](#using-simdjson-as-a-cmake-dependency)
|
- [Using simdjson with package managers](#using-simdjson-with-package-managers)
|
||||||
* [Versions](#versions)
|
- [Using simdjson as a CMake dependency](#using-simdjson-as-a-cmake-dependency)
|
||||||
* [The Basics: Loading and Parsing JSON Documents](#the-basics-loading-and-parsing-json-documents)
|
- [Versions](#versions)
|
||||||
* [Documents are Iterators](#documents-are-iterators)
|
- [The Basics: Loading and Parsing JSON Documents](#the-basics-loading-and-parsing-json-documents)
|
||||||
* [C++11 Support and string_view](#c11-support-and-string_view)
|
- [Documents are Iterators](#documents-are-iterators)
|
||||||
* [Using the Parsed JSON](#using-the-parsed-json)
|
- [Parser, Document and JSON Scope](#parser-document-and-json-scope)
|
||||||
* [Minifying JSON strings without parsing](#minifying-json-strings-without-parsing)
|
- [string_view](#string_view)
|
||||||
* [UTF-8 validation (alone)](#utf-8-validation-alone)
|
- [Using the Parsed JSON](#using-the-parsed-json)
|
||||||
* [JSON Pointer](#json-pointer)
|
- [Using the Parsed JSON: Additional examples](#using-the-parsed-json-additional-examples)
|
||||||
* [Error Handling](#error-handling)
|
- [Minifying JSON strings without parsing](#minifying-json-strings-without-parsing)
|
||||||
* [Error Handling Example without Exceptions](#error-handling-examples-without-exceptions)
|
- [UTF-8 validation (alone)](#utf-8-validation-alone)
|
||||||
* [Disabling Exceptions](#disabling-exceptions)
|
- [JSON Pointer](#json-pointer)
|
||||||
* [Exceptions](#exceptions)
|
- [Error Handling](#error-handling)
|
||||||
* [Current location in document](#current-location-in-document)
|
- [Error Handling Examples without Exceptions](#error-handling-examples-without-exceptions)
|
||||||
* [Rewinding](#rewinding)
|
- [Disabling Exceptions](#disabling-exceptions)
|
||||||
* [Direct Access to the Raw String](#direct-access-to-the-raw-string)
|
- [Exceptions](#exceptions)
|
||||||
* [Newline-Delimited JSON (ndjson) and JSON lines](#newline-delimited-json-ndjson-and-json-lines)
|
- [Current location in document](#current-location-in-document)
|
||||||
* [Parsing Numbers Inside Strings](#parsing-numbers-inside-strings)
|
- [Checking for trailing content](#checking-for-trailing-content)
|
||||||
* [Dynamic Number Types](#dynamic-number-types)
|
- [Rewinding](#rewinding)
|
||||||
* [Thread Safety](#thread-safety)
|
- [Newline-Delimited JSON (ndjson) and JSON lines](#newline-delimited-json-ndjson-and-json-lines)
|
||||||
* [Standard Compliance](#standard-compliance)
|
- [Parsing Numbers Inside Strings](#parsing-numbers-inside-strings)
|
||||||
|
- [Dynamic Number Types](#dynamic-number-types)
|
||||||
|
- [Raw Strings](#raw-strings)
|
||||||
|
- [General Direct Access to the Raw JSON String](#general-direct-access-to-the-raw-json-string)
|
||||||
|
- [Thread Safety](#thread-safety)
|
||||||
|
- [Standard Compliance](#standard-compliance)
|
||||||
|
- [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
|
||||||
------------------
|
------------------
|
||||||
@@ -56,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
|
||||||
@@ -94,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
|
||||||
@@ -135,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
|
||||||
@@ -146,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;
|
||||||
@@ -167,11 +182,33 @@ 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.
|
||||||
|
|
||||||
By default, the simdjson library throws exceptions (`simdjson_error`) on errors. We omit `try`-`catch` clauses from our illustrating examples: if you omit `try`-`catch` in your code, an uncaught exception will halt your program. It is also possible to use simdjson without generating exceptions, and you may even build the library without exception support at all. See [Error Handling](#error-handling) for details.
|
By default, the simdjson library throws exceptions (`simdjson_error`) on errors. We omit `try`-`catch` clauses from our illustrating examples: if you omit `try`-`catch` in your code, an uncaught exception will halt your program. It is also possible to use simdjson without generating exceptions, and you may even build the library without exception support at all. See [Error Handling](#error-handling) for details.
|
||||||
|
|
||||||
|
|
||||||
|
Some users may want to browse code along with the compiled assembly. You want to check out the following lists of examples:
|
||||||
|
|
||||||
|
* [simdjson examples with errors handled through exceptions](https://godbolt.org/z/98Kx9Kqjn)
|
||||||
|
* [simdjson examples with errors without exceptions](https://godbolt.org/z/PKG7GdbPo)
|
||||||
|
|
||||||
|
|
||||||
Documents are Iterators
|
Documents are Iterators
|
||||||
-----------------------
|
-----------------------
|
||||||
|
|
||||||
@@ -201,7 +238,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).
|
||||||
@@ -240,27 +279,34 @@ transcode the UTF-8 strings produced by the simdjson library to other formats. S
|
|||||||
Using the Parsed JSON
|
Using the Parsed JSON
|
||||||
---------------------
|
---------------------
|
||||||
|
|
||||||
|
We recommend that you first compile and run your code in Debug mode: under Visual Studio,
|
||||||
|
it means having the `_DEBUG` macro defined, and, for other compilers, it means leaving
|
||||||
We recommend that you first compile and run your code in Debug mode (with `NDEBUG`
|
the `__OPTIMIZE__` macro undefined. The simdjson code will set `SIMDJSON_DEVELOPMENT_CHECKS=1`.
|
||||||
undefined). When you do so, the simdjson library runs additional sanity tests on
|
Alternatively, you can set the macro `SIMDJSON_DEVELOPMENT_CHECKS` to 1 prior to including
|
||||||
your code to help ensure that you are using the library in a safe manner. Once
|
the `simdjson.h` header to enable these additional checks: just make sure you remove the
|
||||||
your code has been tested, you can then run it in Release mode (with `NDEBUG`
|
definition once your code has been tested. When `SIMDJSON_DEVELOPMENT_CHECKS` is set to 1, the
|
||||||
defined) for best performance. Alternatively, you can set the macro
|
simdjson library runs additional (expensive) tests on your code to help ensure that you are
|
||||||
`SIMDJSON_DEVELOPMENT_CHECKS` to 1 prior to including the `simdjson.h` header
|
using the library in a safe manner. Once your code has been tested, you can then run it in
|
||||||
to enable these additional checks: just make sure you remove the definition once your
|
Release mode: under Visual Studio, it means having the `_DEBUG` macro undefined, and, for other
|
||||||
code has been tested.
|
compilers, it means setting `__OPTIMIZE__` to a positive integer. You can also forcefully
|
||||||
|
disable these checks by setting `SIMDJSON_DEVELOPMENT_CHECKS` to 0. 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.
|
||||||
|
|
||||||
Once you have a document (`simdjson::ondemand::document`), you can navigate it with
|
Once you have a document (`simdjson::ondemand::document`), you can navigate it with
|
||||||
idiomatic C++ iterators, operators and casts. Besides the document instances and
|
idiomatic C++ iterators, operators and casts. Besides the document instances and
|
||||||
native types (`double`, `uint64_t`, `int64_t`, `bool`), we also access
|
native types (`double`, `uint64_t`, `int64_t`, `bool`), we also access
|
||||||
Unicode (UTF-8) strings (`std::string_view`), objects (`simdjson::ondemand::object`)
|
Unicode (UTF-8) strings (`std::string_view`), objects (`simdjson::ondemand::object`)
|
||||||
and arrays (`simdjson::ondemand::array`).
|
and arrays (`simdjson::ondemand::array`).
|
||||||
We also have a generic type (`simdjson::ondemand::value`) which represents a potential
|
We also have a generic ephemeral type (`simdjson::ondemand::value`) which represents a potential
|
||||||
array or object, or scalar type (`double`, `uint64_t`, `int64_t`, `bool`, `null`, string) inside
|
array or object, or scalar type (`double`, `uint64_t`, `int64_t`, `bool`, `null`, string) inside
|
||||||
an array or an object. Both generic types (`simdjson::ondemand::document` and
|
an array or an object. Both generic types (`simdjson::ondemand::document` and
|
||||||
`simdjson::ondemand::value`) have a `type()` method returning a `json_type` value describing the
|
`simdjson::ondemand::value`) have a `type()` method returning a `json_type` value describing the
|
||||||
value (`json_type::array`, `json_type::object`, `json_type::number`, `json_type::string`, `json_type::boolean`, `json_type::null`).
|
value (`json_type::array`, `json_type::object`, `json_type::number`, `json_type::string`,
|
||||||
|
`json_type::boolean`, `json_type::null`). A generic value (`simdjson::ondemand::value`)
|
||||||
|
is only valid temporarily, as soon as you access other values, other keys in objects, etc.
|
||||||
|
it becomes invalid: you should therefore consume the value immediately by converting it to a
|
||||||
|
scalar type, an array or an object.
|
||||||
|
|
||||||
Advanced users who need to determine the number types (integer or float) dynamically,
|
Advanced users who need to determine the number types (integer or float) dynamically,
|
||||||
should review our section [dynamic number types](#dynamic-number-types). Indeed,
|
should review our section [dynamic number types](#dynamic-number-types). Indeed,
|
||||||
@@ -273,32 +319,50 @@ 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.
|
||||||
|
|
||||||
* **Validate What You Use:** When calling `iterate`, the document is quickly indexed. If it is
|
* **Validate What You Use:** When calling `iterate`, the document is quickly indexed. If it is
|
||||||
not a valid Unicode (UTF-8) string or if there is an unclosed string, an error may be reported right away.
|
not a valid Unicode (UTF-8) string or if there is an unclosed string, an error may be reported right away.
|
||||||
However, it is not fully validated. On Demand only fully validates the values you use and the
|
However, it is not fully validated. On Demand only fully validates the values you use and the
|
||||||
structure leading to it.
|
structure leading to it. It means that at every step as you traverse the document, you may encounter an error. You can handle errors either with exceptions or with error codes.
|
||||||
* **Extracting Values:** You can cast a JSON element to a native type:
|
* **Extracting Values:** You can cast a JSON element to a native type:
|
||||||
`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 may be thrown if
|
||||||
the cast is not possible.
|
the cast is not possible: there error code is `simdjson::INCORRECT_TYPE` (see [Error Handling](#error-handling)). Importantly, when getting an ondemand::object or ondemand::array instance, its content is
|
||||||
|
not validated: you are only guaranteed that the corresponding initial character (`{` or `[`) is present. Thus,
|
||||||
|
for example, you could have an ondemand::object instance pointing at the invalid JSON `{ "this is not a valid object" }`: the validation occurs as you access the content.
|
||||||
|
The `get_string()` returns a valid UTF-8 string, after
|
||||||
|
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
|
||||||
> `get_string()` twice on an object (or to cast an object twice to `std::string_view`).
|
> `get_string()` twice on an object (or to cast an object twice to `std::string_view`).
|
||||||
* **Field Access:** To get the value of the "foo" field in an object, use `object["foo"]`. This will
|
* **Field Access:** To get the value of the "foo" field in an object, use `object["foo"]`. This will
|
||||||
scan through the object looking for the field with the matching string, doing a character-by-character
|
scan through the object looking for the field with the matching string, doing a character-by-character
|
||||||
comparison. For efficiency reason, you should avoid looking up the same field repeatedly: e.g., do
|
comparison. It may generate the error `simdjson::NO_SUCH_FIELD` if there is no such key in the object, it may throw an exception (see [Error Handling](#error-handling)). For efficiency reason, you should avoid looking up the same field repeatedly: e.g., do
|
||||||
not do `object["foo"]` followed by `object["foo"]` with the same `object` instance. If you consume an
|
not do `object["foo"]` followed by `object["foo"]` with the same `object` instance. Keep in mind that On Demand does not buffer or save the result of the parsing: if you repeatedly access `object["foo"]`, then it must repeatedly seek the key and parse the content. The library does not provide a distinct function to check if a key is present, instead we recommend you attempt to access the key: e.g., by doing `ondemand::value val{}; if(!object["foo"].get(val)) {...}`, you have that `val` contains the requested value inside the if clause. It is your responsibility as a user to temporarily keep a reference to the value (`auto v = object["foo"]`), or to consume the content and store it in your own data structures. If you consume an
|
||||||
object twice: `std::string_view(object["foo"]` followed by `std::string_view(object["foo"]`, your code
|
object twice: `std::string_view(object["foo"]` followed by `std::string_view(object["foo"]` then your code
|
||||||
is in error. Furthermore, you can only consume one field at a time, on the same object. Thus
|
is in error. Furthermore, you can only consume one field at a time, on the same object. The
|
||||||
if you have retrieved `content["bids"].get_array()` and you later call `content["asks"].get_array()`, then the
|
value instance you get from `content["bids"]` becomes invalid when you call `content["asks"]`.
|
||||||
first array should no longer be accessed: it would be unsafe to do so. You can detect such mistakes by first
|
If you have retrieved `content["bids"].get_array()` and you later call
|
||||||
compiling and running the code in Debug mode: an OUT_OF_ORDER_ITERATION error is generated.
|
`content["asks"].get_array()`, then the first array should no longer be accessed: it would be
|
||||||
|
unsafe to do so. You can detect such mistakes by first compiling and running the code in
|
||||||
|
Debug mode: an OUT_OF_ORDER_ITERATION error is generated.
|
||||||
|
|
||||||
> NOTE: JSON allows you to escape characters in keys. E.g., the key `"date"` may be written as
|
> NOTE: JSON allows you to escape characters in keys. E.g., the key `"date"` may be written as
|
||||||
> `"\u0064\u0061\u0074\u0065"`. By default, simdjson does *not* unescape keys when matching by default.
|
> `"\u0064\u0061\u0074\u0065"`. By default, simdjson does *not* unescape keys when matching by default.
|
||||||
@@ -307,8 +371,9 @@ support for users who avoid exceptions. See [the simdjson error handling documen
|
|||||||
> to support escaped keys, the method `unescaped_key()` provides the desired unescaped keys by
|
> to support escaped keys, the method `unescaped_key()` provides the desired unescaped keys by
|
||||||
> parsing and writing out the unescaped keys to a string buffer and returning a `std::string_view`
|
> parsing and writing out the unescaped keys to a string buffer and returning a `std::string_view`
|
||||||
> instance. You should expect a performance penalty when using `unescaped_key()`.
|
> instance. You should expect a performance penalty when using `unescaped_key()`.
|
||||||
|
>
|
||||||
> ```c++
|
> ```c++
|
||||||
> auto json = R"({"k\u0065y": 1})"_padded;
|
> auto json = R"({"k\u0065y": 1})"_padded;
|
||||||
> ondemand::parser parser;
|
> ondemand::parser parser;
|
||||||
> auto doc = parser.iterate(json);
|
> auto doc = parser.iterate(json);
|
||||||
> ondemand::object object = doc.get_object();
|
> ondemand::object object = doc.get_object();
|
||||||
@@ -415,11 +480,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;
|
||||||
@@ -439,14 +505,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;
|
||||||
@@ -466,8 +533,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.
|
||||||
|
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()`.
|
`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) {
|
||||||
@@ -516,7 +595,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:
|
||||||
|
// We check that the value is indeed null
|
||||||
|
// otherwise: an error is thrown.
|
||||||
|
if(element.is_null()) {
|
||||||
cout << "null";
|
cout << "null";
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -581,6 +664,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++
|
||||||
@@ -769,10 +887,17 @@ auto error = parser.iterate(json).get(doc);
|
|||||||
if (error) { cerr << error << endl; exit(1); }
|
if (error) { cerr << error << endl; exit(1); }
|
||||||
```
|
```
|
||||||
|
|
||||||
When there is no error, the error code simdjson::SUCCESS is returned: it evaluates as false as a Boolean.
|
When there is no error, the error code `simdjson::SUCCESS`is returned: it evaluates as false as a Boolean.
|
||||||
We have several error codes to indicate errors, they all evaluate to true as a Boolean: your software should not generally not depend on exact
|
We have several error codes to indicate errors, they all evaluate to true as a Boolean: your software should not generally not depend on exact
|
||||||
error codes. We may change the error codes in future releases and the exact error codes could vary depending on your system.
|
error codes. We may change the error codes in future releases and the exact error codes could vary depending on your system.
|
||||||
|
|
||||||
|
Some errors are recoverable:
|
||||||
|
|
||||||
|
* You may get the error `simdjson::INCORRECT_TYPE` after trying to convert a value to an incorrect type: e.g., you expected a number and try to convert the value to a number, but it is an array.
|
||||||
|
* You may query a key from an object, but the key is missing in which case you get the error `simdjson::NO_SUCH_FIELD`: e.g., you call `obj["myname"]` and the object does not have a key `"myname"`.
|
||||||
|
|
||||||
|
Other errors (e.g., `simdjson::INCOMPLETE_ARRAY_OR_OBJECT`) may indicate a fatal error and often follow from the fact that the document is not valid JSON. In which case, it is no longer possible to continue accessing the document: calling the method `is_alive()` on the document instance returns false. All following accesses will keep returning the same fatal error (e.g., `simdjson::INCOMPLETE_ARRAY_OR_OBJECT`).
|
||||||
|
|
||||||
When you use the code without exceptions, it is your responsibility to check for error before using the
|
When you use the code without exceptions, it is your responsibility to check for error before using the
|
||||||
result: if there is an error, the result value will not be valid and using it will caused undefined behavior. Most compilers should be able to help you if you activate the right
|
result: if there is an error, the result value will not be valid and using it will caused undefined behavior. Most compilers should be able to help you if you activate the right
|
||||||
set of warnings: they can identify variables that are written to but never otherwise accessed.
|
set of warnings: they can identify variables that are written to but never otherwise accessed.
|
||||||
@@ -915,11 +1040,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; }
|
||||||
|
|
||||||
@@ -934,7 +1059,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;
|
||||||
@@ -956,6 +1081,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.
|
||||||
@@ -965,10 +1103,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; }
|
||||||
@@ -994,7 +1134,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
|
||||||
@@ -1017,6 +1157,28 @@ int main(void) {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
You can do handle errors gracefully as well...
|
||||||
|
|
||||||
|
```C++
|
||||||
|
#include <iostream>
|
||||||
|
#include "simdjson.h"
|
||||||
|
int main(void) {
|
||||||
|
simdjson::ondemand::parser parser;
|
||||||
|
simdjson::padded_string json_string;
|
||||||
|
simdjson::ondemand::document doc;
|
||||||
|
try {
|
||||||
|
json_string = padded_string::load("twitter.json");
|
||||||
|
doc = parser.iterate(json_string);
|
||||||
|
uint64_t identifier = doc["statuses"].at(0)["id"];
|
||||||
|
std::cout << identifier << std::endl;
|
||||||
|
} catch (simdjson::simdjson_error &error) {
|
||||||
|
std::cerr << "JSON error: " << error.what() << " near "
|
||||||
|
<< doc.current_location() << " in " << json_string << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
### 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
|
||||||
@@ -1033,6 +1195,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)
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@@ -1081,6 +1249,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:
|
||||||
|
|
||||||
@@ -1089,7 +1260,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] "
|
||||||
@@ -1106,6 +1277,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
|
||||||
----------
|
----------
|
||||||
|
|
||||||
@@ -1144,41 +1341,6 @@ internal string buffer. Thus you should consume values only once
|
|||||||
even if you can iterate through the array or object more than once.
|
even if you can iterate through the array or object more than once.
|
||||||
If you unescape a string within an array more than once, you have unsafe code.
|
If you unescape a string within an array more than once, you have unsafe code.
|
||||||
|
|
||||||
Direct Access to the Raw String
|
|
||||||
--------------------------------
|
|
||||||
|
|
||||||
The simdjson library makes explicit assumptions about types. For examples, numbers
|
|
||||||
must be integers (up to 64-bit integers) or binary64 floating-point numbers. Some users
|
|
||||||
have different needs. For example, some users might want to support big integers.
|
|
||||||
The library makes this possible by providing a `raw_json_token` method which returns
|
|
||||||
a `std::string_view` instance containing the value as a string which you may then
|
|
||||||
parse as you see fit.
|
|
||||||
|
|
||||||
```C++
|
|
||||||
simdjson::ondemand::parser parser;
|
|
||||||
simdjson::padded_string docdata = R"({"value":12321323213213213213213213213211223})"_padded;
|
|
||||||
simdjson::ondemand::document doc = parser.iterate(docdata);
|
|
||||||
simdjson::ondemand::object obj = doc.get_object();
|
|
||||||
std::string_view token = obj["value"].raw_json_token();
|
|
||||||
// token has value 12321323213213213213213213213211223, it points inside the input string
|
|
||||||
```
|
|
||||||
|
|
||||||
The `raw_json_token` method even works when the JSON value is a string. In such cases, it
|
|
||||||
will return the complete string with the quotes and with eventual escaped sequences as in the
|
|
||||||
source document.
|
|
||||||
|
|
||||||
```C++
|
|
||||||
simdjson::ondemand::parser parser;
|
|
||||||
simdjson::padded_string docdata = R"({"value":"12321323213213213213213213213211223"})"_padded;
|
|
||||||
simdjson::ondemand::document doc = parser.iterate(docdata);
|
|
||||||
simdjson::ondemand::object obj = doc.get_object();
|
|
||||||
string_view token = obj["value"].raw_json_token();
|
|
||||||
// token has value "12321323213213213213213213213211223", it points inside the input string
|
|
||||||
```
|
|
||||||
|
|
||||||
The `raw_json_token()` should be fast and free of allocation.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Newline-Delimited JSON (ndjson) and JSON lines
|
Newline-Delimited JSON (ndjson) and JSON lines
|
||||||
----------------------------------------------
|
----------------------------------------------
|
||||||
@@ -1267,10 +1429,9 @@ This parser can't support a document that big
|
|||||||
|
|
||||||
If your documents are large (e.g., larger than a megabyte), then the `iterate_many` function is maybe ill-suited. It is really meant to support reading efficiently streams of relatively small documents (e.g., a few kilobytes each). If you have larger documents, you should use other functions like `iterate`.
|
If your documents are large (e.g., larger than a megabyte), then the `iterate_many` function is maybe ill-suited. It is really meant to support reading efficiently streams of relatively small documents (e.g., a few kilobytes each). If you have larger documents, you should use other functions like `iterate`.
|
||||||
|
|
||||||
|
We also provide some support for comma-separated documents and other advanced features.
|
||||||
See [iterate_many.md](iterate_many.md) for detailed information and design.
|
See [iterate_many.md](iterate_many.md) for detailed information and design.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Parsing Numbers Inside Strings
|
Parsing Numbers Inside Strings
|
||||||
------------------------------
|
------------------------------
|
||||||
|
|
||||||
@@ -1367,6 +1528,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
|
||||||
------------------------------
|
------------------------------
|
||||||
@@ -1445,6 +1608,114 @@ It will output:
|
|||||||
9999999999999999999 negative: 0 is_integer: 1 large 64-bit integer: 9999999999999999999 large 64-bit integer: 9999999999999999999
|
9999999999999999999 negative: 0 is_integer: 1 large 64-bit integer: 9999999999999999999 large 64-bit integer: 9999999999999999999
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Raw Strings
|
||||||
|
-----------
|
||||||
|
|
||||||
|
It is sometimes useful to have access to a raw (unescaped) string: we make available a
|
||||||
|
minimalist `raw_json_string` data type which contains a pointer inside the string in the
|
||||||
|
original document, right after the quote. It is accessible via `get_raw_json_string()` on a
|
||||||
|
string instance and returned by the `key()` method on an object's field instance. It is always
|
||||||
|
optional: replacing `get_raw_json_string()` with `get_string()` and `key()` by
|
||||||
|
`unescaped_key()` returns an `string_view` instance of the unescaped string.
|
||||||
|
|
||||||
|
You can quickly compare a `raw_json_string` instance with a target string. You may also
|
||||||
|
unescape the `raw_json_string` on your own string buffer: `parser.unescape(mystr, ptr)`
|
||||||
|
advances the provided pointer `ptr` and returns a string_view instance on the newly serialized
|
||||||
|
string upon success, otherwise it returns an error. When unescaping to your own string buffer,
|
||||||
|
you should ensure that you have sufficient memory space: the total size of the strings plus
|
||||||
|
`simdjson::SIMDJSON_PADDING` bytes. The following example illustrates how we can unescape
|
||||||
|
JSON string to a user-provided buffer:
|
||||||
|
|
||||||
|
```C++
|
||||||
|
auto json = R"( {"name": "Jack The Ripper \u0033"} )"_padded;
|
||||||
|
// We create a buffer large enough to store all strings we need:
|
||||||
|
std::unique_ptr<uint8_t[]> buffer(new uint8_t[json.size() + simdjson::SIMDJSON_PADDING]);
|
||||||
|
uint8_t * ptr = buffer.get();
|
||||||
|
ondemand::parser parser;
|
||||||
|
ondemand::document doc = parser.iterate(json);
|
||||||
|
// We store our strings as 'string_view' instances in a vector:
|
||||||
|
std::vector<std::string_view> mystrings;
|
||||||
|
for (auto key_value : doc.get_object()) {
|
||||||
|
std::string_view keysv = parser.unescape(key_value.key(), ptr);// writes 'name'
|
||||||
|
mystrings.push_back(keysv);
|
||||||
|
std::string_view valuesv = parser.unescape(key_value.value().get_raw_json_string(), ptr);
|
||||||
|
// writes 'Jack The Ripper 3', escaping the \u0033
|
||||||
|
mystrings.push_back(valuesv);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
General Direct Access to the Raw JSON String
|
||||||
|
--------------------------------
|
||||||
|
If your value is a string, the `raw_json_string` gives you direct access to the unprocess
|
||||||
|
string. The simdjson library allows you to have access to the raw underlying JSON
|
||||||
|
more generally.
|
||||||
|
|
||||||
|
The simdjson library makes explicit assumptions about types. For examples, numbers
|
||||||
|
must be integers (up to 64-bit integers) or binary64 floating-point numbers. Some users
|
||||||
|
have different needs. For example, some users might want to support big integers.
|
||||||
|
The library makes this possible by providing a `raw_json_token` method which returns
|
||||||
|
a `std::string_view` instance containing the value as a string which you may then
|
||||||
|
parse as you see fit.
|
||||||
|
|
||||||
|
```C++
|
||||||
|
simdjson::ondemand::parser parser;
|
||||||
|
simdjson::padded_string docdata = R"({"value":12321323213213213213213213213211223})"_padded;
|
||||||
|
simdjson::ondemand::document doc = parser.iterate(docdata);
|
||||||
|
simdjson::ondemand::object obj = doc.get_object();
|
||||||
|
std::string_view token = obj["value"].raw_json_token();
|
||||||
|
// token has value 12321323213213213213213213213211223, it points inside the input string
|
||||||
|
```
|
||||||
|
|
||||||
|
The `raw_json_token` method even works when the JSON value is a string. In such cases, it
|
||||||
|
will return the complete string with the quotes and with eventual escaped sequences as in the
|
||||||
|
source document.
|
||||||
|
|
||||||
|
```C++
|
||||||
|
simdjson::ondemand::parser parser;
|
||||||
|
simdjson::padded_string docdata = R"({"value":"12321323213213213213213213213211223"})"_padded;
|
||||||
|
simdjson::ondemand::document doc = parser.iterate(docdata);
|
||||||
|
simdjson::ondemand::object obj = doc.get_object();
|
||||||
|
string_view token = obj["value"].raw_json_token();
|
||||||
|
// token has value "12321323213213213213213213213211223", it points inside the input string
|
||||||
|
```
|
||||||
|
|
||||||
|
The `raw_json_token()` should be fast and free of allocation.
|
||||||
|
|
||||||
|
If you value is an array or an object, `raw_json_token()` returns effectively a single
|
||||||
|
character (`[`) or (`}`) which is not very useful. For arrays and objects, we have another
|
||||||
|
method called `raw_json()` which consumes (traverse) the array or the object.
|
||||||
|
|
||||||
|
```C++
|
||||||
|
simdjson::ondemand::parser parser;
|
||||||
|
simdjson::padded_string docdata = R"({"value":123})"_padded;
|
||||||
|
simdjson::ondemand::document doc = parser.iterate(docdata);
|
||||||
|
simdjson::ondemand::object obj = doc.get_object();
|
||||||
|
string_view token = obj.raw_json(); // gives you `{"value":123}`
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
```C++
|
||||||
|
simdjson::ondemand::parser parser;
|
||||||
|
simdjson::padded_string docdata = R"([1,2,3])"_padded;
|
||||||
|
simdjson::ondemand::document doc = parser.iterate(docdata);
|
||||||
|
simdjson::ondemand::array arr = doc.get_array();
|
||||||
|
string_view token = arr.raw_json(); // gives you `[1,2,3]`
|
||||||
|
```
|
||||||
|
|
||||||
|
Because `raw_json()` consumes to object or the array, if you want to both have
|
||||||
|
access to the raw string, and also use the array or object, you should call `reset()`.
|
||||||
|
|
||||||
|
```C++
|
||||||
|
simdjson::ondemand::parser parser;
|
||||||
|
simdjson::padded_string docdata = R"({"value":123})"_padded;
|
||||||
|
simdjson::ondemand::document doc = parser.iterate(docdata);
|
||||||
|
simdjson::ondemand::object obj = doc.get_object();
|
||||||
|
string_view token = obj.raw_json(); // gives you `{"value":123}`
|
||||||
|
obj.reset(); // revise the object
|
||||||
|
uint64_t x = obj["value"]; // gives me 123
|
||||||
|
```
|
||||||
|
|
||||||
Thread Safety
|
Thread Safety
|
||||||
-------------
|
-------------
|
||||||
|
|
||||||
@@ -1466,7 +1737,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.
|
||||||
@@ -1485,3 +1756,217 @@ 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.
|
||||||
|
- Never seek to access a field twice (e.g., o["data"] and later again o["data"]). Instead capture once an ondemand::value and reuse it.
|
||||||
|
- If you must access several different keys in an object, it might be preferable to iterate through all the fields in the object instead, and branch on the field keys.
|
||||||
|
- If possible, refer to each object and array in your code once. For example, the following code repeatedly refers to the `"data"` key to create an object...
|
||||||
|
```C++
|
||||||
|
std::string_view make = o["data"]["make"];
|
||||||
|
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. Importantly, unless `SIMDJSON_VERBOSE_LOGGING` is defined, logging is entirely disabled and thus carries no overhead.
|
||||||
@@ -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,8 +104,8 @@ 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)`) or a prettified string version (`simdjson::prettify(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
|
||||||
@@ -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.
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user