Compare commits

...

62 Commits

Author SHA1 Message Date
Daniel Lemire 7382dc2be8 preparing patch release 3.12.3 (#2357) 2025-03-28 11:26:19 -04:00
Daniel Lemire 8c14e0c56f fixing issue 2354: get_bool() on document with trailing spaces (#2356) 2025-03-27 15:01:10 -04:00
Daniel Lemire a9a62feb75 Map proto (#2353)
* std::map support

* completed

---------

Co-authored-by: Daniel Lemire <dlemire@lemire.me>
2025-03-23 16:32:48 -04:00
Ezequiel Ramis Folberg b9228b4d3c Update README.md (#2352) 2025-03-22 15:49:02 -04:00
Dirk Stolle 726c3eb611 fix several typos (#2348) 2025-03-17 09:57:08 -04:00
Daniel Lemire 4cdc4f18ef documenting fatal errors 2025-03-13 13:26:50 -04:00
Dirk Eddelbuettel f3b034ac38 Address 'whitespace in literal' decreation warning from clang++-20 2025-03-06 14:28:01 -06:00
Daniel Lemire 9c2e8a8f39 upgrading uraimo/run-on-arch-action 2025-03-01 14:32:13 -05:00
yun dfa43f6cdd doc: replace ndjson[dot]org with ndjson spec (#2340)
the `ndjson[dot]org` expired, and point to incorrect website with malware.
more in https://github.com/ndjson/ndjson.github.io/issues/24

follow up #2234
2025-02-21 09:07:39 +00:00
Daniel Lemire 797e61742c release bump 2025-02-14 16:12:28 -05:00
Daniel Lemire f289412e0a fixing performance issue under Zen 4 processors (#2335)
* fixing performance issue under Zen 4 processors

* trying something else

---------

Co-authored-by: Daniel Lemire <dlemire@lemire.me>
2025-02-14 16:11:36 -05:00
Daniel Lemire 7bd79b4445 Update README.md 2025-02-14 16:03:01 -05:00
Daniel Lemire 078e2c9073 patch release 3.12.1 2025-02-11 13:46:03 -05:00
Daniel Lemire d7b6b20511 creating zip files. 2025-02-11 13:43:34 -05:00
Daniel Lemire dbea3bbd62 Update README.md 2025-01-29 11:48:36 -05:00
Daniel Lemire e422933414 release 3.12.0 2025-01-27 20:35:57 -05:00
Daniel Lemire de4d69b367 Introducing dual licensing (#2328)
* Introducing dual licensing

* adding missing file
2025-01-27 20:34:35 -05:00
Paul Dreik b8675a7f7b fix fuzzing when running on icelake (#2327) 2025-01-26 05:36:33 +01:00
Paul Dreik 5642bb93a4 fix fuzzer CI job (#2324) 2025-01-16 13:33:53 -05:00
Daniel Lemire 1b23a77e03 3.11.6 2025-01-14 21:33:29 -05:00
Daniel Lemire 57699bfed8 release candidate (#2323) 2025-01-09 11:01:48 -05:00
Daniel Lemire 648303b26a typo 2025-01-08 21:29:11 -05:00
Daniel Lemire 9008960e36 fixed comment 2025-01-08 20:35:30 -05:00
Daniel Lemire 8a9e8a1792 fixing issue 2322 2025-01-08 20:28:25 -05:00
Daniel Lemire ba33e9e78f release 2025-01-06 19:33:53 -05:00
Daniel Lemire d98b351eef let us be more careful with concepts, we require __cpp_concepts >= 201907L and check for old versions of Apple clang (#2321)
* let us be more careful with concepts, we require __cpp_concepts >= 202002L

* checking Apple version

* let us be more specific

* removing extra endif
2025-01-06 19:23:09 -05:00
Daniel Lemire 5488dca126 Accidentally, it appears that PPC64 was always disabled by default. (#2320) 2025-01-03 11:01:04 -05:00
Daniel Lemire 7712ecf164 adding char bit check (pedantic) (#2316) 2024-12-31 14:34:13 -05:00
Paul Dreik 2803ca3093 use clang 19 in fuzzer job (#2315)
* use clang 19 in fuzzer job

* fix syntax error in msys2-clang.yml
2024-12-22 15:00:58 -05:00
Daniel Lemire e7f2463920 some tweaks 2024-12-17 16:27:31 -05:00
Daniel Lemire 5bfa0b098c patch release 3.11.3 (#2313)
* preparing patch release 3.11.3
2024-12-12 13:38:22 -05:00
Daniel Lemire f7ba9cb11b Update basics.md 2024-12-10 11:47:21 -05:00
Daniel Lemire d4bf0cc7ec sync 2024-12-09 21:36:43 -05:00
Daniel Lemire 2fbbea0b15 Merge branch 'master' of github.com:simdjson/simdjson 2024-12-09 21:36:12 -05:00
Daniel Lemire c16486f702 release candidate 3.11.2 2024-12-09 21:35:21 -05:00
zhanglistar f615112093 Disabling memory sanitizer with parse_string (#2310) 2024-12-09 10:20:33 -05:00
Daniel Lemire 6bbcbfbb95 version 3.11.1 2024-12-07 11:13:00 -05:00
Valery Mironov e6578fea39 Fix missing override (#2305) 2024-12-07 11:12:25 -05:00
Joyee Cheung 6fb050d04e fix: fix deprecation from -Wdeprecated-literal-operator (#2307)
Otherwise simdjson doesn't build with V8's Node.js fork, which
uses -Werror,-Wdeprecated-literal-operator and latest version
of clang.
2024-12-07 11:12:14 -05:00
Daniel Lemire b4242d3b4f release candidate (#2304) 2024-12-05 22:05:39 -05:00
Daniel Lemire cbfe2d4a21 Update vs17-arm-ci.yml 2024-12-02 20:24:24 -05:00
halx99 79126ca323 fix: processor checks inconsistently problem (#2299) 2024-12-02 20:23:28 -05:00
Daniel Lemire 3f87f958d7 documentation 2024-12-02 00:06:20 -05:00
Daniel Lemire cab383e1de Update README.md 2024-11-30 20:43:20 -05:00
Daniel Lemire 9b314922a1 additional documentation 2024-11-08 11:53:34 -05:00
Daniel Lemire 587beae307 prevent int to pointer implicit conversion for operator[](const char *) (#2286) 2024-11-01 18:11:43 -04:00
Daniel Lemire f53981d945 Update dom.md 2024-11-01 12:23:35 -04:00
Daniel Lemire 41b4ffd6aa Update basics.md 2024-11-01 12:15:40 -04:00
Daniel Lemire 6cd8a6d776 adding pad function (#2283) 2024-10-29 21:26:01 -04:00
Daniel Lemire 3c0d032ded Candidate for C++20 deserialization features (#2276)
* tag_invoke based custom types (#2219)

* tag_invoke based custom types

Now you can use tag_invoke to add a custom type or a group of custom types.

* Fixing macro usage + Fixing noexcept

* Fixing the usage of #include

We don't need <concepts> at all seems like it

* Fixing tag_invoke impl for MSVC

* Making `tag_invoke` to support `ondemand::document` as well + docs (#2228)

* Making `tag_invoke` to support `ondemand::document` as well + docs

* Fix typos and doc update by @lemire

Co-authored-by: Daniel Lemire <daniel@lemire.me>

* Better docs by @lemire

Co-authored-by: Daniel Lemire <daniel@lemire.me>

* Preserving the old, disallowing in the new

I'm disabling `document::get() &&` if the user has provided a `tag_invoke`d version; otherwise, we retain the compatibility.

---------

Co-authored-by: Daniel Lemire <daniel@lemire.me>

* fix: correct small issues with deserialize (#2232)

* Extending the deserialization code with more defaults + docs (#2233)

* Make custom types easier with some predefined cases + docs

* missing include

* adding Ubuntu 24 CXX 20

* using concepts all the way

* minor tweak

* tiny tweak

* tweaks

* more tweaking

* saving

---------

Co-authored-by: Daniel Lemire <dlemire@lemire.me>

* Making `tag_invoke` a "put" as opposed to a "get" (#2256)

* fix: add tests related to issue 2227 (#2229)

* fix: add tests related to issue 2227

* avoiding name clash

* pedantic fix

* deprecate rvalue get on document

* selectively deprecating

* Fix ndjson spec link (#2234)

* fix ndjson spec link

The link in the readme of parse_many links to a casino spam site

* fix link

* [no-ci] Update README.md

* Make simdjson compile again

* Enable SIMDJSON_SINGLEHEADER=OFF in VS Code

With singleheader on, clangd can't find the right
include files.

* Add missing include directives to static build targets of simdjson. (#2240)

* adding a warning

* adding warning regarding SIMDJSON_BUILD_STATIC_LIB

* release candidate

* pedantic viable size

* Making tag_invoke a feeder instead of a producer

* adding missing undef silencer (#2253)

* Ignore pragma once when amalgamating source files (#2248)

With gcc it causes an error in `simdjson.cpp`:
```
simdjson.cpp:548:9: warning: #pragma once in main file
  548 | #pragma once
      |         ^~~~
```

It had previously been commented out in:
https://github.com/simdjson/simdjson/commit/6ef555e6fb79363fae057a9a46b52cd208d9e305

However, this was lost in an upgrade:
https://github.com/simdjson/simdjson/commit/2a4ff7346813b120f2b5b40e95d69352b593cc9c

* Update CI (#2254)

* adding missing undef silencer

* Updating CI

* more fixes

* fix

* big endian fix

* Moving to the new tag_invoke signature

* Fix nlohmann ambiguity on C++23-enabled clang

* Revert "Merge branch 'master' of https://github.com/simdjson/simdjson into builder_development_branch_extra"

This reverts commit 3eeecbab34, reversing
changes made to 6858b208b4.

---------

Co-authored-by: Daniel Lemire <daniel@lemire.me>
Co-authored-by: Sasha Lopoukhine <superlopuh@gmail.com>
Co-authored-by: John Keiser <john@johnkeiser.com>
Co-authored-by: Tan Li Boon <undisputed-seraphim@users.noreply.github.com>
Co-authored-by: tobil4sk <tobil4sk@outlook.com>

* update CI on the builder_development_branch (no code change) (#2262)

* typo

* General madness simpler, no simpler!!! (#2267)

* Minimal tag_invokes for STL types

* simpler madness

* adding a comment

* missing file

* minor tweaks to style

* fixing incorrect max/min usage

* updating single

* simplify

* validating the idea

* putting back the concept

* moving the include

* guarding

* Cheap General Madness (#2268)

* Some General Concepts and their deserializations

* Resolving ambiguity

* Add missing #include

* C++20 custom deserializer: better documentation (#2269)

* mostly a documentation update.

* missing cpp

* [no-ci] fix comment

* various minor fixes

---------

Co-authored-by: Daniel Lemire <dlemire@lemire.me>

---------

Co-authored-by: M. Bahoosh <12122474+the-moisrex@users.noreply.github.com>
Co-authored-by: Daniel Lemire <dlemire@lemire.me>
Co-authored-by: M. Bahoosh <moisrex@gmail.com>

* minor update

* More documentation regarding builder (#2270)

* minor update

* more improvment to our documentation (builder branch)

* putting back missing functions

* merge candidate

---------

Co-authored-by: M. Bahoosh <moisrex@gmail.com>
Co-authored-by: Daniel Lemire <dlemire@lemire.me>
Co-authored-by: Sasha Lopoukhine <superlopuh@gmail.com>
Co-authored-by: John Keiser <john@johnkeiser.com>
Co-authored-by: Tan Li Boon <undisputed-seraphim@users.noreply.github.com>
Co-authored-by: tobil4sk <tobil4sk@outlook.com>
Co-authored-by: M. Bahoosh <12122474+the-moisrex@users.noreply.github.com>
2024-10-18 20:37:38 -04:00
Daniel Lemire 36f5dbcb75 documentation for threading... (#2277)
* documentation for threading...

* remove const

* doc
2024-10-11 12:34:11 -04:00
Daniel Lemire 49901fb254 doc 2024-10-10 21:32:51 -04:00
Daniel Lemire c066b5421b Jsonpath (#2272)
* Add support for JSONPath with '$' prefix and integrate into dom::at_path (#2266)

- Updated `json_path_to_pointer_conversion` to support JSONPath starting with the '$' prefix, while maintaining compatibility with the existing implementation.
- Moved `json_path_to_pointer_conversion` to a separate header file for better modularity and to support JSONPath queries in `dom` mode.
- Implemented `at_path` functionality in `dom` mode to enable querying JSON using JSONPath.
- Added unit tests to validate the new JSONPath support in `dom` mode and ensure compatibility with both standard and existing JSONPath formats.

* two minor fixes

* more tests and documentation

* damn compiler warnings

* more documentation fixes

---------

Co-authored-by: Zhengguo Yang <yangzhgg@gmail.com>
2024-10-08 10:37:59 -04:00
Daniel Lemire ec7550a70e fixes issue 2271 (#2273) 2024-10-08 10:36:12 -04:00
Daniel Lemire 3ef3078e51 documentation for issue 2259 (clarifying) (#2260) 2024-09-21 09:10:35 -04:00
tobil4sk fd06782c97 Make document::is_null behavior consistent with documentation (#2258)
* Make null-like value test consistent with docs

According to the docs: `INCORRECT_TYPE If the JSON value begins with 'n'
and is not 'null'.`

* Match document::is_null behavior to documentation

* Test other token beginning with n with is_null
2024-09-20 20:58:41 -04:00
Daniel Lemire 9303efbd0c [no-ci] Update basics.md 2024-09-20 20:56:11 -04:00
Daniel Lemire 6c979f15cc deps: switch to CPM (#2257)
* deps: switch to CPM

* missing file

* setting the dependencies on URL download

* using fixed version of cxxopts
2024-09-20 13:29:47 -04:00
Daniel Lemire 09ccabbe6c enable BMI, but only when LLVM is the compiler (#2255) 2024-09-20 10:59:54 -04:00
Daniel Lemire e00cc8c6dc Update CI (#2254)
* adding missing undef silencer

* Updating CI

* more fixes

* fix

* big endian fix
2024-09-18 09:09:11 -04:00
tobil4sk c10b32d463 Ignore pragma once when amalgamating source files (#2248)
With gcc it causes an error in `simdjson.cpp`:
```
simdjson.cpp:548:9: warning: #pragma once in main file
  548 | #pragma once
      |         ^~~~
```

It had previously been commented out in:
https://github.com/simdjson/simdjson/commit/6ef555e6fb79363fae057a9a46b52cd208d9e305

However, this was lost in an upgrade:
https://github.com/simdjson/simdjson/commit/2a4ff7346813b120f2b5b40e95d69352b593cc9c
2024-09-17 15:41:12 -04:00
Daniel Lemire 025a44348a adding missing undef silencer (#2253) 2024-09-16 21:04:09 -04:00
109 changed files with 14897 additions and 5990 deletions
+29
View File
@@ -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@v4
- uses: uraimo/run-on-arch-action@v3
name: Test
id: runcmd
with:
arch: aarch64
distro: ubuntu_latest
githubToken: ${{ github.token }}
install: |
apt-get update -q -y
apt-get install -y cmake make g++
run: |
cmake -DSIMDJSON_SANITIZE_UNDEFINED=ON -DSIMDJSON_DEVELOPER_MODE=ON -DSIMDJSON_COMPETITION=OFF -B build
cmake --build build -j=2
ctest --output-on-failure --test-dir build
+1 -1
View File
@@ -17,7 +17,7 @@ jobs:
fuzz-seconds: 600
dry-run: false
- name: Upload Crash
uses: actions/upload-artifact@v1
uses: actions/upload-artifact@v4
if: failure() && steps.build.outcome == 'success'
with:
name: artifacts
+2 -3
View File
@@ -1,9 +1,8 @@
name: Doxygen GitHub Pages
on:
push:
branches:
- master
release:
types: [created]
# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
@@ -24,7 +24,7 @@ jobs:
echo "no trailing whitespace found, good!"
fi
- name: Archive whitespace patch
uses: actions/upload-artifact@v2
uses: actions/upload-artifact@v4
if: always()
with:
name: whitespace-patch
+4 -4
View File
@@ -24,7 +24,7 @@ jobs:
implementations: haswell westmere fallback
UBSAN_OPTIONS: halt_on_error=1
MAXLEN: -max_len=4000
CLANGVERSION: 15
CLANGVERSION: 19
# which optimization level to use for the sanitizer build (see build_fuzzer.variants.sh)
OPTLEVEL: -O3
@@ -125,7 +125,7 @@ jobs:
done
- name: Save the corpus as a github artifact
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: corpus
path: corpus.tar
@@ -148,7 +148,7 @@ jobs:
run: tar cf valgrind.tar valgrind-*.txt
- name: Save valgrind output as a github artifact
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
if: always()
with:
name: valgrindresults
@@ -156,7 +156,7 @@ jobs:
if-no-files-found: ignore
- name: Archive any crashes as an artifact
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
if: always()
with:
name: crashes
+1 -1
View File
@@ -20,7 +20,7 @@ jobs:
- msystem: "MINGW64"
install: mingw-w64-x86_64-libxml2 mingw-w64-x86_64-cmake mingw-w64-x86_64-ninja mingw-w64-x86_64-clang
type: Debug
- msystem: "MINGW64"
- msystem: "MINGW64"
install: mingw-w64-x86_64-libxml2 mingw-w64-x86_64-cmake mingw-w64-x86_64-ninja mingw-w64-x86_64-clang
type: RelWithDebInfo
env:
+1 -1
View File
@@ -22,7 +22,7 @@ jobs:
- msystem: "MINGW64"
install: mingw-w64-x86_64-cmake mingw-w64-x86_64-ninja mingw-w64-x86_64-gcc
type: Debug
- msystem: "MINGW64"
- msystem: "MINGW64"
install: mingw-w64-x86_64-cmake mingw-w64-x86_64-ninja mingw-w64-x86_64-gcc
type: RelWithDebInfo
env:
+2 -2
View File
@@ -13,7 +13,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: uraimo/run-on-arch-action@v2
- uses: uraimo/run-on-arch-action@v3
name: Test
id: runcmd
with:
@@ -24,6 +24,6 @@ jobs:
apt-get update -q -y
apt-get install -y cmake make g++
run: |
cmake -DCMAKE_BUILD_TYPE=Release -B build
cmake -DCMAKE_BUILD_TYPE=Release -DSIMDJSON_DEVELOPER_MODE=ON -DSIMDJSON_COMPETITION=OFF -B build
cmake --build build -j=2
ctest --output-on-failure --test-dir build
+2 -2
View File
@@ -13,7 +13,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: uraimo/run-on-arch-action@v2
- uses: uraimo/run-on-arch-action@v3
name: Test
id: runcmd
with:
@@ -24,6 +24,6 @@ jobs:
apt-get update -q -y
apt-get install -y cmake make g++
run: |
cmake -DCMAKE_BUILD_TYPE=Release -B build
cmake -DCMAKE_BUILD_TYPE=Release -DSIMDJSON_DEVELOPER_MODE=ON -DSIMDJSON_COMPETITION=OFF -B build
cmake --build build -j=2
ctest --output-on-failure --test-dir build
+2 -2
View File
@@ -13,7 +13,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: uraimo/run-on-arch-action@v2
- uses: uraimo/run-on-arch-action@v3
name: Test
id: runcmd
with:
@@ -24,6 +24,6 @@ jobs:
apt-get update -q -y
apt-get install -y cmake make g++
run: |
cmake -DCMAKE_BUILD_TYPE=Release -B build
cmake -DCMAKE_BUILD_TYPE=Release -DSIMDJSON_DEVELOPER_MODE=ON -DSIMDJSON_COMPETITION=OFF -B build
cmake --build build -j=2
ctest --output-on-failure --test-dir build
+22
View File
@@ -0,0 +1,22 @@
name: Ubuntu 24.04 CI (CXX 20)
on: [push, pull_request]
jobs:
ubuntu-build:
if: >-
! contains(toJSON(github.event.commits.*.message), '[skip ci]') &&
! contains(toJSON(github.event.commits.*.message), '[skip github]')
runs-on: ubuntu-24.04
strategy:
matrix:
cxx: [g++-13, clang++-16]
steps:
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
- name: Prepare
run: cmake -DSIMDJSON_CXX_STANDARD=20 -DSIMDJSON_DEVELOPER_MODE=ON -B build
env:
CXX: ${{matrix.cxx}}
- name: Build
run: cmake --build build -j=2
- name: Test
run: ctest --output-on-failure --test-dir build
+1 -2
View File
@@ -10,7 +10,6 @@ jobs:
fail-fast: false
matrix:
include:
- {arch: ARM}
- {arch: ARM64}
- {arch: ARM64EC}
steps:
@@ -19,4 +18,4 @@ jobs:
- name: Use cmake
run: |
cmake -A ${{ matrix.arch }} -DCMAKE_SYSTEM_VERSION="10.0.22621.0" -DCMAKE_CROSSCOMPILING=1 -DSIMDJSON_DEVELOPER_MODE=ON -D SIMDJSON_GOOGLE_BENCHMARKS=OFF -DSIMDJSON_EXCEPTIONS=OFF -B build &&
cmake --build build --verbose
cmake --build build --verbose
+4 -4
View File
@@ -26,15 +26,15 @@ jobs:
run: |
cmake -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 ${{build_type}} --verbose
run: cmake --build build --config ${{matrix.build_type}} --verbose
- name: Run tests
run: |
cd build
ctest -C ${{build_type}} -LE explicitonly --output-on-failure
ctest -C ${{matrix.build_type}} -LE explicitonly --output-on-failure
- name: Install
run: |
cmake --install build --config ${{build_type}}
cmake --install build --config ${{matrix.build_type}}
- 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 ${{build_type}}
cmake --build build_install_test --config ${{matrix.build_type}}
+37
View File
@@ -0,0 +1,37 @@
name: VS17-CLANG-CI
on: [push, pull_request]
jobs:
ci:
if: >-
! contains(toJSON(github.event.commits.*.message), '[skip ci]') &&
! contains(toJSON(github.event.commits.*.message), '[skip github]')
name: windows-vs17
runs-on: windows-latest
strategy:
fail-fast: false
matrix:
include:
- {gen: Visual Studio 17 2022, arch: x64, build_type: Debug}
- {gen: Visual Studio 17 2022, arch: x64, build_type: Release}
- {gen: Visual Studio 17 2022, arch: x64, build_type: RelWithDebInfo}
steps:
- name: checkout
uses: actions/checkout@v4
- name: Configure
run: |
cmake -G "${{matrix.gen}}" -A ${{matrix.arch}} -T ClangCL -DSIMDJSON_DEVELOPER_MODE=ON -DSIMDJSON_COMPETITION=OFF -B build
- name: Build
run: cmake --build build --config ${{matrix.build_type}} --verbose
- name: Run tests
run: |
cd build
ctest -C ${{matrix.build_type}} -LE explicitonly --output-on-failure
- name: Install
run: |
cmake --install build --config ${{matrix.build_type}}
- 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 ${{matrix.build_type}}
+18 -6
View File
@@ -109,11 +109,23 @@
"numbers": "cpp",
"semaphore": "cpp",
"stop_token": "cpp",
"cfenv": "cpp"
},
"cmake.configureSettings": {
"CMAKE_EXPORT_COMPILE_COMMANDS": "YES",
"SIMDJSON_DEVELOPER_MODE": "ON",
"SIMDJSON_SINGLEHEADER": "OFF"
"cfenv": "cpp",
"format": "cpp",
"xlocmes": "cpp",
"xlocmon": "cpp",
"xlocnum": "cpp",
"xloctime": "cpp",
"xutility": "cpp",
"coroutine": "cpp",
"xfacet": "cpp",
"xhash": "cpp",
"xiosbase": "cpp",
"xlocale": "cpp",
"xlocbuf": "cpp",
"xlocinfo": "cpp",
"xmemory": "cpp",
"xstring": "cpp",
"xtr1common": "cpp",
"xtree": "cpp"
}
}
+4 -3
View File
@@ -3,7 +3,7 @@ cmake_minimum_required(VERSION 3.14)
project(
simdjson
# The version number is modified by tools/release.py
VERSION 3.10.1
VERSION 3.12.3
DESCRIPTION "Parsing gigabytes of JSON per second"
HOMEPAGE_URL "https://simdjson.org/"
LANGUAGES CXX C
@@ -20,8 +20,8 @@ string(
# ---- Options, variables ----
# These version numbers are modified by tools/release.py
set(SIMDJSON_LIB_VERSION "23.0.0" CACHE STRING "simdjson library version")
set(SIMDJSON_LIB_SOVERSION "23" CACHE STRING "simdjson library soversion")
set(SIMDJSON_LIB_VERSION "25.0.0" CACHE STRING "simdjson library version")
set(SIMDJSON_LIB_SOVERSION "25" CACHE STRING "simdjson library soversion")
option(SIMDJSON_BUILD_STATIC_LIB "Build simdjson_static library along with simdjson (only makes sense if BUILD_SHARED_LIBS=ON)" OFF)
if(SIMDJSON_BUILD_STATIC_LIB AND NOT BUILD_SHARED_LIBS)
@@ -287,6 +287,7 @@ enable_testing()
add_custom_target(all_tests)
add_subdirectory(windows)
include(cmake/CPM.cmake)
add_subdirectory(dependencies) ## This needs to be before tools because of cxxopts
add_subdirectory(tools) ## This needs to be before tests because of cxxopts
+1 -1
View File
@@ -92,7 +92,7 @@ We welcome contributions from women and less represented groups. If you need hel
Consider the following points when engaging with the project:
- We discourage arguments from authority: ideas are discusssed on their own merits and not based on who stated it.
- We discourage arguments from authority: ideas are discussed on their own merits and not based on who stated it.
- Be mindful that what you may view as an aggression is maybe merely a difference of opinion or a misunderstanding.
- Be mindful that a collection of small aggressions, even if mild in isolation, can become harmful.
+1 -1
View File
@@ -38,7 +38,7 @@ PROJECT_NAME = simdjson
# could be handy for archiving the generated documentation or if some version
# control system is used.
PROJECT_NUMBER = "3.10.1"
PROJECT_NUMBER = "3.12.3"
# Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears at the top of each page and should give viewer a
+1 -1
View File
@@ -186,7 +186,7 @@
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright 2018-2023 The simdjson authors
Copyright 2018-2025 The simdjson authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
+18
View File
@@ -0,0 +1,18 @@
Copyright 2018-2025 The simdjson authors
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+16 -4
View File
@@ -1,7 +1,7 @@
[![Ubuntu 20.04 CI](https://github.com/simdjson/simdjson/workflows/Ubuntu%2020.04%20CI%20(GCC%209)/badge.svg)](https://simdjson.org/plots.html)
[![Fuzzing Status](https://oss-fuzz-build-logs.storage.googleapis.com/badges/simdjson.svg)](https://bugs.chromium.org/p/oss-fuzz/issues/list?sort=-opened&can=1&q=proj:simdjson)
[![][license img]][license]
[![][license img]][license] [![][licensemit img]][licensemit]
[![Doxygen Documentation](https://img.shields.io/badge/docs-doxygen-green.svg)](https://simdjson.github.io/simdjson/)
@@ -31,6 +31,7 @@ Table of Contents
* [Documentation](#documentation)
* [Godbolt](#godbolt)
* [Performance results](#performance-results)
* [Packages](#packages)
* [Bindings and Ports of simdjson](#bindings-and-ports-of-simdjson)
* [About simdjson](#about-simdjson)
* [Funding](#funding)
@@ -61,6 +62,8 @@ Real-world usage
- [ada-url](https://github.com/ada-url/ada)
- [fastgron](https://github.com/adamritter/fastgron)
- [WasmEdge](https://wasmedge.org)
- [RonDB](https://github.com/logicalclocks/rondb)
If you are planning to use simdjson in a product, please work from one of our releases.
@@ -143,6 +146,9 @@ speed for [synthetic files over various sizes generated with a script](https://g
For NDJSON files, we can exceed 3 GB/s with [our multithreaded parsing functions](https://github.com/simdjson/simdjson/blob/master/doc/parse_many.md).
Packages
------------------------------
[![Packaging status](https://repology.org/badge/vertical-allrepos/simdjson.svg)](https://repology.org/project/simdjson/versions)
Bindings and Ports of simdjson
@@ -167,7 +173,8 @@ We distinguish between "bindings" (which just wrap the C++ code) and a port to a
- [simdjsone](https://github.com/saleyn/simdjsone): erlang bindings.
- [lua-simdjson](https://github.com/FourierTransformer/lua-simdjson): lua bindings.
- [hermes-json](https://hackage.haskell.org/package/hermes-json): haskell bindings.
- [simdjzon](https://github.com/travisstaloch/simdjzon): zig port.
- [zimdjson](https://github.com/EzequielRamis/zimdjson): Zig port.
- [simdjzon](https://github.com/travisstaloch/simdjzon): Zig port.
- [JSON-Simd](https://github.com/rawleyfowler/JSON-simd): Raku bindings.
- [JSON::SIMD](https://metacpan.org/pod/JSON::SIMD): Perl bindings; fully-featured JSON module that uses simdjson for decoding.
- [gemmaJSON](https://github.com/sainttttt/gemmaJSON): Nim JSON parser based on simdjson bindings.
@@ -207,6 +214,11 @@ RGPIN-2017-03910 and RGPIN-2024-03787.
[license]: LICENSE
[license img]: https://img.shields.io/badge/License-Apache%202-blue.svg
[licensemit]: LICENSE-MIT
[licensemit img]: https://img.shields.io/badge/License-MIT-blue.svg
Contributing to simdjson
------------------------
@@ -216,7 +228,7 @@ Head over to [CONTRIBUTING.md](CONTRIBUTING.md) for information on contributing
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) as well as under the MIT License. As a user, you can pick the license you prefer.
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.
+1 -1
View File
@@ -13,7 +13,7 @@ struct nlohmann_json {
auto root = nlohmann::json::parse(json.data(), json.data() + json.size());
for (auto tweet : root["statuses"]) {
if (tweet["id"] == find_id) {
result = tweet["text"];
result = to_string(tweet["text"]);
return true;
}
}
+2 -2
View File
@@ -26,8 +26,8 @@ struct nlohmann_json {
}
}
result.text = top_tweet["text"];
result.screen_name = top_tweet["user"]["screen_name"];
result.text = to_string(top_tweet["text"]);
result.screen_name = to_string(top_tweet["user"]["screen_name"]);
return result.retweet_count != -1;
}
};
+24
View File
@@ -0,0 +1,24 @@
# SPDX-License-Identifier: MIT
#
# SPDX-FileCopyrightText: Copyright (c) 2019-2023 Lars Melchior and contributors
set(CPM_DOWNLOAD_VERSION 0.40.2)
set(CPM_HASH_SUM "c8cdc32c03816538ce22781ed72964dc864b2a34a310d3b7104812a5ca2d835d")
if(CPM_SOURCE_CACHE)
set(CPM_DOWNLOAD_LOCATION "${CPM_SOURCE_CACHE}/cpm/CPM_${CPM_DOWNLOAD_VERSION}.cmake")
elseif(DEFINED ENV{CPM_SOURCE_CACHE})
set(CPM_DOWNLOAD_LOCATION "$ENV{CPM_SOURCE_CACHE}/cpm/CPM_${CPM_DOWNLOAD_VERSION}.cmake")
else()
set(CPM_DOWNLOAD_LOCATION "${CMAKE_BINARY_DIR}/cmake/CPM_${CPM_DOWNLOAD_VERSION}.cmake")
endif()
# Expand relative path. This is important if the provided path contains a tilde (~)
get_filename_component(CPM_DOWNLOAD_LOCATION ${CPM_DOWNLOAD_LOCATION} ABSOLUTE)
file(DOWNLOAD
https://github.com/cpm-cmake/CPM.cmake/releases/download/v${CPM_DOWNLOAD_VERSION}/CPM.cmake
${CPM_DOWNLOAD_LOCATION} EXPECTED_HASH SHA256=${CPM_HASH_SUM}
)
include(${CPM_DOWNLOAD_LOCATION})
+76 -37
View File
@@ -1,5 +1,4 @@
include(CMakeDependentOption)
include(import.cmake)
option(SIMDJSON_ALLOW_DOWNLOADS
"Allow dependencies to be downloaded during configure time"
@@ -11,17 +10,21 @@ cmake_dependent_option(SIMDJSON_GOOGLE_BENCHMARKS "compile the Google Benchmark
SIMDJSON_ALLOW_DOWNLOADS OFF)
if(SIMDJSON_GOOGLE_BENCHMARKS)
set_off(BENCHMARK_ENABLE_TESTING)
set_off(BENCHMARK_ENABLE_INSTALL)
set_off(BENCHMARK_ENABLE_WERROR)
import_dependency(google_benchmarks google/benchmark v1.7.1)
add_dependency(google_benchmarks)
CPMAddPackage(
NAME google_benchmarks
URL https://github.com/google/benchmark/archive/refs/tags/v1.7.1.zip
OPTIONS
"BENCHMARK_ENABLE_TESTING OFF"
"BENCHMARK_ENABLE_INSTALL OFF"
"BENCHMARK_ENABLE_WERROR OFF"
)
endif()
# The bulk of our benchmarking and testing data has been moved simdjson/simdjson-data
import_dependency(simdjson-data simdjson/simdjson-data a5b13babe65c1bba7186b41b43d4cbdc20a5c470)
add_dependency(simdjson-data)
CPMAddPackage(
NAME simdjson-data
URL https://github.com/simdjson/simdjson-data/archive/a5b13babe65c1bba7186b41b43d4cbdc20a5c470.zip
)
option(SIMDJSON_USE_BOOST_JSON "Try to include BOOST_JSON, this may break your binaries under some systems." OFF)
# This prevents variables declared with set() from unnecessarily escaping and
# should not be called more than once
@@ -38,20 +41,30 @@ function(competition_scope_)
int main() {}
]] SIMDJSON_FOUND_STRING_VIEW)
if(SIMDJSON_FOUND_STRING_VIEW AND SIMDJSON_USE_BOOST_JSON)
import_dependency(boostjson boostorg/json ee8d72d)
CPMAddPackage(
NAME boostjson
URL https://github.com/boostorg/json/archive/ee8d72d8502b409b5561200299cad30ccdb91415.zip
)
add_library(boostjson STATIC "${boostjson_SOURCE_DIR}/src/src.cpp")
target_compile_definitions(boostjson PUBLIC BOOST_JSON_STANDALONE)
target_include_directories(boostjson SYSTEM PUBLIC
"${boostjson_SOURCE_DIR}/include")
target_compile_definitions(boostjson INTERFACE SIMDJSON_COMPETITION_BOOSTJSON)
endif()
import_dependency(cjson DaveGamble/cJSON c69134d)
CPMAddPackage(
NAME cjson
URL https://github.com/DaveGamble/cJSON/archive/c69134d01746dcf551dd7724b4edb12f922eb0d1.zip
DOWNLOAD_ONLY YES
)
add_library(cjson STATIC "${cjson_SOURCE_DIR}/cJSON.c")
target_include_directories(cjson SYSTEM PUBLIC "${cjson_SOURCE_DIR}")
target_compile_definitions(cjson INTERFACE SIMDJSON_COMPETITION_CJSON)
import_dependency(fastjson mikeando/fastjson 485f994)
CPMAddPackage(
NAME fastjson
URL https://github.com/mikeando/fastjson/archive/485f994a61a64ac73fa6a40d4d639b99b463563b.zip
DOWNLOAD_ONLY YES
)
add_library(fastjson STATIC
"${fastjson_SOURCE_DIR}/src/fastjson.cpp"
"${fastjson_SOURCE_DIR}/src/fastjson2.cpp"
@@ -60,28 +73,36 @@ int main() {}
"${fastjson_SOURCE_DIR}/include")
target_compile_definitions(fastjson INTERFACE SIMDJSON_COMPETITION_FASTJSON)
import_dependency(gason vivkin/gason 7aee524)
CPMAddPackage(
NAME gason
URL https://github.com/vivkin/gason/archive/7aee524189da1c1ecd19f67981e3d903dae25470.zip
DOWNLOAD_ONLY YES
)
add_library(gason STATIC "${gason_SOURCE_DIR}/src/gason.cpp")
target_include_directories(gason SYSTEM PUBLIC "${gason_SOURCE_DIR}/src")
target_compile_definitions(gason INTERFACE SIMDJSON_COMPETITION_GASON)
import_dependency(jsmn zserge/jsmn 18e9fe4)
CPMAddPackage(
NAME jsmn
URL https://github.com/zserge/jsmn/archive/18e9fe42cbfe21d65076f5c77ae2be379ad1270f.zip
DOWNLOAD_ONLY YES
)
add_library(jsmn STATIC "${jsmn_SOURCE_DIR}/jsmn.c")
target_include_directories(jsmn SYSTEM PUBLIC "${jsmn_SOURCE_DIR}")
target_compile_definitions(jsmn INTERFACE SIMDJSON_COMPETITION_JSMN)
message(STATUS "Importing json (nlohmann/json@v3.10.5)")
set(nlohmann_json_SOURCE_DIR "${dep_root}/json")
if(NOT EXISTS "${nlohmann_json_SOURCE_DIR}")
file(DOWNLOAD
"https://github.com/nlohmann/json/releases/download/v3.10.5/json.hpp"
"${nlohmann_json_SOURCE_DIR}/nlohmann/json.hpp")
endif()
add_library(nlohmann_json INTERFACE)
target_include_directories(nlohmann_json SYSTEM INTERFACE "${nlohmann_json_SOURCE_DIR}")
target_compile_definitions(nlohmann_json INTERFACE SIMDJSON_COMPETITION_NLOHMANN_JSON)
CPMAddPackage(
NAME nlohmann_json
URL https://github.com/nlohmann/json/archive/refs/tags/v3.10.5.zip
)
import_dependency(json11 dropbox/json11 ec4e452)
set_property(TARGET nlohmann_json APPEND PROPERTY INTERFACE_COMPILE_DEFINITIONS SIMDJSON_COMPETITION_NLOHMANN_JSON)
CPMAddPackage(
NAME json11
URL https://github.com/dropbox/json11/archive/ec4e45219af1d7cde3d58b49ed762376fccf1ace.zip
DOWNLOAD_ONLY YES
)
add_library(json11 STATIC "${json11_SOURCE_DIR}/json11.cpp")
target_include_directories(json11 SYSTEM PUBLIC "${json11_SOURCE_DIR}")
target_compile_definitions(json11 INTERFACE SIMDJSON_COMPETITION_JSON11)
@@ -91,7 +112,11 @@ int main() {}
target_include_directories(jsoncpp SYSTEM PUBLIC "${jsoncpp_SOURCE_DIR}")
target_compile_definitions(jsoncpp INTERFACE SIMDJSON_COMPETITION_JSONCPP)
import_dependency(rapidjson Tencent/rapidjson f54b0e4)
CPMAddPackage(
NAME rapidjson
URL https://github.com/Tencent/rapidjson/archive/f54b0e47a08782a6131cc3d60f94d038fa6e0a51.zip
DOWNLOAD_ONLY YES
)
add_library(rapidjson INTERFACE)
target_compile_definitions(rapidjson INTERFACE RAPIDJSON_HAS_STDSTRING)
include (TestBigEndian)
@@ -110,14 +135,22 @@ int main() {}
target_compile_definitions(rapidjson INTERFACE SIMDJSON_COMPETITION_RAPIDJSON)
endif()
import_dependency(sajson chadaustin/sajson 2dcfd35)
CPMAddPackage(
NAME sajson
URL https://github.com/chadaustin/sajson/archive/2dcfd350586375f9910f74821d4f07d67ae455ba.zip
DOWNLOAD_ONLY YES
)
add_library(sajson INTERFACE)
target_compile_definitions(sajson INTERFACE SAJSON_UNSORTED_OBJECT_KEYS)
target_include_directories(sajson SYSTEM INTERFACE
"${sajson_SOURCE_DIR}/include")
target_compile_definitions(sajson INTERFACE SIMDJSON_COMPETITION_SAJSON)
import_dependency(ujson4c esnme/ujson4c e14f3fd)
CPMAddPackage(
NAME ujson4c
URL https://github.com/esnme/ujson4c/archive/e14f3fd5207fe30d1bdea723f260609e69d1abfa.zip
DOWNLOAD_ONLY YES
)
add_library(ujson4c STATIC
"${ujson4c_SOURCE_DIR}/src/ujdecode.c"
"${ujson4c_SOURCE_DIR}/3rdparty/ultrajsondec.c")
@@ -126,7 +159,11 @@ int main() {}
"${ujson4c_SOURCE_DIR}/3rdparty")
target_compile_definitions(ujson4c INTERFACE SIMDJSON_COMPETITION_UJSON4C)
import_dependency(yyjson ibireme/yyjson c385651)
CPMAddPackage(
NAME yyjson
URL https://github.com/ibireme/yyjson/archive/c3856514de0a67d7b66939bf3ed491a2d6e61277.zip
DOWNLOAD_ONLY YES
)
add_library(yyjson STATIC "${yyjson_SOURCE_DIR}/src/yyjson.c")
target_include_directories(yyjson SYSTEM PUBLIC "${yyjson_SOURCE_DIR}/src")
target_compile_definitions(yyjson INTERFACE SIMDJSON_COMPETITION_YYJSON)
@@ -151,10 +188,12 @@ cmake_dependent_option(SIMDJSON_CXXOPTS "Download cxxopts (necessary for tools)"
SIMDJSON_ALLOW_DOWNLOADS OFF)
if(SIMDJSON_CXXOPTS)
set_off(CXXOPTS_BUILD_EXAMPLES)
set_off(CXXOPTS_BUILD_TESTS)
set_off(CXXOPTS_ENABLE_INSTALL)
import_dependency(cxxopts jarro2783/cxxopts 5965670)
add_dependency(cxxopts)
CPMAddPackage(
NAME cxxopts
URL https://github.com/jarro2783/cxxopts/archive/59656709c0c58fcd0ed18b38e02938dbe05284c5.zip
OPTIONS
"CXXOPTS_BUILD_EXAMPLES OFF"
"CXXOPTS_BUILD_TESTS OFF"
"CXXOPTS_ENABLE_INSTALL OFF"
)
endif()
-48
View File
@@ -1,48 +0,0 @@
set(dep_root "${simdjson_SOURCE_DIR}/dependencies/.cache")
if(DEFINED ENV{simdjson_DEPENDENCY_CACHE_DIR})
set(dep_root "$ENV{simdjson_DEPENDENCY_CACHE_DIR}")
endif()
function(import_dependency NAME GITHUB_REPO COMMIT)
message(STATUS "Importing ${NAME} (${GITHUB_REPO}@${COMMIT})")
set(target "${dep_root}/${NAME}")
# If the folder exists in the cache, then we assume that everything is as
# should be and do nothing
if(EXISTS "${target}")
set("${NAME}_SOURCE_DIR" "${target}" PARENT_SCOPE)
return()
endif()
set(zip_url "https://github.com/${GITHUB_REPO}/archive/${COMMIT}.zip")
set(archive "${dep_root}/archive.zip")
set(dest "${dep_root}/_extract")
file(DOWNLOAD "${zip_url}" "${archive}")
file(MAKE_DIRECTORY "${dest}")
execute_process(
WORKING_DIRECTORY "${dest}"
COMMAND "${CMAKE_COMMAND}" -E tar xf "${archive}")
file(REMOVE "${archive}")
# GitHub archives only ever have one folder component at the root, so this
# will always match that single folder
file(GLOB dir LIST_DIRECTORIES YES "${dest}/*")
file(RENAME "${dir}" "${target}")
set("${NAME}_SOURCE_DIR" "${target}" PARENT_SCOPE)
endfunction()
# Delegates to the dependency
macro(add_dependency NAME)
if(NOT DEFINED "${NAME}_SOURCE_DIR")
message(FATAL_ERROR "Missing ${NAME}_SOURCE_DIR variable")
endif()
add_subdirectory("${${NAME}_SOURCE_DIR}" "${PROJECT_BINARY_DIR}/_deps/${NAME}" EXCLUDE_FROM_ALL)
endmacro()
function(set_off NAME)
set("${NAME}" OFF CACHE INTERNAL "")
endfunction()
+393 -105
View File
@@ -17,6 +17,8 @@ An overview of what you need to know to use simdjson, with examples.
- [Using the parsed JSON](#using-the-parsed-json)
- [Using the parsed JSON: additional examples](#using-the-parsed-json-additional-examples)
- [Adding support for custom types](#adding-support-for-custom-types)
- [1. Specialize `simdjson::ondemand::value::get` to get custom types (pre-C++20)](#1-specialize-simdjsonondemandvalueget-to-get-custom-types-pre-c20)
- [2. Use `tag_invoke` for custom types (C++20)](#2-use-tag_invoke-for-custom-types-c20)
- [Minifying JSON strings without parsing](#minifying-json-strings-without-parsing)
- [UTF-8 validation (alone)](#utf-8-validation-alone)
- [JSON Pointer](#json-pointer)
@@ -46,7 +48,7 @@ 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.
- 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.
- 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 (clang-cl) as well as as the regular Visual Studio compiler. For better release performance (both compile time and execution time), we recommend Visual Studio users adopt LLVM (clang-cl). We also support MinGW 64-bit under Windows.
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.
@@ -207,6 +209,25 @@ std::string data = "my data";
simdjson::padded_string my_padded_data(data); // copies to a padded buffer
```
You can then parse the JSON data from the `simdjson::padded_string` instance:
```c++
ondemand::document doc = parser.iterate(my_padded_data);
```
Whenever you pass an `std::string` reference to `parser::iterate`,
the parser will access the bytes beyond the end of
the string but before the end of the allocated memory (`std::string::capacity()`).
If you are using a sanitizer that checks for reading uninitialized bytes or `std::string`'s
container-overflow checks, you may encounter sanitizer warnings.
You can safely ignore these warnings. Or you can call `simdjson::pad(std::string&)` to pad the
string with `SIMDJSON_PADDING` spaces: this function returns a `simdjson::padding_string_view` which can be be passed to the parser's iterator function:
```c++
std::string json = "[1]";
ondemand::document doc = parser.iterate(simdjson::pad(json));
```
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.
@@ -247,7 +268,7 @@ documents.
For code safety, you should keep (1) the `parser` instance, (2) the input string and (3) the document instance alive throughout your parsing. Additionally, you should follow the following rules:
- A `parser` may have at most one document open at a time, since it holds allocated memory used for the parsing.
- By design, you should only have one `document` instance per JSON document. Thus, if you must pass a document instance to a function, you should avoid passing it by value: choose to pass it by reference instance to avoid the copy. (We also provide a `document_reference` class if you need to pass by value.)
- By design, you should only have one `document` instance per JSON document. Thus, if you must pass a document instance to a function, you should avoid passing it by value: choose to pass it by reference instance to avoid the copy. In any case, the `document` class does not have a copy constructor.
During the `iterate` call, the original JSON text is never modified--only read. After you are done
with the document, the source (whether file or string) can be safely discarded.
@@ -401,9 +422,13 @@ support for users who avoid exceptions. See [the simdjson error handling documen
of the object: to warn you, an OUT_OF_ORDER_ITERATION error is generated [when development checks](#avoiding-pitfalls-enable-development-checks) are active. If you need to access an object more
than once, you may call `reset()` on it although we discourage this practice. Keep in mind that
you should consume each value at most once.
When you are iterating through an object, you are advancing through its keys and values. You should not also access the object or other objects. E.g. within a loop over `myobject`, you should not be accessing `myobject`. The following is an anti-pattern: `for(auto value: myobject) {myobject["mykey"]}`.
You should never reset an object as you are iterating through it. The following is an anti-pattern: `for(auto value: myobject) {myobject.reset()}`.
* **Array Index:** Because it is forward-only, you cannot look up an array element by index by index. Instead,
you should iterate through the array and keep an index yourself. Exceptionally, if need a single value
out of the array, you may use an array access (e.g., `array[1]`).
out of the array, you may use an array access (e.g., `array[1]`). You should never reset an array as you are iterating through it. The following is an anti-pattern: `for(auto value: myarray) {myarray.reset()}`.
* **Field Access:** To get the value of the "foo" field in an object, use `object["foo"]`. This will
scan through the object looking for the field with the matching string, doing a character-by-character
comparison. It may generate the error `simdjson::NO_SUCH_FIELD` if there is no such key in the object, it may throw an exception (see [Error handling](#error-handling)). For efficiency reason, you should avoid looking up the same field repeatedly: e.g., do
@@ -526,7 +551,7 @@ support for users who avoid exceptions. See [the simdjson error handling documen
double value;
auto doc = parser.iterate(abstract_json);
auto error = doc["str"]["123"]["abc"].get(value);
if (error) { std::cerr << error << std::endl; return EXIT_FAILURE; }
if (error) { std::cerr << simdjson::error_message(error) << std::endl; return EXIT_FAILURE; }
cout << value << endl; // Prints 3.14
```
This examples also show how we can string several operations and only check for the error once, a strategy we call *error chaining*.
@@ -536,7 +561,7 @@ support for users who avoid exceptions. See [the simdjson error handling documen
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
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:
require scanning the document twice or more. You should never use the `count_elements` as part of an attempt to iterate through the array: use a `for` loop to iterate through arrays. In the spirit of On-Demand, the `count_elements` function does not validate the values in the array: they are validated when they are consumed. You may use it as follows if your document is itself an array:
```C++
auto cars_json = R"( [ 40.1, 39.9, 37.7, 40.4 ] )"_padded;
@@ -788,6 +813,18 @@ for (ondemand::object points : parser.iterate(points_json)) {
Adding support for custom types
----------------------
There are 2 main ways provided by simdjson to deserialize a value into a custom type:
1. Provide a [**template specialization** for member functions](https://en.cppreference.com/w/cpp/language/template_specialization#Members_of_specializations)
1. Specialize `simdjson::ondemand::document::get` for the whole document
2. Specialize `simdjson::ondemand::value::get` for each value
2. Using `tag_invoke` *(the recommended way if your system supports C++20 or better)*
We describe both of them in the following sections. Most users who have systems compatible with
C++20 or better should skip ahead to [using `tag_invoke` for custom types (C++20)](#2-use-tag_invoke-for-custom-types-c20) as it is more powerful and simpler.
### 1. Specialize `simdjson::ondemand::value::get` to get custom types (pre-C++20)
Suppose you have your own types, such as a `Car` struct:
```C++
@@ -821,9 +858,15 @@ type:
```
We may do so by providing additional template definitions to the `ondemand::value` type.
We may start by providing a definition for `std::vector<double>` as follows:
We may start by providing a definition for `std::vector<double>` as follows. Observe
how we guard the code with `#if !SIMDJSON_SUPPORTS_DESERIALIZATION`: that is because the necessary code
is automatically provided by simdjson if C++20 (and concepts) are available.
See [Use `tag_invoke` for custom types](#2-use-tag_invoke-for-custom-types-c20) if you have
C++20 support.
```c++
#if !SIMDJSON_SUPPORTS_DESERIALIZATION
// The code is unnecessary with C++20:
template <>
simdjson_inline simdjson_result<std::vector<double>>
simdjson::ondemand::value::get() noexcept {
@@ -839,6 +882,7 @@ simdjson::ondemand::value::get() noexcept {
}
return vec;
}
#endif
```
We may then provide support for our `Car` struct:
@@ -850,26 +894,10 @@ simdjson_inline simdjson_result<Car> simdjson::ondemand::value::get() noexcept {
auto error = get_object().get(obj);
if (error) { return error; }
Car car;
// Instead of repeatedly obj["something"], we iterate through the object which
// we expect to be faster.
for (auto field : obj) {
raw_json_string key;
error = field.key().get(key);
if (error) { return error; }
if (key == "make") {
error = field.value().get_string(car.make);
if (error) { return error; }
} else if (key == "model") {
error = field.value().get_string(car.model);
if (error) { return error; }
} else if (key == "year") {
error = field.value().get_int64().get(car.year);
if (error) { return error; }
} else if (key == "tire_pressure") {
error = field.value().get<std::vector<double>>().get(car.tire_pressure);
if (auto error) { return error; }
}
}
if((error = obj["make"].get_string(car.make))) { return error; }
if((error = obj["model"].get_string(car.model))) { return error; }
if((error = obj["year"].get_int64().get(car.year))) { return error; }
if((error = obj["tire_pressure"].get<std::vector<double>>().get(car.tire_pressure))) { return error; }
return car;
}
```
@@ -893,6 +921,8 @@ struct Car {
std::vector<double> tire_pressure;
};
#if !SIMDJSON_SUPPORTS_DESERIALIZATION
// This code is not necessary if you have a C++20 compliant system:
template <>
simdjson_inline simdjson_result<std::vector<double>>
simdjson::ondemand::value::get() noexcept {
@@ -908,7 +938,7 @@ simdjson::ondemand::value::get() noexcept {
}
return vec;
}
#endif
template <>
simdjson_inline simdjson_result<Car> simdjson::ondemand::value::get() noexcept {
@@ -916,26 +946,10 @@ simdjson_inline simdjson_result<Car> simdjson::ondemand::value::get() noexcept {
auto error = get_object().get(obj);
if (error) { return error; }
Car car;
// Instead of repeatedly obj["something"], we iterate through the object which
// we expect to be faster.
for (auto field : obj) {
raw_json_string key;
error = field.key().get(key);
if (error) { return error; }
if (key == "make") {
error = field.value().get_string(car.make);
if (error) { return error; }
} else if (key == "model") {
error = field.value().get_string(car.model);
if (error) { return error; }
} else if (key == "year") {
error = field.value().get_int64().get(car.year);
if (error) { return error; }
} else if (key == "tire_pressure") {
error = field.value().get<std::vector<double>>().get(car.tire_pressure);
if (error) { return error; }
}
}
if((error = obj["make"].get_string(car.make))) { return error; }
if((error = obj["model"].get_string(car.model))) { return error; }
if((error = obj["year"].get_int64().get(car.year))) { return error; }
if((error = obj["tire_pressure"].get<std::vector<double>>().get(car.tire_pressure))) { return error; }
return car;
}
@@ -950,15 +964,14 @@ int main(void) {
ondemand::parser parser;
ondemand::document doc = parser.iterate(json);
for (auto val : doc) {
Car c(val);
Car c(val); // an exception may be thrown
std::cout << c.make << std::endl;
}
direct();
return EXIT_SUCCESS;
}
```
Observe that we require an explicit cast (`Car c(val)` instead of `for (Car c : doc) {`): it is by design.
Observe that we require an explicit cast (`Car c(val)` instead of `for (Car c : doc) {`): it is by design. We require explicit casting.
If you prefer to avoid exceptions, you may modify the `main` function as follows:
@@ -974,11 +987,11 @@ int main(void) {
ondemand::parser parser;
ondemand::document doc;
auto error = parser.iterate(json).get(doc);
if (error) { std::cerr << error << std::endl; return EXIT_FAILURE; }
if (error) { std::cerr << simdjson::error_message(error) << std::endl; return EXIT_FAILURE; }
for (auto val : doc) {
Car c;
error = val.get<Car>().get(c);
if (error) { std::cerr << error << std::endl; return EXIT_FAILURE; }
if (error) { std::cerr << simdjson::error_message(error) << std::endl; return EXIT_FAILURE; }
std::cout << c.make << std::endl;
}
return EXIT_SUCCESS;
@@ -1009,49 +1022,49 @@ struct Car {
std::vector<double> tire_pressure;
};
#if !SIMDJSON_SUPPORTS_DESERIALIZATION
// This code is not necessary if you have a C++20 compliant system:
template <>
simdjson_inline simdjson_result<std::vector<double>>
simdjson::ondemand::value::get() noexcept {
ondemand::array array;
if (auto error = get_array().get(array); error) { return error; }
auto error = get_array().get(array);
if (error) { return error; }
std::vector<double> vec;
for (auto v : array) {
double val;
if (auto error = v.get_double().get(val); error) { return error; }
error = v.get_double().get(val);
if (error) { return error; }
vec.push_back(val);
}
return vec;
}
#endif
template <>
simdjson_inline simdjson_result<Car> simdjson::ondemand::document::get() & noexcept {
ondemand::object obj;
auto error = get_object().get(obj);
if (error) {
return error;
}
if (error) { return error; }
Car car;
// Instead of repeatedly obj["something"], we iterate through the object which
// we expect to be faster.
for (auto field : obj) {
raw_json_string key;
error = field.key().get(key);
if (error) { return error; }
if (key == "make") {
error = field.value().get_string(car.make);
if (error) { return error; }
} else if (key == "model") {
error = field.value().get_string(car.model);
if (error) { return error; }
} else if (key == "year") {
error = field.value().get_int64().get(car.year);
if (error) { return error; }
} else if (key == "tire_pressure") {
error = field.value().get<std::vector<double>>().get(car.tire_pressure);
if (error) { return error; }
}
}
if((error = obj["make"].get_string(car.make))) { return error; }
if((error = obj["model"].get_string(car.model))) { return error; }
if((error = obj["year"].get_int64().get(car.year))) { return error; }
if((error = obj["tire_pressure"].get<std::vector<double>>().get(car.tire_pressure))) { return error; }
return car;
}
template <>
simdjson_inline simdjson_result<Car> simdjson::ondemand::document::get() noexcept {
ondemand::object obj;
auto error = get_object().get(obj);
if (error) { return error; }
Car car;
if((error = obj["make"].get_string(car.make))) { return error; }
if((error = obj["model"].get_string(car.model))) { return error; }
if((error = obj["year"].get_int64().get(car.year))) { return error; }
if((error = obj["tire_pressure"].get<std::vector<double>>().get(car.tire_pressure))) { return error; }
return car;
}
@@ -1066,6 +1079,235 @@ int main(void) {
}
```
### 2. Use `tag_invoke` for custom types (C++20)
In C++20, the standard introduced the notion of *customization point*.
A customization point is a function or function object that can be customized for different types. It allows library authors to provide default behavior while giving users the ability to override this behavior for specific types.
A tag_invoke function serves as a mechanism for customization points. It is not directly part of the C++ standard library but is often used in libraries that implement customization points.
The tag_invoke function is typically a generic function that takes a tag type and additional arguments.
The first argument is usually a tag type (often an empty struct) that uniquely identifies the customization point (e.g., deserialization of custom types in simdjson). Users or library providers can specialize tag_invoke for their types by defining it in the appropriate namespace, often inline namespace.
If your system supports C++20, we recommend that you adopt the `tag_invoke` approach
instead to deserialize custom types. It may prove to be considerably simpler. When
simdjson detects the necessary support, it sets the `SIMDJSON_SUPPORTS_DESERIALIZATION` macro
to 1, otherwise it is set to 0.
Consider a custom class `Car`:
```C++
struct Car {
std::string make;
std::string model;
int year;
std::vector<float> tire_pressure;
};
```
Observe how we defined the class to use types that simdjson does not directly support (`float`, `int`).
With C++20 support, the library grabs from the JSON the generic type (`double`, `int`) and then it
casts it automatically.
You may support deserializing directly from a JSON value or document to your own `Car` instance
by defining a single `tag_invoke` function:
```C++
namespace simdjson {
// This tag_invoke MUST be inside simdjson namespace
template <typename simdjson_value>
auto tag_invoke(deserialize_tag, simdjson_value &val, Car& car) {
ondemand::object obj;
auto error = val.get_object().get(obj);
if (error) {
return error;
}
if ((error = obj["make"].get_string(car.make))) {
return error;
}
if ((error = obj["model"].get_string(car.model))) {
return error;
}
if ((error = obj["year"].get(car.year))) {
return error;
}
if ((error = obj["tire_pressure"].get<std::vector<float>>().get(
car.tire_pressure))) {
return error;
}
return simdjson::SUCCESS;
}
} // namespace simdjson
```
Observe how we call `get<std::vector<float>>()` even though we never defined support
for `std::vector<float>` in the simdjson library: it is all automated thanks to C++20 concepts.
Importantly, the `tag_invoke` function must be inside the `simdjson` namespace.
Let us explain each argument of `tag_invoke` function.
- `simdjson::deserialize_tag`: it is the tag for Customization Point Object (CPO). You may often ignore this parameter. It is used to indicate that you mean to provide a deserialization function for simdjson.
- `var`: It receives automatically a `simdjson` value type (document, value, document_reference).
- The third parameter is an instance of the type that you want to support.
You can use it like so:
```cpp
simdjson::padded_string json =
R"( { "make": "Toyota", "model": "Camry", "year": 2018,
"tire_pressure": [ 40.1, 39.9 ] })"_padded;
simdjson::ondemand::parser parser;
simdjson::ondemand::document doc = parser.iterate(json);
Car c(doc);
std::cout << c.make << std::endl;
```
Observe how we first get an instance of `document` and then we cast.
You can also handle errors explicitly:
```cpp
Car c;
auto error = doc.get(c);
if(error) { std::cerr << simdjson::error_message(error); return false; }
std::cout << c.make << std::endl;
```
You can also read instances of `Car` from an array or an object:
```cpp
simdjson::padded_string json =
R"( [ { "make": "Toyota", "model": "Camry", "year": 2018,
"tire_pressure": [ 40.1, 39.9 ] },
{ "make": "Kia", "model": "Soul", "year": 2012,
"tire_pressure": [ 30.1, 31.0 ] },
{ "make": "Toyota", "model": "Tercel", "year": 1999,
"tire_pressure": [ 29.8, 30.0 ] }
])"_padded;
simdjson::ondemand::parser parser;
simdjson::ondemand::document doc = parser.iterate(json);
for (auto val : doc) {
Car c(val); // an exception may be thrown
std::cout << c.year << std::endl;
}
```
Observe how we first get a generic (`val`) which we cast to `Car`. It is by design: we require
explicit casting. The cast may throw an exception.
Once more, you can handle errors explicitly:
```cpp
for (auto val : doc) {
Car c;
auto error = val.get(c);
if(error) { std::cerr << simdjson::error_message(error) << std::endl; return false; }
}
```
You can also use the custom `Car` type as part of a template such as `std::vector`:
```cpp
simdjson::ondemand::parser parser;
simdjson::ondemand::document doc = parser.iterate(json);
std::vector<Car> cars(doc);
// visual studio users need an explicit call:
// std::vector<Car> cars = doc.get<std::vector<Car>>();
// because the compiler does not know whether to convert
// doc to an unsigned int or to a vector.
for(Car& c : cars) {
std::cout << c.year << std::endl;
}
```
By default, we support a wide range of standard templates such as
`std::vector`, `std::list`, `std::set`, `std::stack`, `std:queue`,
`std:deque`, `std::priority_queue`, `std::unordered_set`, `std::multiset`,
`std::unordered_multiset`, `std::unique_ptr`, `std::shared_ptr`, `std::optional`,
etc. They are handled automatically.
E.g., you can recover an `std::unique_ptr<Car>` like so:
```C++
int main() {
auto const json = R"( { "make": "Toyota", "model": "Camry", "year": 2018,
"tire_pressure": [ 40.1, 39.9 ] })"_padded;
simdjson::ondemand::parser parser;
simdjson::ondemand::document doc = parser.iterate(json);
std::unique_ptr<Car> c(doc);
std::cout << c->make << std::endl;
return EXIT_SUCCESS;
}
```
You may also conditionally fill in `std::optional` values.
```C++
padded_string json =
R"( { "car1": { "make": "Toyota", "model": "Camry", "year": 2018,
"tire_pressure": [ 40.1, 39.9 ] }
})"_padded;
ondemand::parser parser;
ondemand::document doc = parser.iterate(json);
std::optional<Car> car;
error = doc["key not found"].get<std::optional<Car>>().get(car);
// car has no value, error != simdjson::SUCCESS
error = doc["car1"].get<std::optional<Car>>().get(car);
// car has value Car{"Toyota", "Camry", 2018, {40.1f, 39.9f}}
// error is simdjson::SUCCESS
```
You can also deserialized to map-like types with keys that can be constructed
from `std::string_view` instances:
```C++
padded_string json =
R"( { "car1": { "make": "Toyota", "model": "Camry", "year": 2018,
"tire_pressure": [ 40.1, 39.9 ] }
})"_padded;
ondemand::parser parser;
ondemand::document doc = parser.iterate(json);
std:map<std::string,Car> cars;
error = doc.get<std:map<std::string,Car>>().get(cars);
// car has value car1->Car{"Toyota", "Camry", 2018, {40.1f, 39.9f}}
// error is simdjson::SUCCESS
```
And so forth.
Advanced users may want to overwrite the defaults provided by the simdjson library.
Suppose for example that you want to construct an instance of `std::list<Car>`, but
you also want to filter out any car made by Toyota. You may provide your own
`tag_invoke` function:
```c++
namespace simdjson {
// suppose we want to filter out all Toyotas
template <typename simdjson_value>
auto tag_invoke(deserialize_tag, simdjson_value &val, std::list<Car>& car) {
ondemand::array arr;
auto error = val.get_array().get(arr);
if (error) {
return error;
}
for (auto v : arr) {
Car c;
if ((error = v.get<Car>().get(c))) {
return error;
}
if(c.make != "Toyota") {
car.push_back(c);
}
}
return simdjson::SUCCESS;
}
}
```
With this code, deserializing an `std::list<Car>` instance would capture only the cars
that are not made by Toyota.
Minifying JSON strings without parsing
----------------------
@@ -1081,6 +1323,7 @@ In some cases, you may have valid JSON strings that you do not wish to parse but
std::unique_ptr<char[]> buffer{new char[length]};
size_t new_length{}; // It will receive the minified length.
auto error = simdjson::minify(some_string, length, buffer.get(), new_length);
if(error) { std::cerr << simdjson::error_message(error); }
// The buffer variable now has "[1,2,3,4]" and new_length has value 9.
```
@@ -1224,9 +1467,11 @@ be represented as `value` instances. You can check that a document is a scalar w
JSONPath
------------
The simdjson library now supports a subset of [JSONPath](https://datatracker.ietf.org/doc/html/draft-normington-jsonpath-00) through the `at_path()` method, allowing you to reach further into the document in a single call. The subset of JSONPath that is implemented is the subset that is trivially convertible into the JSON Pointer format, using `.` to access a field and `[]` to access a specific index.
The simdjson library supports a subset of [JSONPath](https://datatracker.ietf.org/doc/html/draft-normington-jsonpath-00) through the `at_path()` method, allowing you to reach further into the document in a single call. The subset of JSONPath that is implemented is the subset that is trivially convertible into the JSON Pointer format, using `.` to access a field and `[]` to access a specific index.
This implementation relies on `at_path()` converting its argument to JSON Pointer and then calling `at_pointer`, which makes use of [`rewind`](#rewind) to reset the parser at the beginning of the document. Hence, it invalidates all previously parsed values, objects and arrays: make sure to consume the values between each call to `at_path`.
This implementation relies on `at_path()` converting its argument to JSON Pointer and then calling `at_pointer`, which makes use of
[`rewind`](#rewind) to reset the parser at the beginning of the document. Hence, it invalidates all previously parsed values, objects
and arrays: make sure to consume the values between each call to `at_path`.
Consider the following example:
@@ -1267,6 +1512,18 @@ doc.at_path(".\\u00E9") == 123; // true
doc.at_path((const char*)u8".\u00E9") // returns an error (NO_SUCH_FIELD)
```
We also support the `$` prefix. When you start a JSONPath expression with $, you are indicating that the path starts from the root of the JSON document. E.g.,
```c++
auto json = R"( { "c" :{ "foo": { "a": [ 10, 20, 30 ] }}, "d": { "foo2": { "a": [ 10, 20, 30 ] }} , "e": 120 })"_padded;
ondemand::parser parser;
ondemand::document doc = parser.iterate(json);
ondemand::object obj = doc.get_object();
int64_t x = obj.at_path("$.c.foo.a[1]"); // 20
x = obj.at_path("$.d.foo2.a.2"); // 30
```
Error handling
--------------
@@ -1278,7 +1535,7 @@ pair. You can retrieve the value with .get() without generating an exception, li
```c++
ondemand::document doc;
auto error = parser.iterate(json).get(doc);
if (error) { cerr << error << endl; exit(1); }
if(error) { std::cerr << simdjson::error_message(error); exit(1); }
```
When there is no error, the error code `simdjson::SUCCESS`is returned: it evaluates as false as a Boolean.
@@ -1290,7 +1547,20 @@ 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`).
Other errors (`simdjson::INCOMPLETE_ARRAY_OR_OBJECT` and `simdjson::TAPE_ERROR`) indicate a fatal error and follow from the fact that the document is not valid JSON. These errors are not recoverable: you cannot continue. In which case, it is no longer safe to continue accessing the document: calling the method `is_alive()` on the document instance returns false. It is your responsibility as a user to stop using the simdjson
document after encountering these fatal errors. Consider the following example, after
the fatal error, the document instance cannot be used. Observe how the JSON input is invalid.
```cpp
simdjson::padded_string badjson = R"( { "make": "Toyota", "model": "Camry", "year"})"_padded;
simdjson::ondemand::parser parser;
simdjson::ondemand::document doc;
auto errordoc = parser.iterate(badjson).get(doc);
// errordoc == simdjson::SUCCESS
simdjson::ondemand::value v;
auto error = doc.get_object()["year"].get(v);
// simdjson::is_fatal(error)) is true!
// doc.is_alive() is false
```
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
@@ -1309,7 +1579,7 @@ bool simple_error_example() {
auto error = doc["bad number"].get_double().get(x);
// returns "simdjson::NUMBER_ERROR"
if (error != SUCCESS) {
std::cout << error << std::endl;
std::cerr << simdjson::error_message(error) << std::endl;
return false;
}
std::cout << "Got " << x << std::endl;
@@ -1343,7 +1613,7 @@ Notice how we can retrieve the exact error condition (in this instance `simdjson
from the exception.
We can write a "quick start" example where we attempt to parse the following JSON file and access some data, without triggering exceptions:
```JavaScript
```JSON
{
"statuses": [
{
@@ -1362,7 +1632,6 @@ We can write a "quick start" example where we attempt to parse the following JSO
Our program loads the file, selects value corresponding to key `"search_metadata"` which expected to be an object, and then
it selects the key `"count"` within that object.
```C++
#include <iostream>
#include "simdjson.h"
@@ -1370,10 +1639,10 @@ it selects the key `"count"` within that object.
int main(void) {
simdjson::ondemand::parser parser;
auto error = padded_string::load("twitter.json").get(json);
if (error) { std::cerr << error << std::endl; return EXIT_FAILURE; }
if (error) { std::cerr << simdjson::error_message(error) << std::endl; return EXIT_FAILURE; }
simdjson::ondemand::document tweets;
error = parser.iterate(json).get(tweets);
if (error) { std::cerr << error << std::endl; return EXIT_FAILURE; }
if (error) { std::cerr << simdjson::error_message(error) << std::endl; return EXIT_FAILURE; }
simdjson::ondemand::value res;
error = tweets["search_metadata"]["count"].get(res);
if (error != SUCCESS) {
@@ -1389,7 +1658,7 @@ The following is a similar example where one wants to get the id of the first tw
triggering exceptions. To do this, we use `["statuses"].at(0)["id"]`. We break that expression down:
- Get the list of tweets (the `"statuses"` key of the document) using `["statuses"]`). The result is expected to be an array.
- Get the first tweet using `.at(0)`. The result is expected to be an object.
- Get the first tweet using `.at(0)`. The result is expected to be an object. Observe that the `at` method can only be called once on an array (it cannot be used for iteration).
- Get the id of the tweet using ["id"]. We expect the value to be a non-negative integer.
Observe how we use the `at` method when querying an index into an array, and not the bracket operator.
@@ -1404,18 +1673,18 @@ int main(void) {
simdjson::ondemand::document tweets;
padded_string json;
auto error = padded_string::load("twitter.json").get(json);
if (error) { std::cerr << error << std::endl; return EXIT_FAILURE; }
if (error) { std::cerr << simdjson::error_message(error) << std::endl; return EXIT_FAILURE; }
error = parser.iterate(json).get(tweets);
if (error) { std::cerr << error << std::endl; return EXIT_FAILURE; }
if (error) { std::cerr << simdjson::error_message(error) << std::endl; return EXIT_FAILURE; }
uint64_t identifier;
error = tweets["statuses"].at(0)["id"].get(identifier);
if (error) { std::cerr << error << std::endl; return EXIT_FAILURE; }
if (error) { std::cerr << simdjson::error_message(error) << std::endl; return EXIT_FAILURE; }
std::cout << identifier << std::endl;
}
```
The `at` method can only be called once on an array. It cannot be used
to iterate through the values of an array.
*Important remark*: The `at` method can only be called once on an array. It cannot be used
to iterate through the values of an array. We deliberately forbid this usage to avoid performance antipatterns. If you need to iterate through the values of an array, you should use a `for` loop.
### Error handling examples without exceptions
@@ -1433,40 +1702,40 @@ bool parse() {
// Iterating through an array of objects
auto error = parser.iterate(cars_json).get(doc);
if (error) { std::cerr << error << std::endl; return false; }
if (error) { std::cerr << simdjson::error_message(error) << std::endl; return false; }
ondemand::array cars; // invalid until the get() succeeds
error = doc.get_array().get(cars);
for (auto car_value : cars) {
ondemand::object car; // invalid until the get() succeeds
error = car_value.get_object().get(car);
if (error) { std::cerr << error << std::endl; return false; }
if (error) { std::cerr << simdjson::error_message(error) << std::endl; return false; }
// Accessing a field by name
std::string_view make;
std::string_view model;
error = car["make"].get(make);
if (error) { std::cerr << error << std::endl; return false; }
if (error) { std::cerr << simdjson::error_message(error) << std::endl; return false; }
error = car["model"].get(model);
if (error) { std::cerr << error << std::endl; return false; }
if (error) { std::cerr << simdjson::error_message(error) << std::endl; return false; }
cout << "Make/Model: " << make << "/" << model << endl;
// Casting a JSON element to an integer
uint64_t year{};
error = car["year"].get(year);
if (error) { std::cerr << error << std::endl; return false; }
if (error) { std::cerr << simdjson::error_message(error) << std::endl; return false; }
cout << "- This car is " << 2020 - year << " years old." << endl;
// Iterating through an array of floats
double total_tire_pressure = 0;
ondemand::array pressures;
error = car["tire_pressure"].get_array().get(pressures);
if (error) { std::cerr << error << std::endl; return false; }
if (error) { std::cerr << simdjson::error_message(error) << std::endl; return false; }
for (auto tire_pressure_value : pressures) {
double tire_pressure;
error = tire_pressure_value.get_double().get(tire_pressure);
if (error) { std::cerr << error << std::endl; return false; }
if (error) { std::cerr << simdjson::error_message(error) << std::endl; return false; }
total_tire_pressure += tire_pressure;
}
cout << "- Average tire pressure: " << (total_tire_pressure / 4) << endl;
@@ -1588,7 +1857,7 @@ auto doc = parser.iterate(broken_json);
int64_t i;
auto error = doc["integer"].get_int64().get(i); // Expect to get integer from "integer" key, but get TAPE_ERROR
if (error) {
std::cout << error << std::endl; // Prints TAPE_ERROR error message
std::cerr << simdjson::error_message(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);
@@ -1625,7 +1894,7 @@ auto doc = parser.iterate(json);
int64_t i;
auto error = doc["integer"].get_int64().get(i); // Incorrect call on array, INCORRECT_TYPE error
if (error) {
std::cout << error << std::endl; // Prints INCORRECT_TYPE error message
std::cerr << simdjson::error_message(error) << std::endl; // Prints INCORRECT_TYPE error message
std::cout<< doc.current_location() << std::endl; // Prints "[1,2,3] " (location of INCORRECT_TYPE error)
}
```
@@ -1680,6 +1949,8 @@ 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.
Example 1.
```C++
auto json = R"([1, 2] foo ])"_padded;
ondemand::parser parser;
@@ -1694,6 +1965,21 @@ content.
}
```
Example 2.
```cpp
auto json = R"(["extra close"]])"_padded;
ondemand::parser parser;
ondemand::document doc = parser.iterate(json);
ondemand::array array = doc.get_array();
for (std::string_view values : array) {
std::cout << values << std::endl;
}
if(!doc.at_end()) {
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.
@@ -1734,6 +2020,7 @@ to the document `rewind()` method, except that it does not rewind the
internal string buffer. Thus you should consume values only 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.
You must not call `reset()` on an object or an array as you are iterating through it.
Newline-Delimited JSON (ndjson) and JSON lines
@@ -1745,7 +2032,7 @@ serialize data into streams of multiple JSON documents. That is, instead of one
write out multiple records as independent JSON documents, to be read one-by-one.
The simdjson library also supports multithreaded JSON streaming through a large file
containing many smaller JSON documents in either [ndjson](http://ndjson.org)
containing many smaller JSON documents in either [ndjson](https://github.com/ndjson/ndjson-spec)
or [JSON lines](http://jsonlines.org) format. If your JSON documents all contain arrays
or objects, we even support direct file concatenation without whitespace. However, if there
is content between your JSON documents, it should be exclusively ASCII white-space characters.
@@ -1798,7 +2085,7 @@ for (auto doc: stream) {
error = doc.at_pointer("/4").get(val);
// error == simdjson::CAPACITY
if (error) {
std::cerr << error << std::endl;
std::cerr << simdjson::error_message(error) << std::endl;
// We left 293 bytes unprocessed at the tail end of the input.
std::cout << " unprocessed bytes at the end: " << stream.truncated_bytes() << std::endl;
break;
@@ -2304,7 +2591,7 @@ The CPU detection, which runs the first time parsing is attempted and switches t
parser for your CPU, is transparent and thread-safe.
Our runtime dispatching is based on global objects that are instantiated at the beginning of the
main thread and may be discarded at the end of the main thread. If you have multiple threads running
and some threads use the library while the main thread is cleaning up ressources, you may encounter
and some threads use the library while the main thread is cleaning up resources, you may encounter
issues. If you expect such problems, you may consider using [std::quick_exit](https://en.cppreference.com/w/cpp/utility/program/quick_exit).
In a threaded environment, stack space is often limited. Running code like simdjson in debug mode may require hundreds of kilobytes of stack memory. Thus stack overflows are a possibility. We recommend you turn on optimization when working in an environment where stack space is limited. If you must run your code in debug mode, we recommend you configure your system to have more stack space. We discourage you from running production code based on a debug build.
@@ -2673,6 +2960,7 @@ Performance tips
std::string_view year = data["year"];
std::string_view rating = data["rating"];
```
- You will get better performance if you seek the keys in the order in which they appear in the document. So if processing `{"a":1, "b":2, "c":3}`, do `value1 = data["a"]; value2 = data["b"]; value3 data["c"];` and not `value2 = data["b"]; value1 = data["a"]; value3 data["c"];`. Of course, it is not always possible to know for sure in which order the keys appear.
+65 -1
View File
@@ -8,6 +8,7 @@ An overview of what you need to know to use simdjson, with examples.
* [Using the Parsed JSON](#using-the-parsed-json)
* [C++17 Support](#c17-support)
* [JSON Pointer](#json-pointer)
* [JSONPath](#jsonpath)
* [Error Handling](#error-handling)
* [Error Handling Example](#error-handling-example)
* [Exceptions](#exceptions)
@@ -59,6 +60,26 @@ std::string data = "my data";
simdjson::padded_string my_padded_data(data); // copies to a padded buffer
```
You can then parse the JSON document from the `simdjson::padded_string` instance:
```cpp
simdjson::dom::parser parser;
simdjson::dom::element doc = parser.parse(my_padded_data);
```
Whenever you pass an `std::string` reference to `parser::parse`,
the parser will access the bytes beyond the end of
the string but before the end of the allocated memory (`std::string::capacity()`).
If you are using a sanitizer that checks for reading uninitialized bytes or `std::string`'s
container-overflow checks, you may encounter sanitizer warnings.
You can safely ignore these warnings. Or you can call `simdjson::pad(std::string&)` to pad the
string with `SIMDJSON_PADDING` spaces: this function returns a `simdjson::padding_string_view` which can be be passed to the parser's iterator function:
```c++
std::string json = "[1]";
dom::element doc = parser.parse(simdjson::pad(json));
```
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.
@@ -257,6 +278,49 @@ for (dom::element car_element : cars) {
}
```
JSONPath
------------
The simdjson library supports a subset of [JSONPath](https://datatracker.ietf.org/doc/html/draft-normington-jsonpath-00) through the `at_path()` method, allowing you to reach further into the document in a single call. The subset of JSONPath that is implemented is the subset that is trivially convertible into the JSON Pointer format, using `.` to access a field and `[]` to access a specific index.
Consider the following example:
```c++
auto cars_json = R"( [
{ "make": "Toyota", "model": "Camry", "year": 2018, "tire_pressure": [ 40.1, 39.9, 37.7, 40.4 ] },
{ "make": "Kia", "model": "Soul", "year": 2012, "tire_pressure": [ 30.1, 31.0, 28.6, 28.7 ] },
{ "make": "Toyota", "model": "Tercel", "year": 1999, "tire_pressure": [ 29.8, 30.0, 30.2, 30.5 ] }
] )"_padded;
dom::parser parser;
dom::element doc;
auto error = parser.parse(cars_json).get(doc);
if(error) { /*won't happen*/ }
double p;
error = doc.at_path("[0].tire_pressure[1]").get(p);
if(error) { /*won't happen*/ }
cout << p << endl; // Prints 39.9
```
We also support the `$` prefix. When you start a JSONPath expression with $, you are indicating that the path starts from the root of the JSON document. E.g.,
```c++
auto json = R"( { "c" :{ "foo": { "a": [ 10, 20, 30 ] }}, "d": { "foo2": { "a": [ 10, 20, 30 ] }} , "e": 120 })"_padded;
dom::parser parser;
dom::element doc;
auto error = parser.parse(json).get(doc);
if(error) { /*won't happen*/ }
dom::object obj;
error = doc.get_object().get(obj);
if(error) { /*won't happen*/ }
int64_t x;
error = obj.at_path("$[3].foo.a[1]").get(x);
if(error) { /*won't happen*/ }
if(x != 20) { /*won't happen*/ }
x = obj.at_path("$.d.foo2.a.2");
if(error) { /*won't happen*/ }
```
Error Handling
@@ -669,5 +733,5 @@ Setting the `realloc_if_needed` parameter `false` in this manner may lead to bet
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 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.
+116 -2
View File
@@ -25,6 +25,7 @@ Contents
- [Use cases](#use-cases)
- [Tracking your position](#tracking-your-position)
- [Incomplete streams](#incomplete-streams)
- [C++20 features](#c20-features)
Motivation
-----------
@@ -102,7 +103,12 @@ remove almost entirely its cost and replaces it by the overhead of a thread, whi
cheaper. Ain't that awesome!
Thread support is only active if thread supported is detected in which case the macro
SIMDJSON_THREADS_ENABLED is set. Otherwise the library runs in single-thread mode.
SIMDJSON_THREADS_ENABLED is set. You can also manually pass `SIMDJSON_THREADS_ENABLED=1` flag
to the library. Otherwise the library runs in single-thread mode.
You should be consistent. If you link against the simdjson library built for multithreading
(i.e., with `SIMDJSON_THREADS_ENABLED`), then you should build your application with multithreading
system (setting `SIMDJSON_THREADS_ENABLED=1` and linking against a thread library).
A `document_stream` instance uses at most two threads: there is a main thread and a worker thread.
@@ -124,7 +130,7 @@ If your documents are all objects or arrays, then you may even have nothing betw
E.g., `[1,2]{"32":1}` is recognized as two documents.
Some official formats **(non-exhaustive list)**:
- [Newline-Delimited JSON (NDJSON)](http://ndjson.org/)
- [Newline-Delimited JSON (NDJSON)](https://github.com/ndjson/ndjson-spec/)
- [JSON lines (JSONL)](http://jsonlines.org/)
- [Record separator-delimited JSON (RFC 7464)](https://tools.ietf.org/html/rfc7464) <- Not supported by JsonStream!
- [More on Wikipedia...](https://en.wikipedia.org/wiki/JSON_streaming)
@@ -288,3 +294,111 @@ string
object
array
```
C++20 features
--------------------
In C++20, the standard introduced the notion of *customization point*.
A customization point is a function or function object that can be customized for different types. It allows library authors to provide default behavior while giving users the ability to override this behavior for specific types.
A tag_invoke function serves as a mechanism for customization points. It is not directly part of the C++ standard library but is often used in libraries that implement customization points.
The tag_invoke function is typically a generic function that takes a tag type and additional arguments.
The first argument is usually a tag type (often an empty struct) that uniquely identifies the customization point (e.g., deserialization of custom types in simdjson). Users or library providers can specialize tag_invoke for their types by defining it in the appropriate namespace, often inline namespace.
You can deserialize you own data structures conveniently if your system supports C++20.
When it is the case, the macro `SIMDJSON_SUPPORTS_DESERIALIZATION` will be set to 1 by
the simdjson library.
Consider a custom class `Car`:
```C++
struct Car {
std::string make;
std::string model;
int year;
std::vector<float> tire_pressure;
};
```
You may support deserializing directly from a JSON value or document to your own `Car` instance
by defining a single `tag_invoke` function:
```C++
namespace simdjson {
// This tag_invoke MUST be inside simdjson namespace
template <typename simdjson_value>
auto tag_invoke(deserialize_tag, simdjson_value &val, Car& car) {
ondemand::object obj;
auto error = val.get_object().get(obj);
if (error) {
return error;
}
if ((error = obj["make"].get_string(car.make))) {
return error;
}
if ((error = obj["model"].get_string(car.model))) {
return error;
}
if ((error = obj["year"].get(car.year))) {
return error;
}
if ((error = obj["tire_pressure"].get<std::vector<float>>().get(
car.tire_pressure))) {
return error;
}
return simdjson::SUCCESS;
}
} // namespace simdjson
```
Importantly, the `tag_invoke` function must be inside the `simdjson` namespace.
Let us explain each argument of `tag_invoke` function.
- `simdjson::deserialize_tag`: it is the tag for Customization Point Object (CPO). You may often ignore this parameter. It is used to indicate that you mean to provide a deserialization function for simdjson.
- `var`: It receives automatically a `simdjson` value type (document, value, document_reference).
- The third parameter is an instance of the type that you want to support.
Please see our main documentation (`basics.md`) under
"Use `tag_invoke` for custom types (C++20)" for details about
tag_invoke functions.
Given a stream of JSON documents, you can add them to a data structure
such as a `std::vector<Car>` like so if you support exceptions:
```C++
padded_string json =
R"( { "make": "Toyota", "model": "Camry", "year": 2018,
"tire_pressure": [ 40.1, 39.9 ] }
{ "make": "Kia", "model": "Soul", "year": 2012,
"tire_pressure": [ 30.1, 31.0 ] }
{ "make": "Toyota", "model": "Tercel", "year": 1999,
"tire_pressure": [ 29.8, 30.0 ] }
)"_padded;
ondemand::parser parser;
ondemand::document_stream stream;
[[maybe_unused]] auto error = parser.iterate_many(json).get(stream);
std::vector<Car> cars;
for(auto doc : stream) {
cars.push_back((Car)doc); // an exception may be thrown
}
```
Otherwise you may use this longer version for explicit handling of errors:
```C++
std::vector<Car> cars;
for(auto doc : stream) {
Car c;
if ((error = doc.get<Car>().get(c))) {
std::cerr << simdjson::error_message(error); << std::endl;
return EXIT_FAILURE;
}
cars.push_back(c);
}
```
+1 -1
View File
@@ -102,7 +102,7 @@ or indexing (`object["key"]`). In some cases, the values are even deserialized d
maps.
The DOM approach is conceptually simple and "programmer friendly". Using the
DOM tree is often easy enough that many users use the DOM as-is instead of creating
DOM tree is often easy enough that many users process the DOM as-is instead of creating
their own custom data structures.
The DOM approach was the only way to parse JSON documents up to version 0.6 of the simdjson library.
+6 -1
View File
@@ -103,7 +103,12 @@ cases, remove almost entirely its cost and replaces it by the overhead of a thre
of magnitude cheaper. Ain't that awesome!
Thread support is only active if thread supported is detected in which case the macro
SIMDJSON_THREADS_ENABLED is set. Otherwise the library runs in single-thread mode.
SIMDJSON_THREADS_ENABLED is set. You can also manually pass `SIMDJSON_THREADS_ENABLED=1` flag
to the library. Otherwise the library runs in single-thread mode.
You should be consistent. If you link against the simdjson library built for multithreading
(i.e., with `SIMDJSON_THREADS_ENABLED`), then you should build your application with multithreading
system (setting `SIMDJSON_THREADS_ENABLED=1` and linking against a thread library).
A `document_stream` instance uses at most two threads: there is a main thread and a worker thread.
You should expect the main thread to be fully occupied while the worker thread is partially busy
+5 -3
View File
@@ -158,7 +158,9 @@ On Intel and AMD Windows platforms, Microsoft Visual Studio enables programmers
When compiling with Visual Studio, we recommend the flags `/Ob2 /O2` or better. We do not recommend that you compile simdjson with architecture-specific flags such as `arch:AVX2`. The simdjson library automatically selects the best execution kernel at runtime.
Recent versions of Microsoft Visual Studio on Windows provides support for the LLVM Clang compiler. You only need to install the "Clang compiler" optional component (ClangCL). You may also get a copy of the 64-bit LLVM CLang compiler for [Windows directly from LLVM](https://releases.llvm.org/download.html). The simdjson library fully supports the LLVM Clang compiler under Windows. In fact, you may get better performance out of simdjson with the LLVM Clang compiler than with the regular Visual Studio compiler. Meanwhile the [LLVM CLang compiler is binary compatible with Visual Studio](https://clang.llvm.org/docs/MSVCCompatibility.html) which means that you can combine their binaries (executables and libraries).
Recent versions of Microsoft Visual Studio on Windows provides support for the LLVM Clang compiler. You only need to install the "Clang compiler" optional component (clang-cl). You may also get a copy of the 64-bit LLVM CLang compiler for [Windows directly from LLVM](https://releases.llvm.org/download.html). The simdjson library fully supports the LLVM Clang compiler under Windows. In fact, you may get better performance out of simdjson with the LLVM Clang compiler than with the regular Visual Studio compiler. Meanwhile the [LLVM CLang compiler is binary compatible with Visual Studio](https://clang.llvm.org/docs/MSVCCompatibility.html) which means that you can combine their binaries (executables and libraries).
We recommend Visual Studio users prefer LLVM (clang-cl). It compiles to faster release binaries. Furthermore, it compilers faster in release mode.
Under Windows, we also support the GNU GCC compiler via MSYS2. The performance of 64-bit MSYS2 under Windows is excellent (on par with Linux).
@@ -241,8 +243,8 @@ long page_size() {
// Returns true if the buffer + len + simdjson::SIMDJSON_PADDING crosses the
// page boundary.
bool need_allocation(const char *buf, size_t len) {
return ((reinterpret_cast<uintptr_t>(buf + len - 1) % page_size()) <
simdjson::SIMDJSON_PADDING);
return ((reinterpret_cast<uintptr_t>(buf + len - 1) % page_size())
+ simdjson::SIMDJSON_PADDING > static_cast<uintptr_t>(page_size()));
}
simdjson::padded_string_view
+1 -1
View File
@@ -72,7 +72,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
// make this dynamic, so it works regardless of how it was compiled
// or what hardware it runs on
constexpr std::size_t Nimplementations_max=3;
constexpr std::size_t Nimplementations_max=4;
const std::size_t Nimplementations = supported_implementations.size();
if(Nimplementations>Nimplementations_max) {
-1
View File
@@ -53,5 +53,4 @@
#include "simdjson/dom.h"
#include "simdjson/ondemand.h"
#endif // SIMDJSON_H
+9 -3
View File
@@ -19,7 +19,7 @@ SIMDJSON_NO_SANITIZE_UNDEFINED
// See issue https://github.com/simdjson/simdjson/issues/1965
SIMDJSON_NO_SANITIZE_MEMORY
simdjson_inline int trailing_zeroes(uint64_t input_num) {
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
#if SIMDJSON_REGULAR_VISUAL_STUDIO
unsigned long ret;
// Search the mask data from least significant bit (LSB)
// to the most significant bit (MSB) for a set bit (1).
@@ -35,9 +35,15 @@ simdjson_inline uint64_t clear_lowest_bit(uint64_t input_num) {
return input_num & (input_num-1);
}
// We sometimes call leading_zeroes on inputs that are zero,
// but the algorithms do not end up using the returned value.
// Sadly, sanitizers are not smart enough to figure it out.
// Applies only when SIMDJSON_PREFER_REVERSE_BITS is defined and true.
// (See below.)
SIMDJSON_NO_SANITIZE_UNDEFINED
/* result might be undefined when input_num is zero */
simdjson_inline int leading_zeroes(uint64_t input_num) {
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
#if SIMDJSON_REGULAR_VISUAL_STUDIO
unsigned long leading_zero = 0;
// Search the mask data from most significant bit (MSB)
// to least significant bit (LSB) for a set bit (1).
@@ -90,7 +96,7 @@ simdjson_inline uint64_t zero_leading_bit(uint64_t rev_bits, int leading_zeroes)
#endif
simdjson_inline bool add_overflow(uint64_t value1, uint64_t value2, uint64_t *result) {
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
#if SIMDJSON_REGULAR_VISUAL_STUDIO
*result = value1 + value2;
return *result < value1;
#else
@@ -51,6 +51,12 @@ simdjson_inline internal::value128 full_multiplication(uint64_t value1, uint64_t
} // namespace arm64
} // namespace simdjson
#ifndef SIMDJSON_SWAR_NUMBER_PARSING
#if SIMDJSON_IS_BIG_ENDIAN
#define SIMDJSON_SWAR_NUMBER_PARSING 0
#else
#define SIMDJSON_SWAR_NUMBER_PARSING 1
#endif
#endif
#endif // SIMDJSON_ARM64_NUMBERPARSING_DEFS_H
+7 -7
View File
@@ -12,7 +12,7 @@ namespace arm64 {
namespace {
namespace simd {
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
#if SIMDJSON_REGULAR_VISUAL_STUDIO
namespace {
// Start of private section with Visual Studio workaround
@@ -121,7 +121,7 @@ namespace {
// We return uint32_t instead of uint16_t because that seems to be more efficient for most
// purposes (cutting it down to uint16_t costs performance in some compilers).
simdjson_inline uint32_t to_bitmask() const {
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
#if SIMDJSON_REGULAR_VISUAL_STUDIO
const uint8x16_t bit_mask = simdjson_make_uint8x16_t(0x01, 0x02, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80,
0x01, 0x02, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80);
#else
@@ -152,7 +152,7 @@ namespace {
// Splat constructor
simdjson_inline simd8(uint8_t _value) : simd8(splat(_value)) {}
// Member-by-member initialization
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
#if SIMDJSON_REGULAR_VISUAL_STUDIO
simdjson_inline simd8(
uint8_t v0, uint8_t v1, uint8_t v2, uint8_t v3, uint8_t v4, uint8_t v5, uint8_t v6, uint8_t v7,
uint8_t v8, uint8_t v9, uint8_t v10, uint8_t v11, uint8_t v12, uint8_t v13, uint8_t v14, uint8_t v15
@@ -246,7 +246,7 @@ namespace {
uint64x2_t shufmask64 = {thintable_epi8[mask1], thintable_epi8[mask2]};
uint8x16_t shufmask = vreinterpretq_u8_u64(shufmask64);
// we increment by 0x08 the second half of the mask
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
#if SIMDJSON_REGULAR_VISUAL_STUDIO
uint8x16_t inc = simdjson_make_uint8x16_t(0, 0, 0, 0, 0, 0, 0, 0, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08);
#else
uint8x16_t inc = {0, 0, 0, 0, 0, 0, 0, 0, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08};
@@ -276,7 +276,7 @@ namespace {
uint8x8_t compactmask1 = vcreate_u8(thintable_epi8[mask1]);
uint8x8_t compactmask2 = vcreate_u8(thintable_epi8[mask2]);
// we increment by 0x08 the second half of the mask
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
#if SIMDJSON_REGULAR_VISUAL_STUDIO
uint8x8_t inc = simdjson_make_uint8x8_t(0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08);
#else
uint8x8_t inc = {0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08};
@@ -328,7 +328,7 @@ namespace {
// Array constructor
simdjson_inline simd8(const int8_t* values) : simd8(load(values)) {}
// Member-by-member initialization
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
#if SIMDJSON_REGULAR_VISUAL_STUDIO
simdjson_inline simd8(
int8_t v0, int8_t v1, int8_t v2, int8_t v3, int8_t v4, int8_t v5, int8_t v6, int8_t v7,
int8_t v8, int8_t v9, int8_t v10, int8_t v11, int8_t v12, int8_t v13, int8_t v14, int8_t v15
@@ -449,7 +449,7 @@ namespace {
}
simdjson_inline uint64_t to_bitmask() const {
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
#if SIMDJSON_REGULAR_VISUAL_STUDIO
const uint8x16_t bit_mask = simdjson_make_uint8x16_t(
0x01, 0x02, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80,
0x01, 0x02, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80
+1
View File
@@ -9,6 +9,7 @@
#include "simdjson/compiler_check.h"
#include "simdjson/error.h"
#include "simdjson/portability.h"
#include "simdjson/concepts.h"
/**
* @brief The top level simdjson namespace, containing everything the library provides.
+24
View File
@@ -50,4 +50,28 @@
#endif
#endif
#ifdef __has_include
#if __has_include(<version>)
#include <version>
#endif
#endif
#if defined(__apple_build_version__)
#if __apple_build_version__ < 14000000
#define SIMDJSON_CONCEPT_DISABLED 1 // apple-clang/13 doesn't support std::convertible_to
#endif
#endif
#if defined(__cpp_concepts) && !defined(SIMDJSON_CONCEPT_DISABLED)
#if __cpp_concepts >= 201907L
#include <utility>
#define SIMDJSON_SUPPORTS_DESERIALIZATION 1
#else
#define SIMDJSON_SUPPORTS_DESERIALIZATION 0
#endif
#else // defined(__cpp_concepts) && !defined(SIMDJSON_CONCEPT_DISABLED)
#define SIMDJSON_SUPPORTS_DESERIALIZATION 0
#endif // defined(__cpp_concepts) && !defined(SIMDJSON_CONCEPT_DISABLED)
#endif // SIMDJSON_COMPILER_CHECK_H
+131
View File
@@ -0,0 +1,131 @@
#ifndef SIMDJSON_CONCEPTS_H
#define SIMDJSON_CONCEPTS_H
#if SIMDJSON_SUPPORTS_DESERIALIZATION
#include <concepts>
#include <type_traits>
namespace simdjson {
namespace concepts {
namespace details {
#define SIMDJSON_IMPL_CONCEPT(name, method) \
template <typename T> \
concept supports_##name = !std::is_const_v<T> && requires { \
typename std::remove_cvref_t<T>::value_type; \
requires requires(typename std::remove_cvref_t<T>::value_type &&val, \
T obj) { \
obj.method(std::move(val)); \
requires !requires { obj = std::move(val); }; \
}; \
};
SIMDJSON_IMPL_CONCEPT(emplace_back, emplace_back)
SIMDJSON_IMPL_CONCEPT(emplace, emplace)
SIMDJSON_IMPL_CONCEPT(push_back, push_back)
SIMDJSON_IMPL_CONCEPT(add, add)
SIMDJSON_IMPL_CONCEPT(push, push)
SIMDJSON_IMPL_CONCEPT(append, append)
SIMDJSON_IMPL_CONCEPT(insert, insert)
SIMDJSON_IMPL_CONCEPT(op_append, operator+=)
#undef SIMDJSON_IMPL_CONCEPT
} // namespace details
template <typename T>
concept string_view_like = std::is_convertible_v<T, std::string_view> &&
!std::is_convertible_v<T, const char*>;
template<typename T>
concept constructible_from_string_view = std::is_constructible_v<T, std::string_view>
&& !std::is_same_v<T, std::string_view>
&& std::is_default_constructible_v<T>;
template<typename M>
concept string_view_keyed_map = string_view_like<typename M::key_type>
&& requires(std::remove_cvref_t<M>& m, typename M::key_type sv, typename M::mapped_type v) {
{ m.emplace(sv, v) } -> std::same_as<std::pair<typename M::iterator, bool>>;
};
/// Check if T is a container that we can append to, including:
/// std::vector, std::deque, std::list, std::string, ...
template <typename T>
concept appendable_containers =
(details::supports_emplace_back<T> || details::supports_emplace<T> ||
details::supports_push_back<T> || details::supports_push<T> ||
details::supports_add<T> || details::supports_append<T> ||
details::supports_insert<T>) && !string_view_keyed_map<T>;
/// Insert into the container however possible
template <appendable_containers T, typename... Args>
constexpr decltype(auto) emplace_one(T &vec, Args &&...args) {
if constexpr (details::supports_emplace_back<T>) {
return vec.emplace_back(std::forward<Args>(args)...);
} else if constexpr (details::supports_emplace<T>) {
return vec.emplace(std::forward<Args>(args)...);
} else if constexpr (details::supports_push_back<T>) {
return vec.push_back(std::forward<Args>(args)...);
} else if constexpr (details::supports_push<T>) {
return vec.push(std::forward<Args>(args)...);
} else if constexpr (details::supports_add<T>) {
return vec.add(std::forward<Args>(args)...);
} else if constexpr (details::supports_append<T>) {
return vec.append(std::forward<Args>(args)...);
} else if constexpr (details::supports_insert<T>) {
return vec.insert(std::forward<Args>(args)...);
} else if constexpr (details::supports_op_append<T> && sizeof...(Args) == 1) {
return vec.operator+=(std::forward<Args>(args)...);
} else {
static_assert(!sizeof(T *),
"We don't know how to add things to this container");
}
}
/// This checks if the container will return a reference to the newly added
/// element after an insert which for example `std::vector::emplace_back` does
/// since C++17; this will allow some optimizations.
template <typename T>
concept returns_reference = appendable_containers<T> && requires {
typename std::remove_cvref_t<T>::reference;
requires requires(typename std::remove_cvref_t<T>::value_type &&val, T obj) {
{
emplace_one(obj, std::move(val))
} -> std::same_as<typename std::remove_cvref_t<T>::reference>;
};
};
template <typename T>
concept smart_pointer = requires(std::remove_cvref_t<T> ptr) {
// Check if T has a member type named element_type
typename std::remove_cvref_t<T>::element_type;
// Check if T has a get() member function
{
ptr.get()
} -> std::same_as<typename std::remove_cvref_t<T>::element_type *>;
// Check if T can be dereferenced
{ *ptr } -> std::same_as<typename std::remove_cvref_t<T>::element_type &>;
};
template <typename T>
concept optional_type = requires(std::remove_cvref_t<T> obj) {
typename std::remove_cvref_t<T>::value_type;
{ obj.value() } -> std::same_as<typename std::remove_cvref_t<T>::value_type&>;
requires requires(typename std::remove_cvref_t<T>::value_type &&val) {
obj.emplace(std::move(val));
obj = std::move(val);
{
obj.value_or(val)
} -> std::convertible_to<typename std::remove_cvref_t<T>::value_type>;
};
{ static_cast<bool>(obj) } -> std::same_as<bool>; // convertible to bool
};
} // namespace concepts
} // namespace simdjson
#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
#endif // SIMDJSON_CONCEPTS_H
+14
View File
@@ -7,6 +7,7 @@
#include "simdjson/dom/array.h"
#include "simdjson/dom/element.h"
#include "simdjson/error-inl.h"
#include "simdjson/jsonpathutil.h"
#include "simdjson/internal/tape_ref-inl.h"
#include <limits>
@@ -44,6 +45,13 @@ inline simdjson_result<dom::element> simdjson_result<dom::array>::at_pointer(std
if (error()) { return error(); }
return first.at_pointer(json_pointer);
}
inline simdjson_result<dom::element> simdjson_result<dom::array>::at_path(std::string_view json_path) const noexcept {
auto json_pointer = json_path_to_pointer_conversion(json_path);
if (json_pointer == "-1") { return INVALID_JSON_POINTER; }
return at_pointer(json_pointer);
}
inline simdjson_result<dom::element> simdjson_result<dom::array>::at(size_t index) const noexcept {
if (error()) { return error(); }
return first.at(index);
@@ -113,6 +121,12 @@ inline simdjson_result<element> array::at_pointer(std::string_view json_pointer)
return child;
}
inline simdjson_result<element> array::at_path(std::string_view json_path) const noexcept {
auto json_pointer = json_path_to_pointer_conversion(json_path);
if (json_pointer == "-1") { return INVALID_JSON_POINTER; }
return at_pointer(json_pointer);
}
inline simdjson_result<element> array::at(size_t index) const noexcept {
SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
size_t i=0;
+16
View File
@@ -108,6 +108,21 @@ public:
*/
inline simdjson_result<element> at_pointer(std::string_view json_pointer) const noexcept;
/**
* Get the value associated with the given JSONPath expression. We only support
* JSONPath queries that trivially convertible to JSON Pointer queries: key
* names and array indices.
*
* https://datatracker.ietf.org/doc/html/draft-normington-jsonpath-00
*
* @return The value associated with the given JSONPath expression, or:
* - INVALID_JSON_POINTER if the JSONPath to JSON Pointer conversion fails
* - NO_SUCH_FIELD if a field does not exist in an object
* - INDEX_OUT_OF_BOUNDS if an array index is larger than an array length
* - INCORRECT_TYPE if a non-integer is used to access an array
*/
inline simdjson_result<element> at_path(std::string_view json_path) const noexcept;
/**
* Get the value at the given index. This function has linear-time complexity and
* is equivalent to the following:
@@ -152,6 +167,7 @@ public:
simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
inline simdjson_result<dom::element> at_pointer(std::string_view json_pointer) const noexcept;
inline simdjson_result<dom::element> at_path(std::string_view json_path) const noexcept;
inline simdjson_result<dom::element> at(size_t index) const noexcept;
#if SIMDJSON_EXCEPTIONS
+1 -1
View File
@@ -70,7 +70,7 @@ public:
* The memory allocation is strict: you
* can you use this function to increase
* or lower the amount of allocated memory.
* Passsing zero clears the memory.
* Passing zero clears the memory.
*/
error_code allocate(size_t len) noexcept;
/** @private Capacity in bytes, in terms
+11
View File
@@ -9,6 +9,7 @@
#include "simdjson/dom/object-inl.h"
#include "simdjson/error-inl.h"
#include "simdjson/jsonpathutil.h"
#include <ostream>
#include <limits>
@@ -122,6 +123,11 @@ simdjson_inline simdjson_result<dom::element> simdjson_result<dom::element>::at_
if (error()) { return error(); }
return first.at_pointer(json_pointer);
}
simdjson_inline simdjson_result<dom::element> simdjson_result<dom::element>::at_path(const std::string_view json_path) const noexcept {
auto json_pointer = json_path_to_pointer_conversion(json_path);
if (json_pointer == "-1") { return INVALID_JSON_POINTER; }
return at_pointer(json_pointer);
}
#ifndef SIMDJSON_DISABLE_DEPRECATED_API
[[deprecated("For standard compliance, use at_pointer instead, and prefix your pointers with a slash '/', see RFC6901 ")]]
simdjson_inline simdjson_result<dom::element> simdjson_result<dom::element>::at(const std::string_view json_pointer) const noexcept {
@@ -412,6 +418,11 @@ inline simdjson_result<element> element::at_pointer(std::string_view json_pointe
}
}
}
inline simdjson_result<element> element::at_path(std::string_view json_path) const noexcept {
auto json_pointer = json_path_to_pointer_conversion(json_path);
if (json_pointer == "-1") { return INVALID_JSON_POINTER; }
return at_pointer(json_pointer);
}
#ifndef SIMDJSON_DISABLE_DEPRECATED_API
[[deprecated("For standard compliance, use at_pointer instead, and prefix your pointers with a slash '/', see RFC6901 ")]]
inline simdjson_result<element> element::at(std::string_view json_pointer) const noexcept {
+19
View File
@@ -372,6 +372,8 @@ public:
* - INCORRECT_TYPE if this is not an object
*/
inline simdjson_result<element> operator[](const char *key) const noexcept;
simdjson_result<element> operator[](int) const noexcept = delete;
/**
* Get the value associated with the given JSON pointer. We use the RFC 6901
@@ -397,6 +399,21 @@ public:
*/
inline simdjson_result<element> at_pointer(const std::string_view json_pointer) const noexcept;
/**
* Get the value associated with the given JSONPath expression. We only support
* JSONPath queries that trivially convertible to JSON Pointer queries: key
* names and array indices.
*
* https://datatracker.ietf.org/doc/html/draft-normington-jsonpath-00
*
* @return The value associated with the given JSONPath expression, or:
* - INVALID_JSON_POINTER if the JSONPath to JSON Pointer conversion fails
* - NO_SUCH_FIELD if a field does not exist in an object
* - INDEX_OUT_OF_BOUNDS if an array index is larger than an array length
* - INCORRECT_TYPE if a non-integer is used to access an array
*/
inline simdjson_result<element> at_path(std::string_view json_path) const noexcept;
#ifndef SIMDJSON_DISABLE_DEPRECATED_API
/**
*
@@ -525,7 +542,9 @@ public:
simdjson_inline simdjson_result<dom::element> operator[](std::string_view key) const noexcept;
simdjson_inline simdjson_result<dom::element> operator[](const char *key) const noexcept;
simdjson_result<dom::element> operator[](int) const noexcept = delete;
simdjson_inline simdjson_result<dom::element> at_pointer(const std::string_view json_pointer) const noexcept;
simdjson_inline simdjson_result<dom::element> at_path(const std::string_view json_path) const noexcept;
[[deprecated("For standard compliance, use at_pointer instead, and prefix your pointers with a slash '/', see RFC6901 ")]]
simdjson_inline simdjson_result<dom::element> at(const std::string_view json_pointer) const noexcept;
simdjson_inline simdjson_result<dom::element> at(size_t index) const noexcept;
+12
View File
@@ -7,6 +7,7 @@
#include "simdjson/dom/element-inl.h"
#include "simdjson/error-inl.h"
#include "simdjson/jsonpathutil.h"
#include <cstring>
@@ -34,6 +35,11 @@ inline simdjson_result<dom::element> simdjson_result<dom::object>::at_pointer(st
if (error()) { return error(); }
return first.at_pointer(json_pointer);
}
inline simdjson_result<dom::element> simdjson_result<dom::object>::at_path(std::string_view json_path) const noexcept {
auto json_pointer = json_path_to_pointer_conversion(json_path);
if (json_pointer == "-1") { return INVALID_JSON_POINTER; }
return at_pointer(json_pointer);
}
inline simdjson_result<dom::element> simdjson_result<dom::object>::at_key(std::string_view key) const noexcept {
if (error()) { return error(); }
return first.at_key(key);
@@ -131,6 +137,12 @@ inline simdjson_result<element> object::at_pointer(std::string_view json_pointer
return child;
}
inline simdjson_result<element> object::at_path(std::string_view json_path) const noexcept {
auto json_pointer = json_path_to_pointer_conversion(json_path);
if (json_pointer == "-1") { return INVALID_JSON_POINTER; }
return at_pointer(json_pointer);
}
inline simdjson_result<element> object::at_key(std::string_view key) const noexcept {
iterator end_field = end();
for (iterator field = begin(); field != end_field; ++field) {
+18
View File
@@ -145,6 +145,7 @@ public:
* - INCORRECT_TYPE if this is not an object
*/
inline simdjson_result<element> operator[](const char *key) const noexcept;
simdjson_result<element> operator[](int) const noexcept = delete;
/**
* Get the value associated with the given JSON pointer. We use the RFC 6901
@@ -171,6 +172,21 @@ public:
*/
inline simdjson_result<element> at_pointer(std::string_view json_pointer) const noexcept;
/**
* Get the value associated with the given JSONPath expression. We only support
* JSONPath queries that trivially convertible to JSON Pointer queries: key
* names and array indices.
*
* https://datatracker.ietf.org/doc/html/draft-normington-jsonpath-00
*
* @return The value associated with the given JSONPath expression, or:
* - INVALID_JSON_POINTER if the JSONPath to JSON Pointer conversion fails
* - NO_SUCH_FIELD if a field does not exist in an object
* - INDEX_OUT_OF_BOUNDS if an array index is larger than an array length
* - INCORRECT_TYPE if a non-integer is used to access an array
*/
inline simdjson_result<element> at_path(std::string_view json_path) const noexcept;
/**
* Get the value associated with the given key.
*
@@ -243,7 +259,9 @@ public:
inline simdjson_result<dom::element> operator[](std::string_view key) const noexcept;
inline simdjson_result<dom::element> operator[](const char *key) const noexcept;
simdjson_result<dom::element> operator[](int) const noexcept = delete;
inline simdjson_result<dom::element> at_pointer(std::string_view json_pointer) const noexcept;
inline simdjson_result<dom::element> at_path(std::string_view json_path) const noexcept;
inline simdjson_result<dom::element> at_key(std::string_view key) const noexcept;
inline simdjson_result<dom::element> at_key_case_insensitive(std::string_view key) const noexcept;
+24 -3
View File
@@ -202,6 +202,22 @@ public:
* simdjson::dom::parser parser;
* simdjson::dom::element element = parser.parse(padded_json_copy.get(), json_len, false);
*
* ### std::string references
*
* If you pass a mutable std::string reference (std::string&), the parser will seek to extend
* its capacity to SIMDJSON_PADDING bytes beyond the end of the string.
*
* Whenever you pass an std::string reference, the parser will access the bytes beyond the end of
* the string but before the end of the allocated memory (std::string::capacity()).
* If you are using a sanitizer that checks for reading uninitialized bytes or std::string's
* container-overflow checks, you may encounter sanitizer warnings.
* You can safely ignore these warnings. Or you can call simdjson::pad(std::string&) to pad the
* string with SIMDJSON_PADDING spaces: this function returns a simdjson::padding_string_view
* which can be be passed to the parser's parse function:
*
* std::string json = R"({ "foo": 1 } { "foo": 2 } { "foo": 3 } )";
* element doc = parser.parse(simdjson::pad(json));
*
* ### Parser Capacity
*
* If the parser's current capacity is less than len, it will allocate enough capacity
@@ -324,7 +340,7 @@ public:
* arrays or objects) MUST be separated with whitespace.
*
* The documents must not exceed batch_size bytes (by default 1MB) or they will fail to parse.
* Setting batch_size to excessively large or excesively small values may impact negatively the
* Setting batch_size to excessively large or excessively small values may impact negatively the
* performance.
*
* ### Error Handling
@@ -418,7 +434,7 @@ public:
* arrays or objects) MUST be separated with whitespace.
*
* The documents must not exceed batch_size bytes (by default 1MB) or they will fail to parse.
* Setting batch_size to excessively large or excesively small values may impact negatively the
* Setting batch_size to excessively large or excessively small values may impact negatively the
* performance.
*
* ### Error Handling
@@ -549,9 +565,14 @@ public:
/**
* The parser instance can use threads when they are available to speed up some
* operations. It is enabled by default. Changing this attribute will change the
* behavior of the parser for future operations.
* behavior of the parser for future operations. Set to true by default.
*/
bool threaded{true};
#else
/**
* When SIMDJSON_THREADS_ENABLED is not defined, the parser instance cannot use threads.
*/
bool threaded{false};
#endif
/** @private Use the new DOM API instead */
class Iterator;
+5
View File
@@ -6,6 +6,11 @@
#include <iostream>
namespace simdjson {
inline bool is_fatal(error_code error) noexcept {
return error == TAPE_ERROR || error == INCOMPLETE_ARRAY_OR_OBJECT;
}
namespace internal {
// We store the error code so we can validate the error message is associated with the right code
struct error_code_info {
+11 -3
View File
@@ -20,7 +20,7 @@ enum error_code {
SUCCESS = 0, ///< No error
CAPACITY, ///< This parser can't support a document that big
MEMALLOC, ///< Error allocating memory, most likely out of memory
TAPE_ERROR, ///< Something went wrong, this is a generic error
TAPE_ERROR, ///< Something went wrong, this is a generic error. Fatal/unrecoverable error.
DEPTH_ERROR, ///< Your document exceeds the user-specified depth limitation
STRING_ERROR, ///< Problem while parsing a string
T_ATOM_ERROR, ///< Problem while parsing an atom starting with the letter 't'
@@ -45,13 +45,21 @@ enum error_code {
PARSER_IN_USE, ///< parser is already in use.
OUT_OF_ORDER_ITERATION, ///< tried to iterate an array or object out of order (checked when SIMDJSON_DEVELOPMENT_CHECKS=1)
INSUFFICIENT_PADDING, ///< The JSON doesn't have enough padding for simdjson to safely parse it.
INCOMPLETE_ARRAY_OR_OBJECT, ///< The document ends early.
INCOMPLETE_ARRAY_OR_OBJECT, ///< The document ends early. Fatal/unrecoverable error.
SCALAR_DOCUMENT_AS_VALUE, ///< A scalar document is treated as a value.
OUT_OF_BOUNDS, ///< Attempted to access location outside of document.
TRAILING_CONTENT, ///< Unexpected trailing content in the JSON input
NUM_ERROR_CODES
};
/**
* Some errors are fatal and invalidate the document. This function returns true if the
* error is fatal. It returns true for TAPE_ERROR and INCOMPLETE_ARRAY_OR_OBJECT.
* Once a fatal error is encountered, the on-demand document is no longer valid and
* processing should stop.
*/
inline bool is_fatal(error_code error) noexcept;
/**
* It is the convention throughout the code that the macro SIMDJSON_DEVELOPMENT_CHECKS determines whether
* we check for OUT_OF_ORDER_ITERATION. The logic behind it is that these errors only occurs when the code
@@ -86,7 +94,7 @@ struct simdjson_error : public std::exception {
*/
simdjson_error(error_code error) noexcept : _error{error} { }
/** The error message */
const char *what() const noexcept { return error_message(error()); }
const char *what() const noexcept override { return error_message(error()); }
/** The error code */
error_code error() const noexcept { return _error; }
private:
@@ -75,6 +75,12 @@ simdjson_inline internal::value128 full_multiplication(uint64_t value1, uint64_t
} // namespace fallback
} // namespace simdjson
#ifndef SIMDJSON_SWAR_NUMBER_PARSING
#if SIMDJSON_IS_BIG_ENDIAN
#define SIMDJSON_SWAR_NUMBER_PARSING 0
#else
#define SIMDJSON_SWAR_NUMBER_PARSING 1
#endif
#endif
#endif // SIMDJSON_FALLBACK_NUMBERPARSING_DEFS_H
-1
View File
@@ -16,5 +16,4 @@
#include "simdjson/internal/jsoncharutils_tables.h"
#include "simdjson/internal/numberparsing_tables.h"
#include "simdjson/internal/simdprune_tables.h"
#endif // SIMDJSON_GENERIC_DEPENDENCIES_H
+1 -2
View File
@@ -137,7 +137,7 @@ simdjson_inline bool compute_float_64(int64_t power, uint64_t i, bool negative,
// floor(log(5**power)/log(2))
//
// Note that this is not magic: 152170/(1<<16) is
// approximatively equal to log(5)/log(2).
// approximately equal to log(5)/log(2).
// The 1<<16 value is a power of two; we could use a
// larger power of 2 if we wanted to.
//
@@ -574,7 +574,6 @@ simdjson_unused simdjson_inline simdjson_result<number_type> get_number_type(con
// Our objective is accurate parsing (ULP of 0) at high speed.
template<typename W>
simdjson_inline error_code parse_number(const uint8_t *const src, W &writer) {
//
// Check for minus sign
//
@@ -4,6 +4,7 @@
// Stuff other things depend on
#include "simdjson/generic/ondemand/base.h"
#include "simdjson/generic/ondemand/deserialize.h"
#include "simdjson/generic/ondemand/value_iterator.h"
#include "simdjson/generic/ondemand/value.h"
#include "simdjson/generic/ondemand/logger.h"
@@ -23,9 +24,13 @@
#include "simdjson/generic/ondemand/object_iterator.h"
#include "simdjson/generic/ondemand/serialization.h"
// Deserialization for standard types
#include "simdjson/generic/ondemand/std_deserialize.h"
// Inline definitions
#include "simdjson/generic/ondemand/array-inl.h"
#include "simdjson/generic/ondemand/array_iterator-inl.h"
#include "simdjson/generic/ondemand/value-inl.h"
#include "simdjson/generic/ondemand/document-inl.h"
#include "simdjson/generic/ondemand/document_stream-inl.h"
#include "simdjson/generic/ondemand/field-inl.h"
@@ -38,5 +43,6 @@
#include "simdjson/generic/ondemand/raw_json_string-inl.h"
#include "simdjson/generic/ondemand/serialization-inl.h"
#include "simdjson/generic/ondemand/token_iterator-inl.h"
#include "simdjson/generic/ondemand/value-inl.h"
#include "simdjson/generic/ondemand/value_iterator-inl.h"
+1 -47
View File
@@ -2,6 +2,7 @@
#ifndef SIMDJSON_CONDITIONAL_INCLUDE
#define SIMDJSON_GENERIC_ONDEMAND_ARRAY_INL_H
#include "simdjson/jsonpathutil.h"
#include "simdjson/generic/ondemand/base.h"
#include "simdjson/generic/ondemand/array.h"
#include "simdjson/generic/ondemand/array_iterator-inl.h"
@@ -163,53 +164,6 @@ inline simdjson_result<value> array::at_pointer(std::string_view json_pointer) n
return child;
}
inline std::string json_path_to_pointer_conversion(std::string_view json_path) {
if (json_path.empty() || (json_path.front() != '.' &&
json_path.front() != '[')) {
return "-1"; // This is just a sentinel value, the caller should check for this and return an error.
}
std::string result;
// Reserve space to reduce allocations, adjusting for potential increases due
// to escaping.
result.reserve(json_path.size() * 2);
size_t i = 0;
while (i < json_path.length()) {
if (json_path[i] == '.') {
result += '/';
} else if (json_path[i] == '[') {
result += '/';
++i; // Move past the '['
while (i < json_path.length() && json_path[i] != ']') {
if (json_path[i] == '~') {
result += "~0";
} else if (json_path[i] == '/') {
result += "~1";
} else {
result += json_path[i];
}
++i;
}
if (i == json_path.length() || json_path[i] != ']') {
return "-1"; // Using sentinel value that will be handled as an error by the caller.
}
} else {
if (json_path[i] == '~') {
result += "~0";
} else if (json_path[i] == '/') {
result += "~1";
} else {
result += json_path[i];
}
}
++i;
}
return result;
}
inline simdjson_result<value> array::at_path(std::string_view json_path) noexcept {
auto json_pointer = json_path_to_pointer_conversion(json_path);
if (json_pointer == "-1") { return INVALID_JSON_POINTER; }
+2 -1
View File
@@ -44,7 +44,8 @@ public:
* calling this function, if successful, the array is 'rewinded' at its
* beginning as if it had never been accessed. If the JSON is malformed (e.g.,
* there is a missing comma), then an error is returned and it is no longer
* safe to continue.
* safe to continue. Note that count_elements() does not validate the JSON values,
* only the structure of the array.
*
* To check that an array is empty, it is more performant to use
* the is_empty() method.
@@ -13,5 +13,6 @@
#include "simdjson/padded_string.h"
#include "simdjson/padded_string_view.h"
#include "simdjson/internal/dom_parser_implementation.h"
#include "simdjson/jsonpathutil.h"
#endif // SIMDJSON_GENERIC_ONDEMAND_DEPENDENCIES_H
@@ -0,0 +1,123 @@
#if SIMDJSON_SUPPORTS_DESERIALIZATION
#ifndef SIMDJSON_ONDEMAND_DESERIALIZE_H
#ifndef SIMDJSON_CONDITIONAL_INCLUDE
#define SIMDJSON_ONDEMAND_DESERIALIZE_H
#include "simdjson/generic/ondemand/base.h"
#include "simdjson/generic/ondemand/array.h"
#endif // SIMDJSON_CONDITIONAL_INCLUDE
#include <concepts>
namespace simdjson {
namespace tag_invoke_fn_ns {
void tag_invoke();
struct tag_invoke_fn {
template <typename Tag, typename... Args>
requires requires(Tag tag, Args &&...args) {
tag_invoke(std::forward<Tag>(tag), std::forward<Args>(args)...);
}
constexpr auto operator()(Tag tag, Args &&...args) const
noexcept(noexcept(tag_invoke(std::forward<Tag>(tag),
std::forward<Args>(args)...)))
-> decltype(tag_invoke(std::forward<Tag>(tag),
std::forward<Args>(args)...)) {
return tag_invoke(std::forward<Tag>(tag), std::forward<Args>(args)...);
}
};
} // namespace tag_invoke_fn_ns
inline namespace tag_invoke_ns {
inline constexpr tag_invoke_fn_ns::tag_invoke_fn tag_invoke = {};
} // namespace tag_invoke_ns
template <typename Tag, typename... Args>
concept tag_invocable = requires(Tag tag, Args... args) {
tag_invoke(std::forward<Tag>(tag), std::forward<Args>(args)...);
};
template <typename Tag, typename... Args>
concept nothrow_tag_invocable =
tag_invocable<Tag, Args...> && requires(Tag tag, Args... args) {
{
tag_invoke(std::forward<Tag>(tag), std::forward<Args>(args)...)
} noexcept;
};
template <typename Tag, typename... Args>
using tag_invoke_result =
std::invoke_result<decltype(tag_invoke), Tag, Args...>;
template <typename Tag, typename... Args>
using tag_invoke_result_t =
std::invoke_result_t<decltype(tag_invoke), Tag, Args...>;
template <auto &Tag> using tag_t = std::decay_t<decltype(Tag)>;
struct deserialize_tag;
/// These types are deserializable in a built-in way
template <typename> struct is_builtin_deserializable : std::false_type {};
template <> struct is_builtin_deserializable<int64_t> : std::true_type {};
template <> struct is_builtin_deserializable<uint64_t> : std::true_type {};
template <> struct is_builtin_deserializable<double> : std::true_type {};
template <> struct is_builtin_deserializable<bool> : std::true_type {};
template <> struct is_builtin_deserializable<SIMDJSON_IMPLEMENTATION::ondemand::array> : std::true_type {};
template <> struct is_builtin_deserializable<SIMDJSON_IMPLEMENTATION::ondemand::object> : std::true_type {};
template <> struct is_builtin_deserializable<SIMDJSON_IMPLEMENTATION::ondemand::value> : std::true_type {};
template <> struct is_builtin_deserializable<SIMDJSON_IMPLEMENTATION::ondemand::raw_json_string> : std::true_type {};
template <> struct is_builtin_deserializable<std::string_view> : std::true_type {};
template <typename T>
concept is_builtin_deserializable_v = is_builtin_deserializable<T>::value;
template <typename T, typename ValT = SIMDJSON_IMPLEMENTATION::ondemand::value>
concept custom_deserializable = tag_invocable<deserialize_tag, ValT&, T&>;
template <typename T, typename ValT = SIMDJSON_IMPLEMENTATION::ondemand::value>
concept deserializable = custom_deserializable<T, ValT> || is_builtin_deserializable_v<T>;
template <typename T, typename ValT = SIMDJSON_IMPLEMENTATION::ondemand::value>
concept nothrow_custom_deserializable = nothrow_tag_invocable<deserialize_tag, ValT&, T&>;
// built-in types are noexcept and if an error happens, the value simply gets ignored and the error is returned.
template <typename T, typename ValT = SIMDJSON_IMPLEMENTATION::ondemand::value>
concept nothrow_deserializable = nothrow_custom_deserializable<T, ValT> || is_builtin_deserializable_v<T>;
/// Deserialize Tag
inline constexpr struct deserialize_tag {
using value_type = SIMDJSON_IMPLEMENTATION::ondemand::value;
using document_type = SIMDJSON_IMPLEMENTATION::ondemand::document;
using document_reference_type = SIMDJSON_IMPLEMENTATION::ondemand::document_reference;
// Customization Point for value
template <typename T>
requires custom_deserializable<T, value_type>
[[nodiscard]] constexpr /* error_code */ auto operator()(value_type &object, T& output) const noexcept(nothrow_custom_deserializable<T, value_type>) {
return tag_invoke(*this, object, output);
}
// Customization Point for document
template <typename T>
requires custom_deserializable<T, document_type>
[[nodiscard]] constexpr /* error_code */ auto operator()(document_type &object, T& output) const noexcept(nothrow_custom_deserializable<T, document_type>) {
return tag_invoke(*this, object, output);
}
// Customization Point for document reference
template <typename T>
requires custom_deserializable<T, document_reference_type>
[[nodiscard]] constexpr /* error_code */ auto operator()(document_reference_type &object, T& output) const noexcept(nothrow_custom_deserializable<T, document_reference_type>) {
return tag_invoke(*this, object, output);
}
} deserialize{};
} // namespace simdjson
#endif // SIMDJSON_ONDEMAND_DESERIALIZE_H
#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
@@ -8,10 +8,12 @@
#include "simdjson/generic/ondemand/json_type.h"
#include "simdjson/generic/ondemand/raw_json_string.h"
#include "simdjson/generic/ondemand/value.h"
#include "simdjson/generic/ondemand/value-inl.h"
#include "simdjson/generic/ondemand/array-inl.h"
#include "simdjson/generic/ondemand/json_iterator-inl.h"
#include "simdjson/generic/ondemand/object-inl.h"
#include "simdjson/generic/ondemand/value_iterator-inl.h"
#include "simdjson/generic/ondemand/deserialize.h"
#endif // SIMDJSON_CONDITIONAL_INCLUDE
namespace simdjson {
@@ -165,6 +167,16 @@ template<> simdjson_inline simdjson_result<int64_t> document::get() & noexcept {
template<> simdjson_inline simdjson_result<bool> document::get() & noexcept { return get_bool(); }
template<> simdjson_inline simdjson_result<value> document::get() & noexcept { return get_value(); }
template<> simdjson_inline error_code document::get(array& out) & noexcept { return get_array().get(out); }
template<> simdjson_inline error_code document::get(object& out) & noexcept { return get_object().get(out); }
template<> simdjson_inline error_code document::get(raw_json_string& out) & noexcept { return get_raw_json_string().get(out); }
template<> simdjson_inline error_code document::get(std::string_view& out) & noexcept { return get_string(false).get(out); }
template<> simdjson_inline error_code document::get(double& out) & noexcept { return get_double().get(out); }
template<> simdjson_inline error_code document::get(uint64_t& out) & noexcept { return get_uint64().get(out); }
template<> simdjson_inline error_code document::get(int64_t& out) & noexcept { return get_int64().get(out); }
template<> simdjson_inline error_code document::get(bool& out) & noexcept { return get_bool().get(out); }
template<> simdjson_inline error_code document::get(value& out) & noexcept { return get_value().get(out); }
template<> simdjson_deprecated simdjson_inline simdjson_result<raw_json_string> document::get() && noexcept { return get_raw_json_string(); }
template<> simdjson_deprecated simdjson_inline simdjson_result<std::string_view> document::get() && noexcept { return get_string(false); }
template<> simdjson_deprecated simdjson_inline simdjson_result<double> document::get() && noexcept { return std::forward<document>(*this).get_double(); }
@@ -173,13 +185,6 @@ template<> simdjson_deprecated simdjson_inline simdjson_result<int64_t> document
template<> simdjson_deprecated simdjson_inline simdjson_result<bool> document::get() && noexcept { return std::forward<document>(*this).get_bool(); }
template<> simdjson_deprecated simdjson_inline simdjson_result<value> document::get() && noexcept { return get_value(); }
template<typename T> simdjson_inline error_code document::get(T &out) & noexcept {
return get<T>().get(out);
}
template<typename T> simdjson_deprecated simdjson_inline error_code document::get(T &out) && noexcept {
return std::forward<document>(*this).get<T>().get(out);
}
#if SIMDJSON_EXCEPTIONS
template <class T>
simdjson_deprecated simdjson_inline document::operator T() && noexcept(false) { return get<T>(); }
@@ -241,7 +246,14 @@ simdjson_inline simdjson_result<value> document::operator[](const char *key) & n
}
simdjson_inline error_code document::consume() noexcept {
auto error = iter.skip_child(0);
bool scalar = false;
auto error = is_scalar().get(scalar);
if(error) { return error; }
if(scalar) {
iter.return_current_and_advance();
return SUCCESS;
}
error = iter.skip_child(0);
if(error) { iter.abandon(); }
return error;
}
@@ -263,6 +275,8 @@ simdjson_inline simdjson_result<json_type> document::type() noexcept {
}
simdjson_inline simdjson_result<bool> document::is_scalar() noexcept {
// For more speed, we could do:
// return iter.is_single_token();
json_type this_type;
auto error = type().get(this_type);
if(error) { return error; }
@@ -818,6 +832,26 @@ simdjson_inline simdjson_result<bool> simdjson_result<SIMDJSON_IMPLEMENTATION::o
if (error()) { return error(); }
return first.is_null();
}
template<typename T>
simdjson_inline simdjson_result<T> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document_reference>::get() & noexcept {
if (error()) { return error(); }
return first.get<T>();
}
template<typename T>
simdjson_inline simdjson_result<T> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document_reference>::get() && noexcept {
if (error()) { return error(); }
return std::forward<SIMDJSON_IMPLEMENTATION::ondemand::document_reference>(first).get<T>();
}
template <class T>
simdjson_inline error_code simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document_reference>::get(T &out) & noexcept {
if (error()) { return error(); }
return first.get<T>(out);
}
template <class T>
simdjson_inline error_code simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document_reference>::get(T &out) && noexcept {
if (error()) { return error(); }
return std::forward<SIMDJSON_IMPLEMENTATION::ondemand::document_reference>(first).get<T>(out);
}
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::json_type> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document_reference>::type() noexcept {
if (error()) { return error(); }
return first.type();
@@ -830,6 +864,18 @@ simdjson_inline simdjson_result<bool> simdjson_result<SIMDJSON_IMPLEMENTATION::o
if (error()) { return error(); }
return first.is_string();
}
template <>
simdjson_inline error_code simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document_reference>::get(SIMDJSON_IMPLEMENTATION::ondemand::document_reference &out) & noexcept {
if (error()) { return error(); }
out = first;
return SUCCESS;
}
template <>
simdjson_inline error_code simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document_reference>::get(SIMDJSON_IMPLEMENTATION::ondemand::document_reference &out) && noexcept {
if (error()) { return error(); }
out = first;
return SUCCESS;
}
simdjson_inline simdjson_result<bool> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document_reference>::is_negative() noexcept {
if (error()) { return error(); }
return first.is_negative();
@@ -847,10 +893,12 @@ simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::number> simdj
return first.get_number();
}
#if SIMDJSON_EXCEPTIONS
template <class T, typename std::enable_if<std::is_same<T, SIMDJSON_IMPLEMENTATION::ondemand::document_reference>::value == false>::type>
template <class T>
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document_reference>::operator T() noexcept(false) {
static_assert(std::is_same<T, SIMDJSON_IMPLEMENTATION::ondemand::document_reference>::value == false, "You should not call get<T> when T is a document");
static_assert(std::is_same<T, SIMDJSON_IMPLEMENTATION::ondemand::document>::value == false, "You should not call get<T> when T is a document");
if (error()) { throw simdjson_error(error()); }
return first;
return first.get<T>();
}
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document_reference>::operator SIMDJSON_IMPLEMENTATION::ondemand::array() & noexcept(false) {
if (error()) { throw simdjson_error(error()); }
+157 -21
View File
@@ -4,8 +4,11 @@
#define SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_H
#include "simdjson/generic/ondemand/base.h"
#include "simdjson/generic/ondemand/json_iterator.h"
#include "simdjson/generic/ondemand/deserialize.h"
#include "simdjson/generic/ondemand/value.h"
#endif // SIMDJSON_CONDITIONAL_INCLUDE
namespace simdjson {
namespace SIMDJSON_IMPLEMENTATION {
namespace ondemand {
@@ -178,24 +181,39 @@ public:
* @returns A value of the given type, parsed from the JSON.
* @returns INCORRECT_TYPE If the JSON value is not the given type.
*/
template<typename T> simdjson_inline simdjson_result<T> get() & noexcept {
// Unless the simdjson library or the user provides an inline implementation, calling this method should
// immediately fail.
static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. "
"The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, "
"int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), "
" get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template."
" You may also add support for custom types, see our documentation.");
template <typename T>
simdjson_inline simdjson_result<T> get() &
#if SIMDJSON_SUPPORTS_DESERIALIZATION
noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document> : true)
#else
noexcept
#endif
{
static_assert(std::is_default_constructible<T>::value, "Cannot initialize the specified type.");
T out{};
SIMDJSON_TRY(get<T>(out));
return out;
}
/** @overload template<typename T> simdjson_result<T> get() & noexcept */
template<typename T> simdjson_deprecated simdjson_inline simdjson_result<T> get() && noexcept {
// Unless the simdjson library or the user provides an inline implementation, calling this method should
// immediately fail.
static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. "
"The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, "
"int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), "
" get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template."
" You may also add support for custom types, see our documentation.");
/**
* @overload template<typename T> simdjson_result<T> get() & noexcept
*
* We disallow the use tag_invoke CPO on a moved document; it may create UB
* if user uses `ondemand::array` or `ondemand::object` in their custom type.
*
* The member function is still remains specialize-able for compatibility
* reasons, but we completely disallow its use when a tag_invoke customization
* is provided.
*/
template<typename T>
simdjson_inline simdjson_result<T> get() &&
#if SIMDJSON_SUPPORTS_DESERIALIZATION
noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document> : true)
#else
noexcept
#endif
{
static_assert(!std::is_same<T, array>::value && !std::is_same<T, object>::value, "You should never hold either an ondemand::array or ondemand::object without a corresponding ondemand::document being alive; that would be Undefined Behaviour.");
return static_cast<document&>(*this).get<T>();
}
/**
@@ -209,7 +227,39 @@ public:
* @returns INCORRECT_TYPE If the JSON value is not an object.
* @returns SUCCESS If the parse succeeded and the out parameter was set to the value.
*/
template<typename T> simdjson_inline error_code get(T &out) & noexcept;
template<typename T>
simdjson_inline error_code get(T &out) &
#if SIMDJSON_SUPPORTS_DESERIALIZATION
noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document> : true)
#else
noexcept
#endif
{
#if SIMDJSON_SUPPORTS_DESERIALIZATION
if constexpr (custom_deserializable<T, document>) {
return deserialize(*this, out);
} else {
static_assert(!sizeof(T), "The get<T> method with type T is not implemented by the simdjson library. "
"And you do not seem to have added support for it. Indeed, we have that "
"simdjson::custom_deserializable<T> is false and the type T is not a default type "
"such as ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, "
"int64_t, double, or bool.");
static_cast<void>(out); // to get rid of unused errors
return UNINITIALIZED;
}
#else // SIMDJSON_SUPPORTS_DESERIALIZATION
// Unless the simdjson library or the user provides an inline implementation, calling this method should
// immediately fail.
static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. "
"The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, "
"int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), "
" get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template."
" You may also add support for custom types, see our documentation.");
static_cast<void>(out); // to get rid of unused errors
return UNINITIALIZED;
#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
}
/** @overload template<typename T> error_code get(T &out) & noexcept */
template<typename T> simdjson_deprecated simdjson_inline error_code get(T &out) && noexcept;
@@ -311,7 +361,8 @@ public:
* calling this function, if successful, the array is 'rewinded' at its
* beginning as if it had never been accessed. If the JSON is malformed (e.g.,
* there is a missing comma), then an error is returned and it is no longer
* safe to continue.
* safe to continue. Note that count_elements() does not validate the JSON values,
* only the structure of the array.
*/
simdjson_inline simdjson_result<size_t> count_elements() & noexcept;
/**
@@ -423,6 +474,7 @@ public:
simdjson_inline simdjson_result<value> operator[](std::string_view key) & noexcept;
/** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept; */
simdjson_inline simdjson_result<value> operator[](const char *key) & noexcept;
simdjson_result<value> operator[](int) & noexcept = delete;
/**
* Get the type of this JSON value. It does not validate or consume the value.
@@ -691,6 +743,11 @@ protected:
/**
* A document_reference is a thin wrapper around a document reference instance.
* The document_reference instances are used primarily/solely for streams of JSON
* documents. They differ from document instances when parsing a scalar value
* (a document that is not an array or an object). In the case of a document,
* we expect the document to be fully consumed. In the case of a document_reference,
* we allow trailing content.
*/
class document_reference {
public:
@@ -716,7 +773,77 @@ public:
simdjson_inline simdjson_result<value> get_value() noexcept;
simdjson_inline simdjson_result<bool> is_null() noexcept;
template<typename T> simdjson_inline simdjson_result<T> get() & noexcept;
template <typename T>
simdjson_inline simdjson_result<T> get() &
#if SIMDJSON_SUPPORTS_DESERIALIZATION
noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document> : true)
#else
noexcept
#endif
{
static_assert(std::is_default_constructible<T>::value, "Cannot initialize the specified type.");
T out{};
SIMDJSON_TRY(get<T>(out));
return out;
}
template<typename T>
simdjson_inline simdjson_result<T> get() &&
#if SIMDJSON_SUPPORTS_DESERIALIZATION
noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document> : true)
#else
noexcept
#endif
{
static_assert(!std::is_same<T, array>::value && !std::is_same<T, object>::value, "You should never hold either an ondemand::array or ondemand::object without a corresponding ondemand::document_reference being alive; that would be Undefined Behaviour.");
return static_cast<document&>(*this).get<T>();
}
/**
* Get this value as the given type.
*
* Supported types: object, array, raw_json_string, string_view, uint64_t, int64_t, double, bool, value
*
* Be mindful that the document instance must remain in scope while you are accessing object, array and value instances.
*
* @param out This is set to a value of the given type, parsed from the JSON. If there is an error, this may not be initialized.
* @returns INCORRECT_TYPE If the JSON value is not an object.
* @returns SUCCESS If the parse succeeded and the out parameter was set to the value.
*/
template<typename T>
simdjson_inline error_code get(T &out) &
#if SIMDJSON_SUPPORTS_DESERIALIZATION
noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document_reference> : true)
#else
noexcept
#endif
{
#if SIMDJSON_SUPPORTS_DESERIALIZATION
if constexpr (custom_deserializable<T, document_reference>) {
return deserialize(*this, out);
} else {
static_assert(!sizeof(T), "The get<T> method with type T is not implemented by the simdjson library. "
"And you do not seem to have added support for it. Indeed, we have that "
"simdjson::custom_deserializable<T> is false and the type T is not a default type "
"such as ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, "
"int64_t, double, or bool.");
static_cast<void>(out); // to get rid of unused errors
return UNINITIALIZED;
}
#else // SIMDJSON_SUPPORTS_DESERIALIZATION
// Unless the simdjson library or the user provides an inline implementation, calling this method should
// immediately fail.
static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. "
"The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, "
"int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), "
" get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template."
" You may also add support for custom types, see our documentation.");
static_cast<void>(out); // to get rid of unused errors
return UNINITIALIZED;
#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
}
/** @overload template<typename T> error_code get(T &out) & noexcept */
template<typename T> simdjson_inline error_code get(T &out) && noexcept;
simdjson_inline simdjson_result<std::string_view> raw_json() noexcept;
simdjson_inline operator document&() const noexcept;
#if SIMDJSON_EXCEPTIONS
@@ -741,6 +868,7 @@ public:
simdjson_inline simdjson_result<value> find_field(const char *key) & noexcept;
simdjson_inline simdjson_result<value> operator[](std::string_view key) & noexcept;
simdjson_inline simdjson_result<value> operator[](const char *key) & noexcept;
simdjson_result<value> operator[](int) & noexcept = delete;
simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept;
simdjson_inline simdjson_result<value> find_field_unordered(const char *key) & noexcept;
@@ -819,6 +947,7 @@ public:
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> find_field(const char *key) & noexcept;
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> operator[](std::string_view key) & noexcept;
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> operator[](const char *key) & noexcept;
simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> operator[](int) & noexcept = delete;
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> find_field_unordered(std::string_view key) & noexcept;
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> find_field_unordered(const char *key) & noexcept;
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::json_type> type() noexcept;
@@ -868,8 +997,14 @@ public:
simdjson_inline simdjson_result<bool> get_bool() noexcept;
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> get_value() noexcept;
simdjson_inline simdjson_result<bool> is_null() noexcept;
template<typename T> simdjson_inline simdjson_result<T> get() & noexcept;
template<typename T> simdjson_inline simdjson_result<T> get() && noexcept;
template<typename T> simdjson_inline error_code get(T &out) & noexcept;
template<typename T> simdjson_inline error_code get(T &out) && noexcept;
#if SIMDJSON_EXCEPTIONS
template <class T, typename std::enable_if<std::is_same<T, SIMDJSON_IMPLEMENTATION::ondemand::document_reference>::value == false>::type>
template <class T>
explicit simdjson_inline operator T() noexcept(false);
simdjson_inline operator SIMDJSON_IMPLEMENTATION::ondemand::array() & noexcept(false);
simdjson_inline operator SIMDJSON_IMPLEMENTATION::ondemand::object() & noexcept(false);
@@ -890,6 +1025,7 @@ public:
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> find_field(const char *key) & noexcept;
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> operator[](std::string_view key) & noexcept;
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> operator[](const char *key) & noexcept;
simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> operator[](int) & noexcept = delete;
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> find_field_unordered(std::string_view key) & noexcept;
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> find_field_unordered(const char *key) & noexcept;
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::json_type> type() noexcept;
@@ -152,7 +152,6 @@ simdjson_inline document_stream::iterator::iterator(document_stream* _stream, bo
}
simdjson_inline simdjson_result<ondemand::document_reference> document_stream::iterator::operator*() noexcept {
//if(stream->error) { return stream->error; }
return simdjson_result<ondemand::document_reference>(stream->doc, stream->error);
}
+21 -1
View File
@@ -84,6 +84,22 @@ public:
* using a sanitizer that verifies that no uninitialized byte is read, then you should initialize the
* SIMDJSON_PADDING bytes to avoid runtime warnings.
*
* ### std::string references
*
* If you pass a mutable std::string reference (std::string&), the parser will seek to extend
* its capacity to SIMDJSON_PADDING bytes beyond the end of the string.
*
* Whenever you pass an std::string reference, the parser will access the bytes beyond the end of
* the string but before the end of the allocated memory (std::string::capacity()).
* If you are using a sanitizer that checks for reading uninitialized bytes or std::string's
* container-overflow checks, you may encounter sanitizer warnings.
* You can safely ignore these warnings. Or you can call simdjson::pad(std::string&) to pad the
* string with SIMDJSON_PADDING spaces: this function returns a simdjson::padding_string_view
* which can be be passed to the parser's iterate function:
*
* std::string json = R"({ "foo": 1 } { "foo": 2 } { "foo": 3 } )";
* document doc = parser.iterate(simdjson::pad(json));
*
* @param json The JSON to parse.
* @param len The length of the JSON.
* @param capacity The number of bytes allocated in the JSON (must be at least len+SIMDJSON_PADDING).
@@ -278,8 +294,12 @@ public:
* behavior of the parser for future operations.
*/
bool threaded{true};
#else
/**
* When SIMDJSON_THREADS_ENABLED is not defined, the parser instance cannot use threads.
*/
bool threaded{false};
#endif
/**
* Unescape this JSON string, replacing \\ with \, \n with newline, etc. to a user-provided buffer.
* The result must be valid UTF-8.
@@ -20,36 +20,39 @@ simdjson_inline const char * raw_json_string::raw() const noexcept { return rein
simdjson_inline bool raw_json_string::is_free_from_unescaped_quote(std::string_view target) noexcept {
size_t pos{0};
// if the content has no escape character, just scan through it quickly!
for(;pos < target.size() && target[pos] != '\\';pos++) {}
// slow path may begin.
bool escaping{false};
for(;pos < target.size();pos++) {
if((target[pos] == '"') && !escaping) {
return false;
} else if(target[pos] == '\\') {
escaping = !escaping;
} else {
escaping = false;
while(pos < target.size()) {
pos = target.find('"', pos);
if(pos == std::string_view::npos) { return true; }
if(pos != 0 && target[pos-1] != '\\') { return false; }
if(pos > 1 && target[pos-2] == '\\') {
size_t backslash_count{2};
for(size_t i = 3; i <= pos; i++) {
if(target[pos-i] == '\\') { backslash_count++; }
else { break; }
}
if(backslash_count % 2 == 0) { return false; }
}
pos++;
}
return true;
}
simdjson_inline bool raw_json_string::is_free_from_unescaped_quote(const char* target) noexcept {
size_t pos{0};
// if the content has no escape character, just scan through it quickly!
for(;target[pos] && target[pos] != '\\';pos++) {}
// slow path may begin.
bool escaping{false};
for(;target[pos];pos++) {
if((target[pos] == '"') && !escaping) {
return false;
} else if(target[pos] == '\\') {
escaping = !escaping;
} else {
escaping = false;
while(target[pos]) {
const char * result = strchr(target+pos, '"');
if(result == nullptr) { return true; }
pos = result - target;
if(pos != 0 && target[pos-1] != '\\') { return false; }
if(pos > 1 && target[pos-2] == '\\') {
size_t backslash_count{2};
for(size_t i = 3; i <= pos; i++) {
if(target[pos-i] == '\\') { backslash_count++; }
else { break; }
}
if(backslash_count % 2 == 0) { return false; }
}
pos++;
}
return true;
}
@@ -61,7 +64,7 @@ simdjson_inline bool raw_json_string::unsafe_is_equal(size_t length, std::string
}
simdjson_inline bool raw_json_string::unsafe_is_equal(std::string_view target) const noexcept {
// Assumptions: does not contain unescaped quote characters, and
// Assumptions: does not contain unescaped quote characters("), and
// the raw content is quote terminated within a valid JSON string.
if(target.size() <= SIMDJSON_PADDING) {
return (raw()[target.size()] == '"') && !memcmp(raw(), target.data(), target.size());
@@ -0,0 +1,209 @@
#if SIMDJSON_SUPPORTS_DESERIALIZATION
#ifndef SIMDJSON_ONDEMAND_DESERIALIZE_H
#ifndef SIMDJSON_CONDITIONAL_INCLUDE
#define SIMDJSON_ONDEMAND_DESERIALIZE_H
#include "simdjson/generic/ondemand/array.h"
#include "simdjson/generic/ondemand/base.h"
#endif // SIMDJSON_CONDITIONAL_INCLUDE
#include <concepts>
#include <limits>
namespace simdjson {
template <typename T>
constexpr bool require_custom_serialization = false;
//////////////////////////////
// Number deserialization
//////////////////////////////
template <std::unsigned_integral T>
requires(!require_custom_serialization<T>)
error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept {
using limits = std::numeric_limits<T>;
uint64_t x;
SIMDJSON_TRY(val.get_uint64().get(x));
if (x > (limits::max)()) {
return NUMBER_OUT_OF_RANGE;
}
out = static_cast<T>(x);
return SUCCESS;
}
template <std::floating_point T>
requires(!require_custom_serialization<T>)
error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept {
double x;
SIMDJSON_TRY(val.get_double().get(x));
out = static_cast<T>(x);
return SUCCESS;
}
template <std::signed_integral T>
requires(!require_custom_serialization<T>)
error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept {
using limits = std::numeric_limits<T>;
int64_t x;
SIMDJSON_TRY(val.get_int64().get(x));
if (x > (limits::max)() || x < (limits::min)()) {
return NUMBER_OUT_OF_RANGE;
}
out = static_cast<T>(x);
return SUCCESS;
}
template <concepts::constructible_from_string_view T, typename ValT>
requires(!require_custom_serialization<T>)
error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(std::is_nothrow_constructible_v<T, std::string_view>) {
std::string_view str;
SIMDJSON_TRY(val.get_string().get(str));
out = T{str};
return SUCCESS;
}
/**
* STL containers have several constructors including one that takes a single
* size argument. Thus, some compilers (Visual Studio) will not be able to
* disambiguate between the size and container constructor. Users should
* explicitly specify the type of the container as needed: e.g.,
* doc.get<std::vector<int>>().
*/
template <concepts::appendable_containers T, typename ValT>
requires(!require_custom_serialization<T>)
error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(false) {
using value_type = typename std::remove_cvref_t<T>::value_type;
static_assert(
deserializable<value_type, ValT>,
"The specified type inside the container must itself be deserializable");
static_assert(
std::is_default_constructible_v<value_type>,
"The specified type inside the container must default constructible.");
SIMDJSON_IMPLEMENTATION::ondemand::array arr;
SIMDJSON_TRY(val.get_array().get(arr));
for (auto v : arr) {
if constexpr (concepts::returns_reference<T>) {
if (auto const err = v.get<value_type>().get(concepts::emplace_one(out));
err) {
// If an error occurs, the empty element that we just inserted gets
// removed. We're not using a temp variable because if T is a heavy
// type, we want the valid path to be the fast path and the slow path be
// the path that has errors in it.
if constexpr (requires { out.pop_back(); }) {
static_cast<void>(out.pop_back());
}
return err;
}
} else {
value_type temp;
if (auto const err = v.get<value_type>().get(temp); err) {
return err;
}
concepts::emplace_one(out, std::move(temp));
}
}
return SUCCESS;
}
/**
* We want to support std::map and std::unordered_map but only for
* string-keyed types.
*/
template <concepts::string_view_keyed_map T, typename ValT>
requires(!require_custom_serialization<T>)
error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(false) {
using value_type = typename std::remove_cvref_t<T>::mapped_type;
static_assert(
deserializable<value_type, ValT>,
"The specified value type inside the container must itself be deserializable");
static_assert(
std::is_default_constructible_v<value_type>,
"The specified value type inside the container must default constructible.");
SIMDJSON_IMPLEMENTATION::ondemand::object obj;
SIMDJSON_TRY(val.get_object().get(obj));
for (auto field : obj) {
std::string_view key;
SIMDJSON_TRY(field.unescaped_key().get(key));
value_type this_value;
SIMDJSON_TRY(field.value().get<value_type>().get(this_value));
[[maybe_unused]] std::pair<typename T::iterator, bool> result = out.emplace(key, this_value);
// unclear what to do if the key already exists
// if (result.second == false) {
// // key already exists
// }
}
(void)out;
return SUCCESS;
}
/**
* This CPO (Customization Point Object) will help deserialize into
* smart pointers.
*
* If constructing T is nothrow, this conversion should be nothrow as well since
* we return MEMALLOC if we're not able to allocate memory instead of throwing
* the error message.
*
* @tparam T The type inside the smart pointer
* @tparam ValT document/value type
* @param val document/value
* @param out a reference to the smart pointer
* @return status of the conversion
*/
template <concepts::smart_pointer T, typename ValT>
requires(!require_custom_serialization<T>)
error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(nothrow_deserializable<typename std::remove_cvref_t<T>::element_type, ValT>) {
using element_type = typename std::remove_cvref_t<T>::element_type;
// For better error messages, don't use these as constraints on
// the tag_invoke CPO.
static_assert(
deserializable<element_type, ValT>,
"The specified type inside the unique_ptr must itself be deserializable");
static_assert(
std::is_default_constructible_v<element_type>,
"The specified type inside the unique_ptr must default constructible.");
auto ptr = new (std::nothrow) element_type();
if (ptr == nullptr) {
return MEMALLOC;
}
SIMDJSON_TRY(val.template get<element_type>(*ptr));
out.reset(ptr);
return SUCCESS;
}
/**
* This CPO (Customization Point Object) will help deserialize into optional types.
*/
template <concepts::optional_type T, typename ValT>
requires(!require_custom_serialization<T>)
error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(nothrow_deserializable<typename std::remove_cvref_t<T>::value_type, ValT>) {
using value_type = typename std::remove_cvref_t<T>::value_type;
static_assert(
deserializable<value_type, ValT>,
"The specified type inside the unique_ptr must itself be deserializable");
static_assert(
std::is_default_constructible_v<value_type>,
"The specified type inside the unique_ptr must default constructible.");
if (!out) {
out.emplace();
}
SIMDJSON_TRY(val.template get<value_type>(out.value()));
return SUCCESS;
}
} // namespace simdjson
#endif // SIMDJSON_ONDEMAND_DESERIALIZE_H
#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
+18 -9
View File
@@ -78,6 +78,7 @@ simdjson_inline simdjson_result<bool> value::get_bool() noexcept {
simdjson_inline simdjson_result<bool> value::is_null() noexcept {
return iter.is_null();
}
template<> simdjson_inline simdjson_result<array> value::get() noexcept { return get_array(); }
template<> simdjson_inline simdjson_result<object> value::get() noexcept { return get_object(); }
template<> simdjson_inline simdjson_result<raw_json_string> value::get() noexcept { return get_raw_json_string(); }
@@ -88,9 +89,16 @@ template<> simdjson_inline simdjson_result<uint64_t> value::get() noexcept { ret
template<> simdjson_inline simdjson_result<int64_t> value::get() noexcept { return get_int64(); }
template<> simdjson_inline simdjson_result<bool> value::get() noexcept { return get_bool(); }
template<typename T> simdjson_inline error_code value::get(T &out) noexcept {
return get<T>().get(out);
}
template<> simdjson_inline error_code value::get(array& out) noexcept { return get_array().get(out); }
template<> simdjson_inline error_code value::get(object& out) noexcept { return get_object().get(out); }
template<> simdjson_inline error_code value::get(raw_json_string& out) noexcept { return get_raw_json_string().get(out); }
template<> simdjson_inline error_code value::get(std::string_view& out) noexcept { return get_string(false).get(out); }
template<> simdjson_inline error_code value::get(number& out) noexcept { return get_number().get(out); }
template<> simdjson_inline error_code value::get(double& out) noexcept { return get_double().get(out); }
template<> simdjson_inline error_code value::get(uint64_t& out) noexcept { return get_uint64().get(out); }
template<> simdjson_inline error_code value::get(int64_t& out) noexcept { return get_int64().get(out); }
template<> simdjson_inline error_code value::get(bool& out) noexcept { return get_bool().get(out); }
#if SIMDJSON_EXCEPTIONS
template <class T>
@@ -414,6 +422,12 @@ simdjson_inline simdjson_result<bool> simdjson_result<SIMDJSON_IMPLEMENTATION::o
return first.is_null();
}
template<> simdjson_inline error_code simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>::get<SIMDJSON_IMPLEMENTATION::ondemand::value>(SIMDJSON_IMPLEMENTATION::ondemand::value &out) noexcept {
if (error()) { return error(); }
out = first;
return SUCCESS;
}
template<typename T> simdjson_inline simdjson_result<T> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>::get() noexcept {
if (error()) { return error(); }
return first.get<T>();
@@ -427,11 +441,6 @@ template<> simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::va
if (error()) { return error(); }
return std::move(first);
}
template<> simdjson_inline error_code simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>::get<SIMDJSON_IMPLEMENTATION::ondemand::value>(SIMDJSON_IMPLEMENTATION::ondemand::value &out) noexcept {
if (error()) { return error(); }
out = first;
return SUCCESS;
}
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::json_type> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>::type() noexcept {
if (error()) { return error(); }
@@ -465,7 +474,7 @@ simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::number> simdj
template <class T>
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>::operator T() noexcept(false) {
if (error()) { throw simdjson_error(error()); }
return static_cast<T>(first);
return first.get<T>();
}
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>::operator SIMDJSON_IMPLEMENTATION::ondemand::array() noexcept(false) {
if (error()) { throw simdjson_error(error()); }
+62 -10
View File
@@ -5,12 +5,15 @@
#include "simdjson/generic/ondemand/base.h"
#include "simdjson/generic/implementation_simdjson_result_base.h"
#include "simdjson/generic/ondemand/value_iterator.h"
#include "simdjson/generic/ondemand/deserialize.h"
#endif // SIMDJSON_CONDITIONAL_INCLUDE
#include <type_traits>
namespace simdjson {
namespace SIMDJSON_IMPLEMENTATION {
namespace ondemand {
/**
* An ephemeral JSON value returned during iteration. It is only valid for as long as you do
* not access more data in the JSON document.
@@ -35,16 +38,21 @@ public:
* @returns A value of the given type, parsed from the JSON.
* @returns INCORRECT_TYPE If the JSON value is not the given type.
*/
template<typename T> simdjson_inline simdjson_result<T> get() noexcept {
// Unless the simdjson library or the user provides an inline implementation, calling this method should
// immediately fail.
static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. "
"The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, "
"int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), "
" get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template."
" You may also add support for custom types, see our documentation.");
template <typename T>
simdjson_inline simdjson_result<T> get()
#if SIMDJSON_SUPPORTS_DESERIALIZATION
noexcept(custom_deserializable<T, value> ? nothrow_custom_deserializable<T, value> : true)
#else
noexcept
#endif
{
static_assert(std::is_default_constructible<T>::value, "The specified type is not default constructible.");
T out{};
SIMDJSON_TRY(get<T>(out));
return out;
}
/**
* Get this value as the given type.
*
@@ -54,7 +62,38 @@ public:
* @returns INCORRECT_TYPE If the JSON value is not an object.
* @returns SUCCESS If the parse succeeded and the out parameter was set to the value.
*/
template<typename T> simdjson_inline error_code get(T &out) noexcept;
template <typename T>
simdjson_inline error_code get(T &out)
#if SIMDJSON_SUPPORTS_DESERIALIZATION
noexcept(custom_deserializable<T, value> ? nothrow_custom_deserializable<T, value> : true)
#else
noexcept
#endif
{
#if SIMDJSON_SUPPORTS_DESERIALIZATION
if constexpr (custom_deserializable<T, value>) {
return deserialize(*this, out);
} else {
static_assert(!sizeof(T), "The get<T> method with type T is not implemented by the simdjson library. "
"And you do not seem to have added support for it. Indeed, we have that "
"simdjson::custom_deserializable<T> is false and the type T is not a default type "
"such as ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, "
"int64_t, double, or bool.");
static_cast<void>(out); // to get rid of unused errors
return UNINITIALIZED;
}
#else // SIMDJSON_SUPPORTS_DESERIALIZATION
// Unless the simdjson library or the user provides an inline implementation, calling this method should
// immediately fail.
static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. "
"The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, "
"int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), "
" get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template."
" You may also add support for custom types, see our documentation.");
static_cast<void>(out); // to get rid of unused errors
return UNINITIALIZED;
#endif
}
/**
* Cast this JSON value to an array.
@@ -130,6 +169,17 @@ public:
* Important: a value should be consumed once. Calling get_string() twice on the same value
* is an error.
*
* In some instances, you may want to allow replacement of invalid Unicode sequences.
* You may do so by passing the allow_replacement parameter as true. In the following
* example, the string "431924697b\udff0L\u0001Y" is not valid Unicode. By passing true
* to get_string, we allow the replacement of the invalid Unicode sequences with the Unicode
* replacement character (U+FFFD).
*
* simdjson::ondemand::parser parser;
* auto json = R"({"deviceId":"431924697b\udff0L\u0001Y"})"_padded;
* simdjson::ondemand::document doc = parser.iterate(json);
* auto view = doc["deviceId"].get_string(true);
*
* @returns An UTF-8 string. The string is stored in the parser and will be invalidated the next
* time it parses a document or when it is destroyed.
* @returns INCORRECT_TYPE if the JSON value is not a string.
@@ -381,6 +431,7 @@ public:
simdjson_inline simdjson_result<value> operator[](std::string_view key) noexcept;
/** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) noexcept; */
simdjson_inline simdjson_result<value> operator[](const char *key) noexcept;
simdjson_result<value> operator[](int) noexcept = delete;
/**
* Get the type of this JSON value. It does not validate or consume the value.
@@ -748,6 +799,7 @@ public:
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> operator[](std::string_view key) noexcept;
/** @overload simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> find_field_unordered(std::string_view key) noexcept; */
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> operator[](const char *key) noexcept;
simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> operator[](int) noexcept = delete;
/**
* Get the type of this JSON value.
@@ -778,19 +778,23 @@ simdjson_warn_unused simdjson_inline simdjson_result<double> value_iterator::get
}
return result;
}
simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::get_root_bool(bool check_trailing) noexcept {
auto max_len = peek_root_length();
auto json = peek_root_scalar("bool");
uint8_t tmpbuf[5+1+1]; // +1 for null termination
tmpbuf[5+1] = '\0'; // make sure that buffer is always null terminated.
if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 5+1)) { return incorrect_type_error("Not a boolean"); }
auto result = parse_bool(tmpbuf);
if(result.error() == SUCCESS) {
if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
advance_root_scalar("bool");
}
return result;
// We have a boolean if we have either "true" or "false" and the next character is either
// a structural character or whitespace. We also check that the length is correct:
// "true" and "false" are 4 and 5 characters long, respectively.
bool value_true = (max_len >= 4 && !atomparsing::str4ncmp(json, "true") &&
(max_len == 4 || jsoncharutils::is_structural_or_whitespace(json[4])));
bool value_false = (max_len >= 5 && !atomparsing::str4ncmp(json, "false") &&
(max_len == 5 || jsoncharutils::is_structural_or_whitespace(json[5])));
if(value_true == false && value_false == false) { return incorrect_type_error("Not a boolean"); }
if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
advance_root_scalar("bool");
return value_true;
}
simdjson_inline simdjson_result<bool> value_iterator::is_root_null(bool check_trailing) noexcept {
auto max_len = peek_root_length();
auto json = peek_root_scalar("null");
@@ -799,6 +803,8 @@ simdjson_inline simdjson_result<bool> value_iterator::is_root_null(bool check_tr
if(result) { // we have something that looks like a null.
if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
advance_root_scalar("null");
} else if (json[0] == 'n') {
return incorrect_type_error("Not a null but starts with n");
}
return result;
}
@@ -125,7 +125,8 @@ public:
*
* @returns Whether the object had any fields (returns false for empty).
* @error INCOMPLETE_ARRAY_OR_OBJECT If there are no more tokens (implying the *parent*
* array or object is incomplete).
* array or object is incomplete). An INCOMPLETE_ARRAY_OR_OBJECT is an unrecoverable error that
* invalidates the document.
*/
simdjson_warn_unused simdjson_inline simdjson_result<bool> started_object() noexcept;
/**
@@ -135,7 +136,8 @@ public:
*
* @returns Whether the object had any fields (returns false for empty).
* @error INCOMPLETE_ARRAY_OR_OBJECT If there are no more tokens (implying the *parent*
* array or object is incomplete).
* array or object is incomplete). An INCOMPLETE_ARRAY_OR_OBJECT is an unrecoverable error that
* invalidates the document.
*/
simdjson_warn_unused simdjson_inline simdjson_result<bool> started_root_object() noexcept;
@@ -257,7 +259,8 @@ public:
*
* @returns Whether the array had any elements (returns false for empty).
* @error INCOMPLETE_ARRAY_OR_OBJECT If there are no more tokens (implying the *parent*
* array or object is incomplete).
* array or object is incomplete). An INCOMPLETE_ARRAY_OR_OBJECT is an unrecoverable error that
* invalidates the document.
*/
simdjson_warn_unused simdjson_inline simdjson_result<bool> started_array() noexcept;
/**
@@ -267,7 +270,8 @@ public:
*
* @returns Whether the array had any elements (returns false for empty).
* @error INCOMPLETE_ARRAY_OR_OBJECT If there are no more tokens (implying the *parent*
* array or object is incomplete).
* array or object is incomplete). An INCOMPLETE_ARRAY_OR_OBJECT is an unrecoverable error that
* invalidates the document.
*/
simdjson_warn_unused simdjson_inline simdjson_result<bool> started_root_array() noexcept;
+6
View File
@@ -4,8 +4,14 @@
#include "simdjson/haswell/intrinsics.h"
#if !SIMDJSON_CAN_ALWAYS_RUN_HASWELL
// We enable bmi2 only if LLVM/clang is used, because GCC may not
// make good use of it. See https://github.com/simdjson/simdjson/pull/2243
#if defined(__clang__)
SIMDJSON_TARGET_REGION("avx2,bmi,bmi2,pclmul,lzcnt,popcnt")
#else
SIMDJSON_TARGET_REGION("avx2,bmi,pclmul,lzcnt,popcnt")
#endif
#endif
#include "simdjson/haswell/bitmanipulation.h"
#include "simdjson/haswell/bitmask.h"
+6 -2
View File
@@ -148,14 +148,18 @@ namespace simd {
// Copies to 'output" all bytes corresponding to a 0 in the mask (interpreted as a bitset).
// Passing a 0 value for mask would be equivalent to writing out every byte to output.
// Only the first 32 - count_ones(mask) bytes of the result are significant but 32 bytes
// Only the first 64 - count_ones(mask) bytes of the result are significant but 64 bytes
// get written.
// Design consideration: it seems like a function with the
// signature simd8<L> compress(uint32_t mask) would be
// sensible, but the AVX ISA makes this kind of approach difficult.
template<typename L>
simdjson_inline void compress(uint64_t mask, L * output) const {
_mm512_mask_compressstoreu_epi8 (output,~mask,*this);
// we deliberately avoid _mm512_mask_compressstoreu_epi8 for portability
// (AMD Zen4 has terrible performance with it, it is effectively broken)
// _mm512_mask_compressstoreu_epi8 (output,~mask,*this);
__m512i compressed = _mm512_maskz_compress_epi8(~mask, *this);
_mm512_storeu_si512(output, compressed); // could use a mask
}
template<typename L>
+64
View File
@@ -0,0 +1,64 @@
#ifndef SIMDJSON_JSONPATHUTIL_H
#define SIMDJSON_JSONPATHUTIL_H
#include <string>
#include <string_view>
namespace simdjson {
/**
* Converts JSONPath to JSON Pointer.
* @param json_path The JSONPath string to be converted.
* @return A string containing the equivalent JSON Pointer.
*/
inline std::string json_path_to_pointer_conversion(std::string_view json_path) {
size_t i = 0;
// if JSONPath starts with $, skip it
if (!json_path.empty() && json_path.front() == '$') {
i = 1;
}
if (json_path.empty() || (json_path[i] != '.' &&
json_path[i] != '[')) {
return "-1"; // This is just a sentinel value, the caller should check for this and return an error.
}
std::string result;
// Reserve space to reduce allocations, adjusting for potential increases due
// to escaping.
result.reserve(json_path.size() * 2);
while (i < json_path.length()) {
if (json_path[i] == '.') {
result += '/';
} else if (json_path[i] == '[') {
result += '/';
++i; // Move past the '['
while (i < json_path.length() && json_path[i] != ']') {
if (json_path[i] == '~') {
result += "~0";
} else if (json_path[i] == '/') {
result += "~1";
} else {
result += json_path[i];
}
++i;
}
if (i == json_path.length() || json_path[i] != ']') {
return "-1"; // Using sentinel value that will be handled as an error by the caller.
}
} else {
if (json_path[i] == '~') {
result += "~0";
} else if (json_path[i] == '/') {
result += "~1";
} else {
result += json_path[i];
}
}
++i;
}
return result;
}
} // namespace simdjson
#endif // SIMDJSON_JSONPATHUTIL_H
@@ -36,6 +36,12 @@ simdjson_inline internal::value128 full_multiplication(uint64_t value1, uint64_t
} // namespace lasx
} // namespace simdjson
#ifndef SIMDJSON_SWAR_NUMBER_PARSING
#if SIMDJSON_IS_BIG_ENDIAN
#define SIMDJSON_SWAR_NUMBER_PARSING 0
#else
#define SIMDJSON_SWAR_NUMBER_PARSING 1
#endif
#endif
#endif // SIMDJSON_LASX_NUMBERPARSING_DEFS_H
@@ -36,6 +36,12 @@ simdjson_inline internal::value128 full_multiplication(uint64_t value1, uint64_t
} // namespace lsx
} // namespace simdjson
#ifndef SIMDJSON_SWAR_NUMBER_PARSING
#if SIMDJSON_IS_BIG_ENDIAN
#define SIMDJSON_SWAR_NUMBER_PARSING 0
#else
#define SIMDJSON_SWAR_NUMBER_PARSING 1
#endif
#endif
#endif // SIMDJSON_LSX_NUMBERPARSING_DEFS_H
+12 -12
View File
@@ -166,22 +166,22 @@ inline namespace literals {
inline namespace string_view_literals {
constexpr std::string_view operator "" _sv( const char* str, size_t len ) noexcept // (1)
constexpr std::string_view operator ""_sv( const char* str, size_t len ) noexcept // (1)
{
return std::string_view{ str, len };
}
constexpr std::u16string_view operator "" _sv( const char16_t* str, size_t len ) noexcept // (2)
constexpr std::u16string_view operator ""_sv( const char16_t* str, size_t len ) noexcept // (2)
{
return std::u16string_view{ str, len };
}
constexpr std::u32string_view operator "" _sv( const char32_t* str, size_t len ) noexcept // (3)
constexpr std::u32string_view operator ""_sv( const char32_t* str, size_t len ) noexcept // (3)
{
return std::u32string_view{ str, len };
}
constexpr std::wstring_view operator "" _sv( const wchar_t* str, size_t len ) noexcept // (4)
constexpr std::wstring_view operator ""_sv( const wchar_t* str, size_t len ) noexcept // (4)
{
return std::wstring_view{ str, len };
}
@@ -1512,22 +1512,22 @@ nssv_inline_ns namespace string_view_literals {
#if nssv_CONFIG_STD_SV_OPERATOR && nssv_HAVE_STD_DEFINED_LITERALS
nssv_constexpr nonstd::sv_lite::string_view operator "" sv( const char* str, size_t len ) nssv_noexcept // (1)
nssv_constexpr nonstd::sv_lite::string_view operator ""sv( const char* str, size_t len ) nssv_noexcept // (1)
{
return nonstd::sv_lite::string_view{ str, len };
}
nssv_constexpr nonstd::sv_lite::u16string_view operator "" sv( const char16_t* str, size_t len ) nssv_noexcept // (2)
nssv_constexpr nonstd::sv_lite::u16string_view operator ""sv( const char16_t* str, size_t len ) nssv_noexcept // (2)
{
return nonstd::sv_lite::u16string_view{ str, len };
}
nssv_constexpr nonstd::sv_lite::u32string_view operator "" sv( const char32_t* str, size_t len ) nssv_noexcept // (3)
nssv_constexpr nonstd::sv_lite::u32string_view operator ""sv( const char32_t* str, size_t len ) nssv_noexcept // (3)
{
return nonstd::sv_lite::u32string_view{ str, len };
}
nssv_constexpr nonstd::sv_lite::wstring_view operator "" sv( const wchar_t* str, size_t len ) nssv_noexcept // (4)
nssv_constexpr nonstd::sv_lite::wstring_view operator ""sv( const wchar_t* str, size_t len ) nssv_noexcept // (4)
{
return nonstd::sv_lite::wstring_view{ str, len };
}
@@ -1536,22 +1536,22 @@ nssv_constexpr nonstd::sv_lite::wstring_view operator "" sv( const wchar_t* str,
#if nssv_CONFIG_USR_SV_OPERATOR
nssv_constexpr nonstd::sv_lite::string_view operator "" _sv( const char* str, size_t len ) nssv_noexcept // (1)
nssv_constexpr nonstd::sv_lite::string_view operator ""_sv( const char* str, size_t len ) nssv_noexcept // (1)
{
return nonstd::sv_lite::string_view{ str, len };
}
nssv_constexpr nonstd::sv_lite::u16string_view operator "" _sv( const char16_t* str, size_t len ) nssv_noexcept // (2)
nssv_constexpr nonstd::sv_lite::u16string_view operator ""_sv( const char16_t* str, size_t len ) nssv_noexcept // (2)
{
return nonstd::sv_lite::u16string_view{ str, len };
}
nssv_constexpr nonstd::sv_lite::u32string_view operator "" _sv( const char32_t* str, size_t len ) nssv_noexcept // (3)
nssv_constexpr nonstd::sv_lite::u32string_view operator ""_sv( const char32_t* str, size_t len ) nssv_noexcept // (3)
{
return nonstd::sv_lite::u32string_view{ str, len };
}
nssv_constexpr nonstd::sv_lite::wstring_view operator "" _sv( const wchar_t* str, size_t len ) nssv_noexcept // (4)
nssv_constexpr nonstd::sv_lite::wstring_view operator ""_sv( const wchar_t* str, size_t len ) nssv_noexcept // (4)
{
return nonstd::sv_lite::wstring_view{ str, len };
}
+2 -2
View File
@@ -187,11 +187,11 @@ inline simdjson_result<padded_string> padded_string::load(std::string_view filen
} // namespace simdjson
inline simdjson::padded_string operator "" _padded(const char *str, size_t len) {
inline simdjson::padded_string operator ""_padded(const char *str, size_t len) {
return simdjson::padded_string(str, len);
}
#ifdef __cpp_char8_t
inline simdjson::padded_string operator "" _padded(const char8_t *str, size_t len) {
inline simdjson::padded_string operator ""_padded(const char8_t *str, size_t len) {
return simdjson::padded_string(reinterpret_cast<const char8_t *>(str), len);
}
#endif
+2 -2
View File
@@ -161,9 +161,9 @@ inline std::ostream& operator<<(std::ostream& out, simdjson_result<padded_string
} // namespace simdjson
// This is deliberately outside of simdjson so that people get it without having to use the namespace
inline simdjson::padded_string operator "" _padded(const char *str, size_t len);
inline simdjson::padded_string operator ""_padded(const char *str, size_t len);
#ifdef __cpp_char8_t
inline simdjson::padded_string operator "" _padded(const char8_t *str, size_t len);
inline simdjson::padded_string operator ""_padded(const char8_t *str, size_t len);
#endif
namespace simdjson {
@@ -53,6 +53,11 @@ inline bool padded_string_view::remove_utf8_bom() noexcept {
inline std::ostream& operator<<(std::ostream& out, simdjson_result<padded_string_view> &s) noexcept(false) { return out << s.value(); }
#endif
inline padded_string_view pad(std::string& s) noexcept {
const auto len = s.size();
s.append(SIMDJSON_PADDING, ' ');
return padded_string_view(s.data(), len, s.size());
}
} // namespace simdjson
+9
View File
@@ -83,6 +83,15 @@ public:
inline std::ostream& operator<<(std::ostream& out, simdjson_result<padded_string_view> &s) noexcept(false);
#endif
/**
* Create a padded_string_view from a string. The string will be padded with SIMDJSON_PADDING
* space characters. The resulting padded_string_view will have a length equal to the original
* string.
*
* @param s The string.
* @return The padded string.
*/
inline padded_string_view pad(std::string& s) noexcept;
} // namespace simdjson
#endif // SIMDJSON_PADDED_STRING_VIEW_H
+44
View File
@@ -6,11 +6,15 @@
#include <cstdlib>
#include <cfloat>
#include <cassert>
#include <climits>
#ifndef _WIN32
// strcasecmp, strncasecmp
#include <strings.h>
#endif
static_assert(CHAR_BIT == 8, "simdjson requires 8-bit bytes");
// We are using size_t without namespace std:: throughout the project
using std::size_t;
@@ -44,6 +48,7 @@ using std::size_t;
#elif defined(__loongarch_lp64)
#define SIMDJSON_IS_LOONGARCH64 1
#elif defined(__PPC64__) || defined(_M_PPC64)
#define SIMDJSON_IS_PPC64 1
#if defined(__ALTIVEC__)
#define SIMDJSON_IS_PPC64_VMX 1
#endif // defined(__ALTIVEC__)
@@ -201,4 +206,43 @@ using std::size_t;
#endif
#if defined __BYTE_ORDER__ && defined __ORDER_BIG_ENDIAN__
#define SIMDJSON_IS_BIG_ENDIAN (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
#elif defined _WIN32
#define SIMDJSON_IS_BIG_ENDIAN 0
#else
#if defined(__APPLE__) || defined(__FreeBSD__)
#include <machine/endian.h>
#elif defined(sun) || defined(__sun)
#include <sys/byteorder.h>
#elif defined(__MVS__)
#include <sys/endian.h>
#else
#ifdef __has_include
#if __has_include(<endian.h>)
#include <endian.h>
#endif //__has_include(<endian.h>)
#endif //__has_include
#endif
#
#ifndef __BYTE_ORDER__
// safe choice
#define SIMDJSON_IS_BIG_ENDIAN 0
#endif
#
#ifndef __ORDER_LITTLE_ENDIAN__
// safe choice
#define SIMDJSON_IS_BIG_ENDIAN 0
#endif
#
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
#define SIMDJSON_IS_BIG_ENDIAN 0
#else
#define SIMDJSON_IS_BIG_ENDIAN 1
#endif
#endif
#endif // SIMDJSON_PORTABILITY_H
@@ -60,6 +60,12 @@ simdjson_inline internal::value128 full_multiplication(uint64_t value1, uint64_t
} // namespace ppc64
} // namespace simdjson
#ifndef SIMDJSON_SWAR_NUMBER_PARSING
#if SIMDJSON_IS_BIG_ENDIAN
#define SIMDJSON_SWAR_NUMBER_PARSING 0
#else
#define SIMDJSON_SWAR_NUMBER_PARSING 1
#endif
#endif
#endif // SIMDJSON_PPC64_NUMBERPARSING_DEFS_H
+3 -3
View File
@@ -4,7 +4,7 @@
#define SIMDJSON_SIMDJSON_VERSION_H
/** The version of simdjson being used (major.minor.revision) */
#define SIMDJSON_VERSION "3.10.1"
#define SIMDJSON_VERSION "3.12.3"
namespace simdjson {
enum {
@@ -15,11 +15,11 @@ enum {
/**
* The minor version (major.MINOR.revision) of simdjson being used.
*/
SIMDJSON_VERSION_MINOR = 10,
SIMDJSON_VERSION_MINOR = 12,
/**
* The revision (major.minor.REVISION) of simdjson being used.
*/
SIMDJSON_VERSION_REVISION = 1
SIMDJSON_VERSION_REVISION = 3
};
} // namespace simdjson
+22
View File
@@ -323,6 +323,10 @@ class Amalgamator:
for line in fid2:
line = line.rstrip('\n')
# Ignore #pragma once, it causes warnings if it ends up in a .cpp file
if re.search(r'^#pragma once$', line):
continue
# Ignore lines inside #ifndef SIMDJSON_CONDITIONAL_INCLUDE
if re.search(r'^#ifndef\s+SIMDJSON_CONDITIONAL_INCLUDE\s*$', line):
assert file.is_conditional_include, f"{file} uses #ifndef SIMDJSON_CONDITIONAL_INCLUDE but is not an amalgamated file!"
@@ -437,6 +441,22 @@ if SCRIPTPATH != AMALGAMATE_OUTPUT_PATH:
shutil.copy2(os.path.join(SCRIPTPATH,"amalgamate_demo.cpp"),AMALGAMATE_OUTPUT_PATH)
shutil.copy2(os.path.join(SCRIPTPATH,"README.md"),AMALGAMATE_OUTPUT_PATH)
def create_zip():
import zipfile
outdir = AMALGAMATE_OUTPUT_PATH
path = os.path.join(outdir, "singleheader.zip")
print(f"Creating {path}")
with zipfile.ZipFile(path, 'w') as zf:
for name in ["simdjson.cpp", "simdjson.h"]:
source = os.path.join(outdir, name)
print(f"Adding {source}")
zf.write(source, name)
print(f"Created {path}")
create_zip()
print("Done with all files generation.")
print(f"Files have been written to directory: {AMALGAMATE_OUTPUT_PATH}/")
@@ -445,6 +465,8 @@ print(subprocess.run(['ls', '-la', AMAL_C, AMAL_H, DEMOCPP, README],
print("Done with all files generation.")
#
# Instructions to create demo
#
+366 -61
View File
@@ -1,4 +1,4 @@
/* auto-generated on 2024-08-26 09:37:03 -0400. Do not edit! */
/* auto-generated on 2025-03-27 15:01:10 -0400. Do not edit! */
/* including simdjson.cpp: */
/* begin file simdjson.cpp */
#define SIMDJSON_SRC_SIMDJSON_CPP
@@ -77,6 +77,30 @@
#endif
#endif
#ifdef __has_include
#if __has_include(<version>)
#include <version>
#endif
#endif
#if defined(__apple_build_version__)
#if __apple_build_version__ < 14000000
#define SIMDJSON_CONCEPT_DISABLED 1 // apple-clang/13 doesn't support std::convertible_to
#endif
#endif
#if defined(__cpp_concepts) && !defined(SIMDJSON_CONCEPT_DISABLED)
#if __cpp_concepts >= 201907L
#include <utility>
#define SIMDJSON_SUPPORTS_DESERIALIZATION 1
#else
#define SIMDJSON_SUPPORTS_DESERIALIZATION 0
#endif
#else // defined(__cpp_concepts) && !defined(SIMDJSON_CONCEPT_DISABLED)
#define SIMDJSON_SUPPORTS_DESERIALIZATION 0
#endif // defined(__cpp_concepts) && !defined(SIMDJSON_CONCEPT_DISABLED)
#endif // SIMDJSON_COMPILER_CHECK_H
/* end file simdjson/compiler_check.h */
/* including simdjson/portability.h: #include "simdjson/portability.h" */
@@ -89,11 +113,15 @@
#include <cstdlib>
#include <cfloat>
#include <cassert>
#include <climits>
#ifndef _WIN32
// strcasecmp, strncasecmp
#include <strings.h>
#endif
static_assert(CHAR_BIT == 8, "simdjson requires 8-bit bytes");
// We are using size_t without namespace std:: throughout the project
using std::size_t;
@@ -127,6 +155,7 @@ using std::size_t;
#elif defined(__loongarch_lp64)
#define SIMDJSON_IS_LOONGARCH64 1
#elif defined(__PPC64__) || defined(_M_PPC64)
#define SIMDJSON_IS_PPC64 1
#if defined(__ALTIVEC__)
#define SIMDJSON_IS_PPC64_VMX 1
#endif // defined(__ALTIVEC__)
@@ -284,6 +313,45 @@ using std::size_t;
#endif
#if defined __BYTE_ORDER__ && defined __ORDER_BIG_ENDIAN__
#define SIMDJSON_IS_BIG_ENDIAN (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
#elif defined _WIN32
#define SIMDJSON_IS_BIG_ENDIAN 0
#else
#if defined(__APPLE__) || defined(__FreeBSD__)
#include <machine/endian.h>
#elif defined(sun) || defined(__sun)
#include <sys/byteorder.h>
#elif defined(__MVS__)
#include <sys/endian.h>
#else
#ifdef __has_include
#if __has_include(<endian.h>)
#include <endian.h>
#endif //__has_include(<endian.h>)
#endif //__has_include
#endif
#
#ifndef __BYTE_ORDER__
// safe choice
#define SIMDJSON_IS_BIG_ENDIAN 0
#endif
#
#ifndef __ORDER_LITTLE_ENDIAN__
// safe choice
#define SIMDJSON_IS_BIG_ENDIAN 0
#endif
#
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
#define SIMDJSON_IS_BIG_ENDIAN 0
#else
#define SIMDJSON_IS_BIG_ENDIAN 1
#endif
#endif
#endif // SIMDJSON_PORTABILITY_H
/* end file simdjson/portability.h */
@@ -549,7 +617,6 @@ SIMDJSON_PUSH_DISABLE_ALL_WARNINGS
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#pragma once
#ifndef NONSTD_SV_LITE_H_INCLUDED
#define NONSTD_SV_LITE_H_INCLUDED
@@ -709,22 +776,22 @@ inline namespace literals {
inline namespace string_view_literals {
constexpr std::string_view operator "" _sv( const char* str, size_t len ) noexcept // (1)
constexpr std::string_view operator ""_sv( const char* str, size_t len ) noexcept // (1)
{
return std::string_view{ str, len };
}
constexpr std::u16string_view operator "" _sv( const char16_t* str, size_t len ) noexcept // (2)
constexpr std::u16string_view operator ""_sv( const char16_t* str, size_t len ) noexcept // (2)
{
return std::u16string_view{ str, len };
}
constexpr std::u32string_view operator "" _sv( const char32_t* str, size_t len ) noexcept // (3)
constexpr std::u32string_view operator ""_sv( const char32_t* str, size_t len ) noexcept // (3)
{
return std::u32string_view{ str, len };
}
constexpr std::wstring_view operator "" _sv( const wchar_t* str, size_t len ) noexcept // (4)
constexpr std::wstring_view operator ""_sv( const wchar_t* str, size_t len ) noexcept // (4)
{
return std::wstring_view{ str, len };
}
@@ -2055,22 +2122,22 @@ nssv_inline_ns namespace string_view_literals {
#if nssv_CONFIG_STD_SV_OPERATOR && nssv_HAVE_STD_DEFINED_LITERALS
nssv_constexpr nonstd::sv_lite::string_view operator "" sv( const char* str, size_t len ) nssv_noexcept // (1)
nssv_constexpr nonstd::sv_lite::string_view operator ""sv( const char* str, size_t len ) nssv_noexcept // (1)
{
return nonstd::sv_lite::string_view{ str, len };
}
nssv_constexpr nonstd::sv_lite::u16string_view operator "" sv( const char16_t* str, size_t len ) nssv_noexcept // (2)
nssv_constexpr nonstd::sv_lite::u16string_view operator ""sv( const char16_t* str, size_t len ) nssv_noexcept // (2)
{
return nonstd::sv_lite::u16string_view{ str, len };
}
nssv_constexpr nonstd::sv_lite::u32string_view operator "" sv( const char32_t* str, size_t len ) nssv_noexcept // (3)
nssv_constexpr nonstd::sv_lite::u32string_view operator ""sv( const char32_t* str, size_t len ) nssv_noexcept // (3)
{
return nonstd::sv_lite::u32string_view{ str, len };
}
nssv_constexpr nonstd::sv_lite::wstring_view operator "" sv( const wchar_t* str, size_t len ) nssv_noexcept // (4)
nssv_constexpr nonstd::sv_lite::wstring_view operator ""sv( const wchar_t* str, size_t len ) nssv_noexcept // (4)
{
return nonstd::sv_lite::wstring_view{ str, len };
}
@@ -2079,22 +2146,22 @@ nssv_constexpr nonstd::sv_lite::wstring_view operator "" sv( const wchar_t* str,
#if nssv_CONFIG_USR_SV_OPERATOR
nssv_constexpr nonstd::sv_lite::string_view operator "" _sv( const char* str, size_t len ) nssv_noexcept // (1)
nssv_constexpr nonstd::sv_lite::string_view operator ""_sv( const char* str, size_t len ) nssv_noexcept // (1)
{
return nonstd::sv_lite::string_view{ str, len };
}
nssv_constexpr nonstd::sv_lite::u16string_view operator "" _sv( const char16_t* str, size_t len ) nssv_noexcept // (2)
nssv_constexpr nonstd::sv_lite::u16string_view operator ""_sv( const char16_t* str, size_t len ) nssv_noexcept // (2)
{
return nonstd::sv_lite::u16string_view{ str, len };
}
nssv_constexpr nonstd::sv_lite::u32string_view operator "" _sv( const char32_t* str, size_t len ) nssv_noexcept // (3)
nssv_constexpr nonstd::sv_lite::u32string_view operator ""_sv( const char32_t* str, size_t len ) nssv_noexcept // (3)
{
return nonstd::sv_lite::u32string_view{ str, len };
}
nssv_constexpr nonstd::sv_lite::wstring_view operator "" _sv( const wchar_t* str, size_t len ) nssv_noexcept // (4)
nssv_constexpr nonstd::sv_lite::wstring_view operator ""_sv( const wchar_t* str, size_t len ) nssv_noexcept // (4)
{
return nonstd::sv_lite::wstring_view{ str, len };
}
@@ -2364,7 +2431,7 @@ enum error_code {
SUCCESS = 0, ///< No error
CAPACITY, ///< This parser can't support a document that big
MEMALLOC, ///< Error allocating memory, most likely out of memory
TAPE_ERROR, ///< Something went wrong, this is a generic error
TAPE_ERROR, ///< Something went wrong, this is a generic error. Fatal/unrecoverable error.
DEPTH_ERROR, ///< Your document exceeds the user-specified depth limitation
STRING_ERROR, ///< Problem while parsing a string
T_ATOM_ERROR, ///< Problem while parsing an atom starting with the letter 't'
@@ -2389,13 +2456,21 @@ enum error_code {
PARSER_IN_USE, ///< parser is already in use.
OUT_OF_ORDER_ITERATION, ///< tried to iterate an array or object out of order (checked when SIMDJSON_DEVELOPMENT_CHECKS=1)
INSUFFICIENT_PADDING, ///< The JSON doesn't have enough padding for simdjson to safely parse it.
INCOMPLETE_ARRAY_OR_OBJECT, ///< The document ends early.
INCOMPLETE_ARRAY_OR_OBJECT, ///< The document ends early. Fatal/unrecoverable error.
SCALAR_DOCUMENT_AS_VALUE, ///< A scalar document is treated as a value.
OUT_OF_BOUNDS, ///< Attempted to access location outside of document.
TRAILING_CONTENT, ///< Unexpected trailing content in the JSON input
NUM_ERROR_CODES
};
/**
* Some errors are fatal and invalidate the document. This function returns true if the
* error is fatal. It returns true for TAPE_ERROR and INCOMPLETE_ARRAY_OR_OBJECT.
* Once a fatal error is encountered, the on-demand document is no longer valid and
* processing should stop.
*/
inline bool is_fatal(error_code error) noexcept;
/**
* It is the convention throughout the code that the macro SIMDJSON_DEVELOPMENT_CHECKS determines whether
* we check for OUT_OF_ORDER_ITERATION. The logic behind it is that these errors only occurs when the code
@@ -2430,7 +2505,7 @@ struct simdjson_error : public std::exception {
*/
simdjson_error(error_code error) noexcept : _error{error} { }
/** The error message */
const char *what() const noexcept { return error_message(error()); }
const char *what() const noexcept override { return error_message(error()); }
/** The error code */
error_code error() const noexcept { return _error; }
private:
@@ -2662,6 +2737,140 @@ inline const std::string error_message(int error) noexcept;
#endif // SIMDJSON_ERROR_H
/* end file simdjson/error.h */
/* skipped duplicate #include "simdjson/portability.h" */
/* including simdjson/concepts.h: #include "simdjson/concepts.h" */
/* begin file simdjson/concepts.h */
#ifndef SIMDJSON_CONCEPTS_H
#define SIMDJSON_CONCEPTS_H
#if SIMDJSON_SUPPORTS_DESERIALIZATION
#include <concepts>
#include <type_traits>
namespace simdjson {
namespace concepts {
namespace details {
#define SIMDJSON_IMPL_CONCEPT(name, method) \
template <typename T> \
concept supports_##name = !std::is_const_v<T> && requires { \
typename std::remove_cvref_t<T>::value_type; \
requires requires(typename std::remove_cvref_t<T>::value_type &&val, \
T obj) { \
obj.method(std::move(val)); \
requires !requires { obj = std::move(val); }; \
}; \
};
SIMDJSON_IMPL_CONCEPT(emplace_back, emplace_back)
SIMDJSON_IMPL_CONCEPT(emplace, emplace)
SIMDJSON_IMPL_CONCEPT(push_back, push_back)
SIMDJSON_IMPL_CONCEPT(add, add)
SIMDJSON_IMPL_CONCEPT(push, push)
SIMDJSON_IMPL_CONCEPT(append, append)
SIMDJSON_IMPL_CONCEPT(insert, insert)
SIMDJSON_IMPL_CONCEPT(op_append, operator+=)
#undef SIMDJSON_IMPL_CONCEPT
} // namespace details
template <typename T>
concept string_view_like = std::is_convertible_v<T, std::string_view> &&
!std::is_convertible_v<T, const char*>;
template<typename T>
concept constructible_from_string_view = std::is_constructible_v<T, std::string_view>
&& !std::is_same_v<T, std::string_view>
&& std::is_default_constructible_v<T>;
template<typename M>
concept string_view_keyed_map = string_view_like<typename M::key_type>
&& requires(std::remove_cvref_t<M>& m, typename M::key_type sv, typename M::mapped_type v) {
{ m.emplace(sv, v) } -> std::same_as<std::pair<typename M::iterator, bool>>;
};
/// Check if T is a container that we can append to, including:
/// std::vector, std::deque, std::list, std::string, ...
template <typename T>
concept appendable_containers =
(details::supports_emplace_back<T> || details::supports_emplace<T> ||
details::supports_push_back<T> || details::supports_push<T> ||
details::supports_add<T> || details::supports_append<T> ||
details::supports_insert<T>) && !string_view_keyed_map<T>;
/// Insert into the container however possible
template <appendable_containers T, typename... Args>
constexpr decltype(auto) emplace_one(T &vec, Args &&...args) {
if constexpr (details::supports_emplace_back<T>) {
return vec.emplace_back(std::forward<Args>(args)...);
} else if constexpr (details::supports_emplace<T>) {
return vec.emplace(std::forward<Args>(args)...);
} else if constexpr (details::supports_push_back<T>) {
return vec.push_back(std::forward<Args>(args)...);
} else if constexpr (details::supports_push<T>) {
return vec.push(std::forward<Args>(args)...);
} else if constexpr (details::supports_add<T>) {
return vec.add(std::forward<Args>(args)...);
} else if constexpr (details::supports_append<T>) {
return vec.append(std::forward<Args>(args)...);
} else if constexpr (details::supports_insert<T>) {
return vec.insert(std::forward<Args>(args)...);
} else if constexpr (details::supports_op_append<T> && sizeof...(Args) == 1) {
return vec.operator+=(std::forward<Args>(args)...);
} else {
static_assert(!sizeof(T *),
"We don't know how to add things to this container");
}
}
/// This checks if the container will return a reference to the newly added
/// element after an insert which for example `std::vector::emplace_back` does
/// since C++17; this will allow some optimizations.
template <typename T>
concept returns_reference = appendable_containers<T> && requires {
typename std::remove_cvref_t<T>::reference;
requires requires(typename std::remove_cvref_t<T>::value_type &&val, T obj) {
{
emplace_one(obj, std::move(val))
} -> std::same_as<typename std::remove_cvref_t<T>::reference>;
};
};
template <typename T>
concept smart_pointer = requires(std::remove_cvref_t<T> ptr) {
// Check if T has a member type named element_type
typename std::remove_cvref_t<T>::element_type;
// Check if T has a get() member function
{
ptr.get()
} -> std::same_as<typename std::remove_cvref_t<T>::element_type *>;
// Check if T can be dereferenced
{ *ptr } -> std::same_as<typename std::remove_cvref_t<T>::element_type &>;
};
template <typename T>
concept optional_type = requires(std::remove_cvref_t<T> obj) {
typename std::remove_cvref_t<T>::value_type;
{ obj.value() } -> std::same_as<typename std::remove_cvref_t<T>::value_type&>;
requires requires(typename std::remove_cvref_t<T>::value_type &&val) {
obj.emplace(std::move(val));
obj = std::move(val);
{
obj.value_or(val)
} -> std::convertible_to<typename std::remove_cvref_t<T>::value_type>;
};
{ static_cast<bool>(obj) } -> std::same_as<bool>; // convertible to bool
};
} // namespace concepts
} // namespace simdjson
#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
#endif // SIMDJSON_CONCEPTS_H
/* end file simdjson/concepts.h */
/**
* @brief The top level simdjson namespace, containing everything the library provides.
@@ -4328,6 +4537,11 @@ extern SIMDJSON_DLLIMPORTEXPORT const uint32_t digit_to_val32[886];
#include <iostream>
namespace simdjson {
inline bool is_fatal(error_code error) noexcept {
return error == TAPE_ERROR || error == INCOMPLETE_ARRAY_OR_OBJECT;
}
namespace internal {
// We store the error code so we can validate the error message is associated with the right code
struct error_code_info {
@@ -4513,7 +4727,7 @@ namespace internal {
{ SUCCESS, "SUCCESS: No error" },
{ CAPACITY, "CAPACITY: This parser can't support a document that big" },
{ MEMALLOC, "MEMALLOC: Error allocating memory, we're most likely out of memory" },
{ TAPE_ERROR, "TAPE_ERROR: The JSON document has an improper structure: missing or superfluous commas, braces, missing keys, etc." },
{ TAPE_ERROR, "TAPE_ERROR: The JSON document has an improper structure: missing or superfluous commas, braces, missing keys, etc. This is a fatal and unrecoverable error." },
{ DEPTH_ERROR, "DEPTH_ERROR: The JSON document was too deep (too many nested objects and arrays)" },
{ STRING_ERROR, "STRING_ERROR: Problem while parsing a string" },
{ T_ATOM_ERROR, "T_ATOM_ERROR: Problem while parsing an atom starting with the letter 't'" },
@@ -4538,7 +4752,7 @@ namespace internal {
{ PARSER_IN_USE, "PARSER_IN_USE: Cannot parse a new document while a document is still in use." },
{ OUT_OF_ORDER_ITERATION, "OUT_OF_ORDER_ITERATION: Objects and arrays can only be iterated when they are first encountered." },
{ INSUFFICIENT_PADDING, "INSUFFICIENT_PADDING: simdjson requires the input JSON string to have at least SIMDJSON_PADDING extra bytes allocated, beyond the string's length. Consider using the simdjson::padded_string class if needed." },
{ INCOMPLETE_ARRAY_OR_OBJECT, "INCOMPLETE_ARRAY_OR_OBJECT: JSON document ended early in the middle of an object or array." },
{ INCOMPLETE_ARRAY_OR_OBJECT, "INCOMPLETE_ARRAY_OR_OBJECT: JSON document ended early in the middle of an object or array. This is a fatal and unrecoverable error." },
{ SCALAR_DOCUMENT_AS_VALUE, "SCALAR_DOCUMENT_AS_VALUE: A JSON document made of a scalar (number, Boolean, null or string) is treated as a value. Use get_bool(), get_double(), etc. on the document instead. "},
{ OUT_OF_BOUNDS, "OUT_OF_BOUNDS: Attempt to access location outside of document."},
{ TRAILING_CONTENT, "TRAILING_CONTENT: Unexpected trailing content in the JSON input."}
@@ -6447,7 +6661,6 @@ extern SIMDJSON_DLLIMPORTEXPORT const uint64_t thintable_epi8[256];
#endif // SIMDJSON_INTERNAL_SIMDPRUNE_TABLES_H
/* end file simdjson/internal/simdprune_tables.h */
#endif // SIMDJSON_GENERIC_DEPENDENCIES_H
/* end file simdjson/generic/dependencies.h */
/* including generic/dependencies.h: #include <generic/dependencies.h> */
@@ -6605,7 +6818,7 @@ public:
* The memory allocation is strict: you
* can you use this function to increase
* or lower the amount of allocated memory.
* Passsing zero clears the memory.
* Passing zero clears the memory.
*/
error_code allocate(size_t len) noexcept;
/** @private Capacity in bytes, in terms
@@ -7623,7 +7836,7 @@ SIMDJSON_NO_SANITIZE_UNDEFINED
// See issue https://github.com/simdjson/simdjson/issues/1965
SIMDJSON_NO_SANITIZE_MEMORY
simdjson_inline int trailing_zeroes(uint64_t input_num) {
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
#if SIMDJSON_REGULAR_VISUAL_STUDIO
unsigned long ret;
// Search the mask data from least significant bit (LSB)
// to the most significant bit (MSB) for a set bit (1).
@@ -7639,9 +7852,15 @@ simdjson_inline uint64_t clear_lowest_bit(uint64_t input_num) {
return input_num & (input_num-1);
}
// We sometimes call leading_zeroes on inputs that are zero,
// but the algorithms do not end up using the returned value.
// Sadly, sanitizers are not smart enough to figure it out.
// Applies only when SIMDJSON_PREFER_REVERSE_BITS is defined and true.
// (See below.)
SIMDJSON_NO_SANITIZE_UNDEFINED
/* result might be undefined when input_num is zero */
simdjson_inline int leading_zeroes(uint64_t input_num) {
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
#if SIMDJSON_REGULAR_VISUAL_STUDIO
unsigned long leading_zero = 0;
// Search the mask data from most significant bit (MSB)
// to least significant bit (LSB) for a set bit (1).
@@ -7694,7 +7913,7 @@ simdjson_inline uint64_t zero_leading_bit(uint64_t rev_bits, int leading_zeroes)
#endif
simdjson_inline bool add_overflow(uint64_t value1, uint64_t value2, uint64_t *result) {
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
#if SIMDJSON_REGULAR_VISUAL_STUDIO
*result = value1 + value2;
return *result < value1;
#else
@@ -7811,7 +8030,13 @@ simdjson_inline internal::value128 full_multiplication(uint64_t value1, uint64_t
} // namespace arm64
} // namespace simdjson
#ifndef SIMDJSON_SWAR_NUMBER_PARSING
#if SIMDJSON_IS_BIG_ENDIAN
#define SIMDJSON_SWAR_NUMBER_PARSING 0
#else
#define SIMDJSON_SWAR_NUMBER_PARSING 1
#endif
#endif
#endif // SIMDJSON_ARM64_NUMBERPARSING_DEFS_H
/* end file simdjson/arm64/numberparsing_defs.h */
@@ -7831,7 +8056,7 @@ namespace arm64 {
namespace {
namespace simd {
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
#if SIMDJSON_REGULAR_VISUAL_STUDIO
namespace {
// Start of private section with Visual Studio workaround
@@ -7940,7 +8165,7 @@ namespace {
// We return uint32_t instead of uint16_t because that seems to be more efficient for most
// purposes (cutting it down to uint16_t costs performance in some compilers).
simdjson_inline uint32_t to_bitmask() const {
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
#if SIMDJSON_REGULAR_VISUAL_STUDIO
const uint8x16_t bit_mask = simdjson_make_uint8x16_t(0x01, 0x02, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80,
0x01, 0x02, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80);
#else
@@ -7971,7 +8196,7 @@ namespace {
// Splat constructor
simdjson_inline simd8(uint8_t _value) : simd8(splat(_value)) {}
// Member-by-member initialization
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
#if SIMDJSON_REGULAR_VISUAL_STUDIO
simdjson_inline simd8(
uint8_t v0, uint8_t v1, uint8_t v2, uint8_t v3, uint8_t v4, uint8_t v5, uint8_t v6, uint8_t v7,
uint8_t v8, uint8_t v9, uint8_t v10, uint8_t v11, uint8_t v12, uint8_t v13, uint8_t v14, uint8_t v15
@@ -8065,7 +8290,7 @@ namespace {
uint64x2_t shufmask64 = {thintable_epi8[mask1], thintable_epi8[mask2]};
uint8x16_t shufmask = vreinterpretq_u8_u64(shufmask64);
// we increment by 0x08 the second half of the mask
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
#if SIMDJSON_REGULAR_VISUAL_STUDIO
uint8x16_t inc = simdjson_make_uint8x16_t(0, 0, 0, 0, 0, 0, 0, 0, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08);
#else
uint8x16_t inc = {0, 0, 0, 0, 0, 0, 0, 0, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08};
@@ -8095,7 +8320,7 @@ namespace {
uint8x8_t compactmask1 = vcreate_u8(thintable_epi8[mask1]);
uint8x8_t compactmask2 = vcreate_u8(thintable_epi8[mask2]);
// we increment by 0x08 the second half of the mask
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
#if SIMDJSON_REGULAR_VISUAL_STUDIO
uint8x8_t inc = simdjson_make_uint8x8_t(0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08);
#else
uint8x8_t inc = {0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08};
@@ -8147,7 +8372,7 @@ namespace {
// Array constructor
simdjson_inline simd8(const int8_t* values) : simd8(load(values)) {}
// Member-by-member initialization
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
#if SIMDJSON_REGULAR_VISUAL_STUDIO
simdjson_inline simd8(
int8_t v0, int8_t v1, int8_t v2, int8_t v3, int8_t v4, int8_t v5, int8_t v6, int8_t v7,
int8_t v8, int8_t v9, int8_t v10, int8_t v11, int8_t v12, int8_t v13, int8_t v14, int8_t v15
@@ -8268,7 +8493,7 @@ namespace {
}
simdjson_inline uint64_t to_bitmask() const {
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
#if SIMDJSON_REGULAR_VISUAL_STUDIO
const uint8x16_t bit_mask = simdjson_make_uint8x16_t(
0x01, 0x02, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80,
0x01, 0x02, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80
@@ -8991,7 +9216,7 @@ simdjson_inline bool compute_float_64(int64_t power, uint64_t i, bool negative,
// floor(log(5**power)/log(2))
//
// Note that this is not magic: 152170/(1<<16) is
// approximatively equal to log(5)/log(2).
// approximately equal to log(5)/log(2).
// The 1<<16 value is a power of two; we could use a
// larger power of 2 if we wanted to.
//
@@ -9428,7 +9653,6 @@ simdjson_unused simdjson_inline simdjson_result<number_type> get_number_type(con
// Our objective is accurate parsing (ULP of 0) at high speed.
template<typename W>
simdjson_inline error_code parse_number(const uint8_t *const src, W &writer) {
//
// Check for minus sign
//
@@ -10379,7 +10603,7 @@ SIMDJSON_NO_SANITIZE_UNDEFINED
// See issue https://github.com/simdjson/simdjson/issues/1965
SIMDJSON_NO_SANITIZE_MEMORY
simdjson_inline int trailing_zeroes(uint64_t input_num) {
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
#if SIMDJSON_REGULAR_VISUAL_STUDIO
unsigned long ret;
// Search the mask data from least significant bit (LSB)
// to the most significant bit (MSB) for a set bit (1).
@@ -10395,9 +10619,15 @@ simdjson_inline uint64_t clear_lowest_bit(uint64_t input_num) {
return input_num & (input_num-1);
}
// We sometimes call leading_zeroes on inputs that are zero,
// but the algorithms do not end up using the returned value.
// Sadly, sanitizers are not smart enough to figure it out.
// Applies only when SIMDJSON_PREFER_REVERSE_BITS is defined and true.
// (See below.)
SIMDJSON_NO_SANITIZE_UNDEFINED
/* result might be undefined when input_num is zero */
simdjson_inline int leading_zeroes(uint64_t input_num) {
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
#if SIMDJSON_REGULAR_VISUAL_STUDIO
unsigned long leading_zero = 0;
// Search the mask data from most significant bit (MSB)
// to least significant bit (LSB) for a set bit (1).
@@ -10450,7 +10680,7 @@ simdjson_inline uint64_t zero_leading_bit(uint64_t rev_bits, int leading_zeroes)
#endif
simdjson_inline bool add_overflow(uint64_t value1, uint64_t value2, uint64_t *result) {
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
#if SIMDJSON_REGULAR_VISUAL_STUDIO
*result = value1 + value2;
return *result < value1;
#else
@@ -10567,7 +10797,13 @@ simdjson_inline internal::value128 full_multiplication(uint64_t value1, uint64_t
} // namespace arm64
} // namespace simdjson
#ifndef SIMDJSON_SWAR_NUMBER_PARSING
#if SIMDJSON_IS_BIG_ENDIAN
#define SIMDJSON_SWAR_NUMBER_PARSING 0
#else
#define SIMDJSON_SWAR_NUMBER_PARSING 1
#endif
#endif
#endif // SIMDJSON_ARM64_NUMBERPARSING_DEFS_H
/* end file simdjson/arm64/numberparsing_defs.h */
@@ -10587,7 +10823,7 @@ namespace arm64 {
namespace {
namespace simd {
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
#if SIMDJSON_REGULAR_VISUAL_STUDIO
namespace {
// Start of private section with Visual Studio workaround
@@ -10696,7 +10932,7 @@ namespace {
// We return uint32_t instead of uint16_t because that seems to be more efficient for most
// purposes (cutting it down to uint16_t costs performance in some compilers).
simdjson_inline uint32_t to_bitmask() const {
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
#if SIMDJSON_REGULAR_VISUAL_STUDIO
const uint8x16_t bit_mask = simdjson_make_uint8x16_t(0x01, 0x02, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80,
0x01, 0x02, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80);
#else
@@ -10727,7 +10963,7 @@ namespace {
// Splat constructor
simdjson_inline simd8(uint8_t _value) : simd8(splat(_value)) {}
// Member-by-member initialization
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
#if SIMDJSON_REGULAR_VISUAL_STUDIO
simdjson_inline simd8(
uint8_t v0, uint8_t v1, uint8_t v2, uint8_t v3, uint8_t v4, uint8_t v5, uint8_t v6, uint8_t v7,
uint8_t v8, uint8_t v9, uint8_t v10, uint8_t v11, uint8_t v12, uint8_t v13, uint8_t v14, uint8_t v15
@@ -10821,7 +11057,7 @@ namespace {
uint64x2_t shufmask64 = {thintable_epi8[mask1], thintable_epi8[mask2]};
uint8x16_t shufmask = vreinterpretq_u8_u64(shufmask64);
// we increment by 0x08 the second half of the mask
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
#if SIMDJSON_REGULAR_VISUAL_STUDIO
uint8x16_t inc = simdjson_make_uint8x16_t(0, 0, 0, 0, 0, 0, 0, 0, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08);
#else
uint8x16_t inc = {0, 0, 0, 0, 0, 0, 0, 0, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08};
@@ -10851,7 +11087,7 @@ namespace {
uint8x8_t compactmask1 = vcreate_u8(thintable_epi8[mask1]);
uint8x8_t compactmask2 = vcreate_u8(thintable_epi8[mask2]);
// we increment by 0x08 the second half of the mask
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
#if SIMDJSON_REGULAR_VISUAL_STUDIO
uint8x8_t inc = simdjson_make_uint8x8_t(0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08);
#else
uint8x8_t inc = {0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08};
@@ -10903,7 +11139,7 @@ namespace {
// Array constructor
simdjson_inline simd8(const int8_t* values) : simd8(load(values)) {}
// Member-by-member initialization
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
#if SIMDJSON_REGULAR_VISUAL_STUDIO
simdjson_inline simd8(
int8_t v0, int8_t v1, int8_t v2, int8_t v3, int8_t v4, int8_t v5, int8_t v6, int8_t v7,
int8_t v8, int8_t v9, int8_t v10, int8_t v11, int8_t v12, int8_t v13, int8_t v14, int8_t v15
@@ -11024,7 +11260,7 @@ namespace {
}
simdjson_inline uint64_t to_bitmask() const {
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
#if SIMDJSON_REGULAR_VISUAL_STUDIO
const uint8x16_t bit_mask = simdjson_make_uint8x16_t(
0x01, 0x02, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80,
0x01, 0x02, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80
@@ -13977,6 +14213,7 @@ simdjson_warn_unused error_code dom_parser_implementation::stage2_next(dom::docu
return stage2::tape_builder::parse_document<true>(*this, _doc);
}
SIMDJSON_NO_SANITIZE_MEMORY
simdjson_warn_unused uint8_t *dom_parser_implementation::parse_string(const uint8_t *src, uint8_t *dst, bool allow_replacement) const noexcept {
return arm64::stringparsing::parse_string(src, dst, allow_replacement);
}
@@ -14115,8 +14352,14 @@ static_assert(sizeof(__m256i) <= simdjson::SIMDJSON_PADDING, "insufficient paddi
/* end file simdjson/haswell/intrinsics.h */
#if !SIMDJSON_CAN_ALWAYS_RUN_HASWELL
// We enable bmi2 only if LLVM/clang is used, because GCC may not
// make good use of it. See https://github.com/simdjson/simdjson/pull/2243
#if defined(__clang__)
SIMDJSON_TARGET_REGION("avx2,bmi,bmi2,pclmul,lzcnt,popcnt")
#else
SIMDJSON_TARGET_REGION("avx2,bmi,pclmul,lzcnt,popcnt")
#endif
#endif
/* including simdjson/haswell/bitmanipulation.h: #include "simdjson/haswell/bitmanipulation.h" */
/* begin file simdjson/haswell/bitmanipulation.h */
@@ -15333,7 +15576,7 @@ simdjson_inline bool compute_float_64(int64_t power, uint64_t i, bool negative,
// floor(log(5**power)/log(2))
//
// Note that this is not magic: 152170/(1<<16) is
// approximatively equal to log(5)/log(2).
// approximately equal to log(5)/log(2).
// The 1<<16 value is a power of two; we could use a
// larger power of 2 if we wanted to.
//
@@ -15770,7 +16013,6 @@ simdjson_unused simdjson_inline simdjson_result<number_type> get_number_type(con
// Our objective is accurate parsing (ULP of 0) at high speed.
template<typename W>
simdjson_inline error_code parse_number(const uint8_t *const src, W &writer) {
//
// Check for minus sign
//
@@ -16748,8 +16990,14 @@ static_assert(sizeof(__m256i) <= simdjson::SIMDJSON_PADDING, "insufficient paddi
/* end file simdjson/haswell/intrinsics.h */
#if !SIMDJSON_CAN_ALWAYS_RUN_HASWELL
// We enable bmi2 only if LLVM/clang is used, because GCC may not
// make good use of it. See https://github.com/simdjson/simdjson/pull/2243
#if defined(__clang__)
SIMDJSON_TARGET_REGION("avx2,bmi,bmi2,pclmul,lzcnt,popcnt")
#else
SIMDJSON_TARGET_REGION("avx2,bmi,pclmul,lzcnt,popcnt")
#endif
#endif
/* including simdjson/haswell/bitmanipulation.h: #include "simdjson/haswell/bitmanipulation.h" */
/* begin file simdjson/haswell/bitmanipulation.h */
@@ -20193,6 +20441,7 @@ simdjson_warn_unused error_code dom_parser_implementation::stage2_next(dom::docu
return stage2::tape_builder::parse_document<true>(*this, _doc);
}
SIMDJSON_NO_SANITIZE_MEMORY
simdjson_warn_unused uint8_t *dom_parser_implementation::parse_string(const uint8_t *src, uint8_t *dst, bool replacement_char) const noexcept {
return haswell::stringparsing::parse_string(src, dst, replacement_char);
}
@@ -20595,14 +20844,18 @@ namespace simd {
// Copies to 'output" all bytes corresponding to a 0 in the mask (interpreted as a bitset).
// Passing a 0 value for mask would be equivalent to writing out every byte to output.
// Only the first 32 - count_ones(mask) bytes of the result are significant but 32 bytes
// Only the first 64 - count_ones(mask) bytes of the result are significant but 64 bytes
// get written.
// Design consideration: it seems like a function with the
// signature simd8<L> compress(uint32_t mask) would be
// sensible, but the AVX ISA makes this kind of approach difficult.
template<typename L>
simdjson_inline void compress(uint64_t mask, L * output) const {
_mm512_mask_compressstoreu_epi8 (output,~mask,*this);
// we deliberately avoid _mm512_mask_compressstoreu_epi8 for portability
// (AMD Zen4 has terrible performance with it, it is effectively broken)
// _mm512_mask_compressstoreu_epi8 (output,~mask,*this);
__m512i compressed = _mm512_maskz_compress_epi8(~mask, *this);
_mm512_storeu_si512(output, compressed); // could use a mask
}
template<typename L>
@@ -21547,7 +21800,7 @@ simdjson_inline bool compute_float_64(int64_t power, uint64_t i, bool negative,
// floor(log(5**power)/log(2))
//
// Note that this is not magic: 152170/(1<<16) is
// approximatively equal to log(5)/log(2).
// approximately equal to log(5)/log(2).
// The 1<<16 value is a power of two; we could use a
// larger power of 2 if we wanted to.
//
@@ -21984,7 +22237,6 @@ simdjson_unused simdjson_inline simdjson_result<number_type> get_number_type(con
// Our objective is accurate parsing (ULP of 0) at high speed.
template<typename W>
simdjson_inline error_code parse_number(const uint8_t *const src, W &writer) {
//
// Check for minus sign
//
@@ -23226,14 +23478,18 @@ namespace simd {
// Copies to 'output" all bytes corresponding to a 0 in the mask (interpreted as a bitset).
// Passing a 0 value for mask would be equivalent to writing out every byte to output.
// Only the first 32 - count_ones(mask) bytes of the result are significant but 32 bytes
// Only the first 64 - count_ones(mask) bytes of the result are significant but 64 bytes
// get written.
// Design consideration: it seems like a function with the
// signature simd8<L> compress(uint32_t mask) would be
// sensible, but the AVX ISA makes this kind of approach difficult.
template<typename L>
simdjson_inline void compress(uint64_t mask, L * output) const {
_mm512_mask_compressstoreu_epi8 (output,~mask,*this);
// we deliberately avoid _mm512_mask_compressstoreu_epi8 for portability
// (AMD Zen4 has terrible performance with it, it is effectively broken)
// _mm512_mask_compressstoreu_epi8 (output,~mask,*this);
__m512i compressed = _mm512_maskz_compress_epi8(~mask, *this);
_mm512_storeu_si512(output, compressed); // could use a mask
}
template<typename L>
@@ -26448,6 +26704,7 @@ simdjson_warn_unused error_code dom_parser_implementation::stage2_next(dom::docu
return stage2::tape_builder::parse_document<true>(*this, _doc);
}
SIMDJSON_NO_SANITIZE_MEMORY
simdjson_warn_unused uint8_t *dom_parser_implementation::parse_string(const uint8_t *src, uint8_t *dst, bool replacement_char) const noexcept {
return icelake::stringparsing::parse_string(src, dst, replacement_char);
}
@@ -26750,7 +27007,13 @@ simdjson_inline internal::value128 full_multiplication(uint64_t value1, uint64_t
} // namespace ppc64
} // namespace simdjson
#ifndef SIMDJSON_SWAR_NUMBER_PARSING
#if SIMDJSON_IS_BIG_ENDIAN
#define SIMDJSON_SWAR_NUMBER_PARSING 0
#else
#define SIMDJSON_SWAR_NUMBER_PARSING 1
#endif
#endif
#endif // SIMDJSON_PPC64_NUMBERPARSING_DEFS_H
/* end file simdjson/ppc64/numberparsing_defs.h */
@@ -27917,7 +28180,7 @@ simdjson_inline bool compute_float_64(int64_t power, uint64_t i, bool negative,
// floor(log(5**power)/log(2))
//
// Note that this is not magic: 152170/(1<<16) is
// approximatively equal to log(5)/log(2).
// approximately equal to log(5)/log(2).
// The 1<<16 value is a power of two; we could use a
// larger power of 2 if we wanted to.
//
@@ -28354,7 +28617,6 @@ simdjson_unused simdjson_inline simdjson_result<number_type> get_number_type(con
// Our objective is accurate parsing (ULP of 0) at high speed.
template<typename W>
simdjson_inline error_code parse_number(const uint8_t *const src, W &writer) {
//
// Check for minus sign
//
@@ -29494,7 +29756,13 @@ simdjson_inline internal::value128 full_multiplication(uint64_t value1, uint64_t
} // namespace ppc64
} // namespace simdjson
#ifndef SIMDJSON_SWAR_NUMBER_PARSING
#if SIMDJSON_IS_BIG_ENDIAN
#define SIMDJSON_SWAR_NUMBER_PARSING 0
#else
#define SIMDJSON_SWAR_NUMBER_PARSING 1
#endif
#endif
#endif // SIMDJSON_PPC64_NUMBERPARSING_DEFS_H
/* end file simdjson/ppc64/numberparsing_defs.h */
@@ -32861,6 +33129,7 @@ simdjson_warn_unused error_code dom_parser_implementation::stage2_next(dom::docu
return stage2::tape_builder::parse_document<true>(*this, _doc);
}
SIMDJSON_NO_SANITIZE_MEMORY
simdjson_warn_unused uint8_t *dom_parser_implementation::parse_string(const uint8_t *src, uint8_t *dst, bool replacement_char) const noexcept {
return ppc64::stringparsing::parse_string(src, dst, replacement_char);
}
@@ -34653,7 +34922,7 @@ simdjson_inline bool compute_float_64(int64_t power, uint64_t i, bool negative,
// floor(log(5**power)/log(2))
//
// Note that this is not magic: 152170/(1<<16) is
// approximatively equal to log(5)/log(2).
// approximately equal to log(5)/log(2).
// The 1<<16 value is a power of two; we could use a
// larger power of 2 if we wanted to.
//
@@ -35090,7 +35359,6 @@ simdjson_unused simdjson_inline simdjson_result<number_type> get_number_type(con
// Our objective is accurate parsing (ULP of 0) at high speed.
template<typename W>
simdjson_inline error_code parse_number(const uint8_t *const src, W &writer) {
//
// Check for minus sign
//
@@ -39950,6 +40218,7 @@ simdjson_warn_unused error_code dom_parser_implementation::stage2_next(dom::docu
return stage2::tape_builder::parse_document<true>(*this, _doc);
}
SIMDJSON_NO_SANITIZE_MEMORY
simdjson_warn_unused uint8_t *dom_parser_implementation::parse_string(const uint8_t *src, uint8_t *dst, bool replacement_char) const noexcept {
return westmere::stringparsing::parse_string(src, dst, replacement_char);
}
@@ -40176,7 +40445,13 @@ simdjson_inline internal::value128 full_multiplication(uint64_t value1, uint64_t
} // namespace lsx
} // namespace simdjson
#ifndef SIMDJSON_SWAR_NUMBER_PARSING
#if SIMDJSON_IS_BIG_ENDIAN
#define SIMDJSON_SWAR_NUMBER_PARSING 0
#else
#define SIMDJSON_SWAR_NUMBER_PARSING 1
#endif
#endif
#endif // SIMDJSON_LSX_NUMBERPARSING_DEFS_H
/* end file simdjson/lsx/numberparsing_defs.h */
@@ -41213,7 +41488,7 @@ simdjson_inline bool compute_float_64(int64_t power, uint64_t i, bool negative,
// floor(log(5**power)/log(2))
//
// Note that this is not magic: 152170/(1<<16) is
// approximatively equal to log(5)/log(2).
// approximately equal to log(5)/log(2).
// The 1<<16 value is a power of two; we could use a
// larger power of 2 if we wanted to.
//
@@ -41650,7 +41925,6 @@ simdjson_unused simdjson_inline simdjson_result<number_type> get_number_type(con
// Our objective is accurate parsing (ULP of 0) at high speed.
template<typename W>
simdjson_inline error_code parse_number(const uint8_t *const src, W &writer) {
//
// Check for minus sign
//
@@ -42705,7 +42979,13 @@ simdjson_inline internal::value128 full_multiplication(uint64_t value1, uint64_t
} // namespace lsx
} // namespace simdjson
#ifndef SIMDJSON_SWAR_NUMBER_PARSING
#if SIMDJSON_IS_BIG_ENDIAN
#define SIMDJSON_SWAR_NUMBER_PARSING 0
#else
#define SIMDJSON_SWAR_NUMBER_PARSING 1
#endif
#endif
#endif // SIMDJSON_LSX_NUMBERPARSING_DEFS_H
/* end file simdjson/lsx/numberparsing_defs.h */
@@ -45936,6 +46216,7 @@ simdjson_warn_unused error_code dom_parser_implementation::stage2_next(dom::docu
return stage2::tape_builder::parse_document<true>(*this, _doc);
}
SIMDJSON_NO_SANITIZE_MEMORY
simdjson_warn_unused uint8_t *dom_parser_implementation::parse_string(const uint8_t *src, uint8_t *dst, bool allow_replacement) const noexcept {
return lsx::stringparsing::parse_string(src, dst, allow_replacement);
}
@@ -46159,7 +46440,13 @@ simdjson_inline internal::value128 full_multiplication(uint64_t value1, uint64_t
} // namespace lasx
} // namespace simdjson
#ifndef SIMDJSON_SWAR_NUMBER_PARSING
#if SIMDJSON_IS_BIG_ENDIAN
#define SIMDJSON_SWAR_NUMBER_PARSING 0
#else
#define SIMDJSON_SWAR_NUMBER_PARSING 1
#endif
#endif
#endif // SIMDJSON_LASX_NUMBERPARSING_DEFS_H
/* end file simdjson/lasx/numberparsing_defs.h */
@@ -47212,7 +47499,7 @@ simdjson_inline bool compute_float_64(int64_t power, uint64_t i, bool negative,
// floor(log(5**power)/log(2))
//
// Note that this is not magic: 152170/(1<<16) is
// approximatively equal to log(5)/log(2).
// approximately equal to log(5)/log(2).
// The 1<<16 value is a power of two; we could use a
// larger power of 2 if we wanted to.
//
@@ -47649,7 +47936,6 @@ simdjson_unused simdjson_inline simdjson_result<number_type> get_number_type(con
// Our objective is accurate parsing (ULP of 0) at high speed.
template<typename W>
simdjson_inline error_code parse_number(const uint8_t *const src, W &writer) {
//
// Check for minus sign
//
@@ -48704,7 +48990,13 @@ simdjson_inline internal::value128 full_multiplication(uint64_t value1, uint64_t
} // namespace lasx
} // namespace simdjson
#ifndef SIMDJSON_SWAR_NUMBER_PARSING
#if SIMDJSON_IS_BIG_ENDIAN
#define SIMDJSON_SWAR_NUMBER_PARSING 0
#else
#define SIMDJSON_SWAR_NUMBER_PARSING 1
#endif
#endif
#endif // SIMDJSON_LASX_NUMBERPARSING_DEFS_H
/* end file simdjson/lasx/numberparsing_defs.h */
@@ -51947,6 +52239,7 @@ simdjson_warn_unused error_code dom_parser_implementation::stage2_next(dom::docu
return stage2::tape_builder::parse_document<true>(*this, _doc);
}
SIMDJSON_NO_SANITIZE_MEMORY
simdjson_warn_unused uint8_t *dom_parser_implementation::parse_string(const uint8_t *src, uint8_t *dst, bool allow_replacement) const noexcept {
return lasx::stringparsing::parse_string(src, dst, allow_replacement);
}
@@ -52188,7 +52481,13 @@ simdjson_inline internal::value128 full_multiplication(uint64_t value1, uint64_t
} // namespace fallback
} // namespace simdjson
#ifndef SIMDJSON_SWAR_NUMBER_PARSING
#if SIMDJSON_IS_BIG_ENDIAN
#define SIMDJSON_SWAR_NUMBER_PARSING 0
#else
#define SIMDJSON_SWAR_NUMBER_PARSING 1
#endif
#endif
#endif // SIMDJSON_FALLBACK_NUMBERPARSING_DEFS_H
/* end file simdjson/fallback/numberparsing_defs.h */
@@ -52810,7 +53109,7 @@ simdjson_inline bool compute_float_64(int64_t power, uint64_t i, bool negative,
// floor(log(5**power)/log(2))
//
// Note that this is not magic: 152170/(1<<16) is
// approximatively equal to log(5)/log(2).
// approximately equal to log(5)/log(2).
// The 1<<16 value is a power of two; we could use a
// larger power of 2 if we wanted to.
//
@@ -53247,7 +53546,6 @@ simdjson_unused simdjson_inline simdjson_result<number_type> get_number_type(con
// Our objective is accurate parsing (ULP of 0) at high speed.
template<typename W>
simdjson_inline error_code parse_number(const uint8_t *const src, W &writer) {
//
// Check for minus sign
//
@@ -54322,7 +54620,13 @@ simdjson_inline internal::value128 full_multiplication(uint64_t value1, uint64_t
} // namespace fallback
} // namespace simdjson
#ifndef SIMDJSON_SWAR_NUMBER_PARSING
#if SIMDJSON_IS_BIG_ENDIAN
#define SIMDJSON_SWAR_NUMBER_PARSING 0
#else
#define SIMDJSON_SWAR_NUMBER_PARSING 1
#endif
#endif
#endif // SIMDJSON_FALLBACK_NUMBERPARSING_DEFS_H
/* end file simdjson/fallback/numberparsing_defs.h */
@@ -55909,6 +56213,7 @@ simdjson_warn_unused error_code dom_parser_implementation::stage2_next(dom::docu
return stage2::tape_builder::parse_document<true>(*this, _doc);
}
SIMDJSON_NO_SANITIZE_MEMORY
simdjson_warn_unused uint8_t *dom_parser_implementation::parse_string(const uint8_t *src, uint8_t *dst, bool replacement_char) const noexcept {
return fallback::stringparsing::parse_string(src, dst, replacement_char);
}
+10535 -5447
View File
File diff suppressed because it is too large Load Diff
+1
View File
@@ -150,6 +150,7 @@ simdjson_warn_unused error_code dom_parser_implementation::stage2_next(dom::docu
return stage2::tape_builder::parse_document<true>(*this, _doc);
}
SIMDJSON_NO_SANITIZE_MEMORY
simdjson_warn_unused uint8_t *dom_parser_implementation::parse_string(const uint8_t *src, uint8_t *dst, bool allow_replacement) const noexcept {
return arm64::stringparsing::parse_string(src, dst, allow_replacement);
}
+1
View File
@@ -388,6 +388,7 @@ simdjson_warn_unused error_code dom_parser_implementation::stage2_next(dom::docu
return stage2::tape_builder::parse_document<true>(*this, _doc);
}
SIMDJSON_NO_SANITIZE_MEMORY
simdjson_warn_unused uint8_t *dom_parser_implementation::parse_string(const uint8_t *src, uint8_t *dst, bool replacement_char) const noexcept {
return fallback::stringparsing::parse_string(src, dst, replacement_char);
}
+1
View File
@@ -147,6 +147,7 @@ simdjson_warn_unused error_code dom_parser_implementation::stage2_next(dom::docu
return stage2::tape_builder::parse_document<true>(*this, _doc);
}
SIMDJSON_NO_SANITIZE_MEMORY
simdjson_warn_unused uint8_t *dom_parser_implementation::parse_string(const uint8_t *src, uint8_t *dst, bool replacement_char) const noexcept {
return haswell::stringparsing::parse_string(src, dst, replacement_char);
}
+1
View File
@@ -193,6 +193,7 @@ simdjson_warn_unused error_code dom_parser_implementation::stage2_next(dom::docu
return stage2::tape_builder::parse_document<true>(*this, _doc);
}
SIMDJSON_NO_SANITIZE_MEMORY
simdjson_warn_unused uint8_t *dom_parser_implementation::parse_string(const uint8_t *src, uint8_t *dst, bool replacement_char) const noexcept {
return icelake::stringparsing::parse_string(src, dst, replacement_char);
}
+2 -2
View File
@@ -11,7 +11,7 @@ namespace internal {
{ SUCCESS, "SUCCESS: No error" },
{ CAPACITY, "CAPACITY: This parser can't support a document that big" },
{ MEMALLOC, "MEMALLOC: Error allocating memory, we're most likely out of memory" },
{ TAPE_ERROR, "TAPE_ERROR: The JSON document has an improper structure: missing or superfluous commas, braces, missing keys, etc." },
{ TAPE_ERROR, "TAPE_ERROR: The JSON document has an improper structure: missing or superfluous commas, braces, missing keys, etc. This is a fatal and unrecoverable error." },
{ DEPTH_ERROR, "DEPTH_ERROR: The JSON document was too deep (too many nested objects and arrays)" },
{ STRING_ERROR, "STRING_ERROR: Problem while parsing a string" },
{ T_ATOM_ERROR, "T_ATOM_ERROR: Problem while parsing an atom starting with the letter 't'" },
@@ -36,7 +36,7 @@ namespace internal {
{ PARSER_IN_USE, "PARSER_IN_USE: Cannot parse a new document while a document is still in use." },
{ OUT_OF_ORDER_ITERATION, "OUT_OF_ORDER_ITERATION: Objects and arrays can only be iterated when they are first encountered." },
{ INSUFFICIENT_PADDING, "INSUFFICIENT_PADDING: simdjson requires the input JSON string to have at least SIMDJSON_PADDING extra bytes allocated, beyond the string's length. Consider using the simdjson::padded_string class if needed." },
{ INCOMPLETE_ARRAY_OR_OBJECT, "INCOMPLETE_ARRAY_OR_OBJECT: JSON document ended early in the middle of an object or array." },
{ INCOMPLETE_ARRAY_OR_OBJECT, "INCOMPLETE_ARRAY_OR_OBJECT: JSON document ended early in the middle of an object or array. This is a fatal and unrecoverable error." },
{ SCALAR_DOCUMENT_AS_VALUE, "SCALAR_DOCUMENT_AS_VALUE: A JSON document made of a scalar (number, Boolean, null or string) is treated as a value. Use get_bool(), get_double(), etc. on the document instead. "},
{ OUT_OF_BOUNDS, "OUT_OF_BOUNDS: Attempt to access location outside of document."},
{ TRAILING_CONTENT, "TRAILING_CONTENT: Unexpected trailing content in the JSON input."}
+1
View File
@@ -110,6 +110,7 @@ simdjson_warn_unused error_code dom_parser_implementation::stage2_next(dom::docu
return stage2::tape_builder::parse_document<true>(*this, _doc);
}
SIMDJSON_NO_SANITIZE_MEMORY
simdjson_warn_unused uint8_t *dom_parser_implementation::parse_string(const uint8_t *src, uint8_t *dst, bool allow_replacement) const noexcept {
return lasx::stringparsing::parse_string(src, dst, allow_replacement);
}
+1
View File
@@ -114,6 +114,7 @@ simdjson_warn_unused error_code dom_parser_implementation::stage2_next(dom::docu
return stage2::tape_builder::parse_document<true>(*this, _doc);
}
SIMDJSON_NO_SANITIZE_MEMORY
simdjson_warn_unused uint8_t *dom_parser_implementation::parse_string(const uint8_t *src, uint8_t *dst, bool allow_replacement) const noexcept {
return lsx::stringparsing::parse_string(src, dst, allow_replacement);
}
+1
View File
@@ -120,6 +120,7 @@ simdjson_warn_unused error_code dom_parser_implementation::stage2_next(dom::docu
return stage2::tape_builder::parse_document<true>(*this, _doc);
}
SIMDJSON_NO_SANITIZE_MEMORY
simdjson_warn_unused uint8_t *dom_parser_implementation::parse_string(const uint8_t *src, uint8_t *dst, bool replacement_char) const noexcept {
return ppc64::stringparsing::parse_string(src, dst, replacement_char);
}
+1
View File
@@ -152,6 +152,7 @@ simdjson_warn_unused error_code dom_parser_implementation::stage2_next(dom::docu
return stage2::tape_builder::parse_document<true>(*this, _doc);
}
SIMDJSON_NO_SANITIZE_MEMORY
simdjson_warn_unused uint8_t *dom_parser_implementation::parse_string(const uint8_t *src, uint8_t *dst, bool replacement_char) const noexcept {
return westmere::stringparsing::parse_string(src, dst, replacement_char);
}
+1
View File
@@ -12,6 +12,7 @@ add_cpp_test(errortests LABELS dom acceptance per_implementation
add_cpp_test(extracting_values_example LABELS dom acceptance per_implementation)
add_cpp_test(integer_tests LABELS dom acceptance per_implementation)
add_cpp_test(jsoncheck LABELS dom acceptance per_implementation)
add_cpp_test(json_path_tests LABELS dom acceptance per_implementation)
add_cpp_test(minefieldcheck LABELS dom acceptance per_implementation)
add_cpp_test(numberparsingcheck LABELS dom acceptance per_implementation) # https://tools.ietf.org/html/rfc6901
add_cpp_test(parse_many_test LABELS dom acceptance per_implementation)
+350
View File
@@ -0,0 +1,350 @@
/**
* refer to pathcheck.cpp
*/
#include <iostream>
#include <string>
using namespace std::string_literals;
#include "simdjson.h"
#include "test_macros.h"
// we define our own asserts to get around NDEBUG
#ifndef ASSERT
#define ASSERT(x) \
{ \
if (!(x)) { \
std::cerr << "Failed assertion " << #x << std::endl; \
return false; \
} \
}
#endif
using namespace simdjson;
bool demo() {
#if SIMDJSON_EXCEPTIONS
std::cout << "demo test" << std::endl;
auto cars_json = R"( [
{ "make": "Toyota", "model": "Camry", "year": 2018, "tire_pressure": [ 40.1, 39.9, 37.7, 40.4 ] },
{ "make": "Kia", "model": "Soul", "year": 2012, "tire_pressure": [ 30.1, 31.0, 28.6, 28.7 ] },
{ "make": "Toyota", "model": "Tercel", "year": 1999, "tire_pressure": [ 29.8, 30.0, 30.2, 30.5 ] }
] )"_padded;
dom::parser parser;
dom::element cars = parser.parse(cars_json);
double x = cars.at_path("$[0].tire_pressure[1]");
if (x != 39.9)
return false;
// Iterating through an array of objects
std::vector<double> measured;
for (dom::element car_element : cars) {
dom::object car;
simdjson::error_code error;
if ((error = car_element.get(car))) {
std::cerr << error << std::endl;
return false;
}
double x3 = car.at_path("$.tire_pressure[1]");
measured.push_back(x3);
}
std::vector<double> expected = {39.9, 31, 30};
if (measured != expected) {
return false;
}
#endif
return true;
}
const padded_string TEST_JSON = R"(
{
"/~01abc": [
0,
{
"\\\" 0": [
"value0",
"value1"
]
}
],
"0": "0 ok",
"01": "01 ok",
"": "empty ok",
"arr": []
}
)"_padded;
const padded_string TEST_RFC_JSON = R"(
{
"foo": ["bar", "baz"],
"": 0,
"a/b": 1,
"c%d": 2,
"e^f": 3,
"g|h": 4,
"i\\j": 5,
"k\"l": 6,
" ": 7,
"m~n": 8
}
)"_padded;
bool run_success_test(const padded_string &source, const char *json_path,
std::string_view expected_value) {
std::cout << "Running successful JSONPath test '" << json_path << "' ..."
<< std::endl;
dom::parser parser;
dom::element doc;
auto error = parser.parse(source).get(doc);
if (error) {
std::cerr << "cannot parse: " << error << std::endl;
return false;
}
dom::element answer;
error = doc.at_path(json_path).get(answer);
if (error) {
std::cerr << "cannot access pointer: " << error << std::endl;
return false;
}
std::string str_answer = simdjson::minify(answer);
if (str_answer != expected_value) {
std::cerr << "They differ!!!" << std::endl;
std::cerr << " found '" << str_answer << "'" << std::endl;
std::cerr << " expected '" << expected_value << "'" << std::endl;
}
ASSERT_EQUAL(str_answer, expected_value);
return true;
}
bool run_failure_test(const padded_string &source, const char *json_path,
error_code expected_error) {
std::cout << "Running invalid JSONPath test '" << json_path << "' ..."
<< std::endl;
dom::parser parser;
ASSERT_ERROR(parser.parse(source).at_path(json_path).error(), expected_error);
return true;
}
bool demo_relative_path() {
TEST_START();
auto cars_json = R"( [
{ "make": "Toyota", "model": "Camry", "year": 2018, "tire_pressure": [ 40.1, 39.9, 37.7, 40.4 ] },
{ "make": "Kia", "model": "Soul", "year": 2012, "tire_pressure": [ 30.1, 31.0, 28.6, 28.7 ] },
{ "make": "Toyota", "model": "Tercel", "year": 1999, "tire_pressure": [ 29.8, 30.0, 30.2, 30.5 ] }
] )"_padded;
dom::parser parser;
dom::element cars;
std::vector<double> measured;
auto error = parser.parse(cars_json).get(cars);
if (error) {
std::cerr << "cannot parse: " << error << std::endl;
return false;
}
dom::array cars_array;
error = cars.get(cars_array);
if (error) {
std::cerr << "cannot get array: " << error << std::endl;
return false;
}
for (auto car_element : cars_array) {
double x;
ASSERT_SUCCESS(car_element.at_path(".tire_pressure[1]").get(x));
measured.push_back(x);
}
std::vector<double> expected = {39.9, 31, 30};
if (measured != expected) {
return false;
}
TEST_SUCCEED();
}
bool many_json_paths() {
TEST_START();
auto cars_json = R"( [
{ "make": "Toyota", "model": "Camry", "year": 2018, "tire_pressure": [ 40.1, 39.9, 37.7, 40.4 ] },
{ "make": "Kia", "model": "Soul", "year": 2012, "tire_pressure": [ 30.1, 31.0, 28.6, 28.7 ] },
{ "make": "Toyota", "model": "Tercel", "year": 1999, "tire_pressure": [ 29.8, 30.0, 30.2, 30.5 ] }
] )"_padded;
dom::parser parser;
dom::element cars;
std::vector<double> measured;
ASSERT_SUCCESS(parser.parse(cars_json).get(cars));
for (int i = 0; i < 3; i++) {
double x;
std::string json_path = std::string("$[") + std::to_string(i) +
std::string("].tire_pressure[1]");
ASSERT_SUCCESS(cars.at_path(json_path).get(x));
measured.push_back(x);
}
std::vector<double> expected = {39.9, 31, 30};
if (measured != expected) {
return false;
}
TEST_SUCCEED();
}
bool many_json_paths_object_array() {
TEST_START();
auto dogcatpotato =
R"( { "dog" : [1,2,3], "cat" : [5, 6, 7], "potato" : [1234]})"_padded;
dom::parser parser;
dom::element doc;
ASSERT_SUCCESS(parser.parse(dogcatpotato).get(doc));
dom::object obj;
ASSERT_SUCCESS(doc.get_object().get(obj));
int64_t x;
ASSERT_SUCCESS(obj.at_path("$.dog[1]").get(x));
ASSERT_EQUAL(x, 2);
ASSERT_SUCCESS(obj.at_path("$.potato[0]").get(x));
ASSERT_EQUAL(x, 1234);
TEST_SUCCEED();
}
bool many_json_paths_object() {
TEST_START();
auto cfoofoo2 =
R"( { "c" :{ "foo": { "a": [ 10, 20, 30 ] }}, "d": { "foo2": { "a": [ 10, 20, 30 ] }} , "e": 120 })"_padded;
dom::parser parser;
dom::element doc;
ASSERT_SUCCESS(parser.parse(cfoofoo2).get(doc));
dom::object obj;
ASSERT_SUCCESS(doc.get_object().get(obj));
int64_t x;
ASSERT_SUCCESS(obj.at_path("$.c.foo.a[1]").get(x));
ASSERT_EQUAL(x, 20);
ASSERT_SUCCESS(obj.at_path("$.d.foo2.a.2").get(x));
ASSERT_EQUAL(x, 30);
ASSERT_SUCCESS(obj.at_path("$.e").get(x));
ASSERT_EQUAL(x, 120);
TEST_SUCCEED();
}
bool many_json_paths_array() {
TEST_START();
auto cfoofoo2 =
R"( [ 111, 2, 3, { "foo": { "a": [ 10, 20, 33 ] }}, { "foo2": { "a": [ 10, 20, 30 ] }}, 1001 ])"_padded;
dom::parser parser;
dom::element doc;
ASSERT_SUCCESS(parser.parse(cfoofoo2).get(doc));
dom::array arr;
ASSERT_SUCCESS(doc.get_array().get(arr));
int64_t x;
ASSERT_SUCCESS(arr.at_path("$[3].foo.a[1]").get(x));
ASSERT_EQUAL(x, 20);
TEST_SUCCEED();
}
struct car_type {
std::string make;
std::string model;
uint64_t year;
std::vector<double> tire_pressure;
car_type(std::string_view _make, std::string_view _model, uint64_t _year,
std::vector<double> &&_tire_pressure)
: make{_make}, model{_model}, year(_year), tire_pressure(_tire_pressure) {
}
};
bool json_path_invalidation() {
TEST_START();
auto cars_json = R"( [
{ "make": "Toyota", "model": "Camry", "year": 2018, "tire_pressure": [ 40.1, 39.9, 37.7, 40.4 ] },
{ "make": "Kia", "model": "Soul", "year": 2012, "tire_pressure": [ 30.1, 31.0, 28.6, 28.7 ] },
{ "make": "Toyota", "model": "Tercel", "year": 1999, "tire_pressure": [ 29.8, 30.0, 30.2, 30.5 ] }
] )"_padded;
dom::parser parser;
dom::element cars;
std::vector<double> measured;
ASSERT_SUCCESS(parser.parse(cars_json).get(cars));
std::vector<car_type> content;
for (int i = 0; i < 3; i++) {
dom::object obj;
std::string json_path =
std::string("$[") + std::to_string(i) + std::string("]");
// Each successive at_path call invalidates
// previously parsed values, strings, objects and array.
ASSERT_SUCCESS(cars.at_path(json_path).get(obj));
// We materialize the object.
std::string_view make;
ASSERT_SUCCESS(obj["make"].get(make));
std::string_view model;
ASSERT_SUCCESS(obj["model"].get(model));
uint64_t year;
ASSERT_SUCCESS(obj["year"].get(year));
// We materialize the array.
dom::array arr;
ASSERT_SUCCESS(obj["tire_pressure"].get(arr));
std::vector<double> values;
for (auto x : arr) {
double value_double;
ASSERT_SUCCESS(x.get(value_double));
values.push_back(value_double);
}
content.emplace_back(make, model, year, std::move(values));
}
std::string expected[] = {"Toyota", "Kia", "Toyota"};
int i = 0;
for (car_type c : content) {
std::cout << c.make << " " << c.model << " " << c.year << "\n";
ASSERT_EQUAL(expected[i++], c.make);
}
TEST_SUCCEED();
}
// for 0.5 version and following (standard compliant)
bool modern_support() {
#if SIMDJSON_EXCEPTIONS
std::cout << "modern test" << std::endl;
auto example_json = R"({"key": "value", "array": [0, 1, 2]})"_padded;
dom::parser parser;
dom::element example = parser.parse(example_json);
std::string_view value_str = example.at_path("$.key");
ASSERT_EQUAL(value_str, "value");
int64_t array0 = example.at_path("$.array[0]");
ASSERT_EQUAL(array0, 0);
array0 = example.at_path("$.array").at_path("$[0]");
ASSERT_EQUAL(array0, 0);
ASSERT_ERROR(example.at_path("$.no_such_key").error(), NO_SUCH_FIELD);
ASSERT_ERROR(example.at_path("$.array[9]").error(), INDEX_OUT_OF_BOUNDS);
ASSERT_ERROR(example.at_path("$.array.not_a_num").error(), INCORRECT_TYPE);
ASSERT_ERROR(example.at_path("$.array.").error(), INVALID_JSON_POINTER);
#endif
return true;
}
int main() {
if (true && demo() && modern_support() &&
run_success_test(TEST_RFC_JSON, "$.foo", "[\"bar\",\"baz\"]") &&
run_success_test(TEST_RFC_JSON, "$.foo[0]", "\"bar\"") &&
run_success_test(TEST_RFC_JSON, "$.", "0") &&
run_success_test(TEST_RFC_JSON, "$.a/b", "1") &&
run_success_test(TEST_RFC_JSON, "$.c%d", "2") &&
run_success_test(TEST_RFC_JSON, "$.e^f", "3") &&
run_success_test(TEST_RFC_JSON, "$.g|h", "4") &&
run_success_test(TEST_RFC_JSON, "$.i\\j", "5") &&
run_success_test(TEST_RFC_JSON, "$.k\"l", "6") &&
run_success_test(TEST_RFC_JSON, "$. ", "7") &&
run_success_test(TEST_RFC_JSON, "$.m~n", "8") &&
run_success_test(TEST_JSON, "$./~01abc",
R"([0,{"\\\" 0":["value0","value1"]}])") &&
run_success_test(TEST_JSON, "$./~01abc[1]",
R"({"\\\" 0":["value0","value1"]})") &&
run_success_test(TEST_JSON, "$./~01abc[1].\\\" 0",
R"(["value0","value1"])") &&
run_success_test(TEST_JSON, "$.arr", R"([])") // get array
&&
run_failure_test(TEST_JSON, R"($./~01abc[1].\\\" 0[2])", NO_SUCH_FIELD) &&
run_failure_test(TEST_JSON, "$.arr[0]", INDEX_OUT_OF_BOUNDS) &&
run_failure_test(TEST_JSON, "/~01abc", INVALID_JSON_POINTER) &&
run_failure_test(TEST_JSON, ".~1abc", NO_SUCH_FIELD) &&
run_failure_test(TEST_JSON, "./~01abc.01", INVALID_JSON_POINTER) &&
run_failure_test(TEST_JSON, "./~01abc.", INVALID_JSON_POINTER) &&
run_failure_test(TEST_JSON, "./~01abc.-", INDEX_OUT_OF_BOUNDS)) {
std::cout << "Success!" << std::endl;
return 0;
} else {
std::cerr << "Failed!" << std::endl;
return 1;
}
}
+45
View File
@@ -461,7 +461,52 @@ void parse_documentation_lowlevel() {
(void)element;
}
void simplepad() {
std::string json = "[1]";
dom::parser parser;
dom::element doc;
auto error = parser.parse(simdjson::pad(json)).get(doc);
if(error) { exit(-1); }
}
void jsondollar() {
dom::parser parser;
auto json = R"( { "c" :{ "foo": { "a": [ 10, 20, 30 ] }}, "d": { "foo2": { "a": [ 10, 20, 30 ] }} , "e": 120 })"_padded;
dom::element doc;
auto error = parser.parse(json).get(doc);
if(error) { exit(-1); }
dom::object obj;
error = doc.get_object().get(obj);
if(error) { exit(-1); }
int64_t x = 0; // initialization to silence unwarranted compiler warning
error = obj.at_path("$[3].foo.a[1]").get(x);
if(error) { exit(-1); }
if(x != 20) { exit(-1); }
x = obj.at_path("$.d.foo2.a.2");
if(x != 30) { exit(-1); }
if(error) { exit(-1); }
}
void jsonpath() {
auto cars_json = R"( [
{ "make": "Toyota", "model": "Camry", "year": 2018, "tire_pressure": [ 40.1, 39.9, 37.7, 40.4 ] },
{ "make": "Kia", "model": "Soul", "year": 2012, "tire_pressure": [ 30.1, 31.0, 28.6, 28.7 ] },
{ "make": "Toyota", "model": "Tercel", "year": 1999, "tire_pressure": [ 29.8, 30.0, 30.2, 30.5 ] }
] )"_padded;
dom::parser parser;
dom::element doc;
auto error = parser.parse(cars_json).get(doc);
if(error) { exit(-1); }
double p = 0.0; // initialization to silence unwarranted compiler warning
error = doc.at_path("[0].tire_pressure[1]").get(p);
if(error) { exit(-1); }
if(p != 39.9) { exit(-1); }
}
int main() {
simplepad();
jsonpath();
jsondollar();
basics_dom_1();
basics_dom_2();
basics_dom_3();
+31 -26
View File
@@ -2,32 +2,37 @@
link_libraries(simdjson)
include_directories(..)
add_subdirectory(compilation_failure_tests)
add_cpp_test(ondemand_log_tests LABELS ondemand acceptance per_implementation)
add_cpp_test(ondemand_log_error_tests LABELS ondemand acceptance per_implementation)
add_cpp_test(ondemand_tostring_tests LABELS ondemand acceptance per_implementation)
add_cpp_test(ondemand_active_tests LABELS ondemand acceptance per_implementation)
add_cpp_test(ondemand_array_tests LABELS ondemand acceptance per_implementation)
add_cpp_test(ondemand_array_error_tests LABELS ondemand acceptance per_implementation)
add_cpp_test(ondemand_compilation_tests LABELS ondemand acceptance per_implementation)
add_cpp_test(ondemand_document_stream_tests LABELS ondemand acceptance per_implementation)
add_cpp_test(ondemand_error_tests LABELS ondemand acceptance per_implementation)
add_cpp_test(ondemand_error_location_tests LABELS ondemand acceptance per_implementation)
add_cpp_test(ondemand_json_pointer_tests LABELS ondemand acceptance per_implementation)
add_cpp_test(ondemand_json_path_tests LABELS ondemand acceptance per_implementation)
add_cpp_test(ondemand_key_string_tests LABELS ondemand acceptance per_implementation)
add_cpp_test(ondemand_misc_tests LABELS ondemand acceptance per_implementation)
add_cpp_test(ondemand_number_tests LABELS ondemand acceptance per_implementation)
add_cpp_test(ondemand_number_in_string_tests LABELS ondemand acceptance per_implementation)
add_cpp_test(ondemand_object_tests LABELS ondemand acceptance per_implementation)
add_cpp_test(ondemand_object_error_tests LABELS ondemand acceptance per_implementation)
add_cpp_test(ondemand_ordering_tests LABELS ondemand acceptance per_implementation)
add_cpp_test(ondemand_parse_api_tests LABELS ondemand acceptance per_implementation)
add_cpp_test(ondemand_readme_examples LABELS ondemand acceptance per_implementation)
add_cpp_test(ondemand_scalar_tests LABELS ondemand acceptance per_implementation)
add_cpp_test(ondemand_to_string LABELS ondemand acceptance per_implementation)
add_cpp_test(ondemand_twitter_tests LABELS ondemand acceptance per_implementation)
add_cpp_test(ondemand_wrong_type_error_tests LABELS ondemand acceptance per_implementation)
add_cpp_test(ondemand_iterate_many_csv LABELS ondemand acceptance per_implementation)
add_cpp_test(ondemand_car_tag_invoke_deserialization LABELS ondemand acceptance per_implementation)
add_cpp_test(ondemand_car_deserialization LABELS ondemand acceptance per_implementation)
add_cpp_test(ondemand_log_tests LABELS ondemand acceptance per_implementation)
add_cpp_test(ondemand_log_error_tests LABELS ondemand acceptance per_implementation)
add_cpp_test(ondemand_tostring_tests LABELS ondemand acceptance per_implementation)
add_cpp_test(ondemand_active_tests LABELS ondemand acceptance per_implementation)
add_cpp_test(ondemand_array_tests LABELS ondemand acceptance per_implementation)
add_cpp_test(ondemand_array_error_tests LABELS ondemand acceptance per_implementation)
add_cpp_test(ondemand_compilation_tests LABELS ondemand acceptance per_implementation)
add_cpp_test(ondemand_document_stream_tests LABELS ondemand acceptance per_implementation)
add_cpp_test(ondemand_error_tests LABELS ondemand acceptance per_implementation)
add_cpp_test(ondemand_error_location_tests LABELS ondemand acceptance per_implementation)
add_cpp_test(ondemand_json_pointer_tests LABELS ondemand acceptance per_implementation)
add_cpp_test(ondemand_json_path_tests LABELS ondemand acceptance per_implementation)
add_cpp_test(ondemand_key_string_tests LABELS ondemand acceptance per_implementation)
add_cpp_test(ondemand_misc_tests LABELS ondemand acceptance per_implementation)
add_cpp_test(ondemand_number_tests LABELS ondemand acceptance per_implementation)
add_cpp_test(ondemand_number_in_string_tests LABELS ondemand acceptance per_implementation)
add_cpp_test(ondemand_object_tests LABELS ondemand acceptance per_implementation)
add_cpp_test(ondemand_object_error_tests LABELS ondemand acceptance per_implementation)
add_cpp_test(ondemand_ordering_tests LABELS ondemand acceptance per_implementation)
add_cpp_test(ondemand_parse_api_tests LABELS ondemand acceptance per_implementation)
add_cpp_test(ondemand_readme_examples LABELS ondemand acceptance per_implementation)
add_cpp_test(ondemand_scalar_tests LABELS ondemand acceptance per_implementation)
add_cpp_test(ondemand_to_string LABELS ondemand acceptance per_implementation)
add_cpp_test(ondemand_twitter_tests LABELS ondemand acceptance per_implementation)
add_cpp_test(ondemand_wrong_type_error_tests LABELS ondemand acceptance per_implementation)
add_cpp_test(ondemand_iterate_many_csv LABELS ondemand acceptance per_implementation)
add_cpp_test(ondemand_custom_types_tests LABELS ondemand acceptance per_implementation)
add_cpp_test(ondemand_custom_types_document_tests LABELS ondemand acceptance per_implementation)
add_cpp_test(ondemand_stl_types_tests LABELS ondemand acceptance per_implementation)
if(NOT SIMDJSON_SANITIZE)
add_cpp_test(ondemand_cacheline LABELS ondemand acceptance per_implementation)
endif()
+22 -2
View File
@@ -21,8 +21,24 @@ long page_size() {
// Returns true if the buffer + len + simdjson::SIMDJSON_PADDING crosses the
// page boundary.
bool need_allocation(const char *buf, size_t len) {
return ((reinterpret_cast<uintptr_t>(buf + len - 1) % page_size()) <
simdjson::SIMDJSON_PADDING);
return ((reinterpret_cast<uintptr_t>(buf + len - 1) % page_size())
+ simdjson::SIMDJSON_PADDING > static_cast<uintptr_t>(page_size()));
}
bool check_need_allocation() {
long ps = page_size();
std::vector<std::tuple<uintptr_t,size_t,bool>> test_cases = {
{2*ps, 5, false}, {2*ps, ps, true}, {2*ps, 100, false},
};
for(auto t : test_cases) {
uintptr_t buf = std::get<0>(t);
size_t len = std::get<1>(t);
bool expected = std::get<2>(t);
if(need_allocation(reinterpret_cast<const char *>(buf), len) != expected) {
return false;
}
}
return true;
}
simdjson::padded_string_view
@@ -39,6 +55,10 @@ get_padded_string_view(const char *buf, size_t len,
int main() {
printf("page_size: %ld\n", page_size());
if(!check_need_allocation()) {
printf("Bug in the need_allocation function.\n");
return EXIT_FAILURE;
}
const char *jsonpoiner = R"(
{
"key": "value"
@@ -0,0 +1,263 @@
#include "simdjson.h"
#include "test_ondemand.h"
#include <iostream>
#include <vector>
using namespace simdjson;
/**
* A custom type that we want to parse.
*/
struct Car {
std::string make{};
std::string model{};
int64_t year{};
std::vector<double> tire_pressure{};
bool operator==(const Car &other) const {
return make == other.make && model == other.model && year == other.year &&
tire_pressure == other.tire_pressure;
}
};
std::ostream &operator<<(std::ostream &os, const Car &c) {
os << c.make << " " << c.model << " " << c.year << " ";
for (auto p : c.tire_pressure) {
os << p << " ";
}
return os;
}
#if !SIMDJSON_SUPPORTS_DESERIALIZATION
// This code is not necessary if you have a C++20 compliant system:
template <>
simdjson_inline simdjson_result<std::vector<double>>
simdjson::ondemand::value::get() noexcept {
ondemand::array array;
auto error = get_array().get(array);
if (error) {
return error;
}
std::vector<double> vec;
for (auto v : array) {
double val;
error = v.get_double().get(val);
if (error) {
return error;
}
vec.push_back(val);
}
return vec;
}
#endif
template <>
simdjson_inline simdjson_result<Car> simdjson::ondemand::value::get() noexcept {
ondemand::object obj;
auto error = get_object().get(obj);
if (error) {
return error;
}
Car car;
if ((error = obj["make"].get_string(car.make))) {
return error;
}
if ((error = obj["model"].get_string(car.model))) {
return error;
}
if ((error = obj["year"].get_int64().get(car.year))) {
return error;
}
if ((error = obj["tire_pressure"].get<std::vector<double>>().get(
car.tire_pressure))) {
return error;
}
return car;
}
template <>
simdjson_inline simdjson_result<Car>
simdjson::ondemand::document::get() &noexcept {
ondemand::object obj;
auto error = get_object().get(obj);
if (error) {
return error;
}
Car car;
if ((error = obj["make"].get_string(car.make))) {
return error;
}
if ((error = obj["model"].get_string(car.model))) {
return error;
}
if ((error = obj["year"].get_int64().get(car.year))) {
return error;
}
if ((error = obj["tire_pressure"].get<std::vector<double>>().get(
car.tire_pressure))) {
return error;
}
return car;
}
template <>
simdjson_inline simdjson_result<Car>
simdjson::ondemand::document_reference::get() &noexcept {
ondemand::object obj;
auto error = get_object().get(obj);
if (error) {
return error;
}
Car car;
if ((error = obj["make"].get_string(car.make))) {
return error;
}
if ((error = obj["model"].get_string(car.model))) {
return error;
}
if ((error = obj["year"].get_int64().get(car.year))) {
return error;
}
if ((error = obj["tire_pressure"].get<std::vector<double>>().get(
car.tire_pressure))) {
return error;
}
return car;
}
int main_should_compile(void) {
padded_string json =
R"( [ { "make": "Toyota", "model": "Camry", "year": 2018,
"tire_pressure": [ 40.1, 39.9 ] },
{ "make": "Kia", "model": "Soul", "year": 2012,
"tire_pressure": [ 30.1, 31.0 ] },
{ "make": "Toyota", "model": "Tercel", "year": 1999,
"tire_pressure": [ 29.8, 30.0 ] }
])"_padded;
ondemand::parser parser;
ondemand::document doc;
[[maybe_unused]] auto doc_error = parser.iterate(json).get(doc);
for (auto val : doc) {
#if SIMDJSON_EXCEPTIONS
Car c(val); // an exception may be thrown
#else
Car c;
if (auto error = val.get<Car>().get(c)) {
std::cerr << error << std::endl;
return EXIT_FAILURE;
}
#endif
}
return EXIT_SUCCESS;
}
namespace car_error_tests {
bool car_deserialize() {
TEST_START();
padded_string json =
R"( [ { "make": "Toyota", "model": "Camry", "year": 2018,
"tire_pressure": [ 40.1, 39.9 ] },
{ "make": "Kia", "model": "Soul", "year": 2012,
"tire_pressure": [ 30.1, 31.0 ] },
{ "make": "Toyota", "model": "Tercel", "year": 1999,
"tire_pressure": [ 29.8, 30.0 ] }
])"_padded;
ondemand::parser parser;
ondemand::document doc;
[[maybe_unused]] auto doc_error = parser.iterate(json).get(doc);
std::vector<Car> cars;
for (auto val : doc) {
#if SIMDJSON_EXCEPTIONS
Car c(val); // an exception may be thrown
#else
Car c;
if (auto error = val.get<Car>().get(c)) {
std::cerr << error << std::endl;
return EXIT_FAILURE;
}
#endif
cars.push_back(c);
std::cout << c.make << std::endl;
}
std::vector<Car> expected = {{"Toyota", "Camry", 2018, {40.1, 39.9}},
{"Kia", "Soul", 2012, {30.1, 31.0}},
{"Toyota", "Tercel", 1999, {29.8, 30.0}}};
ASSERT_EQUAL(cars.size(), expected.size());
for (size_t i = 0; i < cars.size(); i++) {
ASSERT_EQUAL(cars[i], expected[i]);
}
TEST_SUCCEED();
}
bool car_doc_deserialize() {
TEST_START();
padded_string json = R"( { "make": "Toyota", "model": "Camry", "year": 2018,
"tire_pressure": [ 40.1, 39.9 ] }
)"_padded;
ondemand::parser parser;
ondemand::document doc;
[[maybe_unused]] auto doc_error = parser.iterate(json).get(doc);
#if SIMDJSON_EXCEPTIONS
Car c(doc); // an exception may be thrown
#else
Car c;
if (auto error = doc.get<Car>().get(c)) {
std::cerr << error << std::endl;
return EXIT_FAILURE;
}
#endif
Car expected = {"Toyota", "Camry", 2018, {40.1, 39.9}};
ASSERT_EQUAL(c, expected);
TEST_SUCCEED();
}
bool car_stream_deserialize() {
TEST_START();
padded_string json =
R"( { "make": "Toyota", "model": "Camry", "year": 2018,
"tire_pressure": [ 40.1, 39.9 ] }
{ "make": "Kia", "model": "Soul", "year": 2012,
"tire_pressure": [ 30.1, 31.0 ] }
{ "make": "Toyota", "model": "Tercel", "year": 1999,
"tire_pressure": [ 29.8, 30.0 ] }
)"_padded;
ondemand::parser parser;
ondemand::document_stream stream;
auto error = parser.iterate_many(json).get(stream);
if(error) {
std::cerr << error << std::endl;
return EXIT_FAILURE;
}
std::vector<Car> cars;
#if SIMDJSON_EXCEPTIONS
for(ondemand::document_reference doc : stream) {
//Car c(doc); // an exception may be thrown
cars.push_back(Car(doc)); // an exception may be thrown
}
#else
for(auto doc : stream) {
Car c;
if ((error = doc.get<Car>().get(c))) {
std::cerr << error << std::endl;
return EXIT_FAILURE;
}
cars.push_back(c);
}
#endif
std::vector<Car> expected = {{"Toyota", "Camry", 2018, {40.1, 39.9}},
{"Kia", "Soul", 2012, {30.1, 31.0}},
{"Toyota", "Tercel", 1999, {29.8, 30.0}}};
ASSERT_EQUAL(cars.size(), expected.size());
for (size_t i = 0; i < cars.size(); i++) {
ASSERT_EQUAL(cars[i], expected[i]);
}
TEST_SUCCEED();
}
bool run() { return car_stream_deserialize() && car_doc_deserialize() && car_deserialize(); }
} // namespace car_error_tests
int main(int argc, char *argv[]) {
return test_main(argc, argv, car_error_tests::run);
}
@@ -0,0 +1,373 @@
#include "simdjson.h"
#include "test_ondemand.h"
#include <cstdlib>
#include <iostream>
#include <vector>
#include <list>
#include <optional>
#include <map>
#include <unordered_map>
using namespace simdjson;
#if !SIMDJSON_SUPPORTS_DESERIALIZATION
int main(void) {
printf("This test is only relevant when SIMDJSON_SUPPORTS_DESERIALIZATION is true (C++20)\n");
return EXIT_SUCCESS;
}
#else
/**
* A custom type that we want to parse.
*/
struct Car {
std::string make{};
std::string model{};
int year{};
std::vector<float> tire_pressure{};
bool operator==(const Car &other) const {
return make == other.make && model == other.model && year == other.year &&
tire_pressure == other.tire_pressure;
}
};
std::ostream &operator<<(std::ostream &os, const Car &c) {
os << c.make << " " << c.model << " " << c.year << " ";
for (auto p : c.tire_pressure) {
os << p << " ";
}
return os;
}
namespace simdjson {
// This tag_invoke MUST be inside simdjson namespace
template <typename simdjson_value>
auto tag_invoke(deserialize_tag, simdjson_value &val, Car& car) {
ondemand::object obj;
auto error = val.get_object().get(obj);
if (error) {
return error;
}
if ((error = obj["make"].get_string(car.make))) {
return error;
}
if ((error = obj["model"].get_string(car.model))) {
return error;
}
if ((error = obj["year"].get(car.year))) {
return error;
}
if ((error = obj["tire_pressure"].get<std::vector<float>>().get(
car.tire_pressure))) {
return error;
}
return simdjson::SUCCESS;
}
// suppose we want to filter out all Toyotas
template <typename simdjson_value>
auto tag_invoke(deserialize_tag, simdjson_value &val, std::list<Car>& car) {
ondemand::array arr;
auto error = val.get_array().get(arr);
if (error) {
return error;
}
for (auto v : arr) {
Car c;
if ((error = v.get<Car>().get(c))) {
return error;
}
if(c.make != "Toyota") {
car.push_back(c);
}
}
return simdjson::SUCCESS;
}
} // namespace simdjson
int main_should_compile(void) {
padded_string json =
R"( [ { "make": "Toyota", "model": "Camry", "year": 2018,
"tire_pressure": [ 40.1, 39.9 ] },
{ "make": "Kia", "model": "Soul", "year": 2012,
"tire_pressure": [ 30.1, 31.0 ] },
{ "make": "Toyota", "model": "Tercel", "year": 1999,
"tire_pressure": [ 29.8, 30.0 ] }
])"_padded;
ondemand::parser parser;
ondemand::document doc;
[[maybe_unused]] auto doc_error = parser.iterate(json).get(doc);
for (auto val : doc) {
#if SIMDJSON_EXCEPTIONS
Car c(val); // an exception may be thrown
#else
Car c;
if (auto error = val.get<Car>().get(c)) {
std::cerr << error << std::endl;
return EXIT_FAILURE;
}
#endif
}
return EXIT_SUCCESS;
}
namespace car_error_tests {
bool car_deserialize() {
TEST_START();
padded_string json =
R"( [ { "make": "Toyota", "model": "Camry", "year": 2018,
"tire_pressure": [ 40.1, 39.9 ] },
{ "make": "Kia", "model": "Soul", "year": 2012,
"tire_pressure": [ 30.1, 31.0 ] },
{ "make": "Toyota", "model": "Tercel", "year": 1999,
"tire_pressure": [ 29.8, 30.0 ] }
])"_padded;
ondemand::parser parser;
ondemand::document doc;
[[maybe_unused]] auto doc_error = parser.iterate(json).get(doc);
std::vector<Car> cars;
for (auto val : doc) {
#if SIMDJSON_EXCEPTIONS
Car c(val); // an exception may be thrown
#else
Car c;
if (auto error = val.get<Car>().get(c)) {
std::cerr << error << std::endl;
return EXIT_FAILURE;
}
#endif
cars.push_back(c);
std::cout << c.make << std::endl;
}
std::vector<Car> expected = {{"Toyota", "Camry", 2018, {40.1f, 39.9f}},
{"Kia", "Soul", 2012, {30.1f, 31.0f}},
{"Toyota", "Tercel", 1999, {29.8f, 30.0f}}};
ASSERT_EQUAL(cars.size(), expected.size());
for (size_t i = 0; i < cars.size(); i++) {
ASSERT_EQUAL(cars[i], expected[i]);
}
TEST_SUCCEED();
}
bool vector_car_deserialize() {
TEST_START();
padded_string json =
R"( [ { "make": "Toyota", "model": "Camry", "year": 2018,
"tire_pressure": [ 40.1, 39.9 ] },
{ "make": "Kia", "model": "Soul", "year": 2012,
"tire_pressure": [ 30.1, 31.0 ] },
{ "make": "Toyota", "model": "Tercel", "year": 1999,
"tire_pressure": [ 29.8, 30.0 ] }
])"_padded;
ondemand::parser parser;
ondemand::document doc;
[[maybe_unused]] auto doc_error = parser.iterate(json).get(doc);
#if SIMDJSON_EXCEPTIONS
#if SIMDJSON_REGULAR_VISUAL_STUDIO
std::vector<Car> cars = doc.get<std::vector<Car>>(); // an exception may be thrown
#else
std::vector<Car> cars(doc); // an exception may be thrown
#endif
#else
std::vector<Car> cars;
if (auto error = doc.get<std::vector<Car>>().get(cars)) {
std::cerr << error << std::endl;
return EXIT_FAILURE;
}
#endif
std::vector<Car> expected = {{"Toyota", "Camry", 2018, {40.1f, 39.9f}},
{"Kia", "Soul", 2012, {30.1f, 31.0f}},
{"Toyota", "Tercel", 1999, {29.8f, 30.0f}}};
ASSERT_EQUAL(cars.size(), expected.size());
for (size_t i = 0; i < cars.size(); i++) {
ASSERT_EQUAL(cars[i], expected[i]);
}
TEST_SUCCEED();
}
bool list_car_deserialize() {
TEST_START();
padded_string json =
R"( [ { "make": "Toyota", "model": "Camry", "year": 2018,
"tire_pressure": [ 40.1, 39.9 ] },
{ "make": "Kia", "model": "Soul", "year": 2012,
"tire_pressure": [ 30.1, 31.0 ] },
{ "make": "Toyota", "model": "Tercel", "year": 1999,
"tire_pressure": [ 29.8, 30.0 ] }
])"_padded;
ondemand::parser parser;
ondemand::document doc;
[[maybe_unused]] auto doc_error = parser.iterate(json).get(doc);
#if SIMDJSON_EXCEPTIONS
#if SIMDJSON_REGULAR_VISUAL_STUDIO
std::list<Car> cars = doc.get<std::list<Car>>(); // an exception may be thrown
#else
std::list<Car> cars(doc); // an exception may be thrown
#endif
#else
std::list<Car> cars;
if (auto error = doc.get<std::list<Car>>().get(cars)) {
std::cerr << error << std::endl;
return EXIT_FAILURE;
}
#endif
std::list<Car> expected = {{"Kia", "Soul", 2012, {30.1f, 31.0f}}};
ASSERT_EQUAL(cars.size(), expected.size());
ASSERT_EQUAL(cars.front(), expected.front());
TEST_SUCCEED();
}
bool optional_car_deserialize() {
TEST_START();
padded_string json =
R"( { "car1": { "make": "Toyota", "model": "Camry", "year": 2018,
"tire_pressure": [ 40.1, 39.9 ] }
})"_padded;
ondemand::parser parser;
ondemand::document doc;
[[maybe_unused]] auto error = parser.iterate(json).get(doc);
std::optional<Car> car;
error = doc["key not found"].get<std::optional<Car>>().get(car);
ASSERT_TRUE(!car);
error = doc["car1"].get<std::optional<Car>>().get(car);
std::optional<Car> expected = Car{"Toyota", "Camry", 2018, {40.1f, 39.9f}};
ASSERT_TRUE(car == expected);
TEST_SUCCEED();
}
bool car_deserialize_to_map() {
TEST_START();
std::map<std::string,std::string> expected = { {"make", "Toyota"}, {"model", "Camry"}};
padded_string json =
R"( { "make": "Toyota", "model": "Camry" })"_padded;
ondemand::parser parser;
ondemand::document doc;
[[maybe_unused]] auto error = parser.iterate(json).get(doc);
static_assert(simdjson::concepts::string_view_keyed_map<std::map<std::string, std::string>>, "should be custom deserializable");
using map_type = typename std::map<std::string,std::string>;
static_assert(simdjson::custom_deserializable<map_type,simdjson::ondemand::value>, "should be custom deserializable");
map_type brands;
error = doc.get<map_type>().get(brands);
ASSERT_TRUE(brands == expected);
TEST_SUCCEED();
}
bool car_deserialize_with_map() {
TEST_START();
padded_string json =
R"( { "car1": { "make": "Toyota", "model": "Camry", "year": 2018,
"tire_pressure": [ 40.1, 39.9 ] }
})"_padded;
ondemand::parser parser;
ondemand::document doc;
[[maybe_unused]] auto error = parser.iterate(json).get(doc);
std::map<std::string,Car> car;
error = doc.get<std::map<std::string,Car>>().get(car);
std::optional<Car> expected = Car{"Toyota", "Camry", 2018, {40.1f, 39.9f}};
ASSERT_TRUE(car["car1"] == expected);
TEST_SUCCEED();
}
bool car_doc_deserialize() {
TEST_START();
padded_string json = R"( { "make": "Toyota", "model": "Camry", "year": 2018,
"tire_pressure": [ 40.1, 39.9 ] }
)"_padded;
ondemand::parser parser;
ondemand::document doc;
[[maybe_unused]] auto doc_error = parser.iterate(json).get(doc);
#if SIMDJSON_EXCEPTIONS
Car c(doc); // an exception may be thrown
#else
Car c;
if (auto error = doc.get<Car>().get(c)) {
std::cerr << error << std::endl;
return EXIT_FAILURE;
}
#endif
Car expected = {"Toyota", "Camry", 2018, {40.1f, 39.9f}};
ASSERT_EQUAL(c, expected);
TEST_SUCCEED();
}
bool car_stream_deserialize() {
TEST_START();
padded_string json =
R"( { "make": "Toyota", "model": "Camry", "year": 2018,
"tire_pressure": [ 40.1, 39.9 ] }
{ "make": "Kia", "model": "Soul", "year": 2012,
"tire_pressure": [ 30.1, 31.0 ] }
{ "make": "Toyota", "model": "Tercel", "year": 1999,
"tire_pressure": [ 29.8, 30.0 ] }
)"_padded;
ondemand::parser parser;
ondemand::document_stream stream;
[[maybe_unused]] auto error = parser.iterate_many(json).get(stream);
std::vector<Car> cars;
#if SIMDJSON_EXCEPTIONS
for(auto doc : stream) {
cars.push_back((Car)doc); // an exception may be thrown
}
#else
for(auto doc : stream) {
Car c;
if ((error = doc.get<Car>().get(c))) {
std::cerr << error << std::endl;
return EXIT_FAILURE;
}
cars.push_back(c);
}
#endif
std::vector<Car> expected = {{"Toyota", "Camry", 2018, {40.1f, 39.9f}},
{"Kia", "Soul", 2012, {30.1f, 31.0f}},
{"Toyota", "Tercel", 1999, {29.8f, 30.0f}}};
ASSERT_EQUAL(cars.size(), expected.size());
for (size_t i = 0; i < cars.size(); i++) {
ASSERT_EQUAL(cars[i], expected[i]);
}
TEST_SUCCEED();
}
bool car_unique_ptr_deserialize() {
TEST_START();
auto const json = R"( { "make": "Toyota", "model": "Camry", "year": 2018,
"tire_pressure": [ 40.1, 39.9 ] })"_padded;
simdjson::ondemand::parser parser;
simdjson::ondemand::document doc;
[[maybe_unused]] auto error = parser.iterate(json).get(doc);
#if SIMDJSON_EXCEPTIONS
std::unique_ptr<Car> c(doc);
#else
std::unique_ptr<Car> c;
if ((error = doc.get<std::unique_ptr<Car>>().get(c))) {
std::cerr << error << std::endl;
return EXIT_FAILURE;
}
#endif
ASSERT_EQUAL(c->make, "Toyota");
TEST_SUCCEED();
}
bool run() { return car_deserialize_with_map()
&& car_deserialize_to_map()
&& list_car_deserialize()
&& optional_car_deserialize()
&& car_unique_ptr_deserialize()
&& vector_car_deserialize()
&& car_stream_deserialize()
&& car_doc_deserialize()
&& car_deserialize(); }
} // namespace car_error_tests
int main(int argc, char *argv[]) {
return test_main(argc, argv, car_error_tests::run);
}
#endif // SIMDJSON_SUPPORTS_DESERIALIZATION

Some files were not shown because too many files have changed in this diff Show More