mirror of
https://github.com/simdjson/simdjson
synced 2026-06-08 17:27:07 +00:00
Compare commits
77 Commits
v3.11.4
...
asteriks_fix
| Author | SHA1 | Date | |
|---|---|---|---|
| 956661f800 | |||
| a306d2bd73 | |||
| 9627831b5f | |||
| 6c5ada32b9 | |||
| f576354342 | |||
| 1589d15361 | |||
| c58f5dda2d | |||
| 5753f54f6c | |||
| f0cdafa857 | |||
| 29ef75c783 | |||
| c3d45c7758 | |||
| 3fda1b9c7d | |||
| fdcea9ad22 | |||
| 7b3168bfc8 | |||
| 3350ce97ba | |||
| 61ec1fb659 | |||
| bfc8b89e6b | |||
| 1382432686 | |||
| bebbf830fb | |||
| e7dda647e2 | |||
| ec46aace3b | |||
| 1dfe1bd350 | |||
| 0b1d69938e | |||
| 120e69f13c | |||
| 14922fa6c4 | |||
| 8fa2629c84 | |||
| c51c2d2ce9 | |||
| 3c9cde5ec1 | |||
| 651c982d26 | |||
| 3634cdbf94 | |||
| 3b47ae6a77 | |||
| 07daf0a92e | |||
| 9f74c0e958 | |||
| 7a336e560c | |||
| c6e7c89b59 | |||
| ed838ffab9 | |||
| 5981ca18e4 | |||
| 1a11e19d07 | |||
| 671a81f4e3 | |||
| 008d89eb56 | |||
| a71655120a | |||
| 531567ae94 | |||
| 46ae2d250f | |||
| c35122bcb4 | |||
| f380604de5 | |||
| 00d01ea0f5 | |||
| 68bef810aa | |||
| e328bad696 | |||
| c9ccb2d139 | |||
| d99072982f | |||
| 6b7f987cd5 | |||
| d32cd20ce6 | |||
| 2013a46518 | |||
| 6cb1911d3a | |||
| 9ff7d2ccbe | |||
| fa4a4ad8f0 | |||
| de6ad3c60c | |||
| 005133c555 | |||
| 78025fdd64 | |||
| f3b034ac38 | |||
| 9c2e8a8f39 | |||
| dfa43f6cdd | |||
| 797e61742c | |||
| f289412e0a | |||
| 7bd79b4445 | |||
| 078e2c9073 | |||
| d7b6b20511 | |||
| dbea3bbd62 | |||
| e422933414 | |||
| de4d69b367 | |||
| b8675a7f7b | |||
| 5642bb93a4 | |||
| 1b23a77e03 | |||
| 57699bfed8 | |||
| 648303b26a | |||
| 9008960e36 | |||
| 8a9e8a1792 |
@@ -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:
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
+3
-3
@@ -3,7 +3,7 @@ cmake_minimum_required(VERSION 3.14)
|
|||||||
project(
|
project(
|
||||||
simdjson
|
simdjson
|
||||||
# The version number is modified by tools/release.py
|
# The version number is modified by tools/release.py
|
||||||
VERSION 3.11.4
|
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 "24.0.0" CACHE STRING "simdjson library version")
|
set(SIMDJSON_LIB_VERSION "25.0.0" CACHE STRING "simdjson library version")
|
||||||
set(SIMDJSON_LIB_SOVERSION "24" 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)
|
||||||
|
|||||||
@@ -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.11.4"
|
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
|
||||||
|
|||||||
@@ -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
@@ -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.
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
|
|
||||||
[/badge.svg)](https://simdjson.org/plots.html)
|
|
||||||
[](https://bugs.chromium.org/p/oss-fuzz/issues/list?sort=-opened&can=1&q=proj:simdjson)
|
[](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]
|
||||||
|
|
||||||
|
|
||||||
[](https://simdjson.github.io/simdjson/)
|
[](https://simdjson.github.io/simdjson/)
|
||||||
|
|
||||||
@@ -62,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.
|
||||||
|
|
||||||
@@ -211,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
|
||||||
------------------------
|
------------------------
|
||||||
|
|
||||||
@@ -220,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.
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -1986,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.
|
||||||
|
|||||||
+68
@@ -323,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
@@ -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)
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -128,6 +128,12 @@ simdjson_inline simdjson_result<dom::element> simdjson_result<dom::element>::at_
|
|||||||
if (json_pointer == "-1") { return INVALID_JSON_POINTER; }
|
if (json_pointer == "-1") { return INVALID_JSON_POINTER; }
|
||||||
return at_pointer(json_pointer);
|
return at_pointer(json_pointer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
simdjson_inline simdjson_result<std::vector<dom::element>> simdjson_result<dom::element>::at_path_with_wildcard(const std::string_view json_path) const noexcept {
|
||||||
|
if (error()) { return error(); }
|
||||||
|
return first.at_path_with_wildcard(json_path);
|
||||||
|
}
|
||||||
|
|
||||||
#ifndef SIMDJSON_DISABLE_DEPRECATED_API
|
#ifndef SIMDJSON_DISABLE_DEPRECATED_API
|
||||||
[[deprecated("For standard compliance, use at_pointer instead, and prefix your pointers with a slash '/', see RFC6901 ")]]
|
[[deprecated("For standard compliance, use at_pointer instead, and prefix your pointers with a slash '/', see RFC6901 ")]]
|
||||||
simdjson_inline simdjson_result<dom::element> simdjson_result<dom::element>::at(const std::string_view json_pointer) const noexcept {
|
simdjson_inline simdjson_result<dom::element> simdjson_result<dom::element>::at(const std::string_view json_pointer) const noexcept {
|
||||||
@@ -418,6 +424,20 @@ inline simdjson_result<element> element::at_pointer(std::string_view json_pointe
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline simdjson_result<std::vector<element>> element::at_path_with_wildcard(std::string_view json_path) const noexcept {
|
||||||
|
SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
|
||||||
|
|
||||||
|
switch (tape.tape_ref_type()) {
|
||||||
|
case internal::tape_type::START_OBJECT:
|
||||||
|
return object(tape).at_path_with_wildcard(json_path);
|
||||||
|
case internal::tape_type::START_ARRAY:
|
||||||
|
return array(tape).at_path_with_wildcard(json_path);
|
||||||
|
default:
|
||||||
|
return std::vector<element>{};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
inline simdjson_result<element> element::at_path(std::string_view json_path) const noexcept {
|
inline simdjson_result<element> element::at_path(std::string_view json_path) const noexcept {
|
||||||
auto json_pointer = json_path_to_pointer_conversion(json_path);
|
auto json_pointer = json_path_to_pointer_conversion(json_path);
|
||||||
if (json_pointer == "-1") { return INVALID_JSON_POINTER; }
|
if (json_pointer == "-1") { return INVALID_JSON_POINTER; }
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
#ifndef SIMDJSON_DOM_ELEMENT_H
|
#ifndef SIMDJSON_DOM_ELEMENT_H
|
||||||
#define SIMDJSON_DOM_ELEMENT_H
|
#define SIMDJSON_DOM_ELEMENT_H
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include "simdjson/dom/base.h"
|
#include "simdjson/dom/base.h"
|
||||||
#include "simdjson/dom/array.h"
|
#include "simdjson/dom/array.h"
|
||||||
|
|
||||||
@@ -399,6 +401,8 @@ public:
|
|||||||
*/
|
*/
|
||||||
inline simdjson_result<element> at_pointer(const std::string_view json_pointer) const noexcept;
|
inline simdjson_result<element> at_pointer(const std::string_view json_pointer) const noexcept;
|
||||||
|
|
||||||
|
inline simdjson_result<std::vector<element>> at_path_with_wildcard(const std::string_view json_path) const noexcept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value associated with the given JSONPath expression. We only support
|
* Get the value associated with the given JSONPath expression. We only support
|
||||||
* JSONPath queries that trivially convertible to JSON Pointer queries: key
|
* JSONPath queries that trivially convertible to JSON Pointer queries: key
|
||||||
@@ -544,6 +548,7 @@ public:
|
|||||||
simdjson_inline simdjson_result<dom::element> operator[](const char *key) const noexcept;
|
simdjson_inline simdjson_result<dom::element> operator[](const char *key) const noexcept;
|
||||||
simdjson_result<dom::element> operator[](int) const noexcept = delete;
|
simdjson_result<dom::element> operator[](int) const noexcept = delete;
|
||||||
simdjson_inline simdjson_result<dom::element> at_pointer(const std::string_view json_pointer) const noexcept;
|
simdjson_inline simdjson_result<dom::element> at_pointer(const std::string_view json_pointer) const noexcept;
|
||||||
|
simdjson_inline simdjson_result<std::vector<dom::element>> at_path_with_wildcard(const std::string_view json_path) const noexcept;
|
||||||
simdjson_inline simdjson_result<dom::element> at_path(const std::string_view json_path) const noexcept;
|
simdjson_inline simdjson_result<dom::element> at_path(const std::string_view json_path) const noexcept;
|
||||||
[[deprecated("For standard compliance, use at_pointer instead, and prefix your pointers with a slash '/', see RFC6901 ")]]
|
[[deprecated("For standard compliance, use at_pointer instead, and prefix your pointers with a slash '/', see RFC6901 ")]]
|
||||||
simdjson_inline simdjson_result<dom::element> at(const std::string_view json_pointer) const noexcept;
|
simdjson_inline simdjson_result<dom::element> at(const std::string_view json_pointer) const noexcept;
|
||||||
|
|||||||
@@ -40,10 +40,19 @@ inline simdjson_result<dom::element> simdjson_result<dom::object>::at_path(std::
|
|||||||
if (json_pointer == "-1") { return INVALID_JSON_POINTER; }
|
if (json_pointer == "-1") { return INVALID_JSON_POINTER; }
|
||||||
return at_pointer(json_pointer);
|
return at_pointer(json_pointer);
|
||||||
}
|
}
|
||||||
|
inline simdjson_result<std::vector<dom::element>> simdjson_result<dom::object>::at_path_with_wildcard(std::string_view json_path) const noexcept {
|
||||||
|
if (error()) {
|
||||||
|
return error();
|
||||||
|
}
|
||||||
|
return first.at_path_with_wildcard(json_path);
|
||||||
|
}
|
||||||
inline simdjson_result<dom::element> simdjson_result<dom::object>::at_key(std::string_view key) const noexcept {
|
inline simdjson_result<dom::element> simdjson_result<dom::object>::at_key(std::string_view key) const noexcept {
|
||||||
if (error()) { return error(); }
|
if (error()) { return error(); }
|
||||||
return first.at_key(key);
|
return first.at_key(key);
|
||||||
}
|
}
|
||||||
|
inline std::vector<dom::element>& simdjson_result<dom::object>::get_values(std::vector<dom::element>& out) const noexcept {
|
||||||
|
return first.get_values(out);
|
||||||
|
}
|
||||||
inline simdjson_result<dom::element> simdjson_result<dom::object>::at_key_case_insensitive(std::string_view key) const noexcept {
|
inline simdjson_result<dom::element> simdjson_result<dom::object>::at_key_case_insensitive(std::string_view key) const noexcept {
|
||||||
if (error()) { return error(); }
|
if (error()) { return error(); }
|
||||||
return first.at_key_case_insensitive(key);
|
return first.at_key_case_insensitive(key);
|
||||||
@@ -143,6 +152,97 @@ inline simdjson_result<element> object::at_path(std::string_view json_path) cons
|
|||||||
return at_pointer(json_pointer);
|
return at_pointer(json_pointer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline void object::process_json_path_of_child_elements(std::vector<element>::iterator& current, std::vector<element>::iterator& end, const std::string_view& path_suffix, std::vector<element>& accumulator) const noexcept {
|
||||||
|
if (current == end) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
simdjson_result<std::vector<element>> result;
|
||||||
|
|
||||||
|
for (auto it = current; it != end; ++it) {
|
||||||
|
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.
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
#ifndef SIMDJSON_DOM_OBJECT_H
|
#ifndef SIMDJSON_DOM_OBJECT_H
|
||||||
#define SIMDJSON_DOM_OBJECT_H
|
#define SIMDJSON_DOM_OBJECT_H
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include "simdjson/dom/base.h"
|
#include "simdjson/dom/base.h"
|
||||||
#include "simdjson/dom/element.h"
|
#include "simdjson/dom/element.h"
|
||||||
#include "simdjson/internal/tape_ref.h"
|
#include "simdjson/internal/tape_ref.h"
|
||||||
@@ -172,6 +174,16 @@ public:
|
|||||||
*/
|
*/
|
||||||
inline simdjson_result<element> at_pointer(std::string_view json_pointer) const noexcept;
|
inline simdjson_result<element> at_pointer(std::string_view json_pointer) const noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Recursive function which processes the json path of each child element
|
||||||
|
*/
|
||||||
|
inline void process_json_path_of_child_elements(std::vector<element>::iterator& current, std::vector<element>::iterator& end, const std::string_view& path_suffix, std::vector<element>& accumulator) const noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds support for JSONPath expression with wildcards '*'
|
||||||
|
*/
|
||||||
|
inline simdjson_result<std::vector<element>> at_path_with_wildcard(std::string_view json_path) const noexcept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value associated with the given JSONPath expression. We only support
|
* Get the value associated with the given JSONPath expression. We only support
|
||||||
* JSONPath queries that trivially convertible to JSON Pointer queries: key
|
* JSONPath queries that trivially convertible to JSON Pointer queries: key
|
||||||
@@ -203,6 +215,14 @@ public:
|
|||||||
*/
|
*/
|
||||||
inline simdjson_result<element> at_key(std::string_view key) const noexcept;
|
inline simdjson_result<element> at_key(std::string_view key) const noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the values associated with keys of an object
|
||||||
|
* This function has linear-time complexity: the keys are checked one by one.
|
||||||
|
*
|
||||||
|
* @return the values associated with each key of an object
|
||||||
|
*/
|
||||||
|
inline std::vector<element>& get_values(std::vector<element>& out) const noexcept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value associated with the given key in a case-insensitive manner.
|
* Get the value associated with the given key in a case-insensitive manner.
|
||||||
* It is only guaranteed to work over ASCII inputs.
|
* It is only guaranteed to work over ASCII inputs.
|
||||||
@@ -261,8 +281,11 @@ public:
|
|||||||
inline simdjson_result<dom::element> operator[](const char *key) const noexcept;
|
inline simdjson_result<dom::element> operator[](const char *key) const noexcept;
|
||||||
simdjson_result<dom::element> operator[](int) const noexcept = delete;
|
simdjson_result<dom::element> operator[](int) const noexcept = delete;
|
||||||
inline simdjson_result<dom::element> at_pointer(std::string_view json_pointer) const noexcept;
|
inline simdjson_result<dom::element> at_pointer(std::string_view json_pointer) const noexcept;
|
||||||
|
inline void process_json_path_of_child_elements(std::vector<dom::element>::iterator& current, std::vector<dom::element>::iterator& end, const std::string_view& path_suffix, std::vector<dom::element>& accumulator) const noexcept;
|
||||||
|
inline simdjson_result<std::vector<dom::element>> at_path_with_wildcard(std::string_view json_path_new) const noexcept;
|
||||||
inline simdjson_result<dom::element> at_path(std::string_view json_path) const noexcept;
|
inline simdjson_result<dom::element> at_path(std::string_view json_path) const noexcept;
|
||||||
inline simdjson_result<dom::element> at_key(std::string_view key) const noexcept;
|
inline simdjson_result<dom::element> at_key(std::string_view key) const noexcept;
|
||||||
|
inline std::vector<dom::element>& get_values(std::vector<dom::element>& out) const noexcept;
|
||||||
inline simdjson_result<dom::element> at_key_case_insensitive(std::string_view key) const noexcept;
|
inline simdjson_result<dom::element> at_key_case_insensitive(std::string_view key) const noexcept;
|
||||||
|
|
||||||
#if SIMDJSON_EXCEPTIONS
|
#if SIMDJSON_EXCEPTIONS
|
||||||
|
|||||||
@@ -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());
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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 };
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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.11.4"
|
#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 = 11,
|
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 = 4
|
SIMDJSON_VERSION_REVISION = 2
|
||||||
};
|
};
|
||||||
} // namespace simdjson
|
} // namespace simdjson
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
#
|
#
|
||||||
|
|||||||
+25
-17
@@ -1,4 +1,4 @@
|
|||||||
/* auto-generated on 2025-01-06 19:23:09 -0500. 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
|
||||||
@@ -776,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 };
|
||||||
}
|
}
|
||||||
@@ -2122,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 };
|
||||||
}
|
}
|
||||||
@@ -2146,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 };
|
||||||
}
|
}
|
||||||
@@ -20813,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>
|
||||||
@@ -23443,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>
|
||||||
|
|||||||
+238
-205
@@ -1,4 +1,4 @@
|
|||||||
/* auto-generated on 2025-01-06 19:23:09 -0500. Do not edit! */
|
/* auto-generated on 2025-02-14 16:11:36 -0500. Do not edit! */
|
||||||
/* including simdjson.h: */
|
/* including simdjson.h: */
|
||||||
/* begin file simdjson.h */
|
/* begin file simdjson.h */
|
||||||
#ifndef SIMDJSON_H
|
#ifndef SIMDJSON_H
|
||||||
@@ -796,22 +796,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 };
|
||||||
}
|
}
|
||||||
@@ -2142,22 +2142,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 };
|
||||||
}
|
}
|
||||||
@@ -2166,22 +2166,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 };
|
||||||
}
|
}
|
||||||
@@ -2437,7 +2437,7 @@ namespace std {
|
|||||||
#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.11.4"
|
#define SIMDJSON_VERSION "3.12.2"
|
||||||
|
|
||||||
namespace simdjson {
|
namespace simdjson {
|
||||||
enum {
|
enum {
|
||||||
@@ -2448,11 +2448,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 = 11,
|
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 = 4
|
SIMDJSON_VERSION_REVISION = 2
|
||||||
};
|
};
|
||||||
} // namespace simdjson
|
} // namespace simdjson
|
||||||
|
|
||||||
@@ -6826,10 +6826,11 @@ 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.
|
||||||
}
|
}
|
||||||
@@ -17948,14 +17949,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>
|
||||||
@@ -40965,36 +40970,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;
|
||||||
}
|
}
|
||||||
@@ -41006,7 +41014,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());
|
||||||
@@ -51938,36 +51946,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;
|
||||||
}
|
}
|
||||||
@@ -51979,7 +51990,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());
|
||||||
@@ -63403,36 +63414,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;
|
||||||
}
|
}
|
||||||
@@ -63444,7 +63458,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());
|
||||||
@@ -65392,14 +65406,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>
|
||||||
@@ -74861,36 +74879,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;
|
||||||
}
|
}
|
||||||
@@ -74902,7 +74923,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());
|
||||||
@@ -86440,36 +86461,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;
|
||||||
}
|
}
|
||||||
@@ -86481,7 +86505,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());
|
||||||
@@ -98336,36 +98360,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;
|
||||||
}
|
}
|
||||||
@@ -98377,7 +98404,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());
|
||||||
@@ -109709,36 +109736,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;
|
||||||
}
|
}
|
||||||
@@ -109750,7 +109780,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());
|
||||||
@@ -121095,36 +121125,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;
|
||||||
}
|
}
|
||||||
@@ -121136,7 +121169,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());
|
||||||
|
|||||||
@@ -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") &&
|
||||||
|
|||||||
@@ -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 ] },
|
||||||
|
|||||||
@@ -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() {
|
||||||
@@ -638,6 +655,7 @@ namespace misc_tests {
|
|||||||
|
|
||||||
bool run() {
|
bool run() {
|
||||||
return
|
return
|
||||||
|
issue2322() &&
|
||||||
issue2312() &&
|
issue2312() &&
|
||||||
#if SIMDJSON_EXCEPTIONS
|
#if SIMDJSON_EXCEPTIONS
|
||||||
issue2199() &&
|
issue2199() &&
|
||||||
|
|||||||
@@ -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")
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user