Compare commits

...

102 Commits

Author SHA1 Message Date
Daniel Lemire 956661f800 removing printout 2025-08-05 18:40:37 -04:00
Daniel Lemire a306d2bd73 documentation 2025-08-05 17:27:38 -04:00
Daniel Lemire 9627831b5f some minor fixes 2025-08-05 17:02:13 -04:00
Joseph Olabisi 6c5ada32b9 remove unneccessary string allocation 2025-07-22 21:03:02 +01:00
Joseph Olabisi f576354342 fix jsonpathutil 2025-07-21 23:06:38 +01:00
Joseph Olabisi 1589d15361 fix 2025-07-21 22:34:17 +01:00
Joseph Olabisi c58f5dda2d minor changes 2025-07-21 21:45:31 +01:00
Joseph Olabisi 5753f54f6c fix boundary check and unnecessary string allocation 2025-07-21 21:31:47 +01:00
Joseph Olabisi f0cdafa857 add more tests 2025-07-21 21:15:38 +01:00
Joseph Olabisi 29ef75c783 fix bug with array, add boundary check to get_next_key_and_json_path function 2025-07-21 20:58:49 +01:00
Joseph Olabisi c3d45c7758 refactor process_json_path_of_child_element from recursion to loop in order to prevent stack overflow 2025-07-16 20:35:52 +01:00
Joseph Olabisi 3fda1b9c7d minor error handling 2025-07-14 01:35:19 +01:00
Joseph Olabisi fdcea9ad22 refactor and create util for getting key and json path 2025-07-14 01:15:02 +01:00
Joseph Olabisi 7b3168bfc8 add test for wildcard in nested array 2025-07-14 00:41:15 +01:00
Joseph Olabisi 3350ce97ba fix logic for wildcards inside arrays 2025-07-14 00:14:56 +01:00
Joseph Olabisi 61ec1fb659 fix bug in object-inl.h 2025-07-12 16:43:38 +01:00
Joseph Olabisi bfc8b89e6b final changes based on feedback - reduce string allocations 2025-07-10 17:10:25 +01:00
Joseph Olabisi 1382432686 address additional feedbacks (copilot) 2025-07-10 14:28:32 +01:00
Joseph Olabisi bebbf830fb address some feedbacks 2025-07-10 13:24:07 +01:00
Joseph Olabisi e7dda647e2 add test 2025-05-06 18:34:25 +01:00
Joseph Olabisi ec46aace3b nit 2025-05-06 18:27:00 +01:00
Joseph Olabisi 1dfe1bd350 nit 2025-05-06 18:24:14 +01:00
Joseph Olabisi 0b1d69938e cleanup 2025-05-06 18:22:32 +01:00
Joseph Olabisi 120e69f13c cleanup object-inl.h 2025-05-06 14:51:25 +01:00
Joseph Olabisi 14922fa6c4 revert object-inl.h 2025-05-06 14:37:50 +01:00
Joseph Olabisi 8fa2629c84 cleanup array-inl.h 2025-05-06 02:05:58 +01:00
Joseph Olabisi c51c2d2ce9 revert array-inl.h 2025-05-06 01:55:21 +01:00
Joseph Olabisi 3c9cde5ec1 restore quickstart.cpp 2025-05-06 01:47:28 +01:00
Joseph Olabisi 651c982d26 cleanup 2025-05-06 01:45:05 +01:00
Joseph Olabisi 3634cdbf94 restore examples/quickstart/CMakeLists.txt 2025-05-06 01:39:34 +01:00
Joseph Olabisi 3b47ae6a77 cleanup 2025-05-06 01:37:32 +01:00
Joseph Olabisi 07daf0a92e cleanup 2025-05-06 00:35:51 +01:00
Joseph Olabisi 9f74c0e958 cleanup 2025-05-06 00:29:22 +01:00
Joseph Olabisi 7a336e560c cleanup 2025-05-06 00:27:31 +01:00
Joseph Olabisi c6e7c89b59 modified: CMakeLists.txt 2025-05-06 00:23:16 +01:00
Joseph Olabisi ed838ffab9 cleanup 2 2025-05-06 00:21:35 +01:00
Joseph Olabisi 5981ca18e4 add some initial tests 2025-05-03 18:24:56 +01:00
Joseph Olabisi 1a11e19d07 cleanup 2025-05-03 13:46:11 +01:00
Joseph Olabisi 671a81f4e3 nit 2025-04-27 00:02:23 +01:00
Joseph Olabisi 008d89eb56 corrected logic 2025-04-26 21:01:05 +01:00
Joseph Olabisi a71655120a nit 2025-04-24 20:54:42 +01:00
Joseph Olabisi 531567ae94 approximately 30% improvement in runtime 2025-04-18 22:52:12 +01:00
Joseph Olabisi 46ae2d250f nit 2025-04-18 22:19:49 +01:00
Joseph Olabisi c35122bcb4 refactor to tail recursion 2025-04-18 21:43:44 +01:00
Joseph Olabisi f380604de5 minor improvements 2025-04-18 21:05:35 +01:00
Joseph Olabisi 00d01ea0f5 use memcmp 2025-04-15 11:22:43 +01:00
Joseph Olabisi 68bef810aa fix benchmark 2025-04-11 20:22:49 +01:00
Joseph Olabisi e328bad696 add benchmark 2025-04-11 10:11:42 +01:00
Joseph Olabisi c9ccb2d139 rename at_path_new to at_path_with_wildcard 2025-04-08 08:43:46 +01:00
Joseph Olabisi d99072982f handle array INCORRECT_TYPE 2025-04-05 20:52:53 +01:00
Joseph Olabisi 6b7f987cd5 add support for wildcard for arrays 2025-04-05 20:14:00 +01:00
Joseph Olabisi d32cd20ce6 fix key 2025-04-01 09:31:43 +01:00
Joseph Olabisi 2013a46518 done - handling child properties of wildcard result 2025-03-29 18:40:40 +00:00
Joseph Olabisi 6cb1911d3a wip - handling child properties of wildcard result 2025-03-26 10:31:58 +00:00
Joseph Olabisi 9ff7d2ccbe wip 2025-03-25 09:59:22 +00:00
Joseph Olabisi fa4a4ad8f0 wip - nested paths/pointers on wildcard results 2025-03-23 23:02:55 +00:00
Joseph Olabisi de6ad3c60c partially handle keys with wildcard 2025-03-21 22:31:47 +00:00
Joseph Olabisi 005133c555 wip - bruteforce surface wildcard with result 2025-03-18 02:20:30 +00:00
Joseph Olabisi 78025fdd64 wip brute-force wildcard for json_path 2025-03-11 21:16:26 +00: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
62 changed files with 1800 additions and 429 deletions
+1 -1
View File
@@ -13,7 +13,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- uses: uraimo/run-on-arch-action@v2 - uses: uraimo/run-on-arch-action@v3
name: Test name: Test
id: runcmd id: runcmd
with: with:
+2 -3
View File
@@ -1,9 +1,8 @@
name: Doxygen GitHub Pages name: Doxygen GitHub Pages
on: on:
push: release:
branches: types: [created]
- master
# Allows you to run this workflow manually from the Actions tab # Allows you to run this workflow manually from the Actions tab
workflow_dispatch: workflow_dispatch:
+4 -4
View File
@@ -24,7 +24,7 @@ jobs:
implementations: haswell westmere fallback implementations: haswell westmere fallback
UBSAN_OPTIONS: halt_on_error=1 UBSAN_OPTIONS: halt_on_error=1
MAXLEN: -max_len=4000 MAXLEN: -max_len=4000
CLANGVERSION: 15 CLANGVERSION: 19
# which optimization level to use for the sanitizer build (see build_fuzzer.variants.sh) # which optimization level to use for the sanitizer build (see build_fuzzer.variants.sh)
OPTLEVEL: -O3 OPTLEVEL: -O3
@@ -125,7 +125,7 @@ jobs:
done done
- name: Save the corpus as a github artifact - name: Save the corpus as a github artifact
uses: actions/upload-artifact@v3 uses: actions/upload-artifact@v4
with: with:
name: corpus name: corpus
path: corpus.tar path: corpus.tar
@@ -148,7 +148,7 @@ jobs:
run: tar cf valgrind.tar valgrind-*.txt run: tar cf valgrind.tar valgrind-*.txt
- name: Save valgrind output as a github artifact - name: Save valgrind output as a github artifact
uses: actions/upload-artifact@v3 uses: actions/upload-artifact@v4
if: always() if: always()
with: with:
name: valgrindresults name: valgrindresults
@@ -156,7 +156,7 @@ jobs:
if-no-files-found: ignore if-no-files-found: ignore
- name: Archive any crashes as an artifact - name: Archive any crashes as an artifact
uses: actions/upload-artifact@v3 uses: actions/upload-artifact@v4
if: always() if: always()
with: with:
name: crashes name: crashes
+1 -1
View File
@@ -20,7 +20,7 @@ jobs:
- 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 install: mingw-w64-x86_64-libxml2 mingw-w64-x86_64-cmake mingw-w64-x86_64-ninja mingw-w64-x86_64-clang
type: Debug 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 install: mingw-w64-x86_64-libxml2 mingw-w64-x86_64-cmake mingw-w64-x86_64-ninja mingw-w64-x86_64-clang
type: RelWithDebInfo type: RelWithDebInfo
env: env:
+1 -1
View File
@@ -13,7 +13,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- uses: uraimo/run-on-arch-action@v2 - uses: uraimo/run-on-arch-action@v3
name: Test name: Test
id: runcmd id: runcmd
with: with:
+1 -1
View File
@@ -13,7 +13,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- uses: uraimo/run-on-arch-action@v2 - uses: uraimo/run-on-arch-action@v3
name: Test name: Test
id: runcmd id: runcmd
with: with:
+1 -1
View File
@@ -13,7 +13,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- uses: uraimo/run-on-arch-action@v2 - uses: uraimo/run-on-arch-action@v3
name: Test name: Test
id: runcmd id: runcmd
with: with:
+1 -2
View File
@@ -10,7 +10,6 @@ jobs:
fail-fast: false fail-fast: false
matrix: matrix:
include: include:
- {arch: ARM}
- {arch: ARM64} - {arch: ARM64}
- {arch: ARM64EC} - {arch: ARM64EC}
steps: steps:
@@ -19,4 +18,4 @@ jobs:
- name: Use cmake - name: Use cmake
run: | 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 -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
+3 -3
View File
@@ -3,7 +3,7 @@ cmake_minimum_required(VERSION 3.14)
project( project(
simdjson simdjson
# The version number is modified by tools/release.py # The version number is modified by tools/release.py
VERSION 3.10.1 VERSION 3.12.2
DESCRIPTION "Parsing gigabytes of JSON per second" DESCRIPTION "Parsing gigabytes of JSON per second"
HOMEPAGE_URL "https://simdjson.org/" HOMEPAGE_URL "https://simdjson.org/"
LANGUAGES CXX C LANGUAGES CXX C
@@ -20,8 +20,8 @@ string(
# ---- Options, variables ---- # ---- Options, variables ----
# These version numbers are modified by tools/release.py # These version numbers are modified by tools/release.py
set(SIMDJSON_LIB_VERSION "23.0.0" CACHE STRING "simdjson library version") set(SIMDJSON_LIB_VERSION "25.0.0" CACHE STRING "simdjson library version")
set(SIMDJSON_LIB_SOVERSION "23" CACHE STRING "simdjson library soversion") 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) option(SIMDJSON_BUILD_STATIC_LIB "Build simdjson_static library along with simdjson (only makes sense if BUILD_SHARED_LIBS=ON)" OFF)
if(SIMDJSON_BUILD_STATIC_LIB AND NOT BUILD_SHARED_LIBS) if(SIMDJSON_BUILD_STATIC_LIB AND NOT BUILD_SHARED_LIBS)
+1 -1
View File
@@ -38,7 +38,7 @@ PROJECT_NAME = simdjson
# could be handy for archiving the generated documentation or if some version # could be handy for archiving the generated documentation or if some version
# control system is used. # control system is used.
PROJECT_NUMBER = "3.10.1" PROJECT_NUMBER = "3.12.2"
# Using the PROJECT_BRIEF tag one can provide an optional one line description # Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears at the top of each page and should give viewer a # for a project that appears at the top of each page and should give viewer a
+1 -1
View File
@@ -186,7 +186,7 @@
same "printed page" as the copyright notice for easier same "printed page" as the copyright notice for easier
identification within third-party archives. identification within third-party archives.
Copyright 2018-2023 The simdjson authors Copyright 2018-2025 The simdjson authors
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
+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.
+14 -3
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) [![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/) [![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) * [Documentation](#documentation)
* [Godbolt](#godbolt) * [Godbolt](#godbolt)
* [Performance results](#performance-results) * [Performance results](#performance-results)
* [Packages](#packages)
* [Bindings and Ports of simdjson](#bindings-and-ports-of-simdjson) * [Bindings and Ports of simdjson](#bindings-and-ports-of-simdjson)
* [About simdjson](#about-simdjson) * [About simdjson](#about-simdjson)
* [Funding](#funding) * [Funding](#funding)
@@ -61,6 +62,8 @@ Real-world usage
- [ada-url](https://github.com/ada-url/ada) - [ada-url](https://github.com/ada-url/ada)
- [fastgron](https://github.com/adamritter/fastgron) - [fastgron](https://github.com/adamritter/fastgron)
- [WasmEdge](https://wasmedge.org) - [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. 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). 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 Bindings and Ports of simdjson
@@ -207,6 +213,11 @@ RGPIN-2017-03910 and RGPIN-2024-03787.
[license]: LICENSE [license]: LICENSE
[license img]: https://img.shields.io/badge/License-Apache%202-blue.svg [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 Contributing to simdjson
------------------------ ------------------------
@@ -216,7 +227,7 @@ Head over to [CONTRIBUTING.md](CONTRIBUTING.md) for information on contributing
License 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. 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.
+31 -7
View File
@@ -48,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. - 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. 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.
@@ -209,6 +209,25 @@ std::string data = "my data";
simdjson::padded_string my_padded_data(data); // copies to a padded buffer 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. We recommend against creating many `std::string` or many `std::padding_string` instances in your application to store your JSON data.
Consider reusing the same buffers and limiting memory allocations. Consider reusing the same buffers and limiting memory allocations.
@@ -403,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 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 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. 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, * **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 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 * **Field Access:** To get the value of the "foo" field in an object, use `object["foo"]`. This will
scan through the object looking for the field with the matching string, doing a character-by-character scan through the object looking for the field with the matching string, doing a character-by-character
comparison. It may generate the error `simdjson::NO_SUCH_FIELD` if there is no such key in the object, it may throw an exception (see [Error handling](#error-handling)). For efficiency reason, you should avoid looking up the same field repeatedly: e.g., do comparison. It may generate the error `simdjson::NO_SUCH_FIELD` if there is no such key in the object, it may throw an exception (see [Error handling](#error-handling)). For efficiency reason, you should avoid looking up the same field repeatedly: e.g., do
@@ -538,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 For this purpose, `array` instances have a `count_elements` method. Users should be
aware that the `count_elements` method can be costly since it requires scanning the aware that the `count_elements` method can be costly since it requires scanning the
whole array. You should only call `count_elements` as a last resort as it may 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++ ```C++
auto cars_json = R"( [ 40.1, 39.9, 37.7, 40.4 ] )"_padded; auto cars_json = R"( [ 40.1, 39.9, 37.7, 40.4 ] )"_padded;
@@ -1606,7 +1629,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: 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 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. - 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. Observe how we use the `at` method when querying an index into an array, and not the bracket operator.
@@ -1631,8 +1654,8 @@ int main(void) {
} }
``` ```
The `at` method can only be called once on an array. It cannot be used *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. 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 ### Error handling examples without exceptions
@@ -1951,6 +1974,7 @@ to the document `rewind()` method, except that it does not rewind the
internal string buffer. Thus you should consume values only once internal string buffer. Thus you should consume values only once
even if you can iterate through the array or object more than once. even if you can iterate through the array or object more than once.
If you unescape a string within an array more than once, you have unsafe code. If you unescape a string within an array more than once, you have unsafe code.
You must not call `reset()` on an object or an array as you are iterating through it.
Newline-Delimited JSON (ndjson) and JSON lines Newline-Delimited JSON (ndjson) and JSON lines
@@ -1962,7 +1986,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. 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 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 [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 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. is content between your JSON documents, it should be exclusively ASCII white-space characters.
+88
View File
@@ -60,6 +60,26 @@ std::string data = "my data";
simdjson::padded_string my_padded_data(data); // copies to a padded buffer 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. The parsed document resulting from the `parser.load` and `parser.parse` calls depends on the `parser` instance. Thus the `parser` instance must remain in scope. Furthermore, you must have at most one parsed document in play per `parser` instance.
You cannot copy a `parser` instance, you may only move it. You cannot copy a `parser` instance, you may only move it.
@@ -303,6 +323,74 @@ if(error) { /*won't happen*/ }
``` ```
## Using `at_path_with_wildcard` for JSONPath Queries
The `at_path_with_wildcard` function in simdjson extends the JSONPath querying capabilities by supporting wildcard expressions (`*`) in JSON paths. This allows users to retrieve multiple elements from a JSON document in a single query. For example, you can use `$.address.*` to fetch all fields within the `address` object or `$.phoneNumbers[*].numbers[*]` to retrieve all phone numbers across multiple objects in an array.
The `*` wildcard matches all elements at a specific level. For instance, `$.address.*` retrieves all key-value pairs in the `address` object, while `$.*.streetAddress` fetches all `streetAddress` fields across objects at the root level. You can combine wildcards with array indexing. For example, `$.phoneNumbers[*].numbers[1]` retrieves the second number from each `numbers` array in the `phoneNumbers` array. If no elements match the wildcard query, the function returns an empty result. For instance, querying `$.empty_object.*` or `$.empty_array.*` will yield an empty set.
### Example Usage
Here is an example demonstrating the use of `at_path_with_wildcard`:
```cpp
simdjson::padded_string json_string = R"(
{
"firstName": "John",
"lastName": "doe",
"age": 26,
"address": {
"streetAddress": "naist street",
"city": "Nara",
"postalCode": "630-0192"
},
"phoneNumbers": [
{
"type": "iPhone",
"numbers": ["0123-4567-8888", "0123-4567-8788"]
},
{
"type": "home",
"numbers": ["0123-4567-8910"]
}
]
})"_padded;
dom::parser parser;
dom::element parsed_json = parser.parse(json_string);
std::vector<dom::element> values;
// Fetch all fields in the address object
auto error = parsed_json.at_path_with_wildcard("$.address.*").get(values);
if(error) {
// do something
}
for (auto &value : values) {
std::string_view field;
error = value.get(field);
if(error) {
// do something
}
std::cout << field << std::endl;
}
// Fetch all phone numbers
error = parsed_json.at_path_with_wildcard("$.phoneNumbers[*].numbers[*]").get(values);
if(error) {
// do something
}
for (auto &value : values) {
std::string_view number;
error = value.get(number);
if(error) {
// do something
}
std::cout << number << std::endl;
}
```
This function is particularly useful for extracting data from complex JSON structures with nested arrays and objects. By leveraging wildcards, you can simplify your queries and reduce the need for multiple iterations.
Error Handling Error Handling
-------------- --------------
+1 -1
View File
@@ -130,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. E.g., `[1,2]{"32":1}` is recognized as two documents.
Some official formats **(non-exhaustive list)**: 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/) - [JSON lines (JSONL)](http://jsonlines.org/)
- [Record separator-delimited JSON (RFC 7464)](https://tools.ietf.org/html/rfc7464) <- Not supported by JsonStream! - [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) - [More on Wikipedia...](https://en.wikipedia.org/wiki/JSON_streaming)
+1 -1
View File
@@ -102,7 +102,7 @@ or indexing (`object["key"]`). In some cases, the values are even deserialized d
maps. maps.
The DOM approach is conceptually simple and "programmer friendly". Using the 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. 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. The DOM approach was the only way to parse JSON documents up to version 0.6 of the simdjson library.
+3 -1
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. 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). 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).
+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 // make this dynamic, so it works regardless of how it was compiled
// or what hardware it runs on // 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(); const std::size_t Nimplementations = supported_implementations.size();
if(Nimplementations>Nimplementations_max) { if(Nimplementations>Nimplementations_max) {
+3 -3
View File
@@ -19,7 +19,7 @@ SIMDJSON_NO_SANITIZE_UNDEFINED
// See issue https://github.com/simdjson/simdjson/issues/1965 // See issue https://github.com/simdjson/simdjson/issues/1965
SIMDJSON_NO_SANITIZE_MEMORY SIMDJSON_NO_SANITIZE_MEMORY
simdjson_inline int trailing_zeroes(uint64_t input_num) { simdjson_inline int trailing_zeroes(uint64_t input_num) {
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO #if SIMDJSON_REGULAR_VISUAL_STUDIO
unsigned long ret; unsigned long ret;
// Search the mask data from least significant bit (LSB) // Search the mask data from least significant bit (LSB)
// to the most significant bit (MSB) for a set bit (1). // to the most significant bit (MSB) for a set bit (1).
@@ -43,7 +43,7 @@ simdjson_inline uint64_t clear_lowest_bit(uint64_t input_num) {
SIMDJSON_NO_SANITIZE_UNDEFINED SIMDJSON_NO_SANITIZE_UNDEFINED
/* result might be undefined when input_num is zero */ /* result might be undefined when input_num is zero */
simdjson_inline int leading_zeroes(uint64_t input_num) { simdjson_inline int leading_zeroes(uint64_t input_num) {
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO #if SIMDJSON_REGULAR_VISUAL_STUDIO
unsigned long leading_zero = 0; unsigned long leading_zero = 0;
// Search the mask data from most significant bit (MSB) // Search the mask data from most significant bit (MSB)
// to least significant bit (LSB) for a set bit (1). // to least significant bit (LSB) for a set bit (1).
@@ -96,7 +96,7 @@ simdjson_inline uint64_t zero_leading_bit(uint64_t rev_bits, int leading_zeroes)
#endif #endif
simdjson_inline bool add_overflow(uint64_t value1, uint64_t value2, uint64_t *result) { 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; *result = value1 + value2;
return *result < value1; return *result < value1;
#else #else
+7 -7
View File
@@ -12,7 +12,7 @@ namespace arm64 {
namespace { namespace {
namespace simd { namespace simd {
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO #if SIMDJSON_REGULAR_VISUAL_STUDIO
namespace { namespace {
// Start of private section with Visual Studio workaround // 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 // 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). // purposes (cutting it down to uint16_t costs performance in some compilers).
simdjson_inline uint32_t to_bitmask() const { 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, 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); 0x01, 0x02, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80);
#else #else
@@ -152,7 +152,7 @@ namespace {
// Splat constructor // Splat constructor
simdjson_inline simd8(uint8_t _value) : simd8(splat(_value)) {} simdjson_inline simd8(uint8_t _value) : simd8(splat(_value)) {}
// Member-by-member initialization // Member-by-member initialization
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO #if SIMDJSON_REGULAR_VISUAL_STUDIO
simdjson_inline simd8( 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 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 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]}; uint64x2_t shufmask64 = {thintable_epi8[mask1], thintable_epi8[mask2]};
uint8x16_t shufmask = vreinterpretq_u8_u64(shufmask64); uint8x16_t shufmask = vreinterpretq_u8_u64(shufmask64);
// we increment by 0x08 the second half of the mask // 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); uint8x16_t inc = simdjson_make_uint8x16_t(0, 0, 0, 0, 0, 0, 0, 0, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08);
#else #else
uint8x16_t inc = {0, 0, 0, 0, 0, 0, 0, 0, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08}; 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 compactmask1 = vcreate_u8(thintable_epi8[mask1]);
uint8x8_t compactmask2 = vcreate_u8(thintable_epi8[mask2]); uint8x8_t compactmask2 = vcreate_u8(thintable_epi8[mask2]);
// we increment by 0x08 the second half of the mask // 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); uint8x8_t inc = simdjson_make_uint8x8_t(0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08);
#else #else
uint8x8_t inc = {0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08}; uint8x8_t inc = {0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08};
@@ -328,7 +328,7 @@ namespace {
// Array constructor // Array constructor
simdjson_inline simd8(const int8_t* values) : simd8(load(values)) {} simdjson_inline simd8(const int8_t* values) : simd8(load(values)) {}
// Member-by-member initialization // Member-by-member initialization
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO #if SIMDJSON_REGULAR_VISUAL_STUDIO
simdjson_inline simd8( 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 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 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 { 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( 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,
0x01, 0x02, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80 0x01, 0x02, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80
+14 -2
View File
@@ -56,10 +56,22 @@
#endif #endif
#endif #endif
#ifdef __cpp_concepts #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> #include <utility>
#define SIMDJSON_SUPPORTS_DESERIALIZATION 1 #define SIMDJSON_SUPPORTS_DESERIALIZATION 1
#else // __cpp_concepts #else
#define SIMDJSON_SUPPORTS_DESERIALIZATION 0 #define SIMDJSON_SUPPORTS_DESERIALIZATION 0
#endif #endif
#else // defined(__cpp_concepts) && !defined(SIMDJSON_CONCEPT_DISABLED)
#define SIMDJSON_SUPPORTS_DESERIALIZATION 0
#endif // defined(__cpp_concepts) && !defined(SIMDJSON_CONCEPT_DISABLED)
#endif // SIMDJSON_COMPILER_CHECK_H #endif // SIMDJSON_COMPILER_CHECK_H
+8 -8
View File
@@ -20,14 +20,14 @@ namespace details {
}; \ }; \
}; };
SIMDJSON_IMPL_CONCEPT(emplace_back, emplace_back); SIMDJSON_IMPL_CONCEPT(emplace_back, emplace_back)
SIMDJSON_IMPL_CONCEPT(emplace, emplace); SIMDJSON_IMPL_CONCEPT(emplace, emplace)
SIMDJSON_IMPL_CONCEPT(push_back, push_back); SIMDJSON_IMPL_CONCEPT(push_back, push_back)
SIMDJSON_IMPL_CONCEPT(add, add); SIMDJSON_IMPL_CONCEPT(add, add)
SIMDJSON_IMPL_CONCEPT(push, push); SIMDJSON_IMPL_CONCEPT(push, push)
SIMDJSON_IMPL_CONCEPT(append, append); SIMDJSON_IMPL_CONCEPT(append, append)
SIMDJSON_IMPL_CONCEPT(insert, insert); SIMDJSON_IMPL_CONCEPT(insert, insert)
SIMDJSON_IMPL_CONCEPT(op_append, operator+=); SIMDJSON_IMPL_CONCEPT(op_append, operator+=)
#undef SIMDJSON_IMPL_CONCEPT #undef SIMDJSON_IMPL_CONCEPT
} // namespace details } // namespace details
+105
View File
@@ -52,11 +52,22 @@ inline simdjson_result<dom::element> simdjson_result<dom::array>::at_pointer(std
return at_pointer(json_pointer); return at_pointer(json_pointer);
} }
inline simdjson_result<std::vector<dom::element>> simdjson_result<dom::array>::at_path_with_wildcard(std::string_view json_path) const noexcept {
if (error()) {
return error();
}
return first.at_path_with_wildcard(json_path);
}
inline simdjson_result<dom::element> simdjson_result<dom::array>::at(size_t index) const noexcept { inline simdjson_result<dom::element> simdjson_result<dom::array>::at(size_t index) const noexcept {
if (error()) { return error(); } if (error()) { return error(); }
return first.at(index); return first.at(index);
} }
inline std::vector<dom::element>& simdjson_result<dom::array>::get_values(std::vector<dom::element>& out) const noexcept {
return first.get_values(out);
}
namespace dom { namespace dom {
// //
@@ -127,6 +138,91 @@ inline simdjson_result<element> array::at_path(std::string_view json_path) const
return at_pointer(json_pointer); return at_pointer(json_pointer);
} }
inline void array::process_json_path_of_child_elements(std::vector<element>::iterator& current, std::vector<element>::iterator& end, const std::string_view& path_suffix, std::vector<element>& accumulator) const noexcept {
if (current == end) {
return;
}
simdjson_result<std::vector<element>> result;
for (auto it = current; it != end; ++it) {
result = it->at_path_with_wildcard(path_suffix);
if (!result.error()) {
std::vector<element> child_result = result.value();
accumulator.reserve(accumulator.size() + child_result.size());
accumulator.insert(accumulator.end(),
std::make_move_iterator(child_result.begin()),
std::make_move_iterator(child_result.end()));
}
}
}
inline simdjson_result<std::vector<element>> array::at_path_with_wildcard(std::string_view json_path) const noexcept {
SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
size_t i = 0;
// json_path.starts_with('$') requires C++20.
if (!json_path.empty() && json_path.front() == '$') {
i = 1;
}
if (i >= json_path.size() || (json_path[i] != '.' && json_path[i] != '[')) {
return INVALID_JSON_POINTER;
}
if (json_path.find("*") != std::string::npos) {
std::vector<element> child_values;
if (
(json_path.compare(i, 3, "[*]") == 0 && json_path.size() == i + 3) ||
(json_path.compare(i, 2,".*") == 0 && json_path.size() == i + 2)
) {
get_values(child_values);
return child_values;
}
std::pair<std::string_view, std::string_view> key_and_json_path = get_next_key_and_json_path(json_path);
std::string_view key = key_and_json_path.first;
json_path = key_and_json_path.second;
if (key.size() > 0) {
if (key == "*") {
get_values(child_values);
} else {
auto pointer_result = at_pointer("/" + std::string(key));
if (!pointer_result.error()) {
child_values.emplace_back(pointer_result.value());
}
}
std::vector<element> result = {};
if (child_values.size() > 0) {
std::vector<element>::iterator child_values_begin = child_values.begin();
std::vector<element>::iterator child_values_end = child_values.end();
process_json_path_of_child_elements(child_values_begin, child_values_end, json_path, result);
}
return result;
} else {
return INVALID_JSON_POINTER;
}
} else {
auto result = at_path(json_path);
if (result.error()) {
return result.error();
}
return std::vector{std::move(result.value())};
}
}
inline simdjson_result<element> array::at(size_t index) const noexcept { inline simdjson_result<element> array::at(size_t index) const noexcept {
SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914 SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
size_t i=0; size_t i=0;
@@ -137,6 +233,15 @@ inline simdjson_result<element> array::at(size_t index) const noexcept {
return INDEX_OUT_OF_BOUNDS; return INDEX_OUT_OF_BOUNDS;
} }
inline std::vector<element>& array::get_values(std::vector<element>& out) const noexcept {
out.reserve(this->size());
for (auto element : *this) {
out.emplace_back(element);
}
return out;
}
inline array::operator element() const noexcept { inline array::operator element() const noexcept {
return element(tape); return element(tape);
} }
+25
View File
@@ -1,6 +1,8 @@
#ifndef SIMDJSON_DOM_ARRAY_H #ifndef SIMDJSON_DOM_ARRAY_H
#define SIMDJSON_DOM_ARRAY_H #define SIMDJSON_DOM_ARRAY_H
#include <vector>
#include "simdjson/dom/base.h" #include "simdjson/dom/base.h"
#include "simdjson/internal/tape_ref.h" #include "simdjson/internal/tape_ref.h"
@@ -108,6 +110,17 @@ public:
*/ */
inline simdjson_result<element> at_pointer(std::string_view json_pointer) const noexcept; inline simdjson_result<element> at_pointer(std::string_view json_pointer) const noexcept;
/**
* Recursive function which processes the json path of each child element
*/
inline void process_json_path_of_child_elements(std::vector<element>::iterator& current, std::vector<element>::iterator& end, const std::string_view& path_suffix, std::vector<element>& accumulator) const noexcept;
/**
* Adds support for JSONPath expression with wildcards '*'
*/
inline simdjson_result<std::vector<element>> at_path_with_wildcard(std::string_view json_path) const noexcept;
/** /**
* Get the value associated with the given JSONPath expression. We only support * Get the value associated with the given JSONPath expression. We only support
* JSONPath queries that trivially convertible to JSON Pointer queries: key * JSONPath queries that trivially convertible to JSON Pointer queries: key
@@ -141,6 +154,15 @@ public:
*/ */
inline simdjson_result<element> at(size_t index) const noexcept; inline simdjson_result<element> at(size_t index) const noexcept;
/**
* Gets the values of items in an array element
* This function has linear-time complexity: the values are checked one by one.
*
* @return The child elements of an array
*/
inline std::vector<element>& get_values(std::vector<element>& out) const noexcept;
/** /**
* Implicitly convert object to element * Implicitly convert object to element
*/ */
@@ -167,8 +189,11 @@ public:
simdjson_inline simdjson_result(error_code error) noexcept; ///< @private simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
inline simdjson_result<dom::element> at_pointer(std::string_view json_pointer) const noexcept; inline simdjson_result<dom::element> at_pointer(std::string_view json_pointer) const noexcept;
inline void process_json_path_of_child_elements(std::vector<dom::element>::iterator& current, std::vector<dom::element>::iterator& end, const std::string_view& path_suffix, std::vector<dom::element>& accumulator) const noexcept;
inline simdjson_result<std::vector<dom::element>> at_path_with_wildcard(std::string_view json_path) const noexcept;
inline simdjson_result<dom::element> at_path(std::string_view json_path) const noexcept; inline simdjson_result<dom::element> at_path(std::string_view json_path) const noexcept;
inline simdjson_result<dom::element> at(size_t index) const noexcept; inline simdjson_result<dom::element> at(size_t index) const noexcept;
inline std::vector<dom::element>& get_values(std::vector<dom::element>& out) const noexcept;
#if SIMDJSON_EXCEPTIONS #if SIMDJSON_EXCEPTIONS
inline dom::array::iterator begin() const noexcept(false); inline dom::array::iterator begin() const noexcept(false);
+20
View File
@@ -128,6 +128,12 @@ simdjson_inline simdjson_result<dom::element> simdjson_result<dom::element>::at_
if (json_pointer == "-1") { return INVALID_JSON_POINTER; } if (json_pointer == "-1") { return INVALID_JSON_POINTER; }
return at_pointer(json_pointer); return at_pointer(json_pointer);
} }
simdjson_inline simdjson_result<std::vector<dom::element>> simdjson_result<dom::element>::at_path_with_wildcard(const std::string_view json_path) const noexcept {
if (error()) { return error(); }
return first.at_path_with_wildcard(json_path);
}
#ifndef SIMDJSON_DISABLE_DEPRECATED_API #ifndef SIMDJSON_DISABLE_DEPRECATED_API
[[deprecated("For standard compliance, use at_pointer instead, and prefix your pointers with a slash '/', see RFC6901 ")]] [[deprecated("For standard compliance, use at_pointer instead, and prefix your pointers with a slash '/', see RFC6901 ")]]
simdjson_inline simdjson_result<dom::element> simdjson_result<dom::element>::at(const std::string_view json_pointer) const noexcept { simdjson_inline simdjson_result<dom::element> simdjson_result<dom::element>::at(const std::string_view json_pointer) const noexcept {
@@ -418,6 +424,20 @@ inline simdjson_result<element> element::at_pointer(std::string_view json_pointe
} }
} }
} }
inline simdjson_result<std::vector<element>> element::at_path_with_wildcard(std::string_view json_path) const noexcept {
SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
switch (tape.tape_ref_type()) {
case internal::tape_type::START_OBJECT:
return object(tape).at_path_with_wildcard(json_path);
case internal::tape_type::START_ARRAY:
return array(tape).at_path_with_wildcard(json_path);
default:
return std::vector<element>{};
}
}
inline simdjson_result<element> element::at_path(std::string_view json_path) const noexcept { inline simdjson_result<element> element::at_path(std::string_view json_path) const noexcept {
auto json_pointer = json_path_to_pointer_conversion(json_path); auto json_pointer = json_path_to_pointer_conversion(json_path);
if (json_pointer == "-1") { return INVALID_JSON_POINTER; } if (json_pointer == "-1") { return INVALID_JSON_POINTER; }
+8
View File
@@ -1,6 +1,8 @@
#ifndef SIMDJSON_DOM_ELEMENT_H #ifndef SIMDJSON_DOM_ELEMENT_H
#define SIMDJSON_DOM_ELEMENT_H #define SIMDJSON_DOM_ELEMENT_H
#include <vector>
#include "simdjson/dom/base.h" #include "simdjson/dom/base.h"
#include "simdjson/dom/array.h" #include "simdjson/dom/array.h"
@@ -372,6 +374,8 @@ public:
* - INCORRECT_TYPE if this is not an object * - INCORRECT_TYPE if this is not an object
*/ */
inline simdjson_result<element> operator[](const char *key) const noexcept; 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 * Get the value associated with the given JSON pointer. We use the RFC 6901
@@ -397,6 +401,8 @@ public:
*/ */
inline simdjson_result<element> at_pointer(const std::string_view json_pointer) const noexcept; inline simdjson_result<element> at_pointer(const std::string_view json_pointer) const noexcept;
inline simdjson_result<std::vector<element>> at_path_with_wildcard(const std::string_view json_path) const noexcept;
/** /**
* Get the value associated with the given JSONPath expression. We only support * Get the value associated with the given JSONPath expression. We only support
* JSONPath queries that trivially convertible to JSON Pointer queries: key * JSONPath queries that trivially convertible to JSON Pointer queries: key
@@ -540,7 +546,9 @@ public:
simdjson_inline simdjson_result<dom::element> operator[](std::string_view key) const noexcept; 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_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_pointer(const std::string_view json_pointer) const noexcept;
simdjson_inline simdjson_result<std::vector<dom::element>> at_path_with_wildcard(const std::string_view json_path) const noexcept;
simdjson_inline simdjson_result<dom::element> at_path(const std::string_view json_path) const noexcept; simdjson_inline simdjson_result<dom::element> at_path(const std::string_view json_path) const noexcept;
[[deprecated("For standard compliance, use at_pointer instead, and prefix your pointers with a slash '/', see RFC6901 ")]] [[deprecated("For standard compliance, use at_pointer instead, and prefix your pointers with a slash '/', see RFC6901 ")]]
simdjson_inline simdjson_result<dom::element> at(const std::string_view json_pointer) const noexcept; simdjson_inline simdjson_result<dom::element> at(const std::string_view json_pointer) const noexcept;
+112
View File
@@ -40,10 +40,19 @@ inline simdjson_result<dom::element> simdjson_result<dom::object>::at_path(std::
if (json_pointer == "-1") { return INVALID_JSON_POINTER; } if (json_pointer == "-1") { return INVALID_JSON_POINTER; }
return at_pointer(json_pointer); return at_pointer(json_pointer);
} }
inline simdjson_result<std::vector<dom::element>> simdjson_result<dom::object>::at_path_with_wildcard(std::string_view json_path) const noexcept {
if (error()) {
return error();
}
return first.at_path_with_wildcard(json_path);
}
inline simdjson_result<dom::element> simdjson_result<dom::object>::at_key(std::string_view key) const noexcept { inline simdjson_result<dom::element> simdjson_result<dom::object>::at_key(std::string_view key) const noexcept {
if (error()) { return error(); } if (error()) { return error(); }
return first.at_key(key); return first.at_key(key);
} }
inline std::vector<dom::element>& simdjson_result<dom::object>::get_values(std::vector<dom::element>& out) const noexcept {
return first.get_values(out);
}
inline simdjson_result<dom::element> simdjson_result<dom::object>::at_key_case_insensitive(std::string_view key) const noexcept { inline simdjson_result<dom::element> simdjson_result<dom::object>::at_key_case_insensitive(std::string_view key) const noexcept {
if (error()) { return error(); } if (error()) { return error(); }
return first.at_key_case_insensitive(key); return first.at_key_case_insensitive(key);
@@ -143,6 +152,97 @@ inline simdjson_result<element> object::at_path(std::string_view json_path) cons
return at_pointer(json_pointer); return at_pointer(json_pointer);
} }
inline void object::process_json_path_of_child_elements(std::vector<element>::iterator& current, std::vector<element>::iterator& end, const std::string_view& path_suffix, std::vector<element>& accumulator) const noexcept {
if (current == end) {
return;
}
simdjson_result<std::vector<element>> result;
for (auto it = current; it != end; ++it) {
result = it->at_path_with_wildcard(path_suffix);
if (!result.error()) {
std::vector<element> child_result = result.value();
accumulator.reserve(accumulator.size() + child_result.size());
accumulator.insert(accumulator.end(),
std::make_move_iterator(child_result.begin()),
std::make_move_iterator(child_result.end()));
}
}
}
inline simdjson_result<std::vector<element>> object::at_path_with_wildcard(std::string_view json_path) const noexcept {
SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
size_t i = 0;
if (json_path.empty()) {
return INVALID_JSON_POINTER;
}
// if JSONPath starts with $, skip it
// json_path.starts_with('$') requires C++20.
if (json_path.front() == '$') {
i = 1;
}
if (i >= json_path.size() || (json_path[i] != '.' && json_path[i] != '[')) {
// expect json path to always start with $ but this isn't currently
// expected in jsonpathutil.h.
return INVALID_JSON_POINTER;
}
if (json_path.find("*") != std::string::npos) {
std::vector<element> child_values;
if (
(json_path.compare(i, 3, "[*]") == 0 && json_path.size() == i + 3) ||
(json_path.compare(i, 2,".*") == 0 && json_path.size() == i + 2)
) {
get_values(child_values);
return child_values;
}
std::pair<std::string_view, std::string_view> key_and_json_path = get_next_key_and_json_path(json_path);
std::string_view key = key_and_json_path.first;
json_path = key_and_json_path.second;
if (key.size() > 0) {
if (key == "*") {
get_values(child_values);
} else {
auto pointer_result = at_pointer("/" + std::string(key));
if (!pointer_result.error()) {
child_values.emplace_back(pointer_result.value());
}
}
std::vector<element> result = {};
if (child_values.size() > 0) {
std::vector<element>::iterator child_values_begin = child_values.begin();
std::vector<element>::iterator child_values_end = child_values.end();
process_json_path_of_child_elements(child_values_begin, child_values_end, json_path, result);
}
return result;
} else {
return INVALID_JSON_POINTER;
}
} else {
auto at_path_result = this->at_path(json_path);
if (at_path_result.error()) {
return at_path_result.error();
}
std::vector<element> result{std::move(at_path_result.value())};
return result;
}
}
inline simdjson_result<element> object::at_key(std::string_view key) const noexcept { inline simdjson_result<element> object::at_key(std::string_view key) const noexcept {
iterator end_field = end(); iterator end_field = end();
for (iterator field = begin(); field != end_field; ++field) { for (iterator field = begin(); field != end_field; ++field) {
@@ -152,6 +252,18 @@ inline simdjson_result<element> object::at_key(std::string_view key) const noexc
} }
return NO_SUCH_FIELD; return NO_SUCH_FIELD;
} }
inline std::vector<element>& object::get_values(std::vector<element>& out) const noexcept {
iterator end_field = end();
iterator begin_field = begin();
out.reserve(std::distance(begin_field, end_field));
for (iterator field = begin_field; field != end_field; ++field) {
out.emplace_back(field.value());
}
return out;
}
// In case you wonder why we need this, please see // In case you wonder why we need this, please see
// https://github.com/simdjson/simdjson/issues/323 // https://github.com/simdjson/simdjson/issues/323
// People do seek keys in a case-insensitive manner. // People do seek keys in a case-insensitive manner.
+25
View File
@@ -1,6 +1,8 @@
#ifndef SIMDJSON_DOM_OBJECT_H #ifndef SIMDJSON_DOM_OBJECT_H
#define SIMDJSON_DOM_OBJECT_H #define SIMDJSON_DOM_OBJECT_H
#include <vector>
#include "simdjson/dom/base.h" #include "simdjson/dom/base.h"
#include "simdjson/dom/element.h" #include "simdjson/dom/element.h"
#include "simdjson/internal/tape_ref.h" #include "simdjson/internal/tape_ref.h"
@@ -145,6 +147,7 @@ public:
* - INCORRECT_TYPE if this is not an object * - INCORRECT_TYPE if this is not an object
*/ */
inline simdjson_result<element> operator[](const char *key) const noexcept; 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 * Get the value associated with the given JSON pointer. We use the RFC 6901
@@ -171,6 +174,16 @@ public:
*/ */
inline simdjson_result<element> at_pointer(std::string_view json_pointer) const noexcept; inline simdjson_result<element> at_pointer(std::string_view json_pointer) const noexcept;
/**
* Recursive function which processes the json path of each child element
*/
inline void process_json_path_of_child_elements(std::vector<element>::iterator& current, std::vector<element>::iterator& end, const std::string_view& path_suffix, std::vector<element>& accumulator) const noexcept;
/**
* Adds support for JSONPath expression with wildcards '*'
*/
inline simdjson_result<std::vector<element>> at_path_with_wildcard(std::string_view json_path) const noexcept;
/** /**
* Get the value associated with the given JSONPath expression. We only support * Get the value associated with the given JSONPath expression. We only support
* JSONPath queries that trivially convertible to JSON Pointer queries: key * JSONPath queries that trivially convertible to JSON Pointer queries: key
@@ -202,6 +215,14 @@ public:
*/ */
inline simdjson_result<element> at_key(std::string_view key) const noexcept; inline simdjson_result<element> at_key(std::string_view key) const noexcept;
/**
* Gets the values associated with keys of an object
* This function has linear-time complexity: the keys are checked one by one.
*
* @return the values associated with each key of an object
*/
inline std::vector<element>& get_values(std::vector<element>& out) const noexcept;
/** /**
* Get the value associated with the given key in a case-insensitive manner. * Get the value associated with the given key in a case-insensitive manner.
* It is only guaranteed to work over ASCII inputs. * It is only guaranteed to work over ASCII inputs.
@@ -258,9 +279,13 @@ public:
inline simdjson_result<dom::element> operator[](std::string_view key) const noexcept; inline simdjson_result<dom::element> operator[](std::string_view key) const noexcept;
inline simdjson_result<dom::element> operator[](const char *key) const noexcept; inline simdjson_result<dom::element> operator[](const char *key) const noexcept;
simdjson_result<dom::element> operator[](int) const noexcept = delete;
inline simdjson_result<dom::element> at_pointer(std::string_view json_pointer) const noexcept; inline simdjson_result<dom::element> at_pointer(std::string_view json_pointer) const noexcept;
inline void process_json_path_of_child_elements(std::vector<dom::element>::iterator& current, std::vector<dom::element>::iterator& end, const std::string_view& path_suffix, std::vector<dom::element>& accumulator) const noexcept;
inline simdjson_result<std::vector<dom::element>> at_path_with_wildcard(std::string_view json_path_new) const noexcept;
inline simdjson_result<dom::element> at_path(std::string_view json_path) const noexcept; inline simdjson_result<dom::element> at_path(std::string_view json_path) const noexcept;
inline simdjson_result<dom::element> at_key(std::string_view key) const noexcept; inline simdjson_result<dom::element> at_key(std::string_view key) const noexcept;
inline std::vector<dom::element>& get_values(std::vector<dom::element>& out) const noexcept;
inline simdjson_result<dom::element> at_key_case_insensitive(std::string_view key) const noexcept; inline simdjson_result<dom::element> at_key_case_insensitive(std::string_view key) const noexcept;
#if SIMDJSON_EXCEPTIONS #if SIMDJSON_EXCEPTIONS
+16
View File
@@ -202,6 +202,22 @@ public:
* simdjson::dom::parser parser; * simdjson::dom::parser parser;
* simdjson::dom::element element = parser.parse(padded_json_copy.get(), json_len, false); * 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 * ### Parser Capacity
* *
* If the parser's current capacity is less than len, it will allocate enough capacity * If the parser's current capacity is less than len, it will allocate enough capacity
+1 -1
View File
@@ -86,7 +86,7 @@ struct simdjson_error : public std::exception {
*/ */
simdjson_error(error_code error) noexcept : _error{error} { } simdjson_error(error_code error) noexcept : _error{error} { }
/** The error message */ /** 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 */ /** The error code */
error_code error() const noexcept { return _error; } error_code error() const noexcept { return _error; }
private: private:
+2 -1
View File
@@ -44,7 +44,8 @@ public:
* calling this function, if successful, the array is 'rewinded' at its * 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., * beginning as if it had never been accessed. If the JSON is malformed (e.g.,
* there is a missing comma), then an error is returned and it is no longer * there is a missing comma), then an error is returned and it is no longer
* safe to continue. * safe to continue. 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 * To check that an array is empty, it is more performant to use
* the is_empty() method. * the is_empty() method.
@@ -246,7 +246,14 @@ simdjson_inline simdjson_result<value> document::operator[](const char *key) & n
} }
simdjson_inline error_code document::consume() noexcept { 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(); } if(error) { iter.abandon(); }
return error; return error;
} }
@@ -268,6 +275,8 @@ simdjson_inline simdjson_result<json_type> document::type() noexcept {
} }
simdjson_inline simdjson_result<bool> document::is_scalar() 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; json_type this_type;
auto error = type().get(this_type); auto error = type().get(this_type);
if(error) { return error; } if(error) { return error; }
+6 -1
View File
@@ -354,7 +354,8 @@ public:
* calling this function, if successful, the array is 'rewinded' at its * 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., * beginning as if it had never been accessed. If the JSON is malformed (e.g.,
* there is a missing comma), then an error is returned and it is no longer * there is a missing comma), then an error is returned and it is no longer
* safe to continue. * safe to continue. 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; simdjson_inline simdjson_result<size_t> count_elements() & noexcept;
/** /**
@@ -466,6 +467,7 @@ public:
simdjson_inline simdjson_result<value> operator[](std::string_view key) & noexcept; 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; */ /** @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_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. * Get the type of this JSON value. It does not validate or consume the value.
@@ -852,6 +854,7 @@ public:
simdjson_inline simdjson_result<value> find_field(const char *key) & noexcept; 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[](std::string_view key) & noexcept;
simdjson_inline simdjson_result<value> operator[](const char *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(std::string_view key) & noexcept;
simdjson_inline simdjson_result<value> find_field_unordered(const char *key) & noexcept; simdjson_inline simdjson_result<value> find_field_unordered(const char *key) & noexcept;
@@ -930,6 +933,7 @@ public:
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> find_field(const char *key) & noexcept; 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[](std::string_view key) & noexcept;
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> operator[](const char *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(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::value> find_field_unordered(const char *key) & noexcept;
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::json_type> type() noexcept; simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::json_type> type() noexcept;
@@ -1007,6 +1011,7 @@ public:
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> find_field(const char *key) & noexcept; 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[](std::string_view key) & noexcept;
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> operator[](const char *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(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::value> find_field_unordered(const char *key) & noexcept;
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::json_type> type() noexcept; simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::json_type> type() noexcept;
@@ -84,6 +84,22 @@ public:
* using a sanitizer that verifies that no uninitialized byte is read, then you should initialize the * using a sanitizer that verifies that no uninitialized byte is read, then you should initialize the
* SIMDJSON_PADDING bytes to avoid runtime warnings. * SIMDJSON_PADDING bytes to avoid runtime warnings.
* *
* ### 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 json The JSON to parse.
* @param len The length of the JSON. * @param len The length of the JSON.
* @param capacity The number of bytes allocated in the JSON (must be at least len+SIMDJSON_PADDING). * @param capacity The number of bytes allocated in the JSON (must be at least len+SIMDJSON_PADDING).
@@ -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 { simdjson_inline bool raw_json_string::is_free_from_unescaped_quote(std::string_view target) noexcept {
size_t pos{0}; size_t pos{0};
// if the content has no escape character, just scan through it quickly! while(pos < target.size()) {
for(;pos < target.size() && target[pos] != '\\';pos++) {} pos = target.find('"', pos);
// slow path may begin. if(pos == std::string_view::npos) { return true; }
bool escaping{false}; if(pos != 0 && target[pos-1] != '\\') { return false; }
for(;pos < target.size();pos++) { if(pos > 1 && target[pos-2] == '\\') {
if((target[pos] == '"') && !escaping) { size_t backslash_count{2};
return false; for(size_t i = 3; i <= pos; i++) {
} else if(target[pos] == '\\') { if(target[pos-i] == '\\') { backslash_count++; }
escaping = !escaping; else { break; }
} else { }
escaping = false; if(backslash_count % 2 == 0) { return false; }
} }
pos++;
} }
return true; return true;
} }
simdjson_inline bool raw_json_string::is_free_from_unescaped_quote(const char* target) noexcept { simdjson_inline bool raw_json_string::is_free_from_unescaped_quote(const char* target) noexcept {
size_t pos{0}; size_t pos{0};
// if the content has no escape character, just scan through it quickly! while(target[pos]) {
for(;target[pos] && target[pos] != '\\';pos++) {} const char * result = strchr(target+pos, '"');
// slow path may begin. if(result == nullptr) { return true; }
bool escaping{false}; pos = result - target;
for(;target[pos];pos++) { if(pos != 0 && target[pos-1] != '\\') { return false; }
if((target[pos] == '"') && !escaping) { if(pos > 1 && target[pos-2] == '\\') {
return false; size_t backslash_count{2};
} else if(target[pos] == '\\') { for(size_t i = 3; i <= pos; i++) {
escaping = !escaping; if(target[pos-i] == '\\') { backslash_count++; }
} else { else { break; }
escaping = false; }
if(backslash_count % 2 == 0) { return false; }
} }
pos++;
} }
return true; 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 { 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. // the raw content is quote terminated within a valid JSON string.
if(target.size() <= SIMDJSON_PADDING) { if(target.size() <= SIMDJSON_PADDING) {
return (raw()[target.size()] == '"') && !memcmp(raw(), target.data(), target.size()); return (raw()[target.size()] == '"') && !memcmp(raw(), target.data(), target.size());
+13
View File
@@ -163,6 +163,17 @@ public:
* Important: a value should be consumed once. Calling get_string() twice on the same value * Important: a value should be consumed once. Calling get_string() twice on the same value
* is an error. * 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 * @returns An UTF-8 string. The string is stored in the parser and will be invalidated the next
* time it parses a document or when it is destroyed. * time it parses a document or when it is destroyed.
* @returns INCORRECT_TYPE if the JSON value is not a string. * @returns INCORRECT_TYPE if the JSON value is not a string.
@@ -414,6 +425,7 @@ public:
simdjson_inline simdjson_result<value> operator[](std::string_view key) noexcept; 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; */ /** @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_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. * Get the type of this JSON value. It does not validate or consume the value.
@@ -781,6 +793,7 @@ public:
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> operator[](std::string_view key) noexcept; 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; */ /** @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_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. * Get the type of this JSON value.
+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). // 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. // 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. // get written.
// Design consideration: it seems like a function with the // Design consideration: it seems like a function with the
// signature simd8<L> compress(uint32_t mask) would be // signature simd8<L> compress(uint32_t mask) would be
// sensible, but the AVX ISA makes this kind of approach difficult. // sensible, but the AVX ISA makes this kind of approach difficult.
template<typename L> template<typename L>
simdjson_inline void compress(uint64_t mask, L * output) const { 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> template<typename L>
+48 -3
View File
@@ -4,6 +4,8 @@
#include <string> #include <string>
#include <string_view> #include <string_view>
#include <utility>
namespace simdjson { namespace simdjson {
/** /**
* Converts JSONPath to JSON Pointer. * Converts JSONPath to JSON Pointer.
@@ -12,12 +14,12 @@ namespace simdjson {
*/ */
inline std::string json_path_to_pointer_conversion(std::string_view json_path) { inline std::string json_path_to_pointer_conversion(std::string_view json_path) {
size_t i = 0; size_t i = 0;
// if JSONPath starts with $, skip it // if JSONPath starts with $, skip it
// json_path.starts_with('$') requires C++20.
if (!json_path.empty() && json_path.front() == '$') { if (!json_path.empty() && json_path.front() == '$') {
i = 1; i = 1;
} }
if (json_path.empty() || (json_path[i] != '.' && if (i >= json_path.size() || (json_path[i] != '.' &&
json_path[i] != '[')) { json_path[i] != '[')) {
return "-1"; // This is just a sentinel value, the caller should check for this and return an error. return "-1"; // This is just a sentinel value, the caller should check for this and return an error.
} }
@@ -60,5 +62,48 @@ inline std::string json_path_to_pointer_conversion(std::string_view json_path) {
return result; return result;
} }
inline std::pair<std::string_view, std::string_view> get_next_key_and_json_path(std::string_view& json_path) {
std::string_view key;
if (json_path.empty()) {
return {key, json_path};
}
size_t i = 0;
// if JSONPath starts with $, skip it
if (json_path.front() == '$') {
i = 1;
}
if (i < json_path.length() && json_path[i] == '.') {
i += 1;
size_t key_start = i;
while (i < json_path.length() && json_path[i] != '[' && json_path[i] != '.') {
++i;
}
key = json_path.substr(key_start, i - key_start);
} else if ((i+1 < json_path.size()) && json_path[i] == '[' && (json_path[i+1] == '\'' || json_path[i+1] == '"')) {
i += 2;
size_t key_start = i;
while (i < json_path.length() && json_path[i] != '\'' && json_path[i] != '"') {
++i;
}
key = json_path.substr(key_start, i - key_start);
i += 2;
} else if ((i+2 < json_path.size()) && json_path[i] == '[' && json_path[i+1] == '*' && json_path[i+2] == ']') { // i.e [*].additional_keys or [*]["additional_keys"]
key = "*";
i += 3;
}
return std::make_pair(key, json_path.substr(i));
}
} // namespace simdjson } // namespace simdjson
#endif // SIMDJSON_JSONPATHUTIL_H #endif // SIMDJSON_JSONPATHUTIL_H
+12 -12
View File
@@ -166,22 +166,22 @@ inline namespace literals {
inline namespace string_view_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 }; 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 }; 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 }; 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 }; 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 #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 }; 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 }; 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 }; 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 }; 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 #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 }; 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 }; 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 }; 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 }; 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 } // 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); return simdjson::padded_string(str, len);
} }
#ifdef __cpp_char8_t #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); return simdjson::padded_string(reinterpret_cast<const char8_t *>(str), len);
} }
#endif #endif
+2 -2
View File
@@ -161,9 +161,9 @@ inline std::ostream& operator<<(std::ostream& out, simdjson_result<padded_string
} // namespace simdjson } // namespace simdjson
// This is deliberately outside of simdjson so that people get it without having to use the namespace // 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 #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 #endif
namespace simdjson { 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(); } inline std::ostream& operator<<(std::ostream& out, simdjson_result<padded_string_view> &s) noexcept(false) { return out << s.value(); }
#endif #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 } // 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); inline std::ostream& operator<<(std::ostream& out, simdjson_result<padded_string_view> &s) noexcept(false);
#endif #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 } // namespace simdjson
#endif // SIMDJSON_PADDED_STRING_VIEW_H #endif // SIMDJSON_PADDED_STRING_VIEW_H
+5
View File
@@ -6,11 +6,15 @@
#include <cstdlib> #include <cstdlib>
#include <cfloat> #include <cfloat>
#include <cassert> #include <cassert>
#include <climits>
#ifndef _WIN32 #ifndef _WIN32
// strcasecmp, strncasecmp // strcasecmp, strncasecmp
#include <strings.h> #include <strings.h>
#endif #endif
static_assert(CHAR_BIT == 8, "simdjson requires 8-bit bytes");
// We are using size_t without namespace std:: throughout the project // We are using size_t without namespace std:: throughout the project
using std::size_t; using std::size_t;
@@ -44,6 +48,7 @@ using std::size_t;
#elif defined(__loongarch_lp64) #elif defined(__loongarch_lp64)
#define SIMDJSON_IS_LOONGARCH64 1 #define SIMDJSON_IS_LOONGARCH64 1
#elif defined(__PPC64__) || defined(_M_PPC64) #elif defined(__PPC64__) || defined(_M_PPC64)
#define SIMDJSON_IS_PPC64 1
#if defined(__ALTIVEC__) #if defined(__ALTIVEC__)
#define SIMDJSON_IS_PPC64_VMX 1 #define SIMDJSON_IS_PPC64_VMX 1
#endif // defined(__ALTIVEC__) #endif // defined(__ALTIVEC__)
+3 -3
View File
@@ -4,7 +4,7 @@
#define SIMDJSON_SIMDJSON_VERSION_H #define SIMDJSON_SIMDJSON_VERSION_H
/** The version of simdjson being used (major.minor.revision) */ /** The version of simdjson being used (major.minor.revision) */
#define SIMDJSON_VERSION "3.10.1" #define SIMDJSON_VERSION "3.12.2"
namespace simdjson { namespace simdjson {
enum { enum {
@@ -15,11 +15,11 @@ enum {
/** /**
* The minor version (major.MINOR.revision) of simdjson being used. * 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. * The revision (major.minor.REVISION) of simdjson being used.
*/ */
SIMDJSON_VERSION_REVISION = 1 SIMDJSON_VERSION_REVISION = 2
}; };
} // namespace simdjson } // namespace simdjson
+18
View File
@@ -441,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,"amalgamate_demo.cpp"),AMALGAMATE_OUTPUT_PATH)
shutil.copy2(os.path.join(SCRIPTPATH,"README.md"),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("Done with all files generation.")
print(f"Files have been written to directory: {AMALGAMATE_OUTPUT_PATH}/") print(f"Files have been written to directory: {AMALGAMATE_OUTPUT_PATH}/")
@@ -449,6 +465,8 @@ print(subprocess.run(['ls', '-la', AMAL_C, AMAL_H, DEMOCPP, README],
print("Done with all files generation.") print("Done with all files generation.")
# #
# Instructions to create demo # Instructions to create demo
# #
+81 -48
View File
@@ -1,4 +1,4 @@
/* auto-generated on 2024-10-10 22:17:29 -0400. Do not edit! */ /* auto-generated on 2025-02-14 16:11:36 -0500. Do not edit! */
/* including simdjson.cpp: */ /* including simdjson.cpp: */
/* begin file simdjson.cpp */ /* begin file simdjson.cpp */
#define SIMDJSON_SRC_SIMDJSON_CPP #define SIMDJSON_SRC_SIMDJSON_CPP
@@ -83,12 +83,24 @@
#endif #endif
#endif #endif
#ifdef __cpp_concepts #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> #include <utility>
#define SIMDJSON_SUPPORTS_DESERIALIZATION 1 #define SIMDJSON_SUPPORTS_DESERIALIZATION 1
#else // __cpp_concepts #else
#define SIMDJSON_SUPPORTS_DESERIALIZATION 0 #define SIMDJSON_SUPPORTS_DESERIALIZATION 0
#endif #endif
#else // defined(__cpp_concepts) && !defined(SIMDJSON_CONCEPT_DISABLED)
#define SIMDJSON_SUPPORTS_DESERIALIZATION 0
#endif // defined(__cpp_concepts) && !defined(SIMDJSON_CONCEPT_DISABLED)
#endif // SIMDJSON_COMPILER_CHECK_H #endif // SIMDJSON_COMPILER_CHECK_H
/* end file simdjson/compiler_check.h */ /* end file simdjson/compiler_check.h */
/* including simdjson/portability.h: #include "simdjson/portability.h" */ /* including simdjson/portability.h: #include "simdjson/portability.h" */
@@ -101,11 +113,15 @@
#include <cstdlib> #include <cstdlib>
#include <cfloat> #include <cfloat>
#include <cassert> #include <cassert>
#include <climits>
#ifndef _WIN32 #ifndef _WIN32
// strcasecmp, strncasecmp // strcasecmp, strncasecmp
#include <strings.h> #include <strings.h>
#endif #endif
static_assert(CHAR_BIT == 8, "simdjson requires 8-bit bytes");
// We are using size_t without namespace std:: throughout the project // We are using size_t without namespace std:: throughout the project
using std::size_t; using std::size_t;
@@ -139,6 +155,7 @@ using std::size_t;
#elif defined(__loongarch_lp64) #elif defined(__loongarch_lp64)
#define SIMDJSON_IS_LOONGARCH64 1 #define SIMDJSON_IS_LOONGARCH64 1
#elif defined(__PPC64__) || defined(_M_PPC64) #elif defined(__PPC64__) || defined(_M_PPC64)
#define SIMDJSON_IS_PPC64 1
#if defined(__ALTIVEC__) #if defined(__ALTIVEC__)
#define SIMDJSON_IS_PPC64_VMX 1 #define SIMDJSON_IS_PPC64_VMX 1
#endif // defined(__ALTIVEC__) #endif // defined(__ALTIVEC__)
@@ -759,22 +776,22 @@ inline namespace literals {
inline namespace string_view_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 }; 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 }; 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 }; 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 }; return std::wstring_view{ str, len };
} }
@@ -2105,22 +2122,22 @@ nssv_inline_ns namespace string_view_literals {
#if nssv_CONFIG_STD_SV_OPERATOR && nssv_HAVE_STD_DEFINED_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 }; 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 }; 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 }; 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 }; return nonstd::sv_lite::wstring_view{ str, len };
} }
@@ -2129,22 +2146,22 @@ nssv_constexpr nonstd::sv_lite::wstring_view operator "" sv( const wchar_t* str,
#if nssv_CONFIG_USR_SV_OPERATOR #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 }; 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 }; 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 }; 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 }; return nonstd::sv_lite::wstring_view{ str, len };
} }
@@ -2480,7 +2497,7 @@ struct simdjson_error : public std::exception {
*/ */
simdjson_error(error_code error) noexcept : _error{error} { } simdjson_error(error_code error) noexcept : _error{error} { }
/** The error message */ /** 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 */ /** The error code */
error_code error() const noexcept { return _error; } error_code error() const noexcept { return _error; }
private: private:
@@ -2736,14 +2753,14 @@ namespace details {
}; \ }; \
}; };
SIMDJSON_IMPL_CONCEPT(emplace_back, emplace_back); SIMDJSON_IMPL_CONCEPT(emplace_back, emplace_back)
SIMDJSON_IMPL_CONCEPT(emplace, emplace); SIMDJSON_IMPL_CONCEPT(emplace, emplace)
SIMDJSON_IMPL_CONCEPT(push_back, push_back); SIMDJSON_IMPL_CONCEPT(push_back, push_back)
SIMDJSON_IMPL_CONCEPT(add, add); SIMDJSON_IMPL_CONCEPT(add, add)
SIMDJSON_IMPL_CONCEPT(push, push); SIMDJSON_IMPL_CONCEPT(push, push)
SIMDJSON_IMPL_CONCEPT(append, append); SIMDJSON_IMPL_CONCEPT(append, append)
SIMDJSON_IMPL_CONCEPT(insert, insert); SIMDJSON_IMPL_CONCEPT(insert, insert)
SIMDJSON_IMPL_CONCEPT(op_append, operator+=); SIMDJSON_IMPL_CONCEPT(op_append, operator+=)
#undef SIMDJSON_IMPL_CONCEPT #undef SIMDJSON_IMPL_CONCEPT
} // namespace details } // namespace details
@@ -7788,7 +7805,7 @@ SIMDJSON_NO_SANITIZE_UNDEFINED
// See issue https://github.com/simdjson/simdjson/issues/1965 // See issue https://github.com/simdjson/simdjson/issues/1965
SIMDJSON_NO_SANITIZE_MEMORY SIMDJSON_NO_SANITIZE_MEMORY
simdjson_inline int trailing_zeroes(uint64_t input_num) { simdjson_inline int trailing_zeroes(uint64_t input_num) {
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO #if SIMDJSON_REGULAR_VISUAL_STUDIO
unsigned long ret; unsigned long ret;
// Search the mask data from least significant bit (LSB) // Search the mask data from least significant bit (LSB)
// to the most significant bit (MSB) for a set bit (1). // to the most significant bit (MSB) for a set bit (1).
@@ -7812,7 +7829,7 @@ simdjson_inline uint64_t clear_lowest_bit(uint64_t input_num) {
SIMDJSON_NO_SANITIZE_UNDEFINED SIMDJSON_NO_SANITIZE_UNDEFINED
/* result might be undefined when input_num is zero */ /* result might be undefined when input_num is zero */
simdjson_inline int leading_zeroes(uint64_t input_num) { simdjson_inline int leading_zeroes(uint64_t input_num) {
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO #if SIMDJSON_REGULAR_VISUAL_STUDIO
unsigned long leading_zero = 0; unsigned long leading_zero = 0;
// Search the mask data from most significant bit (MSB) // Search the mask data from most significant bit (MSB)
// to least significant bit (LSB) for a set bit (1). // to least significant bit (LSB) for a set bit (1).
@@ -7865,7 +7882,7 @@ simdjson_inline uint64_t zero_leading_bit(uint64_t rev_bits, int leading_zeroes)
#endif #endif
simdjson_inline bool add_overflow(uint64_t value1, uint64_t value2, uint64_t *result) { 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; *result = value1 + value2;
return *result < value1; return *result < value1;
#else #else
@@ -8008,7 +8025,7 @@ namespace arm64 {
namespace { namespace {
namespace simd { namespace simd {
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO #if SIMDJSON_REGULAR_VISUAL_STUDIO
namespace { namespace {
// Start of private section with Visual Studio workaround // Start of private section with Visual Studio workaround
@@ -8117,7 +8134,7 @@ namespace {
// We return uint32_t instead of uint16_t because that seems to be more efficient for most // 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). // purposes (cutting it down to uint16_t costs performance in some compilers).
simdjson_inline uint32_t to_bitmask() const { 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, 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); 0x01, 0x02, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80);
#else #else
@@ -8148,7 +8165,7 @@ namespace {
// Splat constructor // Splat constructor
simdjson_inline simd8(uint8_t _value) : simd8(splat(_value)) {} simdjson_inline simd8(uint8_t _value) : simd8(splat(_value)) {}
// Member-by-member initialization // Member-by-member initialization
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO #if SIMDJSON_REGULAR_VISUAL_STUDIO
simdjson_inline simd8( 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 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 uint8_t v8, uint8_t v9, uint8_t v10, uint8_t v11, uint8_t v12, uint8_t v13, uint8_t v14, uint8_t v15
@@ -8242,7 +8259,7 @@ namespace {
uint64x2_t shufmask64 = {thintable_epi8[mask1], thintable_epi8[mask2]}; uint64x2_t shufmask64 = {thintable_epi8[mask1], thintable_epi8[mask2]};
uint8x16_t shufmask = vreinterpretq_u8_u64(shufmask64); uint8x16_t shufmask = vreinterpretq_u8_u64(shufmask64);
// we increment by 0x08 the second half of the mask // 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); uint8x16_t inc = simdjson_make_uint8x16_t(0, 0, 0, 0, 0, 0, 0, 0, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08);
#else #else
uint8x16_t inc = {0, 0, 0, 0, 0, 0, 0, 0, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08}; uint8x16_t inc = {0, 0, 0, 0, 0, 0, 0, 0, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08};
@@ -8272,7 +8289,7 @@ namespace {
uint8x8_t compactmask1 = vcreate_u8(thintable_epi8[mask1]); uint8x8_t compactmask1 = vcreate_u8(thintable_epi8[mask1]);
uint8x8_t compactmask2 = vcreate_u8(thintable_epi8[mask2]); uint8x8_t compactmask2 = vcreate_u8(thintable_epi8[mask2]);
// we increment by 0x08 the second half of the mask // 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); uint8x8_t inc = simdjson_make_uint8x8_t(0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08);
#else #else
uint8x8_t inc = {0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08}; uint8x8_t inc = {0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08};
@@ -8324,7 +8341,7 @@ namespace {
// Array constructor // Array constructor
simdjson_inline simd8(const int8_t* values) : simd8(load(values)) {} simdjson_inline simd8(const int8_t* values) : simd8(load(values)) {}
// Member-by-member initialization // Member-by-member initialization
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO #if SIMDJSON_REGULAR_VISUAL_STUDIO
simdjson_inline simd8( 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 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 int8_t v8, int8_t v9, int8_t v10, int8_t v11, int8_t v12, int8_t v13, int8_t v14, int8_t v15
@@ -8445,7 +8462,7 @@ namespace {
} }
simdjson_inline uint64_t to_bitmask() const { 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( 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,
0x01, 0x02, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80 0x01, 0x02, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80
@@ -10555,7 +10572,7 @@ SIMDJSON_NO_SANITIZE_UNDEFINED
// See issue https://github.com/simdjson/simdjson/issues/1965 // See issue https://github.com/simdjson/simdjson/issues/1965
SIMDJSON_NO_SANITIZE_MEMORY SIMDJSON_NO_SANITIZE_MEMORY
simdjson_inline int trailing_zeroes(uint64_t input_num) { simdjson_inline int trailing_zeroes(uint64_t input_num) {
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO #if SIMDJSON_REGULAR_VISUAL_STUDIO
unsigned long ret; unsigned long ret;
// Search the mask data from least significant bit (LSB) // Search the mask data from least significant bit (LSB)
// to the most significant bit (MSB) for a set bit (1). // to the most significant bit (MSB) for a set bit (1).
@@ -10579,7 +10596,7 @@ simdjson_inline uint64_t clear_lowest_bit(uint64_t input_num) {
SIMDJSON_NO_SANITIZE_UNDEFINED SIMDJSON_NO_SANITIZE_UNDEFINED
/* result might be undefined when input_num is zero */ /* result might be undefined when input_num is zero */
simdjson_inline int leading_zeroes(uint64_t input_num) { simdjson_inline int leading_zeroes(uint64_t input_num) {
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO #if SIMDJSON_REGULAR_VISUAL_STUDIO
unsigned long leading_zero = 0; unsigned long leading_zero = 0;
// Search the mask data from most significant bit (MSB) // Search the mask data from most significant bit (MSB)
// to least significant bit (LSB) for a set bit (1). // to least significant bit (LSB) for a set bit (1).
@@ -10632,7 +10649,7 @@ simdjson_inline uint64_t zero_leading_bit(uint64_t rev_bits, int leading_zeroes)
#endif #endif
simdjson_inline bool add_overflow(uint64_t value1, uint64_t value2, uint64_t *result) { 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; *result = value1 + value2;
return *result < value1; return *result < value1;
#else #else
@@ -10775,7 +10792,7 @@ namespace arm64 {
namespace { namespace {
namespace simd { namespace simd {
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO #if SIMDJSON_REGULAR_VISUAL_STUDIO
namespace { namespace {
// Start of private section with Visual Studio workaround // Start of private section with Visual Studio workaround
@@ -10884,7 +10901,7 @@ namespace {
// We return uint32_t instead of uint16_t because that seems to be more efficient for most // 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). // purposes (cutting it down to uint16_t costs performance in some compilers).
simdjson_inline uint32_t to_bitmask() const { 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, 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); 0x01, 0x02, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80);
#else #else
@@ -10915,7 +10932,7 @@ namespace {
// Splat constructor // Splat constructor
simdjson_inline simd8(uint8_t _value) : simd8(splat(_value)) {} simdjson_inline simd8(uint8_t _value) : simd8(splat(_value)) {}
// Member-by-member initialization // Member-by-member initialization
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO #if SIMDJSON_REGULAR_VISUAL_STUDIO
simdjson_inline simd8( 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 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 uint8_t v8, uint8_t v9, uint8_t v10, uint8_t v11, uint8_t v12, uint8_t v13, uint8_t v14, uint8_t v15
@@ -11009,7 +11026,7 @@ namespace {
uint64x2_t shufmask64 = {thintable_epi8[mask1], thintable_epi8[mask2]}; uint64x2_t shufmask64 = {thintable_epi8[mask1], thintable_epi8[mask2]};
uint8x16_t shufmask = vreinterpretq_u8_u64(shufmask64); uint8x16_t shufmask = vreinterpretq_u8_u64(shufmask64);
// we increment by 0x08 the second half of the mask // 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); uint8x16_t inc = simdjson_make_uint8x16_t(0, 0, 0, 0, 0, 0, 0, 0, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08);
#else #else
uint8x16_t inc = {0, 0, 0, 0, 0, 0, 0, 0, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08}; uint8x16_t inc = {0, 0, 0, 0, 0, 0, 0, 0, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08};
@@ -11039,7 +11056,7 @@ namespace {
uint8x8_t compactmask1 = vcreate_u8(thintable_epi8[mask1]); uint8x8_t compactmask1 = vcreate_u8(thintable_epi8[mask1]);
uint8x8_t compactmask2 = vcreate_u8(thintable_epi8[mask2]); uint8x8_t compactmask2 = vcreate_u8(thintable_epi8[mask2]);
// we increment by 0x08 the second half of the mask // 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); uint8x8_t inc = simdjson_make_uint8x8_t(0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08);
#else #else
uint8x8_t inc = {0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08}; uint8x8_t inc = {0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08};
@@ -11091,7 +11108,7 @@ namespace {
// Array constructor // Array constructor
simdjson_inline simd8(const int8_t* values) : simd8(load(values)) {} simdjson_inline simd8(const int8_t* values) : simd8(load(values)) {}
// Member-by-member initialization // Member-by-member initialization
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO #if SIMDJSON_REGULAR_VISUAL_STUDIO
simdjson_inline simd8( 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 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 int8_t v8, int8_t v9, int8_t v10, int8_t v11, int8_t v12, int8_t v13, int8_t v14, int8_t v15
@@ -11212,7 +11229,7 @@ namespace {
} }
simdjson_inline uint64_t to_bitmask() const { 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( 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,
0x01, 0x02, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80 0x01, 0x02, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80
@@ -14165,6 +14182,7 @@ simdjson_warn_unused error_code dom_parser_implementation::stage2_next(dom::docu
return stage2::tape_builder::parse_document<true>(*this, _doc); 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 { 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); return arm64::stringparsing::parse_string(src, dst, allow_replacement);
} }
@@ -20392,6 +20410,7 @@ simdjson_warn_unused error_code dom_parser_implementation::stage2_next(dom::docu
return stage2::tape_builder::parse_document<true>(*this, _doc); 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 { 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); return haswell::stringparsing::parse_string(src, dst, replacement_char);
} }
@@ -20794,14 +20813,18 @@ namespace simd {
// Copies to 'output" all bytes corresponding to a 0 in the mask (interpreted as a bitset). // 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. // 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. // get written.
// Design consideration: it seems like a function with the // Design consideration: it seems like a function with the
// signature simd8<L> compress(uint32_t mask) would be // signature simd8<L> compress(uint32_t mask) would be
// sensible, but the AVX ISA makes this kind of approach difficult. // sensible, but the AVX ISA makes this kind of approach difficult.
template<typename L> template<typename L>
simdjson_inline void compress(uint64_t mask, L * output) const { 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> template<typename L>
@@ -23424,14 +23447,18 @@ namespace simd {
// Copies to 'output" all bytes corresponding to a 0 in the mask (interpreted as a bitset). // 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. // 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. // get written.
// Design consideration: it seems like a function with the // Design consideration: it seems like a function with the
// signature simd8<L> compress(uint32_t mask) would be // signature simd8<L> compress(uint32_t mask) would be
// sensible, but the AVX ISA makes this kind of approach difficult. // sensible, but the AVX ISA makes this kind of approach difficult.
template<typename L> template<typename L>
simdjson_inline void compress(uint64_t mask, L * output) const { 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> template<typename L>
@@ -26646,6 +26673,7 @@ simdjson_warn_unused error_code dom_parser_implementation::stage2_next(dom::docu
return stage2::tape_builder::parse_document<true>(*this, _doc); 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 { 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); return icelake::stringparsing::parse_string(src, dst, replacement_char);
} }
@@ -33070,6 +33098,7 @@ simdjson_warn_unused error_code dom_parser_implementation::stage2_next(dom::docu
return stage2::tape_builder::parse_document<true>(*this, _doc); 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 { 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); return ppc64::stringparsing::parse_string(src, dst, replacement_char);
} }
@@ -40158,6 +40187,7 @@ simdjson_warn_unused error_code dom_parser_implementation::stage2_next(dom::docu
return stage2::tape_builder::parse_document<true>(*this, _doc); 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 { 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); return westmere::stringparsing::parse_string(src, dst, replacement_char);
} }
@@ -46155,6 +46185,7 @@ simdjson_warn_unused error_code dom_parser_implementation::stage2_next(dom::docu
return stage2::tape_builder::parse_document<true>(*this, _doc); 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 { 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); return lsx::stringparsing::parse_string(src, dst, allow_replacement);
} }
@@ -52177,6 +52208,7 @@ simdjson_warn_unused error_code dom_parser_implementation::stage2_next(dom::docu
return stage2::tape_builder::parse_document<true>(*this, _doc); 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 { 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); return lasx::stringparsing::parse_string(src, dst, allow_replacement);
} }
@@ -56150,6 +56182,7 @@ simdjson_warn_unused error_code dom_parser_implementation::stage2_next(dom::docu
return stage2::tape_builder::parse_document<true>(*this, _doc); 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 { 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); return fallback::stringparsing::parse_string(src, dst, replacement_char);
} }
+747 -273
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); 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 { 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); 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); 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 { 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); 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); 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 { 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); 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); 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 { 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); return icelake::stringparsing::parse_string(src, dst, replacement_char);
} }
+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); 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 { 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); 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); 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 { 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); 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); 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 { 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); 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); 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 { 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); return westmere::stringparsing::parse_string(src, dst, replacement_char);
} }
+152 -1
View File
@@ -292,6 +292,157 @@ bool json_path_invalidation() {
} }
TEST_SUCCEED(); TEST_SUCCEED();
} }
bool json_path_with_wildcard() {
TEST_START();
simdjson::padded_string json_string = R"(
{
"firstName": "John",
"lastName" : "doe",
"age" : 26,
"address" : {
"streetAddress": "naist street",
"city" : "Nara",
"postalCode" : "630-0192"
},
"phoneNumbers": [
{
"type" : "iPhone",
"numbers": [
"0123-4567-8888",
"0123-4567-8788",
"0123-4567-8887"
]
},
{
"type" : "home",
"numbers": [
"0123-4567-8910",
"0123-4267-8910",
"0103-4567-8910"
]
},
{ },
{
"type": "office",
"numbers": [ ]
}
],
"empty_object": { },
"empty_array": [ ]
})"_padded;
dom::parser parser;
dom::element parsed_json = parser.parse(json_string);
std::vector<dom::element> values;
std::string_view string_value;
std::uint64_t num_value;
dom::object obj;
ASSERT_EQUAL(parsed_json.at_path_with_wildcard("$").error(), INVALID_JSON_POINTER);
ASSERT_EQUAL(parsed_json.at_path_with_wildcard("1").error(), INVALID_JSON_POINTER);
ASSERT_EQUAL(parsed_json.at_path_with_wildcard("2").error(), INVALID_JSON_POINTER);
ASSERT_EQUAL(parsed_json.at_path_with_wildcard("a").error(), INVALID_JSON_POINTER);
ASSERT_EQUAL(parsed_json.at_path_with_wildcard("$2").error(), INVALID_JSON_POINTER);
ASSERT_EQUAL(parsed_json.at_path_with_wildcard("$a").error(), INVALID_JSON_POINTER);
// $.*
ASSERT_SUCCESS(parsed_json.at_path_with_wildcard("$.*").get(values));
ASSERT_SUCCESS(values[0].get(string_value));
ASSERT_EQUAL(string_value, "John");
ASSERT_SUCCESS(values[1].get(string_value));
ASSERT_EQUAL(string_value, "doe");
ASSERT_SUCCESS(values[2].get(num_value));
ASSERT_EQUAL(num_value, 26);
ASSERT_SUCCESS(values[3].get(obj));
ASSERT_SUCCESS(obj["streetAddress"].get(string_value));
ASSERT_EQUAL(string_value, "naist street");
ASSERT_SUCCESS(obj["city"].get(string_value));
ASSERT_EQUAL(string_value, "Nara");
// $[*]
ASSERT_SUCCESS(parsed_json.at_path_with_wildcard("$[*]").get(values));
ASSERT_SUCCESS(values[0].get(string_value));
ASSERT_EQUAL(string_value, "John");
ASSERT_SUCCESS(values[1].get(string_value));
ASSERT_EQUAL(string_value, "doe");
ASSERT_SUCCESS(values[2].get(num_value));
ASSERT_EQUAL(num_value, 26);
ASSERT_SUCCESS(values[3].get(obj));
ASSERT_SUCCESS(obj["streetAddress"].get(string_value));
ASSERT_EQUAL(string_value, "naist street");
ASSERT_SUCCESS(obj["city"].get(string_value));
ASSERT_EQUAL(string_value, "Nara");
// $.address.*
ASSERT_SUCCESS(parsed_json.at_path_with_wildcard("$.address.*").get(values));
std::vector<std::string> expected = {"naist street", "Nara", "630-0192"};
for (int i = 0; i < 3; i++) {
ASSERT_SUCCESS(values[i].get(string_value));
ASSERT_EQUAL(string_value, expected[i]);
}
// $.*.streetAddress
ASSERT_SUCCESS(parsed_json.at_path_with_wildcard("$.*.streetAddress").get(values));
ASSERT_SUCCESS(values[0].get(string_value));
ASSERT_EQUAL(string_value, "naist street");
// $.phoneNumbers[*].numbers[*]
ASSERT_SUCCESS(parsed_json.at_path_with_wildcard("$.phoneNumbers[*].numbers[*]").get(values));
std::vector<std::string> expected_numbers = {
"0123-4567-8888",
"0123-4567-8788",
"0123-4567-8887",
"0123-4567-8910",
"0123-4267-8910",
"0103-4567-8910"
};
for (int i = 0; i < 6; i++) {
ASSERT_SUCCESS(values[i].get(string_value));
ASSERT_EQUAL(string_value, expected_numbers[i]);
}
// $.phoneNumbers[*].numbers[1]
ASSERT_SUCCESS(parsed_json.at_path_with_wildcard("$.phoneNumbers[*].numbers[1]").get(values));
ASSERT_SUCCESS(values[0].get(string_value));
ASSERT_EQUAL(string_value, expected_numbers[1]);
ASSERT_SUCCESS(values[1].get(string_value));
ASSERT_EQUAL(string_value, expected_numbers[4]);
// $.empty_object.*
ASSERT_SUCCESS(parsed_json.at_path_with_wildcard("$.empty_object.*").get(values));
ASSERT_EQUAL(values.size(), 0);
// $.empty_array.*
ASSERT_SUCCESS(parsed_json.at_path_with_wildcard("$.empty_array.*").get(values));
ASSERT_EQUAL(values.size(), 0);
// $.phoneNumbers.*.numbers[3]
ASSERT_SUCCESS(parsed_json.at_path_with_wildcard("$.phoneNumbers.*.numbers[3]").get(values));
ASSERT_EQUAL(values.size(), 0);
TEST_SUCCEED();
}
// for 0.5 version and following (standard compliant) // for 0.5 version and following (standard compliant)
bool modern_support() { bool modern_support() {
#if SIMDJSON_EXCEPTIONS #if SIMDJSON_EXCEPTIONS
@@ -314,7 +465,7 @@ bool modern_support() {
} }
int main() { int main() {
if (true && demo() && modern_support() && if (true && json_path_with_wildcard() && demo() && modern_support() &&
run_success_test(TEST_RFC_JSON, "$.foo", "[\"bar\",\"baz\"]") && run_success_test(TEST_RFC_JSON, "$.foo", "[\"bar\",\"baz\"]") &&
run_success_test(TEST_RFC_JSON, "$.foo[0]", "\"bar\"") && run_success_test(TEST_RFC_JSON, "$.foo[0]", "\"bar\"") &&
run_success_test(TEST_RFC_JSON, "$.", "0") && run_success_test(TEST_RFC_JSON, "$.", "0") &&
+64
View File
@@ -21,6 +21,62 @@ void basics_2() {
cout << doc; cout << doc;
} }
void wild() {
simdjson::padded_string json_string = R"(
{
"firstName": "John",
"lastName": "doe",
"age": 26,
"address": {
"streetAddress": "naist street",
"city": "Nara",
"postalCode": "630-0192"
},
"phoneNumbers": [
{
"type": "iPhone",
"numbers": ["0123-4567-8888", "0123-4567-8788"]
},
{
"type": "home",
"numbers": ["0123-4567-8910"]
}
]
})"_padded;
dom::parser parser;
dom::element parsed_json = parser.parse(json_string);
std::vector<dom::element> values;
// Fetch all fields in the address object
auto error = parsed_json.at_path_with_wildcard("$.address.*").get(values);
if(error) {
// do something
}
for (auto &value : values) {
std::string_view field;
error = value.get(field);
if(error) {
// do something
}
std::cout << field << std::endl;
}
// Fetch all phone numbers
error = parsed_json.at_path_with_wildcard("$.phoneNumbers[*].numbers[*]").get(values);
if(error) {
// do something
}
for (auto &value : values) {
std::string_view number;
error = value.get(number);
if(error) {
// do something
}
std::cout << number << std::endl;
}
}
void basics_dom_1() { void basics_dom_1() {
auto cars_json = R"( [ auto cars_json = R"( [
{ "make": "Toyota", "model": "Camry", "year": 2018, "tire_pressure": [ 40.1, 39.9, 37.7, 40.4 ] }, { "make": "Toyota", "model": "Camry", "year": 2018, "tire_pressure": [ 40.1, 39.9, 37.7, 40.4 ] },
@@ -461,6 +517,13 @@ void parse_documentation_lowlevel() {
(void)element; (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() { void jsondollar() {
dom::parser parser; dom::parser parser;
@@ -497,6 +560,7 @@ void jsonpath() {
} }
int main() { int main() {
simplepad();
jsonpath(); jsonpath();
jsondollar(); jsondollar();
basics_dom_1(); basics_dom_1();
+37
View File
@@ -5,6 +5,23 @@ using namespace simdjson;
namespace misc_tests { namespace misc_tests {
using namespace std; using namespace std;
bool issue2322() {
TEST_START();
std::vector<std::pair<std::string, bool>> examples = {{R"("hello")", false},
{R"(\"hello)", true},
{R"("hello\")", true},
{R"("hel\"lo")", false},
{R"("hel\\lo")", false},
{R"(\"hel\\\"lo\")", true},
{R"(\\"hel\\\"lo\")", false}};
for (std::pair<std::string, bool> v : examples) {
ASSERT_EQUAL(ondemand::raw_json_string::is_free_from_unescaped_quote(v.first),
v.second);
ASSERT_EQUAL(ondemand::raw_json_string::is_free_from_unescaped_quote(v.first.c_str()),
v.second);
}
TEST_SUCCEED();
}
#if SIMDJSON_EXCEPTIONS #if SIMDJSON_EXCEPTIONS
// user reported an asan error: // user reported an asan error:
bool issue2199() { bool issue2199() {
@@ -537,6 +554,24 @@ namespace misc_tests {
TEST_SUCCEED(); TEST_SUCCEED();
} }
simdjson_warn_unused bool issue2312() {
TEST_START();
std::string init_string = R"("abc":)";
init_string.resize(init_string.size() + simdjson::SIMDJSON_PADDING);
simdjson::padded_string_view padded_view{init_string.data(), 5, init_string.size()};
simdjson::ondemand::parser parser;
simdjson::ondemand::document doc;
ASSERT_SUCCESS(parser.iterate(padded_view).get(doc));
std::string_view abc;
ASSERT_SUCCESS(doc.get_string().get(abc));
ASSERT_EQUAL(abc, "abc");
ASSERT_SUCCESS(parser.iterate(padded_view).get(doc));
std::string_view raw;
ASSERT_SUCCESS(doc.raw_json().get(raw));
ASSERT_EQUAL(raw, "\"abc\"");
TEST_SUCCEED();
}
simdjson_warn_unused bool big_integer() { simdjson_warn_unused bool big_integer() {
TEST_START(); TEST_START();
simdjson::ondemand::parser parser; simdjson::ondemand::parser parser;
@@ -620,6 +655,8 @@ namespace misc_tests {
bool run() { bool run() {
return return
issue2322() &&
issue2312() &&
#if SIMDJSON_EXCEPTIONS #if SIMDJSON_EXCEPTIONS
issue2199() && issue2199() &&
#endif #endif
+10 -1
View File
@@ -8,7 +8,15 @@
#endif #endif
using namespace std; using namespace std;
using namespace simdjson; using namespace simdjson;
using error_code=simdjson::error_code; using error_code = simdjson::error_code;
bool simplepad() {
std::string json = "[1]";
ondemand::parser parser;
ondemand::document doc;
auto error = parser.iterate(simdjson::pad(json)).get(doc);
return error == SUCCESS;
}
bool string1() { bool string1() {
const char * data = "my data"; // 7 bytes const char * data = "my data"; // 7 bytes
@@ -1918,6 +1926,7 @@ bool run() {
&& using_the_parsed_json_4() && using_the_parsed_json_4()
&& using_the_parsed_json_5() && using_the_parsed_json_5()
#endif #endif
&& simplepad()
&& using_the_parsed_json_6() && using_the_parsed_json_6()
&& json_pointer_simple() && json_pointer_simple()
&& json_pointer_unicode() && json_pointer_unicode()
-2
View File
@@ -184,8 +184,6 @@ else:
if(detectedreadme != toversionstring(*newversion)): if(detectedreadme != toversionstring(*newversion)):
print(colored(255, 0, 0, "Consider updating the readme link to "+toversionstring(*newversion))) print(colored(255, 0, 0, "Consider updating the readme link to "+toversionstring(*newversion)))
print("Please run the tests before issuing a release. \n") print("Please run the tests before issuing a release. \n")
print("to issue release, enter \n git commit -a && git push && git tag -a v"+toversionstring(*newversion)+" -m \"version "+toversionstring(*newversion)+"\" && git push --tags \n") print("to issue release, enter \n git commit -a && git push && git tag -a v"+toversionstring(*newversion)+" -m \"version "+toversionstring(*newversion)+"\" && git push --tags \n")