mirror of
https://github.com/simdjson/simdjson
synced 2026-06-08 17:27:07 +00:00
Compare commits
20 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 1bcf71bd85 | |||
| f01641e463 | |||
| 65e59ccf9b | |||
| 61641f9a7a | |||
| 996dc25180 | |||
| 77cf997595 | |||
| 453ae4e955 | |||
| f5602fa3c7 | |||
| 942f7f298b | |||
| 6a4fc260a1 | |||
| fb83b114ef | |||
| 542cd7af71 | |||
| 769364abb2 | |||
| f25d5f9fc2 | |||
| 12fb30ae9c | |||
| c0a952687d | |||
| 307ddd4415 | |||
| 21657455ed | |||
| afb1c9f4b1 | |||
| 9973f7b3a3 |
+86
-81
@@ -12,7 +12,7 @@ endif()
|
||||
project(
|
||||
simdjson
|
||||
# The version number is modified by tools/release.py
|
||||
VERSION 4.5.0
|
||||
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 "32.0.0" CACHE STRING "simdjson library version")
|
||||
set(SIMDJSON_LIB_SOVERSION "32" 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)
|
||||
@@ -225,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.5.0"
|
||||
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
|
||||
|
||||
+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.
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include <array>
|
||||
#include <cstring>
|
||||
#include <limits>
|
||||
#include <type_traits>
|
||||
#ifndef SIMDJSON_GENERIC_STRING_BUILDER_INL_H
|
||||
|
||||
@@ -755,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);
|
||||
}
|
||||
@@ -763,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
|
||||
|
||||
@@ -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.5.0"
|
||||
#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 = 5,
|
||||
SIMDJSON_VERSION_MINOR = 6,
|
||||
/**
|
||||
* The revision (major.minor.REVISION) of simdjson being used.
|
||||
*/
|
||||
SIMDJSON_VERSION_REVISION = 0
|
||||
SIMDJSON_VERSION_REVISION = 4
|
||||
};
|
||||
} // namespace simdjson
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* auto-generated on 2026-03-25 17:25:37 -0400. version 4.5.0 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
|
||||
|
||||
+3062
-990
File diff suppressed because it is too large
Load Diff
Binary file not shown.
@@ -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()
|
||||
|
||||
@@ -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