mirror of
https://github.com/simdjson/simdjson
synced 2026-06-08 17:27:07 +00:00
Compare commits
28 Commits
v4.4.1
...
version4.6.4
| Author | SHA1 | Date | |
|---|---|---|---|
| 1bcf71bd85 | |||
| f01641e463 | |||
| 65e59ccf9b | |||
| 61641f9a7a | |||
| 996dc25180 | |||
| 77cf997595 | |||
| 453ae4e955 | |||
| f5602fa3c7 | |||
| 942f7f298b | |||
| 6a4fc260a1 | |||
| fb83b114ef | |||
| 542cd7af71 | |||
| 769364abb2 | |||
| f25d5f9fc2 | |||
| 12fb30ae9c | |||
| c0a952687d | |||
| 307ddd4415 | |||
| 21657455ed | |||
| afb1c9f4b1 | |||
| 9973f7b3a3 | |||
| 18d612df15 | |||
| bddb23177e | |||
| 2c5de6c6ed | |||
| 844e5eac23 | |||
| 45caa861cd | |||
| 50bf372d3f | |||
| b4a0fd3ff4 | |||
| a1ff05a5e8 |
+97
-83
@@ -12,7 +12,7 @@ endif()
|
||||
project(
|
||||
simdjson
|
||||
# The version number is modified by tools/release.py
|
||||
VERSION 4.4.1
|
||||
VERSION 4.6.4
|
||||
DESCRIPTION "Parsing gigabytes of JSON per second"
|
||||
HOMEPAGE_URL "https://simdjson.org/"
|
||||
LANGUAGES CXX C
|
||||
@@ -29,8 +29,8 @@ string(
|
||||
# ---- Options, variables ----
|
||||
|
||||
# These version numbers are modified by tools/release.py
|
||||
set(SIMDJSON_LIB_VERSION "31.0.0" CACHE STRING "simdjson library version")
|
||||
set(SIMDJSON_LIB_SOVERSION "31" CACHE STRING "simdjson library soversion")
|
||||
set(SIMDJSON_LIB_VERSION "33.0.0" CACHE STRING "simdjson library version")
|
||||
set(SIMDJSON_LIB_SOVERSION "33" CACHE STRING "simdjson library soversion")
|
||||
|
||||
option(SIMDJSON_BUILD_STATIC_LIB "Build simdjson_static library along with simdjson (only makes sense if BUILD_SHARED_LIBS=ON)" OFF)
|
||||
if(SIMDJSON_BUILD_STATIC_LIB AND NOT BUILD_SHARED_LIBS)
|
||||
@@ -76,9 +76,12 @@ if(SIMDJSON_DEVELOPMENT_CHECKS)
|
||||
endif()
|
||||
|
||||
if(is_top_project)
|
||||
option(SIMDJSON_INSTALL "Enable target install" ON)
|
||||
option(SIMDJSON_DEVELOPER_MODE "Enable targets for developing simdjson" OFF)
|
||||
option(BUILD_SHARED_LIBS "Build simdjson as a shared library" OFF)
|
||||
option(SIMDJSON_SINGLEHEADER "Disable singleheader generation" ON)
|
||||
else()
|
||||
option(SIMDJSON_INSTALL "Enable target install" ${BUILD_SHARED_LIBS})
|
||||
endif()
|
||||
|
||||
include(cmake/handle-deprecations.cmake)
|
||||
@@ -92,13 +95,16 @@ add_library(simdjson ${SIMDJSON_SOURCES})
|
||||
add_library(simdjson::simdjson ALIAS simdjson)
|
||||
set(SIMDJSON_LIBRARIES simdjson)
|
||||
|
||||
# Check for <bit> header compatibility
|
||||
include(CheckIncludeFileCXX)
|
||||
check_include_file_cxx(bit SIMDJSON_HAS_BIT_HEADER)
|
||||
|
||||
# Enable precompiled headers for faster builds
|
||||
if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.16")
|
||||
target_precompile_headers(simdjson PRIVATE
|
||||
set(SIMDJSON_PRECOMPILE_HEADERS
|
||||
<algorithm>
|
||||
<array>
|
||||
<atomic>
|
||||
<bit>
|
||||
<cassert>
|
||||
<cctype>
|
||||
<cerrno>
|
||||
@@ -111,6 +117,12 @@ if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.16")
|
||||
<utility>
|
||||
<vector>
|
||||
)
|
||||
|
||||
if(SIMDJSON_HAS_BIT_HEADER)
|
||||
list(APPEND SIMDJSON_PRECOMPILE_HEADERS <bit>)
|
||||
endif()
|
||||
|
||||
target_precompile_headers(simdjson PRIVATE ${SIMDJSON_PRECOMPILE_HEADERS})
|
||||
endif()
|
||||
|
||||
if(SIMDJSON_BUILD_STATIC_LIB)
|
||||
@@ -216,87 +228,89 @@ endif()
|
||||
|
||||
# ---- Install rules ----
|
||||
|
||||
include(CMakePackageConfigHelpers)
|
||||
include(GNUInstallDirs)
|
||||
if(SIMDJSON_INSTALL)
|
||||
include(CMakePackageConfigHelpers)
|
||||
include(GNUInstallDirs)
|
||||
|
||||
if(SIMDJSON_SINGLEHEADER)
|
||||
install(
|
||||
FILES singleheader/simdjson.h
|
||||
DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}"
|
||||
COMPONENT simdjson_Development
|
||||
)
|
||||
if(SIMDJSON_SINGLEHEADER)
|
||||
install(
|
||||
FILES singleheader/simdjson.h
|
||||
DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}"
|
||||
COMPONENT simdjson_Development
|
||||
)
|
||||
endif()
|
||||
|
||||
install(
|
||||
TARGETS simdjson
|
||||
EXPORT simdjsonTargets
|
||||
RUNTIME COMPONENT simdjson_Runtime
|
||||
LIBRARY COMPONENT simdjson_Runtime
|
||||
NAMELINK_COMPONENT simdjson_Development
|
||||
ARCHIVE COMPONENT simdjson_Development
|
||||
INCLUDES DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}"
|
||||
)
|
||||
configure_file(cmake/simdjson-config.cmake.in simdjson-config.cmake @ONLY)
|
||||
|
||||
write_basic_package_version_file(
|
||||
simdjson-config-version.cmake
|
||||
COMPATIBILITY SameMinorVersion
|
||||
)
|
||||
|
||||
set(
|
||||
SIMDJSON_INSTALL_CMAKEDIR "${CMAKE_INSTALL_LIBDIR}/cmake/simdjson"
|
||||
CACHE STRING "CMake package config location relative to the install prefix"
|
||||
)
|
||||
mark_as_advanced(SIMDJSON_INSTALL_CMAKEDIR)
|
||||
|
||||
install(
|
||||
FILES
|
||||
"${PROJECT_BINARY_DIR}/simdjson-config.cmake"
|
||||
"${PROJECT_BINARY_DIR}/simdjson-config-version.cmake"
|
||||
DESTINATION "${SIMDJSON_INSTALL_CMAKEDIR}"
|
||||
COMPONENT simdjson_Development
|
||||
)
|
||||
|
||||
install(
|
||||
EXPORT simdjsonTargets
|
||||
NAMESPACE simdjson::
|
||||
DESTINATION "${SIMDJSON_INSTALL_CMAKEDIR}"
|
||||
COMPONENT simdjson_Development
|
||||
)
|
||||
|
||||
if(SIMDJSON_BUILD_STATIC_LIB)
|
||||
install(
|
||||
TARGETS simdjson_static
|
||||
EXPORT simdjson_staticTargets
|
||||
ARCHIVE COMPONENT simdjson_Development
|
||||
INCLUDES DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}"
|
||||
)
|
||||
install(
|
||||
EXPORT simdjson_staticTargets
|
||||
NAMESPACE simdjson::
|
||||
DESTINATION "${SIMDJSON_INSTALL_CMAKEDIR}"
|
||||
COMPONENT simdjson_Development
|
||||
)
|
||||
endif()
|
||||
|
||||
# pkg-config
|
||||
include(cmake/JoinPaths.cmake)
|
||||
join_paths(PKGCONFIG_INCLUDEDIR "\${prefix}" "${CMAKE_INSTALL_INCLUDEDIR}")
|
||||
join_paths(PKGCONFIG_LIBDIR "\${prefix}" "${CMAKE_INSTALL_LIBDIR}")
|
||||
|
||||
if(SIMDJSON_ENABLE_THREADS)
|
||||
set(PKGCONFIG_CFLAGS "-DSIMDJSON_THREADS_ENABLED=1")
|
||||
if(CMAKE_THREAD_LIBS_INIT)
|
||||
set(PKGCONFIG_LIBS_PRIVATE "Libs.private: ${CMAKE_THREAD_LIBS_INIT}")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
configure_file("simdjson.pc.in" "simdjson.pc" @ONLY)
|
||||
install(
|
||||
FILES "${CMAKE_CURRENT_BINARY_DIR}/simdjson.pc"
|
||||
DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig"
|
||||
)
|
||||
endif()
|
||||
|
||||
install(
|
||||
TARGETS simdjson
|
||||
EXPORT simdjsonTargets
|
||||
RUNTIME COMPONENT simdjson_Runtime
|
||||
LIBRARY COMPONENT simdjson_Runtime
|
||||
NAMELINK_COMPONENT simdjson_Development
|
||||
ARCHIVE COMPONENT simdjson_Development
|
||||
INCLUDES DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}"
|
||||
)
|
||||
configure_file(cmake/simdjson-config.cmake.in simdjson-config.cmake @ONLY)
|
||||
|
||||
write_basic_package_version_file(
|
||||
simdjson-config-version.cmake
|
||||
COMPATIBILITY SameMinorVersion
|
||||
)
|
||||
|
||||
set(
|
||||
SIMDJSON_INSTALL_CMAKEDIR "${CMAKE_INSTALL_LIBDIR}/cmake/simdjson"
|
||||
CACHE STRING "CMake package config location relative to the install prefix"
|
||||
)
|
||||
mark_as_advanced(SIMDJSON_INSTALL_CMAKEDIR)
|
||||
|
||||
install(
|
||||
FILES
|
||||
"${PROJECT_BINARY_DIR}/simdjson-config.cmake"
|
||||
"${PROJECT_BINARY_DIR}/simdjson-config-version.cmake"
|
||||
DESTINATION "${SIMDJSON_INSTALL_CMAKEDIR}"
|
||||
COMPONENT simdjson_Development
|
||||
)
|
||||
|
||||
install(
|
||||
EXPORT simdjsonTargets
|
||||
NAMESPACE simdjson::
|
||||
DESTINATION "${SIMDJSON_INSTALL_CMAKEDIR}"
|
||||
COMPONENT simdjson_Development
|
||||
)
|
||||
|
||||
if(SIMDJSON_BUILD_STATIC_LIB)
|
||||
install(
|
||||
TARGETS simdjson_static
|
||||
EXPORT simdjson_staticTargets
|
||||
ARCHIVE COMPONENT simdjson_Development
|
||||
INCLUDES DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}"
|
||||
)
|
||||
install(
|
||||
EXPORT simdjson_staticTargets
|
||||
NAMESPACE simdjson::
|
||||
DESTINATION "${SIMDJSON_INSTALL_CMAKEDIR}"
|
||||
COMPONENT simdjson_Development
|
||||
)
|
||||
endif()
|
||||
|
||||
# pkg-config
|
||||
include(cmake/JoinPaths.cmake)
|
||||
join_paths(PKGCONFIG_INCLUDEDIR "\${prefix}" "${CMAKE_INSTALL_INCLUDEDIR}")
|
||||
join_paths(PKGCONFIG_LIBDIR "\${prefix}" "${CMAKE_INSTALL_LIBDIR}")
|
||||
|
||||
if(SIMDJSON_ENABLE_THREADS)
|
||||
set(PKGCONFIG_CFLAGS "-DSIMDJSON_THREADS_ENABLED=1")
|
||||
if(CMAKE_THREAD_LIBS_INIT)
|
||||
set(PKGCONFIG_LIBS_PRIVATE "Libs.private: ${CMAKE_THREAD_LIBS_INIT}")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
configure_file("simdjson.pc.in" "simdjson.pc" @ONLY)
|
||||
install(
|
||||
FILES "${CMAKE_CURRENT_BINARY_DIR}/simdjson.pc"
|
||||
DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig"
|
||||
)
|
||||
|
||||
#
|
||||
# CPack
|
||||
#
|
||||
|
||||
@@ -38,7 +38,7 @@ PROJECT_NAME = simdjson
|
||||
# could be handy for archiving the generated documentation or if some version
|
||||
# control system is used.
|
||||
|
||||
PROJECT_NUMBER = "4.4.1"
|
||||
PROJECT_NUMBER = "4.6.4"
|
||||
|
||||
# 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
|
||||
|
||||
@@ -65,6 +65,7 @@ Real-world usage
|
||||
- [GreptimeDB](https://github.com/GreptimeTeam/greptimedb)
|
||||
- [mamba](https://github.com/mamba-org/mamba)
|
||||
- [Ladybird Browser](https://ladybird.org)
|
||||
- [SereneDB](https://github.com/serenedb/serenedb)
|
||||
|
||||
|
||||
If you are planning to use simdjson in a product, please work from one of our releases.
|
||||
@@ -211,10 +212,16 @@ We have an in-depth paper focused on the UTF-8 validation:
|
||||
|
||||
We also have an informal [blog post providing some background and context](https://branchfree.org/2019/02/25/paper-parsing-gigabytes-of-json-per-second/).
|
||||
|
||||
For the video inclined, <br />
|
||||
For the video inclined, we had a talk at QCon San Francisco 2019<br />
|
||||
[](http://www.youtube.com/watch?v=wlvKAT7SZIQ)<br />
|
||||
(It was the best voted talk, we're kinda proud of it.)
|
||||
|
||||
We also had a CppCon 2025 talk. We show how C++26 reflection allows for one-line serialization (to_json(player)) or deserialization—without invasive macros or manual mapping—using nothing but the C++ standard library. Whether you’re a performance junkie or simply interested in the roadmap for the next decade of C++ development, watch our full talk!
|
||||
|
||||
[](http://www.youtube.com/watch?v=Mcgk3CxHYMs)<br />
|
||||
|
||||
|
||||
|
||||
Citing this work
|
||||
-----------------
|
||||
|
||||
|
||||
Vendored
+1
-1
@@ -12,7 +12,7 @@ cmake_dependent_option(SIMDJSON_GOOGLE_BENCHMARKS "compile the Google Benchmark
|
||||
if(SIMDJSON_GOOGLE_BENCHMARKS)
|
||||
CPMAddPackage(
|
||||
NAME google_benchmarks
|
||||
URL https://github.com/google/benchmark/archive/refs/tags/v1.9.4.zip
|
||||
URL https://github.com/google/benchmark/archive/refs/tags/v1.9.5.zip
|
||||
OPTIONS
|
||||
"BENCHMARK_ENABLE_TESTING OFF"
|
||||
"BENCHMARK_ENABLE_INSTALL OFF"
|
||||
|
||||
+23
-26
@@ -28,6 +28,8 @@ separate document](https://github.com/simdjson/simdjson/blob/master/doc/builder.
|
||||
- [UTF-8 validation (alone)](#utf-8-validation-alone)
|
||||
- [JSON Pointer](#json-pointer)
|
||||
- [JSONPath](#jsonpath)
|
||||
* [Using `for_each_at_path_with_wildcard` for JSONPath Queries (On-Demand)](#using-for_each_at_path_with_wildcard-for-jsonpath-queries-on-demand)
|
||||
+ [Example Usage](#example-usage)
|
||||
- [Compile-Time JSONPath and JSON Pointer (C++26 Reflection)](#compile-time-jsonpath-and-json-pointer-c26-reflection)
|
||||
- [Error handling](#error-handling)
|
||||
* [Error handling examples without exceptions](#error-handling-examples-without-exceptions)
|
||||
@@ -436,7 +438,7 @@ support for users who avoid exceptions. See [the simdjson error handling documen
|
||||
* **Extracting Values:** You can cast a JSON element to a native type:
|
||||
`double(element)`. This works for `std::string_view`, double, uint64_t, int64_t, bool,
|
||||
ondemand::object and ondemand::array. We also have explicit methods such as `get_string()`, `get_double()`,
|
||||
`get_uint64()`, `get_int64()`, `get_bool()`, `get_object()` and `get_array()`. After a cast or an explicit method,
|
||||
`get_uint64()`, `get_int64()`, `get_uint32()`, `get_int32()`, `get_bool()`, `get_object()` and `get_array()`. After a cast or an explicit method,
|
||||
the number, string or boolean will be parsed, or the initial `{` or `[` will be verified for `ondemand::object` and `ondemand::array`. An exception may be thrown if
|
||||
the cast is not possible: the error code is `simdjson::INCORRECT_TYPE` (see [Error handling](#error-handling)). Importantly, when getting an ondemand::object or ondemand::array instance, its content is
|
||||
not validated: you are only guaranteed that the corresponding initial character (`{` or `[`) is present. Thus,
|
||||
@@ -446,8 +448,8 @@ support for users who avoid exceptions. See [the simdjson error handling documen
|
||||
pass `true` (`get_string(true)`) as a parameter to get replacement characters where errors
|
||||
occur. If you somehow need to access non-UTF-8 strings in a lossless manner
|
||||
(e.g., if you strings contain unpaired surrogates), you may use the `get_wobbly_string()` function to get a string in the [WTF-8 format](https://simonsapin.github.io/wtf-8).
|
||||
When calling `get_uint64()` and `get_int64()`, if the number does not fit in a corresponding
|
||||
64-bit integer type, it is also considered an error. When parsing numbers or other scalar values, the library checks
|
||||
When calling `get_uint64()`, `get_int64()`, `get_uint32()` or `get_int32()`, if the number does not fit in the
|
||||
corresponding integer type, it is also considered an error (`NUMBER_OUT_OF_RANGE`). When parsing numbers or other scalar values, the library checks
|
||||
that the value is followed by an expected character, thus you *may* get a number parsing error when accessing the digits
|
||||
as an integer in the following strings: `{"number":12332a`, `{"number":12332\0`, `{"number":12332` (the digits appear at the end). We always abide by the [RFC 8259](https://www.tbray.org/ongoing/When/201x/2017/12/14/rfc8259.html) JSON specification so that, for example, numbers prefixed by the `+` sign are in error.
|
||||
|
||||
@@ -1790,15 +1792,15 @@ int64_t x = obj.at_path("$.c.foo.a[1]"); // 20
|
||||
x = obj.at_path("$.d.foo2.a.2"); // 30
|
||||
```
|
||||
|
||||
## Using `at_path_with_wildcard` for JSONPath Queries (On-Demand)
|
||||
## Using `for_each_at_path_with_wildcard` for JSONPath Queries (On-Demand)
|
||||
|
||||
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 `for_each_at_path_with_wildcard` function in simdjson extends the JSONPath querying capabilities by supporting wildcard expressions (`*`) in JSON paths. It calls a user-provided callback for each matching element, avoiding the need to materialize all results into a vector. 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.
|
||||
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 callback is simply never called. For instance, querying `$.empty_object.*` or `$.empty_array.*` will yield no callbacks.
|
||||
|
||||
### Example Usage
|
||||
|
||||
Here is an example demonstrating the use of `at_path_with_wildcard`:
|
||||
Here is an example demonstrating the use of `for_each_at_path_with_wildcard`:
|
||||
|
||||
```cpp
|
||||
simdjson::padded_string json_string = R"(
|
||||
@@ -1827,27 +1829,22 @@ ondemand::parser parser;
|
||||
ondemand::document doc = parser.iterate(json_string);
|
||||
|
||||
// Fetch all fields in the address object
|
||||
std::vector<ondemand::value> values;
|
||||
auto error = doc.at_path_with_wildcard("$.address.*").get(values);
|
||||
if (!error) {
|
||||
for (auto value : values) {
|
||||
std::string_view field;
|
||||
if (value.get(field) == SUCCESS) {
|
||||
std::cout << field << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
auto error = doc.for_each_at_path_with_wildcard("$.address.*",
|
||||
[](ondemand::value value) {
|
||||
std::string_view field;
|
||||
if (value.get(field) == SUCCESS) {
|
||||
std::cout << field << std::endl;
|
||||
}
|
||||
});
|
||||
|
||||
// Fetch all phone numbers
|
||||
error = doc.at_path_with_wildcard("$.phoneNumbers[*].numbers[*]").get(values);
|
||||
if (!error) {
|
||||
for (auto value : values) {
|
||||
std::string_view number;
|
||||
if (value.get(number) == SUCCESS) {
|
||||
std::cout << number << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
doc.for_each_at_path_with_wildcard("$.phoneNumbers[*].numbers[*]",
|
||||
[](ondemand::value value) {
|
||||
std::string_view number;
|
||||
if (value.get(number) == SUCCESS) {
|
||||
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.
|
||||
|
||||
+18
-1
@@ -168,6 +168,23 @@ Once you have an element, you can navigate it with idiomatic C++ iterators, oper
|
||||
`SIMDJSON_MINUS_ZERO_AS_FLOAT` to `1` when building simdjson, you can get that `-0` is mapped to `-0.0`
|
||||
as in JavaScript. You can get the desired effect by building simdjson with cmake setting the
|
||||
`SIMDJSON_MINUS_ZERO_AS_FLOAT` to on: `cmake -B build -D SIMDJSON_MINUS_ZERO_AS_FLOAT=ON`.
|
||||
* **Big Integer Support (opt-in):** By default, integers that exceed the 64-bit range cause parsing to fail with `BIGINT_ERROR`. You can opt in to big integer support so that these numbers are stored as raw digit strings on the tape instead:
|
||||
```cpp
|
||||
simdjson::dom::parser parser;
|
||||
parser.number_as_string(true); // opt-in, default false
|
||||
simdjson::dom::element doc;
|
||||
auto error = parser.parse("[1, 123456789012345678901]"_padded).get(doc);
|
||||
if (error) { std::cerr << error << std::endl; return EXIT_FAILURE; }
|
||||
for (simdjson::dom::element elem : doc) {
|
||||
if (elem.is_bigint()) {
|
||||
std::string_view digits;
|
||||
error = elem.get_bigint().get(digits);
|
||||
if (error) { std::cerr << error << std::endl; return EXIT_FAILURE; }
|
||||
std::cout << "big integer: " << digits << std::endl;
|
||||
}
|
||||
}
|
||||
```
|
||||
When enabled, big integers have type `element_type::BIGINT`. Calling `get_int64()`, `get_uint64()`, or `get_double()` on a big integer returns `INCORRECT_TYPE`. Normal numbers (int64, uint64, double) are unaffected.
|
||||
* **Field Access:** To get the value of the "foo" field in an object, use `object["foo"]`.
|
||||
* **Array Iteration:** To iterate through an array, use `for (auto value : array) { ... }`. If you
|
||||
know the type of the value, you can cast it right there, too! `for (double value : array) { ... }`
|
||||
@@ -180,7 +197,7 @@ Once you have an element, you can navigate it with idiomatic C++ iterators, oper
|
||||
* **Array and Object size** Given an array or an object, you can get its size (number of elements or keys)
|
||||
with the `size()` method.
|
||||
* **Checking an Element Type:** You can check an element's type with `element.type()`. It
|
||||
returns an `element_type` with values such as `simdjson::dom::element_type::ARRAY`, `simdjson::dom::element_type::OBJECT`, `simdjson::dom::element_type::INT64`, `simdjson::dom::element_type::UINT64`,`simdjson::dom::element_type::DOUBLE`, `simdjson::dom::element_type::STRING`, `simdjson::dom::element_type::BOOL` or, `simdjson::dom::element_type::NULL_VALUE`.
|
||||
returns an `element_type` with values such as `simdjson::dom::element_type::ARRAY`, `simdjson::dom::element_type::OBJECT`, `simdjson::dom::element_type::INT64`, `simdjson::dom::element_type::UINT64`,`simdjson::dom::element_type::DOUBLE`, `simdjson::dom::element_type::STRING`, `simdjson::dom::element_type::BOOL`, `simdjson::dom::element_type::NULL_VALUE` or, `simdjson::dom::element_type::BIGINT` (when big integer support is enabled).
|
||||
* **Output to streams and strings:** Given a document or an element (or node) out of a JSON document, you can output a minified string version using the C++ stream idiom (`out << element`). You can also request the construction of a minified string version (`simdjson::minify(element)`) or a prettified string version (`simdjson::prettify(element)`). Numbers are serialized as 64-bit floating-point numbers (`double`).
|
||||
|
||||
### Examples
|
||||
|
||||
@@ -93,6 +93,14 @@ Float values are represented as two 64-bit tape elements:
|
||||
|
||||
Performance consideration: We store numbers of the main tape because we believe that locality of reference is helpful for performance.
|
||||
|
||||
## Big Integers
|
||||
|
||||
When a JSON integer exceeds the 64-bit range (both signed and unsigned), it is classified as a big integer. By default, parsing returns `BIGINT_ERROR`. When `parser.number_as_string(true)` is set, the raw digits are stored on the string tape using the same format as strings (4-byte little-endian length prefix, followed by the UTF-8 digit bytes, followed by a null terminator).
|
||||
|
||||
A big integer is represented on the main tape as the 64-bit tape element `('Z' << 56) + x` where the payload `x` is the location on the string tape of the null-terminated digit string.
|
||||
|
||||
For example, the JSON value `99999999999999999999` would be stored as the string `"99999999999999999999"` on the string tape, with a `'Z'` tag on the main tape. Negative big integers include the leading minus sign.
|
||||
|
||||
## Root node
|
||||
|
||||
Each JSON document will have two special 64-bit tape elements representing a root node, one at the beginning and one at the end.
|
||||
|
||||
@@ -54,6 +54,9 @@ static void print_json(std::ostream& os, simdjson::dom::element element) noexcep
|
||||
case simdjson::dom::element_type::NULL_VALUE:
|
||||
os << "null" << endl;
|
||||
break;
|
||||
case simdjson::dom::element_type::BIGINT:
|
||||
os << element.get_bigint().value_unsafe() << endl;
|
||||
break;
|
||||
}
|
||||
}
|
||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
|
||||
|
||||
@@ -141,6 +141,15 @@ inline bool document::dump_raw_tape(std::ostream &os) const noexcept {
|
||||
case 'r': // we start and end with the root node
|
||||
// should we be hitting the root node?
|
||||
return false;
|
||||
case 'Z': // we have a big integer
|
||||
os << "bigint ";
|
||||
std::memcpy(&string_length, string_buf.get() + payload, sizeof(uint32_t));
|
||||
os << std::string_view(
|
||||
reinterpret_cast<const char *>(string_buf.get() + payload + sizeof(uint32_t)),
|
||||
string_length
|
||||
);
|
||||
os << '\n';
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -81,6 +81,10 @@ simdjson_inline simdjson_result<bool> simdjson_result<dom::element>::get_bool()
|
||||
if (error()) { return error(); }
|
||||
return first.get_bool();
|
||||
}
|
||||
simdjson_inline simdjson_result<std::string_view> simdjson_result<dom::element>::get_bigint() const noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.get_bigint();
|
||||
}
|
||||
|
||||
simdjson_inline bool simdjson_result<dom::element>::is_array() const noexcept {
|
||||
return !error() && first.is_array();
|
||||
@@ -110,6 +114,9 @@ simdjson_inline bool simdjson_result<dom::element>::is_bool() const noexcept {
|
||||
simdjson_inline bool simdjson_result<dom::element>::is_null() const noexcept {
|
||||
return !error() && first.is_null();
|
||||
}
|
||||
simdjson_inline bool simdjson_result<dom::element>::is_bigint() const noexcept {
|
||||
return !error() && first.is_bigint();
|
||||
}
|
||||
|
||||
simdjson_inline simdjson_result<dom::element> simdjson_result<dom::element>::operator[](std::string_view key) const noexcept {
|
||||
if (error()) { return error(); }
|
||||
@@ -218,6 +225,15 @@ inline simdjson_result<bool> element::get_bool() const noexcept {
|
||||
}
|
||||
return INCORRECT_TYPE;
|
||||
}
|
||||
inline simdjson_result<std::string_view> element::get_bigint() const noexcept {
|
||||
SIMDJSON_DEVELOPMENT_ASSERT(tape.usable());
|
||||
switch (tape.tape_ref_type()) {
|
||||
case internal::tape_type::BIGINT:
|
||||
return tape.get_string_view();
|
||||
default:
|
||||
return INCORRECT_TYPE;
|
||||
}
|
||||
}
|
||||
inline simdjson_result<const char *> element::get_c_str() const noexcept {
|
||||
SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
|
||||
switch (tape.tape_ref_type()) {
|
||||
@@ -360,6 +376,10 @@ inline bool element::is_null() const noexcept {
|
||||
return tape.is_null_on_tape();
|
||||
}
|
||||
|
||||
inline bool element::is_bigint() const noexcept {
|
||||
return tape.tape_ref_type() == internal::tape_type::BIGINT;
|
||||
}
|
||||
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
|
||||
inline element::operator bool() const noexcept(false) { return get<bool>(); }
|
||||
@@ -492,6 +512,8 @@ inline std::ostream& operator<<(std::ostream& out, element_type type) {
|
||||
return out << "bool";
|
||||
case element_type::NULL_VALUE:
|
||||
return out << "null";
|
||||
case element_type::BIGINT:
|
||||
return out << "bigint";
|
||||
default:
|
||||
return out << "unexpected content!!!"; // abort() usage is forbidden in the library
|
||||
}
|
||||
|
||||
@@ -21,7 +21,8 @@ enum class element_type {
|
||||
DOUBLE = 'd', ///< double: Any number with a "." or "e" that fits in double.
|
||||
STRING = '"', ///< std::string_view
|
||||
BOOL = 't', ///< bool
|
||||
NULL_VALUE = 'n' ///< null
|
||||
NULL_VALUE = 'n', ///< null
|
||||
BIGINT = 'Z' ///< std::string_view: big integer stored as raw digit string
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -120,6 +121,14 @@ public:
|
||||
*/
|
||||
inline simdjson_result<bool> get_bool() const noexcept;
|
||||
|
||||
/**
|
||||
* Read this element as a big integer (raw digit string).
|
||||
*
|
||||
* @returns A string_view of the raw digits, or:
|
||||
* INCORRECT_TYPE if the JSON element is not a big integer.
|
||||
*/
|
||||
inline simdjson_result<std::string_view> get_bigint() const noexcept;
|
||||
|
||||
/**
|
||||
* Whether this element is a json array.
|
||||
*
|
||||
@@ -175,6 +184,11 @@ public:
|
||||
*/
|
||||
inline bool is_null() const noexcept;
|
||||
|
||||
/**
|
||||
* Whether this element is a big integer (number exceeding 64-bit range).
|
||||
*/
|
||||
inline bool is_bigint() const noexcept;
|
||||
|
||||
/**
|
||||
* Tell whether the value can be cast to provided type (T).
|
||||
*
|
||||
@@ -533,6 +547,7 @@ public:
|
||||
simdjson_inline simdjson_result<uint64_t> get_uint64() const noexcept;
|
||||
simdjson_inline simdjson_result<double> get_double() const noexcept;
|
||||
simdjson_inline simdjson_result<bool> get_bool() const noexcept;
|
||||
simdjson_inline simdjson_result<std::string_view> get_bigint() const noexcept;
|
||||
|
||||
simdjson_inline bool is_array() const noexcept;
|
||||
simdjson_inline bool is_object() const noexcept;
|
||||
@@ -543,6 +558,7 @@ public:
|
||||
simdjson_inline bool is_number() const noexcept;
|
||||
simdjson_inline bool is_bool() const noexcept;
|
||||
simdjson_inline bool is_null() const noexcept;
|
||||
simdjson_inline bool is_bigint() const noexcept;
|
||||
|
||||
simdjson_inline simdjson_result<dom::element> operator[](std::string_view key) const noexcept;
|
||||
simdjson_inline simdjson_result<dom::element> operator[](const char *key) const noexcept;
|
||||
|
||||
@@ -36,10 +36,11 @@ inline bool parser::dump_raw_tape(std::ostream &os) const noexcept {
|
||||
}
|
||||
|
||||
inline simdjson_result<size_t> parser::read_file(std::string_view path) noexcept {
|
||||
const std::string path_copy(path);
|
||||
// Open the file
|
||||
SIMDJSON_PUSH_DISABLE_WARNINGS
|
||||
SIMDJSON_DISABLE_DEPRECATED_WARNING // Disable CRT_SECURE warning on MSVC: manually verified this is safe
|
||||
std::FILE *fp = std::fopen(path.data(), "rb");
|
||||
std::FILE *fp = std::fopen(path_copy.c_str(), "rb");
|
||||
SIMDJSON_POP_DISABLE_WARNINGS
|
||||
|
||||
if (fp == nullptr) {
|
||||
@@ -132,6 +133,7 @@ inline simdjson_result<element> parser::parse_into_document(document& provided_d
|
||||
buf += 3;
|
||||
len -= 3;
|
||||
}
|
||||
implementation->_number_as_string = _number_as_string;
|
||||
_error = implementation->parse(buf, len, provided_doc);
|
||||
|
||||
if (_error) { return _error; }
|
||||
|
||||
@@ -610,6 +610,13 @@ public:
|
||||
inline bool dump_raw_tape(std::ostream &os) const noexcept;
|
||||
|
||||
|
||||
/**
|
||||
* When enabled, big integers (exceeding uint64 range) are stored as strings
|
||||
* in the tape instead of returning BIGINT_ERROR. Default: false.
|
||||
*/
|
||||
inline void number_as_string(bool enabled) noexcept { _number_as_string = enabled; }
|
||||
inline bool number_as_string() const noexcept { return _number_as_string; }
|
||||
|
||||
private:
|
||||
/**
|
||||
* The maximum document length this parser will automatically support.
|
||||
@@ -618,6 +625,9 @@ private:
|
||||
*/
|
||||
size_t _max_capacity;
|
||||
|
||||
/** Whether to store big integers as strings instead of returning BIGINT_ERROR */
|
||||
bool _number_as_string{false};
|
||||
|
||||
/**
|
||||
* The loaded buffer (reused each time load() is called)
|
||||
*/
|
||||
|
||||
@@ -460,6 +460,12 @@ inline void string_builder<serializer>::append(simdjson::dom::element value) {
|
||||
case tape_type::STRING:
|
||||
format.string(iter.get_string_view());
|
||||
break;
|
||||
case tape_type::BIGINT: {
|
||||
// Big integer stored as string — output raw digits (no quotes)
|
||||
auto sv = iter.get_string_view();
|
||||
format.chars(sv.data(), sv.data() + sv.size());
|
||||
break;
|
||||
}
|
||||
case tape_type::INT64:
|
||||
format.number(iter.next_tape_value<int64_t>());
|
||||
iter.json_index++; // numbers take up 2 spots, so we need to increment
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include <array>
|
||||
#include <cstring>
|
||||
#include <limits>
|
||||
#include <type_traits>
|
||||
#ifndef SIMDJSON_GENERIC_STRING_BUILDER_INL_H
|
||||
|
||||
@@ -32,7 +33,8 @@
|
||||
#define SIMDJSON_EXPERIMENTAL_HAS_LSX 1
|
||||
#endif
|
||||
#endif
|
||||
#if defined(__riscv_v_intrinsic) && __riscv_v_intrinsic >= 11000
|
||||
#if defined(__riscv_v_intrinsic) && __riscv_v_intrinsic >= 11000 && \
|
||||
defined(__riscv_vector)
|
||||
#ifndef SIMDJSON_EXPERIMENTAL_HAS_RVV
|
||||
#define SIMDJSON_EXPERIMENTAL_HAS_RVV 1
|
||||
#endif
|
||||
@@ -754,6 +756,11 @@ simdjson_inline void string_builder::append(number_type v) noexcept {
|
||||
simdjson_inline void
|
||||
string_builder::escape_and_append(std::string_view input) noexcept {
|
||||
// escaping might turn a control character into \x00xx so 6 characters.
|
||||
// Guard against size_t overflow in the multiplication below.
|
||||
if (input.size() > (std::numeric_limits<size_t>::max)() / 6) {
|
||||
set_valid(false);
|
||||
return;
|
||||
}
|
||||
if (capacity_check(6 * input.size())) {
|
||||
position += write_string_escaped(input, buffer.get() + position);
|
||||
}
|
||||
@@ -762,6 +769,11 @@ string_builder::escape_and_append(std::string_view input) noexcept {
|
||||
simdjson_inline void
|
||||
string_builder::escape_and_append_with_quotes(std::string_view input) noexcept {
|
||||
// escaping might turn a control character into \x00xx so 6 characters.
|
||||
// Guard against size_t overflow in the arithmetic below.
|
||||
if (input.size() > ((std::numeric_limits<size_t>::max)() - 2) / 6) {
|
||||
set_valid(false);
|
||||
return;
|
||||
}
|
||||
if (capacity_check(2 + 6 * input.size())) {
|
||||
buffer.get()[position++] = '"';
|
||||
position += write_string_escaped(input, buffer.get() + position);
|
||||
|
||||
@@ -170,46 +170,34 @@ inline simdjson_result<value> array::at_path(std::string_view json_path) noexcep
|
||||
return at_pointer(json_pointer);
|
||||
}
|
||||
|
||||
inline simdjson_result<std::vector<value>> array::at_path_with_wildcard(std::string_view json_path) noexcept {
|
||||
std::vector<value> result;
|
||||
|
||||
#if SIMDJSON_SUPPORTS_CONCEPTS
|
||||
template <typename Func>
|
||||
requires std::invocable<Func, value>
|
||||
#else
|
||||
template <typename Func>
|
||||
#endif
|
||||
inline error_code array::for_each_at_path_with_wildcard(std::string_view json_path, Func&& callback) noexcept {
|
||||
auto result_pair = get_next_key_and_json_path(json_path);
|
||||
std::string_view key = result_pair.first;
|
||||
std::string_view remaining_path = result_pair.second;
|
||||
// Wildcard case
|
||||
if(key=="*"){
|
||||
for(auto element: *this){
|
||||
|
||||
if(element.error()){
|
||||
return element.error();
|
||||
}
|
||||
|
||||
if(remaining_path.empty()){
|
||||
// Use value_unsafe() because we've already checked for errors above.
|
||||
// The 'element' is a simdjson_result<value> wrapper, and we need to extract
|
||||
// the underlying value. value_unsafe() is safe here because error() returned false.
|
||||
result.push_back(std::move(element).value_unsafe());
|
||||
|
||||
}else{
|
||||
auto nested_result = element.at_path_with_wildcard(remaining_path);
|
||||
|
||||
if(nested_result.error()){
|
||||
return nested_result.error();
|
||||
}
|
||||
// Same logic as above.
|
||||
std::vector<value> nested_matches = std::move(nested_result).value_unsafe();
|
||||
|
||||
result.insert(result.end(),
|
||||
std::make_move_iterator(nested_matches.begin()),
|
||||
std::make_move_iterator(nested_matches.end()));
|
||||
if (key=="*"){
|
||||
for(auto element: *this) {
|
||||
value val;
|
||||
SIMDJSON_TRY(element.get(val));
|
||||
if (remaining_path.empty()) {
|
||||
callback(val);
|
||||
} else {
|
||||
error_code err = element.for_each_at_path_with_wildcard(remaining_path, callback);
|
||||
if(err) { return err; }
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}else{
|
||||
return SUCCESS;
|
||||
} else {
|
||||
// Specific index case in which we access the element at the given index
|
||||
size_t idx=0;
|
||||
size_t idx = 0;
|
||||
|
||||
for(char c:key){
|
||||
for (char c : key) {
|
||||
if(c < '0' || c > '9'){
|
||||
return INVALID_JSON_POINTER;
|
||||
}
|
||||
@@ -217,16 +205,13 @@ inline simdjson_result<std::vector<value>> array::at_path_with_wildcard(std::str
|
||||
}
|
||||
|
||||
auto element = at(idx);
|
||||
|
||||
if(element.error()){
|
||||
return element.error();
|
||||
}
|
||||
|
||||
if(remaining_path.empty()){
|
||||
result.push_back(std::move(element).value_unsafe());
|
||||
return result;
|
||||
}else{
|
||||
return element.at_path_with_wildcard(remaining_path);
|
||||
value val;
|
||||
SIMDJSON_TRY(element.get(val));
|
||||
if (remaining_path.empty()){
|
||||
callback(val);
|
||||
return SUCCESS;
|
||||
} else {
|
||||
return element.for_each_at_path_with_wildcard(remaining_path, callback);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -289,9 +274,15 @@ simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> simdj
|
||||
if (error()) { return error(); }
|
||||
return first.at_path(json_path);
|
||||
}
|
||||
simdjson_inline simdjson_result<std::vector<SIMDJSON_IMPLEMENTATION::ondemand::value>> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array>::at_path_with_wildcard(std::string_view json_path) noexcept {
|
||||
#if SIMDJSON_SUPPORTS_CONCEPTS
|
||||
template <typename Func>
|
||||
requires std::invocable<Func, SIMDJSON_IMPLEMENTATION::ondemand::value>
|
||||
#else
|
||||
template <typename Func>
|
||||
#endif
|
||||
simdjson_inline error_code simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array>::for_each_at_path_with_wildcard(std::string_view json_path, Func&& callback) noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.at_path_with_wildcard(json_path);
|
||||
return first.for_each_at_path_with_wildcard(json_path, std::forward<Func>(callback));
|
||||
}
|
||||
simdjson_inline simdjson_result<std::string_view> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array>::raw_json() noexcept {
|
||||
if (error()) { return error(); }
|
||||
|
||||
@@ -119,13 +119,21 @@ public:
|
||||
inline simdjson_result<value> at_path(std::string_view json_path) noexcept;
|
||||
|
||||
/**
|
||||
* Get all values matching the given JSONPath expression with wildcard support.
|
||||
* Call the provided callback for each value matching the given JSONPath
|
||||
* expression with wildcard support.
|
||||
* Supports wildcard patterns like "[*]" to match all array elements.
|
||||
*
|
||||
* @param json_path JSONPath expression with wildcards
|
||||
* @return Vector of values matching the wildcard pattern
|
||||
* @param callback Function called for each matching value
|
||||
* @return error_code indicating success or failure
|
||||
*/
|
||||
inline simdjson_result<std::vector<value>> at_path_with_wildcard(std::string_view json_path) noexcept;
|
||||
#if SIMDJSON_SUPPORTS_CONCEPTS
|
||||
template <typename Func>
|
||||
requires std::invocable<Func, value>
|
||||
#else
|
||||
template <typename Func>
|
||||
#endif
|
||||
inline error_code for_each_at_path_with_wildcard(std::string_view json_path, Func&& callback) noexcept;
|
||||
|
||||
/**
|
||||
* Consumes the array and returns a string_view instance corresponding to the
|
||||
@@ -249,7 +257,13 @@ public:
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> at(size_t index) noexcept;
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> at_pointer(std::string_view json_pointer) noexcept;
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> at_path(std::string_view json_path) noexcept;
|
||||
simdjson_inline simdjson_result<std::vector<SIMDJSON_IMPLEMENTATION::ondemand::value>> at_path_with_wildcard(std::string_view json_path) noexcept;
|
||||
#if SIMDJSON_SUPPORTS_CONCEPTS
|
||||
template <typename Func>
|
||||
requires std::invocable<Func, SIMDJSON_IMPLEMENTATION::ondemand::value>
|
||||
#else
|
||||
template <typename Func>
|
||||
#endif
|
||||
simdjson_inline error_code for_each_at_path_with_wildcard(std::string_view json_path, Func&& callback) noexcept;
|
||||
simdjson_inline simdjson_result<std::string_view> raw_json() noexcept;
|
||||
#if SIMDJSON_SUPPORTS_CONCEPTS
|
||||
// TODO: move this code into object-inl.h
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
#include "simdjson/generic/ondemand/deserialize.h"
|
||||
#endif // SIMDJSON_CONDITIONAL_INCLUDE
|
||||
|
||||
#include <limits>
|
||||
|
||||
namespace simdjson {
|
||||
namespace SIMDJSON_IMPLEMENTATION {
|
||||
namespace ondemand {
|
||||
@@ -131,6 +133,18 @@ simdjson_inline simdjson_result<int64_t> document::get_int64() noexcept {
|
||||
simdjson_inline simdjson_result<int64_t> document::get_int64_in_string() noexcept {
|
||||
return get_root_value_iterator().get_root_int64_in_string(true);
|
||||
}
|
||||
simdjson_inline simdjson_result<uint32_t> document::get_uint32() noexcept {
|
||||
uint64_t result;
|
||||
SIMDJSON_TRY(get_uint64().get(result));
|
||||
if (result > (std::numeric_limits<uint32_t>::max)()) { return NUMBER_OUT_OF_RANGE; }
|
||||
return static_cast<uint32_t>(result);
|
||||
}
|
||||
simdjson_inline simdjson_result<int32_t> document::get_int32() noexcept {
|
||||
int64_t result;
|
||||
SIMDJSON_TRY(get_int64().get(result));
|
||||
if (result > (std::numeric_limits<int32_t>::max)() || result < (std::numeric_limits<int32_t>::min)()) { return NUMBER_OUT_OF_RANGE; }
|
||||
return static_cast<int32_t>(result);
|
||||
}
|
||||
simdjson_inline simdjson_result<double> document::get_double() noexcept {
|
||||
return get_root_value_iterator().get_root_double(true);
|
||||
}
|
||||
@@ -164,6 +178,8 @@ template<> simdjson_inline simdjson_result<std::string_view> document::get() & n
|
||||
template<> simdjson_inline simdjson_result<double> document::get() & noexcept { return get_double(); }
|
||||
template<> simdjson_inline simdjson_result<uint64_t> document::get() & noexcept { return get_uint64(); }
|
||||
template<> simdjson_inline simdjson_result<int64_t> document::get() & noexcept { return get_int64(); }
|
||||
template<> simdjson_inline simdjson_result<uint32_t> document::get() & noexcept { return get_uint32(); }
|
||||
template<> simdjson_inline simdjson_result<int32_t> document::get() & noexcept { return get_int32(); }
|
||||
template<> simdjson_inline simdjson_result<bool> document::get() & noexcept { return get_bool(); }
|
||||
template<> simdjson_inline simdjson_result<value> document::get() & noexcept { return get_value(); }
|
||||
|
||||
@@ -174,6 +190,8 @@ template<> simdjson_warn_unused simdjson_inline error_code document::get(std::st
|
||||
template<> simdjson_warn_unused simdjson_inline error_code document::get(double& out) & noexcept { return get_double().get(out); }
|
||||
template<> simdjson_warn_unused simdjson_inline error_code document::get(uint64_t& out) & noexcept { return get_uint64().get(out); }
|
||||
template<> simdjson_warn_unused simdjson_inline error_code document::get(int64_t& out) & noexcept { return get_int64().get(out); }
|
||||
template<> simdjson_warn_unused simdjson_inline error_code document::get(uint32_t& out) & noexcept { return get_uint32().get(out); }
|
||||
template<> simdjson_warn_unused simdjson_inline error_code document::get(int32_t& out) & noexcept { return get_int32().get(out); }
|
||||
template<> simdjson_warn_unused simdjson_inline error_code document::get(bool& out) & noexcept { return get_bool().get(out); }
|
||||
template<> simdjson_warn_unused simdjson_inline error_code document::get(value& out) & noexcept { return get_value().get(out); }
|
||||
|
||||
@@ -347,8 +365,14 @@ simdjson_inline simdjson_result<value> document::at_path(std::string_view json_p
|
||||
}
|
||||
}
|
||||
|
||||
simdjson_inline simdjson_result<std::vector<value>> document::at_path_with_wildcard(std::string_view json_path) noexcept {
|
||||
rewind(); // Rewind the document each time at_path_with_wildcard is called
|
||||
#if SIMDJSON_SUPPORTS_CONCEPTS
|
||||
template <typename Func>
|
||||
requires std::invocable<Func, value>
|
||||
#else
|
||||
template <typename Func>
|
||||
#endif
|
||||
simdjson_inline error_code document::for_each_at_path_with_wildcard(std::string_view json_path, Func&& callback) noexcept {
|
||||
rewind(); // Rewind the document each time for_each_at_path_with_wildcard is called
|
||||
if (json_path.empty()) {
|
||||
return INVALID_JSON_POINTER;
|
||||
}
|
||||
@@ -356,9 +380,9 @@ simdjson_inline simdjson_result<std::vector<value>> document::at_path_with_wildc
|
||||
SIMDJSON_TRY(type().get(t));
|
||||
switch (t) {
|
||||
case json_type::array:
|
||||
return (*this).get_array().at_path_with_wildcard(json_path);
|
||||
return (*this).get_array().for_each_at_path_with_wildcard(json_path, std::forward<Func>(callback));
|
||||
case json_type::object:
|
||||
return (*this).get_object().at_path_with_wildcard(json_path);
|
||||
return (*this).get_object().for_each_at_path_with_wildcard(json_path, std::forward<Func>(callback));
|
||||
default:
|
||||
return INVALID_JSON_POINTER;
|
||||
}
|
||||
@@ -504,6 +528,14 @@ simdjson_inline simdjson_result<int64_t> simdjson_result<SIMDJSON_IMPLEMENTATION
|
||||
if (error()) { return error(); }
|
||||
return first.get_int64_in_string();
|
||||
}
|
||||
simdjson_inline simdjson_result<uint32_t> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document>::get_uint32() noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.get_uint32();
|
||||
}
|
||||
simdjson_inline simdjson_result<int32_t> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document>::get_int32() noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.get_int32();
|
||||
}
|
||||
simdjson_inline simdjson_result<double> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document>::get_double() noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.get_double();
|
||||
@@ -687,9 +719,15 @@ simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> simdjs
|
||||
return first.at_path(json_path);
|
||||
}
|
||||
|
||||
simdjson_inline simdjson_result<std::vector<SIMDJSON_IMPLEMENTATION::ondemand::value>> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document>::at_path_with_wildcard(std::string_view json_path) noexcept {
|
||||
#if SIMDJSON_SUPPORTS_CONCEPTS
|
||||
template <typename Func>
|
||||
requires std::invocable<Func, SIMDJSON_IMPLEMENTATION::ondemand::value>
|
||||
#else
|
||||
template <typename Func>
|
||||
#endif
|
||||
simdjson_inline error_code simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document>::for_each_at_path_with_wildcard(std::string_view json_path, Func&& callback) noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.at_path_with_wildcard(json_path);
|
||||
return first.for_each_at_path_with_wildcard(json_path, std::forward<Func>(callback));
|
||||
}
|
||||
|
||||
#if SIMDJSON_STATIC_REFLECTION
|
||||
@@ -731,6 +769,18 @@ simdjson_inline simdjson_result<uint64_t> document_reference::get_uint64() noexc
|
||||
simdjson_inline simdjson_result<uint64_t> document_reference::get_uint64_in_string() noexcept { return doc->get_root_value_iterator().get_root_uint64_in_string(false); }
|
||||
simdjson_inline simdjson_result<int64_t> document_reference::get_int64() noexcept { return doc->get_root_value_iterator().get_root_int64(false); }
|
||||
simdjson_inline simdjson_result<int64_t> document_reference::get_int64_in_string() noexcept { return doc->get_root_value_iterator().get_root_int64_in_string(false); }
|
||||
simdjson_inline simdjson_result<uint32_t> document_reference::get_uint32() noexcept {
|
||||
uint64_t result;
|
||||
SIMDJSON_TRY(doc->get_root_value_iterator().get_root_uint64(false).get(result));
|
||||
if (result > (std::numeric_limits<uint32_t>::max)()) { return NUMBER_OUT_OF_RANGE; }
|
||||
return static_cast<uint32_t>(result);
|
||||
}
|
||||
simdjson_inline simdjson_result<int32_t> document_reference::get_int32() noexcept {
|
||||
int64_t result;
|
||||
SIMDJSON_TRY(doc->get_root_value_iterator().get_root_int64(false).get(result));
|
||||
if (result > (std::numeric_limits<int32_t>::max)() || result < (std::numeric_limits<int32_t>::min)()) { return NUMBER_OUT_OF_RANGE; }
|
||||
return static_cast<int32_t>(result);
|
||||
}
|
||||
simdjson_inline simdjson_result<double> document_reference::get_double() noexcept { return doc->get_root_value_iterator().get_root_double(false); }
|
||||
simdjson_inline simdjson_result<double> document_reference::get_double_in_string() noexcept { return doc->get_root_value_iterator().get_root_double(false); }
|
||||
simdjson_inline simdjson_result<std::string_view> document_reference::get_string(bool allow_replacement) noexcept { return doc->get_root_value_iterator().get_root_string(false, allow_replacement); }
|
||||
@@ -748,6 +798,8 @@ template<> simdjson_inline simdjson_result<std::string_view> document_reference:
|
||||
template<> simdjson_inline simdjson_result<double> document_reference::get() & noexcept { return get_double(); }
|
||||
template<> simdjson_inline simdjson_result<uint64_t> document_reference::get() & noexcept { return get_uint64(); }
|
||||
template<> simdjson_inline simdjson_result<int64_t> document_reference::get() & noexcept { return get_int64(); }
|
||||
template<> simdjson_inline simdjson_result<uint32_t> document_reference::get() & noexcept { return get_uint32(); }
|
||||
template<> simdjson_inline simdjson_result<int32_t> document_reference::get() & noexcept { return get_int32(); }
|
||||
template<> simdjson_inline simdjson_result<bool> document_reference::get() & noexcept { return get_bool(); }
|
||||
template<> simdjson_inline simdjson_result<value> document_reference::get() & noexcept { return get_value(); }
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
@@ -786,7 +838,13 @@ simdjson_inline simdjson_result<number> document_reference::get_number() noexcep
|
||||
simdjson_inline simdjson_result<std::string_view> document_reference::raw_json_token() noexcept { return doc->raw_json_token(); }
|
||||
simdjson_inline simdjson_result<value> document_reference::at_pointer(std::string_view json_pointer) noexcept { return doc->at_pointer(json_pointer); }
|
||||
simdjson_inline simdjson_result<value> document_reference::at_path(std::string_view json_path) noexcept { return doc->at_path(json_path); }
|
||||
simdjson_inline simdjson_result<std::vector<value>> document_reference::at_path_with_wildcard(std::string_view json_path) noexcept { return doc->at_path_with_wildcard(json_path); }
|
||||
#if SIMDJSON_SUPPORTS_CONCEPTS
|
||||
template <typename Func>
|
||||
requires std::invocable<Func, value>
|
||||
#else
|
||||
template <typename Func>
|
||||
#endif
|
||||
simdjson_inline error_code document_reference::for_each_at_path_with_wildcard(std::string_view json_path, Func&& callback) noexcept { return doc->for_each_at_path_with_wildcard(json_path, std::forward<Func>(callback)); }
|
||||
simdjson_inline simdjson_result<std::string_view> document_reference::raw_json() noexcept { return doc->raw_json();}
|
||||
simdjson_inline document_reference::operator document&() const noexcept { return *doc; }
|
||||
#if SIMDJSON_SUPPORTS_CONCEPTS && SIMDJSON_STATIC_REFLECTION
|
||||
@@ -879,6 +937,14 @@ simdjson_inline simdjson_result<int64_t> simdjson_result<SIMDJSON_IMPLEMENTATION
|
||||
if (error()) { return error(); }
|
||||
return first.get_int64_in_string();
|
||||
}
|
||||
simdjson_inline simdjson_result<uint32_t> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document_reference>::get_uint32() noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.get_uint32();
|
||||
}
|
||||
simdjson_inline simdjson_result<int32_t> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document_reference>::get_int32() noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.get_int32();
|
||||
}
|
||||
simdjson_inline simdjson_result<double> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document_reference>::get_double() noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.get_double();
|
||||
@@ -1043,11 +1109,17 @@ simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> simdjs
|
||||
}
|
||||
return first.at_path(json_path);
|
||||
}
|
||||
simdjson_inline simdjson_result<std::vector<SIMDJSON_IMPLEMENTATION::ondemand::value>> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document_reference>::at_path_with_wildcard(std::string_view json_path) noexcept {
|
||||
#if SIMDJSON_SUPPORTS_CONCEPTS
|
||||
template <typename Func>
|
||||
requires std::invocable<Func, SIMDJSON_IMPLEMENTATION::ondemand::value>
|
||||
#else
|
||||
template <typename Func>
|
||||
#endif
|
||||
simdjson_inline error_code simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document_reference>::for_each_at_path_with_wildcard(std::string_view json_path, Func&& callback) noexcept {
|
||||
if (error()) {
|
||||
return error();
|
||||
}
|
||||
return first.at_path_with_wildcard(json_path);
|
||||
return first.for_each_at_path_with_wildcard(json_path, std::forward<Func>(callback));
|
||||
}
|
||||
#if SIMDJSON_STATIC_REFLECTION
|
||||
template<constevalutil::fixed_string... FieldNames, typename T>
|
||||
|
||||
@@ -76,6 +76,26 @@ public:
|
||||
* @returns INCORRECT_TYPE If the JSON value is not a 64-bit integer.
|
||||
*/
|
||||
simdjson_inline simdjson_result<int64_t> get_int64_in_string() noexcept;
|
||||
/**
|
||||
* Cast this JSON value to a 32-bit unsigned integer.
|
||||
*
|
||||
* Calls get_uint64() and checks that the result fits in a uint32_t.
|
||||
*
|
||||
* @returns A 32-bit unsigned integer.
|
||||
* @returns INCORRECT_TYPE If the JSON value is not an unsigned integer.
|
||||
* @returns NUMBER_OUT_OF_RANGE If the value does not fit in a uint32_t.
|
||||
*/
|
||||
simdjson_inline simdjson_result<uint32_t> get_uint32() noexcept;
|
||||
/**
|
||||
* Cast this JSON value to a 32-bit signed integer.
|
||||
*
|
||||
* Calls get_int64() and checks that the result fits in an int32_t.
|
||||
*
|
||||
* @returns A 32-bit signed integer.
|
||||
* @returns INCORRECT_TYPE If the JSON value is not an integer.
|
||||
* @returns NUMBER_OUT_OF_RANGE If the value does not fit in an int32_t.
|
||||
*/
|
||||
simdjson_inline simdjson_result<int32_t> get_int32() noexcept;
|
||||
/**
|
||||
* Cast this JSON value to a double.
|
||||
*
|
||||
@@ -724,21 +744,24 @@ public:
|
||||
simdjson_inline simdjson_result<value> at_path(std::string_view json_path) noexcept;
|
||||
|
||||
/**
|
||||
* Get all values matching the given JSONPath expression with wildcard support.
|
||||
* Call the provided callback for each value matching the given JSONPath
|
||||
* expression with wildcard support.
|
||||
*
|
||||
* Supports wildcard patterns like "$.array[*]" or "$.object.*" to match multiple elements.
|
||||
*
|
||||
* This method materializes all matching values into a vector.
|
||||
* The document will be consumed after this call.
|
||||
*
|
||||
* @param json_path JSONPath expression with wildcards
|
||||
* @return Vector of values matching the wildcard pattern, or:
|
||||
* - INVALID_JSON_POINTER if the JSONPath cannot be parsed
|
||||
* - NO_SUCH_FIELD if a field does not exist
|
||||
* - INDEX_OUT_OF_BOUNDS if an array index is out of bounds
|
||||
* - INCORRECT_TYPE if path traversal encounters wrong type
|
||||
* @param callback Function called for each matching value
|
||||
* @return error_code indicating success or failure
|
||||
*/
|
||||
simdjson_inline simdjson_result<std::vector<value>> at_path_with_wildcard(std::string_view json_path) noexcept;
|
||||
#if SIMDJSON_SUPPORTS_CONCEPTS
|
||||
template <typename Func>
|
||||
requires std::invocable<Func, value>
|
||||
#else
|
||||
template <typename Func>
|
||||
#endif
|
||||
simdjson_inline error_code for_each_at_path_with_wildcard(std::string_view json_path, Func&& callback) noexcept;
|
||||
|
||||
/**
|
||||
* Consumes the document and returns a string_view instance corresponding to the
|
||||
@@ -829,6 +852,8 @@ public:
|
||||
simdjson_inline simdjson_result<uint64_t> get_uint64_in_string() noexcept;
|
||||
simdjson_inline simdjson_result<int64_t> get_int64() noexcept;
|
||||
simdjson_inline simdjson_result<int64_t> get_int64_in_string() noexcept;
|
||||
simdjson_inline simdjson_result<uint32_t> get_uint32() noexcept;
|
||||
simdjson_inline simdjson_result<int32_t> get_int32() noexcept;
|
||||
simdjson_inline simdjson_result<double> get_double() noexcept;
|
||||
simdjson_inline simdjson_result<double> get_double_in_string() noexcept;
|
||||
simdjson_inline simdjson_result<std::string_view> get_string(bool allow_replacement = false) noexcept;
|
||||
@@ -957,7 +982,13 @@ public:
|
||||
simdjson_inline simdjson_result<std::string_view> raw_json_token() noexcept;
|
||||
simdjson_inline simdjson_result<value> at_pointer(std::string_view json_pointer) noexcept;
|
||||
simdjson_inline simdjson_result<value> at_path(std::string_view json_path) noexcept;
|
||||
simdjson_inline simdjson_result<std::vector<value>> at_path_with_wildcard(std::string_view json_path) noexcept;
|
||||
#if SIMDJSON_SUPPORTS_CONCEPTS
|
||||
template <typename Func>
|
||||
requires std::invocable<Func, value>
|
||||
#else
|
||||
template <typename Func>
|
||||
#endif
|
||||
simdjson_inline error_code for_each_at_path_with_wildcard(std::string_view json_path, Func&& callback) noexcept;
|
||||
|
||||
private:
|
||||
document *doc{nullptr};
|
||||
@@ -982,6 +1013,8 @@ public:
|
||||
simdjson_inline simdjson_result<uint64_t> get_uint64_in_string() noexcept;
|
||||
simdjson_inline simdjson_result<int64_t> get_int64() noexcept;
|
||||
simdjson_inline simdjson_result<int64_t> get_int64_in_string() noexcept;
|
||||
simdjson_inline simdjson_result<uint32_t> get_uint32() noexcept;
|
||||
simdjson_inline simdjson_result<int32_t> get_int32() noexcept;
|
||||
simdjson_inline simdjson_result<double> get_double() noexcept;
|
||||
simdjson_inline simdjson_result<double> get_double_in_string() noexcept;
|
||||
simdjson_inline simdjson_result<std::string_view> get_string(bool allow_replacement = false) noexcept;
|
||||
@@ -1041,7 +1074,13 @@ public:
|
||||
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> at_pointer(std::string_view json_pointer) noexcept;
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> at_path(std::string_view json_path) noexcept;
|
||||
simdjson_inline simdjson_result<std::vector<SIMDJSON_IMPLEMENTATION::ondemand::value>> at_path_with_wildcard(std::string_view json_path) noexcept;
|
||||
#if SIMDJSON_SUPPORTS_CONCEPTS
|
||||
template <typename Func>
|
||||
requires std::invocable<Func, SIMDJSON_IMPLEMENTATION::ondemand::value>
|
||||
#else
|
||||
template <typename Func>
|
||||
#endif
|
||||
simdjson_inline error_code for_each_at_path_with_wildcard(std::string_view json_path, Func&& callback) noexcept;
|
||||
#if SIMDJSON_STATIC_REFLECTION
|
||||
template<constevalutil::fixed_string... FieldNames, typename T>
|
||||
requires(std::is_class_v<T> && (sizeof...(FieldNames) > 0))
|
||||
@@ -1069,6 +1108,8 @@ public:
|
||||
simdjson_inline simdjson_result<uint64_t> get_uint64_in_string() noexcept;
|
||||
simdjson_inline simdjson_result<int64_t> get_int64() noexcept;
|
||||
simdjson_inline simdjson_result<int64_t> get_int64_in_string() noexcept;
|
||||
simdjson_inline simdjson_result<uint32_t> get_uint32() noexcept;
|
||||
simdjson_inline simdjson_result<int32_t> get_int32() noexcept;
|
||||
simdjson_inline simdjson_result<double> get_double() noexcept;
|
||||
simdjson_inline simdjson_result<double> get_double_in_string() noexcept;
|
||||
simdjson_inline simdjson_result<std::string_view> get_string(bool allow_replacement = false) noexcept;
|
||||
@@ -1124,7 +1165,13 @@ public:
|
||||
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> at_pointer(std::string_view json_pointer) noexcept;
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> at_path(std::string_view json_path) noexcept;
|
||||
simdjson_inline simdjson_result<std::vector<SIMDJSON_IMPLEMENTATION::ondemand::value>> at_path_with_wildcard(std::string_view json_path) noexcept;
|
||||
#if SIMDJSON_SUPPORTS_CONCEPTS
|
||||
template <typename Func>
|
||||
requires std::invocable<Func, SIMDJSON_IMPLEMENTATION::ondemand::value>
|
||||
#else
|
||||
template <typename Func>
|
||||
#endif
|
||||
simdjson_inline error_code for_each_at_path_with_wildcard(std::string_view json_path, Func&& callback) noexcept;
|
||||
#if SIMDJSON_STATIC_REFLECTION
|
||||
template<constevalutil::fixed_string... FieldNames, typename T>
|
||||
requires(std::is_class_v<T> && (sizeof...(FieldNames) > 0))
|
||||
|
||||
@@ -177,9 +177,13 @@ inline simdjson_result<value> object::at_path(std::string_view json_path) noexce
|
||||
return at_pointer(json_pointer);
|
||||
}
|
||||
|
||||
inline simdjson_result<std::vector<value>> object::at_path_with_wildcard(std::string_view json_path) noexcept {
|
||||
std::vector<value> result;
|
||||
|
||||
#if SIMDJSON_SUPPORTS_CONCEPTS
|
||||
template <typename Func>
|
||||
requires std::invocable<Func, value>
|
||||
#else
|
||||
template <typename Func>
|
||||
#endif
|
||||
inline error_code object::for_each_at_path_with_wildcard(std::string_view json_path, Func&& callback) noexcept {
|
||||
auto result_pair = get_next_key_and_json_path(json_path);
|
||||
std::string_view key = result_pair.first;
|
||||
std::string_view remaining_path = result_pair.second;
|
||||
@@ -189,34 +193,22 @@ inline simdjson_result<std::vector<value>> object::at_path_with_wildcard(std::st
|
||||
for (auto field : *this) {
|
||||
value val;
|
||||
SIMDJSON_TRY(field.value().get(val));
|
||||
|
||||
if (remaining_path.empty()) {
|
||||
result.push_back(std::move(val));
|
||||
callback(val);
|
||||
} else {
|
||||
auto nested_result = val.at_path_with_wildcard(remaining_path);
|
||||
|
||||
if (nested_result.error()) {
|
||||
return nested_result.error();
|
||||
}
|
||||
// Extract and append all nested matches to our result
|
||||
std::vector<value> nested_vec;
|
||||
SIMDJSON_TRY(std::move(nested_result).get(nested_vec));
|
||||
|
||||
result.insert(result.end(),
|
||||
std::make_move_iterator(nested_vec.begin()),
|
||||
std::make_move_iterator(nested_vec.end()));
|
||||
SIMDJSON_TRY(val.for_each_at_path_with_wildcard(remaining_path, callback));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
return SUCCESS;
|
||||
} else {
|
||||
value val;
|
||||
SIMDJSON_TRY(find_field(key).get(val));
|
||||
|
||||
if (remaining_path.empty()) {
|
||||
result.push_back(std::move(val));
|
||||
return result;
|
||||
callback(val);
|
||||
return SUCCESS;
|
||||
} else {
|
||||
return val.at_path_with_wildcard(remaining_path);
|
||||
return val.for_each_at_path_with_wildcard(remaining_path, callback);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -347,9 +339,15 @@ simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> simdjs
|
||||
return first.at_path(json_path);
|
||||
}
|
||||
|
||||
simdjson_inline simdjson_result<std::vector<SIMDJSON_IMPLEMENTATION::ondemand::value>> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object>::at_path_with_wildcard(std::string_view json_path) noexcept {
|
||||
#if SIMDJSON_SUPPORTS_CONCEPTS
|
||||
template <typename Func>
|
||||
requires std::invocable<Func, SIMDJSON_IMPLEMENTATION::ondemand::value>
|
||||
#else
|
||||
template <typename Func>
|
||||
#endif
|
||||
simdjson_inline error_code simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object>::for_each_at_path_with_wildcard(std::string_view json_path, Func&& callback) noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.at_path_with_wildcard(json_path);
|
||||
return first.for_each_at_path_with_wildcard(json_path, std::forward<Func>(callback));
|
||||
}
|
||||
|
||||
inline simdjson_result<bool> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object>::reset() noexcept {
|
||||
|
||||
@@ -172,13 +172,21 @@ public:
|
||||
inline simdjson_result<value> at_path(std::string_view json_path) noexcept;
|
||||
|
||||
/**
|
||||
* Get all values matching the given JSONPath expression with wildcard support.
|
||||
* Call the provided callback for each value matching the given JSONPath
|
||||
* expression with wildcard support.
|
||||
* Supports wildcard patterns like ".*" to match all object fields.
|
||||
*
|
||||
* @param json_path JSONPath expression with wildcards
|
||||
* @return Vector of values matching the wildcard pattern
|
||||
* @param callback Function called for each matching value
|
||||
* @return error_code indicating success or failure
|
||||
*/
|
||||
inline simdjson_result<std::vector<value>> at_path_with_wildcard(std::string_view json_path) noexcept;
|
||||
#if SIMDJSON_SUPPORTS_CONCEPTS
|
||||
template <typename Func>
|
||||
requires std::invocable<Func, value>
|
||||
#else
|
||||
template <typename Func>
|
||||
#endif
|
||||
inline error_code for_each_at_path_with_wildcard(std::string_view json_path, Func&& callback) noexcept;
|
||||
|
||||
/**
|
||||
* Reset the iterator so that we are pointing back at the
|
||||
@@ -328,7 +336,13 @@ public:
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> operator[](std::string_view key) && noexcept;
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> at_pointer(std::string_view json_pointer) noexcept;
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> at_path(std::string_view json_path) noexcept;
|
||||
simdjson_inline simdjson_result<std::vector<SIMDJSON_IMPLEMENTATION::ondemand::value>> at_path_with_wildcard(std::string_view json_path) noexcept;
|
||||
#if SIMDJSON_SUPPORTS_CONCEPTS
|
||||
template <typename Func>
|
||||
requires std::invocable<Func, SIMDJSON_IMPLEMENTATION::ondemand::value>
|
||||
#else
|
||||
template <typename Func>
|
||||
#endif
|
||||
simdjson_inline error_code for_each_at_path_with_wildcard(std::string_view json_path, Func&& callback) noexcept;
|
||||
inline simdjson_result<bool> reset() noexcept;
|
||||
inline simdjson_result<bool> is_empty() noexcept;
|
||||
inline simdjson_result<size_t> count_fields() & noexcept;
|
||||
|
||||
@@ -172,7 +172,7 @@ simdjson_pure simdjson_inline size_t parser::max_depth() const noexcept {
|
||||
}
|
||||
|
||||
simdjson_inline void parser::set_max_capacity(size_t max_capacity) noexcept {
|
||||
if(max_capacity < dom::MINIMAL_DOCUMENT_CAPACITY) {
|
||||
if(max_capacity > dom::MINIMAL_DOCUMENT_CAPACITY) {
|
||||
_max_capacity = max_capacity;
|
||||
} else {
|
||||
_max_capacity = dom::MINIMAL_DOCUMENT_CAPACITY;
|
||||
@@ -199,7 +199,7 @@ simdjson_inline simdjson_warn_unused ondemand::parser& parser::get_parser() {
|
||||
return *parser::get_parser_instance();
|
||||
}
|
||||
|
||||
simdjson_inline bool release_parser() {
|
||||
simdjson_inline bool parser::release_parser() {
|
||||
auto &parser_instance = parser::get_threadlocal_parser_if_exists();
|
||||
if (parser_instance) {
|
||||
parser_instance.reset();
|
||||
|
||||
@@ -388,8 +388,6 @@ public:
|
||||
static simdjson_inline bool release_parser();
|
||||
|
||||
private:
|
||||
friend bool release_parser();
|
||||
friend ondemand::parser& get_parser();
|
||||
/** Get the thread-local parser instance, allocates it if needed */
|
||||
static simdjson_inline simdjson_warn_unused std::unique_ptr<ondemand::parser>& get_parser_instance();
|
||||
/** Get the thread-local parser instance, it might be null */
|
||||
|
||||
@@ -12,6 +12,8 @@
|
||||
#include "simdjson/generic/ondemand/value.h"
|
||||
#endif // SIMDJSON_CONDITIONAL_INCLUDE
|
||||
|
||||
#include <limits>
|
||||
|
||||
namespace simdjson {
|
||||
namespace SIMDJSON_IMPLEMENTATION {
|
||||
namespace ondemand {
|
||||
@@ -72,6 +74,18 @@ simdjson_inline simdjson_result<int64_t> value::get_int64() noexcept {
|
||||
simdjson_inline simdjson_result<int64_t> value::get_int64_in_string() noexcept {
|
||||
return iter.get_int64_in_string();
|
||||
}
|
||||
simdjson_inline simdjson_result<uint32_t> value::get_uint32() noexcept {
|
||||
uint64_t result;
|
||||
SIMDJSON_TRY(get_uint64().get(result));
|
||||
if (result > (std::numeric_limits<uint32_t>::max)()) { return NUMBER_OUT_OF_RANGE; }
|
||||
return static_cast<uint32_t>(result);
|
||||
}
|
||||
simdjson_inline simdjson_result<int32_t> value::get_int32() noexcept {
|
||||
int64_t result;
|
||||
SIMDJSON_TRY(get_int64().get(result));
|
||||
if (result > (std::numeric_limits<int32_t>::max)() || result < (std::numeric_limits<int32_t>::min)()) { return NUMBER_OUT_OF_RANGE; }
|
||||
return static_cast<int32_t>(result);
|
||||
}
|
||||
simdjson_inline simdjson_result<bool> value::get_bool() noexcept {
|
||||
return iter.get_bool();
|
||||
}
|
||||
@@ -87,6 +101,8 @@ template<> simdjson_inline simdjson_result<number> value::get() noexcept { retur
|
||||
template<> simdjson_inline simdjson_result<double> value::get() noexcept { return get_double(); }
|
||||
template<> simdjson_inline simdjson_result<uint64_t> value::get() noexcept { return get_uint64(); }
|
||||
template<> simdjson_inline simdjson_result<int64_t> value::get() noexcept { return get_int64(); }
|
||||
template<> simdjson_inline simdjson_result<uint32_t> value::get() noexcept { return get_uint32(); }
|
||||
template<> simdjson_inline simdjson_result<int32_t> value::get() noexcept { return get_int32(); }
|
||||
template<> simdjson_inline simdjson_result<bool> value::get() noexcept { return get_bool(); }
|
||||
|
||||
|
||||
@@ -98,6 +114,8 @@ template<> simdjson_warn_unused simdjson_inline error_code value::get(number& ou
|
||||
template<> simdjson_warn_unused simdjson_inline error_code value::get(double& out) noexcept { return get_double().get(out); }
|
||||
template<> simdjson_warn_unused simdjson_inline error_code value::get(uint64_t& out) noexcept { return get_uint64().get(out); }
|
||||
template<> simdjson_warn_unused simdjson_inline error_code value::get(int64_t& out) noexcept { return get_int64().get(out); }
|
||||
template<> simdjson_warn_unused simdjson_inline error_code value::get(uint32_t& out) noexcept { return get_uint32().get(out); }
|
||||
template<> simdjson_warn_unused simdjson_inline error_code value::get(int32_t& out) noexcept { return get_int32().get(out); }
|
||||
template<> simdjson_warn_unused simdjson_inline error_code value::get(bool& out) noexcept { return get_bool().get(out); }
|
||||
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
@@ -296,14 +314,20 @@ simdjson_inline simdjson_result<value> value::at_path(std::string_view json_path
|
||||
}
|
||||
}
|
||||
|
||||
inline simdjson_result<std::vector<value>> value::at_path_with_wildcard(std::string_view json_path) noexcept {
|
||||
#if SIMDJSON_SUPPORTS_CONCEPTS
|
||||
template <typename Func>
|
||||
requires std::invocable<Func, value>
|
||||
#else
|
||||
template <typename Func>
|
||||
#endif
|
||||
inline error_code value::for_each_at_path_with_wildcard(std::string_view json_path, Func&& callback) noexcept {
|
||||
json_type t;
|
||||
SIMDJSON_TRY(type().get(t));
|
||||
switch (t) {
|
||||
case json_type::array:
|
||||
return (*this).get_array().at_path_with_wildcard(json_path);
|
||||
return (*this).get_array().for_each_at_path_with_wildcard(json_path, std::forward<Func>(callback));
|
||||
case json_type::object:
|
||||
return (*this).get_object().at_path_with_wildcard(json_path);
|
||||
return (*this).get_object().for_each_at_path_with_wildcard(json_path, std::forward<Func>(callback));
|
||||
default:
|
||||
return INVALID_JSON_POINTER;
|
||||
}
|
||||
@@ -401,6 +425,14 @@ simdjson_inline simdjson_result<int64_t> simdjson_result<SIMDJSON_IMPLEMENTATION
|
||||
if (error()) { return error(); }
|
||||
return first.get_int64_in_string();
|
||||
}
|
||||
simdjson_inline simdjson_result<uint32_t> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>::get_uint32() noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.get_uint32();
|
||||
}
|
||||
simdjson_inline simdjson_result<int32_t> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>::get_int32() noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.get_int32();
|
||||
}
|
||||
simdjson_inline simdjson_result<double> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>::get_double() noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.get_double();
|
||||
@@ -559,12 +591,18 @@ simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> simdjs
|
||||
return first.at_path(json_path);
|
||||
}
|
||||
|
||||
inline simdjson_result<std::vector<SIMDJSON_IMPLEMENTATION::ondemand::value>> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>::at_path_with_wildcard(
|
||||
std::string_view json_path) noexcept {
|
||||
#if SIMDJSON_SUPPORTS_CONCEPTS
|
||||
template <typename Func>
|
||||
requires std::invocable<Func, SIMDJSON_IMPLEMENTATION::ondemand::value>
|
||||
#else
|
||||
template <typename Func>
|
||||
#endif
|
||||
inline error_code simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>::for_each_at_path_with_wildcard(
|
||||
std::string_view json_path, Func&& callback) noexcept {
|
||||
if (error()) {
|
||||
return error();
|
||||
}
|
||||
return first.at_path_with_wildcard(json_path);
|
||||
return first.for_each_at_path_with_wildcard(json_path, std::forward<Func>(callback));
|
||||
}
|
||||
|
||||
} // namespace simdjson
|
||||
|
||||
@@ -161,6 +161,28 @@ public:
|
||||
*/
|
||||
simdjson_inline simdjson_result<int64_t> get_int64_in_string() noexcept;
|
||||
|
||||
/**
|
||||
* Cast this JSON value to a 32-bit unsigned integer.
|
||||
*
|
||||
* Calls get_uint64() and checks that the result fits in a uint32_t.
|
||||
*
|
||||
* @returns A 32-bit unsigned integer.
|
||||
* @returns INCORRECT_TYPE If the JSON value is not an unsigned integer.
|
||||
* @returns NUMBER_OUT_OF_RANGE If the value does not fit in a uint32_t.
|
||||
*/
|
||||
simdjson_inline simdjson_result<uint32_t> get_uint32() noexcept;
|
||||
|
||||
/**
|
||||
* Cast this JSON value to a 32-bit signed integer.
|
||||
*
|
||||
* Calls get_int64() and checks that the result fits in an int32_t.
|
||||
*
|
||||
* @returns A 32-bit signed integer.
|
||||
* @returns INCORRECT_TYPE If the JSON value is not an integer.
|
||||
* @returns NUMBER_OUT_OF_RANGE If the value does not fit in an int32_t.
|
||||
*/
|
||||
simdjson_inline simdjson_result<int32_t> get_int32() noexcept;
|
||||
|
||||
/**
|
||||
* Cast this JSON value to a double.
|
||||
*
|
||||
@@ -676,13 +698,21 @@ public:
|
||||
simdjson_inline simdjson_result<value> at_path(std::string_view at_path) noexcept;
|
||||
|
||||
/**
|
||||
* Get all values matching the given JSONPath expression with wildcard support.
|
||||
* Call the provided callback for each value matching the given JSONPath
|
||||
* expression with wildcard support.
|
||||
* Supports wildcard character (*) for arrays or ".*" for objects.
|
||||
*
|
||||
* @param json_path JSONPath expression with wildcards
|
||||
* @return Vector of values matching the wildcard pattern
|
||||
* @param callback Function called for each matching value
|
||||
* @return error_code indicating success or failure
|
||||
*/
|
||||
simdjson_inline simdjson_result<std::vector<value>> at_path_with_wildcard(std::string_view json_path) noexcept;
|
||||
#if SIMDJSON_SUPPORTS_CONCEPTS
|
||||
template <typename Func>
|
||||
requires std::invocable<Func, value>
|
||||
#else
|
||||
template <typename Func>
|
||||
#endif
|
||||
simdjson_inline error_code for_each_at_path_with_wildcard(std::string_view json_path, Func&& callback) noexcept;
|
||||
|
||||
protected:
|
||||
/**
|
||||
@@ -746,6 +776,8 @@ public:
|
||||
simdjson_inline simdjson_result<uint64_t> get_uint64_in_string() noexcept;
|
||||
simdjson_inline simdjson_result<int64_t> get_int64() noexcept;
|
||||
simdjson_inline simdjson_result<int64_t> get_int64_in_string() noexcept;
|
||||
simdjson_inline simdjson_result<uint32_t> get_uint32() noexcept;
|
||||
simdjson_inline simdjson_result<int32_t> get_int32() noexcept;
|
||||
simdjson_inline simdjson_result<double> get_double() noexcept;
|
||||
simdjson_inline simdjson_result<double> get_double_in_string() noexcept;
|
||||
simdjson_inline simdjson_result<std::string_view> get_string(bool allow_replacement = false) noexcept;
|
||||
@@ -873,9 +905,23 @@ public:
|
||||
simdjson_inline simdjson_result<int32_t> current_depth() const noexcept;
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> at_pointer(std::string_view json_pointer) noexcept;
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> at_path(std::string_view json_path) noexcept;
|
||||
simdjson_inline simdjson_result<std::vector<SIMDJSON_IMPLEMENTATION::ondemand::value>> at_path_with_wildcard(std::string_view json_path) noexcept;
|
||||
#if SIMDJSON_SUPPORTS_CONCEPTS
|
||||
template <typename Func>
|
||||
requires std::invocable<Func, SIMDJSON_IMPLEMENTATION::ondemand::value>
|
||||
#else
|
||||
template <typename Func>
|
||||
#endif
|
||||
simdjson_inline error_code for_each_at_path_with_wildcard(std::string_view json_path, Func&& callback) noexcept;
|
||||
};
|
||||
|
||||
// Forward-declare explicit specializations so MSVC /permissive- sees them before
|
||||
// any template instantiation that would resolve element.get(val) to the primary.
|
||||
template<> simdjson_inline error_code
|
||||
simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>::get<SIMDJSON_IMPLEMENTATION::ondemand::value>(
|
||||
SIMDJSON_IMPLEMENTATION::ondemand::value &out) noexcept;
|
||||
template<> simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>
|
||||
simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>::get<SIMDJSON_IMPLEMENTATION::ondemand::value>() noexcept;
|
||||
|
||||
} // namespace simdjson
|
||||
|
||||
#endif // SIMDJSON_GENERIC_ONDEMAND_VALUE_H
|
||||
|
||||
@@ -212,6 +212,12 @@ protected:
|
||||
*/
|
||||
size_t _max_depth{0};
|
||||
|
||||
public:
|
||||
/** Whether to store big integers as strings instead of returning BIGINT_ERROR */
|
||||
bool _number_as_string{false};
|
||||
|
||||
protected:
|
||||
|
||||
// Declaring these so that subclasses can use them to implement their constructors.
|
||||
simdjson_inline dom_parser_implementation() noexcept;
|
||||
simdjson_inline dom_parser_implementation(dom_parser_implementation &&other) noexcept;
|
||||
|
||||
@@ -19,7 +19,8 @@ enum class tape_type {
|
||||
DOUBLE = 'd',
|
||||
TRUE_VALUE = 't',
|
||||
FALSE_VALUE = 'f',
|
||||
NULL_VALUE = 'n'
|
||||
NULL_VALUE = 'n',
|
||||
BIGINT = 'Z' // Big integer stored as string in string buffer
|
||||
}; // enum class tape_type
|
||||
|
||||
} // namespace internal
|
||||
|
||||
@@ -168,10 +168,13 @@ inline padded_string::operator padded_string_view() const noexcept simdjson_life
|
||||
}
|
||||
|
||||
inline simdjson_result<padded_string> padded_string::load(std::string_view filename) noexcept {
|
||||
// std::string_view is not guaranteed to be null-terminated, but std::fopen requires
|
||||
// a null-terminated C string. Construct a temporary std::string to ensure null-termination.
|
||||
const std::string null_terminated_filename(filename);
|
||||
// Open the file
|
||||
SIMDJSON_PUSH_DISABLE_WARNINGS
|
||||
SIMDJSON_DISABLE_DEPRECATED_WARNING // Disable CRT_SECURE warning on MSVC: manually verified this is safe
|
||||
std::FILE *fp = std::fopen(filename.data(), "rb");
|
||||
std::FILE *fp = std::fopen(null_terminated_filename.c_str(), "rb");
|
||||
SIMDJSON_POP_DISABLE_WARNINGS
|
||||
|
||||
if (fp == nullptr) {
|
||||
@@ -223,10 +226,13 @@ inline simdjson_result<padded_string> padded_string::load(std::string_view filen
|
||||
|
||||
#if defined(_WIN32) && SIMDJSON_CPLUSPLUS17
|
||||
inline simdjson_result<padded_string> padded_string::load(std::wstring_view filename) noexcept {
|
||||
// std::wstring_view is not guaranteed to be null-terminated, but _wfopen requires
|
||||
// a null-terminated wide C string. Construct a temporary std::wstring to ensure null-termination.
|
||||
const std::wstring null_terminated_filename(filename);
|
||||
// Open the file using the wide characters
|
||||
SIMDJSON_PUSH_DISABLE_WARNINGS
|
||||
SIMDJSON_DISABLE_DEPRECATED_WARNING // Disable CRT_SECURE warning on MSVC: manually verified this is safe
|
||||
std::FILE *fp = _wfopen(filename.data(), L"rb");
|
||||
std::FILE *fp = _wfopen(null_terminated_filename.c_str(), L"rb");
|
||||
SIMDJSON_POP_DISABLE_WARNINGS
|
||||
|
||||
if (fp == nullptr) {
|
||||
@@ -349,6 +355,9 @@ inline padded_string padded_string_builder::convert() noexcept {
|
||||
}
|
||||
|
||||
inline bool padded_string_builder::reserve(size_t additional) noexcept {
|
||||
if (simdjson_unlikely(additional + size < size)) {
|
||||
return false; // overflow: cannot satisfy request
|
||||
}
|
||||
size_t needed = size + additional;
|
||||
if (needed <= capacity) {
|
||||
return true;
|
||||
@@ -358,8 +367,9 @@ inline bool padded_string_builder::reserve(size_t additional) noexcept {
|
||||
// repeated allocations.
|
||||
if (new_capacity < 4096) {
|
||||
new_capacity *= 2;
|
||||
} else {
|
||||
new_capacity += new_capacity/2; // grow by 1.5x
|
||||
// overflow guard: ensure new_capacity + new_capacity/2 does not overflow
|
||||
} else if (new_capacity + new_capacity / 2 > new_capacity) {
|
||||
new_capacity += new_capacity / 2; // grow by 1.5x
|
||||
}
|
||||
char *new_data = internal::allocate_padded_buffer(new_capacity);
|
||||
if (new_data == nullptr) {
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#define SIMDJSON_SIMDJSON_VERSION_H
|
||||
|
||||
/** The version of simdjson being used (major.minor.revision) */
|
||||
#define SIMDJSON_VERSION "4.4.1"
|
||||
#define SIMDJSON_VERSION "4.6.4"
|
||||
|
||||
namespace simdjson {
|
||||
enum {
|
||||
@@ -15,11 +15,11 @@ enum {
|
||||
/**
|
||||
* The minor version (major.MINOR.revision) of simdjson being used.
|
||||
*/
|
||||
SIMDJSON_VERSION_MINOR = 4,
|
||||
SIMDJSON_VERSION_MINOR = 6,
|
||||
/**
|
||||
* The revision (major.minor.REVISION) of simdjson being used.
|
||||
*/
|
||||
SIMDJSON_VERSION_REVISION = 1
|
||||
SIMDJSON_VERSION_REVISION = 4
|
||||
};
|
||||
} // namespace simdjson
|
||||
|
||||
|
||||
+297
-11
@@ -1,4 +1,4 @@
|
||||
/* auto-generated on 2026-03-17 12:38:11 -0400. version 4.4.1 Do not edit! */
|
||||
/* auto-generated on 2026-05-06 17:28:39 -0400. version 4.6.4 Do not edit! */
|
||||
/* including simdjson.cpp: */
|
||||
/* begin file simdjson.cpp */
|
||||
#define SIMDJSON_SRC_SIMDJSON_CPP
|
||||
@@ -7308,6 +7308,12 @@ protected:
|
||||
*/
|
||||
size_t _max_depth{0};
|
||||
|
||||
public:
|
||||
/** Whether to store big integers as strings instead of returning BIGINT_ERROR */
|
||||
bool _number_as_string{false};
|
||||
|
||||
protected:
|
||||
|
||||
// Declaring these so that subclasses can use them to implement their constructors.
|
||||
simdjson_inline dom_parser_implementation() noexcept;
|
||||
simdjson_inline dom_parser_implementation(dom_parser_implementation &&other) noexcept;
|
||||
@@ -7883,7 +7889,8 @@ enum class tape_type {
|
||||
DOUBLE = 'd',
|
||||
TRUE_VALUE = 't',
|
||||
FALSE_VALUE = 'f',
|
||||
NULL_VALUE = 'n'
|
||||
NULL_VALUE = 'n',
|
||||
BIGINT = 'Z' // Big integer stored as string in string buffer
|
||||
}; // enum class tape_type
|
||||
|
||||
} // namespace internal
|
||||
@@ -14178,6 +14185,9 @@ struct tape_writer {
|
||||
/** Write a double value to tape. */
|
||||
simdjson_inline void append_double(double value) noexcept;
|
||||
|
||||
/** Write a big integer (as string) to tape. src points to first digit, len is byte count. */
|
||||
simdjson_inline void append_bigint(const uint8_t *src, size_t len, uint8_t *&string_buf) noexcept;
|
||||
|
||||
/**
|
||||
* Append a tape entry (an 8-bit type,and 56 bits worth of value).
|
||||
*/
|
||||
@@ -14261,6 +14271,18 @@ simdjson_inline void tape_writer::write(uint64_t &tape_loc, uint64_t val, intern
|
||||
tape_loc = val | ((uint64_t(char(t))) << 56);
|
||||
}
|
||||
|
||||
simdjson_inline void tape_writer::append_bigint(const uint8_t *src, size_t len, uint8_t *&string_buf) noexcept {
|
||||
// Write to string buffer: [4-byte LE length][digits][null]
|
||||
uint32_t str_len = uint32_t(len);
|
||||
memcpy(string_buf, &str_len, sizeof(uint32_t));
|
||||
memcpy(string_buf + sizeof(uint32_t), src, len);
|
||||
string_buf[sizeof(uint32_t) + len] = 0;
|
||||
// Tape entry: offset into string buffer
|
||||
// The caller must set the offset relative to doc.string_buf base
|
||||
append(0, internal::tape_type::BIGINT); // placeholder offset, caller patches
|
||||
string_buf += sizeof(uint32_t) + len + 1;
|
||||
}
|
||||
|
||||
} // namespace stage2
|
||||
} // unnamed namespace
|
||||
} // namespace arm64
|
||||
@@ -15198,7 +15220,23 @@ simdjson_warn_unused simdjson_inline error_code tape_builder::visit_root_string(
|
||||
|
||||
simdjson_warn_unused simdjson_inline error_code tape_builder::visit_number(json_iterator &iter, const uint8_t *value) noexcept {
|
||||
iter.log_value("number");
|
||||
return numberparsing::parse_number(value, tape);
|
||||
error_code err = numberparsing::parse_number(value, tape);
|
||||
if (simdjson_unlikely(err == BIGINT_ERROR &&
|
||||
iter.dom_parser._number_as_string)) {
|
||||
// Write big integer to string buffer using the same format as strings.
|
||||
// Scan digits the same way parse_number does (skip optional '-', then digits).
|
||||
const uint8_t *p = value;
|
||||
if (*p == '-') p++;
|
||||
while (numberparsing::is_digit(*p)) p++;
|
||||
size_t len = size_t(p - value);
|
||||
tape.append(current_string_buf_loc - iter.dom_parser.doc->string_buf.get(), internal::tape_type::BIGINT);
|
||||
uint8_t *dst = current_string_buf_loc + sizeof(uint32_t);
|
||||
memcpy(dst, value, len);
|
||||
dst += len;
|
||||
on_end_string(dst);
|
||||
return SUCCESS;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
simdjson_warn_unused simdjson_inline error_code tape_builder::visit_root_number(json_iterator &iter, const uint8_t *value) noexcept {
|
||||
@@ -20539,6 +20577,9 @@ struct tape_writer {
|
||||
/** Write a double value to tape. */
|
||||
simdjson_inline void append_double(double value) noexcept;
|
||||
|
||||
/** Write a big integer (as string) to tape. src points to first digit, len is byte count. */
|
||||
simdjson_inline void append_bigint(const uint8_t *src, size_t len, uint8_t *&string_buf) noexcept;
|
||||
|
||||
/**
|
||||
* Append a tape entry (an 8-bit type,and 56 bits worth of value).
|
||||
*/
|
||||
@@ -20622,6 +20663,18 @@ simdjson_inline void tape_writer::write(uint64_t &tape_loc, uint64_t val, intern
|
||||
tape_loc = val | ((uint64_t(char(t))) << 56);
|
||||
}
|
||||
|
||||
simdjson_inline void tape_writer::append_bigint(const uint8_t *src, size_t len, uint8_t *&string_buf) noexcept {
|
||||
// Write to string buffer: [4-byte LE length][digits][null]
|
||||
uint32_t str_len = uint32_t(len);
|
||||
memcpy(string_buf, &str_len, sizeof(uint32_t));
|
||||
memcpy(string_buf + sizeof(uint32_t), src, len);
|
||||
string_buf[sizeof(uint32_t) + len] = 0;
|
||||
// Tape entry: offset into string buffer
|
||||
// The caller must set the offset relative to doc.string_buf base
|
||||
append(0, internal::tape_type::BIGINT); // placeholder offset, caller patches
|
||||
string_buf += sizeof(uint32_t) + len + 1;
|
||||
}
|
||||
|
||||
} // namespace stage2
|
||||
} // unnamed namespace
|
||||
} // namespace haswell
|
||||
@@ -21559,7 +21612,23 @@ simdjson_warn_unused simdjson_inline error_code tape_builder::visit_root_string(
|
||||
|
||||
simdjson_warn_unused simdjson_inline error_code tape_builder::visit_number(json_iterator &iter, const uint8_t *value) noexcept {
|
||||
iter.log_value("number");
|
||||
return numberparsing::parse_number(value, tape);
|
||||
error_code err = numberparsing::parse_number(value, tape);
|
||||
if (simdjson_unlikely(err == BIGINT_ERROR &&
|
||||
iter.dom_parser._number_as_string)) {
|
||||
// Write big integer to string buffer using the same format as strings.
|
||||
// Scan digits the same way parse_number does (skip optional '-', then digits).
|
||||
const uint8_t *p = value;
|
||||
if (*p == '-') p++;
|
||||
while (numberparsing::is_digit(*p)) p++;
|
||||
size_t len = size_t(p - value);
|
||||
tape.append(current_string_buf_loc - iter.dom_parser.doc->string_buf.get(), internal::tape_type::BIGINT);
|
||||
uint8_t *dst = current_string_buf_loc + sizeof(uint32_t);
|
||||
memcpy(dst, value, len);
|
||||
dst += len;
|
||||
on_end_string(dst);
|
||||
return SUCCESS;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
simdjson_warn_unused simdjson_inline error_code tape_builder::visit_root_number(json_iterator &iter, const uint8_t *value) noexcept {
|
||||
@@ -26895,6 +26964,9 @@ struct tape_writer {
|
||||
/** Write a double value to tape. */
|
||||
simdjson_inline void append_double(double value) noexcept;
|
||||
|
||||
/** Write a big integer (as string) to tape. src points to first digit, len is byte count. */
|
||||
simdjson_inline void append_bigint(const uint8_t *src, size_t len, uint8_t *&string_buf) noexcept;
|
||||
|
||||
/**
|
||||
* Append a tape entry (an 8-bit type,and 56 bits worth of value).
|
||||
*/
|
||||
@@ -26978,6 +27050,18 @@ simdjson_inline void tape_writer::write(uint64_t &tape_loc, uint64_t val, intern
|
||||
tape_loc = val | ((uint64_t(char(t))) << 56);
|
||||
}
|
||||
|
||||
simdjson_inline void tape_writer::append_bigint(const uint8_t *src, size_t len, uint8_t *&string_buf) noexcept {
|
||||
// Write to string buffer: [4-byte LE length][digits][null]
|
||||
uint32_t str_len = uint32_t(len);
|
||||
memcpy(string_buf, &str_len, sizeof(uint32_t));
|
||||
memcpy(string_buf + sizeof(uint32_t), src, len);
|
||||
string_buf[sizeof(uint32_t) + len] = 0;
|
||||
// Tape entry: offset into string buffer
|
||||
// The caller must set the offset relative to doc.string_buf base
|
||||
append(0, internal::tape_type::BIGINT); // placeholder offset, caller patches
|
||||
string_buf += sizeof(uint32_t) + len + 1;
|
||||
}
|
||||
|
||||
} // namespace stage2
|
||||
} // unnamed namespace
|
||||
} // namespace icelake
|
||||
@@ -27915,7 +27999,23 @@ simdjson_warn_unused simdjson_inline error_code tape_builder::visit_root_string(
|
||||
|
||||
simdjson_warn_unused simdjson_inline error_code tape_builder::visit_number(json_iterator &iter, const uint8_t *value) noexcept {
|
||||
iter.log_value("number");
|
||||
return numberparsing::parse_number(value, tape);
|
||||
error_code err = numberparsing::parse_number(value, tape);
|
||||
if (simdjson_unlikely(err == BIGINT_ERROR &&
|
||||
iter.dom_parser._number_as_string)) {
|
||||
// Write big integer to string buffer using the same format as strings.
|
||||
// Scan digits the same way parse_number does (skip optional '-', then digits).
|
||||
const uint8_t *p = value;
|
||||
if (*p == '-') p++;
|
||||
while (numberparsing::is_digit(*p)) p++;
|
||||
size_t len = size_t(p - value);
|
||||
tape.append(current_string_buf_loc - iter.dom_parser.doc->string_buf.get(), internal::tape_type::BIGINT);
|
||||
uint8_t *dst = current_string_buf_loc + sizeof(uint32_t);
|
||||
memcpy(dst, value, len);
|
||||
dst += len;
|
||||
on_end_string(dst);
|
||||
return SUCCESS;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
simdjson_warn_unused simdjson_inline error_code tape_builder::visit_root_number(json_iterator &iter, const uint8_t *value) noexcept {
|
||||
@@ -33522,6 +33622,9 @@ struct tape_writer {
|
||||
/** Write a double value to tape. */
|
||||
simdjson_inline void append_double(double value) noexcept;
|
||||
|
||||
/** Write a big integer (as string) to tape. src points to first digit, len is byte count. */
|
||||
simdjson_inline void append_bigint(const uint8_t *src, size_t len, uint8_t *&string_buf) noexcept;
|
||||
|
||||
/**
|
||||
* Append a tape entry (an 8-bit type,and 56 bits worth of value).
|
||||
*/
|
||||
@@ -33605,6 +33708,18 @@ simdjson_inline void tape_writer::write(uint64_t &tape_loc, uint64_t val, intern
|
||||
tape_loc = val | ((uint64_t(char(t))) << 56);
|
||||
}
|
||||
|
||||
simdjson_inline void tape_writer::append_bigint(const uint8_t *src, size_t len, uint8_t *&string_buf) noexcept {
|
||||
// Write to string buffer: [4-byte LE length][digits][null]
|
||||
uint32_t str_len = uint32_t(len);
|
||||
memcpy(string_buf, &str_len, sizeof(uint32_t));
|
||||
memcpy(string_buf + sizeof(uint32_t), src, len);
|
||||
string_buf[sizeof(uint32_t) + len] = 0;
|
||||
// Tape entry: offset into string buffer
|
||||
// The caller must set the offset relative to doc.string_buf base
|
||||
append(0, internal::tape_type::BIGINT); // placeholder offset, caller patches
|
||||
string_buf += sizeof(uint32_t) + len + 1;
|
||||
}
|
||||
|
||||
} // namespace stage2
|
||||
} // unnamed namespace
|
||||
} // namespace ppc64
|
||||
@@ -34542,7 +34657,23 @@ simdjson_warn_unused simdjson_inline error_code tape_builder::visit_root_string(
|
||||
|
||||
simdjson_warn_unused simdjson_inline error_code tape_builder::visit_number(json_iterator &iter, const uint8_t *value) noexcept {
|
||||
iter.log_value("number");
|
||||
return numberparsing::parse_number(value, tape);
|
||||
error_code err = numberparsing::parse_number(value, tape);
|
||||
if (simdjson_unlikely(err == BIGINT_ERROR &&
|
||||
iter.dom_parser._number_as_string)) {
|
||||
// Write big integer to string buffer using the same format as strings.
|
||||
// Scan digits the same way parse_number does (skip optional '-', then digits).
|
||||
const uint8_t *p = value;
|
||||
if (*p == '-') p++;
|
||||
while (numberparsing::is_digit(*p)) p++;
|
||||
size_t len = size_t(p - value);
|
||||
tape.append(current_string_buf_loc - iter.dom_parser.doc->string_buf.get(), internal::tape_type::BIGINT);
|
||||
uint8_t *dst = current_string_buf_loc + sizeof(uint32_t);
|
||||
memcpy(dst, value, len);
|
||||
dst += len;
|
||||
on_end_string(dst);
|
||||
return SUCCESS;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
simdjson_warn_unused simdjson_inline error_code tape_builder::visit_root_number(json_iterator &iter, const uint8_t *value) noexcept {
|
||||
@@ -40711,6 +40842,9 @@ struct tape_writer {
|
||||
/** Write a double value to tape. */
|
||||
simdjson_inline void append_double(double value) noexcept;
|
||||
|
||||
/** Write a big integer (as string) to tape. src points to first digit, len is byte count. */
|
||||
simdjson_inline void append_bigint(const uint8_t *src, size_t len, uint8_t *&string_buf) noexcept;
|
||||
|
||||
/**
|
||||
* Append a tape entry (an 8-bit type,and 56 bits worth of value).
|
||||
*/
|
||||
@@ -40794,6 +40928,18 @@ simdjson_inline void tape_writer::write(uint64_t &tape_loc, uint64_t val, intern
|
||||
tape_loc = val | ((uint64_t(char(t))) << 56);
|
||||
}
|
||||
|
||||
simdjson_inline void tape_writer::append_bigint(const uint8_t *src, size_t len, uint8_t *&string_buf) noexcept {
|
||||
// Write to string buffer: [4-byte LE length][digits][null]
|
||||
uint32_t str_len = uint32_t(len);
|
||||
memcpy(string_buf, &str_len, sizeof(uint32_t));
|
||||
memcpy(string_buf + sizeof(uint32_t), src, len);
|
||||
string_buf[sizeof(uint32_t) + len] = 0;
|
||||
// Tape entry: offset into string buffer
|
||||
// The caller must set the offset relative to doc.string_buf base
|
||||
append(0, internal::tape_type::BIGINT); // placeholder offset, caller patches
|
||||
string_buf += sizeof(uint32_t) + len + 1;
|
||||
}
|
||||
|
||||
} // namespace stage2
|
||||
} // unnamed namespace
|
||||
} // namespace westmere
|
||||
@@ -41731,7 +41877,23 @@ simdjson_warn_unused simdjson_inline error_code tape_builder::visit_root_string(
|
||||
|
||||
simdjson_warn_unused simdjson_inline error_code tape_builder::visit_number(json_iterator &iter, const uint8_t *value) noexcept {
|
||||
iter.log_value("number");
|
||||
return numberparsing::parse_number(value, tape);
|
||||
error_code err = numberparsing::parse_number(value, tape);
|
||||
if (simdjson_unlikely(err == BIGINT_ERROR &&
|
||||
iter.dom_parser._number_as_string)) {
|
||||
// Write big integer to string buffer using the same format as strings.
|
||||
// Scan digits the same way parse_number does (skip optional '-', then digits).
|
||||
const uint8_t *p = value;
|
||||
if (*p == '-') p++;
|
||||
while (numberparsing::is_digit(*p)) p++;
|
||||
size_t len = size_t(p - value);
|
||||
tape.append(current_string_buf_loc - iter.dom_parser.doc->string_buf.get(), internal::tape_type::BIGINT);
|
||||
uint8_t *dst = current_string_buf_loc + sizeof(uint32_t);
|
||||
memcpy(dst, value, len);
|
||||
dst += len;
|
||||
on_end_string(dst);
|
||||
return SUCCESS;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
simdjson_warn_unused simdjson_inline error_code tape_builder::visit_root_number(json_iterator &iter, const uint8_t *value) noexcept {
|
||||
@@ -46931,6 +47093,9 @@ struct tape_writer {
|
||||
/** Write a double value to tape. */
|
||||
simdjson_inline void append_double(double value) noexcept;
|
||||
|
||||
/** Write a big integer (as string) to tape. src points to first digit, len is byte count. */
|
||||
simdjson_inline void append_bigint(const uint8_t *src, size_t len, uint8_t *&string_buf) noexcept;
|
||||
|
||||
/**
|
||||
* Append a tape entry (an 8-bit type,and 56 bits worth of value).
|
||||
*/
|
||||
@@ -47014,6 +47179,18 @@ simdjson_inline void tape_writer::write(uint64_t &tape_loc, uint64_t val, intern
|
||||
tape_loc = val | ((uint64_t(char(t))) << 56);
|
||||
}
|
||||
|
||||
simdjson_inline void tape_writer::append_bigint(const uint8_t *src, size_t len, uint8_t *&string_buf) noexcept {
|
||||
// Write to string buffer: [4-byte LE length][digits][null]
|
||||
uint32_t str_len = uint32_t(len);
|
||||
memcpy(string_buf, &str_len, sizeof(uint32_t));
|
||||
memcpy(string_buf + sizeof(uint32_t), src, len);
|
||||
string_buf[sizeof(uint32_t) + len] = 0;
|
||||
// Tape entry: offset into string buffer
|
||||
// The caller must set the offset relative to doc.string_buf base
|
||||
append(0, internal::tape_type::BIGINT); // placeholder offset, caller patches
|
||||
string_buf += sizeof(uint32_t) + len + 1;
|
||||
}
|
||||
|
||||
} // namespace stage2
|
||||
} // unnamed namespace
|
||||
} // namespace lasx
|
||||
@@ -47951,7 +48128,23 @@ simdjson_warn_unused simdjson_inline error_code tape_builder::visit_root_string(
|
||||
|
||||
simdjson_warn_unused simdjson_inline error_code tape_builder::visit_number(json_iterator &iter, const uint8_t *value) noexcept {
|
||||
iter.log_value("number");
|
||||
return numberparsing::parse_number(value, tape);
|
||||
error_code err = numberparsing::parse_number(value, tape);
|
||||
if (simdjson_unlikely(err == BIGINT_ERROR &&
|
||||
iter.dom_parser._number_as_string)) {
|
||||
// Write big integer to string buffer using the same format as strings.
|
||||
// Scan digits the same way parse_number does (skip optional '-', then digits).
|
||||
const uint8_t *p = value;
|
||||
if (*p == '-') p++;
|
||||
while (numberparsing::is_digit(*p)) p++;
|
||||
size_t len = size_t(p - value);
|
||||
tape.append(current_string_buf_loc - iter.dom_parser.doc->string_buf.get(), internal::tape_type::BIGINT);
|
||||
uint8_t *dst = current_string_buf_loc + sizeof(uint32_t);
|
||||
memcpy(dst, value, len);
|
||||
dst += len;
|
||||
on_end_string(dst);
|
||||
return SUCCESS;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
simdjson_warn_unused simdjson_inline error_code tape_builder::visit_root_number(json_iterator &iter, const uint8_t *value) noexcept {
|
||||
@@ -53055,6 +53248,9 @@ struct tape_writer {
|
||||
/** Write a double value to tape. */
|
||||
simdjson_inline void append_double(double value) noexcept;
|
||||
|
||||
/** Write a big integer (as string) to tape. src points to first digit, len is byte count. */
|
||||
simdjson_inline void append_bigint(const uint8_t *src, size_t len, uint8_t *&string_buf) noexcept;
|
||||
|
||||
/**
|
||||
* Append a tape entry (an 8-bit type,and 56 bits worth of value).
|
||||
*/
|
||||
@@ -53138,6 +53334,18 @@ simdjson_inline void tape_writer::write(uint64_t &tape_loc, uint64_t val, intern
|
||||
tape_loc = val | ((uint64_t(char(t))) << 56);
|
||||
}
|
||||
|
||||
simdjson_inline void tape_writer::append_bigint(const uint8_t *src, size_t len, uint8_t *&string_buf) noexcept {
|
||||
// Write to string buffer: [4-byte LE length][digits][null]
|
||||
uint32_t str_len = uint32_t(len);
|
||||
memcpy(string_buf, &str_len, sizeof(uint32_t));
|
||||
memcpy(string_buf + sizeof(uint32_t), src, len);
|
||||
string_buf[sizeof(uint32_t) + len] = 0;
|
||||
// Tape entry: offset into string buffer
|
||||
// The caller must set the offset relative to doc.string_buf base
|
||||
append(0, internal::tape_type::BIGINT); // placeholder offset, caller patches
|
||||
string_buf += sizeof(uint32_t) + len + 1;
|
||||
}
|
||||
|
||||
} // namespace stage2
|
||||
} // unnamed namespace
|
||||
} // namespace lsx
|
||||
@@ -54075,7 +54283,23 @@ simdjson_warn_unused simdjson_inline error_code tape_builder::visit_root_string(
|
||||
|
||||
simdjson_warn_unused simdjson_inline error_code tape_builder::visit_number(json_iterator &iter, const uint8_t *value) noexcept {
|
||||
iter.log_value("number");
|
||||
return numberparsing::parse_number(value, tape);
|
||||
error_code err = numberparsing::parse_number(value, tape);
|
||||
if (simdjson_unlikely(err == BIGINT_ERROR &&
|
||||
iter.dom_parser._number_as_string)) {
|
||||
// Write big integer to string buffer using the same format as strings.
|
||||
// Scan digits the same way parse_number does (skip optional '-', then digits).
|
||||
const uint8_t *p = value;
|
||||
if (*p == '-') p++;
|
||||
while (numberparsing::is_digit(*p)) p++;
|
||||
size_t len = size_t(p - value);
|
||||
tape.append(current_string_buf_loc - iter.dom_parser.doc->string_buf.get(), internal::tape_type::BIGINT);
|
||||
uint8_t *dst = current_string_buf_loc + sizeof(uint32_t);
|
||||
memcpy(dst, value, len);
|
||||
dst += len;
|
||||
on_end_string(dst);
|
||||
return SUCCESS;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
simdjson_warn_unused simdjson_inline error_code tape_builder::visit_root_number(json_iterator &iter, const uint8_t *value) noexcept {
|
||||
@@ -59598,6 +59822,9 @@ struct tape_writer {
|
||||
/** Write a double value to tape. */
|
||||
simdjson_inline void append_double(double value) noexcept;
|
||||
|
||||
/** Write a big integer (as string) to tape. src points to first digit, len is byte count. */
|
||||
simdjson_inline void append_bigint(const uint8_t *src, size_t len, uint8_t *&string_buf) noexcept;
|
||||
|
||||
/**
|
||||
* Append a tape entry (an 8-bit type,and 56 bits worth of value).
|
||||
*/
|
||||
@@ -59681,6 +59908,18 @@ simdjson_inline void tape_writer::write(uint64_t &tape_loc, uint64_t val, intern
|
||||
tape_loc = val | ((uint64_t(char(t))) << 56);
|
||||
}
|
||||
|
||||
simdjson_inline void tape_writer::append_bigint(const uint8_t *src, size_t len, uint8_t *&string_buf) noexcept {
|
||||
// Write to string buffer: [4-byte LE length][digits][null]
|
||||
uint32_t str_len = uint32_t(len);
|
||||
memcpy(string_buf, &str_len, sizeof(uint32_t));
|
||||
memcpy(string_buf + sizeof(uint32_t), src, len);
|
||||
string_buf[sizeof(uint32_t) + len] = 0;
|
||||
// Tape entry: offset into string buffer
|
||||
// The caller must set the offset relative to doc.string_buf base
|
||||
append(0, internal::tape_type::BIGINT); // placeholder offset, caller patches
|
||||
string_buf += sizeof(uint32_t) + len + 1;
|
||||
}
|
||||
|
||||
} // namespace stage2
|
||||
} // unnamed namespace
|
||||
} // namespace rvv_vls
|
||||
@@ -60618,7 +60857,23 @@ simdjson_warn_unused simdjson_inline error_code tape_builder::visit_root_string(
|
||||
|
||||
simdjson_warn_unused simdjson_inline error_code tape_builder::visit_number(json_iterator &iter, const uint8_t *value) noexcept {
|
||||
iter.log_value("number");
|
||||
return numberparsing::parse_number(value, tape);
|
||||
error_code err = numberparsing::parse_number(value, tape);
|
||||
if (simdjson_unlikely(err == BIGINT_ERROR &&
|
||||
iter.dom_parser._number_as_string)) {
|
||||
// Write big integer to string buffer using the same format as strings.
|
||||
// Scan digits the same way parse_number does (skip optional '-', then digits).
|
||||
const uint8_t *p = value;
|
||||
if (*p == '-') p++;
|
||||
while (numberparsing::is_digit(*p)) p++;
|
||||
size_t len = size_t(p - value);
|
||||
tape.append(current_string_buf_loc - iter.dom_parser.doc->string_buf.get(), internal::tape_type::BIGINT);
|
||||
uint8_t *dst = current_string_buf_loc + sizeof(uint32_t);
|
||||
memcpy(dst, value, len);
|
||||
dst += len;
|
||||
on_end_string(dst);
|
||||
return SUCCESS;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
simdjson_warn_unused simdjson_inline error_code tape_builder::visit_root_number(json_iterator &iter, const uint8_t *value) noexcept {
|
||||
@@ -64189,6 +64444,9 @@ struct tape_writer {
|
||||
/** Write a double value to tape. */
|
||||
simdjson_inline void append_double(double value) noexcept;
|
||||
|
||||
/** Write a big integer (as string) to tape. src points to first digit, len is byte count. */
|
||||
simdjson_inline void append_bigint(const uint8_t *src, size_t len, uint8_t *&string_buf) noexcept;
|
||||
|
||||
/**
|
||||
* Append a tape entry (an 8-bit type,and 56 bits worth of value).
|
||||
*/
|
||||
@@ -64272,6 +64530,18 @@ simdjson_inline void tape_writer::write(uint64_t &tape_loc, uint64_t val, intern
|
||||
tape_loc = val | ((uint64_t(char(t))) << 56);
|
||||
}
|
||||
|
||||
simdjson_inline void tape_writer::append_bigint(const uint8_t *src, size_t len, uint8_t *&string_buf) noexcept {
|
||||
// Write to string buffer: [4-byte LE length][digits][null]
|
||||
uint32_t str_len = uint32_t(len);
|
||||
memcpy(string_buf, &str_len, sizeof(uint32_t));
|
||||
memcpy(string_buf + sizeof(uint32_t), src, len);
|
||||
string_buf[sizeof(uint32_t) + len] = 0;
|
||||
// Tape entry: offset into string buffer
|
||||
// The caller must set the offset relative to doc.string_buf base
|
||||
append(0, internal::tape_type::BIGINT); // placeholder offset, caller patches
|
||||
string_buf += sizeof(uint32_t) + len + 1;
|
||||
}
|
||||
|
||||
} // namespace stage2
|
||||
} // unnamed namespace
|
||||
} // namespace fallback
|
||||
@@ -64455,7 +64725,23 @@ simdjson_warn_unused simdjson_inline error_code tape_builder::visit_root_string(
|
||||
|
||||
simdjson_warn_unused simdjson_inline error_code tape_builder::visit_number(json_iterator &iter, const uint8_t *value) noexcept {
|
||||
iter.log_value("number");
|
||||
return numberparsing::parse_number(value, tape);
|
||||
error_code err = numberparsing::parse_number(value, tape);
|
||||
if (simdjson_unlikely(err == BIGINT_ERROR &&
|
||||
iter.dom_parser._number_as_string)) {
|
||||
// Write big integer to string buffer using the same format as strings.
|
||||
// Scan digits the same way parse_number does (skip optional '-', then digits).
|
||||
const uint8_t *p = value;
|
||||
if (*p == '-') p++;
|
||||
while (numberparsing::is_digit(*p)) p++;
|
||||
size_t len = size_t(p - value);
|
||||
tape.append(current_string_buf_loc - iter.dom_parser.doc->string_buf.get(), internal::tape_type::BIGINT);
|
||||
uint8_t *dst = current_string_buf_loc + sizeof(uint32_t);
|
||||
memcpy(dst, value, len);
|
||||
dst += len;
|
||||
on_end_string(dst);
|
||||
return SUCCESS;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
simdjson_warn_unused simdjson_inline error_code tape_builder::visit_root_number(json_iterator &iter, const uint8_t *value) noexcept {
|
||||
|
||||
+3153
-1001
File diff suppressed because it is too large
Load Diff
Binary file not shown.
@@ -172,7 +172,23 @@ simdjson_warn_unused simdjson_inline error_code tape_builder::visit_root_string(
|
||||
|
||||
simdjson_warn_unused simdjson_inline error_code tape_builder::visit_number(json_iterator &iter, const uint8_t *value) noexcept {
|
||||
iter.log_value("number");
|
||||
return numberparsing::parse_number(value, tape);
|
||||
error_code err = numberparsing::parse_number(value, tape);
|
||||
if (simdjson_unlikely(err == BIGINT_ERROR &&
|
||||
iter.dom_parser._number_as_string)) {
|
||||
// Write big integer to string buffer using the same format as strings.
|
||||
// Scan digits the same way parse_number does (skip optional '-', then digits).
|
||||
const uint8_t *p = value;
|
||||
if (*p == '-') p++;
|
||||
while (numberparsing::is_digit(*p)) p++;
|
||||
size_t len = size_t(p - value);
|
||||
tape.append(current_string_buf_loc - iter.dom_parser.doc->string_buf.get(), internal::tape_type::BIGINT);
|
||||
uint8_t *dst = current_string_buf_loc + sizeof(uint32_t);
|
||||
memcpy(dst, value, len);
|
||||
dst += len;
|
||||
on_end_string(dst);
|
||||
return SUCCESS;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
simdjson_warn_unused simdjson_inline error_code tape_builder::visit_root_number(json_iterator &iter, const uint8_t *value) noexcept {
|
||||
|
||||
@@ -26,6 +26,9 @@ struct tape_writer {
|
||||
/** Write a double value to tape. */
|
||||
simdjson_inline void append_double(double value) noexcept;
|
||||
|
||||
/** Write a big integer (as string) to tape. src points to first digit, len is byte count. */
|
||||
simdjson_inline void append_bigint(const uint8_t *src, size_t len, uint8_t *&string_buf) noexcept;
|
||||
|
||||
/**
|
||||
* Append a tape entry (an 8-bit type,and 56 bits worth of value).
|
||||
*/
|
||||
@@ -109,6 +112,18 @@ simdjson_inline void tape_writer::write(uint64_t &tape_loc, uint64_t val, intern
|
||||
tape_loc = val | ((uint64_t(char(t))) << 56);
|
||||
}
|
||||
|
||||
simdjson_inline void tape_writer::append_bigint(const uint8_t *src, size_t len, uint8_t *&string_buf) noexcept {
|
||||
// Write to string buffer: [4-byte LE length][digits][null]
|
||||
uint32_t str_len = uint32_t(len);
|
||||
memcpy(string_buf, &str_len, sizeof(uint32_t));
|
||||
memcpy(string_buf + sizeof(uint32_t), src, len);
|
||||
string_buf[sizeof(uint32_t) + len] = 0;
|
||||
// Tape entry: offset into string buffer
|
||||
// The caller must set the offset relative to doc.string_buf base
|
||||
append(0, internal::tape_type::BIGINT); // placeholder offset, caller patches
|
||||
string_buf += sizeof(uint32_t) + len + 1;
|
||||
}
|
||||
|
||||
} // namespace stage2
|
||||
} // unnamed namespace
|
||||
} // namespace SIMDJSON_IMPLEMENTATION
|
||||
|
||||
@@ -11,6 +11,7 @@ add_cpp_test(document_tests LABELS dom acceptance per_implementation
|
||||
add_cpp_test(errortests LABELS dom acceptance per_implementation)
|
||||
add_cpp_test(extracting_values_example LABELS dom acceptance per_implementation)
|
||||
add_cpp_test(integer_tests LABELS dom acceptance per_implementation)
|
||||
add_cpp_test(big_integer_tests LABELS dom acceptance per_implementation)
|
||||
add_cpp_test(jsoncheck LABELS dom acceptance per_implementation)
|
||||
add_cpp_test(json_path_tests LABELS dom acceptance per_implementation)
|
||||
add_cpp_test(minefieldcheck LABELS dom acceptance per_implementation)
|
||||
|
||||
@@ -0,0 +1,151 @@
|
||||
#include "simdjson.h"
|
||||
#include "test_macros.h"
|
||||
#include <sstream>
|
||||
|
||||
using namespace simdjson;
|
||||
|
||||
namespace big_integer_tests {
|
||||
|
||||
bool option_off_by_default() {
|
||||
TEST_START();
|
||||
dom::parser parser;
|
||||
ASSERT_EQUAL(parser.number_as_string(), false);
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool default_returns_bigint_error() {
|
||||
TEST_START();
|
||||
dom::parser parser;
|
||||
auto result = parser.parse(R"({"val":123456789012345678901})"_padded);
|
||||
ASSERT_EQUAL(result.error(), BIGINT_ERROR);
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool opt_in_parses_big_integer() {
|
||||
TEST_START();
|
||||
dom::parser parser;
|
||||
parser.number_as_string(true);
|
||||
dom::element doc;
|
||||
ASSERT_SUCCESS(parser.parse(R"({"val":123456789012345678901})"_padded).get(doc));
|
||||
dom::element val;
|
||||
ASSERT_SUCCESS(doc["val"].get(val));
|
||||
ASSERT_EQUAL(val.type(), dom::element_type::BIGINT);
|
||||
ASSERT_TRUE(val.is_bigint());
|
||||
std::string_view digits;
|
||||
ASSERT_SUCCESS(val.get_bigint().get(digits));
|
||||
ASSERT_EQUAL(digits, "123456789012345678901");
|
||||
// Verify streaming works (same pattern as readme_examples)
|
||||
std::ostringstream os;
|
||||
os << val.get_bigint().value_unsafe();
|
||||
ASSERT_EQUAL(os.str(), "123456789012345678901");
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool negative_big_integer() {
|
||||
TEST_START();
|
||||
dom::parser parser;
|
||||
parser.number_as_string(true);
|
||||
dom::element doc;
|
||||
ASSERT_SUCCESS(parser.parse(R"({"val":-12345678901234567890})"_padded).get(doc));
|
||||
dom::element val;
|
||||
ASSERT_SUCCESS(doc["val"].get(val));
|
||||
ASSERT_EQUAL(val.type(), dom::element_type::BIGINT);
|
||||
std::string_view digits;
|
||||
ASSERT_SUCCESS(val.get_bigint().get(digits));
|
||||
ASSERT_EQUAL(digits, "-12345678901234567890");
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool big_integer_in_array() {
|
||||
TEST_START();
|
||||
dom::parser parser;
|
||||
parser.number_as_string(true);
|
||||
dom::element doc;
|
||||
ASSERT_SUCCESS(parser.parse(R"([1, 123456789012345678901, 3])"_padded).get(doc));
|
||||
dom::array arr;
|
||||
ASSERT_SUCCESS(doc.get_array().get(arr));
|
||||
size_t count = 0;
|
||||
for (auto elem : arr) { (void)elem; count++; }
|
||||
ASSERT_EQUAL(count, 3);
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool serialization_preserves_digits() {
|
||||
TEST_START();
|
||||
dom::parser parser;
|
||||
parser.number_as_string(true);
|
||||
dom::element doc;
|
||||
ASSERT_SUCCESS(parser.parse(R"({"val":123456789012345678901})"_padded).get(doc));
|
||||
std::string output = simdjson::to_string(doc);
|
||||
// Raw digits should appear
|
||||
ASSERT_TRUE(output.find("123456789012345678901") != std::string::npos);
|
||||
// Must not be quoted — it's a number, not a string
|
||||
ASSERT_EQUAL(output.find("\"123456789012345678901\""), std::string::npos);
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool normal_numbers_unaffected() {
|
||||
TEST_START();
|
||||
dom::parser parser;
|
||||
parser.number_as_string(true);
|
||||
dom::element doc;
|
||||
ASSERT_SUCCESS(parser.parse(R"({"a":42,"b":-1,"c":3.14,"d":18446744073709551615})"_padded).get(doc));
|
||||
int64_t a;
|
||||
ASSERT_SUCCESS(doc["a"].get_int64().get(a));
|
||||
ASSERT_EQUAL(a, 42);
|
||||
uint64_t d;
|
||||
ASSERT_SUCCESS(doc["d"].get_uint64().get(d));
|
||||
ASSERT_EQUAL(d, 18446744073709551615ULL);
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool type_checks() {
|
||||
TEST_START();
|
||||
dom::parser parser;
|
||||
parser.number_as_string(true);
|
||||
dom::element doc;
|
||||
ASSERT_SUCCESS(parser.parse(R"({"val":123456789012345678901})"_padded).get(doc));
|
||||
dom::element val;
|
||||
ASSERT_SUCCESS(doc["val"].get(val));
|
||||
// is_bigint should be true
|
||||
ASSERT_TRUE(val.is_bigint());
|
||||
// other type checks should be false
|
||||
ASSERT_FALSE(val.is_int64());
|
||||
ASSERT_FALSE(val.is_uint64());
|
||||
ASSERT_FALSE(val.is_double());
|
||||
ASSERT_FALSE(val.is_string());
|
||||
ASSERT_FALSE(val.is_bool());
|
||||
ASSERT_FALSE(val.is_null());
|
||||
// get_int64/uint64/double should return INCORRECT_TYPE
|
||||
ASSERT_ERROR(val.get_int64(), INCORRECT_TYPE);
|
||||
ASSERT_ERROR(val.get_uint64(), INCORRECT_TYPE);
|
||||
ASSERT_ERROR(val.get_double(), INCORRECT_TYPE);
|
||||
ASSERT_ERROR(val.get_string(), INCORRECT_TYPE);
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool element_type_output() {
|
||||
TEST_START();
|
||||
std::ostringstream os;
|
||||
os << dom::element_type::BIGINT;
|
||||
ASSERT_EQUAL(os.str(), "bigint");
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool run() {
|
||||
return option_off_by_default() &&
|
||||
default_returns_bigint_error() &&
|
||||
opt_in_parses_big_integer() &&
|
||||
negative_big_integer() &&
|
||||
big_integer_in_array() &&
|
||||
serialization_preserves_digits() &&
|
||||
normal_numbers_unaffected() &&
|
||||
type_checks() &&
|
||||
element_type_output();
|
||||
}
|
||||
|
||||
} // namespace big_integer_tests
|
||||
|
||||
int main() {
|
||||
return big_integer_tests::run() ? 0 : 1;
|
||||
}
|
||||
@@ -114,6 +114,20 @@ namespace parser_load {
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool parser_load_string_view_subpath() {
|
||||
TEST_START();
|
||||
const std::string valid_path(TWITTER_JSON);
|
||||
const std::string backing = valid_path + ".extra";
|
||||
const std::string_view view(backing.data(), valid_path.size());
|
||||
uint64_t count_from_string = 0;
|
||||
uint64_t count_from_view = 0;
|
||||
dom::parser parser;
|
||||
ASSERT_SUCCESS(parser.load(valid_path)["search_metadata"]["count"].get(count_from_string));
|
||||
ASSERT_SUCCESS(parser.load(view)["search_metadata"]["count"].get(count_from_view));
|
||||
ASSERT_EQUAL(count_from_view, count_from_string);
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool parser_load_chain() {
|
||||
TEST_START();
|
||||
dom::parser parser;
|
||||
@@ -136,6 +150,7 @@ namespace parser_load {
|
||||
&& parser_load_nonexistent()
|
||||
&& parser_load_many_nonexistent()
|
||||
&& padded_string_load_nonexistent()
|
||||
&& parser_load_string_view_subpath()
|
||||
&& parser_load_chain()
|
||||
&& parser_load_many_chain()
|
||||
&& parser_parse_many_documents_error_in_the_middle()
|
||||
|
||||
@@ -273,6 +273,9 @@ namespace treewalk_1 {
|
||||
case dom::element_type::NULL_VALUE:
|
||||
cout << "null" << endl;
|
||||
break;
|
||||
case dom::element_type::BIGINT:
|
||||
cout << element.get_bigint().value_unsafe() << endl;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -884,6 +884,30 @@ namespace document_stream_tests {
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool uint32_with_trailing() {
|
||||
TEST_START();
|
||||
auto json = R"( 133 badstuff )"_padded;
|
||||
ondemand::parser parser;
|
||||
ondemand::document_stream doc;
|
||||
ASSERT_SUCCESS(parser.iterate_many(json).get(doc));
|
||||
uint32_t x;
|
||||
ASSERT_SUCCESS((*doc.begin()).get_uint32().get(x));
|
||||
ASSERT_EQUAL(x,133);
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool int32_with_trailing() {
|
||||
TEST_START();
|
||||
auto json = R"( 133 badstuff )"_padded;
|
||||
ondemand::parser parser;
|
||||
ondemand::document_stream doc;
|
||||
ASSERT_SUCCESS(parser.iterate_many(json).get(doc));
|
||||
int32_t x;
|
||||
ASSERT_SUCCESS((*doc.begin()).get_int32().get(x));
|
||||
ASSERT_EQUAL(x,133);
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool double_with_trailing() {
|
||||
TEST_START();
|
||||
auto json = R"( 133 badstuff )"_padded;
|
||||
@@ -931,6 +955,8 @@ namespace document_stream_tests {
|
||||
string_with_trailing() &&
|
||||
uint64_with_trailing() &&
|
||||
int64_with_trailing() &&
|
||||
uint32_with_trailing() &&
|
||||
int32_with_trailing() &&
|
||||
bool_with_trailing() &&
|
||||
null_with_trailing() &&
|
||||
truncated_utf8() &&
|
||||
|
||||
@@ -171,6 +171,17 @@ namespace error_tests {
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool parser_set_max_capacity() {
|
||||
TEST_START();
|
||||
ondemand::parser parser;
|
||||
parser.set_max_capacity(1024 * 1024);
|
||||
ASSERT_EQUAL(parser.max_capacity(), size_t(1024 * 1024));
|
||||
auto json = R"({"k":"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"})"_padded;
|
||||
ondemand::document doc;
|
||||
ASSERT_SUCCESS(parser.iterate(json).get(doc));
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool simple_error_example() {
|
||||
TEST_START();
|
||||
ondemand::parser parser;
|
||||
@@ -212,7 +223,11 @@ namespace error_tests {
|
||||
ASSERT_ERROR( val.get_double(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_uint64(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_int64(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_uint32(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_int32(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_object(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_int32(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_uint32(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_int64(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_uint64(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_double(), INCORRECT_TYPE );
|
||||
@@ -235,7 +250,11 @@ namespace error_tests {
|
||||
ASSERT_ERROR( val.get_double(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_uint64(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_int64(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_uint32(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_int32(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_object(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_int32(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_uint32(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_int64(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_uint64(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_double(), INCORRECT_TYPE );
|
||||
@@ -257,7 +276,11 @@ namespace error_tests {
|
||||
ASSERT_ERROR( val.get_double(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_uint64(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_int64(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_uint32(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_int32(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_object(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_int32(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_uint32(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_int64(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_uint64(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_double(), INCORRECT_TYPE );
|
||||
@@ -279,7 +302,11 @@ namespace error_tests {
|
||||
ASSERT_ERROR( val.get_double(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_uint64(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_int64(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_uint32(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_int32(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_object(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_int32(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_uint32(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_int64(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_uint64(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_double(), INCORRECT_TYPE );
|
||||
@@ -306,7 +333,11 @@ namespace error_tests {
|
||||
ASSERT_ERROR( val.get_double(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_uint64(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_int64(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_uint32(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_int32(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_object(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_int32(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_uint32(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_int64(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_uint64(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_double(), INCORRECT_TYPE );
|
||||
@@ -329,7 +360,11 @@ namespace error_tests {
|
||||
ASSERT_ERROR( val.get_double(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_uint64(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_int64(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_uint32(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_int32(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_object(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_int32(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_uint32(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_int64(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_uint64(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_double(), INCORRECT_TYPE );
|
||||
@@ -350,7 +385,11 @@ namespace error_tests {
|
||||
ASSERT_ERROR( val.get_double(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_uint64(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_int64(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_uint32(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_int32(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_object(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_int32(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_uint32(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_int64(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_uint64(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_double(), INCORRECT_TYPE );
|
||||
@@ -371,7 +410,11 @@ namespace error_tests {
|
||||
ASSERT_ERROR( val.get_double(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_uint64(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_int64(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_uint32(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_int32(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_object(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_int32(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_uint32(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_int64(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_uint64(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_double(), INCORRECT_TYPE );
|
||||
@@ -432,6 +475,7 @@ namespace error_tests {
|
||||
raw_json_string_error() &&
|
||||
empty_document_error() &&
|
||||
parser_max_capacity() &&
|
||||
parser_set_max_capacity() &&
|
||||
get_fail_then_succeed_bool() &&
|
||||
get_fail_then_succeed_null() &&
|
||||
simple_error_example() &&
|
||||
|
||||
@@ -545,8 +545,111 @@ namespace number_tests {
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool get_int32_values() {
|
||||
TEST_START();
|
||||
ondemand::parser parser;
|
||||
ondemand::document doc;
|
||||
int32_t val;
|
||||
padded_string docdata;
|
||||
|
||||
// Valid int32 values
|
||||
docdata = "0"_padded;
|
||||
ASSERT_SUCCESS(parser.iterate(docdata).get(doc));
|
||||
ASSERT_SUCCESS(doc.get_int32().get(val));
|
||||
ASSERT_EQUAL(val, 0);
|
||||
|
||||
docdata = "42"_padded;
|
||||
ASSERT_SUCCESS(parser.iterate(docdata).get(doc));
|
||||
ASSERT_SUCCESS(doc.get_int32().get(val));
|
||||
ASSERT_EQUAL(val, 42);
|
||||
|
||||
docdata = "-1"_padded;
|
||||
ASSERT_SUCCESS(parser.iterate(docdata).get(doc));
|
||||
ASSERT_SUCCESS(doc.get_int32().get(val));
|
||||
ASSERT_EQUAL(val, -1);
|
||||
|
||||
docdata = "2147483647"_padded; // INT32_MAX
|
||||
ASSERT_SUCCESS(parser.iterate(docdata).get(doc));
|
||||
ASSERT_SUCCESS(doc.get_int32().get(val));
|
||||
ASSERT_EQUAL(val, 2147483647);
|
||||
|
||||
docdata = "-2147483648"_padded; // INT32_MIN
|
||||
ASSERT_SUCCESS(parser.iterate(docdata).get(doc));
|
||||
ASSERT_SUCCESS(doc.get_int32().get(val));
|
||||
ASSERT_EQUAL(val, -2147483648);
|
||||
|
||||
// Out of range
|
||||
docdata = "2147483648"_padded; // INT32_MAX + 1
|
||||
ASSERT_SUCCESS(parser.iterate(docdata).get(doc));
|
||||
ASSERT_ERROR(doc.get_int32(), NUMBER_OUT_OF_RANGE);
|
||||
|
||||
docdata = "-2147483649"_padded; // INT32_MIN - 1
|
||||
ASSERT_SUCCESS(parser.iterate(docdata).get(doc));
|
||||
ASSERT_ERROR(doc.get_int32(), NUMBER_OUT_OF_RANGE);
|
||||
|
||||
docdata = "9999999999"_padded;
|
||||
ASSERT_SUCCESS(parser.iterate(docdata).get(doc));
|
||||
ASSERT_ERROR(doc.get_int32(), NUMBER_OUT_OF_RANGE);
|
||||
|
||||
// Test via value path
|
||||
auto json = R"({"x": 42})"_padded;
|
||||
ASSERT_SUCCESS(parser.iterate(json).get(doc));
|
||||
ASSERT_SUCCESS(doc["x"].get_int32().get(val));
|
||||
ASSERT_EQUAL(val, 42);
|
||||
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool get_uint32_values() {
|
||||
TEST_START();
|
||||
ondemand::parser parser;
|
||||
ondemand::document doc;
|
||||
uint32_t val;
|
||||
padded_string docdata;
|
||||
|
||||
// Valid uint32 values
|
||||
docdata = "0"_padded;
|
||||
ASSERT_SUCCESS(parser.iterate(docdata).get(doc));
|
||||
ASSERT_SUCCESS(doc.get_uint32().get(val));
|
||||
ASSERT_EQUAL(val, 0u);
|
||||
|
||||
docdata = "42"_padded;
|
||||
ASSERT_SUCCESS(parser.iterate(docdata).get(doc));
|
||||
ASSERT_SUCCESS(doc.get_uint32().get(val));
|
||||
ASSERT_EQUAL(val, 42u);
|
||||
|
||||
docdata = "4294967295"_padded; // UINT32_MAX
|
||||
ASSERT_SUCCESS(parser.iterate(docdata).get(doc));
|
||||
ASSERT_SUCCESS(doc.get_uint32().get(val));
|
||||
ASSERT_EQUAL(val, 4294967295u);
|
||||
|
||||
// Out of range
|
||||
docdata = "4294967296"_padded; // UINT32_MAX + 1
|
||||
ASSERT_SUCCESS(parser.iterate(docdata).get(doc));
|
||||
ASSERT_ERROR(doc.get_uint32(), NUMBER_OUT_OF_RANGE);
|
||||
|
||||
docdata = "9999999999"_padded;
|
||||
ASSERT_SUCCESS(parser.iterate(docdata).get(doc));
|
||||
ASSERT_ERROR(doc.get_uint32(), NUMBER_OUT_OF_RANGE);
|
||||
|
||||
// Negative values should fail (get_uint64 will fail with INCORRECT_TYPE)
|
||||
docdata = "-1"_padded;
|
||||
ASSERT_SUCCESS(parser.iterate(docdata).get(doc));
|
||||
ASSERT_ERROR(doc.get_uint32(), INCORRECT_TYPE);
|
||||
|
||||
// Test via value path
|
||||
auto json = R"({"x": 42})"_padded;
|
||||
ASSERT_SUCCESS(parser.iterate(json).get(doc));
|
||||
ASSERT_SUCCESS(doc["x"].get_uint32().get(val));
|
||||
ASSERT_EQUAL(val, 42u);
|
||||
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool run() {
|
||||
return minus_zero() &&
|
||||
return get_int32_values() &&
|
||||
get_uint32_values() &&
|
||||
minus_zero() &&
|
||||
gigantic_big_int() &&
|
||||
big_int_not_zero() &&
|
||||
negative_big_int() &&
|
||||
|
||||
@@ -177,6 +177,68 @@ simdjson_inline simdjson_result<Car> simdjson::ondemand::document::get() & noexc
|
||||
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
|
||||
// Test matching the doc example in doc/basics.md
|
||||
// "Using for_each_at_path_with_wildcard for JSONPath Queries (On-Demand)"
|
||||
bool wildcard_basics_example() {
|
||||
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"]
|
||||
},
|
||||
{
|
||||
"type": "home",
|
||||
"numbers": ["0123-4567-8910"]
|
||||
}
|
||||
]
|
||||
})"_padded;
|
||||
|
||||
ondemand::parser parser;
|
||||
ondemand::document doc = parser.iterate(json_string);
|
||||
|
||||
// Fetch all fields in the address object
|
||||
std::vector<std::string_view> fields;
|
||||
auto error = doc.for_each_at_path_with_wildcard("$.address.*",
|
||||
[&](ondemand::value value) {
|
||||
std::string_view field;
|
||||
if (value.get(field) == SUCCESS) {
|
||||
fields.push_back(field);
|
||||
}
|
||||
});
|
||||
ASSERT_SUCCESS(error);
|
||||
ASSERT_EQUAL(fields.size(), 3);
|
||||
ASSERT_EQUAL(fields[0], "naist street");
|
||||
ASSERT_EQUAL(fields[1], "Nara");
|
||||
ASSERT_EQUAL(fields[2], "630-0192");
|
||||
|
||||
// Fetch all phone numbers
|
||||
std::vector<std::string_view> numbers;
|
||||
error = doc.for_each_at_path_with_wildcard("$.phoneNumbers[*].numbers[*]",
|
||||
[&](ondemand::value value) {
|
||||
std::string_view number;
|
||||
if (value.get(number) == SUCCESS) {
|
||||
numbers.push_back(number);
|
||||
}
|
||||
});
|
||||
ASSERT_SUCCESS(error);
|
||||
ASSERT_EQUAL(numbers.size(), 3);
|
||||
ASSERT_EQUAL(numbers[0], "0123-4567-8888");
|
||||
ASSERT_EQUAL(numbers[1], "0123-4567-8788");
|
||||
ASSERT_EQUAL(numbers[2], "0123-4567-8910");
|
||||
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
void main_capture() {
|
||||
padded_string json_padded = "{\"a\":[1,2,3], \"b\": 2, \"c\": \"hello\"}"_padded;
|
||||
std::vector<std::string_view> fields;
|
||||
@@ -2016,6 +2078,7 @@ bool value_raw_json_object() {
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
bool run() {
|
||||
return true
|
||||
&& fatal_error()
|
||||
@@ -2075,6 +2138,7 @@ bool run() {
|
||||
&& current_location_no_error()
|
||||
&& to_string_example_no_except()
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
&& wildcard_basics_example()
|
||||
&& issue2215()
|
||||
&& to_string_example()
|
||||
&& raw_string()
|
||||
|
||||
@@ -21,18 +21,16 @@ namespace wildcard_tests {
|
||||
ondemand::parser parser;
|
||||
auto doc = parser.iterate(json);
|
||||
|
||||
std::vector<ondemand::value> titles;
|
||||
ASSERT_SUCCESS(doc.at_path_with_wildcard("$.books[*].title").get(titles));
|
||||
std::vector<std::string_view> titles;
|
||||
ASSERT_SUCCESS(doc.for_each_at_path_with_wildcard("$.books[*].title", [&](ondemand::value v) {
|
||||
std::string_view sv;
|
||||
if (v.get_string().get(sv) == SUCCESS) { titles.push_back(sv); }
|
||||
}));
|
||||
|
||||
ASSERT_EQUAL(titles.size(), 3);
|
||||
|
||||
std::string_view title;
|
||||
ASSERT_SUCCESS(titles[0].get_string().get(title));
|
||||
ASSERT_EQUAL(title, "Book A");
|
||||
ASSERT_SUCCESS(titles[1].get_string().get(title));
|
||||
ASSERT_EQUAL(title, "Book B");
|
||||
ASSERT_SUCCESS(titles[2].get_string().get(title));
|
||||
ASSERT_EQUAL(title, "Book C");
|
||||
ASSERT_EQUAL(titles[0], "Book A");
|
||||
ASSERT_EQUAL(titles[1], "Book B");
|
||||
ASSERT_EQUAL(titles[2], "Book C");
|
||||
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
@@ -46,18 +44,16 @@ namespace wildcard_tests {
|
||||
ondemand::parser parser;
|
||||
auto doc = parser.iterate(json);
|
||||
|
||||
std::vector<ondemand::value> prices;
|
||||
ASSERT_SUCCESS(doc.at_path_with_wildcard("$.prices[*]").get(prices));
|
||||
std::vector<uint64_t> prices;
|
||||
ASSERT_SUCCESS(doc.for_each_at_path_with_wildcard("$.prices[*]", [&](ondemand::value v) {
|
||||
uint64_t p;
|
||||
if (v.get_uint64().get(p) == SUCCESS) { prices.push_back(p); }
|
||||
}));
|
||||
|
||||
ASSERT_EQUAL(prices.size(), 5);
|
||||
|
||||
uint64_t price;
|
||||
ASSERT_SUCCESS(prices[0].get_uint64().get(price));
|
||||
ASSERT_EQUAL(price, 10);
|
||||
ASSERT_SUCCESS(prices[2].get_uint64().get(price));
|
||||
ASSERT_EQUAL(price, 30);
|
||||
ASSERT_SUCCESS(prices[4].get_uint64().get(price));
|
||||
ASSERT_EQUAL(price, 50);
|
||||
ASSERT_EQUAL(prices[0], 10);
|
||||
ASSERT_EQUAL(prices[2], 30);
|
||||
ASSERT_EQUAL(prices[4], 50);
|
||||
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
@@ -75,19 +71,14 @@ namespace wildcard_tests {
|
||||
ondemand::parser parser;
|
||||
auto doc = parser.iterate(json);
|
||||
|
||||
std::vector<ondemand::value> names;
|
||||
auto error = doc.at_path_with_wildcard("$.users.*.name").get(names);
|
||||
std::set<std::string_view> name_set;
|
||||
auto error = doc.for_each_at_path_with_wildcard("$.users.*.name", [&](ondemand::value v) {
|
||||
std::string_view sv;
|
||||
if (v.get_string().get(sv) == SUCCESS) { name_set.insert(sv); }
|
||||
});
|
||||
ASSERT_SUCCESS(error);
|
||||
|
||||
ASSERT_EQUAL(names.size(), 3);
|
||||
|
||||
// Verify we got all three names (order may vary)
|
||||
std::set<std::string_view> name_set;
|
||||
for (auto& name : names) {
|
||||
std::string_view view;
|
||||
ASSERT_SUCCESS(name.get_string().get(view));
|
||||
name_set.insert(view);
|
||||
}
|
||||
ASSERT_EQUAL(name_set.size(), 3);
|
||||
ASSERT_TRUE(name_set.count("Alice") > 0);
|
||||
ASSERT_TRUE(name_set.count("Bob") > 0);
|
||||
ASSERT_TRUE(name_set.count("Charlie") > 0);
|
||||
@@ -117,19 +108,15 @@ namespace wildcard_tests {
|
||||
ondemand::parser parser;
|
||||
auto doc = parser.iterate(json);
|
||||
|
||||
std::vector<ondemand::value> salaries;
|
||||
auto error = doc.at_path_with_wildcard("$.departments.*.employees[*].salary").get(salaries);
|
||||
uint64_t total = 0;
|
||||
size_t count = 0;
|
||||
auto error = doc.for_each_at_path_with_wildcard("$.departments.*.employees[*].salary", [&](ondemand::value v) {
|
||||
uint64_t s;
|
||||
if (v.get_uint64().get(s) == SUCCESS) { total += s; count++; }
|
||||
});
|
||||
ASSERT_SUCCESS(error);
|
||||
|
||||
ASSERT_EQUAL(salaries.size(), 4);
|
||||
|
||||
// Check sum of all salaries
|
||||
uint64_t total = 0;
|
||||
for (auto& salary : salaries) {
|
||||
uint64_t value;
|
||||
ASSERT_SUCCESS(salary.get_uint64().get(value));
|
||||
total += value;
|
||||
}
|
||||
ASSERT_EQUAL(count, 4);
|
||||
ASSERT_EQUAL(total, 360000);
|
||||
|
||||
TEST_SUCCEED();
|
||||
@@ -142,11 +129,12 @@ namespace wildcard_tests {
|
||||
ondemand::parser parser;
|
||||
auto doc = parser.iterate(json);
|
||||
|
||||
std::vector<ondemand::value> items;
|
||||
auto error = doc.at_path_with_wildcard("$.items[*].name").get(items);
|
||||
size_t count = 0;
|
||||
auto error = doc.for_each_at_path_with_wildcard("$.items[*].name", [&](ondemand::value) {
|
||||
count++;
|
||||
});
|
||||
ASSERT_SUCCESS(error);
|
||||
|
||||
ASSERT_EQUAL(items.size(), 0);
|
||||
ASSERT_EQUAL(count, 0);
|
||||
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
@@ -158,11 +146,12 @@ namespace wildcard_tests {
|
||||
ondemand::parser parser;
|
||||
auto doc = parser.iterate(json);
|
||||
|
||||
std::vector<ondemand::value> names;
|
||||
auto error = doc.at_path_with_wildcard("$.users.*.name").get(names);
|
||||
size_t count = 0;
|
||||
auto error = doc.for_each_at_path_with_wildcard("$.users.*.name", [&](ondemand::value) {
|
||||
count++;
|
||||
});
|
||||
ASSERT_SUCCESS(error);
|
||||
|
||||
ASSERT_EQUAL(names.size(), 0);
|
||||
ASSERT_EQUAL(count, 0);
|
||||
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
@@ -175,8 +164,7 @@ namespace wildcard_tests {
|
||||
auto doc = parser.iterate(json);
|
||||
|
||||
// Can't use array wildcard on scalar
|
||||
std::vector<ondemand::value> values;
|
||||
auto error = doc.at_path_with_wildcard("$.data[*]").get(values);
|
||||
auto error = doc.for_each_at_path_with_wildcard("$.data[*]", [](ondemand::value) {});
|
||||
ASSERT_ERROR(error, INVALID_JSON_POINTER);
|
||||
|
||||
TEST_SUCCEED();
|
||||
@@ -195,12 +183,12 @@ namespace wildcard_tests {
|
||||
ondemand::parser parser;
|
||||
auto doc = parser.iterate(json);
|
||||
|
||||
// Get all nested arrays
|
||||
std::vector<ondemand::value> arrays;
|
||||
ASSERT_SUCCESS(doc.at_path_with_wildcard("$.matrix[*]").get(arrays));
|
||||
size_t count = 0;
|
||||
ASSERT_SUCCESS(doc.for_each_at_path_with_wildcard("$.matrix[*]", [&](ondemand::value) {
|
||||
count++;
|
||||
}));
|
||||
|
||||
// Verify we got 3 arrays
|
||||
ASSERT_EQUAL(arrays.size(), 3);
|
||||
ASSERT_EQUAL(count, 3);
|
||||
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
@@ -218,18 +206,16 @@ namespace wildcard_tests {
|
||||
ondemand::parser parser;
|
||||
auto doc = parser.iterate(json);
|
||||
|
||||
std::vector<ondemand::value> statuses;
|
||||
ASSERT_SUCCESS(doc.at_path_with_wildcard("$.data[*].info.status").get(statuses));
|
||||
std::vector<std::string_view> statuses;
|
||||
ASSERT_SUCCESS(doc.for_each_at_path_with_wildcard("$.data[*].info.status", [&](ondemand::value v) {
|
||||
std::string_view sv;
|
||||
if (v.get_string().get(sv) == SUCCESS) { statuses.push_back(sv); }
|
||||
}));
|
||||
|
||||
ASSERT_EQUAL(statuses.size(), 3);
|
||||
|
||||
std::string_view status;
|
||||
ASSERT_SUCCESS(statuses[0].get_string().get(status));
|
||||
ASSERT_EQUAL(status, "active");
|
||||
ASSERT_SUCCESS(statuses[1].get_string().get(status));
|
||||
ASSERT_EQUAL(status, "inactive");
|
||||
ASSERT_SUCCESS(statuses[2].get_string().get(status));
|
||||
ASSERT_EQUAL(status, "active");
|
||||
ASSERT_EQUAL(statuses[0], "active");
|
||||
ASSERT_EQUAL(statuses[1], "inactive");
|
||||
ASSERT_EQUAL(statuses[2], "active");
|
||||
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
@@ -250,13 +236,12 @@ namespace wildcard_tests {
|
||||
ondemand::parser parser;
|
||||
auto doc = parser.iterate(json);
|
||||
|
||||
std::vector<ondemand::value> values;
|
||||
ASSERT_SUCCESS(doc.at_path_with_wildcard("$.mixed[*]").get(values));
|
||||
size_t count = 0;
|
||||
ASSERT_SUCCESS(doc.for_each_at_path_with_wildcard("$.mixed[*]", [&](ondemand::value) {
|
||||
count++;
|
||||
}));
|
||||
|
||||
// Just verify we got all 6 elements
|
||||
ASSERT_EQUAL(values.size(), 6);
|
||||
|
||||
// Don't try to access the values - they've been consumed by the OnDemand API
|
||||
ASSERT_EQUAL(count, 6);
|
||||
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
@@ -275,8 +260,11 @@ namespace wildcard_tests {
|
||||
auto doc = parser.iterate(json);
|
||||
|
||||
// Third element doesn't have "name" field
|
||||
std::vector<ondemand::value> names;
|
||||
auto error = doc.at_path_with_wildcard("$.data[*].name").get(names);
|
||||
std::vector<std::string_view> names;
|
||||
auto error = doc.for_each_at_path_with_wildcard("$.data[*].name", [&](ondemand::value v) {
|
||||
std::string_view sv;
|
||||
if (v.get_string().get(sv) == SUCCESS) { names.push_back(sv); }
|
||||
});
|
||||
|
||||
// This might error or return partial results
|
||||
if (error) {
|
||||
@@ -301,18 +289,47 @@ namespace wildcard_tests {
|
||||
ondemand::parser parser;
|
||||
auto doc = parser.iterate(json);
|
||||
|
||||
std::vector<ondemand::value> names;
|
||||
ASSERT_SUCCESS(doc.at_path_with_wildcard("$[*].name").get(names));
|
||||
std::vector<std::string_view> names;
|
||||
ASSERT_SUCCESS(doc.for_each_at_path_with_wildcard("$[*].name", [&](ondemand::value v) {
|
||||
std::string_view sv;
|
||||
if (v.get_string().get(sv) == SUCCESS) { names.push_back(sv); }
|
||||
}));
|
||||
|
||||
ASSERT_EQUAL(names.size(), 3);
|
||||
ASSERT_EQUAL(names[0], "Item 1");
|
||||
ASSERT_EQUAL(names[1], "Item 2");
|
||||
ASSERT_EQUAL(names[2], "Item 3");
|
||||
|
||||
std::string_view name;
|
||||
ASSERT_SUCCESS(names[0].get_string().get(name));
|
||||
ASSERT_EQUAL(name, "Item 1");
|
||||
ASSERT_SUCCESS(names[1].get_string().get(name));
|
||||
ASSERT_EQUAL(name, "Item 2");
|
||||
ASSERT_SUCCESS(names[2].get_string().get(name));
|
||||
ASSERT_EQUAL(name, "Item 3");
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
// https://github.com/simdjson/simdjson/issues/2684
|
||||
bool wildcard_raw_json_issue_2684() {
|
||||
TEST_START();
|
||||
auto json = R"([{"tag_meta":{"meta_code":2000211,"meta_value":""},"tag_value":""}])"_padded;
|
||||
|
||||
ondemand::parser parser;
|
||||
auto doc = parser.iterate(json);
|
||||
|
||||
size_t count = 0;
|
||||
bool raw_json_ok = true;
|
||||
ASSERT_SUCCESS(doc.for_each_at_path_with_wildcard("$[*].tag_meta", [&](ondemand::value v) {
|
||||
count++;
|
||||
std::string_view raw;
|
||||
if (v.raw_json().get(raw) != SUCCESS) {
|
||||
raw_json_ok = false;
|
||||
return;
|
||||
}
|
||||
// raw_json() must not leak sibling fields or outer array delimiters
|
||||
std::string_view expected = R"({"meta_code":2000211,"meta_value":""})";
|
||||
if (raw != expected || raw.find("tag_value") != std::string_view::npos) {
|
||||
std::cerr << " raw_json() returned: " << raw << std::endl;
|
||||
raw_json_ok = false;
|
||||
}
|
||||
}));
|
||||
|
||||
ASSERT_EQUAL(count, 1);
|
||||
ASSERT_TRUE(raw_json_ok);
|
||||
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
@@ -329,10 +346,11 @@ namespace wildcard_tests {
|
||||
wildcard_with_nested_objects() &&
|
||||
mixed_types_in_array() &&
|
||||
wildcard_nonexistent_field() &&
|
||||
root_array_wildcard();
|
||||
root_array_wildcard() &&
|
||||
wildcard_raw_json_issue_2684();
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
return test_main(argc, argv, wildcard_tests::run);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user